> ## Documentation Index
> Fetch the complete documentation index at: https://developers.telnyx.com/llms.txt
> Use this file to discover all available pages before exploring further.

# EventLog

> A persistent, replayable progress-event stream — emit with monotonic seq, read from a cursor, count-based retention.

`EventLog` is a persistent, replayable progress-event stream over ordered KV storage.
`emit(type, payload)` assigns a strictly increasing `seq` and persists the row, so
consumers can replay events in order after a restart, or resume from a cursor
(`read(afterSeq)`).

Retention is count-based: the log keeps at most `retain` rows (default 1000), and each
emit past that bound prunes the oldest rows — the storage footprint stays bounded
regardless of emit rate, and pruning never reuses a `seq`.

## Accessing the log

Every agent holds a built-in log on one property *(SDK ≥ 0.11.0)*:

<EventsProp />

## Obtaining an EventLog

For a separate stream, an agent constructs its own log over the actor's durable
storage — typically once, as a field:

```ts theme={null}
import { Agent, EventLog } from "@telnyx/edge-runtime";

class ResearchAgent extends Agent<MyEnv> {
  private readonly activity = new EventLog(this.ctx.storage, { retain: 500 });
}
```

The first argument is the actor's `ctx.storage`, so the log shares the actor's
durability and single-writer guarantees; `retain` bounds how many rows are kept
(default 1000). One actor can hold several logs for unrelated streams — each
`EventLog` keys its rows independently.

## new EventLog()

<Constructor />

## Worked example: streaming progress from a long-running task

The pattern has three parts: the task **emits** durable events, the socket server
**replays and pushes** them, and the client **subscribes** from a cursor.

**1. Emit from the task, push to live watchers.** `emit` persists the row and returns
its `seq`; reading strictly after `seq - 1` yields the stored row to hand to
[AgentSocketServer](/docs/agent-sdk/api-reference/agent-socket-server)'s
`broadcastEvent`:

```ts theme={null}
class ResearchAgent extends Agent<MyEnv> {
  private readonly activity = new EventLog(this.ctx.storage, { retain: 500 });
  private readonly desk = new AgentSocketServer(this, {
    getState: () => this.getState(),
    // cursor replay: a client attaching with { events: N } gets everything after N
    getEvents: (afterSeq) => this.activity.read(afterSeq),
  });

  override webSocket(ws: WebSocket, req: Request) {
    return this.desk.attach(ws, req);
  }

  async runReport(): Promise<void> {
    const steps = ["fetch", "analyze", "summarize"];
    for (let i = 0; i < steps.length; i++) {
      await this.doStep(steps[i]);
      const seq = await this.activity.emit("progress", {
        step: steps[i],
        done: i + 1,
        total: steps.length,
      });
      const [event] = await this.activity.read(seq - 1);
      this.desk.broadcastEvent(event); // live push to subscribed watchers
    }
  }
}
```

**2. Subscribe on the client.** [AgentClient](/docs/agent-sdk/api-reference/agent-client)'s
`onEvents` delivers each event in `seq` order; `from` replays missed events after a
disconnect, so a page that reconnects mid-task picks up exactly where it left off:

```ts theme={null}
const agent = new AgentClient(url, { token, subscribe: ["events"], resume: true });

agent.onEvents((e) => renderProgress(e.type, e.payload), { from: lastSeenSeq });
```

Because the log is durable and `seq` never regresses, this survives agent restarts
mid-task: the replay comes from storage, not from anything held in memory.

## emit()

<Emit />

## read()

<ReadMethod />

## count()

<CountMethod />

## StoredEvent

<StoredEventType />

## EventLogOptions

<EventLogOptionsType />
