Skip to content

fix(billing): count tool call tokens when upstream omits usage - #5255

Open
mumingluan wants to merge 1 commit into
QuantumNous:mainfrom
mumingluan:fix/tool-call-token-estimation
Open

fix(billing): count tool call tokens when upstream omits usage#5255
mumingluan wants to merge 1 commit into
QuantumNous:mainfrom
mumingluan:fix/tool-call-token-estimation

Conversation

@mumingluan

@mumingluan mumingluan commented Jun 2, 2026

Copy link
Copy Markdown

Problem

When an upstream channel returns a tool/function-calling response without a usage object, OpenaiHandler falls back to estimating completion tokens locally via service.CountTextToken.

The current estimate only accounts for message content and reasoning content:

ctkm := service.CountTextToken(choice.Message.StringContent()+choice.Message.GetReasoningContent(), info.UpstreamModelName)

For tool-calling responses, the actual generated output (the tool call function.name and arguments) is not counted. This undercounts completion tokens, which in turn undercharges for requests that produce tool calls but whose upstream channel omits usage data.

Fix

Include each tool call's function.name and arguments in the text passed to CountTextToken, so the local estimate reflects the full generated output:

textContent := choice.Message.StringContent() + choice.Message.GetReasoningContent()
for _, tool := range choice.Message.ParseToolCalls() {
    textContent += tool.Function.Name + tool.Function.Arguments
}
ctkm := service.CountTextToken(textContent, info.UpstreamModelName)

Scope / Safety

  • Only affects the estimation fallback path (Usage.PromptTokens == 0 && Usage.CompletionTokens == 0). Responses where the upstream provides usage are unchanged.
  • Uses the existing Message.ParseToolCalls() helper; no new API.
  • go build ./relay/channel/openai/ passes; no new lint/type errors.

Test plan

  • Send a tool/function-calling request to a channel that does not return usage.
  • Before: logged completion tokens omit tool call content.
  • After: completion tokens include tool call name + arguments.

Summary by CodeRabbit

Bug Fixes

  • Improved token usage estimation accuracy for OpenAI relay responses. The system now comprehensively includes tool-call function names and arguments in token calculations, providing significantly more precise and accurate completion token counts and better usage estimates for API responses where explicit usage metrics may not be directly available from the service.

When an upstream channel returns a tool/function-calling response
without a usage object, OpenaiHandler estimates completion tokens
locally via CountTextToken. The estimate only covered message content
and reasoning content, ignoring tool call names and arguments, which
undercounts completion tokens (and therefore billing) for tool-calling
responses.

Include each tool call's function name and arguments in the text passed
to CountTextToken so the estimate reflects the full generated output.
@coderabbitai

coderabbitai Bot commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e0b82d2f-6f59-4411-a8c4-811e8336fa2b

📥 Commits

Reviewing files that changed from the base of the PR and between 7aaa533 and a2daab0.

📒 Files selected for processing (1)
  • relay/channel/openai/relay-openai.go

Walkthrough

The PR enhances the token estimation logic in the OpenAI relay handler by including tool-call function names and arguments in the text used for completion-token counting, alongside the existing message content and reasoning content.

Changes

Token Estimation Enhancement

Layer / File(s) Summary
Tool-call inclusion in token estimation
relay/channel/openai/relay-openai.go
The completion-token estimation input now appends parsed tool-call function names and arguments via choice.Message.ParseToolCalls() iteration, extending the text used for token counting beyond message string content and reasoning content.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~5 minutes

Possibly related PRs

  • QuantumNous/new-api#1606: Both PRs modify the OpenAI relay token-usage computation in relay/channel/openai/relay-openai.go when prompt/completion tokens are zero, affecting the same token-recomputation logic path.

Suggested reviewers

  • seefs001
  • Calcium-Ion

Poem

🐰 A rabbit hops through tokens bright,
Tool-calls now counted in the night,
No prompt, no completion? Fear not, dear friend!
We parse and sum till tokens blend,
Arguments counted, functions too—hooray! ✨

🚥 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 'fix(billing): count tool call tokens when upstream omits usage' clearly and specifically describes the main change: improving token counting for tool calls in billing scenarios when upstream responses lack usage data.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@Calcium-Ion
Calcium-Ion force-pushed the main branch 2 times, most recently from 51fdfc5 to 2b6f1df Compare August 30, 2026 15:03
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.

1 participant