"use client"; import { CopilotKit, useCoAgent } from "@copilotkit/react-core"; import { CopilotChat } from "@copilotkit/react-ui"; import "@copilotkit/react-ui/styles.css"; import { useState, useEffect } from "react"; import DocumentSelector from "./DocumentSelector"; import StateDisplay from "./StateDisplay"; interface Citation { document_id: string; chunk_id: string; document_uri: string; document_title?: string; page_numbers: number[]; headings?: string[]; content: string; } interface SearchAnswer { query: string; answer: string; confidence: number; cited_chunks: string[]; citations: Citation[]; } interface ResearchContext { original_question: string; sub_questions: string[]; qa_responses: SearchAnswer[]; } interface EvaluationResult { new_questions: string[]; confidence_score: number; is_sufficient: boolean; reasoning: string; } interface ResearchReport { title: string; executive_summary: string; main_findings: string[]; conclusions: string[]; limitations: string[]; recommendations: string[]; sources_summary: string; } interface ResearchState { context: ResearchContext; iterations: number; max_iterations: number; confidence_threshold: number; max_concurrency: number; last_eval: EvaluationResult | null; result?: ResearchReport; current_activity?: string; current_activity_message?: string; documentFilter?: string[]; awaiting_decision?: boolean; } function AgentContent() { const { state, setState, running } = useCoAgent({ name: "research_agent", initialState: { context: { original_question: "", sub_questions: [], qa_responses: [], }, iterations: 0, max_iterations: 3, confidence_threshold: 0.8, max_concurrency: 1, last_eval: null, documentFilter: [], awaiting_decision: false, }, }); const [editableQuestions, setEditableQuestions] = useState([]); const [newQuestion, setNewQuestion] = useState(""); const [submitting, setSubmitting] = useState(false); // Sync editable questions when state changes useEffect(() => { if (state.awaiting_decision && state.context.sub_questions) { setEditableQuestions([...state.context.sub_questions]); } }, [state.awaiting_decision, state.context.sub_questions]); const handleDocumentFilterChange = (ids: string[]) => { setState({ ...state, documentFilter: ids }); }; const handleRemoveQuestion = (index: number) => { setEditableQuestions(editableQuestions.filter((_, i) => i !== index)); }; const handleAddQuestion = () => { if (newQuestion.trim()) { setEditableQuestions([...editableQuestions, newQuestion.trim()]); setNewQuestion(""); } }; const handleDecision = async (action: "search" | "synthesize") => { setSubmitting(true); try { const response = await fetch( `${process.env.NEXT_PUBLIC_API_URL || "http://localhost:8000"}/v1/research/decide`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ thread_id: state.context.original_question, // Use as identifier action, questions: editableQuestions, }), } ); if (response.ok) { setState({ ...state, awaiting_decision: false }); } } catch (error) { console.error("Failed to send decision:", error); } finally { setSubmitting(false); } }; return ( <>
{/* Chat on the left */}
{/* State display on the right */}

Research State

Live updates from the research agent

{/* Document filter - hidden when research is running */} {!running && (
)} {/* Decision UI when awaiting human input - hidden when report exists, submitting, or not running */} {state.awaiting_decision && !submitting && !state.result && running && (
Research Decision Point
{state.context.qa_responses?.length || 0} answers collected | Iteration {state.iterations || 0}
{/* Questions list */}
Pending Questions ({editableQuestions.length}):
{editableQuestions.map((q, idx) => (
{q}
))}
{/* Add question input */}
setNewQuestion(e.target.value)} placeholder="Add a new question..." disabled={submitting} style={{ flex: 1, padding: "0.5rem", border: "1px solid #cbd5e1", borderRadius: "4px", fontSize: "0.85rem", }} onKeyDown={(e) => { if (e.key === "Enter") { handleAddQuestion(); } }} />
{/* Action buttons */}
)}
); } export default function Agent() { return ( ); }