Repository navigation
Description
Feature hasn't been suggested before.
- I have verified this feature I'm about to request hasn't been suggested before.
Describe the enhancement you want to request
Let a plugin supply an interactive HTML/JS artifact and have the Desktop app render it inline in the conversation, the way the Codex app renders "Visualizations" in the chat.
What I want to build. A local plugin that renders charts. It produces a self-contained HTML file (Chart.js, no network, no server) and returns it as a tool result. Today the chat cannot show it:
- The chat renders assistant markdown through DOMPurify with
USE_PROFILES: {html, mathMl}. The html profile has 119 tags and includes neitheriframenorscript, andFORBID_CONTENTSis["style","script"]. So a chart in a message is stripped. - Tool-result file parts are not rendered in the chat bubble at all. The bubble renders only
text,reasoningandtoolparts. - The only place an
.htmlfile is rendered live is the Files-panel artifact viewer: a blob-URL<iframe sandbox="allow-scripts allow-popups allow-forms allow-modals">with noallow-same-origin. That primitive already exists in 2.1.2 — it is just not reachable from the conversation.
What I am asking for. A way for a tool to attach an HTML artifact that the app renders inline in the message, sandboxed the same way the Files viewer sandboxes it, with the app owning the frame. The agent writes the HTML; the app renders it.
Why it matters. Right now the only interactive-chart path for an agent is "write a file, tell the user to open it". A chart is a natural chat citizen — comparing two runs, a regression over folds, a score by tier — and the user has to leave the conversation to look at it. Codex already does this in its chat, so the gap is visible.
Related, not duplicates. #25076 and #20034 asked for roughly this and were closed as stale without a maintainer reply; #40583 was closed the same way. PR #54747 (generative UI) is a different trade-off: it renders OpenCode's own component set, so it cannot show agent-authored HTML or JS, and it is merged only to beta — it is in no published release. #57619 is about extension distribution for side panels, not the chat timeline. #41361 and #48585 are adjacent.
Environment. OpenCode v2.1.2 (Desktop 2.1.2), Windows 11. No plugins other than the one described here.
What I have already checked. I read the 2.1.2 renderer bundle: the html profile tag list, the DOMPurify config, the tool-card registry (14 hard-coded entries, no plugin hook), and the Files-panel viewer. The Desktop app sets no Content-Security-Policy on its oc:// document, so a blob-URL frame is not CSP-blocked there; the web UI's own CSP has no frame-src, which is a separate, already-tracked gap (#50828).
Workaround today. Return a PNG for inline display and a local link for the interactive version. That is what my plugin does, and it is why I am asking: the interactive half is unreachable from the chat.
Activity
opencode-agent commentedon Oct 21, 2026
Thanks for the detailed request, @teodor-georgiev. You're asking for a way for a plugin's tool to attach a self-contained HTML/JS artifact, such as an interactive chart, and have the Desktop app render it inline in the conversation. It would be sandboxed the same way the Files-panel artifact viewer already sandboxes
.htmlfiles, with the app owning the frame.As you found, a plugin can't do this today. Plugins have no hook into the chat renderer: tool cards are hard-coded, and file parts in tool results aren't shown in the message bubble. So this needs a change in the app itself, for example a tool-result HTML part that the session UI renders in the existing sandboxed iframe. Maintainers will consider it.
Related issues, most relevant first:
Dante-dan commentedon Oct 22, 2026
A bounded first step could use the existing tool-result file content rather than a plugin-supplied renderer:
Tool.Contentalready carriesuri,mime, andname. Add an explicit inline-artifact presentation marker for self-containedtext/htmlresults, preserving the ordinary text/file fallback. The currentcurrentToolOutputextracts only text before passing it to the tool display; that is a concrete place where the artifact gets lost from presentation.ArtifactFrame, with blob cleanup and a bounded inline viewport. Keep the markdown sanitizer unchanged. The current viewer permits scripts, popups, forms, and modals withoutallow-same-origin; for inline charts I would start with onlyallow-scripts, no host callbacks, and no arbitrary remote URLs.This would cover local-plugin charts without adding MCP Apps callbacks or an arbitrary UI plugin API. The engine contract discussed in #10884 should inform the presentation marker so the two paths can share a renderer later.
Could a maintainer approve this direction, or indicate whether inline HTML should instead wait for the MCP Apps host design?