Skip to content

feat: structure-aware range selection (pressure compression prioritizes contiguous task segment boundaries) | feat: structure-aware range selection(压力压缩优先选连贯任务段边界) #344

Open

Description

@ranxianglei

来源: ranxianglei/billion-context#1122 分析 "auto compress problem"(软目标与弹性余量讨论)时发现;owner @ranxianglei 指示立项(2026-09-22)。

背景

#1122 用户希望自主 agent 在切换到完全不同任务时能自主压缩旧任务上下文,而不是只靠百分比阈值。讨论结论(#1122 线程):保留 usage-band 触发(成本有界、无中途压缩风暴、前缀缓存稳定),改进放在压力下选哪些范围折叠——当前候选选择不感知内容结构。

现状(acp-kernel@0.0.82)

  • recommendNode(dist/index.js L2814-2841):buildCompressibleRanges() 生成候选 → mergeRangesToThreshold(compressible, config.compress.minCompressRange) 合并成 recommendedRanges;生成/排序只按位置与最小长度,无结构判断。
  • host 侧(billion-context preflight)同样 oldest-first 折叠。
  • 后果:进行中的 tool-call 序列可能被从中间切开折叠;自洽的已完成交换被拆散;摘要边界与任务边界错位,后续 decompress/search_context 回查质量受损。

提议

在候选生成/排序处引入结构感知优先级(纯启发式、确定性、可单测;明确不引入 side-model 语义分割——成本与非确定性不可接受):

  1. 优先端点落在连贯段边界的范围:完整 tool-call 请求/响应序列、自洽 user→assistant 交换、已有 tier summary 边界;
  2. 避免切开未完成的工具调用序列与当前活跃轮次(现有 preserveRecentMessages/Tokens 只保护最近 N 条/token,粒度不足);
  3. 触发条件完全不动(decideNudge 的 usage band / pressure 分支保持原样),只改候选顺序与切分点。

建议验收标准

  • 含进行中 tool-call 序列的历史 → 推荐范围端点不落其内部;
  • 全为自洽段的历史 → 行为与现状一致(回归不变);
  • 确定性:同输入同输出,单测钉死。

影响面

  • 仅 recommendNode 候选逻辑;nudge / preemptive / host preflight 消费方自动受益;
  • 配置 schema 可不变(如担心行为漂移可加默认开启的开关);
  • billion-context 两种压缩模式(plugin/proxy)均不受 wire/injection 影响。

关联

  • 需求出处:auto compress problem billion-context#1122
  • 配套:billion-context PR #1123(compress.minContextLimit 软目标旋钮,独立可合,不依赖本 issue)
  • 镜像 issue:ranxianglei/billion-context-pi(同内容,跟踪 pi 侧跟进)

Activity

  1. ranxianglei commented on Sep 22, 2026

    @ranxianglei
    OwnerAuthor

    🤖 Powered by ework · qwen3.8-27b

    [bot] 🏷 收到。已按规范先做审核(feature 类:合理性 / 系统设计 / 耦合性),结论与方案如下,随后开始实现。

    审核结论

    1. 问题成立,但现状比 issue 描述的更完整。 已对照 master@b30723f(v0.0.82)逐行验证:buildCompressibleRanges(src/recommend.ts)已具备部分结构感知——

      • 范围按 user 消息边界切分(组内条数 ≥ 3 时);
      • 有全集合完整性筛查(#684,computeIntegrityWithdrawals):被保护区切开的 turn、落单的 call/result 对不会被广告;
      • block / protected tool / 保护区都会产生 gap,范围天然在已有 tier summary 边界处断开。

      真正缺的是两个具体缺口:

      • S1 进行中轮次:历史尾部存在尚无对应 result 的 tool-call(当前活跃轮次)时,若它落在 preserveRecentMessages/Tokens 区之外,整轮会被整体折进候选范围——端点落在未完成序列内部;
      • S2 逐范围可折叠性:现有筛查把"整个可压缩集合"当作一个折叠单位来算,但实际每个推荐范围是独立折叠的。当 call 与其 result 之间隔着 gap(典型形态:并行工具调用 [callA, skill-call(受保护), skill-result(受保护), resultA])时会得到 R1=[callA]、R2=[resultA],任一单独折叠都会在 apply 侧被拒("Range would split N tool call/result pair(s)")。
    2. 设计(纯启发式、确定性、无 side-model、触发条件完全不动):

      • S1:把"没有对应 result 的 tool-call"判为 open call,将其所属整个 turn 从可压缩集中排除(按 gap 处理);无 open call 时提前退出、零开销、行为不变;
      • S2:分组后对每个连续段迭代运行 computeIntegrityWithdrawals 至收敛,被撤回的消息转为 gap 并重新切分;自洽历史 0 次迭代即收敛 → 输出与现状字节一致(满足验收标准 2);
      • decideNudge 触发逻辑一行不动;不加新配置字段——两处改动都是条件触发的精化,自洽历史不产生漂移(如日后观察到漂移再加默认开启开关);
      • 组合正确性:全集合划分一致(现有筛查)+ 每段单独可折叠(S2)⇒ mergeRangesToThreshold 合并出的任意批次都可折叠(pair 对每段封闭故对并集封闭;turn 不含 user 消息,不可能跨切分点)。
    3. 耦合点:PR fix(recommend): never bridge block gaps when batching compressible ranges #343(fix(recommend): never bridge block gaps…)当前 open,改同一文件的 mergeRangesToThreshold。本改动位于其上游(消息列表层、合并之前),两者可组合;谁先合并谁为基,另一方 rebase。不会重复 fix(recommend): never bridge block gaps when batching compressible ranges #343 的内容。

    接下来实现 + 测试(钉死三条验收标准:进行中序列端点不落其内部 / 自洽历史回归不变 / 确定性双跑一致),跑完整 typecheck/test/build 后提 PR 引用本 issue。

  2. ranxianglei commented on Sep 22, 2026

    @ranxianglei
    OwnerAuthor

    🤖 Powered by ework · qwen3.8-27b

    [bot] 🏷 已完成,PR 已开:**https://github.com/ranxianglei/acp-kernel/pull/345**(Closes #344)

    实现(src/recommend.ts +140/-11,仅候选逻辑)

    S1 进行中轮次排除 — 新导出 computeOpenTurnMemberIds(messages):数组中任何没有对应 tool-result 的 tool-call(open call),其整个 turn group(reasoning run + burst + 已配对结果)标记为 gap,不进入可压缩集。覆盖两种形态:

    • 尾部活跃轮次(模型正在干活)——端点不再落进未完成序列;
    • 部分完成的并行 burst(call_1 已有结果、call_2 未回)——整段排除而非只摘 open call。
      无 open call 时早退,零开销。触发该轮的 user message 保持可压缩(user 消息无 wire 层配对约束,且 recent-zone 默认已保护尾部)。

    S2 逐段可折叠性精化 — 现有整集 integrity screen 假设"整个可压缩集一起折叠",但每个推荐范围是单独折叠的;段内 gap(protected tool、zone 边界)把 call/result 对或 reasoning/call 轮次劈开时,今天会广告出 apply 侧 fold gate 必然清空的范围。现在对每个连续段重跑 computeIntegrityWithdrawals 至稳定(硬上限 8 轮,每轮至少删一条故实际几轮收敛),被撤成员变 gap、范围在其处断开。

    刻意不动的:decideNudge 触发分支原样(issue 第 3 条);配置 schema 不加旋钮(两个改动都是条件性 no-op,只在结构错位处改变输出);基础分组规则(user 边界 count≥3 切分)逐字节不变。

    验收标准对照

    标准 证据
    进行中序列端点不落其内 tests/recommend-structure-aware.test.ts:open tail / partial burst / 顺序调用变体(call→result→live call:只排除 live call,已完成轮次仍可压缩)
    全自洽历史行为不变 两组回归钉死(deep-equal 旧输出)+ 全部既有测试绿 + 每个广告范围经 applyCompression 实测折叠干净
    确定性 混合 fixture 双跑 deep-equal

    验证(rebased head, node 22)

    typecheck ✅ / test ✅ 879/879(含 10 项新增)/ build ✅。format:check 不在 CI 中;顺带发现 prettier 3.9.6(^3.3.0 未锁版解析结果)对 master 上 115 个文件报格式漂移——存量问题,本 PR 未动以保持 diff 干净。

    与 PR #343 的关系

    #343 修 mergeRangesToThreshold 跨 block gap 合并;本工作在合并上游(message-list 级),两者正交组合:本 PR 保证合并前每段单独可折叠,#343 保证批次不跨 block gap。若 #343 先合,我会 rebase 到其上再请审。

    pi 侧跟进由镜像 issue(billion-context-pi)跟踪,等本库发版后 bump 即可。

  3. changed the title [-]feat: structure-aware range selection(压力压缩优先选连贯任务段边界)[/-] [+]feat: structure-aware range selection (pressure compression prioritizes contiguous task segment boundaries) | feat: structure-aware range selection(压力压缩优先选连贯任务段边界)[/+] on Oct 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions