Skip to content

fix(web): render local images inline - #5114

Open
berend wants to merge 12 commits into
pingdotgg:mainfrom
berend:fix/local-markdown-images
Open

fix(web): render local images inline#5114
berend wants to merge 12 commits into
pingdotgg:mainfrom
berend:fix/local-markdown-images

Conversation

@berend

@berend berend commented Jul 31, 2026

Copy link
Copy Markdown

Problem

Local workspace images referenced in chat Markdown render as broken placeholders, even though the same paths work as file links. Image generation and view_image also provide local paths that were not surfaced as visible image output.

Fixes #2398.

Fix

  • Resolve supported relative, absolute, and file:// workspace image sources through T3 Code's existing signed asset URLs.
  • Preserve Codex imageGeneration.savedPath and imageView.path lifecycle data and render those outputs inline in the work log.
  • Keep remote image rendering and existing workspace file-link behavior unchanged.
  • Add focused coverage for Markdown image resolution, Codex lifecycle mapping, and web work-log derivation.

This reuses the existing workspace asset boundary: paths are resolved against the thread workspace and served through expiring signed URLs instead of exposing raw local-file URLs.

Screenshots

The screenshots for generated image output and workspace images rendered through Markdown were captured with a local development build and will be attached separately.

Validation

  • pnpm exec vp test run apps/web/src/markdown-links.test.ts apps/web/src/session-logic.test.ts apps/server/src/provider/Layers/CodexAdapter.test.ts — 122 tests passed
  • pnpm exec vp run --filter @t3tools/web typecheck
  • pnpm exec vp run --filter t3 typecheck
  • Manual local development build verification for relative Markdown images, file links, remote images, Codex image generation, and view_image
display_via_markdown render_image

you can see the before in the linked issue

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included screenshots for the UI changes
  • A video is not applicable because there are no animation or interaction changes

🤖 Implementation and tests were generated with OpenAI Codex (GPT-5.6 Sol) through the T3 Code Codex harness, then reviewed and verified in a local development build.


Note

Low Risk
UI and asset-display changes reusing the existing signed workspace-file boundary; no auth or persistence changes.

Overview
Fixes broken local image placeholders by routing workspace image paths through the existing signed asset URL flow instead of raw file: URLs.

Chat Markdown adds resolveMarkdownImageFileLinkMeta and a MarkdownWorkspaceImage component that resolves relative, absolute, and file:// image sources against the thread workspace. The sanitize schema now allows file: on img src; remote images are unchanged.

Work log derives an imagePath on image_view entries from Codex savedPath/path, Claude file lists, and image-like details, then renders inline previews under the row via ChatMarkdown. Server keeps savedPath in activity payload projection and maps Codex savedPath into lifecycle detail.

Clipboard stores the original markdown source on data-markdown-src so copy/paste round-trips workspace paths (including encoded Windows paths) rather than expiring signed URLs.

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

Note

Render local workspace images inline in chat work log entries

  • Adds MarkdownWorkspaceImage component in ChatMarkdown.tsx that resolves workspace file paths to signed asset URLs and renders them inline, with loading/error fallbacks.
  • Extends SimpleWorkEntryRow in MessagesTimeline.tsx to display an inline image when workEntry.imagePath is set and a threadRef is available.
  • Adds imagePath to WorkLogEntry in session-logic.ts, derived from item.savedPath, item.path, changedFiles, or payload.detail for image_view activities.
  • Updates clipboard serialization in markdown-clipboard.ts to use the original markdown source (via data-markdown-src) rather than signed URLs when copying images.
  • Extends ActivityPayloadProjection to retain savedPath through payload projection so image paths survive to the frontend.

Macroscope summarized b9f2090.

AI-Assisted: true
AI-Agent: codex
AI-Model: openai/gpt-5.6-sol
@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 7fecf021-ec36-42ce-b75f-43b542d582e9

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:M 30-99 changed lines (additions + deletions). labels Jul 31, 2026
Comment thread apps/web/src/session-logic.ts
@macroscopeapp

macroscopeapp Bot commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

This PR introduces a new feature enabling inline rendering of local workspace images. It adds new user-facing behavior with a new component that fetches signed asset URLs, touches multiple layers (server projection, web rendering, clipboard handling), and warrants human review to verify the integration across these components.

You can customize Macroscope's approvability policy. Learn more.

Use the preserved activity detail when nested provider image data is removed during transport projection. Add regression coverage for the projected production payload shape.

Addresses pingdotgg#5114 (comment)

AI-Assisted: true
AI-Agent: codex
AI-Model: openai/gpt-5.6-sol
Comment thread apps/web/src/session-logic.ts
Comment thread apps/web/src/session-logic.ts Outdated
Reject non-path image detail summaries and recover projected structured image paths before rendering. Preserve original Markdown image sources when copying so signed asset URLs do not leave the app.

Addresses pingdotgg#5114 (comment)

Addresses pingdotgg#5114 (comment)

AI-Assisted: true
AI-Agent: codex
AI-Model: openai/gpt-5.6-sol
@github-actions github-actions Bot added size:L 100-499 changed lines (additions + deletions). and removed size:M 30-99 changed lines (additions + deletions). labels Jul 31, 2026
Comment thread apps/web/src/components/chat/MessagesTimeline.tsx
berend and others added 2 commits August 1, 2026 16:53
Add integration coverage for the existing Windows work-log image path flow. This changes no production behavior; it confirms that Markdown URL sanitization already preserves the decoded path for signed asset requests.

Documents pingdotgg#5114 (comment) as a false positive.

AI-Assisted: true
AI-Agent: codex
AI-Model: openai/gpt-5.6-sol
Comment thread apps/web/src/components/chat/MessagesTimeline.tsx
berend and others added 2 commits August 1, 2026 22:59
Add clipboard coverage proving that percent-encoded Windows image paths resolve back to the original workspace path. This changes no production behavior and confirms the copied Markdown remains functional.

Documents pingdotgg#5114 (comment) as a false positive.

AI-Assisted: true
AI-Agent: codex
AI-Model: openai/gpt-5.6-sol

karimou5 commented Aug 2, 2026

Copy link
Copy Markdown

Tested this PR locally and it fixed the issue for me.

Environment: Ubuntu 24.04.4 LTS (Debian-based), x86_64, kernel 7.0.0-28-generic, T3 Code AppImage. I built PR head c0559ff together with an unrelated local preview screenshot patch.

Both local Markdown images and view_image output now render inline correctly. The targeted test suite also passed: 218 tests.

sandscooling pushed a commit to sandscooling/t3code that referenced this pull request Aug 4, 2026

@cursor cursor Bot 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.

Want fixes drafted automatically? Bugbot Autofix can create code changes for findings. A team admin can enable Autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 3ec9e15. Configure here.

Comment thread apps/web/src/session-logic.ts
Preserve structured savedPath values in projected item data so generated images still render when the human-readable activity detail is truncated.

Addresses pingdotgg#5114 (comment)

AI-Assisted: true
AI-Agent: codex
AI-Model: openai/gpt-5.6-sol
sandscooling pushed a commit to sandscooling/t3code that referenced this pull request Aug 7, 2026
Upstream be1a836, 54 commits. Both carried pull requests (pingdotgg#4989 mermaid,
pingdotgg#5114 inline images) are still open upstream, so this is a plain merge rather
than the reset-and-replay that a landed pull request forces.

Five files conflicted across eight hunks:

ActivityPayloadProjection.ts: dropStaleRateLimitActivities (local) and
dropSupersededToolUpdatedActivities (upstream b7d1981) were inserted at the
same point. Independent filters, so both are kept and composed.

ClaudeAdapter.ts: upstream pingdotgg#5557 fixes the same interrupt bug as the local
4429c29, and fixes it better. It reads the CLI's own terminal_reason field
rather than tracking an interrupt flag across the session, and separately
filters [ede_diagnostic] strings out of the error banner. Upstream's version
is taken and all nine pieces of the local fix are reverted, along with the two
tests that covered the reverted implementation. The third test in that group,
which asserts a genuine failure still reports as an error, passes against
upstream's fix and is kept. Local plan-usage work in the same file is
untouched.

ChatView.tsx: the local turnInterruptionNotice and upstream's new turnPlans
argument collided on one call. deriveTimelineEntries takes both, so both are
passed.

ComposerPendingUserInputPanel.tsx: local collapsible chrome versus upstream's
theme library restyle (85b1734). Upstream's change to this file is five
className token swaps and nothing structural, so the local structure is kept
and the five swaps applied to it.

pnpm-lock.yaml: regenerated on upstream's lockfile; mermaid re-added.

Verified: web 1983 tests pass, web and server typechecks clean. The server
suite fails 30 files / 116 tests on Windows, which is pre-existing and not
from this merge. Every failing file was compared against the pre-merge tree:
27 fail identically, 2 more outside src/ fail identically, one test in
ProviderRegistry that failed before now passes, and the only new failures are
3 brand new upstream tests in cloud/http.test.ts that hit a pre-existing
Windows incompatibility (fsync on a directory handle in serviceLauncher.ts,
from upstream pingdotgg#5181, already present in the base). Upstream CI runs Ubuntu and
macOS only, so this suite has never been green on Windows.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L 100-499 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature]: Codex image generation support

2 participants