Repository navigation
feat(app): open agent-referenced files as rich artifact tabs - #49882
Merged
Merged
Conversation
Hona
force-pushed
the
artifact-viewer
branch
from
September 19, 2026 03:19
b5a86ae to
8abcfa7
Compare
Hona
enabled auto-merge (squash)
September 21, 2026 02:34
Hona
disabled auto-merge
September 21, 2026 04:53
Hona
enabled auto-merge (squash)
September 21, 2026 04:53
Hona
disabled auto-merge
September 21, 2026 04:53
Hona
enabled auto-merge (squash)
September 21, 2026 04:53
Hona
disabled auto-merge
September 21, 2026 04:53
Markdown links and inline paths in the timeline open the referenced workspace file in the side panel. The file tab now renders images, SVG, audio, video, PDF, sandboxed HTML previews, and rendered Markdown with a Preview/Source toggle instead of decoding every file as text. On a local desktop server, HTML can open in the browser pane through file://, which the pane now permits only for loopback endpoints.
…rowser.preview Dedicated viewers replace the media fallback: images fit the pane with click-to-1:1, video fills the width, audio gets a card, SVG and other documents share the Preview/Source toggle, and the toolbar reports dimensions, duration, and size. CSV/TSV render as tables, fonts as a specimen, and Mermaid sources as diagrams. The browser plugin gains browser.preview so an agent can open a file in the user's Review pane and focus its tab; the desktop forwards it to the renderer's artifact opener.
Absolute paths that are not under the workspace root stay absolute through tab normalization and are read from their own directory, so a link or browser.preview to /tmp or C:\\tmp output opens in the viewer instead of handing off to the OS.
…iew toggle to its labels optimizeDeps.exclude keeps the markdown worker's dependencies unbundled, but Vite applies it to imports inside pre-bundled packages too, so mermaid's chunk kept a bare import of marked that the browser could not resolve from packages/app. A rolldown plugin resolves those ids for node_modules importers so the pre-bundle carries its own copy.
- Confine browser-pane file:// URLs to the session workspace and only for the desktop's own sidecar; a forwarded loopback server no longer counts. - Load before opening a tab so guessed inline paths that miss leave no tab. - Strip :line[:col] suffixes; resolve links that climb past the root from the referencing folder, not the workspace root. - Keep drive-root directories valid when reading absolute Windows paths. - Cap media at 25 MB and fall back to the binary placeholder when the browser cannot decode an image, video, or audio file. - Pad CSV headers to the widest row.
SessionFileView now owns only the code view and asks one question: is this a text file. Everything else (kind dispatch, Preview/Source, decode fallback, toolbar meta) lives in ArtifactView with a three-prop interface and no knowledge of tabs, scroll sync, or comments. The sub-viewers are module-private. The opener reuses createOpenSessionFileTab instead of a copy, and the PDF frame opens with the thumbnail pane closed.
…markdown links - Sub-frame file: navigations and file: subresources in the browser pane now honor the workspace roots; only HTTP sub-frames keep Chromium's default rules. - A root-level markdown preview resolved relative links against '/' because getDirectory yields '/' for a bare filename. - Drop the unused toast import, the single-use fileUrl export, and the repeated checksum; the parent passes its cacheKey down.
Hona
force-pushed
the
artifact-viewer
branch
from
September 21, 2026 04:57
fe886fa to
08dc51e
Compare
Hona
enabled auto-merge (squash)
September 21, 2026 04:57
Hona
disabled auto-merge
September 21, 2026 05:20
This was referenced Sep 21, 2026
jinhuang712
pushed a commit
to jinhuang712/opencode
that referenced
this pull request
Sep 26, 2026
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.
Agents drop files everywhere: screenshots, recordings, reports, generated pages, CSV dumps. Referencing one in a reply used to be a dead end.
file://links were stripped by DOMPurify and blocked by Electron, relative links tried to navigate the renderer, and the file tab decoded every byte as text.Now a reference in the timeline opens the file in the side panel, the tab renders whatever it is, and the agent can do the same on its own with
browser.preview.flowchart LR A["markdown link · `inline/path`"] --> R T["agent: browser.preview({ path })"] --> R R{inside workspace?} R -- no --> N["absolute path · read from its own folder"] --> D R -- yes --> D{kind} D -- html, local desktop<br/>with browser pane --> E["browser tab: file://"] D -- anything else --> F["file tab viewer + Preview / Source"]Viewers
w × h · sizew × h · sizeduration · sizew × h · duration · sizesize<iframe>, Preview / Source, Open in browser on a local desktop serversizesize.mmdsizerows · columns · sizettf otf woff woff2FontFacesizesizeBefore / after
Everything else
`inline/path`C:/tmp/…)Agent tool
Discoverable through
search(): the description carries the words agents use (show, display, view, artifact, media, screenshot, image, video, pdf, csv, font, …) and a test pins each phrase.browser.navigate/tabs.openwith afile://URL fail with a message that points here.The desktop answers immediately and reports
{ type: "preview", path }on the pane attachment; the renderer resolves the path against the session workspace and applies the same rules as a clicked link. Older desktops answerunsupportedthrough the existing version handshake.How it fits together
packages/session-ui: the DOMPurify hook keeps local hrefs asdata-local-link(same pattern asdata-local-image), andMarkdownroutes clicks on those anchors and on`path`inline code to a new optionalopenLocalFileonMarkdownProvider.packages/app/src/workspaces/files/artifact.ts: extension → kind/mime,fileContentFromBytes(media stays base64 with a mime type, NUL-sniffed unknown binaries keep only their size),resolveArtifactPathfor../,parseDelimited,contentBytes.packages/app/src/session/files/open-artifact.tsx:ArtifactOpenerProviderresolves a link against the workspace root or the referencing file's directory, keeps files outside the root absolute so they still open in a tab, picks a browser tab or a file tab, and subscribes tobrowser.previewrequests.packages/app/src/session/files/artifact-view.tsx: the viewers and the toolbar.packages/desktop/src/main/browser/policy.ts: the browser pane acceptsfile://only when the server endpoint is loopback, since that agent already has the machine's disk. Popups and the agent-facingbrowser.navigatetool stay HTTP only.Notes
file://page instead.browser.previewneed the desktop app with the experimental browser pane; link clicks fall back to the in-app viewer everywhere else.