Skip to content

fix: unify usage mapping and include toolUsePromptTokenCount#2959

Open
seefs001 wants to merge 1 commit intoQuantumNous:mainfrom
seefs001:fix/gemini-tool-use-token
Open

fix: unify usage mapping and include toolUsePromptTokenCount#2959
seefs001 wants to merge 1 commit intoQuantumNous:mainfrom
seefs001:fix/gemini-tool-use-token

Conversation

@seefs001
Copy link
Collaborator

@seefs001 seefs001 commented Feb 17, 2026

fix #2935

Summary by CodeRabbit

  • Improvements

    • Enhanced token usage tracking to separately account for tool-use operations, providing more granular metrics for token consumption.
    • Improved consistency in token calculation across different request types and handlers.
    • Refined fallback logic for missing token counts to ensure accurate usage reporting.
  • Tests

    • Added comprehensive test coverage for token accounting scenarios, including tool-use operations and edge cases.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 17, 2026

Walkthrough

This PR adds separate tracking for tool-use prompt tokens in the Gemini DTO and centralizes token usage computation through a new helper function that properly excludes tool-use tokens from completion token calculations, ensuring accurate billing.

Changes

Cohort / File(s) Summary
DTO Schema Extension
dto/gemini.go
Added ToolUsePromptTokenCount and ToolUsePromptTokensDetails fields to GeminiUsageMetadata struct to separately track tool-use token consumption.
Usage Builder & Handler Refactoring
relay/channel/gemini/relay-gemini.go
Introduced buildUsageFromGeminiMetadata() helper function to consolidate token accounting logic, including modality-based aggregation (TEXT/AUDIO), reasoning tokens, cached tokens, and proper exclusion of tool-use prompt tokens from completion counts. Updated multiple handlers (GeminiChatHandler, GeminiStreamHandler, GeminiTextGenerationHandler) to use this helper.
Native Relay Refactoring
relay/channel/gemini/relay-gemini-native.go
Simplified usage construction by replacing manual field assignments with a call to buildUsageFromGeminiMetadata() for consistent token accounting.
Comprehensive Test Coverage
relay/channel/gemini/relay_gemini_usage_test.go
Added six new test functions validating correct token exclusion/inclusion of tool-use prompt tokens, streaming response handling, and fallback to estimated prompt tokens across chat, stream, and text generation handlers.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

Poem

🐰 A rabbit hops through token streams,
Tool-use tokens now sorted with careful schemes,
No more inflated bills to fear,
The helper function keeps billing clear! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly describes the main change: unifying usage mapping logic and including toolUsePromptTokenCount as part of input token accounting, which aligns with the PR's core objective of fixing token counting.
Linked Issues check ✅ Passed The PR addresses issue #2935 by adding toolUsePromptTokenCount fields to GeminiUsageMetadata and refactoring usage mapping to exclude tool-use tokens from output token counts via buildUsageFromGeminiMetadata helper function.
Out of Scope Changes check ✅ Passed All changes are directly scoped to fixing Gemini token accounting: DTO updates, usage mapping consolidation, and comprehensive test coverage—no unrelated modifications detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Tip

Issue Planner is now in beta. Read the docs and try it out! Share your feedback on Discord.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@relay/channel/gemini/relay-gemini.go`:
- Around line 1064-1066: The fallback computation for CompletionTokens can
produce a negative value when fallbackPromptTokens > TotalTokens; in the block
that currently sets usage.CompletionTokens = usage.TotalTokens -
usage.PromptTokens, clamp the result to a non-negative value (e.g., set
usage.CompletionTokens to max(0, usage.TotalTokens - usage.PromptTokens)) so
CompletionTokens never becomes negative; ensure you reference the same variables
used in this file (usage.TotalTokens, usage.PromptTokens, usage.CompletionTokens
and the previously computed fallbackPromptTokens) and preserve the existing
branch logic.

Comment on lines +1064 to +1066
if usage.TotalTokens > 0 && usage.CompletionTokens <= 0 {
usage.CompletionTokens = usage.TotalTokens - usage.PromptTokens
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Edge case: fallback CompletionTokens can become negative when fallbackPromptTokens exceeds TotalTokens.

When the API returns PromptTokenCount == 0 and CandidatesTokenCount == 0 but a nonzero TotalTokens, this path computes CompletionTokens = TotalTokens - PromptTokens. If fallbackPromptTokens (used on Line 1038) is larger than TotalTokens, CompletionTokens goes negative.

Consider clamping to zero:

Proposed fix
 	if usage.TotalTokens > 0 && usage.CompletionTokens <= 0 {
-		usage.CompletionTokens = usage.TotalTokens - usage.PromptTokens
+		computed := usage.TotalTokens - usage.PromptTokens
+		if computed < 0 {
+			computed = 0
+		}
+		usage.CompletionTokens = computed
 	}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if usage.TotalTokens > 0 && usage.CompletionTokens <= 0 {
usage.CompletionTokens = usage.TotalTokens - usage.PromptTokens
}
if usage.TotalTokens > 0 && usage.CompletionTokens <= 0 {
computed := usage.TotalTokens - usage.PromptTokens
if computed < 0 {
computed = 0
}
usage.CompletionTokens = computed
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@relay/channel/gemini/relay-gemini.go` around lines 1064 - 1066, The fallback
computation for CompletionTokens can produce a negative value when
fallbackPromptTokens > TotalTokens; in the block that currently sets
usage.CompletionTokens = usage.TotalTokens - usage.PromptTokens, clamp the
result to a non-negative value (e.g., set usage.CompletionTokens to max(0,
usage.TotalTokens - usage.PromptTokens)) so CompletionTokens never becomes
negative; ensure you reference the same variables used in this file
(usage.TotalTokens, usage.PromptTokens, usage.CompletionTokens and the
previously computed fallbackPromptTokens) and preserve the existing branch
logic.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Gemini 的 tooluse token 计费错误

1 participant

Comments