Subscribe to a View and return the visible node list with pagination, branch navigation, and write operations. The hook re-renders the component on every view update.
This hook must be used within a TransportProvider or a ChatTransportProvider.
1
2
3
4
5
6
7
8
9
10
11
12
import { useView } from '@ably/ai-transport/react';
function Chat() {
const { messages, send, loadOlder, hasOlder } = useView({ limit: 30 });
return (
<div>
{hasOlder && <button onClick={() => loadOlder()}>Load older</button>}
{messages.map((m) => <Message key={m.id} message={m} />)}
</div>
);
}Parameters
transportoptionalClientTransport<TEvent, TMessage> or NullviewoptionalView<TEvent, TMessage> or NullView to subscribe to directly. Takes priority over transport.limitoptionalNumberskipoptionalBooleantrue, skip all subscriptions and return an empty handle.Returns
ViewHandle<TEvent, TMessage>
messagesTMessage[]nodesMessageNode<TMessage>[]hasOlderBooleanloadOlder.loadingBooleanloadErrorAbly.ErrorInfo or UndefinedloadOlder failed; cleared on the next successful load.loadOlderFunctionselectFunctiongetSelectedIndexFunctiongetSiblingsFunctionhasSiblingsFunctiongetNodeFunctionsendFunctionregenerateFunctioneditFunctionupdateFunctionLoad older messages
loadOlder: () => Promise<void>Load older messages into the view. No-op if already loading. On failure, loadError is set; on success, loadError is cleared.
Select a sibling
select: (msgId: string, index: number) => voidSelect a sibling at a fork point by index. Updates this view's branch selection and triggers a re-render with the new branch visible.
Get the selected sibling index
getSelectedIndex: (msgId: string) => numberThe index of the currently selected sibling at a fork point.
Get sibling messages
getSiblings: (msgId: string) => TMessage[]Every sibling message at a fork point, ordered chronologically by serial.
Check for siblings
hasSiblings: (msgId: string) => booleanWhether a message has sibling alternatives. Use this to decide whether to render branch-navigation arrows.
Get a node by ID
getNode: (msgId: string) => MessageNode<TMessage> | undefinedThe node for a given message ID, or undefined if the tree has no such node.
Send messages
send: (messages: TMessage | TMessage[], options?: SendOptions) => Promise<ActiveTurn<TEvent>>Send one or more user messages and start a new turn. The parent is auto-computed from this view's selected branch unless overridden in options.
Regenerate a response
regenerate: (messageId: string, options?: SendOptions) => Promise<ActiveTurn<TEvent>>Regenerate an assistant message. Creates a new turn that forks the target message with no new user messages.
Edit a user message
edit: (messageId: string, newMessages: TMessage | TMessage[], options?: SendOptions) => Promise<ActiveTurn<TEvent>>Edit a user message and start a new turn from that point. The original message and its descendants remain in the tree as a separate branch.
Update an existing message
update: (msgId: string, events: TEvent[], options?: SendOptions) => Promise<ActiveTurn<TEvent>>Update an existing message in place and start a continuation turn. Commonly used for delivering client-executed tool results.
See View for the full method semantics and the ActiveTurn shape returned by the write operations. Each returned promise rejects with an ErrorInfo on failure.
Example
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import { useView } from '@ably/ai-transport/react';
import { useState } from 'react';
function Chat() {
const { messages, hasOlder, loadOlder, send, regenerate } = useView({ limit: 30 });
const [input, setInput] = useState('');
const onSubmit = async (e) => {
e.preventDefault();
if (!input.trim()) return;
const text = input;
setInput('');
await send({ id: crypto.randomUUID(), role: 'user', parts: [{ type: 'text', text }] });
};
return (
<div>
{hasOlder && <button onClick={() => loadOlder()}>Load older</button>}
{messages.map((m) => (
<div key={m.id}>
<strong>{m.role}:</strong> <Parts parts={m.parts} />
{m.role === 'assistant' && <button onClick={() => regenerate(m.id)}>Regenerate</button>}
</div>
))}
<form onSubmit={onSubmit}>
<input value={input} onChange={(e) => setInput(e.target.value)} />
<button type="submit">Send</button>
</form>
</div>
);
}