Proactive auto-compaction for pi: when the context window crosses a threshold, compact between turns so a long session never stalls at the wall or forces a restart.
Part of the Pify suite. Install with pify install compact or pi install npm:@pify/compact.
A long session fills the context window, and once it is full the run stops moving — you compact by hand or start over, losing the thread. pi has built-in compaction; this is for when you turn that off (or want a different threshold): it watches usage and compacts on its own, quietly, in the gap between turns.
The trigger is agent_settled — the moment a run has fully settled, with no retry, compaction, or queued continuation pending. When context usage has reached the threshold, it calls pi's own ctx.compact() there. Compacting while the agent is idle means it never aborts a live run, which sidesteps the spurious "operation aborted" message that mid-run compaction produces; the next turn simply goes out with a smaller context, the current task preserved via the compaction instructions.
It stays dormant unless pi's built-in compaction is off, so the two never double-compact — and if it can't determine pi's setting, it errs to dormant. It won't act on an unknown usage reading (the null pi reports right after a compaction), so it can't loop.
Three triggers decide when: the percentage (thresholdPercent), an absolute token ceiling (maxTokens), and — new — a reserve-aware ceiling at contextWindow − reserveTokens, read from pi's own compaction settings. The reserve one matters on smaller windows, where a flat 80% can leave less headroom than the model needs for its reply; compacting at the reserve boundary guarantees room to respond. Whichever fires first wins; the two ceilings are hard safeties that bypass the growth gate.
agent_settled only sees the context that already exists. A big paste can overflow the window on the very next turn, before any settle. So on a fresh prompt while idle, this also preflights: it projects current tokens + the prompt's estimated cost (text and attached images) and, if that would cross the threshold, compacts before the prompt is sent — so the turn goes out against a window that fits. (Idea from Chasen-Liao/pi-auto-compact.) Turn it off with preflight.
The summary is pi's, generated by its model — but this package hands that model a short, deterministic list of facts to keep: the task and any scope change, the files modified and read, stated preferences, recent commits, and any open blocker, all extracted by plain parsing (no model call, no tokens of its own) from the session and appended to the compaction instructions as "preserve these exact facts." So the summary is far less likely to generalize away the load-bearing details. (Extraction adapted from sting8k/pi-vcc.) Turn it off with anchors.
Separately — and always on, even while dormant — a deterministic pass watches the outbound context for a different long-session death: a model that collapses into a long single-codepoint run (observed in the wild as a thinking block ending in thousands of 【). pi replays prior assistant thinking to the provider on every later request, so a degenerated tail rides along every subsequent prompt, biases the model to continue the run, and the session dies in an abort loop. The guard collapses those runs in the outbound view only (persisted history is never touched) and, while the degenerated turn is the most recent one, appends a one-shot recovery notice. It costs no tokens and no model call; a clean context passes through untouched, so the prompt cache holds. (Adapted from billion-context-pi.)
.pi/compact.json (project) or <agentDir>/compact.json (global):
{
"thresholdPercent": 80,
"maxTokens": 0,
"minGrowthTokens": 0,
"reserveAware": true,
"anchors": true,
"preflight": true,
"degenerationGuard": true,
"degenerationMinRun": 200,
"enabled": true
}thresholdPercent (1–99) is how full the window may get before compaction. maxTokens is an absolute token ceiling that also triggers compaction (0 = off) — useful on very large windows where a percentage never trips before the session is already huge (80% of a 1M window is 800k tokens). Whichever comes first wins.
reserveAware (default on) adds the reserve-boundary trigger described above; anchors (default on) appends the deterministic fact list to the compaction instructions; preflight (default on) compacts before a prompt that would overflow the next turn.
minGrowthTokens (0 = off) gates the percentage trigger: even at the threshold, hold off until the context has grown by this many tokens since the last compaction. It stops the thrash where a compaction frees little, leaves usage near the threshold, and the next idle moment compacts again. The absolute ceiling ignores it — a hard ceiling is a safety and is never held back. (Idea from billion-context-pi's growth-gated triggering; off by default because a flat cadence can be better on repetitive workloads.)
degenerationGuard (default on) and degenerationMinRun (minimum run length that counts as degeneration; floored at 8) tune the guard described above.
PIFY_COMPACT_THRESHOLD, PIFY_COMPACT_MAX_TOKENS, and PIFY_COMPACT_MIN_GROWTH override the numeric knobs for one run. Bad values fall back to the defaults with a warning.
/autocompact— status: active/dormant, threshold, and current context %./autocompact now— compact immediately (when active)./autocompact on/off— toggle for this session.
To use this, turn pi's built-in compaction off — otherwise this package stays dormant to avoid double-compaction. There are no runtime dependencies and no model calls of its own; the compaction itself is pi's, on your session model. Works on Linux, macOS, and Windows.
MIT © Pify maintainers