@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/server

Import paths

Import fromAutofixHistory helpers
@openuidev/server/openaicompletions.fix and completions.streamstoreChatCompletionHistory, chatCompletionMessagesToItems
@openuidev/server/vercelai.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.

app/api/chat/route.ts
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:

codeWhen
invalid_librarylibrary.schema is missing
generation_too_largeGeneration exceeds 100,000 characters
http_errorAutofix HTTP request failed (status is set)
invalid_responseAutofix response could not be read
stream_consumedchunks or toResponse() was used more than once
fix_failedStreamed 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 pointExportDescription
@openuidev/server/openaicreateAutofixChat Completions Autofix: completions.fix / stream
@openuidev/server/openaistoreChatCompletionHistoryPersist a Chat Completions turn
@openuidev/server/openaichatCompletionMessagesToItemsConvert messages to Conversations API items
@openuidev/server/openaiStoreChatCompletionHistoryOptionsHistory helper configuration
@openuidev/server/vercelcreateAutofixVercel AI SDK Autofix: ai.fix / ai.stream

On this page