import React, { useState, useEffect } from "react"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { ScrollArea } from "@/components/ui/scroll-area"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { Textarea } from "@/components/ui/textarea"; import { Button } from "@/components/ui/button"; import { Plus, Edit, Trash, Check, AlertCircle } from "lucide-react"; import { toolTemplates } from "@/lib/tool-templates"; import { ToolConfigurationDialog } from "./tool-configuration-dialog"; import { BackendTag } from "./backend-tag"; import { useBackendTools } from "@/lib/use-backend-tools"; interface SessionConfigurationPanelProps { callStatus: string; onSave: (config: any) => void; } const SessionConfigurationPanel: React.FC = ({ callStatus, onSave, }) => { const [instructions, setInstructions] = useState( "You are a helpful assistant in a phone call." ); const [voice, setVoice] = useState("ash"); const [tools, setTools] = useState([]); const [editingIndex, setEditingIndex] = useState(null); const [editingSchemaStr, setEditingSchemaStr] = useState(""); const [isJsonValid, setIsJsonValid] = useState(true); const [openDialog, setOpenDialog] = useState(false); const [selectedTemplate, setSelectedTemplate] = useState(""); const [saveStatus, setSaveStatus] = useState< "idle" | "saving" | "saved" | "error" >("idle"); const [hasUnsavedChanges, setHasUnsavedChanges] = useState(false); // Custom hook to fetch backend tools every 3 seconds const backendTools = useBackendTools("http://localhost:8081/tools", 3000); // Track changes to determine if there are unsaved modifications useEffect(() => { setHasUnsavedChanges(true); }, [instructions, voice, tools]); // Reset save status after a delay when saved useEffect(() => { if (saveStatus === "saved") { const timer = setTimeout(() => { setSaveStatus("idle"); }, 3000); return () => clearTimeout(timer); } }, [saveStatus]); const handleSave = async () => { setSaveStatus("saving"); try { await onSave({ instructions, voice, tools: tools.map((tool) => JSON.parse(tool)), }); setSaveStatus("saved"); setHasUnsavedChanges(false); } catch (error) { setSaveStatus("error"); } }; const handleAddTool = () => { setEditingIndex(null); setEditingSchemaStr(""); setSelectedTemplate(""); setIsJsonValid(true); setOpenDialog(true); }; const handleEditTool = (index: number) => { setEditingIndex(index); setEditingSchemaStr(tools[index] || ""); setSelectedTemplate(""); setIsJsonValid(true); setOpenDialog(true); }; const handleDeleteTool = (index: number) => { const newTools = [...tools]; newTools.splice(index, 1); setTools(newTools); }; const handleDialogSave = () => { try { JSON.parse(editingSchemaStr); } catch { return; } const newTools = [...tools]; if (editingIndex === null) { newTools.push(editingSchemaStr); } else { newTools[editingIndex] = editingSchemaStr; } setTools(newTools); setOpenDialog(false); }; const handleTemplateChange = (val: string) => { setSelectedTemplate(val); // Determine if the selected template is from local or backend let templateObj = toolTemplates.find((t) => t.name === val) || backendTools.find((t: any) => t.name === val); if (templateObj) { setEditingSchemaStr(JSON.stringify(templateObj, null, 2)); setIsJsonValid(true); } }; const onSchemaChange = (value: string) => { setEditingSchemaStr(value); try { JSON.parse(value); setIsJsonValid(true); } catch { setIsJsonValid(false); } }; const getToolNameFromSchema = (schema: string): string => { try { const parsed = JSON.parse(schema); return parsed?.name || "Untitled Tool"; } catch { return "Invalid JSON"; } }; const isBackendTool = (name: string): boolean => { return backendTools.some((t: any) => t.name === name); }; return (
Session Configuration
{saveStatus === "error" ? ( Save failed ) : hasUnsavedChanges ? ( Not saved ) : ( Saved )}