feat: /acp compact — dedicated compression model (session shared-prefix + models.json) - #241
Open
ranxianglei wants to merge 2 commits into
Open
feat: /acp compact — dedicated compression model (session shared-prefix + models.json)#241ranxianglei wants to merge 2 commits into
ranxianglei wants to merge 2 commits into
Conversation
added 2 commits
August 28, 2026 01:04
Add an optional dedicated model that writes compress summaries instead of the main model, reusing credentials from ~/.pi/agent/models.json. - /acp compact [list | <id> | reset] command - compressionModelId persisted to ~/.pi/acp.json - CompressionModelClient (list/resolve/summarize via ModelRuntime) - handleCompress routes to the model with guaranteed fallback to the main model on any failure (never blocks the session) - 18 new tests (models.json read, mock SSE API, fallback) - README.md + CONFIGURATION.md docs
…n model Add a 'session' mode to the dedicated compression model: instead of only supporting a cheaper models.json model, /acp compact session now uses the session's own model in a separate call that reuses the session prompt prefix (system prompt + active tools + the exact transformed messages Pi just sent), so the provider prompt cache keeps the input cheap and the compression reasoning stays out of the main model's context. - runtime: per-session capture of the transformed messages (setLastSentMessages) - index: capture the rebuilt messages in the context transform; pass pi to the tool - compress-model: SESSION_MODEL_REF + summarizeContext (takes a built Context) - compress-tool: branch on session vs models.json; build the shared-prefix Context; per-range instruction appended to the captured prefix - commands: /acp compact session + status display - tests: 4 new session tests (set/status/shared-prefix success/fallback) - docs: README + CONFIGURATION for the session mode
6 tasks
📦 Built Extension ArtifactBranch: Option A — Install from npm PR tag (recommended)pi install npm:billion-context-pi@pr-241Each push to this PR publishes a new version under the Option B — Download artifact
tar xzf billion-context-pi-pr241.tgz
pi install ./packageThis comment is automatically updated on each push. |
5 tasks
Owner
Author
[bot] Reviewing this PR now. Branch |
Owner
Author
[bot] Review complete — LGTM, all CI checks green. Merging is left to you (human-only per AGENTS.md). CI (run on branch
|
| Check | Result |
|---|---|
npm run typecheck |
✅ pass |
npm test |
✅ 450/450 pass (22 new: 12 in tests/compress-model.test.ts, 10 in tests/acp-compact.test.ts) |
npm run build |
✅ dist/index.js 535.59 KB, self-contained — zero runtime refs to pi-ai (type-only imports erased) |
Verified integration points
- Pins intact:
acp-kernel0.0.46,pi-coding-agent0.83.0 unchanged; new devDep@earendil-works/pi-aipinned exactly to0.83.0(type-only, so devDep placement is correct). The 1.3K-line lockfile diff is just pi-ai's transitive deps (AWS/Anthropic SDKs) — expected. - Shared-prefix capture (
src/index.ts:367):runtime.setLastSentMessages(sid, rebuilt)stores exactly the array returned as{ messages: rebuilt }— the final ACP-transformed messages (tags + injected nudge). Correct source. - Prefix fidelity:
getSystemPromptText(ctx)usesctx.getSystemPrompt()(same prompt Pi sends),convertToLlm(AgentMessage[]): Message[]exists in pi-coding-agent 0.83.0, andcollectActiveTools's{name, description, parameters}mapping matches pi-ai'sTool/Contextshapes exactly. So the session-mode request should be byte-identical to the main model's prefix → cache hit. - Fallbacks: per-range
try/catch→ main-model summary retained on any failure; unresolvable ref, missing session model, and empty response all degrade gracefully with a⚠️ note in the panel. Session never blocked. - Tests: the 4 session tests use a real mock SSE server and assert the shared prefix (
"lorem ipsum") is actually present in the outbound request body, plus the unreachable-model fallback path. Good coverage of the load-bearing behavior. - Docs: README + CONFIGURATION cover both modes, the fallback guarantee, resolution rules, and the global-file scope.
Non-blocking observations
- Fallback quality cliff: when a compression model is set, the tool description tells the main model to pass a minimal placeholder ("compressed"). If the compression call fails for that range, the block's stored summary is that placeholder — much weaker than the old "main model writes full summaries" behavior, and the only recovery is decompress + re-compress. The session is never interrupted (as designed), but consider either (a) stating this tradeoff explicitly in the tool description/docs, or (b) asking the main model for a 1–2 sentence real summary instead of a bare placeholder so the fallback is still useful.
- Project-level override edge case:
/acp compactwrites the global~/.pi/acp.json, butloadUserConfiglets a project.pi/acp.jsonoverride per-field. If a project file setscompressionModelId, the nextreloadConfig(forced bylastUserConfigKey = undefined) re-reads and the project value wins over the command's in-memory update. CONFIGURATION documents the scope, but the command's "applies across sessions" message could mislead in that corner. - Memory:
lastSentMessagesholds a full copy of the transformed messages per session untilclearSessionTracking— fine, just noting it's a duplicate of data already in memory. - Minor:
commandArgString(args: string)is typedstringbut handles arrays (test convenience) — the type is a slight lie; harmless. truncateContent(content, 120000)caps range content only in models.json mode; session mode sends the full (cached) context with no cap. Inconsistent but each is reasonable for its mode.
None of these block the merge. Nice work — the session-mode design (isolation without a cheaper model, via cache) is the interesting part.
6 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements #240: a
/acp compactcommand that offloadscompresssummary-writing to a separate call, in two modes:session— the session's own model, in a separate call that reuses the session prompt prefix (system prompt + active tools + the exact transformed messages Pi just sent). Because the prefix matches what the main model already sent, the provider prompt cache keeps the input cheap, and the compression reasoning stays out of the main model's context.<id>— a cheapermodels.jsonmodel (reuses itsbaseUrl/apiKey; a different cache namespace, so no prefix sharing, but a lower per-token price).Unset → the main model writes summaries (unchanged default). Any call failure (network/timeout/API/empty) → fallback to the main model's summary for that range — the session is never interrupted.
Changes
src/compress-model.ts:CompressionModelClient(listModels/resolveModel/summarize/summarizeContext),SESSION_MODEL_REF.src/compress-tool.ts: branch onsessionvsmodels.json; build the shared-prefixContext; per-range instruction appended to the captured prefix.src/index.ts: capture the ACP-transformed messages in the context transform; passpito the tool.src/runtime.ts: per-sessionsetLastSentMessages/getLastSentMessages.src/commands.ts:/acp compact [session|<id>|reset]+ status display.src/user-config.ts/src/config.ts:compressionModelId(+saveCompressionModelIdwriter).compress-model+acp-compact, incl. 4 session tests). 450/450 pass.Related