Repository navigation
Conversation
Assistants can draw charts, diagrams and small interactive figures inside their replies. The model writes a self-contained HTML page in a `:::visual{title}` container around an html fence; the client shows it inline in a sandboxed frame served from `/api/visuals/frame` with its own CSP (opaque origin, scripts only inline or from configured CDNs, no other network), themed with the app's colors and sized to the page.
Admins turn it on or off with `interface.visuals` (default on) and set the CDN allowlist in `visuals.sources`. Users turn it on or off under Settings > Chat > Inline visuals (default on); the setting rides on every agents request, and the server adds the visuals instructions for the answering agent when both allow it. Artifacts are unchanged; a visual can open in the artifacts panel.
usnavy13
marked this pull request as ready for review
October 8, 2026 21:43
…-conversation-visualizations
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Pull Request
Summary
The major assistants now answer with visuals, not just text. OpenAI launched Intelligent UI with GPT-6 on October 7: ChatGPT replies can now include charts, graphics, buttons, forms and interactive elements that appear as the model writes (OpenAI's announcement post). Anthropic shipped custom visuals in chat in March, where Claude writes HTML charts and diagrams inline and decides when to use them. Google has generative UI in the Gemini app, where Gemini 3 outputs HTML, CSS and JS for a custom interactive response. All three ship only in their own consumer apps, with no API for them, so LibreChat users have had no way to get this.
LibreChat today can draw Mermaid diagrams inline and can show HTML or React in the Artifacts side panel, but a model has no way to put a chart, a calculator or a small interactive explanation directly in its answer. Users have asked for this for a while: inline Plotly/Recharts charts (#5871), graphs without the paid Code Interpreter (#6576), an agent-level chart toggle (#8214), Vega-Lite charts in replies (#12993), and Plotly output inline (#4366). The move of Mermaid from the artifact panel into the conversation (#7848) showed the same preference for visuals in place.
This PR adds inline visuals. When the setting is on, the model is told it may write a self-contained HTML page inside a
:::visual{title="…"}container around an html fence. The page renders inline in the reply, in a sandboxed frame themed with the app's colors and sized to its content. That covers charts, diagrams, timelines, comparisons, calculators, quizzes and small games, with or without web search. It uses the approach Claude and Gemini use, model-written HTML, rather than OpenAI's fixed component library, so a model can draw anything a page can and nothing ties it to one provider. The frame bootstrap is adapted from T3 Code's HTML renders (pingdotgg/t3code#15968, MIT), and the frame speaks the MCP Apps message names.Admins control it with
interface.visuals(default on, overridable per role like other interface settings). Each user controls it under Settings > Chat > Inline visuals (default on, saved in the browser like Maximize chat space); it applies to every chat, including saved agents. When the setting is off the model is not asked for visuals; when the admin turns visuals off, existing visuals show a short notice instead of rendering. Artifacts are unchanged and can be used at the same time; the instructions tell the model to use a visual for a figure inside an answer and an artifact for something the user will keep or edit. Any visual can open in the artifacts panel with its source.Related to #5871, #6576, #8214, #12993, #4366. Partly addresses #13373 (interactive outputs, without the model callback). Adjacent to #10641 (MCP Apps), whose sandbox model this shares.
How it works
The visual travels as text in the reply, so it needs no new content part, tool call or storage. The client renders it in a frame served by the app with its own CSP, because a
srcdocframe would inherit the app's nonce CSP and block the page's scripts.sequenceDiagram participant Settings as Settings (user) participant Client participant API as packages/api participant Model participant Frame as /api/visuals/frame Settings->>Client: Inline visuals on Client->>API: POST agents chat, visuals: true API->>Model: system prompt + visuals instructions (if interface.visuals allows) Model->>Client: streams text with :::visual{title} + html fence Client->>Client: "Building visual…" until the container closes Client->>Frame: load shell (sandbox, own CSP) Frame->>Client: ui/notifications/sandbox-proxy-ready Client->>Frame: sandbox-resource-ready { html + theme bootstrap } Frame->>Client: ui/notifications/size-changed { height }Security: the frame has an opaque origin (
sandbox allow-scripts, noallow-same-origin), so a page cannot read the app's cookies, storage or DOM. Its CSP allows scripts only inline and fromvisuals.sources(jsDelivr, cdnjs, unpkg and esm.sh by default), blocks every other request including the app's own API, blocks form posts, and uses the app'sCSP_FRAME_ANCESTORS. Links open in a new tab only on a live user gesture.Type of change
Testing
interface.visualsunset (on).visuals: false.interface.visuals: false; the setting disappears and existing visuals show "Visuals are turned off for this app."Tested environments/configuration:
Automated tests:
packages/api:src/visuals/frame.spec.ts,src/visuals/prompt.spec.ts, visuals cases insrc/agents/__tests__/initialize.test.ts,src/app/interface.spec.tspackages/data-provider:specs/visuals.spec.ts;packages/data-schemas:loadVisualsConfiginsrc/app/service.spec.tsclient:src/components/Visuals/__tests__/(plugin, bootstrap, theme, frame handshake and sizing, Visual states), the settings registry, rich-text copy and the block splittere2e/specs/mock/visuals.spec.ts: renders a visual in the real frame (script runs, parent and storage isolated, theme applied, fetch blocked, frame fits the page), opens it in the panel, and checks the request flag with the setting on and offnpx tsc --noEmitin data-provider, data-schemas, api and client;npm run static-checks -- --against origin/devScreenshots / recordings
A new surface, so there is no "before". All shots use the ClickHouse theme in dark mode.
Settings > Chat > Messages:
Claude, Monty Hall you can play (after picking a door), 1920×1080:
Claude, interactive compound interest calculator, 1440×900:
Risk / compatibility
visuals: true, which adds about 750 tokens of instructions and lets models answer with visuals. Admins who want the old behavior setinterface.visuals: false; users can turn it off in Settings.interface.visuals(boolean) and avisuals.sourcessection (https origins,librechat.yamlonly, likemcpAppSandbox). An invalid source list allows no origins rather than the defaults.GET /api/visuals/frameis unauthenticated because it serves an empty shell; it carries no user data.visualsboolean. Older clients do not send it, so they get no visuals instructions. Assistants endpoints are not supported.visuals.sources: []removes the CDN path.