# Charlie · Capa IA transversal de AnimalCharlie.

Charlie es la capa IA viva del ERP AnimalCharlie. No es solo un chat: calcula contexto de cada módulo, detecta alertas, propone próximos pasos, deja notas trazables y puede preparar acciones de trabajo. Las escrituras nunca se hacen directamente contra los módulos; siempre pasan por la capa segura `/api/charlie/*` y requieren confirmación cuando modifican datos.

## Contrato Base

- Especificación OpenAPI: `/api/openapi.json`, protegida con `charlie.read` o `charlie.execute`. Desde la UI se abre con el botón `OpenAPI`, que reutiliza la sesión autenticada y evita abrir una pestaña sin cabecera `Authorization`.
- Catálogo de acciones: `/api/charlie/actions`
- Catálogo MCP de módulos: `GET /api/charlie/mcps`
- Ficha MCP de módulo: `GET /api/charlie/mcps/{module}`
- Inteligencia ambiental del módulo activo: `GET /api/charlie/ambient?module=<modulo>`
- Notas y detalles de Charlie: `POST /api/charlie/notes`
- Mensajería del agente: `POST /api/charlie/message`
- Transcripción de audio: `POST /api/charlie/transcribe-audio`
- Ejecución confirmada: `POST /api/charlie/execute`
- Estado Charlie IA V2 web: `GET /api/charlie/v2/status`
- Auditoría: todas las ejecuciones quedan registradas como `charlie_action_execute`
- Editor IA: acción `improve_report_text` para preparar propuestas de mejora de informes sin aplicarlas automáticamente.
- MCP por módulos: acciones `list_module_mcps`, `module_mcp_context` y `module_control_plan`, documentadas en `docs/CHARLIE_MCP.md`.
- Proveedor LLM: OpenAI-compatible por defecto si hay clave, apuntando a `http://10.20.20.56:4000/v1`
- Proveedor de transcripción: Whisper local, por defecto modelo `small`

Todas las rutas, salvo `/api/health` y `/api/login`, usan cabecera de autorizacion con esquema Bearer; no documentar ni registrar tokens reales.

## Charlie IA V2 En La Web

La vista `#charlie` incluye un bloque `Charlie IA V2 / Control web` que consulta solo al backend de AnimalCharlie mediante `GET /api/charlie/v2/status`. El navegador no llama a LiteLLM, Kimi ni a ningún endpoint externo de IA. El endpoint devuelve metadatos seguros: disponibilidad, proveedor mediado por backend, agente previsto para el módulo activo, política de confirmación, acciones confirmables y secciones separadas de datos vistos, inferencias, acciones propuestas y evidencia.

La pagina completa `#charlie` muestra además `Conversación entre agentes` dentro de `#charlieV2Console`. Ese bloque pinta qué se dijeron el orquestador y los agentes por módulo con etapas `interpreta`, `consulta`, `responde`, `sintetiza` y `propone`, incluyendo agente, módulo, estado y extracto del mensaje. La UI consume `agentConversation`, `agentMessages` o `conversation` cuando llegan del backend; si no existen, usa `trace.agentConversation`, `trace.messages`, `routing.steps` o `routing.hops`; y, como fallback visible, deriva una simulación visual a partir de datos backend reales (`moduleAgents`, `moduleAgentResults`, `reply`, `actionDraft` y `proposedActions`). En consultas de calidad lechera, secado o datos históricos deben aparecer `hermes-module-milk_quality` y `hermes-module-datahub` cuando estén en el routing o en los resultados.

Mientras `CHARLIE_IA_V2_ENABLED` no esté activado o falte la configuración backend de Hermes Charlie (`HERMES_CHARLIE_BASE_URL` en entorno, sin exponerla al cliente), el panel muestra `No disponible` y deja claro que el Charlie actual sigue funcionando. Las respuestas de `/api/charlie/message` y `/api/charlie/execute` incluyen además `v2.sections` para que la UI clasifique la última respuesta sin cambiar el contrato operativo existente.

El backend refuerza el enrutado semántico con señales explícitas de dominio (`milk_quality`, `billing`, `sige`, `clients`, `medicines`) para que las preguntas naturales caigan en el agente correcto aunque el módulo activo sea ambiguo. Cuando Hermes Charlie devuelve una respuesta sin usar el contexto seguro, AnimalCharlie genera una síntesis verificable a partir de `safeResults`, métricas, totales y resultados de agentes de módulo; las acciones propuestas se filtran al módulo seleccionado, se deduplican por etiqueta y se descartan hallazgos neutrales para no proponer trabajo falso.

Las acciones propuestas siguen siendo borradores hasta que el usuario confirma en AnimalCharlie. El panel de confirmación ahora permite `Confirmar y ejecutar` o `Cancelar`; cancelar descarta el borrador en la UI y no llama a `/api/charlie/execute`.

## MCP Interno De Módulos

Charlie ya ve cada módulo activo de Animal Charlie como un MCP interno. El catálogo vive en `ANIMAL_CHARLIE_MCP_MODULE_DEFS` dentro de `server.py` y se publica por `GET /api/charlie/mcps`. Cada ficha declara `id`, `module`, `hash`, alias de lenguaje natural, tipos de entidad, recursos `animal-charlie://...`, herramientas ejecutables y política de confirmación.

Módulos publicados: inicio, certificación BEA, calidad lechera CMT, SIGE, clientes, facturación, Vetiquín, Charlie, calendario, proyectos, personal, acciones, mejoras, evidencias, normativa, integraciones, almacén lechero y archivo.

Las herramientas MCP no saltan la seguridad de Charlie: todas apuntan a acciones de `/api/charlie/execute`; las lecturas pueden ejecutarse directamente y las escrituras mantienen `requiresConfirmation: true`. La acción `list_module_mcps` lista el catálogo completo, `module_mcp_context` devuelve la ficha MCP de un módulo junto con su contexto ambiental actual y `module_control_plan` resume qué módulos ya tienen control de escritura confirmable y qué herramientas faltan por añadir.

Cada MCP incluye `aiInstructions`: instrucciones breves para que el modelo entienda qué es ese módulo, cuándo usarlo y qué límites debe respetar. En cada llamada LLM, Charlie carga `animalCharlieContext.mcpContext` con:

- `allModules`: catálogo resumido de los 18 MCP, sus instrucciones IA, recursos y herramientas seguras.
- `activeModule`: MCP del módulo visual activo si el frontend lo aporta.
- `relevantModules`: MCP derivados del módulo activo, del resultado ejecutado o de las tarjetas devueltas.

El prompt de sistema obliga a usar ese contexto antes de responder, elegir el MCP correcto y no inventar recursos ni herramientas.

El modo agente se expone como acción `agent_runbook`. Recibe un objetivo, un módulo inicial opcional y límites de lectura; selecciona MCPs relevantes, consulta contexto ambiental y acciones de lectura seguras, y devuelve `steps`, `items`, `nextActions` y un `actionDraft`. Antes de devolver el resultado deduplica `items` por módulo/registro para no repetir hallazgos idénticos en el resumen ni en las operaciones propuestas. Las operaciones siguen siendo confirmables: el modo agente prepara borradores como `create_action`, pero no ejecuta escrituras sin confirmación explícita.

Guía de desarrollo para añadir más módulos MCP: `docs/CHARLIE_MCP.md`.

## Contexto En Segundo Plano Y Sugerencias Puntuales

La UI no muestra a Charlie como panel permanente en todo el ERP. Al cambiar de módulo, el navegador llama a `GET /api/charlie/ambient?module=<modulo>` y mantiene el resultado en memoria para que la IA trabaje de fondo. La bandeja `#charlieAmbientPanel` está oculta por defecto y puede aparecer en cualquier módulo cuando hay una señal accionable, un registro activo o una nota trazable relevante.

El chat diario de Charlie vive en `#charliePopupShell`, un popup flotante anclado abajo a la derecha y abierto desde `#openCharlieBtn`, `#charlieFloatingBtn`, `Alt+C` o los botones `data-charlie-prompt`. El popup comparte historial con el módulo completo `#charlie`, usa el mismo endpoint `POST /api/charlie/message` y no cambia el módulo activo mientras se pregunta.

Cuando el proveedor LLM queda en segundo plano, la UI no imprime la respuesta operativa local como respuesta rápida: muestra una burbuja `Charlie está pensando` con hasta dos vacas de colores planos. Las vacas caminan, bajan la cabeza para comer, hacen desaparecer pequeños grupos de hierba y alternan tiempos aleatorios para que el bucle no parezca mecánico; de forma rara, una vaca deja un detalle mínimo de estiércol. La burbuja se sustituye por la respuesta final del LLM. Si Kimi falla o no termina, el chat muestra el error del proveedor y no usa una respuesta local preprogramada como sustituto.

El estado operativo del popup (`#charliePopupState`) recorta textos largos en una sola línea para no romper la cabecera en escritorio ni móvil. El módulo completo se conserva para OpenAPI, audio, catálogo de acciones y confirmaciones de escritura. Los iconos de entrada de Charlie usan una animación ligera de movimiento y respetan `prefers-reduced-motion`. En móvil estrecho (`max-width: 720px`), AnimalCharlie conserva el ERP completo como app Android/PWA: no fuerza `#charlie`, no oculta navegación ni módulos, y Charlie sigue siendo una superficie más dentro de los permisos reales de la sesión.

El popup puede crecer sin recargar la UI a `#charlieCanvasShell`, un canvas casi a pantalla completa que se abre con `clip-path: circle()` desde el punto de origen del chat. Charlie lo abre automáticamente cuando el mensaje del usuario pide visualizar, mostrar, abrir o resaltar contenido, o cuando la respuesta trae comandos `::canvas`/`charlie-canvas`. Así se evita abrir el canvas en preguntas normales de resumen operativo. Mientras no exista un modelo visual previo y el LLM siga pendiente, el botón `Canvas` del popup queda deshabilitado para evitar abrir un lienzo vacío; al terminar la respuesta vuelve a estar disponible. El canvas renderiza la respuesta como Markdown, genera un panel documental, lista artefactos accionables y permite abrir el módulo o archivo asociado sin cambiar de ruta hasta que el usuario lo pida. La cabecera del canvas permite copiar o descargar el Markdown generado, el renderizador admite bloques de checklist y línea temporal para planes o seguimientos, el parser rescata también JSON genérico (`json/js/txt`) con objetos `type/kind` aunque el bloque no venga perfecto y, si llega un plan en texto sin bloque visual, infiere checklist/timeline o crea una plantilla de borrador para mantener el lienzo útil. Desde Certificación, `#openReportCanvasBtn` convierte el documento activo en KPIs, gráfica por secciones, tabla de estructura y extracto editable; en Personal, `staff_contracts_overview` puede devolver contratos como KPIs, gráfica y tabla en el mismo canvas.

El renderizador reconoce comandos visuales incluidos en la respuesta:

- `::canvas image url="https://..." title="Foto"` para imágenes.
- `::canvas file url="https://..." title="Documento"` para archivos o documentos.
- `::canvas invoice number="F-001" total="120.00" client="Cliente"` para facturas.
- `::canvas highlight text="Dato a resaltar"` para marcas visibles.
- `::canvas animation title="Proceso"` para microanimaciones dentro del panel.
- `::canvas checklist items="[ ] Llamar cliente|[x] Enviar informe"` para listas de seguimiento.
- `::canvas timeline events="2026-05-23|Visita|Pendiente de cierre"` para cronologías operativas.
- Bloques JSON con etiqueta `charlie-canvas` y uno o varios objetos equivalentes.
- Bloques JSON flexibles en vallas `json`, `js` o `txt`, e incluso objetos sueltos dentro de la respuesta, siempre que incluyan `type` o `kind`; el canvas los rescata como artefactos y limpia del Markdown visible el payload crudo ya renderizado.

La bandeja puntual renderiza:

- Una recomendación o alerta concreta.
- El registro relacionado cuando existe contexto de entidad.
- Uno o dos controles contextualizados para analizar, guardar nota o preparar acción confirmada.

El resto del contexto, métricas y notas se siguen calculando en segundo plano para alimentar el módulo Charlie, el registro activo y las acciones seguras.

Módulos cubiertos por `charlie_ambient_context`: inicio/dashboard, clientes, facturación, calendario, proyectos, personal, SIGE, certificación BEA, calidad lechera, Vetiquín, almacén lechero, acciones, evidencias, normativa, integraciones, archivo y Charlie.

Ejemplos de cálculos:

- Facturación: borradores, vencidas, saldo vencido, planes recurrentes listos y total pendiente.
- Clientes: clientes activos, explotaciones, riesgo alto y saldo pendiente agregado.
- Acciones: abiertas, vencidas y alta prioridad.
- Calidad lechera: informes CMT, vacas revisadas, positivas y CMT 4+.
- Vetiquín: recetas vinculadas, pendientes de revisión por estado, avisos, antibióticos, falta de número de registro o tiempos de espera, revisiones documentadas en `metadata.reviewedAt`, retiradas de leche/carne que requieren atención, y recetas con indicador antibiótico en datos CIMAVet. Al guardar, archivar o cerrar una revisión desde Vetiquín, la UI refresca entidad activa y contexto ambiental para que la bandeja de Charlie use la cola real actualizada.
- Integraciones: conectores disponibles, configurados y consultas runtime.
- BEA: informes, borradores, aprobados y comentarios abiertos.

`POST /api/charlie/notes` crea una nota trazable en `charlie_notes` con `module`, `entity_type`, `entity_id`, `title`, `body`, `kind`, `status`, `source`, `created_at` y `created_by`. La acción equivalente del catálogo es `create_note`, requiere confirmación y deja auditoría `charlie_note_create`.

Cada respuesta ambiental incluye `controls`, una lista de controles operativos que la UI renderiza dentro del módulo activo:

- `kind: "prompt"` abre el chat flotante de Charlie con el análisis del módulo.
- `kind: "note"` guarda la nota sugerida para el módulo.
- `kind: "execute"` lanza una acción segura de `/api/charlie/execute`. Si `requiresConfirmation` es `true`, la UI abre el panel de confirmación de Charlie antes de escribir.

Todos los módulos reciben al menos análisis IA, guardado de nota y recalculo/lectura contextual. Los módulos con acciones específicas añaden accesos directos, por ejemplo `prioritize_work`, `client_followup_plan`, `billing_risk_report`, `staff_contracts_overview`, `medicine_review_queue`, `medicine_withdrawal_watchlist`, `data_quality_audit`, `list_today_calendar`, `module_control_plan` o `dashboard_summary`.

## Ficha Activa De Registro

Además del contexto de módulo, el ERP consulta `GET /api/charlie/entity?module=<modulo>&entityType=<tipo>&entityId=<id>` para mantener el registro activo en segundo plano. El contexto alimenta `#erpRecordPill`, las sugerencias puntuales de `#charlieAmbientPanel` y las notas ligadas al registro cuando el usuario selecciona un cliente, factura, explotación, SIGE, evento o informe.

La respuesta incluye:

- `title`, `subtitle`, `entityType` y `entityId` para identificar el registro activo.
- `facts`, una lista corta de campos clave normalizados para lectura rápida.
- `notes`, filtradas por `module`, `entity_type` y `entity_id`.
- `controls`, con los mismos tipos que la capa ambiental: `prompt`, `note` y `execute`.

Los módulos deben usar identificadores estables al seleccionar registros. Cuando un módulo cambia de registro activo debe llamar a `refreshCharlieEntity(<modulo>)` o actualizar su estado interno antes de que la capa de fondo recalcule. Las listas de proyectos, personal, acciones, evidencias, normativa y backups marcan la fila activa para que Charlie siga la navegación real del usuario sin aparecer como bloque global. Las notas de ficha se guardan en `charlie_notes` con `entityType` y `entityId`, por lo que no sustituyen las notas generales del módulo.

Ejemplo:

```http
GET /api/charlie/ambient?module=billing
Authorization: Bearer <token>
```

```http
POST /api/charlie/notes
Authorization: Bearer <token>
Content-Type: application/json

{
  "module": "billing",
  "title": "Nota de seguimiento en Facturación",
  "body": "Facturas vencidas: 3; Total pendiente: 1280.50",
  "kind": "calculation"
}
```

## Proveedor LLM

Charlie usa un proveedor compatible con OpenAI Chat Completions para generar la respuesta conversacional. Kimi queda como modelo preferente dentro del mismo servidor local de IA que ya usaba Charlie. La clave no se guarda en código ni debe subirse a Git.

Orden de configuración:

1. Variable de entorno `KIMI_API_KEY`, si se quiere separar la clave.
2. Variables de entorno `OPENAI_COMPAT_API_KEY` u `OPENAI_API_KEY`, que son las usadas por el servidor local.
3. Archivo local `data/kimi-api-key.txt`, si se quiere separar la clave, o `data/openai-compatible-api-key.txt` con permisos `600`.

Opciones:

- `CHARLIE_LLM_PROVIDER`: `kimi`, `openai-compatible` o `minimax`. Si no se define, Charlie usa Kimi cuando encuentra la clave compatible local y cae a OpenAI-compatible o MiniMax si se fuerza otro proveedor.
- `KIMI_BASE_URL`: por defecto reutiliza `OPENAI_COMPAT_BASE_URL`, es decir `http://10.20.20.56:4000/v1` en el despliegue local.
- `KIMI_MODEL`: por defecto `kimi-k2.6:cloud`, modelo detectado en el servidor local. Si se define como `auto`, Charlie consulta `GET /models` y prefiere `kimi-k2.6:cloud`, `kimi`, `kimi-k2.6`, `kimi-k2.5`, `kimi-k2` o `kimi-k2-thinking`.
- `KIMI_TIMEOUT`: por defecto reutiliza el timeout OpenAI-compatible, `180` segundos.
- `KIMI_THINKING`: `disabled` por defecto para respuestas operativas breves; el servidor local puede seguir devolviendo `reasoning_content`, pero Charlie nunca lo muestra como respuesta final: solo publica `content`.
- `OPENAI_COMPAT_BASE_URL`: por defecto `http://10.20.20.56:4000/v1`.
- `OPENAI_COMPAT_MODEL`: opcional para forzar otro modelo del mismo servidor local.
- `OPENAI_COMPAT_TIMEOUT`: por defecto `180` segundos.
- `CHARLIE_LLM_MODE`: `auto`, `background`, `sync` u `off`. En `auto`, Kimi y los proveedores OpenAI-compatible responden en segundo plano para no bloquear el chat cuando el modelo es lento.
- `CHARLIE_LLM_MAX_TOKENS`: por defecto `1400`.
- `CHARLIE_LLM_TEMPERATURE`: por defecto `0.25`.
- `CHARLIE_LLM_JOB_TTL_SECONDS`: por defecto `900`.
- `CHARLIE_LLM_JOB_LIMIT`: por defecto `50`.

Permisos globales: `GET /api/charlie/actions`, MCPs, documentación, inteligencia ambiental y contexto de registro aceptan `charlie.read` o `charlie.execute`; `POST /api/charlie/message`, `POST /api/charlie/transcribe-audio`, `POST /api/charlie/notes`, jobs LLM y `POST /api/charlie/execute` requieren `charlie.execute`.

El proveedor LLM no ejecuta acciones directamente. El servidor interpreta intención, prepara borradores y solo ejecuta escrituras mediante `/api/charlie/execute` con `confirm: true`.

Cuando `CHARLIE_LLM_MODE` usa segundo plano, `POST /api/charlie/message` calcula la intención operativa local solo como contexto interno, devuelve `provider.jobId` y deja `reply` vacío para que la UI mantenga la burbuja de pensamiento hasta que `GET /api/charlie/llm-jobs/{id}` trae la respuesta de la IA. Si el proveedor falla o agota el tiempo, el chat muestra el fallo y no rellena la conversación con el texto local.

MiniMax queda disponible como proveedor alternativo con `CHARLIE_LLM_PROVIDER=minimax`, `MINIMAX_API_KEY` o `data/minimax-api-key.txt`, `MINIMAX_BASE_URL`, `MINIMAX_MODEL` y `MINIMAX_TIMEOUT`.

## Backend Bridge Hermes Charlie

AnimalCharlie puede usar `/api/charlie/message` como fachada compatible hacia Hermes Charlie V2. El navegador mantiene el mismo contrato y nunca recibe tokens ni llama directamente a LiteLLM. No llama a LiteLLM desde el navegador: cualquier salida a Hermes Charlie se hace solo desde `server.py`.

Configuración segura:

- `CHARLIE_V2_ENABLED` o `CHARLIE_IA_V2_ENABLED`: activa el puente. Por defecto queda apagado y `/api/charlie/message` conserva el Charlie actual.
- `CHARLIE_HERMES_BASE_URL`: URL interna de Hermes Charlie. No se publica al frontend.
- `CHARLIE_HERMES_MESSAGE_PATH`: ruta del endpoint de mensajes en Hermes Charlie; por defecto `/api/charlie/message`.
- `CHARLIE_HERMES_TOKEN` o `HERMES_CHARLIE_TOKEN`: token interno para la cabecera `Authorization: Bearer ...`.
- `CHARLIE_HERMES_TOKEN_PATH`: ruta local no versionada para leer el token si no viene por entorno; por defecto `data/charlie-hermes-token.txt`.
- `CHARLIE_HERMES_REQUIRE_TOKEN`: si vale `1`, el puente se considera no configurado hasta encontrar token.
- `CHARLIE_HERMES_FALLBACK_ENABLED`: si vale `1`, los fallos de Hermes Charlie caen al Charlie actual cuando la petición no ha pedido V2 explícitamente.
- `CHARLIE_HERMES_TIMEOUT`: timeout de llamada backend a Hermes Charlie.
- `CHARLIE_HERMES_PROVIDER`, `CHARLIE_HERMES_MODEL` y `CHARLIE_HERMES_AGENT`: metadatos seguros para diagnóstico, sin secretos.
- `CHARLIE_HERMES_MAX_MESSAGE_CHARS`, `CHARLIE_HERMES_MAX_CONTEXT_CHARS` y `CHARLIE_HERMES_MAX_RESULTS`: límites del contrato enviado.

El payload que AnimalCharlie envía a Hermes Charlie incluye `requestId`, usuario/rol/permisos calculados por AnimalCharlie, módulo activo, entidad activa, mensaje, límites y contexto local ya sanitizado. `allowWrites` se fuerza siempre a `false`: Hermes Charlie puede devolver propuestas o borradores, pero las escrituras siguen pasando por `/api/charlie/execute` con confirmación visible.

Errores normalizados: `charlie_v2_disabled`, `charlie_v2_not_configured`, `charlie_v2_unauthorized`, `charlie_v2_module_denied`, `charlie_v2_model_unavailable`, `charlie_v2_timeout`, `charlie_v2_tool_denied`, `charlie_v2_invalid_response` y `charlie_v2_upstream_error`.

La interfaz debe presentar estos errores por su `message`, `detail`, `code` o `error` seguro. No debe mostrar objetos serializados como `[object Object]`; si el backend devuelve un error estructurado, el usuario verá el código/mensaje normalizado sin exponer secretos ni payloads internos.

Auditoría: cada intento V2 registra `charlie_v2_message` con `requestId`, módulo, tipo de entidad, duración, proveedor/modelo/agente y resultado. No guarda el prompt completo ni tokens. El evento `charlie_message` asociado conserva compatibilidad y registra longitud del mensaje, runtime usado y borrador propuesto cuando exista.

## Editor IA De Informes

El editor de informes usa Charlie desde la barra `#editorToolbar` mediante el botón `#aiImproveReportBtn`. La UI captura selección, sección actual o informe completo, registra la instrucción en `payload.aiInstructionLog` y llama a `/api/charlie/execute` con la acción `improve_report_text`.

La acción es de lectura y devuelve una propuesta estructurada:

- `improvedText`: texto propuesto.
- `explanation`: motivo breve de la mejora.
- `warnings`: avisos cuando falten datos, evidencias o contexto.
- `provider`: motor usado por Charlie.

El frontend muestra la propuesta en `#reportAiPreview` y solo modifica `#manualPreview` si el usuario pulsa `Aplicar` o `Insertar debajo`. Si el proveedor externo no responde a tiempo, la UI aborta la espera remota y reintenta con `llmMode: local`; el backend limita esa espera con `CHARLIE_REPORT_AI_TIMEOUT` para no bloquear el editor. La auditoría de `improve_report_text` guarda instrucción, alcance, informe y longitud del texto, pero no el cuerpo completo del informe.

Seguimiento funcional: `docs/EDITOR_IA_INFORMES.md`.

## Voz y Audio

Charlie tiene dos entradas de voz:

- Dictado directo en navegador mediante `SpeechRecognition`/`webkitSpeechRecognition`.
- Carga drag and drop de audio con `POST /api/charlie/transcribe-audio`.

La ruta de audio recibe un JSON con `filename`, `contentType`, `dataUrl` en base64 y `language`. El servidor guarda el audio en `data/audio/`, usa Whisper local por defecto, audita el tamaño real recibido y devuelve `transcript`. Ese texto puede corregirse manualmente antes de enviarlo a Charlie o procesarlo como informe.

Opciones:

- `BEA_WHISPER_EXTERNAL_ENABLED`: por defecto `0`; poner `1` para usar el proveedor externo OpenAI-compatible.
- `BEA_WHISPER_TRANSCRIPTION_URL`: opcional; si se activa externo sin URL explícita usa `http://10.20.20.56:4000/v1/audio/transcriptions`.
- `BEA_WHISPER_MODEL`: por defecto `whisper-large-v3-turbo` cuando el externo está activo.
- `BEA_WHISPER_API_KEY`: clave del proveedor externo; configurar solo en el entorno de la máquina o en `data/whisper-api-key.txt`.
- `BEA_WHISPER_TIMEOUT`: por defecto `120` segundos.
- `BEA_WHISPER_EXTERNAL_FALLBACK`: por defecto `1`; si el externo falla, usa Whisper local.
- `WHISPER_BIN`: binario de Whisper, por defecto `whisper`.
- `WHISPER_MODEL`: por defecto `small`.
- `WHISPER_TIMEOUT`: por defecto `360` segundos.
- `WHISPER_UV_PYTHON`: Python usado por el fallback `uv tool run --from openai-whisper whisper`; por defecto `/home/hermes/.local/bin/python3.11`.

## Política de Seguridad

Charlie distingue entre acciones de lectura y escritura.

- Lectura: puede ejecutarse directamente si el rol tiene permisos.
- Escritura: requiere `confirm: true`.
- Borrado destructivo: no se expone como acción de Charlie en esta fase.
- Roles: `admin`, `technician`, `reviewer`; cada acción declara sus roles permitidos.
- Auditoría: se registra usuario, rol, acción, parámetros y resultado principal.

## Acciones Iniciales

| Acción | Módulo | Tipo | Confirmación |
| --- | --- | --- | --- |
| `search` | Global | lectura | No |
| `dashboard_summary` | Dashboard | lectura | No |
| `module_insights` | Global | lectura | No |
| `module_control_plan` | Global | lectura | No |
| `list_module_mcps` | Charlie | lectura | No |
| `module_mcp_context` | Charlie | lectura | No |
| `agent_runbook` | Global | lectura | No |
| `sige_fill_from_attachments` | SIGE | lectura | No |
| `search_medicines` | Vetiquín | lectura | No |
| `recommend_medicines` | Vetiquín | lectura | No |
| `list_clients` | Clientes | lectura | No |
| `list_overdue_invoices` | Facturación | lectura | No |
| `list_today_calendar` | Calendario | lectura | No |
| `staff_contracts_overview` | Personal | lectura | No |
| `prioritize_work` | Global | lectura | No |
| `client_followup_plan` | Clientes | lectura | No |
| `billing_risk_report` | Facturación | lectura | No |
| `medicine_review_queue` | Vetiquín | lectura | No |
| `medicine_withdrawal_watchlist` | Vetiquín | lectura | No |
| `milk_quality_review_queue` | Calidad lechera | lectura | No |
| `data_quality_audit` | Global | lectura | No |
| `record_briefing` | Global | lectura | No |
| `improve_report_text` | Certificación | lectura | No |
| `create_client` | Clientes | escritura | Sí |
| `create_action` | Acciones | escritura | Sí |
| `create_note` | Global | escritura | Sí |
| `create_calendar_event` | Calendario | escritura | Sí |
| `create_project` | Proyectos | escritura | Sí |
| `create_billing_invoice_draft` | Facturación | escritura | Sí |
| `create_staff_contract_draft` | Personal | escritura | Sí |

Las funciones nuevas de lectura calculan prioridades, riesgos, huecos, informes CMT, contratos o planes MCP sin escribir datos. Si Charlie propone convertir una recomendación en tarea, nota, cliente, evento, proyecto, factura o contrato, lo hace mediante una acción de escritura separada y confirmada.

En SIGE, `sige_fill_from_attachments` lee los documentos vinculados al expediente activo, usa el proveedor LLM configurado para Charlie cuando está disponible y devuelve sugerencias con campo, valor, confianza, fuente y motivo. No guarda campos del SIGE: la UI muestra cada propuesta, el usuario selecciona cuáles aplicar y después guarda el expediente por el flujo normal.

Las acciones de contratos de Personal conservan el mismo criterio sensible que el módulo: solo aparecen y se ejecutan con rol `admin`. Para otros roles, Charlie puede enseñar métricas generales de Personal, pero no listar ni preparar contratos.

## Ejemplo de Mensaje

```http
POST /api/charlie/message
Authorization: Bearer <token>
Content-Type: application/json

{
  "message": "busca facturas vencidas",
  "context": {
    "module": "billing"
  }
}
```

## Ejemplo con Vetiquín

```http
POST /api/charlie/message
Authorization: Bearer <token>
Content-Type: application/json

{
  "message": "recomienda medicamentos con principio activo amoxicilina para bovino",
  "context": {
    "module": "medicines"
  }
}
```

Charlie responde con resultados de `search_medicines` o `recommend_medicines`, enlazados al módulo `medicines`. En recomendaciones clínicas no debe inventar pauta, vía ni tiempos de espera: solo resume datos CIMAVet y recuerda revisar ficha técnica, especie destino e indicación.

## Ejemplo de Transcripción

```http
POST /api/charlie/transcribe-audio
Authorization: Bearer <token>
Content-Type: application/json

{
  "filename": "visita-granja.webm",
  "contentType": "audio/webm",
  "language": "es",
  "dataUrl": "data:audio/webm;base64,..."
}
```

## Ejemplo de Ejecución Confirmada

```http
POST /api/charlie/execute
Authorization: Bearer <token>
Content-Type: application/json

{
  "action": "create_client",
  "confirm": true,
  "parameters": {
    "name": "Ganadería Demo S.L.",
    "email": "demo@example.com",
    "phone": "+34 600 000 000"
  }
}
```

## Integración con un Modelo IA

El modelo no debe inventar endpoints. Debe consultar `/api/charlie/actions`, construir una intención con `action` y `parameters`, y ejecutar solo mediante `/api/charlie/execute`.

Flujo recomendado:

1. Interpretar la petición del usuario.
2. Seleccionar una acción del catálogo.
3. Validar datos obligatorios.
4. Si la acción escribe datos, mostrar resumen y pedir confirmación.
5. Ejecutar con `confirm: true`.
6. Mostrar resultado y enlace al módulo correspondiente.

## Estado Actual

Charlie queda preparado como capa IA transversal del ERP. La interfaz web incluye cálculo ambiental en segundo plano, sugerencias puntuales en módulos concretos, el módulo `Charlie`, el catálogo de acciones, el chat, el panel de confirmación, respuestas LLM en segundo plano y notas IA persistentes por módulo o registro.
