Skip to content

MicroCompact 摘要器覆盖不足导致工具历史静默丢失,子代理/诊断缺保护策略 #608

@Yumiue

Description

@Yumiue

用户场景分析

场景 A:长调试会话中,旧工具结果消失

用户正在排查一个构建问题,已经和 Agent 交互了 30 轮。第 8 轮时执行了一次 bash 跑了完整构建日志(5000 行),第 12 轮时调用了一个 MCP Jira 工具查询了相关 issue。到了第 25 轮,Agent 需要回溯构建日志里的某个 warning 和 Jira issue 描述来做关联分析,但此时这俩工具结果已经分别变成了:

  • [summary] bash [exit=0] workdir=/proj lines=5000 chars=120000 — 日志内容全丢
  • [Old tool result content cleared] — MCP 工具无摘要器,直接清空

Agent 不得不重新执行 bash 编译 + 重新查 Jira,浪费 token 和时间。

场景 B:子 Agent 推理链被打断

用户让主 Agent spawn 一个子 Agent 去分析某个模块的架构。子 Agent 返回了 200 行的分析报告。15 轮后,主 Agent 需要引用子 Agent 的结论,但结果已被替换为 [Old tool result content cleared],Agent 只能重新 spawn 一次。

场景 C:Memo 提取时漏掉关键尾部信息

构建命令输出 3000 行,前 600 字符是正常的编译标语 + 依赖信息,真正致命的 error: linker failed 在第 2800 行。Run 结束后触发 memo 提取,sanitizeProjectedToolContent 硬截取前 600 字符,memo 只看到"构建正常"的假象,漏掉了真正的错误。


问题根因

  1. RegisterBuiltinSummarizers 只注册了 7 个内置工具的摘要器,spawn_subagentdiagnosememo/*todo/write 以及全部 MCP 工具没有摘要器,压缩时直接返回 [Old tool result content cleared]

  2. spawnsubagent/tool.godiagnose/tool.go 未显式声明 MicroCompactPolicy(),默认 Compact,导致子 Agent/诊断结果参与压缩

  3. microcompact.go:summarizeOrClear 找不到摘要器时无兜底逻辑,静默清空

  4. projection.go:sanitizeProjectedToolContent 对 tool 输出只截头部 600 rune,尾部关键信息(如构建错误)被丢弃

  5. pin_checker.go:defaultPinToolNames 只覆盖 write_file + editcopy_filemove_file 等操作关键文件的工具不被保护

  6. codebase/read.go 设为 PreserveHistory,连续读取多个大文件后 token 大量被陈旧内容占据


解决方案

方案 1(核心):为 subagent + diagnose 加 PreserveHistory 策略

  • internal/tools/spawnsubagent/tool.go:新增 MicroCompactPolicy() 返回 MicroCompactPolicyPreserveHistory
  • internal/tools/diagnose/tool.go:同上

影响:子 Agent 和诊断结果永远不会被微压缩,只有 24 span 大裁剪时才会移除。

方案 2(核心):注册缺失工具的基础摘要器 + 通用兜底

  • internal/tools/micro_compact_summarizers_builtin.gobuiltinSummarizers 列表中追加:
    • spawn_subagent:保留 role / goal(截断 80 rune)+ 输出行数字符数
    • diagnose:保留 [error] 标记 + 输出规模
    • memo/remember、recall、list、remove:保留操作类型 + 输出规模
    • todo/write:保留输出规模
  • internal/context/microcompact.go:summarizeOrClear 中,当专用摘要器为 nil 时不直接返回清空占位符,而是调用一个通用兜底函数 fallbackSummary,生成最小摘要 [summary] <tool_name> lines=N chars=N

影响:MCP 工具和其他未知工具至少保留规模信息,不会完全清空。

方案 3:Memo 提取链路改为头尾各保留一半

  • 修改 internal/context/projection.go
    • recentWindowToolContentCharLimit 从单一上限拆为 recentWindowToolContentHeadChars = 300 + recentWindowToolContentTailChars = 300
    • sanitizeRawToolContentsanitizeProjectedToolContent 改为头尾各取 300 rune,中间标记 [truncated]
  • 新增 headRunes / tailRunes 辅助函数

影响:Memo 提取能同时看到工具输出的开头和结尾,不会漏掉尾部的关键信息。

方案 4:PinChecker 扩展工具白名单

  • pin_checker.godefaultPinToolNames 追加 copy_filemove_file
  • NewDefaultPinChecker 接受可选的 extraPatterns ...string 参数

影响copy_file / move_file 操作关键文件时也享受 pin 保护。

方案 5:codebase/read 改回 Compact 并注册专用摘要器

  • internal/tools/codebase/read.goMicroCompactPolicy() 返回 MicroCompactPolicyCompact
  • micro_compact_summarizers_builtin.go:为 ToolNameCodebaseRead 注册 readFileSummarizer(复用已有实现)

影响:陈旧 read 结果被摘要为 [summary] /path/file.go lines=42 chars=1500,释放 token。


验收标准

# 验收项 验证方法
1 spawn_subagentdiagnoseMicroCompactPolicy() 返回 PreserveHistory 运行现有单元测试 go test ./internal/tools/spawnsubagent/... ./internal/tools/diagnose/... 不失败;检查返回值
2 spawn_subagentdiagnosememo/*todo/write 的工具结果在压缩后不再是 [Old tool result content cleared],而是包含工具名和输出规模的结构化摘要 go test ./internal/context/... 覆盖 microCompactMessagesWithPolicies 的用例不失败;新增或修改用例验证新摘要格式
3 MCP 工具(如 mcp.github.issue)在无专用摘要器时,压缩后生成 [summary] mcp.github.issue lines=N chars=N 而非清空占位符 同上,测试用例中构造 MCP 命名风格的工具消息验证
4 Memo 提取的 tool 内容同时包含头部和尾部,中间有截断标记 go test ./internal/context/... -run TestSanitize 相关用例通过
5 copy_file / move_file 操作 go.mod 等关键文件时不被微压缩 go test ./internal/context/... -run TestPinChecker 覆盖新工具
6 codebase/read 的旧结果被压缩为类似 [summary] /path/file.go lines=N chars=N 的摘要 现有 read_test.goMicroCompactPolicy() 用例更新为 Compact
7 所有已有单元测试不回归 go test ./internal/context/... ./internal/tools/...

改动文件一览

internal/context/microcompact.go            — 通用兜底摘要器
internal/context/projection.go              — Memo 提取头尾保留
internal/context/pin_checker.go             — 扩展工具白名单
internal/context/microcompact_summarizers_builtin.go → 注意路径!
internal/tools/micro_compact_summarizers_builtin.go  — 追加摘要器注册
internal/tools/spawnsubagent/tool.go        — 加 PreserveHistory
internal/tools/diagnose/tool.go             — 加 PreserveHistory
internal/tools/codebase/read.go             — 改回 Compact

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions