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 compact command via POST /api/agent/[id] with payload {type: "compact", customInstructions?}. The AgentSessionWrapper.send() method forwards this to inner.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 parseCompactionSummary function in lib/compaction-summary.ts extracts file lists and summary text.
  • React state management lives in hooks/useAgentSession.ts, which toggles isCompacting based 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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →