// Copyright (c) 2025 Bytedance Ltd. and/or its affiliates // SPDX-License-Identifier: MIT "use client"; import { ReactFlow, Background, Handle, Position, type Edge, type ReactFlowInstance, } from "@xyflow/react"; import { Play, type LucideIcon, ChevronRight, ChevronLeft, Pause, Fullscreen, Minimize, } from "lucide-react"; import "@xyflow/react/dist/style.css"; import { useCallback, useRef, useState } from "react"; import { Tooltip } from "~/components/deer-flow/tooltip"; import { ShineBorder } from "~/components/magicui/shine-border"; import { Button } from "~/components/ui/button"; import { Slider } from "~/components/ui/slider"; import { useIntersectionObserver } from "~/hooks/use-intersection-observer"; import { cn } from "~/lib/utils"; import { playbook, type GraphNode } from "../store"; import { activateStep, nextStep, play, prevStep, togglePlay, useMAVStore, } from "../store/mav-store"; const nodeTypes = { circle: CircleNode, agent: AgentNode, default: AgentNode, }; export function MultiAgentVisualization({ className }: { className?: string }) { const { graph: { nodes, edges }, activeStepIndex, playing, } = useMAVStore((state) => state); const flowRef = useRef>(null); const containerRef = useRef(null); const [hasPlayed, setHasPlayed] = useState(false); const [fullscreen, setFullscreen] = useState(false); const { ref: anchorRef } = useIntersectionObserver({ rootMargin: "0%", threshold: 0, onChange: (isIntersecting) => { if (isIntersecting && !playing && !hasPlayed) { setHasPlayed(true); void play(); } }, }); const toggleFullscreen = useCallback(async () => { if (containerRef.current) { if (!document.fullscreenElement) { setFullscreen(true); await containerRef.current.requestFullscreen(); setTimeout(() => { void flowRef.current?.fitView({ maxZoom: 2.5 }); }, 100); } else { setFullscreen(false); await document.exitFullscreen(); setTimeout(() => { void flowRef.current?.fitView(); }, 100); } } }, []); return (
{ flowRef.current = instance; }} >
= 0 ? activeStepIndex : 0]} onValueChange={([value]) => { setHasPlayed(true); activateStep(value!); }} />
); } function CircleNode({ data }: { data: { label: string; active: boolean } }) { return ( <> {data.active && ( )}

{data.label}

{data.label === "Start" && ( )} {data.label === "End" && ( )} ); } function AgentNode({ data, id, }: { data: { icon?: LucideIcon; label: string; active: boolean; stepDescription?: string; stepTooltipPosition?: "left" | "right" | "top" | "bottom"; }; id: string; }) { return ( <> {data.active && ( )}
{data.icon && } {data.label}
); }