feat: CoreMessage.thinkingTokens — meter host-projected thinking payload - #242
Conversation
Reasoning-model hosts resend thinking blocks every turn but they are not part of the visible text projection, so every per-message counting site undercounted by exactly the cumulative thinking volume. For providers or relays without reliable usage reporting this shifts nudge/emergency compression bands late and risks upstream context overflow. Add optional CoreMessage.thinkingTokens (metering-only: never rendered, truncated, or indexed) plus countMessageTokens() as the single counting caliber used by block compressedTokens, context breakdown, protected/ compressible range tokens, status reports, and ref-tag token attributes. Host contract: attach to exactly one core per original message.
📦 Built Package ArtifactBranch: Option A — Install from npm PR tag (recommended)In your adapter project: npm install acp-kernel@pr-242Each push to this PR publishes a new version under the Option B — Download artifact
tar xzf acp-kernel-pr242.tgz
npm install ./packageThis comment is automatically updated on each push. |
Review nit from #242 review: the positive-finite guard on CoreMessage.thinkingTokens was duplicated inline in render-refs.ts instead of going through the shared caliber. Extract it as thinkingTokenValue() in tokenize.ts so countMessageTokens and the ref-tag tokens attribute cannot drift apart, and cover the ref-tag path with an invalid-payload test.
|
[bot] 🏷 Review complete (issue #241). Verified independently on One fix applied directly ( Verdict: ready to merge (human merges). |
Fixes #241
Reasoning-model hosts resend thinking blocks every turn, but thinking is not part of the visible text projection — so every per-message counting site undercounted by exactly the cumulative thinking volume. With reliable usage reporting the realUsage floor masks this; without it (usage-less relays/providers) estimates run systematically low and nudge/emergency compression bands trigger late → upstream context overflow risk.
Changes
CoreMessage.thinkingTokens?: number(src/types.ts) — metering-only: never rendered, truncated, or indexed. Host contract: attach to exactly one core per original message (split tool-call cores must not repeat it or totals multiply).countMessageTokens(message, countTokens)in src/tokenize.ts — single counting caliber: text + guarded positive-finite thinking; exported from index.ts.compressedTokens; computeContextBreakdowncharsstays text-length: the truncation gate counts truncatable payload)tokensattribute (what the model sees per message now matches block/range/breakdown accounting)Compatibility
Non-breaking: field is optional; hosts that never set it behave exactly as before.
Verification
typecheck ✓ / 637 tests ✓ (incl. new tests/thinking-tokens.test.ts, 6 tests) / build ✓