fix(server-utils): Include Gemini reasoning tokens in Vercel AI token usage - #23433
Draft
zkasuran wants to merge 1 commit into
Draft
fix(server-utils): Include Gemini reasoning tokens in Vercel AI token usage#23433zkasuran wants to merge 1 commit into
zkasuran wants to merge 1 commit into
Conversation
… usage
Gemini reports its reasoning ("thoughts") tokens separately from the
candidate output count, so the Vercel AI SDK's `outputTokens` only covers
the visible answer. `getProviderMetadataAttributes()` never looked at the
Google/Vertex `usageMetadata`, so `gen_ai.usage.output_tokens` dropped the
reasoning tokens and the total was computed as input + candidate-only
output.
For a real Gemini reasoning response with usageMetadata
{promptTokenCount:14, candidatesTokenCount:1, thoughtsTokenCount:100,
totalTokenCount:115} the span emitted output_tokens=1 and total=15 instead
of output_tokens=101 and total=115.
Read the google/vertex `usageMetadata` and derive output tokens as
`candidatesTokenCount + thoughtsTokenCount`, set the total from the real
`totalTokenCount`, and record the reasoning breakdown under
`gen_ai.usage.reasoning.output_tokens`. Deriving output from the raw
candidate + thoughts counts (rather than adding onto the SDK value) keeps
it correct even if a future SDK version already folds reasoning into
`outputTokens`.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Gemini reasoning models undercount their output tokens in the Vercel AI integration. Gemini reports its reasoning ("thoughts") tokens separately from the visible candidate output, so the AI SDK's
outputTokenscovers only the answer and exposes the reasoning count throughproviderMetadata.google.usageMetadata.thoughtsTokenCount.getProviderMetadataAttributes()handled OpenAI, Anthropic, Bedrock and DeepSeek metadata but never looked at the Google/Vertex block, so the reasoning tokens were dropped fromgen_ai.usage.output_tokensand the total was computed as input + candidate-only output.Per the gen_ai token usage conventions,
gen_ai.usage.output_tokensincludes reasoning tokens. The fix reads thegoogle/vertexusageMetadata, derives output ascandidatesTokenCount + thoughtsTokenCount, sets the total from the realtotalTokenCountand records the reasoning breakdown undergen_ai.usage.reasoning.output_tokens. Both the OTel span path and theaitracing-channel path go through this shared helper, so both emit the corrected shape.Deriving output from the raw candidate + thoughts counts (rather than adding reasoning onto the existing SDK value) is deliberate: it stays correct even if a future AI SDK version folds reasoning into
outputTokensitself, so it cannot double count. The change is gated onthoughtsTokenCount > 0, so non-reasoning Gemini responses are left exactly as they were.Root cause
getProviderMetadataAttributes()inpackages/server-utils/src/ai/vercel-ai/index.tshad nogoogle/vertexbranch. The total is also computed from input + output before provider metadata is applied. For a real Gemini reasoning response:the emitted span attributes were, before the fix:
{"gen_ai.usage.output_tokens":1,"gen_ai.usage.input_tokens":14,"gen_ai.usage.total_tokens":15}and after the fix:
{"gen_ai.usage.output_tokens":101,"gen_ai.usage.input_tokens":14,"gen_ai.usage.total_tokens":115,"gen_ai.usage.reasoning.output_tokens":100}A vitest covering the OTel processor path and the shared
getProviderMetadataAttributes()helper (including the v6vertexkey and a non-reasoning regression case) is added inpackages/server-utils/test/ai/lib/tracing/vercel-ai-reasoning-tokens.test.ts.yarn lint) & (yarn test).AI assistance (Claude, Anthropic) was used in developing this change. The design, review and verification were done by the author. Verified locally before submitting:
yarn testinpackages/server-utils(377 passing, 4 new),yarn lint(oxlint, clean),oxfmt --check(clean) andyarn build:types(tsc, clean).