useTree
useTree exposes stable structural query callbacks backed by a session's Tree. The returned methods are thin useCallback wrappers around session.tree and never trigger re-renders on their own.
Use this hook when you need to inspect tree structure outside the visible branch (for example, to count edit or regenerate siblings on a node before showing navigation arrows). Branch navigation for the currently visible chain lives on useView.
1
2
3
4
5
6
7
8
9
import { useTree } from '@ably/ai-transport/react';
function SiblingSwitcher({ nodeKey }) {
const { getSiblingNodes } = useTree();
const siblings = getSiblingNodes(nodeKey);
if (siblings.length <= 1) return null;
return <Siblings nodes={siblings} />;
}This hook must be used within a ClientSessionProvider unless session is supplied explicitly.
Parameters
sessionoptionalClientSession<TInput, TOutput, TProjection, TMessage>Returns
getRunNodeRunNoderunId, or undefined if not found.getNodeByCodecMessageId(codecMessageId) => ConversationNode | undefinedcodecMessageId, or undefined if not observed. Narrow on kind ('input' or 'run') before reading kind-specific fields.getSiblingNodes(key) => ConversationNode[]Look up a Run by id
getRunNode(runId: string): RunNode<TProjection> | undefinedReturn the full RunNode record for a given runId, or undefined if the Run has not been observed. Use this when you need fields the View's RunInfo does not expose (parent / fork relationships, the raw projection, serials).
Look up a node by codec-message-id
getNodeByCodecMessageId(codecMessageId: string): ConversationNode<TProjection> | undefinedResolve the node that owns the given codecMessageId through the tree's index. The result is a ConversationNode union: an InputNode (user prompt) or a RunNode (agent reply). Narrow on kind ('input' or 'run') before reading kind-specific fields. Returns undefined when the message has not been observed.
Get sibling nodes
getSiblingNodes(key: string): ConversationNode<TProjection>[]Return the sibling group the node keyed by key belongs to. The key is either a RunNode.runId or an InputNode.codecMessageId. The two sibling-group shapes are: input edits, where input nodes share a parent and chain via forkOf (the original user prompt plus every edit of it); and regenerate siblings, where reply runs share an input-node parent (the original reply plus every regenerate of it).
Ordered oldest-first by serial. Returns a single-element array when the node has no siblings, an empty array when the key is unknown. Narrow each node on kind before reading kind-specific fields.
Example
A run-history sidebar that lists every observed Run and lights up sibling navigation where alternatives exist.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import { useTree, useView } from '@ably/ai-transport/react';
function RunHistory() {
const { messages, runOf } = useView();
const { getSiblingNodes } = useTree();
const runs = messages
.map(({ codecMessageId }) => runOf(codecMessageId))
.filter((r): r is RunInfo => Boolean(r));
return (
<ul>
{runs.map((run) => {
const siblings = getSiblingNodes(run.runId);
return (
<li key={run.runId}>
<RunSummary run={run} />
{siblings.length > 1 && <SiblingPicker siblings={siblings} />}
</li>
);
})}
</ul>
);
}