# 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 (
);
})}
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.