hermes-agent/web/src/pages
Ben Barclay c661634537
fix(dashboard): stream file uploads via multipart instead of base64 JSON (NS-501) (#47663)
* fix(dashboard): stream file uploads via multipart instead of base64 JSON

The dashboard file manager uploaded files (including backup/restore zip
archives) by reading them client-side with FileReader.readAsDataURL and
POSTing a base64 data URL inside a JSON body to /api/files/upload. For a
large backup this (a) inflates the payload ~33%, (b) buffers the whole
file plus its decoded copy in memory, and (c) reliably trips an upstream
proxy body-size/timeout limit, surfacing as a 502 with the upload
appearing to hang indefinitely (NS-501). Dashboard-only hosted users have
no shell fallback to place the archive, so backup restore was unusable.

Add a streaming multipart endpoint POST /api/files/upload-stream
(UploadFile + Form) that reads the request body in 1 MiB chunks straight
to a sibling temp file, enforces the existing 100 MB size cap as it
streams (413 on overflow, before buffering the whole file), and
atomically renames into place so a partial/aborted/over-limit upload
never clobbers an existing file. The frontend api.uploadFile now sends
multipart/form-data (raw bytes, no base64, browser-set boundary) and
FilesPage passes the File object directly; the dead readAsDataUrl helper
is removed. The legacy base64 JSON endpoint stays for backward compat.

FastAPI's UploadFile/Form require python-multipart, which is NOT pulled in
by fastapi itself, so it is added to the base deps, the [web] extra, and
the tool.dashboard lazy-install set (kept in sync).

Validated: 5 new endpoint tests (roundtrip, multi-chunk >1 MiB,
over-limit 413 without clobbering + no temp-file leak, overwrite=false
conflict, forced-root traversal containment); existing base64 tests still
pass; web typecheck + vite build clean; and a real uvicorn server E2E
(5 MB multipart upload -> HTTP 200 in 0.21s, exact byte match) plus a
30 MB TestClient roundtrip confirm constant-memory streaming end to end.

Reported via beta (NS-501).

* build(deps): regenerate uv.lock for python-multipart (NS-501)

CI ran uv lock --check / uv sync --locked which failed because the
python-multipart dependency add was not reflected in uv.lock. Regenerate
the lockfile (resolves to 0.0.20, matching the [web] extra pin) after
merging current main.
2026-06-18 15:54:32 +10:00
..
AnalyticsPage.tsx feat(dashboard): nous-blue theme, bulk sessions, schedule picker (#37383) 2026-06-02 12:37:40 -04:00
ChannelsPage.tsx Fix dashboard gateway profile scoping 2026-06-17 05:40:57 -07:00
ChatPage.tsx fix(dashboard): recover the Chat tab when the agent session ends (NS-504) (#47674) 2026-06-18 10:05:26 +10:00
ConfigPage.tsx fix(dashboard): Config page header shows the switched profile's config.yaml path (#44374) 2026-06-11 09:46:15 -07:00
CronPage.tsx refactor(cron): rebrand Cron Recipes -> Automation Blueprints 2026-06-11 10:49:47 -07:00
DocsPage.tsx fix(web): force light color-scheme on docs iframe 2026-05-07 04:55:47 -07:00
EnvPage.tsx feat(dashboard): enrich profiles dashboard and de-dupe channel env vars (#37872) 2026-06-03 10:37:36 -04:00
FilesPage.tsx fix(dashboard): stream file uploads via multipart instead of base64 JSON (NS-501) (#47663) 2026-06-18 15:54:32 +10:00
LogsPage.tsx Merge remote-tracking branch 'origin/main' into refactor/use-ds-primitives 2026-05-28 14:20:49 -04:00
McpPage.tsx feat(dashboard): complete admin panel — MCP catalog, enable/disable toggles, hook creation, system stats (#36736) 2026-06-02 00:16:11 -04:00
ModelsPage.tsx Update implementation to make it cleaner 2026-06-12 11:03:44 -07:00
PairingPage.tsx feat(dashboard): full administration panel — MCP, pairing, webhooks, credentials, memory, gateway, ops (#36704) 2026-06-01 02:58:02 -07:00
PluginsPage.tsx feat(plugins): install from a subdirectory within a repo (#42963) 2026-06-09 13:42:51 -04:00
ProfileBuilderPage.tsx feat(dashboard): clone profiles from any source 2026-06-13 07:33:58 -07:00
ProfilesPage.tsx fix(dashboard): scope chat sidebar model card to selected profile (#46665) 2026-06-15 12:50:19 -04:00
SessionsPage.tsx fix(webui): split merge-into-tail compaction so reply renders as its own bubble (#29824) 2026-06-12 15:41:57 -07:00
SkillsPage.tsx feat(dashboard): SKILL.md editor on Skills page + attach-skill selector in cron modals (#44231) 2026-06-11 06:10:27 -07:00
SystemPage.tsx Detect containerized dashboard update management 2026-06-15 20:08:39 -07:00
WebhooksPage.tsx Enable webhooks from dashboard page 2026-06-10 22:55:06 -07:00