Skip to content

Commit 493b301

Browse files
nicohrubecmydea
authored andcommitted
fix(core): Use ai.operationId for Vercel AI V6 operation name mapping (#20285)
Vercel AI SDK V6 appends `functionId` to the `operation.name` span attribute (e.g., `ai.streamText myAgent`), causing `mapVercelAiOperationName` to miss the exact-match lookup and leave `gen_ai.operation.name` unmapped. This fix uses the `ai.operationId` attribute (which always contains the bare operation like `ai.streamText`) when present, falling back to `operation.name` for older Vercel SDK versions. The existing `ToolLoopAgent` integration test is strengthened with a functionId to prevent regression. Closes #20284
1 parent 33f8506 commit 493b301

File tree

3 files changed

+11
-2
lines changed

3 files changed

+11
-2
lines changed

dev-packages/node-integration-tests/suites/tracing/vercelai/v6/scenario-tool-loop-agent.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ async function run() {
88
let callCount = 0;
99

1010
const agent = new ToolLoopAgent({
11-
experimental_telemetry: { isEnabled: true },
11+
experimental_telemetry: { isEnabled: true, functionId: 'weather_agent' },
1212
model: new MockLanguageModelV3({
1313
doGenerate: async () => {
1414
if (callCount++ === 0) {

dev-packages/node-integration-tests/suites/tracing/vercelai/v6/test.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -619,6 +619,7 @@ describe('Vercel AI integration (V6)', () => {
619619
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.vercelai.otel',
620620
[GEN_AI_REQUEST_MODEL_ATTRIBUTE]: 'mock-model-id',
621621
}),
622+
description: 'invoke_agent weather_agent',
622623
op: 'gen_ai.invoke_agent',
623624
origin: 'auto.vercelai.otel',
624625
status: 'ok',
@@ -633,6 +634,7 @@ describe('Vercel AI integration (V6)', () => {
633634
[GEN_AI_USAGE_OUTPUT_TOKENS_ATTRIBUTE]: 20,
634635
[GEN_AI_RESPONSE_FINISH_REASONS_ATTRIBUTE]: ['tool-calls'],
635636
}),
637+
description: 'generate_content mock-model-id',
636638
op: 'gen_ai.generate_content',
637639
origin: 'auto.vercelai.otel',
638640
status: 'ok',
@@ -662,6 +664,7 @@ describe('Vercel AI integration (V6)', () => {
662664
[GEN_AI_USAGE_OUTPUT_TOKENS_ATTRIBUTE]: 25,
663665
[GEN_AI_RESPONSE_FINISH_REASONS_ATTRIBUTE]: ['stop'],
664666
}),
667+
description: 'generate_content mock-model-id',
665668
op: 'gen_ai.generate_content',
666669
origin: 'auto.vercelai.otel',
667670
status: 'ok',

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

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,13 @@ function processEndedVercelAiSpan(span: SpanJSON): void {
322322
// Rename AI SDK attributes to standardized gen_ai attributes
323323
// Map operation.name to OpenTelemetry semantic convention values
324324
if (attributes[OPERATION_NAME_ATTRIBUTE]) {
325-
const operationName = mapVercelAiOperationName(attributes[OPERATION_NAME_ATTRIBUTE] as string);
325+
// V6+ sets ai.operationId to the bare operation (e.g. "ai.streamText") while
326+
// operation.name appends functionId (e.g. "ai.streamText myAgent").
327+
// When ai.operationId is present, use it for correct mapping.
328+
const rawOperationName = attributes[AI_OPERATION_ID_ATTRIBUTE]
329+
? (attributes[AI_OPERATION_ID_ATTRIBUTE] as string)
330+
: (attributes[OPERATION_NAME_ATTRIBUTE] as string);
331+
const operationName = mapVercelAiOperationName(rawOperationName);
326332
attributes[GEN_AI_OPERATION_NAME_ATTRIBUTE] = operationName;
327333
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
328334
delete attributes[OPERATION_NAME_ATTRIBUTE];

0 commit comments

Comments
 (0)