$npx -y skills add OthmanAdi/openui-forge --skill openui-forge-openaiOpenUI generative UI with OpenAI SDK backend. Streaming chat completions with gpt-5.5 (or any current OpenAI-compatible model).
| 1 | # OpenUI Forge — OpenAI |
| 2 | |
| 3 | Build generative UI apps with OpenUI + OpenAI SDK. One backend, one adapter, streaming out of the box. |
| 4 | |
| 5 | ## Activation Triggers |
| 6 | |
| 7 | - "openui openai", "openui gpt", "openui chatgpt" |
| 8 | - "generative ui openai", "openai streaming ui" |
| 9 | |
| 10 | ## Prerequisites |
| 11 | |
| 12 | - Node.js >= 22 (24 LTS recommended), React >= 18.3.1 (19+ recommended) |
| 13 | - `OPENAI_API_KEY` environment variable set |
| 14 | - Optional: `OPENAI_BASE_URL` to route via an OpenAI-compatible provider (Gemini, OpenRouter, xAI, DeepSeek, etc.) without code changes. `OPENAI_BASE_URL` is the correct env var; the legacy `OPENAI_API_BASE` was removed in openai v6. See [Provider Routing](#provider-routing) below. |
| 15 | - Optional: `OPENAI_MODEL` to pin a specific model (defaults to `gpt-5.5`) |
| 16 | - Next.js project (App Router recommended) |
| 17 | |
| 18 | ## Provider Routing |
| 19 | |
| 20 | This is the OpenAI-compatible variant: the same `OpenAI` client and `chat.completions.create` code talks to any provider below by setting `OPENAI_BASE_URL` (and `OPENAI_MODEL`). No code changes. `OPENAI_BASE_URL` is the correct env var; the old `OPENAI_API_BASE` was removed in openai v6. |
| 21 | |
| 22 | | Provider | `OPENAI_BASE_URL` | Example `OPENAI_MODEL` | |
| 23 | |----------|-------------------|------------------------| |
| 24 | | Gemini | `https://generativelanguage.googleapis.com/v1beta/openai/` | `gemini-3.5-flash` | |
| 25 | | OpenRouter | `https://openrouter.ai/api/v1` | `anthropic/claude-opus-4.7` | |
| 26 | | xAI (Grok) | `https://api.x.ai/v1` | `grok-4.3` | |
| 27 | | DeepSeek | `https://api.deepseek.com` | `deepseek-v4-pro` | |
| 28 | | Groq | `https://api.groq.com/openai/v1` | `llama-3.3-70b-versatile` | |
| 29 | | Mistral | `https://api.mistral.ai/v1` | `mistral-large-latest` | |
| 30 | | Together | `https://api.together.ai/v1` | `openai/gpt-oss-20b` | |
| 31 | | Fireworks | `https://api.fireworks.ai/inference/v1` | `accounts/fireworks/models/glm-5` | |
| 32 | | Ollama (local) | `http://localhost:11434/v1/` | `llama3.3` (any placeholder API key) | |
| 33 | | LM Studio (local) | `http://localhost:1234/v1` | loaded model id (any placeholder API key) | |
| 34 | |
| 35 | Model ids drift; check each provider's current catalog. Base-url routing covers chat completions only, not full OpenAI API parity. |
| 36 | |
| 37 | > **Azure OpenAI is not a generic drop-in.** Use `OPENAI_BASE_URL=https://YOUR-RESOURCE.openai.azure.com/openai/v1/`, set `OPENAI_MODEL` to your *deployment name* (not a catalog id like `gpt-5.5`), and prefer the `AzureOpenAI` client. The legacy data-plane path also needs an `?api-version=` query param. |
| 38 | |
| 39 | ## Quick Start |
| 40 | |
| 41 | 1. Install dependencies: |
| 42 | ```bash |
| 43 | npm install @openuidev/react-ui @openuidev/react-headless @openuidev/react-lang lucide-react zod openai |
| 44 | ``` |
| 45 | 2. Add the CSS import to `app/layout.tsx`: |
| 46 | ```tsx |
| 47 | import "@openuidev/react-ui/components.css"; |
| 48 | ``` |
| 49 | 3. Create the API route (Step 4 below) |
| 50 | 4. Create the frontend page (Step 5 below) |
| 51 | 5. Run `npm run dev` and test |
| 52 | |
| 53 | ## Full Code |
| 54 | |
| 55 | ### Backend: `app/api/chat/route.ts` |
| 56 | |
| 57 | ```typescript |
| 58 | import { openuiChatLibrary } from "@openuidev/react-ui/genui-lib"; |
| 59 | import OpenAI from "openai"; |
| 60 | |
| 61 | const client = new OpenAI(); |
| 62 | |
| 63 | export async function POST(req: Request) { |
| 64 | const { messages } = await req.json(); |
| 65 | |
| 66 | const systemPrompt = openuiChatLibrary.prompt({ |
| 67 | preamble: "You are a helpful assistant that generates interactive UIs.", |
| 68 | additionalRules: ["Always use Stack as root when combining multiple components."], |
| 69 | }); |
| 70 | |
| 71 | const response = await client.chat.completions.create({ |
| 72 | model: process.env.OPENAI_MODEL ?? "gpt-5.5", |
| 73 | stream: true, |
| 74 | messages: [{ role: "system", content: systemPrompt }, ...messages], |
| 75 | }); |
| 76 | |
| 77 | // response.toReadableStream() produces NDJSON (one JSON object per line, no SSE `data:` prefix). |
| 78 | // Pair with openAIReadableStreamAdapter() on the frontend. |
| 79 | return new Response(response.toReadableStream(), { |
| 80 | headers: { "Content-Type": "application/x-ndjson" }, |
| 81 | }); |
| 82 | } |
| 83 | ``` |
| 84 | |
| 85 | ### Frontend: `app/chat/page.tsx` |
| 86 | |
| 87 | ```tsx |
| 88 | "use client"; |
| 89 | import { FullScreen } from "@openuidev/react-ui"; |
| 90 | import { openuiChatLibrary } from "@openuidev/react-ui/genui-lib"; |
| 91 | import { |
| 92 | openAIReadableStreamAdapter, |
| 93 | openAIMessageFormat, |
| 94 | } from "@openuidev/react-headless"; |
| 95 | |
| 96 | export default function ChatPage() { |
| 97 | return ( |
| 98 | <FullScreen |
| 99 | componentLibrary={openuiChatLibrary} |
| 100 | streamProtocol={openAIReadableStreamAdapter()} |
| 101 | messageFormat={openAIMessageFormat} |
| 102 | apiUrl="/api/chat" |
| 103 | /> |
| 104 | ); |
| 105 | } |
| 106 | ``` |
| 107 | |
| 108 | ## Component Creation |
| 109 | |
| 110 | ```tsx |
| 111 | import { defineComponent } from "@openuidev/react-lang"; |
| 112 | import { z } from "zod"; |
| 113 | |
| 114 | export const MyCard = defineComponent({ |
| 115 | name: "MyCard", |
| 116 | description: "A card displaying a title and body text", |
| 117 | props: z.object({ |
| 118 | title: z.string().describe("The card heading"), |
| 119 | body: z.string().describe("The card body content"), |
| 120 | }), |
| 121 | component: ({ props }) => ( |
| 122 | <div style={{ border: "1px solid #ddd", borderRadius: 8, padding: 16 }}> |
| 123 | <h3>{props.title} |