autotel-devtools 8.1.1 → 9.0.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.
Files changed (63) hide show
  1. package/dist/cli.cjs +108 -1429
  2. package/dist/cli.cjs.map +1 -1
  3. package/dist/cli.d.cts +1 -1
  4. package/dist/cli.d.ts +1 -1
  5. package/dist/cli.js +109 -1422
  6. package/dist/cli.js.map +1 -1
  7. package/dist/error-aggregator-BvNmgn7E.d.ts +120 -0
  8. package/dist/error-aggregator-nnfbpSR7.d.cts +120 -0
  9. package/dist/exporter-1Y3GmLVS.d.cts +182 -0
  10. package/dist/exporter-CZ5HdD3o.d.ts +182 -0
  11. package/dist/genai/index.cjs +650 -537
  12. package/dist/genai/index.cjs.map +1 -1
  13. package/dist/genai/index.d.cts +164 -157
  14. package/dist/genai/index.d.ts +164 -157
  15. package/dist/genai/index.js +649 -536
  16. package/dist/genai/index.js.map +1 -1
  17. package/dist/http-BkkKa9C_.js +1128 -0
  18. package/dist/http-BkkKa9C_.js.map +1 -0
  19. package/dist/http-Yj6iSrMX.cjs +1275 -0
  20. package/dist/http-Yj6iSrMX.cjs.map +1 -0
  21. package/dist/index.cjs +50 -1728
  22. package/dist/index.cjs.map +1 -1
  23. package/dist/index.d.cts +21 -23
  24. package/dist/index.d.ts +21 -23
  25. package/dist/index.js +44 -1716
  26. package/dist/index.js.map +1 -1
  27. package/dist/listen-BBsxO0wm.cjs +125 -0
  28. package/dist/listen-BBsxO0wm.cjs.map +1 -0
  29. package/dist/listen-DfOCquUq.js +120 -0
  30. package/dist/listen-DfOCquUq.js.map +1 -0
  31. package/dist/resource-utils-B4UVvfnH.js +18 -0
  32. package/dist/resource-utils-B4UVvfnH.js.map +1 -0
  33. package/dist/resource-utils-DjHJB6uc.cjs +24 -0
  34. package/dist/resource-utils-DjHJB6uc.cjs.map +1 -0
  35. package/dist/server/exporter.cjs +135 -159
  36. package/dist/server/exporter.cjs.map +1 -1
  37. package/dist/server/exporter.d.cts +2 -4
  38. package/dist/server/exporter.d.ts +2 -4
  39. package/dist/server/exporter.js +134 -158
  40. package/dist/server/exporter.js.map +1 -1
  41. package/dist/server/index.cjs +29 -1660
  42. package/dist/server/index.d.cts +34 -31
  43. package/dist/server/index.d.ts +34 -31
  44. package/dist/server/index.js +5 -1630
  45. package/dist/server/log-exporter.cjs +75 -102
  46. package/dist/server/log-exporter.cjs.map +1 -1
  47. package/dist/server/log-exporter.d.cts +27 -46
  48. package/dist/server/log-exporter.d.ts +27 -46
  49. package/dist/server/log-exporter.js +74 -100
  50. package/dist/server/log-exporter.js.map +1 -1
  51. package/dist/server/remote-exporter.cjs +171 -213
  52. package/dist/server/remote-exporter.cjs.map +1 -1
  53. package/dist/server/remote-exporter.d.cts +62 -82
  54. package/dist/server/remote-exporter.d.ts +62 -82
  55. package/dist/server/remote-exporter.js +170 -212
  56. package/dist/server/remote-exporter.js.map +1 -1
  57. package/package.json +5 -5
  58. package/dist/error-aggregator-D0Uu5r38.d.ts +0 -147
  59. package/dist/error-aggregator-D1Mr221Y.d.cts +0 -147
  60. package/dist/exporter-De6p4iAD.d.cts +0 -182
  61. package/dist/exporter-De6p4iAD.d.ts +0 -182
  62. package/dist/server/index.cjs.map +0 -1
  63. package/dist/server/index.js.map +0 -1
@@ -1,591 +1,704 @@
1
- 'use strict';
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
2
 
3
- // src/widget/genai/detect.ts
4
- var GENAI_MARKERS = [
5
- "gen_ai.system",
6
- "gen_ai.provider.name",
7
- "gen_ai.operation.name",
8
- "ai.model.provider"
3
+ //#region src/widget/genai/detect.ts
4
+ const GENAI_MARKERS = [
5
+ "gen_ai.system",
6
+ "gen_ai.provider.name",
7
+ "gen_ai.operation.name",
8
+ "ai.model.provider"
9
9
  ];
10
10
  function isGenAiSpan(span) {
11
- const attrs = span.attributes ?? {};
12
- for (const key of GENAI_MARKERS) {
13
- if (attrs[key] != null) return true;
14
- }
15
- return false;
11
+ const attrs = span.attributes ?? {};
12
+ for (const key of GENAI_MARKERS) if (attrs[key] != null) return true;
13
+ return false;
16
14
  }
17
15
 
18
- // src/widget/genai/prices.ts
19
- var TABLE = {
20
- "openai/gpt-4o": { inputPerMTok: 2.5, outputPerMTok: 10 },
21
- "openai/gpt-4o-mini": { inputPerMTok: 0.15, outputPerMTok: 0.6 },
22
- "openai/gpt-4-turbo": { inputPerMTok: 10, outputPerMTok: 30 },
23
- "openai/gpt-3.5-turbo": { inputPerMTok: 0.5, outputPerMTok: 1.5 },
24
- "anthropic/claude-opus-4": { inputPerMTok: 15, outputPerMTok: 75 },
25
- "anthropic/claude-sonnet-4": { inputPerMTok: 3, outputPerMTok: 15 },
26
- "anthropic/claude-3-5-sonnet": { inputPerMTok: 3, outputPerMTok: 15 },
27
- "anthropic/claude-3-5-haiku": { inputPerMTok: 0.8, outputPerMTok: 4 },
28
- "anthropic/claude-3-opus": { inputPerMTok: 15, outputPerMTok: 75 },
29
- "anthropic/claude-3-haiku": { inputPerMTok: 0.25, outputPerMTok: 1.25 },
30
- "google/gemini-2.5-flash": { inputPerMTok: 0.3, outputPerMTok: 2.5 },
31
- "google/gemini-2.0-flash": { inputPerMTok: 0.1, outputPerMTok: 0.4 },
32
- "google/gemini-1.5-pro": { inputPerMTok: 1.25, outputPerMTok: 5 },
33
- "google/gemini-1.5-flash": { inputPerMTok: 0.075, outputPerMTok: 0.3 },
34
- "mistral/mistral-large": { inputPerMTok: 2, outputPerMTok: 6 },
35
- "mistral/mistral-small": { inputPerMTok: 0.2, outputPerMTok: 0.6 },
36
- "groq/llama-3.1-70b": { inputPerMTok: 0.59, outputPerMTok: 0.79 },
37
- "deepseek/deepseek-chat": { inputPerMTok: 0.27, outputPerMTok: 1.1 }
16
+ //#endregion
17
+ //#region src/widget/genai/prices.ts
18
+ const TABLE = {
19
+ "openai/gpt-4o": {
20
+ inputPerMTok: 2.5,
21
+ outputPerMTok: 10
22
+ },
23
+ "openai/gpt-4o-mini": {
24
+ inputPerMTok: .15,
25
+ outputPerMTok: .6
26
+ },
27
+ "openai/gpt-4-turbo": {
28
+ inputPerMTok: 10,
29
+ outputPerMTok: 30
30
+ },
31
+ "openai/gpt-3.5-turbo": {
32
+ inputPerMTok: .5,
33
+ outputPerMTok: 1.5
34
+ },
35
+ "anthropic/claude-opus-4": {
36
+ inputPerMTok: 15,
37
+ outputPerMTok: 75
38
+ },
39
+ "anthropic/claude-sonnet-4": {
40
+ inputPerMTok: 3,
41
+ outputPerMTok: 15
42
+ },
43
+ "anthropic/claude-3-5-sonnet": {
44
+ inputPerMTok: 3,
45
+ outputPerMTok: 15
46
+ },
47
+ "anthropic/claude-3-5-haiku": {
48
+ inputPerMTok: .8,
49
+ outputPerMTok: 4
50
+ },
51
+ "anthropic/claude-3-opus": {
52
+ inputPerMTok: 15,
53
+ outputPerMTok: 75
54
+ },
55
+ "anthropic/claude-3-haiku": {
56
+ inputPerMTok: .25,
57
+ outputPerMTok: 1.25
58
+ },
59
+ "google/gemini-2.5-flash": {
60
+ inputPerMTok: .3,
61
+ outputPerMTok: 2.5
62
+ },
63
+ "google/gemini-2.0-flash": {
64
+ inputPerMTok: .1,
65
+ outputPerMTok: .4
66
+ },
67
+ "google/gemini-1.5-pro": {
68
+ inputPerMTok: 1.25,
69
+ outputPerMTok: 5
70
+ },
71
+ "google/gemini-1.5-flash": {
72
+ inputPerMTok: .075,
73
+ outputPerMTok: .3
74
+ },
75
+ "mistral/mistral-large": {
76
+ inputPerMTok: 2,
77
+ outputPerMTok: 6
78
+ },
79
+ "mistral/mistral-small": {
80
+ inputPerMTok: .2,
81
+ outputPerMTok: .6
82
+ },
83
+ "groq/llama-3.1-70b": {
84
+ inputPerMTok: .59,
85
+ outputPerMTok: .79
86
+ },
87
+ "deepseek/deepseek-chat": {
88
+ inputPerMTok: .27,
89
+ outputPerMTok: 1.1
90
+ }
38
91
  };
39
92
  function normalizeProvider(provider) {
40
- const p = provider.toLowerCase();
41
- if (p === "az.ai.openai" || p === "azure_openai") return "openai";
42
- if (p === "vertex_ai" || p === "gcp.vertex_ai" || p === "gcp.gemini") return "google";
43
- return p;
93
+ const p = provider.toLowerCase();
94
+ if (p === "az.ai.openai" || p === "azure_openai") return "openai";
95
+ if (p === "vertex_ai" || p === "gcp.vertex_ai" || p === "gcp.gemini") return "google";
96
+ return p;
44
97
  }
45
- var SORTED_KEYS = Object.keys(TABLE).sort((a, b) => {
46
- const am = a.split("/")[1] ?? "";
47
- const bm = b.split("/")[1] ?? "";
48
- return bm.length - am.length;
98
+ const SORTED_KEYS = Object.keys(TABLE).sort((a, b) => {
99
+ const am = a.split("/")[1] ?? "";
100
+ return (b.split("/")[1] ?? "").length - am.length;
49
101
  });
50
102
  function lookupPrice(provider, model) {
51
- const normalizedProvider = normalizeProvider(provider);
52
- const normalizedModel = model.toLowerCase();
53
- for (const key of SORTED_KEYS) {
54
- const [tableProvider, tableModel] = key.split("/");
55
- if (tableProvider === normalizedProvider && normalizedModel.startsWith(tableModel)) {
56
- return TABLE[key];
57
- }
58
- }
59
- return void 0;
103
+ const normalizedProvider = normalizeProvider(provider);
104
+ const normalizedModel = model.toLowerCase();
105
+ for (const key of SORTED_KEYS) {
106
+ const [tableProvider, tableModel] = key.split("/");
107
+ if (tableProvider === normalizedProvider && normalizedModel.startsWith(tableModel)) return TABLE[key];
108
+ }
60
109
  }
61
110
  function priceCall(inputs) {
62
- const entry = lookupPrice(inputs.provider, inputs.model);
63
- if (!entry) {
64
- return { currency: "USD", input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0, source: "unknown" };
65
- }
66
- const cacheReadRate = entry.cacheReadPerMTok ?? entry.inputPerMTok * 0.1;
67
- const cacheWriteRate = entry.cacheWritePerMTok ?? entry.inputPerMTok * 1.25;
68
- const cacheRead = (inputs.cacheReadInputTokens ?? 0) / 1e6 * cacheReadRate;
69
- const cacheWrite = (inputs.cacheCreationInputTokens ?? 0) / 1e6 * cacheWriteRate;
70
- const billableInputTokens = Math.max(
71
- 0,
72
- (inputs.inputTokens ?? 0) - (inputs.cacheReadInputTokens ?? 0) - (inputs.cacheCreationInputTokens ?? 0)
73
- );
74
- const input = billableInputTokens / 1e6 * entry.inputPerMTok;
75
- const output = (inputs.outputTokens ?? 0) / 1e6 * entry.outputPerMTok;
76
- const total = input + output + cacheRead + cacheWrite;
77
- return { currency: "USD", input, output, cacheRead, cacheWrite, total, source: "table" };
111
+ const entry = lookupPrice(inputs.provider, inputs.model);
112
+ if (!entry) return {
113
+ currency: "USD",
114
+ input: 0,
115
+ output: 0,
116
+ cacheRead: 0,
117
+ cacheWrite: 0,
118
+ total: 0,
119
+ source: "unknown"
120
+ };
121
+ const cacheReadRate = entry.cacheReadPerMTok ?? entry.inputPerMTok * .1;
122
+ const cacheWriteRate = entry.cacheWritePerMTok ?? entry.inputPerMTok * 1.25;
123
+ const cacheRead = (inputs.cacheReadInputTokens ?? 0) / 1e6 * cacheReadRate;
124
+ const cacheWrite = (inputs.cacheCreationInputTokens ?? 0) / 1e6 * cacheWriteRate;
125
+ const input = Math.max(0, (inputs.inputTokens ?? 0) - (inputs.cacheReadInputTokens ?? 0) - (inputs.cacheCreationInputTokens ?? 0)) / 1e6 * entry.inputPerMTok;
126
+ const output = (inputs.outputTokens ?? 0) / 1e6 * entry.outputPerMTok;
127
+ return {
128
+ currency: "USD",
129
+ input,
130
+ output,
131
+ cacheRead,
132
+ cacheWrite,
133
+ total: input + output + cacheRead + cacheWrite,
134
+ source: "table"
135
+ };
78
136
  }
79
137
 
80
- // src/widget/genai/normalize.ts
138
+ //#endregion
139
+ //#region src/widget/genai/normalize.ts
81
140
  function str(v) {
82
- return typeof v === "string" ? v : void 0;
141
+ return typeof v === "string" ? v : void 0;
83
142
  }
84
143
  function num(v) {
85
- if (typeof v === "number") return v;
86
- if (typeof v === "string" && v !== "") {
87
- const n = Number(v);
88
- return Number.isFinite(n) ? n : void 0;
89
- }
90
- return void 0;
144
+ if (typeof v === "number") return v;
145
+ if (typeof v === "string" && v !== "") {
146
+ const n = Number(v);
147
+ return Number.isFinite(n) ? n : void 0;
148
+ }
91
149
  }
92
150
  function strArray(v) {
93
- if (Array.isArray(v) && v.every((x) => typeof x === "string")) return v;
94
- if (typeof v === "string") return [v];
95
- return void 0;
151
+ if (Array.isArray(v) && v.every((x) => typeof x === "string")) return v;
152
+ if (typeof v === "string") return [v];
96
153
  }
97
154
  function bool(v) {
98
- if (typeof v === "boolean") return v;
99
- if (v === "true") return true;
100
- if (v === "false") return false;
101
- return void 0;
155
+ if (typeof v === "boolean") return v;
156
+ if (v === "true") return true;
157
+ if (v === "false") return false;
102
158
  }
103
159
  function parseJson(v) {
104
- if (v == null) return void 0;
105
- if (typeof v === "object") return v;
106
- if (typeof v !== "string") return void 0;
107
- try {
108
- return JSON.parse(v);
109
- } catch {
110
- return void 0;
111
- }
160
+ if (v == null) return void 0;
161
+ if (typeof v === "object") return v;
162
+ if (typeof v !== "string") return void 0;
163
+ try {
164
+ return JSON.parse(v);
165
+ } catch {
166
+ return;
167
+ }
112
168
  }
113
169
  function normalizeMessageParts(raw) {
114
- if (Array.isArray(raw.parts)) {
115
- return raw.parts.map((p) => {
116
- const type = p.type ?? "text";
117
- if (type === "text") return { kind: "text", text: String(p.content ?? "") };
118
- if (type === "image") return { kind: "image", mediaType: "image/*", dataRef: String(p.content ?? "") };
119
- if (type === "audio") return { kind: "audio", mediaType: "audio/*", dataRef: String(p.content ?? "") };
120
- return { kind: "json", value: p.content };
121
- });
122
- }
123
- if (Array.isArray(raw.content)) {
124
- return raw.content.map((p) => {
125
- if (p.type === "text" || p.text !== void 0) {
126
- return { kind: "text", text: String(p.text ?? "") };
127
- }
128
- if (p.type === "image") {
129
- return { kind: "image", mediaType: p.mimeType ?? "image/*", dataRef: String(p.image ?? p.data ?? "") };
130
- }
131
- if (p.type === "audio") {
132
- return { kind: "audio", mediaType: p.mimeType ?? "audio/*", dataRef: String(p.data ?? "") };
133
- }
134
- return { kind: "json", value: p };
135
- });
136
- }
137
- if (typeof raw.content === "string") return [{ kind: "text", text: raw.content }];
138
- if (raw.content != null) return [{ kind: "json", value: raw.content }];
139
- return [];
170
+ if (Array.isArray(raw.parts)) return raw.parts.map((p) => {
171
+ const type = p.type ?? "text";
172
+ if (type === "text") return {
173
+ kind: "text",
174
+ text: String(p.content ?? "")
175
+ };
176
+ if (type === "image") return {
177
+ kind: "image",
178
+ mediaType: "image/*",
179
+ dataRef: String(p.content ?? "")
180
+ };
181
+ if (type === "audio") return {
182
+ kind: "audio",
183
+ mediaType: "audio/*",
184
+ dataRef: String(p.content ?? "")
185
+ };
186
+ return {
187
+ kind: "json",
188
+ value: p.content
189
+ };
190
+ });
191
+ if (Array.isArray(raw.content)) return raw.content.map((p) => {
192
+ if (p.type === "text" || p.text !== void 0) return {
193
+ kind: "text",
194
+ text: String(p.text ?? "")
195
+ };
196
+ if (p.type === "image") return {
197
+ kind: "image",
198
+ mediaType: p.mimeType ?? "image/*",
199
+ dataRef: String(p.image ?? p.data ?? "")
200
+ };
201
+ if (p.type === "audio") return {
202
+ kind: "audio",
203
+ mediaType: p.mimeType ?? "audio/*",
204
+ dataRef: String(p.data ?? "")
205
+ };
206
+ return {
207
+ kind: "json",
208
+ value: p
209
+ };
210
+ });
211
+ if (typeof raw.content === "string") return [{
212
+ kind: "text",
213
+ text: raw.content
214
+ }];
215
+ if (raw.content != null) return [{
216
+ kind: "json",
217
+ value: raw.content
218
+ }];
219
+ return [];
140
220
  }
141
221
  function normalizeMessage(raw) {
142
- const role = raw.role ?? "user";
143
- if (Array.isArray(raw.content)) {
144
- const content = raw.content;
145
- const hasToolPart = content.some(
146
- (p) => p.type === "tool-call" || p.type === "tool-result"
147
- );
148
- if (hasToolPart) {
149
- const toolCalls = [];
150
- const parts = [];
151
- const toolResults = [];
152
- for (const part of content) {
153
- if (part.type === "tool-call") {
154
- toolCalls.push({
155
- id: part.toolCallId,
156
- name: part.toolName ?? "",
157
- arguments: parseJson(part.input) ?? part.input ?? {}
158
- });
159
- } else if (part.type === "tool-result") {
160
- const out = part.output;
161
- const value = out && typeof out === "object" && "value" in out ? out.value : out;
162
- toolResults.push({ id: part.toolCallId, value });
163
- } else if (part.type === "text" || part.text !== void 0) {
164
- parts.push({ kind: "text", text: String(part.text ?? "") });
165
- }
166
- }
167
- if (toolResults.length > 1) {
168
- const msg3 = { role, parts: [] };
169
- msg3._toolResults = toolResults;
170
- return msg3;
171
- }
172
- const msg2 = { role, parts };
173
- if (toolCalls.length > 0) msg2.toolCalls = toolCalls;
174
- if (toolResults.length === 1) {
175
- msg2.toolCallId = toolResults[0].id;
176
- msg2.parts = [{ kind: "json", value: toolResults[0].value }];
177
- }
178
- if (raw.finish_reason) msg2.finishReason = raw.finish_reason;
179
- return msg2;
180
- }
181
- }
182
- const msg = { role, parts: normalizeMessageParts(raw) };
183
- if (Array.isArray(raw.tool_calls) && raw.tool_calls.length > 0) {
184
- msg.toolCalls = raw.tool_calls.map((tc) => ({
185
- id: tc.id,
186
- name: tc.function?.name ?? "",
187
- arguments: parseJson(tc.function?.arguments) ?? tc.function?.arguments ?? {},
188
- type: tc.type
189
- }));
190
- }
191
- if (raw.tool_call_id) msg.toolCallId = raw.tool_call_id;
192
- if (raw.finish_reason) msg.finishReason = raw.finish_reason;
193
- return msg;
222
+ const role = raw.role ?? "user";
223
+ if (Array.isArray(raw.content)) {
224
+ const content = raw.content;
225
+ if (content.some((p) => p.type === "tool-call" || p.type === "tool-result")) {
226
+ const toolCalls = [];
227
+ const parts = [];
228
+ const toolResults = [];
229
+ for (const part of content) if (part.type === "tool-call") toolCalls.push({
230
+ id: part.toolCallId,
231
+ name: part.toolName ?? "",
232
+ arguments: parseJson(part.input) ?? part.input ?? {}
233
+ });
234
+ else if (part.type === "tool-result") {
235
+ const out = part.output;
236
+ const value = out && typeof out === "object" && "value" in out ? out.value : out;
237
+ toolResults.push({
238
+ id: part.toolCallId,
239
+ value
240
+ });
241
+ } else if (part.type === "text" || part.text !== void 0) parts.push({
242
+ kind: "text",
243
+ text: String(part.text ?? "")
244
+ });
245
+ if (toolResults.length > 1) {
246
+ const msg = {
247
+ role,
248
+ parts: []
249
+ };
250
+ msg._toolResults = toolResults;
251
+ return msg;
252
+ }
253
+ const msg = {
254
+ role,
255
+ parts
256
+ };
257
+ if (toolCalls.length > 0) msg.toolCalls = toolCalls;
258
+ if (toolResults.length === 1) {
259
+ msg.toolCallId = toolResults[0].id;
260
+ msg.parts = [{
261
+ kind: "json",
262
+ value: toolResults[0].value
263
+ }];
264
+ }
265
+ if (raw.finish_reason) msg.finishReason = raw.finish_reason;
266
+ return msg;
267
+ }
268
+ }
269
+ const msg = {
270
+ role,
271
+ parts: normalizeMessageParts(raw)
272
+ };
273
+ if (Array.isArray(raw.tool_calls) && raw.tool_calls.length > 0) msg.toolCalls = raw.tool_calls.map((tc) => ({
274
+ id: tc.id,
275
+ name: tc.function?.name ?? "",
276
+ arguments: parseJson(tc.function?.arguments) ?? tc.function?.arguments ?? {},
277
+ type: tc.type
278
+ }));
279
+ if (raw.tool_call_id) msg.toolCallId = raw.tool_call_id;
280
+ if (raw.finish_reason) msg.finishReason = raw.finish_reason;
281
+ return msg;
194
282
  }
195
283
  function readMessagesAttribute(attrs, key) {
196
- const value = parseJson(attrs[key]);
197
- if (!Array.isArray(value)) return void 0;
198
- return value.map(normalizeMessage);
284
+ const value = parseJson(attrs[key]);
285
+ if (!Array.isArray(value)) return void 0;
286
+ return value.map(normalizeMessage);
199
287
  }
200
288
  function messagesFromEvents(events) {
201
- if (!events || events.length === 0) return [];
202
- const out = [];
203
- for (const ev of events) {
204
- const attrs = ev.attributes ?? {};
205
- if (ev.name === "gen_ai.choice") {
206
- const message = parseJson(attrs.message) ?? attrs.message;
207
- const finishReason = str(attrs.finish_reason);
208
- if (message) {
209
- const normalized = normalizeMessage(message);
210
- if (finishReason) normalized.finishReason = finishReason;
211
- out.push(normalized);
212
- }
213
- continue;
214
- }
215
- const m = ev.name.match(/^gen_ai\.(system|user|assistant|tool)\.message$/);
216
- if (!m) continue;
217
- const role = m[1];
218
- const content = attrs.content;
219
- const parsed = typeof content === "string" ? parseJson(content) ?? content : content;
220
- out.push(normalizeMessage({
221
- role,
222
- content: parsed,
223
- tool_calls: parseJson(attrs.tool_calls),
224
- tool_call_id: str(attrs.id) ?? str(attrs.tool_call_id)
225
- }));
226
- }
227
- return out;
289
+ if (!events || events.length === 0) return [];
290
+ const out = [];
291
+ for (const ev of events) {
292
+ const attrs = ev.attributes ?? {};
293
+ if (ev.name === "gen_ai.choice") {
294
+ const message = parseJson(attrs.message) ?? attrs.message;
295
+ const finishReason = str(attrs.finish_reason);
296
+ if (message) {
297
+ const normalized = normalizeMessage(message);
298
+ if (finishReason) normalized.finishReason = finishReason;
299
+ out.push(normalized);
300
+ }
301
+ continue;
302
+ }
303
+ const m = ev.name.match(/^gen_ai\.(system|user|assistant|tool)\.message$/);
304
+ if (!m) continue;
305
+ const role = m[1];
306
+ const content = attrs.content;
307
+ const parsed = typeof content === "string" ? parseJson(content) ?? content : content;
308
+ out.push(normalizeMessage({
309
+ role,
310
+ content: parsed,
311
+ tool_calls: parseJson(attrs.tool_calls),
312
+ tool_call_id: str(attrs.id) ?? str(attrs.tool_call_id)
313
+ }));
314
+ }
315
+ return out;
228
316
  }
229
317
  function readToolDefinitions(attrs) {
230
- const raw = parseJson(
231
- attrs["gen_ai.tool.definitions"] ?? attrs["gen_ai.orchestrator.agent.definitions"]
232
- );
233
- if (!Array.isArray(raw)) return void 0;
234
- return raw.filter((d) => typeof d.name === "string").map((d) => ({
235
- name: d.name,
236
- description: d.description,
237
- type: d.type,
238
- schema: d.schema ?? d.parameters
239
- }));
318
+ const raw = parseJson(attrs["gen_ai.tool.definitions"] ?? attrs["gen_ai.orchestrator.agent.definitions"]);
319
+ if (!Array.isArray(raw)) return void 0;
320
+ return raw.filter((d) => typeof d.name === "string").map((d) => ({
321
+ name: d.name,
322
+ description: d.description,
323
+ type: d.type,
324
+ schema: d.schema ?? d.parameters
325
+ }));
240
326
  }
241
327
  function readUsage(attrs) {
242
- const inputTokens = num(attrs["gen_ai.usage.input_tokens"]) ?? num(attrs["gen_ai.usage.prompt_tokens"]) ?? num(attrs["llm.usage.prompt_tokens"]) ?? num(attrs["ai.usage.inputTokens"]);
243
- const outputTokens = num(attrs["gen_ai.usage.output_tokens"]) ?? num(attrs["gen_ai.usage.completion_tokens"]) ?? num(attrs["llm.usage.completion_tokens"]) ?? num(attrs["ai.usage.outputTokens"]);
244
- return {
245
- inputTokens,
246
- outputTokens,
247
- reasoningOutputTokens: num(attrs["gen_ai.usage.reasoning.output_tokens"]),
248
- cacheReadInputTokens: num(attrs["gen_ai.usage.cache_read.input_tokens"]),
249
- cacheCreationInputTokens: num(attrs["gen_ai.usage.cache_creation.input_tokens"])
250
- };
328
+ return {
329
+ inputTokens: num(attrs["gen_ai.usage.input_tokens"]) ?? num(attrs["gen_ai.usage.prompt_tokens"]) ?? num(attrs["llm.usage.prompt_tokens"]) ?? num(attrs["ai.usage.inputTokens"]),
330
+ outputTokens: num(attrs["gen_ai.usage.output_tokens"]) ?? num(attrs["gen_ai.usage.completion_tokens"]) ?? num(attrs["llm.usage.completion_tokens"]) ?? num(attrs["ai.usage.outputTokens"]),
331
+ reasoningOutputTokens: num(attrs["gen_ai.usage.reasoning.output_tokens"]),
332
+ cacheReadInputTokens: num(attrs["gen_ai.usage.cache_read.input_tokens"]),
333
+ cacheCreationInputTokens: num(attrs["gen_ai.usage.cache_creation.input_tokens"])
334
+ };
251
335
  }
252
336
  function normalizeProviderName(raw) {
253
- const p = raw.toLowerCase();
254
- if (p === "az.ai.openai" || p === "azure_openai") return "openai";
255
- if (p === "gcp.vertex_ai" || p === "vertex_ai" || p === "gcp.gemini" || p === "google-gla" || // Logfire / Pydantic AI naming for Google GenAI library
256
- p === "google_genai" || p === "gemini") {
257
- return "google";
258
- }
259
- return p;
337
+ const p = raw.toLowerCase();
338
+ if (p === "az.ai.openai" || p === "azure_openai") return "openai";
339
+ if (p === "gcp.vertex_ai" || p === "vertex_ai" || p === "gcp.gemini" || p === "google-gla" || p === "google_genai" || p === "gemini") return "google";
340
+ return p;
260
341
  }
261
- var KNOWN_TOP_LEVEL_KEYS = /* @__PURE__ */ new Set([
262
- "gen_ai.system",
263
- "gen_ai.provider.name",
264
- "gen_ai.operation.name",
265
- "gen_ai.request.model",
266
- "gen_ai.response.model",
267
- "gen_ai.response.id",
268
- "gen_ai.response.finish_reasons",
269
- "gen_ai.request.temperature",
270
- "gen_ai.request.top_p",
271
- "gen_ai.request.top_k",
272
- "gen_ai.request.max_tokens",
273
- "gen_ai.request.stop_sequences",
274
- "gen_ai.request.seed",
275
- "gen_ai.request.frequency_penalty",
276
- "gen_ai.request.presence_penalty",
277
- "gen_ai.request.choice.count",
278
- "gen_ai.usage.input_tokens",
279
- "gen_ai.usage.output_tokens",
280
- "gen_ai.usage.prompt_tokens",
281
- "gen_ai.usage.completion_tokens",
282
- "gen_ai.usage.reasoning.output_tokens",
283
- "gen_ai.usage.cache_read.input_tokens",
284
- "gen_ai.usage.cache_creation.input_tokens",
285
- "gen_ai.input.messages",
286
- "gen_ai.output.messages",
287
- "gen_ai.input.messages.ref",
288
- "gen_ai.output.messages.ref",
289
- "gen_ai.system_instructions",
290
- "gen_ai.tool.definitions",
291
- "gen_ai.orchestrator.agent.definitions",
292
- "gen_ai.agent.id",
293
- "gen_ai.agent.name",
294
- "gen_ai.agent.description",
295
- "gen_ai.tool.name",
296
- "gen_ai.tool.call.id",
297
- "gen_ai.handoff.from_agent",
298
- "gen_ai.handoff.to_agent",
299
- "gen_ai.guardrail.name",
300
- "gen_ai.guardrail.triggered",
301
- "gen_ai.conversation.id",
302
- "gen_ai.evaluation.name",
303
- "gen_ai.evaluation.score.value",
304
- "gen_ai.evaluation.score.label",
305
- "gen_ai.evaluation.explanation",
306
- "gen_ai.audio.input.format",
307
- "gen_ai.audio.output.format",
308
- "gen_ai.speech.voice",
309
- "gen_ai.speech.input_text",
310
- "gen_ai.transcription.text",
311
- "gen_ai.embeddings.dimension.count",
312
- "gen_ai.openai.request.service_tier",
313
- "gen_ai.openai.response.service_tier",
314
- "gen_ai.openai.response.system_fingerprint",
315
- "gen_ai.openai.request.response_format",
316
- "openai.request.service_tier",
317
- "openai.response.service_tier",
318
- "openai.response.system_fingerprint",
319
- "openai.request.response_format"
342
+ const KNOWN_TOP_LEVEL_KEYS = new Set([
343
+ "gen_ai.system",
344
+ "gen_ai.provider.name",
345
+ "gen_ai.operation.name",
346
+ "gen_ai.request.model",
347
+ "gen_ai.response.model",
348
+ "gen_ai.response.id",
349
+ "gen_ai.response.finish_reasons",
350
+ "gen_ai.request.temperature",
351
+ "gen_ai.request.top_p",
352
+ "gen_ai.request.top_k",
353
+ "gen_ai.request.max_tokens",
354
+ "gen_ai.request.stop_sequences",
355
+ "gen_ai.request.seed",
356
+ "gen_ai.request.frequency_penalty",
357
+ "gen_ai.request.presence_penalty",
358
+ "gen_ai.request.choice.count",
359
+ "gen_ai.usage.input_tokens",
360
+ "gen_ai.usage.output_tokens",
361
+ "gen_ai.usage.prompt_tokens",
362
+ "gen_ai.usage.completion_tokens",
363
+ "gen_ai.usage.reasoning.output_tokens",
364
+ "gen_ai.usage.cache_read.input_tokens",
365
+ "gen_ai.usage.cache_creation.input_tokens",
366
+ "gen_ai.input.messages",
367
+ "gen_ai.output.messages",
368
+ "gen_ai.input.messages.ref",
369
+ "gen_ai.output.messages.ref",
370
+ "gen_ai.system_instructions",
371
+ "gen_ai.tool.definitions",
372
+ "gen_ai.orchestrator.agent.definitions",
373
+ "gen_ai.agent.id",
374
+ "gen_ai.agent.name",
375
+ "gen_ai.agent.description",
376
+ "gen_ai.tool.name",
377
+ "gen_ai.tool.call.id",
378
+ "gen_ai.handoff.from_agent",
379
+ "gen_ai.handoff.to_agent",
380
+ "gen_ai.guardrail.name",
381
+ "gen_ai.guardrail.triggered",
382
+ "gen_ai.conversation.id",
383
+ "gen_ai.evaluation.name",
384
+ "gen_ai.evaluation.score.value",
385
+ "gen_ai.evaluation.score.label",
386
+ "gen_ai.evaluation.explanation",
387
+ "gen_ai.audio.input.format",
388
+ "gen_ai.audio.output.format",
389
+ "gen_ai.speech.voice",
390
+ "gen_ai.speech.input_text",
391
+ "gen_ai.transcription.text",
392
+ "gen_ai.embeddings.dimension.count",
393
+ "gen_ai.openai.request.service_tier",
394
+ "gen_ai.openai.response.service_tier",
395
+ "gen_ai.openai.response.system_fingerprint",
396
+ "gen_ai.openai.request.response_format",
397
+ "openai.request.service_tier",
398
+ "openai.response.service_tier",
399
+ "openai.response.system_fingerprint",
400
+ "openai.request.response_format"
320
401
  ]);
321
402
  function toGenAiSpan(span) {
322
- const attrs = span.attributes ?? {};
323
- const rawProvider = str(attrs["gen_ai.provider.name"]) ?? str(attrs["gen_ai.system"]) ?? // Vercel AI SDK wrapper spans expose only `ai.model.provider`.
324
- str(attrs["ai.model.provider"]) ?? "unknown";
325
- const provider = normalizeProviderName(rawProvider);
326
- const operation = str(attrs["gen_ai.operation.name"]) ?? "chat";
327
- const requestModel = str(attrs["gen_ai.request.model"]) ?? str(attrs["llm.request.model"]) ?? // Pydantic AI's `agent run` parent span carries `model_name` but not
328
- // `gen_ai.request.model`. Same pattern for any host-language convention
329
- // that mirrors gen_ai.* loosely.
330
- str(attrs["model_name"]) ?? str(attrs["ai.model.id"]) ?? "unknown";
331
- const responseModel = str(attrs["gen_ai.response.model"]) ?? str(attrs["llm.response.model"]) ?? str(attrs["ai.response.model"]);
332
- const inputMessages = readMessagesAttribute(attrs, "gen_ai.input.messages") ?? [];
333
- const outputMessages = readMessagesAttribute(attrs, "gen_ai.output.messages") ?? [];
334
- let systemInstructions = [];
335
- const rawSystem = parseJson(attrs["gen_ai.system_instructions"]);
336
- if (Array.isArray(rawSystem) && rawSystem.length > 0) {
337
- const first = rawSystem[0];
338
- if (first && typeof first === "object" && "role" in first) {
339
- systemInstructions = rawSystem.map((m) => normalizeMessage(m));
340
- } else {
341
- const parts = rawSystem.map(
342
- (p) => p.type === "text" || p.content !== void 0 ? { kind: "text", text: String(p.content ?? "") } : { kind: "json", value: p }
343
- );
344
- systemInstructions = [{ role: "system", parts }];
345
- }
346
- }
347
- let messages = inputMessages.length || outputMessages.length || systemInstructions.length ? [...systemInstructions, ...inputMessages, ...outputMessages] : messagesFromEvents(span.events);
348
- const inputRef = str(attrs["gen_ai.input.messages.ref"]);
349
- const outputRef = str(attrs["gen_ai.output.messages.ref"]);
350
- const hasInputContent = messages.some((m) => m.role === "system" || m.role === "user");
351
- const hasOutputContent = messages.some((m) => m.role === "assistant");
352
- if (inputRef && !hasInputContent) {
353
- messages.push({ role: "user", parts: [{ kind: "ref", ref: inputRef, direction: "input" }] });
354
- }
355
- if (outputRef && !hasOutputContent) {
356
- messages.push({ role: "assistant", parts: [{ kind: "ref", ref: outputRef, direction: "output" }] });
357
- }
358
- if (messages.length === 0) {
359
- const aiPrompt = parseJson(attrs["ai.prompt.messages"]);
360
- if (Array.isArray(aiPrompt)) {
361
- messages.push(...aiPrompt.map(normalizeMessage));
362
- } else {
363
- const aiPromptBlob = parseJson(attrs["ai.prompt"]);
364
- if (aiPromptBlob) {
365
- if (Array.isArray(aiPromptBlob.messages)) {
366
- messages.push(...aiPromptBlob.messages.map(normalizeMessage));
367
- } else {
368
- if (aiPromptBlob.system) {
369
- messages.push({ role: "system", parts: [{ kind: "text", text: aiPromptBlob.system }] });
370
- }
371
- if (aiPromptBlob.prompt) {
372
- messages.push({ role: "user", parts: [{ kind: "text", text: aiPromptBlob.prompt }] });
373
- }
374
- }
375
- }
376
- }
377
- const aiResponseToolCalls = parseJson(
378
- attrs["ai.response.toolCalls"]
379
- );
380
- const assistantToolCalls = Array.isArray(aiResponseToolCalls) ? aiResponseToolCalls.filter((c) => typeof c.toolName === "string").map((c) => ({
381
- id: c.toolCallId,
382
- name: c.toolName,
383
- arguments: parseJson(c.input ?? c.args) ?? c.input ?? c.args ?? {}
384
- })) : void 0;
385
- const aiResponseText = str(attrs["ai.response.text"]);
386
- if (aiResponseText || assistantToolCalls && assistantToolCalls.length > 0) {
387
- const finishReason = strArray(attrs["gen_ai.response.finish_reasons"])?.[0] ?? str(attrs["ai.response.finishReason"]);
388
- const msg = normalizeMessage({ role: "assistant", content: aiResponseText ?? "" });
389
- if (finishReason) msg.finishReason = finishReason;
390
- if (assistantToolCalls && assistantToolCalls.length > 0) msg.toolCalls = assistantToolCalls;
391
- messages.push(msg);
392
- }
393
- }
394
- if (messages.length === 0) {
395
- const pydanticMessages = parseJson(attrs["pydantic_ai.all_messages"]);
396
- if (Array.isArray(pydanticMessages)) {
397
- messages.push(...pydanticMessages.map(normalizeMessage));
398
- }
399
- }
400
- if (messages.length === 0) {
401
- const legacy = [];
402
- for (let i = 0; i < 32; i++) {
403
- const role = str(attrs[`gen_ai.prompt.${i}.role`]) ?? str(attrs[`llm.prompts.${i}.role`]);
404
- const content = attrs[`gen_ai.prompt.${i}.content`] ?? attrs[`llm.prompts.${i}.content`];
405
- if (!role) break;
406
- legacy.push(normalizeMessage({ role, content }));
407
- }
408
- for (let i = 0; i < 32; i++) {
409
- const role = str(attrs[`gen_ai.completion.${i}.role`]) ?? str(attrs[`llm.completions.${i}.role`]);
410
- const content = attrs[`gen_ai.completion.${i}.content`] ?? attrs[`llm.completions.${i}.content`];
411
- const finishReason = str(attrs[`gen_ai.completion.${i}.finish_reason`]);
412
- if (!role) break;
413
- const msg = normalizeMessage({ role, content });
414
- if (finishReason) msg.finishReason = finishReason;
415
- legacy.push(msg);
416
- }
417
- if (legacy.length > 0) messages = legacy;
418
- }
419
- messages = messages.flatMap((m) => {
420
- const bundled = m._toolResults;
421
- if (!bundled) return [m];
422
- return bundled.map((r) => ({
423
- role: "tool",
424
- parts: [{ kind: "json", value: r.value }],
425
- toolCallId: r.id
426
- }));
427
- });
428
- const toolCalls = [];
429
- for (const m of messages) if (m.toolCalls) toolCalls.push(...m.toolCalls);
430
- if (toolCalls.length > 0) {
431
- const callsById = /* @__PURE__ */ new Map();
432
- for (const tc of toolCalls) if (tc.id) callsById.set(tc.id, tc);
433
- for (const m of messages) {
434
- if (m.role !== "tool" || !m.toolCallId) continue;
435
- const target = callsById.get(m.toolCallId);
436
- if (!target || target.result !== void 0) continue;
437
- const textPart = m.parts.find((p) => p.kind === "text");
438
- const jsonPart = m.parts.find((p) => p.kind === "json");
439
- if (textPart && textPart.kind === "text") {
440
- target.result = parseJson(textPart.text) ?? textPart.text;
441
- } else if (jsonPart && jsonPart.kind === "json") {
442
- target.result = jsonPart.value;
443
- }
444
- }
445
- }
446
- const usage = readUsage(attrs);
447
- const cost = priceCall({
448
- provider,
449
- model: responseModel ?? requestModel,
450
- inputTokens: usage.inputTokens,
451
- outputTokens: usage.outputTokens,
452
- cacheReadInputTokens: usage.cacheReadInputTokens,
453
- cacheCreationInputTokens: usage.cacheCreationInputTokens
454
- });
455
- const finishReasons = strArray(attrs["gen_ai.response.finish_reasons"]);
456
- const agentName = str(attrs["gen_ai.agent.name"]);
457
- const agentId = str(attrs["gen_ai.agent.id"]);
458
- const agentDescription = str(attrs["gen_ai.agent.description"]);
459
- const toolName = str(attrs["gen_ai.tool.name"]);
460
- const toolCallId = str(attrs["gen_ai.tool.call.id"]);
461
- const handoffFrom = str(attrs["gen_ai.handoff.from_agent"]);
462
- const handoffTo = str(attrs["gen_ai.handoff.to_agent"]);
463
- const guardrailName = str(attrs["gen_ai.guardrail.name"]);
464
- const guardrailTriggered = bool(attrs["gen_ai.guardrail.triggered"]);
465
- const evalName = str(attrs["gen_ai.evaluation.name"]);
466
- const evalScoreValue = num(attrs["gen_ai.evaluation.score.value"]);
467
- const evalScoreLabel = str(attrs["gen_ai.evaluation.score.label"]);
468
- const evalExplanation = str(attrs["gen_ai.evaluation.explanation"]);
469
- const audioIn = str(attrs["gen_ai.audio.input.format"]);
470
- const audioOut = str(attrs["gen_ai.audio.output.format"]);
471
- const speechVoice = str(attrs["gen_ai.speech.voice"]);
472
- const speechInputText = str(attrs["gen_ai.speech.input_text"]);
473
- const transcriptionText = str(attrs["gen_ai.transcription.text"]);
474
- const embeddingDims = num(attrs["gen_ai.embeddings.dimension.count"]);
475
- const raw = {};
476
- for (const [k, v] of Object.entries(attrs)) {
477
- if (KNOWN_TOP_LEVEL_KEYS.has(k)) continue;
478
- if (k.startsWith("gen_ai.prompt.") || k.startsWith("gen_ai.completion.")) continue;
479
- if (k.startsWith("llm.prompts.") || k.startsWith("llm.completions.")) continue;
480
- raw[k] = v;
481
- }
482
- return {
483
- traceId: span.traceId,
484
- spanId: span.spanId,
485
- parentSpanId: span.parentSpanId,
486
- name: span.name,
487
- startMs: span.startTime,
488
- endMs: span.endTime,
489
- status: span.status?.code === "OK" ? "ok" : span.status?.code === "ERROR" ? "error" : "unset",
490
- errorMessage: span.status?.message,
491
- provider,
492
- operation,
493
- requestModel,
494
- responseModel,
495
- params: {
496
- temperature: num(attrs["gen_ai.request.temperature"]),
497
- topP: num(attrs["gen_ai.request.top_p"]),
498
- topK: num(attrs["gen_ai.request.top_k"]),
499
- maxTokens: num(attrs["gen_ai.request.max_tokens"]),
500
- stopSequences: strArray(attrs["gen_ai.request.stop_sequences"]),
501
- seed: num(attrs["gen_ai.request.seed"]),
502
- frequencyPenalty: num(attrs["gen_ai.request.frequency_penalty"]),
503
- presencePenalty: num(attrs["gen_ai.request.presence_penalty"]),
504
- choiceCount: num(attrs["gen_ai.request.choice.count"])
505
- },
506
- messages,
507
- toolDefinitions: readToolDefinitions(attrs),
508
- toolCalls,
509
- usage,
510
- cost,
511
- finishReasons,
512
- responseId: str(attrs["gen_ai.response.id"]),
513
- agent: agentId || agentName || agentDescription ? { id: agentId, name: agentName, description: agentDescription } : void 0,
514
- tool: toolName || toolCallId ? { name: toolName, callId: toolCallId } : void 0,
515
- handoff: handoffFrom || handoffTo ? { fromAgent: handoffFrom, toAgent: handoffTo } : void 0,
516
- guardrail: guardrailName || guardrailTriggered !== void 0 ? { name: guardrailName, triggered: guardrailTriggered } : void 0,
517
- conversationId: str(attrs["gen_ai.conversation.id"]),
518
- evaluation: evalName || evalScoreValue !== void 0 || evalScoreLabel || evalExplanation ? {
519
- name: evalName,
520
- scoreValue: evalScoreValue,
521
- scoreLabel: evalScoreLabel,
522
- explanation: evalExplanation
523
- } : void 0,
524
- modality: audioIn || audioOut || speechVoice || speechInputText || transcriptionText || embeddingDims ? {
525
- audioInputFormat: audioIn,
526
- audioOutputFormat: audioOut,
527
- speechVoice,
528
- speechInputText,
529
- transcriptionText,
530
- embeddingDimensions: embeddingDims
531
- } : void 0,
532
- extras: {
533
- openaiServiceTier: str(attrs["gen_ai.openai.request.service_tier"]) || str(attrs["gen_ai.openai.response.service_tier"]) || str(attrs["openai.request.service_tier"]) || str(attrs["openai.response.service_tier"]) ? {
534
- request: str(attrs["gen_ai.openai.request.service_tier"]) ?? str(attrs["openai.request.service_tier"]),
535
- response: str(attrs["gen_ai.openai.response.service_tier"]) ?? str(attrs["openai.response.service_tier"])
536
- } : void 0,
537
- openaiSystemFingerprint: str(attrs["gen_ai.openai.response.system_fingerprint"]) ?? str(attrs["openai.response.system_fingerprint"]),
538
- openaiResponseFormat: str(attrs["gen_ai.openai.request.response_format"]) ?? str(attrs["openai.request.response_format"]),
539
- raw
540
- }
541
- };
403
+ const attrs = span.attributes ?? {};
404
+ const provider = normalizeProviderName(str(attrs["gen_ai.provider.name"]) ?? str(attrs["gen_ai.system"]) ?? str(attrs["ai.model.provider"]) ?? "unknown");
405
+ const operation = str(attrs["gen_ai.operation.name"]) ?? "chat";
406
+ const requestModel = str(attrs["gen_ai.request.model"]) ?? str(attrs["llm.request.model"]) ?? str(attrs["model_name"]) ?? str(attrs["ai.model.id"]) ?? "unknown";
407
+ const responseModel = str(attrs["gen_ai.response.model"]) ?? str(attrs["llm.response.model"]) ?? str(attrs["ai.response.model"]);
408
+ const inputMessages = readMessagesAttribute(attrs, "gen_ai.input.messages") ?? [];
409
+ const outputMessages = readMessagesAttribute(attrs, "gen_ai.output.messages") ?? [];
410
+ let systemInstructions = [];
411
+ const rawSystem = parseJson(attrs["gen_ai.system_instructions"]);
412
+ if (Array.isArray(rawSystem) && rawSystem.length > 0) {
413
+ const first = rawSystem[0];
414
+ if (first && typeof first === "object" && "role" in first) systemInstructions = rawSystem.map((m) => normalizeMessage(m));
415
+ else systemInstructions = [{
416
+ role: "system",
417
+ parts: rawSystem.map((p) => p.type === "text" || p.content !== void 0 ? {
418
+ kind: "text",
419
+ text: String(p.content ?? "")
420
+ } : {
421
+ kind: "json",
422
+ value: p
423
+ })
424
+ }];
425
+ }
426
+ let messages = inputMessages.length || outputMessages.length || systemInstructions.length ? [
427
+ ...systemInstructions,
428
+ ...inputMessages,
429
+ ...outputMessages
430
+ ] : messagesFromEvents(span.events);
431
+ const inputRef = str(attrs["gen_ai.input.messages.ref"]);
432
+ const outputRef = str(attrs["gen_ai.output.messages.ref"]);
433
+ const hasInputContent = messages.some((m) => m.role === "system" || m.role === "user");
434
+ const hasOutputContent = messages.some((m) => m.role === "assistant");
435
+ if (inputRef && !hasInputContent) messages.push({
436
+ role: "user",
437
+ parts: [{
438
+ kind: "ref",
439
+ ref: inputRef,
440
+ direction: "input"
441
+ }]
442
+ });
443
+ if (outputRef && !hasOutputContent) messages.push({
444
+ role: "assistant",
445
+ parts: [{
446
+ kind: "ref",
447
+ ref: outputRef,
448
+ direction: "output"
449
+ }]
450
+ });
451
+ if (messages.length === 0) {
452
+ const aiPrompt = parseJson(attrs["ai.prompt.messages"]);
453
+ if (Array.isArray(aiPrompt)) messages.push(...aiPrompt.map(normalizeMessage));
454
+ else {
455
+ const aiPromptBlob = parseJson(attrs["ai.prompt"]);
456
+ if (aiPromptBlob) if (Array.isArray(aiPromptBlob.messages)) messages.push(...aiPromptBlob.messages.map(normalizeMessage));
457
+ else {
458
+ if (aiPromptBlob.system) messages.push({
459
+ role: "system",
460
+ parts: [{
461
+ kind: "text",
462
+ text: aiPromptBlob.system
463
+ }]
464
+ });
465
+ if (aiPromptBlob.prompt) messages.push({
466
+ role: "user",
467
+ parts: [{
468
+ kind: "text",
469
+ text: aiPromptBlob.prompt
470
+ }]
471
+ });
472
+ }
473
+ }
474
+ const aiResponseToolCalls = parseJson(attrs["ai.response.toolCalls"]);
475
+ const assistantToolCalls = Array.isArray(aiResponseToolCalls) ? aiResponseToolCalls.filter((c) => typeof c.toolName === "string").map((c) => ({
476
+ id: c.toolCallId,
477
+ name: c.toolName,
478
+ arguments: parseJson(c.input ?? c.args) ?? c.input ?? c.args ?? {}
479
+ })) : void 0;
480
+ const aiResponseText = str(attrs["ai.response.text"]);
481
+ if (aiResponseText || assistantToolCalls && assistantToolCalls.length > 0) {
482
+ const finishReason = strArray(attrs["gen_ai.response.finish_reasons"])?.[0] ?? str(attrs["ai.response.finishReason"]);
483
+ const msg = normalizeMessage({
484
+ role: "assistant",
485
+ content: aiResponseText ?? ""
486
+ });
487
+ if (finishReason) msg.finishReason = finishReason;
488
+ if (assistantToolCalls && assistantToolCalls.length > 0) msg.toolCalls = assistantToolCalls;
489
+ messages.push(msg);
490
+ }
491
+ }
492
+ if (messages.length === 0) {
493
+ const pydanticMessages = parseJson(attrs["pydantic_ai.all_messages"]);
494
+ if (Array.isArray(pydanticMessages)) messages.push(...pydanticMessages.map(normalizeMessage));
495
+ }
496
+ if (messages.length === 0) {
497
+ const legacy = [];
498
+ for (let i = 0; i < 32; i++) {
499
+ const role = str(attrs[`gen_ai.prompt.${i}.role`]) ?? str(attrs[`llm.prompts.${i}.role`]);
500
+ const content = attrs[`gen_ai.prompt.${i}.content`] ?? attrs[`llm.prompts.${i}.content`];
501
+ if (!role) break;
502
+ legacy.push(normalizeMessage({
503
+ role,
504
+ content
505
+ }));
506
+ }
507
+ for (let i = 0; i < 32; i++) {
508
+ const role = str(attrs[`gen_ai.completion.${i}.role`]) ?? str(attrs[`llm.completions.${i}.role`]);
509
+ const content = attrs[`gen_ai.completion.${i}.content`] ?? attrs[`llm.completions.${i}.content`];
510
+ const finishReason = str(attrs[`gen_ai.completion.${i}.finish_reason`]);
511
+ if (!role) break;
512
+ const msg = normalizeMessage({
513
+ role,
514
+ content
515
+ });
516
+ if (finishReason) msg.finishReason = finishReason;
517
+ legacy.push(msg);
518
+ }
519
+ if (legacy.length > 0) messages = legacy;
520
+ }
521
+ messages = messages.flatMap((m) => {
522
+ const bundled = m._toolResults;
523
+ if (!bundled) return [m];
524
+ return bundled.map((r) => ({
525
+ role: "tool",
526
+ parts: [{
527
+ kind: "json",
528
+ value: r.value
529
+ }],
530
+ toolCallId: r.id
531
+ }));
532
+ });
533
+ const toolCalls = [];
534
+ for (const m of messages) if (m.toolCalls) toolCalls.push(...m.toolCalls);
535
+ if (toolCalls.length > 0) {
536
+ const callsById = /* @__PURE__ */ new Map();
537
+ for (const tc of toolCalls) if (tc.id) callsById.set(tc.id, tc);
538
+ for (const m of messages) {
539
+ if (m.role !== "tool" || !m.toolCallId) continue;
540
+ const target = callsById.get(m.toolCallId);
541
+ if (!target || target.result !== void 0) continue;
542
+ const textPart = m.parts.find((p) => p.kind === "text");
543
+ const jsonPart = m.parts.find((p) => p.kind === "json");
544
+ if (textPart && textPart.kind === "text") target.result = parseJson(textPart.text) ?? textPart.text;
545
+ else if (jsonPart && jsonPart.kind === "json") target.result = jsonPart.value;
546
+ }
547
+ }
548
+ const usage = readUsage(attrs);
549
+ const cost = priceCall({
550
+ provider,
551
+ model: responseModel ?? requestModel,
552
+ inputTokens: usage.inputTokens,
553
+ outputTokens: usage.outputTokens,
554
+ cacheReadInputTokens: usage.cacheReadInputTokens,
555
+ cacheCreationInputTokens: usage.cacheCreationInputTokens
556
+ });
557
+ const finishReasons = strArray(attrs["gen_ai.response.finish_reasons"]);
558
+ const agentName = str(attrs["gen_ai.agent.name"]);
559
+ const agentId = str(attrs["gen_ai.agent.id"]);
560
+ const agentDescription = str(attrs["gen_ai.agent.description"]);
561
+ const toolName = str(attrs["gen_ai.tool.name"]);
562
+ const toolCallId = str(attrs["gen_ai.tool.call.id"]);
563
+ const handoffFrom = str(attrs["gen_ai.handoff.from_agent"]);
564
+ const handoffTo = str(attrs["gen_ai.handoff.to_agent"]);
565
+ const guardrailName = str(attrs["gen_ai.guardrail.name"]);
566
+ const guardrailTriggered = bool(attrs["gen_ai.guardrail.triggered"]);
567
+ const evalName = str(attrs["gen_ai.evaluation.name"]);
568
+ const evalScoreValue = num(attrs["gen_ai.evaluation.score.value"]);
569
+ const evalScoreLabel = str(attrs["gen_ai.evaluation.score.label"]);
570
+ const evalExplanation = str(attrs["gen_ai.evaluation.explanation"]);
571
+ const audioIn = str(attrs["gen_ai.audio.input.format"]);
572
+ const audioOut = str(attrs["gen_ai.audio.output.format"]);
573
+ const speechVoice = str(attrs["gen_ai.speech.voice"]);
574
+ const speechInputText = str(attrs["gen_ai.speech.input_text"]);
575
+ const transcriptionText = str(attrs["gen_ai.transcription.text"]);
576
+ const embeddingDims = num(attrs["gen_ai.embeddings.dimension.count"]);
577
+ const raw = {};
578
+ for (const [k, v] of Object.entries(attrs)) {
579
+ if (KNOWN_TOP_LEVEL_KEYS.has(k)) continue;
580
+ if (k.startsWith("gen_ai.prompt.") || k.startsWith("gen_ai.completion.")) continue;
581
+ if (k.startsWith("llm.prompts.") || k.startsWith("llm.completions.")) continue;
582
+ raw[k] = v;
583
+ }
584
+ return {
585
+ traceId: span.traceId,
586
+ spanId: span.spanId,
587
+ parentSpanId: span.parentSpanId,
588
+ name: span.name,
589
+ startMs: span.startTime,
590
+ endMs: span.endTime,
591
+ status: span.status?.code === "OK" ? "ok" : span.status?.code === "ERROR" ? "error" : "unset",
592
+ errorMessage: span.status?.message,
593
+ provider,
594
+ operation,
595
+ requestModel,
596
+ responseModel,
597
+ params: {
598
+ temperature: num(attrs["gen_ai.request.temperature"]),
599
+ topP: num(attrs["gen_ai.request.top_p"]),
600
+ topK: num(attrs["gen_ai.request.top_k"]),
601
+ maxTokens: num(attrs["gen_ai.request.max_tokens"]),
602
+ stopSequences: strArray(attrs["gen_ai.request.stop_sequences"]),
603
+ seed: num(attrs["gen_ai.request.seed"]),
604
+ frequencyPenalty: num(attrs["gen_ai.request.frequency_penalty"]),
605
+ presencePenalty: num(attrs["gen_ai.request.presence_penalty"]),
606
+ choiceCount: num(attrs["gen_ai.request.choice.count"])
607
+ },
608
+ messages,
609
+ toolDefinitions: readToolDefinitions(attrs),
610
+ toolCalls,
611
+ usage,
612
+ cost,
613
+ finishReasons,
614
+ responseId: str(attrs["gen_ai.response.id"]),
615
+ agent: agentId || agentName || agentDescription ? {
616
+ id: agentId,
617
+ name: agentName,
618
+ description: agentDescription
619
+ } : void 0,
620
+ tool: toolName || toolCallId ? {
621
+ name: toolName,
622
+ callId: toolCallId
623
+ } : void 0,
624
+ handoff: handoffFrom || handoffTo ? {
625
+ fromAgent: handoffFrom,
626
+ toAgent: handoffTo
627
+ } : void 0,
628
+ guardrail: guardrailName || guardrailTriggered !== void 0 ? {
629
+ name: guardrailName,
630
+ triggered: guardrailTriggered
631
+ } : void 0,
632
+ conversationId: str(attrs["gen_ai.conversation.id"]),
633
+ evaluation: evalName || evalScoreValue !== void 0 || evalScoreLabel || evalExplanation ? {
634
+ name: evalName,
635
+ scoreValue: evalScoreValue,
636
+ scoreLabel: evalScoreLabel,
637
+ explanation: evalExplanation
638
+ } : void 0,
639
+ modality: audioIn || audioOut || speechVoice || speechInputText || transcriptionText || embeddingDims ? {
640
+ audioInputFormat: audioIn,
641
+ audioOutputFormat: audioOut,
642
+ speechVoice,
643
+ speechInputText,
644
+ transcriptionText,
645
+ embeddingDimensions: embeddingDims
646
+ } : void 0,
647
+ extras: {
648
+ openaiServiceTier: str(attrs["gen_ai.openai.request.service_tier"]) || str(attrs["gen_ai.openai.response.service_tier"]) || str(attrs["openai.request.service_tier"]) || str(attrs["openai.response.service_tier"]) ? {
649
+ request: str(attrs["gen_ai.openai.request.service_tier"]) ?? str(attrs["openai.request.service_tier"]),
650
+ response: str(attrs["gen_ai.openai.response.service_tier"]) ?? str(attrs["openai.response.service_tier"])
651
+ } : void 0,
652
+ openaiSystemFingerprint: str(attrs["gen_ai.openai.response.system_fingerprint"]) ?? str(attrs["openai.response.system_fingerprint"]),
653
+ openaiResponseFormat: str(attrs["gen_ai.openai.request.response_format"]) ?? str(attrs["openai.request.response_format"]),
654
+ raw
655
+ }
656
+ };
542
657
  }
543
658
 
544
- // src/widget/genai/stitch.ts
659
+ //#endregion
660
+ //#region src/widget/genai/stitch.ts
545
661
  function buildToolResultIndex(spans) {
546
- const index = /* @__PURE__ */ new Map();
547
- for (const span of spans) {
548
- const attrs = span.attributes ?? {};
549
- const id = attrs["ai.toolCall.id"];
550
- if (typeof id !== "string") continue;
551
- const raw = attrs["ai.toolCall.result"];
552
- if (raw == null) continue;
553
- if (typeof raw === "string") {
554
- try {
555
- index.set(id, JSON.parse(raw));
556
- } catch {
557
- index.set(id, raw);
558
- }
559
- } else {
560
- index.set(id, raw);
561
- }
562
- }
563
- return index;
662
+ const index = /* @__PURE__ */ new Map();
663
+ for (const span of spans) {
664
+ const attrs = span.attributes ?? {};
665
+ const id = attrs["ai.toolCall.id"];
666
+ if (typeof id !== "string") continue;
667
+ const raw = attrs["ai.toolCall.result"];
668
+ if (raw == null) continue;
669
+ if (typeof raw === "string") try {
670
+ index.set(id, JSON.parse(raw));
671
+ } catch {
672
+ index.set(id, raw);
673
+ }
674
+ else index.set(id, raw);
675
+ }
676
+ return index;
564
677
  }
565
678
  function hydrateToolResults(genAiSpan, index) {
566
- if (index.size === 0) return;
567
- for (const call of genAiSpan.toolCalls) {
568
- if (call.result !== void 0) continue;
569
- if (!call.id) continue;
570
- const result = index.get(call.id);
571
- if (result !== void 0) call.result = result;
572
- }
573
- for (const msg of genAiSpan.messages) {
574
- if (!msg.toolCalls) continue;
575
- for (const call of msg.toolCalls) {
576
- if (call.result !== void 0) continue;
577
- if (!call.id) continue;
578
- const result = index.get(call.id);
579
- if (result !== void 0) call.result = result;
580
- }
581
- }
679
+ if (index.size === 0) return;
680
+ for (const call of genAiSpan.toolCalls) {
681
+ if (call.result !== void 0) continue;
682
+ if (!call.id) continue;
683
+ const result = index.get(call.id);
684
+ if (result !== void 0) call.result = result;
685
+ }
686
+ for (const msg of genAiSpan.messages) {
687
+ if (!msg.toolCalls) continue;
688
+ for (const call of msg.toolCalls) {
689
+ if (call.result !== void 0) continue;
690
+ if (!call.id) continue;
691
+ const result = index.get(call.id);
692
+ if (result !== void 0) call.result = result;
693
+ }
694
+ }
582
695
  }
583
696
 
697
+ //#endregion
584
698
  exports.buildToolResultIndex = buildToolResultIndex;
585
699
  exports.hydrateToolResults = hydrateToolResults;
586
700
  exports.isGenAiSpan = isGenAiSpan;
587
701
  exports.lookupPrice = lookupPrice;
588
702
  exports.priceCall = priceCall;
589
703
  exports.toGenAiSpan = toGenAiSpan;
590
- //# sourceMappingURL=index.cjs.map
591
704
  //# sourceMappingURL=index.cjs.map