Skip to content

fix: sync kernel-compacted compress anchor text into outbound arguments (Fixes #340) - #341

Merged
ranxianglei merged 1 commit into
masterfrom
2026-09-09_anchor-text-sync
Sep 9, 2026
Merged

fix: sync kernel-compacted compress anchor text into outbound arguments (Fixes #340)#341
ranxianglei merged 1 commit into
masterfrom
2026-09-09_anchor-text-sync

Conversation

@ranxianglei

Copy link
Copy Markdown
Owner

Fixes #340

问题

内核 0.0.60(acp-kernel #230/#232)已能在出口视图里瘦身 compress 锚点调用文本(滤死范围 + >200 字符摘要存根化),但 pi 的 coreOutToAgentMessages(src/messages.ts)从原始 entry 重建 assistant 消息,内核改写被丢弃 → 出口请求仍携带全量 args 复写本(风暴会话 54 条锚点 290K chars)。

修复

两条重建路径都消费内核改写文本,把压缩后的 JSON(从首个 { 起,与内核 parseCallText 同规则)同步回 toolCall.arguments:

  • 单 call 路径(patchRefTag,assistant 分支前置):core 文本与原 arguments 有实质差异时替换
  • 多 call 路径(reconstructToolCallMessage,新增 kernelTextByCallId 映射):按 callId 逐 call 同步

Fail-safe:内核文本缺失/不可解析 → 原样保留;字符串形态 content(qwen 等非严格 provider)保持字符串形态;无差异时返回原对象引用(零开销)。同步是通用的——内核只改写 compress 调用文本,故天然只作用于锚点。

真实会话验证(风暴会话 01a07b3c 重放,processTurncoreOutToAgentMessages)

compress 锚点出口 args:54 条 290,196 chars → 17 条 22,327 chars(-92.3%)

(死锚点由内核管线隐藏,活锚点摘要存根化 + 死范围过滤)

其他

  • devDependencies.acp-kernel 0.0.560.0.60(已发布,npm latest 确认)
  • 新测试 tests/anchor-text-sync.test.ts 6 例:单 call 同步 / 字符串形态保持 / 多 call 逐 call 同步 / 无差异原引用透传 / 不可解析 fail-safe / 标签前缀扫描
  • 全套 638 tests 635 pass 0 fail;typecheck/build ✅

关联

coreOutToAgentMessages now consumes kernel-rewritten tool-call text
(hide-consumed dead-range filtering + summary stubbing, acp-kernel
#230/#232) and syncs the compacted JSON back into toolCall.arguments
for both projection paths (plain-id single-call and base#callId
multi-call). Fail-safe: unparseable/absent kernel text keeps originals;
string-form content (non-strict providers) keeps its shape.

Bumps acp-kernel pin 0.0.56 -> 0.0.60 (published).

Fixes #340
@github-actions

github-actions Bot commented Sep 9, 2026

Copy link
Copy Markdown

📦 Built Extension Artifact

Branch: 2026-09-09_anchor-text-sync (9156c3b)

Option A — Install from npm PR tag (recommended)

pi install npm:billion-context-pi@pr-341

Each push to this PR publishes a new version under the pr-341 npm tag.

Option B — Download artifact

  1. Download the artifact from the Actions run
  2. Extract the tarball and install:
tar xzf billion-context-pi-pr341.tgz
pi install ./package

This comment is automatically updated on each push.

@ranxianglei

Copy link
Copy Markdown
Owner Author

🤖 Powered by ework · qwen3.8-27b

[bot] 🏷 PR #341 审核完成。已 checkout 分支(9156c3b)、跑 npm ci / typecheck / 全套测试 / build / check-pr.sh 全绿,并逐行核对了内核 0.0.60 的改写源码。结论:问题真实、根因定位准确、实现正确,可合并(合并为 human-only,我无法代合并)。

1. 问题属实(证据)

  • 基线 coreOutToAgentMessages(src/messages.ts:218-253)重建 assistant 消息只用原始 entry:单 call 路径 patchRefTag 对 assistant 直接 return original(旧 src/messages.ts:319),多 call 路径 reconstructToolCallMessage 只按 survivingCallIds 过滤 blocks(src/messages.ts:270-289)。两条路径都不消费内核改写后的 core.text → 出口 args 永远全量。
  • 内核 0.0.60 确实改写 compress 调用文本:node_modules/acp-kernel/dist/index.js:669-801(parseCallText / rewriteCompressText / serializeCompacted / compactCompressText / hideConsumedCompressCalls)——滤死范围 + SUMMARY_STUB_CHARS=200(index.js:711)摘要存根化。

2. 层次判断:根因,非症状

根因是 pi 适配层从原始 entry 重建、丢弃内核出口视图的改写。PR 让两条重建路径消费内核改写文本并同步回 toolCall.arguments,打在根因上,而非在出口再截一刀(治标)。与 #340 已确认的根因一致。

3. 关键正确性:首 { 解析规则 sound

内核改写输出 = prefix + JSON.stringify({...obj, content}),其中 prefix = raw.slice(0, firstBrace)(index.js:695)——按定义 prefix 不含 {。故改写文本的首个 { 恰为 JSON 对象起点,适配层 compactedArgsFromindexOf("{") 与内核 parseCallText(index.js:671)同规则,解析结果即内核想要的 args 形态。

  • 边界:若 assistant 文本前缀含 {,内核 parseCallText 会 parse 失败 → 不改写 → 适配层 parse 同样失败 → fail-safe 原样保留,两侧一致,不会误伤。

4. 形态 / 零开销 / fail-safe

  • string 形态(qwen 等):内核 serializeCompacted(index.js:718)按 contentWasString 保持字符串形态,适配层泛型 parse+回写天然保留。
  • 无差异:safeStringify(parsed) === safeStringify(originalArgs) → 返回原对象引用(测试 4 用 assert.equal(..., args) 验证同一引用,零开销)。
  • fail-safe:内核文本缺失 / 不可解析 / 非对象 → 原样保留(测试 5)。
  • 泛型同步只作用于锚点:内核只改写 toolName === "compress" 的调用(index.js:768/775/783),非 compress 调用 kernel text == 原文 → 无差异 → 不变。

5. 验证(本地全绿)

  • npm ci → acp-kernel@0.0.60 确认安装(npm latest = 0.0.60,发布顺序依赖满足)
  • npm run typecheck
  • npm test638 tests / 635 pass / 0 fail / 3 skipped(3 个 skip 为既有,与 PR 描述一致)
  • npm run build ✅(dist/index.js 734.61 KB,acp-kernel 内联)
  • scripts/ci/check-pr.sh ✅(分支名 + version 合规)
  • 新增 tests/anchor-text-sync.test.ts 6 例全过:单 call 同步 / string 形态 / 多 call 逐 call(untouched bash 保原)/ 无差异原引用 / 不可解析 fail-safe / 标签前缀首 { 扫描

6. 依赖与合规

  • package.json 仅 bump devDependencies.acp-kernel 0.0.56→0.0.60,未动 version(0.1.60,非 release 提交,合规);package-lock.json 同步(两处 0.0.60)。
  • 死锚点(整条调用)由内核管线隐藏 + 既有 survivingCallIds 过滤处理;活锚点摘要存根化 + 死范围过滤由本 PR 同步。两层职责清晰,无重叠。

次要观察(非阻塞)

  • kernelTextByCallId 是全局 map(非按消息作用域),依赖 toolCallId 会话内唯一——既有假设,实践中安全。
  • 单 call 路径(patchRefTag)不调 peelRefTagBlocks,多 call 路径调——与基线一致(基线单 call assistant 分支本就 return original 不 peel),非本 PR 引入;session log 的 assistant 内容通常无 tag,peel 为 no-op,无回归。

结论:建议合并。 问题真实、根因定位准确、实现正确、测试充分、依赖就绪。合并由 human 执行。

@ranxianglei
ranxianglei merged commit 75f318a into master Sep 9, 2026
9 checks passed
@ranxianglei ranxianglei mentioned this pull request Sep 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

出口请求未同步内核瘦身后的 compress 锚点文本:args 复写本 ~22K 永驻(独立于 #336 thinking 地板)

1 participant