Skip to content

Commit 04ecbc3

Browse files
authored
feat(node): Update vercel ai integration attributes (#16721)
Make changes to the Vercel AI integration as per https://www.notion.so/sentry/Agent-Monitoring-SDK-differences-21c8b10e4b5d80bcab51f72ae1418ea8 AI summary: ### Key Improvements: 1. **Eliminated duplicate attributes** - Tool call and prompt attributes are now renamed instead of duplicated 2. **Added tool input/output support** - New `gen_ai.tool.input` and `gen_ai.tool.output` attributes 3. **Auto-sets tool type** - Automatically adds `gen_ai.tool.type: 'function'` for tool calls 4. **Better OpenTelemetry compliance** - Cleaner attribute mapping following semantic conventions ### Technical Changes: - Uses `renameAttributeKey()` consistently instead of duplicating attributes - Removes old `ai.*` attributes after creating new `gen_ai.*` ones
1 parent 86d8994 commit 04ecbc3

File tree

2 files changed

+20
-10
lines changed
  • dev-packages/node-integration-tests/suites/tracing/vercelai
  • packages/core/src/utils

2 files changed

+20
-10
lines changed

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

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -182,10 +182,9 @@ describe('Vercel AI integration', () => {
182182
expect.objectContaining({
183183
data: {
184184
'ai.operationId': 'ai.toolCall',
185-
'ai.toolCall.id': 'call-1',
186-
'ai.toolCall.name': 'getWeather',
187185
'gen_ai.tool.call.id': 'call-1',
188186
'gen_ai.tool.name': 'getWeather',
187+
'gen_ai.tool.type': 'function',
189188
'operation.name': 'ai.toolCall',
190189
'sentry.op': 'gen_ai.execute_tool',
191190
'sentry.origin': 'auto.vercelai.otel',
@@ -389,12 +388,11 @@ describe('Vercel AI integration', () => {
389388
expect.objectContaining({
390389
data: {
391390
'ai.operationId': 'ai.toolCall',
392-
'ai.toolCall.args': expect.any(String),
393-
'ai.toolCall.id': 'call-1',
394-
'ai.toolCall.name': 'getWeather',
395-
'ai.toolCall.result': expect.any(String),
396391
'gen_ai.tool.call.id': 'call-1',
397392
'gen_ai.tool.name': 'getWeather',
393+
'gen_ai.tool.input': expect.any(String),
394+
'gen_ai.tool.output': expect.any(String),
395+
'gen_ai.tool.type': 'function',
398396
'operation.name': 'ai.toolCall',
399397
'sentry.op': 'gen_ai.execute_tool',
400398
'sentry.origin': 'auto.vercelai.otel',

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

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,10 @@ import {
1212
AI_RESPONSE_TEXT_ATTRIBUTE,
1313
AI_RESPONSE_TOOL_CALLS_ATTRIBUTE,
1414
AI_TELEMETRY_FUNCTION_ID_ATTRIBUTE,
15+
AI_TOOL_CALL_ARGS_ATTRIBUTE,
1516
AI_TOOL_CALL_ID_ATTRIBUTE,
1617
AI_TOOL_CALL_NAME_ATTRIBUTE,
18+
AI_TOOL_CALL_RESULT_ATTRIBUTE,
1719
AI_USAGE_COMPLETION_TOKENS_ATTRIBUTE,
1820
AI_USAGE_PROMPT_TOKENS_ATTRIBUTE,
1921
GEN_AI_RESPONSE_MODEL_ATTRIBUTE,
@@ -94,6 +96,9 @@ function processEndedVercelAiSpan(span: SpanJSON): void {
9496
renameAttributeKey(attributes, AI_RESPONSE_TEXT_ATTRIBUTE, 'gen_ai.response.text');
9597
renameAttributeKey(attributes, AI_RESPONSE_TOOL_CALLS_ATTRIBUTE, 'gen_ai.response.tool_calls');
9698
renameAttributeKey(attributes, AI_PROMPT_TOOLS_ATTRIBUTE, 'gen_ai.request.available_tools');
99+
100+
renameAttributeKey(attributes, AI_TOOL_CALL_ARGS_ATTRIBUTE, 'gen_ai.tool.input');
101+
renameAttributeKey(attributes, AI_TOOL_CALL_RESULT_ATTRIBUTE, 'gen_ai.tool.output');
97102
}
98103

99104
/**
@@ -111,9 +116,16 @@ function renameAttributeKey(attributes: Record<string, unknown>, oldKey: string,
111116
function processToolCallSpan(span: Span, attributes: SpanAttributes): void {
112117
addOriginToSpan(span, 'auto.vercelai.otel');
113118
span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_OP, 'gen_ai.execute_tool');
114-
span.setAttribute('gen_ai.tool.call.id', attributes[AI_TOOL_CALL_ID_ATTRIBUTE]);
115-
span.setAttribute('gen_ai.tool.name', attributes[AI_TOOL_CALL_NAME_ATTRIBUTE]);
116-
span.updateName(`execute_tool ${attributes[AI_TOOL_CALL_NAME_ATTRIBUTE]}`);
119+
renameAttributeKey(attributes, AI_TOOL_CALL_NAME_ATTRIBUTE, 'gen_ai.tool.name');
120+
renameAttributeKey(attributes, AI_TOOL_CALL_ID_ATTRIBUTE, 'gen_ai.tool.call.id');
121+
// https://opentelemetry.io/docs/specs/semconv/registry/attributes/gen-ai/#gen-ai-tool-type
122+
if (!attributes['gen_ai.tool.type']) {
123+
span.setAttribute('gen_ai.tool.type', 'function');
124+
}
125+
const toolName = attributes['gen_ai.tool.name'];
126+
if (toolName) {
127+
span.updateName(`execute_tool ${toolName}`);
128+
}
117129
}
118130

119131
function processGenerateSpan(span: Span, name: string, attributes: SpanAttributes): void {
@@ -127,7 +139,7 @@ function processGenerateSpan(span: Span, name: string, attributes: SpanAttribute
127139
const functionId = attributes[AI_TELEMETRY_FUNCTION_ID_ATTRIBUTE];
128140
if (functionId && typeof functionId === 'string' && name.split('.').length - 1 === 1) {
129141
span.updateName(`${nameWthoutAi} ${functionId}`);
130-
span.setAttribute('ai.pipeline.name', functionId);
142+
span.setAttribute('gen_ai.function_id', functionId);
131143
}
132144

133145
if (attributes[AI_PROMPT_ATTRIBUTE]) {

0 commit comments

Comments
 (0)