Skip to content

feat(compact): route /compact through the ACP compression pipeline - #143

Open
ranxianglei wants to merge 2 commits into
masterfrom
2026-08-13_compact-acp-pipeline
Open

feat(compact): route /compact through the ACP compression pipeline#143
ranxianglei wants to merge 2 commits into
masterfrom
2026-08-13_compact-acp-pipeline

Conversation

@ranxianglei

Copy link
Copy Markdown
Owner

What

Intercept Pi's session_before_compact and route it through the ACP compression pipeline instead of cancelling native compaction: pick a compressible span, summarize it with a model, applyCompression, then hand the summary back to Pi as the compaction result.

How

  1. processTurn → get compressible ranges
  2. selectRangeSpan → pick a span ≥ minCompressRange (seeds on largest range, expands by smallest gap)
  3. summarizeRange → call a model (compressModel or session model) with the slice
  4. applyCompression → create an ACP block
  5. return { compaction: { summary, firstKeptEntryId, tokensBefore } } so Pi stores it

Fallback: on any failure (no compressible ranges, no usable model, unparseable response, kernel rejection, exception) return undefined → Pi falls back to its own compaction. Context is never lost.

Summary prompt uses the kernel Prompts (key design choice)

The summary-generation system prompt is built from the kernel's load-bearing compression rules (compressPhilosophy + howToCompressRules) via the Prompts interface — not a hand-rolled constant. This means:

  • /compact honors acp.json prompt overrides (the same Prompts the compress tool + tier-1 compression use)
  • stays consistent with the rest of the ACP pipeline (no drift between /compact and the compress tool)
  • tier-1 howToCompressRules are the right rule set (/compact compresses an old contiguous range, not a tier-2/3 distillation)

Config

compressModel in ~/.pi/acp.json as provider:modelId (e.g. "openai:gpt-4o"). When unset, falls back to the current session model — so /compact works with zero config.

Dependency

Adds @earendil-works/pi-ai as a devDependency for the complete() type (kept external at runtime via tsup — resolves inside Pi where pi-ai is installed). ctx.modelRegistry is a synchronous facade that deliberately does not expose complete()/stream(), so the standalone import is the supported path.

Files

  • src/auto-compress.ts (new) — range helpers + summarizeRange + buildSummaryPrompt
  • src/index.tswireCompactionDisable interception
  • tests/auto-compress.test.ts (new) — 19 tests
  • tests/integration.test.ts — updated compaction-contract test

Validation

typecheck ✓ / 294 tests pass (19 new) ✓ / build ✓

Not included (split into separate PRs)

Extracted from #119 (thanks @21307369).

awork added 2 commits August 14, 2026 00:07
Intercept Pi's session_before_compact: instead of cancelling native
compaction, pick a compressible span (selectRangeSpan), summarize it with a
model, and applyCompression, then hand the summary back to Pi as the
compaction result. On any failure (no compressible ranges, no usable model,
unparseable response, kernel rejection, exception) return undefined so Pi
falls back to its own compaction rather than losing context.

The summary prompt is built from the kernel's load-bearing compression rules
(compressPhilosophy + howToCompressRules) via the Prompts interface, so
/compact honors acp.json prompt overrides and stays consistent with the
compress tool — NOT a hand-rolled prompt that would drift from the rules.

Model resolution: explicit compressModel (provider:modelId in acp.json) wins,
else the current session model (zero-config). Adds @earendil-works/pi-ai as a
devDependency for the complete() type (kept external at runtime via tsup).

Extracted from #119 (lsmir2).
readCompressModel uses os.homedir(), which reads USERPROFILE on
Windows (not HOME). The three home-scoped tests only set HOME, so
they read the real home dir on Windows CI and failed. Extract a
withHome helper that sets both env vars.
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