OpenUI を使用する
OpenUI は Generative UI のオープン標準です。ストリーミングを重視したコンパクトな言語(OpenUI Lang)と、React Runtime および組み込みコンポーネントライブラリを組み合わせ、ストリーミング中のモデル出力を構造化 UI としてレンダリングできます。
OpenUI は AG-UI プロトコルを通じて Mastra に接続します。@ag-ui/mastra Adapter が Mastra Agent をラップして AG-UI イベントを送出し、クライアント上の OpenUI agUIAdapter() がそれを解析します。
完全に動作する例については、OpenUI リポジトリの mastra-chat を参照してください。
統合ガイド統合ガイドへの直接リンク
Mastra を Next.js API Route に組み込み、AG-UI プロトコルを介して OpenUI の <AgentInterface /> チャット画面に接続します。
新しい 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-chat新しく作成したプロジェクトのディレクトリに移動します。
cd openui-mastra-chat作成されたアプリは、次の構造を持つ Next.js プロジェクトです。
openui-mastra-chat└── src├── app│ ├── api│ │ └── chat│ │ └── route.ts│ ├── globals.css│ ├── layout.tsx│ └── page.tsx├── generated│ └── system-prompt.txt└── library.tsチャットルートは
src/app/api/chat/route.ts、チャット画面はsrc/app/page.tsx、コンポーネントライブラリはsrc/library.tsにあります。OpenUI CLI はライブラリからsrc/generated/system-prompt.txtを生成します。ライブラリを変更した場合は、必ず再生成してください。OpenAI キーを
.env.localに追加します。.env.localOPENAI_API_KEY=sk-...注記OpenUI にはモデル Provider のキーが必要です。Mastra がサポートする任意の Provider を使用し、次の Step で Agent 設定を変更してください。
Mastra パッケージと Mastra 用 AG-UI Adapter をインストールします。
- 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/mastraは MastraAgentを、AG-UI プロトコルイベントを送出するMastraAgentでラップします。クライアント上の OpenUIagUIAdapter()がこれらのイベントを使用します。src/app/api/chat/route.tsを開きます。@mastra/core/toolsのcreateToolを使用して、Agent に必要な Tool を定義します。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' }},})Mastra
AgentをMastraAgentでラップします。Agent が 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',})Agent の AG-UI イベントを Server-Sent Events(SSE)としてストリーミングする
POSTHandler をエクスポートします。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',},})}OpenUI の
<AgentInterface />チャット画面をルートに接続します。fetchLLM()でllmAdapter を作成し、streamAdapterをagUIAdapter()に設定して、OpenUI が 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>)}componentLibraryProp は、モデルが生成できるコンポーネントを制御します。出力を制限または拡張するには、openuiChatLibraryを独自のライブラリに置き換えます。開発サーバーを起動します。
- npm
- pnpm
- Yarn
- Bun
npm run devpnpm run devyarn devbun run devhttp://localhost:3000 を開きます。OpenUI チャット画面から Mastra Agent とチャットできるようになり、モデルのストリーミングに合わせて構造化 UI が段階的にレンダリングされます。
AG-UI でストリーミングするAG-UI でストリーミングするへの直接リンク
OpenUI は、AI Agent 用の型付きイベントを転送する、Transport に依存しない AG-UI プロトコルを使用します。@ag-ui/mastra は Mastra Agent をこのプロトコルに変換します。
- サーバーは
agent.run({ messages, threadId, runId, ... })を呼び出し、送出された各イベントを SSE メッセージとしてシリアライズします。 - クライアントは
<AgentInterface />にfetchLLM({ streamAdapter: agUIAdapter() })を渡します。これにより、SSE ストリームが OpenUI Lang のレンダリングを駆動する内部イベントに解析されます。
threadId はリクエスト間で会話を関連付け、runId は 1 回の実行を識別します。リクエストごとに新しい runId を生成し、クライアント側で threadId を永続化してください。
コンポーネントライブラリコンポーネントライブラリへの直接リンク
OpenUI はコンポーネントライブラリから UI を生成します。ライブラリは、利用可能なコンポーネント、その Props、モデルに使用方法を指示する方法を定義します。
組み込みライブラリ組み込みライブラリへの直接リンク
@openuidev/react-ui には、そのまま使用できる 2 つのライブラリがあります。
openuiChatLibrary:チャットインターフェース用のコンポーネント(カード、フォーム、テーブル、チャート)。openuiDashboardLibrary:ダッシュボードやデータ量の多い画面向けのコンポーネント。
ライブラリを <AgentInterface componentLibrary={...} /> に渡すと、そのコンポーネントをモデルで使用できるようになります。
ライブラリをカスタマイズするライブラリをカスタマイズするへの直接リンク
出力を制限または拡張するには、src/library.ts に独自のライブラリを定義し、コンポーネントの一部をエクスポートします。そのライブラリを <AgentInterface /> に渡し、ライブラリを変更するたびにシステムプロンプトを再生成します。
- 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
生成されたプロンプトは API Route で読み込まれ、Agent の instructions にマージされるため、Agent は送出できるコンポーネントを正確に認識できます。