Skip to content

Commit d879950

Browse files
committed
make simple
1 parent 5e33cdb commit d879950

File tree

4 files changed

+33
-105
lines changed

4 files changed

+33
-105
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: 13 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -22,21 +22,13 @@ import {
2222
GEN_AI_USAGE_OUTPUT_TOKENS_ATTRIBUTE,
2323
GEN_AI_USAGE_TOTAL_TOKENS_ATTRIBUTE,
2424
} from '../ai/gen-ai-attributes';
25-
import {
26-
DO_SPAN_NAME_PREFIX,
27-
EMBEDDINGS_OPS,
28-
GENERATE_CONTENT_OPS,
29-
INVOKE_AGENT_OPS,
30-
RERANK_OPS,
31-
toolCallSpanContextMap,
32-
} from './constants';
25+
import { SPAN_TO_OPERATION_NAME, toolCallSpanContextMap } from './constants';
3326
import type { TokenSummary } from './types';
3427
import {
3528
accumulateTokensForParent,
3629
applyAccumulatedTokens,
3730
applyToolDescriptionsAndTokens,
3831
convertAvailableToolsToJsonString,
39-
getSpanOpFromName,
4032
requestMessagesFromPrompt,
4133
} from './utils';
4234
import type { OpenAiProviderMetadata, ProviderMetadata } from './vercel-ai-attributes';
@@ -64,32 +56,6 @@ import {
6456
OPERATION_NAME_ATTRIBUTE,
6557
} from './vercel-ai-attributes';
6658

67-
/**
68-
* Maps Vercel AI SDK operation names to OpenTelemetry semantic convention values
69-
* @see https://opentelemetry.io/docs/specs/semconv/gen-ai/gen-ai-spans/#llm-request-spans
70-
*/
71-
function mapVercelAiOperationName(operationName: string): string {
72-
// Top-level pipeline operations map to invoke_agent
73-
if (INVOKE_AGENT_OPS.has(operationName)) {
74-
return 'invoke_agent';
75-
}
76-
// .do* operations are the actual LLM calls
77-
if (GENERATE_CONTENT_OPS.has(operationName)) {
78-
return 'generate_content';
79-
}
80-
if (EMBEDDINGS_OPS.has(operationName)) {
81-
return 'embeddings';
82-
}
83-
if (RERANK_OPS.has(operationName)) {
84-
return 'rerank';
85-
}
86-
if (operationName === 'ai.toolCall') {
87-
return 'execute_tool';
88-
}
89-
// Return the original value for unknown operations
90-
return operationName;
91-
}
92-
9359
/**
9460
* Post-process spans emitted by the Vercel AI SDK.
9561
* This is supposed to be used in `client.on('spanStart', ...)
@@ -314,7 +280,9 @@ function processEndedVercelAiSpan(span: SpanJSON): void {
314280
// Rename AI SDK attributes to standardized gen_ai attributes
315281
// Map operation.name to OpenTelemetry semantic convention values
316282
if (attributes[OPERATION_NAME_ATTRIBUTE]) {
317-
const operationName = mapVercelAiOperationName(attributes[OPERATION_NAME_ATTRIBUTE] as string);
283+
const operationName =
284+
SPAN_TO_OPERATION_NAME.get(attributes[OPERATION_NAME_ATTRIBUTE] as string) ??
285+
(attributes[OPERATION_NAME_ATTRIBUTE] as string);
318286
attributes[GEN_AI_OPERATION_NAME_ATTRIBUTE] = operationName;
319287
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
320288
delete attributes[OPERATION_NAME_ATTRIBUTE];
@@ -415,15 +383,17 @@ function processGenerateSpan(span: Span, name: string, attributes: SpanAttribute
415383
}
416384
span.setAttribute('ai.streaming', name.includes('stream'));
417385

418-
// Set the op based on the span name
419-
const op = getSpanOpFromName(name);
420-
if (op) {
421-
span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_OP, op);
386+
// Set the op based on the operation name registry
387+
const operationName = SPAN_TO_OPERATION_NAME.get(name);
388+
if (operationName) {
389+
span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_OP, `gen_ai.${operationName}`);
390+
} else if (name.startsWith('ai.stream')) {
391+
span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_OP, 'ai.run');
422392
}
423393

424394
// For invoke_agent pipeline spans, use 'invoke_agent' as the description
425395
// to be consistent with other AI integrations (e.g. LangGraph)
426-
if (INVOKE_AGENT_OPS.has(name)) {
396+
if (operationName === 'invoke_agent') {
427397
if (functionId && typeof functionId === 'string') {
428398
span.updateName(`invoke_agent ${functionId}`);
429399
} else {
@@ -433,11 +403,8 @@ function processGenerateSpan(span: Span, name: string, attributes: SpanAttribute
433403
}
434404

435405
const modelId = attributes[AI_MODEL_ID_ATTRIBUTE];
436-
if (modelId) {
437-
const doSpanPrefix = GENERATE_CONTENT_OPS.has(name) ? 'generate_content' : DO_SPAN_NAME_PREFIX[name];
438-
if (doSpanPrefix) {
439-
span.updateName(`${doSpanPrefix} ${modelId}`);
440-
}
406+
if (modelId && operationName) {
407+
span.updateName(`${operationName} ${modelId}`);
441408
}
442409
}
443410

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,
@@ -279,33 +274,3 @@ export function requestMessagesFromPrompt(span: Span, attributes: SpanAttributes
279274
} catch {}
280275
}
281276
}
282-
283-
/**
284-
* Maps a Vercel AI span name to the corresponding Sentry op.
285-
*/
286-
export function getSpanOpFromName(name: string): string | undefined {
287-
switch (name) {
288-
case 'ai.generateText':
289-
case 'ai.streamText':
290-
case 'ai.generateObject':
291-
case 'ai.streamObject':
292-
return GEN_AI_INVOKE_AGENT_OPERATION_ATTRIBUTE;
293-
case 'ai.generateText.doGenerate':
294-
case 'ai.streamText.doStream':
295-
case 'ai.generateObject.doGenerate':
296-
case 'ai.streamObject.doStream':
297-
return GEN_AI_GENERATE_CONTENT_OPERATION_ATTRIBUTE;
298-
case 'ai.embed.doEmbed':
299-
case 'ai.embedMany.doEmbed':
300-
return GEN_AI_EMBEDDINGS_OPERATION_ATTRIBUTE;
301-
case 'ai.rerank.doRerank':
302-
return GEN_AI_RERANK_DO_RERANK_OPERATION_ATTRIBUTE;
303-
case 'ai.toolCall':
304-
return GEN_AI_EXECUTE_TOOL_OPERATION_ATTRIBUTE;
305-
default:
306-
if (name.startsWith('ai.stream')) {
307-
return 'ai.run';
308-
}
309-
return undefined;
310-
}
311-
}
Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
import { describe, expect, it } from 'vitest';
2-
import { getSpanOpFromName } from '../../../src/tracing/vercel-ai/utils';
2+
import { SPAN_TO_OPERATION_NAME } from '../../../src/tracing/vercel-ai/constants';
33

44
describe('vercel-ai rerank support', () => {
5-
describe('getSpanOpFromName', () => {
6-
it('should not assign a gen_ai op to ai.rerank pipeline span', () => {
7-
expect(getSpanOpFromName('ai.rerank')).toBeUndefined();
5+
describe('SPAN_TO_OPERATION_NAME', () => {
6+
it('should not have a mapping for ai.rerank pipeline span', () => {
7+
expect(SPAN_TO_OPERATION_NAME.get('ai.rerank')).toBeUndefined();
88
});
99

10-
it('should map ai.rerank.doRerank to gen_ai.rerank', () => {
11-
expect(getSpanOpFromName('ai.rerank.doRerank')).toBe('gen_ai.rerank');
10+
it('should map ai.rerank.doRerank to rerank', () => {
11+
expect(SPAN_TO_OPERATION_NAME.get('ai.rerank.doRerank')).toBe('rerank');
1212
});
1313
});
1414
});

0 commit comments

Comments
 (0)