---
title: 'Events'
description: 'The event stream: endpoints, cursors, frames, event types and run outcomes'
---
[View as Markdown](https://camelai.com/docs/camelrun/events.md) · [Docs index for coding agents](https://run.camelai.com/llms.txt)

An agent's event stream says what it is doing as it does it: text as the model
writes it, tool calls and their progress, questions it waits on, and files it
presents. Use it for display. **A run's result is the source of truth; events
are for display.** A stream can drop events (a restart, a slow reader, a frame
too large), and the SDKs settle every run from its outcome, never from its
events.

## Read the stream

| Endpoint                     | Token                                                    | Mode                                                                           |
| ---------------------------- | -------------------------------------------------------- | ------------------------------------------------------------------------------ |
| `GET /v1/agents/{id}/events` | An API key, or a [browser token](/docs/camelrun/browser) | Read-only watcher                                                              |
| `GET /clients/{id}/events`   | The agent's own token (the SDKs)                         | The application's connection, which also carries tool calls to the application |

| Option                    |                                                                                                                                                        |
| ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `Last-Event-ID: <cursor>` | Resume after this event id                                                                                                                             |
| `?snapshot=1`             | Where the stream can't replay what you missed, send a `snapshot` of the running turn first instead of a 409. Watchers get one by default               |
| `?poll=1&wait=N`          | Answer once, as JSON (`{cursor, events: [{id, data}]}`), instead of streaming. `wait` is at most 25 seconds. For clients that can't hold a stream open |

The response is `text/event-stream`. Each frame is `data:` JSON, and most have
an `id:` line, the cursor. A `: heartbeat` comment arrives about every 5
seconds, so a stream silent for much longer is dead: reconnect with the last
cursor.

```text
event: ready
data: {"version":5,"agentId":"client_...","connection":"..."}

id: 1727520000000123
data: {"type":"event","requestId":"8c1...","event":{"type":"agent_start"}}
```

camelRun buffers each agent's last 512 events (at most 2 MiB) for replay. A
cursor behind that gets a snapshot, or `409 REPLAY_GAP` without one. Nothing
durable is lost in a gap, only display events; recover settled outcomes from
`GET /v1/agents/{id}/state` and `/history`.

## Frames

| Frame                                                 |                                                                                                                              |
| ----------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| `{"type": "event", "requestId", "event"}`             | One event. `requestId` is the run it belongs to                                                                              |
| `{"type": "response", "id", "outcome"}`               | A request settled. See [Run outcomes](#run-outcomes)                                                                         |
| `{"type": "snapshot", "cursor", "requestId", "turn"}` | The running turn, sent in place of what couldn't be replayed: `messages` it finished and the `partial` message streaming now |

## Event types

New types may be added, so ignore ones you don't know.

### Runs and messages

| Type                       | When                                                                                     |
| -------------------------- | ---------------------------------------------------------------------------------------- |
| `turn_opened`              | A model run begins. `index` is where its first message will sit in history               |
| `agent_start`, `agent_end` | The model loop starts and ends                                                           |
| `turn_start`, `turn_end`   | A model round (one response and its tool calls) starts and ends                          |
| `message_start`            | A message begins: the user's, an assistant response, or a tool result                    |
| `message_update`           | The streaming assistant message grew. Carries only the delta, in `assistantMessageEvent` |
| `message_end`              | A message finished, as history keeps it                                                  |
| `message_retracted`        | A response was taken back (before a retry), and the message at `index` is gone           |

`assistantMessageEvent.type` is `text_delta` for reply text, `thinking_delta`
for reasoning, and `toolcall_delta` for a tool call's arguments as partial JSON,
each with its `start` and `end`. Fold deltas into the message from its
`message_start`; `@camelai/run/watch` does this for you.

### Tools, people and the runtime

| Type                    | When                                                                                                                                |
| ----------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| `tool_execution_start`  | A tool call starts: `toolCallId`, `toolName`, `args`                                                                                |
| `tool_execution_update` | A tool reported progress (`partialResult`), at most every 250 ms per call                                                           |
| `tool_execution_end`    | A tool call finished: `result`, `isError`                                                                                           |
| `file_presented`        | The agent presented a file, with a signed download `url`                                                                            |
| `input_required`        | The turn waits on a person. `input` has `id`, `kind` (`question`, `approval`, `form` or `url`), `message`, `detail` and `expiresAt` |
| `input_resolved`        | An input settled: `answered`, `declined`, `cancelled`, `expired` or `superseded`                                                    |

### Sub-agents

See [Multi-agent](/docs/camelrun/multi-agent). These events reach only streams that ask for them (`?subagents=1`, or `subagents: true` in the SDKs).

| Type                                 | When                                                                                                                   |
| ------------------------------------ | ---------------------------------------------------------------------------------------------------------------------- |
| `subagent_start`                     | A `delegate` call started its sub-agent: `toolCallId`, `agentId`, `requestId`, `name`, `depth`                         |
| `subagent_event`                     | One of the sub-agent's events (`event`), its streamed text left out; a grandchild's arrive nested in its parent's      |
| `subagent_end`                       | The sub-agent's run ended (`status`: `completed`, `input_required`, `failed`; `error?`), or its parent stopped waiting |
| `auto_retry_start`, `auto_retry_end` | A transient provider failure is being retried                                                                          |
| `compaction_start`, `compaction_end` | The conversation is being summarized to fit the model's context                                                        |
| `turn_resumed`                       | The node running this turn was lost, and it continues on another                                                       |

## Run outcomes

A prompt's `outcome.result`, from a `response` frame or
`GET /v1/agents/{id}/requests/{requestId}`:

| Field          |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `reply`        | The final assistant message's text                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| `output`       | A prompt sent with `output`: the answer, which fits its schema. See [Structured output](/docs/camelrun/structured-output)                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| `replyIndex`   | That message's index in the agent's history                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| `messages`     | How many messages the history holds after the run                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| `error`        | The model's error (a provider refusal after retries), or `null`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| `code`         | A stable name for `error`, where there is one: `model_key_missing` (no key for the agent's model), `model_key_invalid` (the provider refused the key), `output_missing` (a structured run ended without its output)                                                                                                                                                                                                                                                                                                                                               |
| `stopped`      | Why the run stopped early: `input_required` or `spend_limit`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| `inputs`       | When `stopped` is `input_required`, the pending inputs                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| `files`        | Files the run wrote (at most 100)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| `presented`    | Files the run presented (at most 20)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| `toolErrors`   | Tool calls that didn't complete. See [Tool errors](/docs/camelrun/errors#tool-errors)                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| `toolCalls`    | Every tool call the run made, in order, the first 100: `{tool, toolCallId?, innerCallId?, ok, code?, agentId?}`; `agentId` is the sub-agent a `delegate` call ran. A call from `js_exec`'s code has js\_exec's `toolCallId` and its own `innerCallId`; `js_exec` itself isn't listed. When `ok` is false, `code` is a `toolErrors` code, `tool_error` (the tool answered with an error), `input_required` (it waits on a person; the run that resumes it lists it again) or `aborted`. Arguments and results are left out: read them from history by `toolCallId` |
| `sourceErrors` | Tool sources (MCP servers, OpenAPI specs) that couldn't be listed                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| `usage`        | What its model responses used; `subagentCostUsd`, what its sub-agents spent                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |

`outcome.error` without a `result` means camelRun couldn't carry the request
out, and `uncertain: true` means a restart cut it short so nobody can tell
whether its work took effect. An ended request record (`state: "completed"`)
also puts `status` (`completed`, `input_required` or `failed`), `error` and
`stopped` on top, so a failed run reads as failed without looking inside
`result`.
`GET /v1/agents/{id}/requests/{requestId}?wait=25` waits for a running request
(up to 25 seconds): it answers as soon as the request settles, or when the wait
ends with it still `running`, so you can ask again.

The SDKs turn this into a typed `Run`: `status` (`completed`, `input_required`
or `failed`), `text`, `inputs`, `error`, `files`, `toolErrors`, `toolCalls` and
`sourceErrors`. A browser token never sees a run's result, `toolCalls`
included: only whether and why it stopped.
