问题背景
在一个超长 agent 会话(120K+ context,多次范围压缩)中观察到:compressible ranges 累积了 55 条"缝隙残留"消息,每条 146B~6K,合计约 60K context,且无法被自动清理。
成因分析
范围压缩(startId~endId)在多次执行后,范围边界之间的消息成为"孤儿":
- 单条 <
minCompressRange(3000 字符)的消息,compress 工具拒绝单独压缩;
- 孤儿消息没有 block 覆盖,不会进入 tier 蒸馏(T1→T2→T3)的折叠范围;
- nudge 会持续把它们列为 compressible,但 agent 压掉 146B 的消息要花 ~100B 摘要,边际收益为负——于是永远留在缝隙里。
这是结构性必然:任何长会话只要用范围压缩,就会产生此类缝隙。
建议(按优先级)
1. 孤儿消息自动回收(Orphan sweep)— 根治缝隙残留
将 compressible 但无 block 覆盖且 < minCompressRange 的孤立消息自动并入最近邻 block 的摘要(作为补充行),而不是永远留在缝隙。或提供一次性的"碎片整理":允许把 N 条不连续的微残留归并成 1 个 block。
2. nudge/提示消息自身成为残留
每次压缩 nudge 注入的提示文本(约 150B,如"⚠️ Compressible ranges available...")会留在缝隙里,成为上述孤儿的主要来源之一。建议:nudge 消息标记为"可回收微块"(不参与保留窗口、可静默丢弃),或纳入已有的 messageFilters 体系。
3. minCompressRange 单位与文档
schema 定义其为 characters(3000 chars ≈ 750 tokens),但相邻配置(preserveRecentTokens、nudgeGrowthTokens)是 token,agent 极易误判阈值量级。建议统一为 token 或至少在配置注释/schema 描述中显著标注单位。
4. (低优先级)compress 支持"不连续片段一次成块"
允许一次调用把多个不相邻的 [start,end] 片段合并为单个 block,降低碎片整理的操作成本(当前每个 entry 必须连续)。
环境
- opencode-acp 版本:@latest(2026-09 使用)
- 复现场景:Sisyphus 风格 agent(大量 rmux/bash 工具输出 + 手动 compress + 长会话)
问题背景
在一个超长 agent 会话(120K+ context,多次范围压缩)中观察到:compressible ranges 累积了 55 条"缝隙残留"消息,每条 146B~6K,合计约 60K context,且无法被自动清理。
成因分析
范围压缩(startId~endId)在多次执行后,范围边界之间的消息成为"孤儿":
minCompressRange(3000 字符)的消息,compress 工具拒绝单独压缩;这是结构性必然:任何长会话只要用范围压缩,就会产生此类缝隙。
建议(按优先级)
1. 孤儿消息自动回收(Orphan sweep)— 根治缝隙残留
将 compressible 但无 block 覆盖且 < minCompressRange 的孤立消息自动并入最近邻 block 的摘要(作为补充行),而不是永远留在缝隙。或提供一次性的"碎片整理":允许把 N 条不连续的微残留归并成 1 个 block。
2. nudge/提示消息自身成为残留
每次压缩 nudge 注入的提示文本(约 150B,如"⚠️ Compressible ranges available...")会留在缝隙里,成为上述孤儿的主要来源之一。建议:nudge 消息标记为"可回收微块"(不参与保留窗口、可静默丢弃),或纳入已有的
messageFilters体系。3.
minCompressRange单位与文档schema 定义其为 characters(3000 chars ≈ 750 tokens),但相邻配置(
preserveRecentTokens、nudgeGrowthTokens)是 token,agent 极易误判阈值量级。建议统一为 token 或至少在配置注释/schema 描述中显著标注单位。4. (低优先级)compress 支持"不连续片段一次成块"
允许一次调用把多个不相邻的 [start,end] 片段合并为单个 block,降低碎片整理的操作成本(当前每个 entry 必须连续)。
环境