import { useAgent } from "agents/react"; import { useState } from "react"; import { Button, Input, Surface, Text } from "@cloudflare/kumo"; import { DemoWrapper } from "../../layout"; import { LogPanel, ConnectionStatus, CodeExplanation, HighlightedJson, type CodeSection } from "../../components"; import { useLogs, useUserId } from "../../hooks"; import type { PipelineOrchestratorAgent, PipelineState, PipelineResult } from "./pipeline-agent"; import type { StageResult } from "./stage-agents"; const codeSections: CodeSection[] = [ { title: "Chain agents into a pipeline", description: "Each stage processes data and passes it to the next agent via getAgentByName(). An orchestrator agent drives the pipeline and collects results from each stage.", code: `import { Agent, callable, getAgentByName } from "agents"; class PipelineOrchestratorAgent extends Agent { @callable() async runPipeline(input: string) { const stages = []; const validator = await getAgentByName( this.env.ValidatorStageAgent, "validator" ); const validated = await validator.process(input); stages.push(validated); const transformer = await getAgentByName( this.env.TransformStageAgent, "transformer" ); const transformed = await transformer.process(validated.output); stages.push(transformed); const enricher = await getAgentByName( this.env.EnrichStageAgent, "enricher" ); const enriched = await enricher.process(transformed.output); stages.push(enriched); return { input, stages }; } }` }, { title: "Stage agents are plain Durable Objects", description: "Each stage is a separate agent with a process() method. No @callable needed — the orchestrator calls them directly via Durable Object RPC. Each stage is isolated and independently scalable.", code: `class ValidatorStageAgent extends Agent { async process(input: string) { const trimmed = input.trim(); if (!trimmed) throw new Error("Input cannot be empty"); return { stage: "validate", input, output: { trimmed, lowercased: trimmed.toLowerCase() }, }; } } class TransformStageAgent extends Agent { async process(validated: { trimmed: string }) { return { stage: "transform", output: { uppercase: validated.trimmed.toUpperCase(), reversed: validated.trimmed.split("").reverse().join(""), }, }; } }` } ]; const PRESETS = [ "The quick brown fox jumps over the lazy dog", "Cloudflare Workers run at the edge", "Hello World from the Agents SDK" ]; const STAGE_LABELS: Record = { validate: "Validate", transform: "Transform", enrich: "Enrich" }; function StageCard({ stage }: { stage: StageResult }) { return (
{STAGE_LABELS[stage.stage] || stage.stage} {stage.duration}ms
); } export function PipelineDemo() { const userId = useUserId(); const { logs, addLog, clearLogs } = useLogs(); const [input, setInput] = useState(PRESETS[0]); const [isRunning, setIsRunning] = useState(false); const [lastRun, setLastRun] = useState(null); const agent = useAgent({ agent: "pipeline-orchestrator-agent", name: `pipeline-demo-${userId}`, onOpen: () => addLog("info", "connected"), onClose: () => addLog("info", "disconnected"), onError: () => addLog("error", "error", "Connection error"), onStateUpdate: (newState) => { if (newState?.lastRun) setLastRun(newState.lastRun); } }); const handleRun = async () => { if (!input.trim()) return; setIsRunning(true); addLog("out", "runPipeline", { input }); try { const result = await agent.call("runPipeline", [input]); const typed = result as PipelineResult; addLog("in", "result", { stages: typed.stages.length, totalMs: typed.totalDuration }); setLastRun(typed); } catch (e) { addLog("error", "error", e instanceof Error ? e.message : String(e)); } finally { setIsRunning(false); } }; return ( Data flows through a chain of agents, each performing a specific transformation and passing the result to the next stage via{" "} getAgentByName() . Each stage is a separate Durable Object, so stages are isolated and independently scalable. Enter some text and run it through the validate, transform, enrich pipeline. } statusIndicator={ } >
{/* Controls */}
{/* Input */}
Pipeline Input
) => setInput(e.target.value) } onKeyDown={(e: React.KeyboardEvent) => e.key === "Enter" && handleRun() } className="w-full mb-3" placeholder="Enter text to process..." />
{PRESETS.map((preset, i) => ( ))}
{/* Pipeline visualization */}
Pipeline Stages {lastRun && ( {lastRun.totalDuration}ms total )}
{/* Stage flow diagram */}
Validate Transform Enrich
{lastRun ? (
{lastRun.stages.map((stage) => ( ))}
) : (

Run the pipeline to see stage results

)}
{/* Logs */}
); }