JIT Rendering

When a widget needs custom logic, the assistant writes sandboxed code that streams results into the UI.

Some interfaces need computation the A2UI vocabulary can't express — a custom calculation, a live-updating value, a transformation of fetched data. For those, MeghaOS uses Just-in-Time (JIT) code: the LLM writes Python, the agent runs it in a sandbox, and the result is bound into the rendered UI.

How it works

compose_ui returns A2UI JSON. When custom logic is required, the LLM embeds a __jit__ key holding Python code inside the same response — no separate code-generation call.

The sandbox

the sandbox runs generated code with a restricted sandbox as the primary path — in-process, blocking filesystem and network access at the AST level. A subprocess + sandbox-exec fallback handles code that needs numpy/pandas.

Key behaviors:

  • Compile cache keyed on an MD5 of the code — repeated code skips compile_restricted.
  • Exec-namespace injectionexecute(code, params=None) injects parameters as plain variables in the exec namespace. Legacy {param} string templates are auto-detected for backward compatibility.
  • Output is collected via a restricted sandbox's the output collector and retrieved after exec.

Allowed imports

Generated code may only import a small, vetted allowlist — enough for real computation, but no filesystem or process access:

text
json · math · datetime · re · httpx · requests · urllib ·
random · time · pandas · numpy

Anything outside this set is rejected, which is what keeps in-process execution safe. (Code that needs pandas/numpy may take the subprocess + sandbox-exec path.)

Note

This is the opposite of the code_sandbox plugin's RUN_PYTHON, which runs unrestricted on the host. JIT is the locked-down path used for UI logic; RUN_PYTHON is the deliberate, trusted escape hatch.

Note

A subtle bug once silently disabled Tier-1 JIT: a restricted sandbox 7.x removed safe_iter, which the old code imported. The fix removed safe_iter and uses the output collector class as _print_, retrieving output via glb['_print'] after exec(bc, glb).

Binding output to the UI

A UI component can declare "jit_bind": "key". After the code runs and returns a dict, the value at that key is bound into the component deterministically — no guessing which output maps to which widget.

json
{ "type": "animated_value", "jit_bind": "total", "prefix": "$" }

Streaming (live widgets)

For widgets that update continuously, the streaming engine runs a loop that re-executes the code on an interval and pushes updates to the shell:

  • Drift-free timertick_start = time.monotonic; each cycle sleeps max(0, interval - elapsed) so ticks don't drift.
  • JSON diffingjsonpatch.make_patch computes the delta each tick and sends only a patch field, minimizing payload size.
  • Updates are broadcast straight to the shell via the Unix socket (no ZeroMQ).
  • Max 10 concurrent streams, guarded in start_stream.

A streaming app is auto-detected when its code references the injected elapsed_time value (seconds since the stream started), letting the code animate or recompute against a live clock each tick.

Reactive actions

When the user interacts with a JIT widget (e.g. changes a parameter), handle_jit_action performs reactive binding: it re-substitutes dynamic values into the original initial_ui template via _substitute_dynamic_valueszero additional LLM calls. Fast, deterministic, cheap.

Semantic code cache

Generated code is cached semantically in a vector database (JITCodeCache in ). store_code / find_code(threshold=0.90) use text embeddings so a similar query reuses prior code instead of regenerating — replacing the old exact-match dictionary cache.

Relevant files

FileRole
Session bookkeeping for JIT widgets
Streaming loop, diffing, fallback UI builder
Parameter handling
_execute_jit_code, compose_ui, handle_jit_action