Skip to content

统一 compress 参数解析(salvage + diagnostics)— 4 个实现收敛到内核 #108

Description

@ranxianglei

统一 compress 参数解析(salvage + diagnostics)— 4 个实现收敛到内核

背景

billion-context-omp#121(弱模型 compress 参数失败,实测 ~50% 失败率)与后续 #74b41cf23 删除 auto-compress 317 行,含其 salvage 逻辑)暴露了一个结构性问题:compress 工具参数解析在整条 stack 里从来没有共享层。现存 4 个各自为政的实现,容错程度各不相同,同一份畸形输入全栈行为不一致:

实现 位置 对畸形输入
proxy billion-context/src/util.ts:26-32 safeJsonParse + src/compress-tool.ts:54-83 parseCompressInput catch → {} 静默吞;只打一行 parsed 0 valid ranges. top keys: (空 keys),模型收到 Compression FAILED: no valid ranges parsedstream.ts:216-219
omp billion-context-omp/src/messages.ts:105-126 compressToolArgs(host 流 + src/wire-fold.ts:318-321 共用) JSON.parse catch → return null 静默丢弃,无任何日志(已用真实代码逐形状复现)
pi billion-context-pi/src/compress-tool.ts:75-94 normalizeRanges 返回可行动错误串并 throw(唯一给模型自我纠正机会的,但只给机会不修数据)
kernel rebuild src/rebuild.ts:63-107 extractRanges JSON.parse catch → continue 静默丢弃(fork-recovery 路径)

#70f71a9bc)删除的 auto-compress salvage(剥 ```json 围栏 + 截断 JSON 正则抽取)说明这类修复曾经存在过,随 #74 架构调整被整体丢弃——能力跟着通道被删,而不是先提升到拥有它的层

#121 实测的三类失败形状(本仓库代码全部复现):

畸形形状 proxy omp pi kernel rebuild
JSON 截断(提前收尾,括号不全) 静默丢弃 静默丢弃 错误串 静默丢弃
```json 围栏包裹 静默丢弃 静默丢弃 错误串 静默丢弃
尾逗号 静默丢弃 静默丢弃 错误串 静默丢弃

新发现:kernel 侧 vLLM fork-recovery 缺口(超出 #121 描述)

src/rebuild.tsextractRanges 只接受 Array.isArray(content),不支持 JSON-string content。vLLM 宿主会把整个 tool 参数 stringify(billion-context#176),此场景下 fork-recovery(session 恢复/重建)静默丢失全部压缩块——而 proxy 的 parseCompressInput 接受 JSON-string content。同一协议四个实现再次漂移。

内核 / adapter 划分(依据 DESIGN.md)

DESIGN.md:18-41:CORE = 纯 TS、零宿主依赖、无状态、零 I/O;ADAPTER = 薄宿主层。职责表(DESIGN.md:199-214):决策 = core,文本渲染/日志 = adapter。

进内核(本 PR)

  1. parseCompressArgs(input: unknown, opts?: { callId?: string }) → { ranges: CompressRangeSpec[]; diagnostics } — 统一 lenient 解析器:
    • 严格 JSON(对象,或整体被 stringify 的 JSON 串)
    • 剥 ```json 围栏
    • 尾逗号
    • 字符串字面量内裸换行 → 转义(JSON spec 要求转义,修复无歧义,且仅在修复后可解析时生效)
    • 截断数组 salvagecontent 数组提前收尾时,按字符串状态/括号深度 walk 原始文本,提取所有完整的顶层条目逐一解析 + 校验——能救多少救多少,不整份丢弃
    • JSON-string content(vLLM #176 形状)
    • 名字变体:startId / startRef / messageId(end 侧同理)
    • diagnostics 是数据不是日志{ ok, kind, rawPrefix(前 800 字符), length, keys, invalidItems }。内核不打印日志(零 I/O 边界),adapter 决定怎么用(落盘 / 回喂模型 / UI 提示)
  2. rebuild.ts 换用 — 顺带修 vLLM fork-recovery 缺口
  3. index.ts 导出

留 adapter(各自实现,消费 kernel diagnostics 数据)

  • raw args 协议提取(openai SSE / responses / anthropic tool_use / omp stream / wire / pi host-parsed)
  • 失败留证(proxy loggerLog / omp debug.event / pi ui.notify)
  • 失败回喂模型(proxy SSE note / pi throw + tool result / omp tool result text)
  • nudge 注入点 + 提示文本、循环/轮次控制
  • omp host 侧 live tool-args 解析在 opencode 宿主内,三个 adapter 仓库都够不着,需宿主侧修

重试策略协调:不另起状态机

#73(mid-band cadence + rejection escalation)已提议 kernel 侧 compressRejects: number(on CompressionState)+ rejectionFeedback() helper(escalate@3 / suppress@4 / 成功重置)。parse 失败重试 nudge 与 kernel reject 升级共用同一 failure-streak 机制#73 的 streak 统计所有 compress 失败(reject + parse),adapter 按失败来源选择反馈文本。本 PR 的 parser 只产出数据(diagnostics + salvage ranges),retry 策略随 #73 落地,避免双归属。

下游 adapter bump(本 PR 落地后,各开 PR)

仓库 改动 收益
billion-context(proxy) parseCompressInput/safeJsonParse → kernel parseCompressArgs;diagnostics → loggerLog;salvage ranges 照常进 applyRanges ~50% 失败率全在该链;salvage 后大量输入不再是失败
billion-context-omp compressToolArgs → kernel parser;diagnostics → debug.event 消灭静默丢弃;wire-fold 路径同步受益
billion-context-pi normalizeRanges → kernel parser;保留 throw 契约(pi isError 依赖 throw);#164 retry nudge 接 #73 streak 行为对齐 + 单一数据源

Acceptance

  • parseCompressArgs 通过畸形语料:截断 / 围栏 / 尾逗号 / 裸换行 / JSON-string content / vLLM content 串 / 名字变体 / 截断 salvage / garbage / 空输入 / 缺 content / 无效项计数 / callId 盖章
  • rebuildCompressionState 在 vLLM JSON-string content 下不再静默丢弃(fork-recovery 回归测试)
  • 所有失败路径 diagnostics 字段完整正确(rawPrefix / length / keys / invalidItems)
  • npm test / npm run typecheck / npm run build 全绿
  • 三个 adapter 仓库 bump 新版并过各自测试(后续 PR)

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