@openuidev/server
API reference for Autofix helpers and conversation history persistence on the OpenUI Gateway.
Server utilities for OpenUI Gateway. Validate and repair model-generated OpenUI Lang, and persist a completed turn as Conversations API items. Import from the subpath that matches your SDK. The helpers call Autofix HTTP API.
Install
pnpm add @openuidev/serverImport paths
| Import from | Autofix | History helpers |
|---|---|---|
@openuidev/server/openai | completions.fix and completions.stream | storeChatCompletionHistory, chatCompletionMessagesToItems |
@openuidev/server/vercel | ai.fix and ai.stream | — |
Pair each Autofix stream with the matching frontend adapter: openAIAdapter() or useChat.
createAutofix(options)
Use the spec from openui generate --spec for the same library as your renderer, including its schema.
import { createAutofix } from "@openuidev/server/openai";
import library from "./openui.spec.json";
const autofix = createAutofix({
apiKey: process.env.THESYS_API_KEY!,
library,
});function createAutofix(options: {
apiKey: string;
library: LibrarySpec & { schema: LibraryJSONSchema };
apiBaseUrl?: string; // defaults to https://api.thesys.dev
fetch?: typeof globalThis.fetch;
}): Autofix;From @openuidev/server/openai, Autofix is { completions: { fix, stream } }. From @openuidev/server/vercel, it is { ai: { fix, stream } }.
fix(input)
Validate completed OpenUI text. Valid output is returned as-is. Invalid output is sent to POST /v1/autofix.
const result = await autofix.completions.fix({ generation, messages, signal });
if (result.content !== null) {
// already_valid or fixed — use result.content
} else {
// fix_failed — choose a fallback
console.warn(result.unfixedErrors);
}function fix(input: {
generation: string;
messages?: ChatCompletionMessageParam[];
signal?: AbortSignal;
}): Promise<AutofixResult>;generation is the completed OpenUI text. Optional messages is the conversation before that generation. On fixed, content is the program the Autofix API returned.
type AutofixResult = {
original: string;
fixedErrors: AutofixDiagnostic[];
unfixedErrors: AutofixDiagnostic[];
} & (
{ status: "already_valid" | "fixed"; content: string } | { status: "fix_failed"; content: null }
);
interface AutofixDiagnostic {
code: string;
message: string;
component?: string;
path?: string;
statementId?: string;
}stream(input)
Wrap a native SDK stream. The helper forwards provider events and inserts a repair before the stream completes when the finished UI is invalid.
function stream(input: {
stream: AsyncIterable<Chunk> & { controller?: AbortController };
messages?: ChatCompletionMessageParam[];
signal?: AbortSignal;
}): AutofixStream<Chunk>;Use autofix.completions.stream() with a native Chat Completions stream, or autofix.ai.stream() with toUIMessageStream({ stream: result.stream }) — not the raw result.stream.
interface AutofixStream<T> {
chunks: AsyncIterable<T>;
toResponse(): Response;
result: Promise<AutofixResult | null>;
}Use either chunks or toResponse() once. result settles after that consumer finishes. Persist result.content when it is a string — that is the Autofix program, not the joined stream text. result is null when Autofix did not run.
import OpenAI from "openai";
import { createAutofix } from "@openuidev/server/openai";
import library from "./openui.spec.json";
const model = new OpenAI();
const autofix = createAutofix({
apiKey: process.env.THESYS_API_KEY!,
library,
});
export async function POST(request: Request) {
const { messages } = await request.json();
const source = await model.chat.completions.create(
{ model: "openai/gpt-5.5", messages, stream: true },
{ signal: request.signal },
);
return autofix.completions
.stream({ stream: source, messages, signal: request.signal })
.toResponse();
}const output = autofix.completions.stream({ stream: source, messages, signal });
for await (const chunk of output.chunks) {
// Native SDK events, including any appended correction
}
const settled = await output.result;
if (settled?.content) {
// Persist settled.content
}A failed repair on a stream throws with code: "fix_failed". Use fix() on the same helper when you already have completed text.
Stream errors
Thrown errors include a code string:
code | When |
|---|---|
invalid_library | library.schema is missing |
generation_too_large | Generation exceeds 100,000 characters |
http_error | Autofix HTTP request failed (status is set) |
invalid_response | Autofix response could not be read |
stream_consumed | chunks or toResponse() was used more than once |
fix_failed | Streamed generation could not be repaired |
Conversation history
Persist only the new turn — not the full messages array — or items will be duplicated. Use the master API key. System and developer messages are skipped.
storeChatCompletionHistory(options)
import { storeChatCompletionHistory } from "@openuidev/server/openai";
await storeChatCompletionHistory({
apiKey: process.env.THESYS_API_KEY!,
conversationId: threadId,
messages: [
{ role: "user", content: lastUserText },
{ role: "assistant", content: assistantText },
],
});function storeChatCompletionHistory(options: {
apiKey: string;
conversationId: string;
messages: ChatCompletionMessageParam[];
apiBaseUrl?: string;
fetch?: typeof fetch;
}): Promise<ConversationItemList>;chatCompletionMessagesToItems(messages)
Convert Chat Completions messages to Conversations API items without posting.
import { chatCompletionMessagesToItems } from "@openuidev/server/openai";
chatCompletionMessagesToItems([
{ role: "user", content: "hello" },
{ role: "assistant", content: "hi" },
]);Exports
| Entry point | Export | Description |
|---|---|---|
@openuidev/server/openai | createAutofix | Chat Completions Autofix: completions.fix / stream |
@openuidev/server/openai | storeChatCompletionHistory | Persist a Chat Completions turn |
@openuidev/server/openai | chatCompletionMessagesToItems | Convert messages to Conversations API items |
@openuidev/server/openai | StoreChatCompletionHistoryOptions | History helper configuration |
@openuidev/server/vercel | createAutofix | Vercel AI SDK Autofix: ai.fix / ai.stream |