learn.chetana.fr

Nuxt 4, AG-UI et l'UI générative

14 min readCore

L'architecture front

Nuxt 4 full SSR + NuxtUI + Pinia. L'auth suit le pattern BFF : des routes serveur Nitro gèrent la session Logto (cookie chiffré dc_session) et proxifient l'API FastAPI — le navigateur ne parle jamais au backend directement. Si tu as suivi la construction de learn.chetana.fr : c'est exactement le même pattern (on l'a copié sur les mêmes bonnes raisons).

Consommer le SSE : le fetch reader

EventSource natif ne fait que du GET sans en-têtes — insuffisant. Le projet parse le flux à la main :

const res = await fetch('/api/proxy/copilot/run', { method: 'POST', body, headers })
const reader = res.body!.getReader()
// accumuler les chunks, découper sur \n\n, parser event:/data:, ignorer les ping
for await (const event of streamEvents(reader)) {
  dispatch(event)   // → composables useCopilotMessages, useCopilotRun, …
}

Les événements suivent le protocole AG-UI (@ag-ui/core) — un standard émergent pour le dialogue agent↔UI : événements typés (RUN_STARTED, TEXT_MESSAGE_CONTENT, TOOL_CALL_*, STATE_DELTA…), state synchronisé par JSON-Patch (deltas, pas de re-fetch). L'état du copilot est géré par ~25 composables spécialisés (useCopilotRun, useCopilotSse, useCopilotMessages…) — la logique de protocole isolée de la logique d'affichage.

L'UI générative : le LLM compose l'interface

Le pattern le plus original du front. Le backend émet des specs d'UI déclaratives (des blocs typés : table, chart, formulaire — validés contre un manifest) ; un registry côté Nuxt les mappe vers de vrais composants NuxtUI/charts :

LLM → ui_block {type: "table", columns: [...], rows_ref: ...}
    → registry front : component-map → <UTable> hydraté

Rappelle-toi l'invariant du module 4 : les données complètes arrivent par ui_events sans transiter par le LLM — le modèle choisit quoi montrer (la forme), le front rend les données (le fond). S'y ajoutent les frontend tools : des outils déclarés au LLM mais exécutés dans le navigateur (naviguer vers une page, ouvrir un panneau) — l'agent agit sur l'UI elle-même.

🧩 Quiz1/3

Pourquoi parser le SSE avec fetch + reader plutôt qu'EventSource ?

🃏 Flashcards1/4