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

# Runtime v1 agents

> How agents on runtime v1 differ from runtime v2, how to tell which one you have, and what to change when you move.

Apollo agents run on one of two runtime generations. **Runtime v2** is the
current one — every other page in these docs describes it. Agents created
before the runtime v2 rollout run on **runtime v1**, and a handful of things
work differently for them. This page collects all of those differences so the
main pages don't have to.

## Which runtime is my agent on?

As a rule of thumb, agents created before **August 1 2026** run on runtime v1,
and agents created on or after that date run on runtime v2. When you'd rather
not rely on a date, two things tell you for sure:

| Tell                                                                      | Runtime v1                                    | Runtime v2                                    |
| ------------------------------------------------------------------------- | --------------------------------------------- | --------------------------------------------- |
| Thread ids the agent produces                                             | 24-character hex — `68e78d0dc5a4b19a030d03d6` | UUID — `3f9c2a1e-7b0d-4c52-9e1a-6d2f8b4c0a17` |
| `runtime_version` on the agent's live [version](/api/management/versions) | A `1.x` value, or none                        | A runtime build such as `0.8.0`               |

The thread id is the quickest check — send one message and look at the
`thread_id` that comes back.

## What's different

Sending is identical on both runtimes: `sendMessage`, `streamMessage`, `rerun`,
and the channel openers route automatically based on the agent behind your
key, and you never pick a runtime when sending. The differences surface in a
few places only:

| Capability                                 | Runtime v1                                                                                        | Runtime v2                                                                         |
| ------------------------------------------ | ------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- |
| Send / stream / rerun / channels           | ✅ Same calls                                                                                      | ✅ Same calls                                                                       |
| Reading threads back                       | No selector needed                                                                                | Pass `runtime_version` (e.g. `'0.8.0'`) — see [below](#reading-runtime-v1-threads) |
| Live streaming                             | [`streamMessage`](/sdk/messaging#stream-a-message) (SSE) or a [WebSocket session](/sdk/websocket) | `streamMessage` (SSE)                                                              |
| `suggestions` stream frame                 | Not emitted — `followup_suggestions` ride on the message                                          | Emitted after the terminal `message`                                               |
| Traces (`threadTrace`, `interactionTrace`) | ✅                                                                                                 | Not yet available                                                                  |
| `runtime_version` build pin on sends       | Ignored                                                                                           | Honored (advanced; normally omit)                                                  |
| Thread id format                           | 24-character hex                                                                                  | UUID                                                                               |

## Reading runtime v1 threads

A thread lives on the runtime that created it, and thread reads name that
runtime with `runtime_version`. Runtime v1 is the **default** — so reads of
runtime v1 threads take no selector at all, while reads of runtime v2 threads
must carry one:

```ts theme={"dark"}
// Runtime v1 thread — the default target, nothing to pass
const v1Messages = await client.messaging.listMessages(v1ThreadId);

// Runtime v2 thread — name the runtime the agent runs on
const v2Messages = await client.messaging.listMessages(threadId, {
  runtime_version: '0.8.0',
});
```

The rule is on the major version: a `1.x` value (or none) selects runtime v1;
**any value outside the `1.x` family selects runtime v2**, and it doesn't have
to match the thread's exact build. Asking the wrong runtime returns 404 — the
most common symptom is a UUID thread that "disappears" when read without
`runtime_version`.

The same applies on the management client and the REST API:

| Read                                                                                                         | Runtime v1 thread                                      | Runtime v2 thread                                                                                                                                              |
| ------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `messaging.listMessages(threadId)` · `GET /messaging/v1/threads/{threadId}/messages`                         | As is                                                  | `runtime_version`                                                                                                                                              |
| `threads.getThread` · `getThreadMessages` · `updateThread` · `GET`/`PATCH /management/v1/threads/{threadId}` | As is                                                  | `runtime_version`                                                                                                                                              |
| `threads.listThreads` · `GET /management/v1/threads`                                                         | All filters (`project_id`, `tool`, `rule`, `param`, …) | `runtime_version` plus `agent_id` or `user_id` — only `agent_id`, `user_id`, and `created` (with `agent_id`) apply; runtime v1–only filters return a clear 400 |

## Traces

Runtime v1 agents expose the reasoning [trace](/api/messaging/traces) behind
every interaction — what the agent understood, which rules fired, what it
decided:

```ts theme={"dark"}
// Messaging client (publishable key)
const traces = await client.messaging.threadTrace(threadId);          // one per interaction, paginated
const trace = await client.messaging.interactionTrace(interactionId);

// Management client (organization API key)
await management.threads.getThreadTrace(threadId);
await management.threads.getInteractionTrace(interactionId);
```

`threadTrace` is paginated — pass `page[size]`, `page[after]` / `page[before]`,
and `sort_by` / `sort_order` in an optional second argument. On a runtime v1
[WebSocket session](/sdk/websocket) opened with `include_trace=true`, the final
`message` envelope also embeds the trace as `data.trace_info`.

Trace support for runtime v2 is coming; until then these calls apply to
runtime v1 agents only.

## WebSocket sessions

Runtime v1 agents accept a bidirectional WebSocket session through
`client.connect()` — typed envelopes, automatic reconnection, and `seq`-based
resume. The full protocol is on the [WebSocket](/sdk/websocket) page (SDK) and
[API → WebSocket](/api/messaging/websocket) (wire format).

Runtime v2 agents don't open sessions: `connect()` answers with an `error`
envelope explaining the session is SSE-only. They stream over HTTP with
`streamMessage` instead — one call per turn, the same token-by-token reply,
resumable with `Last-Event-ID`, and nothing to keep alive. The frames map
almost one to one:

| WebSocket session (runtime v1)                                                                            | `streamMessage` (runtime v2)                                                       |
| --------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- |
| `const socket = await client.connect(); socket.sendMessage({ type: 'message', agent_id, user_id, text })` | `const stream = await client.messaging.streamMessage({ body: { user_id, text } })` |
| `socket.on('message', (envelope) => …)` and switch on `envelope.type`                                     | `for await (const event of stream)` and switch on `event.type`                     |
| `thread` · `event` · `message` · `error` envelopes                                                        | The same four types, plus `suggestions` after the terminal `message`               |
| Token text at `envelope.data.data.text` (event `thread-message-text-content-updated`)                     | Token text at `event.data.text`                                                    |
| `agent_id` required on every frame                                                                        | Not needed — the agent comes from your key                                         |
| Reconnect, then `socket.sendResume({ type: 'resume', resume_after: lastSeq })`                            | Call again with `'Last-Event-ID': String(lastSeq)` in the request                  |
| `socket.close()`                                                                                          | Nothing to close — the stream ends with the turn                                   |

## Moving an integration to runtime v2

When the agent behind your key moves to runtime v2, sends keep working
untouched. Work through this list for everything else:

* [ ] **Thread reads** — add `runtime_version` (the build your agent runs on, e.g. `'0.8.0'`) to `listMessages`, `threads.getThread`, `getThreadMessages`, and `updateThread`; scope `listThreads` with `runtime_version` plus `agent_id` or `user_id`.
* [ ] **Thread ids** — stop validating them as 24-character hex ids; runtime v2 ids are UUIDs.
* [ ] **Streaming** — replace `connect()` + `sendMessage` frames with `streamMessage`, drop `agent_id` from the request, and resume with `Last-Event-ID` instead of a `resume` frame.
* [ ] **Follow-up suggestions** — handle the new `suggestions` frame (`data.followup_suggestions`, with the `thread_id` and `interaction_id` it belongs to) instead of reading them off the message.
* [ ] **Traces** — guard `threadTrace` / `interactionTrace` / `getThreadTrace` / `getInteractionTrace` calls until runtime v2 trace support lands.

<Note>
  Still importing `ApolloClient` from `@aui.io/aui-client` 1.x (the
  `ia-controller` client)? Upgrade to v3 first — the
  [SDK upgrade guide](/sdk/migration) maps every call — then come back to this
  page for the runtime differences.
</Note>
