Ir al contenido

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.


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

  1. Envío desde la UI. AdvisorPanel.vue recorta el borrador y llama a useAdvisorChat.send. Un envío mientras hay una ejecución en curso se ignora. La petición lleva threadId solo después de que un frame terminal anterior lo haya proporcionado.
  2. Transporte. RestAdvisorAdapter.ask emite un POST fetch simple a /api/advisor/stream y parsea el cuerpo SSE a mano. Cada frame se valida contra el advisorStreamEventSchema compartido; un frame inválido se convierte en un error de transporte local invalid-frame.
  3. Ruta. createAdvisorApi valida el cuerpo (message de 1 a 4000 caracteres, threadId UUID opcional; en caso contrario HTTP 400). Abre un stream SSE, arranca un temporizador de comentario : keep-alive de 15 segundos e itera AskAdvisorUC.execute.
  4. Caso de uso. AskAdvisorUC lee language (por defecto en) y base_currency (por defecto USD) mediante IUserSettingsPort, asigna un threadId si falta y delega la ejecución en IAdvisorPort. Persiste la fila de auditoría cuando pasa un evento terminal, o desde finally como fila aborted si el consumidor se detiene antes.
  5. Adaptador, resolución de la cadena. MastraAdvisorAdapter lee el ajuste de perfiles de ejecución y luego resolveChainForRequest: lee ai_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 evento failed sin llamar al modelo.
  6. Adaptador, grafo de agentes. Se construye un par nuevo taxAnalyst y advisor por petición, porque la cadena resuelta, los presupuestos y el RunBudgetTracker son datos propios de cada petición. Memory es el único objeto longevo (se construye una vez sobre ai-advisor.db).
  7. Ejecución del agente. Se llama a advisor.stream(...) con maxSteps del perfil, historial lastMessages, semanticRecall: false, memoria de trabajo desactivada y un contexto de petición con locale y baseCurrency (nunca entradas del modelo).
  8. Herramientas. advisor delega en taxAnalyst, 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 por enforceBudget.
  9. Mapeo de chunks. applyChunk (mastraChunk.ts) convierte los chunks del stream de Mastra en AdvisorEvent de 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.
  10. Guardarraíles. Dos procesadores de salida inspeccionan la salida del supervisor en el chunk finish. Un disparo se convierte en un evento refused; una ejecución que tocó contenido de inversión marca el payload de finish para que el frame terminal lleve disclaimer: true.
  11. 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. completed se convierte en done.
  12. 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.
  13. Cancelación. Si el cliente cierra la conexión, stream.onAbort llama a iterator.return(); el finally del adaptador aborta la llamada al proveedor y el caso de uso escribe una fila aborted.

[!NOTE] El POST /api/advisor/ask sin streaming ejecuta el mismo caso de uso, concatena los eventos token y devuelve una única respuesta JSON (ver API y Streaming). La UI usa solo la ruta con streaming.


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.