Compact tool activity regressed into separate Activity rows and standalone Thinking blurbs when interim assistant text retired the current live activity group and Thinking rendered outside the disclosure.
Render Compact-mode Thinking inside the shared Activity body for live and settled turns, keep interim assistant text from splitting the current Activity group, and remove the now-unused stream-local activity-close path. This restores the intended single compact disclosure without adding new functionality.
When a queued message was waiting for the active stream to finish,
the 120ms setTimeout drain in setBusy(false) would write the queued
text to the shared #msg composer and call send(), which reads
S.session.session_id at call time. If the user switched to a different
chat during the 120ms window, the queued message was sent to the
wrong session.
Two fixes:
1. setBusy(false) drain: guard the setTimeout callback — if the
currently viewed session no longer matches the drain session,
put the message back into the original session's queue instead
of sending it.
2. _sendInProgress re-queue: track _sendInProgressSid alongside
_sendInProgress so that when a concurrent send() is caught by the
guard, the re-queued message targets the in-flight session rather
than the currently viewed one.
Adds a "Download Folder" item to the workspace file-tree right-click
menu and a GET /api/folder/download endpoint that streams the
directory as a zip with Content-Disposition: attachment.
Configurable caps:
HERMES_WEBUI_FOLDER_ZIP_MAX_MB (default 1024)
HERMES_WEBUI_FOLDER_ZIP_MAX_FILES (default 50000)
Pre-flights the walk so cap-exceeded returns 413 + JSON BEFORE any
zip bytes are sent. Symlinks resolving outside the workspace are
skipped. Mirrors the existing _handle_file_raw shape (session_id
resolution, safe_resolve, RFC 5987 filename via
_content_disposition_value). Stdlib zipfile only; no new dependencies.
Tests: 11 static-inspection tests matching the style of
tests/test_issue1867_upload_size_preflight.py. All passing on
Python 3.11/3.12/3.13.
Adds a reload button to the app titlebar visible only in PWA standalone
or fullscreen mode, and a pull-to-refresh gesture on the messages container
that smooth-scrolls to the top before activating.
The reload button sits next to the message count label and provides a
one-tap refresh for users who installed the WebUI as a home-screen app
where browser navigation controls are unavailable.
The pull-to-refresh gesture detects downward drag at the top of the
message list, shows a visual indicator ('Pull to refresh' / 'Release to refresh'),
and reloads on release past the 80px threshold. When triggered mid-conversation,
it smooth-scrolls to the top first.
Opus advisor review of stage-375 flagged that the protected-bracket set including `<` and `>` caused tables containing comparison operators across adjacent columns to mis-collapse: `| x < 5 | y > 10 |` matched `< ... >` as a bracket pair and stashed the inner pipe, producing one cell instead of two.
Real LLM table output uses angle brackets as comparison operators far more often than as content-grouping pairs, so the safer default is to NOT treat them as a matched pair. Dropped `<` from the opener class and `>` from both closer classes.
Three regression tests added (`TestComparisonOperatorsAcrossColumns` class): `< … >` across columns, `<` alone, `>` alone.
PR #2428's iterative _protectPipes regex introduced two issues we caught during stage assembly:
1. The negated character classes [^)\]}'>] added `'` as a stop character. That breaks cells containing string-literal pipes like `('a'|'b')` (Python type-union examples) — they would still mis-split. Dropped the apostrophe-stop.
2. The literal `}` inside the regex character classes confused the brace-counting extractFunc driver in tests/test_renderer_js_behaviour.py, breaking all 45 existing node-driven renderer tests. Rewrote both brace literals as hex escapes (\\x7b and \\x7d) — semantically identical at the regex-engine level but the JS source carries no bare brace glyph.
Also added tests/test_issue2428_table_pipe_protection.py with 9 regression tests covering single-pipe, multi-pipe-in-brackets, apostrophes-with-pipes, and the KaTeX \$...\$ guard.