Skip to content

Commit deae8d6

Browse files
committed
fix: update vendor mapping to handle azure-openai providers correctly
- Add azure-openai prefix mapping to OpenAI system - Fix failing tests for vendor transformation - Apply prettier formatting
1 parent 35f9f34 commit deae8d6

File tree

2 files changed

+166
-133
lines changed

2 files changed

+166
-133
lines changed

packages/traceloop-sdk/src/lib/tracing/ai-sdk-transformations.ts

Lines changed: 58 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ const AI_PROMPT_TOOLS = "ai.prompt.tools";
2424
// Uses prefixes to match AI SDK patterns like "openai.chat", "anthropic.messages", etc.
2525
const VENDOR_MAPPING: Record<string, string> = {
2626
openai: "OpenAI",
27+
"azure-openai": "OpenAI",
2728
anthropic: "Anthropic",
2829
cohere: "Cohere",
2930
mistral: "MistralAI",
@@ -51,9 +52,7 @@ export const transformAiSdkSpanName = (span: ReadableSpan): void => {
5152
}
5253
};
5354

54-
const transformResponseText = (
55-
attributes: Record<string, any>,
56-
): void => {
55+
const transformResponseText = (attributes: Record<string, any>): void => {
5756
if (AI_RESPONSE_TEXT in attributes) {
5857
attributes[`${SpanAttributes.LLM_COMPLETIONS}.0.content`] =
5958
attributes[AI_RESPONSE_TEXT];
@@ -62,9 +61,7 @@ const transformResponseText = (
6261
}
6362
};
6463

65-
const transformResponseObject = (
66-
attributes: Record<string, any>,
67-
): void => {
64+
const transformResponseObject = (attributes: Record<string, any>): void => {
6865
if (AI_RESPONSE_OBJECT in attributes) {
6966
attributes[`${SpanAttributes.LLM_COMPLETIONS}.0.content`] =
7067
attributes[AI_RESPONSE_OBJECT];
@@ -73,22 +70,26 @@ const transformResponseObject = (
7370
}
7471
};
7572

76-
const transformResponseToolCalls = (
77-
attributes: Record<string, any>,
78-
): void => {
73+
const transformResponseToolCalls = (attributes: Record<string, any>): void => {
7974
if (AI_RESPONSE_TOOL_CALLS in attributes) {
8075
try {
81-
const toolCalls = JSON.parse(attributes[AI_RESPONSE_TOOL_CALLS] as string);
82-
76+
const toolCalls = JSON.parse(
77+
attributes[AI_RESPONSE_TOOL_CALLS] as string,
78+
);
79+
8380
attributes[`${SpanAttributes.LLM_COMPLETIONS}.0.role`] = "assistant";
84-
81+
8582
toolCalls.forEach((toolCall: any, index: number) => {
8683
if (toolCall.toolCallType === "function") {
87-
attributes[`${SpanAttributes.LLM_COMPLETIONS}.0.tool_calls.${index}.name`] = toolCall.toolName;
88-
attributes[`${SpanAttributes.LLM_COMPLETIONS}.0.tool_calls.${index}.arguments`] = toolCall.args;
84+
attributes[
85+
`${SpanAttributes.LLM_COMPLETIONS}.0.tool_calls.${index}.name`
86+
] = toolCall.toolName;
87+
attributes[
88+
`${SpanAttributes.LLM_COMPLETIONS}.0.tool_calls.${index}.arguments`
89+
] = toolCall.args;
8990
}
9091
});
91-
92+
9293
delete attributes[AI_RESPONSE_TOOL_CALLS];
9394
} catch {
9495
// Ignore parsing errors
@@ -98,33 +99,38 @@ const transformResponseToolCalls = (
9899

99100
const processMessageContent = (content: any): string => {
100101
if (Array.isArray(content)) {
101-
const textItems = content.filter((item: any) =>
102-
item && typeof item === 'object' && item.type === "text" && item.text
102+
const textItems = content.filter(
103+
(item: any) =>
104+
item && typeof item === "object" && item.type === "text" && item.text,
103105
);
104-
106+
105107
if (textItems.length > 0) {
106108
const joinedText = textItems.map((item: any) => item.text).join(" ");
107109
return joinedText;
108110
} else {
109111
return JSON.stringify(content);
110112
}
111113
}
112-
113-
if (content && typeof content === 'object') {
114+
115+
if (content && typeof content === "object") {
114116
if (content.type === "text" && content.text) {
115117
return content.text;
116118
}
117119
return JSON.stringify(content);
118120
}
119-
121+
120122
if (typeof content === "string") {
121123
try {
122124
const parsed = JSON.parse(content);
123125
if (Array.isArray(parsed)) {
124-
const allTextItems = parsed.every((item: any) =>
125-
item && typeof item === 'object' && item.type === "text" && item.text
126+
const allTextItems = parsed.every(
127+
(item: any) =>
128+
item &&
129+
typeof item === "object" &&
130+
item.type === "text" &&
131+
item.text,
126132
);
127-
133+
128134
if (allTextItems && parsed.length > 0) {
129135
return parsed.map((item: any) => item.text).join(" ");
130136
} else {
@@ -134,42 +140,48 @@ const processMessageContent = (content: any): string => {
134140
} catch {
135141
// Ignore parsing errors
136142
}
137-
143+
138144
return content;
139145
}
140-
146+
141147
return String(content);
142148
};
143149

144-
const transformTools = (
145-
attributes: Record<string, any>,
146-
): void => {
150+
const transformTools = (attributes: Record<string, any>): void => {
147151
if (AI_PROMPT_TOOLS in attributes) {
148152
try {
149153
const tools = attributes[AI_PROMPT_TOOLS];
150154
if (Array.isArray(tools)) {
151155
tools.forEach((toolItem: any, index: number) => {
152156
let tool = toolItem;
153-
if (typeof toolItem === 'string') {
157+
if (typeof toolItem === "string") {
154158
try {
155159
tool = JSON.parse(toolItem);
156160
} catch {
157161
return;
158162
}
159163
}
160-
161-
if (tool && typeof tool === 'object') {
164+
165+
if (tool && typeof tool === "object") {
162166
if (tool.name) {
163-
attributes[`${SpanAttributes.LLM_REQUEST_FUNCTIONS}.${index}.name`] = tool.name;
167+
attributes[
168+
`${SpanAttributes.LLM_REQUEST_FUNCTIONS}.${index}.name`
169+
] = tool.name;
164170
}
165-
171+
166172
if (tool.description) {
167-
attributes[`${SpanAttributes.LLM_REQUEST_FUNCTIONS}.${index}.description`] = tool.description;
173+
attributes[
174+
`${SpanAttributes.LLM_REQUEST_FUNCTIONS}.${index}.description`
175+
] = tool.description;
168176
}
169-
177+
170178
if (tool.parameters) {
171-
attributes[`${SpanAttributes.LLM_REQUEST_FUNCTIONS}.${index}.parameters`] =
172-
typeof tool.parameters === 'string' ? tool.parameters : JSON.stringify(tool.parameters);
179+
attributes[
180+
`${SpanAttributes.LLM_REQUEST_FUNCTIONS}.${index}.parameters`
181+
] =
182+
typeof tool.parameters === "string"
183+
? tool.parameters
184+
: JSON.stringify(tool.parameters);
173185
}
174186
}
175187
});
@@ -181,20 +193,18 @@ const transformTools = (
181193
}
182194
};
183195

184-
const transformPrompts = (
185-
attributes: Record<string, any>,
186-
): void => {
196+
const transformPrompts = (attributes: Record<string, any>): void => {
187197
if (AI_PROMPT_MESSAGES in attributes) {
188198
try {
189199
let jsonString = attributes[AI_PROMPT_MESSAGES] as string;
190-
200+
191201
try {
192202
JSON.parse(jsonString);
193203
} catch {
194204
jsonString = jsonString.replace(/\\'/g, "'");
195205
jsonString = jsonString.replace(/\\\\\\\\/g, "\\\\");
196206
}
197-
207+
198208
const messages = JSON.parse(jsonString);
199209
messages.forEach((msg: { role: string; content: any }, index: number) => {
200210
const processedContent = processMessageContent(msg.content);
@@ -211,8 +221,9 @@ const transformPrompts = (
211221
if (AI_PROMPT in attributes) {
212222
try {
213223
const promptData = JSON.parse(attributes[AI_PROMPT] as string);
214-
if (promptData.prompt && typeof promptData.prompt === 'string') {
215-
attributes[`${SpanAttributes.LLM_PROMPTS}.0.content`] = promptData.prompt;
224+
if (promptData.prompt && typeof promptData.prompt === "string") {
225+
attributes[`${SpanAttributes.LLM_PROMPTS}.0.content`] =
226+
promptData.prompt;
216227
attributes[`${SpanAttributes.LLM_PROMPTS}.0.role`] = "user";
217228
delete attributes[AI_PROMPT];
218229
}
@@ -222,19 +233,15 @@ const transformPrompts = (
222233
}
223234
};
224235

225-
const transformPromptTokens = (
226-
attributes: Record<string, any>,
227-
): void => {
236+
const transformPromptTokens = (attributes: Record<string, any>): void => {
228237
if (AI_USAGE_PROMPT_TOKENS in attributes) {
229238
attributes[`${SpanAttributes.LLM_USAGE_PROMPT_TOKENS}`] =
230239
attributes[AI_USAGE_PROMPT_TOKENS];
231240
delete attributes[AI_USAGE_PROMPT_TOKENS];
232241
}
233242
};
234243

235-
const transformCompletionTokens = (
236-
attributes: Record<string, any>,
237-
): void => {
244+
const transformCompletionTokens = (attributes: Record<string, any>): void => {
238245
if (AI_USAGE_COMPLETION_TOKENS in attributes) {
239246
attributes[`${SpanAttributes.LLM_USAGE_COMPLETION_TOKENS}`] =
240247
attributes[AI_USAGE_COMPLETION_TOKENS];

0 commit comments

Comments
 (0)