# Understanding the Monotonic Run ID System in Pi Web's SSE

> Discover the monotonic run ID system in Pi Web's SSE. Learn how it assigns unique IDs to prompt executions, ensuring efficient event handling and preventing race conditions for a smoother user experience.

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

---

**The monotonic run ID system assigns a strictly increasing numeric identifier to each prompt execution, enabling Pi Web to discard stale Server-Sent Events, handle page reloads gracefully, and prevent race conditions when multiple browser tabs are active.**

Pi Web streams language model responses to the browser via **Server-Sent Events (SSE)**, but these streams can arrive out of sequence or persist after a user refreshes the page. To ensure the interface only reflects the current execution state, the **agegr/pi-web** repository implements a monotonic run ID system that tags every SSE payload with a unique, incrementing numeric identifier. This mechanism serializes prompt executions and guarantees that delayed or residual messages from previous runs never corrupt the active conversation.

## Why SSE Streams Require Event Serialization

Server-Sent Events provide real-time updates, yet they introduce synchronization challenges unique to long-lived HTTP connections. When a user reloads the browser, loses network connectivity, or triggers a new prompt before the previous one completes, SSE messages can arrive **out of order** or **after a prompt has already finished**. Without a versioning mechanism, the client might display "thinking" indicators from aborted runs or append completed messages to the wrong conversation thread.

## How the Monotonic Run ID System Works

At the core of this implementation is a **monotonically increasing counter** combined with a React ref that tracks the current valid run identifier.

### Generating Incrementing Run IDs

When a user submits a message, the system increments a global counter and stores the value in `promptRunIdRef.current`. This happens in [`hooks/useAgentSession.ts`](https://github.com/agegr/pi-web/blob/main/hooks/useAgentSession.ts) before the network request is dispatched:

```typescript
// Initiating a new prompt execution
const runId = ++globalPromptRunCounter;
promptRunIdRef.current = runId;
await startPrompt({ message, runId });

```

The `runId` is passed to the server and echoed back in every SSE event belonging to that specific prompt execution.

### Guarding Event Handlers Against Stale Data

Every SSE handler validates the `runId` attached to the event against `promptRunIdRef.current` before processing. If the IDs differ, the event is discarded because it belongs to an older or superseded execution:

```typescript
function handleSseEvent(event: AgentEvent) {
  const { runId } = event;
  // Discard events from previous runs
  if (runId !== undefined && promptRunIdRef.current !== runId) return;

  switch (event.type) {
    case "agent_end":
      // Process completion only if current
      break;
    // …other cases…
  }
}

```

This guard appears throughout the lifecycle management in [`hooks/useAgentSession.ts`](https://github.com/agegr/pi-web/blob/main/hooks/useAgentSession.ts):

* **`finishPromptWithoutStream`** – Early-exits when an outdated run ID is received during non-streaming finalization.
* **`waitForPromptSettlement`** – Aborts waiting for settlement if the run IDs no longer match, preventing blocking operations on obsolete prompts.
* **Main SSE handler** – Ignores `agent_end` events and other streaming updates whose `runId` differs from the current ref.

```typescript
const finishPromptWithoutStream = useCallback(
  async (sid: string | null = sessionIdRef.current, runId?: number) => {
    // Abort if the run ID no longer matches the current one
    if (runId !== undefined && promptRunIdRef.current !== runId) return;
    // …finalization logic…
  },
  []
);

```

## Key Source Files and Architecture

The monotonic run ID system spans several modules in the **agegr/pi-web** codebase:

| File | Purpose |
|------|---------|
| [`hooks/useAgentSession.ts`](https://github.com/agegr/pi-web/blob/main/hooks/useAgentSession.ts) | Core hook managing SSE connections, prompt lifecycle, and run-ID validation guards. |
| [`lib/rpc-manager.ts`](https://github.com/agegr/pi-web/blob/main/lib/rpc-manager.ts) | Creates and registers `AgentSession` instances; assigns run IDs when prompts are initiated. |
| [`components/ChatWindow.tsx`](https://github.com/agegr/pi-web/blob/main/components/ChatWindow.tsx) | UI component displaying streaming messages and reacting to validated SSE events. |
| [`components/ChatInput.tsx`](https://github.com/agegr/pi-web/blob/main/components/ChatInput.tsx) | Input component that triggers new prompt executions and run ID generation. |

## Benefits for Real-Time Streaming

The **monotonic** nature of the counter—where each new run receives a greater integer—provides specific guarantees:

1. **Stale events are ignored** – Any delayed SSE from a previous run cannot resurrect a completed chat bubble or reinstate a dismissed loading state.
2. **Concurrent tabs stay synchronized** – When a second tab initiates a new run, its higher run ID supersedes the older one, preventing both tabs from displaying duplicate "thinking" indicators for different prompts.
3. **Reconnection after refresh works reliably** – On page load, the client initializes `promptRunIdRef` from session state and only accepts SSE carrying that specific run ID, discarding stray messages the server may still emit from prior sessions.

## Summary

- The **monotonic run ID system** assigns incrementing numeric identifiers to each prompt execution in Pi Web's SSE stream.
- Every SSE event carries a `runId` that must match `promptRunIdRef.current` in [`hooks/useAgentSession.ts`](https://github.com/agegr/pi-web/blob/main/hooks/useAgentSession.ts) before processing.
- Guards in `finishPromptWithoutStream` and `waitForPromptSettlement` prevent outdated events from completing or settling prompts.
- This mechanism ensures UI consistency across page reloads, network interruptions, and multiple browser tabs by strictly filtering events that do not belong to the current run.

## Frequently Asked Questions

### How does Pi Web prevent stale SSE events from displaying after a page refresh?

When the page reloads, the client initializes `promptRunIdRef.current` from the session state with the latest run ID. Any SSE events arriving from the server that carry a different `runId`—whether from the previous session or delayed network packets—are discarded by the validation check in `handleSseEvent`, ensuring only current execution state updates the UI.

### What is the purpose of the promptRunIdRef check in useAgentSession.ts?

The `promptRunIdRef` check acts as a concurrency guard that compares the `runId` embedded in each SSE event against the React ref's current value. If the values differ, the handler returns early, preventing functions like `finishPromptWithoutStream` or `waitForPromptSettlement` from processing data belonging to an obsolete or superseded prompt execution.

### How does the monotonic run ID system handle concurrent prompt executions across browser tabs?

Because the run ID is generated from a **monotonically increasing global counter**, each new prompt receives a strictly higher number than previous executions. When multiple tabs are active, the tab with the most recent interaction holds the highest valid run ID in its `promptRunIdRef`, causing older tabs to silently ignore their own stale events while the newest tab's state remains authoritative.

### Why use a monotonically increasing counter instead of random UUIDs for run identification?

While UUIDs provide uniqueness, the **monotonic** property guarantees a temporal ordering that simplifies logic for determining which execution is "newer." This ordering allows the system to perform simple numeric comparisons (`!==`) rather than tracking complex histories, making the `finishPromptWithoutStream` and `waitForPromptSettlement` guards both lightweight and deterministic.