Frontend del Asesor de IA
🖥️ Frontend del Asesor de IA
Sección titulada «🖥️ Frontend del Asesor de IA»La UI del asesor sigue la misma forma hexagonal que el resto de apps/frontend: un puerto, un adaptador REST, DTOs validados con Zod, Pinia Colada para el estado del servidor y componentes organizados por funcionalidad. Ver Arquitectura Hexagonal.
flowchart TD
Header["AppHeader.vue<br/>Botón Sparkles, Mod+/"] --> PanelState["useAdvisorPanel<br/>singleton de módulo"]
PanelState --> Panel["AdvisorPanel.vue (montado una vez en App.vue)"]
Panel --> ChatC["useAdvisorChat(port)"]
Panel --> CfgQ["useAdvisorConfigQuery<br/>activa mientras está abierto"]
ChatC --> Turn["AdvisorTurn.vue"]
Turn --> MD["AdvisorMarkdown.vue<br/>markdown-it"]
Turn --> Tools["AdvisorToolActivity.vue"]
Turn --> Outcome["AdvisorOutcome.vue"]
Panel --> Empty["AdvisorEmptyState.vue"]
ChatC --> PortF["IAdvisorPort (ADVISOR_PORT_KEY)"]
CfgQ --> PortF
PortF --> RestA["RestAdvisorAdapter"]
SettingsView["SettingsView.vue"] --> AS["AdvisorSettings.vue"]
AS --> ModelEd["ModelChainEditor + useModelChainEditor"]
AS --> ProfEd["ExecutionProfilesEditor + useExecutionProfilesEditor"]
ModelEd --> Mut["useSetModelChainMutation"]
ProfEd --> Mut2["useSetExecutionProfilesMutation"]
Mut --> PortF
Mut2 --> PortF
🔌 Puerto y Adaptador
Sección titulada «🔌 Puerto y Adaptador»IAdvisorPort (frontend) declara el ask(request, signal) con streaming junto a los métodos de configuración, siguiendo el precedente de market-data. RestAdvisorAdapter lee el stream a mano: el EventSource del navegador no puede hacer POST y se reconecta por sí solo, lo que volvería a ejecutar (y a facturar) en silencio una llamada al LLM ya terminada. Todo reintento es una acción explícita del usuario. El adaptador informa cada fallo de transporte al errorBus exactamente una vez; el consumidor nunca vuelve a mostrar un toast. Las llamadas de configuración usan bffClient y validan con AdvisorConfigSchema / executionProfilesSchema.
🧠 Estado
Sección titulada «🧠 Estado»useAdvisorChatmantiene los turnos y el id de hilo solo en memoria. Exponesend,abort,retryynewConversation. Los resultados de turno son los resultados de red más dos locales,transport-lostyuser-aborted.isRetryableOutcomepermite reintentar tras un error de red, fin de stream, HTTP 5xx o 429, una ejecución fallida cuya causa es temporal (rate-limited,provider-unavailable,network,unknown) o una parada del usuario; no tras un frame malformado, un cuerpo ausente, un HTTP 4xx distinto de 429, una clave rechazada o un modelo desconocido.- El estado del servidor (configuración, perfiles) pasa por Pinia Colada (
useAdvisorQueries.ts,useAdvisorMutations.ts); no hay store global de Pinia. La query de configuración solo está activa mientras el panel está abierto. useAdvisorPaneles un singleton de módulo porque el botón de la cabecera y el panel viven en subárboles no relacionados.
💬 UX del Panel de Chat
Sección titulada «💬 UX del Panel de Chat»- Una hoja lateral derecha que se abre desde el botón de la cabecera o con Mod + / (Cmd en macOS, Ctrl en el resto). Escape la cierra y el foco vuelve al disparador.
- Las respuestas se transmiten como Markdown (
markdown-it): HTML crudo desactivado, imágenes desactivadas, sin autoenlazado, solo las rutas internas de la app son clicables; el código en línea se renderiza confont-mono tabular-nums. - Cada llamada a herramienta muestra una fila de actividad (en curso, terminada o fallida).
- La cabecera muestra el id del modelo activo y una insignia local / cloud obtenida de
classifyExecutionProfile, la misma regla que el backend. El modelo activo es el que respondió el último turno o, en su defecto, la primera entrada de la cadena. - Bajo una respuesta: una insignia “Cifras incompletas”, el pie del descargo (solo cuando
disclaimeres true, nunca en línea) y un pie atenuadostepsUsed / maxStepsuna vez terminada la ejecución. - Una ejecución
refusedmuestra una alerta “Respuesta retenida” con un chip de reformulación. Una ejecuciónfailedmuestra un texto por código;NO_MODEL_AVAILABLEyVAULT_LOCKEDenlazan a Ajustes, yALL_PROVIDERS_FAILEDelige el texto segúncause.kindnombrando el proveedor y el modelo (auth-rejectedapunta a la clave API,model-not-foundal id del modelo). - Enter envía, Shift+Enter inserta un salto de línea, se respeta la composición IME; Stop aborta de inmediato; un segundo envío durante una ejecución se ignora. El autoscroll se pausa mientras el usuario se desplaza hacia arriba (
useStickToBottom). El modo de movimiento reducido desactiva la animación de deslizamiento y del cursor. AppToaster.vuedesplaza los toasts por debajo de la cabecera de la hoja mientras el panel está abierto para que no tapen el botón de cierre.- El estado vacío ofrece preguntas sugeridas en dos grupos, “Impuestos” y “Tu cartera”.
⚙️ Ajustes: Asesor de IA
Sección titulada «⚙️ Ajustes: Asesor de IA»- Editor de la cadena de modelos: añadir, quitar, reordenar; selector de proveedor, id de modelo y una entrada
contextWindowsolo para una entradaollamalocal; etiquetas derivadas local/nube y de perfil; indicador de credencial para proveedores con clave; una cadena vacía no se puede guardar. - Editor de perfiles de ejecución: límites numéricos con los techos del esquema aplicados en el cliente, presupuestos por herramienta medidos editables, presupuestos locales mostrados en solo lectura como derivados de la ventana declarada, restablecimiento a valores por defecto. El estado del formulario es texto, de modo que un número a medio escribir nunca se coacciona antes de tiempo.
- Las claves API de proveedores se introducen en Ajustes → Bóveda, en el grupo “AI Providers”.
🌐 i18n y Sistema de Diseño
Sección titulada «🌐 i18n y Sistema de Diseño»- i18n: todas las cadenas usan
useI18n(); las claves viven bajoadvisor.*,settings.advisor.*yvault.category.*enen.tsyes.ts. El helperinterpolaterellena los marcadores{name}en una sola pasada para que los valores que contengan$&o{other}permanezcan literales. - Sistema de diseño: solo se usan tokens de
DESIGN.md;designTokens.spec.tsescanea los componentes del asesor en busca de clases inventadas. Los colores de ganancia y pérdida nunca colorean prosa. Ver Diseño Institucional Claro.