diff --git a/internal/tracing/openinference/openai/response_attrs.go b/internal/tracing/openinference/openai/response_attrs.go index 9be34c5b87..7c843cb2c4 100644 --- a/internal/tracing/openinference/openai/response_attrs.go +++ b/internal/tracing/openinference/openai/response_attrs.go @@ -233,38 +233,27 @@ func setResponseOutputAttrs(output *openai.ResponseOutputItemUnion, attrs []attr case output.OfCustomToolCall != nil: attrs = setResponseCustomToolCallAttrs(output.OfCustomToolCall, attrs, config, messageIndex) case output.OfImageGenerationCall != nil: - // TODO: Handle image generation call - // https://github.com/Arize-ai/openinference/blob/f6561ca5a169f13d5b40120311b782348550b5ac/python/instrumentation/openinference-instrumentation-openai/src/openinference/instrumentation/openai/_attributes/_responses_api.py#L573 + attrs = setResponseImageGenerationCallAttrs(output.OfImageGenerationCall, attrs, config, messageIndex) case output.OfCodeInterpreterCall != nil: - // TODO: Handle code interpreter call - // https://github.com/Arize-ai/openinference/blob/f6561ca5a169f13d5b40120311b782348550b5ac/python/instrumentation/openinference-instrumentation-openai/src/openinference/instrumentation/openai/_attributes/_responses_api.py#L576 + attrs = setResponseCodeInterpreterCallAttrs(output.OfCodeInterpreterCall, attrs, config, messageIndex) case output.OfLocalShellCall != nil: - // TODO: Handle local shell call - // https://github.com/Arize-ai/openinference/blob/f6561ca5a169f13d5b40120311b782348550b5ac/python/instrumentation/openinference-instrumentation-openai/src/openinference/instrumentation/openai/_attributes/_responses_api.py#L579 + attrs = setResponseLocalShellCallAttrs(output.OfLocalShellCall, attrs, config, messageIndex) case output.OfMcpCall != nil: - // TODO: Handle mcp call - // https://github.com/Arize-ai/openinference/blob/f6561ca5a169f13d5b40120311b782348550b5ac/python/instrumentation/openinference-instrumentation-openai/src/openinference/instrumentation/openai/_attributes/_responses_api.py#L582 + attrs = setResponseMcpCallAttrs(output.OfMcpCall, attrs, config, messageIndex) case output.OfMcpListTools != nil: - // TODO: Handle mcp list tools - // https://github.com/Arize-ai/openinference/blob/f6561ca5a169f13d5b40120311b782348550b5ac/python/instrumentation/openinference-instrumentation-openai/src/openinference/instrumentation/openai/_attributes/_responses_api.py#L585 + attrs = setResponseMcpListToolsAttrs(output.OfMcpListTools, attrs, config, messageIndex) case output.OfMcpApprovalRequest != nil: - // TODO: Handle mcp approval request - // https://github.com/Arize-ai/openinference/blob/f6561ca5a169f13d5b40120311b782348550b5ac/python/instrumentation/openinference-instrumentation-openai/src/openinference/instrumentation/openai/_attributes/_responses_api.py#L588 + attrs = setResponseMcpApprovalRequestAttrs(output.OfMcpApprovalRequest, attrs, config, messageIndex) case output.OfShellCall != nil: - // TODO: Handle shell call - // https://github.com/Arize-ai/openinference/blob/f6561ca5a169f13d5b40120311b782348550b5ac/python/instrumentation/openinference-instrumentation-openai/src/openinference/instrumentation/openai/_attributes/_responses_api.py#L591 + attrs = setResponseShellCallAttrs(output.OfShellCall, attrs, config, messageIndex) case output.OfShellCallOutput != nil: - // TODO: Handle shell call output - // https://github.com/Arize-ai/openinference/blob/f6561ca5a169f13d5b40120311b782348550b5ac/python/instrumentation/openinference-instrumentation-openai/src/openinference/instrumentation/openai/_attributes/_responses_api.py#L594 + attrs = setResponseShellCallOutputAttrs(output.OfShellCallOutput, attrs, config, messageIndex) case output.OfApplyPatchCall != nil: - // TODO: Handle patch call - // https://github.com/Arize-ai/openinference/blob/f6561ca5a169f13d5b40120311b782348550b5ac/python/instrumentation/openinference-instrumentation-openai/src/openinference/instrumentation/openai/_attributes/_responses_api.py#L597 + attrs = setResponseApplyPatchCallAttrs(output.OfApplyPatchCall, attrs, config, messageIndex) case output.OfApplyPatchCallOutput != nil: - // TODO: Handle patch call output - // https://github.com/Arize-ai/openinference/blob/f6561ca5a169f13d5b40120311b782348550b5ac/python/instrumentation/openinference-instrumentation-openai/src/openinference/instrumentation/openai/_attributes/_responses_api.py#L600 + attrs = setResponseApplyPatchCallOutputAttrs(output.OfApplyPatchCallOutput, attrs, config, messageIndex) case output.OfCompaction != nil: - // TODO: Handle compaction response - // https://github.com/Arize-ai/openinference/blob/f6561ca5a169f13d5b40120311b782348550b5ac/python/instrumentation/openinference-instrumentation-openai/src/openinference/instrumentation/openai/_attributes/_responses_api.py#L603 + attrs = setResponseCompactionAttrs(output.OfCompaction, attrs, config, messageIndex) } return attrs } @@ -383,3 +372,151 @@ func setResponseCustomToolCallAttrs(c *openai.ResponseCustomToolCall, attrs []at } return attrs } + +func setResponseImageGenerationCallAttrs(c *openai.ResponseOutputItemImageGenerationCall, attrs []attribute.KeyValue, config *openinference.TraceConfig, messageIndex int) []attribute.KeyValue { + attrs = append(attrs, attribute.String(openinference.OutputMessageAttribute(messageIndex, openinference.MessageRole), "assistant")) + if config.HideOutputText { + attrs = append(attrs, attribute.String(openinference.OutputMessageToolCallAttribute(messageIndex, 0, openinference.ToolCallID), openinference.RedactedValue), + attribute.String(openinference.OutputMessageToolCallAttribute(messageIndex, 0, openinference.ToolCallFunctionName), openinference.RedactedValue)) + } else { + attrs = append(attrs, attribute.String(openinference.OutputMessageToolCallAttribute(messageIndex, 0, openinference.ToolCallID), c.ID), + attribute.String(openinference.OutputMessageToolCallAttribute(messageIndex, 0, openinference.ToolCallFunctionName), c.Type)) + } + return attrs +} + +func setResponseCodeInterpreterCallAttrs(c *openai.ResponseCodeInterpreterToolCall, attrs []attribute.KeyValue, config *openinference.TraceConfig, messageIndex int) []attribute.KeyValue { + attrs = append(attrs, attribute.String(openinference.OutputMessageAttribute(messageIndex, openinference.MessageRole), "assistant")) + if config.HideOutputText { + attrs = append(attrs, attribute.String(openinference.OutputMessageToolCallAttribute(messageIndex, 0, openinference.ToolCallID), openinference.RedactedValue), + attribute.String(openinference.OutputMessageToolCallAttribute(messageIndex, 0, openinference.ToolCallFunctionName), openinference.RedactedValue), + attribute.String(openinference.OutputMessageToolCallAttribute(messageIndex, 0, openinference.ToolCallFunctionArguments), openinference.RedactedValue)) + } else { + attrs = append(attrs, attribute.String(openinference.OutputMessageToolCallAttribute(messageIndex, 0, openinference.ToolCallID), c.ID), + attribute.String(openinference.OutputMessageToolCallAttribute(messageIndex, 0, openinference.ToolCallFunctionName), c.Type), + attribute.String(openinference.OutputMessageToolCallAttribute(messageIndex, 0, openinference.ToolCallFunctionArguments), c.Code)) + } + return attrs +} + +func setResponseLocalShellCallAttrs(c *openai.ResponseOutputItemLocalShellCall, attrs []attribute.KeyValue, config *openinference.TraceConfig, messageIndex int) []attribute.KeyValue { + attrs = append(attrs, attribute.String(openinference.OutputMessageAttribute(messageIndex, openinference.MessageRole), "assistant")) + if config.HideOutputText { + attrs = append(attrs, attribute.String(openinference.OutputMessageToolCallAttribute(messageIndex, 0, openinference.ToolCallID), openinference.RedactedValue), + attribute.String(openinference.OutputMessageToolCallAttribute(messageIndex, 0, openinference.ToolCallFunctionName), openinference.RedactedValue), + attribute.String(openinference.OutputMessageToolCallAttribute(messageIndex, 0, openinference.ToolCallFunctionArguments), openinference.RedactedValue)) + } else { + attrs = append(attrs, attribute.String(openinference.OutputMessageToolCallAttribute(messageIndex, 0, openinference.ToolCallID), c.CallID), + attribute.String(openinference.OutputMessageToolCallAttribute(messageIndex, 0, openinference.ToolCallFunctionName), c.Type)) + if data, err := json.Marshal(c.Action.Command); err == nil { + attrs = append(attrs, attribute.String(openinference.OutputMessageToolCallAttribute(messageIndex, 0, openinference.ToolCallFunctionArguments), string(data))) + } + } + return attrs +} + +func setResponseMcpCallAttrs(c *openai.ResponseMcpCall, attrs []attribute.KeyValue, config *openinference.TraceConfig, messageIndex int) []attribute.KeyValue { + attrs = append(attrs, attribute.String(openinference.OutputMessageAttribute(messageIndex, openinference.MessageRole), "assistant")) + if config.HideOutputText { + attrs = append(attrs, attribute.String(openinference.OutputMessageToolCallAttribute(messageIndex, 0, openinference.ToolCallID), openinference.RedactedValue), + attribute.String(openinference.OutputMessageToolCallAttribute(messageIndex, 0, openinference.ToolCallFunctionName), openinference.RedactedValue), + attribute.String(openinference.OutputMessageToolCallAttribute(messageIndex, 0, openinference.ToolCallFunctionArguments), openinference.RedactedValue)) + } else { + attrs = append(attrs, attribute.String(openinference.OutputMessageToolCallAttribute(messageIndex, 0, openinference.ToolCallID), c.ID), + attribute.String(openinference.OutputMessageToolCallAttribute(messageIndex, 0, openinference.ToolCallFunctionName), c.Name), + attribute.String(openinference.OutputMessageToolCallAttribute(messageIndex, 0, openinference.ToolCallFunctionArguments), c.Arguments)) + } + return attrs +} + +func setResponseMcpListToolsAttrs(c *openai.ResponseMcpListTools, attrs []attribute.KeyValue, config *openinference.TraceConfig, messageIndex int) []attribute.KeyValue { + attrs = append(attrs, attribute.String(openinference.OutputMessageAttribute(messageIndex, openinference.MessageRole), "assistant")) + if config.HideOutputText { + attrs = append(attrs, attribute.String(openinference.OutputMessageToolCallAttribute(messageIndex, 0, openinference.ToolCallID), openinference.RedactedValue), + attribute.String(openinference.OutputMessageToolCallAttribute(messageIndex, 0, openinference.ToolCallFunctionName), openinference.RedactedValue)) + } else { + attrs = append(attrs, attribute.String(openinference.OutputMessageToolCallAttribute(messageIndex, 0, openinference.ToolCallID), c.ID), + attribute.String(openinference.OutputMessageToolCallAttribute(messageIndex, 0, openinference.ToolCallFunctionName), c.Type)) + } + return attrs +} + +func setResponseMcpApprovalRequestAttrs(c *openai.ResponseMcpApprovalRequest, attrs []attribute.KeyValue, config *openinference.TraceConfig, messageIndex int) []attribute.KeyValue { + attrs = append(attrs, attribute.String(openinference.OutputMessageAttribute(messageIndex, openinference.MessageRole), "assistant")) + if config.HideOutputText { + attrs = append(attrs, attribute.String(openinference.OutputMessageToolCallAttribute(messageIndex, 0, openinference.ToolCallID), openinference.RedactedValue), + attribute.String(openinference.OutputMessageToolCallAttribute(messageIndex, 0, openinference.ToolCallFunctionName), openinference.RedactedValue), + attribute.String(openinference.OutputMessageToolCallAttribute(messageIndex, 0, openinference.ToolCallFunctionArguments), openinference.RedactedValue)) + } else { + attrs = append(attrs, attribute.String(openinference.OutputMessageToolCallAttribute(messageIndex, 0, openinference.ToolCallID), c.ID), + attribute.String(openinference.OutputMessageToolCallAttribute(messageIndex, 0, openinference.ToolCallFunctionName), c.Name), + attribute.String(openinference.OutputMessageToolCallAttribute(messageIndex, 0, openinference.ToolCallFunctionArguments), c.Arguments)) + } + return attrs +} + +func setResponseShellCallAttrs(c *openai.ResponseFunctionShellToolCall, attrs []attribute.KeyValue, config *openinference.TraceConfig, messageIndex int) []attribute.KeyValue { + attrs = append(attrs, attribute.String(openinference.OutputMessageAttribute(messageIndex, openinference.MessageRole), "assistant")) + if config.HideOutputText { + attrs = append(attrs, attribute.String(openinference.OutputMessageToolCallAttribute(messageIndex, 0, openinference.ToolCallID), openinference.RedactedValue), + attribute.String(openinference.OutputMessageToolCallAttribute(messageIndex, 0, openinference.ToolCallFunctionName), openinference.RedactedValue), + attribute.String(openinference.OutputMessageToolCallAttribute(messageIndex, 0, openinference.ToolCallFunctionArguments), openinference.RedactedValue)) + } else { + attrs = append(attrs, attribute.String(openinference.OutputMessageToolCallAttribute(messageIndex, 0, openinference.ToolCallID), c.CallID), + attribute.String(openinference.OutputMessageToolCallAttribute(messageIndex, 0, openinference.ToolCallFunctionName), c.Type)) + if data, err := json.Marshal(c.Action.Commands); err == nil { + attrs = append(attrs, attribute.String(openinference.OutputMessageToolCallAttribute(messageIndex, 0, openinference.ToolCallFunctionArguments), string(data))) + } + } + return attrs +} + +func setResponseShellCallOutputAttrs(c *openai.ResponseFunctionShellToolCallOutput, attrs []attribute.KeyValue, config *openinference.TraceConfig, messageIndex int) []attribute.KeyValue { + attrs = append(attrs, attribute.String(openinference.OutputMessageAttribute(messageIndex, openinference.MessageRole), "tool")) + if config.HideOutputText { + attrs = append(attrs, attribute.String(openinference.OutputMessageToolCallAttribute(messageIndex, 0, openinference.ToolCallID), openinference.RedactedValue), + attribute.String(openinference.OutputMessageToolCallAttribute(messageIndex, 0, openinference.ToolCallFunctionName), openinference.RedactedValue)) + } else { + attrs = append(attrs, attribute.String(openinference.OutputMessageToolCallAttribute(messageIndex, 0, openinference.ToolCallID), c.CallID), + attribute.String(openinference.OutputMessageToolCallAttribute(messageIndex, 0, openinference.ToolCallFunctionName), c.Type)) + } + return attrs +} + +func setResponseApplyPatchCallAttrs(c *openai.ResponseApplyPatchToolCall, attrs []attribute.KeyValue, config *openinference.TraceConfig, messageIndex int) []attribute.KeyValue { + attrs = append(attrs, attribute.String(openinference.OutputMessageAttribute(messageIndex, openinference.MessageRole), "assistant")) + if config.HideOutputText { + attrs = append(attrs, attribute.String(openinference.OutputMessageToolCallAttribute(messageIndex, 0, openinference.ToolCallID), openinference.RedactedValue), + attribute.String(openinference.OutputMessageToolCallAttribute(messageIndex, 0, openinference.ToolCallFunctionName), openinference.RedactedValue)) + } else { + attrs = append(attrs, attribute.String(openinference.OutputMessageToolCallAttribute(messageIndex, 0, openinference.ToolCallID), c.CallID), + attribute.String(openinference.OutputMessageToolCallAttribute(messageIndex, 0, openinference.ToolCallFunctionName), c.Type)) + } + return attrs +} + +func setResponseApplyPatchCallOutputAttrs(c *openai.ResponseApplyPatchToolCallOutput, attrs []attribute.KeyValue, config *openinference.TraceConfig, messageIndex int) []attribute.KeyValue { + attrs = append(attrs, attribute.String(openinference.OutputMessageAttribute(messageIndex, openinference.MessageRole), "tool")) + if config.HideOutputText { + attrs = append(attrs, attribute.String(openinference.OutputMessageToolCallAttribute(messageIndex, 0, openinference.ToolCallID), openinference.RedactedValue), + attribute.String(openinference.OutputMessageToolCallAttribute(messageIndex, 0, openinference.ToolCallFunctionName), openinference.RedactedValue), + attribute.String(openinference.OutputMessageToolCallAttribute(messageIndex, 0, openinference.ToolCallFunctionArguments), openinference.RedactedValue)) + } else { + attrs = append(attrs, attribute.String(openinference.OutputMessageToolCallAttribute(messageIndex, 0, openinference.ToolCallID), c.CallID), + attribute.String(openinference.OutputMessageToolCallAttribute(messageIndex, 0, openinference.ToolCallFunctionName), c.Type), + attribute.String(openinference.OutputMessageToolCallAttribute(messageIndex, 0, openinference.ToolCallFunctionArguments), c.Output)) + } + return attrs +} + +func setResponseCompactionAttrs(c *openai.ResponseCompactionItem, attrs []attribute.KeyValue, config *openinference.TraceConfig, messageIndex int) []attribute.KeyValue { + attrs = append(attrs, attribute.String(openinference.OutputMessageAttribute(messageIndex, openinference.MessageRole), "assistant")) + if config.HideOutputText { + attrs = append(attrs, attribute.String(openinference.OutputMessageToolCallAttribute(messageIndex, 0, openinference.ToolCallID), openinference.RedactedValue), + attribute.String(openinference.OutputMessageToolCallAttribute(messageIndex, 0, openinference.ToolCallFunctionName), openinference.RedactedValue)) + } else { + attrs = append(attrs, attribute.String(openinference.OutputMessageToolCallAttribute(messageIndex, 0, openinference.ToolCallID), c.ID), + attribute.String(openinference.OutputMessageToolCallAttribute(messageIndex, 0, openinference.ToolCallFunctionName), c.Type)) + } + return attrs +} diff --git a/internal/tracing/openinference/openai/response_attrs_test.go b/internal/tracing/openinference/openai/response_attrs_test.go index d01380e6c7..9062195ba8 100644 --- a/internal/tracing/openinference/openai/response_attrs_test.go +++ b/internal/tracing/openinference/openai/response_attrs_test.go @@ -1254,69 +1254,125 @@ func TestSetResponseOutputAttrs(t *testing.T) { // The rest are TODO branches, just check passthrough (should not panic or add attrs) { name: "OfImageGenerationCall", - union: openai.ResponseOutputItemUnion{OfImageGenerationCall: &openai.ResponseOutputItemImageGenerationCall{}}, + union: openai.ResponseOutputItemUnion{OfImageGenerationCall: &openai.ResponseOutputItemImageGenerationCall{ID: "ig-1", Type: "image_generation_call"}}, config: defaultConfig, - want: nil, + want: []attribute.KeyValue{ + attribute.String(openinference.OutputMessageAttribute(0, openinference.MessageRole), "assistant"), + attribute.String(openinference.OutputMessageToolCallAttribute(0, 0, openinference.ToolCallID), "ig-1"), + attribute.String(openinference.OutputMessageToolCallAttribute(0, 0, openinference.ToolCallFunctionName), "image_generation_call"), + }, }, { name: "OfCodeInterpreterCall", - union: openai.ResponseOutputItemUnion{OfCodeInterpreterCall: &openai.ResponseCodeInterpreterToolCall{}}, + union: openai.ResponseOutputItemUnion{OfCodeInterpreterCall: &openai.ResponseCodeInterpreterToolCall{ID: "ci-1", Type: "code_interpreter_call", Code: "print(1)"}}, config: defaultConfig, - want: nil, + want: []attribute.KeyValue{ + attribute.String(openinference.OutputMessageAttribute(0, openinference.MessageRole), "assistant"), + attribute.String(openinference.OutputMessageToolCallAttribute(0, 0, openinference.ToolCallID), "ci-1"), + attribute.String(openinference.OutputMessageToolCallAttribute(0, 0, openinference.ToolCallFunctionName), "code_interpreter_call"), + attribute.String(openinference.OutputMessageToolCallAttribute(0, 0, openinference.ToolCallFunctionArguments), "print(1)"), + }, }, { - name: "OfLocalShellCall", - union: openai.ResponseOutputItemUnion{OfLocalShellCall: &openai.ResponseOutputItemLocalShellCall{}}, + name: "OfLocalShellCall", + union: openai.ResponseOutputItemUnion{OfLocalShellCall: &openai.ResponseOutputItemLocalShellCall{ + CallID: "lsc-1", Type: "local_shell_call", + Action: openai.ResponseOutputItemLocalShellCallAction{Command: []string{"ls"}}, + }}, config: defaultConfig, - want: nil, + want: []attribute.KeyValue{ + attribute.String(openinference.OutputMessageAttribute(0, openinference.MessageRole), "assistant"), + attribute.String(openinference.OutputMessageToolCallAttribute(0, 0, openinference.ToolCallID), "lsc-1"), + attribute.String(openinference.OutputMessageToolCallAttribute(0, 0, openinference.ToolCallFunctionName), "local_shell_call"), + attribute.String(openinference.OutputMessageToolCallAttribute(0, 0, openinference.ToolCallFunctionArguments), `["ls"]`), + }, }, { name: "OfMcpCall", - union: openai.ResponseOutputItemUnion{OfMcpCall: &openai.ResponseMcpCall{}}, + union: openai.ResponseOutputItemUnion{OfMcpCall: &openai.ResponseMcpCall{ID: "mc-1", Name: "search", Arguments: `{"q":"go"}`, Type: "mcp_call"}}, config: defaultConfig, - want: nil, + want: []attribute.KeyValue{ + attribute.String(openinference.OutputMessageAttribute(0, openinference.MessageRole), "assistant"), + attribute.String(openinference.OutputMessageToolCallAttribute(0, 0, openinference.ToolCallID), "mc-1"), + attribute.String(openinference.OutputMessageToolCallAttribute(0, 0, openinference.ToolCallFunctionName), "search"), + attribute.String(openinference.OutputMessageToolCallAttribute(0, 0, openinference.ToolCallFunctionArguments), `{"q":"go"}`), + }, }, { name: "OfMcpListTools", - union: openai.ResponseOutputItemUnion{OfMcpListTools: &openai.ResponseMcpListTools{}}, + union: openai.ResponseOutputItemUnion{OfMcpListTools: &openai.ResponseMcpListTools{ID: "mlt-1", Type: "mcp_list_tools"}}, config: defaultConfig, - want: nil, + want: []attribute.KeyValue{ + attribute.String(openinference.OutputMessageAttribute(0, openinference.MessageRole), "assistant"), + attribute.String(openinference.OutputMessageToolCallAttribute(0, 0, openinference.ToolCallID), "mlt-1"), + attribute.String(openinference.OutputMessageToolCallAttribute(0, 0, openinference.ToolCallFunctionName), "mcp_list_tools"), + }, }, { name: "OfMcpApprovalRequest", - union: openai.ResponseOutputItemUnion{OfMcpApprovalRequest: &openai.ResponseMcpApprovalRequest{}}, + union: openai.ResponseOutputItemUnion{OfMcpApprovalRequest: &openai.ResponseMcpApprovalRequest{ID: "mar-1", Name: "delete", Arguments: `{}`, Type: "mcp_approval_request"}}, config: defaultConfig, - want: nil, + want: []attribute.KeyValue{ + attribute.String(openinference.OutputMessageAttribute(0, openinference.MessageRole), "assistant"), + attribute.String(openinference.OutputMessageToolCallAttribute(0, 0, openinference.ToolCallID), "mar-1"), + attribute.String(openinference.OutputMessageToolCallAttribute(0, 0, openinference.ToolCallFunctionName), "delete"), + attribute.String(openinference.OutputMessageToolCallAttribute(0, 0, openinference.ToolCallFunctionArguments), `{}`), + }, }, { - name: "OfShellCall", - union: openai.ResponseOutputItemUnion{OfShellCall: &openai.ResponseFunctionShellToolCall{}}, + name: "OfShellCall", + union: openai.ResponseOutputItemUnion{OfShellCall: &openai.ResponseFunctionShellToolCall{ + CallID: "sc-1", Type: "shell_call", + Action: openai.ResponseFunctionShellToolCallAction{Commands: []string{"echo hi"}}, + }}, config: defaultConfig, - want: nil, + want: []attribute.KeyValue{ + attribute.String(openinference.OutputMessageAttribute(0, openinference.MessageRole), "assistant"), + attribute.String(openinference.OutputMessageToolCallAttribute(0, 0, openinference.ToolCallID), "sc-1"), + attribute.String(openinference.OutputMessageToolCallAttribute(0, 0, openinference.ToolCallFunctionName), "shell_call"), + attribute.String(openinference.OutputMessageToolCallAttribute(0, 0, openinference.ToolCallFunctionArguments), `["echo hi"]`), + }, }, { name: "OfShellCallOutput", - union: openai.ResponseOutputItemUnion{OfShellCallOutput: &openai.ResponseFunctionShellToolCallOutput{}}, + union: openai.ResponseOutputItemUnion{OfShellCallOutput: &openai.ResponseFunctionShellToolCallOutput{CallID: "sc-1", Type: "shell_call_output"}}, config: defaultConfig, - want: nil, + want: []attribute.KeyValue{ + attribute.String(openinference.OutputMessageAttribute(0, openinference.MessageRole), "tool"), + attribute.String(openinference.OutputMessageToolCallAttribute(0, 0, openinference.ToolCallID), "sc-1"), + attribute.String(openinference.OutputMessageToolCallAttribute(0, 0, openinference.ToolCallFunctionName), "shell_call_output"), + }, }, { name: "OfApplyPatchCall", - union: openai.ResponseOutputItemUnion{OfApplyPatchCall: &openai.ResponseApplyPatchToolCall{}}, + union: openai.ResponseOutputItemUnion{OfApplyPatchCall: &openai.ResponseApplyPatchToolCall{CallID: "apc-1", Type: "apply_patch_call"}}, config: defaultConfig, - want: nil, + want: []attribute.KeyValue{ + attribute.String(openinference.OutputMessageAttribute(0, openinference.MessageRole), "assistant"), + attribute.String(openinference.OutputMessageToolCallAttribute(0, 0, openinference.ToolCallID), "apc-1"), + attribute.String(openinference.OutputMessageToolCallAttribute(0, 0, openinference.ToolCallFunctionName), "apply_patch_call"), + }, }, { name: "OfApplyPatchCallOutput", - union: openai.ResponseOutputItemUnion{OfApplyPatchCallOutput: &openai.ResponseApplyPatchToolCallOutput{}}, + union: openai.ResponseOutputItemUnion{OfApplyPatchCallOutput: &openai.ResponseApplyPatchToolCallOutput{CallID: "apc-1", Type: "apply_patch_call_output", Output: "patched"}}, config: defaultConfig, - want: nil, + want: []attribute.KeyValue{ + attribute.String(openinference.OutputMessageAttribute(0, openinference.MessageRole), "tool"), + attribute.String(openinference.OutputMessageToolCallAttribute(0, 0, openinference.ToolCallID), "apc-1"), + attribute.String(openinference.OutputMessageToolCallAttribute(0, 0, openinference.ToolCallFunctionName), "apply_patch_call_output"), + attribute.String(openinference.OutputMessageToolCallAttribute(0, 0, openinference.ToolCallFunctionArguments), "patched"), + }, }, { name: "OfCompaction", - union: openai.ResponseOutputItemUnion{OfCompaction: &openai.ResponseCompactionItem{}}, + union: openai.ResponseOutputItemUnion{OfCompaction: &openai.ResponseCompactionItem{ID: "c-1", Type: "compaction"}}, config: defaultConfig, - want: nil, + want: []attribute.KeyValue{ + attribute.String(openinference.OutputMessageAttribute(0, openinference.MessageRole), "assistant"), + attribute.String(openinference.OutputMessageToolCallAttribute(0, 0, openinference.ToolCallID), "c-1"), + attribute.String(openinference.OutputMessageToolCallAttribute(0, 0, openinference.ToolCallFunctionName), "compaction"), + }, }, } @@ -1700,3 +1756,523 @@ func TestBuildResponsesResponseAttributes(t *testing.T) { }) } } + +func TestSetResponseImageGenerationCallAttrs(t *testing.T) { + tests := []struct { + name string + call *openai.ResponseOutputItemImageGenerationCall + config *openinference.TraceConfig + messageIndex int + expectedAttrs []attribute.KeyValue + }{ + { + name: "image generation call", + call: &openai.ResponseOutputItemImageGenerationCall{ + ID: "img-123", + Result: "base64encodedimage", + Status: "completed", + Type: "image_generation_call", + }, + config: openinference.NewTraceConfig(), + messageIndex: 0, + expectedAttrs: []attribute.KeyValue{ + attribute.String(openinference.OutputMessageAttribute(0, openinference.MessageRole), "assistant"), + attribute.String(openinference.OutputMessageToolCallAttribute(0, 0, openinference.ToolCallID), "img-123"), + attribute.String(openinference.OutputMessageToolCallAttribute(0, 0, openinference.ToolCallFunctionName), "image_generation_call"), + }, + }, + { + name: "image generation call with hidden output", + call: &openai.ResponseOutputItemImageGenerationCall{ + ID: "img-456", + Type: "image_generation_call", + }, + config: &openinference.TraceConfig{HideOutputText: true}, + messageIndex: 1, + expectedAttrs: []attribute.KeyValue{ + attribute.String(openinference.OutputMessageAttribute(1, openinference.MessageRole), "assistant"), + attribute.String(openinference.OutputMessageToolCallAttribute(1, 0, openinference.ToolCallID), openinference.RedactedValue), + attribute.String(openinference.OutputMessageToolCallAttribute(1, 0, openinference.ToolCallFunctionName), openinference.RedactedValue), + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + attrs := setResponseImageGenerationCallAttrs(tt.call, []attribute.KeyValue{}, tt.config, tt.messageIndex) + openinference.RequireAttributesEqual(t, tt.expectedAttrs, attrs) + }) + } +} + +func TestSetResponseCodeInterpreterCallAttrs(t *testing.T) { + tests := []struct { + name string + call *openai.ResponseCodeInterpreterToolCall + config *openinference.TraceConfig + messageIndex int + expectedAttrs []attribute.KeyValue + }{ + { + name: "code interpreter call with code", + call: &openai.ResponseCodeInterpreterToolCall{ + ID: "ci-123", + Code: "print('hello')", + ContainerID: "container-abc", + Status: "completed", + Type: "code_interpreter_call", + }, + config: openinference.NewTraceConfig(), + messageIndex: 0, + expectedAttrs: []attribute.KeyValue{ + attribute.String(openinference.OutputMessageAttribute(0, openinference.MessageRole), "assistant"), + attribute.String(openinference.OutputMessageToolCallAttribute(0, 0, openinference.ToolCallID), "ci-123"), + attribute.String(openinference.OutputMessageToolCallAttribute(0, 0, openinference.ToolCallFunctionName), "code_interpreter_call"), + attribute.String(openinference.OutputMessageToolCallAttribute(0, 0, openinference.ToolCallFunctionArguments), "print('hello')"), + }, + }, + { + name: "code interpreter call with hidden output", + call: &openai.ResponseCodeInterpreterToolCall{ + ID: "ci-456", + Code: "secret code", + Type: "code_interpreter_call", + }, + config: &openinference.TraceConfig{HideOutputText: true}, + messageIndex: 0, + expectedAttrs: []attribute.KeyValue{ + attribute.String(openinference.OutputMessageAttribute(0, openinference.MessageRole), "assistant"), + attribute.String(openinference.OutputMessageToolCallAttribute(0, 0, openinference.ToolCallID), openinference.RedactedValue), + attribute.String(openinference.OutputMessageToolCallAttribute(0, 0, openinference.ToolCallFunctionName), openinference.RedactedValue), + attribute.String(openinference.OutputMessageToolCallAttribute(0, 0, openinference.ToolCallFunctionArguments), openinference.RedactedValue), + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + attrs := setResponseCodeInterpreterCallAttrs(tt.call, []attribute.KeyValue{}, tt.config, tt.messageIndex) + openinference.RequireAttributesEqual(t, tt.expectedAttrs, attrs) + }) + } +} + +func TestSetResponseMcpCallAttrs(t *testing.T) { + tests := []struct { + name string + call *openai.ResponseMcpCall + config *openinference.TraceConfig + messageIndex int + expectedAttrs []attribute.KeyValue + }{ + { + name: "mcp call with arguments", + call: &openai.ResponseMcpCall{ + ID: "mcp-123", + Name: "search_web", + Arguments: `{"query":"golang testing"}`, + ServerLabel: "my-mcp-server", + Status: "completed", + Type: "mcp_call", + }, + config: openinference.NewTraceConfig(), + messageIndex: 0, + expectedAttrs: []attribute.KeyValue{ + attribute.String(openinference.OutputMessageAttribute(0, openinference.MessageRole), "assistant"), + attribute.String(openinference.OutputMessageToolCallAttribute(0, 0, openinference.ToolCallID), "mcp-123"), + attribute.String(openinference.OutputMessageToolCallAttribute(0, 0, openinference.ToolCallFunctionName), "search_web"), + attribute.String(openinference.OutputMessageToolCallAttribute(0, 0, openinference.ToolCallFunctionArguments), `{"query":"golang testing"}`), + }, + }, + { + name: "mcp call with hidden output", + call: &openai.ResponseMcpCall{ + ID: "mcp-456", + Name: "run_query", + Arguments: `{"sql":"SELECT * FROM users"}`, + Type: "mcp_call", + }, + config: &openinference.TraceConfig{HideOutputText: true}, + messageIndex: 1, + expectedAttrs: []attribute.KeyValue{ + attribute.String(openinference.OutputMessageAttribute(1, openinference.MessageRole), "assistant"), + attribute.String(openinference.OutputMessageToolCallAttribute(1, 0, openinference.ToolCallID), openinference.RedactedValue), + attribute.String(openinference.OutputMessageToolCallAttribute(1, 0, openinference.ToolCallFunctionName), openinference.RedactedValue), + attribute.String(openinference.OutputMessageToolCallAttribute(1, 0, openinference.ToolCallFunctionArguments), openinference.RedactedValue), + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + attrs := setResponseMcpCallAttrs(tt.call, []attribute.KeyValue{}, tt.config, tt.messageIndex) + openinference.RequireAttributesEqual(t, tt.expectedAttrs, attrs) + }) + } +} + +func TestSetResponseMcpListToolsAttrs(t *testing.T) { + tests := []struct { + name string + call *openai.ResponseMcpListTools + config *openinference.TraceConfig + messageIndex int + expectedAttrs []attribute.KeyValue + }{ + { + name: "mcp list tools", + call: &openai.ResponseMcpListTools{ + ID: "list-123", + ServerLabel: "my-mcp-server", + Type: "mcp_list_tools", + }, + config: openinference.NewTraceConfig(), + messageIndex: 0, + expectedAttrs: []attribute.KeyValue{ + attribute.String(openinference.OutputMessageAttribute(0, openinference.MessageRole), "assistant"), + attribute.String(openinference.OutputMessageToolCallAttribute(0, 0, openinference.ToolCallID), "list-123"), + attribute.String(openinference.OutputMessageToolCallAttribute(0, 0, openinference.ToolCallFunctionName), "mcp_list_tools"), + }, + }, + { + name: "mcp list tools with hidden output", + call: &openai.ResponseMcpListTools{ + ID: "list-456", + Type: "mcp_list_tools", + }, + config: &openinference.TraceConfig{HideOutputText: true}, + messageIndex: 0, + expectedAttrs: []attribute.KeyValue{ + attribute.String(openinference.OutputMessageAttribute(0, openinference.MessageRole), "assistant"), + attribute.String(openinference.OutputMessageToolCallAttribute(0, 0, openinference.ToolCallID), openinference.RedactedValue), + attribute.String(openinference.OutputMessageToolCallAttribute(0, 0, openinference.ToolCallFunctionName), openinference.RedactedValue), + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + attrs := setResponseMcpListToolsAttrs(tt.call, []attribute.KeyValue{}, tt.config, tt.messageIndex) + openinference.RequireAttributesEqual(t, tt.expectedAttrs, attrs) + }) + } +} + +func TestSetResponseMcpApprovalRequestAttrs(t *testing.T) { + tests := []struct { + name string + call *openai.ResponseMcpApprovalRequest + config *openinference.TraceConfig + messageIndex int + expectedAttrs []attribute.KeyValue + }{ + { + name: "mcp approval request", + call: &openai.ResponseMcpApprovalRequest{ + ID: "apr-123", + Name: "delete_file", + Arguments: `{"path":"/etc/passwd"}`, + ServerLabel: "my-mcp-server", + Type: "mcp_approval_request", + }, + config: openinference.NewTraceConfig(), + messageIndex: 0, + expectedAttrs: []attribute.KeyValue{ + attribute.String(openinference.OutputMessageAttribute(0, openinference.MessageRole), "assistant"), + attribute.String(openinference.OutputMessageToolCallAttribute(0, 0, openinference.ToolCallID), "apr-123"), + attribute.String(openinference.OutputMessageToolCallAttribute(0, 0, openinference.ToolCallFunctionName), "delete_file"), + attribute.String(openinference.OutputMessageToolCallAttribute(0, 0, openinference.ToolCallFunctionArguments), `{"path":"/etc/passwd"}`), + }, + }, + { + name: "mcp approval request with hidden output", + call: &openai.ResponseMcpApprovalRequest{ + ID: "apr-456", + Name: "drop_table", + Type: "mcp_approval_request", + }, + config: &openinference.TraceConfig{HideOutputText: true}, + messageIndex: 0, + expectedAttrs: []attribute.KeyValue{ + attribute.String(openinference.OutputMessageAttribute(0, openinference.MessageRole), "assistant"), + attribute.String(openinference.OutputMessageToolCallAttribute(0, 0, openinference.ToolCallID), openinference.RedactedValue), + attribute.String(openinference.OutputMessageToolCallAttribute(0, 0, openinference.ToolCallFunctionName), openinference.RedactedValue), + attribute.String(openinference.OutputMessageToolCallAttribute(0, 0, openinference.ToolCallFunctionArguments), openinference.RedactedValue), + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + attrs := setResponseMcpApprovalRequestAttrs(tt.call, []attribute.KeyValue{}, tt.config, tt.messageIndex) + openinference.RequireAttributesEqual(t, tt.expectedAttrs, attrs) + }) + } +} + +func TestSetResponseShellCallAttrs(t *testing.T) { + tests := []struct { + name string + call *openai.ResponseFunctionShellToolCall + config *openinference.TraceConfig + messageIndex int + expectedAttrs []attribute.KeyValue + }{ + { + name: "shell call with commands", + call: &openai.ResponseFunctionShellToolCall{ + ID: "shell-123", + CallID: "call_shell_abc", + Action: openai.ResponseFunctionShellToolCallAction{ + Commands: []string{"ls", "-la"}, + }, + Status: "completed", + Type: "shell_call", + }, + config: openinference.NewTraceConfig(), + messageIndex: 0, + expectedAttrs: []attribute.KeyValue{ + attribute.String(openinference.OutputMessageAttribute(0, openinference.MessageRole), "assistant"), + attribute.String(openinference.OutputMessageToolCallAttribute(0, 0, openinference.ToolCallID), "call_shell_abc"), + attribute.String(openinference.OutputMessageToolCallAttribute(0, 0, openinference.ToolCallFunctionName), "shell_call"), + attribute.String(openinference.OutputMessageToolCallAttribute(0, 0, openinference.ToolCallFunctionArguments), `["ls","-la"]`), + }, + }, + { + name: "shell call with hidden output", + call: &openai.ResponseFunctionShellToolCall{ + ID: "shell-456", + CallID: "call_shell_xyz", + Action: openai.ResponseFunctionShellToolCallAction{ + Commands: []string{"rm", "-rf", "/"}, + }, + Type: "shell_call", + }, + config: &openinference.TraceConfig{HideOutputText: true}, + messageIndex: 0, + expectedAttrs: []attribute.KeyValue{ + attribute.String(openinference.OutputMessageAttribute(0, openinference.MessageRole), "assistant"), + attribute.String(openinference.OutputMessageToolCallAttribute(0, 0, openinference.ToolCallID), openinference.RedactedValue), + attribute.String(openinference.OutputMessageToolCallAttribute(0, 0, openinference.ToolCallFunctionName), openinference.RedactedValue), + attribute.String(openinference.OutputMessageToolCallAttribute(0, 0, openinference.ToolCallFunctionArguments), openinference.RedactedValue), + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + attrs := setResponseShellCallAttrs(tt.call, []attribute.KeyValue{}, tt.config, tt.messageIndex) + openinference.RequireAttributesEqual(t, tt.expectedAttrs, attrs) + }) + } +} + +func TestSetResponseApplyPatchCallAttrs(t *testing.T) { + tests := []struct { + name string + call *openai.ResponseApplyPatchToolCall + config *openinference.TraceConfig + messageIndex int + expectedAttrs []attribute.KeyValue + }{ + { + name: "apply patch call", + call: &openai.ResponseApplyPatchToolCall{ + ID: "patch-123", + CallID: "call_patch_abc", + Status: "completed", + Type: "apply_patch_call", + }, + config: openinference.NewTraceConfig(), + messageIndex: 0, + expectedAttrs: []attribute.KeyValue{ + attribute.String(openinference.OutputMessageAttribute(0, openinference.MessageRole), "assistant"), + attribute.String(openinference.OutputMessageToolCallAttribute(0, 0, openinference.ToolCallID), "call_patch_abc"), + attribute.String(openinference.OutputMessageToolCallAttribute(0, 0, openinference.ToolCallFunctionName), "apply_patch_call"), + }, + }, + { + name: "apply patch call with hidden output", + call: &openai.ResponseApplyPatchToolCall{ + ID: "patch-456", + CallID: "call_patch_xyz", + Type: "apply_patch_call", + }, + config: &openinference.TraceConfig{HideOutputText: true}, + messageIndex: 0, + expectedAttrs: []attribute.KeyValue{ + attribute.String(openinference.OutputMessageAttribute(0, openinference.MessageRole), "assistant"), + attribute.String(openinference.OutputMessageToolCallAttribute(0, 0, openinference.ToolCallID), openinference.RedactedValue), + attribute.String(openinference.OutputMessageToolCallAttribute(0, 0, openinference.ToolCallFunctionName), openinference.RedactedValue), + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + attrs := setResponseApplyPatchCallAttrs(tt.call, []attribute.KeyValue{}, tt.config, tt.messageIndex) + openinference.RequireAttributesEqual(t, tt.expectedAttrs, attrs) + }) + } +} + +func TestSetResponseLocalShellCallAttrs(t *testing.T) { + tests := []struct { + name string + call *openai.ResponseOutputItemLocalShellCall + config *openinference.TraceConfig + messageIndex int + expectedAttrs []attribute.KeyValue + }{ + { + name: "local shell call with command", + call: &openai.ResponseOutputItemLocalShellCall{ + CallID: "lsc-1", + Type: "local_shell_call", + Action: openai.ResponseOutputItemLocalShellCallAction{Command: []string{"ls", "-la"}}, + }, + config: openinference.NewTraceConfig(), + messageIndex: 0, + expectedAttrs: []attribute.KeyValue{ + attribute.String(openinference.OutputMessageAttribute(0, openinference.MessageRole), "assistant"), + attribute.String(openinference.OutputMessageToolCallAttribute(0, 0, openinference.ToolCallID), "lsc-1"), + attribute.String(openinference.OutputMessageToolCallAttribute(0, 0, openinference.ToolCallFunctionName), "local_shell_call"), + attribute.String(openinference.OutputMessageToolCallAttribute(0, 0, openinference.ToolCallFunctionArguments), `["ls","-la"]`), + }, + }, + { + name: "local shell call with HideOutputText", + call: &openai.ResponseOutputItemLocalShellCall{ + CallID: "lsc-2", + Type: "local_shell_call", + Action: openai.ResponseOutputItemLocalShellCallAction{Command: []string{"rm", "-rf", "/"}}, + }, + config: &openinference.TraceConfig{HideOutputText: true}, + messageIndex: 0, + expectedAttrs: []attribute.KeyValue{ + attribute.String(openinference.OutputMessageAttribute(0, openinference.MessageRole), "assistant"), + attribute.String(openinference.OutputMessageToolCallAttribute(0, 0, openinference.ToolCallID), openinference.RedactedValue), + attribute.String(openinference.OutputMessageToolCallAttribute(0, 0, openinference.ToolCallFunctionName), openinference.RedactedValue), + attribute.String(openinference.OutputMessageToolCallAttribute(0, 0, openinference.ToolCallFunctionArguments), openinference.RedactedValue), + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + attrs := setResponseLocalShellCallAttrs(tt.call, []attribute.KeyValue{}, tt.config, tt.messageIndex) + openinference.RequireAttributesEqual(t, tt.expectedAttrs, attrs) + }) + } +} + +func TestSetResponseShellCallOutputAttrs(t *testing.T) { + tests := []struct { + name string + call *openai.ResponseFunctionShellToolCallOutput + config *openinference.TraceConfig + messageIndex int + expectedAttrs []attribute.KeyValue + }{ + { + name: "shell call output", + call: &openai.ResponseFunctionShellToolCallOutput{CallID: "sc-1", Type: "shell_call_output"}, + config: openinference.NewTraceConfig(), + messageIndex: 0, + expectedAttrs: []attribute.KeyValue{ + attribute.String(openinference.OutputMessageAttribute(0, openinference.MessageRole), "tool"), + attribute.String(openinference.OutputMessageToolCallAttribute(0, 0, openinference.ToolCallID), "sc-1"), + attribute.String(openinference.OutputMessageToolCallAttribute(0, 0, openinference.ToolCallFunctionName), "shell_call_output"), + }, + }, + { + name: "shell call output with HideOutputText", + call: &openai.ResponseFunctionShellToolCallOutput{CallID: "sc-2", Type: "shell_call_output"}, + config: &openinference.TraceConfig{HideOutputText: true}, + messageIndex: 0, + expectedAttrs: []attribute.KeyValue{ + attribute.String(openinference.OutputMessageAttribute(0, openinference.MessageRole), "tool"), + attribute.String(openinference.OutputMessageToolCallAttribute(0, 0, openinference.ToolCallID), openinference.RedactedValue), + attribute.String(openinference.OutputMessageToolCallAttribute(0, 0, openinference.ToolCallFunctionName), openinference.RedactedValue), + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + attrs := setResponseShellCallOutputAttrs(tt.call, []attribute.KeyValue{}, tt.config, tt.messageIndex) + openinference.RequireAttributesEqual(t, tt.expectedAttrs, attrs) + }) + } +} + +func TestSetResponseApplyPatchCallOutputAttrs(t *testing.T) { + tests := []struct { + name string + call *openai.ResponseApplyPatchToolCallOutput + config *openinference.TraceConfig + messageIndex int + expectedAttrs []attribute.KeyValue + }{ + { + name: "apply patch call output", + call: &openai.ResponseApplyPatchToolCallOutput{CallID: "apc-1", Type: "apply_patch_call_output", Output: "patched"}, + config: openinference.NewTraceConfig(), + messageIndex: 0, + expectedAttrs: []attribute.KeyValue{ + attribute.String(openinference.OutputMessageAttribute(0, openinference.MessageRole), "tool"), + attribute.String(openinference.OutputMessageToolCallAttribute(0, 0, openinference.ToolCallID), "apc-1"), + attribute.String(openinference.OutputMessageToolCallAttribute(0, 0, openinference.ToolCallFunctionName), "apply_patch_call_output"), + attribute.String(openinference.OutputMessageToolCallAttribute(0, 0, openinference.ToolCallFunctionArguments), "patched"), + }, + }, + { + name: "apply patch call output with HideOutputText", + call: &openai.ResponseApplyPatchToolCallOutput{CallID: "apc-2", Type: "apply_patch_call_output", Output: "secret"}, + config: &openinference.TraceConfig{HideOutputText: true}, + messageIndex: 0, + expectedAttrs: []attribute.KeyValue{ + attribute.String(openinference.OutputMessageAttribute(0, openinference.MessageRole), "tool"), + attribute.String(openinference.OutputMessageToolCallAttribute(0, 0, openinference.ToolCallID), openinference.RedactedValue), + attribute.String(openinference.OutputMessageToolCallAttribute(0, 0, openinference.ToolCallFunctionName), openinference.RedactedValue), + attribute.String(openinference.OutputMessageToolCallAttribute(0, 0, openinference.ToolCallFunctionArguments), openinference.RedactedValue), + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + attrs := setResponseApplyPatchCallOutputAttrs(tt.call, []attribute.KeyValue{}, tt.config, tt.messageIndex) + openinference.RequireAttributesEqual(t, tt.expectedAttrs, attrs) + }) + } +} + +func TestSetResponseCompactionAttrs(t *testing.T) { + tests := []struct { + name string + call *openai.ResponseCompactionItem + config *openinference.TraceConfig + messageIndex int + expectedAttrs []attribute.KeyValue + }{ + { + name: "compaction", + call: &openai.ResponseCompactionItem{ID: "c-1", Type: "compaction"}, + config: openinference.NewTraceConfig(), + messageIndex: 0, + expectedAttrs: []attribute.KeyValue{ + attribute.String(openinference.OutputMessageAttribute(0, openinference.MessageRole), "assistant"), + attribute.String(openinference.OutputMessageToolCallAttribute(0, 0, openinference.ToolCallID), "c-1"), + attribute.String(openinference.OutputMessageToolCallAttribute(0, 0, openinference.ToolCallFunctionName), "compaction"), + }, + }, + { + name: "compaction with HideOutputText", + call: &openai.ResponseCompactionItem{ID: "c-2", Type: "compaction"}, + config: &openinference.TraceConfig{HideOutputText: true}, + messageIndex: 0, + expectedAttrs: []attribute.KeyValue{ + attribute.String(openinference.OutputMessageAttribute(0, openinference.MessageRole), "assistant"), + attribute.String(openinference.OutputMessageToolCallAttribute(0, 0, openinference.ToolCallID), openinference.RedactedValue), + attribute.String(openinference.OutputMessageToolCallAttribute(0, 0, openinference.ToolCallFunctionName), openinference.RedactedValue), + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + attrs := setResponseCompactionAttrs(tt.call, []attribute.KeyValue{}, tt.config, tt.messageIndex) + openinference.RequireAttributesEqual(t, tt.expectedAttrs, attrs) + }) + } +}