FAQ y troubleshooting
¿Cómo integro Emi en mi producto?
Sección titulada «¿Cómo integro Emi en mi producto?»# 1. Pedir a EMA admin:# - API key del producto (queda en wrangler secret del worker cliente)# - Activar el producto en emashared.tenant_emi_access para los tenants# que correspondan (Wave 4 trae UI en Vault)# 2. POST a emi:
POST https://emi.emahealth.io/api/chatAuthorization: Bearer <EMI_APP_API_KEY>X-Tenant-Id: <tenant uuid> # requerido para emaclinic, emalab, emapath, emawellContent-Type: application/json
{ "messages": [ { "role": "user", "content": "..." } ], "context": { "locale": "es", "patientId": "...", # opcional, según producto "encounterId": "...", "visitorEmail": "..." # opcional, sales lead capture }}Respuesta:
{ "message": "...", "agent": "support", "turnCount": 3, "leadId": "..." // sólo si SalesAgent invocó create_or_update_lead}El historial de la conversación lo administra el cliente (Emi es stateless).
¿Por qué obtengo 403 inactive?
Sección titulada «¿Por qué obtengo 403 inactive?»El tenant no tiene activación para esa app en emashared.tenant_emi_access.
Verificar:
- Que exista una row para
(tenant_id, app). - Que
status = 'active'. - Si Supabase está fallando,
checkAccesses fail-closed (F003) y también devuelve 403. Revisar logs del worker.
Wave 4 va a tener UI en Vault para gestionar esto. Hoy se hace por SQL.
¿Por qué obtengo 403 rate limited?
Sección titulada «¿Por qué obtengo 403 rate limited?»El tenant pasó el daily_invocation_limit configurado en
tenant_emi_access. Solo invocaciones exitosas cuentan (F004); los
deniegos no se penalizan dos veces.
Solución: subir el límite en tenant_emi_access.daily_invocation_limit o
esperar al próximo día UTC.
¿Qué pasa si no envío X-Tenant-Id?
Sección titulada «¿Qué pasa si no envío X-Tenant-Id?»Depende de la app:
| App | Tenant requerido | Sin header |
|---|---|---|
| emahealth | no | OK (visitante anónimo) |
| emavault | no | OK (dashboard interno) |
| emaclinic | sí | 400 X-Tenant-Id header required |
| emalab | sí | 400 |
| emapath | sí | 400 |
| emawell | sí | 400 |
La request da timeout
Sección titulada «La request da timeout»El tool loop puede exceder el deadline de Cloudflare Workers cuando los
queries a Aidbox o Supabase son lentos. MAX_TOOL_ITERATIONS = 5 previene
loops infinitos pero no resuelve queries pesados.
Diagnóstico:
- Revisar logs del worker (
wrangler tail emaemi). - Identificar qué tool está tardando (logger estructurado incluye
latency_ms). - Optimizar la query (índices, paginación) o reducir el scope.
El modelo retorna 503
Sección titulada «El modelo retorna 503»Anthropic responde 529 (overloaded) intermitentemente. runAgent
reintenta 3 veces con backoff exponencial (1s, 2s, 3s). Si los 3 fallan,
emi devuelve 503 al cliente.
Si pasa seguido:
- Esperar — suele ser transitorio.
- Verificar el rate limit de la API key de Anthropic.
El widget muestra 501 Not Implemented
Sección titulada «El widget muestra 501 Not Implemented»Es emawell. WellnessCoach no está implementado todavía (Wave 5+).
¿Cómo cambio un system prompt?
Sección titulada «¿Cómo cambio un system prompt?»Hoy es manual:
- Editar
SYSTEM_PROMPTen el archivo del agente (src/agents/sales.ts, etc.). npm run deploy.
No hay hot-swap. En Wave 5+ se puede mover a un store versionado.
¿Las conversaciones se guardan?
Sección titulada «¿Las conversaciones se guardan?»El historial de mensajes no. Cada request es independiente y trae
sus propios messages. Si necesitás historial, lo guardás del lado del
cliente.
Lo que sí se guarda en emi_invocations (Wave 3 audit log):
timestamp, app, agent, tenant_id, status, turn_count, tokens, cost_usd
y un context_summary sin PHI (has_patient_id, etc.). Nunca prompts
ni responses completos.
Una tool no encuentra los datos del paciente
Sección titulada «Una tool no encuentra los datos del paciente»Verificar:
- El
patientIdestá encontext(ocontext.metadata) de la request. - El
X-Tenant-Idcorresponde al tenant donde vive ese paciente. - Las credenciales Aidbox del tenant están bien provisionadas en
tenant_aidbox_credentialsy la master key (AIDBOX_SECRET_KEY_V1) las puede decryptar. - El paciente realmente existe en Aidbox de ese tenant.
Si la tool falla por error técnico (red, query inválida), el agente
retorna 503 y queda registrado tanto en emi_invocations.status='error'
como en el logger estructurado.
¿Qué tools tiene SalesAgent?
Sección titulada «¿Qué tools tiene SalesAgent?»Una, agregada en Wave 3 (F010-F012): create_or_update_lead. Si el
visitante deja su email en la conversación, el agente puede invocar
esta tool para crear/actualizar un lead en emavault.leads. Antes de
Wave 3 era Q&A puro.
¿Cómo se rota la master key de Aidbox?
Sección titulada «¿Cómo se rota la master key de Aidbox?»Versionada (AIDBOX_SECRET_KEY_V1, _V2, …). Cada fila de
tenant_aidbox_credentials tiene encryption_key_version que apunta a
la versión que la encriptó. Para rotar:
- Agregar
AIDBOX_SECRET_KEY_V2como secret nuevo. - Re-encryptar credenciales gradualmente con V2 y actualizar
encryption_key_version. - Cuando todas migraron, eliminar
AIDBOX_SECRET_KEY_V1.
Esto evita re-encrypt en bloque (F008).
Phases vs Waves
Sección titulada «Phases vs Waves»- Phase 1 = primer release (SalesAgent básico, sin tools, sin audit).
- Wave 3 = release actual: 6 apps, audit, multi-tenancy FHIR, cost tracking, sales lead capture, agentes lab/path/wellness declarados (con scope acotado o 501).
- Wave 4 = pendiente: UI en Vault para activación, pricing en BD,
eliminar deps
FHIR_*legacy. - Wave 5+ = tools reales para
lab_assistantywellness_coach. - Wave 6 =
pathology_assistantcon CAP synoptic + ICD-O-3.