Skip to content

feat: add DeepSeek models, fix Shell tab switching, add image/PDF preview#742

Draft
z2512690268 wants to merge 2 commits intositeboon:mainfrom
z2512690268:feature/shell-fixes-and-file-preview
Draft

feat: add DeepSeek models, fix Shell tab switching, add image/PDF preview#742
z2512690268 wants to merge 2 commits intositeboon:mainfrom
z2512690268:feature/shell-fixes-and-file-preview

Conversation

@z2512690268
Copy link
Copy Markdown

@z2512690268 z2512690268 commented May 5, 2026

Summary

  • Add DeepSeek models: Added deepseek-v4-flash and deepseek-v4-pro to the model selector
  • Fix Shell→Chat→Shell tab switching: The Shell component now stays mounted with CSS absolute positioning instead of being conditionally rendered. This prevents the PTY process from being killed when switching tabs. Also fixed an onExit race condition where a killed PTY's exit event would interfere with the replacement PTY session.
  • Fix xterm.js layout corruption: When the Shell tab becomes visible after being hidden, the terminal now correctly recalculates its dimensions.
  • Add image preview in code editor: Images clicked from Chat/Git/etc. now render in a dedicated preview component instead of showing "Cannot display binary file."
  • Add PDF preview in code editor: PDF files now render inline via <iframe> in the editor sidebar/fullscreen overlay.

Changes

File Change
shared/modelConstants.js Add DeepSeek model entries
server/modules/websocket/services/shell-websocket.service.ts Fix PTY onExit race condition, add PTY identity checks
src/components/main-content/view/MainContent.tsx Keep Shell mounted, use absolute positioning for tab switching
src/components/shell/view/Shell.tsx Re-fit xterm.js when tab becomes visible
src/components/shell/hooks/useShellRuntime.ts Export fitAddonRef for dimension recalculation
src/components/shell/types/types.ts Add fitAddonRef to result type
src/components/code-editor/utils/binaryFile.ts Split file detection into image/PDF/binary categories
src/components/code-editor/hooks/useCodeEditorDocument.ts Expose fileCategory for preview routing
src/components/code-editor/view/CodeEditor.tsx Wire image/PDF preview components
src/components/code-editor/view/subcomponents/CodeEditorImagePreview.tsx New image preview component
src/components/code-editor/view/subcomponents/CodeEditorPdfPreview.tsx New PDF preview component

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Image and PDF previews in the code editor
    • Added DeepSeek V4 Flash and V4 Pro model options
  • Improvements

    • Shell reconnections now start fresh sessions to avoid stale output
    • Shell terminal refitting/focus improved when switching tabs; shell disconnects on unmount
    • More accurate file type detection and handling for images, PDFs, and binaries

…view

- Add deepseek-v4-flash and deepseek-v4-pro to model selector
- Fix Shell→Chat→Shell switching: keep Shell mounted with absolute
  positioning instead of unmounting, preventing PTY teardown
- Fix PTY onExit race condition when old PTY is killed and new one
  is spawned
- Add image and PDF preview in code editor sidebar/fullscreen
- Fix xterm.js layout corruption when Shell tab becomes visible
  after being hidden

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 5, 2026

📝 Walkthrough

Walkthrough

Server-side shell websocket now always replaces prior PTY on reconnect and guards stdout/exit handlers; client-side adds file category detection with image/pdf previews, new image/pdf preview components, main-content overlay layout changes, and shell terminal fit/teardown improvements. Two Claude model options were added.

Changes

Shell WebSocket Session Management (server)

Layer / File(s) Summary
Reconnection Logic
server/modules/websocket/services/shell-websocket.service.ts
On init, previous PTY session is cleared: timeout cleared, prior PTY best-effort killed, map entry deleted; reconnect no longer reattaches or replays buffered output.
Output Handling
server/modules/websocket/services/shell-websocket.service.ts
PTY onData handler captures the spawned PTY and ignores output unless the session map still references that exact PTY instance.
Exit/Cleanup
server/modules/websocket/services/shell-websocket.service.ts
PTY onExit only notifies and cleans when the exiting PTY is still the active one for the session key; timeout clearing and shellProcess nulling are guarded and conditional.

File Category & Preview System (client)

Layer / File(s) Summary
File Classification
src/components/code-editor/utils/binaryFile.ts
Adds IMAGE_EXTENSIONS, PDF_EXTENSIONS, getExt(), isImageFile(), isPdfFile(), FileCategory type, and getFileCategory(); isBinaryFile() refactored to use getExt() and exclude PDFs.
Hook Integration
src/components/code-editor/hooks/useCodeEditorDocument.ts
Replaces isBinary state with fileCategory state; computes category via getFileCategory() and early-returns for non-text categories; isBinary derived from fileCategory === 'binary'.
Editor Wiring
src/components/code-editor/view/CodeEditor.tsx
Pulls fileCategory from the hook and early-returns to render image/pdf previews before the binary-file handler; introduces previewFile to ensure projectId is populated.
Image Preview Component
src/components/code-editor/view/subcomponents/CodeEditorImagePreview.tsx
New component that fetches an image blob via api.readFileBlob, creates an object URL, renders preview (sidebar and fullscreen modes), handles loading/error states, and revokes URL on cleanup.
PDF Preview Component
src/components/code-editor/view/subcomponents/CodeEditorPdfPreview.tsx
New component that fetches a PDF blob, renders it in an iframe, supports sidebar/fullscreen modes, handles loading/error states, and revokes URL on cleanup.

Claude Model Options

Layer / File(s) Summary
Model Registry
shared/modelConstants.js
Adds deepseek-v4-flash and deepseek-v4-pro entries to CLAUDE_MODELS.OPTIONS with display labels.

Shell Display & Overlay Infrastructure (client)

Layer / File(s) Summary
Layout Changes
src/components/main-content/view/MainContent.tsx
Converts chat and shell regions to absolute overlays controlled by z-index and invisible instead of conditional block/hidden rendering.
Runtime Teardown
src/components/shell/hooks/useShellRuntime.ts, src/components/shell/types/types.ts
Adds unmount cleanup to disconnect shell and dispose the terminal; exposes fitAddonRef in the hook return and type.
Terminal Fit Behavior
src/components/shell/view/Shell.tsx
Replaces previous focus effect with a delayed call to fitAddonRef.current?.fit() then focus, with timeout cleanup to handle overlay transitions.

Sequence Diagram

sequenceDiagram
  participant Client as Client (WebSocket)
  participant Server as Server (WebSocket handler)
  participant PTY as PTY process

  Note over Client,Server: Reconnect sequence (new behavior)
  Client->>Server: open websocket (init, sessionKey)
  Server->>Server: lookup session map by sessionKey
  alt existing session present
    Server->>PTY: clear session timeout
    Server->>PTY: attempt to kill prior PTY (best-effort)
    Server->>Server: delete session map entry
  end
  Server->>PTY: spawn new PTY
  PTY-->>Server: onData events (bound to spawned PTY)
  Server->>Client: relay PTY output
  PTY-->>Server: onExit (only acts if session still references spawned PTY)
  Server->>Client: send exit/cleanup messages
Loading

Possibly Related PRs

  • siteboon/claudecodeui#402: Related changes to shell/WebSocket and client shell integration (server-side and client-side terminal wiring).
  • siteboon/claudecodeui#480: Related client changes to shell runtime/hooks and terminal UI wiring (refs/fit behavior).
  • siteboon/claudecodeui#444: Prior edits to code-editor binary detection and hook return shape; directly related to the file-category refactor.

Suggested Reviewers

  • viper151
  • blackmammoth

Poem

🐇
I hopped in with whiskers bright and steady,
Cleared stale PTYs so shells stay ready,
Images and PDFs now bloom in view,
Terminals fit true when tabs slide through,
A little rabbit cheers: preview and steady!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 14.29% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately and concisely summarizes the three main changes: DeepSeek model support, Shell tab switching fix, and image/PDF preview functionality.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


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 and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
server/modules/websocket/services/shell-websocket.service.ts (1)

268-275: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Critical: stale PTY callbacks race because they read mutable outer bindings.

At lines 273–274 and 349–352, callbacks read ptySessionKey and shellProcess from mutable outer scope. When a subsequent init call reassigns these variables to new values, old PTY handlers can evaluate against the new PTY and incorrectly pass the identity guard, causing stale output emission or deletion of the active session.

Proposed fix: capture immutable key/process per spawned PTY
-        ptySessionKey = `${projectPath}_${sessionId ?? 'default'}${commandSuffix}`;
+        const sessionKey = `${projectPath}_${sessionId ?? 'default'}${commandSuffix}`;
+        ptySessionKey = sessionKey;
...
-        shellProcess = pty.spawn(shell, shellArgs, {
+        const spawnedPty = pty.spawn(shell, shellArgs, {
           name: 'xterm-256color',
           cols: termCols,
           rows: termRows,
           cwd: resolvedProjectPath,
           env: {
             ...process.env,
             TERM: 'xterm-256color',
             COLORTERM: 'truecolor',
             FORCE_COLOR: '3',
           },
         });
+        shellProcess = spawnedPty;
 
-        ptySessionsMap.set(ptySessionKey, {
-          pty: shellProcess,
+        ptySessionsMap.set(sessionKey, {
+          pty: spawnedPty,
           ws,
           buffer: [],
           timeoutId: null,
           projectPath,
           sessionId,
         });
 
-        shellProcess.onData((chunk) => {
-          if (!ptySessionKey) {
-            return;
-          }
-
-          const session = ptySessionsMap.get(ptySessionKey);
-          if (!session || session.pty !== shellProcess) {
+        spawnedPty.onData((chunk) => {
+          const session = ptySessionsMap.get(sessionKey);
+          if (!session || session.pty !== spawnedPty) {
             return;
           }
...
-        shellProcess.onExit((exitCode) => {
-          if (!ptySessionKey) {
-            return;
-          }
-
-          const session = ptySessionsMap.get(ptySessionKey);
+        spawnedPty.onExit((exitCode) => {
+          const session = ptySessionsMap.get(sessionKey);
           // Only act if this PTY is still the active one — a replacement PTY
           // may have been spawned while this one was being killed.
-          if (!session || session.pty !== shellProcess) {
+          if (!session || session.pty !== spawnedPty) {
             return;
           }
...
-          ptySessionsMap.delete(ptySessionKey);
-          shellProcess = null;
+          ptySessionsMap.delete(sessionKey);
+          if (shellProcess === spawnedPty) {
+            shellProcess = null;
+          }
         });

Also applies to: 344–354

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/modules/websocket/services/shell-websocket.service.ts` around lines
268 - 275, The callbacks for shellProcess (shellProcess.onData and
shellProcess.onExit) are closing over mutable outer variables ptySessionKey and
shellProcess, causing race conditions when init/spawn reassigns them; fix by
capturing immutable locals inside the spawn/init scope (e.g., const
localPtySessionKey = ptySessionKey and const localShell = shellProcess) and use
those in the onData/onExit handlers and when calling ptySessionsMap.get,
ptySessionsMap.delete, and any identity checks so each PTY's handlers always
reference the correct process/key and removal uses the same captured references.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@shared/modelConstants.js`:
- Around line 23-24: The DeepSeek entries were incorrectly placed in
CLAUDE_MODELS causing provider selection to stay "claude" and triggering
queryClaudeSDK with invalid models; fix by removing the DeepSeek entries from
CLAUDE_MODELS and adding a new DEEPSEEK_MODELS constant (with the
deepseek-v4-flash and deepseek-v4-pro values), add a corresponding PROVIDERS
entry for provider id "deepseek" and implement/route to a queryDeepSeekSDK
handler (or extend the provider dispatch logic) so the agent route handler
selects the "deepseek" provider instead of calling queryClaudeSDK for DeepSeek
models.

In `@src/components/code-editor/view/CodeEditor.tsx`:
- Around line 169-190: The image/pdf preview branches pass the original file
object which can lack projectId (the preview components use file.projectId ??
''), so preserve the fallback by forwarding a file with projectId populated from
projectPath when missing; update the CodeEditorImagePreview and
CodeEditorPdfPreview calls to pass {...file, projectId: file.projectId ??
file.projectPath ?? ''} so the previews request the correct project id.

In `@src/components/code-editor/view/subcomponents/CodeEditorPdfPreview.tsx`:
- Around line 93-103: The close (and fullscreen) icon-only buttons in
CodeEditorPdfPreview.tsx lack explicit accessible names; add aria-label
attributes (e.g., aria-label="Close" for the button that calls onClose and
aria-label="Toggle fullscreen" or similar for the fullscreen control) to ensure
screen readers get a reliable name, and mirror the same changes in
CodeEditorImagePreview.tsx for the equivalent buttons; leave the existing title
prop if desired but ensure aria-label is present on the <button> elements that
use onClose and the fullscreen handler.

---

Outside diff comments:
In `@server/modules/websocket/services/shell-websocket.service.ts`:
- Around line 268-275: The callbacks for shellProcess (shellProcess.onData and
shellProcess.onExit) are closing over mutable outer variables ptySessionKey and
shellProcess, causing race conditions when init/spawn reassigns them; fix by
capturing immutable locals inside the spawn/init scope (e.g., const
localPtySessionKey = ptySessionKey and const localShell = shellProcess) and use
those in the onData/onExit handlers and when calling ptySessionsMap.get,
ptySessionsMap.delete, and any identity checks so each PTY's handlers always
reference the correct process/key and removal uses the same captured references.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 80f9297e-56c1-4cb9-a510-a8109ad62538

📥 Commits

Reviewing files that changed from the base of the PR and between beb0a50 and 2e648a0.

📒 Files selected for processing (11)
  • server/modules/websocket/services/shell-websocket.service.ts
  • shared/modelConstants.js
  • src/components/code-editor/hooks/useCodeEditorDocument.ts
  • src/components/code-editor/utils/binaryFile.ts
  • src/components/code-editor/view/CodeEditor.tsx
  • src/components/code-editor/view/subcomponents/CodeEditorImagePreview.tsx
  • src/components/code-editor/view/subcomponents/CodeEditorPdfPreview.tsx
  • src/components/main-content/view/MainContent.tsx
  • src/components/shell/hooks/useShellRuntime.ts
  • src/components/shell/types/types.ts
  • src/components/shell/view/Shell.tsx

Comment thread shared/modelConstants.js
Comment on lines +23 to +24
{ value: "deepseek-v4-flash", label: "DeepSeek V4 Flash" },
{ value: "deepseek-v4-pro", label: "DeepSeek V4 Pro" },
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.

⚠️ Potential issue | 🔴 Critical | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify how CLAUDE_MODELS / PROVIDERS are consumed downstream to determine
# if DeepSeek entries being under the "claude" provider causes routing failures.

# Find all files that import or reference CLAUDE_MODELS or PROVIDERS
rg -n --type=ts --type=js -C3 'CLAUDE_MODELS|PROVIDERS' \
  -g '!shared/modelConstants.js'

Repository: siteboon/claudecodeui

Length of output: 11976


🏁 Script executed:

#!/bin/bash
# Search for API endpoint/base URL configuration and how it's determined by provider
rg -n --type=js --type=ts 'endpoint|baseUrl|BASE_URL|api\.anthropic|api\.deepseek' \
  -A2 -B2 | head -100

Repository: siteboon/claudecodeui

Length of output: 5764


🏁 Script executed:

#!/bin/bash
# Search for any DeepSeek-specific handling in backend
rg -n --type=js --type=ts -i 'deepseek' \
  server/ src/

Repository: siteboon/claudecodeui

Length of output: 47


🏁 Script executed:

#!/bin/bash
# Check claude-sdk.js to see how it's initialized and whether it uses provider-specific config
head -80 server/claude-sdk.js

Repository: siteboon/claudecodeui

Length of output: 2539


🏁 Script executed:

#!/bin/bash
# Search for where backend routes based on provider to different SDK handlers
rg -n --type=js 'provider.*===.*claude|if.*provider' server/routes/ -A3 -B1

Repository: siteboon/claudecodeui

Length of output: 3477


🏁 Script executed:

#!/bin/bash
# Look for where queryClaude, queryGemini, queryCodex functions are called
rg -n --type=js 'queryClaude|queryGemini|queryCodex|spawnGemini' server/ -B5 -A2 | head -150

Repository: siteboon/claudecodeui

Length of output: 7769


🏁 Script executed:

#!/bin/bash
# Check agent.js to see the main dispatch logic
cat -n server/routes/agent.js | head -100

Repository: siteboon/claudecodeui

Length of output: 3921


🏁 Script executed:

#!/bin/bash
# Check queryClaudeSDK to see if there's any endpoint override based on model name
sed -n '200,250p' server/claude-sdk.js

Repository: siteboon/claudecodeui

Length of output: 1618


🏁 Script executed:

#!/bin/bash
# Search for any endpoint/baseUrl configuration in claude-sdk.js
rg -n 'baseUrl|BASE_URL|endpoint|api\.anthropic' server/claude-sdk.js -B2 -A2

Repository: siteboon/claudecodeui

Length of output: 309


DeepSeek models misclassified under CLAUDE_MODELS — will cause runtime failures

CLAUDE_MODELS is explicitly the "Claude (Anthropic) Models" section, and the backend's provider dispatch logic (server/routes/agent.js:942) uses hardcoded if/else on provider ID. When a user selects a DeepSeek model from the frontend, the provider remains "claude", triggering queryClaudeSDK() at runtime.

The queryClaudeSDK() function (server/claude-sdk.js:207) passes the model value directly to the Anthropic SDK without any endpoint override or model-based routing. This means a request with model="deepseek-v4-flash" will be sent to the Anthropic API, which will reject it as an invalid model, causing the request to fail.

These models require either a dedicated DEEPSEEK_MODELS constant with a corresponding PROVIDERS entry and backend handler, or routing logic that intercepts DeepSeek model names and redirects them to the correct endpoint and API client.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@shared/modelConstants.js` around lines 23 - 24, The DeepSeek entries were
incorrectly placed in CLAUDE_MODELS causing provider selection to stay "claude"
and triggering queryClaudeSDK with invalid models; fix by removing the DeepSeek
entries from CLAUDE_MODELS and adding a new DEEPSEEK_MODELS constant (with the
deepseek-v4-flash and deepseek-v4-pro values), add a corresponding PROVIDERS
entry for provider id "deepseek" and implement/route to a queryDeepSeekSDK
handler (or extend the provider dispatch logic) so the agent route handler
selects the "deepseek" provider instead of calling queryClaudeSDK for DeepSeek
models.

Comment thread src/components/code-editor/view/CodeEditor.tsx
…iolation

The previewFile useMemo was placed after the if (loading) early return,
causing a white screen on file open. Moved it before the loading check.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/components/code-editor/view/subcomponents/CodeEditorImagePreview.tsx`:
- Around line 30-47: The imageUrl state isn't cleared when a new load starts or
when loading fails, causing the UI to show a stale <img> alongside an error;
update the CodeEditorImagePreview component to call setImageUrl(null) (or '') at
the start of the load (near setLoading(true); setError(null);) and again inside
the catch block before setError('Unable to load image'), and ensure any previous
objectUrl is revoked (URL.revokeObjectURL) when replacing/clearing it to avoid
leaks; reference the setImageUrl, setLoading, setError calls and the objectUrl
variable when making these changes.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: dfaf9be2-0d6e-43a4-a3c5-647da27d1bc9

📥 Commits

Reviewing files that changed from the base of the PR and between 2e648a0 and 48d9af8.

📒 Files selected for processing (4)
  • server/modules/websocket/services/shell-websocket.service.ts
  • src/components/code-editor/view/CodeEditor.tsx
  • src/components/code-editor/view/subcomponents/CodeEditorImagePreview.tsx
  • src/components/code-editor/view/subcomponents/CodeEditorPdfPreview.tsx
✅ Files skipped from review due to trivial changes (1)
  • src/components/code-editor/view/subcomponents/CodeEditorPdfPreview.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/components/code-editor/view/CodeEditor.tsx
  • server/modules/websocket/services/shell-websocket.service.ts

Comment on lines +30 to +47
setLoading(true);
setError(null);

const response = await api.readFileBlob(file.projectId ?? '', file.path);

if (!response.ok) {
throw new Error(`Request failed with status ${response.status}`);
}

const blob = await response.blob();
if (cancelled) return;
objectUrl = URL.createObjectURL(blob);
setImageUrl(objectUrl);
} catch (err: unknown) {
if (cancelled) return;
console.error('Error loading image:', err);
setError('Unable to load image');
} finally {
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.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Clear imageUrl on reload/failure to avoid mixed success/error UI.

imageUrl is not reset when a new load starts (Line 30) or when load fails (Line 43). If a previous URL remains truthy, Line 68 can still render <img> while Line 75 renders the error block.

Proposed fix
     const loadImage = async () => {
       try {
         setLoading(true);
         setError(null);
+        setImageUrl(null);
 
         const response = await api.readFileBlob(file.projectId ?? '', file.path);
@@
       } catch (err: unknown) {
         if (cancelled) return;
         console.error('Error loading image:', err);
+        setImageUrl(null);
         setError('Unable to load image');
       } finally {
         if (!cancelled) setLoading(false);
       }
     };

Also applies to: 68-77

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/code-editor/view/subcomponents/CodeEditorImagePreview.tsx`
around lines 30 - 47, The imageUrl state isn't cleared when a new load starts or
when loading fails, causing the UI to show a stale <img> alongside an error;
update the CodeEditorImagePreview component to call setImageUrl(null) (or '') at
the start of the load (near setLoading(true); setError(null);) and again inside
the catch block before setError('Unable to load image'), and ensure any previous
objectUrl is revoked (URL.revokeObjectURL) when replacing/clearing it to avoid
leaks; reference the setImageUrl, setLoading, setError calls and the objectUrl
variable when making these changes.

@blackmammoth
Copy link
Copy Markdown
Collaborator

Hey @z2512690268, thanks for the PR! Please separate the work into different pieces and submit a pr for each one of them. For e.g. adding a deep seek model should be a separate PR.

@blackmammoth blackmammoth marked this pull request as draft May 5, 2026 13:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants