titulo: Arquitectura del agente logistico

dominio: ia

contenido: # Arquitectura del agente logistico


titulo: Arquitectura del agente logistico > Objetivo

contenido:
## Objetivo

LightDatai debe ser un agente logistico para operadores, administradores, clientes y choferes. Tiene que entender los circuitos del sistema y consultar datos vivos antes de responder.

No se conecta directo desde el navegador a Ollama/Gemma. El flujo correcto es:

```text
AppChat / modulo UI
  -> AppApi.iaLogisticaPreguntar()
  -> POST /controlador.php { accion:"ia.logistica.preguntar", pregunta, contextoUi }
  -> ControladorIa
      -> valida sesion/perfil
      -> planifica desde la pregunta (global por defecto)
      -> busca docs relevantes via RAG
      -> arma Context Pack operativo
      -> llama Ollama local
      -> devuelve respuesta + fuentes + acciones sugeridas
```

Regla de razonamiento: la pregunta del usuario manda. La ventana activa no limita la consulta; solo aporta contexto cuando el usuario dice "estos", "esta pantalla", "lo que estoy viendo", "filtrados" o "seleccionados". Para datos operativos, el backend planifica y consulta DB antes de pedir redaccion al modelo.


titulo: Arquitectura del agente logistico > Capas > 1. UI

contenido:
### 1. UI

- `base_php/js/core/AppChat.js`: conversacion con Asistente IA.
- `base_php/js/core/AppApi.js`: metodo `iaLogisticaPreguntar`.
- Modulos abiertos pueden aportar `estado()` y seleccion actual.

La UI no decide permisos ni consulta DB directa. Solo manda pregunta y contexto visual opcional.


titulo: Arquitectura del agente logistico > Capas > 2. Puerta unica

contenido:
### 2. Puerta unica

Todo entra por:

```text
POST /controlador.php
```

Accion propuesta:

```text
ia.logistica.preguntar
```

Esto mantiene la auditoria, sesion PHP, hash de sesion y multi-tenant.


titulo: Arquitectura del agente logistico > Capas > 3. Backend IA

contenido:
### 3. Backend IA

Archivo runtime propuesto:

```text
back/sistema/controlador_ia.php
```

Esta carpeta `back/lightdata_ai/` documenta la arquitectura; el controlador ejecutable vive en `back/sistema/` para respetar el patron actual de controladores.

Responsabilidades:

- validar pregunta;
- conocer usuario, perfil y alcance;
- recuperar documentos relevantes;
- armar contexto operativo;
- llamar al modelo local;
- normalizar la respuesta;
- devolver acciones sugeridas, no ejecutarlas.


titulo: Arquitectura del agente logistico > Capas > 4. RAG documental

contenido:
### 4. RAG documental

El agente no tiene que memorizar todos los docs. Debe buscar fragmentos relevantes en:

- `manuales_y_circuitos/`
- `docs/`
- `docs/modulos/`
- `docs/DICCIONARIO-DATOS.md`
- `docs/CIRCUITOS-MS.md`
- `docs/MODELO-DATOS.md`
- esta carpeta `back/lightdata_ai/`


titulo: Arquitectura del agente logistico > Capas > 5. Datos vivos

contenido:
### 5. Datos vivos

El agente usa MySQL/Redis/MS segun intencion:

- envio puntual: `ControladorEnvios::obtener`;
- listado/riesgo: `ControladorEnvios::listar`;
- dashboard: `ControladorInformes::dashboard`;
- zonas/clientes/choferes: catalogos;
- GPS/presencia: Redis/WS;
- health: `ControladorHealth`;
- costos/liquidaciones: controladores/procesos existentes.


titulo: Arquitectura del agente logistico > Capas > 6. Capacidades operativas

contenido:
### 6. Capacidades operativas

El agente no debe razonar con un diccionario de frases. Debe elegir entre capacidades validadas del OS:

- ruta UI (`envios.listado`, `informes.porzonas`, `informes.porcliente`);
- herramienta disponible (`consultarEnvios`, `consultarInforme`);
- controlador backend real (`ControladorEnvios`, `ControladorInformes`);
- tablas fuente (`envios`, `envios_zonas`, `estados_envios`, etc.);
- dimensiones y metricas que puede agrupar.

El catalogo runtime vive en:

```text
back/lightdata_ai/capacidades.php
```

Ejemplo: si el usuario pregunta "pendientes por zonas", el agente debe elegir `informes.porzonas`, no tratar "zona" como texto libre ni inventar una zona. La respuesta se arma con `ControladorInformes::envios(['por' => 'zona'])` y estados reales de `estados_envios`.


titulo: Arquitectura del agente logistico > Capas > 7. Conocimiento operativo

contenido:
### 7. Conocimiento operativo

Antes de elegir una capacidad, el agente necesita entender el circuito y el modelo de datos:

- `envios.estado` es el estado actual;
- `estados_envios` traduce el DID de estado;
- `envios_historial` explica cambios y fecha de estado;
- `envios_direcciones_destino.didEnvioZona` relaciona un envio con `envios_zonas`;
- `clientes.nombre_fantasia` es el nombre operacional del cliente;
- `pendientes` no es un texto: es una regla sobre estados no cerrados.

El conocimiento runtime vive en:

```text
back/lightdata_ai/conocimiento.php
```

Flujo correcto:

```text
lenguaje natural
  -> conocimiento operativo: tablas, campos, relaciones, estados, circuitos
  -> capacidad/herramienta validada
  -> controlador backend real
  -> respuesta con datos vivos
  -> accion UI opcional
```


titulo: Arquitectura del agente logistico > Principios

contenido:
## Principios

- El agente responde solo con fuentes recuperadas o datos consultados.
- Si falta informacion, debe decirlo.
- Las consultas respetan permisos del perfil.
- Las respuestas deben ser breves, operativas y accionables.
- Las acciones reales requieren confirmacion y backend server-side.
- El contexto enviado al modelo debe ser chico y explicable.


titulo: Arquitectura del agente logistico > Flujo de una pregunta

contenido:
## Flujo de una pregunta

Ejemplo:

```text
"por que no se liquido el envio SEED-CABA-015?"
```

1. Detectar intencion: `explicar_liquidacion` + tracking.
2. Buscar envio por tracking.
3. Traer cabecera, historial, costos, liquidaciones y cliente.
4. Recuperar docs de liquidaciones, costos y estados pagables.
5. Armar contexto.
6. Llamar modelo.
7. Responder con causa probable, evidencia y accion sugerida.


titulo: Arquitectura del agente logistico > Salida esperada

contenido:
## Salida esperada

```json
{
  "respuesta": "El envio no se liquido porque el movimiento del chofer todavia figura con precioProcesado=0...",
  "intencion": "explicar_liquidacion",
  "fuentes": [
    { "tipo": "db", "nombre": "envios", "did": 123 },
    { "tipo": "doc", "path": "docs/DICCIONARIO-DATOS.md" }
  ],
  "acciones": [
    {
      "tipo": "abrir_modulo",
      "label": "Abrir ficha del envio",
      "payload": { "ruta": "envios.ficha", "opts": { "did": 123 } }
    }
  ]
}
```


titulo: RAG documental > Que es RAG

contenido:
## Que es RAG

RAG significa `Retrieval-Augmented Generation`: generacion aumentada con busqueda.

En Lightdata:

```text
Usuario pregunta
  -> el backend busca docs/circuitos/tablas relevantes
  -> arma contexto corto
  -> el modelo responde con ese contexto
```

El modelo no debe tener todos los manuales pegados en cada prompt. Debe recibir solo los fragmentos necesarios.


titulo: RAG documental > Por que lo necesitamos

contenido:
## Por que lo necesitamos

El agente tiene que entender:

- circuitos end-to-end;
- significado de estados;
- tablas y relaciones;
- permisos por perfil;
- procesos batch;
- microservicios;
- reglas de costos y liquidaciones;
- que modulo abrir para cada tarea.

Ese conocimiento es estable, cambia con el codigo y debe venir de documentos versionados.


titulo: RAG documental > Corpus inicial

contenido:
## Corpus inicial

Indexar estos archivos:

```text
manuales_y_circuitos/*.md
docs/*.md
docs/modulos/*.md
procesos/*.md
MS/README.md
back/lightdata_ai/*.md
```

Prioridad alta:

- `manuales_y_circuitos/02-circuitos-end-to-end.md`
- `manuales_y_circuitos/03-manual-tecnico-desarrollo.md`
- `manuales_y_circuitos/04-estado-modulos.md`
- `manuales_y_circuitos/06-microservicios-y-procesos.md`
- `manuales_y_circuitos/07-agente-logistico-ia.md`
- `manuales_y_circuitos/08-redis-cache-operativo.md`
- `docs/DICCIONARIO-DATOS.md`
- `docs/CIRCUITOS-MS.md`
- `docs/MODELO-DATOS.md`


titulo: RAG documental > Chunking

contenido:
## Chunking

Partir documentos por seccion Markdown:

```text
titulo h1
subtitulo h2/h3
contenido
path
line_start
line_end
tags
```

Tamanio recomendado:

- 400 a 900 tokens por chunk;
- solapamiento bajo, 50 a 100 tokens;
- conservar encabezados para contexto.


titulo: RAG documental > Metadata

contenido:
## Metadata

Cada chunk debe tener:

```json
{
  "id": "docs/DICCIONARIO-DATOS.md#envios_historial",
  "path": "docs/DICCIONARIO-DATOS.md",
  "titulo": "envios_historial",
  "dominio": "envios",
  "tipo": "diccionario",
  "tags": ["envios", "historial", "estado", "precioProcesado"],
  "line_start": 120,
  "line_end": 155
}
```


titulo: RAG documental > Busqueda

contenido:
## Busqueda

Primera version simple:

- busqueda textual BM25/LIKE sobre indice local;
- tags manuales por path/seccion;
- ranking por coincidencias de dominio.

Version mejor:

- embeddings locales;
- vector store en Redis/SQLite/Postgres;
- reranking con reglas por modulo/intencion.

Como ya existe Gemma/Ollama local, una alternativa practica es usar embeddings locales con Ollama si el modelo de embeddings esta disponible. Si no, arrancar con busqueda textual.


titulo: RAG documental > Pipeline recomendado

contenido:
## Pipeline recomendado

```text
pregunta
  -> detectar dominio/intencion
  -> buscar 5-12 chunks relevantes
  -> filtrar por score y dominio
  -> compactar a "contexto_documental"
  -> combinar con "contexto_operativo"
  -> llamar modelo
```


titulo: RAG documental > Ejemplos

contenido:
## Ejemplos

Pregunta:

```text
"por que no se calculo el costo del chofer?"
```

Docs a recuperar:

- proceso chofer lista de precios;
- `envios_historial.precioProcesado`;
- `costos_envios`;
- `sistema_usuarios.lista_de_precios`;
- `sistema_usuarios_accesos.estados_precio`.

Pregunta:

```text
"como se actualiza el informe por zona?"
```

Docs a recuperar:

- `docs/CIRCUITOS-MS.md`;
- `MS/README.md`;
- `ControladorInformes`;
- Redis/cache operativo si pregunta por performance.


titulo: RAG documental > Prompt documental

contenido:
## Prompt documental

El backend debe pasar algo asi:

```text
CONTEXTO_DOCUMENTAL:
[1] docs/DICCIONARIO-DATOS.md#envios_historial
envios_historial guarda un movimiento por cambio de estado...

[2] procesos/README.md#proceso_chofer_listaprecios
El proceso usa precioProcesado=0...
```

El modelo debe citar o nombrar las fuentes si la respuesta depende de ellas.


titulo: RAG documental > Ingestion

contenido:
## Ingestion

Comando futuro sugerido:

```text
php back/lightdata_ai/scripts/index_docs.php
```

Salida:

```text
back/lightdata_ai/index/docs_index.jsonl
```

No hace falta resolver embeddings en la primera version. Lo importante es tener el contrato y los chunks.


titulo: Contexto operativo

dominio: general

contenido: # Contexto operativo


titulo: Contexto operativo > Objetivo

contenido:
## Objetivo

El contexto operativo es el JSON vivo que se arma para cada pregunta. Debe incluir solo los datos necesarios, respetando permisos y evitando mandar tablas completas al modelo.


titulo: Contexto operativo > Estructura base

contenido:
## Estructura base

```json
{
  "tenant": {
    "did": 1,
    "nombre": "Demo Lightdata",
    "fechaSistema": "2026-06-08",
    "timezone": "America/Buenos_Aires"
  },
  "usuario": {
    "did": 22,
    "perfil": "adm",
    "tipo": "adm",
    "alcance": "tenant"
  },
  "ui": {
    "modulo": "envios.listado",
    "filtros": {},
    "seleccion": [],
    "vista": {}
  },
  "intencion": "analisis_envios",
  "catalogos": {},
  "operacion": {},
  "documentos": []
}
```


titulo: Contexto operativo > Contexto UI

contenido:
## Contexto UI

El front puede mandar:

```json
{
  "modulo": "envios.listado",
  "filtros": {
    "tipoFecha": "estado",
    "desde": "2026-06-08",
    "hasta": "2026-06-08",
    "estados": [3,4]
  },
  "seleccion": [123,124],
  "vista": {
    "page": 1,
    "perPage": 50,
    "sort": { "col": "fechaEstado", "dir": "desc" }
  }
}
```

El backend debe tratar esto como sugerencia, no como permiso.


titulo: Contexto operativo > Intenciones y datos

contenido:
## Intenciones y datos

| Intencion | Datos vivos |
|---|---|
| `tracking` | envio exacto, historial, observaciones, asignaciones |
| `analisis_envios` | resumen, muestra filtrada, riesgos |
| `ruteo` | choferes, zonas, envios asignables, GPS si aplica |
| `cobranzas` | envios cobrables, liquidaciones, costos |
| `dashboard` | agregados por estado/zona/chofer, health |
| `ayuda_sistema` | documentos RAG, modulo activo |
| `explicar_liquidacion` | envio, historial, costos, estados pagables, liquidaciones |


titulo: Contexto operativo > Datos minimos por envio

dominio: envios

contenido:
## Datos minimos por envio

```json
{
  "did": 123,
  "tracking": "SEED-CABA-015",
  "cliente": "Deco Hogar",
  "origen": "Directo",
  "estado": 3,
  "estadoNombre": "En planta de procesamiento",
  "fechaVenta": "2026-06-06",
  "fechaEstado": "2026-06-06 10:17",
  "destino": {
    "nombre": "Lucia Ruiz",
    "cp": "1431",
    "localidad": "CABA",
    "zona": "CABA"
  },
  "chofer": "",
  "flags": {
    "sinChofer": true,
    "sinZona": false,
    "demorado": true,
    "cobranza": false,
    "logisticaInversa": false
  }
}
```


titulo: Contexto operativo > Resumen operativo

contenido:
## Resumen operativo

```json
{
  "totalEnvios": 82,
  "porEstado": {
    "2": 9,
    "3": 14,
    "5": 21
  },
  "riesgos": {
    "sinChofer": 8,
    "sinZona": 3,
    "demorados": 12,
    "conCobranza": 5
  },
  "porZona": [],
  "porChofer": []
}
```


titulo: Contexto operativo > Permisos

contenido:
## Permisos

Respetar los controladores existentes:

- perfil chofer/logistica externa: solo envios asignados;
- perfil cliente: solo clientes vinculados;
- admin/coordinador: segun permisos del sistema;
- nunca mandar datos de otros tenants.

La seguridad real vive en backend. La UI no filtra como garantia.


titulo: Contexto operativo > Limites

contenido:
## Limites

- muestra de envios: 25 a 60 maximo;
- historial por envio: ultimos 20 movimientos;
- docs RAG: 5 a 12 chunks;
- contexto IA cacheable: 60 a 180 segundos;
- no mandar payloads de integraciones salvo intencion especifica.


titulo: Contexto operativo > Datos sensibles

contenido:
## Datos sensibles

Por defecto excluir:

- telefonos;
- emails;
- tokens;
- direcciones completas;
- payloads `dataCuenta`;
- valores de credenciales;
- logs crudos.

Incluirlos solo si la pregunta lo requiere y el perfil puede verlos.


titulo: Contexto operativo > Fuentes

contenido:
## Fuentes

Toda respuesta deberia poder explicar de donde salio:

```json
[
  { "tipo": "db", "tabla": "envios", "did": 123 },
  { "tipo": "redis", "clave": "ops:1:envios:resumen" },
  { "tipo": "doc", "path": "docs/DICCIONARIO-DATOS.md", "titulo": "envios_historial" }
]
```


titulo: Herramientas del agente

contenido: # Herramientas del agente


titulo: Herramientas del agente > Objetivo

contenido:
## Objetivo

El agente no debe depender solo de texto. Debe poder pedir herramientas controladas al backend para consultar datos y preparar acciones.


titulo: Herramientas del agente > Tipos de herramienta

contenido: ## Tipos de herramienta


titulo: Herramientas del agente > Tipos de herramienta > Lectura

contenido:
### Lectura

Estas herramientas consultan y devuelven datos.

```text
buscar_envio
obtener_envio
listar_envios_riesgo
resumen_operacion
buscar_cliente
buscar_chofer
consultar_cobranzas
consultar_liquidacion
consultar_health
buscar_docs
```


titulo: Herramientas del agente > Tipos de herramienta > Navegacion UI

contenido:
### Navegacion UI

Estas herramientas no cambian datos; preparan botones para la UI.

```text
abrir_modulo
abrir_envio
abrir_cliente
abrir_informe
aplicar_filtros
```


titulo: Herramientas del agente > Tipos de herramienta > Preparacion de acciones

contenido:
### Preparacion de acciones

Estas herramientas preparan payloads. Siempre requieren confirmacion.

```text
preparar_cambio_estado
preparar_asignacion_chofer
preparar_observacion
preparar_reimpresion
preparar_reprocesar_preenvio
```


titulo: Herramientas del agente > Contrato general

contenido:
## Contrato general

```json
{
  "tool": "buscar_envio",
  "args": {
    "tracking": "SEED-CABA-015"
  }
}
```

Respuesta:

```json
{
  "ok": true,
  "data": {},
  "fuentes": []
}
```


titulo: Herramientas del agente > Herramientas iniciales

contenido: ## Herramientas iniciales


titulo: Herramientas del agente > Herramientas iniciales > Catalogo de capacidades

contenido:
### Catalogo de capacidades

Antes de llamar una herramienta, el agente debe elegir una capacidad validada de:

```text
back/lightdata_ai/capacidades.php
```

Esto evita diccionarios por frase. Ejemplos:

| Pregunta | Capacidad | Herramienta | Backend |
|---|---|---|---|
| pendientes por zonas | `informes.porzonas` | `consultarInforme({tipo:"zonas"})` | `ControladorInformes::envios(['por'=>'zona'])` |
| pendientes por cliente | `informes.porcliente` | `consultarInforme({tipo:"clientes"})` | `ControladorInformes::envios(['por'=>'cliente'])` |
| envios cancelados desde una fecha | `envios.listado` | `consultarEnvios` | `ControladorEnvios::listar/resumen` |
| crear ruta por zona para chofer | `ruteate.preparar_asignacion_zona_chofer` | `prepararAsignacionRuta` | `ControladorEnvios` + `sistema_usuarios` + `ruteate.asignacionProcesar` |


titulo: Herramientas del agente > Herramientas iniciales > Conocimiento operativo previo

contenido:
### Conocimiento operativo previo

Las capacidades no alcanzan solas. El agente debe tener contexto de tablas/campos/circuitos desde:

```text
back/lightdata_ai/conocimiento.php
```

Ese contexto le dice, por ejemplo:

- estado actual: `envios.estado -> estados_envios.did`;
- fecha de estado: `MAX(envios_historial.fecha)`;
- zona de entrega: `envios_direcciones_destino.didEnvioZona -> envios_zonas.did`;
- informe por zonas: agrupacion de `ControladorInformes::envios(['por'=>'zona'])`;
- pendientes: estados que no son cerrados segun `estados_envios`.
- ruta/asignacion: seleccionar envios ruteables por zona de entrega, resolver chofer operativo y preparar confirmacion; no reasignar envios de otros choferes sin pedido explicito.


titulo: Herramientas del agente > Herramientas iniciales > `buscar_envio`

contenido:
### `buscar_envio`

Entrada:

```json
{ "tracking": "SEED-CABA-015", "idVenta": "", "idPack": "" }
```

Salida:

```json
{
  "envios": [
    { "did": 123, "tracking": "SEED-CABA-015", "estado": 3, "cliente": "Deco Hogar" }
  ]
}
```


titulo: Herramientas del agente > Herramientas iniciales > `obtener_envio`

contenido:
### `obtener_envio`

Entrada:

```json
{ "did": 123 }
```

Usa `ControladorEnvios::obtener`.


titulo: Herramientas del agente > Herramientas iniciales > `resumen_operacion`

contenido:
### `resumen_operacion`

Entrada:

```json
{ "fecha": "2026-06-08", "filtros": {} }
```

Primero intenta Redis:

```text
ops:{tenant}:envios:resumen
ops:{tenant}:envios:por_estado
ops:{tenant}:envios:por_zona
ops:{tenant}:envios:por_chofer
```

Si no hay cache, consulta DB y guarda TTL corto.


titulo: Herramientas del agente > Herramientas iniciales > `buscar_docs`

contenido:
### `buscar_docs`

Entrada:

```json
{ "query": "como se liquida el costo del chofer", "tags": ["liquidaciones", "costos"] }
```

Salida:

```json
{
  "chunks": [
    {
      "path": "procesos/README.md",
      "titulo": "proceso_chofer_listaprecios",
      "texto": "..."
    }
  ]
}
```


titulo: Herramientas del agente > Acciones sugeridas para UI

contenido:
## Acciones sugeridas para UI

El endpoint puede devolver:

```json
{
  "acciones": [
    {
      "tipo": "abrir_modulo",
      "label": "Ver envios demorados",
      "payload": {
        "ruta": "envios.listado",
        "estado": {
          "filtros": { "estados": [3], "asignado": "0" }
        }
      }
    },
    {
      "tipo": "preparar_cambio_estado",
      "label": "Pasar seleccionados a En camino",
      "payload": {
        "dids": [123,124],
        "estado": 4
      },
      "requiereConfirmacion": true
    }
  ]
}
```


titulo: Herramientas del agente > Reglas de seguridad

contenido:
## Reglas de seguridad

- Ninguna herramienta escribe sin endpoint especifico y confirmacion UI.
- El backend revalida permisos.
- No se ejecutan SQL libres generados por el modelo.
- No se aceptan nombres de tabla/columna arbitrarios desde el modelo.
- Las herramientas exponen funciones de dominio, no acceso crudo a DB.


titulo: Herramientas del agente > Roadmap de herramientas

contenido:
## Roadmap de herramientas

Fase 1:

- `buscar_docs`
- `buscar_envio`
- `obtener_envio`
- `resumen_operacion`

Fase 2:

- `listar_envios_riesgo`
- `buscar_cliente`
- `buscar_chofer`
- `consultar_cobranzas`

Fase 3:

- acciones preparadas con confirmacion;
- apertura de modulos con filtros;
- explicaciones de liquidacion/costos.


titulo: Redis y cache para el agente

dominio: ms

contenido: # Redis y cache para el agente


titulo: Redis y cache para el agente > Rol de Redis

contenido:
## Rol de Redis

Redis alimenta al agente con estado caliente y evita consultas repetidas cuando el usuario pregunta varias cosas seguidas.

No reemplaza a MySQL.

```text
MySQL = verdad
Redis = cache, estado reciente, locks, sesiones
RAG = conocimiento estable
Modelo = razonamiento
```


titulo: Redis y cache para el agente > Claves que usa el agente

contenido: ## Claves que usa el agente


titulo: Redis y cache para el agente > Claves que usa el agente > Sesion y presencia

contenido:
### Sesion y presencia

```text
rt:session:{tenant}:{uid}:{hash}
rt:presence:{tenant}
```

Uso:

- validar WS;
- saber usuarios conectados;
- responder preguntas como "que choferes estan online?".


titulo: Redis y cache para el agente > Claves que usa el agente > GPS

dominio: ruteate

contenido:
### GPS

```text
geo:last:{tenant}:{chofer}
```

Uso:

- ultimo punto conocido;
- preguntas de ubicacion;
- contexto de En Mano/GeoChoferes.


titulo: Redis y cache para el agente > Claves que usa el agente > Catalogos

contenido:
### Catalogos

```text
cat:{tenant}:estados_envios
cat:{tenant}:clientes
cat:{tenant}:choferes
cat:{tenant}:zonas
cat:{tenant}:depositos
cat:{tenant}:servicios
cat:{tenant}:listas
cat:{tenant}:listaschofer
```

Uso:

- traducir DIDs a nombres;
- interpretar estados;
- resolver filtros;
- armar contexto compacto.


titulo: Redis y cache para el agente > Claves que usa el agente > Operacion

contenido:
### Operacion

```text
ops:{tenant}:envios:resumen
ops:{tenant}:envios:por_estado
ops:{tenant}:envios:por_zona
ops:{tenant}:envios:por_chofer
ops:{tenant}:enmano:{fecha}
```

Uso:

- dashboard IA;
- preguntas generales;
- alertas de riesgo;
- contexto rapido.


titulo: Redis y cache para el agente > Claves que usa el agente > Contexto IA

contenido:
### Contexto IA

```text
ia:{tenant}:context:logistica:{uid}:{hashCorto}
```

TTL: 60 a 180 segundos.

Uso:

- reutilizar contexto entre preguntas de la misma conversacion;
- evitar reconstruir catalogos/resumen constantemente;
- invalidar cuando cambia filtro, seleccion o evento operativo.


titulo: Redis y cache para el agente > Invalidacion

contenido:
## Invalidacion

| Evento | Claves |
|---|---|
| cambio de estado | `ops:{tenant}:envios:*`, `ia:{tenant}:context:logistica:*` |
| asignacion | `ops:{tenant}:envios:por_chofer`, `ops:{tenant}:enmano:*`, `ia:{tenant}:context:logistica:*` |
| zona asignada | `ops:{tenant}:envios:por_zona`, `ia:{tenant}:context:logistica:*` |
| guardar cliente | `cat:{tenant}:clientes` |
| guardar usuario/chofer | `cat:{tenant}:choferes`, `rt:presence:{tenant}` |
| guardar zona | `cat:{tenant}:zonas`, `route:{tenant}:zonas_resolver` |
| guardar listas | `cat:{tenant}:listas`, `price:{tenant}:cliente:*` |
| guardar listas chofer | `cat:{tenant}:listaschofer`, `price:{tenant}:chofer:*` |

Usar `SCAN`, no `KEYS`, para borrar patrones en produccion.


titulo: Redis y cache para el agente > Cache-aside

contenido:
## Cache-aside

Patron recomendado:

```text
leer:
  GET redis
  si existe -> usar
  si no -> DB -> SETEX -> usar

guardar:
  DB
  DEL/SCAN claves afectadas
```


titulo: Redis y cache para el agente > No cachear

contenido:
## No cachear

- listados completos de envios;
- historial completo;
- auditoria;
- liquidaciones finales;
- costos definitivos;
- payloads de integraciones;
- datos sensibles sin TTL corto.


titulo: Redis y cache para el agente > Relacion con documento central

contenido:
## Relacion con documento central

Ver tambien:

```text
manuales_y_circuitos/08-redis-cache-operativo.md
```

Ese documento define la estrategia global de Redis para todo Lightdata OS. Este archivo baja el uso especifico para el agente.


titulo: Endpoints y contratos

contenido: # Endpoints y contratos


titulo: Endpoints y contratos > Endpoint principal

contenido:
## Endpoint principal

```http
POST /controlador.php
Content-Type: application/json
```

Request:

```json
{
  "accion": "ia.logistica.preguntar",
  "pregunta": "que envios estan demorados hoy?",
  "contextoUi": {
    "modulo": "envios.listado",
    "filtros": {},
    "seleccion": []
  }
}
```

`contextoUi` es opcional para el razonamiento. El agente consulta globalmente por defecto y solo usa la vista activa cuando la pregunta contiene referencias como "estos", "esta pantalla", "lo que estoy viendo", "filtrados" o "seleccionados".

Response:

```json
{
  "ok": true,
  "respuesta": "Tenes 12 envios con riesgo operativo...",
  "intencion": "analisis_envios",
  "fuentes": [
    { "tipo": "planner", "nombre": "global" },
    { "tipo": "db", "nombre": "envios" }
  ],
  "acciones": [],
  "debug": {
    "modelo": "qwen2.5:7b-instruct",
    "plan": {
      "dominio": "envios",
      "intencion": "conteo_envios",
      "base": "global",
      "estado": { "did": 7, "nombre": "A retirar" }
    }
  }
}
```

Ejemplos esperados:

```text
Usuario: cuantos envios a retirar tengo?
Respuesta: Tenes 15 envios en estado A retirar.

Usuario: de 1 semana para atras cuanto tengo a retirar?
Respuesta: Tenes 15 envios en estado A retirar entre 2026-06-01 y 2026-06-08.

Usuario: cuantos envios tuve?
Respuesta: Para verlo bien, decime el rango de fechas y si queres contar por fecha de estado, venta o carga.

Usuario: abrime envios filtrado por el cliente mongocho
Respuesta: Tenes 0 envios.
Accion: abrir `envios.listado` con `{ "filtros": { "nombre": "mongocho" }, "page": 1 }`.

Usuario: decime cuantos pendientes tengo por zonas?
Respuesta: Tenes 82 envios pendientes por zona: Sin zona: 73, Sur: 7, Norte: 2.
Capacidad: `informes.porzonas`.
Accion: abrir `informes.porzonas`.

Usuario: podes crear una ruta para envios de zona sur, para el chofer teta? si no los tiene asignacelos.
Respuesta: Zona Sur: encontre 7 envios. 0 ya estan asignados a Chofer Teta. 7 estan sin asignar y puedo prepararlos para asignar a Chofer Teta con confirmacion.
Capacidad: `ruteate.preparar_asignacion_zona_chofer`.
Acciones: previsualizar `ruteate.rutear` y confirmar `ruteate.asignacionProcesar`.
```


titulo: Endpoints y contratos > AppApi

contenido:
## AppApi

Metodo propuesto:

```js
async iaLogisticaPreguntar({ pregunta, contextoUi = {} }) {
  const d = await this._post('ia.logistica.preguntar', { pregunta, contextoUi });
  return {
    respuesta: d.respuesta || '',
    intencion: d.intencion || '',
    fuentes: d.fuentes || [],
    acciones: d.acciones || [],
    debug: d.debug || {},
  };
}
```


titulo: Endpoints y contratos > Dispatch PHP

contenido:
## Dispatch PHP

En `empresa_demo/controlador.php`:

```php
if ($modulo === 'ia') {
    $c = new ControladorIa(db(), (int)$_SESSION['uid']);
    switch ($metodo) {
        case 'logistica.preguntar':
            salir(['ok' => true] + $c->preguntarLogistica($in));
    }
}
```


titulo: Endpoints y contratos > Controlador

contenido:
## Controlador

Archivo runtime:

```text
back/sistema/controlador_ia.php
```

Metodos esperados:

```php
class ControladorIa
{
    public function preguntarLogistica(array $in): array;
    private function detectarIntencion(string $pregunta, array $ui): string;
    private function armarContexto(string $intencion, array $ui): array;
    private function llamarModelo(array $messages): string;
}
```


titulo: Endpoints y contratos > Ollama

contenido:
## Ollama

Variables:

```text
LD_IA_OLLAMA_URL=http://127.0.0.1:11434
LD_IA_LOGISTICA_MODELO=qwen2.5:7b-instruct
LD_IA_TIMEOUT=150
LD_IA_MAX_ENVIOS=60
```

Request a Ollama:

```json
{
  "model": "qwen2.5:7b-instruct",
  "stream": false,
  "messages": [
    { "role": "system", "content": "..." },
    { "role": "user", "content": "..." }
  ],
  "options": {
    "temperature": 0.2,
    "num_ctx": 8192
  }
}
```


titulo: Endpoints y contratos > Prompt base

contenido:
## Prompt base

```text
Sos LightDatai, un agente logistico para operadores de un TMS.
Responde en espanol claro, breve y accionable.
Usa solo CONTEXTO_DOCUMENTAL y CONTEXTO_OPERATIVO.
Si falta un dato, decilo.
No inventes tracking, estados, choferes, zonas ni cantidades.
No ejecutes cambios. Solo propone acciones para confirmar en UI.
```


titulo: Endpoints y contratos > Errores

contenido:
## Errores

Modelo caido:

```json
{
  "ok": false,
  "error": "No pude consultar el modelo local",
  "codigo": "IA_MODELO_NO_DISPONIBLE"
}
```

Pregunta vacia:

```json
{
  "ok": false,
  "error": "Falta pregunta",
  "codigo": "IA_PREGUNTA_VACIA"
}
```

Sin datos:

```json
{
  "ok": true,
  "respuesta": "No encontre datos suficientes con los filtros actuales.",
  "intencion": "analisis_envios",
  "fuentes": [],
  "acciones": []
}
```


titulo: Roadmap de implementacion

contenido: # Roadmap de implementacion


titulo: Roadmap de implementacion > Fase 0 - Documentacion

contenido:
## Fase 0 - Documentacion

Estado: en curso.

- Crear `back/lightdata_ai/`.
- Documentar arquitectura, RAG, contexto, Redis y endpoints.
- Conectar con manuales existentes.


titulo: Roadmap de implementacion > Fase 1 - Endpoint IA minimo

contenido:
## Fase 1 - Endpoint IA minimo

Estado: implementado base.

Objetivo: que el chat responda usando endpoint propio y modelo local.

Tareas:

- [x] Crear `back/sistema/controlador_ia.php`.
- [x] Agregar dispatch `ia.logistica.preguntar`.
- [x] Agregar `AppApi.iaLogisticaPreguntar`.
- [x] Modificar `AppChat` para reemplazar respuesta mock de IA.
- [x] Armar contexto basico: usuario, tenant, modulo activo, filtros.
- [x] Llamar Ollama `qwen2.5:7b-instruct`.

Aceptacion:

- [x] el navegador no llama a `localhost:11434`;
- [x] la auditoria registra `ia.logistica.preguntar`;
- [x] si Ollama esta caido, la UI responde con error amable.


titulo: Roadmap de implementacion > Fase 2 - RAG documental textual

contenido:
## Fase 2 - RAG documental textual

Objetivo: que el agente entienda circuitos y DB.

Tareas:

- Crear index JSONL de documentos.
- Chunkear Markdown por secciones.
- Buscar por texto/tags.
- Incluir 5-12 chunks por pregunta.
- Agregar fuentes documentales en respuesta.

Aceptacion:

- pregunta sobre costos recupera procesos/listas/diccionario;
- pregunta sobre realtime recupera `CIRCUITOS-MS` y `MS/README`;
- respuesta no inventa tablas.


titulo: Roadmap de implementacion > Fase 3 - Contexto operativo real

contenido:
## Fase 3 - Contexto operativo real

Estado: iniciado con planner global para envios.

Objetivo: responder sobre datos vivos sin depender de la ventana activa ni de que el modelo llame herramientas.

Avance:

- [x] Planner global para conteos/listados de envios.
- [x] Acciones ejecutables desde chat (`abrir_modulo` + `estado`).
- [x] Abrir `envios.listado` con filtros derivados de lenguaje natural, por ejemplo cliente -> `filtros.nombre`.
- [x] Catalogo de capacidades operativas para elegir rutas/herramientas/controladores sin diccionarios de frases.

Tareas:

- [x] Reusar `ControladorEnvios` para conteos/listas globales de envios.
- [x] Detectar estado real desde `estados_envios` (`A retirar`, `Retirado`, etc.).
- [x] Interpretar fechas basicas: hoy, ayer, semana pasada, ultimos N dias/semanas.
- [x] Usar la ventana activa solo ante frases como "estos", "esta pantalla", "lo que estoy viendo".
- [x] Reusar `ControladorInformes` para agregados como `informes.porzonas` e `informes.porcliente`.
- [ ] Reusar `ControladorUsuarios`, `ControladorHealth`.
- [ ] Detectar tracking/ID/cliente/chofer con mas cobertura.
- [ ] Armar resumen operativo multi-dominio.
- Traer envio puntual con historial si aplica.
- Respetar permisos de perfil.

Aceptacion:

- [ ] "que paso con X" trae ficha real;
- [ ] "como estamos hoy" trae dashboard/resumen;
- [x] "cuantos envios a retirar tengo" consulta DB global y responde total vigente;
- [x] "de 1 semana para atras cuanto tengo a retirar" interpreta rango y consulta DB;
- [x] "cuantos pendientes tengo por zonas" elige `informes.porzonas` y no inventa zonas;
- [x] cliente/chofer no ve datos fuera de alcance porque se reutiliza `ControladorEnvios`.


titulo: Roadmap de implementacion > Fase 4 - Redis operativo

contenido:
## Fase 4 - Redis operativo

Objetivo: reducir DB y alimentar IA con estado caliente.

Tareas:

- Helper PHP de Redis/cache.
- Cache de catalogos.
- Cache de resumen operativo con TTL corto.
- `rt:presence:{tenant}`.
- `ia:{tenant}:context:logistica:{uid}:{hashCorto}`.
- Invalidaciones por CRUD y eventos MS.

Aceptacion:

- preguntas seguidas no reconstruyen todo;
- cambios de estado invalidan contexto;
- Redis caido degrada a DB.


titulo: Roadmap de implementacion > Fase 5 - Acciones sugeridas

contenido:
## Fase 5 - Acciones sugeridas

Objetivo: que el agente ayude a operar sin ejecutar sin permiso.

Tareas:

- Devolver `acciones[]`.
- UI pinta botones.
- Acciones de navegacion: abrir modulo/ficha/informe.
- Acciones preparadas: cambio estado/asignacion/observacion.
- Confirmacion obligatoria.

Aceptacion:

- el agente puede abrir envios filtrados;
- no ejecuta cambios sin modal;
- backend revalida permisos.


titulo: Roadmap de implementacion > Fase 6 - Embeddings/vector search

contenido:
## Fase 6 - Embeddings/vector search

Objetivo: mejorar RAG.

Opciones:

- embeddings locales con Ollama;
- SQLite/JSONL al inicio;
- Redis vector si se habilita modulo compatible;
- otro vector store si conviene.

No bloquear Fase 1-5 por embeddings. La busqueda textual bien etiquetada alcanza para arrancar.


titulo: Roadmap de implementacion > Fase 7 - Memoria conversacional

contenido:
## Fase 7 - Memoria conversacional

Objetivo: continuidad entre preguntas.

Tareas:

- Tabla `ia_conversaciones` o Redis TTL.
- Guardar resumen del hilo, no prompt completo.
- Feedback util/no util.
- Historial visible por usuario si se decide.

Aceptacion:

- el agente entiende "y de esos cuales estan sin chofer";
- no guarda datos sensibles innecesarios;
- el usuario puede reiniciar contexto.


titulo: Lightdata AI

contenido:
# Lightdata AI

Carpeta de arquitectura y documentacion del agente logistico de Lightdata OS.

El objetivo es que el agente pueda responder y asistir sobre la operacion sin depender de memoria inventada del modelo. Para eso combina:

- RAG documental: manuales, circuitos, diccionario de datos y documentacion de modulos.
- Contexto operativo vivo: MySQL tenant, Redis operativo, WebSocket/GPS e informes.
- Herramientas controladas: buscar envios, leer historiales, resumir operacion, sugerir acciones y abrir modulos.


titulo: Lightdata AI > Indice

contenido:
## Indice

1. [01-arquitectura.md](01-arquitectura.md)
   - Vision general del agente, flujo front -> endpoint -> contexto -> modelo.

2. [02-rag-documental.md](02-rag-documental.md)
   - Que es RAG, que documentos indexar y como recuperar conocimiento de circuitos/DB.

3. [03-contexto-operativo.md](03-contexto-operativo.md)
   - JSON de contexto vivo que se arma por pregunta, permisos y modulo activo.

4. [04-herramientas-agente.md](04-herramientas-agente.md)
   - Herramientas/acciones controladas que el agente puede pedir o sugerir.

5. [05-redis-y-cache.md](05-redis-y-cache.md)
   - Que informacion conviene mantener caliente en Redis para IA y operacion.

6. [06-endpoints-contratos.md](06-endpoints-contratos.md)
   - Contratos de `ia.logistica.preguntar`, RAG search y respuestas.

7. [07-roadmap-implementacion.md](07-roadmap-implementacion.md)
   - Fases para construirlo sin romper el OS actual.


titulo: Lightdata AI > Regla de oro

contenido:
## Regla de oro

```text
El modelo razona.
El backend busca, filtra y valida.
MySQL conserva la verdad.
Redis mantiene estado caliente.
La UI confirma cualquier accion operativa.
```

El agente no debe ejecutar cambios destructivos ni masivos por texto libre. Puede preparar una accion, explicar el impacto y pedir confirmacion mediante UI.