How Session Compaction Works in Pi Web and What Events It Emits
Pi Web compresses large chat histories into summary entries via manual or automatic compaction, emitting compaction_start/compaction_end events (or auto_compaction_start/auto_compaction_end) to keep the UI synchronized.
Session compaction in Pi Web prevents chat logs from growing unwieldy by replacing older messages with a single condensed entry. This process is implemented in the agegr/pi-web repository and integrates tightly with the React frontend through a well-defined event system.
What Triggers Session Compaction
Compaction can start through two mechanisms defined in lib/rpc-manager.ts:
-
Manual trigger — The UI sends a
compactcommand viaPOST /api/agent/[id]with payload{type: "compact", customInstructions?}. TheAgentSessionWrapper.send()method forwards this toinner.compact(...). -
Automatic trigger — Pi's underlying SDK applies its own heuristics to initiate compaction when sessions grow large. The same event structure applies, prefixed with
auto_.
The Compaction Event Lifecycle
The SDK emits lifecycle events that Pi Web's wrapper captures and re-emits to clients.
compaction_start and auto_compaction_start
Before summarization begins, the SDK emits compaction_start (manual) or auto_compaction_start (automatic). The wrapper receives this through its inner.subscribe callback and propagates it to connected UIs.
case "compaction_start":
case "auto_compaction_start":
setIsCompacting(true);
break;
Compaction Processing
During compaction, the SDK reads historical entries, generates a summary string, and writes a new JSON-L entry with type "compaction". This entry contains:
- Summary body — Human-readable condensed history
- readFiles — Files accessed during the conversation
- modifiedFiles — Files changed during the conversation
The helper function parseCompactionSummary in lib/compaction-summary.ts extracts these components:
import { parseCompactionSummary } from "@/lib/compaction-summary";
const entry = /* a SessionMessageEntry of type "compaction" */;
const summary = parseCompactionSummary(entry.message.content as string);
console.log(summary.body); // condensed conversation text
console.log(summary.readFiles); // ["src/index.ts", "package.json"]
console.log(summary.modifiedFiles); // ["src/index.ts"]
compaction_end and auto_compaction_end
After writing the summary entry, the SDK emits compaction_end or auto_compaction_end. The wrapper forwards this event, clears any "Stop compaction" UI button, and updates its internal isCompacting flag.
React Hook Integration
The hooks/useAgentSession.ts file implements the primary event handler for compaction state:
const handleAgentEvent = useCallback((event: AgentEvent) => {
switch (event.type) {
case "compaction_start":
case "auto_compaction_start":
setIsCompacting(true); // render loading indicator
break;
case "compaction_end":
case "auto_compaction_end":
setIsCompacting(false); // hide spinner
break;
// ...additional event handling
}
}, []);
The hook also performs state reconciliation to recover from missed end events, ensuring the UI never permanently shows a stuck compaction state.
Triggering Manual Compaction
Client code can request compaction with optional custom instructions:
await sendAgentCommand(sessionId, {
type: "compact",
customInstructions: "Summarize the debugging session focusing on error patterns."
});
Key Source Files
| File | Purpose |
|---|---|
lib/compaction-summary.ts |
Parses compaction entries into structured data |
lib/rpc-manager.ts |
Defines the compact command and event forwarding |
hooks/useAgentSession.ts |
Listens for events, manages isCompacting state |
lib/types.ts |
Declares the "compaction" session entry type |
Summary
- Session compaction replaces old messages with a single summary entry to control file size.
- Four event types exist:
compaction_start,compaction_end,auto_compaction_start,auto_compaction_end. - The
parseCompactionSummaryfunction inlib/compaction-summary.tsextracts file lists and summary text. - React state management lives in
hooks/useAgentSession.ts, which togglesisCompactingbased on event pairs.
Frequently Asked Questions
What is the difference between manual and automatic compaction?
Manual compaction starts when the user explicitly sends a compact command with optional instructions. Automatic compaction triggers when Pi's SDK detects the session has grown large enough to warrant summarization. Both emit the same event types, but automatic compaction prefixes events with auto_.
What happens if a compaction_end event is lost?
The hooks/useAgentSession.ts hook implements defensive state reconciliation. It unconditionally updates the compaction state when certain events arrive, ensuring isCompacting resets to false even if the end event was dropped or the connection interrupted.
What information does a compaction entry preserve?
Each compaction entry preserves a human-readable summary and metadata about file access patterns. The parseCompactionSummary function extracts body (summary text), readFiles (files read during the session), and modifiedFiles (files written or changed). Original message content is discarded in favor of the condensed representation.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →