Repository navigation
fix: always protect the compress tool (and its result) - #7
Merged
Merged
Conversation
… config The compress tool's records are ACP metadata: the system prompt treats past compress calls as load-bearing context, and decompress relies on them. Yet isMessageProtected only matched contentType === "tool-call" AND required the tool to be listed in protectedTools — which pai-acp leaves empty by default. So both the compress tool-call AND its tool-result leaked into the compressible ranges recommended to the model, meaning the model could be nudged to compress away its own compress call, breaking decompress/search and the "summary is historical" contract. Fixes: 1. ALWAYS_PROTECTED_TOOLS = ["compress"]: isMessageProtected hard-codes this list, so compress is protected even with empty user config. Adding more metadata tools later is one-line. 2. tool-result now also evaluated: the contentType guard widened to "tool-call" | "tool-result". Hosts project tool-results with the same toolName as their call, so direct matching works when toolName is present. 3. toolCallId pairing for tool-results lacking toolName (common: hosts often project a result with only toolCallId). New collectProtectedToolCallIds() + isMessageProtectedWithPairing(); the recommend path uses the pairing variant so a compress result is protected via its call's id even when its own toolName is absent. applyCompression's existing filterProtectedToolMessages already pairs by toolCallId, so the hard-coded list flows through both the recommend (buildCompressibleRanges) and execution (applySingleRange) paths. 2 new tests: compress always excluded with empty protectedTools; compress result protected via pairing without toolName. typecheck clean; 191 tests pass; build OK.
This was referenced Oct 1, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
问题
compress 工具的调用记录是 ACP 元数据(system prompt 依赖、decompress 依赖),但 `isMessageProtected` 只匹配 `contentType === "tool-call"` 且要求该工具列在 `protectedTools` 里 —— 而 pai-acp 默认 `protectedTools: []`。
后果:compress 的 tool-call 和 tool-result 都漏进推荐给模型的可压缩范围,模型可能被 nudge 去压缩掉自己的 compress 调用,破坏 decompress/search 和"summary 是历史元数据"的契约。
实测(修复前):
```
消息: u0, bash, tool, compress(call), tool(result), u1, bash, tool
可压缩块: m00001–m00005 ← compress 调用(m4) 和 result(m5) 都在里
```
修复
`ALWAYS_PROTECTED_TOOLS = ["compress"]`:`isMessageProtected` 硬编码此列表,compress 无论用户配置如何都受保护。未来加更多元数据工具只需一行。
tool-result 也纳入判断:contentType 守卫从 `tool-call` 扩展到 `tool-call | tool-result`。host 投影 tool-result 时带相同 toolName,有 toolName 时直接匹配。
toolCallId 配对(应对 tool-result 缺 toolName 的常见情况):新增 `collectProtectedToolCallIds()` + `isMessageProtectedWithPairing()`。recommend 路径用配对版,compress 的 tool-result 即便没有 toolName 也通过其 call 的 id 被保护。
`applyCompression` 的 `filterProtectedToolMessages` 已有 toolCallId 配对逻辑,硬编码列表同时流经 recommend(buildCompressibleRanges)和执行(applySingleRange)两条路径。
修复后
```
可压缩块: m00001–m00003, m00006–m00008 ← compress 调用/result 都排除
protected: m00004–m00005 [compress]
```
测试
+117/-3,3 文件。