diff --git a/web/app/dashboard/ai-agents/_components/config-workbench.tsx b/web/app/dashboard/ai-agents/_components/config-workbench.tsx index 4d9be36..87f7a69 100644 --- a/web/app/dashboard/ai-agents/_components/config-workbench.tsx +++ b/web/app/dashboard/ai-agents/_components/config-workbench.tsx @@ -50,7 +50,6 @@ import { type CreateAIAgentPayload, type KnowledgeBase, type MCPToolCatalogItem, - type MCPToolSourceType, type SkillDefinition, } from "@/lib/api/admin" import { @@ -69,9 +68,10 @@ type DirectToolItem = CreateAIAgentPayload["directTools"][number] type DirectToolOption = { value: string label: string + group: string + subtitle: string + description?: string meta: DirectToolItem - sourceType: MCPToolSourceType - groupLabel: string } const runtimeModes: { @@ -153,8 +153,6 @@ export function AIAgentConfigWorkbench({ const [publishedWorkflows, setPublishedWorkflows] = useState([]) const [teamToAdd, setTeamToAdd] = useState("") - const [directToolGroupToAdd, setDirectToolGroupToAdd] = useState("") - const [directToolToAdd, setDirectToolToAdd] = useState("") useEffect(() => { setCurrentAgentId(agentId ?? null) @@ -313,9 +311,10 @@ export function AIAgentConfigWorkbench({ ) .map((tool) => ({ value: tool.toolCode, - label: `${tool.title || tool.toolName} · ${tool.toolCode}`, - sourceType: tool.sourceType, - groupLabel: tool.sourceType === "builtin" ? "内置工具" : tool.serverCode, + label: tool.title || tool.toolName, + group: tool.sourceType === "builtin" ? "内置工具" : tool.serverCode, + subtitle: tool.toolCode, + description: tool.description || undefined, meta: { toolCode: tool.toolCode, serverCode: tool.serverCode, @@ -327,27 +326,6 @@ export function AIAgentConfigWorkbench({ })), [toolCatalog], ) - const directToolGroupOptions = useMemo( - () => - Array.from( - new Map( - directToolOptions.map((option) => [ - option.groupLabel, - { value: option.groupLabel, label: option.groupLabel }, - ]), - ).values(), - ), - [directToolOptions], - ) - const addableDirectToolOptions = useMemo( - () => - directToolOptions.filter( - (option) => - option.groupLabel === directToolGroupToAdd && - !directTools.some((tool) => tool.toolCode === option.value), - ), - [directToolGroupToAdd, directToolOptions, directTools], - ) const workflowOptions = useMemo( () => publishedWorkflows.map((workflow) => ({ @@ -370,15 +348,13 @@ export function AIAgentConfigWorkbench({ setNext([...current, id]) } - function addDirectTool(value: string) { - const option = directToolOptions.find((item) => item.value === value) - if (!option) return - setDirectTools((current) => - current.some((tool) => tool.toolCode === option.meta.toolCode) - ? current - : [...current, option.meta], + function setDirectToolSelection(values: string[]) { + setDirectTools( + values.flatMap((value) => { + const option = directToolOptions.find((item) => item.value === value) + return option ? [option.meta] : [] + }), ) - setDirectToolToAdd("") } function setWorkflowSelection(values: string[]) { @@ -802,50 +778,14 @@ export function AIAgentConfigWorkbench({ title="Direct Tool" description="从工具分组中选择 Agent 可以直接调用的工具。" > -
- { - setDirectToolGroupToAdd(value) - setDirectToolToAdd("") - }} - /> - - -
-
- {directTools.length === 0 ? ( - 未配置 Direct Tool - ) : ( - directTools.map((tool) => ( - } - title={tool.title || tool.toolCode} - meta={tool.serverCode || "内置工具"} - onRemove={() => - setDirectTools((current) => - current.filter((item) => item.toolCode !== tool.toolCode), - ) - } - /> - )) - )} -
+ tool.toolCode)} + options={directToolOptions} + placeholder="选择 Direct Tool" + emptyText="没有可用 Direct Tool" + onValuesChange={setDirectToolSelection} + /> ) : null} @@ -1026,42 +966,6 @@ function FieldBlock({ ) } -function ResourceRow({ - icon, - title, - meta, - onRemove, -}: { - icon: ReactNode - title: string - meta?: string - onRemove: () => void -}) { - return ( -
- - {icon} - -
-
{title}
- {meta ?
{meta}
: null} -
- -
- ) -} - -function EmptyResource({ children }: { children: ReactNode }) { - return ( -
- {children} -
- ) -} - function BadgeList({ empty, items, diff --git a/web/components/option-combobox.tsx b/web/components/option-combobox.tsx index d9a0da5..fd2ba95 100644 --- a/web/components/option-combobox.tsx +++ b/web/components/option-combobox.tsx @@ -24,6 +24,7 @@ import { useI18n } from "@/i18n/provider" export type ComboboxOption = { value: string label: string + group?: string subtitle?: string description?: string } @@ -59,14 +60,14 @@ type OptionComboboxProps = CommonOptionComboboxProps & export function OptionCombobox(props: OptionComboboxProps) { const { - options, - placeholder, - searchPlaceholder, - emptyText, - disabled = false, - triggerClassName, - preserveExternalSelection = false, - renderOptionAction, + options, + placeholder, + searchPlaceholder, + emptyText, + disabled = false, + triggerClassName, + preserveExternalSelection = false, + renderOptionAction, } = props const t = useI18n() const [open, setOpen] = useState(false) @@ -80,6 +81,13 @@ export function OptionCombobox(props: OptionComboboxProps) { : selectedOptions.length === 1 ? selectedOptions[0].label : `已选择 ${selectedOptions.length} 项` + const optionGroups = Array.from( + options.reduce((groups, option) => { + const group = option.group ?? "" + groups.set(group, [...(groups.get(group) ?? []), option]) + return groups + }, new Map()), + ) function selectOption(optionValue: string) { if (props.multiple) { @@ -118,11 +126,12 @@ export function OptionCombobox(props: OptionComboboxProps) { {emptyText ?? t("common.emptyOptions")} - - {options.map((option) => ( + {optionGroups.map(([group, groupOptions]) => ( + + {groupOptions.map((option) => ( selectOption(option.value)} >
@@ -166,8 +175,9 @@ export function OptionCombobox(props: OptionComboboxProps) { ) : null}
- ))} -
+ ))} +
+ ))}