import { useCallback, useEffect, useMemo } from "react"; import { Loader2, AlertCircle } from "lucide-react"; import { Button } from "@/components/ui/button"; import { QuestionForm } from "@/components/QuestionForm"; import { ChangeSetBanner } from "@/components/ChangeSetBanner"; import { RefineSpawnDialog } from "../RefineSpawnDialog"; import { useRefineAgent } from "@/hooks"; function extractInstruction(prompt: string | null | undefined): string | undefined { if (!prompt) return undefined; const match = prompt.match(/\n([\s\S]*?)\n<\/user_instruction>/); return match?.[1] || undefined; } interface RefineAgentPanelProps { initiativeId: string; } export function RefineAgentPanel({ initiativeId }: RefineAgentPanelProps) { // All agent logic is now encapsulated in the hook const { state, agent, questions, changeSet, spawn, resume, stop, dismiss, refresh } = useRefineAgent(initiativeId); // spawn.mutate and resume.mutate are stable (ref-backed in useRefineAgent), // so these callbacks won't change on every render. const handleSpawn = useCallback((instruction?: string) => { spawn.mutate({ initiativeId, instruction, }); }, [initiativeId, spawn.mutate]); const handleAnswerSubmit = useCallback( (answers: Record) => { resume.mutate(answers); }, [resume.mutate], ); const handleDismiss = useCallback(() => { dismiss(); }, [dismiss]); // Cmd+Enter (Mac) / Ctrl+Enter (Windows) dismisses when completed useEffect(() => { if (state !== "completed") return; const handler = (e: KeyboardEvent) => { if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) { e.preventDefault(); handleDismiss(); } }; window.addEventListener("keydown", handler); return () => window.removeEventListener("keydown", handler); }, [state, handleDismiss]); // No active agent — show spawn button if (state === "none") { return (
); } // Running if (state === "running") { const runningLabel = agent?.mode === 'discuss' ? 'Architect is discussing...' : 'Architect is refining...'; return (
{runningLabel}
); } // Waiting for input — show inline questions if (state === "waiting" && questions) { return (

Agent has questions

{ // Can't cancel mid-question — just dismiss }} onDismiss={() => stop.mutate()} isSubmitting={resume.isPending} isDismissing={stop.isPending} />
); } // Completed with change set if (state === "completed" && changeSet) { return (
); } // Completed without changes if (state === "completed") { return (
Agent completed — no changes made.
); } // Crashed const crashedInstruction = useMemo( () => (state === "crashed" ? extractInstruction(agent?.prompt) : undefined), [state, agent?.prompt], ); if (state === "crashed") { return (
Agent crashed Retry } />
); } return null; }