/** * Sandbox Example — Client * * Split layout: chat on the left, execution log + customer data on the right. * The agent writes code that runs in a sandboxed isolate — the execution log * shows the code and its captured console output. */ import { Suspense, useCallback, useState, useEffect, useRef } from "react"; import { useAgent } from "agents/react"; import { useAgentChat } from "@cloudflare/ai-chat/react"; import { isToolUIPart, getToolName } from "ai"; import type { UIMessage } from "ai"; import { Button, Badge, InputArea, Empty, Surface, Text } from "@cloudflare/kumo"; import { ConnectionIndicator, ModeToggle, PoweredByAgents, type ConnectionStatus } from "@cloudflare/agents-ui"; import { PaperPlaneRightIcon, TrashIcon, GearIcon, CodeIcon, DatabaseIcon, TerminalIcon, PlayIcon } from "@phosphor-icons/react"; import { Streamdown } from "streamdown"; import type { SandboxState, ExecutionRecord, CustomerRecord } from "./server"; function getMessageText(message: UIMessage): string { return message.parts .filter((part) => part.type === "text") .map((part) => (part as { type: "text"; text: string }).text) .join(""); } // ─── Execution Log ───────────────────────────────────────────────────────── function ExecutionLog({ executions }: { executions: ExecutionRecord[] }) { if (executions.length === 0) { return ( } title="No executions yet" description='Ask the agent to write code — e.g. "List all Gold tier customers"' /> ); } return (
{executions.map((exec) => (
Code {exec.error ? ( Error ) : ( OK )} {exec.timestamp}
{/* Code */}
            {exec.code.length > 500
              ? exec.code.slice(0, 500) + "\n// ... truncated"
              : exec.code}
          
{/* Output */}
Output
              {exec.output || "(no output)"}
            
))}
); } // ─── Customer Table ──────────────────────────────────────────────────────── function CustomerTable({ customers }: { customers: CustomerRecord[] }) { if (customers.length === 0) { return ( } title="No customers" description="The database is empty" /> ); } return (
{customers.map((c) => ( ))}
Name Email Tier Region
{c.name} {c.email} {c.tier} {c.region}
); } // ─── Main ────────────────────────────────────────────────────────────────── function ChatPanel() { const [connectionStatus, setConnectionStatus] = useState("connecting"); const [input, setInput] = useState(""); const [sandboxState, setSandboxState] = useState(null); const messagesEndRef = useRef(null); const agent = useAgent({ agent: "SandboxAgent", onOpen: useCallback(() => setConnectionStatus("connected"), []), onClose: useCallback(() => setConnectionStatus("disconnected"), []), onError: useCallback( (error: Event) => console.error("WebSocket error:", error), [] ), onStateUpdate: useCallback( (state: SandboxState) => setSandboxState(state), [] ) }); const { messages, sendMessage, clearHistory, status } = useAgentChat({ agent }); const isStreaming = status === "streaming"; const isConnected = connectionStatus === "connected"; useEffect(() => { messagesEndRef.current?.scrollIntoView({ behavior: "smooth" }); }, [messages]); const send = useCallback(() => { const text = input.trim(); if (!text || isStreaming) return; setInput(""); sendMessage({ role: "user", parts: [{ type: "text", text }] }); }, [input, isStreaming, sendMessage]); const [rightTab, setRightTab] = useState<"executions" | "data">("executions"); return (
{/* Left: Chat */}
Sandbox Dynamic Code Execution
{messages.length === 0 && ( } title="Talk to the sandbox agent" description={`Try: "Write code to count customers by tier" or "Find customers whose email contains 'example'"`} /> )} {messages.map((message, index) => { const isUser = message.role === "user"; const isLastAssistant = message.role === "assistant" && index === messages.length - 1; return (
{isUser ? (
{getMessageText(message)}
) : ( getMessageText(message) && (
{getMessageText(message)}
) )} {message.parts .filter((part) => isToolUIPart(part)) .map((part) => { if (!isToolUIPart(part)) return null; const toolName = getToolName(part); if (part.state === "output-available") { return (
{toolName === "executeCode" ? ( ) : ( )} {toolName === "executeCode" ? "Code executed in sandbox" : "Query executed"}
); } if ( part.state === "input-available" || part.state === "input-streaming" ) { return (
{toolName === "executeCode" ? "Running code in sandbox..." : `Running ${toolName}...`}
); } return null; })}
); })}
{ e.preventDefault(); send(); }} className="max-w-2xl mx-auto px-5 py-4" >
{ if (e.key === "Enter" && !e.shiftKey) { e.preventDefault(); send(); } }} placeholder='Try: "Write code to count customers by region"' disabled={!isConnected || isStreaming} rows={2} className="flex-1 !ring-0 focus:!ring-0 !shadow-none !bg-transparent !outline-none" />
{/* Right: Execution Log + Data */}
{rightTab === "executions" && sandboxState && ( )} {rightTab === "data" && sandboxState && ( )} {!sandboxState && (
Connecting...
)}
); } export default function App() { return ( Loading...
} > ); }