# Patterns & Use Cases ## AI Chat w/Tools **Server (AIChatAgent):** ```ts import { AIChatAgent } from "agents"; import { openai } from "@ai-sdk/openai"; import { tool } from "ai"; import { z } from "zod"; export class ChatAgent extends AIChatAgent { async onChatMessage(onFinish) { return this.streamText({ model: openai("gpt-4"), messages: this.messages, // Auto-managed tools: { getWeather: tool({ description: "Get current weather", parameters: z.object({ city: z.string() }), execute: async ({ city }) => `Weather in ${city}: Sunny, 72°F` }), searchDocs: tool({ description: "Search documentation", parameters: z.object({ query: z.string() }), execute: async ({ query }) => JSON.stringify( this.sql<{title, content}>`SELECT title, content FROM docs WHERE content LIKE ${'%' + query + '%'}` ) }) }, onFinish, }); } } ``` **Client (React):** ```tsx import { useAgent } from "agents/react"; import { useAgentChat } from "agents/ai-react"; function ChatUI() { const agent = useAgent({ agent: "ChatAgent" }); const { messages, input, handleInputChange, handleSubmit, isLoading } = useAgentChat({ agent }); return (
{messages.map(m =>
{m.role}: {m.content}
)}
); } ``` ## Human-in-the-Loop (Client Tools) Server defines tool, client executes: ```ts // Server export class ChatAgent extends AIChatAgent { async onChatMessage(onFinish) { return this.streamText({ model: openai("gpt-4"), messages: this.messages, tools: { confirmAction: tool({ description: "Ask user to confirm", parameters: z.object({ action: z.string() }), execute: "client", // Client-side execution }) }, onFinish, }); } } // Client const { messages } = useAgentChat({ agent, onToolCall: async (toolCall) => { if (toolCall.toolName === "confirmAction") { return { confirmed: window.confirm(`Confirm: ${toolCall.args.action}?`) }; } } }); ``` ## Task Queue & Scheduled Processing ```ts export class TaskAgent extends Agent { onStart() { this.schedule("*/5 * * * *", "processQueue", {}); // Every 5 min this.schedule("0 0 * * *", "dailyCleanup", {}); // Daily } async onRequest(req: Request) { await this.queue("processVideo", { videoId: (await req.json()).videoId }); return Response.json({ queued: true }); } async processQueue() { const tasks = await this.dequeue(10); for (const task of tasks) { if (task.name === "processVideo") await this.processVideo(task.data.videoId); } } async dailyCleanup() { this.sql`DELETE FROM logs WHERE created_at < ${Date.now() - 86400000}`; } } ``` ## Manual WebSocket Chat Custom protocols (non-AI): ```ts export class ChatAgent extends Agent { async onConnect(conn: Connection, ctx: ConnectionContext) { conn.accept(); conn.setState({userId: ctx.request.headers.get("X-User-ID") || "anon"}); conn.send(JSON.stringify({type: "history", messages: this.state.messages})); } async onMessage(conn: Connection, msg: WSMessage) { const newMsg = {userId: conn.state.userId, text: JSON.parse(msg as string).text, timestamp: Date.now()}; this.setState({messages: [...this.state.messages, newMsg]}); this.connections.forEach(c => c.send(JSON.stringify(newMsg))); } } ``` ## Email Processing w/AI ```ts export class EmailAgent extends Agent { async onEmail(email: AgentEmail) { const [text, from, subject] = [await email.text(), email.from, email.headers.get("subject") || ""]; this.sql`INSERT INTO emails (from_addr, subject, body) VALUES (${from}, ${subject}, ${text})`; const { text: summary } = await generateText({ model: openai("gpt-4o-mini"), prompt: `Summarize: ${subject}\n\n${text}` }); this.connections.forEach(c => c.send(JSON.stringify({type: "new_email", from, summary}))); if (summary.includes("urgent")) await this.schedule(0, "sendAutoReply", { to: from }); } } ``` ## Real-time Collaboration ```ts export class GameAgent extends Agent { initialState = { players: [], gameStarted: false }; async onConnect(conn: Connection, ctx: ConnectionContext) { conn.accept(); const playerId = ctx.request.headers.get("X-Player-ID") || crypto.randomUUID(); conn.setState({ playerId }); const newPlayer = { id: playerId, score: 0 }; this.setState({...this.state, players: [...this.state.players, newPlayer]}); this.connections.forEach(c => c.send(JSON.stringify({type: "player_joined", player: newPlayer}))); } async onMessage(conn: Connection, msg: WSMessage) { const m = JSON.parse(msg as string); if (m.type === "move") { this.setState({ ...this.state, players: this.state.players.map(p => p.id === conn.state.playerId ? {...p, score: p.score + m.points} : p) }); this.connections.forEach(c => c.send(JSON.stringify({type: "player_moved", playerId: conn.state.playerId}))); } if (m.type === "start" && this.state.players.length >= 2) { this.setState({...this.state, gameStarted: true}); this.connections.forEach(c => c.send(JSON.stringify({type: "game_started"}))); } } } ```