UI Integration with @ulifeai/agentb-ui
The @ulifeai/agentb-ui package provides React components and hooks to quickly build a rich, interactive chat interface for your AgentB agents. It handles the complexities of Server-Sent Event (SSE) stream consumption, message state management, and rendering of different event types.
This guide focuses on using the primary components and the useChat hook.
Key Components & Hooks
<AgentBChat />Component:The main, all-in-one chat component.
Renders a complete chat interface including a message list, message input field, and status indicators.
Internally uses the
useChathook to manage state and communication.
useChatHook (import { useChat } from '@ulifeai/agentb-ui';):The core React hook for managing agent interactions.
Responsibilities:
Initiating requests to your AgentB backend's streaming SSE endpoint.
Consuming and parsing the SSE stream of
AgentEvents usingparseSSEStream.Managing the list of
ChatMessageobjects displayed in the UI.Handling message accumulation for streaming text responses.
Tracking loading states, streaming status, and errors.
Providing a
sendMessagefunction to send user input to the backend.
Returns: An object containing
messages,sendMessage,isLoading,isStreaming,error,threadId,setMessages, andcurrentRunId.
Supporting Components (Often used internally by
<AgentBChat />):<MessageList />: Renders the list ofChatMessages.<MessageItem />: Renders a single chat message, styled according to its sender and content type (text, tool thought, tool result, error, etc.).<MessageInput />: The text input field for the user.
Types (
ChatMessage,AgentEvent, etc.):The package re-exports
AgentEventtypes (mirrored from the backend) and defines UI-specific types likeChatMessagewhich adaptsAgentEventdata for display.
Using <AgentBChat />
<AgentBChat />This is the simplest way to add a full chat UI.
1. Installation (Reminder):
npm install @ulifeai/agentb-ui react-icons uuid tailwind-merge clsx
# or
yarn add @ulifeai/agentb-ui react-icons uuid tailwind-merge clsx2. Import and Use:
import React from 'react';
import { AgentBChat, UseChatOptions } from '@ulifeai/agentb-ui';
// You might need to import default styles or set up Tailwind
// import '@ulifeai/agentb-ui/dist/style.css'; // Path depends on package structure
function MyChatPage() {
const chatOptions: UseChatOptions = {
backendUrl: 'http://localhost:3001/agent/stream', // Your AgentB SSE endpoint
// Optional:
// initialThreadId: 'existing-thread-id',
// initialMessages: [
// { id: '1', text: 'Hello from initial props!', sender: 'user', status: 'sent', timestamp: new Date().toISOString() }
// ],
};
return (
<div style={{ height: '100vh', display: 'flex', flexDirection: 'column' }}>
{/* Optional: Add your app's header/navbar here */}
<header style={{ padding: '1rem', backgroundColor: '#eee' }}>My AgentB Chat App</header>
<div style={{ flexGrow: 1, position: 'relative' /* For potential absolute positioning inside AgentBChat */ }}>
<AgentBChat
options={chatOptions}
// --- Optional Customization Props ---
// title="My Virtual Assistant"
// inputPlaceholder="Type your message..."
// showSuggestions={false} // Example: disable default suggestions
// See package documentation for all available props
/>
</div>
</div>
);
}
export default MyChatPage;3. Backend Server:
Ensure your AgentB backend (e.g., using AgentB.getExpressStreamingHttpHandler()) is running and accessible at the backendUrl. Crucially, it must have CORS enabled if your React app and backend are on different origins/ports.
The <AgentBChat /> component will then render a complete chat interface.
Using the useChat Hook (For Custom UIs)
useChat Hook (For Custom UIs)If you need to build a completely custom chat UI but want to leverage AgentB's robust state management and SSE handling, you can use the useChat hook directly.
UseChatOptions (passed to the hook):
interface UseChatOptions {
backendUrl: string;
initialThreadId?: string;
initialMessages?: ChatMessage[]; // UI's ChatMessage type
}UseChatReturn (what the hook returns):
interface UseChatReturn {
messages: ChatMessage[]; // Array of messages to display
sendMessage: (text: string) => Promise<void>; // Function to send a user message
isLoading: boolean; // True if waiting for the initial part of agent's response (before streaming starts)
isStreaming: boolean; // True if the agent is currently streaming text
error: string | null; // Any error message from the interaction
threadId: string | null; // The current conversation thread ID
setMessages: React.Dispatch<React.SetStateAction<ChatMessage[]>>; // To directly manipulate messages if needed
currentRunId: string | null; // ID of the current agent run
}Example: Basic Custom UI with useChat
import React, { useState, useEffect, useRef } from 'react';
import { useChat, ChatMessage } from '@ulifeai/agentb-ui'; // Assuming ChatMessage is exported
function MyCustomChat() {
const {
messages,
sendMessage,
isLoading,
isStreaming,
error,
threadId
} = useChat({
backendUrl: 'http://localhost:3001/agent/stream',
});
const [inputText, setInputText] = useState('');
const messagesEndRef = useRef<null | HTMLDivElement>(null);
const scrollToBottom = () => {
messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
};
useEffect(scrollToBottom, [messages]);
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
if (!inputText.trim()) return;
sendMessage(inputText);
setInputText('');
};
return (
<div style={{ display: 'flex', flexDirection: 'column', height: '400px', border: '1px solid #ccc' }}>
<div style={{ flexGrow: 1, overflowY: 'auto', padding: '10px' }}>
{messages.map((msg) => (
<div key={msg.id} style={{ marginBottom: '10px', textAlign: msg.sender === 'user' ? 'right' : 'left' }}>
<span style={{
backgroundColor: msg.sender === 'user' ? '#dcf8c6' : (msg.sender === 'system' || msg.metadata?.isError) ? '#fdecea' : '#fff',
padding: '5px 10px',
borderRadius: '7px',
boxShadow: '0 1px 0.5px rgba(0,0,0,0.13)',
display: 'inline-block',
maxWidth: '70%',
}}>
<strong>{msg.sender}: </strong>{msg.text}
{msg.status === 'failed' && <em style={{color: 'red'}}> (failed)</em>}
{msg.metadata?.toolName && <em style={{fontSize: '0.8em', display: 'block', color: '#555'}}>Tool: {msg.metadata.toolName}</em>}
</span>
</div>
))}
<div ref={messagesEndRef} />
</div>
{isLoading && <p>Agent is thinking...</p>}
{isStreaming && <p>Agent is typing...</p>}
{error && <p style={{ color: 'red' }}>Error: {error}</p>}
<form onSubmit={handleSubmit} style={{ display: 'flex', padding: '10px' }}>
<input
type="text"
value={inputText}
onChange={(e) => setInputText(e.target.value)}
placeholder="Type your message..."
style={{ flexGrow: 1, padding: '10px', marginRight: '10px' }}
disabled={isLoading || isStreaming}
/>
<button type="submit" disabled={isLoading || isStreaming} style={{ padding: '10px' }}>
Send
</button>
</form>
{threadId && <p style={{fontSize: '0.8em', textAlign: 'center'}}>Thread ID: {threadId}</p>}
</div>
);
}
export default MyCustomChat;This example is basic but shows how useChat provides the necessary state and functions to build your own interface.
ChatMessage Interface (UI-Specific)
ChatMessage Interface (UI-Specific)The messages array returned by useChat (and used by <AgentBChat />) contains objects of type ChatMessage. This interface is defined in @ulifeai/agentb-ui (in ui/src/components/types.ts) and adapts backend AgentEvent data for display.
Key ChatMessage properties:
export interface ChatMessage {
id: string; // Unique message ID (can be original message ID or generated for UI thoughts)
text: string; // Main content or description of the event for display
sender: 'user' | 'ai' | 'system' | 'tool_thought' | 'tool_executing' | 'tool_result';
timestamp: string; // ISO string
status: 'sending' | 'sent' | 'failed' | 'streaming' | 'in_progress' | 'completed' | 'error';
metadata?: {
eventType?: AgentEvent['type']; // Original backend event type
toolName?: string;
toolInput?: Record<string, any> | string;
toolOutput?: any; // Success data or error string/object
isError?: boolean;
stepId?: string;
originalEvent?: AgentEvent; // The full backend event for debugging/advanced rendering
};
}The useChat hook intelligently processes backend AgentEvents and creates/updates these ChatMessage objects. For example:
thread.message.deltawithcontentChunkappends to an 'ai' sender message withstatus: 'streaming'.agent.tool.execution.startedmight create a message withsender: 'tool_executing'and text like "Executing tool X...".agent.tool.execution.completedupdates that message tosender: 'tool_result'with success/failure details.
Styling
The <AgentBChat /> component and its sub-components are designed with Tailwind CSS in mind but include default functional styling. You can:
Use Tailwind: If your project uses Tailwind CSS, the components should pick up your theme and allow utility class overrides.
CSS Overrides: Target the components' CSS classes with your own stylesheets. Inspect the rendered HTML to find the class names used (they are typically prefixed, e.g.,
agentb-chat-container,agentb-message-item).Style Props (Limited): Some components might accept
styleorclassNameprops for direct styling. Check the specific component's documentation/props.
Summary
@ulifeai/agentb-ui significantly accelerates the development of chat interfaces for your AgentB agents.
For a quick, full-featured UI, use
<AgentBChat />.For maximum control over UI presentation while still benefiting from AgentB's client-side logic, use the
useChathook.
Always ensure your AgentB backend server is running, correctly configured (especially CORS), and that the backendUrl in your UI points to the correct SSE endpoint.
Last updated