"use client"; import { motion, AnimatePresence } from "framer-motion"; import { useSteppedVisualization } from "@/hooks/useSteppedVisualization"; import { StepControls } from "@/components/visualizations/shared/step-controls"; import { useSvgPalette } from "@/hooks/useDarkMode"; // -- Layout constants -- const SVG_W = 560; const SVG_H = 340; const AGENT_R = 40; // Agent positions: inverted triangle (Lead top-center, Coder bottom-left, Reviewer bottom-right) const AGENTS = [ { id: "lead", label: "Lead", cx: SVG_W / 2, cy: 70, inbox: "lead.jsonl" }, { id: "coder", label: "Coder", cx: 140, cy: 230, inbox: "coder.jsonl" }, { id: "reviewer", label: "Reviewer", cx: SVG_W - 140, cy: 230, inbox: "reviewer.jsonl" }, ] as const; // Inbox tray dimensions, positioned below each agent circle const TRAY_W = 72; const TRAY_H = 22; const TRAY_OFFSET_Y = AGENT_R + 14; // Message block dimensions const MSG_W = 60; const MSG_H = 20; function agentById(id: string) { return AGENTS.find((a) => a.id === id)!; } function trayCenter(id: string) { const a = agentById(id); return { x: a.cx, y: a.cy + TRAY_OFFSET_Y + TRAY_H / 2 }; } // Step configuration const STEPS = [ { title: "The Team", desc: "Teams use a leader-worker pattern. Each teammate has a file-based mailbox inbox." }, { title: "Lead Assigns Work", desc: "Communication is async: write a message to the recipient's .jsonl inbox file." }, { title: "Read Inbox", desc: "Teammates poll their inbox before each LLM call. New messages become context." }, { title: "Independent Work", desc: "Each teammate runs its own agent loop independently." }, { title: "Pass Result", desc: "Results flow through the same mailbox mechanism. All communication is via files." }, { title: "Feedback Loop", desc: "The mailbox pattern supports any communication topology: linear, broadcast, round-robin." }, { title: "File-Based Coordination", desc: "No shared memory, no locks. All coordination through append-only files. Simple, robust, debuggable." }, ]; // Helper: determine which agent glows at each step function agentGlows(agentId: string, step: number): boolean { if (step === 1 && agentId === "lead") return true; if (step === 2 && agentId === "coder") return true; if (step === 3 && agentId === "coder") return true; if (step === 4 && agentId === "coder") return true; if (step === 5 && agentId === "reviewer") return true; return false; } // Helper: determine which inbox tray has a message sitting in it function trayHasMessage(agentId: string, step: number): boolean { if (step === 2 && agentId === "coder") return true; if (step === 4 && agentId === "reviewer") return false; if (step === 5 && agentId === "reviewer") return true; return false; } // Animated message that travels from one point to another function TravelingMessage({ fromX, fromY, toX, toY, label, delay = 0, }: { fromX: number; fromY: number; toX: number; toY: number; label: string; delay?: number; }) { return ( {label} ); } // Faded trace line between two agents function TraceLine({ from, to, strokeColor }: { from: string; to: string; strokeColor: string }) { const f = trayCenter(from); const t = trayCenter(to); return ( ); } export default function AgentTeams({ title }: { title?: string }) { const vis = useSteppedVisualization({ totalSteps: STEPS.length, autoPlayInterval: 2500 }); const step = vis.currentStep; const palette = useSvgPalette(); return ( {title || "Agent Team Mailboxes"} {/* SVG visualization */} {/* Step 6: trace lines */} {step === 6 && ( <> > )} {/* Agent nodes */} {AGENTS.map((agent) => { const glowing = agentGlows(agent.id, step); const pulsing = step === 3 && agent.id === "coder"; return ( {/* Agent circle */} {/* Agent label */} {agent.label} {/* Inbox tray (file icon style) */} {agent.inbox} ); })} {/* Step 0: team config card */} {step === 0 && ( team.config workers: [coder, reviewer] )} {/* Step 1: message from Lead to Coder inbox */} {step === 1 && ( )} {/* Step 2: message from Coder inbox to Coder circle */} {step === 2 && ( )} {/* Step 3: Coder working, result appears */} {step === 3 && ( result:done )} {/* Step 4: Coder result message travels to Reviewer inbox */} {step === 4 && ( )} {/* Step 5: Reviewer reads inbox, sends feedback to Lead */} {step === 5 && ( <> > )} {/* Step 6: filesystem tree */} {step === 6 && ( .claude/teams/project/ lead.jsonl coder.jsonl reviewer.jsonl )} {/* Step controls */} ); }