# How Pi-Web Compaction SSE Events Work: Old `auto_*` vs New `compaction_*` Event Names

> Understand Pi-Web compaction SSE events with our guide. Learn about old auto_* and new compaction_* event names and how they track session compaction.

- Repository: [Alex Yang/pi-web](https://github.com/agegr/pi-web)
- Tags: internals
- Published: 2026-08-18

---

**Pi-Web uses Server-Sent Events (SSE) to track session compaction by accepting both legacy `auto_compaction_start/end` and modern `compaction_start/end` event names in its RPC manager and React hooks.**

The **agegr/pi-web** repository implements a dual-compatibility system for compaction SSE events that allows the UI to display loading states and manage idle timers regardless of which version of the underlying `pi` agent is running. This article breaks down exactly how both event naming schemes are handled, where they're defined in the source code, and how the state flows from backend events to UI components.

## What Are Compaction SSE Events?

Compaction is the process where the `pi` agent rewrites a session's `.jsonl` file to prune old entries and reclaim disk space. Because this operation locks the session file, Pi-Web needs to:

- Display a **"compacting" spinner** to indicate background activity
- **Disable user actions** that would modify the session during the rewrite
- **Reset idle timers** when compaction completes to prevent premature session timeout

The agent emits SSE events when compaction starts and finishes. Over time, the event naming convention changed, requiring Pi-Web to support both schemes.

## The Two Event Naming Schemes

| Pi Agent Version | Start Event | End Event |
|------------------|-------------|-----------|
| **Legacy** | `auto_compaction_start` | `auto_compaction_end` |
| **Modern** | `compaction_start` | `compaction_end` |

Both pairs are accepted simultaneously, ensuring backward and forward compatibility.

## Where Event Types Are Defined

The canonical list of compaction-related event types lives in [`lib/rpc-manager.ts`](https://github.com/agegr/pi-web/blob/main/lib/rpc-manager.ts), where two `Set` declarations control runtime behavior:

```typescript
// lib/rpc-manager.ts
const RUNNING_STATE_EVENT_TYPES = new Set([
  "agent_start",
  "agent_end",
  "agent_settled",
  "auto_compaction_start",
  "auto_compaction_end",
  "compaction_start",
  "compaction_end",
]);

const IDLE_RESET_EVENT_TYPES = new Set([
  "agent_end",
  "agent_settled",
  "auto_compaction_end",
  "compaction_end",
]);

```

**`RUNNING_STATE_EVENT_TYPES`** — triggers `notifyRunningChange()` to refresh the sidebar's active sessions list.

**`IDLE_RESET_EVENT_TYPES`** — invokes `resetIdleTimer()` to prevent session timeout after background operations complete.

## How [`useAgentSession.ts`](https://github.com/agegr/pi-web/blob/main/useAgentSession.ts) Consumes Both Event Names

The `useAgentSession` hook in [`hooks/useAgentSession.ts`](https://github.com/agegr/pi-web/blob/main/hooks/useAgentSession.ts) switches on event types using **fall-through case statements** to handle both naming conventions identically:

```typescript
// hooks/useAgentSession.ts
case "auto_compaction_start":
case "compaction_start":
  setIsCompacting(true);
  break;

case "auto_compaction_end":
case "auto_compaction_end":
  setIsCompacting(false);
  resetIdleTimer();
  break;

```

This pattern ensures:
- `isCompacting` state becomes `true` when either start event arrives
- `isCompacting` clears and the idle timer resets when either end event arrives

## Event Flow from Agent to UI

1. **Agent initiates compaction** → emits `compaction_start` (modern) or `auto_compaction_start` (legacy)
2. **SSE stream delivers event** → [`rpc-manager.ts`](https://github.com/agegr/pi-web/blob/main/rpc-manager.ts) matches against `RUNNING_STATE_EVENT_TYPES`
3. **`useAgentSession` hook updates** → `setIsCompacting(true)` triggers React re-render
4. **UI components respond** → [`ChatWindow.tsx`](https://github.com/agegr/pi-web/blob/main/ChatWindow.tsx) and others display the compaction spinner
5. **Agent completes compaction** → emits corresponding end event
6. **State cleanup occurs** → `isCompacting` clears, idle timer resets via `IDLE_RESET_EVENT_TYPES`

## Manual Compaction Trigger

The "Compact" button bypasses the SSE flow for synchronous feedback. It POSTs to `/api/agent/[id]/compact` and disables automatically while the request is in-flight:

```typescript
// Component example using the compact endpoint
const compactSession = async (sessionId: string) => {
  await fetch(`/api/agent/${sessionId}/compact`, { method: "POST" });
  // Button disabled state handled by request lifecycle, no SSE needed
};

```

## React Hook Implementation Pattern

For custom components needing compaction awareness, subscribe to the SSE stream and mirror the case handling from [`useAgentSession.ts`](https://github.com/agegr/pi-web/blob/main/useAgentSession.ts):

```typescript
useEffect(() => {
  const sse = new EventSource(`/api/agent/${sessionId}/events`);
  
  sse.onmessage = (event) => {
    const data: AgentEvent = JSON.parse(event.data);
    
    switch (data.type) {
      case "compaction_start":
      case "auto_compaction_start":
        setIsCompacting(true);
        break;
      case "compaction_end":
      case "auto_compaction_end":
        setIsCompacting(false);
        resetIdleTimer();
        break;
    }
  };
  
  return () => sse.close();
}, [sessionId]);

```

## Key Source Files Reference

| File | Purpose |
|------|---------|
| [`lib/rpc-manager.ts`](https://github.com/agegr/pi-web/blob/main/lib/rpc-manager.ts) | Defines `RUNNING_STATE_EVENT_TYPES` and `IDLE_RESET_EVENT_TYPES` with both old and new event names |
| [`hooks/useAgentSession.ts`](https://github.com/agegr/pi-web/blob/main/hooks/useAgentSession.ts) | SSE consumer implementing the dual case statements for `isCompacting` state |
| [`components/ChatWindow.tsx`](https://github.com/agegr/pi-web/blob/main/components/ChatWindow.tsx) | UI component receiving events via `handleAgentEvent` to sync local state |
| [`AGENTS.md`](https://github.com/agegr/pi-web/blob/main/AGENTS.md) | Design documentation explaining the rationale for dual event name support |

## Summary

- **Dual compatibility:** Pi-Web accepts both `auto_compaction_*` and `compaction_*` event names for seamless operation across agent versions
- **Centralized definitions:** Event type sets in [`lib/rpc-manager.ts`](https://github.com/agegr/pi-web/blob/main/lib/rpc-manager.ts) control running-state notifications and idle-timer behavior
- **Hook-based state:** [`useAgentSession.ts`](https://github.com/agegr/pi-web/blob/main/useAgentSession.ts) uses fall-through case statements to set `isCompacting` without duplicating logic
- **End-to-end flow:** Events propagate from agent → SSE stream → RPC manager → React hook → UI spinner and disabled actions

## Frequently Asked Questions

### Why does Pi-Web support both old and new compaction event names?

The `pi` agent SDK changed its event naming convention at some point. Rather than forcing users to upgrade agent and web UI in lockstep, Pi-Web includes both `auto_compaction_*` and `compaction_*` in its event type sets. This ensures the UI works correctly regardless of which agent version is connected.

### How does the idle timer interact with compaction events?

Only **end** events reset the idle timer. `IDLE_RESET_EVENT_TYPES` includes `auto_compaction_end` and `compaction_end` but excludes the start events. This prevents the idle timer from being continuously reset while a long-running compaction keeps the session technically "active" but unresponsive to user input.

### Where should I look to modify compaction-related UI behavior?

Start with [`hooks/useAgentSession.ts`](https://github.com/agegr/pi-web/blob/main/hooks/useAgentSession.ts) for the core state machine, then check [`components/ChatWindow.tsx`](https://github.com/agegr/pi-web/blob/main/components/ChatWindow.tsx) for the UI implementation. The `handleAgentEvent` function in [`ChatWindow.tsx`](https://github.com/agegr/pi-web/blob/main/ChatWindow.tsx) receives the same events and maintains its own `isCompacting` state for local UI controls.