Skip to content

fix(session): clamp output token count to prevent negative values (#9168)#9178

Open
kagura-agent wants to merge 1 commit intoKilo-Org:mainfrom
kagura-agent:fix/clamp-negative-output-tokens
Open

fix(session): clamp output token count to prevent negative values (#9168)#9178
kagura-agent wants to merge 1 commit intoKilo-Org:mainfrom
kagura-agent:fix/clamp-negative-output-tokens

Conversation

@kagura-agent
Copy link
Copy Markdown

Summary

Fixes #9168 — prevents negative output token counts when a provider reports reasoningTokens > outputTokens.

Problem

getUsage() computes output: outputTokens - reasoningTokens, assuming the AI SDK v6 convention that outputTokens includes reasoningTokens. Some providers (e.g. Moonshot kimi-k2.5 via the Kilo gateway) violate this invariant, producing negative values that propagate into the TUI, VS Code extension, session exports, and lifetime stats.

Changes

  • packages/opencode/src/session/index.ts: Wrap the subtraction with Math.max(0, ...) to clamp negative output token counts to zero.
  • Added a warning log when reasoningTokens > outputTokens to help track how often this provider-side inconsistency occurs.

Impact

  • Display: no more negative numbers in TUI/extension/exports
  • Stats: aggregation in stats.ts no longer biased low
  • Cost: unaffected (provider-reported cost takes precedence for Kilo gateway)

Testing

  • Verified the fix is minimal and surgical — only the clamping and warning log added
  • The Session.getUsage function does not currently have dedicated unit tests; the fix is a one-line defensive clamp with well-understood behavior

Comment thread packages/opencode/src/session/index.ts Outdated
total,
input: adjustedInputTokens,
output: safe(outputTokens - reasoningTokens),
output: safe(Math.max(0, outputTokens - reasoningTokens)),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

WARNING: This fallback still drops real output tokens for the inconsistent provider case

When reasoningTokens > outputTokens, clamping outputTokens - reasoningTokens to 0 avoids the negative value, but it also discards the provider's reported non-reasoning output count entirely. Downstream displays and stats that read tokens.output will still undercount every affected response. A safer fallback here is to treat outputTokens as already-separated when the invariant is violated.

Suggested change
output: safe(Math.max(0, outputTokens - reasoningTokens)),
output: safe(reasoningTokens > outputTokens ? outputTokens : outputTokens - reasoningTokens),

@kilo-code-bot
Copy link
Copy Markdown
Contributor

kilo-code-bot Bot commented Apr 19, 2026

Code Review Summary

Status: 1 Issues Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 1
SUGGESTION 0
Issue Details (click to expand)

WARNING

File Line Issue
packages/opencode/src/session/session.ts 321 Clamping to zero still undercounts real output tokens when the provider already reports outputTokens without reasoning tokens included.
Other Observations (not in diff)

No issues found in unchanged code that require summary-only reporting.

Files Reviewed (1 files)
  • packages/opencode/src/session/session.ts - 1 issue

Fix these issues in Kilo Cloud


Reviewed by gpt-5.4-20260305 · 354,377 tokens

@kagura-agent
Copy link
Copy Markdown
Author

Heads up: this PR now has merge conflicts after recent upstream refactoring of session/index.ts. I'll rebase and update shortly.

…lo-Org#9168)

When reasoningTokens exceeds outputTokens (due to provider SDK inconsistencies),
the subtraction produces a negative output token count. Wrap with Math.max(0, ...)
to ensure non-negative values.

Rebased onto refactored session module structure (session.ts extracted from index.ts).
@kagura-agent kagura-agent force-pushed the fix/clamp-negative-output-tokens branch from 4241435 to 59a3837 Compare April 22, 2026 20:07
@kagura-agent
Copy link
Copy Markdown
Author

Rebased onto latest main. The session module was refactored (logic extracted from index.ts to session.ts), so the fix is now applied in the new location. Same one-line change: Math.max(0, ...) to clamp the output token count.

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.

Negative output token count when reasoning > outputTokens (Kilo gateway / Moonshot kimi-k2.5 thinking)

1 participant