Skip to content

feat: prompt-pack resolution layer (issue #259) - #261

Open
ranxianglei wants to merge 3 commits into
masterfrom
2026-09-12_prompt-packs
Open

ranxianglei wants to merge 3 commits into
masterfrom
2026-09-12_prompt-packs

Conversation

@ranxianglei

Copy link
Copy Markdown
Owner

What

Moves the prompt-pack resolution layer out of the Pi adapter (local copy shipped in billion-context-pi #397) into acp-kernel, so the billion-context proxy and any future host can consume named surface presets without copying modules.

New module src/packs/

  • types.tsPack / PackSurface / PackSource contracts + isValidPackName (rejects traversal/malformed names before any fs access).
  • sanitize.tssanitizePackSurface: narrows raw pack JSON into a typed surface over the existing primitives (Prompts rules, CompressPromptSections, NudgePromptSections, ToolPrompts). Unknown keys, wrong types, and empty results are dropped — a bad pack degrades to "no override", never corrupts a good default. adapters.<hostId> is kept opaquely (shallow-copied) as the namespace for host-specific surface data.
  • builtin.ts — builtin registry: default (no overrides) and lean. Lean carries only host-agnostic content: a compact ACP-tags section plus one-line descriptions for all four ACP tools. Compression rules stay default (load-bearing, delivered by builders/nudges); Pi-specific lean surfaces ride under adapters.pi.
  • dir.tscreateDirPackSource(id, dir): one factory for any directory origin, <dir>/<name>.json files, tolerant of missing dirs and malformed JSON.
  • resolver.tscreatePackResolver(sources) (first non-null wins; listPacks dedupes by name with the same priority) + defaultPackSources({projectDir, userDirs}) = project > user dirs (in order) > builtins. Directory paths stay host policy — the kernel never derives them from cwd or homedir.

Pack selection (which name is active given the config cascade) stays adapter-side, as proposed in the issue.

Acceptance

  • kernel exports the packs module (src/index.ts), zero new runtime deps (only node:fs/node:path, already used by persist/)
  • lean resolves and applies through existing builders — tests assert the lean acpTags section through buildCompressSystemPrompt / buildCompressTextSystemPrompt / buildCompressHybridSystemPrompt, and the one-line descriptions through applyAcpToolOverrides over all three wire shapes (anthropic/openai/responses), with originals verified unmutated and non-matching tools passed through by reference
  • full test suite green: 712/712 (typecheck + build also clean)

中文摘要:把 prompt-pack 解析层从 Pi 适配器搬进内核(新增 src/packs/*,共 5 个模块 + 测试);lean 包只含主机无关的压缩表面,主机专属数据走不透明的 adapters.<hostId> 命名空间,目录路径策略留在宿主侧。验收三条全部满足(导出、经现有 builders 应用、712/712 全绿),可以合并;合并后 Pi 适配器可删除本地副本改用内核实现。

Move the pack resolution layer out of the Pi adapter so any host can
reuse named surface presets:

- Pack/PackSurface/PackSource contracts + sanitizePackSurface
- builtin registry (default, lean); lean = host-agnostic compact acpTags
  section + one-line tool descriptions, host-specific data rides opaquely
  under adapters.<hostId>
- createDirPackSource / createPackResolver / defaultPackSources
  (project > user dirs > builtin); directory paths stay host policy
- pack selection (which name is active) stays adapter-side
@github-actions

github-actions Bot commented Sep 12, 2026

Copy link
Copy Markdown

📦 Built Package Artifact

Branch: 2026-09-12_prompt-packs (81b2236)

Option A — Install from npm PR tag (recommended)

In your adapter project:

npm install acp-kernel@pr-261

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

Option B — Download artifact

  1. Download the artifact from the Actions run
  2. Extract the tarball and install:
tar xzf acp-kernel-pr261.tgz
npm install ./package

This comment is automatically updated on each push.

A file lean.json declaring name:custom made listPacks list an unresolvable
name. Filename now wins; document trust boundary and per-session caching on
createDirPackSource.
@ranxianglei

Copy link
Copy Markdown
Owner Author

[bot] 🏷 Independent review pass completed (separate agent, read-only): approve-with-nits, no blockers. Verified: casts in sanitizePackSurface are sound (whitelisted keys, string|null values match SectionOverride); no path traversal (isValidPackName blocks / and .. before any fs call); lean content is host-agnostic (Pi provenance only in description metadata); exports map unchanged so package-root consumers unaffected.

Fixed in 81b2236:

  • createDirPackSource: filename is now authoritative for Pack.name — previously a file lean.json declaring "name":"custom" made listPacks() list an unresolvable name. Regression test added.
  • Documented the trust boundary (project-local dir = repo author can ship surface overrides to consumers, inherent to the feature like .editorconfig; content still sanitized) and per-session caching guidance on the factory JSDoc.
  • Added coverage for non-object pack files (top-level array → null).

Suite now 713/713 green, typecheck clean.

Remaining notes (no action taken):

  • tests/packs.test.ts does hermetic tmpdir file I/O, which is in tension with AGENTS.md §3's "tests are pure" letter — but follows the existing precedent of tests/persist.test.ts. Suggest amending the spec wording separately if you want strictness.
  • Symlinked .json inside a pack dir would read an outside file; risk is bounded by sanitization (only surface text reaches prompts) and noted in the JSDoc trust-boundary sentence.
  • Lean's acpTags section uses escaped tag notation while default sections embed a live tag example — defensible as written, worth an A/B if any host reports models failing to recognize refs.

中文摘要:独立 review 通过(无 blocker),已直接修掉文件名与包名不一致导致 listPacks 列出不可解析名字的问题并补了回归测试,测试 713/713 全绿,可以合并。

@ranxianglei

Copy link
Copy Markdown
Owner Author

🤖 Powered by ework · qwen3.8-27b

[bot] 🏷 Review started on PR #261 (head 2026-09-12_prompt-packs @ 81b2236). Pulling the branch, checking diff cleanliness, then running the full pre-flight (typecheck + test + build) and verifying the three acceptance criteria against actual code. Will report findings in a follow-up comment.

…-dependency in dir source list(); wrap overlong PR lines; document packs in README + AGENTS module map
@ranxianglei

Copy link
Copy Markdown
Owner Author

🤖 Powered by ework · qwen3.8-27b

[bot] 🏷 Review complete — mergeable. I checked out the head (2026-09-12_prompt-packs), audited the design against #259, verified all three acceptance criteria by running everything locally, and pushed one small review-fix commit: 4a59c73.

Diff cleanliness (first gate): clean. 7 files, +745/−0 vs base 9baa6a0 — five new src/packs/* modules, the test file, and the src/index.ts export block. No lockfile churn, no unrelated reformatting, no version bump. Duplicate screen: no other open PR touches the pack layer.

Pre-flight (all run on Node 22, real node --test, not the bun shim):

  • npm run typecheck — clean
  • npm test713/713 pass (one more than the 712 claimed in the description; all green either way)
  • npm run build — clean

Acceptance criteria, verified against code (not just the test claims):

  1. Exports added to src/index.ts; zero new runtime deps — only node:fs/node:path, same as persist/. ✓
  2. Lean resolves and applies through existing primitives: tests assert the lean acpTags section through buildCompressSystemPrompt / buildCompressTextSystemPrompt / buildCompressHybridSystemPrompt, and the one-line descriptions through applyAcpToolOverrides over all three wire shapes, with originals unmutated and non-matching tools passed through by reference. I also cross-checked that lean's paramDescriptions cover all six compress-schema params (topic, content, startId, endId, summary, summaryMaxChars) and that its tool set matches ACP_TOOL_NAMES exactly. ✓
  3. Full suite green + typecheck + build clean. ✓

Design audit vs #259: implemented exactly as proposed — PackSurface layers on the kernel's #169/#256 primitives (Partial<Prompts> / CompressPromptSections / NudgePromptSections / ToolPrompts), host-specific data rides opaquely under adapters.<hostId> (shallow-copied in sanitizePackSurface), directory paths stay host policy (defaultPackSources takes explicit paths; the kernel never derives cwd/homedir), pack selection stays adapter-side. The sanitize contract ("bad pack degrades to no override") holds: unknown keys, wrong types, and empty results are all dropped, and isValidPackName gates every fs access. The follow-up fix making the filename authoritative over an inner name field closes a real listing/resolve mismatch.

Issues found — fixed directly on the branch in 4a59c73:

  1. src/packs/sanitize.ts — the three key lists were plain string arrays, so a renamed/removed key upstream would silently stop being honored (no compile error). Now as const satisfies readonly (keyof Prompts)[] / (keyof CompressPromptSections)[] / (keyof NudgePromptSections)[] — drift becomes a type error.
  2. src/packs/dir.tslist() called this.resolve(...), which throws if the source is destructured (const { list } = src). Resolver usage is safe, but the PackSource contract says implementations must be safe to call per turn; list() now uses a closure-captured resolve, with a regression assertion added to the roundtrip test.
  3. Four overlong lines introduced by this PR (two export lines in src/index.ts, two in tests/packs.test.ts) now wrapped per Prettier. Note: format:check fails repo-wide on ~103 files including master baseline (pre-existing drift, no config file, CI doesn't gate it) — I fixed only this PR's own lines rather than churning unrelated files.
  4. Docs: the new public API was undocumented outside JSDoc. Added a "Prompt packs" section to README.md and a packs/ entry to the AGENTS.md module map.

中文摘要:审核通过——diff 干净(7 文件纯新增)、三条验收全部实测复现(typecheck/build 干净、测试 713/713 全绿、lean 经现有 builders 与三种 wire shape 应用无误);已直接在 PR 分支补了一个小修 commit 4a59c73(sanitize 键表改为 satisfies keyof 编译期防漂移、dir source list() 去掉 this 依赖并补回归断言、包装本 PR 引入的超长行、README/AGENTS.md 补文档),可以合并。

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.

1 participant