@ai-sdk/otel 1.0.0-beta.12 → 1.0.0-beta.123

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,38 +1,39 @@
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';
@@ -56,13 +57,13 @@ function recordSpanError(span: Span, error: unknown): void {
56
57
  }
57
58
 
58
59
  function shouldRecord(
59
- telemetry: TelemetrySettings | undefined,
60
- ): telemetry is TelemetrySettings {
61
- return telemetry?.isEnabled === true;
60
+ telemetry: TelemetryOptions | undefined,
61
+ ): telemetry is TelemetryOptions {
62
+ return telemetry?.isEnabled !== false;
62
63
  }
63
64
 
64
65
  function selectAttributes(
65
- telemetry: TelemetrySettings | undefined,
66
+ telemetry: TelemetryOptions | undefined,
66
67
  attributes: Record<
67
68
  string,
68
69
  | AttributeValue
@@ -110,9 +111,9 @@ function selectAttributes(
110
111
 
111
112
  interface OtelStepStartEvent<
112
113
  TOOLS extends ToolSet = ToolSet,
113
- CONTEXT extends GenerationContext<TOOLS> = GenerationContext<TOOLS>,
114
- OUTPUT extends Output = Output,
115
- > extends OnStepStartEvent<TOOLS, CONTEXT, OUTPUT> {
114
+ RUNTIME_CONTEXT extends AISDKContext = AISDKContext,
115
+ OUTPUT extends Output.Output = Output.Output,
116
+ > extends GenerateTextStepStartEvent<TOOLS, RUNTIME_CONTEXT, OUTPUT> {
116
117
  readonly promptMessages?: LanguageModelV4Prompt;
117
118
  readonly stepTools?: ReadonlyArray<Record<string, unknown>>;
118
119
  readonly stepToolChoice?: unknown;
@@ -120,19 +121,19 @@ interface OtelStepStartEvent<
120
121
 
121
122
  interface CallState {
122
123
  operationId: string;
123
- telemetry: TelemetrySettings | undefined;
124
+ telemetry: TelemetryOptions | undefined;
124
125
  rootSpan: Span | undefined;
125
- rootContext: Context | undefined;
126
+ rootContext: OpenTelemetryContext | undefined;
126
127
  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 }>;
128
+ stepContext: OpenTelemetryContext | undefined;
129
+ embedSpans: Map<string, { span: Span; context: OpenTelemetryContext }>;
130
+ rerankSpan: { span: Span; context: OpenTelemetryContext } | undefined;
131
+ toolSpans: Map<string, { span: Span; context: OpenTelemetryContext }>;
131
132
  baseTelemetryAttributes: Attributes;
132
133
  settings: Record<string, unknown>;
133
134
  }
134
135
 
135
- export class OpenTelemetryIntegration implements TelemetryIntegration {
136
+ export class LegacyOpenTelemetry implements Telemetry {
136
137
  private readonly callStates = new Map<string, CallState>();
137
138
 
138
139
  /**
@@ -174,25 +175,45 @@ export class OpenTelemetryIntegration implements TelemetryIntegration {
174
175
  return context.with(toolSpanEntry.context, execute);
175
176
  }
176
177
 
178
+ /**
179
+ * Runs the provider `doGenerate`/`doStream` call with the active legacy
180
+ * model-call context.
181
+ */
182
+ executeLanguageModelCall<T>({
183
+ callId,
184
+ execute,
185
+ }: {
186
+ callId: string;
187
+ execute: () => PromiseLike<T>;
188
+ }): PromiseLike<T> {
189
+ const stepContext = this.getCallState(callId)?.stepContext;
190
+
191
+ if (stepContext == null) {
192
+ return execute();
193
+ }
194
+
195
+ return context.with(stepContext, execute);
196
+ }
197
+
177
198
  onStart(
178
199
  event:
179
- | OnStartEvent<ToolSet, Output>
180
- | ObjectOnStartEvent
181
- | EmbedOnStartEvent
182
- | RerankOnStartEvent,
200
+ | InferTelemetryEvent<GenerateTextStartEvent>
201
+ | InferTelemetryEvent<GenerateObjectStartEvent>
202
+ | InferTelemetryEvent<EmbedStartEvent>
203
+ | InferTelemetryEvent<RerankStartEvent>,
183
204
  ): void {
184
- if (event.isEnabled !== true) return;
185
-
186
205
  if (
187
206
  event.operationId === 'ai.embed' ||
188
207
  event.operationId === 'ai.embedMany'
189
208
  ) {
190
- this.onEmbedOperationStart(event as EmbedOnStartEvent);
209
+ this.onEmbedOperationStart(event as InferTelemetryEvent<EmbedStartEvent>);
191
210
  return;
192
211
  }
193
212
 
194
213
  if (event.operationId === 'ai.rerank') {
195
- this.onRerankOperationStart(event as RerankOnStartEvent);
214
+ this.onRerankOperationStart(
215
+ event as InferTelemetryEvent<RerankStartEvent>,
216
+ );
196
217
  return;
197
218
  }
198
219
 
@@ -200,20 +221,22 @@ export class OpenTelemetryIntegration implements TelemetryIntegration {
200
221
  event.operationId === 'ai.generateObject' ||
201
222
  event.operationId === 'ai.streamObject'
202
223
  ) {
203
- this.onObjectOperationStart(event as ObjectOnStartEvent);
224
+ this.onObjectOperationStart(
225
+ event as InferTelemetryEvent<GenerateObjectStartEvent>,
226
+ );
204
227
  return;
205
228
  }
206
229
 
207
- this.onGenerateStart(event as OnStartEvent<ToolSet, Output>);
230
+ this.onGenerateStart(event as InferTelemetryEvent<GenerateTextStartEvent>);
208
231
  }
209
232
 
210
- private onGenerateStart(event: OnStartEvent<ToolSet, Output>): void {
211
- const telemetry: TelemetrySettings = {
212
- isEnabled: event.isEnabled,
233
+ private onGenerateStart(
234
+ event: InferTelemetryEvent<GenerateTextStartEvent>,
235
+ ): void {
236
+ const telemetry: TelemetryOptions = {
213
237
  recordInputs: event.recordInputs,
214
238
  recordOutputs: event.recordOutputs,
215
239
  functionId: event.functionId,
216
- metadata: event.metadata,
217
240
  };
218
241
 
219
242
  const settings: Record<string, unknown> = {
@@ -230,9 +253,9 @@ export class OpenTelemetryIntegration implements TelemetryIntegration {
230
253
 
231
254
  const baseTelemetryAttributes = getBaseTelemetryAttributes({
232
255
  model: { provider: event.provider, modelId: event.modelId },
233
- telemetry,
234
256
  headers: event.headers,
235
257
  settings,
258
+ context: event.runtimeContext as Record<string, unknown> | undefined,
236
259
  });
237
260
 
238
261
  const attributes = selectAttributes(telemetry, {
@@ -246,8 +269,7 @@ export class OpenTelemetryIntegration implements TelemetryIntegration {
246
269
  'ai.prompt': {
247
270
  input: () =>
248
271
  JSON.stringify({
249
- system: event.system,
250
- prompt: event.prompt,
272
+ system: event.instructions,
251
273
  messages: event.messages,
252
274
  }),
253
275
  },
@@ -271,13 +293,13 @@ export class OpenTelemetryIntegration implements TelemetryIntegration {
271
293
  });
272
294
  }
273
295
 
274
- private onObjectOperationStart(event: ObjectOnStartEvent): void {
275
- const telemetry: TelemetrySettings = {
276
- isEnabled: event.isEnabled,
296
+ private onObjectOperationStart(
297
+ event: InferTelemetryEvent<GenerateObjectStartEvent>,
298
+ ): void {
299
+ const telemetry: TelemetryOptions = {
277
300
  recordInputs: event.recordInputs,
278
301
  recordOutputs: event.recordOutputs,
279
302
  functionId: event.functionId,
280
- metadata: event.metadata,
281
303
  };
282
304
 
283
305
  const settings: Record<string, unknown> = {
@@ -293,9 +315,9 @@ export class OpenTelemetryIntegration implements TelemetryIntegration {
293
315
 
294
316
  const baseTelemetryAttributes = getBaseTelemetryAttributes({
295
317
  model: { provider: event.provider, modelId: event.modelId },
296
- telemetry,
297
318
  headers: event.headers,
298
319
  settings,
320
+ context: undefined,
299
321
  });
300
322
 
301
323
  const attributes = selectAttributes(telemetry, {
@@ -339,7 +361,7 @@ export class OpenTelemetryIntegration implements TelemetryIntegration {
339
361
  }
340
362
 
341
363
  /** @deprecated */
342
- onObjectStepStart(event: ObjectOnStepStartEvent): void {
364
+ onObjectStepStart(event: GenerateObjectStepStartEvent): void {
343
365
  const state = this.getCallState(event.callId);
344
366
  if (!state?.rootSpan || !state.rootContext) return;
345
367
 
@@ -390,7 +412,7 @@ export class OpenTelemetryIntegration implements TelemetryIntegration {
390
412
  }
391
413
 
392
414
  /** @deprecated */
393
- onObjectStepFinish(event: ObjectOnStepFinishEvent): void {
415
+ onObjectStepEnd(event: GenerateObjectStepEndEvent): void {
394
416
  const state = this.getCallState(event.callId);
395
417
  if (!state?.stepSpan) return;
396
418
 
@@ -418,8 +440,10 @@ export class OpenTelemetryIntegration implements TelemetryIntegration {
418
440
  'ai.usage.inputTokens': event.usage.inputTokens,
419
441
  'ai.usage.outputTokens': event.usage.outputTokens,
420
442
  'ai.usage.totalTokens': event.usage.totalTokens,
421
- 'ai.usage.reasoningTokens': event.usage.reasoningTokens,
422
- 'ai.usage.cachedInputTokens': event.usage.cachedInputTokens,
443
+ 'ai.usage.reasoningTokens':
444
+ event.usage.outputTokenDetails?.reasoningTokens,
445
+ 'ai.usage.cachedInputTokens':
446
+ event.usage.inputTokenDetails?.cacheReadTokens,
423
447
 
424
448
  'gen_ai.response.finish_reasons': [event.finishReason],
425
449
  'gen_ai.response.id': event.response.id,
@@ -443,13 +467,13 @@ export class OpenTelemetryIntegration implements TelemetryIntegration {
443
467
  state.stepContext = undefined;
444
468
  }
445
469
 
446
- private onEmbedOperationStart(event: EmbedOnStartEvent): void {
447
- const telemetry: TelemetrySettings = {
448
- isEnabled: event.isEnabled,
470
+ private onEmbedOperationStart(
471
+ event: InferTelemetryEvent<EmbedStartEvent>,
472
+ ): void {
473
+ const telemetry: TelemetryOptions = {
449
474
  recordInputs: event.recordInputs,
450
475
  recordOutputs: event.recordOutputs,
451
476
  functionId: event.functionId,
452
- metadata: event.metadata,
453
477
  };
454
478
 
455
479
  const settings: Record<string, unknown> = {
@@ -458,9 +482,9 @@ export class OpenTelemetryIntegration implements TelemetryIntegration {
458
482
 
459
483
  const baseTelemetryAttributes = getBaseTelemetryAttributes({
460
484
  model: { provider: event.provider, modelId: event.modelId },
461
- telemetry,
462
485
  headers: event.headers,
463
486
  settings,
487
+ context: undefined,
464
488
  });
465
489
 
466
490
  const value = event.value;
@@ -503,7 +527,7 @@ export class OpenTelemetryIntegration implements TelemetryIntegration {
503
527
  });
504
528
  }
505
529
 
506
- onStepStart(event: OtelStepStartEvent<ToolSet, Output>): void {
530
+ onStepStart(event: OtelStepStartEvent): void {
507
531
  const state = this.getCallState(event.callId);
508
532
  if (!state?.rootSpan || !state.rootContext) return;
509
533
 
@@ -568,7 +592,7 @@ export class OpenTelemetryIntegration implements TelemetryIntegration {
568
592
  state.stepContext = trace.setSpan(state.rootContext, state.stepSpan);
569
593
  }
570
594
 
571
- onToolCallStart(event: OnToolCallStartEvent<ToolSet>): void {
595
+ onToolExecutionStart(event: ToolExecutionStartEvent<ToolSet>): void {
572
596
  const state = this.getCallState(event.callId);
573
597
  if (!state?.stepContext) return;
574
598
 
@@ -600,7 +624,7 @@ export class OpenTelemetryIntegration implements TelemetryIntegration {
600
624
  });
601
625
  }
602
626
 
603
- onToolCallFinish(event: OnToolCallFinishEvent<ToolSet>): void {
627
+ onToolExecutionEnd(event: ToolExecutionEndEvent<ToolSet>): void {
604
628
  const state = this.getCallState(event.callId);
605
629
  if (!state) return;
606
630
 
@@ -610,31 +634,33 @@ export class OpenTelemetryIntegration implements TelemetryIntegration {
610
634
  const { span } = toolSpanEntry;
611
635
  const { telemetry } = state;
612
636
 
613
- if (event.success) {
637
+ const { toolOutput } = event;
638
+ if (toolOutput.type === 'tool-result') {
614
639
  try {
615
640
  span.setAttributes(
616
641
  selectAttributes(telemetry, {
617
642
  'ai.toolCall.result': {
618
- output: () => JSON.stringify(event.output),
643
+ output: () => JSON.stringify(toolOutput.output),
619
644
  },
620
645
  }),
621
646
  );
622
- } catch (_ignored) {
647
+ } catch {
623
648
  // JSON.stringify might fail for non-serializable results
624
649
  }
625
650
  } else {
626
- recordSpanError(span, event.error);
651
+ recordSpanError(span, toolOutput.error);
627
652
  }
628
653
 
629
654
  span.end();
630
655
  state.toolSpans.delete(event.toolCall.toolCallId);
631
656
  }
632
657
 
633
- onStepFinish(event: OnStepFinishEvent<ToolSet>): void {
658
+ onStepEnd(event: GenerateTextStepEndEvent<ToolSet>): void {
634
659
  const state = this.getCallState(event.callId);
635
660
  if (!state?.stepSpan) return;
636
661
 
637
662
  const { telemetry } = state;
663
+ const isStreamText = state.operationId === 'ai.streamText';
638
664
 
639
665
  state.stepSpan.setAttributes(
640
666
  selectAttributes(telemetry, {
@@ -681,12 +707,23 @@ export class OpenTelemetryIntegration implements TelemetryIntegration {
681
707
  'ai.response.providerMetadata': event.providerMetadata
682
708
  ? JSON.stringify(event.providerMetadata)
683
709
  : undefined,
710
+ 'ai.response.msToFirstChunk': isStreamText
711
+ ? event.performance.timeToFirstOutputMs
712
+ : undefined,
713
+ 'ai.response.msToFinish': isStreamText
714
+ ? event.performance.responseTimeMs
715
+ : undefined,
716
+ 'ai.response.avgOutputTokensPerSecond': isStreamText
717
+ ? event.performance.effectiveOutputTokensPerSecond
718
+ : undefined,
684
719
 
685
720
  'ai.usage.inputTokens': event.usage.inputTokens,
686
721
  'ai.usage.outputTokens': event.usage.outputTokens,
687
722
  'ai.usage.totalTokens': event.usage.totalTokens,
688
- 'ai.usage.reasoningTokens': event.usage.reasoningTokens,
689
- 'ai.usage.cachedInputTokens': event.usage.cachedInputTokens,
723
+ 'ai.usage.reasoningTokens':
724
+ event.usage.outputTokenDetails?.reasoningTokens,
725
+ 'ai.usage.cachedInputTokens':
726
+ event.usage.inputTokenDetails?.cacheReadTokens,
690
727
  'ai.usage.inputTokenDetails.noCacheTokens':
691
728
  event.usage.inputTokenDetails?.noCacheTokens,
692
729
  'ai.usage.inputTokenDetails.cacheReadTokens':
@@ -706,17 +743,36 @@ export class OpenTelemetryIntegration implements TelemetryIntegration {
706
743
  }),
707
744
  );
708
745
 
746
+ if (isStreamText && event.performance.timeToFirstOutputMs != null) {
747
+ state.stepSpan.addEvent('ai.stream.firstChunk', {
748
+ 'ai.response.msToFirstChunk': event.performance.timeToFirstOutputMs,
749
+ });
750
+ }
751
+
752
+ if (isStreamText) {
753
+ state.stepSpan.addEvent('ai.stream.finish', {
754
+ 'ai.response.msToFinish': event.performance.responseTimeMs,
755
+ 'ai.response.avgOutputTokensPerSecond':
756
+ event.performance.effectiveOutputTokensPerSecond,
757
+ });
758
+ }
759
+
709
760
  state.stepSpan.end();
710
761
  state.stepSpan = undefined;
711
762
  state.stepContext = undefined;
712
763
  }
713
764
 
714
- onFinish(
765
+ /** @deprecated Use `onStepEnd` instead. */
766
+ onStepFinish(event: GenerateTextStepEndEvent<ToolSet>): void {
767
+ this.onStepEnd(event);
768
+ }
769
+
770
+ onEnd(
715
771
  event:
716
- | OnFinishEvent<ToolSet>
717
- | ObjectOnFinishEvent<unknown>
718
- | EmbedOnFinishEvent
719
- | RerankOnFinishEvent,
772
+ | GenerateTextEndEvent<ToolSet>
773
+ | GenerateObjectEndEvent<unknown>
774
+ | EmbedEndEvent
775
+ | RerankEndEvent,
720
776
  ): void {
721
777
  const state = this.getCallState(event.callId);
722
778
  if (!state?.rootSpan) return;
@@ -725,12 +781,12 @@ export class OpenTelemetryIntegration implements TelemetryIntegration {
725
781
  state.operationId === 'ai.embed' ||
726
782
  state.operationId === 'ai.embedMany'
727
783
  ) {
728
- this.onEmbedOperationFinish(event as EmbedOnFinishEvent);
784
+ this.onEmbedOperationEnd(event as EmbedEndEvent);
729
785
  return;
730
786
  }
731
787
 
732
788
  if (state.operationId === 'ai.rerank') {
733
- this.onRerankOperationFinish(event as RerankOnFinishEvent);
789
+ this.onRerankOperationEnd(event as RerankEndEvent);
734
790
  return;
735
791
  }
736
792
 
@@ -738,14 +794,14 @@ export class OpenTelemetryIntegration implements TelemetryIntegration {
738
794
  state.operationId === 'ai.generateObject' ||
739
795
  state.operationId === 'ai.streamObject'
740
796
  ) {
741
- this.onObjectOperationFinish(event as ObjectOnFinishEvent<unknown>);
797
+ this.onObjectOperationEnd(event as GenerateObjectEndEvent<unknown>);
742
798
  return;
743
799
  }
744
800
 
745
- this.onGenerateFinish(event as OnFinishEvent<ToolSet>);
801
+ this.onGenerateEnd(event as GenerateTextEndEvent<ToolSet>);
746
802
  }
747
803
 
748
- private onGenerateFinish(event: OnFinishEvent<ToolSet>): void {
804
+ private onGenerateEnd(event: GenerateTextEndEvent<ToolSet>): void {
749
805
  const state = this.getCallState(event.callId);
750
806
  if (!state?.rootSpan) return;
751
807
 
@@ -759,8 +815,8 @@ export class OpenTelemetryIntegration implements TelemetryIntegration {
759
815
  },
760
816
  'ai.response.reasoning': {
761
817
  output: () =>
762
- event.reasoning.length > 0
763
- ? event.reasoning
818
+ event.finalStep.reasoning.length > 0
819
+ ? event.finalStep.reasoning
764
820
  .filter(part => 'text' in part)
765
821
  .map(part => part.text)
766
822
  .join('\n')
@@ -790,25 +846,27 @@ export class OpenTelemetryIntegration implements TelemetryIntegration {
790
846
  )
791
847
  : undefined,
792
848
  },
793
- 'ai.response.providerMetadata': event.providerMetadata
794
- ? JSON.stringify(event.providerMetadata)
849
+ 'ai.response.providerMetadata': event.finalStep.providerMetadata
850
+ ? JSON.stringify(event.finalStep.providerMetadata)
795
851
  : undefined,
796
852
 
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,
853
+ 'ai.usage.inputTokens': event.usage.inputTokens,
854
+ 'ai.usage.outputTokens': event.usage.outputTokens,
855
+ 'ai.usage.totalTokens': event.usage.totalTokens,
856
+ 'ai.usage.reasoningTokens':
857
+ event.usage.outputTokenDetails?.reasoningTokens,
858
+ 'ai.usage.cachedInputTokens':
859
+ event.usage.inputTokenDetails?.cacheReadTokens,
802
860
  'ai.usage.inputTokenDetails.noCacheTokens':
803
- event.totalUsage.inputTokenDetails?.noCacheTokens,
861
+ event.usage.inputTokenDetails?.noCacheTokens,
804
862
  'ai.usage.inputTokenDetails.cacheReadTokens':
805
- event.totalUsage.inputTokenDetails?.cacheReadTokens,
863
+ event.usage.inputTokenDetails?.cacheReadTokens,
806
864
  'ai.usage.inputTokenDetails.cacheWriteTokens':
807
- event.totalUsage.inputTokenDetails?.cacheWriteTokens,
865
+ event.usage.inputTokenDetails?.cacheWriteTokens,
808
866
  'ai.usage.outputTokenDetails.textTokens':
809
- event.totalUsage.outputTokenDetails?.textTokens,
867
+ event.usage.outputTokenDetails?.textTokens,
810
868
  'ai.usage.outputTokenDetails.reasoningTokens':
811
- event.totalUsage.outputTokenDetails?.reasoningTokens,
869
+ event.usage.outputTokenDetails?.reasoningTokens,
812
870
  }),
813
871
  );
814
872
 
@@ -816,7 +874,7 @@ export class OpenTelemetryIntegration implements TelemetryIntegration {
816
874
  this.cleanupCallState(event.callId);
817
875
  }
818
876
 
819
- private onObjectOperationFinish(event: ObjectOnFinishEvent<unknown>): void {
877
+ private onObjectOperationEnd(event: GenerateObjectEndEvent<unknown>): void {
820
878
  const state = this.getCallState(event.callId);
821
879
  if (!state?.rootSpan) return;
822
880
 
@@ -836,8 +894,10 @@ export class OpenTelemetryIntegration implements TelemetryIntegration {
836
894
  'ai.usage.inputTokens': event.usage.inputTokens,
837
895
  'ai.usage.outputTokens': event.usage.outputTokens,
838
896
  'ai.usage.totalTokens': event.usage.totalTokens,
839
- 'ai.usage.reasoningTokens': event.usage.reasoningTokens,
840
- 'ai.usage.cachedInputTokens': event.usage.cachedInputTokens,
897
+ 'ai.usage.reasoningTokens':
898
+ event.usage.outputTokenDetails?.reasoningTokens,
899
+ 'ai.usage.cachedInputTokens':
900
+ event.usage.inputTokenDetails?.cacheReadTokens,
841
901
  }),
842
902
  );
843
903
 
@@ -845,7 +905,7 @@ export class OpenTelemetryIntegration implements TelemetryIntegration {
845
905
  this.cleanupCallState(event.callId);
846
906
  }
847
907
 
848
- private onEmbedOperationFinish(event: EmbedOnFinishEvent): void {
908
+ private onEmbedOperationEnd(event: EmbedEndEvent): void {
849
909
  const state = this.getCallState(event.callId);
850
910
  if (!state?.rootSpan) return;
851
911
 
@@ -874,7 +934,7 @@ export class OpenTelemetryIntegration implements TelemetryIntegration {
874
934
  this.cleanupCallState(event.callId);
875
935
  }
876
936
 
877
- onEmbedStart(event: EmbedStartEvent): void {
937
+ onEmbedStart(event: EmbeddingModelCallStartEvent): void {
878
938
  const state = this.getCallState(event.callId);
879
939
  if (!state?.rootSpan || !state.rootContext) return;
880
940
 
@@ -904,7 +964,7 @@ export class OpenTelemetryIntegration implements TelemetryIntegration {
904
964
  });
905
965
  }
906
966
 
907
- onEmbedFinish(event: EmbedFinishEvent): void {
967
+ onEmbedEnd(event: EmbeddingModelCallEndEvent): void {
908
968
  const state = this.getCallState(event.callId);
909
969
  if (!state) return;
910
970
 
@@ -928,13 +988,13 @@ export class OpenTelemetryIntegration implements TelemetryIntegration {
928
988
  state.embedSpans.delete(event.embedCallId);
929
989
  }
930
990
 
931
- private onRerankOperationStart(event: RerankOnStartEvent): void {
932
- const telemetry: TelemetrySettings = {
933
- isEnabled: event.isEnabled,
991
+ private onRerankOperationStart(
992
+ event: InferTelemetryEvent<RerankStartEvent>,
993
+ ): void {
994
+ const telemetry: TelemetryOptions = {
934
995
  recordInputs: event.recordInputs,
935
996
  recordOutputs: event.recordOutputs,
936
997
  functionId: event.functionId,
937
- metadata: event.metadata,
938
998
  };
939
999
 
940
1000
  const settings: Record<string, unknown> = {
@@ -943,9 +1003,9 @@ export class OpenTelemetryIntegration implements TelemetryIntegration {
943
1003
 
944
1004
  const baseTelemetryAttributes = getBaseTelemetryAttributes({
945
1005
  model: { provider: event.provider, modelId: event.modelId },
946
- telemetry,
947
1006
  headers: event.headers,
948
1007
  settings,
1008
+ context: undefined,
949
1009
  });
950
1010
 
951
1011
  const attributes = selectAttributes(telemetry, {
@@ -977,7 +1037,7 @@ export class OpenTelemetryIntegration implements TelemetryIntegration {
977
1037
  });
978
1038
  }
979
1039
 
980
- private onRerankOperationFinish(event: RerankOnFinishEvent): void {
1040
+ private onRerankOperationEnd(event: RerankEndEvent): void {
981
1041
  const state = this.getCallState(event.callId);
982
1042
  if (!state?.rootSpan) return;
983
1043
 
@@ -985,7 +1045,7 @@ export class OpenTelemetryIntegration implements TelemetryIntegration {
985
1045
  this.cleanupCallState(event.callId);
986
1046
  }
987
1047
 
988
- onRerankStart(event: RerankStartEvent): void {
1048
+ onRerankStart(event: RerankingModelCallStartEvent): void {
989
1049
  const state = this.getCallState(event.callId);
990
1050
  if (!state?.rootSpan || !state.rootContext) return;
991
1051
 
@@ -1012,7 +1072,7 @@ export class OpenTelemetryIntegration implements TelemetryIntegration {
1012
1072
  state.rerankSpan = { span: rerankSpan, context: rerankContext };
1013
1073
  }
1014
1074
 
1015
- onRerankFinish(event: RerankFinishEvent): void {
1075
+ onRerankEnd(event: RerankingModelCallEndEvent): void {
1016
1076
  const state = this.getCallState(event.callId);
1017
1077
  if (!state?.rerankSpan) return;
1018
1078
 
@@ -1032,37 +1092,33 @@ export class OpenTelemetryIntegration implements TelemetryIntegration {
1032
1092
  state.rerankSpan = undefined;
1033
1093
  }
1034
1094
 
1035
- onChunk(event: OnChunkEvent<ToolSet>): void {
1036
- const chunk = event.chunk as {
1037
- type: string;
1038
- callId?: unknown;
1039
- attributes?: unknown;
1040
- };
1095
+ onAbort(event: GenerateTextAbortEvent<ToolSet>): void {
1096
+ const state = this.getCallState(event.callId);
1097
+ if (!state?.rootSpan) return;
1041
1098
 
1042
- if (typeof chunk.callId !== 'string') {
1043
- return;
1099
+ for (const { span: toolSpan } of state.toolSpans.values()) {
1100
+ toolSpan.end();
1044
1101
  }
1102
+ state.toolSpans.clear();
1045
1103
 
1046
- if (
1047
- chunk.type !== 'ai.stream.firstChunk' &&
1048
- chunk.type !== 'ai.stream.finish'
1049
- ) {
1050
- return;
1104
+ if (state.stepSpan) {
1105
+ state.stepSpan.end();
1106
+ state.stepSpan = undefined;
1107
+ state.stepContext = undefined;
1051
1108
  }
1052
1109
 
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;
1110
+ for (const { span: embedSpan } of state.embedSpans.values()) {
1111
+ embedSpan.end();
1112
+ }
1113
+ state.embedSpans.clear();
1061
1114
 
1062
- state.stepSpan.addEvent(chunk.type, attributes);
1063
- if (Object.keys(attributes).length > 0) {
1064
- state.stepSpan.setAttributes(attributes);
1115
+ if (state.rerankSpan) {
1116
+ state.rerankSpan.span.end();
1117
+ state.rerankSpan = undefined;
1065
1118
  }
1119
+
1120
+ state.rootSpan.end();
1121
+ this.cleanupCallState(event.callId);
1066
1122
  }
1067
1123
 
1068
1124
  onError(error: unknown): void {