github nesquena/hermes-webui v0.51.130
v0.51.130 — Release DB (profile-isolation + boot + Artifacts tab)

latest releases: v0.51.132, v0.51.131
5 hours ago

Release DB — v0.51.130 (stage-batch12, 3-PR profile-isolation + boot-precedence + Artifacts tab)

What's in this batch

Profile isolation fix (brick-class-adjacent)

  • #2827 by @Koraji95-coder — Closes #2762. WebUI cookie-switched profiles were leaking session token-usage / title writes to the previously-active profile's state.db (sidecar messages + workspace files already routed correctly; only the state.db sidecar sync leaked). Root cause: cookie middleware sets _tls.profile on the HTTP thread, but the daemon thread spawned in _run_agent_streaming doesn't inherit it. Fix plumbs profile= through sync_session_usage_get_state_db instead of relying on TLS. Adds defensive _validate_profile_name (rejects path traversal, leading-dash, whitespace, over-long, Unicode bidi). 11 regression tests.

Boot model precedence follow-up

  • #2726 by @starship-s — Refines v0.51.105 #2709 boot-default precedence fix. Original was over-broad in 2 ways: unconditionally cleared persisted browser model state even on restored sessions, and reapplied default on every dropdown repopulate clobbering the in-page selection. Fix gates the default-reapply behind opt-in {preferProfileDefaultOnFreshBoot: true} parameter. +306 LOC tests using a Node DOM shim.

Workspace Artifacts tab

  • #2673 by @AJV20 — Closes #2655. New tab in workspace panel showing files mentioned/edited during the session. MVP frontend-scoped; surfaces from existing tool-call event stream. Empty-state copy: "Open a conversation to see files changed in this session." Composes cleanly with #2716's session stale-guard pattern via typeof === 'function' defensive check.

Cherry-pick mechanics + in-stage fixes

All 3 PRs on stale-base merge-bases. Used git apply --3way of each PR's net delta onto current stage HEAD. Two JS conflicts resolved manually:

  • boot.js (#2726 vs post-#2716 master): kept PR's parameterized populateModelDropdown call
  • workspace.js (#2673 vs post-#2716 master): kept master's sessionId stale-guard AND added PR's renderSessionArtifacts() refresh

Test fixes:

  • 3 brittle source-string assertions patched to accept both pre-#2716 and post-#2716 JS shapes (variable name changes, semantics preserved)
  • tests/test_issue2762_state_sync_profile_kwarg.py::_read_session helper patched to query real state.db schema (sessions.id PRIMARY KEY, not session_id; test was always broken against the actual schema — verified by checking api/state_sync.py:174 which UPDATEs WHERE id = ?)

Conflict-resolution bug caught + fixed: My earlier resolution between #2716 and #2726 dropped the const sessionModelState=... declaration in _hydrateBootModelDropdown, but the callback body references it on 6 lines. Boot.js would have ReferenceError'd on every boot. Caught by tests/test_new_chat_default_model_frontend.py::test_boot_model_hydration_prefers_active_session_over_persisted_model brittle source-string assertion. Restored.

Opus pre-release advisor verdict

SHIP, with 1 MUST-FIX patched inline (1 LOC):

  • api/routes.py:9007 — parity fix for sync_session_usage call site in _handle_chat_sync. The PR fixed api/streaming.py:5078 (worker thread, where the leak manifested), but a second production call site at api/routes.py:9007 (HTTP thread, where TLS works fine today) didn't receive the parity update. Safe TODAY, but defense-in-depth: anyone wrapping that handler in a worker pool later silently regresses the fix. Added profile=getattr(s, 'profile', None).

All 7 risk areas verified clean (sessionModelState near-miss restoration byte-equivalent to pre-cherry-pick; #2726 preserves #2709's brick-class fix without destructive localStorage delete; profile validation regex tight against bidi/null-byte/traversal/leading-dash/whitespace/over-long; test schema patch matches production SQL; Artifacts tab composition correct).

Follow-up issue to file: Artifacts tab false-positive — read-only tool calls (read_file, search_files) appear in the Artifacts list despite empty-state copy promising "created or edited". Gate _artifactCandidatesFromToolCall args-path extraction on ARTIFACT_MUTATION_TOOLS.has(name) (preferred) or relax the empty-state copy to "Files touched by this session". ~10 LOC, not blocking.

Verification

  • ✅ Full pytest: 6,485 passed / 6 skipped / 3 xpassed / 8 subtests passed in 2m30s
  • ✅ JS syntax green on all touched files (boot.js, ui.js, workspace.js, messages.js, sessions.js)
  • ✅ Python syntax green on api/state_sync.py + api/streaming.py + api/routes.py
  • ✅ Agent self-verified: profile= threading on _get_state_db / sync_session_usage / production call sites, populateModelDropdown opt-in parameterization, sessionModelState definition restored, renderSessionArtifacts defined + called from stale-guarded loadDir
  • ✅ Browser-verified at 1920×1080: Artifacts tab renders in workspace panel with proper segmented tabs and empty-state copy
  • ✅ Opus pre-release advisor reviewed 7 risk areas — 1 MUST-FIX patched inline, 1 follow-up filed

Closes

  • #2762 (profile isolation TLS-vs-thread)
  • #2655 (workspace Artifacts tab)

🤖 Generated and reviewed end-to-end by the agent pipeline. The pipeline caught 1 conflict-resolution bug mid-stage (sessionModelState declaration), 4 brittle source-string assertions needing post-cherry-pick updates, and 1 test schema mismatch — all fixed inline. Opus pre-release advisor caught 1 defense-in-depth gap; patched inline. Net: +906/-46 across 13 files.

What's Changed

  • Release DB — v0.51.130 (stage-batch12, 3-PR profile-isolation + boot-precedence + workspace Artifacts tab) by @nesquena-hermes in #2869

Full Changelog: v0.51.129...v0.51.130

Don't miss a new hermes-webui release

NewReleases is sending notifications on new releases.