# useView `useView` subscribes to a session's default view and returns the visible messages, branch navigation, write operations, and pagination state. It is the primary hook for rendering a conversation UI. By default the hook subscribes to the nearest [`ClientSessionProvider`](https://ably.com/docs/ai-transport/api/react/core/providers.md#client-session-provider)'s default view. Pass `session` to use a different session's default view, or `view` to subscribe to a specific view created with [`useCreateView`](https://ably.com/docs/ai-transport/api/react/core/use-create-view.md) or [`session.createView()`](https://ably.com/docs/ai-transport/api/javascript/core/client-session.md#create-view). #### Javascript ``` import { useView } from '@ably/ai-transport/react'; function Conversation() { const { messages, send } = useView({ limit: 30 }); return ( <> {messages.map(({ codecMessageId, message }) => ( ))} send({ kind: 'user-message', message: { role: 'user', parts: [{ type: 'text', text }] } }) } /> ); } ``` This hook must be used within a [`ClientSessionProvider`](https://ably.com/docs/ai-transport/api/react/core/providers.md#client-session-provider) unless `session` or `view` is supplied explicitly. ## Parameters | Parameter | Required | Description | Type | | --- | --- | --- | --- | | session | optional | A client session whose default view to subscribe to. Defaults to the nearest provider. | `ClientSession` | | view | optional | A specific view to subscribe to directly. Takes priority over `session`. | `ClientView` | | limit | optional | Number of older codecMessages to reveal per page (exactly `limit`, fewer only at the end of history). When provided, auto-loads the first page on mount. | Number | | skip | optional | When `true`, skip all subscriptions and return an empty handle immediately. | Boolean |
## Returns | Property | Description | Type | | --- | --- | --- | | messages | The visible messages along the selected branch, each paired with its `codecMessageId`. Read the domain object from each entry's `message` field. | `CodecMessage[]` | | hasOlder | Whether there are older messages that can be revealed via `loadOlder`. | Boolean | | loading | Whether a page load is currently in progress. | Boolean | | loadError | Set when the most recent `loadOlder` call failed. Cleared automatically on the next successful load. | `Ably.ErrorInfo` or Undefined | | loadOlder | Reveal older messages, resolving to the revealed page (oldest-first). Returns `[]` when nothing was revealed: already loading, no view resolved, history exhausted, or the load failed. | `() => Promise[]>` | | runOf | Look up the `RunInfo` for the run that owns the given `codecMessageId`. |
| | run | Direct lookup by run id. |
| | runs | Snapshot of the visible runs along the selected branch, in chronological order. Returns `[]` when the view isn't resolved. | `() => RunInfo[]` | | branchSelection | Resolve the `BranchHandle` anchored at `codecMessageId`: the sibling state plus a `select(index)` verb to navigate it. Always returns a safe handle. |
| | send | Publish an input on the session. The core session is HTTP-free, so wake the agent by POSTing `run.toInvocation().toJSON()` to your agent endpoint. At most one new message per send; the array form carries only wire-only inputs (tool results, approvals). Wrap a domain message via `codec.createUserMessage` (or build the `{ kind: 'user-message', message }` literal) to send a fresh user message. Takes optional
. | `(events, options?) => Promise>` | | regenerate | Regenerate an assistant message using this view's branch for history. | `(messageId, options?) => Promise>` | | edit | Edit a user message, forking from this view's branch. | `(messageId, inputs, options?) => Promise>` |
| Property | Description | Type | | --- | --- | --- | | runId | The run's unique identifier. | String | | clientId | Identity of the Ably client that started this run. Empty string when the wire didn't carry an owner client id. | String | | status | Run lifecycle status. `'active'` while streaming, `'suspended'` while paused awaiting input, otherwise the `RunEndReason` the run terminated with. | `'active' \| 'suspended' \| RunEndReason` | | error | The terminal error, present exactly when `status` is `'error'`. Carries the agent-stamped error detail so a UI can show why a run failed. | `Ably.ErrorInfo` | | invocationId | The agent-minted `invocationId` observed for this run, adopted from `ai-run-start`. Empty string until run-start arrives, or if the wire didn't carry an invocation-id. | String |
| Property | Description | Type | | --- | --- | --- | | hasSiblings | True when the anchor has more than one sibling. | Boolean | | siblings | The selected sibling and any alternatives in tree-order. Always contains the currently rendered message for known ids. | `TMessage[]` | | index | Index of the selected sibling within `siblings`. `0` when there is no real branching. | Number | | selected | Convenience reference to `siblings[index]`. `undefined` only when `siblings` is empty. | `TMessage` or Undefined | | select | Select a sibling at this branch point. `index` is clamped to `[0, siblings.length - 1]`; a silent no-op when the anchor is not a branch anchor. | `(index: number) => void` |
| Property | Description | Type | | --- | --- | --- | | forkOf | The codec-message-id of the message this send replaces (fork). | String | | parent | The codec-message-id of the predecessor in the conversation thread. Auto-computed when omitted. | String | | runId | Reuse an existing `runId` (for example to resume a suspended run). | String | | role | The wire role set on this send's input events. Defaults to `user`; a client tool-result fork uses `assistant` so the tree reads the fork as a reply run. | String | | supersedes | The `runId` this send supersedes, so the tree hides that run from branch selection. Set only on a client tool-result fork. | String |
## Reveal older messages `loadOlder(): Promise[]>` Reveal older messages into the view, resolving to the revealed page (oldest-first). When `limit` is set on the hook, the first page auto-loads on mount. Call `loadOlder` again to reveal more. The call is gated so concurrent invocations collapse to one in-flight request; it returns `[]` when nothing was revealed (already loading, no view resolved, history exhausted, or the load failed). On failure, `loadError` is set. On the next successful load, `loadError` is cleared automatically. ## Look up a run by message id `runOf(codecMessageId: string): RunInfo | undefined` Look up the [`RunInfo`](#returns) for the run that owns the given `codecMessageId`. Returns `undefined` when the codec-message-id has not been observed. The hook re-renders on run lifecycle events as well as on message updates. A run suspending or ending changes content within a run without changing the visible message structure, so a component reading `runOf(...).status` still sees the change. ## Look up a run by id `run(runId: string): RunInfo | undefined` Direct lookup by run id. Symmetric with [`runOf`](#run-of) for callers that already hold a `runId`. ## Resolve a branch selection `branchSelection(codecMessageId: string): BranchHandle` Resolve the `BranchHandle` anchored at `codecMessageId`: the sibling state plus a `select(index)` verb to navigate it. Always returns a safe handle: for branch anchors with N siblings, `siblings` carries every sibling run's view of the anchor slot; for non-anchor messages, `siblings` is `[thisMessage]` and `hasSiblings` is `false`. ## Select a sibling Switch the visible sibling through the [`BranchHandle`](#branch-selection) the `branchSelection` call returns, rather than a separate hook method: ### Javascript ``` view.branchSelection(codecMessageId).select(1); ``` `index` is clamped to `[0, siblings.length - 1]`. The call is a silent no-op when the message is not a branch anchor, and emits `'update'` on the underlying view when the visible output changes. ## Send inputs `send(events: TInput | TInput[], options?: SendOptions): Promise>` Publish an input on the session. The core session is HTTP-free, so wake the agent by POSTing `run.toInvocation().toJSON()` to your agent endpoint. Each `TInput` carries its own routing metadata (`parent`, `target`, `codecMessageId`). To send a fresh user message, build a `UserMessage` input. Use the codec factory (`codec.createUserMessage(message)`) or build the literal directly: `{ kind: 'user-message', message }`. A send introduces at most one new message: exactly one `UserMessage` for a fresh send (which mints a new run), or none for a continuation. The array form exists only to carry the wire-only inputs that resolve a single assistant turn (`tool-result`, `tool-result-error`, `tool-approval-response`); pair it with `options.runId` to extend a suspended run. Passing more than one new message rejects with `InvalidArgument`. ## Regenerate an assistant message `regenerate(messageId: string, options?: SendOptions): Promise>` Regenerate an assistant message. Creates a new run that targets the message and threads under its parent user message. Both ids are computed automatically from this view's branch. ## Edit a user message `edit(messageId: string, inputs: TInput | TInput[], options?: SendOptions): Promise>` Edit a user message. Creates a new run that forks the target message with the replacement inputs. `forkOf`, `parent`, and history are computed automatically from this view's branch. ## Example A conversation component that loads older messages on mount, renders branch navigation when a sibling is available, and offers a regenerate button on each assistant turn. ### Javascript ``` import { useView } from '@ably/ai-transport/react'; function Conversation() { const { messages, hasOlder, loadOlder, branchSelection, send, regenerate, } = useView({ limit: 30 }); return ( <> {hasOlder && } {messages.map(({ codecMessageId, message }) => { const branch = branchSelection(codecMessageId); return (
{branch.hasSiblings && ( branch.select(i)} /> )} {message.role === 'assistant' && ( )}
); })} send({ kind: 'user-message', message: { role: 'user', parts: [{ type: 'text', text }] } }) } /> ); } ```
## Related Topics - [Providers](https://ably.com/docs/ai-transport/api/react/core/providers.md): API reference for the AI Transport React providers: ClientSessionProvider and the createSessionHooks factory. - [useClientSession](https://ably.com/docs/ai-transport/api/react/core/use-client-session.md): Read a ClientSession from the nearest ClientSessionProvider in the AI Transport React integration. - [useCreateView](https://ably.com/docs/ai-transport/api/react/core/use-create-view.md): Create an independent View over the AI Transport conversation tree from React, with its own branch selections and pagination. - [useMessagesWithSeed](https://ably.com/docs/ai-transport/api/react/core/use-messages-with-seed.md): Reconcile a persisted conversation seed with the live AI Transport session from React and render the composed conversation. - [useTree](https://ably.com/docs/ai-transport/api/react/core/use-tree.md): Stable structural query callbacks for the AI Transport conversation tree from React. - [useAblyMessages](https://ably.com/docs/ai-transport/api/react/core/use-ably-messages.md): Subscribe to raw Ably InboundMessages on the AI Transport channel from React. ## Documentation Index To discover additional Ably documentation: 1. Fetch [llms.txt](https://ably.com/llms.txt) for the canonical list of available pages. 2. Identify relevant URLs from that index. 3. Fetch target pages as needed. Avoid using assumed or outdated documentation paths.