---
description: How the @flue/sdk event and conversation types map to their reference pages, plus the SDK-owned event stream and redelivery semantics.
title: Events | Flue
image: https://flueframework.com/docs/og4.jpg
---

# Events

Last updated Jul 17, 2026[View as Markdown](https://nightly.flueframework.com/docs/sdk/events/index.md)

`@flue/sdk` delivers conversation data in three vocabularies, at three levels of abstraction:

* **Materialized conversation state** — [FlueConversationState](https://nightly.flueframework.com/docs/sdk/flue-client/#flueconversationstate) and [FlueConversationSnapshot](https://nightly.flueframework.com/docs/sdk/flue-client/#flueconversationsnapshot): complete, renderable conversations made of messages, parts, and settlements. This is what [observe()](https://nightly.flueframework.com/docs/sdk/flue-client/#observe) maintains and [history()](https://nightly.flueframework.com/docs/sdk/flue-client/#history) returns, and it is the level application code should consume.
* **Conversation stream chunks** — [ConversationStreamChunk](https://nightly.flueframework.com/docs/reference/streaming-protocol/#conversationstreamchunk): the incremental update protocol that `observe()` reduces into state and that [wait()](https://nightly.flueframework.com/docs/sdk/flue-client/#wait)’s `onEvent` callback exposes raw.
* **Activity records** — [FlueEvent](https://nightly.flueframework.com/docs/reference/events/): the runtime’s low-level activity event union (model turns, tool calls, compaction, logs). No `FlueClient` method delivers these; the types are exported for first-party presenters such as the `flue run` CLI renderer.

Each vocabulary is documented on the page that owns it, linked above and mapped export-by-export [below](#exported-types). This page adds only what the SDK itself owns: the [FlueEventStream](#flueeventstream) iteration surface and the [offset and redelivery semantics](#offsets-and-redelivery) an SDK consumer sees.

A minimal consumer reads messages and parts from an observation:

```ts
import { createFlueClient } from '@flue/sdk';

const client = createFlueClient({ url: 'https://app.example.com/api/support/thread-42' });
const observation = client.observe();

observation.subscribe(() => {
  const { conversation } = observation.getSnapshot();
  for (const message of conversation?.messages ?? []) {
    if (message.display !== 'visible') continue;
    for (const part of message.parts) {
      if (part.type === 'text') renderText(message.id, part.text, part.state);
    }
  }
});
```

## Exported types

* `FlueConversationSnapshot`, `FlueConversationState`, `FlueConversationMessage`, `FlueConversationPart`, `FlueConversationSettlement` — the materialized conversation, documented field-by-field on [FlueClient](https://nightly.flueframework.com/docs/sdk/flue-client/#flueconversationsnapshot) with `history()` and `observe()`.
* `ConversationStreamChunk` — the `updates`\-view chunk union, documented on the [Streaming Protocol reference](https://nightly.flueframework.com/docs/reference/streaming-protocol/#conversationstreamchunk). Delivered raw by `wait()`’s `onEvent`; not stable application API — application code should consume materialized state via `observe()` instead.
* `FlueEvent`, `AttachedAgentEvent`, `AgentSubmissionSettledEvent`, and the model-turn payload types (`LlmMessage` and its content blocks, `LlmTurnPurpose`, `ModelRequest`, `ModelRequestInfo`, `ModelRequestInput`, `ModelResponse`, `PromptUsage`) — the runtime event vocabulary, documented on the [Events reference](https://nightly.flueframework.com/docs/reference/events/). The SDK exports mirror the runtime union exactly, pinned by wire-conformance type tests, so presenters can consume runtime activity without depending on `@flue/runtime`.
* `IMAGE_DATA_OMITTED` — the sentinel replacing raw image bytes in event payloads, exported from both packages and documented on the [Events reference](https://nightly.flueframework.com/docs/reference/events/#image%5Fdata%5Fomitted).
* `FlueSerializedError`, `UnsupportedFlueEventVersionError` — documented with the rest of the error surface in [SDK errors](https://nightly.flueframework.com/docs/sdk/errors/).

## FlueEventStream

```ts
interface FlueEventStream<T = FlueEvent> extends AsyncIterable<T> {
  cancel(reason?: unknown): void;
  readonly offset: string;
}
```

An async iterable of events backed by a Durable Streams connection, with automatic reconnection, offset-based replay, and live tailing. The SDK constructs these internally (`wait()` consumes a `FlueEventStream<ConversationStreamChunk>`); the type is exported so first-party presenters can type streams of their own. `for await...of` is the consumption interface; breaking out of the loop cleans up the underlying connection.

* `cancel(reason?)` — cancels the stream and aborts the underlying connection. Iteration then ends (`done: true`) rather than throwing.
* `offset` — the resume checkpoint. It advances per delivered batch: it moves to a batch’s next-offset only once every event in that batch has been yielded, so resuming from a checkpointed value never skips undelivered events — at worst it re-delivers the batch that was in flight when the checkpoint was taken (at-least-once).

Iterating a stream of `FlueEvent` values rejects any event whose `v` is not `3` with [UnsupportedFlueEventVersionError](https://nightly.flueframework.com/docs/sdk/errors/#unsupportedflueeventversionerror); the SDK does not normalize historical event formats.

### FlueStreamOptions

```ts
interface FlueStreamOptions {
  offset?: string;
  tail?: number;
  live?: LiveMode;
  signal?: AbortSignal;
  backoffOptions?: BackoffOptions;
}
```

Options for one event-stream read. `LiveMode` and `BackoffOptions` are re-exported from `@durable-streams/client`.

* `offset` — starting offset. Defaults to `'-1'` (full history).
* `tail` — limits an `offset: '-1'` read to at most the most recent number of events.
* `live` — live tailing mode: `boolean | 'long-poll' | 'sse'`. Defaults to `true` (long-poll). `false` reads to the current end and completes.
* `signal` — aborts the stream; iteration ends without throwing.
* `backoffOptions` — retry behavior for connection attempts (`initialDelay`, `maxDelay`, `multiplier`, and callbacks, per `@durable-streams/client`).

## Offsets and redelivery

Every conversation read is anchored to a durable-stream offset — an opaque string checkpoint. Offsets surface on [FlueConversationSnapshot](https://nightly.flueframework.com/docs/sdk/flue-client/#flueconversationsnapshot), [AgentSendResult](https://nightly.flueframework.com/docs/sdk/flue-client/#agentsendresult), [AgentConversationObservationSnapshot](https://nightly.flueframework.com/docs/sdk/flue-client/#agentconversationobservationsnapshot), and [FlueEventStream](#flueeventstream). Treat them as opaque: compare for equality if you must, never parse or arithmetic on them. Chunk `position` values and `FlueEvent.eventIndex` values are not offsets — they identify and order items but cannot be used as resume points. The wire-level offset format and coordination headers are specified in the [Streaming Protocol reference](https://nightly.flueframework.com/docs/reference/streaming-protocol/#offsets).

Delivery is **at-least-once**: when a connection drops mid-batch, the transport reconnects from the pre-batch offset and replays the batch in flight. The SDK’s consumers each absorb this:

* `observe()` dedupes by chunk `position` and rehydrates a fresh snapshot on reconnect rather than resuming incrementally; see [observe()](https://nightly.flueframework.com/docs/sdk/flue-client/#observe).
* `wait()` watches only for the terminal `submission-settled` chunk of its submission, which is idempotent under redelivery. Its `onEvent` callback, however, receives the raw stream: it can observe the same chunk more than once after a reconnect, and it receives every chunk of the conversation from the admission offset, not only chunks belonging to the awaited submission. Dedupe by `position` if the distinction matters; prefer `observe()` for maintained UI state.

Both live modes (`'long-poll'` and `'sse'`) carry the same chunks with the same guarantees; SSE trades connection lifetime for lower token-by-token latency.

## Docs Navigation

Current page: [Events](https://nightly.flueframework.com/docs/sdk/events/)

### Sections

* [Guide](https://nightly.flueframework.com/docs/guide/getting-started/)
* [Reference](https://nightly.flueframework.com/docs/reference/agent-api/)
* [CLI](https://nightly.flueframework.com/docs/cli/overview/)
* [SDK](https://nightly.flueframework.com/docs/sdk/overview/)
* [Ecosystem](https://nightly.flueframework.com/docs/ecosystem/)

### SDK

* [Overview](https://nightly.flueframework.com/docs/sdk/overview/)
* [createFlueClient(...)](https://nightly.flueframework.com/docs/sdk/create-flue-client/)
* [FlueClient](https://nightly.flueframework.com/docs/sdk/flue-client/)
* [Events](https://nightly.flueframework.com/docs/sdk/events/)
* [Errors](https://nightly.flueframework.com/docs/sdk/errors/)