"use client"; import { useState } from "react"; import { motion, AnimatePresence } from "framer-motion"; import { useSteppedVisualization } from "@/hooks/useSteppedVisualization"; import { StepControls } from "@/components/visualizations/shared/step-controls"; import { useSvgPalette } from "@/hooks/useDarkMode"; type Protocol = "shutdown" | "plan"; // -- Layout constants for the sequence diagram -- const SVG_W = 560; const SVG_H = 360; const LIFELINE_LEFT_X = 140; const LIFELINE_RIGHT_X = 420; const LIFELINE_TOP = 60; const LIFELINE_BOTTOM = 330; const ACTIVATION_W = 12; const ARROW_Y_START = 110; const ARROW_Y_GAP = 70; // Request ID shown on message tags const REQUEST_ID = "req_abc"; // -- Shutdown protocol step definitions -- const SHUTDOWN_STEPS = [ { title: "Structured Protocols", desc: "Protocols define structured message exchanges with correlated request IDs." }, { title: "Shutdown Request", desc: "The leader initiates shutdown. The request_id links the request to its response." }, { title: "Teammate Decides", desc: "The teammate can accept or reject. It's not a forced kill -- it's a polite request." }, { title: "Approved", desc: "Same request_id in the response. Teammate exits cleanly." }, ]; // -- Plan approval protocol step definitions -- const PLAN_STEPS = [ { title: "Plan Approval", desc: "Teammates in plan_mode must get approval before implementing changes." }, { title: "Submit Plan", desc: "The teammate designs a plan and sends it to the leader for review." }, { title: "Leader Reviews", desc: "Leader reviews and approves or rejects with feedback. Same request-response pattern." }, ]; // Horizontal arrow between lifelines function SequenceArrow({ y, direction, label, tagLabel, color, tagBg, tagStroke, tagText, }: { y: number; direction: "right" | "left"; label: string; tagLabel?: string; color: string; tagBg?: string; tagStroke?: string; tagText?: string; }) { const fromX = direction === "right" ? LIFELINE_LEFT_X + ACTIVATION_W / 2 : LIFELINE_RIGHT_X - ACTIVATION_W / 2; const toX = direction === "right" ? LIFELINE_RIGHT_X - ACTIVATION_W / 2 : LIFELINE_LEFT_X + ACTIVATION_W / 2; const arrowTip = direction === "right" ? toX - 6 : toX + 6; const labelX = (fromX + toX) / 2; return ( {/* Arrow line */} {/* Arrow head */} {/* Message label */} {label} {/* Request ID tag */} {tagLabel && ( {tagLabel} )} ); } // Decision diamond on a lifeline function DecisionBox({ x, y }: { x: number; y: number }) { const size = 14; return ( ? approve reject ); } // Activation bar on a lifeline function ActivationBar({ x, yStart, yEnd, color, }: { x: number; yStart: number; yEnd: number; color: string; }) { return ( ); } export default function TeamProtocols({ title }: { title?: string }) { const [protocol, setProtocol] = useState("shutdown"); const totalSteps = protocol === "shutdown" ? SHUTDOWN_STEPS.length : PLAN_STEPS.length; const steps = protocol === "shutdown" ? SHUTDOWN_STEPS : PLAN_STEPS; const vis = useSteppedVisualization({ totalSteps, autoPlayInterval: 2500 }); const step = vis.currentStep; const palette = useSvgPalette(); const switchProtocol = (p: Protocol) => { setProtocol(p); vis.reset(); }; const leftLabel = protocol === "shutdown" ? "Leader" : "Leader"; const rightLabel = protocol === "shutdown" ? "Teammate" : "Teammate"; return (

{title || "FSM Team Protocols"}

{/* Protocol toggle */}
{/* Sequence diagram SVG */} {/* Lifeline headers */} {leftLabel} {rightLabel} {/* Lifeline dashed lines */} {protocol === "shutdown" && ( {/* Activation bars appear as needed */} {step >= 1 && ( = 3 ? ARROW_Y_START + ARROW_Y_GAP * 2 + 20 : ARROW_Y_START + 30} color="#3b82f6" /> )} {step >= 1 && ( = 3 ? ARROW_Y_START + ARROW_Y_GAP * 2 + 15 : ARROW_Y_START + ARROW_Y_GAP + 20} color="#8b5cf6" /> )} {/* Step 1: shutdown_request arrow (Leader -> Teammate) */} {step >= 1 && ( )} {/* Step 2: decision box on teammate lifeline */} {step >= 2 && ( )} {/* Step 3: shutdown_response arrow (Teammate -> Leader) */} {step >= 3 && ( )} {/* Step 3: exit annotation */} {step >= 3 && ( exit )} )} {protocol === "plan" && ( {/* Activation bars */} {step >= 1 && ( = 2 ? ARROW_Y_START + ARROW_Y_GAP * 2 + 15 : ARROW_Y_START + 30} color="#8b5cf6" /> )} {step >= 1 && ( = 2 ? ARROW_Y_START + ARROW_Y_GAP * 2 + 15 : ARROW_Y_START + ARROW_Y_GAP + 10} color="#3b82f6" /> )} {/* Step 1: plan submission arrow (Teammate -> Leader) */} {step >= 1 && ( )} {/* Step 1: plan content box */} {step >= 1 && ( Plan: 1. Add error handler 2. Update tests 3. Refactor module )} {/* Step 2: approval response arrow (Leader -> Teammate) */} {step >= 2 && ( )} {/* Step 2: checkmark */} {step >= 2 && ( OK )} )} {/* Step controls */}
); }