Utiliser OpenUI
OpenUI est une norme ouverte pour les interfaces utilisateur génératives. Elle associe un langage compact conçu pour le streaming, OpenUI Lang, à un runtime React et à des bibliothèques de composants intégrées, afin que la sortie du modèle soit rendue sous la forme d’une interface structurée pendant le streaming.
OpenUI se connecte à Mastra via le protocole AG-UI. L’adaptateur @ag-ui/mastra encapsule un Agent Mastra et émet des événements AG-UI, que agUIAdapter() d’OpenUI analyse côté client.
Pour un exemple complet et fonctionnel, consultez l’exemple mastra-chat dans le dépôt OpenUI.
Guide d’intégrationLien direct vers Guide d’intégration
Intégrez Mastra dans votre route d’API Next.js et connectez-lui une surface de chat OpenUI <AgentInterface /> via le protocole AG-UI.
Générez une nouvelle application OpenUI :
- npm
- pnpm
- Yarn
- Bun
npx @openuidev/cli@latest create --name openui-mastra-chatpnpm dlx @openuidev/cli@latest create --name openui-mastra-chatyarn dlx @openuidev/cli@latest create --name openui-mastra-chatbun x @openuidev/cli@latest create --name openui-mastra-chatAccédez au répertoire de votre nouveau projet :
cd openui-mastra-chatL’application générée est un projet Next.js ayant la structure suivante :
openui-mastra-chat└── src├── app│ ├── api│ │ └── chat│ │ └── route.ts│ ├── globals.css│ ├── layout.tsx│ └── page.tsx├── generated│ └── system-prompt.txt└── library.tsLa route de chat se trouve dans
src/app/api/chat/route.ts, la surface de chat danssrc/app/page.tsxet la bibliothèque de composants danssrc/library.ts. La CLI OpenUI écritsrc/generated/system-prompt.txtà partir de votre bibliothèque ; régénérez-le à chaque modification de la bibliothèque.Ajoutez votre clé OpenAI à
.env.local:.env.localOPENAI_API_KEY=sk-...remarqueOpenUI requiert une clé de fournisseur de modèles. Utilisez n’importe quel fournisseur pris en charge par Mastra et ajustez la configuration de l’Agent à l’étape suivante.
Installez les packages Mastra et l’adaptateur AG-UI pour Mastra :
- npm
- pnpm
- Yarn
- Bun
npm install @mastra/core @ag-ui/mastra @ag-ui/core zodpnpm add @mastra/core @ag-ui/mastra @ag-ui/core zodyarn add @mastra/core @ag-ui/mastra @ag-ui/core zodbun add @mastra/core @ag-ui/mastra @ag-ui/core zod@ag-ui/mastraencapsule unAgentMastra dans unMastraAgentqui émet des événements du protocole AG-UI.agUIAdapter()d’OpenUI consomme ces événements côté client.Ouvrez
src/app/api/chat/route.ts. Définissez tous les Tools dont votre Agent a besoin aveccreateTooldepuis@mastra/core/tools:src/app/api/chat/route.tsimport { createTool } from '@mastra/core/tools'import { z } from 'zod'const getWeather = createTool({id: 'get_weather',description: 'Get current weather for a city.',inputSchema: z.object({ location: z.string().describe('City name') }),execute: async ({ location }) => {return { location, temperature_celsius: 22, condition: 'Clear' }},})Encapsulez un
AgentMastra dansMastraAgent. Injectez le prompt système généré afin que l’Agent sache utiliser la bibliothèque de composants OpenUI :src/app/api/chat/route.tsimport { MastraAgent } from '@ag-ui/mastra'import { Agent } from '@mastra/core/agent'import { readFileSync } from 'fs'import { join } from 'path'const systemPrompt = readFileSync(join(process.cwd(), 'src/generated/system-prompt.txt'), 'utf-8')const agent = new MastraAgent({agent: new Agent({id: 'openui-agent',name: 'OpenUI Agent',instructions: `You are a helpful assistant. Use tools when relevant.\n\n${systemPrompt}`,model: {id: 'openai/gpt-5.6-sol',apiKey: process.env.OPENAI_API_KEY,},tools: { getWeather },}),resourceId: 'chat-user',})Exportez un gestionnaire
POSTqui diffuse les événements AG-UI de l’Agent sous forme d’événements envoyés par le serveur, ou SSE :src/app/api/chat/route.tsimport type { Message } from '@ag-ui/core'import { NextRequest } from 'next/server'export async function POST(req: NextRequest) {const { messages, threadId }: { messages: Message[]; threadId: string } = await req.json()const encoder = new TextEncoder()const stream = new ReadableStream({start(controller) {const subscription = agent.run({ messages, threadId, runId: crypto.randomUUID(), tools: [], context: [] }).subscribe({next: event => {controller.enqueue(encoder.encode(`data: ${JSON.stringify(event)}\n\n`))},complete: () => {controller.enqueue(encoder.encode('data: [DONE]\n\n'))controller.close()},error: error => {controller.enqueue(encoder.encode(`data: ${JSON.stringify({ error: error.message })}\n\n`),)controller.close()},})req.signal.addEventListener('abort', () => subscription.unsubscribe())},})return new Response(stream, {headers: {'Content-Type': 'text/event-stream','Cache-Control': 'no-cache, no-transform',Connection: 'keep-alive',},})}Connectez la surface de chat OpenUI
<AgentInterface />à la route. Créez un adaptateurllmavecfetchLLM()et définissezstreamAdaptersuragUIAdapter()afin qu’OpenUI sache analyser les événements AG-UI.src/app/page.tsx'use client'import '@openuidev/react-ui/components.css'import { AgentInterface, agUIAdapter, fetchLLM } from '@openuidev/react-ui'import { openuiChatLibrary } from '@openuidev/react-ui/genui-lib'const llm = fetchLLM({url: '/api/chat',streamAdapter: agUIAdapter(),})export default function Page() {return (<div className="relative h-screen w-screen overflow-hidden"><AgentInterface llm={llm} componentLibrary={openuiChatLibrary} /></div>)}La prop
componentLibrarycontrôle les composants que le modèle peut générer. RemplacezopenuiChatLibrarypar votre propre bibliothèque pour restreindre ou étendre la sortie.Démarrez le serveur de développement :
- npm
- pnpm
- Yarn
- Bun
npm run devpnpm run devyarn devbun run devOuvrez http://localhost:3000. Vous pouvez maintenant converser avec votre Agent Mastra via la surface de chat OpenUI, l’interface structurée étant rendue progressivement pendant le streaming du modèle.
Streaming avec AG-UILien direct vers Streaming avec AG-UI
OpenUI consomme le protocole AG-UI, un flux d’événements typés destiné aux Agents IA et indépendant du transport. @ag-ui/mastra traduit un Agent Mastra dans ce protocole :
- Le serveur appelle
agent.run({ messages, threadId, runId, ... })et sérialise chaque événement émis sous la forme d’un message SSE. - Le client transmet
fetchLLM({ streamAdapter: agUIAdapter() })à<AgentInterface />, qui analyse le flux SSE pour produire les événements internes pilotant le rendu d’OpenUI Lang.
threadId relie une conversation entre les requêtes et runId identifie une exécution unique. Générez un nouveau runId pour chaque requête et conservez threadId côté client.
Bibliothèques de composantsLien direct vers Bibliothèques de composants
OpenUI génère une interface à partir d’une bibliothèque de composants. Cette bibliothèque définit les composants disponibles, leurs props et la manière dont le modèle doit les utiliser.
Bibliothèques intégréesLien direct vers Bibliothèques intégrées
@openuidev/react-ui fournit deux bibliothèques prêtes à l’emploi :
openuiChatLibrary: composants pour les interfaces de chat, notamment cartes, formulaires, tableaux et graphiques.openuiDashboardLibrary: composants pour les tableaux de bord et les surfaces riches en données.
Transmettez la bibliothèque à <AgentInterface componentLibrary={...} /> pour mettre ses composants à la disposition du modèle.
Personnaliser la bibliothèqueLien direct vers Personnaliser la bibliothèque
Pour restreindre ou étendre la sortie, définissez votre propre bibliothèque dans src/library.ts et exportez un sous-ensemble de composants. Transmettez cette bibliothèque à <AgentInterface /> et régénérez le prompt système à chaque modification de la bibliothèque :
- npm
- pnpm
- Yarn
- Bun
npx @openuidev/cli generate src/library.ts --out src/generated/system-prompt.txt
pnpm dlx @openuidev/cli generate src/library.ts --out src/generated/system-prompt.txt
yarn dlx @openuidev/cli generate src/library.ts --out src/generated/system-prompt.txt
bun x @openuidev/cli generate src/library.ts --out src/generated/system-prompt.txt
Le prompt généré est lu par la route d’API et fusionné dans les instructions de l’Agent, afin que celui-ci sache exactement quels composants il peut émettre.