Skip to content

fix(agent): isolate last-turn total in token usage reporting#18052

Merged
steipete merged 1 commit intoopenclaw:mainfrom
arosstale:fix/17016-token-usage-reporting
Feb 16, 2026
Merged

fix(agent): isolate last-turn total in token usage reporting#18052
steipete merged 1 commit intoopenclaw:mainfrom
arosstale:fix/17016-token-usage-reporting

Conversation

@arosstale
Copy link
Contributor

@arosstale arosstale commented Feb 16, 2026

Summary

Fix session_status incorrectly reporting 100% context usage by isolating the current turn total from accumulated multi-turn usage.

Fixes #17016

Root Cause

recordAssistantUsage accumulates cacheRead across the entire multi-turn run. toNormalizedUsage then produces an usage.total that reflects all accumulated tokens, which gets clamped to contextTokens. Result: every session appears at 100% context utilization.

Fix

In runEmbeddedPiAgent (src/agents/pi-embedded-runner/run.ts):

  1. Capture lastTurnTotal from the most recent model call response
  2. After toNormalizedUsage, replace usage.total with lastTurnTotal so downstream consumers (status, UI) see the actual current-turn token count

Tests

  • usage-reporting.test.ts: verifies usage.total reflects current turn total, not accumulated.

Sign-Off

  • Models used: Gemini 3 Pro (Jules patch), Claude (Anthropic cherry-pick/review)
  • Submitter effort: AI-generated (Jules), human-reviewed and cherry-picked
  • Keyword: lobster-biscuit

Greptile Summary

Fixes incorrect 100% context utilization reporting in session_status by isolating the last-turn token total from accumulated multi-turn usage. The fix captures lastTurnTotal from the most recent model call and overrides usage.total (which was inflated by accumulated cacheRead/output tokens) after toNormalizedUsage normalization.

  • run.ts: Captures lastTurnTotal from lastAssistantUsage?.total ?? attemptUsage?.total (line 497), then replaces usage.total with it after normalization (lines 897-899). This complements the existing lastCallUsage mechanism that downstream consumers (persistSessionUsageUpdate) already prefer for context-window calculations.
  • usage-reporting.test.ts: New test verifying usage.total reflects the last turn's total (200) rather than the accumulated total (350) in a simulated multi-turn scenario. Reuses shared mocks from run.overflow-compaction.mocks.shared.js.

Confidence Score: 4/5

  • This PR is safe to merge with minimal risk; it is a targeted fix to a usage reporting bug with no behavioral changes to core logic.
  • The change is small and well-scoped (2 lines of logic + 1 test file). The fix correctly addresses the reported bug where accumulated multi-turn token totals caused 100% context utilization display. The existing lastCallUsage mechanism already provides the primary defense for context-window display, making this a defense-in-depth improvement. No risk of breaking existing functionality since usage.total is only overridden when lastTurnTotal is a positive number.
  • No files require special attention. The run.ts change is minimal and well-guarded.

Last reviewed commit: 1fa49bc

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR fixes a bug where session_status incorrectly reports 100% context usage after multi-turn tool-use runs with the embedded provider flow. The root cause is that recordAssistantUsage accumulates cacheRead across all API turns, causing the calculated total to exceed contextTokens and get clamped to the maximum value (e.g., 200,000 tokens), even when actual usage is much lower.

Changes:

  • Capture lastTurnTotal from the most recent model call response in runEmbeddedPiAgent
  • Replace accumulated usage.total with lastTurnTotal before passing to downstream consumers
  • Add comprehensive test verifying correct token total reporting in multi-turn scenarios

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
src/agents/pi-embedded-runner/usage-reporting.test.ts New test file verifying that usage.total reflects current turn total (200) instead of accumulated total (350) in multi-turn scenarios
src/agents/pi-embedded-runner/run.ts Captures lastTurnTotal from last assistant/attempt usage (line 497) and replaces usage.total with it after normalization (lines 897-899) to fix context utilization reporting

@@ -893,6 +894,9 @@ export async function runEmbeddedPiAgent(
}

const usage = toNormalizedUsage(usageAccumulator);
Copy link

Copilot AI Feb 16, 2026

Choose a reason for hiding this comment

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

Consider adding a brief comment explaining why usage.total is being replaced with lastTurnTotal. This would help future maintainers understand that the accumulated total from toNormalizedUsage includes multi-turn cache reads and needs to be replaced with the actual last-turn total to avoid incorrect 100% context utilization reporting. The existing comment at lines 494-496 explains the related concept for lastRunPromptUsage, but this specific replacement could benefit from its own explanation.

Suggested change
const usage = toNormalizedUsage(usageAccumulator);
const usage = toNormalizedUsage(usageAccumulator);
// `toNormalizedUsage` accumulates totals across multiple turns and cache reads,
// which can overstate the last turn's context size (and show 100% utilization).
// Replace the accumulated `usage.total` with the actual last-turn total so that
// context-window stats reflect only the final call rather than all prior calls.

Copilot uses AI. Check for mistakes.
…w#17016)

recordAssistantUsage accumulated cacheRead across the entire multi-turn
run, and totalTokens was clamped to contextTokens. This caused
session_status to report 100% context usage regardless of actual load.

Changes:
- run.ts: capture lastTurnTotal from the most recent model call and
  inject it into the normalized usage before it reaches agentMeta.
- usage-reporting.test.ts: verify usage.total reflects current turn,
  not accumulated total.

Fixes openclaw#17016
@steipete steipete merged commit a62ff19 into openclaw:main Feb 16, 2026
23 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling size: S

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: session_status totalTokens always shows contextTokens (100%) after multi-turn tool-use runs

3 participants