Skip to content

Commit ea11368

Browse files
nicohrubecclaude
andcommitted
ref(core)!: Rename Vercel AI cache/reasoning token attributes
Emit the `gen_ai.usage.cache_read.input_tokens`, `gen_ai.usage.cache_creation.input_tokens`, and `gen_ai.usage.reasoning.output_tokens` attributes from `@sentry/conventions` instead of the deprecated `gen_ai.usage.input_tokens.cached`, `gen_ai.usage.input_tokens.cache_write`, and `gen_ai.usage.output_tokens.reasoning` aliases in the Vercel AI integration. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 2f727f6 commit ea11368

4 files changed

Lines changed: 24 additions & 17 deletions

File tree

MIGRATION.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,7 @@ Affected SDKs: All SDKs.
265265
- The `gen_ai.request.available_tools` span attribute was renamed to `gen_ai.tool.definitions` across all AI integrations.
266266
- The `gen_ai.tool.input` span attribute was renamed to `gen_ai.tool.call.arguments` across all AI integrations.
267267
- The `gen_ai.tool.output` span attribute was renamed to `gen_ai.tool.call.result` across all AI integrations.
268+
- The Vercel AI token attributes `gen_ai.usage.input_tokens.cached`, `gen_ai.usage.input_tokens.cache_write`, and `gen_ai.usage.output_tokens.reasoning` were renamed to `gen_ai.usage.cache_read.input_tokens`, `gen_ai.usage.cache_creation.input_tokens`, and `gen_ai.usage.reasoning.output_tokens`.
268269
- Span attributes now use the shared `@sentry/conventions` package under the hood.
269270

270271
If you reference these attributes in custom instrumentation, `beforeSendSpan`, dashboards, or alerts, update them to the new names.

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,10 @@ import {
1616
GEN_AI_TOOL_DESCRIPTION,
1717
GEN_AI_TOOL_NAME,
1818
GEN_AI_TOOL_TYPE,
19+
GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS,
1920
GEN_AI_USAGE_INPUT_TOKENS,
20-
GEN_AI_USAGE_INPUT_TOKENS_CACHED,
2121
GEN_AI_USAGE_OUTPUT_TOKENS,
22+
GEN_AI_USAGE_REASONING_OUTPUT_TOKENS,
2223
GEN_AI_USAGE_TOTAL_TOKENS,
2324
} from '@sentry/conventions/attributes';
2425
import { GEN_AI_TOOL_CALL_ID_ATTRIBUTE } from '../../../../../../packages/server-utils/src/ai/core/gen-ai-attributes';
@@ -793,8 +794,8 @@ describe.each(matrix)('Vercel AI integration (version %s)', (version, vercelAiVe
793794
// Cache/reasoning token breakdown and conversation id are derived from the model's
794795
// `providerMetadata` — by the OTel processor on v6 and by the channel subscriber on v7,
795796
// both via the shared `getProviderMetadataAttributes` helper, so the shape is identical.
796-
expect(generateContent.attributes[GEN_AI_USAGE_INPUT_TOKENS_CACHED]?.value).toBe(5);
797-
expect(generateContent.attributes['gen_ai.usage.output_tokens.reasoning']?.value).toBe(7);
797+
expect(generateContent.attributes[GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS]?.value).toBe(5);
798+
expect(generateContent.attributes[GEN_AI_USAGE_REASONING_OUTPUT_TOKENS]?.value).toBe(7);
798799
expect(generateContent.attributes[GEN_AI_CONVERSATION_ID]?.value).toBe('resp_abc123');
799800

800801
const invokeAgent = container.items.find(

packages/server-utils/src/ai/vercel-ai/index.ts

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,11 @@ import {
2626
GEN_AI_TOOL_DESCRIPTION,
2727
GEN_AI_TOOL_NAME,
2828
GEN_AI_TOOL_TYPE,
29+
GEN_AI_USAGE_CACHE_CREATION_INPUT_TOKENS,
30+
GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS,
2931
GEN_AI_USAGE_INPUT_TOKENS,
30-
GEN_AI_USAGE_INPUT_TOKENS_CACHED,
31-
GEN_AI_USAGE_INPUT_TOKENS_CACHE_WRITE,
3232
GEN_AI_USAGE_OUTPUT_TOKENS,
33+
GEN_AI_USAGE_REASONING_OUTPUT_TOKENS,
3334
GEN_AI_USAGE_TOTAL_TOKENS,
3435
} from '@sentry/conventions/attributes';
3536
import { GEN_AI_TOOL_CALL_ID_ATTRIBUTE } from '../core/gen-ai-attributes';
@@ -257,7 +258,7 @@ function buildOutputMessages(attributes: Record<string, unknown>): void {
257258
export function processVercelAiSpanAttributes(attributes: Record<string, unknown>): void {
258259
renameAttributeKey(attributes, AI_USAGE_COMPLETION_TOKENS_ATTRIBUTE, GEN_AI_USAGE_OUTPUT_TOKENS);
259260
renameAttributeKey(attributes, AI_USAGE_PROMPT_TOKENS_ATTRIBUTE, GEN_AI_USAGE_INPUT_TOKENS);
260-
renameAttributeKey(attributes, AI_USAGE_CACHED_INPUT_TOKENS_ATTRIBUTE, GEN_AI_USAGE_INPUT_TOKENS_CACHED);
261+
renameAttributeKey(attributes, AI_USAGE_CACHED_INPUT_TOKENS_ATTRIBUTE, GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS);
261262

262263
// Parent spans (ai.streamText, ai.streamObject, etc.) use inputTokens/outputTokens instead of promptTokens/completionTokens
263264
renameAttributeKey(attributes, 'ai.usage.inputTokens', GEN_AI_USAGE_INPUT_TOKENS);
@@ -277,10 +278,10 @@ export function processVercelAiSpanAttributes(attributes: Record<string, unknown
277278
if (
278279
!inputTokensAreCacheInclusive &&
279280
typeof attributes[GEN_AI_USAGE_INPUT_TOKENS] === 'number' &&
280-
typeof attributes[GEN_AI_USAGE_INPUT_TOKENS_CACHED] === 'number'
281+
typeof attributes[GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS] === 'number'
281282
) {
282283
attributes[GEN_AI_USAGE_INPUT_TOKENS] =
283-
attributes[GEN_AI_USAGE_INPUT_TOKENS] + attributes[GEN_AI_USAGE_INPUT_TOKENS_CACHED];
284+
attributes[GEN_AI_USAGE_INPUT_TOKENS] + attributes[GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS];
284285
}
285286

286287
// Compute total tokens from input + output (embeddings may only have input tokens)
@@ -547,8 +548,8 @@ export function getProviderMetadataAttributes(providerMetadata: unknown): Record
547548
// OpenAI (v5 uses 'openai', v6 Azure Responses API uses 'azure')
548549
const openaiMetadata: OpenAiProviderMetadata | undefined = metadata.openai ?? metadata.azure;
549550
if (openaiMetadata) {
550-
setAttributeIfDefined(attributes, GEN_AI_USAGE_INPUT_TOKENS_CACHED, openaiMetadata.cachedPromptTokens);
551-
setAttributeIfDefined(attributes, 'gen_ai.usage.output_tokens.reasoning', openaiMetadata.reasoningTokens);
551+
setAttributeIfDefined(attributes, GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS, openaiMetadata.cachedPromptTokens);
552+
setAttributeIfDefined(attributes, GEN_AI_USAGE_REASONING_OUTPUT_TOKENS, openaiMetadata.reasoningTokens);
552553
setAttributeIfDefined(
553554
attributes,
554555
'gen_ai.usage.output_tokens.prediction_accepted',
@@ -565,24 +566,28 @@ export function getProviderMetadataAttributes(providerMetadata: unknown): Record
565566
if (metadata.anthropic) {
566567
const cachedInputTokens =
567568
metadata.anthropic.usage?.cache_read_input_tokens ?? metadata.anthropic.cacheReadInputTokens;
568-
setAttributeIfDefined(attributes, GEN_AI_USAGE_INPUT_TOKENS_CACHED, cachedInputTokens);
569+
setAttributeIfDefined(attributes, GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS, cachedInputTokens);
569570

570571
const cacheWriteInputTokens =
571572
metadata.anthropic.usage?.cache_creation_input_tokens ?? metadata.anthropic.cacheCreationInputTokens;
572-
setAttributeIfDefined(attributes, GEN_AI_USAGE_INPUT_TOKENS_CACHE_WRITE, cacheWriteInputTokens);
573+
setAttributeIfDefined(attributes, GEN_AI_USAGE_CACHE_CREATION_INPUT_TOKENS, cacheWriteInputTokens);
573574
}
574575

575576
if (metadata.bedrock?.usage) {
576-
setAttributeIfDefined(attributes, GEN_AI_USAGE_INPUT_TOKENS_CACHED, metadata.bedrock.usage.cacheReadInputTokens);
577577
setAttributeIfDefined(
578578
attributes,
579-
GEN_AI_USAGE_INPUT_TOKENS_CACHE_WRITE,
579+
GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS,
580+
metadata.bedrock.usage.cacheReadInputTokens,
581+
);
582+
setAttributeIfDefined(
583+
attributes,
584+
GEN_AI_USAGE_CACHE_CREATION_INPUT_TOKENS,
580585
metadata.bedrock.usage.cacheWriteInputTokens,
581586
);
582587
}
583588

584589
if (metadata.deepseek) {
585-
setAttributeIfDefined(attributes, GEN_AI_USAGE_INPUT_TOKENS_CACHED, metadata.deepseek.promptCacheHitTokens);
590+
setAttributeIfDefined(attributes, GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS, metadata.deepseek.promptCacheHitTokens);
586591
setAttributeIfDefined(attributes, 'gen_ai.usage.input_tokens.cache_miss', metadata.deepseek.promptCacheMissTokens);
587592
}
588593

packages/server-utils/test/ai/lib/tracing/vercel-ai-cached-tokens.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ describe('vercel-ai cached tokens', () => {
3838
});
3939

4040
expect(span.data?.['gen_ai.usage.input_tokens']).toBe(150);
41-
expect(span.data?.['gen_ai.usage.input_tokens.cached']).toBe(50);
41+
expect(span.data?.['gen_ai.usage.cache_read.input_tokens']).toBe(50);
4242
expect(span.data?.['gen_ai.usage.total_tokens']).toBe(150);
4343
});
4444

@@ -57,7 +57,7 @@ describe('vercel-ai cached tokens', () => {
5757
});
5858

5959
expect(span.data?.['gen_ai.usage.input_tokens']).toBe(9500);
60-
expect(span.data?.['gen_ai.usage.input_tokens.cached']).toBe(8000);
60+
expect(span.data?.['gen_ai.usage.cache_read.input_tokens']).toBe(8000);
6161
expect(span.data?.['gen_ai.usage.output_tokens']).toBe(300);
6262
expect(span.data?.['gen_ai.usage.total_tokens']).toBe(9800);
6363
});

0 commit comments

Comments
 (0)