How Pi Web Handles Session Compaction Events via Server-Sent Events (SSE)

Pi Web streams session compaction events through a single SSE endpoint (GET /api/agent/[id]/events) and processes them in hooks/useAgentSession.ts to maintain real-time UI state synchronization, with automatic reconciliation as a fallback for missed events.

Session compaction is a critical operation in Pi Web that compresses older conversation history to optimize storage and performance. The application uses Server-Sent Events (SSE) to push compaction status updates from the back-end Pi Agent to the browser in real time. This article examines the complete flow—from event definition through SSE delivery to state recovery—based on the agegr/pi-web source code.

SSE Event Types for Session Compaction

Pi Web defines four compaction-related event types that flow through the SSE channel. These are registered in lib/rpc-manager.ts (lines 89–96) as part of the running-state event set:

Event Type Description
auto_compaction_start Automatic compaction initiated by the agent
auto_compaction_end Automatic compaction completed
compaction_start Manual compaction started by user action
compaction_end Manual compaction finished

The same events are also included in the idle-reset set (lines 99–104). This ensures that when any compaction end event arrives, the UI's idle timer is cleared—preventing premature disconnection during long-running compaction operations.

How the Browser Processes Compaction Events

The React hook hooks/useAgentSession.ts contains the primary event handler for all SSE messages. The handleAgentEvent function (around lines 1210–1216) uses a switch statement to route compaction events to the appropriate state updates.

State Update Flow

When a compaction event arrives via SSE, the handler executes this sequence:

  1. compaction_start or auto_compaction_start — Sets isCompacting(true) to activate UI indicators
  2. compaction_end or auto_compaction_end — Sets isCompacting(false) and triggers idle timer reset

The isCompacting boolean drives visible UI elements including the blue compaction status badge and the "Stop compaction" abort button.

// Excerpt from hooks/useAgentSession.ts
const handleAgentEvent = useCallback((event: AgentEvent) => {
  switch (event.type) {
    case "auto_compaction_start":
    case "compaction_start":
      // UI enters compacting mode
      setIsCompacting(true);
      break;
    case "auto_compaction_end":
    case "compaction_end":
      // Compaction finished — clear UI state and reset idle timer
      setIsCompacting(false);
      break;
    // …additional event types…
  }
}, []);

Initiating and Aborting Compaction

Compaction is triggered through the RPC command system defined in lib/rpc-manager.ts. The client sends commands to the AgentSessionWrapper, which forwards them to the underlying Pi Agent.

Starting Compaction

// Start automatic compaction from any component with session access
await sendAgentCommand(sessionId, { type: "set_auto_compaction" });

The set_auto_compaction command handler (around line 630 in rpc-manager.ts) configures the agent to begin compressing conversation history. When the back-end actually starts the operation, it emits auto_compaction_start via SSE.

Aborting Compaction

// Abort in-progress compaction
await sendAgentCommand(sessionId, { type: "abort_compaction" });

The abort_compaction command (line 714) terminates an active compaction run. The Pi Agent performs file-level compaction operations and guarantees that start/end event pairs are always emitted, even for aborted operations.

Recovery from Missed Compaction Events

Network interruptions can cause the browser to miss SSE messages. Pi Web implements periodic reconciliation to ensure the UI never gets stuck in an incorrect compaction state.

The reconcileAgentState function polls the REST endpoint /api/agent/[sid] and synchronizes the local isCompacting flag with the authoritative server state:

// Periodic reconciliation while agent connection is active
const reconcileAgentState = async (sid: string) => {
  const res = await fetch(`/api/agent/${sid}`);
  const { state } = await res.json();
  // Override local state with server truth, defaulting to false if undefined
  setIsCompacting(state?.isCompacting ?? false);
};

This reconciliation runs on an interval and also executes immediately after SSE reconnection, guaranteeing that temporary disconnections do not leave stale UI indicators.

File-Level Architecture

The compaction event system spans multiple source files with distinct responsibilities:

File Role in Compaction Flow
lib/rpc-manager.ts Defines AgentSessionWrapper, registers compaction events in running-state and idle-reset sets, implements command handlers for set_auto_compaction and abort_compaction
hooks/useAgentSession.ts Consumes SSE stream, routes compaction events through handleAgentEvent, maintains isCompacting state, implements reconcileAgentState recovery
lib/types.ts Declares "compaction" entry type for JSONL session files referenced by SSE events
lib/session-reader.ts Preserves compaction entry ordering during session file reads, enables accurate session reconstruction

Summary

  • Four event types (auto_compaction_start, auto_compaction_end, compaction_start, compaction_end) flow through Pi Web's single SSE endpoint
  • handleAgentEvent in hooks/useAgentSession.ts toggles the isCompacting boolean that drives all compaction UI
  • Idle-reset event set ensures compaction end events always clear the disconnect timer
  • reconcileAgentState polls the REST API to recover from missed SSE messages and network gaps
  • Command system in lib/rpc-manager.ts exposes set_auto_compaction and abort_compaction for user-initiated control

Frequently Asked Questions

What happens if the browser misses a compaction_end event?

The idle-reset set includes compaction_end and auto_compaction_end (lines 99–104 in lib/rpc-manager.ts), so standard timer behavior is protected. Additionally, the reconcileAgentState polling mechanism fetches the current session state from /api/agent/[sid] and corrects isCompacting to match the server. This dual-layer recovery prevents UI desync.

How does Pi Web distinguish between manual and automatic compaction?

Separate event type pairs are used: compaction_start/compaction_end for manual operations and auto_compaction_start/auto_compaction_end for agent-initiated background compaction. The handleAgentEvent switch statement processes both identically, but the distinction enables differentiated telemetry and user-facing messaging.

Can compaction be aborted mid-operation?

Yes. The client sends { type: "abort_compaction" } via sendAgentCommand, handled at line 714 in lib/rpc-manager.ts. The Pi Agent terminates the file-level compaction and guarantees an end event is still emitted, allowing the UI to exit compacting state cleanly.

Where is the compaction state persisted if the page is refreshed?

The back-end Pi Agent maintains the authoritative isCompacting flag in session state accessible at /api/agent/[sid]. On page reload, the React hook re-initializes and the first reconcileAgentState call restores the correct compaction status before SSE streaming resumes.

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 →