/** * Hook that wraps useAgenticCatalog and provides a unified capabilities view. * * Merges catalog.tools + catalog.a2a_agents into a single CapabilityItem[] * list with search, status, and type filtering. */ import { useMemo, useState } from 'react' import { useAgenticCatalog } from '../../agentic/useAgenticCatalog' import type { CapabilityItem } from '../../agentic/types' import { deriveStatus } from './ToolStatusBadge' type Args = { backendUrl: string apiKey?: string } export type TypeFilter = 'all' | 'tool' | 'a2a' export function useToolsInventory({ backendUrl, apiKey }: Args) { const { catalog, loading, error, refresh } = useAgenticCatalog({ backendUrl, apiKey, enabled: true, }) const [search, setSearch] = useState('') const [statusFilter, setStatusFilter] = useState<'all' | 'active' | 'inactive'>('all') const [typeFilter, setTypeFilter] = useState('all') /* Build unified list from both sources */ const allItems: CapabilityItem[] = useMemo(() => { const toolItems: CapabilityItem[] = (catalog?.tools || []) .filter((t) => t.id && t.name) .map((t) => ({ kind: 'tool', data: t })) const a2aItems: CapabilityItem[] = (catalog?.a2a_agents || []) .filter((a) => a.id && a.name) .map((a) => ({ kind: 'a2a_agent', data: a })) return [...toolItems, ...a2aItems] }, [catalog?.tools, catalog?.a2a_agents]) /* Filtered list */ const items = useMemo(() => { let filtered = allItems // Type filter if (typeFilter !== 'all') { const kind = typeFilter === 'a2a' ? 'a2a_agent' : 'tool' filtered = filtered.filter((item) => item.kind === kind) } // Search filter if (search.trim()) { const q = search.toLowerCase() filtered = filtered.filter((item) => { const d = item.data const searchable = `${d.name} ${d.description || ''} ${d.id} ${ item.kind === 'a2a_agent' && 'endpoint_url' in d ? d.endpoint_url || '' : '' }` return searchable.toLowerCase().includes(q) }) } // Status filter if (statusFilter !== 'all') { filtered = filtered.filter((item) => deriveStatus(item.data.enabled) === statusFilter) } return filtered }, [allItems, search, statusFilter, typeFilter]) /* Counts */ const counts = useMemo(() => { const tools = (catalog?.tools || []) const a2a = (catalog?.a2a_agents || []) return { total: tools.length + a2a.length, tools: { total: tools.length, active: tools.filter((t) => t.enabled === true).length, inactive: tools.filter((t) => t.enabled === false).length, }, a2a: { total: a2a.length, active: a2a.filter((a) => a.enabled === true).length, inactive: a2a.filter((a) => a.enabled === false).length, }, active: tools.filter((t) => t.enabled === true).length + a2a.filter((a) => a.enabled === true).length, inactive: tools.filter((t) => t.enabled === false).length + a2a.filter((a) => a.enabled === false).length, } }, [catalog?.tools, catalog?.a2a_agents]) return { items, counts, loading, error, refresh, search, setSearch, statusFilter, setStatusFilter, typeFilter, setTypeFilter, forgeHealthy: catalog?.forge?.healthy ?? null, } }