"use client" import { zodResolver } from "@hookform/resolvers/zod" import { useEffect, useMemo, useState } from "react" import { Resolver, useForm } from "react-hook-form" import { z } from "zod/v4" import { LoaderCircleIcon, PlayIcon } from "lucide-react" import { toast } from "sonner" import { ProjectDialog } from "@/components/project-dialog" import { OptionCombobox } from "@/components/option-combobox" import { Badge } from "@/components/ui/badge" import { Button } from "@/components/ui/button" import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" import { Field, FieldContent, FieldError, FieldLabel, } from "@/components/ui/field" import { Input } from "@/components/ui/input" import { Textarea } from "@/components/ui/textarea" import { debugResumeSkillDefinition, debugRunSkillDefinition, fetchAIAgentsAll, type AIAgent, type SkillDebugResumePayload, type SkillDebugRunPayload, type SkillDebugRunResult, } from "@/lib/api/admin" type DebugDialogProps = { open: boolean skillCode: string skillName: string onOpenChange: (open: boolean) => void } const debugFormSchema = z.object({ aiAgentId: z.string().trim().min(1, "请选择 AI Agent"), conversationId: z.string().trim(), userMessage: z.string().trim().min(1, "请输入用户消息"), }) type DebugForm = z.infer const debugFormResolver = zodResolver(debugFormSchema as never) as Resolver< z.input, undefined, z.output > const emptyForm: DebugForm = { aiAgentId: "", conversationId: "", userMessage: "", } const quickResumeActions = [ { label: "确认", value: "确认" }, { label: "取消", value: "取消" }, ] function ResultBlock({ title, value, emptyText = "暂无数据", }: { title: string value?: string emptyText?: string }) { return ( {title} {value ? (
            {value}
          
) : (
{emptyText}
)}
) } export function DebugDialog({ open, skillCode, skillName, onOpenChange, }: DebugDialogProps) { if (!open) { return null } return ( ) } function DebugDialogBody({ open, skillCode, skillName, onOpenChange, }: DebugDialogProps) { const formId = `skill-debug-form-${skillCode}` const [running, setRunning] = useState(false) const [resuming, setResuming] = useState(false) const [aiAgents, setAiAgents] = useState([]) const [result, setResult] = useState(null) const [resumeResult, setResumeResult] = useState(null) const [resumeMessage, setResumeMessage] = useState("") const form = useForm< z.input, undefined, z.output >({ resolver: debugFormResolver, defaultValues: emptyForm, }) const { handleSubmit, reset, register, setValue, watch, formState: { errors }, } = form const selectedAgentId = watch("aiAgentId") useEffect(() => { async function loadAIAgents() { try { const data = await fetchAIAgentsAll({ status: 1 }) setAiAgents(data) } catch (error) { console.error("Failed to load AI agents:", error) } } void loadAIAgents() }, []) useEffect(() => { if (!open) { return } reset(emptyForm) setResult(null) setResumeResult(null) setResumeMessage("") }, [open, reset]) useEffect(() => { if (!open || aiAgents.length === 0 || selectedAgentId) { return } setValue("aiAgentId", String(aiAgents[0].id), { shouldValidate: true }) }, [aiAgents, open, selectedAgentId, setValue]) const aiAgentOptions = useMemo( () => aiAgents.map((item) => ({ value: String(item.id), label: item.name, })), [aiAgents], ) const selectedAgent = useMemo( () => aiAgents.find((item) => String(item.id) === selectedAgentId) ?? null, [aiAgents, selectedAgentId], ) async function onSubmit(values: DebugForm) { const payload: SkillDebugRunPayload = { aiAgentId: Number(values.aiAgentId), skillCode, userMessage: values.userMessage.trim(), } const conversationId = Number(values.conversationId) if (conversationId > 0) { payload.conversationId = conversationId } setRunning(true) try { const data = await debugRunSkillDefinition(payload) setResult(data) setResumeResult(null) setResumeMessage("") } catch (error) { toast.error(error instanceof Error ? error.message : "Skill 调试失败") setResult(null) } finally { setRunning(false) } } async function handleResumeDebug(messageText?: string) { const nextMessage = (messageText ?? resumeMessage).trim() if (!result?.checkPointId || !result.interrupted) { return } if (!nextMessage) { toast.error("请输入恢复消息") return } const payload: SkillDebugResumePayload = { aiAgentId: Number(selectedAgentId || result.aiAgentId), checkPointId: result.checkPointId, userMessage: nextMessage, } const conversationId = result.conversationId || Number(watch("conversationId")) if (conversationId > 0) { payload.conversationId = conversationId } setResuming(true) try { const data = await debugResumeSkillDefinition(payload) setResumeResult(data) setResumeMessage(nextMessage) } catch (error) { toast.error(error instanceof Error ? error.message : "恢复调试失败") setResumeResult(null) } finally { setResuming(false) } } return ( } >
调试输入
AI Agent setValue("aiAgentId", value, { shouldValidate: true }) } /> Conversation ID
Skill 命中 Agent
用户消息