Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion docs/app/api/openui-cloud/chat/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import { readOpenuiCloudConfig } from "@/lib/openui-cloud/config";
import { unavailableResponse } from "@/lib/openui-cloud/errors";
import { resolveRequestedModel } from "@/lib/openui-cloud/models";
import { hasAllowedOrigin, hasJsonContentType, readLimitedJson } from "@/lib/openui-cloud/request";
import { artifactTool, generateSystemPrompt } from "@openuidev/thesys-server";
import { generateSystemPrompt } from "@openuidev/lang-core";
import { artifactTool } from "@openuidev/thesys-server";
import OpenAI from "openai";
import type { ResponseInputItem } from "openai/resources/responses/responses";

Expand Down Expand Up @@ -56,6 +57,7 @@ export async function POST(request: Request): Promise<Response> {
{ type: "image_search" },
],
instructions: generateSystemPrompt({
cloud: true,
instructions:
"When creating an artifact, actively use the available web and image search tools to ground its content and visual choices.",
}),
Expand Down
8 changes: 4 additions & 4 deletions docs/content/docs/openui-cloud/api/chat-completions.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,20 @@ Use the `embedClient` from the [API overview](/docs/openui-cloud/api/overview),
Use the server helper to have OpenUI Cloud assemble the system prompt for its built-in component library.

```ts title="server.ts"
import { generateSystemPrompt } from "@openuidev/thesys-server";
import { generateSystemPrompt } from "@openuidev/lang-core";

const completion = await embedClient.chat.completions.create({
model: "openai/gpt-5",
messages: [
{ role: "system", content: generateSystemPrompt() },
{ role: "system", content: generateSystemPrompt({ cloud: true }) },
{ role: "user", content: "Compare quarterly revenue by region." },
],
});

console.log(completion.choices[0].message.content);
```

The returned message content is an OpenUI Lang program. See [Component Library](/docs/openui-cloud/build/component-library) for the built-in client library and custom component workflow.
The returned message content is an OpenUI Lang program. See [Component Library](/docs/openui-cloud/build/component-library) for the built-in client library and using your own library.

## Stream and render responses

Expand Down Expand Up @@ -75,7 +75,7 @@ Hosted `web_search`, `image_search`, remote MCP, and artifacts-as-tool are avail

### Plain text passthrough

Use a `{provider}/{model}` model ID without the managed `generateSystemPrompt()` sentinel. OpenUI Cloud forwards your messages and system prompt without injecting a generative UI prompt or component schema.
Use a `{provider}/{model}` model ID without the managed `generateSystemPrompt({ cloud: true })` sentinel. OpenUI Cloud forwards your messages and system prompt without injecting a generative UI prompt or component schema.

```ts
const completion = await embedClient.chat.completions.create({
Expand Down
4 changes: 2 additions & 2 deletions docs/content/docs/openui-cloud/api/conversations.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,13 @@ const conversation = await conversationClient.conversations.create({
Then send only the new turn to Responses and set `store: true`:

```ts
import { generateSystemPrompt } from "@openuidev/thesys-server";
import { generateSystemPrompt } from "@openuidev/lang-core";

const response = await embedClient.responses.create({
model: "openai/gpt-5",
conversation: conversation.id,
input: "Compare quarterly revenue by region.",
instructions: generateSystemPrompt(),
instructions: generateSystemPrompt({ cloud: true }),
store: true,
stream: true,
});
Expand Down
17 changes: 9 additions & 8 deletions docs/content/docs/openui-cloud/api/responses.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,18 @@ Use the `embedClient` from the [API overview](/docs/openui-cloud/api/overview),
Use the server helper to have OpenUI Cloud assemble the system prompt for its built-in component library.

```ts title="server.ts"
import { generateSystemPrompt } from "@openuidev/thesys-server";
import { generateSystemPrompt } from "@openuidev/lang-core";

const response = await embedClient.responses.create({
model: "openai/gpt-5",
input: "Compare quarterly revenue by region.",
instructions: generateSystemPrompt(),
instructions: generateSystemPrompt({ cloud: true }),
});

console.log(response.output_text);
```

The returned `output_text` is an OpenUI Lang program. See [Component Library](/docs/openui-cloud/build/component-library) for the built-in client library and custom component workflow.
The returned `output_text` is an OpenUI Lang program. See [Component Library](/docs/openui-cloud/build/component-library) for the built-in client library and using your own library.

## Stream and render responses

Expand Down Expand Up @@ -72,14 +72,14 @@ Chain a follow-up to an earlier response:
const first = await embedClient.responses.create({
model: "openai/gpt-5",
input: "Compare quarterly revenue by region.",
instructions: generateSystemPrompt(),
instructions: generateSystemPrompt({ cloud: true }),
store: true,
});

const followUp = await embedClient.responses.create({
model: "openai/gpt-5",
input: "Focus on Europe and explain the change.",
instructions: generateSystemPrompt(),
instructions: generateSystemPrompt({ cloud: true }),
previous_response_id: first.id,
store: true,
});
Expand All @@ -105,7 +105,7 @@ import type { Tool } from "openai/resources/responses/responses";
const response = await embedClient.responses.create({
model: "openai/gpt-5",
input: "Research the market and summarize the most important changes.",
instructions: generateSystemPrompt(),
instructions: generateSystemPrompt({ cloud: true }),
tools: [
{ type: "web_search" },
{ type: "image_search" } as unknown as Tool,
Expand All @@ -129,14 +129,15 @@ For a `function` tool, execute each returned `function_call` on your server and
Add `artifactTool()` to generate editable slides or reports inside the agent stream:

```ts
import { artifactTool, generateSystemPrompt } from "@openuidev/thesys-server";
import { generateSystemPrompt } from "@openuidev/lang-core";
import { artifactTool } from "@openuidev/thesys-server";
import type { Tool } from "openai/resources/responses/responses";

const response = await embedClient.responses.create({
model: "openai/gpt-5",
conversation: threadId,
input: "Create a three-slide deck on Q4 results.",
instructions: generateSystemPrompt(),
instructions: generateSystemPrompt({ cloud: true }),
tools: [artifactTool({ artifacts: ["slides", "report"] }) as unknown as Tool],
store: true,
stream: true,
Expand Down
10 changes: 7 additions & 3 deletions docs/content/docs/openui-cloud/build/component-library.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,19 @@ import { chatLibrary } from "@openuidev/thesys";
<AgentInterface llm={llm} componentLibrary={chatLibrary} />;
```

On the backend, `generateSystemPrompt()` uses the built-in library by default. Use the `embedClient` from the [API overview](/docs/openui-cloud/api/overview); the placement of the generated instructions depends on the API:
On the backend, `generateSystemPrompt({ cloud: true })` uses the built-in library by default. Use the `embedClient` from the [API overview](/docs/openui-cloud/api/overview); the placement of the generated instructions depends on the API:

<Tabs groupId="cloud-api" items={["Responses", "Chat Completions"]} persist>
<Tab value="Responses">

```ts
import { generateSystemPrompt } from "@openuidev/thesys-server";
import { generateSystemPrompt } from "@openuidev/lang-core";

const response = await embedClient.responses.create({
model: "openai/gpt-5",
input: "Show revenue by region as an interactive dashboard.",
instructions: generateSystemPrompt({
cloud: true,
instructions: "Optional instructions for the model.",
}),
});
Expand All @@ -36,14 +37,15 @@ const response = await embedClient.responses.create({
<Tab value="Chat Completions">

```ts
import { generateSystemPrompt } from "@openuidev/thesys-server";
import { generateSystemPrompt } from "@openuidev/lang-core";

const completion = await embedClient.chat.completions.create({
model: "openai/gpt-5",
messages: [
{
role: "system",
content: generateSystemPrompt({
cloud: true,
instructions: "Optional instructions for the model.",
}),
},
Expand Down Expand Up @@ -123,6 +125,7 @@ npx @openuidev/cli@latest generate --spec src/lib/chat-library.tsx --out ./gener
model: "openai/gpt-5",
input,
instructions: generateSystemPrompt({
cloud: true,
instructions: "Optional instructions for the model.",
+ library: librarySpec,
+ promptOptions: { preamble: "You build dashboards for Acme operators." },
Expand All @@ -142,6 +145,7 @@ npx @openuidev/cli@latest generate --spec src/lib/chat-library.tsx --out ./gener
{
role: "system",
content: generateSystemPrompt({
cloud: true,
instructions: "Optional instructions for the model.",
+ library: librarySpec,
+ promptOptions: { preamble: "You build dashboards for Acme operators." },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ This example uses the [Vercel AI SDK](https://ai-sdk.dev/) (`streamText`, `tool(

## How it connects

The API route calls `streamText` with Cloud Completions, `generateSystemPrompt()`, and tools defined with `tool()`. When the model calls a tool, the AI SDK executes it server-side and continues — up to 5 steps. The response is a UIMessage stream.
The API route calls `streamText` with Cloud Completions, `generateSystemPrompt({ cloud: true })`, and tools defined with `tool()`. When the model calls a tool, the AI SDK executes it server-side and continues — up to 5 steps. The response is a UIMessage stream.

The page passes that stream to `<AgentInterface />`:

Expand Down Expand Up @@ -54,7 +54,7 @@ Storage is omitted, so AgentInterface uses its built-in in-memory default (wiped

```ts
import { createOpenAI } from "@ai-sdk/openai";
import { generateSystemPrompt } from "@openuidev/thesys-server";
import { generateSystemPrompt } from "@openuidev/lang-core";
import { convertToModelMessages, stepCountIs, streamText } from "ai";
import { tools } from "@/lib/tools";

Expand All @@ -67,7 +67,7 @@ export async function POST(req: Request) {
const { messages } = await req.json();
const result = streamText({
model: openai.chat("google/gemini-3.6-flash-free"),
system: generateSystemPrompt(),
system: generateSystemPrompt({ cloud: true }),
messages: await convertToModelMessages(messages),
tools,
stopWhen: stepCountIs(5),
Expand Down
3 changes: 2 additions & 1 deletion docs/content/docs/openui-lang/quickstart.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -297,8 +297,9 @@ Never claim that a recipe is allergen-safe.
Update the `instructions` field inside `createParams`:

<CopyableDiff
code={`-instructions: generateSystemPrompt(),
code={`-instructions: generateSystemPrompt({ cloud: true }),
+instructions: generateSystemPrompt({
+ cloud: true,
+ library: recipeLibrarySpec,
+ instructions: recipeInstructions,
+}),`}
Expand Down
24 changes: 23 additions & 1 deletion docs/content/docs/openui-lang/system-prompts.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ const systemPrompt = generateSystemPrompt({
editMode: true, // Enable incremental editing (LLM outputs patches, not full regen)
inlineMode: true, // Enable text + code responses (LLM can answer questions without code)

// Custom instructions
// Preamble and extra rules
preamble: "You build dashboards using openui-lang.",
additionalRules: ['Use @Reset after form submit, not @Set($var, "")'],
},
Expand All @@ -85,6 +85,28 @@ const systemPrompt = generateSystemPrompt({
| `editMode` | Incremental editing - LLM outputs only changed statements | `false` |
| `inlineMode` | Text + fenced code responses - LLM can answer questions without generating UI | `false` |

### OpenUI Cloud

Pass `cloud: true` to emit Cloud's managed config block instead of a local prompt. OpenUI Cloud assembles the real system prompt on the server. `instructions` is Cloud-only extra prose appended after the config block.

```ts
import { generateSystemPrompt } from "@openuidev/lang-core";

const instructions = generateSystemPrompt({ cloud: true });
```

With your own library, pass the generated spec:

```ts
const instructions = generateSystemPrompt({
cloud: true,
library: librarySpec,
promptOptions: { preamble: "You build dashboards for Acme." },
});
```

See [Component Library](/docs/openui-cloud/build/component-library) for the Cloud workflow.

Built-in functions (`@Count`, `@Filter`, `@Sort`, `@Each`, etc.) are automatically included when either `toolCalls` or `bindings` is enabled. For static UI libraries without data fetching, they are omitted to keep the prompt concise.

### `library.prompt()` (frontend shorthand)
Expand Down
45 changes: 34 additions & 11 deletions packages/lang-core/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,16 +61,38 @@ const result2 = sp.set("root = Stack([header])\nheader = CardHeader(\"Hello\")\n
### Generate a system prompt

```ts
import { generatePrompt, type PromptSpec } from "@openuidev/lang-core";
import componentSpec from "./generated/component-spec.json";

const prompt = generatePrompt({
...componentSpec,
tools: myToolSpecs,
toolCalls: true,
bindings: true,
editMode: true,
preamble: "You build dashboards.",
import { generateSystemPrompt, type LibrarySpec } from "@openuidev/lang-core";
import librarySpec from "./generated/library.spec.json";

const prompt = generateSystemPrompt({
library: librarySpec as LibrarySpec,
promptOptions: {
tools: myToolSpecs,
toolCalls: true,
bindings: true,
editMode: true,
preamble: "You build dashboards.",
},
});
```

### OpenUI Cloud

Pass `cloud: true` to emit Cloud's managed config block instead of a local prompt. OpenUI Cloud
assembles the real system prompt on the server.

```ts
import { generateSystemPrompt } from "@openuidev/lang-core";

// Built-in Cloud chat library
const instructions = generateSystemPrompt({ cloud: true });

// Using your own library (the `.spec.json` from `openui generate`)
const myLibraryPrompt = generateSystemPrompt({
cloud: true,
library: librarySpec,
promptOptions: { preamble: "You build dashboards for Acme." },
instructions: "Be terse.",
});
```

Expand Down Expand Up @@ -99,7 +121,8 @@ const merged = mergeStatements(original, patch);

| Export | Description |
| :--- | :--- |
| `generatePrompt(spec)` | Generate a system prompt from a `PromptSpec` |
| `generatePrompt(spec)` | Generate a system prompt from a `PromptSpec` (now deprecated) |
| `generateSystemPrompt(spec)` | Generate a system prompt from `{ library, promptOptions }`. Pass `{ cloud: true }` for OpenUI Cloud's managed config. |

**`PromptSpec`** includes component signatures, tool definitions (`ToolSpec[]`), feature flags (`toolCalls`, `bindings`, `editMode`, `inlineMode`), examples, and custom rules.

Expand Down
2 changes: 1 addition & 1 deletion packages/lang-core/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@openuidev/lang-core",
"version": "0.2.16",
"version": "0.2.17",
"description": "Framework-agnostic core for OpenUI Lang: parser, prompt generation, validation, and type definitions",
"license": "MIT",
"type": "module",
Expand Down
1 change: 1 addition & 0 deletions packages/lang-core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export { tokenize } from "./parser/lexer";
export { mergeStatements } from "./parser/merge";
export { generatePrompt, generateSystemPrompt } from "./parser/prompt";
export type {
CloudPromptOptions,
ComponentPromptSpec,
LibrarySpec,
PromptSpec,
Expand Down
Loading
Loading