chat · renderer · product

OpenAI ChatKit widgets (and Open-JSON-UI)

A drop-in chat UI whose widgets are designer-made templates (a strict JSX dialect, .widget files with Jinja placeholders) hydrated with data and streamed into a conversation.

OpenAI ChatKit widgets (and Open-JSON-UI)

What it is

A drop-in chat UI (a web component plus React bindings, served from OpenAI’s CDN) with widgets: structured cards and lists the assistant streams into the conversation. Widgets are designed in ChatKit Studio’s Widget Builder in a “strict, simplified JSX dialect”, exported as .widget files (layout, data schema and sample data), hydrated on the server with Jinja-style {{ }} placeholders, and streamed to the client as JSON.

Open-JSON-UI is CopilotKit’s name for “an open standardization of OpenAI’s internal declarative Generative UI schema”; CopilotKit lists it next to A2UI as a declarative spec. We found no standalone repository or spec document for it, only CopilotKit’s docs pages.

The problem it’s solving

Giving teams a production chat front end with rich, interactive responses without building one, and keeping the model’s output safe by constraining it to designed templates.

Its path / bet

Templates designed by people, filled by agents. The layout is authored ahead of time (visually, in Studio); at runtime the server builds a widget from a template plus data. The model decides when to show a widget and supplies data; it can generate widget JSON directly, but the documented path is template plus data.

How it works

  • Containers: Card (with confirm and cancel actions), ListView (rows of ListViewItem), Basic (entity previews). Components: Box, Row, Col, Text, Title, Caption, Markdown, Badge, Image, Button, Form, Select, DatePicker, charts and more.
  • Python server: WidgetTemplate.from_file("x.widget").build(data) returns a Pydantic model; stream_widget sends it. Yielding successive versions from a generator makes the SDK diff them and emit update events; only Text and Markdown nodes with an id stream text smoothly, other diffs re-render that part.
  • Actions: onClickAction, onSubmitAction, onChangeAction with a type and payload, handled on the server by default or on the client with handler: "client".
  • Back to the model: a widget converts into model input (ThreadItemConverter.widget_to_input), and each widget carries copy_text, a plain-text rendering.

Strengths

  • Polished, opinionated, and backed by the largest model vendor.
  • The template-plus-data split is sound: design once, hydrate many times.
  • copy_text and widget_to_input: a plain-text version of every widget, for the clipboard and for the model. A small, practical form of read-back.
  • Diffing successive widget states on the server makes “just re-render the whole thing” cheap for the developer.

Weaknesses / limits

  • Tied to OpenAI’s hosted script and, until November, to Agent Builder; the product it launched with is being retired, which makes its long-term priority unclear.
  • Chat-embedded only: widgets live in messages, not on a standing screen.
  • Jinja templating and a JSX dialect are two more languages; the template, not the model, holds the layout.
  • Browser only. Open-JSON-UI’s status as a “standard” rests on one vendor’s description.

Relation to fictty

Watch. A different surface and a vendor-locked client. The ideas worth noting are the template-plus-data split (fictty’s project components) and the plain-text twin of every widget (fictty’s screen).

Could fictty adopt it instead of building?

No. The renderer is OpenAI’s hosted web component; the widget schema has no published standalone spec we could find; and there’s no terminal story.

What fictty should take from it

  • A plain-text twin for every node, designed for the model as much as for the clipboard. fictty’s screen gives the frame; a per-node “copy text” in get --state would let an agent quote one card without parsing the whole frame.
  • Diff successive whole values on the server side so producers can just re-push; fictty already makes a whole push as cheap as a frame, which is the stronger version of the same idea.
  • Retired hosting is a risk lesson: formats bound to one vendor’s hosted runtime inherit its product decisions. fictty’s runtime is local and MIT; say so.

Sources

Not verified: the exact JSON shape of a serialized widget (the docs we read describe components and props but don’t show a full payload), and whether Open-JSON-UI has any spec beyond CopilotKit’s pages.