@ai-sdk/otel 1.0.0-beta.13 → 1.0.0-beta.130

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.
@@ -1,42 +1,44 @@
1
- import { LanguageModelV4Prompt } from '@ai-sdk/provider';
1
+ import type { LanguageModelV4Prompt } from '@ai-sdk/provider';
2
+ import type { Context as AISDKContext } from '@ai-sdk/provider-utils';
2
3
  import {
3
- Attributes,
4
- AttributeValue,
5
4
  context,
6
- Context,
7
- Span,
8
5
  SpanStatusCode,
9
6
  trace,
10
- Tracer,
7
+ type Attributes,
8
+ type AttributeValue,
9
+ type Context as OpenTelemetryContext,
10
+ type Span,
11
+ type Tracer,
11
12
  } from '@opentelemetry/api';
12
13
  import type {
13
- EmbedFinishEvent,
14
- EmbedOnFinishEvent,
15
- EmbedOnStartEvent,
14
+ EmbeddingModelCallEndEvent,
15
+ EmbedEndEvent,
16
16
  EmbedStartEvent,
17
- GenerationContext,
18
- ObjectOnFinishEvent,
19
- ObjectOnStartEvent,
20
- ObjectOnStepFinishEvent,
21
- ObjectOnStepStartEvent,
22
- OnChunkEvent,
23
- OnFinishEvent,
24
- OnStartEvent,
25
- OnStepFinishEvent,
26
- OnStepStartEvent,
27
- OnToolCallFinishEvent,
28
- OnToolCallStartEvent,
29
- OutputInterface as Output,
30
- RerankFinishEvent,
31
- RerankOnFinishEvent,
32
- RerankOnStartEvent,
17
+ EmbeddingModelCallStartEvent,
18
+ GenerateObjectEndEvent,
19
+ GenerateObjectStartEvent,
20
+ GenerateObjectStepEndEvent,
21
+ GenerateObjectStepStartEvent,
22
+ GenerateTextAbortEvent,
23
+ GenerateTextEndEvent,
24
+ GenerateTextStartEvent,
25
+ GenerateTextStepEndEvent,
26
+ GenerateTextStepStartEvent,
27
+ ToolExecutionEndEvent,
28
+ ToolExecutionStartEvent,
29
+ Output,
30
+ RerankingModelCallEndEvent,
31
+ RerankEndEvent,
33
32
  RerankStartEvent,
34
- TelemetryIntegration,
35
- TelemetrySettings,
33
+ RerankingModelCallStartEvent,
34
+ InferTelemetryEvent,
35
+ Telemetry,
36
+ TelemetryOptions,
36
37
  ToolSet,
37
38
  } from 'ai';
38
39
  import { assembleOperationName } from './assemble-operation-name';
39
40
  import { getBaseTelemetryAttributes } from './get-base-telemetry-attributes';
41
+ import { sanitizeAttributeValue } from './sanitize-attribute-value';
40
42
  import { stringifyForTelemetry } from './stringify-for-telemetry';
41
43
 
42
44
  function recordSpanError(span: Span, error: unknown): void {
@@ -56,13 +58,13 @@ function recordSpanError(span: Span, error: unknown): void {
56
58
  }
57
59
 
58
60
  function shouldRecord(
59
- telemetry: TelemetrySettings | undefined,
60
- ): telemetry is TelemetrySettings {
61
- return telemetry?.isEnabled === true;
61
+ telemetry: TelemetryOptions | undefined,
62
+ ): telemetry is TelemetryOptions {
63
+ return telemetry?.isEnabled !== false;
62
64
  }
63
65
 
64
66
  function selectAttributes(
65
- telemetry: TelemetrySettings | undefined,
67
+ telemetry: TelemetryOptions | undefined,
66
68
  attributes: Record<
67
69
  string,
68
70
  | AttributeValue
@@ -87,7 +89,10 @@ function selectAttributes(
87
89
  ) {
88
90
  if (telemetry?.recordInputs === false) continue;
89
91
  const resolved = value.input();
90
- if (resolved != null) result[key] = resolved;
92
+ if (resolved != null) {
93
+ const sanitized = sanitizeAttributeValue(resolved);
94
+ if (sanitized != null) result[key] = sanitized;
95
+ }
91
96
  continue;
92
97
  }
93
98
 
@@ -98,11 +103,15 @@ function selectAttributes(
98
103
  ) {
99
104
  if (telemetry?.recordOutputs === false) continue;
100
105
  const resolved = value.output();
101
- if (resolved != null) result[key] = resolved;
106
+ if (resolved != null) {
107
+ const sanitized = sanitizeAttributeValue(resolved);
108
+ if (sanitized != null) result[key] = sanitized;
109
+ }
102
110
  continue;
103
111
  }
104
112
 
105
- result[key] = value as AttributeValue;
113
+ const sanitized = sanitizeAttributeValue(value as AttributeValue);
114
+ if (sanitized != null) result[key] = sanitized;
106
115
  }
107
116
 
108
117
  return result;
@@ -110,9 +119,9 @@ function selectAttributes(
110
119
 
111
120
  interface OtelStepStartEvent<
112
121
  TOOLS extends ToolSet = ToolSet,
113
- CONTEXT extends GenerationContext<TOOLS> = GenerationContext<TOOLS>,
114
- OUTPUT extends Output = Output,
115
- > extends OnStepStartEvent<TOOLS, CONTEXT, OUTPUT> {
122
+ RUNTIME_CONTEXT extends AISDKContext = AISDKContext,
123
+ OUTPUT extends Output.Output = Output.Output,
124
+ > extends GenerateTextStepStartEvent<TOOLS, RUNTIME_CONTEXT, OUTPUT> {
116
125
  readonly promptMessages?: LanguageModelV4Prompt;
117
126
  readonly stepTools?: ReadonlyArray<Record<string, unknown>>;
118
127
  readonly stepToolChoice?: unknown;
@@ -120,19 +129,19 @@ interface OtelStepStartEvent<
120
129
 
121
130
  interface CallState {
122
131
  operationId: string;
123
- telemetry: TelemetrySettings | undefined;
132
+ telemetry: TelemetryOptions | undefined;
124
133
  rootSpan: Span | undefined;
125
- rootContext: Context | undefined;
134
+ rootContext: OpenTelemetryContext | undefined;
126
135
  stepSpan: Span | undefined;
127
- stepContext: Context | undefined;
128
- embedSpans: Map<string, { span: Span; context: Context }>;
129
- rerankSpan: { span: Span; context: Context } | undefined;
130
- toolSpans: Map<string, { span: Span; context: Context }>;
136
+ stepContext: OpenTelemetryContext | undefined;
137
+ embedSpans: Map<string, { span: Span; context: OpenTelemetryContext }>;
138
+ rerankSpan: { span: Span; context: OpenTelemetryContext } | undefined;
139
+ toolSpans: Map<string, { span: Span; context: OpenTelemetryContext }>;
131
140
  baseTelemetryAttributes: Attributes;
132
141
  settings: Record<string, unknown>;
133
142
  }
134
143
 
135
- export class OpenTelemetryIntegration implements TelemetryIntegration {
144
+ export class LegacyOpenTelemetry implements Telemetry {
136
145
  private readonly callStates = new Map<string, CallState>();
137
146
 
138
147
  /**
@@ -174,25 +183,45 @@ export class OpenTelemetryIntegration implements TelemetryIntegration {
174
183
  return context.with(toolSpanEntry.context, execute);
175
184
  }
176
185
 
186
+ /**
187
+ * Runs the provider `doGenerate`/`doStream` call with the active legacy
188
+ * model-call context.
189
+ */
190
+ executeLanguageModelCall<T>({
191
+ callId,
192
+ execute,
193
+ }: {
194
+ callId: string;
195
+ execute: () => PromiseLike<T>;
196
+ }): PromiseLike<T> {
197
+ const stepContext = this.getCallState(callId)?.stepContext;
198
+
199
+ if (stepContext == null) {
200
+ return execute();
201
+ }
202
+
203
+ return context.with(stepContext, execute);
204
+ }
205
+
177
206
  onStart(
178
207
  event:
179
- | OnStartEvent<ToolSet, Output>
180
- | ObjectOnStartEvent
181
- | EmbedOnStartEvent
182
- | RerankOnStartEvent,
208
+ | InferTelemetryEvent<GenerateTextStartEvent>
209
+ | InferTelemetryEvent<GenerateObjectStartEvent>
210
+ | InferTelemetryEvent<EmbedStartEvent>
211
+ | InferTelemetryEvent<RerankStartEvent>,
183
212
  ): void {
184
- if (event.isEnabled !== true) return;
185
-
186
213
  if (
187
214
  event.operationId === 'ai.embed' ||
188
215
  event.operationId === 'ai.embedMany'
189
216
  ) {
190
- this.onEmbedOperationStart(event as EmbedOnStartEvent);
217
+ this.onEmbedOperationStart(event as InferTelemetryEvent<EmbedStartEvent>);
191
218
  return;
192
219
  }
193
220
 
194
221
  if (event.operationId === 'ai.rerank') {
195
- this.onRerankOperationStart(event as RerankOnStartEvent);
222
+ this.onRerankOperationStart(
223
+ event as InferTelemetryEvent<RerankStartEvent>,
224
+ );
196
225
  return;
197
226
  }
198
227
 
@@ -200,20 +229,22 @@ export class OpenTelemetryIntegration implements TelemetryIntegration {
200
229
  event.operationId === 'ai.generateObject' ||
201
230
  event.operationId === 'ai.streamObject'
202
231
  ) {
203
- this.onObjectOperationStart(event as ObjectOnStartEvent);
232
+ this.onObjectOperationStart(
233
+ event as InferTelemetryEvent<GenerateObjectStartEvent>,
234
+ );
204
235
  return;
205
236
  }
206
237
 
207
- this.onGenerateStart(event as OnStartEvent<ToolSet, Output>);
238
+ this.onGenerateStart(event as InferTelemetryEvent<GenerateTextStartEvent>);
208
239
  }
209
240
 
210
- private onGenerateStart(event: OnStartEvent<ToolSet, Output>): void {
211
- const telemetry: TelemetrySettings = {
212
- isEnabled: event.isEnabled,
241
+ private onGenerateStart(
242
+ event: InferTelemetryEvent<GenerateTextStartEvent>,
243
+ ): void {
244
+ const telemetry: TelemetryOptions = {
213
245
  recordInputs: event.recordInputs,
214
246
  recordOutputs: event.recordOutputs,
215
247
  functionId: event.functionId,
216
- metadata: event.metadata,
217
248
  };
218
249
 
219
250
  const settings: Record<string, unknown> = {
@@ -230,9 +261,9 @@ export class OpenTelemetryIntegration implements TelemetryIntegration {
230
261
 
231
262
  const baseTelemetryAttributes = getBaseTelemetryAttributes({
232
263
  model: { provider: event.provider, modelId: event.modelId },
233
- telemetry,
234
264
  headers: event.headers,
235
265
  settings,
266
+ context: event.runtimeContext as Record<string, unknown> | undefined,
236
267
  });
237
268
 
238
269
  const attributes = selectAttributes(telemetry, {
@@ -246,8 +277,7 @@ export class OpenTelemetryIntegration implements TelemetryIntegration {
246
277
  'ai.prompt': {
247
278
  input: () =>
248
279
  JSON.stringify({
249
- system: event.system,
250
- prompt: event.prompt,
280
+ system: event.instructions,
251
281
  messages: event.messages,
252
282
  }),
253
283
  },
@@ -271,13 +301,13 @@ export class OpenTelemetryIntegration implements TelemetryIntegration {
271
301
  });
272
302
  }
273
303
 
274
- private onObjectOperationStart(event: ObjectOnStartEvent): void {
275
- const telemetry: TelemetrySettings = {
276
- isEnabled: event.isEnabled,
304
+ private onObjectOperationStart(
305
+ event: InferTelemetryEvent<GenerateObjectStartEvent>,
306
+ ): void {
307
+ const telemetry: TelemetryOptions = {
277
308
  recordInputs: event.recordInputs,
278
309
  recordOutputs: event.recordOutputs,
279
310
  functionId: event.functionId,
280
- metadata: event.metadata,
281
311
  };
282
312
 
283
313
  const settings: Record<string, unknown> = {
@@ -293,9 +323,9 @@ export class OpenTelemetryIntegration implements TelemetryIntegration {
293
323
 
294
324
  const baseTelemetryAttributes = getBaseTelemetryAttributes({
295
325
  model: { provider: event.provider, modelId: event.modelId },
296
- telemetry,
297
326
  headers: event.headers,
298
327
  settings,
328
+ context: undefined,
299
329
  });
300
330
 
301
331
  const attributes = selectAttributes(telemetry, {
@@ -339,7 +369,7 @@ export class OpenTelemetryIntegration implements TelemetryIntegration {
339
369
  }
340
370
 
341
371
  /** @deprecated */
342
- onObjectStepStart(event: ObjectOnStepStartEvent): void {
372
+ onObjectStepStart(event: GenerateObjectStepStartEvent): void {
343
373
  const state = this.getCallState(event.callId);
344
374
  if (!state?.rootSpan || !state.rootContext) return;
345
375
 
@@ -390,7 +420,7 @@ export class OpenTelemetryIntegration implements TelemetryIntegration {
390
420
  }
391
421
 
392
422
  /** @deprecated */
393
- onObjectStepFinish(event: ObjectOnStepFinishEvent): void {
423
+ onObjectStepEnd(event: GenerateObjectStepEndEvent): void {
394
424
  const state = this.getCallState(event.callId);
395
425
  if (!state?.stepSpan) return;
396
426
 
@@ -418,8 +448,10 @@ export class OpenTelemetryIntegration implements TelemetryIntegration {
418
448
  'ai.usage.inputTokens': event.usage.inputTokens,
419
449
  'ai.usage.outputTokens': event.usage.outputTokens,
420
450
  'ai.usage.totalTokens': event.usage.totalTokens,
421
- 'ai.usage.reasoningTokens': event.usage.reasoningTokens,
422
- 'ai.usage.cachedInputTokens': event.usage.cachedInputTokens,
451
+ 'ai.usage.reasoningTokens':
452
+ event.usage.outputTokenDetails?.reasoningTokens,
453
+ 'ai.usage.cachedInputTokens':
454
+ event.usage.inputTokenDetails?.cacheReadTokens,
423
455
 
424
456
  'gen_ai.response.finish_reasons': [event.finishReason],
425
457
  'gen_ai.response.id': event.response.id,
@@ -443,13 +475,13 @@ export class OpenTelemetryIntegration implements TelemetryIntegration {
443
475
  state.stepContext = undefined;
444
476
  }
445
477
 
446
- private onEmbedOperationStart(event: EmbedOnStartEvent): void {
447
- const telemetry: TelemetrySettings = {
448
- isEnabled: event.isEnabled,
478
+ private onEmbedOperationStart(
479
+ event: InferTelemetryEvent<EmbedStartEvent>,
480
+ ): void {
481
+ const telemetry: TelemetryOptions = {
449
482
  recordInputs: event.recordInputs,
450
483
  recordOutputs: event.recordOutputs,
451
484
  functionId: event.functionId,
452
- metadata: event.metadata,
453
485
  };
454
486
 
455
487
  const settings: Record<string, unknown> = {
@@ -458,9 +490,9 @@ export class OpenTelemetryIntegration implements TelemetryIntegration {
458
490
 
459
491
  const baseTelemetryAttributes = getBaseTelemetryAttributes({
460
492
  model: { provider: event.provider, modelId: event.modelId },
461
- telemetry,
462
493
  headers: event.headers,
463
494
  settings,
495
+ context: undefined,
464
496
  });
465
497
 
466
498
  const value = event.value;
@@ -503,7 +535,7 @@ export class OpenTelemetryIntegration implements TelemetryIntegration {
503
535
  });
504
536
  }
505
537
 
506
- onStepStart(event: OtelStepStartEvent<ToolSet, Output>): void {
538
+ onStepStart(event: OtelStepStartEvent): void {
507
539
  const state = this.getCallState(event.callId);
508
540
  if (!state?.rootSpan || !state.rootContext) return;
509
541
 
@@ -568,7 +600,7 @@ export class OpenTelemetryIntegration implements TelemetryIntegration {
568
600
  state.stepContext = trace.setSpan(state.rootContext, state.stepSpan);
569
601
  }
570
602
 
571
- onToolCallStart(event: OnToolCallStartEvent<ToolSet>): void {
603
+ onToolExecutionStart(event: ToolExecutionStartEvent<ToolSet>): void {
572
604
  const state = this.getCallState(event.callId);
573
605
  if (!state?.stepContext) return;
574
606
 
@@ -600,7 +632,7 @@ export class OpenTelemetryIntegration implements TelemetryIntegration {
600
632
  });
601
633
  }
602
634
 
603
- onToolCallFinish(event: OnToolCallFinishEvent<ToolSet>): void {
635
+ onToolExecutionEnd(event: ToolExecutionEndEvent<ToolSet>): void {
604
636
  const state = this.getCallState(event.callId);
605
637
  if (!state) return;
606
638
 
@@ -610,31 +642,33 @@ export class OpenTelemetryIntegration implements TelemetryIntegration {
610
642
  const { span } = toolSpanEntry;
611
643
  const { telemetry } = state;
612
644
 
613
- if (event.success) {
645
+ const { toolOutput } = event;
646
+ if (toolOutput.type === 'tool-result') {
614
647
  try {
615
648
  span.setAttributes(
616
649
  selectAttributes(telemetry, {
617
650
  'ai.toolCall.result': {
618
- output: () => JSON.stringify(event.output),
651
+ output: () => JSON.stringify(toolOutput.output),
619
652
  },
620
653
  }),
621
654
  );
622
- } catch (_ignored) {
655
+ } catch {
623
656
  // JSON.stringify might fail for non-serializable results
624
657
  }
625
658
  } else {
626
- recordSpanError(span, event.error);
659
+ recordSpanError(span, toolOutput.error);
627
660
  }
628
661
 
629
662
  span.end();
630
663
  state.toolSpans.delete(event.toolCall.toolCallId);
631
664
  }
632
665
 
633
- onStepFinish(event: OnStepFinishEvent<ToolSet>): void {
666
+ onStepEnd(event: GenerateTextStepEndEvent<ToolSet>): void {
634
667
  const state = this.getCallState(event.callId);
635
668
  if (!state?.stepSpan) return;
636
669
 
637
670
  const { telemetry } = state;
671
+ const isStreamText = state.operationId === 'ai.streamText';
638
672
 
639
673
  state.stepSpan.setAttributes(
640
674
  selectAttributes(telemetry, {
@@ -681,12 +715,23 @@ export class OpenTelemetryIntegration implements TelemetryIntegration {
681
715
  'ai.response.providerMetadata': event.providerMetadata
682
716
  ? JSON.stringify(event.providerMetadata)
683
717
  : undefined,
718
+ 'ai.response.msToFirstChunk': isStreamText
719
+ ? event.performance.timeToFirstOutputMs
720
+ : undefined,
721
+ 'ai.response.msToFinish': isStreamText
722
+ ? event.performance.responseTimeMs
723
+ : undefined,
724
+ 'ai.response.avgOutputTokensPerSecond': isStreamText
725
+ ? event.performance.effectiveOutputTokensPerSecond
726
+ : undefined,
684
727
 
685
728
  'ai.usage.inputTokens': event.usage.inputTokens,
686
729
  'ai.usage.outputTokens': event.usage.outputTokens,
687
730
  'ai.usage.totalTokens': event.usage.totalTokens,
688
- 'ai.usage.reasoningTokens': event.usage.reasoningTokens,
689
- 'ai.usage.cachedInputTokens': event.usage.cachedInputTokens,
731
+ 'ai.usage.reasoningTokens':
732
+ event.usage.outputTokenDetails?.reasoningTokens,
733
+ 'ai.usage.cachedInputTokens':
734
+ event.usage.inputTokenDetails?.cacheReadTokens,
690
735
  'ai.usage.inputTokenDetails.noCacheTokens':
691
736
  event.usage.inputTokenDetails?.noCacheTokens,
692
737
  'ai.usage.inputTokenDetails.cacheReadTokens':
@@ -706,17 +751,36 @@ export class OpenTelemetryIntegration implements TelemetryIntegration {
706
751
  }),
707
752
  );
708
753
 
754
+ if (isStreamText && event.performance.timeToFirstOutputMs != null) {
755
+ state.stepSpan.addEvent('ai.stream.firstChunk', {
756
+ 'ai.response.msToFirstChunk': event.performance.timeToFirstOutputMs,
757
+ });
758
+ }
759
+
760
+ if (isStreamText) {
761
+ state.stepSpan.addEvent('ai.stream.finish', {
762
+ 'ai.response.msToFinish': event.performance.responseTimeMs,
763
+ 'ai.response.avgOutputTokensPerSecond':
764
+ event.performance.effectiveOutputTokensPerSecond,
765
+ });
766
+ }
767
+
709
768
  state.stepSpan.end();
710
769
  state.stepSpan = undefined;
711
770
  state.stepContext = undefined;
712
771
  }
713
772
 
714
- onFinish(
773
+ /** @deprecated Use `onStepEnd` instead. */
774
+ onStepFinish(event: GenerateTextStepEndEvent<ToolSet>): void {
775
+ this.onStepEnd(event);
776
+ }
777
+
778
+ onEnd(
715
779
  event:
716
- | OnFinishEvent<ToolSet>
717
- | ObjectOnFinishEvent<unknown>
718
- | EmbedOnFinishEvent
719
- | RerankOnFinishEvent,
780
+ | GenerateTextEndEvent<ToolSet>
781
+ | GenerateObjectEndEvent<unknown>
782
+ | EmbedEndEvent
783
+ | RerankEndEvent,
720
784
  ): void {
721
785
  const state = this.getCallState(event.callId);
722
786
  if (!state?.rootSpan) return;
@@ -725,12 +789,12 @@ export class OpenTelemetryIntegration implements TelemetryIntegration {
725
789
  state.operationId === 'ai.embed' ||
726
790
  state.operationId === 'ai.embedMany'
727
791
  ) {
728
- this.onEmbedOperationFinish(event as EmbedOnFinishEvent);
792
+ this.onEmbedOperationEnd(event as EmbedEndEvent);
729
793
  return;
730
794
  }
731
795
 
732
796
  if (state.operationId === 'ai.rerank') {
733
- this.onRerankOperationFinish(event as RerankOnFinishEvent);
797
+ this.onRerankOperationEnd(event as RerankEndEvent);
734
798
  return;
735
799
  }
736
800
 
@@ -738,14 +802,14 @@ export class OpenTelemetryIntegration implements TelemetryIntegration {
738
802
  state.operationId === 'ai.generateObject' ||
739
803
  state.operationId === 'ai.streamObject'
740
804
  ) {
741
- this.onObjectOperationFinish(event as ObjectOnFinishEvent<unknown>);
805
+ this.onObjectOperationEnd(event as GenerateObjectEndEvent<unknown>);
742
806
  return;
743
807
  }
744
808
 
745
- this.onGenerateFinish(event as OnFinishEvent<ToolSet>);
809
+ this.onGenerateEnd(event as GenerateTextEndEvent<ToolSet>);
746
810
  }
747
811
 
748
- private onGenerateFinish(event: OnFinishEvent<ToolSet>): void {
812
+ private onGenerateEnd(event: GenerateTextEndEvent<ToolSet>): void {
749
813
  const state = this.getCallState(event.callId);
750
814
  if (!state?.rootSpan) return;
751
815
 
@@ -759,8 +823,8 @@ export class OpenTelemetryIntegration implements TelemetryIntegration {
759
823
  },
760
824
  'ai.response.reasoning': {
761
825
  output: () =>
762
- event.reasoning.length > 0
763
- ? event.reasoning
826
+ event.finalStep.reasoning.length > 0
827
+ ? event.finalStep.reasoning
764
828
  .filter(part => 'text' in part)
765
829
  .map(part => part.text)
766
830
  .join('\n')
@@ -790,25 +854,27 @@ export class OpenTelemetryIntegration implements TelemetryIntegration {
790
854
  )
791
855
  : undefined,
792
856
  },
793
- 'ai.response.providerMetadata': event.providerMetadata
794
- ? JSON.stringify(event.providerMetadata)
857
+ 'ai.response.providerMetadata': event.finalStep.providerMetadata
858
+ ? JSON.stringify(event.finalStep.providerMetadata)
795
859
  : undefined,
796
860
 
797
- 'ai.usage.inputTokens': event.totalUsage.inputTokens,
798
- 'ai.usage.outputTokens': event.totalUsage.outputTokens,
799
- 'ai.usage.totalTokens': event.totalUsage.totalTokens,
800
- 'ai.usage.reasoningTokens': event.totalUsage.reasoningTokens,
801
- 'ai.usage.cachedInputTokens': event.totalUsage.cachedInputTokens,
861
+ 'ai.usage.inputTokens': event.usage.inputTokens,
862
+ 'ai.usage.outputTokens': event.usage.outputTokens,
863
+ 'ai.usage.totalTokens': event.usage.totalTokens,
864
+ 'ai.usage.reasoningTokens':
865
+ event.usage.outputTokenDetails?.reasoningTokens,
866
+ 'ai.usage.cachedInputTokens':
867
+ event.usage.inputTokenDetails?.cacheReadTokens,
802
868
  'ai.usage.inputTokenDetails.noCacheTokens':
803
- event.totalUsage.inputTokenDetails?.noCacheTokens,
869
+ event.usage.inputTokenDetails?.noCacheTokens,
804
870
  'ai.usage.inputTokenDetails.cacheReadTokens':
805
- event.totalUsage.inputTokenDetails?.cacheReadTokens,
871
+ event.usage.inputTokenDetails?.cacheReadTokens,
806
872
  'ai.usage.inputTokenDetails.cacheWriteTokens':
807
- event.totalUsage.inputTokenDetails?.cacheWriteTokens,
873
+ event.usage.inputTokenDetails?.cacheWriteTokens,
808
874
  'ai.usage.outputTokenDetails.textTokens':
809
- event.totalUsage.outputTokenDetails?.textTokens,
875
+ event.usage.outputTokenDetails?.textTokens,
810
876
  'ai.usage.outputTokenDetails.reasoningTokens':
811
- event.totalUsage.outputTokenDetails?.reasoningTokens,
877
+ event.usage.outputTokenDetails?.reasoningTokens,
812
878
  }),
813
879
  );
814
880
 
@@ -816,7 +882,7 @@ export class OpenTelemetryIntegration implements TelemetryIntegration {
816
882
  this.cleanupCallState(event.callId);
817
883
  }
818
884
 
819
- private onObjectOperationFinish(event: ObjectOnFinishEvent<unknown>): void {
885
+ private onObjectOperationEnd(event: GenerateObjectEndEvent<unknown>): void {
820
886
  const state = this.getCallState(event.callId);
821
887
  if (!state?.rootSpan) return;
822
888
 
@@ -836,8 +902,10 @@ export class OpenTelemetryIntegration implements TelemetryIntegration {
836
902
  'ai.usage.inputTokens': event.usage.inputTokens,
837
903
  'ai.usage.outputTokens': event.usage.outputTokens,
838
904
  'ai.usage.totalTokens': event.usage.totalTokens,
839
- 'ai.usage.reasoningTokens': event.usage.reasoningTokens,
840
- 'ai.usage.cachedInputTokens': event.usage.cachedInputTokens,
905
+ 'ai.usage.reasoningTokens':
906
+ event.usage.outputTokenDetails?.reasoningTokens,
907
+ 'ai.usage.cachedInputTokens':
908
+ event.usage.inputTokenDetails?.cacheReadTokens,
841
909
  }),
842
910
  );
843
911
 
@@ -845,7 +913,7 @@ export class OpenTelemetryIntegration implements TelemetryIntegration {
845
913
  this.cleanupCallState(event.callId);
846
914
  }
847
915
 
848
- private onEmbedOperationFinish(event: EmbedOnFinishEvent): void {
916
+ private onEmbedOperationEnd(event: EmbedEndEvent): void {
849
917
  const state = this.getCallState(event.callId);
850
918
  if (!state?.rootSpan) return;
851
919
 
@@ -874,7 +942,7 @@ export class OpenTelemetryIntegration implements TelemetryIntegration {
874
942
  this.cleanupCallState(event.callId);
875
943
  }
876
944
 
877
- onEmbedStart(event: EmbedStartEvent): void {
945
+ onEmbedStart(event: EmbeddingModelCallStartEvent): void {
878
946
  const state = this.getCallState(event.callId);
879
947
  if (!state?.rootSpan || !state.rootContext) return;
880
948
 
@@ -904,7 +972,7 @@ export class OpenTelemetryIntegration implements TelemetryIntegration {
904
972
  });
905
973
  }
906
974
 
907
- onEmbedFinish(event: EmbedFinishEvent): void {
975
+ onEmbedEnd(event: EmbeddingModelCallEndEvent): void {
908
976
  const state = this.getCallState(event.callId);
909
977
  if (!state) return;
910
978
 
@@ -928,13 +996,13 @@ export class OpenTelemetryIntegration implements TelemetryIntegration {
928
996
  state.embedSpans.delete(event.embedCallId);
929
997
  }
930
998
 
931
- private onRerankOperationStart(event: RerankOnStartEvent): void {
932
- const telemetry: TelemetrySettings = {
933
- isEnabled: event.isEnabled,
999
+ private onRerankOperationStart(
1000
+ event: InferTelemetryEvent<RerankStartEvent>,
1001
+ ): void {
1002
+ const telemetry: TelemetryOptions = {
934
1003
  recordInputs: event.recordInputs,
935
1004
  recordOutputs: event.recordOutputs,
936
1005
  functionId: event.functionId,
937
- metadata: event.metadata,
938
1006
  };
939
1007
 
940
1008
  const settings: Record<string, unknown> = {
@@ -943,9 +1011,9 @@ export class OpenTelemetryIntegration implements TelemetryIntegration {
943
1011
 
944
1012
  const baseTelemetryAttributes = getBaseTelemetryAttributes({
945
1013
  model: { provider: event.provider, modelId: event.modelId },
946
- telemetry,
947
1014
  headers: event.headers,
948
1015
  settings,
1016
+ context: undefined,
949
1017
  });
950
1018
 
951
1019
  const attributes = selectAttributes(telemetry, {
@@ -977,7 +1045,7 @@ export class OpenTelemetryIntegration implements TelemetryIntegration {
977
1045
  });
978
1046
  }
979
1047
 
980
- private onRerankOperationFinish(event: RerankOnFinishEvent): void {
1048
+ private onRerankOperationEnd(event: RerankEndEvent): void {
981
1049
  const state = this.getCallState(event.callId);
982
1050
  if (!state?.rootSpan) return;
983
1051
 
@@ -985,7 +1053,7 @@ export class OpenTelemetryIntegration implements TelemetryIntegration {
985
1053
  this.cleanupCallState(event.callId);
986
1054
  }
987
1055
 
988
- onRerankStart(event: RerankStartEvent): void {
1056
+ onRerankStart(event: RerankingModelCallStartEvent): void {
989
1057
  const state = this.getCallState(event.callId);
990
1058
  if (!state?.rootSpan || !state.rootContext) return;
991
1059
 
@@ -1012,7 +1080,7 @@ export class OpenTelemetryIntegration implements TelemetryIntegration {
1012
1080
  state.rerankSpan = { span: rerankSpan, context: rerankContext };
1013
1081
  }
1014
1082
 
1015
- onRerankFinish(event: RerankFinishEvent): void {
1083
+ onRerankEnd(event: RerankingModelCallEndEvent): void {
1016
1084
  const state = this.getCallState(event.callId);
1017
1085
  if (!state?.rerankSpan) return;
1018
1086
 
@@ -1032,37 +1100,33 @@ export class OpenTelemetryIntegration implements TelemetryIntegration {
1032
1100
  state.rerankSpan = undefined;
1033
1101
  }
1034
1102
 
1035
- onChunk(event: OnChunkEvent<ToolSet>): void {
1036
- const chunk = event.chunk as {
1037
- type: string;
1038
- callId?: unknown;
1039
- attributes?: unknown;
1040
- };
1103
+ onAbort(event: GenerateTextAbortEvent<ToolSet>): void {
1104
+ const state = this.getCallState(event.callId);
1105
+ if (!state?.rootSpan) return;
1041
1106
 
1042
- if (typeof chunk.callId !== 'string') {
1043
- return;
1107
+ for (const { span: toolSpan } of state.toolSpans.values()) {
1108
+ toolSpan.end();
1044
1109
  }
1110
+ state.toolSpans.clear();
1045
1111
 
1046
- if (
1047
- chunk.type !== 'ai.stream.firstChunk' &&
1048
- chunk.type !== 'ai.stream.finish'
1049
- ) {
1050
- return;
1112
+ if (state.stepSpan) {
1113
+ state.stepSpan.end();
1114
+ state.stepSpan = undefined;
1115
+ state.stepContext = undefined;
1051
1116
  }
1052
1117
 
1053
- const state = this.getCallState(chunk.callId);
1054
- if (!state?.stepSpan) return;
1055
-
1056
- const attributes = Object.fromEntries(
1057
- Object.entries(
1058
- (chunk.attributes as Record<string, unknown>) ?? {},
1059
- ).filter(([, value]) => value != null),
1060
- ) as Attributes;
1118
+ for (const { span: embedSpan } of state.embedSpans.values()) {
1119
+ embedSpan.end();
1120
+ }
1121
+ state.embedSpans.clear();
1061
1122
 
1062
- state.stepSpan.addEvent(chunk.type, attributes);
1063
- if (Object.keys(attributes).length > 0) {
1064
- state.stepSpan.setAttributes(attributes);
1123
+ if (state.rerankSpan) {
1124
+ state.rerankSpan.span.end();
1125
+ state.rerankSpan = undefined;
1065
1126
  }
1127
+
1128
+ state.rootSpan.end();
1129
+ this.cleanupCallState(event.callId);
1066
1130
  }
1067
1131
 
1068
1132
  onError(error: unknown): void {