fix(web): render assistant images inline in chat - #9126

Merged
t3dotgg merged 3 commits into
mainfrom
fix/assistant-inline-images
Sep 3, 2026
Merged

fix(web): render assistant images inline in chat#9126
t3dotgg merged 3 commits into
mainfrom
fix/assistant-inline-images

Conversation

@t3dotgg

@t3dotggt3dotgg commented Sep 1, 2026

Copy link
Copy Markdown
Member

Problem

When an agent viewed or produced an image, the chat timeline hid it twice. The tool row folded under the "Worked for ..." summary once the turn settled, and even unfolded, the image only appeared after the user clicked the row open. The agent thought it had shown a screenshot; the user saw nothing.

What changed

Rows that preview an image now render on their own. They stay out of tool groups, stay out of the settled-turn fold, and show the image without an expand click. This reuses the existing signed asset route, so no image bytes travel over the websocket.

The change is in apps/web, which desktop wraps. Mobile has a parallel work-log row and still gates its image behind expand; that is a separate fix.

Markdown images with local paths

Absolute paths and file:// URIs already resolve through the signed asset route after #9023, which introduced the media-file resource. The reporter tested a build from before that merge. I added a POSIX regression test for ![x](/tmp/embed-test/2.png) and ![x](file:///tmp/embed-test/5.png) because the existing coverage only exercised Windows path forms.

Still unsupported: data URIs

data: images in Markdown and in HTML <img> stay unsupported on purpose. Large base64 in a message is a performance problem twice over: it inflates every websocket frame that carries the message, and it inflates the DOM node that renders it. Agents should write the file and reference its path instead.

Provider coverage

Claude and the ACP providers (Cursor, Grok) are the only ones that put real image data on the wire. T3 Code does not carry those bytes through. It carries the file path and re-reads the file through the signed asset route, which is why this fix is a rendering change and not a contract change. Codex view_image and OpenCode only emit a label, no pixels, so path-based rendering is all they could ever support.

Tests

  • apps/web/src/components/chat/MessagesTimeline.logic.test.ts covers the row placement: the command row folds, the image row stays visible and does not collapse into a tool group.
  • apps/web/src/components/ChatMarkdown.workspace-images.test.tsx covers POSIX absolute and file:// sources resolving to a signed media-file asset.

vp test run on the touched files plus the neighboring work-log and markdown-image suites: 147 passed. Web typecheck and lint clean.

No before/after images. This was not run in a browser.

Refs #9094

Built by Claude Opus 5 in the Claude Code harness.


Note

Low Risk
UI-only timeline and markdown rendering changes with broad test coverage; no auth, API, or data contract changes.

Overview
Image-preview work rows (agent viewed/produced screenshots) now stay visible in the chat timeline instead of folding into “Worked for …” or hiding behind tool groups and expand clicks.

Timeline derivation adds workEntryRendersImagePreview (via workEntryViewedImagePath) and threads it through group visibility, settled-turn folds, live activity grouping, and standalone row emission so image rows behave like first-class answers. MessagesTimeline.tsx renders ChatMarkdownAssetImagebelow the row header without requiring expand; tool output text remains behind expand.

Adds regression tests for POSIX/file:// markdown images resolving to signed media-file assets, plus timeline tests that image rows survive folding and in-progress turns.

Reviewed by Cursor Bugbot for commit 54b2d49. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Render assistant images inline in chat timeline work rows

  • Adds workEntryRendersImagePreview predicate in MessagesTimeline.logic.ts to classify work entries with a viewed image path as image-preview rows.
  • Updates workEntryIsVisibleInGroup, deriveTurnFolds, and deriveMessagesTimelineRows so image-preview entries pass the group-visibility filter, are excluded from settled-turn folds, and are emitted as standalone rows rather than absorbed into active or adjacent tool groups.
  • Moves the viewed-image rendering in MessagesTimeline.tsx out of the expanded-detail container so it displays without expanding the row; expanding still controls the separate tool body.
  • Adds tests covering POSIX/file-URI asset loading in ChatMarkdown.workspace-images.test.tsx and image-preview visibility in MessagesTimeline.logic.test.ts.
  • Behavioral Change: work entries previously folded or grouped when neutral will now appear as visible image rows when they have a viewed image path.

Macroscope summarized 54b2d49.

@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:M 30-99 changed lines (additions + deletions). labels Sep 1, 2026
Comment threadapps/web/src/components/chat/MessagesTimeline.logic.ts
@github-actions

github-actionsBot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

ProviderMetricMain baselineThis PRImpactPR ceiling
CodexTotal thread wire13.6 KiB13.7 KiB+134 B (+1.0%)15.1 KiB
CodexThread snapshot wire7.0 KiB7.0 KiB+6 B (+0.1%)7.3 KiB
CodexLive turn WebSocket wire6.6 KiB6.7 KiB+128 B (+1.9%)7.8 KiB
CodexLive turn WebSocket decoded57.1 KiB58.5 KiB+1.4 KiB (+2.5%)66.4 KiB
CodexLive turn messages10100 (0.0%)21
ClaudeTotal thread wire13.5 KiB13.6 KiB+55 B (+0.4%)15.1 KiB
ClaudeThread snapshot wire7.0 KiB7.0 KiB−6 B (−0.1%)7.3 KiB
ClaudeLive turn WebSocket wire6.5 KiB6.6 KiB+61 B (+0.9%)7.8 KiB
ClaudeLive turn WebSocket decoded57.8 KiB57.9 KiB+88 B (+0.1%)66.4 KiB
ClaudeLive turn messages810+2 (+25.0%)21

Baseline: 4b26132 · PR result: 54b2d49 · Source CI: success

Scenario and decoded snapshot size

10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.

  • Codex decoded thread snapshot: 113.8 KiB
  • Claude decoded thread snapshot: 114.5 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

@macroscopeapp

macroscopeappBot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved at 1a1d3b1

Macroscope's review found this PR approvable — This is a contained web chat rendering fix that keeps existing image-preview entries visible and renders them through the existing signed asset loader. Production changes are limited to timeline grouping and row presentation, with regression tests added and no schema, security, billing, default, or deployment changes.

No code changes detected at 54b2d49. Prior analysis still applies.

You can add or adjust custom eligibility rules. Learn more.

@t3dotgg
t3dotggforce-pushed the fix/assistant-inline-images branch from bcfe6ea to 2ef0c74CompareSeptember 2, 2026 00:04

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 2ef0c74. Configure here.

Comment threadapps/web/src/components/chat/MessagesTimeline.logic.ts
@t3dotgg
t3dotggforce-pushed the fix/assistant-inline-images branch from 1a1d3b1 to 0cdfff6CompareSeptember 3, 2026 09:25
t3dotggand others added 3 commits September 3, 2026 02:26
An image the agent viewed or produced was hidden twice in the timeline.
The row folded under "Worked for ..." when the turn settled, and the image
itself only rendered after the user expanded the row.
Image preview rows now render on their own, outside tool groups and outside
the settled-turn fold, and the image shows without an expand click.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
While the turn was still working, a trailing image view was collected
into the live tool row, which renders only a label. The image appeared
only after the turn settled. Image preview rows now stop the active
collection the same way agent spawns and errors do.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Standalone image rows sit outside any expanded group, so the neutral
filter hid them while the tool was still in progress and left an empty
gap. Image preview rows now bypass that filter.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@t3dotgg
t3dotggforce-pushed the fix/assistant-inline-images branch from 0cdfff6 to 54b2d49CompareSeptember 3, 2026 09:27
@t3dotgg
t3dotgg merged commit 652515a into mainSep 3, 2026
27 checks passed
@t3dotgg
t3dotgg deleted the fix/assistant-inline-images branch September 3, 2026 09:33
github-actionsBot added a commit to omarcresp/t3code-flake that referenced this pull request Sep 3, 2026
## What's Changed
* fix(web): keep trailing tool groups out of "Worked for" accordion by @Yash-Singh1 in pingdotgg/t3code#9384
* feat(marketing): put named-developer quotes on the landing page by @t3dotgg in pingdotgg/t3code#9385
* fix(claude): expand slash commands when a message has attachments by @t3dotgg in pingdotgg/t3code#9122
* fix(web): stop the resting composer layout loop by @t3dotgg in pingdotgg/t3code#9393
* fix(web): render assistant images inline in chat by @t3dotgg in pingdotgg/t3code#9126
* feat(providers): add Google Antigravity via the official ACP agent by @t3dotgg in pingdotgg/t3code#9348
**Full Changelog**: pingdotgg/t3code@v0.0.39-nightly.20260903.1267...v0.0.39-nightly.20260903.1268
Upstream release: https://github.com/pingdotgg/t3code/releases/tag/v0.0.39-nightly.20260903.1268
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M30-99 changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@t3dotgg
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

fix(web): render assistant images inline in chat - #9126

Merged
t3dotgg merged 3 commits into
mainfrom
fix/assistant-inline-images
Sep 3, 2026
Merged

fix(web): render assistant images inline in chat#9126
t3dotgg merged 3 commits into
mainfrom
fix/assistant-inline-images

Conversation

@t3dotgg

@t3dotggt3dotgg commented Sep 1, 2026

Copy link
Copy Markdown
Member

Problem

When an agent viewed or produced an image, the chat timeline hid it twice. The tool row folded under the "Worked for ..." summary once the turn settled, and even unfolded, the image only appeared after the user clicked the row open. The agent thought it had shown a screenshot; the user saw nothing.

What changed

Rows that preview an image now render on their own. They stay out of tool groups, stay out of the settled-turn fold, and show the image without an expand click. This reuses the existing signed asset route, so no image bytes travel over the websocket.

The change is in apps/web, which desktop wraps. Mobile has a parallel work-log row and still gates its image behind expand; that is a separate fix.

Markdown images with local paths

Absolute paths and file:// URIs already resolve through the signed asset route after #9023, which introduced the media-file resource. The reporter tested a build from before that merge. I added a POSIX regression test for ![x](/tmp/embed-test/2.png) and ![x](file:///tmp/embed-test/5.png) because the existing coverage only exercised Windows path forms.

Still unsupported: data URIs

data: images in Markdown and in HTML <img> stay unsupported on purpose. Large base64 in a message is a performance problem twice over: it inflates every websocket frame that carries the message, and it inflates the DOM node that renders it. Agents should write the file and reference its path instead.

Provider coverage

Claude and the ACP providers (Cursor, Grok) are the only ones that put real image data on the wire. T3 Code does not carry those bytes through. It carries the file path and re-reads the file through the signed asset route, which is why this fix is a rendering change and not a contract change. Codex view_image and OpenCode only emit a label, no pixels, so path-based rendering is all they could ever support.

Tests

  • apps/web/src/components/chat/MessagesTimeline.logic.test.ts covers the row placement: the command row folds, the image row stays visible and does not collapse into a tool group.
  • apps/web/src/components/ChatMarkdown.workspace-images.test.tsx covers POSIX absolute and file:// sources resolving to a signed media-file asset.

vp test run on the touched files plus the neighboring work-log and markdown-image suites: 147 passed. Web typecheck and lint clean.

No before/after images. This was not run in a browser.

Refs #9094

Built by Claude Opus 5 in the Claude Code harness.


Note

Low Risk
UI-only timeline and markdown rendering changes with broad test coverage; no auth, API, or data contract changes.

Overview
Image-preview work rows (agent viewed/produced screenshots) now stay visible in the chat timeline instead of folding into “Worked for …” or hiding behind tool groups and expand clicks.

Timeline derivation adds workEntryRendersImagePreview (via workEntryViewedImagePath) and threads it through group visibility, settled-turn folds, live activity grouping, and standalone row emission so image rows behave like first-class answers. MessagesTimeline.tsx renders ChatMarkdownAssetImagebelow the row header without requiring expand; tool output text remains behind expand.

Adds regression tests for POSIX/file:// markdown images resolving to signed media-file assets, plus timeline tests that image rows survive folding and in-progress turns.

Reviewed by Cursor Bugbot for commit 54b2d49. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Render assistant images inline in chat timeline work rows

  • Adds workEntryRendersImagePreview predicate in MessagesTimeline.logic.ts to classify work entries with a viewed image path as image-preview rows.
  • Updates workEntryIsVisibleInGroup, deriveTurnFolds, and deriveMessagesTimelineRows so image-preview entries pass the group-visibility filter, are excluded from settled-turn folds, and are emitted as standalone rows rather than absorbed into active or adjacent tool groups.
  • Moves the viewed-image rendering in MessagesTimeline.tsx out of the expanded-detail container so it displays without expanding the row; expanding still controls the separate tool body.
  • Adds tests covering POSIX/file-URI asset loading in ChatMarkdown.workspace-images.test.tsx and image-preview visibility in MessagesTimeline.logic.test.ts.
  • Behavioral Change: work entries previously folded or grouped when neutral will now appear as visible image rows when they have a viewed image path.

Macroscope summarized 54b2d49.

@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:M 30-99 changed lines (additions + deletions). labels Sep 1, 2026
Comment threadapps/web/src/components/chat/MessagesTimeline.logic.ts
@github-actions

github-actionsBot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

ProviderMetricMain baselineThis PRImpactPR ceiling
CodexTotal thread wire13.6 KiB13.7 KiB+134 B (+1.0%)15.1 KiB
CodexThread snapshot wire7.0 KiB7.0 KiB+6 B (+0.1%)7.3 KiB
CodexLive turn WebSocket wire6.6 KiB6.7 KiB+128 B (+1.9%)7.8 KiB
CodexLive turn WebSocket decoded57.1 KiB58.5 KiB+1.4 KiB (+2.5%)66.4 KiB
CodexLive turn messages10100 (0.0%)21
ClaudeTotal thread wire13.5 KiB13.6 KiB+55 B (+0.4%)15.1 KiB
ClaudeThread snapshot wire7.0 KiB7.0 KiB−6 B (−0.1%)7.3 KiB
ClaudeLive turn WebSocket wire6.5 KiB6.6 KiB+61 B (+0.9%)7.8 KiB
ClaudeLive turn WebSocket decoded57.8 KiB57.9 KiB+88 B (+0.1%)66.4 KiB
ClaudeLive turn messages810+2 (+25.0%)21

Baseline: 4b26132 · PR result: 54b2d49 · Source CI: success

Scenario and decoded snapshot size

10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.

  • Codex decoded thread snapshot: 113.8 KiB
  • Claude decoded thread snapshot: 114.5 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

@macroscopeapp

macroscopeappBot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved at 1a1d3b1

Macroscope's review found this PR approvable — This is a contained web chat rendering fix that keeps existing image-preview entries visible and renders them through the existing signed asset loader. Production changes are limited to timeline grouping and row presentation, with regression tests added and no schema, security, billing, default, or deployment changes.

No code changes detected at 54b2d49. Prior analysis still applies.

You can add or adjust custom eligibility rules. Learn more.

@t3dotgg
t3dotggforce-pushed the fix/assistant-inline-images branch from bcfe6ea to 2ef0c74CompareSeptember 2, 2026 00:04

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 2ef0c74. Configure here.

Comment threadapps/web/src/components/chat/MessagesTimeline.logic.ts
@t3dotgg
t3dotggforce-pushed the fix/assistant-inline-images branch from 1a1d3b1 to 0cdfff6CompareSeptember 3, 2026 09:25
t3dotggand others added 3 commits September 3, 2026 02:26
An image the agent viewed or produced was hidden twice in the timeline.
The row folded under "Worked for ..." when the turn settled, and the image
itself only rendered after the user expanded the row.
Image preview rows now render on their own, outside tool groups and outside
the settled-turn fold, and the image shows without an expand click.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
While the turn was still working, a trailing image view was collected
into the live tool row, which renders only a label. The image appeared
only after the turn settled. Image preview rows now stop the active
collection the same way agent spawns and errors do.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Standalone image rows sit outside any expanded group, so the neutral
filter hid them while the tool was still in progress and left an empty
gap. Image preview rows now bypass that filter.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@t3dotgg
t3dotggforce-pushed the fix/assistant-inline-images branch from 0cdfff6 to 54b2d49CompareSeptember 3, 2026 09:27
@t3dotgg
t3dotgg merged commit 652515a into mainSep 3, 2026
27 checks passed
@t3dotgg
t3dotgg deleted the fix/assistant-inline-images branch September 3, 2026 09:33
github-actionsBot added a commit to omarcresp/t3code-flake that referenced this pull request Sep 3, 2026
## What's Changed
* fix(web): keep trailing tool groups out of "Worked for" accordion by @Yash-Singh1 in pingdotgg/t3code#9384
* feat(marketing): put named-developer quotes on the landing page by @t3dotgg in pingdotgg/t3code#9385
* fix(claude): expand slash commands when a message has attachments by @t3dotgg in pingdotgg/t3code#9122
* fix(web): stop the resting composer layout loop by @t3dotgg in pingdotgg/t3code#9393
* fix(web): render assistant images inline in chat by @t3dotgg in pingdotgg/t3code#9126
* feat(providers): add Google Antigravity via the official ACP agent by @t3dotgg in pingdotgg/t3code#9348
**Full Changelog**: pingdotgg/t3code@v0.0.39-nightly.20260903.1267...v0.0.39-nightly.20260903.1268
Upstream release: https://github.com/pingdotgg/t3code/releases/tag/v0.0.39-nightly.20260903.1268
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M30-99 changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@t3dotgg
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(web): render assistant images inline in chat - #9126

Merged
t3dotgg merged 3 commits into
mainfrom
fix/assistant-inline-images
Sep 3, 2026
Merged

fix(web): render assistant images inline in chat#9126
t3dotgg merged 3 commits into
mainfrom
fix/assistant-inline-images

Conversation

@t3dotgg

@t3dotggt3dotgg commented Sep 1, 2026

Copy link
Copy Markdown
Member

Problem

When an agent viewed or produced an image, the chat timeline hid it twice. The tool row folded under the "Worked for ..." summary once the turn settled, and even unfolded, the image only appeared after the user clicked the row open. The agent thought it had shown a screenshot; the user saw nothing.

What changed

Rows that preview an image now render on their own. They stay out of tool groups, stay out of the settled-turn fold, and show the image without an expand click. This reuses the existing signed asset route, so no image bytes travel over the websocket.

The change is in apps/web, which desktop wraps. Mobile has a parallel work-log row and still gates its image behind expand; that is a separate fix.

Markdown images with local paths

Absolute paths and file:// URIs already resolve through the signed asset route after #9023, which introduced the media-file resource. The reporter tested a build from before that merge. I added a POSIX regression test for ![x](/tmp/embed-test/2.png) and ![x](file:///tmp/embed-test/5.png) because the existing coverage only exercised Windows path forms.

Still unsupported: data URIs

data: images in Markdown and in HTML <img> stay unsupported on purpose. Large base64 in a message is a performance problem twice over: it inflates every websocket frame that carries the message, and it inflates the DOM node that renders it. Agents should write the file and reference its path instead.

Provider coverage

Claude and the ACP providers (Cursor, Grok) are the only ones that put real image data on the wire. T3 Code does not carry those bytes through. It carries the file path and re-reads the file through the signed asset route, which is why this fix is a rendering change and not a contract change. Codex view_image and OpenCode only emit a label, no pixels, so path-based rendering is all they could ever support.

Tests

  • apps/web/src/components/chat/MessagesTimeline.logic.test.ts covers the row placement: the command row folds, the image row stays visible and does not collapse into a tool group.
  • apps/web/src/components/ChatMarkdown.workspace-images.test.tsx covers POSIX absolute and file:// sources resolving to a signed media-file asset.

vp test run on the touched files plus the neighboring work-log and markdown-image suites: 147 passed. Web typecheck and lint clean.

No before/after images. This was not run in a browser.

Refs #9094

Built by Claude Opus 5 in the Claude Code harness.


Note

Low Risk
UI-only timeline and markdown rendering changes with broad test coverage; no auth, API, or data contract changes.

Overview
Image-preview work rows (agent viewed/produced screenshots) now stay visible in the chat timeline instead of folding into “Worked for …” or hiding behind tool groups and expand clicks.

Timeline derivation adds workEntryRendersImagePreview (via workEntryViewedImagePath) and threads it through group visibility, settled-turn folds, live activity grouping, and standalone row emission so image rows behave like first-class answers. MessagesTimeline.tsx renders ChatMarkdownAssetImagebelow the row header without requiring expand; tool output text remains behind expand.

Adds regression tests for POSIX/file:// markdown images resolving to signed media-file assets, plus timeline tests that image rows survive folding and in-progress turns.

Reviewed by Cursor Bugbot for commit 54b2d49. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Render assistant images inline in chat timeline work rows

  • Adds workEntryRendersImagePreview predicate in MessagesTimeline.logic.ts to classify work entries with a viewed image path as image-preview rows.
  • Updates workEntryIsVisibleInGroup, deriveTurnFolds, and deriveMessagesTimelineRows so image-preview entries pass the group-visibility filter, are excluded from settled-turn folds, and are emitted as standalone rows rather than absorbed into active or adjacent tool groups.
  • Moves the viewed-image rendering in MessagesTimeline.tsx out of the expanded-detail container so it displays without expanding the row; expanding still controls the separate tool body.
  • Adds tests covering POSIX/file-URI asset loading in ChatMarkdown.workspace-images.test.tsx and image-preview visibility in MessagesTimeline.logic.test.ts.
  • Behavioral Change: work entries previously folded or grouped when neutral will now appear as visible image rows when they have a viewed image path.

Macroscope summarized 54b2d49.

@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:M 30-99 changed lines (additions + deletions). labels Sep 1, 2026
Comment threadapps/web/src/components/chat/MessagesTimeline.logic.ts
@github-actions

github-actionsBot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

ProviderMetricMain baselineThis PRImpactPR ceiling
CodexTotal thread wire13.6 KiB13.7 KiB+134 B (+1.0%)15.1 KiB
CodexThread snapshot wire7.0 KiB7.0 KiB+6 B (+0.1%)7.3 KiB
CodexLive turn WebSocket wire6.6 KiB6.7 KiB+128 B (+1.9%)7.8 KiB
CodexLive turn WebSocket decoded57.1 KiB58.5 KiB+1.4 KiB (+2.5%)66.4 KiB
CodexLive turn messages10100 (0.0%)21
ClaudeTotal thread wire13.5 KiB13.6 KiB+55 B (+0.4%)15.1 KiB
ClaudeThread snapshot wire7.0 KiB7.0 KiB−6 B (−0.1%)7.3 KiB
ClaudeLive turn WebSocket wire6.5 KiB6.6 KiB+61 B (+0.9%)7.8 KiB
ClaudeLive turn WebSocket decoded57.8 KiB57.9 KiB+88 B (+0.1%)66.4 KiB
ClaudeLive turn messages810+2 (+25.0%)21

Baseline: 4b26132 · PR result: 54b2d49 · Source CI: success

Scenario and decoded snapshot size

10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.

  • Codex decoded thread snapshot: 113.8 KiB
  • Claude decoded thread snapshot: 114.5 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

@macroscopeapp

macroscopeappBot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved at 1a1d3b1

Macroscope's review found this PR approvable — This is a contained web chat rendering fix that keeps existing image-preview entries visible and renders them through the existing signed asset loader. Production changes are limited to timeline grouping and row presentation, with regression tests added and no schema, security, billing, default, or deployment changes.

No code changes detected at 54b2d49. Prior analysis still applies.

You can add or adjust custom eligibility rules. Learn more.

@t3dotgg
t3dotggforce-pushed the fix/assistant-inline-images branch from bcfe6ea to 2ef0c74CompareSeptember 2, 2026 00:04

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 2ef0c74. Configure here.

Comment threadapps/web/src/components/chat/MessagesTimeline.logic.ts
@t3dotgg
t3dotggforce-pushed the fix/assistant-inline-images branch from 1a1d3b1 to 0cdfff6CompareSeptember 3, 2026 09:25
t3dotggand others added 3 commits September 3, 2026 02:26
An image the agent viewed or produced was hidden twice in the timeline.
The row folded under "Worked for ..." when the turn settled, and the image
itself only rendered after the user expanded the row.
Image preview rows now render on their own, outside tool groups and outside
the settled-turn fold, and the image shows without an expand click.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
While the turn was still working, a trailing image view was collected
into the live tool row, which renders only a label. The image appeared
only after the turn settled. Image preview rows now stop the active
collection the same way agent spawns and errors do.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Standalone image rows sit outside any expanded group, so the neutral
filter hid them while the tool was still in progress and left an empty
gap. Image preview rows now bypass that filter.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@t3dotgg
t3dotggforce-pushed the fix/assistant-inline-images branch from 0cdfff6 to 54b2d49CompareSeptember 3, 2026 09:27
@t3dotgg
t3dotgg merged commit 652515a into mainSep 3, 2026
27 checks passed
@t3dotgg
t3dotgg deleted the fix/assistant-inline-images branch September 3, 2026 09:33
github-actionsBot added a commit to omarcresp/t3code-flake that referenced this pull request Sep 3, 2026
## What's Changed
* fix(web): keep trailing tool groups out of "Worked for" accordion by @Yash-Singh1 in pingdotgg/t3code#9384
* feat(marketing): put named-developer quotes on the landing page by @t3dotgg in pingdotgg/t3code#9385
* fix(claude): expand slash commands when a message has attachments by @t3dotgg in pingdotgg/t3code#9122
* fix(web): stop the resting composer layout loop by @t3dotgg in pingdotgg/t3code#9393
* fix(web): render assistant images inline in chat by @t3dotgg in pingdotgg/t3code#9126
* feat(providers): add Google Antigravity via the official ACP agent by @t3dotgg in pingdotgg/t3code#9348
**Full Changelog**: pingdotgg/t3code@v0.0.39-nightly.20260903.1267...v0.0.39-nightly.20260903.1268
Upstream release: https://github.com/pingdotgg/t3code/releases/tag/v0.0.39-nightly.20260903.1268
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M30-99 changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@t3dotgg
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(web): render assistant images inline in chat - #9126

Merged
t3dotgg merged 3 commits into
mainfrom
fix/assistant-inline-images
Sep 3, 2026
Merged

fix(web): render assistant images inline in chat#9126
t3dotgg merged 3 commits into
mainfrom
fix/assistant-inline-images

Conversation

@t3dotgg

@t3dotggt3dotgg commented Sep 1, 2026

Copy link
Copy Markdown
Member

Problem

When an agent viewed or produced an image, the chat timeline hid it twice. The tool row folded under the "Worked for ..." summary once the turn settled, and even unfolded, the image only appeared after the user clicked the row open. The agent thought it had shown a screenshot; the user saw nothing.

What changed

Rows that preview an image now render on their own. They stay out of tool groups, stay out of the settled-turn fold, and show the image without an expand click. This reuses the existing signed asset route, so no image bytes travel over the websocket.

The change is in apps/web, which desktop wraps. Mobile has a parallel work-log row and still gates its image behind expand; that is a separate fix.

Markdown images with local paths

Absolute paths and file:// URIs already resolve through the signed asset route after #9023, which introduced the media-file resource. The reporter tested a build from before that merge. I added a POSIX regression test for ![x](/tmp/embed-test/2.png) and ![x](file:///tmp/embed-test/5.png) because the existing coverage only exercised Windows path forms.

Still unsupported: data URIs

data: images in Markdown and in HTML <img> stay unsupported on purpose. Large base64 in a message is a performance problem twice over: it inflates every websocket frame that carries the message, and it inflates the DOM node that renders it. Agents should write the file and reference its path instead.

Provider coverage

Claude and the ACP providers (Cursor, Grok) are the only ones that put real image data on the wire. T3 Code does not carry those bytes through. It carries the file path and re-reads the file through the signed asset route, which is why this fix is a rendering change and not a contract change. Codex view_image and OpenCode only emit a label, no pixels, so path-based rendering is all they could ever support.

Tests

  • apps/web/src/components/chat/MessagesTimeline.logic.test.ts covers the row placement: the command row folds, the image row stays visible and does not collapse into a tool group.
  • apps/web/src/components/ChatMarkdown.workspace-images.test.tsx covers POSIX absolute and file:// sources resolving to a signed media-file asset.

vp test run on the touched files plus the neighboring work-log and markdown-image suites: 147 passed. Web typecheck and lint clean.

No before/after images. This was not run in a browser.

Refs #9094

Built by Claude Opus 5 in the Claude Code harness.


Note

Low Risk
UI-only timeline and markdown rendering changes with broad test coverage; no auth, API, or data contract changes.

Overview
Image-preview work rows (agent viewed/produced screenshots) now stay visible in the chat timeline instead of folding into “Worked for …” or hiding behind tool groups and expand clicks.

Timeline derivation adds workEntryRendersImagePreview (via workEntryViewedImagePath) and threads it through group visibility, settled-turn folds, live activity grouping, and standalone row emission so image rows behave like first-class answers. MessagesTimeline.tsx renders ChatMarkdownAssetImagebelow the row header without requiring expand; tool output text remains behind expand.

Adds regression tests for POSIX/file:// markdown images resolving to signed media-file assets, plus timeline tests that image rows survive folding and in-progress turns.

Reviewed by Cursor Bugbot for commit 54b2d49. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Render assistant images inline in chat timeline work rows

  • Adds workEntryRendersImagePreview predicate in MessagesTimeline.logic.ts to classify work entries with a viewed image path as image-preview rows.
  • Updates workEntryIsVisibleInGroup, deriveTurnFolds, and deriveMessagesTimelineRows so image-preview entries pass the group-visibility filter, are excluded from settled-turn folds, and are emitted as standalone rows rather than absorbed into active or adjacent tool groups.
  • Moves the viewed-image rendering in MessagesTimeline.tsx out of the expanded-detail container so it displays without expanding the row; expanding still controls the separate tool body.
  • Adds tests covering POSIX/file-URI asset loading in ChatMarkdown.workspace-images.test.tsx and image-preview visibility in MessagesTimeline.logic.test.ts.
  • Behavioral Change: work entries previously folded or grouped when neutral will now appear as visible image rows when they have a viewed image path.

Macroscope summarized 54b2d49.

@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:M 30-99 changed lines (additions + deletions). labels Sep 1, 2026
Comment threadapps/web/src/components/chat/MessagesTimeline.logic.ts
@github-actions

github-actionsBot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

ProviderMetricMain baselineThis PRImpactPR ceiling
CodexTotal thread wire13.6 KiB13.7 KiB+134 B (+1.0%)15.1 KiB
CodexThread snapshot wire7.0 KiB7.0 KiB+6 B (+0.1%)7.3 KiB
CodexLive turn WebSocket wire6.6 KiB6.7 KiB+128 B (+1.9%)7.8 KiB
CodexLive turn WebSocket decoded57.1 KiB58.5 KiB+1.4 KiB (+2.5%)66.4 KiB
CodexLive turn messages10100 (0.0%)21
ClaudeTotal thread wire13.5 KiB13.6 KiB+55 B (+0.4%)15.1 KiB
ClaudeThread snapshot wire7.0 KiB7.0 KiB−6 B (−0.1%)7.3 KiB
ClaudeLive turn WebSocket wire6.5 KiB6.6 KiB+61 B (+0.9%)7.8 KiB
ClaudeLive turn WebSocket decoded57.8 KiB57.9 KiB+88 B (+0.1%)66.4 KiB
ClaudeLive turn messages810+2 (+25.0%)21

Baseline: 4b26132 · PR result: 54b2d49 · Source CI: success

Scenario and decoded snapshot size

10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.

  • Codex decoded thread snapshot: 113.8 KiB
  • Claude decoded thread snapshot: 114.5 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

@macroscopeapp

macroscopeappBot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved at 1a1d3b1

Macroscope's review found this PR approvable — This is a contained web chat rendering fix that keeps existing image-preview entries visible and renders them through the existing signed asset loader. Production changes are limited to timeline grouping and row presentation, with regression tests added and no schema, security, billing, default, or deployment changes.

No code changes detected at 54b2d49. Prior analysis still applies.

You can add or adjust custom eligibility rules. Learn more.

@t3dotgg
t3dotggforce-pushed the fix/assistant-inline-images branch from bcfe6ea to 2ef0c74CompareSeptember 2, 2026 00:04

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 2ef0c74. Configure here.

Comment threadapps/web/src/components/chat/MessagesTimeline.logic.ts
@t3dotgg
t3dotggforce-pushed the fix/assistant-inline-images branch from 1a1d3b1 to 0cdfff6CompareSeptember 3, 2026 09:25
t3dotggand others added 3 commits September 3, 2026 02:26
An image the agent viewed or produced was hidden twice in the timeline.
The row folded under "Worked for ..." when the turn settled, and the image
itself only rendered after the user expanded the row.
Image preview rows now render on their own, outside tool groups and outside
the settled-turn fold, and the image shows without an expand click.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
While the turn was still working, a trailing image view was collected
into the live tool row, which renders only a label. The image appeared
only after the turn settled. Image preview rows now stop the active
collection the same way agent spawns and errors do.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Standalone image rows sit outside any expanded group, so the neutral
filter hid them while the tool was still in progress and left an empty
gap. Image preview rows now bypass that filter.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@t3dotgg
t3dotggforce-pushed the fix/assistant-inline-images branch from 0cdfff6 to 54b2d49CompareSeptember 3, 2026 09:27
@t3dotgg
t3dotgg merged commit 652515a into mainSep 3, 2026
27 checks passed
@t3dotgg
t3dotgg deleted the fix/assistant-inline-images branch September 3, 2026 09:33
github-actionsBot added a commit to omarcresp/t3code-flake that referenced this pull request Sep 3, 2026
## What's Changed
* fix(web): keep trailing tool groups out of "Worked for" accordion by @Yash-Singh1 in pingdotgg/t3code#9384
* feat(marketing): put named-developer quotes on the landing page by @t3dotgg in pingdotgg/t3code#9385
* fix(claude): expand slash commands when a message has attachments by @t3dotgg in pingdotgg/t3code#9122
* fix(web): stop the resting composer layout loop by @t3dotgg in pingdotgg/t3code#9393
* fix(web): render assistant images inline in chat by @t3dotgg in pingdotgg/t3code#9126
* feat(providers): add Google Antigravity via the official ACP agent by @t3dotgg in pingdotgg/t3code#9348
**Full Changelog**: pingdotgg/t3code@v0.0.39-nightly.20260903.1267...v0.0.39-nightly.20260903.1268
Upstream release: https://github.com/pingdotgg/t3code/releases/tag/v0.0.39-nightly.20260903.1268
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M30-99 changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@t3dotgg
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

fix(web): render assistant images inline in chat - #9126

Merged
t3dotgg merged 3 commits into
mainfrom
fix/assistant-inline-images
Sep 3, 2026
Merged

fix(web): render assistant images inline in chat#9126
t3dotgg merged 3 commits into
mainfrom
fix/assistant-inline-images

Conversation

@t3dotgg

@t3dotggt3dotgg commented Sep 1, 2026

Copy link
Copy Markdown
Member

Problem

When an agent viewed or produced an image, the chat timeline hid it twice. The tool row folded under the "Worked for ..." summary once the turn settled, and even unfolded, the image only appeared after the user clicked the row open. The agent thought it had shown a screenshot; the user saw nothing.

What changed

Rows that preview an image now render on their own. They stay out of tool groups, stay out of the settled-turn fold, and show the image without an expand click. This reuses the existing signed asset route, so no image bytes travel over the websocket.

The change is in apps/web, which desktop wraps. Mobile has a parallel work-log row and still gates its image behind expand; that is a separate fix.

Markdown images with local paths

Absolute paths and file:// URIs already resolve through the signed asset route after #9023, which introduced the media-file resource. The reporter tested a build from before that merge. I added a POSIX regression test for ![x](/tmp/embed-test/2.png) and ![x](file:///tmp/embed-test/5.png) because the existing coverage only exercised Windows path forms.

Still unsupported: data URIs

data: images in Markdown and in HTML <img> stay unsupported on purpose. Large base64 in a message is a performance problem twice over: it inflates every websocket frame that carries the message, and it inflates the DOM node that renders it. Agents should write the file and reference its path instead.

Provider coverage

Claude and the ACP providers (Cursor, Grok) are the only ones that put real image data on the wire. T3 Code does not carry those bytes through. It carries the file path and re-reads the file through the signed asset route, which is why this fix is a rendering change and not a contract change. Codex view_image and OpenCode only emit a label, no pixels, so path-based rendering is all they could ever support.

Tests

  • apps/web/src/components/chat/MessagesTimeline.logic.test.ts covers the row placement: the command row folds, the image row stays visible and does not collapse into a tool group.
  • apps/web/src/components/ChatMarkdown.workspace-images.test.tsx covers POSIX absolute and file:// sources resolving to a signed media-file asset.

vp test run on the touched files plus the neighboring work-log and markdown-image suites: 147 passed. Web typecheck and lint clean.

No before/after images. This was not run in a browser.

Refs #9094

Built by Claude Opus 5 in the Claude Code harness.


Note

Low Risk
UI-only timeline and markdown rendering changes with broad test coverage; no auth, API, or data contract changes.

Overview
Image-preview work rows (agent viewed/produced screenshots) now stay visible in the chat timeline instead of folding into “Worked for …” or hiding behind tool groups and expand clicks.

Timeline derivation adds workEntryRendersImagePreview (via workEntryViewedImagePath) and threads it through group visibility, settled-turn folds, live activity grouping, and standalone row emission so image rows behave like first-class answers. MessagesTimeline.tsx renders ChatMarkdownAssetImagebelow the row header without requiring expand; tool output text remains behind expand.

Adds regression tests for POSIX/file:// markdown images resolving to signed media-file assets, plus timeline tests that image rows survive folding and in-progress turns.

Reviewed by Cursor Bugbot for commit 54b2d49. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Render assistant images inline in chat timeline work rows

  • Adds workEntryRendersImagePreview predicate in MessagesTimeline.logic.ts to classify work entries with a viewed image path as image-preview rows.
  • Updates workEntryIsVisibleInGroup, deriveTurnFolds, and deriveMessagesTimelineRows so image-preview entries pass the group-visibility filter, are excluded from settled-turn folds, and are emitted as standalone rows rather than absorbed into active or adjacent tool groups.
  • Moves the viewed-image rendering in MessagesTimeline.tsx out of the expanded-detail container so it displays without expanding the row; expanding still controls the separate tool body.
  • Adds tests covering POSIX/file-URI asset loading in ChatMarkdown.workspace-images.test.tsx and image-preview visibility in MessagesTimeline.logic.test.ts.
  • Behavioral Change: work entries previously folded or grouped when neutral will now appear as visible image rows when they have a viewed image path.

Macroscope summarized 54b2d49.

@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:M 30-99 changed lines (additions + deletions). labels Sep 1, 2026
Comment threadapps/web/src/components/chat/MessagesTimeline.logic.ts
@github-actions

github-actionsBot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

ProviderMetricMain baselineThis PRImpactPR ceiling
CodexTotal thread wire13.6 KiB13.7 KiB+134 B (+1.0%)15.1 KiB
CodexThread snapshot wire7.0 KiB7.0 KiB+6 B (+0.1%)7.3 KiB
CodexLive turn WebSocket wire6.6 KiB6.7 KiB+128 B (+1.9%)7.8 KiB
CodexLive turn WebSocket decoded57.1 KiB58.5 KiB+1.4 KiB (+2.5%)66.4 KiB
CodexLive turn messages10100 (0.0%)21
ClaudeTotal thread wire13.5 KiB13.6 KiB+55 B (+0.4%)15.1 KiB
ClaudeThread snapshot wire7.0 KiB7.0 KiB−6 B (−0.1%)7.3 KiB
ClaudeLive turn WebSocket wire6.5 KiB6.6 KiB+61 B (+0.9%)7.8 KiB
ClaudeLive turn WebSocket decoded57.8 KiB57.9 KiB+88 B (+0.1%)66.4 KiB
ClaudeLive turn messages810+2 (+25.0%)21

Baseline: 4b26132 · PR result: 54b2d49 · Source CI: success

Scenario and decoded snapshot size

10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.

  • Codex decoded thread snapshot: 113.8 KiB
  • Claude decoded thread snapshot: 114.5 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

@macroscopeapp

macroscopeappBot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved at 1a1d3b1

Macroscope's review found this PR approvable — This is a contained web chat rendering fix that keeps existing image-preview entries visible and renders them through the existing signed asset loader. Production changes are limited to timeline grouping and row presentation, with regression tests added and no schema, security, billing, default, or deployment changes.

No code changes detected at 54b2d49. Prior analysis still applies.

You can add or adjust custom eligibility rules. Learn more.

@t3dotgg
t3dotggforce-pushed the fix/assistant-inline-images branch from bcfe6ea to 2ef0c74CompareSeptember 2, 2026 00:04

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 2ef0c74. Configure here.

Comment threadapps/web/src/components/chat/MessagesTimeline.logic.ts
@t3dotgg
t3dotggforce-pushed the fix/assistant-inline-images branch from 1a1d3b1 to 0cdfff6CompareSeptember 3, 2026 09:25
t3dotggand others added 3 commits September 3, 2026 02:26
An image the agent viewed or produced was hidden twice in the timeline.
The row folded under "Worked for ..." when the turn settled, and the image
itself only rendered after the user expanded the row.
Image preview rows now render on their own, outside tool groups and outside
the settled-turn fold, and the image shows without an expand click.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
While the turn was still working, a trailing image view was collected
into the live tool row, which renders only a label. The image appeared
only after the turn settled. Image preview rows now stop the active
collection the same way agent spawns and errors do.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Standalone image rows sit outside any expanded group, so the neutral
filter hid them while the tool was still in progress and left an empty
gap. Image preview rows now bypass that filter.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@t3dotgg
t3dotggforce-pushed the fix/assistant-inline-images branch from 0cdfff6 to 54b2d49CompareSeptember 3, 2026 09:27
@t3dotgg
t3dotgg merged commit 652515a into mainSep 3, 2026
27 checks passed
@t3dotgg
t3dotgg deleted the fix/assistant-inline-images branch September 3, 2026 09:33
github-actionsBot added a commit to omarcresp/t3code-flake that referenced this pull request Sep 3, 2026
## What's Changed
* fix(web): keep trailing tool groups out of "Worked for" accordion by @Yash-Singh1 in pingdotgg/t3code#9384
* feat(marketing): put named-developer quotes on the landing page by @t3dotgg in pingdotgg/t3code#9385
* fix(claude): expand slash commands when a message has attachments by @t3dotgg in pingdotgg/t3code#9122
* fix(web): stop the resting composer layout loop by @t3dotgg in pingdotgg/t3code#9393
* fix(web): render assistant images inline in chat by @t3dotgg in pingdotgg/t3code#9126
* feat(providers): add Google Antigravity via the official ACP agent by @t3dotgg in pingdotgg/t3code#9348
**Full Changelog**: pingdotgg/t3code@v0.0.39-nightly.20260903.1267...v0.0.39-nightly.20260903.1268
Upstream release: https://github.com/pingdotgg/t3code/releases/tag/v0.0.39-nightly.20260903.1268
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M30-99 changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@t3dotgg
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(web): render assistant images inline in chat - #9126

Merged
t3dotgg merged 3 commits into
mainfrom
fix/assistant-inline-images
Sep 3, 2026
Merged

fix(web): render assistant images inline in chat#9126
t3dotgg merged 3 commits into
mainfrom
fix/assistant-inline-images

Conversation

@t3dotgg

@t3dotggt3dotgg commented Sep 1, 2026

Copy link
Copy Markdown
Member

Problem

When an agent viewed or produced an image, the chat timeline hid it twice. The tool row folded under the "Worked for ..." summary once the turn settled, and even unfolded, the image only appeared after the user clicked the row open. The agent thought it had shown a screenshot; the user saw nothing.

What changed

Rows that preview an image now render on their own. They stay out of tool groups, stay out of the settled-turn fold, and show the image without an expand click. This reuses the existing signed asset route, so no image bytes travel over the websocket.

The change is in apps/web, which desktop wraps. Mobile has a parallel work-log row and still gates its image behind expand; that is a separate fix.

Markdown images with local paths

Absolute paths and file:// URIs already resolve through the signed asset route after #9023, which introduced the media-file resource. The reporter tested a build from before that merge. I added a POSIX regression test for ![x](/tmp/embed-test/2.png) and ![x](file:///tmp/embed-test/5.png) because the existing coverage only exercised Windows path forms.

Still unsupported: data URIs

data: images in Markdown and in HTML <img> stay unsupported on purpose. Large base64 in a message is a performance problem twice over: it inflates every websocket frame that carries the message, and it inflates the DOM node that renders it. Agents should write the file and reference its path instead.

Provider coverage

Claude and the ACP providers (Cursor, Grok) are the only ones that put real image data on the wire. T3 Code does not carry those bytes through. It carries the file path and re-reads the file through the signed asset route, which is why this fix is a rendering change and not a contract change. Codex view_image and OpenCode only emit a label, no pixels, so path-based rendering is all they could ever support.

Tests

  • apps/web/src/components/chat/MessagesTimeline.logic.test.ts covers the row placement: the command row folds, the image row stays visible and does not collapse into a tool group.
  • apps/web/src/components/ChatMarkdown.workspace-images.test.tsx covers POSIX absolute and file:// sources resolving to a signed media-file asset.

vp test run on the touched files plus the neighboring work-log and markdown-image suites: 147 passed. Web typecheck and lint clean.

No before/after images. This was not run in a browser.

Refs #9094

Built by Claude Opus 5 in the Claude Code harness.


Note

Low Risk
UI-only timeline and markdown rendering changes with broad test coverage; no auth, API, or data contract changes.

Overview
Image-preview work rows (agent viewed/produced screenshots) now stay visible in the chat timeline instead of folding into “Worked for …” or hiding behind tool groups and expand clicks.

Timeline derivation adds workEntryRendersImagePreview (via workEntryViewedImagePath) and threads it through group visibility, settled-turn folds, live activity grouping, and standalone row emission so image rows behave like first-class answers. MessagesTimeline.tsx renders ChatMarkdownAssetImagebelow the row header without requiring expand; tool output text remains behind expand.

Adds regression tests for POSIX/file:// markdown images resolving to signed media-file assets, plus timeline tests that image rows survive folding and in-progress turns.

Reviewed by Cursor Bugbot for commit 54b2d49. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Render assistant images inline in chat timeline work rows

  • Adds workEntryRendersImagePreview predicate in MessagesTimeline.logic.ts to classify work entries with a viewed image path as image-preview rows.
  • Updates workEntryIsVisibleInGroup, deriveTurnFolds, and deriveMessagesTimelineRows so image-preview entries pass the group-visibility filter, are excluded from settled-turn folds, and are emitted as standalone rows rather than absorbed into active or adjacent tool groups.
  • Moves the viewed-image rendering in MessagesTimeline.tsx out of the expanded-detail container so it displays without expanding the row; expanding still controls the separate tool body.
  • Adds tests covering POSIX/file-URI asset loading in ChatMarkdown.workspace-images.test.tsx and image-preview visibility in MessagesTimeline.logic.test.ts.
  • Behavioral Change: work entries previously folded or grouped when neutral will now appear as visible image rows when they have a viewed image path.

Macroscope summarized 54b2d49.

@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:M 30-99 changed lines (additions + deletions). labels Sep 1, 2026
Comment threadapps/web/src/components/chat/MessagesTimeline.logic.ts
@github-actions

github-actionsBot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

ProviderMetricMain baselineThis PRImpactPR ceiling
CodexTotal thread wire13.6 KiB13.7 KiB+134 B (+1.0%)15.1 KiB
CodexThread snapshot wire7.0 KiB7.0 KiB+6 B (+0.1%)7.3 KiB
CodexLive turn WebSocket wire6.6 KiB6.7 KiB+128 B (+1.9%)7.8 KiB
CodexLive turn WebSocket decoded57.1 KiB58.5 KiB+1.4 KiB (+2.5%)66.4 KiB
CodexLive turn messages10100 (0.0%)21
ClaudeTotal thread wire13.5 KiB13.6 KiB+55 B (+0.4%)15.1 KiB
ClaudeThread snapshot wire7.0 KiB7.0 KiB−6 B (−0.1%)7.3 KiB
ClaudeLive turn WebSocket wire6.5 KiB6.6 KiB+61 B (+0.9%)7.8 KiB
ClaudeLive turn WebSocket decoded57.8 KiB57.9 KiB+88 B (+0.1%)66.4 KiB
ClaudeLive turn messages810+2 (+25.0%)21

Baseline: 4b26132 · PR result: 54b2d49 · Source CI: success

Scenario and decoded snapshot size

10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.

  • Codex decoded thread snapshot: 113.8 KiB
  • Claude decoded thread snapshot: 114.5 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

@macroscopeapp

macroscopeappBot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved at 1a1d3b1

Macroscope's review found this PR approvable — This is a contained web chat rendering fix that keeps existing image-preview entries visible and renders them through the existing signed asset loader. Production changes are limited to timeline grouping and row presentation, with regression tests added and no schema, security, billing, default, or deployment changes.

No code changes detected at 54b2d49. Prior analysis still applies.

You can add or adjust custom eligibility rules. Learn more.

@t3dotgg
t3dotggforce-pushed the fix/assistant-inline-images branch from bcfe6ea to 2ef0c74CompareSeptember 2, 2026 00:04

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 2ef0c74. Configure here.

Comment threadapps/web/src/components/chat/MessagesTimeline.logic.ts
@t3dotgg
t3dotggforce-pushed the fix/assistant-inline-images branch from 1a1d3b1 to 0cdfff6CompareSeptember 3, 2026 09:25
t3dotggand others added 3 commits September 3, 2026 02:26
An image the agent viewed or produced was hidden twice in the timeline.
The row folded under "Worked for ..." when the turn settled, and the image
itself only rendered after the user expanded the row.
Image preview rows now render on their own, outside tool groups and outside
the settled-turn fold, and the image shows without an expand click.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
While the turn was still working, a trailing image view was collected
into the live tool row, which renders only a label. The image appeared
only after the turn settled. Image preview rows now stop the active
collection the same way agent spawns and errors do.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Standalone image rows sit outside any expanded group, so the neutral
filter hid them while the tool was still in progress and left an empty
gap. Image preview rows now bypass that filter.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@t3dotgg
t3dotggforce-pushed the fix/assistant-inline-images branch from 0cdfff6 to 54b2d49CompareSeptember 3, 2026 09:27
@t3dotgg
t3dotgg merged commit 652515a into mainSep 3, 2026
27 checks passed
@t3dotgg
t3dotgg deleted the fix/assistant-inline-images branch September 3, 2026 09:33
github-actionsBot added a commit to omarcresp/t3code-flake that referenced this pull request Sep 3, 2026
## What's Changed
* fix(web): keep trailing tool groups out of "Worked for" accordion by @Yash-Singh1 in pingdotgg/t3code#9384
* feat(marketing): put named-developer quotes on the landing page by @t3dotgg in pingdotgg/t3code#9385
* fix(claude): expand slash commands when a message has attachments by @t3dotgg in pingdotgg/t3code#9122
* fix(web): stop the resting composer layout loop by @t3dotgg in pingdotgg/t3code#9393
* fix(web): render assistant images inline in chat by @t3dotgg in pingdotgg/t3code#9126
* feat(providers): add Google Antigravity via the official ACP agent by @t3dotgg in pingdotgg/t3code#9348
**Full Changelog**: pingdotgg/t3code@v0.0.39-nightly.20260903.1267...v0.0.39-nightly.20260903.1268
Upstream release: https://github.com/pingdotgg/t3code/releases/tag/v0.0.39-nightly.20260903.1268
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M30-99 changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@t3dotgg
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(web): render assistant images inline in chat - #9126

Merged
t3dotgg merged 3 commits into
mainfrom
fix/assistant-inline-images
Sep 3, 2026
Merged

fix(web): render assistant images inline in chat#9126
t3dotgg merged 3 commits into
mainfrom
fix/assistant-inline-images

Conversation

@t3dotgg

@t3dotggt3dotgg commented Sep 1, 2026

Copy link
Copy Markdown
Member

Problem

When an agent viewed or produced an image, the chat timeline hid it twice. The tool row folded under the "Worked for ..." summary once the turn settled, and even unfolded, the image only appeared after the user clicked the row open. The agent thought it had shown a screenshot; the user saw nothing.

What changed

Rows that preview an image now render on their own. They stay out of tool groups, stay out of the settled-turn fold, and show the image without an expand click. This reuses the existing signed asset route, so no image bytes travel over the websocket.

The change is in apps/web, which desktop wraps. Mobile has a parallel work-log row and still gates its image behind expand; that is a separate fix.

Markdown images with local paths

Absolute paths and file:// URIs already resolve through the signed asset route after #9023, which introduced the media-file resource. The reporter tested a build from before that merge. I added a POSIX regression test for ![x](/tmp/embed-test/2.png) and ![x](file:///tmp/embed-test/5.png) because the existing coverage only exercised Windows path forms.

Still unsupported: data URIs

data: images in Markdown and in HTML <img> stay unsupported on purpose. Large base64 in a message is a performance problem twice over: it inflates every websocket frame that carries the message, and it inflates the DOM node that renders it. Agents should write the file and reference its path instead.

Provider coverage

Claude and the ACP providers (Cursor, Grok) are the only ones that put real image data on the wire. T3 Code does not carry those bytes through. It carries the file path and re-reads the file through the signed asset route, which is why this fix is a rendering change and not a contract change. Codex view_image and OpenCode only emit a label, no pixels, so path-based rendering is all they could ever support.

Tests

  • apps/web/src/components/chat/MessagesTimeline.logic.test.ts covers the row placement: the command row folds, the image row stays visible and does not collapse into a tool group.
  • apps/web/src/components/ChatMarkdown.workspace-images.test.tsx covers POSIX absolute and file:// sources resolving to a signed media-file asset.

vp test run on the touched files plus the neighboring work-log and markdown-image suites: 147 passed. Web typecheck and lint clean.

No before/after images. This was not run in a browser.

Refs #9094

Built by Claude Opus 5 in the Claude Code harness.


Note

Low Risk
UI-only timeline and markdown rendering changes with broad test coverage; no auth, API, or data contract changes.

Overview
Image-preview work rows (agent viewed/produced screenshots) now stay visible in the chat timeline instead of folding into “Worked for …” or hiding behind tool groups and expand clicks.

Timeline derivation adds workEntryRendersImagePreview (via workEntryViewedImagePath) and threads it through group visibility, settled-turn folds, live activity grouping, and standalone row emission so image rows behave like first-class answers. MessagesTimeline.tsx renders ChatMarkdownAssetImagebelow the row header without requiring expand; tool output text remains behind expand.

Adds regression tests for POSIX/file:// markdown images resolving to signed media-file assets, plus timeline tests that image rows survive folding and in-progress turns.

Reviewed by Cursor Bugbot for commit 54b2d49. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Render assistant images inline in chat timeline work rows

  • Adds workEntryRendersImagePreview predicate in MessagesTimeline.logic.ts to classify work entries with a viewed image path as image-preview rows.
  • Updates workEntryIsVisibleInGroup, deriveTurnFolds, and deriveMessagesTimelineRows so image-preview entries pass the group-visibility filter, are excluded from settled-turn folds, and are emitted as standalone rows rather than absorbed into active or adjacent tool groups.
  • Moves the viewed-image rendering in MessagesTimeline.tsx out of the expanded-detail container so it displays without expanding the row; expanding still controls the separate tool body.
  • Adds tests covering POSIX/file-URI asset loading in ChatMarkdown.workspace-images.test.tsx and image-preview visibility in MessagesTimeline.logic.test.ts.
  • Behavioral Change: work entries previously folded or grouped when neutral will now appear as visible image rows when they have a viewed image path.

Macroscope summarized 54b2d49.

@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:M 30-99 changed lines (additions + deletions). labels Sep 1, 2026
Comment threadapps/web/src/components/chat/MessagesTimeline.logic.ts
@github-actions

github-actionsBot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

ProviderMetricMain baselineThis PRImpactPR ceiling
CodexTotal thread wire13.6 KiB13.7 KiB+134 B (+1.0%)15.1 KiB
CodexThread snapshot wire7.0 KiB7.0 KiB+6 B (+0.1%)7.3 KiB
CodexLive turn WebSocket wire6.6 KiB6.7 KiB+128 B (+1.9%)7.8 KiB
CodexLive turn WebSocket decoded57.1 KiB58.5 KiB+1.4 KiB (+2.5%)66.4 KiB
CodexLive turn messages10100 (0.0%)21
ClaudeTotal thread wire13.5 KiB13.6 KiB+55 B (+0.4%)15.1 KiB
ClaudeThread snapshot wire7.0 KiB7.0 KiB−6 B (−0.1%)7.3 KiB
ClaudeLive turn WebSocket wire6.5 KiB6.6 KiB+61 B (+0.9%)7.8 KiB
ClaudeLive turn WebSocket decoded57.8 KiB57.9 KiB+88 B (+0.1%)66.4 KiB
ClaudeLive turn messages810+2 (+25.0%)21

Baseline: 4b26132 · PR result: 54b2d49 · Source CI: success

Scenario and decoded snapshot size

10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.

  • Codex decoded thread snapshot: 113.8 KiB
  • Claude decoded thread snapshot: 114.5 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

@macroscopeapp

macroscopeappBot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved at 1a1d3b1

Macroscope's review found this PR approvable — This is a contained web chat rendering fix that keeps existing image-preview entries visible and renders them through the existing signed asset loader. Production changes are limited to timeline grouping and row presentation, with regression tests added and no schema, security, billing, default, or deployment changes.

No code changes detected at 54b2d49. Prior analysis still applies.

You can add or adjust custom eligibility rules. Learn more.

@t3dotgg
t3dotggforce-pushed the fix/assistant-inline-images branch from bcfe6ea to 2ef0c74CompareSeptember 2, 2026 00:04

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 2ef0c74. Configure here.

Comment threadapps/web/src/components/chat/MessagesTimeline.logic.ts
@t3dotgg
t3dotggforce-pushed the fix/assistant-inline-images branch from 1a1d3b1 to 0cdfff6CompareSeptember 3, 2026 09:25
t3dotggand others added 3 commits September 3, 2026 02:26
An image the agent viewed or produced was hidden twice in the timeline.
The row folded under "Worked for ..." when the turn settled, and the image
itself only rendered after the user expanded the row.
Image preview rows now render on their own, outside tool groups and outside
the settled-turn fold, and the image shows without an expand click.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
While the turn was still working, a trailing image view was collected
into the live tool row, which renders only a label. The image appeared
only after the turn settled. Image preview rows now stop the active
collection the same way agent spawns and errors do.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Standalone image rows sit outside any expanded group, so the neutral
filter hid them while the tool was still in progress and left an empty
gap. Image preview rows now bypass that filter.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@t3dotgg
t3dotggforce-pushed the fix/assistant-inline-images branch from 0cdfff6 to 54b2d49CompareSeptember 3, 2026 09:27
@t3dotgg
t3dotgg merged commit 652515a into mainSep 3, 2026
27 checks passed
@t3dotgg
t3dotgg deleted the fix/assistant-inline-images branch September 3, 2026 09:33
github-actionsBot added a commit to omarcresp/t3code-flake that referenced this pull request Sep 3, 2026
## What's Changed
* fix(web): keep trailing tool groups out of "Worked for" accordion by @Yash-Singh1 in pingdotgg/t3code#9384
* feat(marketing): put named-developer quotes on the landing page by @t3dotgg in pingdotgg/t3code#9385
* fix(claude): expand slash commands when a message has attachments by @t3dotgg in pingdotgg/t3code#9122
* fix(web): stop the resting composer layout loop by @t3dotgg in pingdotgg/t3code#9393
* fix(web): render assistant images inline in chat by @t3dotgg in pingdotgg/t3code#9126
* feat(providers): add Google Antigravity via the official ACP agent by @t3dotgg in pingdotgg/t3code#9348
**Full Changelog**: pingdotgg/t3code@v0.0.39-nightly.20260903.1267...v0.0.39-nightly.20260903.1268
Upstream release: https://github.com/pingdotgg/t3code/releases/tag/v0.0.39-nightly.20260903.1268
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M30-99 changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@t3dotgg
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

fix(web): render assistant images inline in chat - #9126

Merged
t3dotgg merged 3 commits into
mainfrom
fix/assistant-inline-images
Sep 3, 2026
Merged

fix(web): render assistant images inline in chat#9126
t3dotgg merged 3 commits into
mainfrom
fix/assistant-inline-images

Conversation

@t3dotgg

@t3dotggt3dotgg commented Sep 1, 2026

Copy link
Copy Markdown
Member

Problem

When an agent viewed or produced an image, the chat timeline hid it twice. The tool row folded under the "Worked for ..." summary once the turn settled, and even unfolded, the image only appeared after the user clicked the row open. The agent thought it had shown a screenshot; the user saw nothing.

What changed

Rows that preview an image now render on their own. They stay out of tool groups, stay out of the settled-turn fold, and show the image without an expand click. This reuses the existing signed asset route, so no image bytes travel over the websocket.

The change is in apps/web, which desktop wraps. Mobile has a parallel work-log row and still gates its image behind expand; that is a separate fix.

Markdown images with local paths

Absolute paths and file:// URIs already resolve through the signed asset route after #9023, which introduced the media-file resource. The reporter tested a build from before that merge. I added a POSIX regression test for ![x](/tmp/embed-test/2.png) and ![x](file:///tmp/embed-test/5.png) because the existing coverage only exercised Windows path forms.

Still unsupported: data URIs

data: images in Markdown and in HTML <img> stay unsupported on purpose. Large base64 in a message is a performance problem twice over: it inflates every websocket frame that carries the message, and it inflates the DOM node that renders it. Agents should write the file and reference its path instead.

Provider coverage

Claude and the ACP providers (Cursor, Grok) are the only ones that put real image data on the wire. T3 Code does not carry those bytes through. It carries the file path and re-reads the file through the signed asset route, which is why this fix is a rendering change and not a contract change. Codex view_image and OpenCode only emit a label, no pixels, so path-based rendering is all they could ever support.

Tests

  • apps/web/src/components/chat/MessagesTimeline.logic.test.ts covers the row placement: the command row folds, the image row stays visible and does not collapse into a tool group.
  • apps/web/src/components/ChatMarkdown.workspace-images.test.tsx covers POSIX absolute and file:// sources resolving to a signed media-file asset.

vp test run on the touched files plus the neighboring work-log and markdown-image suites: 147 passed. Web typecheck and lint clean.

No before/after images. This was not run in a browser.

Refs #9094

Built by Claude Opus 5 in the Claude Code harness.


Note

Low Risk
UI-only timeline and markdown rendering changes with broad test coverage; no auth, API, or data contract changes.

Overview
Image-preview work rows (agent viewed/produced screenshots) now stay visible in the chat timeline instead of folding into “Worked for …” or hiding behind tool groups and expand clicks.

Timeline derivation adds workEntryRendersImagePreview (via workEntryViewedImagePath) and threads it through group visibility, settled-turn folds, live activity grouping, and standalone row emission so image rows behave like first-class answers. MessagesTimeline.tsx renders ChatMarkdownAssetImagebelow the row header without requiring expand; tool output text remains behind expand.

Adds regression tests for POSIX/file:// markdown images resolving to signed media-file assets, plus timeline tests that image rows survive folding and in-progress turns.

Reviewed by Cursor Bugbot for commit 54b2d49. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Render assistant images inline in chat timeline work rows

  • Adds workEntryRendersImagePreview predicate in MessagesTimeline.logic.ts to classify work entries with a viewed image path as image-preview rows.
  • Updates workEntryIsVisibleInGroup, deriveTurnFolds, and deriveMessagesTimelineRows so image-preview entries pass the group-visibility filter, are excluded from settled-turn folds, and are emitted as standalone rows rather than absorbed into active or adjacent tool groups.
  • Moves the viewed-image rendering in MessagesTimeline.tsx out of the expanded-detail container so it displays without expanding the row; expanding still controls the separate tool body.
  • Adds tests covering POSIX/file-URI asset loading in ChatMarkdown.workspace-images.test.tsx and image-preview visibility in MessagesTimeline.logic.test.ts.
  • Behavioral Change: work entries previously folded or grouped when neutral will now appear as visible image rows when they have a viewed image path.

Macroscope summarized 54b2d49.

@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:M 30-99 changed lines (additions + deletions). labels Sep 1, 2026
Comment threadapps/web/src/components/chat/MessagesTimeline.logic.ts
@github-actions

github-actionsBot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

ProviderMetricMain baselineThis PRImpactPR ceiling
CodexTotal thread wire13.6 KiB13.7 KiB+134 B (+1.0%)15.1 KiB
CodexThread snapshot wire7.0 KiB7.0 KiB+6 B (+0.1%)7.3 KiB
CodexLive turn WebSocket wire6.6 KiB6.7 KiB+128 B (+1.9%)7.8 KiB
CodexLive turn WebSocket decoded57.1 KiB58.5 KiB+1.4 KiB (+2.5%)66.4 KiB
CodexLive turn messages10100 (0.0%)21
ClaudeTotal thread wire13.5 KiB13.6 KiB+55 B (+0.4%)15.1 KiB
ClaudeThread snapshot wire7.0 KiB7.0 KiB−6 B (−0.1%)7.3 KiB
ClaudeLive turn WebSocket wire6.5 KiB6.6 KiB+61 B (+0.9%)7.8 KiB
ClaudeLive turn WebSocket decoded57.8 KiB57.9 KiB+88 B (+0.1%)66.4 KiB
ClaudeLive turn messages810+2 (+25.0%)21

Baseline: 4b26132 · PR result: 54b2d49 · Source CI: success

Scenario and decoded snapshot size

10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.

  • Codex decoded thread snapshot: 113.8 KiB
  • Claude decoded thread snapshot: 114.5 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

@macroscopeapp

macroscopeappBot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved at 1a1d3b1

Macroscope's review found this PR approvable — This is a contained web chat rendering fix that keeps existing image-preview entries visible and renders them through the existing signed asset loader. Production changes are limited to timeline grouping and row presentation, with regression tests added and no schema, security, billing, default, or deployment changes.

No code changes detected at 54b2d49. Prior analysis still applies.

You can add or adjust custom eligibility rules. Learn more.

@t3dotgg
t3dotggforce-pushed the fix/assistant-inline-images branch from bcfe6ea to 2ef0c74CompareSeptember 2, 2026 00:04

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 2ef0c74. Configure here.

Comment threadapps/web/src/components/chat/MessagesTimeline.logic.ts
@t3dotgg
t3dotggforce-pushed the fix/assistant-inline-images branch from 1a1d3b1 to 0cdfff6CompareSeptember 3, 2026 09:25
t3dotggand others added 3 commits September 3, 2026 02:26
An image the agent viewed or produced was hidden twice in the timeline.
The row folded under "Worked for ..." when the turn settled, and the image
itself only rendered after the user expanded the row.
Image preview rows now render on their own, outside tool groups and outside
the settled-turn fold, and the image shows without an expand click.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
While the turn was still working, a trailing image view was collected
into the live tool row, which renders only a label. The image appeared
only after the turn settled. Image preview rows now stop the active
collection the same way agent spawns and errors do.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Standalone image rows sit outside any expanded group, so the neutral
filter hid them while the tool was still in progress and left an empty
gap. Image preview rows now bypass that filter.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@t3dotgg
t3dotggforce-pushed the fix/assistant-inline-images branch from 0cdfff6 to 54b2d49CompareSeptember 3, 2026 09:27
@t3dotgg
t3dotgg merged commit 652515a into mainSep 3, 2026
27 checks passed
@t3dotgg
t3dotgg deleted the fix/assistant-inline-images branch September 3, 2026 09:33
github-actionsBot added a commit to omarcresp/t3code-flake that referenced this pull request Sep 3, 2026
## What's Changed
* fix(web): keep trailing tool groups out of "Worked for" accordion by @Yash-Singh1 in pingdotgg/t3code#9384
* feat(marketing): put named-developer quotes on the landing page by @t3dotgg in pingdotgg/t3code#9385
* fix(claude): expand slash commands when a message has attachments by @t3dotgg in pingdotgg/t3code#9122
* fix(web): stop the resting composer layout loop by @t3dotgg in pingdotgg/t3code#9393
* fix(web): render assistant images inline in chat by @t3dotgg in pingdotgg/t3code#9126
* feat(providers): add Google Antigravity via the official ACP agent by @t3dotgg in pingdotgg/t3code#9348
**Full Changelog**: pingdotgg/t3code@v0.0.39-nightly.20260903.1267...v0.0.39-nightly.20260903.1268
Upstream release: https://github.com/pingdotgg/t3code/releases/tag/v0.0.39-nightly.20260903.1268
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M30-99 changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@t3dotgg