promptlayer 1.0.60 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -0
- package/dist/esm/chunk-SWBNW72U.js +2 -0
- package/dist/esm/chunk-SWBNW72U.js.map +1 -0
- package/dist/esm/index.js +2 -2
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/openai-agents.js +3 -0
- package/dist/esm/openai-agents.js.map +1 -0
- package/dist/index.d.mts +229 -9
- package/dist/index.d.ts +229 -9
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/openai-agents.d.mts +42 -0
- package/dist/openai-agents.d.ts +42 -0
- package/dist/openai-agents.js +3 -0
- package/dist/openai-agents.js.map +1 -0
- package/package.json +24 -3
- package/src/integrations/openai-agents/helpers.test.ts +254 -0
- package/src/integrations/openai-agents/ids.ts +27 -0
- package/src/integrations/openai-agents/index.ts +8 -0
- package/src/integrations/openai-agents/instrumentation.test.ts +46 -0
- package/src/integrations/openai-agents/instrumentation.ts +47 -0
- package/src/integrations/openai-agents/mapping.ts +714 -0
- package/src/integrations/openai-agents/otlp-json.ts +120 -0
- package/src/integrations/openai-agents/processor.test.ts +509 -0
- package/src/integrations/openai-agents/processor.ts +388 -0
- package/src/integrations/openai-agents/time.ts +56 -0
- package/src/integrations/openai-agents/types.ts +49 -0
- package/src/integrations/openai-agents/url.ts +9 -0
- package/src/openai-agents.ts +1 -0
- package/src/types.ts +302 -9
- package/src/utils/blueprint-builder.test.ts +727 -0
- package/src/utils/blueprint-builder.ts +957 -126
- package/src/utils/streaming.test.ts +498 -0
- package/src/utils/streaming.ts +471 -43
- package/src/utils/utils.ts +4 -0
- package/tsup.config.ts +4 -1
- package/vitest.config.ts +3 -0
|
@@ -0,0 +1,714 @@
|
|
|
1
|
+
import { SDK_VERSION } from "@/utils/utils";
|
|
2
|
+
import type {
|
|
3
|
+
Span as AgentsSpan,
|
|
4
|
+
SpanData,
|
|
5
|
+
Trace as AgentsTrace,
|
|
6
|
+
} from "@openai/agents";
|
|
7
|
+
import type { AttributeValue } from "@/integrations/openai-agents/types";
|
|
8
|
+
|
|
9
|
+
const SPAN_KIND_INTERNAL = 1;
|
|
10
|
+
const SPAN_KIND_CLIENT = 3;
|
|
11
|
+
|
|
12
|
+
type AttributeMap = Record<string, AttributeValue>;
|
|
13
|
+
type NormalizedMessage = Record<string, AttributeValue>;
|
|
14
|
+
type NormalizedToolCall = {
|
|
15
|
+
id: string;
|
|
16
|
+
type: "tool_call";
|
|
17
|
+
name: string;
|
|
18
|
+
arguments: AttributeValue;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const isPlainObject = (value: unknown): value is Record<string, unknown> => {
|
|
22
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const isScalar = (value: unknown): value is string | number | boolean => {
|
|
26
|
+
return (
|
|
27
|
+
typeof value === "string" ||
|
|
28
|
+
typeof value === "number" ||
|
|
29
|
+
typeof value === "boolean"
|
|
30
|
+
);
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const sanitizeKey = (key: string): string => {
|
|
34
|
+
return key.replace(/[^a-zA-Z0-9_.-]/g, "_");
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const toJsonable = (value: unknown): AttributeValue => {
|
|
38
|
+
if (
|
|
39
|
+
value === null ||
|
|
40
|
+
typeof value === "string" ||
|
|
41
|
+
typeof value === "number" ||
|
|
42
|
+
typeof value === "boolean"
|
|
43
|
+
) {
|
|
44
|
+
return value;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (Array.isArray(value)) {
|
|
48
|
+
return value.map((item) => toJsonable(item));
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (isPlainObject(value)) {
|
|
52
|
+
return Object.fromEntries(
|
|
53
|
+
Object.entries(value).map(([key, item]) => [key, toJsonable(item)])
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return String(value);
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const stableStringify = (value: unknown): string => {
|
|
61
|
+
const normalize = (input: unknown): unknown => {
|
|
62
|
+
if (Array.isArray(input)) {
|
|
63
|
+
return input.map((item) => normalize(item));
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (isPlainObject(input)) {
|
|
67
|
+
return Object.keys(input)
|
|
68
|
+
.sort()
|
|
69
|
+
.reduce<Record<string, unknown>>((acc, key) => {
|
|
70
|
+
acc[key] = normalize(input[key]);
|
|
71
|
+
return acc;
|
|
72
|
+
}, {});
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return input;
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
return JSON.stringify(normalize(toJsonable(value)));
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
const setStringAttr = (attrs: AttributeMap, key: string, value: unknown) => {
|
|
82
|
+
if (value !== undefined && value !== null && value !== "") {
|
|
83
|
+
attrs[key] = String(value);
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
const setNumberAttr = (attrs: AttributeMap, key: string, value: unknown) => {
|
|
88
|
+
if (value !== undefined && value !== null && value !== "") {
|
|
89
|
+
const numericValue = Number(value);
|
|
90
|
+
if (!Number.isNaN(numericValue)) {
|
|
91
|
+
attrs[key] = numericValue;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
const setJsonAttr = (
|
|
97
|
+
attrs: AttributeMap,
|
|
98
|
+
key: string,
|
|
99
|
+
value: unknown,
|
|
100
|
+
includeRawPayloads: boolean
|
|
101
|
+
) => {
|
|
102
|
+
if (includeRawPayloads && value !== undefined && value !== null) {
|
|
103
|
+
attrs[key] = stableStringify(value);
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
const flattenIndexedMessages = (
|
|
108
|
+
prefix: string,
|
|
109
|
+
messages: NormalizedMessage[],
|
|
110
|
+
attrs: AttributeMap
|
|
111
|
+
) => {
|
|
112
|
+
messages.forEach((message, index) => {
|
|
113
|
+
Object.entries(message).forEach(([key, value]) => {
|
|
114
|
+
attrs[`${prefix}.${index}.${key}`] = isScalar(value)
|
|
115
|
+
? value
|
|
116
|
+
: stableStringify(value);
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
const normalizeToolCalls = (toolCalls: unknown): NormalizedToolCall[] => {
|
|
122
|
+
if (!Array.isArray(toolCalls)) {
|
|
123
|
+
return [];
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return toolCalls
|
|
127
|
+
.map((call) => {
|
|
128
|
+
if (!isPlainObject(call)) {
|
|
129
|
+
return null;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const functionData = isPlainObject(call.function) ? call.function : null;
|
|
133
|
+
const name = functionData?.name ?? call.name ?? "tool";
|
|
134
|
+
let argumentsValue =
|
|
135
|
+
functionData?.arguments ?? call.arguments ?? {};
|
|
136
|
+
|
|
137
|
+
if (typeof argumentsValue === "string") {
|
|
138
|
+
try {
|
|
139
|
+
argumentsValue = JSON.parse(argumentsValue);
|
|
140
|
+
} catch {
|
|
141
|
+
argumentsValue = argumentsValue;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return {
|
|
146
|
+
id: String(call.id ?? ""),
|
|
147
|
+
type: "tool_call",
|
|
148
|
+
name: String(name),
|
|
149
|
+
arguments: toJsonable(argumentsValue),
|
|
150
|
+
};
|
|
151
|
+
})
|
|
152
|
+
.filter((call): call is NormalizedToolCall => call !== null);
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
const getCallId = (item: Record<string, unknown>): string | undefined => {
|
|
156
|
+
const value = item.call_id ?? item.callId ?? item.id;
|
|
157
|
+
return value !== undefined && value !== null ? String(value) : undefined;
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
const normalizeToolOutputContent = (output: unknown): string | undefined => {
|
|
161
|
+
if (output === undefined || output === null) {
|
|
162
|
+
return undefined;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if (typeof output === "string") {
|
|
166
|
+
return output;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (Array.isArray(output)) {
|
|
170
|
+
const textContent = extractTextContent(output);
|
|
171
|
+
return textContent ?? stableStringify(output);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
if (isPlainObject(output)) {
|
|
175
|
+
const textContent = extractTextContent([output]);
|
|
176
|
+
return textContent ?? stableStringify(output);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const textContent = extractTextContent(output);
|
|
180
|
+
if (textContent !== undefined) {
|
|
181
|
+
return textContent;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
return stableStringify(output);
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
const normalizeToolCallMessage = (
|
|
188
|
+
item: Record<string, unknown>
|
|
189
|
+
): NormalizedMessage | null => {
|
|
190
|
+
let argumentsValue = item.arguments ?? {};
|
|
191
|
+
if (typeof argumentsValue === "string") {
|
|
192
|
+
try {
|
|
193
|
+
argumentsValue = JSON.parse(argumentsValue);
|
|
194
|
+
} catch {
|
|
195
|
+
argumentsValue = argumentsValue;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
return {
|
|
200
|
+
role: "assistant",
|
|
201
|
+
tool_calls: [
|
|
202
|
+
{
|
|
203
|
+
id: getCallId(item) ?? "",
|
|
204
|
+
type: "tool_call",
|
|
205
|
+
name: String(item.name ?? "tool"),
|
|
206
|
+
arguments: toJsonable(argumentsValue),
|
|
207
|
+
},
|
|
208
|
+
],
|
|
209
|
+
};
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
const normalizeToolResultMessage = (
|
|
213
|
+
item: Record<string, unknown>,
|
|
214
|
+
outputOverride?: unknown
|
|
215
|
+
): NormalizedMessage | null => {
|
|
216
|
+
const toolCallId = getCallId(item);
|
|
217
|
+
const content = normalizeToolOutputContent(
|
|
218
|
+
outputOverride ?? item.output ?? item.content
|
|
219
|
+
);
|
|
220
|
+
|
|
221
|
+
if (!toolCallId && !content) {
|
|
222
|
+
return null;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
const message: NormalizedMessage = {
|
|
226
|
+
role: "tool",
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
if (toolCallId) {
|
|
230
|
+
message.tool_call_id = toolCallId;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
if (content !== undefined) {
|
|
234
|
+
message.content = content;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
return message;
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
function extractTextContent(content: unknown): string | undefined {
|
|
241
|
+
if (content === undefined || content === null) {
|
|
242
|
+
return undefined;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
if (typeof content === "string") {
|
|
246
|
+
return content;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
if (Array.isArray(content)) {
|
|
250
|
+
const textParts = content
|
|
251
|
+
.map((part) => {
|
|
252
|
+
if (!isPlainObject(part)) {
|
|
253
|
+
return null;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
const partType = part.type;
|
|
257
|
+
if (
|
|
258
|
+
partType === "text" ||
|
|
259
|
+
partType === "input_text" ||
|
|
260
|
+
partType === "output_text"
|
|
261
|
+
) {
|
|
262
|
+
const text = part.text ?? part.content;
|
|
263
|
+
return text !== undefined && text !== null ? String(text) : null;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
return null;
|
|
267
|
+
})
|
|
268
|
+
.filter((part): part is string => part !== null);
|
|
269
|
+
|
|
270
|
+
return textParts.length > 0 ? textParts.join("\n") : undefined;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
return String(content);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
export const normalizeMessages = (items: unknown): NormalizedMessage[] => {
|
|
277
|
+
if (!Array.isArray(items)) {
|
|
278
|
+
return [];
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
return items
|
|
282
|
+
.map((item) => {
|
|
283
|
+
if (!isPlainObject(item)) {
|
|
284
|
+
return null;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
const normalized: NormalizedMessage = {};
|
|
288
|
+
if (item.role !== undefined) {
|
|
289
|
+
normalized.role = String(item.role);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
const content = extractTextContent(item.content);
|
|
293
|
+
if (content) {
|
|
294
|
+
normalized.content = content;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
const toolCalls = normalizeToolCalls(item.tool_calls);
|
|
298
|
+
if (toolCalls.length > 0) {
|
|
299
|
+
normalized.tool_calls = toolCalls;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
if (item.tool_call_id) {
|
|
303
|
+
normalized.tool_call_id = String(item.tool_call_id);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
return Object.keys(normalized).length > 0 ? normalized : null;
|
|
307
|
+
})
|
|
308
|
+
.filter((message): message is NormalizedMessage => message !== null);
|
|
309
|
+
};
|
|
310
|
+
|
|
311
|
+
const normalizeResponseMessage = (
|
|
312
|
+
item: Record<string, unknown>
|
|
313
|
+
): NormalizedMessage | null => {
|
|
314
|
+
const message: NormalizedMessage = {};
|
|
315
|
+
const role = item.role;
|
|
316
|
+
const content = extractTextContent(item.content);
|
|
317
|
+
const toolCalls = normalizeToolCalls(item.tool_calls);
|
|
318
|
+
|
|
319
|
+
if (role !== undefined && role !== null) {
|
|
320
|
+
message.role = String(role);
|
|
321
|
+
} else if (content || toolCalls.length > 0) {
|
|
322
|
+
message.role = "assistant";
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
if (content) {
|
|
326
|
+
message.content = content;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
if (toolCalls.length > 0) {
|
|
330
|
+
message.tool_calls = toolCalls;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
if (item.tool_call_id) {
|
|
334
|
+
message.tool_call_id = String(item.tool_call_id);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
return Object.keys(message).length > 0 ? message : null;
|
|
338
|
+
};
|
|
339
|
+
|
|
340
|
+
const RAW_TOOL_CALL_ITEM_TYPES = new Set([
|
|
341
|
+
"function_call",
|
|
342
|
+
"computer_call",
|
|
343
|
+
"shell_call",
|
|
344
|
+
"apply_patch_call",
|
|
345
|
+
"custom_tool_call",
|
|
346
|
+
"mcp_call",
|
|
347
|
+
]);
|
|
348
|
+
|
|
349
|
+
const RAW_TOOL_RESULT_ITEM_TYPES = new Set([
|
|
350
|
+
"function_call_output",
|
|
351
|
+
"function_call_result",
|
|
352
|
+
"computer_call_output",
|
|
353
|
+
"computer_call_result",
|
|
354
|
+
"shell_call_output",
|
|
355
|
+
"apply_patch_call_output",
|
|
356
|
+
"custom_tool_call_output",
|
|
357
|
+
]);
|
|
358
|
+
|
|
359
|
+
export const normalizeResponseItems = (items: unknown): NormalizedMessage[] => {
|
|
360
|
+
if (typeof items === "string") {
|
|
361
|
+
return [{ role: "user", content: items }];
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
if (!Array.isArray(items)) {
|
|
365
|
+
return [];
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
return items
|
|
369
|
+
.flatMap((item) => {
|
|
370
|
+
if (!isPlainObject(item)) {
|
|
371
|
+
return [];
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
if (item.type === "message_output_item" && isPlainObject(item.rawItem)) {
|
|
375
|
+
const message = normalizeResponseMessage(item.rawItem);
|
|
376
|
+
return message ? [message] : [];
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
if (item.type === "tool_call_item" && isPlainObject(item.rawItem)) {
|
|
380
|
+
const message = normalizeToolCallMessage(item.rawItem);
|
|
381
|
+
return message ? [message] : [];
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
if (item.type === "tool_call_output_item" && isPlainObject(item.rawItem)) {
|
|
385
|
+
const message = normalizeToolResultMessage(item.rawItem, item.output);
|
|
386
|
+
return message ? [message] : [];
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
if (typeof item.type === "string" && RAW_TOOL_CALL_ITEM_TYPES.has(item.type)) {
|
|
390
|
+
const message = normalizeToolCallMessage(item);
|
|
391
|
+
return message ? [message] : [];
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
if (
|
|
395
|
+
typeof item.type === "string" &&
|
|
396
|
+
RAW_TOOL_RESULT_ITEM_TYPES.has(item.type)
|
|
397
|
+
) {
|
|
398
|
+
const message = normalizeToolResultMessage(item);
|
|
399
|
+
return message ? [message] : [];
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
const message = normalizeResponseMessage(item);
|
|
403
|
+
return message ? [message] : [];
|
|
404
|
+
})
|
|
405
|
+
.filter((message): message is NormalizedMessage => message !== null);
|
|
406
|
+
};
|
|
407
|
+
|
|
408
|
+
const applyUsageAttributes = (attrs: AttributeMap, usage: unknown) => {
|
|
409
|
+
if (!isPlainObject(usage)) {
|
|
410
|
+
return;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
setNumberAttr(
|
|
414
|
+
attrs,
|
|
415
|
+
"gen_ai.usage.input_tokens",
|
|
416
|
+
usage.input_tokens ?? usage.prompt_tokens
|
|
417
|
+
);
|
|
418
|
+
setNumberAttr(
|
|
419
|
+
attrs,
|
|
420
|
+
"gen_ai.usage.output_tokens",
|
|
421
|
+
usage.output_tokens ?? usage.completion_tokens
|
|
422
|
+
);
|
|
423
|
+
};
|
|
424
|
+
|
|
425
|
+
const generationAttributes = (
|
|
426
|
+
spanData: Extract<SpanData, { type: "generation" }>,
|
|
427
|
+
includeRawPayloads: boolean
|
|
428
|
+
): AttributeMap => {
|
|
429
|
+
const attrs: AttributeMap = {
|
|
430
|
+
"gen_ai.provider.name": "openai.responses",
|
|
431
|
+
};
|
|
432
|
+
|
|
433
|
+
setStringAttr(attrs, "gen_ai.request.model", spanData.model);
|
|
434
|
+
applyUsageAttributes(attrs, spanData.usage);
|
|
435
|
+
flattenIndexedMessages("gen_ai.prompt", normalizeMessages(spanData.input), attrs);
|
|
436
|
+
flattenIndexedMessages(
|
|
437
|
+
"gen_ai.completion",
|
|
438
|
+
normalizeMessages(spanData.output),
|
|
439
|
+
attrs
|
|
440
|
+
);
|
|
441
|
+
setJsonAttr(
|
|
442
|
+
attrs,
|
|
443
|
+
"openai_agents.model_config_json",
|
|
444
|
+
spanData.model_config,
|
|
445
|
+
includeRawPayloads
|
|
446
|
+
);
|
|
447
|
+
setJsonAttr(
|
|
448
|
+
attrs,
|
|
449
|
+
"openai_agents.generation.raw_input_json",
|
|
450
|
+
spanData.input,
|
|
451
|
+
includeRawPayloads
|
|
452
|
+
);
|
|
453
|
+
setJsonAttr(
|
|
454
|
+
attrs,
|
|
455
|
+
"openai_agents.generation.raw_output_json",
|
|
456
|
+
spanData.output,
|
|
457
|
+
includeRawPayloads
|
|
458
|
+
);
|
|
459
|
+
|
|
460
|
+
return attrs;
|
|
461
|
+
};
|
|
462
|
+
|
|
463
|
+
const responseAttributes = (
|
|
464
|
+
spanData: Extract<SpanData, { type: "response" }>,
|
|
465
|
+
includeRawPayloads: boolean
|
|
466
|
+
): AttributeMap => {
|
|
467
|
+
const attrs: AttributeMap = {
|
|
468
|
+
"gen_ai.provider.name": "openai.responses",
|
|
469
|
+
};
|
|
470
|
+
const responseObject = isPlainObject(spanData._response) ? spanData._response : {};
|
|
471
|
+
const usage =
|
|
472
|
+
isPlainObject(responseObject.usage) ? responseObject.usage : undefined;
|
|
473
|
+
|
|
474
|
+
setStringAttr(
|
|
475
|
+
attrs,
|
|
476
|
+
"gen_ai.request.model",
|
|
477
|
+
responseObject.model
|
|
478
|
+
);
|
|
479
|
+
setStringAttr(
|
|
480
|
+
attrs,
|
|
481
|
+
"gen_ai.response.model",
|
|
482
|
+
responseObject.model
|
|
483
|
+
);
|
|
484
|
+
setStringAttr(
|
|
485
|
+
attrs,
|
|
486
|
+
"gen_ai.response.id",
|
|
487
|
+
spanData.response_id ?? responseObject.id ?? responseObject.response_id
|
|
488
|
+
);
|
|
489
|
+
applyUsageAttributes(attrs, usage);
|
|
490
|
+
flattenIndexedMessages(
|
|
491
|
+
"gen_ai.prompt",
|
|
492
|
+
normalizeResponseItems(spanData._input ?? responseObject.input),
|
|
493
|
+
attrs
|
|
494
|
+
);
|
|
495
|
+
flattenIndexedMessages(
|
|
496
|
+
"gen_ai.completion",
|
|
497
|
+
normalizeResponseItems(responseObject.output),
|
|
498
|
+
attrs
|
|
499
|
+
);
|
|
500
|
+
setJsonAttr(
|
|
501
|
+
attrs,
|
|
502
|
+
"openai_agents.response.raw_json",
|
|
503
|
+
responseObject,
|
|
504
|
+
includeRawPayloads
|
|
505
|
+
);
|
|
506
|
+
setStringAttr(
|
|
507
|
+
attrs,
|
|
508
|
+
"openai_agents.response.object",
|
|
509
|
+
responseObject.object
|
|
510
|
+
);
|
|
511
|
+
|
|
512
|
+
return attrs;
|
|
513
|
+
};
|
|
514
|
+
|
|
515
|
+
const functionAttributes = (
|
|
516
|
+
spanData: Extract<SpanData, { type: "function" }>,
|
|
517
|
+
includeRawPayloads: boolean
|
|
518
|
+
): AttributeMap => {
|
|
519
|
+
const attrs: AttributeMap = {
|
|
520
|
+
node_type: "CODE_EXECUTION",
|
|
521
|
+
tool_name: spanData.name,
|
|
522
|
+
"openai_agents.function.name": spanData.name,
|
|
523
|
+
};
|
|
524
|
+
|
|
525
|
+
setStringAttr(attrs, "function_input", spanData.input);
|
|
526
|
+
setStringAttr(attrs, "function_output", spanData.output);
|
|
527
|
+
setStringAttr(attrs, "openai_agents.function.input", spanData.input);
|
|
528
|
+
setStringAttr(attrs, "openai_agents.function.output", spanData.output);
|
|
529
|
+
setJsonAttr(
|
|
530
|
+
attrs,
|
|
531
|
+
"openai_agents.function.mcp_data_json",
|
|
532
|
+
spanData.mcp_data,
|
|
533
|
+
includeRawPayloads
|
|
534
|
+
);
|
|
535
|
+
|
|
536
|
+
return attrs;
|
|
537
|
+
};
|
|
538
|
+
|
|
539
|
+
const agentAttributes = (
|
|
540
|
+
spanData: Extract<SpanData, { type: "agent" }>,
|
|
541
|
+
includeRawPayloads: boolean
|
|
542
|
+
): AttributeMap => {
|
|
543
|
+
const attrs: AttributeMap = {
|
|
544
|
+
"openai_agents.agent.name": spanData.name,
|
|
545
|
+
};
|
|
546
|
+
|
|
547
|
+
setStringAttr(attrs, "openai_agents.agent.output_type", spanData.output_type);
|
|
548
|
+
setJsonAttr(
|
|
549
|
+
attrs,
|
|
550
|
+
"openai_agents.agent.handoffs_json",
|
|
551
|
+
spanData.handoffs,
|
|
552
|
+
includeRawPayloads
|
|
553
|
+
);
|
|
554
|
+
setJsonAttr(
|
|
555
|
+
attrs,
|
|
556
|
+
"openai_agents.agent.tools_json",
|
|
557
|
+
spanData.tools,
|
|
558
|
+
includeRawPayloads
|
|
559
|
+
);
|
|
560
|
+
|
|
561
|
+
return attrs;
|
|
562
|
+
};
|
|
563
|
+
|
|
564
|
+
const handoffAttributes = (
|
|
565
|
+
spanData: Extract<SpanData, { type: "handoff" }>
|
|
566
|
+
): AttributeMap => {
|
|
567
|
+
const attrs: AttributeMap = {};
|
|
568
|
+
setStringAttr(attrs, "openai_agents.handoff.from_agent", spanData.from_agent);
|
|
569
|
+
setStringAttr(attrs, "openai_agents.handoff.to_agent", spanData.to_agent);
|
|
570
|
+
return attrs;
|
|
571
|
+
};
|
|
572
|
+
|
|
573
|
+
const guardrailAttributes = (
|
|
574
|
+
spanData: Extract<SpanData, { type: "guardrail" }>
|
|
575
|
+
): AttributeMap => {
|
|
576
|
+
return {
|
|
577
|
+
"openai_agents.guardrail.name": spanData.name,
|
|
578
|
+
"openai_agents.guardrail.triggered": spanData.triggered,
|
|
579
|
+
};
|
|
580
|
+
};
|
|
581
|
+
|
|
582
|
+
const customAttributes = (
|
|
583
|
+
spanData: Extract<SpanData, { type: "custom" }>,
|
|
584
|
+
includeRawPayloads: boolean
|
|
585
|
+
): AttributeMap => {
|
|
586
|
+
const attrs: AttributeMap = {
|
|
587
|
+
"openai_agents.custom.name": spanData.name,
|
|
588
|
+
};
|
|
589
|
+
setJsonAttr(
|
|
590
|
+
attrs,
|
|
591
|
+
"openai_agents.custom.data_json",
|
|
592
|
+
spanData.data,
|
|
593
|
+
includeRawPayloads
|
|
594
|
+
);
|
|
595
|
+
return attrs;
|
|
596
|
+
};
|
|
597
|
+
|
|
598
|
+
const rawSpanDataAttributes = (
|
|
599
|
+
spanData: SpanData,
|
|
600
|
+
includeRawPayloads: boolean
|
|
601
|
+
): AttributeMap => {
|
|
602
|
+
if (!includeRawPayloads) {
|
|
603
|
+
return {};
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
return {
|
|
607
|
+
"openai_agents.raw_json": stableStringify(spanData),
|
|
608
|
+
};
|
|
609
|
+
};
|
|
610
|
+
|
|
611
|
+
export const telemetrySourceVersion = (): string => {
|
|
612
|
+
return SDK_VERSION;
|
|
613
|
+
};
|
|
614
|
+
|
|
615
|
+
export const spanKindFor = (span: Pick<AgentsSpan<any>, "spanData">): number => {
|
|
616
|
+
return span.spanData.type === "generation" || span.spanData.type === "response"
|
|
617
|
+
? SPAN_KIND_CLIENT
|
|
618
|
+
: SPAN_KIND_INTERNAL;
|
|
619
|
+
};
|
|
620
|
+
|
|
621
|
+
export const spanNameFor = (span: Pick<AgentsSpan<any>, "spanData">): string => {
|
|
622
|
+
switch (span.spanData.type) {
|
|
623
|
+
case "function":
|
|
624
|
+
return `Function: ${span.spanData.name}`;
|
|
625
|
+
case "agent":
|
|
626
|
+
return `Agent: ${span.spanData.name}`;
|
|
627
|
+
case "guardrail":
|
|
628
|
+
return `Guardrail: ${span.spanData.name}`;
|
|
629
|
+
case "custom":
|
|
630
|
+
return String(span.spanData.name);
|
|
631
|
+
default:
|
|
632
|
+
return span.spanData.type
|
|
633
|
+
.split("_")
|
|
634
|
+
.map((part: string) => part.charAt(0).toUpperCase() + part.slice(1))
|
|
635
|
+
.join(" ");
|
|
636
|
+
}
|
|
637
|
+
};
|
|
638
|
+
|
|
639
|
+
export const baseTraceAttributes = (
|
|
640
|
+
trace: Pick<AgentsTrace, "traceId" | "name" | "groupId" | "metadata">,
|
|
641
|
+
includeRawPayloads: boolean
|
|
642
|
+
): AttributeMap => {
|
|
643
|
+
const attrs: AttributeMap = {
|
|
644
|
+
"promptlayer.telemetry.source": "openai-agents-js",
|
|
645
|
+
"promptlayer.telemetry.source_version": telemetrySourceVersion(),
|
|
646
|
+
"openai_agents.trace_id_original": trace.traceId,
|
|
647
|
+
"openai_agents.workflow_name": trace.name,
|
|
648
|
+
};
|
|
649
|
+
|
|
650
|
+
if (trace.groupId) {
|
|
651
|
+
attrs["openai_agents.group_id"] = trace.groupId;
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
if (isPlainObject(trace.metadata)) {
|
|
655
|
+
Object.entries(trace.metadata).forEach(([key, value]) => {
|
|
656
|
+
if (isScalar(value)) {
|
|
657
|
+
attrs[`openai_agents.metadata.${sanitizeKey(key)}`] = value;
|
|
658
|
+
}
|
|
659
|
+
});
|
|
660
|
+
setJsonAttr(
|
|
661
|
+
attrs,
|
|
662
|
+
"openai_agents.metadata_json",
|
|
663
|
+
trace.metadata,
|
|
664
|
+
includeRawPayloads
|
|
665
|
+
);
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
return attrs;
|
|
669
|
+
};
|
|
670
|
+
|
|
671
|
+
export const baseSpanAttributes = (
|
|
672
|
+
span: Pick<AgentsSpan<any>, "spanId" | "parentId" | "spanData">
|
|
673
|
+
): AttributeMap => {
|
|
674
|
+
const attrs: AttributeMap = {
|
|
675
|
+
"promptlayer.telemetry.source": "openai-agents-js",
|
|
676
|
+
"promptlayer.telemetry.source_version": telemetrySourceVersion(),
|
|
677
|
+
"openai_agents.span_id_original": span.spanId,
|
|
678
|
+
"openai_agents.span_type": span.spanData.type,
|
|
679
|
+
};
|
|
680
|
+
|
|
681
|
+
if (span.parentId) {
|
|
682
|
+
attrs["openai_agents.parent_id_original"] = span.parentId;
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
return attrs;
|
|
686
|
+
};
|
|
687
|
+
|
|
688
|
+
export const spanDataAttributes = (
|
|
689
|
+
spanData: SpanData,
|
|
690
|
+
includeRawPayloads: boolean
|
|
691
|
+
): AttributeMap => {
|
|
692
|
+
switch (spanData.type) {
|
|
693
|
+
case "generation":
|
|
694
|
+
return generationAttributes(spanData, includeRawPayloads);
|
|
695
|
+
case "response":
|
|
696
|
+
return responseAttributes(spanData, includeRawPayloads);
|
|
697
|
+
case "function":
|
|
698
|
+
return functionAttributes(spanData, includeRawPayloads);
|
|
699
|
+
case "agent":
|
|
700
|
+
return agentAttributes(spanData, includeRawPayloads);
|
|
701
|
+
case "handoff":
|
|
702
|
+
return handoffAttributes(spanData);
|
|
703
|
+
case "guardrail":
|
|
704
|
+
return guardrailAttributes(spanData);
|
|
705
|
+
case "custom":
|
|
706
|
+
return customAttributes(spanData, includeRawPayloads);
|
|
707
|
+
default:
|
|
708
|
+
return rawSpanDataAttributes(spanData, includeRawPayloads);
|
|
709
|
+
}
|
|
710
|
+
};
|
|
711
|
+
|
|
712
|
+
export const OTLP_STATUS_CODE_UNSET = 0;
|
|
713
|
+
export const OTLP_STATUS_CODE_OK = 1;
|
|
714
|
+
export const OTLP_STATUS_CODE_ERROR = 2;
|