@ai-sdk/otel 0.0.1-beta.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/dist/index.js ADDED
@@ -0,0 +1,868 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ OpenTelemetryIntegration: () => OpenTelemetryIntegration
24
+ });
25
+ module.exports = __toCommonJS(index_exports);
26
+
27
+ // src/open-telemetry-integration.ts
28
+ var import_api = require("@opentelemetry/api");
29
+
30
+ // src/assemble-operation-name.ts
31
+ function assembleOperationName({
32
+ operationId,
33
+ telemetry
34
+ }) {
35
+ return {
36
+ // standardized operation and resource name:
37
+ "operation.name": `${operationId}${(telemetry == null ? void 0 : telemetry.functionId) != null ? ` ${telemetry.functionId}` : ""}`,
38
+ "resource.name": telemetry == null ? void 0 : telemetry.functionId,
39
+ // detailed, AI SDK specific data:
40
+ "ai.operationId": operationId,
41
+ "ai.telemetry.functionId": telemetry == null ? void 0 : telemetry.functionId
42
+ };
43
+ }
44
+
45
+ // src/get-base-telemetry-attributes.ts
46
+ function getBaseTelemetryAttributes({
47
+ model,
48
+ settings,
49
+ telemetry,
50
+ headers
51
+ }) {
52
+ var _a;
53
+ return {
54
+ "ai.model.provider": model.provider,
55
+ "ai.model.id": model.modelId,
56
+ // settings:
57
+ ...Object.entries(settings).reduce((attributes, [key, value]) => {
58
+ attributes[`ai.settings.${key}`] = value;
59
+ return attributes;
60
+ }, {}),
61
+ // add metadata as attributes:
62
+ ...Object.entries((_a = telemetry == null ? void 0 : telemetry.metadata) != null ? _a : {}).reduce(
63
+ (attributes, [key, value]) => {
64
+ if (value != void 0) {
65
+ attributes[`ai.telemetry.metadata.${key}`] = value;
66
+ }
67
+ return attributes;
68
+ },
69
+ {}
70
+ ),
71
+ // request headers
72
+ ...Object.entries(headers != null ? headers : {}).reduce((attributes, [key, value]) => {
73
+ if (value !== void 0) {
74
+ attributes[`ai.request.headers.${key}`] = value;
75
+ }
76
+ return attributes;
77
+ }, {})
78
+ };
79
+ }
80
+
81
+ // src/stringify-for-telemetry.ts
82
+ var import_ai = require("ai");
83
+ function stringifyForTelemetry(prompt) {
84
+ return JSON.stringify(
85
+ prompt.map((message) => ({
86
+ ...message,
87
+ content: typeof message.content === "string" ? message.content : message.content.map(
88
+ (part) => part.type === "file" ? {
89
+ ...part,
90
+ data: part.data instanceof Uint8Array ? (0, import_ai.convertDataContentToBase64String)(part.data) : part.data
91
+ } : part
92
+ )
93
+ }))
94
+ );
95
+ }
96
+
97
+ // src/open-telemetry-integration.ts
98
+ function recordSpanError(span, error) {
99
+ if (error instanceof Error) {
100
+ span.recordException({
101
+ name: error.name,
102
+ message: error.message,
103
+ stack: error.stack
104
+ });
105
+ span.setStatus({
106
+ code: import_api.SpanStatusCode.ERROR,
107
+ message: error.message
108
+ });
109
+ } else {
110
+ span.setStatus({ code: import_api.SpanStatusCode.ERROR });
111
+ }
112
+ }
113
+ function shouldRecord(telemetry) {
114
+ return (telemetry == null ? void 0 : telemetry.isEnabled) === true;
115
+ }
116
+ function selectAttributes(telemetry, attributes) {
117
+ if (!shouldRecord(telemetry)) {
118
+ return {};
119
+ }
120
+ const result = {};
121
+ for (const [key, value] of Object.entries(attributes)) {
122
+ if (value == null) continue;
123
+ if (typeof value === "object" && "input" in value && typeof value.input === "function") {
124
+ if ((telemetry == null ? void 0 : telemetry.recordInputs) === false) continue;
125
+ const resolved = value.input();
126
+ if (resolved != null) result[key] = resolved;
127
+ continue;
128
+ }
129
+ if (typeof value === "object" && "output" in value && typeof value.output === "function") {
130
+ if ((telemetry == null ? void 0 : telemetry.recordOutputs) === false) continue;
131
+ const resolved = value.output();
132
+ if (resolved != null) result[key] = resolved;
133
+ continue;
134
+ }
135
+ result[key] = value;
136
+ }
137
+ return result;
138
+ }
139
+ var OpenTelemetryIntegration = class {
140
+ constructor(options = {}) {
141
+ this.callStates = /* @__PURE__ */ new Map();
142
+ var _a;
143
+ this.tracer = (_a = options.tracer) != null ? _a : import_api.trace.getTracer("ai");
144
+ }
145
+ getCallState(callId) {
146
+ return this.callStates.get(callId);
147
+ }
148
+ cleanupCallState(callId) {
149
+ this.callStates.delete(callId);
150
+ }
151
+ executeTool({
152
+ callId,
153
+ toolCallId,
154
+ execute
155
+ }) {
156
+ var _a;
157
+ const toolSpanEntry = (_a = this.getCallState(callId)) == null ? void 0 : _a.toolSpans.get(toolCallId);
158
+ if (toolSpanEntry == null) {
159
+ return execute();
160
+ }
161
+ return import_api.context.with(toolSpanEntry.context, execute);
162
+ }
163
+ onStart(event) {
164
+ if (event.isEnabled !== true) return;
165
+ if (event.operationId === "ai.embed" || event.operationId === "ai.embedMany") {
166
+ this.onEmbedOperationStart(event);
167
+ return;
168
+ }
169
+ if (event.operationId === "ai.rerank") {
170
+ this.onRerankOperationStart(event);
171
+ return;
172
+ }
173
+ if (event.operationId === "ai.generateObject" || event.operationId === "ai.streamObject") {
174
+ this.onObjectOperationStart(event);
175
+ return;
176
+ }
177
+ this.onGenerateStart(event);
178
+ }
179
+ onGenerateStart(event) {
180
+ const telemetry = {
181
+ isEnabled: event.isEnabled,
182
+ recordInputs: event.recordInputs,
183
+ recordOutputs: event.recordOutputs,
184
+ functionId: event.functionId,
185
+ metadata: event.metadata
186
+ };
187
+ const settings = {
188
+ maxOutputTokens: event.maxOutputTokens,
189
+ temperature: event.temperature,
190
+ topP: event.topP,
191
+ topK: event.topK,
192
+ presencePenalty: event.presencePenalty,
193
+ frequencyPenalty: event.frequencyPenalty,
194
+ stopSequences: event.stopSequences,
195
+ seed: event.seed,
196
+ maxRetries: event.maxRetries
197
+ };
198
+ const baseTelemetryAttributes = getBaseTelemetryAttributes({
199
+ model: { provider: event.provider, modelId: event.modelId },
200
+ telemetry,
201
+ headers: event.headers,
202
+ settings
203
+ });
204
+ const attributes = selectAttributes(telemetry, {
205
+ ...assembleOperationName({
206
+ operationId: event.operationId,
207
+ telemetry
208
+ }),
209
+ ...baseTelemetryAttributes,
210
+ "ai.model.provider": event.provider,
211
+ "ai.model.id": event.modelId,
212
+ "ai.prompt": {
213
+ input: () => JSON.stringify({
214
+ system: event.system,
215
+ prompt: event.prompt,
216
+ messages: event.messages
217
+ })
218
+ }
219
+ });
220
+ const rootSpan = this.tracer.startSpan(event.operationId, { attributes });
221
+ const rootContext = import_api.trace.setSpan(import_api.context.active(), rootSpan);
222
+ this.callStates.set(event.callId, {
223
+ operationId: event.operationId,
224
+ telemetry,
225
+ rootSpan,
226
+ rootContext,
227
+ stepSpan: void 0,
228
+ stepContext: void 0,
229
+ embedSpans: /* @__PURE__ */ new Map(),
230
+ rerankSpan: void 0,
231
+ toolSpans: /* @__PURE__ */ new Map(),
232
+ baseTelemetryAttributes,
233
+ settings
234
+ });
235
+ }
236
+ onObjectOperationStart(event) {
237
+ const telemetry = {
238
+ isEnabled: event.isEnabled,
239
+ recordInputs: event.recordInputs,
240
+ recordOutputs: event.recordOutputs,
241
+ functionId: event.functionId,
242
+ metadata: event.metadata
243
+ };
244
+ const settings = {
245
+ maxOutputTokens: event.maxOutputTokens,
246
+ temperature: event.temperature,
247
+ topP: event.topP,
248
+ topK: event.topK,
249
+ presencePenalty: event.presencePenalty,
250
+ frequencyPenalty: event.frequencyPenalty,
251
+ seed: event.seed,
252
+ maxRetries: event.maxRetries
253
+ };
254
+ const baseTelemetryAttributes = getBaseTelemetryAttributes({
255
+ model: { provider: event.provider, modelId: event.modelId },
256
+ telemetry,
257
+ headers: event.headers,
258
+ settings
259
+ });
260
+ const attributes = selectAttributes(telemetry, {
261
+ ...assembleOperationName({
262
+ operationId: event.operationId,
263
+ telemetry
264
+ }),
265
+ ...baseTelemetryAttributes,
266
+ "ai.prompt": {
267
+ input: () => JSON.stringify({
268
+ system: event.system,
269
+ prompt: event.prompt,
270
+ messages: event.messages
271
+ })
272
+ },
273
+ "ai.schema": event.schema ? { input: () => JSON.stringify(event.schema) } : void 0,
274
+ "ai.schema.name": event.schemaName,
275
+ "ai.schema.description": event.schemaDescription,
276
+ "ai.settings.output": event.output
277
+ });
278
+ const rootSpan = this.tracer.startSpan(event.operationId, { attributes });
279
+ const rootContext = import_api.trace.setSpan(import_api.context.active(), rootSpan);
280
+ this.callStates.set(event.callId, {
281
+ operationId: event.operationId,
282
+ telemetry,
283
+ rootSpan,
284
+ rootContext,
285
+ stepSpan: void 0,
286
+ stepContext: void 0,
287
+ embedSpans: /* @__PURE__ */ new Map(),
288
+ rerankSpan: void 0,
289
+ toolSpans: /* @__PURE__ */ new Map(),
290
+ baseTelemetryAttributes,
291
+ settings
292
+ });
293
+ }
294
+ /** @deprecated */
295
+ onObjectStepStart(event) {
296
+ var _a;
297
+ const state = this.getCallState(event.callId);
298
+ if (!(state == null ? void 0 : state.rootSpan) || !state.rootContext) return;
299
+ const { telemetry } = state;
300
+ const stepOperationId = state.operationId === "ai.streamObject" ? "ai.streamObject.doStream" : "ai.generateObject.doGenerate";
301
+ const attributes = selectAttributes(telemetry, {
302
+ ...assembleOperationName({
303
+ operationId: stepOperationId,
304
+ telemetry
305
+ }),
306
+ ...state.baseTelemetryAttributes,
307
+ "ai.prompt.messages": {
308
+ input: () => event.promptMessages ? stringifyForTelemetry(event.promptMessages) : void 0
309
+ },
310
+ "gen_ai.system": event.provider,
311
+ "gen_ai.request.model": event.modelId,
312
+ "gen_ai.request.frequency_penalty": state.settings.frequencyPenalty,
313
+ "gen_ai.request.max_tokens": state.settings.maxOutputTokens,
314
+ "gen_ai.request.presence_penalty": state.settings.presencePenalty,
315
+ "gen_ai.request.temperature": (_a = state.settings.temperature) != null ? _a : void 0,
316
+ "gen_ai.request.top_k": state.settings.topK,
317
+ "gen_ai.request.top_p": state.settings.topP
318
+ });
319
+ state.stepSpan = this.tracer.startSpan(
320
+ stepOperationId,
321
+ { attributes },
322
+ state.rootContext
323
+ );
324
+ state.stepContext = import_api.trace.setSpan(state.rootContext, state.stepSpan);
325
+ }
326
+ /** @deprecated */
327
+ onObjectStepFinish(event) {
328
+ const state = this.getCallState(event.callId);
329
+ if (!(state == null ? void 0 : state.stepSpan)) return;
330
+ const { telemetry } = state;
331
+ state.stepSpan.setAttributes(
332
+ selectAttributes(telemetry, {
333
+ "ai.response.finishReason": event.finishReason,
334
+ "ai.response.object": {
335
+ output: () => {
336
+ try {
337
+ return JSON.stringify(JSON.parse(event.objectText));
338
+ } catch (e) {
339
+ return event.objectText;
340
+ }
341
+ }
342
+ },
343
+ "ai.response.id": event.response.id,
344
+ "ai.response.model": event.response.modelId,
345
+ "ai.response.timestamp": event.response.timestamp.toISOString(),
346
+ "ai.response.providerMetadata": event.providerMetadata ? JSON.stringify(event.providerMetadata) : void 0,
347
+ "ai.usage.inputTokens": event.usage.inputTokens,
348
+ "ai.usage.outputTokens": event.usage.outputTokens,
349
+ "ai.usage.totalTokens": event.usage.totalTokens,
350
+ "ai.usage.reasoningTokens": event.usage.reasoningTokens,
351
+ "ai.usage.cachedInputTokens": event.usage.cachedInputTokens,
352
+ "gen_ai.response.finish_reasons": [event.finishReason],
353
+ "gen_ai.response.id": event.response.id,
354
+ "gen_ai.response.model": event.response.modelId,
355
+ "gen_ai.usage.input_tokens": event.usage.inputTokens,
356
+ "gen_ai.usage.output_tokens": event.usage.outputTokens
357
+ })
358
+ );
359
+ if (event.msToFirstChunk != null) {
360
+ state.stepSpan.addEvent("ai.stream.firstChunk", {
361
+ "ai.stream.msToFirstChunk": event.msToFirstChunk
362
+ });
363
+ state.stepSpan.setAttributes({
364
+ "ai.stream.msToFirstChunk": event.msToFirstChunk
365
+ });
366
+ }
367
+ state.stepSpan.end();
368
+ state.stepSpan = void 0;
369
+ state.stepContext = void 0;
370
+ }
371
+ onEmbedOperationStart(event) {
372
+ const telemetry = {
373
+ isEnabled: event.isEnabled,
374
+ recordInputs: event.recordInputs,
375
+ recordOutputs: event.recordOutputs,
376
+ functionId: event.functionId,
377
+ metadata: event.metadata
378
+ };
379
+ const settings = {
380
+ maxRetries: event.maxRetries
381
+ };
382
+ const baseTelemetryAttributes = getBaseTelemetryAttributes({
383
+ model: { provider: event.provider, modelId: event.modelId },
384
+ telemetry,
385
+ headers: event.headers,
386
+ settings
387
+ });
388
+ const value = event.value;
389
+ const isMany = event.operationId === "ai.embedMany";
390
+ const attributes = selectAttributes(telemetry, {
391
+ ...assembleOperationName({
392
+ operationId: event.operationId,
393
+ telemetry
394
+ }),
395
+ ...baseTelemetryAttributes,
396
+ ...isMany ? {
397
+ "ai.values": {
398
+ input: () => value.map((v) => JSON.stringify(v))
399
+ }
400
+ } : {
401
+ "ai.value": {
402
+ input: () => JSON.stringify(value)
403
+ }
404
+ }
405
+ });
406
+ const rootSpan = this.tracer.startSpan(event.operationId, { attributes });
407
+ const rootContext = import_api.trace.setSpan(import_api.context.active(), rootSpan);
408
+ this.callStates.set(event.callId, {
409
+ operationId: event.operationId,
410
+ telemetry,
411
+ rootSpan,
412
+ rootContext,
413
+ stepSpan: void 0,
414
+ stepContext: void 0,
415
+ embedSpans: /* @__PURE__ */ new Map(),
416
+ rerankSpan: void 0,
417
+ toolSpans: /* @__PURE__ */ new Map(),
418
+ baseTelemetryAttributes,
419
+ settings
420
+ });
421
+ }
422
+ onStepStart(event) {
423
+ var _a;
424
+ const state = this.getCallState(event.callId);
425
+ if (!(state == null ? void 0 : state.rootSpan) || !state.rootContext) return;
426
+ const { telemetry } = state;
427
+ const stepOperationId = state.operationId === "ai.streamText" ? "ai.streamText.doStream" : "ai.generateText.doGenerate";
428
+ const attributes = selectAttributes(telemetry, {
429
+ ...assembleOperationName({
430
+ operationId: stepOperationId,
431
+ telemetry
432
+ }),
433
+ ...state.baseTelemetryAttributes,
434
+ "ai.model.provider": event.provider,
435
+ "ai.model.id": event.modelId,
436
+ "ai.prompt.messages": {
437
+ input: () => event.promptMessages ? stringifyForTelemetry(event.promptMessages) : void 0
438
+ },
439
+ "ai.prompt.tools": {
440
+ input: () => {
441
+ var _a2;
442
+ return (_a2 = event.stepTools) == null ? void 0 : _a2.map((tool) => JSON.stringify(tool));
443
+ }
444
+ },
445
+ "ai.prompt.toolChoice": {
446
+ input: () => event.stepToolChoice != null ? JSON.stringify(event.stepToolChoice) : void 0
447
+ },
448
+ "gen_ai.system": event.provider,
449
+ "gen_ai.request.model": event.modelId,
450
+ "gen_ai.request.frequency_penalty": state.settings.frequencyPenalty,
451
+ "gen_ai.request.max_tokens": state.settings.maxOutputTokens,
452
+ "gen_ai.request.presence_penalty": state.settings.presencePenalty,
453
+ "gen_ai.request.stop_sequences": state.settings.stopSequences,
454
+ "gen_ai.request.temperature": (_a = state.settings.temperature) != null ? _a : void 0,
455
+ "gen_ai.request.top_k": state.settings.topK,
456
+ "gen_ai.request.top_p": state.settings.topP
457
+ });
458
+ state.stepSpan = this.tracer.startSpan(
459
+ stepOperationId,
460
+ { attributes },
461
+ state.rootContext
462
+ );
463
+ state.stepContext = import_api.trace.setSpan(state.rootContext, state.stepSpan);
464
+ }
465
+ onToolCallStart(event) {
466
+ const state = this.getCallState(event.callId);
467
+ if (!(state == null ? void 0 : state.stepContext)) return;
468
+ const { telemetry } = state;
469
+ const { toolCall } = event;
470
+ const attributes = selectAttributes(telemetry, {
471
+ ...assembleOperationName({
472
+ operationId: "ai.toolCall",
473
+ telemetry
474
+ }),
475
+ "ai.toolCall.name": toolCall.toolName,
476
+ "ai.toolCall.id": toolCall.toolCallId,
477
+ "ai.toolCall.args": {
478
+ output: () => JSON.stringify(toolCall.input)
479
+ }
480
+ });
481
+ const toolSpan = this.tracer.startSpan(
482
+ "ai.toolCall",
483
+ { attributes },
484
+ state.stepContext
485
+ );
486
+ const toolContext = import_api.trace.setSpan(state.stepContext, toolSpan);
487
+ state.toolSpans.set(toolCall.toolCallId, {
488
+ span: toolSpan,
489
+ context: toolContext
490
+ });
491
+ }
492
+ onToolCallFinish(event) {
493
+ const state = this.getCallState(event.callId);
494
+ if (!state) return;
495
+ const toolSpanEntry = state.toolSpans.get(event.toolCall.toolCallId);
496
+ if (!toolSpanEntry) return;
497
+ const { span } = toolSpanEntry;
498
+ const { telemetry } = state;
499
+ if (event.success) {
500
+ try {
501
+ span.setAttributes(
502
+ selectAttributes(telemetry, {
503
+ "ai.toolCall.result": {
504
+ output: () => JSON.stringify(event.output)
505
+ }
506
+ })
507
+ );
508
+ } catch (_ignored) {
509
+ }
510
+ } else {
511
+ recordSpanError(span, event.error);
512
+ }
513
+ span.end();
514
+ state.toolSpans.delete(event.toolCall.toolCallId);
515
+ }
516
+ onStepFinish(event) {
517
+ var _a, _b, _c, _d, _e;
518
+ const state = this.getCallState(event.callId);
519
+ if (!(state == null ? void 0 : state.stepSpan)) return;
520
+ const { telemetry } = state;
521
+ state.stepSpan.setAttributes(
522
+ selectAttributes(telemetry, {
523
+ "ai.response.finishReason": event.finishReason,
524
+ "ai.response.text": {
525
+ output: () => {
526
+ var _a2;
527
+ return (_a2 = event.text) != null ? _a2 : void 0;
528
+ }
529
+ },
530
+ "ai.response.reasoning": {
531
+ output: () => event.reasoning.length > 0 ? event.reasoning.filter((part) => "text" in part).map((part) => part.text).join("\n") : void 0
532
+ },
533
+ "ai.response.toolCalls": {
534
+ output: () => event.toolCalls.length > 0 ? JSON.stringify(
535
+ event.toolCalls.map((toolCall) => ({
536
+ toolCallId: toolCall.toolCallId,
537
+ toolName: toolCall.toolName,
538
+ input: toolCall.input
539
+ }))
540
+ ) : void 0
541
+ },
542
+ "ai.response.files": {
543
+ output: () => event.files.length > 0 ? JSON.stringify(
544
+ event.files.map((file) => ({
545
+ type: "file",
546
+ mediaType: file.mediaType,
547
+ data: file.base64
548
+ }))
549
+ ) : void 0
550
+ },
551
+ "ai.response.id": event.response.id,
552
+ "ai.response.model": event.response.modelId,
553
+ "ai.response.timestamp": event.response.timestamp.toISOString(),
554
+ "ai.response.providerMetadata": event.providerMetadata ? JSON.stringify(event.providerMetadata) : void 0,
555
+ "ai.usage.inputTokens": event.usage.inputTokens,
556
+ "ai.usage.outputTokens": event.usage.outputTokens,
557
+ "ai.usage.totalTokens": event.usage.totalTokens,
558
+ "ai.usage.reasoningTokens": event.usage.reasoningTokens,
559
+ "ai.usage.cachedInputTokens": event.usage.cachedInputTokens,
560
+ "ai.usage.inputTokenDetails.noCacheTokens": (_a = event.usage.inputTokenDetails) == null ? void 0 : _a.noCacheTokens,
561
+ "ai.usage.inputTokenDetails.cacheReadTokens": (_b = event.usage.inputTokenDetails) == null ? void 0 : _b.cacheReadTokens,
562
+ "ai.usage.inputTokenDetails.cacheWriteTokens": (_c = event.usage.inputTokenDetails) == null ? void 0 : _c.cacheWriteTokens,
563
+ "ai.usage.outputTokenDetails.textTokens": (_d = event.usage.outputTokenDetails) == null ? void 0 : _d.textTokens,
564
+ "ai.usage.outputTokenDetails.reasoningTokens": (_e = event.usage.outputTokenDetails) == null ? void 0 : _e.reasoningTokens,
565
+ "gen_ai.response.finish_reasons": [event.finishReason],
566
+ "gen_ai.response.id": event.response.id,
567
+ "gen_ai.response.model": event.response.modelId,
568
+ "gen_ai.usage.input_tokens": event.usage.inputTokens,
569
+ "gen_ai.usage.output_tokens": event.usage.outputTokens
570
+ })
571
+ );
572
+ state.stepSpan.end();
573
+ state.stepSpan = void 0;
574
+ state.stepContext = void 0;
575
+ }
576
+ onFinish(event) {
577
+ const state = this.getCallState(event.callId);
578
+ if (!(state == null ? void 0 : state.rootSpan)) return;
579
+ if (state.operationId === "ai.embed" || state.operationId === "ai.embedMany") {
580
+ this.onEmbedOperationFinish(event);
581
+ return;
582
+ }
583
+ if (state.operationId === "ai.rerank") {
584
+ this.onRerankOperationFinish(event);
585
+ return;
586
+ }
587
+ if (state.operationId === "ai.generateObject" || state.operationId === "ai.streamObject") {
588
+ this.onObjectOperationFinish(event);
589
+ return;
590
+ }
591
+ this.onGenerateFinish(event);
592
+ }
593
+ onGenerateFinish(event) {
594
+ var _a, _b, _c, _d, _e;
595
+ const state = this.getCallState(event.callId);
596
+ if (!(state == null ? void 0 : state.rootSpan)) return;
597
+ const { telemetry } = state;
598
+ state.rootSpan.setAttributes(
599
+ selectAttributes(telemetry, {
600
+ "ai.response.finishReason": event.finishReason,
601
+ "ai.response.text": {
602
+ output: () => {
603
+ var _a2;
604
+ return (_a2 = event.text) != null ? _a2 : void 0;
605
+ }
606
+ },
607
+ "ai.response.reasoning": {
608
+ output: () => event.reasoning.length > 0 ? event.reasoning.filter((part) => "text" in part).map((part) => part.text).join("\n") : void 0
609
+ },
610
+ "ai.response.toolCalls": {
611
+ output: () => event.toolCalls.length > 0 ? JSON.stringify(
612
+ event.toolCalls.map((toolCall) => ({
613
+ toolCallId: toolCall.toolCallId,
614
+ toolName: toolCall.toolName,
615
+ input: toolCall.input
616
+ }))
617
+ ) : void 0
618
+ },
619
+ "ai.response.files": {
620
+ output: () => event.files.length > 0 ? JSON.stringify(
621
+ event.files.map((file) => ({
622
+ type: "file",
623
+ mediaType: file.mediaType,
624
+ data: file.base64
625
+ }))
626
+ ) : void 0
627
+ },
628
+ "ai.response.providerMetadata": event.providerMetadata ? JSON.stringify(event.providerMetadata) : void 0,
629
+ "ai.usage.inputTokens": event.totalUsage.inputTokens,
630
+ "ai.usage.outputTokens": event.totalUsage.outputTokens,
631
+ "ai.usage.totalTokens": event.totalUsage.totalTokens,
632
+ "ai.usage.reasoningTokens": event.totalUsage.reasoningTokens,
633
+ "ai.usage.cachedInputTokens": event.totalUsage.cachedInputTokens,
634
+ "ai.usage.inputTokenDetails.noCacheTokens": (_a = event.totalUsage.inputTokenDetails) == null ? void 0 : _a.noCacheTokens,
635
+ "ai.usage.inputTokenDetails.cacheReadTokens": (_b = event.totalUsage.inputTokenDetails) == null ? void 0 : _b.cacheReadTokens,
636
+ "ai.usage.inputTokenDetails.cacheWriteTokens": (_c = event.totalUsage.inputTokenDetails) == null ? void 0 : _c.cacheWriteTokens,
637
+ "ai.usage.outputTokenDetails.textTokens": (_d = event.totalUsage.outputTokenDetails) == null ? void 0 : _d.textTokens,
638
+ "ai.usage.outputTokenDetails.reasoningTokens": (_e = event.totalUsage.outputTokenDetails) == null ? void 0 : _e.reasoningTokens
639
+ })
640
+ );
641
+ state.rootSpan.end();
642
+ this.cleanupCallState(event.callId);
643
+ }
644
+ onObjectOperationFinish(event) {
645
+ const state = this.getCallState(event.callId);
646
+ if (!(state == null ? void 0 : state.rootSpan)) return;
647
+ const { telemetry } = state;
648
+ state.rootSpan.setAttributes(
649
+ selectAttributes(telemetry, {
650
+ "ai.response.finishReason": event.finishReason,
651
+ "ai.response.object": {
652
+ output: () => event.object != null ? JSON.stringify(event.object) : void 0
653
+ },
654
+ "ai.response.providerMetadata": event.providerMetadata ? JSON.stringify(event.providerMetadata) : void 0,
655
+ "ai.usage.inputTokens": event.usage.inputTokens,
656
+ "ai.usage.outputTokens": event.usage.outputTokens,
657
+ "ai.usage.totalTokens": event.usage.totalTokens,
658
+ "ai.usage.reasoningTokens": event.usage.reasoningTokens,
659
+ "ai.usage.cachedInputTokens": event.usage.cachedInputTokens
660
+ })
661
+ );
662
+ state.rootSpan.end();
663
+ this.cleanupCallState(event.callId);
664
+ }
665
+ onEmbedOperationFinish(event) {
666
+ const state = this.getCallState(event.callId);
667
+ if (!(state == null ? void 0 : state.rootSpan)) return;
668
+ const { telemetry } = state;
669
+ const isMany = state.operationId === "ai.embedMany";
670
+ state.rootSpan.setAttributes(
671
+ selectAttributes(telemetry, {
672
+ ...isMany ? {
673
+ "ai.embeddings": {
674
+ output: () => event.embedding.map((e) => JSON.stringify(e))
675
+ }
676
+ } : {
677
+ "ai.embedding": {
678
+ output: () => JSON.stringify(event.embedding)
679
+ }
680
+ },
681
+ "ai.usage.tokens": event.usage.tokens
682
+ })
683
+ );
684
+ state.rootSpan.end();
685
+ this.cleanupCallState(event.callId);
686
+ }
687
+ onEmbedStart(event) {
688
+ const state = this.getCallState(event.callId);
689
+ if (!(state == null ? void 0 : state.rootSpan) || !state.rootContext) return;
690
+ const { telemetry } = state;
691
+ const attributes = selectAttributes(telemetry, {
692
+ ...assembleOperationName({
693
+ operationId: event.operationId,
694
+ telemetry
695
+ }),
696
+ ...state.baseTelemetryAttributes,
697
+ "ai.values": {
698
+ input: () => event.values.map((v) => JSON.stringify(v))
699
+ }
700
+ });
701
+ const embedSpan = this.tracer.startSpan(
702
+ event.operationId,
703
+ { attributes },
704
+ state.rootContext
705
+ );
706
+ const embedContext = import_api.trace.setSpan(state.rootContext, embedSpan);
707
+ state.embedSpans.set(event.embedCallId, {
708
+ span: embedSpan,
709
+ context: embedContext
710
+ });
711
+ }
712
+ onEmbedFinish(event) {
713
+ const state = this.getCallState(event.callId);
714
+ if (!state) return;
715
+ const embedSpanEntry = state.embedSpans.get(event.embedCallId);
716
+ if (!embedSpanEntry) return;
717
+ const { span } = embedSpanEntry;
718
+ const { telemetry } = state;
719
+ span.setAttributes(
720
+ selectAttributes(telemetry, {
721
+ "ai.embeddings": {
722
+ output: () => event.embeddings.map((embedding) => JSON.stringify(embedding))
723
+ },
724
+ "ai.usage.tokens": event.usage.tokens
725
+ })
726
+ );
727
+ span.end();
728
+ state.embedSpans.delete(event.embedCallId);
729
+ }
730
+ onRerankOperationStart(event) {
731
+ const telemetry = {
732
+ isEnabled: event.isEnabled,
733
+ recordInputs: event.recordInputs,
734
+ recordOutputs: event.recordOutputs,
735
+ functionId: event.functionId,
736
+ metadata: event.metadata
737
+ };
738
+ const settings = {
739
+ maxRetries: event.maxRetries
740
+ };
741
+ const baseTelemetryAttributes = getBaseTelemetryAttributes({
742
+ model: { provider: event.provider, modelId: event.modelId },
743
+ telemetry,
744
+ headers: event.headers,
745
+ settings
746
+ });
747
+ const attributes = selectAttributes(telemetry, {
748
+ ...assembleOperationName({
749
+ operationId: event.operationId,
750
+ telemetry
751
+ }),
752
+ ...baseTelemetryAttributes,
753
+ "ai.documents": {
754
+ input: () => event.documents.map((d) => JSON.stringify(d))
755
+ }
756
+ });
757
+ const rootSpan = this.tracer.startSpan(event.operationId, { attributes });
758
+ const rootContext = import_api.trace.setSpan(import_api.context.active(), rootSpan);
759
+ this.callStates.set(event.callId, {
760
+ operationId: event.operationId,
761
+ telemetry,
762
+ rootSpan,
763
+ rootContext,
764
+ stepSpan: void 0,
765
+ stepContext: void 0,
766
+ embedSpans: /* @__PURE__ */ new Map(),
767
+ rerankSpan: void 0,
768
+ toolSpans: /* @__PURE__ */ new Map(),
769
+ baseTelemetryAttributes,
770
+ settings
771
+ });
772
+ }
773
+ onRerankOperationFinish(event) {
774
+ const state = this.getCallState(event.callId);
775
+ if (!(state == null ? void 0 : state.rootSpan)) return;
776
+ state.rootSpan.end();
777
+ this.cleanupCallState(event.callId);
778
+ }
779
+ onRerankStart(event) {
780
+ const state = this.getCallState(event.callId);
781
+ if (!(state == null ? void 0 : state.rootSpan) || !state.rootContext) return;
782
+ const { telemetry } = state;
783
+ const attributes = selectAttributes(telemetry, {
784
+ ...assembleOperationName({
785
+ operationId: event.operationId,
786
+ telemetry
787
+ }),
788
+ ...state.baseTelemetryAttributes,
789
+ "ai.documents": {
790
+ input: () => event.documents.map((d) => JSON.stringify(d))
791
+ }
792
+ });
793
+ const rerankSpan = this.tracer.startSpan(
794
+ event.operationId,
795
+ { attributes },
796
+ state.rootContext
797
+ );
798
+ const rerankContext = import_api.trace.setSpan(state.rootContext, rerankSpan);
799
+ state.rerankSpan = { span: rerankSpan, context: rerankContext };
800
+ }
801
+ onRerankFinish(event) {
802
+ const state = this.getCallState(event.callId);
803
+ if (!(state == null ? void 0 : state.rerankSpan)) return;
804
+ const { span } = state.rerankSpan;
805
+ const { telemetry } = state;
806
+ span.setAttributes(
807
+ selectAttributes(telemetry, {
808
+ "ai.ranking.type": event.documentsType,
809
+ "ai.ranking": {
810
+ output: () => event.ranking.map((r) => JSON.stringify(r))
811
+ }
812
+ })
813
+ );
814
+ span.end();
815
+ state.rerankSpan = void 0;
816
+ }
817
+ onChunk(event) {
818
+ var _a;
819
+ const chunk = event.chunk;
820
+ if (typeof chunk.callId !== "string") {
821
+ return;
822
+ }
823
+ if (chunk.type !== "ai.stream.firstChunk" && chunk.type !== "ai.stream.finish") {
824
+ return;
825
+ }
826
+ const state = this.getCallState(chunk.callId);
827
+ if (!(state == null ? void 0 : state.stepSpan)) return;
828
+ const attributes = Object.fromEntries(
829
+ Object.entries(
830
+ (_a = chunk.attributes) != null ? _a : {}
831
+ ).filter(([, value]) => value != null)
832
+ );
833
+ state.stepSpan.addEvent(chunk.type, attributes);
834
+ if (Object.keys(attributes).length > 0) {
835
+ state.stepSpan.setAttributes(attributes);
836
+ }
837
+ }
838
+ onError(error) {
839
+ var _a;
840
+ const event = error;
841
+ if (!(event == null ? void 0 : event.callId)) return;
842
+ const state = this.getCallState(event.callId);
843
+ if (!(state == null ? void 0 : state.rootSpan)) return;
844
+ const actualError = (_a = event.error) != null ? _a : error;
845
+ if (state.stepSpan) {
846
+ recordSpanError(state.stepSpan, actualError);
847
+ state.stepSpan.end();
848
+ }
849
+ for (const { span: embedSpan } of state.embedSpans.values()) {
850
+ recordSpanError(embedSpan, actualError);
851
+ embedSpan.end();
852
+ }
853
+ state.embedSpans.clear();
854
+ if (state.rerankSpan) {
855
+ recordSpanError(state.rerankSpan.span, actualError);
856
+ state.rerankSpan.span.end();
857
+ state.rerankSpan = void 0;
858
+ }
859
+ recordSpanError(state.rootSpan, actualError);
860
+ state.rootSpan.end();
861
+ this.cleanupCallState(event.callId);
862
+ }
863
+ };
864
+ // Annotate the CommonJS export names for ESM import in node:
865
+ 0 && (module.exports = {
866
+ OpenTelemetryIntegration
867
+ });
868
+ //# sourceMappingURL=index.js.map