Skip to content

feat: trim prompt surfaces ~21% + lean prompt pack (compress.promptPack) - #453

Open
ranxianglei wants to merge 8 commits into
masterfrom
2026-09-24_prompt-trim-lean-pack
Open

ranxianglei wants to merge 8 commits into
masterfrom
2026-09-24_prompt-trim-lean-pack

Conversation

@ranxianglei

@ranxianglei ranxianglei commented Sep 23, 2026 •

Copy link
Copy Markdown
Owner

Closes #452

TL;DR (中文)

两阶段完成:阶段1 削减默认提示词冗余(standing surface 9004→7143 tokens,-20.7%,load-bearing 契约逐字保留);阶段2 新增 compress.promptPack: "default" | "lean" 配置,提供对齐 billion-context-pi 的 lean 模式(系统提示词 -57%,工具描述一行化)。默认包除阶段1削减外运行时行为字节级不变。

Phase 1 — default surface trim (-20.7%)

Per-surface before → after (Anthropic tokenizer):

surface before after
system (ranges mode) 3055 tok 2612 tok
system (candidates mode) 3301 tok 2859 tok
compress tool desc 1063 tok 764 tok
decompress tool desc 452 tok 227 tok
search_context tool desc 101 tok 56 tok
acp_status tool desc 184 tok 98 tok
acp_context_recap tool desc 83 tok 59 tok
context-limit nudge 265 tok 246 tok
turn nudge 117 tok 112 tok
iteration nudge 103 tok 110 tok
total standing surface 9004 tok 7143 tok

Removed: duplicated boundary-ID rules, duplicated batching prose, JSON examples repeated between nudges and tool descriptions, restatements. Kept verbatim: all load-bearing rules (ID resolution, KEEP/REF marker docs, protected-tool semantics, candidate-mode variants, internal dcp XML tags); HOW_TO_COMPRESS_RULES (shared package) untouched.

Latent bug fixed in passing: the TOOLS section said "five" tools but listed four — added the missing acp_context_recap bullet.

Bug fix (disclosed): three nudge templates (lib/prompts/context-limit-nudge.ts, turn-nudge.ts, iteration-nudge.ts) had the literal message-ID tag text stripped from their ID-rule lines on master (verified via git blob hex dump — lines read as "use IDs you can see in tags" with a double-space gap). Restored the explicit tag name so the instruction references the actual tag.

Phase 2 — lean prompt pack (opt-in)

New config: "compress": { "promptPack": "lean" } (default "default", global scope, enum-validated, declared in dcp.schema.json).

  • New lib/prompts/packs.ts: pack builders; DEFAULT_* description constants moved verbatim out of the four tool files (single source of truth); LEAN_* texts adapted from acp-kernel (MIT, same author — provenance noted in-file).
  • PromptStore takes the pack; tool factories now read their descriptions from the store at creation time (pack-aware, zero hot-path cost).
  • Precedence unchanged mechanism: user file override > pack text > bundled builder output.
  • Lean keeps every load-bearing class including INTEGRITY/PENDING anti-fabrication rules. Sizes: lean system 1137 vs 2612 chars (ranges mode, ~57% smaller); lean tool descs 30.5–76.0% of trimmed defaults.

Design rationale: devlog/2026-09-24_prompt-trim-lean-pack/DESIGN.md (incl. why global-only scoping, why RANGE_FORMAT_EXTENSION is shared, alternatives considered).

Behavior changes (old → new, per AGENTS.md disclosure rule)

  1. Default standing surface: 9004 → 7143 tokens (-20.7%). WHY: redundancy removal only — every load-bearing line kept verbatim.
  2. Nudges now name the actual message-ID tag (old: broken empty reference from upstream stripping).
  3. System prompt TOOLS section lists all five tools (old: four).
  4. New opt-in compress.promptPack; with "default" (the default) phase 2 changes nothing at runtime (regression-guarded by byte-equality test).

Tests

  • npm run typecheck passes; touched files prettier-clean.
  • New tests/prompt-packs.test.ts: 16/16 (pack ids, lean<default sizes, load-bearing fragment presence, candidates toggle, lean/default tool-desc pairs, default byte-stability, validation unknown-key+enum, mergeCompress propagation, PromptStore integration incl. override-beats-lean).
  • Full suite: 1308 tests, 1306 pass. The 2 failures are environmental (sandbox mounts /tmp read-only) and pre-exist this change: tests/soft-block.test.ts (mkdirSync('/tmp/opencode-dcp-dangerous-*') EACCES at module load) and one decompress-toFile E2E test using a /tmp path.

Devlog

devlog/2026-09-24_prompt-trim-lean-pack/{REQ.md,WORKLOG.md,DESIGN.md}

Review round (2026-09-24)

Dual-agent review (AGENTS.md §5.3 code + §5.6 tests) completed over the full diff. Findings applied in eff1fdb0:

  • MAJOR fixed: factory→store description wiring now pinned by a dedicated test (all four tools created with a lean-serving store mock; mutation-verified).
  • ensureDefaultFiles default-pack invariant pinned (managed reference files read back and asserted default-pack-only).
  • Config validation also asserts acceptance of "default"; default-pack store test extended to all four description fields.
  • search-description size threshold 0.8→0.9 (char ratio under-measures the ~55% token reduction); two test-name fidelity fixes.
  • Verdicts: code = no blockers (minor recs all applied); tests = sufficient once the wiring gap was fixed.
  • New totals: 17 packs tests, full suite 1359/1358 (sole local failure = pre-existing read-only-/tmp sandbox env, passes in CI).

@ranxianglei
ranxianglei force-pushed the 2026-09-24_prompt-trim-lean-pack branch from 4292e07 to 7ffd651 Compare September 23, 2026 18:33
@github-actions

github-actions Bot commented Sep 23, 2026 •

Copy link
Copy Markdown
Contributor

📦 Built Plugin Artifact

Branch: 2026-09-24_prompt-trim-lean-pack (3893a40)

Option A — Install from npm PR tag (recommended)

opencode plugin opencode-acp@pr-453 --global

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

Option B — Install from GitHub

opencode plugin "github:ranxianglei/opencode-acp#2026-09-24_prompt-trim-lean-pack" --global

Option C — Download artifact

  1. Download the artifact from the Actions run
  2. Extract the tarball and install:
tar xzf opencode-acp-pr453.tgz
cp -r package/dist ~/.cache/opencode/packages/opencode-acp@latest/node_modules/opencode-acp/dist
  1. Restart opencode to pick up changes.

This comment is automatically updated on each push.

…se 1)

Condense system prompt, 5 tool descriptions and nudge templates toward the
density used by billion-context-pi's default surface. Load-bearing content
(HOW_TO_COMPRESS_RULES from context-compress-algorithms, ID rules, KEEP/REF
marker docs, candidate-mode variants, internal dcp tags) is preserved verbatim.

Standing prompt surface (Anthropic tokenizer): 9004 -> 7143 tokens (-20.7%).
Per surface: system(ranges) 3055->2612, compress tool desc 1063->764,
decompress 452->227, search 101->56, acp_status 184->98, recap 83->59.

Also fixes a latent bug: three nudge templates had the dcp-message-id tag
name stripped from their ID-rule lines (committed as 'use IDs you can see in
 tags'); restored the explicit tag name so the rule is actually readable.
Adds opt-in 'lean' prompt surface pack (billion-context-pi style):
- lib/prompts/packs.ts: pack builders + DEFAULT_* description constants
  moved verbatim from tool files; LEAN_* texts adapted from acp-kernel (MIT)
- PromptStore takes promptPack; RuntimePrompts carries the four standing
  tool descriptions; factories read them from the store at creation time
- config: compress.promptPack ('default'|'lean', global scope, validated,
  declared in dcp.schema.json); default behavior byte-identical
- tests/prompt-packs.test.ts (16 tests): sizes, load-bearing fragments,
  candidates toggle, validation, merge, store incl. override-beats-lean
- devlog entry REQ/WORKLOG/DESIGN
Master's new E2E suites (PR #448/#449) build tool factories with a minimal
{reload(){}} prompts mock; since promptPack landed, factories also call
getRuntimePrompts() at creation time. Give both files the same
makeDefaultPromptsMock() helper used by the four pre-existing factory test
files so they run against the shipped default-pack descriptions.
@ranxianglei
ranxianglei force-pushed the 2026-09-24_prompt-trim-lean-pack branch from 7ffd651 to 6870ee9 Compare September 23, 2026 18:49
@ranxianglei

Copy link
Copy Markdown
Owner Author

🤖 Powered by ework · qwen3.8-27b

[bot] 🏷 收到,开始 review PR #453(分支 2026-09-24_prompt-trim-lean-pack,4 commits over master)。

初步状态:

  • CI 全绿(head ea9d396a):pr-validation / test(22+24)/ build / e2e / build-artifact 全部 success,mergeable_state=clean。
  • diff 规模 ~1000 行 / 26 文件,正在逐项核对:①阶段1削减是否只动 surface、load-bearing 条款是否逐字保留;②nudge tag 名修复是否属实(master 上确实缺标签名);③阶段2 promptPack 的校验/合并/PromptStore 接线与优先级(override > pack > builtin);④默认路径字节级不变的回归测试是否有牙;⑤diff 整洁度。

结论稍后在本楼更新。

@ranxianglei

Copy link
Copy Markdown
Owner Author

🤖 Powered by ework · qwen3.8-27b

[bot] 🏷 ## Review 结论:PR #453(分支 2026-09-24_prompt-trim-lean-pack,head ea9d396a)

总体:主体工作(trim + lean pack)扎实、方向正确、回归有防护,可以合并;发现 1 个需要处理的问题(F1,关于本 PR 披露的 nudge tag 修复在运行时不生效)。CI 全绿(pr-validation / test 22+24 / build / e2e / build-artifact,mergeable_state=clean),本地复核:typecheck 干净、tests/prompt-packs.test.ts 16/16 通过。

① 原 issue 方向(#452)

功能类两阶段需求。方案已于 #452 floor 3/4 公示(bcp 的 lean 本质是 acp-kernel 的 prompt pack 机制;只削 surface、不降级 4 条 load-bearing 规则),实现与公示方案一致。病因定位准确:冗余常驻 surface(~9004 tok)+ 缺少可选紧凑 surface,两者都在源头解决,不是治标。✅

② 回归审查(逐项既有行为清点)

触碰路径 既有行为 判定
lib/prompts/system.ts 默认系统提示词(ranges/candidates 双模式) 有意变更(已披露 -20.7%)。承重条款逐字保留已核验:BOUNDARY IDS 规则、KEEP/REF marker 文档、candidates 变体、内部 dcp tag 均在;HOW_TO_COMPRESS_RULES(共享包)未动。TOOLS 段补上缺失的第 5 个工具 bullet ✅
5 个工具描述 decompress/search/status/recap/compress-range 文本 有意变更(已披露)。语义完整保留:mode 互斥、full:true 代价警告、禁止与 compress 并行、scope 说明、示例调用 ✅
3 个 nudge 模板 JSON 骨架保留(DESIGN §7 明确拒绝删骨架,正确决策) ⚠️ 见 F1
工具工厂接线 描述改为创建时从 PromptStore 读取(decompress/recap 工厂补了 reload()) schema/args 未动,热路径零成本 ✅
config 面 新键 compress.promptPack:enum 校验、schema 声明、global-only(排除出 CompressOverridableConfig,理由成文)、mergeCompress 传播、缺省 "default" 旧配置向后兼容 ✅
PromptStore 构造器新增第 5 参(带默认值)、RuntimePrompts 增量扩展、ensureDefaultFiles 固定写 default-pack 文本(注释说明) 全部 5 处调用点核验无遗漏 ✅
其余 无阈值/时序/状态格式变化,diff 未越界 ✅

③ 代码审查 —— F1:nudge tag 名修复运行时不生效(建议合并前处理)

证据链:

  1. master 源码确实缺标签名(hex dump 证实双空格);"修复"声称属实——分支上三个模板已恢复字面 `` 标签(hex dump 证实)。
  2. 但 lib/messages/utils.ts:12 的 DCP_UNPAIRED_TAG_REGEX = /<\/?(?:dcp|acp)[^>]*>/gi 会匹配裸标签;stripHallucinationsFromString(utils.ts:203)应用它,而 stripHallucinations(utils.ts:278)在每个 message-transform pass 对所有消息文本 part 无条件执行(lib/hooks.ts:305)。
  3. nudge 文本经 injectAnchoredNudge(lib/messages/inject/utils.ts:429-466)烘焙进真实持久化消息 part,anchor 去重保证同一条消息的 nudge 会跨多个 pass 存活。
  4. 管线顺序:strip(:305)先于 injectCompressNudges(:373)→ 刚注入的 nudge 只在那一次请求里带着完整标签;下一个 pass 起同一消息被再次 strip。
  5. 本地复现:用生产环境原样正则跑 PR 分支上三个模板的实际文本,三者全部回退为 "use IDs you can see in tags"(双空格)——即 master 的坏状态。

影响:披露第 2 条("Nudges now name the actual message-ID tag")从第二个 pass 起不成立。实际危害中等偏低(系统提示词里的同名引用不受影响——系统提示不走 stripHallucinations,模型仍有正确参照),但按现状合并会让这条披露变成不实描述。

最小修复建议(3 行,不动剥离逻辑):三处 nudge 的行改为不带尖括号的写法,如 ONLY use IDs you can see in the dcp-message-id annotation tags——正则无物可剥,语义不变。不建议走"把 nudge 内容排除出 stripHallucinations"的路子:那触碰 Bug 28/#431 的承重剥离逻辑,超出本 PR 范围。

④ 测试有效性

16 个新测试断言有牙:尺寸护栏(<80%,双模式)、承重片段钉住(含 INTEGRITY/PENDING 反虚构条款)、candidates 双向开关、真实文件 fixture 的优先级集成(override > lean > bundled)、enum+unknown-key 校验、mergeCompress 稀疏/undefined 用例。6 个既有测试文件的 mock 适配是机械替换(pin default pack),无断言弱化。作者声明的 2 个失败与本沙箱 /tmp 只读约束一致,属预存环境问题。小 nit(非阻塞):"default tool descriptions preserved verbatim after moving" 测试名略超断言范围(实际是片段检查,字节级靠 store 恒等测试兜底);我已独立用脚本核验四个 DEFAULT_* 常量自阶段1→packs.ts 逐字节一致。lean 的 e2e 场景留作后续(WORKLOG §6 已记录),v1 opt-in 可接受,记得别丢。

⑤ diff 整洁度

26 文件全部与本 PR 目的相关;describe() 调用的 prettier 重排发生在本就触碰的文件内;无锁文件/版本/无关文件混入;devlog REQ/WORKLOG/DESIGN 齐全,DESIGN.md 质量高(global-only 理由、RANGE_FORMAT_EXTENSION 共享理由、备选方案、风险表俱全)。

处置建议

推荐:(a) 我直接在 PR 分支上补一个 3 行的 commit 修掉 F1(改措辞避开尖括号),然后即可合并;或 (b) 现在合并,F1 作为后续跟进。我的倾向是 (a)——这三行正是本 PR 声称修复的对象,以已知失效的形式合入不合适。等你一句话,说改我就改。


中文摘要:审完 PR #453(提示词削减 20.7% + 新增 lean 提示词包),方向正确、代码/测试/diff 均合格,唯一问题是 nudge 里修复的标签名会在第二轮之后被 stripHallucinations 再剥掉(修复仅一轮有效),建议改成不带尖括号的写法后合并。

In-pass fix flagged by PR #453 code review: hardcoded /tmp path made this
E2E fail in any environment where /tmp is not writable (e.g. sandboxed
CI with read-only /tmp). The toFile validator already accepts os.tmpdir().
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant