import type { AgentInviteOptionResponse } from '@dify/contracts/api/console/agent/types.gen' import type { ComboboxChangeEventDetails } from '@langgenius/dify-ui/combobox' import type { NodeDefault } from '../types' import type { AgentRosterNodeData } from './types' import { Button, buttonVariants } from '@langgenius/dify-ui/button' import { cn } from '@langgenius/dify-ui/cn' import { Combobox, ComboboxInput, ComboboxInputGroup, ComboboxItem, ComboboxItemText, ComboboxList, ComboboxStatus, } from '@langgenius/dify-ui/combobox' import { Popover, PopoverContent, PopoverTitle, PopoverTrigger } from '@langgenius/dify-ui/popover' import { toast } from '@langgenius/dify-ui/toast' import { useQuery } from '@tanstack/react-query' import { useDebounce } from 'ahooks' import { useState } from 'react' import { useTranslation } from 'react-i18next' import AppIcon from '@/app/components/base/app-icon' import Badge from '@/app/components/base/badge' import { useHooksStore } from '@/app/components/workflow/hooks-store' import { useCanManageAgents } from '@/features/agent-v2/permissions' import Link from '@/next/link' import { consoleQuery } from '@/service/client' import BlockIcon from '../block-icon' const AGENT_SELECTOR_PAGE_SIZE = 8 export function AgentSelectorContent({ open, onOpenChange, onSelect, onStartFromScratch, }: { open: boolean onOpenChange: (open: boolean) => void onSelect: (agent: AgentRosterNodeData) => void onStartFromScratch?: () => void }) { const { t } = useTranslation(['agentV2', 'common', 'workflow']) const appId = useHooksStore((s) => s.configsMap?.flowId) const [searchText, setSearchText] = useState('') const debouncedSearchText = useDebounce(searchText.trim(), { wait: 300 }) const agentsQuery = useQuery({ ...consoleQuery.agent.inviteOptions.get.queryOptions({ input: { query: { limit: AGENT_SELECTOR_PAGE_SIZE, page: 1, ...(appId ? { app_id: appId } : {}), ...(debouncedSearchText ? { keyword: debouncedSearchText } : {}), }, }, }), staleTime: 0, }) const agents = agentsQuery.data?.data ?? [] const canManageAgents = useCanManageAgents() const handleInputValueChange = (nextSearchText: string, details: ComboboxChangeEventDetails) => { if (details.reason !== 'item-press') setSearchText(nextSearchText) } const handleValueChange = (agent: AgentInviteOptionResponse | null) => { if (!agent) return if (!agent.active_config_snapshot_id) { toast.error(t(($) => $['nodes.agent.modelNotSelected'], { ns: 'workflow' })) return } onSelect(toAgentRosterNodeData(agent)) } const handleOpenChange = (nextOpen: boolean) => { if (!nextOpen) onOpenChange(false) } const isLoading = agentsQuery.isPending const statusText = isLoading ? t(($) => $.loading, { ns: 'common' }) : agentsQuery.isError ? t(($) => $['roster.loadingError'], { ns: 'agentV2' }) : agents.length === 0 ? debouncedSearchText ? t(($) => $['roster.emptySearch'], { ns: 'agentV2' }) : t(($) => $['roster.empty'], { ns: 'agentV2' }) : null const hasActions = !!onStartFromScratch || canManageAgents return (