useAg2bChat
Stateful hook for synchronous chat.
function useAg2bChat(): {
send: (message: string) => Promise<AgentResponse | undefined>;
response: AgentResponse | undefined;
events: AgentEvent[];
isPending: boolean;
error: unknown;
abort: () => void;
};Usage
Basic chat
Send a message and render the final response.
function Chat() {
const { send, response, isPending } = useAg2bChat();
const [input, setInput] = useState('');
return (
<>
<form
onSubmit={(e) => {
e.preventDefault();
send(input);
setInput('');
}}
>
<input value={input} onChange={(e) => setInput(e.target.value)} />
<button disabled={isPending}>{isPending ? 'sending…' : 'send'}</button>
</form>
{response && <div>{response.content}</div>}
</>
);
}Agent Events
Use events to render progress while a send is in flight — tool calls, iteration boundaries, finish reasons:
function ChatWithIndicators() {
const { send, events, response } = useAg2bChat();
const toolCalls = events.filter((e) => e.type === 'agent_tool_call_start').length;
return (
<>
<button onClick={() => send('What is blocked?')}>send</button>
{toolCalls > 0 && <div>Called {toolCalls} tool(s) so far…</div>}
{response && <div>{response.content}</div>}
</>
);
}Chat History
useAg2bHistory gives you the live conversation. It updates as the loop pushes messages, so the in-flight send appears as it progresses.
function Chat() {
const messages = useAg2bHistory();
const { send, isPending } = useAg2bChat();
const [input, setInput] = useState('');
return (
<>
{messages.map((m, i) => (
<div key={i}>{m.role}: {m.content ?? '(no content)'}</div>
))}
<form
onSubmit={(e) => {
e.preventDefault();
send(input);
setInput('');
}}
>
<input value={input} onChange={(e) => setInput(e.target.value)} />
<button disabled={isPending}>{isPending ? 'sending…' : 'send'}</button>
</form>
</>
);
}Errors
send() never throws — it resolves to undefined and stores the failure in error which can hold:
Ag2bMaxIterationsError— the loop hitmaxIterations.- Provider errors —
Ag2bProviderRequestError,Ag2bProviderResponseError. - A network failure from
fetch(DNS, connection refused, etc.). - Anything thrown from a registered agent hook.
Two exceptions:
-
Tool handler throws don't land here — the LLM can recover from them, so they're emitted as
agent_tool_call_errorevents instead. -
abort()doesn't land here either — to catch aborts, listen for theagent_chat_abortevent.
function Chat() {
const { send, error, isPending } = useAg2bChat();
return (
<>
{error && <div role="alert">{String(error)}</div>}
<button disabled={isPending} onClick={() => send('hi')}>send</button>
</>
);
}Aborting
Cancel an in-flight send with abort(). The hook also auto-aborts on unmount and when send() is called while a prior send is still running:
function ChatWithCancel() {
const { send, abort, isPending } = useAg2bChat();
return (
<>
<button onClick={() => send('Long task')}>send</button>
{isPending && <button onClick={abort}>cancel</button>}
</>
);
}Returns
send
send: (message: string) => Promise<AgentResponse | undefined>Calls agent.chat() with the message. Aborts any prior in-flight send and clears error. Resolves with AgentResponse, or undefined if the send was aborted, superseded by a newer send(), or threw a non-abort error.
response
response: AgentResponse | undefinedThe last successful AgentResponse. Persists across the start of a new send() — only overwritten when the new send completes.
events
events: AgentEvent[]Array of AgentEvent emitted during the current send. Resets on every send().
isPending
isPending: booleantrue while a send is in flight.
error
error: unknownThe last non-abort error from a send. Cleared automatically on the next send(). See Errors.
abort
abort: () => voidCancel the in-flight send. See Aborting.