Repository navigation
[PR] fix: zcode never compresses — compress prompts advertised a tool the model could not see or call - #4372
Conversation
📦 Built Package ArtifactBranch: Option A — Install this exact build (recommended)npm install -g [email protected]This exact version is immutable and reproducible. The rolling Option B — Download artifact
tar xzf billion-context-pr4372.tgz
npm install -g packageInstall instructions are refreshed on each push. |
|
接单 |
[bot] 🏷 (ai: vllm-qwen/qwen3.8-27b) 查重:不重复。 检索了 open+closed 的 issue 与近期 PR(按失败签名而非标题):唯一相关项就是本源 issue #4344(本 PR 的 Fixes 对象);在途 PR 里没有任何另一个 PR 动 zcode 可达性判定 / host-profile / MCP 方言这条机制链(最接近的 #4366 是 zcode/claude/kimi 看门狗重连节奏,不同子系统)。查重声明完毕,开始独立审这个 PR。 标签:bug / zcode / scope/wiring / p2 —— 修的是 zcode 车道的接线缺陷(压缩面宣传了一个模型调不到的工具),严重度沿用 #4344 的最终定级(能用但核心承诺失灵到「装了等于没装」边缘,owner 未提级则维持 p2)。 先报已完成的核对(结论随后补完整八问):
正在做的独立审查点(不复述 PR 自述):① 逐条核 diff 触碰路径的既有行为清单(dsh/pi/omp/opencode/代理模式字节是否真的不动);② relay round-2 重建的字节平价嵌套是否与四条 steady prepare 完全一致;③ 桥断时 nudge 是否也一并静默(矩阵行已钉 nudge:false,代码侧再确认一次调用链);④ claude-code/kimi 拿到注记的前提(pluginMode + 前缀名)是否如 PR 所述成立。 |
[bot] 🏷 (ai: vllm-qwen/qwen3.8-27b) 独立审核完成,结论:可合(待 CI 全量 lane 转绿;我这边所有独立验证项全部通过)。 以下是结构化八问(不照抄 PR 自述,逐条自己核过): 1. 是什么问题:zcode 默认安装(native/MCP)的会话永远压缩不了——bili 在提示词和 nudge 里反复教模型调 2. 什么原因导致的:两层叠加。① 可达性判定只认字面 3. 影响范围与严重程度:只有走 zcode plugin 模式的会话(以及未来任何以 MCP 前缀名暴露工具集的 plugin 宿主);该车道核心承诺静默失效(装了等于没装),但无数据损坏、无其他车道波及。p2 定级沿用 #4344,同意。 4. 怎么修复的:策略是「观测出站工具表这一个事实源」而不是按车道名猜:可达性判定加一个方言分支;仅当模型实际看到 5. 是否有回归问题:逐路径清点完毕——
6. 是否破坏缓存:健康桥会话升级瞬间头部系统提示多一句 → 一次性前缀缓存失效,之后字节稳定(注记位置在四条 steady prepare 和 round-2 重建间完全一致,测试钉了平价);桥断会话提示变小,同样一次性失效后稳定;其他车道零字节变化,缓存不受影响。 7. 是否改了设计方向:没有转向。是把 #3884/#3482 既有的「lane-decisions 单一决策 + 矩阵双向断言」纪律扩展到第二个 wire 方言;kernel 未动、无持久化/wire 格式变化。 8. 是否引入新配置:没有。零配置面变化。 证据:本地在精确 head fc79960 上定向跑了 判定:可合。合并权限在你(系统规则禁止 agent 合并)——CI 全量 lane 绿了直接 merge 即可,标签「马上合并」名副其实。 |
[bot] 🏷 (ai: vllm-qwen/qwen3.8-27b) 补一条 CI 澄清(上一条结论不变:可合): fc79960 上那条
已单独立项 #4404(带来源标记)记录该机制家族,含影响面(release 分支依赖 push check-runs 的 #772 路径失效,workflow_dispatch 兜底仍在)、证据 run id 与修法方向——不塞进本 PR。 本 PR 自己的 pull_request 车道现状:Theorem Lane、e2e-codex-persona、e2e-dsh-plugin-lane、Windows codex overlay、e2e-native-opencode、e2e-local-registry 六条已绿,其余 22 条还在排队等 runner(今日队列拥堵所致)。转全绿即最终放行;若排队中有 lane 变红我会被唤醒继续查。 |
[bot] 🏷 (ai: vllm-qwen/qwen3.8-27b) 接单。当前状态(fc79960c0):18 条 lane 已绿、0 红,剩 10 条 gate(core test matrix 的分片入口)还在排队等 runner——今日队列拥堵的尾巴,代码侧没有任何失败信号。我继续盯:全绿了我立刻回帖确认;任何一条变红我当场定向排查(本地只跑相关收窄 case,不预跑全量)。 另外说明:合并动作本身按系统规则只能由人来点(agent 禁止合并 PR)——CI 全绿后 #4372 直接 merge 即可,标签「马上合并」名副其实。 |
[bot] 🏷 (ai: vllm-qwen/qwen3.8-27b) 状态更正——真正的卡点找到了:不是排队慢,是 ci.yml 本身今早起就是坏文件。 上一条我说「只剩 gate 排队、PR 车道正常」,查清了要修正:本 PR 剩余那批 修复已在途:PR #4405( 今天发布的操作顺序(合并动作都在你这边,agent 不能点合并):
代码侧结论维持上一条八问:可合,zcode 修复本身零回归风险点未决。 |
📦 Merged Build PublishedThis merge to master was published as npm install -g [email protected] # this exact build
npm install -g billion-context@master # always the newest merged build
|
…less zombie rounds ranxianglei#4372's zcode profile (toolsHostScopedByDefault) made every no-tools plugin round read as unreachable, which starved zombieStreak — the ranxianglei#2155 degrade-to-proxy recovery could never fire for zcode sessions (red on master: tests/issue2155-self-heal.test.ts:270, 3/3). Discriminator: ranxianglei#4344's silent bridge sends the lane HEADER with an empty tool list; the zombie shape (plugin gone from the client) sends NO header on a sticky plugin-bound session. resolveLaneDecisions now takes pluginHeaderPresent and keeps compressReachable=true for headerless plugin rounds; the four prepares pass it from the live request headers. ranxianglei#4344's header-present silent case is untouched (matrix row pair added).
Fixes #4344
What was broken (plain words)
Zcode users got the "time to compress" reminders (5+ nudges at 21-29% context usage) but compression never actually ran — 0 compressions in 46 requests. Same users on DSH/Opencode were fine. Two things were wrong at once, and bili could not tell them apart:
native routing inactive (cert-MITM)— the reporter's log has these lines). The model's tool table held no bili tool at all, yet bili kept advertising compression.mcp__bili__compress(fixed MCP shim prefix, [Bug] MCP 模式下 acp_rule 的工具名带有前缀,可能导致硬保护失效 #2578), while the standing prompt and nudges teach the bare namecompress. A strong model can bridge that gap by itself; the reporter's deepseek-v4.1-flash never called it.Why bili couldn't tell these apart: the reachability gate read only the literal name
compress(dialect-blind), and zcode had no host-profile entry so the surface was unconditionally ON in plugin mode. Not a regression — these gaps existed since the mechanisms were born (#3417 registry never had a zcode entry; prompts always taught bare names). The execution path itself is fine (e2e-plugin-grow-compress has folded viamcp__bili__compresssince 2026-09-30).The fix (observe, don't assume)
src/server/lane-decisions.ts): a request declaringmcp__bili__compresscounts as compress reachable, exactly like the bare-name observation from [bug] #3177 的 DSH compress-surface 抑制在「agent 能看到 bili 工具」的 DSH 环境下误伤:nudge 与 compress 系统提示被永久关闭 #3401. Lane-independent.src/host-profiles.ts):toolsHostScopedByDefault: true— same discipline as dsh (billion-context 0.1.197 在 DeepSeek Harness(DSH)0.2.0-rc.2 里反复抛出 Error: unknown tool "compress"。 工具注册落在了错误的作用域 #3177). Healthy bridge → surface ON; bridge absent (empty/foreign-only tool table) → surface silent instead of advertising an unreachable tool, withsurface=off(no-tools)in the log for diagnosis.src/compress-tool.ts,withMcpDialectNote): when the wire declares the prefixed compress and NOT the bare one, one static sentence is appended to the standing prompt: callmcp__bili__compress(notcompress), likewise decompress/search_context/acp_status. Appended after the untouched kernel prompt — kernel prompts are NOT modified (nokernel/change). Byte-stable per session (tool table stable → cache-stable, same premise as the surface flag, fix: DSH 压缩面抑制改为按工具实际可达性判定 (#3401) #3403).injectSystem+ the relay round-2 system rebuild (same nesting, attribution outermost per fix: teach code-mode (PTC/run_code) harnesses the ACP calling conventions + name the project in the system prompt (#3252) #3298) + amcpDialectNotefield onPrepared.Effect on other lanes: none change bytes — proxy mode never arms the note (bili injects bare names itself), pi/opencode/omp/dsh keep their prompts as-is. claude-code/kimi (MCP lanes without profile entries) keep their current always-on surface and additionally get the name note when their bridge delivers prefixed names — a strict improvement, same mismatch applies to them.
Config surface
No config field/env/flag added or changed.
Tests (both directions per the #3617 gate discipline)
tests/issue4344-mcp-dialect.test.ts(6 tests): unit — zcode no-tools drops surface +surface=off(no-tools)detail; single regular tool still drops; MCP dialect keeps it + arms the note; bare declaration keeps it + note off; both dialects → note off; dsh dialect lane-independence; pi untouched; proxy mode never arms; note gating. Real chain (openai wire,x-bili-plugin: zcode) — bridged: prompt carries the mapping, wire tool table forwarded untouched, NO bare compress injected; bridge-absent: no prompt, no note, nothing injected; pi negative control: full prompt, no note.tests/lane-decisions-matrix.test.ts: +5 rows across all four wires — zcode no-tools / mcp-dialect / bare / single-regular-tool, dsh mcp-dialect. 86 → 91 rows total.Pre-flight
npm run typecheckclean on the rebased head (base = current master, 0ba857f)testlanes on this pushed headNo
kernel/change, no persistence/config/wire-shape change beyond the intended prompt note. Happy to adjust wording of the appended note — it is host-side and cheap to iterate.