# Agents Módulo de gestión del Agente AI (`Module.AGENTS`). Permite administrar la base de conocimiento y la configuración del agente de IA de la empresa. --- ## Rutas | Ruta | Componente | Descripción | |---|---|---| | `/agents` | `AgentsLayout` | Redirige automáticamente a `/agents/knowledge-base` | | `/agents/knowledge-base` | `KnowledgeBase` | Lista raíz de archivos y carpetas | | `/agents/knowledge-base/:path` | `KnowledgeBase` | Vista de carpeta específica. `path` es el path de carpeta URL-encoded (ej. `encodeURIComponent("policies/general/")`) | | `/agents/settings` | `AgentsSettings` | Configuración general del agente AI | | `/agents/knowledge-base/upload-file` | `UploadFile` | Carga de archivos multi-paso (página completa, sin layout ni sidebar). Acepta `?folderpath=` como query param. | > **Importante:** La ruta `/agents/knowledge-base/upload-file` está registrada **fuera** del `AgentsLayout` en el router para que se renderice como pantalla completa. Está también excluida explícitamente del sidebar y la navbar mediante regex en `src/utils/sidebar.ts` y `src/utils/navbar.ts`. --- ## Estructura de archivos ``` Agents/ ├── index.tsx # Layout con tabs ("Base de conocimiento" | "Configuración") ├── routes.ts # Path factories centralizados ├── router.tsx # Config de rutas del módulo (importado en src/routes.tsx) ├── constants.ts # LAYOUT_SX ├── README.md │ ├── KnowledgeBase/ │ ├── index.tsx # Página: lista de archivos/carpetas (root o dentro de una carpeta) │ ├── types.ts # Todos los tipos API y UI (ver sección Tipos) │ ├── constants.ts # KNOWLEDGE_BASE_STATUS_PILL_TYPE, KNOWLEDGE_BASE_STATUS_KEY, KNOWLEDGE_BASE_NAME_MAX_LENGTH │ ├── services.ts # CRUD completo (ver sección API) │ ├── queries.ts # knowledgeBaseKeys (query key factories) │ │ │ ├── hooks/ │ │ ├── useGetKnowledgeBaseFiles.tsx # useInfiniteQuery: transforma API → UI (folders primero) │ │ ├── useDeleteKnowledgeBaseItems.tsx # Mutations: deleteFile, deleteFiles, deleteFolder │ │ ├── useCreateKnowledgeBaseFolder.tsx # Mutation: crea carpeta + invalidación │ │ ├── useUpdateKnowledgeBaseItem.tsx # Mutations: updateFile, updateFolder (renombrar/mover) │ │ ├── useKnowledgeBaseAudience.tsx # Calcula totalCount de audiencia vía getAudiencesCount │ │ └── useEditAudienceForm.tsx # Form wrapper: transforma segmentation form → tags/userIds │ │ │ ├── UploadFile/ │ │ ├── index.tsx # Página full-screen multi-paso (FILE → AUDIENCE) │ │ ├── types.ts # UploadFormValues, UploadStep (enum), UploadKnowledgeBaseFileResponse │ │ ├── services.ts # uploadKnowledgeBaseFile(filename, formData) → PUT ai-agent/files/:filename │ │ ├── constants.ts # UPLOAD_FIELDS, UPLOAD_DEFAULT_VALUES, MAX_FILE_SIZE_MB/BYTES │ │ ├── utils.ts # getFileName, buildSegmentationTags │ │ └── hooks/ │ │ └── useUploadKnowledgeBaseFile.tsx │ │ └── components/ │ │ ├── UploadFileStep/ # Step 1: selector de archivos │ │ ├── UploadFileAudienceStep/ # Step 2: selector de audiencia/segmentación │ │ ├── UploadFileHeader/ │ │ ├── UploadFileFooter/ │ │ ├── UploadFileExitDialog/ # Confirma salida sin guardar │ │ └── UploadFileConfirmDialog/ # Confirma envío │ │ │ └── components/ │ ├── KnowledgeBaseHeader/ │ │ └── index.tsx # Breadcrumbs + botones "Subir archivos" y "Nueva carpeta/subcarpeta" │ │ │ ├── KnowledgeBaseContent/ │ │ ├── index.tsx # Orquestador: fetching, estado, search, bulk actions (0 props) │ │ ├── KnowledgeBaseTable.tsx # Display puro: tabla + loader + estados vacíos │ │ ├── KnowledgeBaseTableHeader.tsx # Encabezado con checkbox "seleccionar todo" (solo archivos) │ │ ├── KnowledgeBaseTableRow.tsx # Fila individual (archivo o carpeta) │ │ └── KnowledgeBaseTableState.tsx # Estados vacío / error / networkError / emptySearch │ │ │ ├── KnowledgeBaseBreadcrumbs/ │ │ └── index.tsx # Breadcrumbs derivados de los segmentos del path (decodeURIComponent) │ │ │ ├── KnowledgeBaseBulkActionsBar/ │ │ └── index.tsx # Barra animada de acciones en bulk (Editar audiencia | Eliminar) │ │ │ ├── KnowledgeBaseAudienceSelector/ │ │ └── index.tsx # Selector de tipo de audiencia (Todos / Segmentado) │ │ │ ├── KnowledgeBaseSegmentation/ │ │ └── index.tsx # Selector de grupos de segmentación (FormSegmentationGroupSelector) │ │ │ ├── KnowledgeBaseAudienceAlert/ │ │ └── index.tsx # Alerta informativa sobre la audiencia configurada │ │ │ ├── KnowledgeBaseAudienceCollaboratorsDrawer/ │ │ └── index.tsx # Drawer que lista los colaboradores de la audiencia actual │ │ │ ├── EditAudienceDrawer/ │ │ ├── index.tsx # Drawer principal de edición de audiencia │ │ └── EditAudienceDrawerBody.tsx │ │ │ ├── EditAudienceConfirmDialog/ │ │ └── index.tsx # Dialog de confirmación antes de guardar cambios de audiencia │ │ │ ├── MoveItemDrawer/ │ │ └── index.tsx # Drawer para mover un archivo o carpeta a otra ubicación │ │ │ ├── NewFolderDialog/ │ │ └── index.tsx # Dialog con formulario para crear una carpeta │ │ │ ├── EditNameDialog/ │ │ └── index.tsx # Dialog para renombrar un archivo o carpeta │ │ │ └── DeleteConfirmDialog/ │ └── index.tsx # Dialog de confirmación para eliminar items seleccionados │ ├── Settings/ │ ├── index.tsx # Página: formulario de configuración del agente (con skeleton) │ ├── types.ts # AgentConfig, UpdateAgentConfigPayload, AgentSettingsFormValues │ ├── queries.ts # agentConfigKeys (query key factories) │ ├── services.ts # getAgentConfig, updateAgentConfig │ ├── constants.ts # SETTINGS_FIELDS, GOAL_MAX_LENGTH, INSTRUCTIONS_MAX_LENGTH │ │ │ ├── hooks/ │ │ ├── useGetAgentConfig.ts # useQuery wrapper para GET ai-agent/config │ │ └── useUpdateAgentConfig.ts # useMutation con invalidación y snackbar │ │ │ └── components/ │ ├── GeneralSection.tsx # Sección: nombre, descripción, identidad, objetivo, instrucciones │ ├── MessagesSection.tsx # Sección: mensaje inicial, de inactividad y filtro de audiencia │ ├── ModulesSection.tsx # Sección: módulos conectados (switchers — próximamente) │ └── SettingsSkeleton.tsx # Skeleton de carga del formulario ``` --- ## Tipos principales ### `KnowledgeBase/types.ts` — tipos de API ```ts type AgentFileStatus = 'queued' | 'processing' | 'ready' | 'failed'; type SegmentationTag = { groupId: number; itemId: number; groupName: string; itemName: string; }; type AgentFileRow = { name: string; id: string | null; size: number; status: AgentFileStatus; segmentationId: string | null; segmentationTags: SegmentationTag[]; segmentationUserIds: number[]; uploadedBy: { id: number; fullName: string } | null; updatedAt: string | null; downloadUrl: string; }; type AgentFolderRow = { path: string; // termina con "/" fileCount: number; statuses: AgentFileStatus[]; segmentationTags: SegmentationTag[]; segmentationUserIds: number[]; }; type KnowledgeBaseFilesResponse = { folder: string; files: AgentFileRow[]; folders: AgentFolderRow[]; total: number; hasMore: boolean; }; ``` ### `KnowledgeBase/types.ts` — tipos UI ```ts enum KnowledgeBaseItemType { FILE = 'FILE', FOLDER = 'FOLDER' } type KnowledgeBaseItem = { name: string; path: string; parentPath: string | null; type: KnowledgeBaseItemType; extension: string | null; uploadedBy: { id: number; fullName: string } | null; updatedAt: string; size?: string; status?: AgentFileStatus; segmentationTags: SegmentationTag[]; segmentationUserIds: number[]; itemCount?: number; downloadUrl: string; }; type UpdateKnowledgeBaseFilePayload = { newName?: string; newFolder?: string }; type UpdateKnowledgeBaseFolderPayload = { newName?: string; newParent?: string }; type EditKnowledgeBaseAudiencePayload = { documents: string[]; tags: SegmentationTag[]; userIds: number[]; }; type KnowledgeBaseListParams = { folder?: string; limit?: number; offset?: number; search?: string; }; enum KnowledgeBaseAudienceType { ALL = 'all', SEGMENTED = 'segmented' } type KnowledgeBaseAudienceSegmentation = Record>; type KnowledgeBaseAudienceForm = { audienceType: KnowledgeBaseAudienceType | null; segmentation: KnowledgeBaseAudienceSegmentation; }; ``` ### `Settings/types.ts` ```ts type AgentConfig = { id: string; name: string; description: string; identity: string; goal: string; instructions: string; helloMessage: string; inactivityMessage: string; inactivityEnabled: boolean; inactivityTimeoutSec: number; audienceFilterEnabled: boolean; }; type UpdateAgentConfigPayload = Partial; type AgentSettingsFormValues = Partial; ``` ### `KnowledgeBase/UploadFile/types.ts` ```ts type UploadFormValues = KnowledgeBaseAudienceForm & { files: FileCardType[]; folderPath: string; }; enum UploadStep { FILE = 0, AUDIENCE = 1 } type UploadKnowledgeBaseFileResponse = { filename: string; segmentationId: string; segmentationApplied: boolean | null; }; ``` --- ## Integración con el sistema ### `src/routes.tsx` El módulo se integra con spread: `...agentsRouterConfig`. La ruta de upload-file queda fuera del `AgentsLayout` y está envuelta en `PermissionsGuard`. ### `src/components/DashboardLayout/DashboardSidebar/index.tsx` El módulo aparece en el sidebar como: - `key: Module.AGENTS` - Título: `t('backoffice_only:dashboard_sidebar.agents')` - Icono: `IconSparkles` - Path: `agentsRoutes.knowledgeBase.base()` → `/agents/knowledge-base` ### `src/utils/sidebar.ts` y `src/utils/navbar.ts` La ruta `/agents/knowledge-base/upload-file` está excluida del sidebar y navbar vía regex: ```ts /\/agents\/knowledge-base\/upload-file/ ``` ### `src/types/modules.ts` ```ts Module.AI_AGENTS = 'AI_AGENTS' ``` --- ## Integración con API ### Endpoints | Endpoint | Función en services.ts | Descripción | |---|---|---| | `GET ai-agent/files` | `getKnowledgeBaseFiles(params)` | Lista paginada de archivos y carpetas | | `GET ai-agent/files/:filename` | `getKnowledgeBaseFile(filename)` | Detalle de un archivo individual | | `DELETE ai-agent/files/:filename` | `deleteKnowledgeBaseFile(filename)` | Eliminar un archivo | | `DELETE ai-agent/files` | `deleteKnowledgeBaseFiles(filenames[])` | Eliminar archivos en bulk | | `DELETE ai-agent/folders/:path` | `deleteKnowledgeBaseFolder(path)` | Eliminar una carpeta | | `POST ai-agent/folders` | `createKnowledgeBaseFolder(path)` | Crear una carpeta | | `PATCH ai-agent/files/:filename` | `updateKnowledgeBaseFile(filename, payload)` | Renombrar o mover un archivo | | `PATCH ai-agent/folders/:path` | `updateKnowledgeBaseFolder(path, payload)` | Renombrar o mover una carpeta | | `PUT ai-agent/segmentations` | `editKnowledgeBaseAudience(payload)` | Editar audiencia de items seleccionados | | `PUT ai-agent/files/:filename` | `uploadKnowledgeBaseFile(filename, formData)` | Subir un archivo | | `GET ai-agent/config` | `getAgentConfig()` | Obtener configuración del agente | | `PUT ai-agent/config` | `updateAgentConfig(payload)` | Guardar configuración del agente | > El `baseURL` del cliente `api` ya incluye `/backoffice`, por lo que las rutas no llevan ese prefijo. ### Hook: `useGetKnowledgeBaseFiles` ```ts const { items, total, isLoading, isSuccess, isError, fetchNextPage, isFetchingNextPage } = useGetKnowledgeBaseFiles({ folderPath, search, limit, offset }); ``` Usa `useInfiniteQuery`. Las carpetas aparecen primero, seguidas de los archivos. Internamente transforma `AgentFileRow[]` + `AgentFolderRow[]` → `KnowledgeBaseItem[]`. --- ## Navegación por carpetas La misma página `KnowledgeBase` maneja raíz y subcarpetas. El `path` en la URL es el **path de carpeta URL-encoded**: - Navegar a carpeta: `navigate(agentsRoutes.knowledgeBase.folder(encodeURIComponent(folder.path)))` - Leer en página: `const folderPath = decodeURIComponent(params.path ?? '')` - Los breadcrumbs se derivan de los segmentos del path: `"policies/general/"` → `["policies", "general"]` --- ## Traducciones Namespace: `agents` Ubicación: `node_modules/@humanddev/hu-translations/locale/es/agents.json` Claves relevantes para Knowledge Base: | Clave | Uso | |---|---| | `knowledge_base.table.audience` | Header columna Alcance | | `knowledge_base.status.loading` | Pill para `queued` y `processing` | | `knowledge_base.status.ready` | Pill para `ready` | | `knowledge_base.status.error` | Pill para `failed` | --- ## Patrones y convenciones usadas ### Layers (drawers y dialogs) Todos los drawers y dialogs usan el patrón de capas del proyecto: - **Drawers:** `useDrawerLayer()` → `openDrawer({ content: })` - **Dialogs:** `useDialogLayer()` → `openDialog({ content: }, DIALOG_ID)` / `closeDialog(DIALOG_ID)` ### Formularios - Se usa `react-hook-form` con `FormProvider` + `useForm`. - Las constantes de campos se tipan con `Record` para evitar strings sueltos. ### Animaciones - Se usa `appearFromBottom` de `@material-hu/utils/animations` para la entrada de páginas/tablas. - `fadeIn` se usa en filas individuales de la tabla. ### Columna Alcance - `segmentationTags.length === 0 && segmentationUserIds.length === 0` → `"Todos"`, si no → `"Segmentado N"`. - Aplica igual para archivos y carpetas. ### Checkboxes en tabla - Las **carpetas** tienen checkbox **disabled** — no participan en bulk actions. - "Seleccionar todo" solo selecciona archivos (excluye carpetas del conteo). ### Status de carpetas El status visible de una carpeta se deriva de su array `statuses`: - Si contiene `failed` → pill error - Si contiene `queued` o `processing` → pill warning - Si todos son `ready` → pill success - Array vacío → sin pill ### HuGoTheme Las páginas principales (`AgentsLayout`, `UploadFile`) wrappean su contenido con `useHuGoTheme()` para asegurar el tema correcto del design system. ### Snackbars Se usa `useHuSnackbar()` → `enqueueSnackbar({ title, variant })` para feedback de acciones. --- ## Estado actual | Ítem | Estado | Detalle | |---|---|---| | KnowledgeBase UI | ✅ Listo | Layout, tabla, selección, búsqueda, carpetas, columna Alcance | | Breadcrumbs | ✅ Listo | Navegación anidada funcional basada en path | | Bulk actions bar | ✅ Listo | Editar audiencia y Eliminar con animación | | NewFolderDialog | ✅ Listo | Crea carpeta con API integrada | | EditNameDialog | ✅ Listo | Renombra archivos y carpetas con API integrada | | MoveItemDrawer | ✅ Listo | Mueve archivos y carpetas con API integrada | | DeleteConfirmDialog | ✅ Listo | Confirma y ejecuta eliminación vía API | | EditAudienceDrawer | ✅ Listo | Edita audiencia de items seleccionados (bulk) | | Upload page | ✅ Listo | Flujo multi-paso (archivo → audiencia) con API integrada | | Settings form | ✅ Listo | General + Mensajes + Módulos (próximamente); con API integrada | | Capa de servicios KB | ✅ Lista | CRUD completo en `services.ts` + hooks por operación | | Integración con API real | ✅ Activa | Todos los hooks consumen la API directamente | | Menú de acciones individuales por fila | ✅ Listo | Acciones por fila implementadas | | `uploadedBy` → nombre de usuario | ✅ Resuelto | La API devuelve `{ id, fullName }` directamente | | Guard de permisos / `Module.AGENTS` | ✅ Implementado | El router usa `PermissionsGuard` | | Módulos conectados (Settings) | ⏳ Próximamente | Switchers actualmente deshabilitados |