Ciclo de Vida de una Petición al Asesor de IA
🔄 Ciclo de Vida de una Petición al Asesor de IA
Sección titulada «🔄 Ciclo de Vida de una Petición al Asesor de IA»Esta página sigue una pregunta a través de todas las capas: el panel de chat, el transporte, la ruta Hono, el caso de uso, el adaptador Mastra, los agentes y herramientas, los guardarraíles y, por último, la fila de auditoría.
📈 Diagrama de Secuencia
Sección titulada «📈 Diagrama de Secuencia»sequenceDiagram
autonumber
actor User as Usuario
participant UI as AdvisorPanel y useAdvisorChat
participant RA as RestAdvisorAdapter
participant R as routes/advisor.ts
participant UC as AskAdvisorUC
participant A as MastraAdvisorAdapter
participant S as advisor (supervisor)
participant T as taxAnalyst
participant U as Caso de uso tras una herramienta
participant L as SqliteAdvisorRunLogAdapter
User->>UI: escribe una pregunta, Enter
UI->>RA: ask({ message, threadId? }, signal)
RA->>R: POST /api/advisor/stream
R->>R: zValidator(askAdvisorRequestSchema)
R->>UC: execute({ message, threadId })
UC->>UC: lee ajustes language y base_currency, resuelve threadId
UC->>A: ask({ message, threadId, locale, baseCurrency })
A->>A: lee perfiles de ejecución, resuelve cadena con credenciales
alt sin entrada de cadena utilizable
A-->>UC: failed (NO_MODEL_AVAILABLE o VAULT_LOCKED)
else cadena resuelta
A->>A: deriva perfil de ejecución, construye config de herramientas, agentes y modelo
A->>S: stream(message, requestContext, maxSteps, memory)
S->>T: delega (mapa agents)
T->>U: llamada a herramienta, entrada estricta
U-->>T: resultado del caso de uso, limitado por presupuesto
T-->>S: respuesta con cifras literales
S-->>A: chunks text-delta, tool-*, step-finish, finish, tripwire o error
A-->>UC: stream de AdvisorEvent
end
UC-->>R: eventos (token, tool-start, tool-result, tool-error y un terminal)
R->>R: toWireEvent, advisorStreamEventSchema.parse
R-->>RA: frames SSE
RA-->>UI: AdvisorStreamEvent validado
UC->>L: appendRun(receipt, outcome) tras el evento terminal
UI-->>User: Markdown en streaming, actividad de herramientas, insignias, pies
🪜 Paso a Paso
Sección titulada «🪜 Paso a Paso»- Envío desde la UI.
AdvisorPanel.vuerecorta el borrador y llama auseAdvisorChat.send. Un envío mientras hay una ejecución en curso se ignora. La petición llevathreadIdsolo después de que un frame terminal anterior lo haya proporcionado. - Transporte.
RestAdvisorAdapter.askemite un POSTfetchsimple a/api/advisor/streamy parsea el cuerpo SSE a mano. Cada frame se valida contra eladvisorStreamEventSchemacompartido; un frame inválido se convierte en un error de transporte localinvalid-frame. - Ruta.
createAdvisorApivalida el cuerpo (messagede 1 a 4000 caracteres,threadIdUUID opcional; en caso contrario HTTP 400). Abre un stream SSE, arranca un temporizador de comentario: keep-alivede 15 segundos e iteraAskAdvisorUC.execute. - Caso de uso.
AskAdvisorUCleelanguage(por defectoen) ybase_currency(por defectoUSD) medianteIUserSettingsPort, asigna unthreadIdsi falta y delega la ejecución enIAdvisorPort. Persiste la fila de auditoría cuando pasa un evento terminal, o desdefinallycomo filaabortedsi el consumidor se detiene antes. - Adaptador, resolución de la cadena.
MastraAdvisorAdapterlee el ajuste de perfiles de ejecución y luegoresolveChainForRequest: leeai_advisor_model_chain, descarta las entradas cuya credencial no está disponible, descifra las claves y deriva el perfil de la ejecución. Un resultado vacío provoca un cortocircuito a un eventofailedsin llamar al modelo. - Adaptador, grafo de agentes. Se construye un par nuevo
taxAnalystyadvisorpor petición, porque la cadena resuelta, los presupuestos y elRunBudgetTrackerson datos propios de cada petición.Memoryes el único objeto longevo (se construye una vez sobreai-advisor.db). - Ejecución del agente. Se llama a
advisor.stream(...)conmaxStepsdel perfil, historiallastMessages,semanticRecall: false, memoria de trabajo desactivada y un contexto de petición conlocaleybaseCurrency(nunca entradas del modelo). - Herramientas.
advisordelega entaxAnalyst, que llama a herramientas de solo lectura. Cada herramienta valida su entrada estricta, llama a su caso de uso, proyecta un payload reducido y lo pasa porenforceBudget. - Mapeo de chunks.
applyChunk(mastraChunk.ts) convierte los chunks del stream de Mastra enAdvisorEventde dominio y actualiza el borrador del recibo. Los tipos de chunk no reconocidos se descartan en silencio. Las llamadas de delegación (agent-taxAnalyst) no son herramientas del catálogo y no se muestran como eventos de herramienta. - Guardarraíles. Dos procesadores de salida inspeccionan la salida del supervisor en el chunk
finish. Un disparo se convierte en un eventorefused; una ejecución que tocó contenido de inversión marca el payload definishpara que el frame terminal llevedisclaimer: true. - Mapeo a red. La ruta llama a
toWireEvent(la única conversión dominio-a-red) y vuelve a validar el resultado antes de escribir cada frame.completedse convierte endone. - Auditoría. La ruta sigue iterando deliberadamente después del frame terminal para que el caso de uso alcance
appendRun. Se escribe una fila por ejecución. - Cancelación. Si el cliente cierra la conexión,
stream.onAbortllama aiterator.return(); elfinallydel adaptador aborta la llamada al proveedor y el caso de uso escribe una filaaborted.
[!NOTE] El
POST /api/advisor/asksin streaming ejecuta el mismo caso de uso, concatena los eventostokeny devuelve una única respuesta JSON (ver API y Streaming). La UI usa solo la ruta con streaming.
🧯 Rutas de Fallo de un Vistazo
Sección titulada «🧯 Rutas de Fallo de un Vistazo»| Dónde falla | Resultado |
|---|---|
| Cuerpo de petición inválido | HTTP 400 desde zValidator; no se inicia ninguna ejecución. |
| Ninguna entrada de cadena utilizable | failed con NO_MODEL_AVAILABLE o VAULT_LOCKED; sin llamada al modelo, recibo pre-run. |
| Todas las entradas fallan tras los reintentos | failed con ALL_PROVIDERS_FAILED y una cause clasificada. |
| Una herramienta rechaza su entrada o su caso de uso lanza | Frame tool-error (INVALID_TOOL_INPUT o USE_CASE_FAILED); la ejecución aún puede completarse. |
| Disparo de un guardarraíl | refused con el processorId. |
| El cliente se desconecta o pulsa Stop | Fila de auditoría aborted; no hace falta frame terminal. |
| Error inesperado del servidor | failed con INTERNAL_ERROR. |
Para los detalles del lado del proveedor consulta Proveedores y Modelos; para la forma de los frames, API y Streaming.