You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Errors: Total compressible content too small (1248 chars across 15 range(s), min 5000). Combine more messages into your range(s) to meet the threshold. —— 照做合并更多 range
→ Summary too short (22 chars, min 50) 没有 range m00003..m00004: 前缀。批处理场景下模型无法知道哪一条失败。
缺陷 B:预检吞掉"range 已消费"的真实错误,报误导性 too-small
三处解析各自独立、静默吞错:
rangeIndexSets 构建(src/compress.ts:126-139):resolveBoundaries 抛 Boundary not found... (likely consumed by an existing block),被 catch { continue } 吞掉。
minCompressRange 预检(src/compress.ts:162-201):只计算剩余可见字符,totalRangeChars < minCompressRange 时抛出 Total compressible content too small (${totalRangeChars} chars across ${input.ranges.length} range(s), min ${minCompressRange}). Combine more messages... —— 分母是输入 range 数,未扣除已消费的 range;且完全丢弃了"这些 range 已压缩"这一真实原因。
同一 range 在 rangeIndexSets / 预检 / 逐 range 执行中被 resolveBoundaries 解析三次,前两次的失败都被静默吞掉。
类型化错误:boundaries.ts 新增 export class BoundaryNotFoundError extends Error,携带 code: "BOUNDARY_NOT_FOUND"、kind: "unknown" | "consumed"、endpoint: "start" | "end"。resolveAnchorIndex 对 byRef 未命中(unknown)、消息不在可见集(consumed)等情况直接抛类型化错误,替代原来的通用 Boundary not found Error。
单次分类复用:applyCompression 开头对每个 range 解析一次并分类(ok / consumed / unknown / invalid),rangeIndexSets、minCompressRange 预检、逐 range 循环共用分类结果(解析次数 3 → 2)。
预检三分支(替换缺陷 B):
unknown / invalid:无条件按 range 报错,不 fail-fast(保留部分成功语义)。
有 consumed 且剩余可压缩字符 < 阈值 → 报真实原因: Requested range(s) already compressed (e.g. m00003..m00004); remaining compressible content X chars < min 5000. Nothing to do — run acp_status to see current compressible ranges.
无 consumed 且 < 阈值 → 保留原 Total compressible content too small (X chars across K range(s), min Y),但分母 K 改为实际计数 range 数(不再把已消费 range 计入)。
compress 工具反复报错:错误信息误导模型陷入重试死循环(模型问题 × Kernel 缺陷)
摘要
compress工具在 5 次连续调用中反复失败,每次都给出误导性错误,导致模型照错误建议盲目重试而不成功。根因与修复全部位于本仓库(kernel);下游 billion-context-pi 仅消费本修复(pin 升级随其 release 进行)。本 issue 完整记录:现象 → 复现 → 根因(两个缺陷)→ 修复方案 → 兼容性验证。现象(从头到尾)
一次真实会话中,模型连续发起 5 次
compress调用,全部失败:Errors: Summary too short (22 chars, min 50)—— 不知道是哪一段 range 失败Errors: Total compressible content too small (1248 chars across 15 range(s), min 5000). Combine more messages into your range(s) to meet the threshold.—— 照做合并更多 range核心循环:错误 #2-#5 的内容是"把更多消息合并进 range",但实际上这些 range 已被上一次调用压缩消耗(block 已创建,消息已被 prune 隐藏)。模型照错误建议操作永远无法成功,且错误信息没有指出"你引用的 range 已不存在"。
复现步骤
compress时写了 < 50 字符的 summary(触发Summary too short)。Summary too short (22 chars, min 50)无 range 标识)→ 模型无法定位,只能重试整批。minCompressRange预检静默吞掉:resolveBoundaries抛Boundary not found in visible context (likely consumed by an existing block)rangeIndexSets构建处的catch { continue }吞掉该错误,只留下Total compressible content too small (1248 chars across 15 range(s)...)。input.ranges.length(15 个输入 range),即使其中 13 个已消费 → 模型以为合并更多 range 就能超过 5000 字符阈值,继续无效重试。定性:触发是模型失误(合理校验拦截);反复重试且永远失败是 Kernel 缺陷。
根因(Kernel 两个缺陷)
定位自
acp-kernelv0.0.21:缺陷 A:批次错误无 range 归因
applyCompression逐 range 执行时,错误只 push 原始 message(src/compress.ts:218):→
Summary too short (22 chars, min 50)没有range m00003..m00004:前缀。批处理场景下模型无法知道哪一条失败。缺陷 B:预检吞掉"range 已消费"的真实错误,报误导性 too-small
三处解析各自独立、静默吞错:
rangeIndexSets构建(src/compress.ts:126-139):resolveBoundaries抛Boundary not found... (likely consumed by an existing block),被catch { continue }吞掉。minCompressRange预检(src/compress.ts:162-201):只计算剩余可见字符,totalRangeChars < minCompressRange时抛出Total compressible content too small (${totalRangeChars} chars across ${input.ranges.length} range(s), min ${minCompressRange}). Combine more messages...—— 分母是输入 range 数,未扣除已消费的 range;且完全丢弃了"这些 range 已压缩"这一真实原因。resolveBoundaries解析三次,前两次的失败都被静默吞掉。→ 模型收到"合并更多消息"的建议,照做必失败,形成死循环。
修复方案
Kernel(acp-kernel,核心修复)
boundaries.ts新增export class BoundaryNotFoundError extends Error,携带code: "BOUNDARY_NOT_FOUND"、kind: "unknown" | "consumed"、endpoint: "start" | "end"。resolveAnchorIndex对 byRef 未命中(unknown)、消息不在可见集(consumed)等情况直接抛类型化错误,替代原来的通用Boundary not foundError。applyCompression开头对每个 range 解析一次并分类(ok / consumed / unknown / invalid),rangeIndexSets、minCompressRange预检、逐 range 循环共用分类结果(解析次数 3 → 2)。unknown/invalid:无条件按 range 报错,不 fail-fast(保留部分成功语义)。Requested range(s) already compressed (e.g. m00003..m00004); remaining compressible content X chars < min 5000. Nothing to do — run acp_status to see current compressible ranges.Total compressible content too small (X chars across K range(s), min Y),但分母 K 改为实际计数 range 数(不再把已消费 range 计入)。minCompressRange预检通过时,已消费 range 记 warningSkipped range (S..E) — already compressed (messages consumed by existing block(s)); nothing to compress.(沿用 PR fix: overlap warn+skip instead of aborting the whole batch (ISSUE-42) #55 的 warn+skip 风格),并继续处理其余 range。range S..E:前缀。下游(billion-context-pi)
插件零逻辑改动(
compress-tool.ts是透传)。仅需在下次 release 时升级acp-kernel依赖 pin0.0.21 → 0.0.22。兼容性验证
对下游引用的逐一核查(kernel 修改面:
boundaries.ts/compress.ts/index.ts):BoundaryNotFoundError(纯增量)resolveBoundaries签名ResolveBoundariesInput → ResolvedRange完全未变,返回字段逐字段一致Error;新:BoundaryNotFoundError(Error子类,instanceof Error仍成立)applyCompression返回结构{ state, result: { blocksCreated, tokensCompressed, errors, warnings } };warnings字段 v0.0.21 已存在(非新增)compress-tool.ts只解构{ blocksCreated, tokensCompressed, errors, warnings }—— 语义不变,仅errors/warnings文案变化(这正是修复目的)runtime.core.processTurn/applyCompression;无任何代码直接调用resolveBoundaries/parseBoundarytsc --noEmit0 错、240/240 测试通过、build 成功;billion-context-pi:typecheck 0 错、255/255 通过、build 成功(内联新 kernel)唯一理论风险:若有下游按字符串匹配旧错误文案
"Boundary not found in visible context"—— 经全量核查无此用法,且该函数本只被 kernel 内部调用。相关 PR