@ai-sdk/otel 1.0.0-beta.6 → 1.0.0-beta.61

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,11 +1,10 @@
1
1
  import {
2
- Attributes,
3
- Span,
4
- Tracer,
5
2
  SpanStatusCode,
6
3
  context,
4
+ type Attributes,
5
+ type Span,
6
+ type Tracer,
7
7
  } from '@opentelemetry/api';
8
-
9
8
  export async function recordSpan<T>({
10
9
  name,
11
10
  tracer,
@@ -0,0 +1,57 @@
1
+ import type { Attributes, AttributeValue } from '@opentelemetry/api';
2
+ import type { TelemetryOptions } from 'ai';
3
+
4
+ export type AttributeSpec =
5
+ | AttributeValue
6
+ | { input: () => AttributeValue | undefined }
7
+ | { output: () => AttributeValue | undefined }
8
+ | undefined;
9
+
10
+ export type AttributeSpecMap = Record<string, AttributeSpec>;
11
+
12
+ function shouldRecord(
13
+ telemetry: TelemetryOptions | undefined,
14
+ ): telemetry is TelemetryOptions {
15
+ return telemetry?.isEnabled !== false;
16
+ }
17
+
18
+ export function selectAttributes(
19
+ telemetry: TelemetryOptions | undefined,
20
+ attributes: AttributeSpecMap,
21
+ ): Attributes {
22
+ if (!shouldRecord(telemetry)) {
23
+ return {};
24
+ }
25
+
26
+ const result: Attributes = {};
27
+
28
+ for (const [key, value] of Object.entries(attributes)) {
29
+ if (value == null) continue;
30
+
31
+ if (
32
+ typeof value === 'object' &&
33
+ 'input' in value &&
34
+ typeof value.input === 'function'
35
+ ) {
36
+ if (telemetry?.recordInputs === false) continue;
37
+ const resolved = value.input();
38
+ if (resolved != null) result[key] = resolved;
39
+ continue;
40
+ }
41
+
42
+ if (
43
+ typeof value === 'object' &&
44
+ 'output' in value &&
45
+ typeof value.output === 'function'
46
+ ) {
47
+ if (telemetry?.recordOutputs === false) continue;
48
+ const resolved = value.output();
49
+ if (resolved != null) result[key] = resolved;
50
+ continue;
51
+ }
52
+
53
+ result[key] = value as AttributeValue;
54
+ }
55
+
56
+ return result;
57
+ }
@@ -1,5 +1,5 @@
1
1
  import type { Attributes, AttributeValue } from '@opentelemetry/api';
2
- import type { TelemetrySettings } from 'ai';
2
+ import type { TelemetryOptions } from 'ai';
3
3
 
4
4
  type ResolvableAttributeValue = () =>
5
5
  | AttributeValue
@@ -10,7 +10,7 @@ export async function selectTelemetryAttributes({
10
10
  telemetry,
11
11
  attributes,
12
12
  }: {
13
- telemetry?: TelemetrySettings;
13
+ telemetry?: TelemetryOptions;
14
14
  attributes: {
15
15
  [attributeKey: string]:
16
16
  | AttributeValue
@@ -20,7 +20,7 @@ export async function selectTelemetryAttributes({
20
20
  };
21
21
  }): Promise<Attributes> {
22
22
  // when telemetry is disabled, return an empty object to avoid serialization overhead:
23
- if (telemetry?.isEnabled !== true) {
23
+ if (telemetry?.isEnabled === false) {
24
24
  return {};
25
25
  }
26
26
 
@@ -1,4 +1,4 @@
1
- import {
1
+ import type {
2
2
  LanguageModelV4Message,
3
3
  LanguageModelV4Prompt,
4
4
  } from '@ai-sdk/provider';
@@ -21,13 +21,31 @@ export function stringifyForTelemetry(prompt: LanguageModelV4Prompt): string {
21
21
  part.type === 'file'
22
22
  ? {
23
23
  ...part,
24
- data:
25
- part.data instanceof Uint8Array
26
- ? convertDataContentToBase64String(part.data)
27
- : part.data,
24
+ data: serializeFileData(part.data),
28
25
  }
29
26
  : part,
30
27
  ),
31
28
  })),
32
29
  );
33
30
  }
31
+
32
+ function serializeFileData(
33
+ data:
34
+ | { type: 'data'; data: string | Uint8Array }
35
+ | { type: 'url'; url: URL }
36
+ | { type: 'reference'; reference: Record<string, string> }
37
+ | { type: 'text'; text: string },
38
+ ): unknown {
39
+ switch (data.type) {
40
+ case 'data':
41
+ return data.data instanceof Uint8Array
42
+ ? convertDataContentToBase64String(data.data)
43
+ : data.data;
44
+ case 'url':
45
+ return data.url.toString();
46
+ case 'reference':
47
+ return data.reference;
48
+ case 'text':
49
+ return data.text;
50
+ }
51
+ }
@@ -0,0 +1,151 @@
1
+ import type { Attributes, Tracer } from '@opentelemetry/api';
2
+ import type { TelemetryOptions } from 'ai';
3
+ import { selectAttributes, type AttributeSpecMap } from './select-attributes';
4
+
5
+ type SupplementalAttributeOption =
6
+ | 'usage'
7
+ | 'providerMetadata'
8
+ | 'embedding'
9
+ | 'reranking'
10
+ | 'runtimeContext'
11
+ | 'headers'
12
+ | 'toolChoice'
13
+ | 'schema';
14
+
15
+ export type SupplementalAttributeOptions = Record<
16
+ SupplementalAttributeOption,
17
+ boolean
18
+ >;
19
+
20
+ export type OpenTelemetryOptions = {
21
+ /**
22
+ * The tracer to use for the telemetry data.
23
+ */
24
+ tracer?: Tracer;
25
+
26
+ /**
27
+ * Emit AI SDK usage details that are not represented by GenAI SemConv.
28
+ */
29
+ usage?: boolean;
30
+
31
+ /**
32
+ * Emit provider metadata on response spans.
33
+ */
34
+ providerMetadata?: boolean;
35
+
36
+ /**
37
+ * Emit embedding input and output values.
38
+ */
39
+ embedding?: boolean;
40
+
41
+ /**
42
+ * Emit reranking input documents and output ranking.
43
+ */
44
+ reranking?: boolean;
45
+
46
+ /**
47
+ * Emit runtime context values.
48
+ */
49
+ runtimeContext?: boolean;
50
+
51
+ /**
52
+ * Emit request headers.
53
+ */
54
+ headers?: boolean;
55
+
56
+ /**
57
+ * Emit selected tool choice information.
58
+ */
59
+ toolChoice?: boolean;
60
+
61
+ /**
62
+ * Emit object generation schema information.
63
+ */
64
+ schema?: boolean;
65
+ };
66
+
67
+ const disabledSupplementalAttributes: SupplementalAttributeOptions = {
68
+ usage: false,
69
+ providerMetadata: false,
70
+ embedding: false,
71
+ reranking: false,
72
+ runtimeContext: false,
73
+ headers: false,
74
+ toolChoice: false,
75
+ schema: false,
76
+ };
77
+
78
+ export function normalizeSupplementalAttributes(
79
+ options: OpenTelemetryOptions,
80
+ ): SupplementalAttributeOptions {
81
+ return {
82
+ ...disabledSupplementalAttributes,
83
+ usage: options.usage ?? false,
84
+ providerMetadata: options.providerMetadata ?? false,
85
+ embedding: options.embedding ?? false,
86
+ reranking: options.reranking ?? false,
87
+ runtimeContext: options.runtimeContext ?? false,
88
+ headers: options.headers ?? false,
89
+ toolChoice: options.toolChoice ?? false,
90
+ schema: options.schema ?? false,
91
+ };
92
+ }
93
+
94
+ export function getRuntimeContextAttributes(
95
+ context: Record<string, unknown> | undefined,
96
+ ): AttributeSpecMap {
97
+ return Object.fromEntries(
98
+ Object.entries(context ?? {})
99
+ .filter(([, value]) => value != null)
100
+ .map(([key, value]) => [`ai.settings.context.${key}`, value]),
101
+ ) as AttributeSpecMap;
102
+ }
103
+
104
+ export function getHeaderAttributes(
105
+ headers: Record<string, string | undefined> | undefined,
106
+ ): AttributeSpecMap {
107
+ return Object.fromEntries(
108
+ Object.entries(headers ?? {})
109
+ .filter(([, value]) => value != null)
110
+ .map(([key, value]) => [`ai.request.headers.${key}`, value]),
111
+ ) as AttributeSpecMap;
112
+ }
113
+
114
+ export function getDetailedUsageAttributes(usage: {
115
+ inputTokenDetails?: {
116
+ noCacheTokens?: number | undefined;
117
+ };
118
+ outputTokenDetails?: {
119
+ textTokens?: number | undefined;
120
+ reasoningTokens?: number | undefined;
121
+ };
122
+ }): AttributeSpecMap {
123
+ return {
124
+ 'ai.usage.inputTokenDetails.noCacheTokens':
125
+ usage.inputTokenDetails?.noCacheTokens,
126
+ 'ai.usage.outputTokenDetails.textTokens':
127
+ usage.outputTokenDetails?.textTokens,
128
+ 'ai.usage.outputTokenDetails.reasoningTokens':
129
+ usage.outputTokenDetails?.reasoningTokens,
130
+ };
131
+ }
132
+
133
+ export function selectSupplementalAttributes(
134
+ telemetry: TelemetryOptions | undefined,
135
+ enabledAttributes: SupplementalAttributeOptions,
136
+ attributes: Partial<Record<SupplementalAttributeOption, AttributeSpecMap>>,
137
+ ): Attributes {
138
+ const result: Attributes = {};
139
+
140
+ for (const [key, value] of Object.entries(attributes) as Array<
141
+ [SupplementalAttributeOption, AttributeSpecMap | undefined]
142
+ >) {
143
+ if (!enabledAttributes[key] || value == null) {
144
+ continue;
145
+ }
146
+
147
+ Object.assign(result, selectAttributes(telemetry, value));
148
+ }
149
+
150
+ return result;
151
+ }
package/dist/index.d.mts DELETED
@@ -1,52 +0,0 @@
1
- import { LanguageModelV4Prompt } from '@ai-sdk/provider';
2
- import { Tracer } from '@opentelemetry/api';
3
- import { TelemetryIntegration, OnStartEvent, ToolSet, OutputInterface, ObjectOnStartEvent, EmbedOnStartEvent, RerankOnStartEvent, ObjectOnStepStartEvent, ObjectOnStepFinishEvent, GenerationContext, OnStepStartEvent, OnToolCallStartEvent, OnToolCallFinishEvent, OnStepFinishEvent, OnFinishEvent, ObjectOnFinishEvent, EmbedOnFinishEvent, RerankOnFinishEvent, EmbedStartEvent, EmbedFinishEvent, RerankStartEvent, RerankFinishEvent, OnChunkEvent } from 'ai';
4
-
5
- interface OtelStepStartEvent<TOOLS extends ToolSet = ToolSet, CONTEXT extends GenerationContext<TOOLS> = GenerationContext<TOOLS>, OUTPUT extends OutputInterface = OutputInterface> extends OnStepStartEvent<TOOLS, CONTEXT, OUTPUT> {
6
- readonly promptMessages?: LanguageModelV4Prompt;
7
- readonly stepTools?: ReadonlyArray<Record<string, unknown>>;
8
- readonly stepToolChoice?: unknown;
9
- }
10
- declare class OpenTelemetryIntegration implements TelemetryIntegration {
11
- private readonly callStates;
12
- /**
13
- * The tracer to use for the telemetry data.
14
- */
15
- private readonly tracer;
16
- constructor(options?: {
17
- tracer?: Tracer;
18
- });
19
- private getCallState;
20
- private cleanupCallState;
21
- executeTool<T>({ callId, toolCallId, execute, }: {
22
- callId: string;
23
- toolCallId: string;
24
- execute: () => PromiseLike<T>;
25
- }): PromiseLike<T>;
26
- onStart(event: OnStartEvent<ToolSet, OutputInterface> | ObjectOnStartEvent | EmbedOnStartEvent | RerankOnStartEvent): void;
27
- private onGenerateStart;
28
- private onObjectOperationStart;
29
- /** @deprecated */
30
- onObjectStepStart(event: ObjectOnStepStartEvent): void;
31
- /** @deprecated */
32
- onObjectStepFinish(event: ObjectOnStepFinishEvent): void;
33
- private onEmbedOperationStart;
34
- onStepStart(event: OtelStepStartEvent<ToolSet, OutputInterface>): void;
35
- onToolCallStart(event: OnToolCallStartEvent<ToolSet>): void;
36
- onToolCallFinish(event: OnToolCallFinishEvent<ToolSet>): void;
37
- onStepFinish(event: OnStepFinishEvent<ToolSet>): void;
38
- onFinish(event: OnFinishEvent<ToolSet> | ObjectOnFinishEvent<unknown> | EmbedOnFinishEvent | RerankOnFinishEvent): void;
39
- private onGenerateFinish;
40
- private onObjectOperationFinish;
41
- private onEmbedOperationFinish;
42
- onEmbedStart(event: EmbedStartEvent): void;
43
- onEmbedFinish(event: EmbedFinishEvent): void;
44
- private onRerankOperationStart;
45
- private onRerankOperationFinish;
46
- onRerankStart(event: RerankStartEvent): void;
47
- onRerankFinish(event: RerankFinishEvent): void;
48
- onChunk(event: OnChunkEvent<ToolSet>): void;
49
- onError(error: unknown): void;
50
- }
51
-
52
- export { OpenTelemetryIntegration };