Composer generative UI
Composer can interleave ordinary Markdown with validated, interactive Mantis components. The feature keeps the existing Headmaster WebSocket and history format: a completed UI specification is stored inside assistant text, while a trusted per-message protocol marker records whether that response negotiated v1 and whether it was authored under Ask’s read-only policy. Replay never reinterprets old content from the currently selected Composer mode.
This is an independent Mantis implementation. It does not include Morphic source, @json-render, an RFC 6902 patch evaluator, arbitrary generated React, or an Apache web server.
Protocol
Compatible clients advertise inline_ui_version=1 on the Composer WebSocket URL. The backend emits UI only for that exact capability and only in Orchestrator or Ask mode. Visual Tour keeps its existing whole-message JSON contract.
Each inline view is one complete object in its own mantis-ui fence:
The strongest cluster contains the most representative records.
```mantis-ui
{"version":1,"id":"cluster-summary","root":{"id":"summary","type":"entity-card","title":"Memory systems","description":"The densest result cluster.","target":{"uri":"mantis://map/map-id/cluster/cluster-id"},"attributes":[{"label":"Points","value":"128"}],"actions":[{"id":"summarize","type":"summarize","label":"Summarize","target":{"uri":"mantis://map/map-id/cluster/cluster-id"}}]}}
```
The neighboring cluster is more diverse.The client converts the response to AI SDK 7 UIMessage parts in source order:
textfor Markdown and citations;data-mantis-uifor a validated v1 view;data-mantis-ui-errorfor a safe, non-actionable fallback.data-mantis-attachmentfor trusted upload events.
Trusted Headmaster reasoning and tool events are normalized to AI SDK 7 reasoning and dynamic-tool parts in the existing ordered timeline. The specialized Mantis renderers remain responsible for domain-specific output. Tool parts visibly distinguish pending, running, awaiting approval, approval recorded, completed, failed, and denied states. Explicit tool_call_id correlation wins over the legacy sequence fallback.
Closed component catalog
Model-authored views can use only:
stackandgrid;headingandcallout;metric-group;entity-cardandcitation-list;data-table;task-cardin the explicitly non-executingsuggestedstate;media-gallerywith authenticatedagent_files/...keys;artifact;action-row.
The model cannot provide HTML, CSS, class names, JavaScript, event names, network requests, iframe/embed nodes, or arbitrary image/file URLs. Tool lifecycle state continues to come from trusted Headmaster events rather than assistant-authored UI. Markdown fields inside a structured node use a restricted renderer that omits external links and images and disables Mermaid; authenticated media-gallery keys are the only model-authored media path. Image previews are viewport-lazy, limited to supported image MIME types and 12 MiB, and use a bounded authenticated-user-scoped object-URL cache that is revoked when the account changes. Distinct media fetches are limited to four concurrent requests; non-image downloads stream through a 64 MiB ceiling instead of buffering an unbounded response.
Dense artifact payloads open in a keyed, responsive FlexLayout panel on the right side of the existing Mantis workspace. Artifact payloads are kept in a bounded in-memory store, and artifact panels are excluded from persisted layout state and panel-visibility storage so a reload cannot restore an orphaned panel. When the payload cap is reached, the matching oldest artifact tab is closed before its payload is evicted.
Actions
The action registry exposes narrow callbacks for:
navigateandsummarizeusing a canonical point, bag, or clustermantis://URI;add-to-bagusing canonical point URIs;run-task;prefill-composer;submit-followup.
add-to-bag, run-task, and submit-followup require a second confirmation click, are disabled during streaming, and execute at most once per rendered message. Bag actions may specify a bag ID or bag name, never both; an explicit destination must already exist and is never auto-created. When no destination is specified, Mantis uses the active mutable bag or creates a confirmed Composer selection bag. Task actions report successful delivery and wait for trusted task events rather than claiming that work completed. Generated task actions dispatch with the reserved task ID 0; older protocol-v1 positive IDs are accepted for replay but normalized to 0. Only the trusted legacy todo UI may carry a persisted task ID, so generated content cannot complete an unrelated sidebar task. No action accepts a URL or executable payload. Ask mode is enforced as read-only by both the backend action catalog and the frontend handler registry: only navigation, summarization, and Composer prefill actions are available.
Limits and fallback
Every object is parsed as JSON and then checked by a strict Zod schema before React sees it. V1 enforces:
- 4 views per message;
- 16 KiB per view;
- 32 nodes per view;
- depth 6 and fan-out 8;
- 8 metrics;
- 8 table columns and 25 inline rows;
- 20 citations;
- 8 authenticated media items across the complete assistant message;
- 4 actions;
- 32 point references for a bag action;
- unique, non-reserved node IDs plus unique action, item, and row IDs.
Unknown versions, invalid envelopes, unsafe root components, or oversized content render an accessible text fallback. Inside an otherwise-valid stack or grid, an invalid child is replaced by a small inert warning so its unsafe data and actions are discarded without hiding valid sibling headings, metrics, tables, or media. An incomplete streaming fence remains non-interactive until its closing delimiter arrives, and fails closed as soon as it exceeds the byte limit. User-authored fences are always plain text.
Set NEXT_PUBLIC_COMPOSER_GENERATIVE_UI=false to remove the client capability and restore legacy Markdown-only behavior.
Persistence, copy, and model context
The original assistant content remains the source of truth for persistence and audit. The UI fence is removed only from:
- copied text projections;
- follow-up suggestion prompts;
- resumed model-context preambles.
Visible prose and existing citation markup are preserved. This prevents old UI payloads from consuming context while keeping chat replay deterministic. Citation numbering remains continuous across interleaved text and UI parts, and the canvas receives one aggregate citation set per message. Live text is frozen at tool/todo boundaries, and persisted reasoning/tool events are rehydrated with exact reasoning_id, tool_call_id, and sequence correlation, so text/tool/text order survives reconnects and history replay.
Adding a component
A new model-authored component must be added in all four places:
- Define its TypeScript shape and strict, bounded Zod object in
generative-ui/schema.ts. - Add it to the closed
ComposerNodeunion and renderer switch. - Document its exact JSON shape in the backend inline-UI prompt.
- Add acceptance, rejection, streaming, dark-mode, keyboard, and fallback tests appropriate to the component.
Component props must be data only. Actions must use the existing action union and narrow handler registry. Do not add raw URLs, HTML, styles, callbacks, component names, or executable strings. If a new action changes state, it must have a client-derived confirmation description and an authenticated, outcome-bearing execution path.