fix(components): render blob images inline in tool call resource blocks - #506
fix(components): render blob images inline in tool call resource blocks#506clanzhang wants to merge 3 commits into
Conversation
When an ACP tool returns a resource content block with binary blob data (e.g., an image the agent read), the renderer now displays it inline instead of showing a "Download blob" link that navigates to raw base64. The fix checks for blob resources with image/* mimeType and renders them using buildSafeBase64DataUrl(), matching the pattern used for the image content type. Non-image blobs still fall through to the download link. Fixes LodyAI#462
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9d9e3adcac
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
`StandardToolContentBlock` only handled text resources. Blob resources with `image/*` mimeType fell through to a download link that exposed raw base64. Now renders inline `<img>` via `buildSafeBase64DataUrl()`, falling through to the download link when the image cannot be inlined.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f3c3e88c5a
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| ) { | ||
| const src = buildSafeBase64DataUrl(content.resource.mimeType, content.resource.blob); | ||
| if (src) { | ||
| <div className="space-y-2"> |
There was a problem hiding this comment.
Return the inline resource image
When a resource contains a valid image/* blob, this JSX element is merely evaluated and discarded because the branch does not return it. Execution therefore always continues to the URI fallback; typical file: resource URIs are rejected and render nothing, while HTTP(S) URIs still render a download link, so the newly added image path never displays the image.
Useful? React with 👍 / 👎.
wibus-wee
left a comment
There was a problem hiding this comment.
I traced the actual Kimi path. Lody pins acp-extension-kimi@38fb45e, where structured tool results are serialized into ACP text via JSON.stringify(...), not emitted as resource.blob.
So this blob renderer doesn't address the actual base64 path. Also, the new if (src) branch is missing a return, so it currently renders nothing anyway.
I think the better fix is in acp-extension-kimi: normalize Kimi's media result into standard ACP image/resource content, then let the existing UI renderer handle it.
|
@clanzhang, this pull request needs updates before review. It is marked If the PR remains invalid for 7 days, it will be closed and marked Policy findings |
Related issue
Closes #462
Problem / pressure
When an ACP agent reads an image (e.g. Kimi's "reading media" tool), the tool returns a
resourcecontent block with binaryblobdata and animage/*mimeType. TheStandardToolContentBlockcomponent inview.tsxonly checks fortextin the resource — it falls through to rendering a "Download blob" link usingcontent.resource.urias the href. The URI is the resource's original identifier (e.g.file:///path/to/image.png), not a downloadable URL, so clicking it exposes the raw base64 string to the user instead of rendering the image.Summary
Add a
blobbranch to theresourcecase inStandardToolContentBlock. When the resource contains ablobwith animage/*mimeType, construct a data URL via the existingbuildSafeBase64DataUrl()helper and render an inline<img>tag, matching the pattern already used by theimagecontent type case. Non-image blobs fall through to the existing download link.Before / after
resourcewithblob+image/*mimeType → "Download blob" link → raw base64 displayed to userresourcewithblob+image/*mimeType → inline<img>renders the imageTest plan
pnpm --dir packages/components testif availableContext handoff
Instructions for reviewing agents
packages/components/src/components/ai-gui/view.tsx— theresourcecase inStandardToolContentBlock(around line 6121). Verify the newblobbranch correctly reusesbuildSafeBase64DataUrl()and theimage/*mimeType guard.content.resourcehavingblobandmimeTypefields from the ACP SDKEmbeddedResourcetype. If a specific agent sends blob data under a different key (e.g.datainstead ofblob), it would not be caught. ThebuildSafeBase64DataUrlhelper validates both fields so malformed data renders nothing rather than breaking.Authoring context
StandardToolContentBlock. Do not change the ACP protocol, CLI-side materialization, or other content block types.buildSafeBase64DataUrlhelper already validates mimeType format and base64 alphabet, so no new sanitization was added. The data URL is consumed only by an<img>tag'ssrcattribute.imagecase at line 6067-6081. Moderate uncertainty on whether all agents useblobas the key name — the ACP SDKEmbeddedResourcetype distinguishesTextResourceContents(withtext) fromBlobResourceContents(withblob), so this matches the protocol contract.