Skip to main content

Entorno local

Requisitos previos

  • Node.js 20+ y pnpm (no usar npm/yarn en ningún repo de Aura).
  • Docker (para PostgreSQL + pgvector).
  • Ajolote corriendo (servicio de auth) — o acceso al ajolote de dev.
  • Token de GitHub con scope read:packages para instalar los paquetes privados @cuatro-quinas/*.

GitHub Packages (una sola vez)

Los paquetes @cuatro-quinas/ajolote-* se publican en GitHub Packages. Configurá tu ~/.npmrc de usuario (no el del repo):

//npm.pkg.github.com/:_authToken=ghp_TU_TOKEN

Alternativa por sesión: export GITHUB_TOKEN=ghp_... antes de pnpm install.

Backend (Aura-reloaded)

pnpm install
cp env.example .env # completar DATABASE_URL, OPENAI_API_KEY, etc.
docker compose up -d postgres # PostgreSQL + pgvector
docker compose up -d rabbitmq # (opcional) cola de /anfibios/transcriptions — UI en :15672
pnpm db:push # aplica el schema (solo dev)
pnpm ingest:manuals # (opcional) carga manuales en knowledge_base
pnpm start:dev # → API en http://localhost:3000

El módulo Transcripciones (/anfibios/transcriptions) es solo local: necesita RabbitMQ (el docker compose up -d rabbitmq de arriba) + RABBITMQ_URL. Sin eso, subir audios responde 503; el resto de Aura anda igual.

Variables de entorno (backend)

VariableDefaultReq.Descripción
DATABASE_URLConnection string de PostgreSQL
OPENAI_API_KEYEmbeddings (siempre OpenAI)
AUTH_SERVICE_URLURL del ajolote (mismo que usa el front)
AUTH_APP_IDauraApp id en ajolote
LLM_PROVIDERopenaiopenai | groq | cerebras | mistral | mock
LLM_MODELgpt-4o-miniModelo de chat
LLM_API_KEY= OPENAI_API_KEYAPI key del provider de chat
LLM_BASE_URLBase URL para providers no-OpenAI
EMBEDDING_MODELtext-embedding-3-smallModelo de embeddings (runtime)
SIMILARITY_THRESHOLD0.78Umbral de hit en memory_embeddings. Solo semilla del primer boot (ver abajo)
APPROVED_THRESHOLD0.85Umbral para ejemplos aprobados. Solo semilla del primer boot
KNOWLEDGE_THRESHOLD0.60Umbral de hit en knowledge_base. Solo semilla del primer boot
QUERY_LATENCY_BUDGET_MS500Timeout de la query RAG (ms)
CUSTOM_LLM_TOKEN_VOICEBearer del agente de voz de ElevenLabs. Vacío = POST /chat/completions rechaza todo
CUSTOM_LLM_TOKEN_WHATSAPPBearer del agente de WhatsApp. Distinto del de voz: el token es el que elige el canal
PORT3000Puerto HTTP/WS
RETELL_API_KEY / RETELL_SECRETRetell (transferencias / auth webhook)
PATIENT_LOOKUP_URLBase URL del sistema de pacientes para el lookup (AURA_SHARED_SECRET es el secreto compartido de ese endpoint). Vacío = el agente funciona, pero sin filtro de equipo en el RAG, y SecurityBootLogger lo avisa al boot. Antes se llamaba EXISTING_BACKEND_URL, que se sigue leyendo como fallback
PATIENT_LOOKUP_PROVIDERoxitesaQué adaptador contesta: oxitesa | mock | disabled. Un valor desconocido rompe el arranque en vez de degradar en silencio. Sin setear queda oxitesa, que contesta "sin conexión" hasta que se cargue la URL y funciona apenas se carga. mock resuelve desde un roster en memoria; disabled apaga la consulta y es la salida de emergencia
PATIENT_LOOKUP_MOCKJSON [{ dni, phones, equipment }] que pisa el roster por defecto del mock. Los teléfonos se normalizan al cargar, así que se escriben como venga
DEEPGRAM_API_KEYSTT (transcripción en vivo y de audios subidos en /anfibios)
RABBITMQ_URLCola de transcripción de audios (solo local, ver docker-compose). Sin ella la subida da 503
TRANSCRIPTION_CONCURRENCY1Jobs de transcripción en paralelo (prefetch)
TRANSCRIPTION_MAX_ATTEMPTS3Reintentos antes de mandar el job a la DLQ

Cambiar de provider LLM es solo .env (sin recompilar), ej. LLM_PROVIDER=mock para dev sin API keys.

Los tres umbrales de RAG ya no se leen de la ENV

Ahora son ajustes runtime con scope por canal. La ENV se usa una sola vez: en el primer boot, para sembrar la fila scope='global' de cada uno. Después de eso, cambiar KNOWLEDGE_THRESHOLD en el .env no hace nada — hay que tocar el setting (panel de /anfibios/settings, o PATCH con ?scope= para un canal). Siguen declaradas para que el primer arranque de cada entorno conserve el valor que ya tenía.

Frontend (aura-front)

pnpm install
cp .env.example .env.local
pnpm dev # → http://localhost:5173

Variables de entorno (frontend)

VITE_API_BASE_URL=http://localhost:3000 # backend de Aura
VITE_AUTH_URL=http://localhost:5173 # dev server (proxy a ajolote)
VITE_AUTH_PROXY_TARGET=http://100.64.188.115:3010 # ajolote real (dev)
VITE_COPILOT_WS_URL=ws://localhost:3000/copilot/TU_AGENT_ID
VITE_USE_MOCK=false # true = levanta sin backend
VITE_SHOW_SOURCE_FILTER=true # muestra filtro de origen en paneles
Cookie de ajolote en dev

En dev el front le pega a su propio dev server y Vite proxya /api/auth al ajolote real (VITE_AUTH_PROXY_TARGET). Esto es porque la cookie de sesión sale SameSite=Lax y no viaja cross-site. Sin el proxy, get-session devuelve null y nunca quedás logueado. Detalle en Autenticación.

Probar el Custom LLM por curl (y los acentos)

POST /chat/completions es el endpoint que llama ElevenLabs, y en dev se prueba con curl imitando ese request. El body tiene que ser UTF-8. Escribir el JSON con acentos directo en la línea de comandos en Windows manda los bytes en cp1252 (á = 0xE1), que no es UTF-8 válido: el parser los reemplaza por <?> y el turno llega dañado — pierde el match de equipos en el RAG y le entra ruido al modelo. El backend loguea un [TURN] ... received invalid UTF-8 cuando eso pasa, así que si lo ves en el log, el problema está en el cliente, no en Aura.

La forma segura es un archivo y --data-binary:

# el archivo queda en UTF-8 real, sin depender del codepage de la consola
cat > /tmp/turno.json <<'JSON'
{"messages":[{"role":"user","content":"el M50 tira H08 y la cánula está doblada"}]}
JSON

curl -X POST localhost:3000/chat/completions \
-H "Authorization: Bearer $CUSTOM_LLM_TOKEN_WHATSAPP" \
-H 'Content-Type: application/json' -H 'x-conversation-id: demo-1' \
--data-binary @/tmp/turno.json

Y para que la salida se lea bien (los á que se ven como á o ? son la consola, no los datos): chcp 65001 en la terminal de Windows, y PYTHONIOENCODING=utf-8 si inspeccionás las respuestas con Python. Los datos ya están bien: el endpoint responde application/json; charset=utf-8, el SSE declara text/event-stream; charset=utf-8 y en Postgres á está guardado como \303\241.

Ajolote (auth)

El backend y el front tienen que apuntar al mismo ajolote (AUTH_SERVICE_URL == VITE_AUTH_PROXY_TARGET), o los roles no matchean. La administración de usuarios y roles (crear tenant, usuarios, asignar roles) se hace contra ajolote, no desde Aura — ver Autenticación → Roles.