From f0eb694803c0818287ea8a830f89ea0cba014de8 Mon Sep 17 00:00:00 2001 From: mlogclub Date: Mon, 22 Jun 2026 12:03:48 +0800 Subject: [PATCH] refactor: use config workbench for AI agent creation --- .../_components/config-workbench.tsx | 87 +- .../dashboard/ai-agents/_components/edit.tsx | 1299 ----------------- web/app/dashboard/ai-agents/page.tsx | 27 +- .../dashboard/crud/dashboard-crud-page.tsx | 8 +- 4 files changed, 84 insertions(+), 1337 deletions(-) delete mode 100644 web/app/dashboard/ai-agents/_components/edit.tsx diff --git a/web/app/dashboard/ai-agents/_components/config-workbench.tsx b/web/app/dashboard/ai-agents/_components/config-workbench.tsx index a47c893..93f11a3 100644 --- a/web/app/dashboard/ai-agents/_components/config-workbench.tsx +++ b/web/app/dashboard/ai-agents/_components/config-workbench.tsx @@ -26,6 +26,7 @@ import { Input } from "@/components/ui/input" import { Label } from "@/components/ui/label" import { Textarea } from "@/components/ui/textarea" import { + createAIAgent, fetchAIAgent, fetchAIAgentWorkflow, fetchAIConfigsAll, @@ -114,10 +115,13 @@ function uniqueNumbers(input: number[]) { export function AIAgentConfigWorkbench({ agentId, onAgentSaved, + onAgentCreated, }: { - agentId: number + agentId?: number | null onAgentSaved?: () => void + onAgentCreated?: (agent: AIAgent) => void }) { + const [currentAgentId, setCurrentAgentId] = useState(agentId ?? null) const [activeSection, setActiveSection] = useState("basic") const [agent, setAgent] = useState(null) const [workflow, setWorkflow] = useState(null) @@ -162,16 +166,14 @@ export function AIAgentConfigWorkbench({ [workflow?.id, workflow?.updatedAt] ) + useEffect(() => { + setCurrentAgentId(agentId ?? null) + }, [agentId]) + const loadData = useCallback(async () => { - if (!Number.isFinite(agentId) || agentId <= 0) { - setLoading(false) - return - } setLoading(true) try { const [ - agentDetail, - workflowDetail, specs, configs, bases, @@ -179,8 +181,6 @@ export function AIAgentConfigWorkbench({ skillList, catalog, ] = await Promise.all([ - fetchAIAgent(agentId), - fetchAIAgentWorkflow(agentId), fetchAIWorkflowNodeSpecs(), fetchAIConfigsAll({ modelType: AIModelType.LLM }), fetchKnowledgeBasesAll({ status: Status.Ok }), @@ -189,14 +189,44 @@ export function AIAgentConfigWorkbench({ fetchMCPCatalog(), ]) - setAgent(agentDetail) - setWorkflow(workflowDetail) setNodeSpecs(specs ?? []) setAIConfigs(configs ?? []) setKnowledgeBases(bases ?? []) setAgentTeams(teams ?? []) setSkills(skillList ?? []) setToolCatalog(catalog ?? []) + + if (!currentAgentId || currentAgentId <= 0) { + setAgent(null) + setWorkflow(null) + setName("") + setDescription("") + setAIConfigId("") + setServiceMode(String(IMConversationServiceMode.AIFirst)) + setSystemPrompt("") + setWelcomeMessage("") + setReplyTimeoutSeconds("180") + setHandoffMode(String(AIAgentHandoffMode.WaitPool)) + setFallbackMode(String(AIAgentFallbackMode.NoAnswer)) + setFallbackMessage("") + setSelectedKnowledgeIds([]) + setSelectedTeamIds([]) + setSelectedSkillIds([]) + setDirectTools([]) + setWorkflowName("新建 Agent 会话流程") + setWorkflowDescription("") + setDefinition(emptyDefinition) + setValidation(null) + return + } + + const [agentDetail, workflowDetail] = await Promise.all([ + fetchAIAgent(currentAgentId), + fetchAIAgentWorkflow(currentAgentId), + ]) + + setAgent(agentDetail) + setWorkflow(workflowDetail) setName(agentDetail.name) setDescription(agentDetail.description || "") setAIConfigId(toText(agentDetail.aiConfigId)) @@ -220,7 +250,7 @@ export function AIAgentConfigWorkbench({ } finally { setLoading(false) } - }, [agentId]) + }, [currentAgentId]) useEffect(() => { void loadData() @@ -361,13 +391,20 @@ export function AIAgentConfigWorkbench({ } async function saveAgentSettings() { - if (!agent) return setSavingAgent(true) try { const payload = buildPayload() - await updateAIAgent({ id: agent.id, ...payload }) - toast.success("Agent config saved") - await loadData() + if (agent) { + await updateAIAgent({ id: agent.id, ...payload }) + toast.success("Agent config saved") + await loadData() + } else { + const created = await createAIAgent(payload) + setCurrentAgentId(created.id) + setAgent(created) + toast.success("Agent created") + onAgentCreated?.(created) + } onAgentSaved?.() } catch (error) { toast.error(error instanceof Error ? error.message : "Failed to save Agent config") @@ -377,10 +414,11 @@ export function AIAgentConfigWorkbench({ } async function saveWorkflowDraft() { + if (!currentAgentId) return setSavingWorkflow(true) try { const saved = await saveAIAgentWorkflow({ - agentId, + agentId: currentAgentId, name: workflowName, description: workflowDescription, definition, @@ -410,15 +448,16 @@ export function AIAgentConfigWorkbench({ } async function publishWorkflow() { + if (!currentAgentId) return setSavingWorkflow(true) try { await saveAIAgentWorkflow({ - agentId, + agentId: currentAgentId, name: workflowName, description: workflowDescription, definition, }) - const version = await publishAIAgentWorkflow(agentId, definition) + const version = await publishAIAgentWorkflow(currentAgentId, definition) toast.success(`Published version ${version.version}`) await loadData() onAgentSaved?.() @@ -452,7 +491,7 @@ export function AIAgentConfigWorkbench({
-

{agent?.name ?? "AI Agent 配置"}

+

{agent?.name ?? "新建 AI Agent"}

{agent?.statusName ? {agent.statusName} : null} {agent?.workflowVersionId ? 已发布流程 : 草稿流程} @@ -464,7 +503,7 @@ export function AIAgentConfigWorkbench({ 保存 - @@ -690,15 +729,15 @@ export function AIAgentConfigWorkbench({ {validation.valid ? "校验通过" : `${validation.errors.length} 个问题`} ) : null} - - - diff --git a/web/app/dashboard/ai-agents/_components/edit.tsx b/web/app/dashboard/ai-agents/_components/edit.tsx deleted file mode 100644 index 8ac111a..0000000 --- a/web/app/dashboard/ai-agents/_components/edit.tsx +++ /dev/null @@ -1,1299 +0,0 @@ -"use client"; - -import { zodResolver } from "@hookform/resolvers/zod"; -import { - ArrowDownIcon, - ArrowUpIcon, - ChevronDownIcon, - InfoIcon, - PlusIcon, - Trash2Icon, -} from "lucide-react"; -import { useEffect, useMemo, useState, type ReactNode } from "react"; -import { Controller, Resolver, useForm } from "react-hook-form"; -import { toast } from "sonner"; -import { z } from "zod/v4"; - -import { OptionCombobox } from "@/components/option-combobox"; -import { ProjectDialog } from "@/components/project-dialog"; -import { Badge } from "@/components/ui/badge"; -import { Button } from "@/components/ui/button"; -import { - Field, - FieldContent, - FieldError, - FieldLabel, -} from "@/components/ui/field"; -import { Input } from "@/components/ui/input"; -import { - Popover, - PopoverContent, - PopoverDescription, - PopoverTrigger, -} from "@/components/ui/popover"; -import { - Tabs, - TabsContent, - TabsList, - TabsTrigger, -} from "@/components/ui/tabs"; -import { Textarea } from "@/components/ui/textarea"; -import { - fetchAIAgent, - fetchAIConfigsAll, - fetchAgentTeamsAll, - fetchKnowledgeBasesAll, - fetchMCPCatalog, - fetchSkillDefinitionsAll, - type AIAgent, - type AIConfig, - type AdminAgentTeam, - type CreateAIAgentPayload, - type KnowledgeBase, - type MCPToolCatalogItem, - type MCPToolSourceType, - type SkillDefinition, -} from "@/lib/api/admin"; -import { useI18n } from "@/i18n/provider"; -import { - AIAgentFallbackMode, - AIAgentHandoffMode, - AIModelType, - IMConversationServiceMode, - Status, -} from "@/lib/generated/enums"; - -type DirectToolItem = CreateAIAgentPayload["directTools"][number]; - -type DirectToolOption = { - value: string; - label: string; - meta: DirectToolItem; - sourceType: MCPToolSourceType; - autoInjected: boolean; - groupLabel: string; -}; - -type GraphToolOption = { - value: string; - label: string; -}; - -type EditDialogProps = { - open: boolean; - saving: boolean; - itemId: number | null; - onOpenChange: (open: boolean) => void; - onSubmit: (payload: CreateAIAgentPayload) => Promise; -}; - -type TFunction = (key: string, values?: Record) => string; - -type EditForm = { - name: string; - description: string; - aiConfigId: string; - serviceMode: string; - systemPrompt: string; - welcomeMessage: string; - replyTimeoutSeconds: number; - handoffMode: string; - fallbackMode: string; - fallbackMessage: string; -}; - -function getServiceModeOptions(t: TFunction) { - return [ - { value: String(IMConversationServiceMode.AIOnly), label: t("aiAgent.serviceAiOnly") }, - { value: String(IMConversationServiceMode.HumanOnly), label: t("aiAgent.serviceHumanOnly") }, - { value: String(IMConversationServiceMode.AIFirst), label: t("aiAgent.serviceAiFirst") }, - ]; -} - -function getHandoffModeOptions(t: TFunction) { - return [ - { value: String(AIAgentHandoffMode.WaitPool), label: t("aiAgent.handoffWaitPool") }, - { value: String(AIAgentHandoffMode.DefaultTeamPool), label: t("aiAgent.handoffDefaultTeamPool") }, - { value: String(AIAgentHandoffMode.AIHoldAndNotify), label: t("aiAgent.handoffAiHoldAndNotify") }, - ]; -} - -function getFallbackModeOptions(t: TFunction) { - return [ - { value: String(AIAgentFallbackMode.NoAnswer), label: t("aiAgent.fallbackNoAnswer") }, - { value: String(AIAgentFallbackMode.SuggestRetry), label: t("aiAgent.fallbackSuggestRetry") }, - ]; -} - -function buildForm(item: AIAgent | null): EditForm { - if (!item) { - return { - name: "", - description: "", - aiConfigId: "", - serviceMode: String(IMConversationServiceMode.AIFirst), - systemPrompt: "", - welcomeMessage: "", - replyTimeoutSeconds: 180, - handoffMode: String(AIAgentHandoffMode.WaitPool), - fallbackMode: String(AIAgentFallbackMode.NoAnswer), - fallbackMessage: "", - }; - } - return { - name: item.name, - description: item.description || "", - aiConfigId: item.aiConfigId > 0 ? String(item.aiConfigId) : "", - serviceMode: String(item.serviceMode), - systemPrompt: item.systemPrompt || "", - welcomeMessage: item.welcomeMessage || "", - replyTimeoutSeconds: item.replyTimeoutSeconds ?? 180, - handoffMode: String(item.handoffMode), - fallbackMode: String(item.fallbackMode), - fallbackMessage: item.fallbackMessage || "", - }; -} - -function buildPayload( - form: EditForm, - knowledgeIds: number[], - teamIds: number[], - skillIds: number[], - directTools: CreateAIAgentPayload["directTools"], - graphTools: CreateAIAgentPayload["graphTools"], -): CreateAIAgentPayload { - return { - name: form.name.trim(), - description: form.description.trim(), - aiConfigId: Number(form.aiConfigId), - serviceMode: Number(form.serviceMode), - systemPrompt: form.systemPrompt.trim(), - welcomeMessage: form.welcomeMessage.trim(), - replyTimeoutSeconds: Number(form.replyTimeoutSeconds), - teamIds, - handoffMode: Number(form.handoffMode), - fallbackMode: Number(form.fallbackMode), - fallbackMessage: form.fallbackMessage.trim(), - knowledgeIds, - skillIds, - directTools, - graphTools, - }; -} - -export function EditDialog({ - open, - saving, - itemId, - onOpenChange, - onSubmit, -}: EditDialogProps) { - if (!open) { - return null; - } - return ( - - ); -} - -function EditDialogBody({ - open, - saving, - itemId, - onOpenChange, - onSubmit, -}: EditDialogProps) { - const formId = "ai-agent-edit-form"; - const t = useI18n(); - const [loading, setLoading] = useState(false); - const schema = useMemo( - () => - z.object({ - name: z.string().trim().min(1, t("aiAgent.nameRequired")), - description: z.string().trim(), - aiConfigId: z.string().trim().regex(/^\d+$/, t("aiAgent.aiConfigRequired")), - serviceMode: z.string().trim().min(1, t("aiAgent.serviceModeRequired")), - systemPrompt: z.string().trim(), - welcomeMessage: z.string().trim(), - replyTimeoutSeconds: z - .number() - .min(0, t("aiAgent.replyTimeoutInvalid")), - handoffMode: z.string().trim().min(1, t("aiAgent.handoffModeRequired")), - fallbackMode: z.string().trim().min(1, t("aiAgent.fallbackModeRequired")), - fallbackMessage: z.string().trim(), - }), - [t], - ); - const resolver = useMemo( - () => zodResolver(schema as never) as Resolver, - [schema], - ); - const serviceModeOptions = useMemo(() => getServiceModeOptions(t), [t]); - const handoffModeOptions = useMemo(() => getHandoffModeOptions(t), [t]); - const fallbackModeOptions = useMemo(() => getFallbackModeOptions(t), [t]); - const form = useForm({ - resolver, - defaultValues: buildForm(null), - }); - const { - control, - handleSubmit, - register, - reset, - watch, - formState: { errors }, - } = form; - const [selectedKnowledgeIds, setSelectedKnowledgeIds] = useState( - [], - ); - const [selectedTeamIds, setSelectedTeamIds] = useState([]); - const [selectedSkillIds, setSelectedSkillIds] = useState([]); - const [knowledgeToAdd, setKnowledgeToAdd] = useState(""); - const [teamToAdd, setTeamToAdd] = useState(""); - const [skillToAdd, setSkillToAdd] = useState(""); - const [directToolGroupToAdd, setDirectToolGroupToAdd] = useState(""); - const [directToolToAdd, setDirectToolToAdd] = useState(""); - const [graphToolToAdd, setGraphToolToAdd] = useState(""); - const [aiConfigs, setAIConfigs] = useState([]); - const [knowledgeBases, setKnowledgeBases] = useState([]); - const [agentTeams, setAgentTeams] = useState([]); - const [skills, setSkills] = useState([]); - const [directTools, setDirectTools] = useState([]); - const [graphTools, setGraphTools] = useState([]); - const [directToolOptions, setDirectToolOptions] = useState( - [], - ); - const [graphToolOptions, setGraphToolOptions] = useState( - [], - ); - const [toolCatalog, setToolCatalog] = useState([]); - - useEffect(() => { - async function loadDetail() { - if (!itemId) { - reset(buildForm(null)); - setSelectedKnowledgeIds([]); - setSelectedTeamIds([]); - setSelectedSkillIds([]); - setDirectTools([]); - setGraphTools([]); - setKnowledgeToAdd(""); - setTeamToAdd(""); - setSkillToAdd(""); - setDirectToolGroupToAdd(""); - setDirectToolToAdd(""); - setGraphToolToAdd(""); - return; - } - setLoading(true); - try { - const data = await fetchAIAgent(itemId); - reset(buildForm(data)); - setSelectedKnowledgeIds(data.knowledgeIds ?? []); - setSelectedTeamIds((data.teams ?? []).map((team) => team.id)); - setSelectedSkillIds(data.skillIds ?? []); - setDirectTools(data.directTools ?? []); - setGraphTools(data.graphTools ?? []); - setKnowledgeToAdd(""); - setTeamToAdd(""); - setSkillToAdd(""); - setDirectToolGroupToAdd(""); - setDirectToolToAdd(""); - setGraphToolToAdd(""); - } catch (error) { - toast.error( - error instanceof Error ? error.message : t("aiAgent.loadDetailFailed"), - ); - } finally { - setLoading(false); - } - } - void loadDetail(); - }, [itemId, reset, t]); - - useEffect(() => { - async function loadAIConfigs() { - try { - const data = await fetchAIConfigsAll({ - modelType: AIModelType.LLM, - }); - setAIConfigs(data); - } catch (error) { - toast.error( - error instanceof Error ? error.message : t("aiAgent.loadAiConfigFailed"), - ); - } - } - void loadAIConfigs(); - }, [t]); - - useEffect(() => { - async function loadAgentTeams() { - try { - const data = await fetchAgentTeamsAll(); - setAgentTeams(data); - } catch (error) { - toast.error(error instanceof Error ? error.message : t("aiAgent.loadTeamsFailed")); - } - } - void loadAgentTeams(); - }, [t]); - - useEffect(() => { - async function loadKnowledgeBases() { - try { - const data = await fetchKnowledgeBasesAll({ - status: Status.Ok, - }); - setKnowledgeBases(data); - } catch (error) { - toast.error(error instanceof Error ? error.message : t("aiAgent.loadKnowledgeFailed")); - } - } - void loadKnowledgeBases(); - }, [t]); - - useEffect(() => { - async function loadSkills() { - try { - const data = await fetchSkillDefinitionsAll({ - status: Status.Ok, - }); - setSkills(data); - } catch (error) { - toast.error(error instanceof Error ? error.message : t("aiAgent.loadSkillsFailed")); - } - } - void loadSkills(); - }, [t]); - - useEffect(() => { - async function loadDirectToolOptions() { - try { - const catalog = await fetchMCPCatalog(); - setToolCatalog(catalog); - setDirectToolOptions( - catalog - .filter((tool) => !tool.autoInjected && tool.sourceType === "mcp") - .map((tool) => ({ - value: tool.toolCode, - label: `${tool.title || tool.toolName} · ${tool.toolCode}`, - sourceType: tool.sourceType, - autoInjected: tool.autoInjected, - groupLabel: - tool.sourceType === "builtin" - ? t("aiAgent.builtinTools") - : tool.serverCode, - meta: { - toolCode: tool.toolCode, - serverCode: tool.serverCode, - toolName: tool.toolName, - title: tool.title || tool.toolName, - description: tool.description || "", - arguments: undefined, - }, - })), - ); - setGraphToolOptions( - catalog - .filter((tool) => tool.sourceType === "graph") - .map((tool) => ({ - value: tool.toolCode, - label: `${tool.title || tool.toolName} · ${tool.toolCode}`, - })), - ); - } catch (error) { - toast.error( - error instanceof Error ? error.message : t("aiAgent.loadDirectToolsFailed"), - ); - } - } - void loadDirectToolOptions(); - }, [t]); - - const aiConfigOptions = useMemo( - () => - aiConfigs.map((item) => ({ - value: String(item.id), - label: `${item.name} · ${item.modelName}`, - })), - [aiConfigs], - ); - - const teamOptions = useMemo( - () => - agentTeams.map((item: AdminAgentTeam) => ({ - value: String(item.id), - label: item.name, - })), - [agentTeams], - ); - - const knowledgeOptions = useMemo( - () => - knowledgeBases.map((item) => ({ - value: String(item.id), - label: item.name, - })), - [knowledgeBases], - ); - - const skillOptions = useMemo( - () => - skills.map((item) => ({ - value: String(item.id), - label: item.name, - })), - [skills], - ); - - const addableKnowledgeOptions = useMemo( - () => - knowledgeOptions.filter( - (option) => !selectedKnowledgeIds.includes(Number(option.value)), - ), - [knowledgeOptions, selectedKnowledgeIds], - ); - - const selectedKnowledgeOptions = useMemo( - () => - selectedKnowledgeIds - .map((id) => - knowledgeOptions.find((option) => Number(option.value) === id), - ) - .filter( - (option): option is { value: string; label: string } => !!option, - ), - [knowledgeOptions, selectedKnowledgeIds], - ); - - const addableSkillOptions = useMemo( - () => - skillOptions.filter( - (option) => !selectedSkillIds.includes(Number(option.value)), - ), - [selectedSkillIds, skillOptions], - ); - - const selectedSkillOptions = useMemo( - () => - selectedSkillIds - .map((id) => skillOptions.find((option) => Number(option.value) === id)) - .filter( - (option): option is { value: string; label: string } => !!option, - ), - [selectedSkillIds, skillOptions], - ); - - const addableDirectToolOptions = useMemo( - () => - directToolOptions.filter( - (option) => - option.groupLabel === directToolGroupToAdd && - !directTools.some((tool) => tool.toolCode === option.value), - ), - [directToolOptions, directToolGroupToAdd, directTools], - ); - - const directToolGroupOptions = useMemo( - () => - Array.from( - new Map( - directToolOptions.map((option) => [ - option.groupLabel, - { - value: option.groupLabel, - label: option.groupLabel, - }, - ]), - ).values(), - ), - [directToolOptions], - ); - - const directToolsGrouped = useMemo(() => { - const groups = new Map(); - for (const tool of directTools) { - const groupLabel = tool.serverCode || t("aiAgent.ungrouped"); - const current = groups.get(groupLabel) ?? []; - current.push(tool); - groups.set(groupLabel, current); - } - return Array.from(groups.entries()); - }, [directTools, t]); - - const addableGraphToolOptions = useMemo( - () => - graphToolOptions.filter( - (option) => !graphTools.includes(option.value), - ), - [graphToolOptions, graphTools], - ); - - const addableTeamOptions = useMemo( - () => - teamOptions.filter( - (option) => !selectedTeamIds.includes(Number(option.value)), - ), - [teamOptions, selectedTeamIds], - ); - - const selectedTeamOptions = useMemo( - () => - selectedTeamIds - .map((id) => teamOptions.find((option) => Number(option.value) === id)) - .filter( - (option): option is { value: string; label: string } => !!option, - ), - [selectedTeamIds, teamOptions], - ); - - const handoffMode = watch("handoffMode"); - const selectedHandoffModeLabel = - handoffModeOptions.find((item) => item.value === handoffMode)?.label ?? - t("aiAgent.notSelected"); - - async function onFormSubmit(values: EditForm) { - await onSubmit( - buildPayload( - values, - selectedKnowledgeIds, - selectedTeamIds, - selectedSkillIds, - directTools, - graphTools, - ), - ); - } - - function handleAddTeam(value: string) { - const id = Number(value); - if (!Number.isFinite(id) || id <= 0 || selectedTeamIds.includes(id)) { - return; - } - setSelectedTeamIds((prev) => [...prev, id]); - setTeamToAdd(""); - } - - function handleRemoveTeam(id: number) { - setSelectedTeamIds((prev) => prev.filter((item) => item !== id)); - } - - function handleAddKnowledge(value: string) { - const id = Number(value); - if (!Number.isFinite(id) || id <= 0 || selectedKnowledgeIds.includes(id)) { - return; - } - setSelectedKnowledgeIds((prev) => [...prev, id]); - setKnowledgeToAdd(""); - } - - function handleMoveKnowledge(index: number, direction: -1 | 1) { - const targetIndex = index + direction; - if (targetIndex < 0 || targetIndex >= selectedKnowledgeIds.length) { - return; - } - setSelectedKnowledgeIds((prev) => { - const next = [...prev]; - const current = next[index]; - next[index] = next[targetIndex]; - next[targetIndex] = current; - return next; - }); - } - - function handleRemoveKnowledge(id: number) { - setSelectedKnowledgeIds((prev) => prev.filter((item) => item !== id)); - } - - function handleAddSkill(value: string) { - const id = Number(value); - if (!Number.isFinite(id) || id <= 0 || selectedSkillIds.includes(id)) { - return; - } - setSelectedSkillIds((prev) => [...prev, id]); - setSkillToAdd(""); - } - - function handleRemoveSkill(id: number) { - setSelectedSkillIds((prev) => prev.filter((item) => item !== id)); - } - - function handleAddDirectTool(value: string) { - const option = directToolOptions.find((item) => item.value === value); - if (!option) { - return; - } - setDirectTools((prev) => { - if ( - prev.some( - (item) => - item.toolCode === option.meta.toolCode, - ) - ) { - return prev; - } - return [...prev, option.meta]; - }); - setDirectToolGroupToAdd(option.groupLabel); - setDirectToolToAdd(""); - } - - function handleRemoveDirectTool(value: string) { - setDirectTools((prev) => prev.filter((item) => item.toolCode !== value)); - } - - function handleAddGraphTool(value: string) { - if (!value || graphTools.includes(value)) { - return; - } - setGraphTools((prev) => [...prev, value]); - setGraphToolToAdd(""); - } - - function handleRemoveGraphTool(value: string) { - setGraphTools((prev) => prev.filter((item) => item !== value)); - } - - return ( - - - - - } - > - {loading ? ( -
-
{t("aiAgent.loading")}
-
- ) : ( -
-
-
- - {t("aiAgent.name")} - - - - - - - - {t("aiAgent.aiConfig")} - - ( - - )} - /> - - - - - - {t("aiAgent.columnServiceMode")} - - ( - - )} - /> - - - -
- - - {t("aiAgent.description")} - -