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

# generateStream()

> Stream tokens as they are produced

```ts theme={null}
for await (const event of RunAnywhere.llm.generateStream('Write a haiku')) {
  if (event.type === 'textDelta') process.stdout.write(event.text)
}
```

## Signature

```ts theme={null}
generateStream(input: string | ChatMessage[], options?: LlmOptions): AsyncIterableIterator<GenerationEvent>
```

Not a promise. You get the iterator back synchronously and consume it with `for await`.

## The events

In order:

| Event                                | Meaning                                   |
| ------------------------------------ | ----------------------------------------- |
| `started`                            | Generation began                          |
| `textDelta`                          | A chunk of output text                    |
| `reasoningDelta`                     | A chunk of reasoning, for thinking models |
| `toolCallAdded`                      | The model asked to call a tool            |
| `toolArgumentsDone`                  | Tool arguments finished streaming         |
| `usage`                              | Token counts                              |
| `completed` / `failed` / `cancelled` | Exactly one of these ends the stream      |

<Note>
  Electron is the only SDK with a `cancelled` terminal event. Elsewhere a cancelled generation
  simply stops. The SDK never fabricates a successful `completed`.
</Note>

## Where errors surface

Preflight failures throw from the call: no model available, bad options. A failure **during**
generation arrives as a `failed` event, so a window can render a retry without a `try`/`catch`
around the loop.

```ts theme={null}
for await (const event of RunAnywhere.llm.generateStream(prompt)) {
  if (event.type === 'failed') {
    showRetry(event.error)
    break
  }
  if (event.type === 'textDelta') output += event.text
}
```

## Streaming into the renderer

Generation usually runs in the utility host while the text belongs on screen. Forward the
deltas rather than the whole result:

```ts theme={null}
for await (const event of RunAnywhere.llm.generateStream(prompt)) {
  if (event.type === 'textDelta') {
    win.webContents.send('token', event.text)
  }
}
```

Sending per token across IPC is fine for text this small, but batching on a timer keeps a busy
window smoother.

## Cancelling

Break out of the loop. That produces a `cancelled` terminal event rather than an error.

```ts theme={null}
for await (const event of RunAnywhere.llm.generateStream(prompt)) {
  if (aborted) break
  if (event.type === 'textDelta') output += event.text
}
```
