Skip to content

fix: count reasoning tokens in context-usage display estimates (#371) - #374

Merged
ranxianglei merged 3 commits into
masterfrom
2026-09-08_reasoning-in-context-estimate
Sep 10, 2026
Merged

ranxianglei merged 3 commits into
masterfrom
2026-09-08_reasoning-in-context-estimate

Conversation

@ranxianglei

Copy link
Copy Markdown
Owner

Problem

The context-usage display estimators count only text + tool message parts and skip reasoning parts entirely, while the real usage formula includes reasoning (lib/token-utils.ts:44: input + cacheRead + cacheWrite + output + reasoning). Two duplicated code paths are affected:

  1. estimateContextComposition (lib/messages/inject/utils.ts:586) — powers the nudge Breakdown: line.
  2. collectVisibleMessages + renderOverview (lib/compress/status.ts:125/:185) — powers the acp_status overview (CONTEXT BREAKDOWN line). Note: acp_status does not call estimateContextComposition (the import at status.ts:9 is dead) — fixing only the issue's suggested location would not fix the acp_status display.

Result: displayed percentages systematically undercount real usage, and the largest residual component (reasoning — #368) is invisible in the display.

Not affected: /acp context command — its TOTAL comes from API-reported tokens and already includes reasoning. The decision path (when to nudge) also already uses the API formula; this is a display-only fix.

Solution

Count reasoning parts (len/4 heuristic, same as text parts) as their own visible category in both estimators:

  • ContextComposition gains reasoningTokens; total = system + tool + summary + message + reasoning. Reasoning feeds msgTotal (→ protectedTokens, largestRanges reflect full footprint) but not messageTokens (text/code classification stays clean).
  • Nudge breakdown line gains | N reasoning (Q%).
  • acp_status overview: VisibleMessageInfo gains a reasoning field (kept separate from tokens = text+tool to avoid double counting); inclusion gate widened to tokens > 0 || reasoning > 0 (reasoning-only messages now visible); overview total + CONTEXT BREAKDOWN line gain the reasoning category; per-message drilldown sort/totals/lines use full footprint (tokens + reasoning).
  • System prompt CONTEXT BREAKDOWN example + category list updated (example percentages now sum to 100%).

Display-only: no persisted-state, internal-tag, config, or decision-path changes.

Files

  • lib/messages/inject/utils.ts — ContextComposition + estimateContextComposition reasoning branch + total.
  • lib/messages/inject/inject.ts — nudge breakdown line.
  • lib/compress/status.ts — VisibleMessageInfo, collectVisibleMessages, renderOverview, renderUncompressedDrilldown.
  • lib/prompts/system.ts — breakdown example + bullets.
  • tests/inject-utils-pure.test.ts (+4), tests/protection-aware-stats.test.ts (+1), tests/acp-status.test.ts (+3, plus 2 pre-existing vacuous tests fixed — their partial mocks were dropped by filterMessages so they passed with zero visible messages), tests/inject.test.ts (+1 rendered nudge-line test).
  • devlog/2026-09-08_reasoning-in-context-estimate/ — REQ / WORKLOG.

Testing

  • 1086/1086 tests pass (was 1077 on master; +9 new). Typecheck clean, build clean.
  • All 9 new tests verified to fail on the pre-fix code (empirically checked by the test reviewer against base 9b7adfd).
  • Dual-agent review (code §5.3 + tests §5.6): both APPROVE; all actionable findings addressed (rendered nudge-line test, vacuous pre-existing tests, exact-value assertion, example percentages).

Known interactions / documented non-goals

  • PR feat: strip reasoning from protected-exempt historical messages (gated) #370 (stripProtectedReasoning, open): its pass runs BEFORE injectCompressNudges in lib/hooks.ts, so post-merge the nudge-path estimator naturally matches sent content. acp_status reads raw DB messages and will still show request-time-stripped reasoning — feat: strip reasoning from protected-exempt historical messages (gated) #370-side concern, out of scope here.
  • Composition-vs-range divergence (new, minor): buildCompressibleRanges range tokens intentionally still exclude reasoning (ranges = compressible amounts; the pipeline's min-size check countMessageCharacters also excludes reasoning — adding it there risks phantom "Range too small" rejections, chore: bump version to 1.6.0 #37). Consequence: the nudge's "Effective compressible: ~X" and the overview total now include reasoning while per-range lines don't. Candidate follow-up issue.
  • Per-message dcp-message-id token annotation (countMessageCharacters) still excludes reasoning — pre-existing, out of scope, candidate follow-up.
  • countAllMessageTokens fallback (token-utils.ts) unchanged — first-turn only, no reasoning present at that point.

Fixes #371

@github-actions

github-actions Bot commented Sep 8, 2026 •

Copy link
Copy Markdown
Contributor

📦 Built Plugin Artifact

Branch: 2026-09-08_reasoning-in-context-estimate (1664f5d)

Option A — Install from npm PR tag (recommended)

opencode plugin opencode-acp@pr-374 --global

Each push to this PR publishes a new version under the pr-374 npm tag.

Option B — Install from GitHub

opencode plugin "github:ranxianglei/opencode-acp#2026-09-08_reasoning-in-context-estimate" --global

Option C — Download artifact

  1. Download the artifact from the Actions run
  2. Extract the tarball and install:
tar xzf opencode-acp-pr374.tgz
cp -r package/dist ~/.cache/opencode/packages/opencode-acp@latest/node_modules/opencode-acp/dist
  1. Restart opencode to pick up changes.

This comment is automatically updated on each push.

ework-agent added 2 commits September 10, 2026 23:24
estimateContextComposition (nudge breakdown) and collectVisibleMessages
(acp_status overview) both skipped reasoning parts, so displayed
context-usage percentages systematically undercounted real usage
(token-utils.ts usage formula includes reasoning).

- ContextComposition gains reasoningTokens; total includes it
- nudge breakdown + acp_status CONTEXT BREAKDOWN gain a reasoning category
- per-message drilldown totals/sort/lines include reasoning footprint
- system prompt breakdown example + category list updated
- +8 tests (1085/1085 passing)

Fixes #371
- add nudge breakdown line test asserting rendered reasoning category
- fix 2 pre-existing vacuous acp_status tests (partial mocks dropped by
  filterMessages → passed with zero visible messages)
- tighten protected-reasoning assertion to exact value
- system prompt breakdown example percentages now sum to 100%

1086/1086 tests passing
@ranxianglei
ranxianglei force-pushed the 2026-09-08_reasoning-in-context-estimate branch from 425a5d6 to 3d40d57 Compare September 10, 2026 15:44
@ranxianglei

Copy link
Copy Markdown
Owner Author

简述做了啥

@ranxianglei

Copy link
Copy Markdown
Owner Author

🤖 Powered by ework · qwen3.8-27b

简述

一句话:让 ACP 的上下文用量展示估算把 reasoning(thinking)token 也算进去。之前只统计 text+tool,而真实用量公式(lib/token-utils.ts:44)含 reasoning,导致展示百分比系统性偏低、且 reasoning(#368 最大残差项)在展示里完全不可见。纯展示修复,不动持久化状态 / 内部 tag / 配置 / 决策路径。

为什么是两处(两条重复代码路径,只改一处修不全):

  • estimateContextComposition(lib/messages/inject/utils.ts:586)→ 驱动 nudge 的 Breakdown: 行
  • collectVisibleMessages + renderOverview(lib/compress/status.ts)→ 驱动 acp_status overview 的 CONTEXT BREAKDOWN 行。注意 acp_status 并不调用前者(status.ts:9 的 import 是死代码),所以必须一起改。

具体改动:

  • ContextComposition 新增 reasoningTokens,total = system+tool+summary+message+reasoning。reasoning 计入 msgTotal(protectedTokens / largestRanges 反映完整占用),但不计入 messageTokens(保持 text/code 分类干净)。
  • nudge 的 Breakdown 行末尾加 | N reasoning (Q%)。
  • acp_status:VisibleMessageInfo 新增独立 reasoning 字段(与 tokens=text+tool 分开,避免重复计数);可见性门槛放宽为 tokens>0 || reasoning>0(纯 reasoning 消息现在也显示);overview 总数与 CONTEXT BREAKDOWN 行加 reasoning 类;逐消息 drilldown 的排序/小计/每行改用完整占用 tokens+reasoning。
  • 系统提示词 CONTEXT BREAKDOWN 示例 + 分类列表更新(示例百分比凑满 100%)。

验证:1086/1086 通过(master 原 1077,+9);9 个新测试均实证在改前代码上失败;双 agent 评审(code §5.3 + tests §5.6)均 APPROVE。

明确不做 / 遗留:

Fixes #371

@ranxianglei
ranxianglei merged commit 3a4ac99 into master Sep 10, 2026
6 checks passed
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.

Display/acp_status context-usage estimator excludes reasoning tokens (undercounts real usage)

1 participant