This document describes how to test every feature in the Agents SDK Playground. Each section covers a demo page with specific test steps and expected results.
- Start the dev server:
npm run start - Open http://localhost:5173 in your browser
- Verify the home page loads with the feature grid
Tests real-time state synchronization between server and clients.
- Action: Navigate to
/core/state - Expected: Connection status shows "Connected" with a green dot
- Action: Click the +1 button
- Expected:
- Counter value increases by 1
- Event log shows
call → increment()followed byresult ← - "Current State" JSON updates with new counter value
- Action: Click the -1 button
- Expected: Counter value decreases by 1
- Action: Enter
42in the number input, click Set (Server) - Expected:
- Counter changes to 42
- Log shows
call → setCounter(42)andresult ←
- Action: Enter
100in the number input, click Set (Client) - Expected:
- Counter changes to 100
- Log shows
setState →(client-side update, no server call)
- Action: Type "Test Item" in the New Item input, click Add
- Expected:
- Item appears in the Items list
- Items count increments
- Action: Click Remove next to an item
- Expected: Item disappears from the list
- Action: Click the red Reset button
- Expected: Counter returns to 0, items list clears
- Action: Open the same URL in a new tab, modify state in one tab
- Expected: Both tabs show the same state (real-time sync)
Tests the @callable decorator and RPC functionality.
- Action: Enter
5and3, click add(5, 3) - Expected:
- Log shows
call → { method: "add", args: [5, 3] } - Result shows
8
- Log shows
- Action: Click multiply(5, 3)
- Expected: Result shows
15
- Action: Type "Hello World", click Echo
- Expected: Log shows result
"Hello World"
- Action: Set delay to
2000, click slowOperation(2000) - Expected:
- Takes ~2 seconds to complete
- Result shows "Completed after 2000ms"
- Action: Type "Something broke", click Throw Error
- Expected:
- Log shows error entry in red
- Error message contains "Something broke"
- Action: Click getTimestamp()
- Expected: Returns current ISO timestamp string
- Action: Click listMethods()
- Expected:
- "Available Methods" card appears
- Shows all callable methods with descriptions
Tests streaming responses from agent to client.
- Action: Set count to
10, click Stream 10 numbers - Expected:
- Chunks appear one by one:
{"number":1},{"number":2}, etc. - Log shows multiple
chunk ←entries - Final result shows
{"total":10}
- Chunks appear one by one:
- Action: Set countdown to
5, click Countdown from 5 - Expected:
- Numbers stream in with ~500ms delay between each
- Shows "5...", "4...", "3...", "2...", "1...", "Liftoff!"
- Takes approximately 2.5 seconds total
- Action: Set "Error after" to
3, click Error after 3 chunks - Expected:
- First 3 chunks arrive successfully
- Error entry appears in log
- Stream terminates
- Action: Start a stream
- Expected: Button shows "Streaming..." and is disabled until complete
Tests delayed and recurring task scheduling.
- Action: Set delay to
5seconds, enter a message, click Schedule Task - Expected:
- "Active Schedules" shows the new schedule
- After 5 seconds, log shows
schedule_executed ←with the message
- Action: Set interval to
10seconds, enter a label, click Schedule Recurring - Expected:
- Schedule appears in Active Schedules
- Every 10 seconds, log shows
recurring_executed ←
- Action: Click Cancel next to an active schedule
- Expected:
- Schedule disappears from Active Schedules
- No more executions occur
- Action: Click Refresh link
- Expected: Active Schedules list updates
Tests WebSocket connection management and broadcasting.
- Action: Navigate to
/core/connections - Expected: Connected Clients shows
1
- Action: Click Open New Tab (or manually open another tab to same URL)
- Expected:
- Both tabs update to show
2connected clients - Log shows
connection_count ← 2
- Both tabs update to show
- Action: Type a message, click Broadcast
- Expected:
- Message appears in "Received Broadcasts" on ALL connected tabs
- Includes timestamp
- Action: Close one of the tabs
- Expected: Remaining tab updates to show
1connected client
Tests direct SQL interaction with agent's SQLite database.
- Action: Navigate to
/core/sql - Expected: Tables list shows internal tables (e.g.,
cf_agents_state,cf_agents_schedules)
- Action: Click on a table name (e.g.,
cf_agents_state) - Expected:
- Schema card shows columns, types, and nullability
- Query input updates to
SELECT * FROM cf_agents_state LIMIT 10
- Action: Click Execute
- Expected: Results card shows query results as JSON
- Action: Enter a key (e.g., "test-key") and value (e.g., "test-value"), click Insert
- Expected:
- Record appears in the Custom Data list below
- Tables list now includes
playground_data
Tests different agent naming patterns.
- Action:
- Note your User ID (e.g., "user-abc123")
- Open a new tab with the same User ID
- Expected:
- Both tabs connect to the same agent instance
- Connected Clients shows
2
- Action: Change User ID to something different
- Expected:
- Agent Instance name changes
- Connection count resets to
1(you're now on a different agent)
- Action: Select Shared strategy
- Expected:
- Agent instance changes to
routing-shared - All tabs with Shared strategy connect to the same agent
- Agent instance changes to
- Action: Select Per-Session strategy
- Expected:
- Each tab connects to a different agent (based on session ID)
- Opening new tab creates new session = new agent
- Action: Change User ID, refresh the page
- Expected: User ID persists (stored in localStorage)
Tests the manager-child agent pattern using getAgentByName().
- Action: Navigate to
/multi-agent/supervisor - Expected: Connection status shows "Connected", stats show 0 children
- Action: Click + Create Child
- Expected:
- New child card appears with ID like
child-abc123 - Counter shows
0 - Stats update: Children = 1, Total Counter = 0
- Log shows
call → createChild("child-abc123")and result
- New child card appears with ID like
- Action: Click +1 on a child card
- Expected:
- That child's counter increments
- Total Counter in stats updates
- Log shows
call → incrementChild("child-abc123")
- Action: Create multiple children, click +1 to All
- Expected:
- All children increment by 1
- Total Counter updates to sum of all counters
- Log shows
call → incrementAll()
- Action: Click the × button on a child card
- Expected:
- Child disappears from the grid
- Stats update accordingly
- Action: Click Clear All link
- Expected:
- All children removed
- Stats reset to 0
- Action: Create children, refresh the page
- Expected:
- Children are preserved (supervisor tracks IDs in state)
- Stats match previous values
Tests multi-agent chat with Lobby and Room agents.
- Action: Navigate to
/multi-agent/rooms - Expected: Lobby shows "Connected", room list is empty or shows existing rooms
- Action: Type "General" in room name, click Create
- Expected:
- Room appears in the list with 0 online
- Log shows
call → createRoom("General")
- Action: Click on a room in the list
- Expected:
- Chat area shows room name
- Room header shows "0 members" initially, then "1 members"
- Log shows
join_room → General
- Action: Type a message, press Enter or click Send
- Expected:
- Message appears in chat area
- Your messages appear on the right with dark background
- Log shows
send → <message>
- Action: Click link to open new tab (or manually open same URL)
- In new tab, set different username
- Join same room
- Send messages from both tabs
- Expected:
- Both users see each other's messages in real-time
- Members list shows both usernames
- Member count updates in lobby room list
- Action: Click Leave button
- Expected:
- Chat area returns to "Select a room to start chatting"
- Member count decreases for that room
- Action: Refresh page
- Expected:
- Rooms persist (tracked in LobbyAgent state)
- Messages persist (stored in RoomAgent)
Documentation-only demo explaining fan-out parallel processing.
- Action: Navigate to
/multi-agent/workers - Expected:
- Architecture diagram with ManagerAgent → Workers
- "How It Works" explanation
- Example code snippet
- Use cases list
Documentation-only demo explaining chain of responsibility.
- Action: Navigate to
/multi-agent/pipeline - Expected:
- Architecture diagram with linear agent chain
- "How It Works" explanation
- Example code snippet
- Variations section (Linear, Branching, Saga, Async)
- Considerations notes
Interactive demo that simulates multi-step workflow execution with automatic step progression.
- Action: Navigate to
/workflow/basic - Expected: Connection status shows "Connected", no workflows running
- Action: Enter a workflow name (e.g., "Data Processing"), set step count to 4, click Start Workflow
- Expected:
- Workflow appears in "Running" section
- Visual step pipeline shows Step 1 as running (spinner icon)
- Event log shows
startWorkflow →,workflow_started ←
- Action: Wait and observe the workflow
- Expected:
- Steps complete one by one (1-2 seconds each)
- Completed steps show checkmark, current step shows spinner
- Connection lines turn solid as steps complete
- Event log shows
workflow_step_complete ←for each step - When all steps complete,
workflow_complete ←appears
- Action: Start 2-3 workflows with different names
- Expected:
- All workflows appear in Running section
- Each progresses independently
- Completed workflows move to History section
- Action: Start a workflow, then click the X button before it completes
- Expected:
- Workflow status changes to "cancelled"
- Workflow moves to History section
- Event log shows
cancelWorkflow →,workflow_cancelled ←
- Action: After some workflows complete, click Clear in the History section
- Expected:
- Resolved workflows are removed
- Running workflows remain
- Event log shows
clearWorkflows →,cleared ←
Interactive demo that simulates human-in-the-loop approval patterns.
- Action: Navigate to
/workflow/approval - Expected: Connection status shows "Connected", no pending approvals
- Action: Enter a title and description, click Submit Request
- Expected:
- Request appears in "Pending Approval" section with yellow indicator
- Shows Approve and Reject buttons
- Event log shows
requestApproval →,approval_requested ←
- Action: Click one of the preset request buttons (e.g., "Deploy v2.0 to Production")
- Expected:
- Title and description fields are populated
- Can submit the preset request
- Action: Click Approve on a pending request
- Expected:
- Request moves to History with green indicator
- Shows "Approved at [time]"
- Event log shows
approve →,approval_approved ←
- Action: Click Reject on a pending request
- Expected:
- Reject reason input appears
- After clicking "Confirm Reject", request moves to History with red indicator
- Shows "Rejected at [time]" with reason
- Event log shows
reject →,approval_rejected ←
- Action: Submit 3-4 requests without approving
- Expected:
- All appear in Pending Approval section
- Can approve/reject each independently
- Action: Resolve several requests, then click Clear in History
- Expected:
- Resolved requests are removed from History
- Pending requests remain
Tests receiving emails via Cloudflare Email Routing. Requires deployment for real email testing.
- Action: Navigate to
/email/receive - Expected: Connection status shows "Connected", empty inbox, stats show 0
- Action: Observe the page when running locally
- Expected: Warning banner indicates email features require deployment
- Action: Observe the Stats panel
- Expected: Shows Inbox count and Total received count
- Action: Send an email to
receive+demo@yourdomain.com - Expected:
- Email appears in Inbox list
- Stats update (Inbox +1, Total +1)
- Log shows
state_update ←
- Action: Click on an email in the Inbox
- Expected:
- Detail panel shows subject, from, to, date
- Email body displayed below
- Headers expandable via details toggle
- Action: Click the × button on the detail panel
- Expected: Detail panel closes
Tests HMAC-signed email replies for secure routing.
- Action: Navigate to
/email/secure - Expected: Connection status shows "Connected", Inbox/Outbox tabs visible, stats show 0
- Action: Click between Inbox and Outbox tabs
- Expected: Tab content switches, counts shown in tab labels
- Action: Toggle the "Auto-reply with signed headers" switch
- Expected:
- Log shows
toggleAutoReply → - Setting persists in agent state
- Log shows
- Action: Send an email to
secure+demo@yourdomain.comwith auto-reply enabled - Expected:
- Email appears in Inbox
- Signed reply appears in Outbox with green checkmark
- Reply has "Re:" prefix in subject
- Action: Switch to Outbox tab, click on a reply
- Expected:
- Detail shows the reply body
- Green "Signed" badge displayed
- Note about X-Agent-* headers shown
- Action: Reply to a signed email from your email client
- Expected:
- Reply is routed back to the same agent instance
- Email shows lock icon indicating "Secure Reply"
- Action: Click Clear all emails
- Expected:
- Both inbox and outbox are cleared
- Log shows
clearEmails →
To test with real emails:
- Deploy:
npm run deploy - Set secret:
wrangler secret put EMAIL_SECRET - Configure Cloudflare Dashboard → Email → Email Routing
- Add routing rule for your domain to this Worker
- Send emails to:
receive+instanceId@yourdomain.comfor ReceiveEmailAgentsecure+instanceId@yourdomain.comfor SecureEmailAgent
Tests read-only WebSocket connections that can observe but not modify state.
- Action: Navigate to
/core/readonly - Expected: Two side-by-side panels — "Editor (read-write)" on the left, "Viewer (readonly)" on the right
- Action: Click +1 on the Editor panel
- Expected:
- Counter increases on BOTH panels (state syncs to viewer)
- "Last updated by" shows the update source
- Action: Click +1 on the Viewer panel
- Expected: Error toast appears — readonly connections cannot call methods that write state
- Action: Click +10 on the Viewer panel
- Expected: Error toast appears — client-side setState is also blocked for readonly connections
- Action: Click Check Permissions on the Viewer panel
- Expected: Info toast shows
canEdit = false— non-mutating RPCs work on readonly connections
- Action: Uncheck the Lock checkbox on the Viewer panel
- Expected:
- Badge changes to "Viewer (read-write)"
- Viewer can now increment and modify state
Tests retry operations with exponential backoff and selective retry.
- Action: Set "Succeed on attempt" to
3, click Run Flaky Operation - Expected:
- Log shows attempts 1 and 2 failing
- Attempt 3 succeeds
- Result appears in log
- Action: Set "Succeed on attempt" to
10, click Run Flaky Operation - Expected:
- Log shows attempts failing (class default is 4 max attempts)
- Final error after all retries exhausted
- Action: Set "Failures before success" to
2, leave "Permanent error" unchecked, click Run Filtered Retry - Expected:
- Transient errors are retried
- Succeeds after 2 failures
- Action: Check Permanent error, click Run Filtered Retry
- Expected:
- shouldRetry returns false immediately
- No retries — error appears after first attempt
- Action: Set "Max attempts" to
3, click Queue Task - Expected:
- Task is queued (log shows queued ID)
- Retry attempts stream in via log messages
- Succeeds on last attempt
- Action: Click Clear Logs
- Expected: All log entries clear
This is a documentation-focused demo explaining AIChatAgent.
- Action: Navigate to
/ai/chat - Expected:
- Feature cards display (Message Persistence, Stream Resumption, etc.)
- Setup requirements listed
- useAgentChat hook properties documented
Documentation demo for client-side tool execution.
- Action: Navigate to
/ai/tools - Expected:
- Explanation of server-side vs client-side tools
- Example flow with numbered steps
- Confirm/Cancel button mockup visible
Tests AI code generation and execution using the CodeAct pattern.
- Action: Navigate to
/ai/codemode - Expected: Connection status shows "Connected", empty state with "Try Codemode" prompt suggestions
- Action: Type "What is 17 + 25?" and press Enter
- Expected:
- User message appears on the right
- Assistant responds with a tool card showing code execution
- Expanding the tool card shows the generated code and result
- Text response includes the answer
- Action: Click on a collapsed tool card (e.g., "Ran code")
- Expected:
- Card expands to show Code, Result, and Console sections
- Code section shows the generated JavaScript
- Result shows the output
- Action: Send a message and observe
- Expected:
- Send button shows loading spinner during streaming
- Text streams in progressively
- Input is disabled while streaming
- Action: Click the trash icon
- Expected: All messages clear, returns to empty state
Documentation for creating MCP servers.
- Action: Navigate to
/mcp/server - Expected:
- What is MCP explanation
- Tools/Resources/Prompts feature cards
- How It Works steps
Documentation for connecting to MCP servers.
- Action: Navigate to
/mcp/client - Expected:
- API method cards (addMcpServer, mcp.listTools, etc.)
- Connection options code snippet
Documentation for OAuth authentication with MCP.
- Action: Navigate to
/mcp/oauth - Expected:
- OAuth flow steps listed
- Server states table (not-connected, authenticating, etc.)
- Client-side handling code snippet
- Action: Click the theme toggle in the sidebar footer
- Expected:
- Cycles through: System → Light → Dark → System
- UI immediately updates colors
- Background, cards, inputs, buttons all change
- Action: Set to Dark mode, refresh the page
- Expected: Dark mode persists (stored in localStorage)
- Action: Set to System, change OS dark mode setting
- Expected: App follows system preference
- Action: Click on a category header (e.g., "CORE")
- Expected: Category collapses/expands
- Action: Click on a demo link
- Expected: Link highlights with active styling
- Action: Click GitHub or Docs links in footer
- Expected: Opens in new tab
Present on all interactive demos (State, Callable, Streaming, Schedule, Connections, SQL, Routing, Readonly, Retry, Email Receive, Email Secure).
- Action: Trigger many events rapidly
- Expected: Log panel auto-scrolls to bottom
- Action: Click the trash icon
- Expected: All log entries clear, shows "No events yet"
- Expected Colors:
→(outgoing): Blue background←(incoming): Green background✕(error): Red background•(info): No background
- Action: Stop the dev server, refresh the page
- Expected: Connection status shows "Connecting..." indefinitely
- Action: Click Add with empty input
- Expected: Nothing happens (validation prevents empty items)
- Action: Enter "abc" in counter input, click Set
- Expected: Counter becomes
NaNor 0 (depending on parseInt behavior)
- Action: Add 100+ items via the State demo
- Expected:
- No UI lag
- State syncs correctly
- JSON display remains responsive
- Action: Click increment button rapidly (20+ times)
- Expected:
- All operations complete
- Final count is accurate
- Log shows all calls