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

# Reconnect

> Resume an agent event stream from a saved offset after a process crash or disconnect

Demonstrates `GetAgentStream`: start a stream, simulate a mid-stream crash by cancelling the **Events** context (subscriber only), then reconnect from the last saved offset to receive remaining events — including events emitted while the subscriber was gone.

Source: [`examples/agent_with_reconnect/`](https://github.com/agenticenv/agent-sdk-go/tree/main/examples/agent_with_reconnect)

## What it demonstrates

* The 5-step caller-side reconnect protocol
* Capturing `runID` from `stream.ID()` before consuming events
* Tracking the `Offset()` on each event and saving it as the resume point
* Calling `GetAgentStream(ctx, runID)` then `Events(ctx, WithOffset(lastOffset))` from a fresh context
* Discarding already-processed events (offset ≤ saved offset) after reconnect
* Handling `ErrRunAlreadyCompleted` when the run finished while disconnected

## Requirements

Requires a durable runtime — [Temporal](/runtimes/temporal) or [Restate](/runtimes/restate). Local runtime has no stream offsets. The same public API (`GetAgentStream` + `WithOffset`, `GetAgentRun`) works on both.

Single process: Temporal embeds a worker; Restate embeds the SDK endpoint.

```bash theme={null}
# Temporal
task infra:temporal:up && task infra:temporal:wait
AGENT_RUNTIME=temporal go run ./agent_with_reconnect "What time is it?"

# Restate
task infra:restate:up && task infra:restate:wait
AGENT_RUNTIME=restate go run ./agent_with_reconnect "What time is it?"
```

Cancelling the **Events** context only closes the subscriber-side event channel. Cancelling the **Stream** context cancels the agent run. Use separate contexts — do not share one cancelable ctx for `Stream` and `Events` when simulating a subscriber crash. The durable run continues server-side, and `GetAgentStream` resumes from the saved offset.

## Key code

```go theme={null}
// Stream ctx owns the agent run — keep it alive across a "subscriber crash".
agentStream, err := a.Stream(context.Background(), prompt, nil)
runID := agentStream.ID() // Step 1: save before consuming events

eventsCtx, cancelEvents := context.WithCancel(context.Background())
defer cancelEvents()
eventCh, err := agentStream.Events(eventsCtx)

var lastOffset int64
for ev := range eventCh {
    // Step 2: track offset on every event.
    if ob, ok := ev.(interface{ Offset() (int64, bool) }); ok {
        if off, has := ob.Offset(); has {
            lastOffset = off
        }
    }

    // ... handle event ...

    // Simulate crash: cancel Events only (not Stream).
    if ev.Type() == agent.AgentEventTypeTextMessageContent {
        cancelEvents() // drains and closes eventCh; durable run keeps running
        break
    }
}

// Step 3: reconnect from the last offset on "restart".
agentStream, err = a.GetAgentStream(ctx, runID)
if errors.Is(err, agent.ErrRunAlreadyCompleted) {
    log.Fatal("run finished while disconnected — start a new run")
}
resumeCh, err := agentStream.Events(ctx, agent.WithOffset(lastOffset))

// Step 4: events at offset ≤ lastOffset may be redelivered;
// discard duplicates if needed, then consume normally.
for ev := range resumeCh {
    // ... handle event, clear saved state on RUN_FINISHED / RUN_ERROR ...
}
```

## Expected output

```
user: What time is it?
[run_id] agent-stream-reconnect-agent-<uuid>
--- stream start (phase A: first text chunk, then simulating crash) ---
[RUN_STARTED] runID=agent-stream-reconnect-agent-<uuid>
[TEXT_START] msgID=<id>
The current time is

=== simulated crash: saved runID=agent-stream-reconnect-agent-<uuid> lastOffset=3 ===

=== process restart: reconnecting from offset 3 ===

--- stream resumed (phase B: events from last saved offset) ---
 ...
[TEXT_END]
[RUN_FINISHED]
--- stream end ---
```

Events emitted while the subscriber was "gone" (after the simulated crash) are delivered in Phase B.

The simulated crash cancels only the Events context (not Stream), not a real `kill -9`. For a real process-kill story, see [Durable Agent (Temporal)](/examples/durable-agent) or [Durable Agent (Restate)](/examples/durable-agent-restate).

## Learn more

<CardGroup cols={2}>
  <Card title="Durable Execution" icon="shield-check" href="/advanced/durable-execution" horizontal>
    Full protocol, API reference, and offset semantics
  </Card>

  <Card title="Durable Agent (Restate)" icon="shield" href="/examples/durable-agent-restate" horizontal>
    Real process kill + state file reconnect (single process)
  </Card>

  <Card title="Streaming" icon="bolt" href="/getting-started/streaming" horizontal>
    RunID, offsets, and the streaming API
  </Card>

  <Card title="Restate Runtime" icon="server" href="/runtimes/restate" horizontal>
    Embedded endpoint and durable event delivery
  </Card>
</CardGroup>
