Repository navigation
fix: recognize mcp__bili__compress in reasoning drop and prune orphan exemption (#3222) - #3225
Conversation
…mpressTool #3222 mandatory fix 2. stripOrphanedToolCalls hardcoded toolName === "compress", so a pending mcp__bili__compress call (no result yet) was deleted as an orphan under active coverage while its bare-name twin survived. prune() now takes an optional isCompressTool predicate (same family as Config.isCompressTool / hideConsumedCompressCalls); unset stays bare-name only, byte-identical to before. pruneNode passes ctx.config.isCompressTool through; renderHandoff keeps the default (no config on that path). Bumps acp-kernel to 0.0.125.
…re processTurn #3222 mandatory fix 1. Two defects, one mechanism family (compress-call name recognition + request ordering): 1. dropCompressReasoning selected only toolName === "compress", so MCP-lane hosts (mcp__bili__compress) never got #651's reasoning cleanup even with compress.reasoning.drop enabled. The selector now uses isMcpBiliCompress (src/config.ts, wired since #2970). No new config surface. 2. The drop ran AFTER core.processTurn, whose hide-compress-calls node removes inactive-block call+result pairs inside the pipeline. Once the anchor pair is gone, the pre-call reasoning can no longer be located — the leak applies to the bare name too, not just MCP. Fix: planReasoningDrop computes the id set on the INBOUND history before processTurn (anchors always present), applyReasoningDrop filters any derived view by that set afterwards (steady post-turn view AND relay round-2 re-render via Prepared.dropReasoning). Kernel ids are never reused within a session, so the plan stays valid. withReasoningDrop stays for standalone callers (tests) as plan+apply. Regression tests: tests/issue3222-mcp-reasoning-prune.test.ts pins name parity for every protection gate, plus the request-order scenario driving the real kernel pipeline (superseded block's pair hidden mid-turn; old post-hoc computation leaks the reasoning, planned drop does not).
📦 Built Package ArtifactBranch: Option A — Install this exact build (recommended)npm install -g billion-context@0.0.3723-pr.3225.6255f47This exact version is immutable and reproducible. The rolling Option B — Download artifact
tar xzf billion-context-pr3225.tgz
npm install -g packageInstall instructions are refreshed on each push. |
Review follow-up on #3225: the kernel version bump (0.0.124 -> 0.0.125) was not regenerated into package-lock.json, so the lock-sync gate failed and cascaded into skipping the entire test + static-gates matrix. Regenerated via the exact CI command (npm install --package-lock-only); single-line change.
(ai: vllm-qwen/qwen3.8-27b) 查重:不重复。#3225 是 #3222 两条必改的唯一实现 PR(Closes #3222);open issue/PR 按缺陷签名检索无并行工作。 独立审核(不复读 issue 侧结论):我重读了 diff、行为面与两个新测试,并对关键链路做了代码级验证。方向正确、命中根因、无回归、测试有牙。发现并当场修掉一个 CI 阻塞项(lock-sync 红),已推到 PR 分支;其余 gate 此前均绿。 结构化八问:
行为变更清单(old→new):
我当场修掉的 CI 阻塞(小问题直接修):原 PR 10 文件 +315/-38,diff 干净、逐行与本 PR 目的相关。但 CI 的 判定:可合,前提两条——① 我刚推的 lockfile 修复让 CI 全量 test matrix 转绿(目前因级联跳过尚未真正运行,需看新一轮 CI);② kernel 改动按 Kernel Boundary 走人工审核(human merge)。两个新回归测试均有牙:host 侧用真实 |
|
检查 CI |
(ai: vllm-qwen/qwen3.8-27b) 检查完 PR #3225 的 CI:全绿通过(43/43 checks 全部 success)。 1. lock-sync 修复已生效,整条测试矩阵解锁。 我上一轮在分支上补的
2. 唯一一次失败 = 抖动(flake),不是本 PR 的回归。
我已触发 结论:CI 全绿。代码审核结论维持上一轮不变(根因正确、无 bare-name 回归、保护门钉死、两个新回归测试有牙)。剩下就是 kernel 变更按 Kernel Boundary 走人工 merge —— PR 可合并。 |
📦 Merged Build PublishedThis merge to master was published as npm install -g billion-context@0.0.446-master.c43bdf0 # this exact build
npm install -g billion-context@master # always the newest merged build
|
Closes #3222
kernel-change: #3222 mandatory fix 2 requires the kernel's prune pass to recognize MCP-form compress calls when exempting pending calls from orphan stripping; the host cannot solve this because stripOrphanedToolCalls runs inside the kernel pipeline (compress.ts pruneNode) where only ctx.config is available. The change reuses the existing Config.isCompressTool predicate family (already wired by src/config.ts loadOptions since #2970) as an optional PruneOptions field — unset stays bare-name only, byte-identical to before. acp-kernel bumped 0.0.124 -> 0.0.125.
What changes
Mandatory fix 1 — MCP reasoning cleanup (name + request order)
dropCompressReasoningselected onlytoolName === "compress", so MCP-lane hosts (mcp__bili__compress) never received Protected-message exemption inflates the incompressible context floor: per-compression reasoning is never reclaimable (~83.5% of measured residual) #651's reasoning cleanup even withcompress.reasoning.dropenabled. The selector now usesisMcpBiliCompress(src/config.ts).core.processTurn, whose hide-compress-calls node removes inactive-block call+result pairs INSIDE the pipeline. Once the anchor pair is gone, the pre-call reasoning can no longer be located — this leak applies to the BARE name too, not just MCP. Fix:planReasoningDropcomputes the id set on the INBOUND history before processTurn (anchors always present);applyReasoningDropfilters any derived view by that set afterwards (steady post-turn view in all three prepare lanes, plus relay round-2 re-render viaPrepared.dropReasoning). Kernel ids are never reused within a session, so the plan stays valid across views.withReasoningDropis kept for standalone callers (tests) as plan+apply.Mandatory fix 2 — prune keeps pending MCP compress calls
stripOrphanedToolCallshardcodedtoolName === "compress", so a pendingmcp__bili__compresscall (no result yet) was deleted as an orphan under active coverage while its bare-name twin survived.prune()now takes an optionalisCompressToolpredicate;pruneNodepassesctx.config.isCompressTool;renderHandoffkeeps the default (no config on that path, view-only export).Behavior changes (old -> new)
mcp__bili__compressroundcompress.reasoning.*configmcp__bili__compresscall under active coveragecompressisCompressToolsetNo threshold/default/timing drift elsewhere: all protection gates (
drop:false, threshold strictly-greater, no-result, result-is-last, strictEcho, thinkingSignature) are unchanged and re-pinned by tests for BOTH names.Config surface
None. Reuses existing
compress.reasoning.*config and the host-injectedConfig.isCompressToolpredicate already present inloadOptions().kernelConfigsince #2970. No new env var / CLI flag / config field.Verification
tests/issue3222-mcp-reasoning-prune.test.ts(host): name parity across every protection gate + request-order scenario driving the REALcore.processTurn(superseded block's pair hidden mid-turn; pins that old post-hoc computation leaks the reasoning while the planned drop does not).kernel/tests/prune-orphan-mcp.test.ts: pending MCP call kept with predicate; bare-name pinned; bash control still stripped; other MCP tools not misidentified; default options byte-identical.Residual boundary (noted, out of scope)
Id-based apply matches exact message ids. If a drop-target reasoning message is simultaneously reminted by instance-reid (genuinely-new instance whose id a folded copy claims, absent from the previous pass — the #2695/#462 churn corner), the plan misses that one message and it survives (pre-fix behavior for that case, conservative direction: leak, never corruption). Not part of the reported defect; left as a documented boundary rather than widening matching without traffic evidence.