ChatGPT Intelligent UI Technical Breakdown: The Model Describes the Interface; the Compiler and Client Run It

Tracing the path across DIL descriptions, server compilation, and client execution to unpack streaming display, state updates, data injection, and AppBlock.

By Rabi Guha / OpenUI10-09 · 12 min

ChatGPT Intelligent UI can turn answers into interfaces complete with buttons, charts, and sliders. In the original instructional monthly fee estimate, adjusting the seat count immediately changes the price; generating this response and updating it after a drag interaction go through different steps.

This system divides the work among the model, the compiler, and the client: the model describes text, components, and computational logic using DIL; the compiler transforms the description into code and data; the client runs the logic and renders the results using native components. When a user subsequently drags the slider, the pre-written calculations can execute locally on the client without asking the model to regenerate the response.

AI interface engineering team Thesys traced the end-to-end execution pipeline from model output to on-screen interface on the web by analyzing public web traffic, capturing server-sent event (SSE) patches, and inspecting frontend-distributed core runtime scripts and component registries. (The following implementation details are based on Thesys's reverse-engineering observations of the web client.)

ChatGPT Intelligent UI Core Architecture Flow Diagram
The four-layer data flow pipeline of ChatGPT Intelligent UI reverse-engineered by Thesys: the model outputs DIL, the server handles patching and constants extraction, the client Worker sandbox computes diffs, and the host page handles native rendering. (Source: Thesys Architecture Diagram)

What Are the Model, Compiler, and Client Respectively Responsible For?

In the native component path, the client's work is further divided into two parts: the runtime executes logic and produces update operations, while the renderer paints components according to those operations. Walking through that same monthly fee estimate, we can step through the division of labor between the model, compiler, and client.

The Model: Describing Content, Components, and Logic with DIL

When the large model generates a response, it uses neither plain text nor a traditional JSON structure tree, but a specialized language called DIL. It blends three ingredients:

  • Standard Markdown: Used for writing paragraph text and formatting headings;
  • JSX-like component tags: Used for declaring layout containers and functional components (such as <box>, <slider>, <title>);
  • Inline JavaScript (marked with {@body ...}): Used for declaring internal reactive state and derived logic.

Consider a typical instructional calculation example (Note: The $29/seat/month in the example is instructional data used to demonstrate formula logic, not actual tier pricing):

## Team plan estimate
Drag the slider to see the **monthly price** for your team.
{@body const [seats,setSeats] = DIL.useState(8)}
{@body const price = seats*29}
<box border padding={3} gap={2}>
  <slider min={1} max={50} value={seats} onChange={setSeats}/>
  <title size="xl">${price}/mo</title>
</box>

In this snippet, the model defines a default seat count of 8 using DIL.useState(8), computes total price via a standard JavaScript expression, and binds state to the slider component. The tweet summarized the main path as "the model never writes raw code," but that is not entirely accurate—the model directly writes JavaScript logic, except it is embedded inside a specialized markup language.

The Compiler: Transforming Descriptions into Executable Code and Data

The client browser does not directly execute the raw DIL string generated by the model as-is. OpenAI's backend server processes the model output stream, dynamically compiling it into a standalone JavaScript execution function and a JSON constants table (tagged as model_dil_v2 in conversation metadata). Ordinary Markdown in the response (headings, paragraphs, bold text) is also compiled into the same component tree (e.g., converted into title or text with bold), while text is extracted and moved into the constants table.

The server compiler performs five key processing steps:

  • Function standardization: Translates all XML-style tags into __dil.jsx(...) function calls, so the client no longer requires a DIL syntax parser.
  • Expression fault tolerance: The compiler wraps expressions with __dilSafe, returning fallback values on errors to help isolate local faults. This mitigates the impact of a single exception on the overall response, though it does not verify whether the formula is mathematically correct.
  • Text extraction into constants tables: Static text is moved into a hash dictionary named constants, such as {"0": "Team plan estimate", "4": "$"}. Consequently, in the subsequent typing stream, text growth only modifies the JSON dictionary without needing to alter the JavaScript code itself.
  • Injecting stable keys for state: Injects stable keys into every state hook (such as { key: "seats" }), ensuring that when the interface recompiles later, the slider position already adjusted by the user is not reset to its initial value.
  • Allowlist validation and automated fixing: Strictly filters invalid attributes against the design system catalog (for instance, if the model writes an undefined fill property or a malformed numerical value, it is stripped during compilation and tagged with a diagnostic marker).

The Client: Isolating Logic Execution and Rendering Native Interfaces

Executing Logic and Preserving State Inside a Sandbox

Code generated by large models is inherently untrusted external input. Running it directly within the host page introduces significant XSS risks or data leakage hazards.

ChatGPT employs a layered isolation architecture in the browser:

  • The page preloads a hidden sandbox iframe (runner.html) configured with a strict CSP (Content Security Policy: default-src 'none') to restrict resource access.
  • That iframe immediately spawns a dedicated Web Worker.
  • Restricting available capabilities: Before executing code, the Worker removes network access, timers, messaging, and dynamic code execution capabilities accessible to model code, and freezes remaining global objects. The runtime itself still executes compiled programs via controlled evaluation entry points.
  • Embedded Mini Reconciler: A React-like reconciler runs inside the Worker. It executes component logic, compares the new component tree against the previous one, calculates required update operations, and serializes them into low-level binary UI operational instructions (such as CREATE #9 slider).
  • Functions never leave the sandbox: Event handlers bound to components (such as onChange) are never transmitted to the main page; the main page only receives an identifier (such as fn#1).
  • Watchdog mechanism: If a piece of logic falls into an infinite loop or execution times out, the watchdog forcibly terminates and restarts the Worker.

Rendering Components and Receiving User Actions in the Host Page

Once the main page receives the UI instructions emitted by the Worker, it maps them to ChatGPT's own native component library (comprising approximately 70 native components, with 39 appearing in captured responses). The page incorporates built-in entrance animations: text fades in over 0.7s, new lines slide in over 0.42s, and charts expand over 1.8s.

More critically, consider the reverse interaction loop: when a user drags the seat count from 8 to 9 using touch or mouse, the main page merely sends fn#1(9) to the Worker. Inside the Worker, setSeats(9) executes, the reconciler recalculates the price to $261/mo, and emits interface update operations back to the main page. This price calculation completes entirely on the client without invoking the model again. This does not mean the entire page emits no other network requests, such as telemetry reporting.

The reason the generated interface maintains visual harmony with ChatGPT's native styling lies in a shared component catalog and design system across layers. It encompasses three categories:

  • Native components: Elements the client already knows how to render, such as buttons, sliders, and text.
  • Design tokens: Standardized rules for spacing, corner radius, and color. While some properties accept pixel widths or hex colors, tokens remain the preferred choice.
  • Premade composite components: Components pre-authored by OpenAI in DIL and injected into the sandbox, such as image and product components.

In samples captured by the analysis team, the model invoked premade components without defining novel composite components on its own.

The Catalog simultaneously enforces triple constraints: it restricts the model to predefined tags, acts as a schema for the compiler to validate properties and types, and guides the host page on specific rendering rules.

This protocol—transmitting only low-level UI instructions—inherently offers strong cross-platform potential. Although the sandbox environment retains global objects required by React Native's Hermes engine, whether mobile clients run the exact same runtime remains an inference by the analysis team based on code clues, pending direct packet-capture verification.

After Dragging, Changes Occur on the Client

Initial generation: ① → ② → ③ → ④. When dragging: ④ → ③ → ④; initial code in ① and ② remains unchanged.

Educational Demo: Local Computation
Model invocations for this adjustment: 0
Adjust seats: 8 seats
① Model Output (DIL) Initial description stays unchanged

Initial generation: initial 8 seats; price = seats × 29. Dragging does not rewrite this description.

View DIL Description
## Team plan estimate
Drag the slider...
{@body const [seats,setSeats] 
       = DIL.useState(8)}
{@body const price = seats*29}
<box border padding={3} gap={2}>
  <slider min={1} max={50} 
          value={seats} 
          onChange={setSeats}/>
  <title size="xl">
    ${price}/mo
  </title>
</box>
② Server Compilation Initial code stays unchanged

Initial program: injects stable state key; initial value remains 8. Dragging requires no recompilation.

View Compiled Snippet
// Compiled JS + JSON:
DIL.render(__dil.jsx(() => {
  const [seats, setSeats] = 
    DIL.useState(8, {key: "seats"});
  const price = __dilSafe(
    () => seats * 29, undefined
  );
  return ...
}));

// Constants table (JSON):
"constants": {
  "0": "Team plan estimate",
  "4": "$", "5": "/mo"
}
③ Client Worker Sandbox Updates state on interaction
// Sandbox internal state (Hook State):
state.seats = 8;
state.price = 232;

// Trigger user event:
recv: fn#1(8)
// Dispatch native UI operations:
UPDATE #12 text "232"
(Illustrative price update; not complete operation log)
④ ChatGPT Host Native Rendering Updates view on interaction
Team plan estimate
Adjust seat count to view monthly total.
$232/mo
Notice where changes land: Initial seat count in the model and compiler always remains 8; only client state and displayed price change with the slider. Events travel from the page to the runtime, price is recalculated as seats × 29, and UI update operations are returned. (This is an instructional demo of the original mechanism and does not run ChatGPT's Worker. $29/seat/month demonstrates formula logic, not actual tier pricing; operation panel displays simplified instructions.)

Streaming Compilation: Why Can You View and Interact Before the Interface Finishes Generating?

Streaming plain text is straightforward: append each incoming token to the end. But streaming an interactive interface containing nested nodes and logical closures must address two additional challenges:

  1. Incomplete syntax: Large models generate output token by token. If the model has just emitted <box border><slider min=, with subsequent attributes not yet produced, a conventional parser cannot run this incomplete syntax.
  2. Typewriter state continuity: Users might already begin dragging an earlier slider while the model is still generating the latter half of the response. As new data streams in continuously from the background, controls currently being manipulated by the user must never be reset.
Streaming Response Timeline Breakdown Visualization
Thesys's swimlane diagram of a complete streaming packet capture for a 6,341-character response: clearly illustrating the temporal alignment across setup, thinking, text streaming, UI compilation retransmissions, and asynchronous image arrival. (Source: Thesys Reverse-Engineering Packet Timing Diagram)

In a captured response containing 6,341 characters with a body stream lasting 18.7 seconds, the reverse-engineering team recorded 84 update events (delivered via SSE channels as JSON-Patch). Among these, 76 contained new text, falling into three categories below; another 5 delivered image results, 1 initialized the message, and 2 marked completion:

In a Single Response, What Did the 84 Updates Actually Do?

Based on Thesys's reverse-engineered streaming session sample of 6,341 characters with body streaming lasting 18.7 seconds. Click different slices to inspect underlying processing logic:

Structural Change Packets (Structure Changed): 52 events Full code retransmitted
Model Output State (Model Output)
<box border padding={3}>
  <slider min={1} max={50} value={seats} />
  // Added a child component...
Server Injected Patch (SSE JSON-Patch)
{"p": "/message/metadata/model_dil_v2/code",
 "o": "replace",
 "v": "DIL.render(__dil.jsx(() => { ...fully recompiled JS program... }))"}
Engineering cost and cause: Whenever the model adds a component or alters the tree hierarchy, because closing brackets of the compiled JavaScript shift, the server recompiles and retransmits the full code program (replace) in this capture. Across the captured 275 KB patch traffic, retransmitted code accounted for approximately 83% of patch data volume. In this sample, the median interval between full recompile updates was roughly 290 milliseconds.

Distribution bar plotted by update frequency; 83% refers to retransmitted code as a share of patch bytes, reflecting different metrics. Based on a single capture; not representative of average performance across all conversations. Code below is simplified for demonstration.

  1. Structural change packets (52 events): In these updates, the server fully recompiles all DIL emitted up to that point. According to the original observations, compilation begins from the very first token, processing Markdown even in the absence of component tags; the server recompiles periodically, and whether this is triggered precisely by each new chunk remains team conjecture. Following structural changes, the closing brackets of the compiled program also shift and cannot be appended directly like a text stream; they must be retransmitted entirely via replace. In this capture, retransmitted code accounted for approximately 83% of patch data volume. Even though the server recompiles the entire description, the client can still update only the UI elements that need changing: the client Worker evaluates the code, diffs the new component tree against the old one, and sends update operations to the main page.
  2. Text-only growth packets (14 events): When the model merely types within standard paragraphs without altering component structures, the compiled JavaScript code remains unchanged, and network payloads simply append new characters into the JSON constants table; avoiding retransmission of identical scripts does not mean the server skipped compilation. The client updates text nodes while preserving existing structure.
  3. Unclosed tag protection (10 events): When the system detects the model lingering inside a half-written tag, the server's trimming mechanism temporarily cuts off incomplete tags or automatically appends closing tags to populated opening elements. The client continues displaying usable portions. If a new program fails evaluation or rendering, the Worker retains the last successfully executed version.

Data Injection: How Do Images and Prices Enter Compiled Interfaces?

When generating interfaces, large models frequently need to display specific products, location maps, or real photographs. Forcing the model to recite an image URL or the latest official price from memory increases the risk of broken links, transcription errors, or fabricated details.

Intelligent UI uses a path that bypasses the model here:

Images: The Model Writes Search Queries; the Server Injects Results

When handling images, the model specifies search intent rather than concrete URLs:

<AsyncImage 
  query="slow roasted rosemary garlic lamb shoulder browned golden roast in baking tray" 
  aspectRatio="5:4" 
  maxWidth="152px"
/>

Once the server compiler detects this tag closing, it triggers a real image search in the background and injects validated image URLs a few seconds later via appData patches. The team also observed similar server-resolved components, including image groups, product and location entity tags, and source citations (Cite).

Tool Data: Referencing Existing Fields to Bypass Model Paraphrasing

When the model previously invoked an external retrieval tool (for example, looking up headphone specs), it references field names in the interface via {turn448791product0.displayed_price}. The displayed ₹35,989 and merchant name are populated directly by backend native JSON. In this example, the model arranges display placement while values originate from tool results themselves. This reduces transcription errors without guaranteeing source accuracy or selection validity; the team also noted weather search results written back into the text by the model, showing that not all data bypasses the model.

ChatGPT Inlined Drum Lab Drum Machine Demo
The standalone web app 'Drum Lab' generated via the AppBlock escape hatch: bypassing native component library limits to synthesize drum beats in real time inside the browser using the Web Audio API. (Source: Thesys Reverse-Engineering Intercepted Case)

AppBlock: When the Component Library Falls Short, How Does the Alternative Path Run?

Even the richest native component library cannot satisfy every demand—such as when a user asks to "build an audible 16-step drum machine."

Such needs can use the AppBlock escape path. The large model directly generates code containing HTML, CSS, and <script> tags. The DIL compiler does not translate internal code, leaving only a __chatgptClientDefinedWidget placeholder in the compiled program. The client reads source code directly from the raw response text and runs it inside a dual-nested iframe on an isolated domain (Skybridge sandbox: *.web-sandbox.oaiusercontent.com). To prevent the page from looking like an incongruous patch, the host injects Tailwind foundational standards and official CSS variables (such as --viz-text and --viz-panel), enabling it to blend automatically with ChatGPT's light and dark themes.

Unlike the native component pipeline described earlier, AppBlock utilizes a distinct execution path and cannot directly map to the Worker and GenUI channels: the web page itself renders the interface, and state resides within the mini-app's own JavaScript variables. In web client samples captured by the analysis team, AppBlock made no callbacks to ChatGPT, and its internal state was lost upon page refresh.

Three Real Case Groups Generated by ChatGPT Intelligent UI
Three generated case groups showcased by the author: on the left, a dog vest mood board with design options; in the center, a dinner menu dynamically calculating guest counts and ingredient quantities; on the right, a product analytics dashboard with scenario simulation sliders. (Note: Right image data is explicitly labeled as Demo data, not actual business metrics)

Being Clickable Does Not Mean Calculating Correctly, Nor That the Model Remembers Your Choices

Thesys's web client samples also highlight several issues affecting practical usage:

  1. Streaming updates retransmit code repeatedly: Patch traffic for this response was approximately 275 KB, with roughly 83% consisting of retransmitted compiled code; this reflects transmission overhead from a single capture and cannot represent all sessions.
  2. State is lost upon page refresh: While the client reports view-state telemetry events to the backend, in web samples inspected by the team, modified values reverted to initial states after refreshing the page.
  3. Local state does not automatically enter model context: Not all interactions can achieve zero-network overhead or avoid calling the model entirely. When components need external interaction, they rely on the host-provided GenUI object: copy handles copying text and openUrl handles opening external links. These actions are handled by the host environment without requiring the model to regenerate responses. The only way to inform the model of user selections is by explicitly calling GenUI.issueNewTurn(...). For example, in the dog vest mood board, after choosing a style and primary color, clicking "Proceed" causes the component to concatenate local state into a text block (e.g., "Proceeding with design based on board, style: cozy, primary: sand..."), dispatched into the conversation as a new user turn, prompting the model to generate subsequent responses. Without triggering such explicit turns, regardless of how you drag sliders or toggle checkboxes on the frontend, the model remains completely unaware in its context, unable to perceive prior adjustments in subsequent follow-ups.
  4. Follow-ups do not modify existing interfaces in place: When a user suggests next-step revisions, the model does not perform incremental updates on the existing card in place; instead, it generates an entirely new card below.
  5. Silent logic errors: When an expression throws an exception, it may simply render as blank; when a formula runs but computes incorrectly, it may not trigger an exception at all. Successful UI rendering does not prove business calculation accuracy (reverse engineering discovered a dashboard where switching metrics caused revenue to jump abruptly from $6,930 to $256,410).
  6. Error correction lacks contextual closure: Although the server compiler strips illegal attributes and records diagnostics, the model repeatedly made identical attribute syntax errors across multi-turn tests, suggesting diagnostics may not feed back into the model, though internal feedback loops cannot be confirmed from these samples alone.

Furthermore, the reconciler does not always guarantee minimal diff instructions. In a single captured price-component interaction, a single click produced 158 operational instructions, of which only 4 resulted in actual property mutations.

Practical compromises also exist across compatibility and layout. To support clients unable to run compiled code, the server concurrently generates a plain Markdown fallback version (fallbackMarkdown) during compilation. It preserves body text while representing images, products, citations, and maps with existing inline client markers; interactive elements become static content. Calculated values dependent on state derivation and {#each} loops were absent in fallback text captured by the team. Meanwhile, because the model outputs search queries without validating results, image searches still suffer mismatches (in one sample, a query for a handlebar shifter close-up returned an e-bike product photo); captured interfaces relied on fixed column counts and pixel widths without invoking existing breakpoint hooks, meaning native component rendering did not automatically resolve mobile layout gracefully.


OpenUI Achieves Comparable Experiences; Default Demos Still Depend on the Cloud

To bring this experience into your own applications, you can start with the component protocol and renderer provided by OpenUI. Thesys provides an open-source Generative UI framework named OpenUI, along with an open-source demo project replicating similar interactions called Open Intelligent UI (a San Francisco day trip itinerary supporting photo albums, map synchronization, and preference forms). To clarify, this demo project uses OpenUI's own streaming markup language (OpenUI Lang), rather than open-sourcing OpenAI's internal DIL specification.

This open-source solution helps developers construct similar experiences in their own apps, though specific implementations and deployment dependencies require clear distinction:

  • Positioning and value of the OpenUI framework: It defines a lightweight streaming markup language (OpenUI Lang) that reduced overall token usage by approximately 52.8% compared to selected Vercel JSON formats across seven project-tested interface scenarios, with a maximum reduction of roughly 67.1% in an individual scenario (these are self-tested results from project-selected scenarios and cannot translate directly into universal speed gains), accompanied by progressive streaming renderers covering React, Vue, Svelte, and Angular.
  • Runtime environment and model dependencies of the demo: Open Intelligent UI defaults to requiring Node 24 and a cloud gateway key (THESYS_API_KEY), with its preset model configured as openai/gpt-5.5 (a configuration tailored specifically for the demo project, not the model used in this ChatGPT evaluation). While developers can switch to other compatible models or local LLMs, the project itself does not feature a default offline-only architecture; smooth local inference depends critically on whether the connected model stably and reliably outputs compliant component protocols. Supporting alternative models does not guarantee identical experiences across arbitrary local LLMs.
  • External data services and experience boundaries: In the demo, image search relies on Gateway tools with Wikipedia fallbacks; map route geometry comes from public OSRM driving profiles, representing an overview of road trajectories rather than pedestrian or transit navigation, which requires separate routing. Detached from these peripheral data services, invoking a large model locally cannot replicate the complete interactive experience.

Continuing the earlier observation that "the model cannot see local state," in this demo project, the component uses useStateField to store records of added and removed sights in the response state, preserved alongside the message; backend /api/chat uses describeRouteEdits to transcribe these edits into prompt text passed into the next model turn. Selected sights (routeSelected) are also stored in interface state, but this transformation function does not read them, so they are not written into the text provided to the model.

Image data flows also diverge: in OpenUI, the Gateway performs the search, the model receives results, and populates URLs into component properties; in ChatGPT's observed AsyncImage path, the server executes retrieval and injects results directly into appData. Similar interaction experiences do not imply this project reuses OpenAI's DIL compiler, Worker sandbox, or identical data flows.

From model generation to user interaction, Intelligent UI fundamentally links together models that describe needs, compilers that validate structures, clients that respond to input, and reliable data sources, turning what was once a one-way typewriter stream into a directly actionable tool. While open-source ecosystems can replicate comparable interactions, this does not equate to possessing the entire mature system through reverse engineering; Thesys's claim of byte-level compiler output parity applies only to specifically captured test samples, rather than a full reproduction of internal systems. Untangling the responsibilities and boundaries of each layer serves as the pragmatic starting point for understanding and deploying generative interfaces.

Source
We reverse engineered ChatGPT Intelligent UI. Here's how it actually worksRabi Shanker Guha / Thesys·Read the source
Editorial note
Implementation details are based on Thesys's reverse-engineering observations of the web client; mobile implementations have not been directly verified.
↑ End of article
✓ This article is free to read in full

Members can copy or download the full Markdown, and let their AI subscribe and ask.

Read the original ↗
📮 New explainers, straight to your inbox

Found this useful? Leave your email — every new explainer, the moment it's out. Unsubscribe anytime.