Skip to content

fix(desktop): attach non-image web uploads by path instead of failing the read - #103

Merged
ashneil12 merged 1 commit into
mainfrom
fix/web-nonimage-attach-path-only
Jun 13, 2026
Merged

ashneil12 merged 1 commit into
mainfrom
fix/web-nonimage-attach-path-only

Conversation

@ashneil12

Copy link
Copy Markdown
Owner

Problem

In the hosted web rich-chat (vweb client), dropping a non-image file (.md, .txt, .pdf, …) fails with a "Drop files / Could not read <name>" toast. Images work; other files don't. The upload itself succeeds — the file lands at ~/.hermes/uploads/<date>/<name> and the chip shows that server path — but the attach then errors.

Root cause

The hosted web SPA has no local filesystem. A dropped non-image file is uploaded to ~/.hermes/uploads via the web shim and attached as a kind:'file' ref pointing at that server path. At submit/eager-upload time, uploadComposerAttachment re-read the bytes client-side via window.hermesDesktop.readFileDataUrl(serverPath).

But the web shim's readFileDataUrl only serves an in-memory cache that uploadBrowserFile populates for images only (web-shim.ts gates the cache write on image/*). So for any non-image file the read returns '' → null → throw new Error('Could not read ' + label) (use-prompt-actions.ts), where label is the server basename — exactly the toast in the screenshot. Images escape only because their bytes are cached at drop time.

Fix

In the hosted web client, skip the client-side byte read for non-image files and attach by path only. The file already lives on the gateway (~/.hermes/uploads, made agent-readable by the upload endpoint's chown), so file.attach resolves the path directly — _stage_session_file_attachment Case 2 reads the bytes and returns an @file: ref. No data_url round-trip, no 16 MB cap, no double upload.

  • Native Electron remote mode is unchanged — its paths live on the client disk and still upload bytes.
  • Gated on window.__HERMES_WEB_CLIENT__ (set by lib/web-shim.ts), matching the existing web-detection idiom.
  • Verified end-to-end against the gateway: _resolve_attachment_path resolves any existing absolute file (no allowlist), so the uploads path resolves into Case 2.

Test

Adds a regression test: the web client attaches a non-image file by path, with no client read and no data_url, and returns the gateway @file: ref.

Rollout

Canary-first. After merge: publish a new canary image and redeploy a canary instance to verify a real .md drop, then port to prod.

… the read

The hosted web SPA (vweb) has no local filesystem. When a .md/text/pdf is
dropped it is uploaded to ~/.hermes/uploads via the web shim and attached as
a kind:'file' ref pointing at that server path. At submit/eager-upload time
uploadComposerAttachment then re-read the file's bytes client-side via
window.hermesDesktop.readFileDataUrl(serverPath). The web shim only caches
data URLs for IMAGES (uploadBrowserFile gates the cache write on image/*
mime), so for any non-image file the read returned '' and the code threw
`Could not read <server-name>`, surfaced as the "Drop files / Could not read
…md" toast — even though the upload itself had already succeeded. Images
worked only because their bytes are cached.

Fix: in the hosted web client, skip the client-side byte read for non-image
files and attach by path only. The file already lives on the gateway
(~/.hermes/uploads, made agent-readable by the upload endpoint's chown), so
file.attach resolves the path directly (server.py _stage_session_file_attachment
Case 2 reads the bytes and returns an @file: ref). Native Electron remote mode
is unchanged — its paths live on the client disk and still upload bytes.

Adds a regression test asserting the web client attaches by path with no read
and no data_url.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

🔎 Lint report: fix/web-nonimage-attach-path-only vs origin/main

ruff

Total: 0 on HEAD, 0 on base (➖ 0)

🆕 New issues: none

✅ Fixed issues: none

Unchanged: 0 pre-existing issues carried over.

ty (type checker)

Total: 10932 on HEAD, 10932 on base (➖ 0)

🆕 New issues: none

✅ Fixed issues: none

Unchanged: 5741 pre-existing issues carried over.

Diagnostics are surfaced as warnings — this check never fails the build.

@ashneil12
ashneil12 merged commit 7f7cc5c into main Jun 13, 2026
25 checks passed
@ashneil12
ashneil12 deleted the fix/web-nonimage-attach-path-only branch June 13, 2026 08:03
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.

1 participant