@agentbase-sdk/react
v0.1.4
Published
React hooks for Agentbase SDK - build conversational AI interfaces with ease
Maintainers
Readme
Agentbase React SDK
React hooks for building conversational AI interfaces with Agentbase. Simple, powerful, and focused.
Features
- Simple API - Clean hook with just what you need:
send,stop,clear - Streaming Support - Real-time streaming of agent responses
- Multi-Agent Flows - Support for agent handoffs and transfers
- Session Management - Automatic session tracking and continuation of previous conversations
- TypeScript - Full TypeScript support with type definitions
- Server-Side - Keep your API keys secure on the server
Installation
npm install @agentbase-sdk/react agentbase-sdkQuick Start
1. Create a Server-Side API Route
The React SDK calls a server-side endpoint to keep your Agentbase API key secure. Here's an example using Next.js App Router:
// app/api/agent/route.ts
import Agentbase from "agentbase-sdk";
import { NextRequest } from "next/server";
// Initialize Agentbase client (reuse across requests)
const agentbase = new Agentbase({
apiKey: process.env.AGENTBASE_API_KEY!,
});
export const runtime = "edge"; // Optional: Use Edge Runtime for better performance
export async function GET(req: NextRequest) {
try {
// Get session ID from query parameters
const { searchParams } = new URL(req.url);
const sessionId = searchParams.get("session");
if (!sessionId) {
return new Response("Session ID is required", { status: 400 });
}
// Fetch messages for the session
const response = await fetch(
`https://api.agentbase.sh/sessions/${sessionId}/messages`,
{
method: "GET",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${process.env.AGENTBASE_API_KEY}`,
},
}
);
if (!response.ok) {
throw new Error(`Failed to fetch messages: ${response.status}`);
}
const data = await response.json();
return new Response(JSON.stringify(data), {
headers: {
"Content-Type": "application/json",
},
});
} catch (error) {
console.error("Get messages error:", error);
return new Response("Internal server error", { status: 500 });
}
}
export async function POST(req: NextRequest) {
try {
// Parse request body
const body = await req.json();
const {
message,
session,
system,
mode = "fast",
rules,
mcp_servers,
agents,
streaming_tokens = false,
} = body;
// Validate required fields
if (!message) {
return new Response("Message is required", { status: 400 });
}
// Prepare Agentbase parameters
const params: any = {
message,
mode,
streaming_tokens,
};
if (session) params.session = session;
if (system) params.system = system;
if (rules) params.rules = rules;
if (mcp_servers) params.mcp_servers = mcp_servers;
if (agents) params.agents = agents;
// Create a TransformStream to convert async iterator to ReadableStream
const encoder = new TextEncoder();
const stream = new TransformStream();
const writer = stream.writable.getWriter();
// Start streaming in the background
(async () => {
try {
const responseStream = await agentbase.runAgent(params);
for await (const response of responseStream) {
// Format as Server-Sent Events
const data = `data: ${JSON.stringify(response)}\n\n`;
await writer.write(encoder.encode(data));
}
await writer.close();
} catch (error) {
console.error("Streaming error:", error);
await writer.abort(error);
}
})();
// Return the stream as SSE
return new Response(stream.readable, {
headers: {
"Content-Type": "text/event-stream",
"Cache-Control": "no-cache",
Connection: "keep-alive",
},
});
} catch (error) {
console.error("Chat API error:", error);
return new Response("Internal server error", { status: 500 });
}
}See examples/nextjs for the complete working example.
2. Use the useAgent Hook in Your Component
"use client";
import { useAgent } from "@agentbase-sdk/react";
import { useState } from "react";
export default function Chat() {
const [input, setInput] = useState("");
const { messages, send, stop, clear, isRunning, error, session } = useAgent({
api: "/api/agent",
system: "You are a helpful AI assistant. Be concise and friendly.",
mode: "fast",
onError: (error) => {
console.error("Agent error:", error);
},
});
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
if (!input.trim() || isRunning) return;
send(input);
setInput("");
};
return (
<div>
{/* Session Info */}
{session && <div>Session: {session.substring(0, 8)}...</div>}
{/* Error Display */}
{error && <div>Error: {error.message}</div>}
{/* Messages */}
<div>
{messages.map((message, msgIndex) => (
<div key={msgIndex}>
<strong>{message.role === "user" ? "You" : "Assistant"}:</strong>
{/* Render all content items */}
{message.content.map((item, index) => (
<div key={index}>
{item.type === "text" && (
<div>{item.text}</div>
)}
{item.type === "thinking" && (
<div style={{ fontStyle: "italic", opacity: 0.7 }}>
💭 {item.text}
</div>
)}
{item.type === "tool_use" && (
<div>
<strong>🔧 Tool Use:</strong>
<pre>{item.text}</pre>
</div>
)}
{item.type === "tool_response" && (
<div>
<strong>✅ Tool Result:</strong>
<pre>{item.text}</pre>
</div>
)}
{item.type === "transfer" && (
<div>
🔄 Transferred to: {item.agent}
{item.context && <div>{item.context}</div>}
</div>
)}
</div>
))}
</div>
))}
{/* Loading indicator */}
{isRunning && <div>...</div>}
</div>
{/* Controls */}
<button onClick={clear} disabled={messages.length === 0}>
Clear
</button>
{/* Input Form */}
<form onSubmit={handleSubmit}>
<input
value={input}
onChange={(e) => setInput(e.target.value)}
placeholder="Type your message..."
disabled={isRunning}
/>
{isRunning ? (
<button type="button" onClick={stop}>
Stop
</button>
) : (
<button type="submit" disabled={!input.trim()}>
Send
</button>
)}
</form>
</div>
);
}API Reference
useAgent(options)
The main hook for building agent interfaces.
Options
interface UseAgentOptions {
// Required: API endpoint to call
api: string;
// Optional: Session ID to continue a previous conversation
// If provided, chat history will be fetched automatically
sessionId?: string;
// Optional: System prompt for the agent
system?: string;
// Optional: Agent mode (default: "fast")
mode?: "flash" | "fast" | "max";
// Optional: Rules for the agent
rules?: string[];
// Optional: MCP servers configuration
mcpServers?: Array<{
serverName: string;
serverUrl: string;
}>;
// Optional: Agent handoffs for multi-agent flows
agents?: Array<{
name: string;
description?: string;
}>;
// Optional: Stream tokens individually
streamingTokens?: boolean;
// Optional: Initial messages
initialMessages?: Message[];
// Optional: Error callback
onError?: (error: Error) => void;
// Optional: Custom headers and body
headers?: Record<string, string>;
body?: Record<string, any>;
}Returns
interface UseAgentReturn {
// Message history
messages: Message[];
// Send a message to the agent
send: (message: string) => Promise<void>;
// Stop the current agent run
stop: () => void;
// Clear all messages (locally and on server)
clear: () => Promise<void>;
// State
isRunning: boolean;
error: Error | null;
session: string | null;
}Examples
Continuing a Previous Session
Pass a sessionId to the useAgent hook to continue a previous conversation. The hook will automatically:
- Fetch the chat history from your API's GET endpoint
- Display all previous messages
- Continue the conversation in the same session when you send new messages
"use client";
import { useAgent } from "@agentbase-sdk/react";
import { useState } from "react";
function ContinueSessionChat() {
const [input, setInput] = useState("");
const [sessionInput, setSessionInput] = useState("");
const [currentSessionId, setCurrentSessionId] = useState<string | undefined>();
const { messages, send, isRunning, session } = useAgent({
api: "/api/agent",
sessionId: currentSessionId, // Pass the session ID to continue
system: "You are a helpful assistant.",
});
const handleLoadSession = () => {
if (sessionInput.trim()) {
setCurrentSessionId(sessionInput.trim());
}
};
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
if (!input.trim() || isRunning) return;
send(input);
setInput("");
};
return (
<div>
{/* Load Session */}
<div>
<input
value={sessionInput}
onChange={(e) => setSessionInput(e.target.value)}
placeholder="Enter session ID to continue..."
/>
<button onClick={handleLoadSession}>Load Session</button>
</div>
{/* Current Session */}
{session && <div>Current Session: {session}</div>}
{/* Messages */}
<div>
{messages.map((msg, idx) => (
<div key={idx}>
<strong>{msg.role}:</strong>
{msg.content.map((item, i) => (
<div key={i}>
{item.type === "text" && <span>{item.text}</span>}
</div>
))}
</div>
))}
</div>
{/* Input */}
<form onSubmit={handleSubmit}>
<input
value={input}
onChange={(e) => setInput(e.target.value)}
disabled={isRunning}
placeholder="Type your message..."
/>
<button type="submit" disabled={isRunning || !input.trim()}>
Send
</button>
</form>
</div>
);
}Basic Chat
"use client";
import { useAgent } from "@agentbase-sdk/react";
import { useState } from "react";
function BasicChat() {
const [input, setInput] = useState("");
const { messages, send, isRunning } = useAgent({
api: "/api/agent",
system: "You are a helpful assistant.",
});
return (
<div>
{messages.map((msg, idx) => (
<div key={idx}>
<strong>{msg.role}:</strong>
{msg.content.map((item, i) => (
<div key={i}>
{item.type === "text" && <span>{item.text}</span>}
</div>
))}
</div>
))}
<form
onSubmit={(e) => {
e.preventDefault();
if (!input.trim() || isRunning) return;
send(input);
setInput("");
}}
>
<input
value={input}
onChange={(e) => setInput(e.target.value)}
disabled={isRunning}
/>
<button type="submit" disabled={isRunning || !input.trim()}>
Send
</button>
</form>
</div>
);
}Advanced Features
"use client";
import { useAgent } from "@agentbase-sdk/react";
import { useState } from "react";
function AdvancedChat() {
const [input, setInput] = useState("");
const { messages, send, stop, clear, isRunning, error, session } = useAgent({
api: "/api/agent",
system: "You are a helpful assistant.",
mode: "fast",
onError: (error) => console.error("Error:", error),
});
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
if (!input.trim() || isRunning) return;
send(input);
setInput("");
};
return (
<div>
{/* Session Info */}
{session && <div>Session: {session.substring(0, 8)}...</div>}
{/* Error Display */}
{error && <div style={{ color: "red" }}>Error: {error.message}</div>}
{/* Messages */}
<div>
{messages.map((msg, idx) => (
<div key={idx}>
<strong>{msg.role}:</strong>
{msg.content.map((item, i) => (
<div key={i}>
{item.type === "text" && <div>{item.text}</div>}
{item.type === "thinking" && (
<div style={{ fontStyle: "italic", opacity: 0.7 }}>
💭 {item.text}
</div>
)}
{item.type === "tool_use" && (
<div>
<strong>🔧 Tool:</strong>
<pre>{item.text}</pre>
</div>
)}
</div>
))}
</div>
))}
</div>
{/* Controls */}
<div>
<button onClick={clear} disabled={messages.length === 0}>
Clear
</button>
{isRunning && <button onClick={stop}>Stop</button>}
</div>
{/* Input */}
<form onSubmit={handleSubmit}>
<input
value={input}
onChange={(e) => setInput(e.target.value)}
disabled={isRunning}
placeholder="Type your message..."
/>
<button type="submit" disabled={isRunning || !input.trim()}>
Send
</button>
</form>
</div>
);
}Multi-Agent Flow
"use client";
import { useAgent } from "@agentbase-sdk/react";
import { useState } from "react";
function MultiAgentChat() {
const [input, setInput] = useState("");
const { messages, send, isRunning } = useAgent({
api: "/api/agent",
system: "You classify products and route to specialized agents.",
mode: "fast",
agents: [
{
name: "Personal Care Agent",
description: "Handles personal care products",
},
{
name: "Cosmetics Agent",
description: "Handles makeup and cosmetics",
},
],
});
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
if (!input.trim() || isRunning) return;
send(input);
setInput("");
};
return (
<div>
{messages.map((msg, idx) => (
<div key={idx}>
<strong>{msg.role}:</strong>
{msg.content.map((item, i) => (
<div key={i}>
{item.type === "text" && <div>{item.text}</div>}
{item.type === "transfer" && (
<div style={{ background: "#f0f0f0", padding: "8px" }}>
🔄 Transferred to: <strong>{item.agent}</strong>
{item.context && <div>Context: {item.context}</div>}
</div>
)}
</div>
))}
</div>
))}
<form onSubmit={handleSubmit}>
<input
value={input}
onChange={(e) => setInput(e.target.value)}
disabled={isRunning}
placeholder="Type your message..."
/>
<button type="submit" disabled={isRunning || !input.trim()}>
Send
</button>
</form>
</div>
);
}Message Structure
Messages have the following structure:
interface Message {
role: "user" | "assistant";
content: MessageContent;
createdAt: Date;
}
type MessageContent = MessageContentItem[];
interface MessageContentItem {
type: "text" | "thinking" | "tool_use" | "tool_response" | "transfer";
text: string;
agent?: string; // For transfer events
context?: string; // For transfer events
}Full Example
Check out the examples/nextjs directory for a complete Next.js project with:
- Next.js 14 App Router
- TypeScript
- Tailwind CSS
- Server-side API route
- Full chat interface with all features
TypeScript
The library is written in TypeScript and includes full type definitions. All types are exported:
import type {
UseAgentOptions,
UseAgentReturn,
Message,
MessageContent,
MessageContentItem,
AgentResponse,
} from "@agentbase-sdk/react";Development
See DEVELOPMENT.md for detailed development instructions.
# Install dependencies
npm install
# Build the library
npm run build
# Watch mode for development
npm run dev
# Type checking
npm run typecheckLicense
MIT
Links
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
