import React, { useState } from 'react'; import { useCreateAgent, type CreateAgentPayload } from '../hooks/useAgents'; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter, } from '../ui/dialog'; import { Button } from '../ui/button'; import { Input } from '../ui/input'; import { Textarea } from '../ui/textarea'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../ui/select'; import { AlertCircle, Loader2, Eye, EyeOff, Info } from 'lucide-react'; import { LLM_PROVIDERS } from '@dexto/core'; interface CreateAgentModalProps { open: boolean; onOpenChange: (open: boolean) => void; onAgentCreated?: (agentName: string) => void; } interface FormData { id: string; idManuallyEdited: boolean; name: string; description: string; provider: string; model: string; apiKey: string; systemPrompt: string; } const initialFormData: FormData = { id: '', idManuallyEdited: false, name: '', description: '', provider: 'anthropic', model: 'claude-sonnet-4-5-20250929', apiKey: '', systemPrompt: '', }; // Convert name to a valid ID (lowercase, hyphens, no special chars) function nameToId(name: string): string { return name .toLowerCase() .trim() .replace(/[^a-z0-9\s-]/g, '') // Remove special chars .replace(/\s+/g, '-') // Spaces to hyphens .replace(/-+/g, '-') // Multiple hyphens to single .replace(/^-|-$/g, ''); // Trim leading/trailing hyphens } export default function CreateAgentModal({ open, onOpenChange, onAgentCreated, }: CreateAgentModalProps) { const [form, setForm] = useState(initialFormData); const [errors, setErrors] = useState>({}); const [createError, setCreateError] = useState(null); const [showApiKey, setShowApiKey] = useState(false); const createAgentMutation = useCreateAgent(); const isCreating = createAgentMutation.isPending; const updateField = (field: keyof FormData, value: string) => { setForm((prev) => { const next = { ...prev, [field]: value }; // Auto-generate ID from name if ID hasn't been manually edited if (field === 'name' && !prev.idManuallyEdited) { next.id = nameToId(value); } // Mark ID as manually edited if user types in it if (field === 'id') { next.idManuallyEdited = true; } return next; }); if (errors[field]) { setErrors((prev) => { const next = { ...prev }; delete next[field]; return next; }); } }; const validateForm = (): boolean => { const newErrors: Record = {}; if (!form.id.trim()) { newErrors.id = 'Required'; } else if (!/^[a-z0-9-]+$/.test(form.id)) { newErrors.id = 'Lowercase letters, numbers, and hyphens only'; } if (!form.name.trim()) { newErrors.name = 'Required'; } if (!form.description.trim()) { newErrors.description = 'Required'; } if (!form.provider) { newErrors.provider = 'Required'; } if (!form.model.trim()) { newErrors.model = 'Required'; } setErrors(newErrors); return Object.keys(newErrors).length === 0; }; const handleCreate = async () => { if (!validateForm()) return; setCreateError(null); const payload: CreateAgentPayload = { id: form.id.trim(), name: form.name.trim(), description: form.description.trim(), config: { llm: { provider: form.provider as CreateAgentPayload['config']['llm']['provider'], model: form.model.trim(), apiKey: form.apiKey.trim() || undefined, }, ...(form.systemPrompt.trim() && { systemPrompt: { contributors: [ { id: 'primary', type: 'static' as const, priority: 0, enabled: true, content: form.systemPrompt.trim(), }, ], }, }), }, }; createAgentMutation.mutate(payload, { onSuccess: (data) => { setForm(initialFormData); setErrors({}); onOpenChange(false); if (onAgentCreated && data.id) { onAgentCreated(data.id); } }, onError: (error: Error) => { setCreateError(error.message); }, }); }; const handleCancel = () => { setForm(initialFormData); setErrors({}); setCreateError(null); onOpenChange(false); }; return ( Create Agent Configure your new agent. Advanced options can be set after creation. {/* Error */} {createError && (

{createError}

)} {/* Form */}
{/* Identity */}
updateField('name', e.target.value)} placeholder="My Agent" aria-invalid={!!errors.name} /> updateField('id', e.target.value)} placeholder="my-agent" aria-invalid={!!errors.id} className="font-mono text-sm" /> updateField('description', e.target.value)} placeholder="A helpful assistant for..." aria-invalid={!!errors.description} />
{/* Model */}
updateField('model', e.target.value)} placeholder="claude-sonnet-4-5-20250929" aria-invalid={!!errors.model} />
updateField('apiKey', e.target.value)} placeholder="$ANTHROPIC_API_KEY" className="pr-9" />
{/* System Prompt */}