Understanding Generation-Aware Event Cursors in Prime Agent
Generation-aware event cursors are { generation, sequence } pairs that uniquely identify events in a stream, enabling clients to resume without gaps or duplicates.
Prime Agent models assistant messages, tool calls, and state snapshots as an ordered event stream. To support reliable reconnection after network drops or daemon restarts, the system uses generation-aware event cursors—composite identifiers that track both snapshot boundaries and in-snapshot ordering.
What Are Generation-Aware Event Cursors?
A generation-aware event cursor consists of two numeric fields:
| Field | Purpose |
|---|---|
generation |
Increments each time a snapshot of the full session state is taken. All events within the same snapshot share this value. |
sequence |
Zero-based counter that increments for every event within a generation, providing exact positional ordering. |
Together, { generation, sequence } creates a lexicographically sortable key. A cursor with higher generation is always newer; if generation is equal, higher sequence is newer.
This design decouples snapshot recovery (large state boundaries) from incremental streaming (individual events), giving the protocol both durability and granularity.
How Cursors Enable Reliable Resumption
When a client reconnects to a Prime Agent daemon, it passes its last observed cursor. The server then streams only events with strictly greater (generation, sequence) pairs. This guarantees three properties:
- No gaps: Every event after the client's cursor is delivered.
- No duplicates: Events at or before the cursor are skipped.
- Deterministic ordering: Events arrive in exact emission order, even across snapshot boundaries.
The cursor mechanism is defined in the daemon protocol documentation and implemented in [packages/ai/src/utils/event-stream.ts](https://github.com/PrimeIntellect-ai/prime-agent/blob/main/packages/ai/src/utils/event-stream.ts).
Practical Usage Examples
Basic Cursor Tracking
import { Agent } from '@primeintellect/agent';
const agent = new Agent();
// Track the last seen cursor for resumption
let lastCursor: { generation: number; sequence: number } | undefined;
agent.on('assistantMessage', (msg) => {
// Each event carries its generation-aware cursor
lastCursor = msg.cursor;
console.log(`Received message at generation ${msg.cursor.generation}, sequence ${msg.cursor.sequence}`);
});
Resuming After Interruption
// After disconnect, restart from saved cursor
await agent.connection.start({
cursor: lastCursor, // Daemon skips all events <= this cursor
});
Requesting Specific Historical Range
// Manually construct cursor to fetch from a known point
const cursor = { generation: 5, sequence: 12 };
await agent.connection.start({ cursor });
// Receives events starting from generation 5, sequence 13 onward
Implementation Architecture
The Prime Agent codebase implements generation-aware cursors across two key locations:
| File | Role |
|---|---|
packages/coding-agent/docs/daemon.md |
Protocol specification defining cursor semantics |
packages/ai/src/utils/event-stream.ts |
Stream utilities attaching cursors and performing comparisons |
In event-stream.ts, each AssistantMessageEvent receives its cursor at emission time. The stream-merge logic compares incoming cursors against client-supplied values using lexicographic ordering:
// Conceptual comparison from event-stream.ts
function isNewer(candidate: Cursor, reference: Cursor): boolean {
if (candidate.generation > reference.generation) return true;
if (candidate.generation < reference.generation) return false;
return candidate.sequence > reference.sequence;
}
When to Use Generation-Aware Cursors
Consider explicit cursor management when:
- Building long-running agents that must survive process restarts
- Implementing multi-device synchronization where clients join mid-stream
- Creating audit trails requiring precise event positioning
- Developing custom clients outside the official SDK
For typical ephemeral sessions, the SDK handles cursor persistence automatically.
Summary
- Generation-aware event cursors combine
generation(snapshot ID) andsequence(in-snapshot position) to uniquely identify any event. - Cursors enable exactly-once delivery semantics on reconnection by filtering events newer than the supplied cursor.
- The
{ generation, sequence }structure is lexicographically comparable, simplifying server-side filtering logic. - Prime Agent implements this protocol in
daemon.mdandevent-stream.ts, with cursors attached to allAssistantMessageEventobjects.
Frequently Asked Questions
How does the generation number get incremented?
The generation increments each time the daemon captures a snapshot of the full session state. This typically occurs at tool call boundaries or explicit checkpoint requests, persisting the current event log to durable storage.
Can I construct cursors manually for debugging?
Yes. Cursors are plain objects with generation and sequence number fields. You can construct them for targeted debugging, though production code should derive cursors from received events to ensure validity.
What happens if I pass a future cursor?
The daemon validates the cursor against its event log. If the cursor refers to a generation or sequence beyond known events, the connection will error or await new events depending on your client's configuration.
Are cursors stable across server restarts?
Yes. Because generation correlates with persisted snapshots and sequence is deterministic within each snapshot, cursors remain valid even if the daemon process restarts—provided the snapshot store is intact.
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 →