From 833554e89e35c46558434a2e4b022474dd3da7d8 Mon Sep 17 00:00:00 2001 From: Ankur Mittal Date: Thu, 10 Sep 2026 14:27:24 +0530 Subject: [PATCH 01/20] docs: add the Sanitize API to the Gateway docs New API page with the request, config, response statuses, error codes, limits, pricing, and errors. A card on the Gateway introduction, a sidebar entry under APIs, a callout on the Reliability page, and a short Pricing note. Co-Authored-By: Claude Fable 5.1 --- docs/content/docs/gateway/api/sanitize.mdx | 163 ++++++++++++++++++ docs/content/docs/gateway/index.mdx | 4 + docs/content/docs/gateway/meta.json | 3 +- docs/content/docs/gateway/pricing-credits.mdx | 4 + docs/content/docs/gateway/reliability.mdx | 9 +- 5 files changed, 181 insertions(+), 2 deletions(-) create mode 100644 docs/content/docs/gateway/api/sanitize.mdx diff --git a/docs/content/docs/gateway/api/sanitize.mdx b/docs/content/docs/gateway/api/sanitize.mdx new file mode 100644 index 000000000..fda66acce --- /dev/null +++ b/docs/content/docs/gateway/api/sanitize.mdx @@ -0,0 +1,163 @@ +--- +title: Sanitize API +description: Repair invalid OpenUI Lang from any model without routing the request through Gateway. +--- + +The Sanitize API corrects OpenUI Lang after a model has produced it. Send the raw model output, and Gateway validates it, repairs the errors it can, and returns a complete program that the renderer can use. + +Use it when your application calls a model directly and only needs the correction step. The request does not include a conversation or a model, and Gateway does not generate anything new. It applies the same correction that runs inside the [Chat Completions](/docs/gateway/api/chat-completions) and [Responses](/docs/gateway/api/responses) APIs, as a standalone call. + +**Endpoint:** POST [https://api.thesys.dev/v1/embed/sanitize](https://api.thesys.dev/v1/embed/sanitize) + +## Repair a program + +Send the output exactly as the model returned it. Fenced or bare OpenUI Lang both work, and text outside the fence is ignored. + +```ts title="server.ts" +const response = await fetch("https://api.thesys.dev/v1/embed/sanitize", { + method: "POST", + headers: { + Authorization: `Bearer ${process.env.THESYS_API_KEY}`, + "Content-Type": "application/json", + }, + body: JSON.stringify({ output: modelOutput }), +}); + +const result = await response.json(); + +if (result.status !== "repair_failed") { + render(result.program); +} +``` + +The response carries the whole program, not a patch. Replace the model output with `program` and render it. Server calls use the API key described in [Authentication](/docs/gateway/authentication). + +## Describe your components + +Gateway can only judge a program against the components your application renders. By default it uses the built-in OpenUI chat library. Add a `config` object when your application differs from that default. + +```ts +body: JSON.stringify({ + output: modelOutput, + config: { + openUIlibraryVersion: "0.1.0", + customActions: { + book_table: { + description: "Reserve a table for the party size given.", + properties: { size: { type: "number" } }, + required: ["size"], + }, + }, + }, +}); +``` + +| Field | Purpose | +| ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | +| `config.openUIlibraryVersion` | The version of the built-in OpenUI chat library your application renders, for example `"0.1.0"`. | +| `config.library` | A custom component library in the same JSON Schema shape that `library.toJSONSchema()` produces. It replaces the built-in library entirely. | +| `config.customActions` | The actions your application handles from buttons, as a map of action name to parameter schema. Gateway keeps them intact during repair. | + +`openUIlibraryVersion` and `library` are mutually exclusive. `customActions` can accompany either. + +The keys match the config block that `generateSystemPrompt` writes for the generation APIs, so an application that already builds that block can pass the same values here. + +## Read the result + +`status` tells you what happened. The other fields depend on it. + +| `status` | `program` | Errors | Charged | +| --------------- | --------------------- | ---------------------------------------------------- | ------- | +| `already_valid` | The input, unchanged | `fixed-errors` is empty | No | +| `repaired` | The corrected program | `fixed-errors` lists what was wrong and is now fixed | Yes | +| `repair_failed` | `null` | `unfixed-errors` lists what is still wrong | Yes | + +A repaired program: + +```json +{ + "id": "san_P4TPtYimJFMpSgsViggie", + "object": "openui.sanitize", + "created": 1789019848, + "status": "repaired", + "program": "root = Card([header])\nheader = Header(\"Q3 Results\")", + "fixed-errors": [ + { + "code": "unresolved", + "statementId": "followUp", + "message": "reference \"followUp\" is never defined" + } + ], + "usage": { "prompt_tokens": 8014, "completion_tokens": 17, "total_tokens": 8031 } +} +``` + +A failed repair: + +```json +{ + "id": "san_dRvfleg31F5g-Amn3v4-W", + "object": "openui.sanitize", + "created": 1789026253, + "status": "repair_failed", + "program": null, + "unfixed-errors": [ + { + "code": "null-required", + "component": "B", + "path": "/child", + "statementId": "z", + "message": "required field \"/child\" cannot be null" + } + ], + "usage": { "prompt_tokens": 360, "completion_tokens": 146, "total_tokens": 506 } +} +``` + +When the repair fails, fall back to what your application does for any unusable model output, such as showing the text or a generic error state. + +## Error codes + +Each entry in `fixed-errors` or `unfixed-errors` names one problem. `code` is always present. `component`, `path`, and `statementId` are present when the validator can name the component type, the property, and the statement that carried the problem. + +| Code | Meaning | +| ------------------- | ---------------------------------------------------------------------------------- | +| `unknown-component` | A component name that is not in the library. | +| `missing-required` | A required property was left out. | +| `null-required` | A required property was set to `null`. | +| `type-mismatch` | A property has the wrong type, or a value outside its allowed set. | +| `excess-args` | A component received more arguments than its signature has. | +| `inline-reserved` | `Query()` or `Mutation()` was used inside an expression instead of as a statement. | +| `incomplete` | The output stopped in the middle of a statement. | +| `unresolved` | A statement is referenced but never defined. | +| `orphaned` | A statement is defined but not reachable from `root`. | +| `missing-root` | The output has no valid `root` statement. | + +These are the same codes the OpenUI SDK reports in the browser, so an application can handle both with one path. See [Observability](/docs/observability) for how they appear in the Thesys Console. + +## Limits + +- `output` can be up to 100,000 characters. +- Gateway makes up to two repair attempts per request. +- Chat programs only. Artifacts such as slides and reports are not accepted. + +## Pricing + +A sanitize call is charged for the model tokens the repair used, at the repair model's rate with no markup. A program that is already valid uses no model and is not charged. + +`usage` in the response reports the tokens you were charged for. See [Pricing](/docs/gateway/pricing-credits) for rates. + +## Errors + +The endpoint returns the same error shape as the other Gateway APIs. + +| Status | Type | When | +| ------ | ----------------------- | ---------------------------------------------------------- | +| `400` | `invalid_request_error` | `output` is empty or too long, or `config` is malformed. | +| `401` | `authentication_error` | The API key is missing or invalid. | +| `429` | `rate_limit_error` | The organization has no credits, or billing is suspended. | +| `500` | `internal_server_error` | The repair model could not be reached. Nothing is charged. | + +## Observability + +Sanitize calls appear in the Thesys Console under the model name `openui/sanitize`. A successful repair counts as a sanitizer correction on the Reliability page, with the same error codes as corrections made during generation. diff --git a/docs/content/docs/gateway/index.mdx b/docs/content/docs/gateway/index.mdx index 6c421d55e..3f53de336 100644 --- a/docs/content/docs/gateway/index.mdx +++ b/docs/content/docs/gateway/index.mdx @@ -70,6 +70,9 @@ full: true Build stateful model interactions with persistent conversations and hosted tools. + + Repair invalid OpenUI Lang from any model. Send the raw output and get back a valid program. +
@@ -78,5 +81,6 @@ full: true - **Validated generated UI.** Validates generated UI during the stream and fixes malformed syntax, invalid component usage, and schema violations before forwarding the response. - **Unified API.** Switch between providers and models with minimal code changes. - **High reliability.** Automatically retries requests with other providers if one fails. + - **Correction on its own.** Keep your model and backend, and send only the output that needs repair to the Sanitize API. - **No markup on tokens.** Tokens cost the same as they would from the provider directly, with zero markup, including with Bring Your Own Key (BYOK).
diff --git a/docs/content/docs/gateway/meta.json b/docs/content/docs/gateway/meta.json index 4ef188263..e5a82266c 100644 --- a/docs/content/docs/gateway/meta.json +++ b/docs/content/docs/gateway/meta.json @@ -14,6 +14,7 @@ "---APIs---", "api/chat-completions", "api/responses", - "api/conversations" + "api/conversations", + "api/sanitize" ] } diff --git a/docs/content/docs/gateway/pricing-credits.mdx b/docs/content/docs/gateway/pricing-credits.mdx index c1c48b88f..bf8a26e6c 100644 --- a/docs/content/docs/gateway/pricing-credits.mdx +++ b/docs/content/docs/gateway/pricing-credits.mdx @@ -38,6 +38,10 @@ The cost of a Gateway request has two parts: Model usage is billed at the provider's rates without markup. The Gateway API and OpenUI Lang correction behavior remain the same whether you use managed inference or your own provider key. +### Sanitize API + +A [Sanitize API](/docs/gateway/api/sanitize) call is charged for the model tokens the repair used, at the repair model's rate with no markup. Output that is already valid is not charged. + ### Finding model pricing Model prices vary by provider and model. View the latest rates on the [Thesys pricing page](https://www.thesys.dev/pricing), including: diff --git a/docs/content/docs/gateway/reliability.mdx b/docs/content/docs/gateway/reliability.mdx index 8e03a6dd3..ea5efd39b 100644 --- a/docs/content/docs/gateway/reliability.mdx +++ b/docs/content/docs/gateway/reliability.mdx @@ -12,7 +12,7 @@ Gateway handles each problem differently. It automatically retries the request w | Problem | What happens | How Gateway responds | | ------------------------ | ------------------------------------------------------------------------------------------------- | -------------------------------------------------------- | | **Provider unavailable** | An outage, capacity limit, or unavailable route prevents the selected provider from responding. | Gateway retries through a compatible fallback route. | -| **Invalid model output** | The model returns OpenUI Lang with invalid syntax, references, components, properties, or structure. | Gateway corrects eligible errors and continues the stream. | +| **Invalid model output** | The model returns OpenUI Lang with invalid syntax, references, components, properties, or structure. | Gateway corrects eligible errors and continues the stream, or repairs the output on request through the Sanitize API. | ## Recover from provider failures @@ -26,6 +26,12 @@ The application continues to use the same Gateway API and `{provider}/{model}` n ## Correct invalid model output + + The same correction is available as a standalone call. Send your model's OpenUI Lang output to + the [Sanitize API](/docs/gateway/api/sanitize) and get back a valid program, charged only for + the repair. + + Gateway validates OpenUI Lang while the model produces it. It can identify eligible problems such as: - Malformed OpenUI Lang statements @@ -42,6 +48,7 @@ Correction applies only to generated OpenUI Lang. Plain text, arbitrary JSON, ap Gateway improves the reliability of model access and generated OpenUI Lang. Your application remains responsible for: +- Fallback behavior when a repair fails, whether during a stream or through the Sanitize API - Component behavior and UI error boundaries - Authentication and permissions - Tool authorization and input validation From 427d70df57e139554e4408966d52b21ccbee5473 Mon Sep 17 00:00:00 2001 From: Ankur Mittal Date: Thu, 10 Sep 2026 14:53:04 +0530 Subject: [PATCH 02/20] docs: sanitize API is a flat price per repair --- docs/content/docs/gateway/api/sanitize.mdx | 4 ++-- docs/content/docs/gateway/pricing-credits.mdx | 2 +- docs/content/docs/gateway/reliability.mdx | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/content/docs/gateway/api/sanitize.mdx b/docs/content/docs/gateway/api/sanitize.mdx index fda66acce..f520c2a95 100644 --- a/docs/content/docs/gateway/api/sanitize.mdx +++ b/docs/content/docs/gateway/api/sanitize.mdx @@ -143,9 +143,9 @@ These are the same codes the OpenUI SDK reports in the browser, so an applicatio ## Pricing -A sanitize call is charged for the model tokens the repair used, at the repair model's rate with no markup. A program that is already valid uses no model and is not charged. +Each call that runs a repair costs a flat $0.02, deducted from your Gateway Credits. This applies whether the repair succeeds or fails, since the model ran either way. A program that is already valid uses no model and is free. -`usage` in the response reports the tokens you were charged for. See [Pricing](/docs/gateway/pricing-credits) for rates. +`usage` in the response reports the tokens the repair used, for your own tracking. The charge does not depend on it. See [Pricing](/docs/gateway/pricing-credits). ## Errors diff --git a/docs/content/docs/gateway/pricing-credits.mdx b/docs/content/docs/gateway/pricing-credits.mdx index bf8a26e6c..732ded046 100644 --- a/docs/content/docs/gateway/pricing-credits.mdx +++ b/docs/content/docs/gateway/pricing-credits.mdx @@ -40,7 +40,7 @@ Model usage is billed at the provider's rates without markup. The Gateway API an ### Sanitize API -A [Sanitize API](/docs/gateway/api/sanitize) call is charged for the model tokens the repair used, at the repair model's rate with no markup. Output that is already valid is not charged. +A [Sanitize API](/docs/gateway/api/sanitize) call that runs a repair costs a flat $0.02, deducted from your Gateway Credits. It does not use a plan API call. Output that is already valid is free. ### Finding model pricing diff --git a/docs/content/docs/gateway/reliability.mdx b/docs/content/docs/gateway/reliability.mdx index ea5efd39b..bfd034a81 100644 --- a/docs/content/docs/gateway/reliability.mdx +++ b/docs/content/docs/gateway/reliability.mdx @@ -28,8 +28,8 @@ The application continues to use the same Gateway API and `{provider}/{model}` n The same correction is available as a standalone call. Send your model's OpenUI Lang output to - the [Sanitize API](/docs/gateway/api/sanitize) and get back a valid program, charged only for - the repair. + the [Sanitize API](/docs/gateway/api/sanitize) and get back a valid program, at a flat price per + repair. Gateway validates OpenUI Lang while the model produces it. It can identify eligible problems such as: From 03445ef20f37e766d37ad13cdc01caa50c6abe46 Mon Sep 17 00:00:00 2001 From: Ankur Mittal Date: Thu, 10 Sep 2026 15:27:39 +0530 Subject: [PATCH 03/20] docs: move the Sanitize API callout to the top of Reliability --- docs/content/docs/gateway/reliability.mdx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/content/docs/gateway/reliability.mdx b/docs/content/docs/gateway/reliability.mdx index bfd034a81..51246c7c5 100644 --- a/docs/content/docs/gateway/reliability.mdx +++ b/docs/content/docs/gateway/reliability.mdx @@ -3,6 +3,12 @@ title: Reliability description: Keep model requests working when providers are unavailable or models return invalid OpenUI Lang. --- + + Not routing requests through Gateway? Send your model's OpenUI Lang output to the + [Sanitize API](/docs/gateway/api/sanitize) and get back a valid program, at a flat price per + repair. + + Applications that generate interfaces with AI face two common reliability problems. A model provider may be unavailable, or the model may return output that does not follow the OpenUI Lang instructions and component schemas. The first prevents a response; the second can produce an interface the application cannot render. Gateway handles each problem differently. It automatically retries the request with other providers and corrects eligible errors in model output while the response streams. @@ -26,12 +32,6 @@ The application continues to use the same Gateway API and `{provider}/{model}` n ## Correct invalid model output - - The same correction is available as a standalone call. Send your model's OpenUI Lang output to - the [Sanitize API](/docs/gateway/api/sanitize) and get back a valid program, at a flat price per - repair. - - Gateway validates OpenUI Lang while the model produces it. It can identify eligible problems such as: - Malformed OpenUI Lang statements From ee925d1afd94d9bcb86923dcb580236e5fdf9df8 Mon Sep 17 00:00:00 2001 From: Ankur Mittal Date: Thu, 10 Sep 2026 15:54:03 +0530 Subject: [PATCH 04/20] docs: address review on the Sanitize API page No "program" anywhere; one library input, taken from the CLI's spec file, with full examples including imports; no artifact limit line; pricing links to the Pricing page instead of stating the amount. --- docs/content/docs/gateway/api/sanitize.mdx | 128 +++++++++--------- docs/content/docs/gateway/index.mdx | 4 +- docs/content/docs/gateway/pricing-credits.mdx | 2 +- docs/content/docs/gateway/reliability.mdx | 10 +- 4 files changed, 69 insertions(+), 75 deletions(-) diff --git a/docs/content/docs/gateway/api/sanitize.mdx b/docs/content/docs/gateway/api/sanitize.mdx index f520c2a95..1edc716c3 100644 --- a/docs/content/docs/gateway/api/sanitize.mdx +++ b/docs/content/docs/gateway/api/sanitize.mdx @@ -1,78 +1,73 @@ --- title: Sanitize API -description: Repair invalid OpenUI Lang from any model without routing the request through Gateway. +description: Fix invalid OpenUI Lang from any model without routing the request through Gateway. --- -The Sanitize API corrects OpenUI Lang after a model has produced it. Send the raw model output, and Gateway validates it, repairs the errors it can, and returns a complete program that the renderer can use. +The Sanitize API fixes OpenUI Lang after a model has generated it. Send the raw generation and your component library, and Gateway validates the generation, fixes the errors it can, and returns valid OpenUI Lang that the renderer can use. Use it when your application calls a model directly and only needs the correction step. The request does not include a conversation or a model, and Gateway does not generate anything new. It applies the same correction that runs inside the [Chat Completions](/docs/gateway/api/chat-completions) and [Responses](/docs/gateway/api/responses) APIs, as a standalone call. **Endpoint:** POST [https://api.thesys.dev/v1/embed/sanitize](https://api.thesys.dev/v1/embed/sanitize) -## Repair a program +## Fix invalid generation -Send the output exactly as the model returned it. Fenced or bare OpenUI Lang both work, and text outside the fence is ignored. +Send the generation exactly as the model returned it, together with the library spec your application renders. Fenced or bare OpenUI Lang both work, and text outside the fence is ignored. -```ts title="server.ts" -const response = await fetch("https://api.thesys.dev/v1/embed/sanitize", { - method: "POST", - headers: { - Authorization: `Bearer ${process.env.THESYS_API_KEY}`, - "Content-Type": "application/json", - }, - body: JSON.stringify({ output: modelOutput }), -}); - -const result = await response.json(); - -if (result.status !== "repair_failed") { - render(result.program); +```ts title="lib/sanitize.ts" +import library from "./openui.spec.json"; + +export async function sanitize(generation: string) { + const response = await fetch("https://api.thesys.dev/v1/embed/sanitize", { + method: "POST", + headers: { + Authorization: `Bearer ${process.env.THESYS_API_KEY}`, + "Content-Type": "application/json", + }, + body: JSON.stringify({ generation, library }), + }); + + if (!response.ok) { + throw new Error(`Sanitize failed: ${response.status}`); + } + + return response.json(); } ``` -The response carries the whole program, not a patch. Replace the model output with `program` and render it. Server calls use the API key described in [Authentication](/docs/gateway/authentication). - -## Describe your components +```ts title="server.ts" +import { sanitize } from "./lib/sanitize"; -Gateway can only judge a program against the components your application renders. By default it uses the built-in OpenUI chat library. Add a `config` object when your application differs from that default. +const result = await sanitize(modelOutput); -```ts -body: JSON.stringify({ - output: modelOutput, - config: { - openUIlibraryVersion: "0.1.0", - customActions: { - book_table: { - description: "Reserve a table for the party size given.", - properties: { size: { type: "number" } }, - required: ["size"], - }, - }, - }, -}); +if (result.status === "repair_failed") { + renderFallback(modelOutput); +} else { + render(result.generation); +} ``` -| Field | Purpose | -| ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | -| `config.openUIlibraryVersion` | The version of the built-in OpenUI chat library your application renders, for example `"0.1.0"`. | -| `config.library` | A custom component library in the same JSON Schema shape that `library.toJSONSchema()` produces. It replaces the built-in library entirely. | -| `config.customActions` | The actions your application handles from buttons, as a map of action name to parameter schema. Gateway keeps them intact during repair. | +`openui.spec.json` is the library spec that `openui generate --spec` writes for your components. See [Generate OpenUI Lang](/docs/gateway/generate-openui-lang) for how it is created. Omit `library` to check the generation against the built-in OpenUI chat library. + +The response carries the complete generation, not a patch. Replace the model output with `generation` and render it. Server calls use the API key described in [Authentication](/docs/gateway/authentication). -`openUIlibraryVersion` and `library` are mutually exclusive. `customActions` can accompany either. +## Request -The keys match the config block that `generateSystemPrompt` writes for the generation APIs, so an application that already builds that block can pass the same values here. +| Field | Type | Required | Purpose | +| ------------ | ------ | -------- | -------------------------------------------------------------------------------------------------------------- | +| `generation` | string | Yes | The raw model output to fix. Up to 100,000 characters. | +| `library` | object | No | Your library spec, as written by `openui generate --spec`. Without it, Gateway uses the built-in chat library. | ## Read the result `status` tells you what happened. The other fields depend on it. -| `status` | `program` | Errors | Charged | -| --------------- | --------------------- | ---------------------------------------------------- | ------- | -| `already_valid` | The input, unchanged | `fixed-errors` is empty | No | -| `repaired` | The corrected program | `fixed-errors` lists what was wrong and is now fixed | Yes | -| `repair_failed` | `null` | `unfixed-errors` lists what is still wrong | Yes | +| `status` | `generation` | Errors | Charged | +| --------------- | ------------------------ | ---------------------------------------------------- | ------- | +| `already_valid` | The input, unchanged | `fixed-errors` is empty | No | +| `repaired` | The corrected generation | `fixed-errors` lists what was wrong and is now fixed | Yes | +| `repair_failed` | `null` | `unfixed-errors` lists what is still wrong | Yes | -A repaired program: +A fixed generation: ```json { @@ -80,7 +75,7 @@ A repaired program: "object": "openui.sanitize", "created": 1789019848, "status": "repaired", - "program": "root = Card([header])\nheader = Header(\"Q3 Results\")", + "generation": "root = Card([header])\nheader = Header(\"Q3 Results\")", "fixed-errors": [ { "code": "unresolved", @@ -92,7 +87,7 @@ A repaired program: } ``` -A failed repair: +A generation Gateway could not fix: ```json { @@ -100,7 +95,7 @@ A failed repair: "object": "openui.sanitize", "created": 1789026253, "status": "repair_failed", - "program": null, + "generation": null, "unfixed-errors": [ { "code": "null-required", @@ -114,7 +109,7 @@ A failed repair: } ``` -When the repair fails, fall back to what your application does for any unusable model output, such as showing the text or a generic error state. +When the fix fails, fall back to what your application does for any unusable model output, such as showing the text or a generic error state. ## Error codes @@ -128,36 +123,35 @@ Each entry in `fixed-errors` or `unfixed-errors` names one problem. `code` is al | `type-mismatch` | A property has the wrong type, or a value outside its allowed set. | | `excess-args` | A component received more arguments than its signature has. | | `inline-reserved` | `Query()` or `Mutation()` was used inside an expression instead of as a statement. | -| `incomplete` | The output stopped in the middle of a statement. | +| `incomplete` | The generation stopped in the middle of a statement. | | `unresolved` | A statement is referenced but never defined. | | `orphaned` | A statement is defined but not reachable from `root`. | -| `missing-root` | The output has no valid `root` statement. | +| `missing-root` | The generation has no valid `root` statement. | These are the same codes the OpenUI SDK reports in the browser, so an application can handle both with one path. See [Observability](/docs/observability) for how they appear in the Thesys Console. ## Limits -- `output` can be up to 100,000 characters. -- Gateway makes up to two repair attempts per request. -- Chat programs only. Artifacts such as slides and reports are not accepted. +- `generation` can be up to 100,000 characters. +- Gateway makes up to two attempts to fix the generation per request. ## Pricing -Each call that runs a repair costs a flat $0.02, deducted from your Gateway Credits. This applies whether the repair succeeds or fails, since the model ran either way. A program that is already valid uses no model and is free. +Each call that runs a fix is charged a flat price from your Gateway Credits. A generation that is already valid is free. See [Pricing](/docs/gateway/pricing-credits) for the current rate. -`usage` in the response reports the tokens the repair used, for your own tracking. The charge does not depend on it. See [Pricing](/docs/gateway/pricing-credits). +`usage` in the response reports the tokens the fix used, for your own tracking. The charge does not depend on it. ## Errors The endpoint returns the same error shape as the other Gateway APIs. -| Status | Type | When | -| ------ | ----------------------- | ---------------------------------------------------------- | -| `400` | `invalid_request_error` | `output` is empty or too long, or `config` is malformed. | -| `401` | `authentication_error` | The API key is missing or invalid. | -| `429` | `rate_limit_error` | The organization has no credits, or billing is suspended. | -| `500` | `internal_server_error` | The repair model could not be reached. Nothing is charged. | +| Status | Type | When | +| ------ | ----------------------- | ------------------------------------------------------------- | +| `400` | `invalid_request_error` | `generation` is empty or too long, or `library` is malformed. | +| `401` | `authentication_error` | The API key is missing or invalid. | +| `429` | `rate_limit_error` | The organization has no credits, or billing is suspended. | +| `500` | `internal_server_error` | The fixing model could not be reached. Nothing is charged. | ## Observability -Sanitize calls appear in the Thesys Console under the model name `openui/sanitize`. A successful repair counts as a sanitizer correction on the Reliability page, with the same error codes as corrections made during generation. +Sanitize calls appear in the Thesys Console under the model name `openui/sanitize`. A successful fix counts as a sanitizer correction on the Reliability page, with the same error codes as corrections made during generation. diff --git a/docs/content/docs/gateway/index.mdx b/docs/content/docs/gateway/index.mdx index 3f53de336..28c6aa26d 100644 --- a/docs/content/docs/gateway/index.mdx +++ b/docs/content/docs/gateway/index.mdx @@ -71,7 +71,7 @@ full: true Build stateful model interactions with persistent conversations and hosted tools. - Repair invalid OpenUI Lang from any model. Send the raw output and get back a valid program. + Fix invalid OpenUI Lang from any model. Send the raw generation and get back valid OpenUI Lang. @@ -81,6 +81,6 @@ full: true - **Validated generated UI.** Validates generated UI during the stream and fixes malformed syntax, invalid component usage, and schema violations before forwarding the response. - **Unified API.** Switch between providers and models with minimal code changes. - **High reliability.** Automatically retries requests with other providers if one fails. - - **Correction on its own.** Keep your model and backend, and send only the output that needs repair to the Sanitize API. + - **Correction on its own.** Keep your model and backend, and send only the generation that needs fixing to the Sanitize API. - **No markup on tokens.** Tokens cost the same as they would from the provider directly, with zero markup, including with Bring Your Own Key (BYOK). diff --git a/docs/content/docs/gateway/pricing-credits.mdx b/docs/content/docs/gateway/pricing-credits.mdx index 732ded046..a2fc58c70 100644 --- a/docs/content/docs/gateway/pricing-credits.mdx +++ b/docs/content/docs/gateway/pricing-credits.mdx @@ -40,7 +40,7 @@ Model usage is billed at the provider's rates without markup. The Gateway API an ### Sanitize API -A [Sanitize API](/docs/gateway/api/sanitize) call that runs a repair costs a flat $0.02, deducted from your Gateway Credits. It does not use a plan API call. Output that is already valid is free. +A [Sanitize API](/docs/gateway/api/sanitize) call that runs a fix costs a flat $0.02, deducted from your Gateway Credits. It does not use a plan API call. A generation that is already valid is free. ### Finding model pricing diff --git a/docs/content/docs/gateway/reliability.mdx b/docs/content/docs/gateway/reliability.mdx index 51246c7c5..43081a0f8 100644 --- a/docs/content/docs/gateway/reliability.mdx +++ b/docs/content/docs/gateway/reliability.mdx @@ -4,9 +4,9 @@ description: Keep model requests working when providers are unavailable or model --- - Not routing requests through Gateway? Send your model's OpenUI Lang output to the - [Sanitize API](/docs/gateway/api/sanitize) and get back a valid program, at a flat price per - repair. + Not routing requests through Gateway? Send your model's OpenUI Lang generation to the + [Sanitize API](/docs/gateway/api/sanitize) and get back valid OpenUI Lang, at a flat price per + fix. Applications that generate interfaces with AI face two common reliability problems. A model provider may be unavailable, or the model may return output that does not follow the OpenUI Lang instructions and component schemas. The first prevents a response; the second can produce an interface the application cannot render. @@ -18,7 +18,7 @@ Gateway handles each problem differently. It automatically retries the request w | Problem | What happens | How Gateway responds | | ------------------------ | ------------------------------------------------------------------------------------------------- | -------------------------------------------------------- | | **Provider unavailable** | An outage, capacity limit, or unavailable route prevents the selected provider from responding. | Gateway retries through a compatible fallback route. | -| **Invalid model output** | The model returns OpenUI Lang with invalid syntax, references, components, properties, or structure. | Gateway corrects eligible errors and continues the stream, or repairs the output on request through the Sanitize API. | +| **Invalid model output** | The model returns OpenUI Lang with invalid syntax, references, components, properties, or structure. | Gateway corrects eligible errors and continues the stream, or fixes the generation on request through the Sanitize API. | ## Recover from provider failures @@ -48,7 +48,7 @@ Correction applies only to generated OpenUI Lang. Plain text, arbitrary JSON, ap Gateway improves the reliability of model access and generated OpenUI Lang. Your application remains responsible for: -- Fallback behavior when a repair fails, whether during a stream or through the Sanitize API +- Fallback behavior when a fix fails, whether during a stream or through the Sanitize API - Component behavior and UI error boundaries - Authentication and permissions - Tool authorization and input validation From 7ef86ffbe9e783233cc00b4127670f8eddc7af9e Mon Sep 17 00:00:00 2001 From: Ankur Mittal Date: Thu, 10 Sep 2026 16:04:32 +0530 Subject: [PATCH 05/20] docs: sanitize statuses are fixed and fix_failed --- docs/content/docs/gateway/api/sanitize.mdx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/content/docs/gateway/api/sanitize.mdx b/docs/content/docs/gateway/api/sanitize.mdx index 1edc716c3..39e8d4d5b 100644 --- a/docs/content/docs/gateway/api/sanitize.mdx +++ b/docs/content/docs/gateway/api/sanitize.mdx @@ -39,7 +39,7 @@ import { sanitize } from "./lib/sanitize"; const result = await sanitize(modelOutput); -if (result.status === "repair_failed") { +if (result.status === "fix_failed") { renderFallback(modelOutput); } else { render(result.generation); @@ -64,8 +64,8 @@ The response carries the complete generation, not a patch. Replace the model out | `status` | `generation` | Errors | Charged | | --------------- | ------------------------ | ---------------------------------------------------- | ------- | | `already_valid` | The input, unchanged | `fixed-errors` is empty | No | -| `repaired` | The corrected generation | `fixed-errors` lists what was wrong and is now fixed | Yes | -| `repair_failed` | `null` | `unfixed-errors` lists what is still wrong | Yes | +| `fixed` | The corrected generation | `fixed-errors` lists what was wrong and is now fixed | Yes | +| `fix_failed` | `null` | `unfixed-errors` lists what is still wrong | Yes | A fixed generation: @@ -74,7 +74,7 @@ A fixed generation: "id": "san_P4TPtYimJFMpSgsViggie", "object": "openui.sanitize", "created": 1789019848, - "status": "repaired", + "status": "fixed", "generation": "root = Card([header])\nheader = Header(\"Q3 Results\")", "fixed-errors": [ { @@ -94,7 +94,7 @@ A generation Gateway could not fix: "id": "san_dRvfleg31F5g-Amn3v4-W", "object": "openui.sanitize", "created": 1789026253, - "status": "repair_failed", + "status": "fix_failed", "generation": null, "unfixed-errors": [ { From a674b50966737da76b9845a0e839df7352f274f7 Mon Sep 17 00:00:00 2001 From: Ankur Mittal Date: Thu, 10 Sep 2026 17:41:03 +0530 Subject: [PATCH 06/20] docs: rename the Sanitize API to the Auto-fix API --- .../api/{sanitize.mdx => auto-fix.mdx} | 28 +++++++++---------- docs/content/docs/gateway/index.mdx | 4 +-- docs/content/docs/gateway/meta.json | 2 +- docs/content/docs/gateway/pricing-credits.mdx | 4 +-- docs/content/docs/gateway/reliability.mdx | 8 +++--- 5 files changed, 23 insertions(+), 23 deletions(-) rename docs/content/docs/gateway/api/{sanitize.mdx => auto-fix.mdx} (91%) diff --git a/docs/content/docs/gateway/api/sanitize.mdx b/docs/content/docs/gateway/api/auto-fix.mdx similarity index 91% rename from docs/content/docs/gateway/api/sanitize.mdx rename to docs/content/docs/gateway/api/auto-fix.mdx index 39e8d4d5b..66aa9389d 100644 --- a/docs/content/docs/gateway/api/sanitize.mdx +++ b/docs/content/docs/gateway/api/auto-fix.mdx @@ -1,23 +1,23 @@ --- -title: Sanitize API +title: Auto-fix API description: Fix invalid OpenUI Lang from any model without routing the request through Gateway. --- -The Sanitize API fixes OpenUI Lang after a model has generated it. Send the raw generation and your component library, and Gateway validates the generation, fixes the errors it can, and returns valid OpenUI Lang that the renderer can use. +The Auto-fix API fixes OpenUI Lang after a model has generated it. Send the raw generation and your component library, and Gateway validates the generation, fixes the errors it can, and returns valid OpenUI Lang that the renderer can use. Use it when your application calls a model directly and only needs the correction step. The request does not include a conversation or a model, and Gateway does not generate anything new. It applies the same correction that runs inside the [Chat Completions](/docs/gateway/api/chat-completions) and [Responses](/docs/gateway/api/responses) APIs, as a standalone call. -**Endpoint:** POST [https://api.thesys.dev/v1/embed/sanitize](https://api.thesys.dev/v1/embed/sanitize) +**Endpoint:** POST [https://api.thesys.dev/v1/embed/auto-fix](https://api.thesys.dev/v1/embed/auto-fix) ## Fix invalid generation Send the generation exactly as the model returned it, together with the library spec your application renders. Fenced or bare OpenUI Lang both work, and text outside the fence is ignored. -```ts title="lib/sanitize.ts" +```ts title="lib/auto-fix.ts" import library from "./openui.spec.json"; -export async function sanitize(generation: string) { - const response = await fetch("https://api.thesys.dev/v1/embed/sanitize", { +export async function autoFix(generation: string) { + const response = await fetch("https://api.thesys.dev/v1/embed/auto-fix", { method: "POST", headers: { Authorization: `Bearer ${process.env.THESYS_API_KEY}`, @@ -27,7 +27,7 @@ export async function sanitize(generation: string) { }); if (!response.ok) { - throw new Error(`Sanitize failed: ${response.status}`); + throw new Error(`Auto-fix failed: ${response.status}`); } return response.json(); @@ -35,9 +35,9 @@ export async function sanitize(generation: string) { ``` ```ts title="server.ts" -import { sanitize } from "./lib/sanitize"; +import { autoFix } from "./lib/auto-fix"; -const result = await sanitize(modelOutput); +const result = await autoFix(modelOutput); if (result.status === "fix_failed") { renderFallback(modelOutput); @@ -71,8 +71,8 @@ A fixed generation: ```json { - "id": "san_P4TPtYimJFMpSgsViggie", - "object": "openui.sanitize", + "id": "fix_P4TPtYimJFMpSgsViggie", + "object": "openui.auto_fix", "created": 1789019848, "status": "fixed", "generation": "root = Card([header])\nheader = Header(\"Q3 Results\")", @@ -91,8 +91,8 @@ A generation Gateway could not fix: ```json { - "id": "san_dRvfleg31F5g-Amn3v4-W", - "object": "openui.sanitize", + "id": "fix_dRvfleg31F5g-Amn3v4-W", + "object": "openui.auto_fix", "created": 1789026253, "status": "fix_failed", "generation": null, @@ -154,4 +154,4 @@ The endpoint returns the same error shape as the other Gateway APIs. ## Observability -Sanitize calls appear in the Thesys Console under the model name `openui/sanitize`. A successful fix counts as a sanitizer correction on the Reliability page, with the same error codes as corrections made during generation. +Auto-fix calls appear in the Thesys Console under the model name `openui/auto-fix`. A successful fix counts as a sanitizer correction on the Reliability page, with the same error codes as corrections made during generation. diff --git a/docs/content/docs/gateway/index.mdx b/docs/content/docs/gateway/index.mdx index 28c6aa26d..77810e7af 100644 --- a/docs/content/docs/gateway/index.mdx +++ b/docs/content/docs/gateway/index.mdx @@ -70,7 +70,7 @@ full: true Build stateful model interactions with persistent conversations and hosted tools. - + Fix invalid OpenUI Lang from any model. Send the raw generation and get back valid OpenUI Lang. @@ -81,6 +81,6 @@ full: true - **Validated generated UI.** Validates generated UI during the stream and fixes malformed syntax, invalid component usage, and schema violations before forwarding the response. - **Unified API.** Switch between providers and models with minimal code changes. - **High reliability.** Automatically retries requests with other providers if one fails. - - **Correction on its own.** Keep your model and backend, and send only the generation that needs fixing to the Sanitize API. + - **Correction on its own.** Keep your model and backend, and send only the generation that needs fixing to the Auto-fix API. - **No markup on tokens.** Tokens cost the same as they would from the provider directly, with zero markup, including with Bring Your Own Key (BYOK). diff --git a/docs/content/docs/gateway/meta.json b/docs/content/docs/gateway/meta.json index e5a82266c..b0cd756d8 100644 --- a/docs/content/docs/gateway/meta.json +++ b/docs/content/docs/gateway/meta.json @@ -15,6 +15,6 @@ "api/chat-completions", "api/responses", "api/conversations", - "api/sanitize" + "api/auto-fix" ] } diff --git a/docs/content/docs/gateway/pricing-credits.mdx b/docs/content/docs/gateway/pricing-credits.mdx index a2fc58c70..fb122bbc8 100644 --- a/docs/content/docs/gateway/pricing-credits.mdx +++ b/docs/content/docs/gateway/pricing-credits.mdx @@ -38,9 +38,9 @@ The cost of a Gateway request has two parts: Model usage is billed at the provider's rates without markup. The Gateway API and OpenUI Lang correction behavior remain the same whether you use managed inference or your own provider key. -### Sanitize API +### Auto-fix API -A [Sanitize API](/docs/gateway/api/sanitize) call that runs a fix costs a flat $0.02, deducted from your Gateway Credits. It does not use a plan API call. A generation that is already valid is free. +A [Auto-fix API](/docs/gateway/api/auto-fix) call that runs a fix costs a flat $0.02, deducted from your Gateway Credits. It does not use a plan API call. A generation that is already valid is free. ### Finding model pricing diff --git a/docs/content/docs/gateway/reliability.mdx b/docs/content/docs/gateway/reliability.mdx index 43081a0f8..9db80c25a 100644 --- a/docs/content/docs/gateway/reliability.mdx +++ b/docs/content/docs/gateway/reliability.mdx @@ -3,9 +3,9 @@ title: Reliability description: Keep model requests working when providers are unavailable or models return invalid OpenUI Lang. --- - + Not routing requests through Gateway? Send your model's OpenUI Lang generation to the - [Sanitize API](/docs/gateway/api/sanitize) and get back valid OpenUI Lang, at a flat price per + [Auto-fix API](/docs/gateway/api/auto-fix) and get back valid OpenUI Lang, at a flat price per fix. @@ -18,7 +18,7 @@ Gateway handles each problem differently. It automatically retries the request w | Problem | What happens | How Gateway responds | | ------------------------ | ------------------------------------------------------------------------------------------------- | -------------------------------------------------------- | | **Provider unavailable** | An outage, capacity limit, or unavailable route prevents the selected provider from responding. | Gateway retries through a compatible fallback route. | -| **Invalid model output** | The model returns OpenUI Lang with invalid syntax, references, components, properties, or structure. | Gateway corrects eligible errors and continues the stream, or fixes the generation on request through the Sanitize API. | +| **Invalid model output** | The model returns OpenUI Lang with invalid syntax, references, components, properties, or structure. | Gateway corrects eligible errors and continues the stream, or fixes the generation on request through the Auto-fix API. | ## Recover from provider failures @@ -48,7 +48,7 @@ Correction applies only to generated OpenUI Lang. Plain text, arbitrary JSON, ap Gateway improves the reliability of model access and generated OpenUI Lang. Your application remains responsible for: -- Fallback behavior when a fix fails, whether during a stream or through the Sanitize API +- Fallback behavior when a fix fails, whether during a stream or through the Auto-fix API - Component behavior and UI error boundaries - Authentication and permissions - Tool authorization and input validation From cf63bd84fdcbe90fb3a8664eb8bdad1aa3a09496 Mon Sep 17 00:00:00 2001 From: Ankur Mittal Date: Fri, 11 Sep 2026 12:42:26 +0530 Subject: [PATCH 07/20] docs: add the Auto-fix API to the OpenUI Lang reliability page The production section now has two subsections: the Auto-fix API for applications that call the model themselves, and OpenUI Gateway. Co-Authored-By: Claude Fable 5.1 --- docs/content/docs/openui-lang/reliability.mdx | 31 +++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/docs/content/docs/openui-lang/reliability.mdx b/docs/content/docs/openui-lang/reliability.mdx index 7a265ea22..27a8f597c 100644 --- a/docs/content/docs/openui-lang/reliability.mdx +++ b/docs/content/docs/openui-lang/reliability.mdx @@ -99,7 +99,34 @@ After deploying, open the [Reliability dashboard](https://console.thesys.dev/rel skill](/docs/mcp#install-via-the-skills-cli-recommended). -## Production reliability with OpenUI Gateway +## Production reliability + +Validation tells you that a generation is broken. Two hosted services fix it for you. Pick the one that matches how your application calls the model. + +- **[Auto-fix API](#auto-fix-api):** you call the model yourself and send the generation to Thesys for repair. +- **[OpenUI Gateway](#openui-gateway):** Thesys calls the model for you and repairs the generation while it streams. + +### Auto-fix API + +The [Auto-fix API](/docs/gateway/api/auto-fix) repairs OpenUI Lang after your model has generated it. Your application keeps its own model calls, keys, and prompts. Send the raw generation and your library spec, and the API returns valid OpenUI Lang that the renderer can use. + +```ts +const response = await fetch("https://api.thesys.dev/v1/embed/auto-fix", { + method: "POST", + headers: { + Authorization: `Bearer ${process.env.THESYS_API_KEY}`, + "Content-Type": "application/json", + }, + body: JSON.stringify({ generation, library }), +}); + +const result = await response.json(); +// result.status is "already_valid", "fixed", or "fix_failed" +``` + +A generation that is already valid is free. Each fix is charged a flat price. See the [Auto-fix API reference](/docs/gateway/api/auto-fix) for the request, the response, and the error codes. + +### OpenUI Gateway OpenUI Gateway sits between your application and the LLM. It validates generated UI and fixes errors as it streams to your application. @@ -197,7 +224,7 @@ In production data from our [Reliability benchmark](/blog/generative-ui-benchmar application. [Install the OpenUI skill](/docs/mcp#install-via-the-skills-cli-recommended). -### Integrations options +#### Integrations options OpenUI Gateway provides two OpenAI-compatible APIs for this generation flow: From d89917e1e8fe11346d09991a88b63fd6f7c77aa9 Mon Sep 17 00:00:00 2001 From: Ankur Mittal Date: Fri, 11 Sep 2026 12:52:35 +0530 Subject: [PATCH 08/20] docs: match the page voice in the Auto-fix section Co-Authored-By: Claude Fable 5.1 --- docs/content/docs/openui-lang/reliability.mdx | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/docs/content/docs/openui-lang/reliability.mdx b/docs/content/docs/openui-lang/reliability.mdx index 27a8f597c..53a61c25d 100644 --- a/docs/content/docs/openui-lang/reliability.mdx +++ b/docs/content/docs/openui-lang/reliability.mdx @@ -101,14 +101,20 @@ After deploying, open the [Reliability dashboard](https://console.thesys.dev/rel ## Production reliability -Validation tells you that a generation is broken. Two hosted services fix it for you. Pick the one that matches how your application calls the model. +Validation shows that a generation is broken. Two services fix it. Choose the one that matches how your application calls the model. -- **[Auto-fix API](#auto-fix-api):** you call the model yourself and send the generation to Thesys for repair. -- **[OpenUI Gateway](#openui-gateway):** Thesys calls the model for you and repairs the generation while it streams. +- **[Auto-fix API](#auto-fix-api):** your application calls the model and sends the generation for repair. +- **[OpenUI Gateway](#openui-gateway):** OpenUI Gateway calls the model and repairs the generation as it streams. ### Auto-fix API -The [Auto-fix API](/docs/gateway/api/auto-fix) repairs OpenUI Lang after your model has generated it. Your application keeps its own model calls, keys, and prompts. Send the raw generation and your library spec, and the API returns valid OpenUI Lang that the renderer can use. +The [Auto-fix API](/docs/gateway/api/auto-fix) repairs OpenUI Lang after your model has generated it. Your application keeps its own model calls, keys, and prompts. + +For every generation, the Auto-fix API: + +- **Validates** the generation against your component library. +- **Fixes** unknown components, missing references, and broken structure. +- **Returns** the complete fixed generation, ready to render. ```ts const response = await fetch("https://api.thesys.dev/v1/embed/auto-fix", { From 39611af86025a7fa259439547fd0167f21dcbf06 Mon Sep 17 00:00:00 2001 From: Ankur Mittal Date: Fri, 11 Sep 2026 12:57:24 +0530 Subject: [PATCH 09/20] docs: smoother prose in the production reliability intro Co-Authored-By: Claude Fable 5.1 --- docs/content/docs/openui-lang/reliability.mdx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/content/docs/openui-lang/reliability.mdx b/docs/content/docs/openui-lang/reliability.mdx index 53a61c25d..69a9a8e97 100644 --- a/docs/content/docs/openui-lang/reliability.mdx +++ b/docs/content/docs/openui-lang/reliability.mdx @@ -101,14 +101,14 @@ After deploying, open the [Reliability dashboard](https://console.thesys.dev/rel ## Production reliability -Validation shows that a generation is broken. Two services fix it. Choose the one that matches how your application calls the model. +Validation catches broken generations, but it cannot repair them. OpenUI offers two ways to fix generations in production, depending on how your application calls the model. -- **[Auto-fix API](#auto-fix-api):** your application calls the model and sends the generation for repair. -- **[OpenUI Gateway](#openui-gateway):** OpenUI Gateway calls the model and repairs the generation as it streams. +- **[Auto-fix API](#auto-fix-api):** your application calls the model itself and sends the generation to the Auto-fix API for repair. +- **[OpenUI Gateway](#openui-gateway):** OpenUI Gateway calls the model on your behalf and repairs the generation while it streams. ### Auto-fix API -The [Auto-fix API](/docs/gateway/api/auto-fix) repairs OpenUI Lang after your model has generated it. Your application keeps its own model calls, keys, and prompts. +The [Auto-fix API](/docs/gateway/api/auto-fix) repairs OpenUI Lang after your model has generated it, so your application keeps its own model calls, keys, and prompts. For every generation, the Auto-fix API: @@ -130,7 +130,7 @@ const result = await response.json(); // result.status is "already_valid", "fixed", or "fix_failed" ``` -A generation that is already valid is free. Each fix is charged a flat price. See the [Auto-fix API reference](/docs/gateway/api/auto-fix) for the request, the response, and the error codes. +A generation that is already valid is free, and each fix is charged at a flat price. See the [Auto-fix API reference](/docs/gateway/api/auto-fix) for the full request and response format and the error codes. ### OpenUI Gateway From affa01e20bc26280a6643fc342121a89e5b7ab2e Mon Sep 17 00:00:00 2001 From: Ankur Mittal Date: Fri, 11 Sep 2026 13:03:09 +0530 Subject: [PATCH 10/20] docs: open the production reliability section in context Co-Authored-By: Claude Fable 5.1 --- docs/content/docs/openui-lang/reliability.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/content/docs/openui-lang/reliability.mdx b/docs/content/docs/openui-lang/reliability.mdx index 69a9a8e97..80ce0216f 100644 --- a/docs/content/docs/openui-lang/reliability.mdx +++ b/docs/content/docs/openui-lang/reliability.mdx @@ -101,7 +101,7 @@ After deploying, open the [Reliability dashboard](https://console.thesys.dev/rel ## Production reliability -Validation catches broken generations, but it cannot repair them. OpenUI offers two ways to fix generations in production, depending on how your application calls the model. +Even with a well-tuned schema, prompt, and model, some generations in production will still fail validation. OpenUI offers two ways to repair them automatically, depending on how your application calls the model. - **[Auto-fix API](#auto-fix-api):** your application calls the model itself and sends the generation to the Auto-fix API for repair. - **[OpenUI Gateway](#openui-gateway):** OpenUI Gateway calls the model on your behalf and repairs the generation while it streams. From 328cfb9f1317aa770fe2730a83bf2388fb525021 Mon Sep 17 00:00:00 2001 From: Ankur Mittal Date: Fri, 11 Sep 2026 13:20:40 +0530 Subject: [PATCH 11/20] docs: do not name Gateway on the Auto-fix API page Review feedback: the page describes a standalone API. Co-Authored-By: Claude Fable 5.1 --- docs/content/docs/gateway/api/auto-fix.mdx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/content/docs/gateway/api/auto-fix.mdx b/docs/content/docs/gateway/api/auto-fix.mdx index 66aa9389d..26d4a0639 100644 --- a/docs/content/docs/gateway/api/auto-fix.mdx +++ b/docs/content/docs/gateway/api/auto-fix.mdx @@ -1,11 +1,11 @@ --- title: Auto-fix API -description: Fix invalid OpenUI Lang from any model without routing the request through Gateway. +description: Fix invalid OpenUI Lang from any model with one API call. --- -The Auto-fix API fixes OpenUI Lang after a model has generated it. Send the raw generation and your component library, and Gateway validates the generation, fixes the errors it can, and returns valid OpenUI Lang that the renderer can use. +The Auto-fix API fixes OpenUI Lang after a model has generated it. Send the raw generation and your component library. The API validates the generation, fixes the errors it can, and returns valid OpenUI Lang that the renderer can use. -Use it when your application calls a model directly and only needs the correction step. The request does not include a conversation or a model, and Gateway does not generate anything new. It applies the same correction that runs inside the [Chat Completions](/docs/gateway/api/chat-completions) and [Responses](/docs/gateway/api/responses) APIs, as a standalone call. +Use it when your application calls a model directly and only needs the correction step. The request does not name a model, and nothing new is generated. The API applies the same correction that runs inside the [Chat Completions](/docs/gateway/api/chat-completions) and [Responses](/docs/gateway/api/responses) APIs, as a standalone call. **Endpoint:** POST [https://api.thesys.dev/v1/embed/auto-fix](https://api.thesys.dev/v1/embed/auto-fix) @@ -55,7 +55,7 @@ The response carries the complete generation, not a patch. Replace the model out | Field | Type | Required | Purpose | | ------------ | ------ | -------- | -------------------------------------------------------------------------------------------------------------- | | `generation` | string | Yes | The raw model output to fix. Up to 100,000 characters. | -| `library` | object | No | Your library spec, as written by `openui generate --spec`. Without it, Gateway uses the built-in chat library. | +| `library` | object | No | Your library spec, as written by `openui generate --spec`. Without it, the built-in chat library is used. | ## Read the result @@ -87,7 +87,7 @@ A fixed generation: } ``` -A generation Gateway could not fix: +A generation the API could not fix: ```json { @@ -133,17 +133,17 @@ These are the same codes the OpenUI SDK reports in the browser, so an applicatio ## Limits - `generation` can be up to 100,000 characters. -- Gateway makes up to two attempts to fix the generation per request. +- The API makes up to two attempts to fix the generation per request. ## Pricing -Each call that runs a fix is charged a flat price from your Gateway Credits. A generation that is already valid is free. See [Pricing](/docs/gateway/pricing-credits) for the current rate. +Each call that runs a fix is charged a flat price from your credits. A generation that is already valid is free. See [Pricing](/docs/gateway/pricing-credits) for the current rate. `usage` in the response reports the tokens the fix used, for your own tracking. The charge does not depend on it. ## Errors -The endpoint returns the same error shape as the other Gateway APIs. +The endpoint returns the same error shape as the Chat Completions and Responses APIs. | Status | Type | When | | ------ | ----------------------- | ------------------------------------------------------------- | From 4bcf17cb781cdeb04794ef5e11ae8ac388a1d1b9 Mon Sep 17 00:00:00 2001 From: Ankur Mittal Date: Fri, 11 Sep 2026 12:14:55 +0530 Subject: [PATCH 12/20] docs: the Auto-fix API takes the conversation The repair reads the conversation to keep what the user asked for, so the page has to say the field exists, what the limits are, and where the text goes. Co-Authored-By: Claude Fable 5.1 --- docs/content/docs/gateway/api/auto-fix.mdx | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/docs/content/docs/gateway/api/auto-fix.mdx b/docs/content/docs/gateway/api/auto-fix.mdx index 26d4a0639..2d7644588 100644 --- a/docs/content/docs/gateway/api/auto-fix.mdx +++ b/docs/content/docs/gateway/api/auto-fix.mdx @@ -5,7 +5,7 @@ description: Fix invalid OpenUI Lang from any model with one API call. The Auto-fix API fixes OpenUI Lang after a model has generated it. Send the raw generation and your component library. The API validates the generation, fixes the errors it can, and returns valid OpenUI Lang that the renderer can use. -Use it when your application calls a model directly and only needs the correction step. The request does not name a model, and nothing new is generated. The API applies the same correction that runs inside the [Chat Completions](/docs/gateway/api/chat-completions) and [Responses](/docs/gateway/api/responses) APIs, as a standalone call. +Use it when your application calls a model directly and only needs the correction step. The request does not name a model, and nothing new is generated. The API applies the same correction that runs inside the [Chat Completions](/docs/gateway/api/chat-completions) and [Responses](/docs/gateway/api/responses) APIs, as a standalone call. You can also send the conversation that led to the generation, and Gateway reads it only to understand what the user asked for. **Endpoint:** POST [https://api.thesys.dev/v1/embed/auto-fix](https://api.thesys.dev/v1/embed/auto-fix) @@ -16,14 +16,16 @@ Send the generation exactly as the model returned it, together with the library ```ts title="lib/auto-fix.ts" import library from "./openui.spec.json"; -export async function autoFix(generation: string) { +type Message = { role: "user" | "assistant" | "system"; content: string }; + +export async function autoFix(generation: string, messages?: Message[]) { const response = await fetch("https://api.thesys.dev/v1/embed/auto-fix", { method: "POST", headers: { Authorization: `Bearer ${process.env.THESYS_API_KEY}`, "Content-Type": "application/json", }, - body: JSON.stringify({ generation, library }), + body: JSON.stringify({ generation, library, messages }), }); if (!response.ok) { @@ -37,7 +39,8 @@ export async function autoFix(generation: string) { ```ts title="server.ts" import { autoFix } from "./lib/auto-fix"; -const result = await autoFix(modelOutput); +// Pass the same messages you sent to your model. +const result = await autoFix(modelOutput, messages); if (result.status === "fix_failed") { renderFallback(modelOutput); @@ -56,6 +59,7 @@ The response carries the complete generation, not a patch. Replace the model out | ------------ | ------ | -------- | -------------------------------------------------------------------------------------------------------------- | | `generation` | string | Yes | The raw model output to fix. Up to 100,000 characters. | | `library` | object | No | Your library spec, as written by `openui generate --spec`. Without it, the built-in chat library is used. | +| `messages` | array | No | The conversation that produced the generation, as `{ role, content }` turns. Used only to understand intent. | ## Read the result @@ -133,8 +137,14 @@ These are the same codes the OpenUI SDK reports in the browser, so an applicatio ## Limits - `generation` can be up to 100,000 characters. +- `messages` can hold up to 20 turns and 8,000 characters in total. `role` is `user`, `assistant`, or `system`, and `content` is text. +- Gateway reads the most recent turns. Older turns are dropped first. - The API makes up to two attempts to fix the generation per request. +## Data + +The conversation you send is passed to the model that fixes the generation, and is not stored beyond the request logs. + ## Pricing Each call that runs a fix is charged a flat price from your credits. A generation that is already valid is free. See [Pricing](/docs/gateway/pricing-credits) for the current rate. @@ -147,7 +157,7 @@ The endpoint returns the same error shape as the Chat Completions and Responses | Status | Type | When | | ------ | ----------------------- | ------------------------------------------------------------- | -| `400` | `invalid_request_error` | `generation` is empty or too long, or `library` is malformed. | +| `400` | `invalid_request_error` | `generation` is empty or too long, `messages` is over a limit, or `library` is malformed. | | `401` | `authentication_error` | The API key is missing or invalid. | | `429` | `rate_limit_error` | The organization has no credits, or billing is suspended. | | `500` | `internal_server_error` | The fixing model could not be reached. Nothing is charged. | From 542a97b901cf7e65878a257ba94d83895dd18742 Mon Sep 17 00:00:00 2001 From: Ankur Mittal Date: Fri, 11 Sep 2026 12:28:13 +0530 Subject: [PATCH 13/20] Do not say Gateway reads the conversation Review feedback on the conversation-context lines. Co-Authored-By: Claude Fable 5.1 --- docs/content/docs/gateway/api/auto-fix.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/content/docs/gateway/api/auto-fix.mdx b/docs/content/docs/gateway/api/auto-fix.mdx index 2d7644588..16412545f 100644 --- a/docs/content/docs/gateway/api/auto-fix.mdx +++ b/docs/content/docs/gateway/api/auto-fix.mdx @@ -5,7 +5,7 @@ description: Fix invalid OpenUI Lang from any model with one API call. The Auto-fix API fixes OpenUI Lang after a model has generated it. Send the raw generation and your component library. The API validates the generation, fixes the errors it can, and returns valid OpenUI Lang that the renderer can use. -Use it when your application calls a model directly and only needs the correction step. The request does not name a model, and nothing new is generated. The API applies the same correction that runs inside the [Chat Completions](/docs/gateway/api/chat-completions) and [Responses](/docs/gateway/api/responses) APIs, as a standalone call. You can also send the conversation that led to the generation, and Gateway reads it only to understand what the user asked for. +Use it when your application calls a model directly and only needs the correction step. The request does not name a model, and nothing new is generated. The API applies the same correction that runs inside the [Chat Completions](/docs/gateway/api/chat-completions) and [Responses](/docs/gateway/api/responses) APIs, as a standalone call. You can also send the conversation that led to the generation. It is used only to understand what the user asked for. **Endpoint:** POST [https://api.thesys.dev/v1/embed/auto-fix](https://api.thesys.dev/v1/embed/auto-fix) @@ -138,7 +138,7 @@ These are the same codes the OpenUI SDK reports in the browser, so an applicatio - `generation` can be up to 100,000 characters. - `messages` can hold up to 20 turns and 8,000 characters in total. `role` is `user`, `assistant`, or `system`, and `content` is text. -- Gateway reads the most recent turns. Older turns are dropped first. +- Only the most recent turns are used. Older turns are dropped first. - The API makes up to two attempts to fix the generation per request. ## Data From 73488f44028c6111920609812b5b0e374b36e965 Mon Sep 17 00:00:00 2001 From: Ankur Mittal Date: Fri, 11 Sep 2026 14:50:38 +0530 Subject: [PATCH 14/20] docs: the conversation takes the OpenAI chat message shape Co-Authored-By: Claude Fable 5.1 --- docs/content/docs/gateway/api/auto-fix.mdx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/content/docs/gateway/api/auto-fix.mdx b/docs/content/docs/gateway/api/auto-fix.mdx index 16412545f..a5eab8092 100644 --- a/docs/content/docs/gateway/api/auto-fix.mdx +++ b/docs/content/docs/gateway/api/auto-fix.mdx @@ -16,7 +16,7 @@ Send the generation exactly as the model returned it, together with the library ```ts title="lib/auto-fix.ts" import library from "./openui.spec.json"; -type Message = { role: "user" | "assistant" | "system"; content: string }; +type Message = { role: string; content: string | unknown[] }; export async function autoFix(generation: string, messages?: Message[]) { const response = await fetch("https://api.thesys.dev/v1/embed/auto-fix", { @@ -59,7 +59,7 @@ The response carries the complete generation, not a patch. Replace the model out | ------------ | ------ | -------- | -------------------------------------------------------------------------------------------------------------- | | `generation` | string | Yes | The raw model output to fix. Up to 100,000 characters. | | `library` | object | No | Your library spec, as written by `openui generate --spec`. Without it, the built-in chat library is used. | -| `messages` | array | No | The conversation that produced the generation, as `{ role, content }` turns. Used only to understand intent. | +| `messages` | array | No | The conversation that produced the generation, in the OpenAI chat message shape. Only the text of `user`, `assistant`, `system`, and `developer` turns is used; tool turns and non-text parts are ignored. | ## Read the result @@ -137,7 +137,7 @@ These are the same codes the OpenUI SDK reports in the browser, so an applicatio ## Limits - `generation` can be up to 100,000 characters. -- `messages` can hold up to 20 turns and 8,000 characters in total. `role` is `user`, `assistant`, or `system`, and `content` is text. +- `messages` can hold up to 20 usable turns and 8,000 characters of text in total, counted after tool turns and non-text parts are dropped. - Only the most recent turns are used. Older turns are dropped first. - The API makes up to two attempts to fix the generation per request. From 01013f772829d09b028d91f6c3eac98d5894d360 Mon Sep 17 00:00:00 2001 From: Ankur Mittal Date: Fri, 11 Sep 2026 16:50:33 +0530 Subject: [PATCH 15/20] docs: the Autofix API takes the OpenAI chat shape The page described a body of its own and the old `/v1/embed/auto-fix` path, which no longer exists. The name loses its dash too. The request is a chat completion whose last assistant turn carries the generation to fix, so the first example is the OpenAI SDK with a base URL of `/v1/autofix`. A plain fetch and a Python call follow. Streaming is listed as not supported. Co-Authored-By: Claude Fable 5.1 --- docs/content/docs/gateway/api/auto-fix.mdx | 167 ----------- docs/content/docs/gateway/api/autofix.mdx | 263 ++++++++++++++++++ docs/content/docs/gateway/index.mdx | 4 +- docs/content/docs/gateway/meta.json | 2 +- docs/content/docs/gateway/pricing-credits.mdx | 4 +- docs/content/docs/gateway/reliability.mdx | 8 +- docs/content/docs/openui-lang/reliability.mdx | 33 ++- 7 files changed, 290 insertions(+), 191 deletions(-) delete mode 100644 docs/content/docs/gateway/api/auto-fix.mdx create mode 100644 docs/content/docs/gateway/api/autofix.mdx diff --git a/docs/content/docs/gateway/api/auto-fix.mdx b/docs/content/docs/gateway/api/auto-fix.mdx deleted file mode 100644 index a5eab8092..000000000 --- a/docs/content/docs/gateway/api/auto-fix.mdx +++ /dev/null @@ -1,167 +0,0 @@ ---- -title: Auto-fix API -description: Fix invalid OpenUI Lang from any model with one API call. ---- - -The Auto-fix API fixes OpenUI Lang after a model has generated it. Send the raw generation and your component library. The API validates the generation, fixes the errors it can, and returns valid OpenUI Lang that the renderer can use. - -Use it when your application calls a model directly and only needs the correction step. The request does not name a model, and nothing new is generated. The API applies the same correction that runs inside the [Chat Completions](/docs/gateway/api/chat-completions) and [Responses](/docs/gateway/api/responses) APIs, as a standalone call. You can also send the conversation that led to the generation. It is used only to understand what the user asked for. - -**Endpoint:** POST [https://api.thesys.dev/v1/embed/auto-fix](https://api.thesys.dev/v1/embed/auto-fix) - -## Fix invalid generation - -Send the generation exactly as the model returned it, together with the library spec your application renders. Fenced or bare OpenUI Lang both work, and text outside the fence is ignored. - -```ts title="lib/auto-fix.ts" -import library from "./openui.spec.json"; - -type Message = { role: string; content: string | unknown[] }; - -export async function autoFix(generation: string, messages?: Message[]) { - const response = await fetch("https://api.thesys.dev/v1/embed/auto-fix", { - method: "POST", - headers: { - Authorization: `Bearer ${process.env.THESYS_API_KEY}`, - "Content-Type": "application/json", - }, - body: JSON.stringify({ generation, library, messages }), - }); - - if (!response.ok) { - throw new Error(`Auto-fix failed: ${response.status}`); - } - - return response.json(); -} -``` - -```ts title="server.ts" -import { autoFix } from "./lib/auto-fix"; - -// Pass the same messages you sent to your model. -const result = await autoFix(modelOutput, messages); - -if (result.status === "fix_failed") { - renderFallback(modelOutput); -} else { - render(result.generation); -} -``` - -`openui.spec.json` is the library spec that `openui generate --spec` writes for your components. See [Generate OpenUI Lang](/docs/gateway/generate-openui-lang) for how it is created. Omit `library` to check the generation against the built-in OpenUI chat library. - -The response carries the complete generation, not a patch. Replace the model output with `generation` and render it. Server calls use the API key described in [Authentication](/docs/gateway/authentication). - -## Request - -| Field | Type | Required | Purpose | -| ------------ | ------ | -------- | -------------------------------------------------------------------------------------------------------------- | -| `generation` | string | Yes | The raw model output to fix. Up to 100,000 characters. | -| `library` | object | No | Your library spec, as written by `openui generate --spec`. Without it, the built-in chat library is used. | -| `messages` | array | No | The conversation that produced the generation, in the OpenAI chat message shape. Only the text of `user`, `assistant`, `system`, and `developer` turns is used; tool turns and non-text parts are ignored. | - -## Read the result - -`status` tells you what happened. The other fields depend on it. - -| `status` | `generation` | Errors | Charged | -| --------------- | ------------------------ | ---------------------------------------------------- | ------- | -| `already_valid` | The input, unchanged | `fixed-errors` is empty | No | -| `fixed` | The corrected generation | `fixed-errors` lists what was wrong and is now fixed | Yes | -| `fix_failed` | `null` | `unfixed-errors` lists what is still wrong | Yes | - -A fixed generation: - -```json -{ - "id": "fix_P4TPtYimJFMpSgsViggie", - "object": "openui.auto_fix", - "created": 1789019848, - "status": "fixed", - "generation": "root = Card([header])\nheader = Header(\"Q3 Results\")", - "fixed-errors": [ - { - "code": "unresolved", - "statementId": "followUp", - "message": "reference \"followUp\" is never defined" - } - ], - "usage": { "prompt_tokens": 8014, "completion_tokens": 17, "total_tokens": 8031 } -} -``` - -A generation the API could not fix: - -```json -{ - "id": "fix_dRvfleg31F5g-Amn3v4-W", - "object": "openui.auto_fix", - "created": 1789026253, - "status": "fix_failed", - "generation": null, - "unfixed-errors": [ - { - "code": "null-required", - "component": "B", - "path": "/child", - "statementId": "z", - "message": "required field \"/child\" cannot be null" - } - ], - "usage": { "prompt_tokens": 360, "completion_tokens": 146, "total_tokens": 506 } -} -``` - -When the fix fails, fall back to what your application does for any unusable model output, such as showing the text or a generic error state. - -## Error codes - -Each entry in `fixed-errors` or `unfixed-errors` names one problem. `code` is always present. `component`, `path`, and `statementId` are present when the validator can name the component type, the property, and the statement that carried the problem. - -| Code | Meaning | -| ------------------- | ---------------------------------------------------------------------------------- | -| `unknown-component` | A component name that is not in the library. | -| `missing-required` | A required property was left out. | -| `null-required` | A required property was set to `null`. | -| `type-mismatch` | A property has the wrong type, or a value outside its allowed set. | -| `excess-args` | A component received more arguments than its signature has. | -| `inline-reserved` | `Query()` or `Mutation()` was used inside an expression instead of as a statement. | -| `incomplete` | The generation stopped in the middle of a statement. | -| `unresolved` | A statement is referenced but never defined. | -| `orphaned` | A statement is defined but not reachable from `root`. | -| `missing-root` | The generation has no valid `root` statement. | - -These are the same codes the OpenUI SDK reports in the browser, so an application can handle both with one path. See [Observability](/docs/observability) for how they appear in the Thesys Console. - -## Limits - -- `generation` can be up to 100,000 characters. -- `messages` can hold up to 20 usable turns and 8,000 characters of text in total, counted after tool turns and non-text parts are dropped. -- Only the most recent turns are used. Older turns are dropped first. -- The API makes up to two attempts to fix the generation per request. - -## Data - -The conversation you send is passed to the model that fixes the generation, and is not stored beyond the request logs. - -## Pricing - -Each call that runs a fix is charged a flat price from your credits. A generation that is already valid is free. See [Pricing](/docs/gateway/pricing-credits) for the current rate. - -`usage` in the response reports the tokens the fix used, for your own tracking. The charge does not depend on it. - -## Errors - -The endpoint returns the same error shape as the Chat Completions and Responses APIs. - -| Status | Type | When | -| ------ | ----------------------- | ------------------------------------------------------------- | -| `400` | `invalid_request_error` | `generation` is empty or too long, `messages` is over a limit, or `library` is malformed. | -| `401` | `authentication_error` | The API key is missing or invalid. | -| `429` | `rate_limit_error` | The organization has no credits, or billing is suspended. | -| `500` | `internal_server_error` | The fixing model could not be reached. Nothing is charged. | - -## Observability - -Auto-fix calls appear in the Thesys Console under the model name `openui/auto-fix`. A successful fix counts as a sanitizer correction on the Reliability page, with the same error codes as corrections made during generation. diff --git a/docs/content/docs/gateway/api/autofix.mdx b/docs/content/docs/gateway/api/autofix.mdx new file mode 100644 index 000000000..6f5b60437 --- /dev/null +++ b/docs/content/docs/gateway/api/autofix.mdx @@ -0,0 +1,263 @@ +--- +title: Autofix API +description: Fix invalid OpenUI Lang from any model with one API call. +--- + +The Autofix API fixes OpenUI Lang after a model has generated it. Send the conversation with the generation as its last assistant turn, together with your component library. The request is validated, the errors that can be fixed are fixed, and the answer carries valid OpenUI Lang that the renderer can use. + +Use it when your application calls a model directly and only needs the correction step. The request names no model of its own, and nothing new is generated. It is the same correction that runs inside the [Chat Completions](/docs/gateway/api/chat-completions) and [Responses](/docs/gateway/api/responses) APIs, as a standalone call. The turns before the generation are read only to understand what the user asked for. + +The request and the answer are an OpenAI chat completion, so an OpenAI SDK can call the API with a base URL change. + +**Endpoint:** POST [https://api.thesys.dev/v1/autofix](https://api.thesys.dev/v1/autofix) + +An OpenAI SDK adds `/chat/completions` to its base URL, so it posts to `https://api.thesys.dev/v1/autofix/chat/completions`. Both paths take the same body and answer the same way. + +## Fix an invalid generation + +Point the OpenAI client at `/v1/autofix` and send the generation as the last assistant turn. Fenced or bare OpenUI Lang both work, and text outside the fence is ignored. + +The API adds `fix_summary` to the chat completion, which the OpenAI types do not know about, so the example casts the request and the answer. + +```ts title="lib/autofix.ts" +import OpenAI from "openai"; +import type { ChatCompletion } from "openai/resources/chat/completions"; +import library from "./openui.spec.json"; + +const client = new OpenAI({ + apiKey: process.env.THESYS_API_KEY, + baseURL: "https://api.thesys.dev/v1/autofix", +}); + +type FixError = { code: string; message: string; statementId?: string }; +type FixSummary = { + status: "already_valid" | "fixed" | "fix_failed"; + fixed_errors: FixError[]; + unfixed_errors: FixError[]; +}; +type AutofixCompletion = ChatCompletion & { fix_summary: FixSummary }; + +export async function autofix(messages: OpenAI.ChatCompletionMessageParam[], generation: string) { + return (await client.chat.completions.create({ + model: "openui/autofix", + messages: [...messages, { role: "assistant", content: generation }], + library, + } as OpenAI.ChatCompletionCreateParamsNonStreaming)) as AutofixCompletion; +} +``` + +```ts title="server.ts" +import { autofix } from "./lib/autofix"; + +// Pass the same messages you sent to your model. +const completion = await autofix(messages, generation); + +if (completion.fix_summary.status === "fix_failed") { + renderFallback(generation); +} else { + render(completion.choices[0].message.content); +} +``` + +`openui.spec.json` is the library spec that `openui generate --spec` writes for your components. See [Generate OpenUI Lang](/docs/gateway/generate-openui-lang) for how it is created. Omit `library` to check the generation against the built-in OpenUI chat library. + +`model` is accepted so that an SDK client has something to send, and it is ignored: the fix always runs on the same correction model. + +### Without an SDK + +The plain path takes the same body. Server calls use the API key described in [Authentication](/docs/gateway/authentication). + +```ts title="lib/autofix-fetch.ts" +import library from "./openui.spec.json"; + +type Message = { role: string; content: string | unknown[] }; + +export async function autofix(messages: Message[], generation: string) { + const response = await fetch("https://api.thesys.dev/v1/autofix", { + method: "POST", + headers: { + Authorization: `Bearer ${process.env.THESYS_API_KEY}`, + "Content-Type": "application/json", + }, + body: JSON.stringify({ + messages: [...messages, { role: "assistant", content: generation }], + library, + }), + }); + + if (!response.ok) { + throw new Error(`Autofix failed: ${response.status}`); + } + + return response.json(); +} +``` + +### Python + +```python title="autofix.py" +import json +import os + +from openai import OpenAI + +client = OpenAI( + api_key=os.environ["THESYS_API_KEY"], + base_url="https://api.thesys.dev/v1/autofix", +) + +with open("openui.spec.json") as spec: + library = json.load(spec) + +completion = client.chat.completions.create( + model="openui/autofix", + messages=[*messages, {"role": "assistant", "content": generation}], + extra_body={"library": library}, +) + +if completion.fix_summary["status"] == "fix_failed": + render_fallback(generation) +else: + render(completion.choices[0].message.content) +``` + +## Request + +| Field | Type | Required | Purpose | +| ---------- | ------ | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `messages` | array | Yes | The conversation, in the OpenAI chat message shape. The last turn must be an `assistant` turn whose text is the generation to fix, up to 100,000 characters. The turns before it are the context: only the text of `user`, `assistant`, `system`, and `developer` turns is read, and tool turns and non-text parts are dropped. | +| `library` | object | No | Your library spec, as written by `openui generate --spec`. Without it, the built-in chat library is used. | +| `model` | string | No | Accepted so that an SDK client can name a model, and ignored. The answer always reports `openui/autofix`. | +| `stream` | bool | No | Streaming is not supported. A fix has nothing to send until it is finished, so `stream: true` is a `400`. | + +The other OpenAI fields, such as `temperature` and `tools`, are ignored. + +## Read the result + +The answer is a chat completion. `choices[0].message.content` holds the complete generation, not a patch: replace the model output with it and render it. `fix_summary.status` says what happened. + +| `status` | `content` | Errors | Charged | +| --------------- | ------------------------ | ----------------------------------------------------- | ------- | +| `already_valid` | The input, unchanged | `fixed_errors` is empty | No | +| `fixed` | The corrected generation | `fixed_errors` lists what was wrong and is now fixed | Yes | +| `fix_failed` | `null` | `unfixed_errors` lists what is still wrong | Yes | + +`fixed_errors` and `unfixed_errors` are always present, and one of them is usually empty. + +A fixed generation: + +```json +{ + "id": "fix_P4TPtYimJFMpSgsViggie", + "object": "chat.completion", + "created": 1789019848, + "model": "openui/autofix", + "choices": [ + { + "index": 0, + "finish_reason": "stop", + "message": { + "role": "assistant", + "content": "root = Card([header])\nheader = Header(\"Q3 Results\")" + } + } + ], + "usage": { "prompt_tokens": 8014, "completion_tokens": 17, "total_tokens": 8031 }, + "fix_summary": { + "status": "fixed", + "fixed_errors": [ + { + "code": "unresolved", + "statementId": "followUp", + "message": "reference \"followUp\" is never defined" + } + ], + "unfixed_errors": [] + } +} +``` + +A generation that could not be fixed: + +```json +{ + "id": "fix_dRvfleg31F5g-Amn3v4-W", + "object": "chat.completion", + "created": 1789026253, + "model": "openui/autofix", + "choices": [ + { + "index": 0, + "finish_reason": "stop", + "message": { "role": "assistant", "content": null } + } + ], + "usage": { "prompt_tokens": 360, "completion_tokens": 146, "total_tokens": 506 }, + "fix_summary": { + "status": "fix_failed", + "fixed_errors": [], + "unfixed_errors": [ + { + "code": "null-required", + "component": "B", + "path": "/child", + "statementId": "z", + "message": "required field \"/child\" cannot be null" + } + ] + } +} +``` + +When the fix fails, fall back to what your application does for any unusable model output, such as showing the text or a generic error state. + +## Error codes + +Each entry in `fixed_errors` or `unfixed_errors` names one problem. `code` is always present. `component`, `path`, and `statementId` are present when the validator can name the component type, the property, and the statement that carried the problem. + +| Code | Meaning | +| ------------------- | ---------------------------------------------------------------------------------- | +| `unknown-component` | A component name that is not in the library. | +| `missing-required` | A required property was left out. | +| `null-required` | A required property was set to `null`. | +| `type-mismatch` | A property has the wrong type, or a value outside its allowed set. | +| `excess-args` | A component received more arguments than its signature has. | +| `inline-reserved` | `Query()` or `Mutation()` was used inside an expression instead of as a statement. | +| `incomplete` | The generation stopped in the middle of a statement. | +| `unresolved` | A statement is referenced but never defined. | +| `orphaned` | A statement is defined but not reachable from `root`. | +| `missing-root` | The generation has no valid `root` statement. | + +These are the same codes the OpenUI SDK reports in the browser, so an application can handle both with one path. See [Observability](/docs/observability) for how they appear in the Thesys Console. + +## Limits + +- The generation can be up to 100,000 characters. +- The turns before it can hold up to 20 usable turns and 8,000 characters of text in total, counted after tool turns and non-text parts are dropped. +- Only the most recent turns are used. Older turns are dropped first. +- Up to two attempts are made to fix one generation. + +## Data + +The conversation you send is passed to the model that fixes the generation, and is not stored beyond the request logs. + +## Pricing + +Each call that runs a fix is charged a flat price from your credits. A generation that is already valid is free. See [Pricing](/docs/gateway/pricing-credits) for the current rate. + +`usage` in the answer reports the tokens the fix used, for your own tracking. The charge does not depend on it. + +## Errors + +The endpoint returns the same error shape as the Chat Completions and Responses APIs. + +| Status | Type | When | +| ------ | ----------------------- | ------------------------------------------------------------------------------------------------------------------------ | +| `400` | `invalid_request_error` | The last turn is not an assistant turn with a generation, a limit is passed, `library` is malformed, or `stream` is `true`. | +| `401` | `authentication_error` | The API key is missing or invalid. | +| `429` | `rate_limit_error` | The organization has no credits, or billing is suspended. | +| `500` | `internal_server_error` | The fixing model could not be reached. Nothing is charged. | + +## Observability + +Autofix calls appear in the Thesys Console under the model name `openui/autofix`. A successful fix counts as a sanitizer correction on the Reliability page, with the same error codes as corrections made during generation. diff --git a/docs/content/docs/gateway/index.mdx b/docs/content/docs/gateway/index.mdx index 77810e7af..d3caa147b 100644 --- a/docs/content/docs/gateway/index.mdx +++ b/docs/content/docs/gateway/index.mdx @@ -70,7 +70,7 @@ full: true Build stateful model interactions with persistent conversations and hosted tools. - + Fix invalid OpenUI Lang from any model. Send the raw generation and get back valid OpenUI Lang. @@ -81,6 +81,6 @@ full: true - **Validated generated UI.** Validates generated UI during the stream and fixes malformed syntax, invalid component usage, and schema violations before forwarding the response. - **Unified API.** Switch between providers and models with minimal code changes. - **High reliability.** Automatically retries requests with other providers if one fails. - - **Correction on its own.** Keep your model and backend, and send only the generation that needs fixing to the Auto-fix API. + - **Correction on its own.** Keep your model and backend, and send only the generation that needs fixing to the Autofix API. - **No markup on tokens.** Tokens cost the same as they would from the provider directly, with zero markup, including with Bring Your Own Key (BYOK). diff --git a/docs/content/docs/gateway/meta.json b/docs/content/docs/gateway/meta.json index b0cd756d8..d70318724 100644 --- a/docs/content/docs/gateway/meta.json +++ b/docs/content/docs/gateway/meta.json @@ -15,6 +15,6 @@ "api/chat-completions", "api/responses", "api/conversations", - "api/auto-fix" + "api/autofix" ] } diff --git a/docs/content/docs/gateway/pricing-credits.mdx b/docs/content/docs/gateway/pricing-credits.mdx index fb122bbc8..021567d9b 100644 --- a/docs/content/docs/gateway/pricing-credits.mdx +++ b/docs/content/docs/gateway/pricing-credits.mdx @@ -38,9 +38,9 @@ The cost of a Gateway request has two parts: Model usage is billed at the provider's rates without markup. The Gateway API and OpenUI Lang correction behavior remain the same whether you use managed inference or your own provider key. -### Auto-fix API +### Autofix API -A [Auto-fix API](/docs/gateway/api/auto-fix) call that runs a fix costs a flat $0.02, deducted from your Gateway Credits. It does not use a plan API call. A generation that is already valid is free. +An [Autofix API](/docs/gateway/api/autofix) call that runs a fix costs a flat $0.02, deducted from your Gateway Credits. It does not use a plan API call. A generation that is already valid is free. ### Finding model pricing diff --git a/docs/content/docs/gateway/reliability.mdx b/docs/content/docs/gateway/reliability.mdx index 9db80c25a..75237d12e 100644 --- a/docs/content/docs/gateway/reliability.mdx +++ b/docs/content/docs/gateway/reliability.mdx @@ -3,9 +3,9 @@ title: Reliability description: Keep model requests working when providers are unavailable or models return invalid OpenUI Lang. --- - + Not routing requests through Gateway? Send your model's OpenUI Lang generation to the - [Auto-fix API](/docs/gateway/api/auto-fix) and get back valid OpenUI Lang, at a flat price per + [Autofix API](/docs/gateway/api/autofix) and get back valid OpenUI Lang, at a flat price per fix. @@ -18,7 +18,7 @@ Gateway handles each problem differently. It automatically retries the request w | Problem | What happens | How Gateway responds | | ------------------------ | ------------------------------------------------------------------------------------------------- | -------------------------------------------------------- | | **Provider unavailable** | An outage, capacity limit, or unavailable route prevents the selected provider from responding. | Gateway retries through a compatible fallback route. | -| **Invalid model output** | The model returns OpenUI Lang with invalid syntax, references, components, properties, or structure. | Gateway corrects eligible errors and continues the stream, or fixes the generation on request through the Auto-fix API. | +| **Invalid model output** | The model returns OpenUI Lang with invalid syntax, references, components, properties, or structure. | Gateway corrects eligible errors and continues the stream, or fixes the generation on request through the Autofix API. | ## Recover from provider failures @@ -48,7 +48,7 @@ Correction applies only to generated OpenUI Lang. Plain text, arbitrary JSON, ap Gateway improves the reliability of model access and generated OpenUI Lang. Your application remains responsible for: -- Fallback behavior when a fix fails, whether during a stream or through the Auto-fix API +- Fallback behavior when a fix fails, whether during a stream or through the Autofix API - Component behavior and UI error boundaries - Authentication and permissions - Tool authorization and input validation diff --git a/docs/content/docs/openui-lang/reliability.mdx b/docs/content/docs/openui-lang/reliability.mdx index 80ce0216f..11250870f 100644 --- a/docs/content/docs/openui-lang/reliability.mdx +++ b/docs/content/docs/openui-lang/reliability.mdx @@ -103,34 +103,37 @@ After deploying, open the [Reliability dashboard](https://console.thesys.dev/rel Even with a well-tuned schema, prompt, and model, some generations in production will still fail validation. OpenUI offers two ways to repair them automatically, depending on how your application calls the model. -- **[Auto-fix API](#auto-fix-api):** your application calls the model itself and sends the generation to the Auto-fix API for repair. +- **[Autofix API](#autofix-api):** your application calls the model itself and sends the generation to the Autofix API for repair. - **[OpenUI Gateway](#openui-gateway):** OpenUI Gateway calls the model on your behalf and repairs the generation while it streams. -### Auto-fix API +### Autofix API -The [Auto-fix API](/docs/gateway/api/auto-fix) repairs OpenUI Lang after your model has generated it, so your application keeps its own model calls, keys, and prompts. +The [Autofix API](/docs/gateway/api/autofix) repairs OpenUI Lang after your model has generated it, so your application keeps its own model calls, keys, and prompts. -For every generation, the Auto-fix API: +For every generation, the Autofix API: - **Validates** the generation against your component library. - **Fixes** unknown components, missing references, and broken structure. -- **Returns** the complete fixed generation, ready to render. +- **Answers** with the complete fixed generation, ready to render. ```ts -const response = await fetch("https://api.thesys.dev/v1/embed/auto-fix", { - method: "POST", - headers: { - Authorization: `Bearer ${process.env.THESYS_API_KEY}`, - "Content-Type": "application/json", - }, - body: JSON.stringify({ generation, library }), +const client = new OpenAI({ + apiKey: process.env.THESYS_API_KEY, + baseURL: "https://api.thesys.dev/v1/autofix", }); -const result = await response.json(); -// result.status is "already_valid", "fixed", or "fix_failed" +const completion = await client.chat.completions.create({ + model: "openui/autofix", + // The generation to fix is the last assistant turn. + messages: [...messages, { role: "assistant", content: generation }], + library, +}); + +// completion.fix_summary.status is "already_valid", "fixed", or "fix_failed" +// completion.choices[0].message.content holds the fixed generation. ``` -A generation that is already valid is free, and each fix is charged at a flat price. See the [Auto-fix API reference](/docs/gateway/api/auto-fix) for the full request and response format and the error codes. +A generation that is already valid is free, and each fix is charged at a flat price. See the [Autofix API reference](/docs/gateway/api/autofix) for the full request and response format and the error codes. ### OpenUI Gateway From b7ceb25deb4473b35dedf394e7165e096b6e6e6d Mon Sep 17 00:00:00 2001 From: Ankur Mittal Date: Fri, 11 Sep 2026 19:08:43 +0530 Subject: [PATCH 16/20] docs: drop the Python Autofix snippet for now Co-Authored-By: Claude Fable 5.1 --- docs/content/docs/gateway/api/autofix.mdx | 28 ----------------------- 1 file changed, 28 deletions(-) diff --git a/docs/content/docs/gateway/api/autofix.mdx b/docs/content/docs/gateway/api/autofix.mdx index 6f5b60437..29fdc2efe 100644 --- a/docs/content/docs/gateway/api/autofix.mdx +++ b/docs/content/docs/gateway/api/autofix.mdx @@ -93,34 +93,6 @@ export async function autofix(messages: Message[], generation: string) { } ``` -### Python - -```python title="autofix.py" -import json -import os - -from openai import OpenAI - -client = OpenAI( - api_key=os.environ["THESYS_API_KEY"], - base_url="https://api.thesys.dev/v1/autofix", -) - -with open("openui.spec.json") as spec: - library = json.load(spec) - -completion = client.chat.completions.create( - model="openui/autofix", - messages=[*messages, {"role": "assistant", "content": generation}], - extra_body={"library": library}, -) - -if completion.fix_summary["status"] == "fix_failed": - render_fallback(generation) -else: - render(completion.choices[0].message.content) -``` - ## Request | Field | Type | Required | Purpose | From 10ee852bcc99d08cdba82c3dfd546c69ec9e2583 Mon Sep 17 00:00:00 2001 From: Ankur Mittal Date: Fri, 11 Sep 2026 19:09:07 +0530 Subject: [PATCH 17/20] docs: list non-streaming support under Limits Co-Authored-By: Claude Fable 5.1 --- docs/content/docs/gateway/api/autofix.mdx | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/content/docs/gateway/api/autofix.mdx b/docs/content/docs/gateway/api/autofix.mdx index 29fdc2efe..20e1be815 100644 --- a/docs/content/docs/gateway/api/autofix.mdx +++ b/docs/content/docs/gateway/api/autofix.mdx @@ -208,6 +208,7 @@ These are the same codes the OpenUI SDK reports in the browser, so an applicatio - The turns before it can hold up to 20 usable turns and 8,000 characters of text in total, counted after tool turns and non-text parts are dropped. - Only the most recent turns are used. Older turns are dropped first. - Up to two attempts are made to fix one generation. +- Only non-streaming responses are supported. `stream: true` is a `400`. ## Data From ff00748359dac48b56720b10d5e8b18f972881d0 Mon Sep 17 00:00:00 2001 From: Ankur Mittal Date: Fri, 11 Sep 2026 19:10:25 +0530 Subject: [PATCH 18/20] docs: shorter Autofix intro that states OpenAI compatibility Co-Authored-By: Claude Fable 5.1 --- docs/content/docs/gateway/api/autofix.mdx | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/docs/content/docs/gateway/api/autofix.mdx b/docs/content/docs/gateway/api/autofix.mdx index 20e1be815..941c7035b 100644 --- a/docs/content/docs/gateway/api/autofix.mdx +++ b/docs/content/docs/gateway/api/autofix.mdx @@ -3,15 +3,11 @@ title: Autofix API description: Fix invalid OpenUI Lang from any model with one API call. --- -The Autofix API fixes OpenUI Lang after a model has generated it. Send the conversation with the generation as its last assistant turn, together with your component library. The request is validated, the errors that can be fixed are fixed, and the answer carries valid OpenUI Lang that the renderer can use. +The Autofix API repairs invalid OpenUI Lang after a model has generated it. Send the conversation with the generation as the last assistant turn, and the answer carries valid OpenUI Lang. It is the same correction that runs inside the [Chat Completions](/docs/gateway/api/chat-completions) and [Responses](/docs/gateway/api/responses) APIs, as a standalone call for applications that call a model directly. -Use it when your application calls a model directly and only needs the correction step. The request names no model of its own, and nothing new is generated. It is the same correction that runs inside the [Chat Completions](/docs/gateway/api/chat-completions) and [Responses](/docs/gateway/api/responses) APIs, as a standalone call. The turns before the generation are read only to understand what the user asked for. +**Endpoint:** `POST https://api.thesys.dev/v1/autofix` -The request and the answer are an OpenAI chat completion, so an OpenAI SDK can call the API with a base URL change. - -**Endpoint:** POST [https://api.thesys.dev/v1/autofix](https://api.thesys.dev/v1/autofix) - -An OpenAI SDK adds `/chat/completions` to its base URL, so it posts to `https://api.thesys.dev/v1/autofix/chat/completions`. Both paths take the same body and answer the same way. +**OpenAI compatible.** The request and the answer use the OpenAI chat completion shape. Point an OpenAI SDK at the base URL `https://api.thesys.dev/v1/autofix` and it posts to `/v1/autofix/chat/completions`. Both paths take the same body and answer the same way. ## Fix an invalid generation From faf1044e2644244354c8fd40fe139a7b832c08e2 Mon Sep 17 00:00:00 2001 From: Ankur Mittal Date: Fri, 11 Sep 2026 19:11:46 +0530 Subject: [PATCH 19/20] docs: drop the gateway cross-reference from the Autofix intro Co-Authored-By: Claude Fable 5.1 --- docs/content/docs/gateway/api/autofix.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/content/docs/gateway/api/autofix.mdx b/docs/content/docs/gateway/api/autofix.mdx index 941c7035b..9b704525d 100644 --- a/docs/content/docs/gateway/api/autofix.mdx +++ b/docs/content/docs/gateway/api/autofix.mdx @@ -3,7 +3,7 @@ title: Autofix API description: Fix invalid OpenUI Lang from any model with one API call. --- -The Autofix API repairs invalid OpenUI Lang after a model has generated it. Send the conversation with the generation as the last assistant turn, and the answer carries valid OpenUI Lang. It is the same correction that runs inside the [Chat Completions](/docs/gateway/api/chat-completions) and [Responses](/docs/gateway/api/responses) APIs, as a standalone call for applications that call a model directly. +The Autofix API repairs invalid OpenUI Lang after a model has generated it. Send the conversation with the generation as the last assistant turn, and the answer carries valid OpenUI Lang. Use it when your application calls a model directly. **Endpoint:** `POST https://api.thesys.dev/v1/autofix` From a3f2911225854365562e0785ed5a7b8aa89c8e31 Mon Sep 17 00:00:00 2001 From: Ankur Mittal Date: Fri, 11 Sep 2026 19:19:17 +0530 Subject: [PATCH 20/20] docs: show how to detect an invalid generation before calling Autofix Co-Authored-By: Claude Fable 5.1 --- docs/content/docs/gateway/api/autofix.mdx | 37 +++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/docs/content/docs/gateway/api/autofix.mdx b/docs/content/docs/gateway/api/autofix.mdx index 9b704525d..c52286cad 100644 --- a/docs/content/docs/gateway/api/autofix.mdx +++ b/docs/content/docs/gateway/api/autofix.mdx @@ -9,6 +9,43 @@ The Autofix API repairs invalid OpenUI Lang after a model has generated it. Send **OpenAI compatible.** The request and the answer use the OpenAI chat completion shape. Point an OpenAI SDK at the base URL `https://api.thesys.dev/v1/autofix` and it posts to `/v1/autofix/chat/completions`. Both paths take the same body and answer the same way. +## Detect an invalid generation + +Parse the generation with `@openuidev/lang-core` before you call the API. It is the same check the API runs first, so a generation that passes here would come back as `already_valid`. Skip the call when nothing is wrong. + +```ts title="lib/detect.ts" +import { createParser } from "@openuidev/lang-core"; +import library from "./openui.spec.json"; + +const parser = createParser(library.schema, library.root); + +/** Everything that stops the generation from rendering. Empty means valid. */ +export function findErrors(generation: string): string[] { + const { root, meta } = parser.parse(generation); + return [ + ...meta.errors.map((e) => `${e.code} ${e.component}${e.path}: ${e.message}`), + ...meta.unresolved.map((name) => `unresolved: "${name}" is used but never defined`), + ...meta.orphaned.map((name) => `orphaned: "${name}" is defined but never used`), + ...(meta.incomplete ? ["incomplete: the generation ends mid-statement"] : []), + ...(root === null ? ["missing-root: no root element"] : []), + ]; +} +``` + +```ts title="server.ts" +import { findErrors } from "./lib/detect"; + +const errors = findErrors(generation); +if (errors.length === 0) { + render(generation); +} else { + console.warn("invalid generation", errors); + // Send it to the Autofix API, below. +} +``` + +`parse` never throws. It takes fenced or bare OpenUI Lang and reports prop errors in `meta.errors`, with the codes listed under [Error codes](#error-codes). + ## Fix an invalid generation Point the OpenAI client at `/v1/autofix` and send the generation as the last assistant turn. Fenced or bare OpenUI Lang both work, and text outside the fence is ignored.