import React, { useState } from 'react'; import { zodResolver } from "@hookform/resolvers/zod"; import { useForm } from "react-hook-form"; import { z } from "zod"; import { Loader2, Bot, Wand2 } from 'lucide-react'; import { Button } from "@/components/ui/button"; import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogFooter, } from "@/components/ui/dialog"; import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, } from "@/components/ui/form"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { Textarea } from "@/components/ui/textarea"; import { personasApi } from '@/lib/api'; import { toastService } from '@/lib/toast'; import { useCancellableGeneration } from '@/hooks/useCancellableGeneration'; import { getSocket } from '@/services/websocketServiceNew'; import GenerationProgressBar from '@/components/ui/GenerationProgressBar'; import { Persona } from '@/types/persona'; const modificationFormSchema = z.object({ modificationPrompt: z.string().min(10, { message: "Modification prompt must be at least 10 characters long.", }), llm_model: z.string().min(1, { message: "Please select an AI model.", }), reasoning_effort: z.string().optional(), verbosity: z.string().optional(), }); type ModificationFormData = z.infer; interface PersonaModificationModalProps { persona: Persona; isOpen: boolean; onClose: () => void; onPersonaPreview: (modifiedPersona: Persona) => void; } export default function PersonaModificationModal({ persona, isOpen, onClose, onPersonaPreview }: PersonaModificationModalProps) { // Cancellable generation for persona modification const socket = getSocket(); const [modificationState, modificationControls] = useCancellableGeneration('persona modification', socket); const form = useForm({ resolver: zodResolver(modificationFormSchema), defaultValues: { modificationPrompt: "", llm_model: "gemini-3-pro-preview", reasoning_effort: "medium", verbosity: "medium", }, }); const handleClose = () => { if (modificationState.isGenerating) return; // Prevent closing while processing form.reset(); modificationControls.resetGeneration(); onClose(); }; const onSubmit = async (values: ModificationFormData) => { modificationControls.startGeneration(); try { toastService.info("Generating persona preview...", { description: `Using ${values.llm_model} to create a preview of your modifications` }); // Use the persona's MongoDB _id or fallback to id const personaId = persona._id || persona.id; const response = await personasApi.modifyWithAI(personaId, { modification_prompt: values.modificationPrompt, llm_model: values.llm_model, reasoning_effort: values.reasoning_effort || 'medium', verbosity: values.verbosity || 'medium', preview_only: true }); // Set task ID if available if (response.data?.task_id) { modificationControls.setTaskId(response.data.task_id); } if (response.data && response.data.persona) { modificationControls.completeGeneration(); toastService.success("Preview generated successfully!", { description: `Ready to review proposed changes to ${persona.name}` }); onPersonaPreview(response.data.persona); handleClose(); } else { throw new Error("Invalid response from server"); } } catch (error: any) { // Check if this was a cancellation if (error.response?.status === 499) { return; } console.error("Error generating persona preview:", error); modificationControls.failGeneration(error.message || 'Failed to generate preview'); if (error.response) { const errorMessage = error.response.data?.error || "Server error occurred"; toastService.error("Failed to generate preview", { description: errorMessage }); } else if (error.request) { toastService.error("Network error", { description: "Unable to connect to the server" }); } else { toastService.error("Preview generation failed", { description: error.message || "An unexpected error occurred" }); } } }; return ( Modify Persona with Natural Language Describe the changes you'd like to make to {persona.name}, and AI will modify the persona data accordingly. {/* Progress Bar for persona modification */} {modificationState.isGenerating && (
)}
{/* Modification Prompt */} ( Modification Instructions