React Hooks
The @baleybots/react package provides React hooks for building chat interfaces and using Baleybots processors in React applications.
Installation
npm install @baleybots/react @baleybots/core
useChat
useChat is the primary hook for building client-side chat interfaces. It runs the processor in the browser (or React Native) and exposes segments as the canonical UI representation.
For server-hosted multi-agent crew chat, use the product UI's /api/chat endpoint and useCrewSessions — not useChat server mode (removed).
Basic usage
import { useChat, ChatTurns, ChatTurn } from '@baleybots/react';
import { openai } from '@baleybots/core';
import { z } from 'zod';
const ResponseSchema = z.object({
response: z.string(),
});
function ChatComponent() {
const { segments, sendStreaming, isStreaming, pendingApprovals, respondToToolApprovals } =
useChat({
model: openai('gpt-5.6-luna'),
systemPrompt: 'Answer concisely and accurately',
responseSchema: ResponseSchema,
});
const handleSend = async (text: string) => {
await sendStreaming(text);
};
return (
<div>
<ChatTurns segments={segments}>
{(turn) => (
<ChatTurn key={turn.id} turn={turn} />
)}
</ChatTurns>
{isStreaming && <div>Typing…</div>}
{pendingApprovals.length > 0 && (
<button
onClick={() =>
respondToToolApprovals(
pendingApprovals.map((p) => ({ approvalId: p.approvalId, approved: true })),
)
}
>
Approve all
</button>
)}
</div>
);
}
Prefer ChatTurns / ChatTurn (or useChatTurns + groupByTurn) over mapping raw segments or the deprecated messages array.
Return values
| Property | Type | Description |
|---|---|---|
segments | StreamSegment[] | Canonical conversation timeline (includes user segments) |
isLoading | boolean | Whether a request is in progress |
isStreaming | boolean | Whether a response is currently streaming |
error | Error | null | Last error, if any |
send | (text: string) => Promise | Send a message (no streaming) |
sendStreaming | (text: string) => Promise | Send a message with streaming |
clearHistory | () => Promise<void> | Clear the conversation |
stopStreaming | () => void | Abort the current stream |
pendingApprovals | PendingApproval[] | Gated tools awaiting approval (derived from segments) |
respondToToolApprovals | (responses: ToolApprovalResponse[]) => void | Approve/reject every pending id in one batch resume |
messages | UIChatMessage[] | Deprecated — derived from segments for legacy UIs only |
Options
| Option | Type | Description |
|---|---|---|
model | string | ModelConfig | LLM model to use |
systemPrompt | string | System prompt for the processor |
tools | Record<string, ToolDefinition> | Tools available to the processor |
responseSchema | ZodSchema | JSON Schema | Structured response schema (maps to Output.object()) |
maxToolIterations | number | Tool loop step cap (default 50) |
storage | HistoryStorage | Custom history storage backend |
proxyUrl | string | Proxy URL for API requests (browser CORS) |
fetch | typeof fetch | Custom fetch (e.g., for React Native) |
shouldAskApproval | (toolName: string) => boolean | Auto-approve/deny without prompting |
onApprovalRequest | (pending: PendingApproval) => void | Fired when a new approval request appears |
ChatTurns and custom rendering
ChatTurns groups segments into conversational turns via groupByTurn. Override per-segment rendering with a function child on ChatTurn:
import { useChat, ChatTurns, ChatTurn, SegmentRenderer } from '@baleybots/react';
function Chat() {
const { segments, sendStreaming } = useChat({ model: 'openai|gpt-5.6-luna' });
return (
<ChatTurns segments={segments}>
{(turn) => (
<ChatTurn
key={turn.id}
turn={turn}
className={turn.role === 'user' ? 'user-bubble' : 'assistant-bubble'}
>
{(segment) =>
segment.type === 'text' ? (
<p key={segment.id}>{segment.content}</p>
) : undefined
}
</ChatTurn>
)}
</ChatTurns>
);
}
For legacy code that still expects OpenAI-shaped rows, derive messages locally — do not treat hook messages as primary:
import { deriveUIMessages } from '@baleybots/core';
const uiMessages = deriveUIMessages(segments);
useBaleybot
useBaleybot wraps a Baleybot processor for direct use in React. It manages the agent lifecycle and provides a simple interface.
The hook accepts outputSchema (Zod or JSON Schema) and converts it to Output.object() when creating the underlying processor.
import { useBaleybot } from '@baleybots/react';
import { z } from 'zod';
function SentimentAnalyzer() {
const { process, result, isProcessing } = useBaleybot({
name: 'sentiment',
analysisGoal: 'Analyze the sentiment of text',
outputSchema: z.object({
sentiment: z.enum(['positive', 'negative', 'neutral']),
confidence: z.number(),
}),
});
return (
<div>
<button onClick={() => process('I love this product!')}>
Analyze
</button>
{result && <p>Sentiment: {result.sentiment} ({result.confidence})</p>}
</div>
);
}
For direct Baleybot.create() usage outside React, prefer the output config with Output.object() — see Structured Outputs.
Removed APIs
The following were removed from @baleybots/react useChat:
useGroupChat— use clientuseChat; for hosted crew chat use/api/chat- Server mode options:
apiUrl,chatId,multiAgent,agents,loadHistory,isResuming - Scalar approvals:
pendingApproval,approveToolCall,rejectToolCall SendStreamingOptions(mentions, etc.)
See useChat migration for before/after patterns.