feat: compress.reasoning — drop oversized thinking from closed-turn compress calls (#336) - #339
Conversation
…ompress calls (#336) Exact semantic alignment with opencode-acp #377 (owner-locked design): compress calls are hard-exempt from compression, so their thinking rides along every request as an unreclaimable context floor. A request-time pass (src/reasoning-drop.ts) removes thinking parts only when ALL gates hold: closed turn (strictly before the last genuine user message), compress toolCall selector, and total reasoning length strictly exceeds threshold chars (2048 default, summed per-message; 0 drops any non-empty). The active round is never touched; persisted history is never modified; pure/idempotent/fail-safe. Config: compress.reasoning { drop, threshold } merged field-wise across the existing three levels (model > provider > global). OpenAI-style opaque reasoning opts out per-provider: { "compress": { "providers": { "openai": { "reasoning": { "drop": false } } } } } Applied to the rebuilt outgoing view BEFORE the nudge push so a synthetic user-role nudge can never become the boundary. Fixes #336
📦 Built Extension ArtifactBranch: Option A — Install from npm PR tag (recommended)pi install npm:billion-context-pi@pr-339Each push to this PR publishes a new version under the Option B — Download artifact
tar xzf billion-context-pi-pr339.tgz
pi install ./packageThis comment is automatically updated on each push. |
[bot] 🏷 PR #339 review 完成 — LGTM(一个非阻塞 nit) 查重结论:非重复。#339 正是 #338 floor 9 承诺的 clean reimplementation(owner-locked:"exact alignment with opencode-acp #377 … Clean reimplementation coming on a fresh branch; kernel stays untouched")。#338 已按 superseded 关闭;仓库内无其他同主题 open 项。 #336 审核:问题真实存在——compress 调用被硬排除在压缩之外(FORCE_COMPRESS_PROTECTED),其 thinking 部分每轮原样重发,构成单调上涨的不可回收地板。机制与代码路径已核实。 本地验证(PR commit
代码 review(逐点核实):
Nit(非阻塞): Consideration(owner 拍板项,无需动作):默认 结论:实现与 owner-locked 设计及已合入的 opencode-acp #377 语义对齐,全套 CI 本地通过,与 master 无冲突,可人工合并(按仓库规则 PR 合并仅人工)。"Real-session validation"数字(602K→~7K chars,48 messages)合理,但沙箱内无风暴会话日志,无法独立复现。 |
Fixes #336. Supersedes the closed #338 (kernel reasoningReplay approach) — reimplemented cleanly on master with exact semantic alignment to opencode-acp #377 (owner-locked design).
Problem
compresstool-call messages are hard-exempt from every compression selection (their tool results anchor the block summaries), so their thinking parts ride along every request — a monotonically growing, unreclaimable context floor (in the #336 storm session, ~53K tokens of anchor thinking in the outgoing view).Design (mirrors opencode-acp #377)
Request-time pass (
src/reasoning-drop.ts) that removesthinkingparts from a message only when ALL gates hold:toolCallpart with namecompress(only compress; other protected tools would need their own explicit config).threshold.0drops any non-empty.Config — nested under the existing compress three-level cascade, merged field-wise (deepest set field wins):
{ "compress": { "reasoning": { "drop": true, "threshold": 2048 }, "providers": { "openai": { "reasoning": { "drop": false } }, "anthropic": { "models": { "claude-sonnet-4-5": { "reasoning": { "threshold": 8000 } } } } } } }Opaque-reasoning providers (OpenAI encrypted reasoning) opt out per-provider as shown. Persisted history is never modified — only the outgoing view (rebuilt from the session log each request) changes. Pure, idempotent, fail-safe.
Wired in the context transform right after view rebuild and before the nudge push, so a synthetic user-role nudge can never become the boundary.
Tests
638 total, 0 fail. 12 new (
tests/reasoning-drop.test.ts): defaults, invalid-value fallbacks, all three gates (boundary / selector / size incl. 2048==kept, 2049 boundary, per-message sum, no cross-message accumulation), threshold-0 semantics, purity + idempotence, fail-safe, kill-switch, no-user case, toolCall/thoughtSignature preservation, field-wise three-level merge.Real-session validation
Replayed the #336 storm session (01a07b3c, 998 messages): 602K chars of thinking on compress-call messages → ~7K after the pass (48 messages hit), idempotent.
Docs: CONFIGURATION.md + CONFIGURATION.zh-CN.md (
compress.reasoningsection, field table, sample config).