@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.
- package/CHANGELOG.md +891 -0
- package/README.md +119 -0
- package/dist/index.d.ts +139 -22
- package/dist/index.js +1729 -165
- package/dist/index.js.map +1 -1
- package/package.json +16 -13
- package/src/assemble-operation-name.ts +2 -2
- package/src/gen-ai-format-messages.ts +644 -0
- package/src/get-base-telemetry-attributes.ts +8 -15
- package/src/get-tracer.ts +1 -1
- package/src/index.ts +7 -1
- package/src/{open-telemetry-integration.ts → legacy-open-telemetry.ts} +200 -144
- package/src/mock-tracer.ts +1 -1
- package/src/noop-tracer.ts +1 -1
- package/src/open-telemetry.ts +1310 -0
- package/src/record-span.ts +3 -4
- package/src/select-attributes.ts +57 -0
- package/src/select-telemetry-attributes.ts +3 -3
- package/src/stringify-for-telemetry.ts +23 -5
- package/src/supplemental-attributes.ts +201 -0
- package/dist/index.d.mts +0 -52
- package/dist/index.mjs +0 -845
- package/dist/index.mjs.map +0 -1
|
@@ -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
|
-
|
|
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
|
-
|
|
14
|
-
|
|
15
|
-
EmbedOnStartEvent,
|
|
14
|
+
EmbeddingModelCallEndEvent,
|
|
15
|
+
EmbedEndEvent,
|
|
16
16
|
EmbedStartEvent,
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
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
|
-
|
|
35
|
-
|
|
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:
|
|
60
|
-
): telemetry is
|
|
61
|
-
return telemetry?.isEnabled
|
|
60
|
+
telemetry: TelemetryOptions | undefined,
|
|
61
|
+
): telemetry is TelemetryOptions {
|
|
62
|
+
return telemetry?.isEnabled !== false;
|
|
62
63
|
}
|
|
63
64
|
|
|
64
65
|
function selectAttributes(
|
|
65
|
-
telemetry:
|
|
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
|
-
|
|
114
|
-
OUTPUT extends Output = Output,
|
|
115
|
-
> extends
|
|
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:
|
|
124
|
+
telemetry: TelemetryOptions | undefined;
|
|
124
125
|
rootSpan: Span | undefined;
|
|
125
|
-
rootContext:
|
|
126
|
+
rootContext: OpenTelemetryContext | undefined;
|
|
126
127
|
stepSpan: Span | undefined;
|
|
127
|
-
stepContext:
|
|
128
|
-
embedSpans: Map<string, { span: Span; context:
|
|
129
|
-
rerankSpan: { span: Span; context:
|
|
130
|
-
toolSpans: Map<string, { span: Span; 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
|
|
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
|
-
|
|
|
180
|
-
|
|
|
181
|
-
|
|
|
182
|
-
|
|
|
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
|
|
209
|
+
this.onEmbedOperationStart(event as InferTelemetryEvent<EmbedStartEvent>);
|
|
191
210
|
return;
|
|
192
211
|
}
|
|
193
212
|
|
|
194
213
|
if (event.operationId === 'ai.rerank') {
|
|
195
|
-
this.onRerankOperationStart(
|
|
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(
|
|
224
|
+
this.onObjectOperationStart(
|
|
225
|
+
event as InferTelemetryEvent<GenerateObjectStartEvent>,
|
|
226
|
+
);
|
|
204
227
|
return;
|
|
205
228
|
}
|
|
206
229
|
|
|
207
|
-
this.onGenerateStart(event as
|
|
230
|
+
this.onGenerateStart(event as InferTelemetryEvent<GenerateTextStartEvent>);
|
|
208
231
|
}
|
|
209
232
|
|
|
210
|
-
private onGenerateStart(
|
|
211
|
-
|
|
212
|
-
|
|
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.
|
|
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(
|
|
275
|
-
|
|
276
|
-
|
|
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:
|
|
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
|
-
|
|
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':
|
|
422
|
-
|
|
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(
|
|
447
|
-
|
|
448
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
643
|
+
output: () => JSON.stringify(toolOutput.output),
|
|
619
644
|
},
|
|
620
645
|
}),
|
|
621
646
|
);
|
|
622
|
-
} catch
|
|
647
|
+
} catch {
|
|
623
648
|
// JSON.stringify might fail for non-serializable results
|
|
624
649
|
}
|
|
625
650
|
} else {
|
|
626
|
-
recordSpanError(span,
|
|
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
|
-
|
|
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':
|
|
689
|
-
|
|
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
|
-
|
|
765
|
+
/** @deprecated Use `onStepEnd` instead. */
|
|
766
|
+
onStepFinish(event: GenerateTextStepEndEvent<ToolSet>): void {
|
|
767
|
+
this.onStepEnd(event);
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
onEnd(
|
|
715
771
|
event:
|
|
716
|
-
|
|
|
717
|
-
|
|
|
718
|
-
|
|
|
719
|
-
|
|
|
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.
|
|
784
|
+
this.onEmbedOperationEnd(event as EmbedEndEvent);
|
|
729
785
|
return;
|
|
730
786
|
}
|
|
731
787
|
|
|
732
788
|
if (state.operationId === 'ai.rerank') {
|
|
733
|
-
this.
|
|
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.
|
|
797
|
+
this.onObjectOperationEnd(event as GenerateObjectEndEvent<unknown>);
|
|
742
798
|
return;
|
|
743
799
|
}
|
|
744
800
|
|
|
745
|
-
this.
|
|
801
|
+
this.onGenerateEnd(event as GenerateTextEndEvent<ToolSet>);
|
|
746
802
|
}
|
|
747
803
|
|
|
748
|
-
private
|
|
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.
|
|
798
|
-
'ai.usage.outputTokens': event.
|
|
799
|
-
'ai.usage.totalTokens': event.
|
|
800
|
-
'ai.usage.reasoningTokens':
|
|
801
|
-
|
|
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.
|
|
861
|
+
event.usage.inputTokenDetails?.noCacheTokens,
|
|
804
862
|
'ai.usage.inputTokenDetails.cacheReadTokens':
|
|
805
|
-
event.
|
|
863
|
+
event.usage.inputTokenDetails?.cacheReadTokens,
|
|
806
864
|
'ai.usage.inputTokenDetails.cacheWriteTokens':
|
|
807
|
-
event.
|
|
865
|
+
event.usage.inputTokenDetails?.cacheWriteTokens,
|
|
808
866
|
'ai.usage.outputTokenDetails.textTokens':
|
|
809
|
-
event.
|
|
867
|
+
event.usage.outputTokenDetails?.textTokens,
|
|
810
868
|
'ai.usage.outputTokenDetails.reasoningTokens':
|
|
811
|
-
event.
|
|
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
|
|
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':
|
|
840
|
-
|
|
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
|
|
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:
|
|
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
|
-
|
|
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(
|
|
932
|
-
|
|
933
|
-
|
|
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
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
1036
|
-
const
|
|
1037
|
-
|
|
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
|
-
|
|
1043
|
-
|
|
1099
|
+
for (const { span: toolSpan } of state.toolSpans.values()) {
|
|
1100
|
+
toolSpan.end();
|
|
1044
1101
|
}
|
|
1102
|
+
state.toolSpans.clear();
|
|
1045
1103
|
|
|
1046
|
-
if (
|
|
1047
|
-
|
|
1048
|
-
|
|
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
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
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.
|
|
1063
|
-
|
|
1064
|
-
state.
|
|
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 {
|