name: openui-forge-vercel description: OpenUI generative UI with Vercel AI SDK. streamText, toUIMessageStreamResponse, and tools support. version: 1.0.0 author: OthmanAdi
OpenUI Forge — Vercel AI SDK
Build generative UI apps with OpenUI + Vercel AI SDK. Native streaming with streamText and toUIMessageStreamResponse().
Activation Triggers
- "openui vercel", "openui vercel ai", "openui ai sdk"
- "generative ui vercel", "vercel ai streaming ui"
- "useChat openui", "streamText openui"
Prerequisites
- Node.js >= 18, React >= 19
OPENAI_API_KEYenvironment variable set- Next.js project (App Router)
Quick Start
- Install dependencies:
npm install @openuidev/react-ui @openuidev/react-headless @openuidev/react-lang lucide-react zod ai @ai-sdk/openai
- Add CSS imports to
app/layout.tsx:
import "@openuidev/react-ui/components.css";
import "@openuidev/react-ui/styles/index.css";
- Create the API route and frontend page below
- Run
npm run devand test
Full Code
Backend: app/api/chat/route.ts
import { openuiLibrary } from "@openuidev/react-ui";
import { streamText } from "ai";
import { openai } from "@ai-sdk/openai";
export async function POST(req: Request) {
const { messages } = await req.json();
const systemPrompt = openuiLibrary.prompt({
preamble: "You are a helpful assistant that generates interactive UIs.",
additionalRules: ["Always use Stack as root when combining multiple components."],
});
const result = streamText({
model: openai("gpt-4o"),
system: systemPrompt,
messages,
});
return result.toUIMessageStreamResponse();
}
Backend with Tools: app/api/chat/route.ts
import { openuiLibrary } from "@openuidev/react-ui";
import { streamText, tool } from "ai";
import { openai } from "@ai-sdk/openai";
import { z } from "zod";
export async function POST(req: Request) {
const { messages } = await req.json();
const systemPrompt = openuiLibrary.prompt({
preamble: "You are a helpful assistant that generates interactive UIs. Use tools to fetch data before rendering.",
});
const result = streamText({
model: openai("gpt-4o"),
system: systemPrompt,
messages,
tools: {
getWeather: tool({
description: "Get current weather for a city",
parameters: z.object({
city: z.string().describe("City name"),
}),
execute: async ({ city }) => {
return { city, temp: 22, condition: "sunny" };
},
}),
},
maxSteps: 3,
});
return result.toUIMessageStreamResponse();
}
Frontend (with processMessage): app/chat/page.tsx
"use client";
import { FullScreen } from "@openuidev/react-ui";
import { openuiLibrary } from "@openuidev/react-ui";
async function processMessage(messages: { role: string; content: string }[]) {
const res = await fetch("/api/chat", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ messages }),
});
if (!res.body) throw new Error("No response body");
return res.body;
}
export default function ChatPage() {
return (
<FullScreen
componentLibrary={openuiLibrary}
processMessage={processMessage}
/>
);
}
Frontend (with useChat): app/chat/page.tsx
"use client";
import { useChat } from "@ai-sdk/react";
import { FullScreen } from "@openuidev/react-ui";
import { openuiLibrary } from "@openuidev/react-ui";
export default function ChatPage() {
const chat = useChat({ api: "/api/chat" });
return (
<FullScreen
componentLibrary={openuiLibrary}
messages={chat.messages}
onSend={(text) => chat.append({ role: "user", content: text })}
isLoading={chat.isLoading}
/>
);
}
Component Creation
import { defineComponent } from "@openuidev/react-lang";
import { z } from "zod";
export const WeatherCard = defineComponent({
name: "WeatherCard",
description: "Displays weather information for a location",
props: z.object({
city: z.string().describe("City name"),
temp: z.number().describe("Temperature in Celsius"),
condition: z.enum(["sunny", "cloudy", "rainy", "snowy"]).describe("Weather condition"),
}),
component: ({ props }) => (
<div style={{ padding: 16, borderRadius: 12, background: "#f0f9ff" }}>
<h3>{props.city}</h3>
<div style={{ fontSize: 32 }}>{props.temp}C</div>
<div>{props.condition}</div>
</div>
),
});
System Prompt Generation
npx @openuidev/cli generate ./src/lib/library.ts --out src/generated/system-prompt.txt
Or at runtime via openuiLibrary.prompt() as shown in the route.
Validation Checklist
-
OPENAI_API_KEYis set in.env.local -
aiand@ai-sdk/openaipackages installed - Route uses
streamTextand returnsresult.toUIMessageStreamResponse() - Frontend uses
processMessageoruseChat(notopenAIReadableStreamAdapter) -
componentLibraryprop passed toFullScreen - CSS imports in root layout
- If using tools:
maxStepsis set, tool results feed back to model
Error Patterns
| Error | Cause | Fix |
|---|---|---|
ai module not found | Missing Vercel AI SDK | npm install ai @ai-sdk/openai |
| Stream format mismatch | Using openAIReadableStreamAdapter with Vercel AI | Use processMessage or useChat instead |
| Tools not executing | Missing maxSteps | Add maxSteps: 3 (or higher) to streamText options |
| Blank response | Wrong export from @ai-sdk/openai | Use openai("gpt-4o") not new OpenAI() |
| Type errors on messages | Vercel AI message format differs | Let useChat manage messages, or map to CoreMessage[] |