Skip to content

Commit 49fb4df

Browse files
authored
ref(core): Add registry in Vercel ai integration (#20098)
We have mappings for essentially the same thing in 3 places instead of one map to encode what we need
1 parent 608023a commit 49fb4df

File tree

4 files changed

+25
-113
lines changed

4 files changed

+25
-113
lines changed

packages/core/src/tracing/vercel-ai/constants.ts

Lines changed: 14 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,18 @@ import type { ToolCallSpanContext } from './types';
55
// without keeping full Span objects (and their potentially large attributes) alive.
66
export const toolCallSpanContextMap = new Map<string, ToolCallSpanContext>();
77

8-
// Operation sets for efficient mapping to OpenTelemetry semantic convention values
9-
export const INVOKE_AGENT_OPS = new Set(['ai.generateText', 'ai.streamText', 'ai.generateObject', 'ai.streamObject']);
10-
11-
export const GENERATE_CONTENT_OPS = new Set([
12-
'ai.generateText.doGenerate',
13-
'ai.streamText.doStream',
14-
'ai.generateObject.doGenerate',
15-
'ai.streamObject.doStream',
8+
/** Maps Vercel AI span names to standardized OpenTelemetry operation names. */
9+
export const SPAN_TO_OPERATION_NAME = new Map<string, string>([
10+
['ai.generateText', 'invoke_agent'],
11+
['ai.streamText', 'invoke_agent'],
12+
['ai.generateObject', 'invoke_agent'],
13+
['ai.streamObject', 'invoke_agent'],
14+
['ai.generateText.doGenerate', 'generate_content'],
15+
['ai.streamText.doStream', 'generate_content'],
16+
['ai.generateObject.doGenerate', 'generate_content'],
17+
['ai.streamObject.doStream', 'generate_content'],
18+
['ai.embed.doEmbed', 'embeddings'],
19+
['ai.embedMany.doEmbed', 'embeddings'],
20+
['ai.rerank.doRerank', 'rerank'],
21+
['ai.toolCall', 'execute_tool'],
1622
]);
17-
18-
export const EMBEDDINGS_OPS = new Set(['ai.embed.doEmbed', 'ai.embedMany.doEmbed']);
19-
20-
export const RERANK_OPS = new Set(['ai.rerank.doRerank']);
21-
22-
export const DO_SPAN_NAME_PREFIX: Record<string, string> = {
23-
'ai.embed.doEmbed': 'embeddings',
24-
'ai.embedMany.doEmbed': 'embeddings',
25-
'ai.rerank.doRerank': 'rerank',
26-
};

packages/core/src/tracing/vercel-ai/index.ts

Lines changed: 11 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -24,21 +24,13 @@ import {
2424
GEN_AI_USAGE_OUTPUT_TOKENS_ATTRIBUTE,
2525
GEN_AI_USAGE_TOTAL_TOKENS_ATTRIBUTE,
2626
} from '../ai/gen-ai-attributes';
27-
import {
28-
DO_SPAN_NAME_PREFIX,
29-
EMBEDDINGS_OPS,
30-
GENERATE_CONTENT_OPS,
31-
INVOKE_AGENT_OPS,
32-
RERANK_OPS,
33-
toolCallSpanContextMap,
34-
} from './constants';
27+
import { SPAN_TO_OPERATION_NAME, toolCallSpanContextMap } from './constants';
3528
import type { TokenSummary } from './types';
3629
import {
3730
accumulateTokensForParent,
3831
applyAccumulatedTokens,
3932
applyToolDescriptionsAndTokens,
4033
convertAvailableToolsToJsonString,
41-
getSpanOpFromName,
4234
requestMessagesFromPrompt,
4335
} from './utils';
4436
import type { OpenAiProviderMetadata, ProviderMetadata } from './vercel-ai-attributes';
@@ -66,32 +58,6 @@ import {
6658
OPERATION_NAME_ATTRIBUTE,
6759
} from './vercel-ai-attributes';
6860

69-
/**
70-
* Maps Vercel AI SDK operation names to OpenTelemetry semantic convention values
71-
* @see https://opentelemetry.io/docs/specs/semconv/gen-ai/gen-ai-spans/#llm-request-spans
72-
*/
73-
function mapVercelAiOperationName(operationName: string): string {
74-
// Top-level pipeline operations map to invoke_agent
75-
if (INVOKE_AGENT_OPS.has(operationName)) {
76-
return 'invoke_agent';
77-
}
78-
// .do* operations are the actual LLM calls
79-
if (GENERATE_CONTENT_OPS.has(operationName)) {
80-
return 'generate_content';
81-
}
82-
if (EMBEDDINGS_OPS.has(operationName)) {
83-
return 'embeddings';
84-
}
85-
if (RERANK_OPS.has(operationName)) {
86-
return 'rerank';
87-
}
88-
if (operationName === 'ai.toolCall') {
89-
return 'execute_tool';
90-
}
91-
// Return the original value for unknown operations
92-
return operationName;
93-
}
94-
9561
/**
9662
* Post-process spans emitted by the Vercel AI SDK.
9763
* This is supposed to be used in `client.on('spanStart', ...)
@@ -328,7 +294,7 @@ function processEndedVercelAiSpan(span: SpanJSON): void {
328294
const rawOperationName = attributes[AI_OPERATION_ID_ATTRIBUTE]
329295
? (attributes[AI_OPERATION_ID_ATTRIBUTE] as string)
330296
: (attributes[OPERATION_NAME_ATTRIBUTE] as string);
331-
const operationName = mapVercelAiOperationName(rawOperationName);
297+
const operationName = SPAN_TO_OPERATION_NAME.get(rawOperationName) ?? rawOperationName;
332298
attributes[GEN_AI_OPERATION_NAME_ATTRIBUTE] = operationName;
333299
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
334300
delete attributes[OPERATION_NAME_ATTRIBUTE];
@@ -429,15 +395,17 @@ function processGenerateSpan(span: Span, name: string, attributes: SpanAttribute
429395
}
430396
span.setAttribute('ai.streaming', name.includes('stream'));
431397

432-
// Set the op based on the span name
433-
const op = getSpanOpFromName(name);
434-
if (op) {
435-
span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_OP, op);
398+
// Set the op based on the operation name registry
399+
const operationName = SPAN_TO_OPERATION_NAME.get(name);
400+
if (operationName) {
401+
span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_OP, `gen_ai.${operationName}`);
402+
} else if (name.startsWith('ai.stream')) {
403+
span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_OP, 'ai.run');
436404
}
437405

438406
// For invoke_agent pipeline spans, use 'invoke_agent' as the description
439407
// to be consistent with other AI integrations (e.g. LangGraph)
440-
if (INVOKE_AGENT_OPS.has(name)) {
408+
if (operationName === 'invoke_agent') {
441409
if (functionId && typeof functionId === 'string') {
442410
span.updateName(`invoke_agent ${functionId}`);
443411
} else {
@@ -447,11 +415,8 @@ function processGenerateSpan(span: Span, name: string, attributes: SpanAttribute
447415
}
448416

449417
const modelId = attributes[AI_MODEL_ID_ATTRIBUTE];
450-
if (modelId) {
451-
const doSpanPrefix = GENERATE_CONTENT_OPS.has(name) ? 'generate_content' : DO_SPAN_NAME_PREFIX[name];
452-
if (doSpanPrefix) {
453-
span.updateName(`${doSpanPrefix} ${modelId}`);
454-
}
418+
if (modelId && operationName) {
419+
span.updateName(`${operationName} ${modelId}`);
455420
}
456421
}
457422

packages/core/src/tracing/vercel-ai/utils.ts

Lines changed: 0 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,8 @@
11
import type { TraceContext } from '../../types-hoist/context';
22
import type { Span, SpanAttributes, SpanJSON } from '../../types-hoist/span';
33
import {
4-
GEN_AI_EMBEDDINGS_OPERATION_ATTRIBUTE,
5-
GEN_AI_EXECUTE_TOOL_OPERATION_ATTRIBUTE,
6-
GEN_AI_GENERATE_CONTENT_OPERATION_ATTRIBUTE,
74
GEN_AI_INPUT_MESSAGES_ATTRIBUTE,
85
GEN_AI_INPUT_MESSAGES_ORIGINAL_LENGTH_ATTRIBUTE,
9-
GEN_AI_INVOKE_AGENT_OPERATION_ATTRIBUTE,
10-
GEN_AI_RERANK_DO_RERANK_OPERATION_ATTRIBUTE,
116
GEN_AI_REQUEST_AVAILABLE_TOOLS_ATTRIBUTE,
127
GEN_AI_SYSTEM_INSTRUCTIONS_ATTRIBUTE,
138
GEN_AI_TOOL_DESCRIPTION_ATTRIBUTE,
@@ -283,33 +278,3 @@ export function requestMessagesFromPrompt(span: Span, attributes: SpanAttributes
283278
} catch {}
284279
}
285280
}
286-
287-
/**
288-
* Maps a Vercel AI span name to the corresponding Sentry op.
289-
*/
290-
export function getSpanOpFromName(name: string): string | undefined {
291-
switch (name) {
292-
case 'ai.generateText':
293-
case 'ai.streamText':
294-
case 'ai.generateObject':
295-
case 'ai.streamObject':
296-
return GEN_AI_INVOKE_AGENT_OPERATION_ATTRIBUTE;
297-
case 'ai.generateText.doGenerate':
298-
case 'ai.streamText.doStream':
299-
case 'ai.generateObject.doGenerate':
300-
case 'ai.streamObject.doStream':
301-
return GEN_AI_GENERATE_CONTENT_OPERATION_ATTRIBUTE;
302-
case 'ai.embed.doEmbed':
303-
case 'ai.embedMany.doEmbed':
304-
return GEN_AI_EMBEDDINGS_OPERATION_ATTRIBUTE;
305-
case 'ai.rerank.doRerank':
306-
return GEN_AI_RERANK_DO_RERANK_OPERATION_ATTRIBUTE;
307-
case 'ai.toolCall':
308-
return GEN_AI_EXECUTE_TOOL_OPERATION_ATTRIBUTE;
309-
default:
310-
if (name.startsWith('ai.stream')) {
311-
return 'ai.run';
312-
}
313-
return undefined;
314-
}
315-
}

packages/core/test/lib/tracing/vercel-ai-rerank.test.ts

Lines changed: 0 additions & 14 deletions
This file was deleted.

0 commit comments

Comments
 (0)