stage-348: 9-PR contributor batch — docs/onboarding + compress fixes + steer badge + perf + thinking-card state + #2171 prefilter URL-marker patch - #2199
Merged
Conversation
Two-part fix: - Backend: handle_get returns True (not None from j()) for compress/status route, preventing edge-case 404 fallback in do_GET - Frontend: resumeManualCompressionForSession silently returns on 404 instead of showing "Compression failed: not found" toast Includes 6 regression tests covering backend return value, idle/empty session responses, and frontend 404 guard presence.
…eam output
Problem: When two messages are sent in rapid succession, the second
send() can pass the S.busy check because setBusy(true) only runs after
the first await inside send(). This creates a window where two async
send() calls run concurrently, leading to:
- Streaming output from the first response getting swallowed when the
second response's done event overwrites S.messages
- User messages disappearing when server returns 409 for the duplicate
chat/start request
Root cause: send() is async and has awaits (uploadPendingFiles,
api('/api/chat/start')) before setBusy(true) at line 198. During those
await yields, S.busy is still false, allowing a second send() to enter.
Fix: Add a synchronous _sendInProgress guard at the very top of send()
(before any await). Concurrent calls re-queue the message instead of
silently dropping it. try/finally ensures the flag resets on all exit
paths.
Also widens the text-extraction window in
test_1062_busy_input_modes.py from 3000 to 5000 chars to accommodate
the new guard block at the top of send().
When busy_input_mode is 'steer' and the steer is accepted by the server, show a transient indicator in the chat area (not in S.messages). This mirrors the CLI/Gateway approach: steer text is never stored in the message array. The done event's S.messages=d.session.messages replacement therefore doesn't cause a flash where all SSE content vanishes and re-appears. The indicator is an independent DOM element (.steer-indicator) appended to msgInner. It naturally disappears when renderMessages rebuilds msgInner on turn completion (done/cancel/error).
_showSteerIndicator function added before _trySteer extends the total capture region. Widen helper_body 1500→2000 and try_body 1200→1600 so assertions on cmd_steer_fallback and S.pendingFiles=[] still land within the window.
fix: keep background metering from overwriting visible session usage (xz-dev)
fix: preserve thinking card state during reasoning updates (xz-dev)
docs: refresh project snapshot and agent onboarding entrypoint (franksong2702)
fix: prevent concurrent send() from losing messages or swallowing stream output (jasonjcwu, split from #2164)
feat: show steer messages in chat with visual badge (jasonjcwu, split from #2164)
fix: keep compression banner attached to the compaction marker (LumenYoung)
fix: prevent 404 on /api/session/compress/status during session switch (jasonjcwu)
fix: refresh context ring after compression (LumenYoung)
Trim session tail response overhead (franksong2702)
…contributor batch
…LOWER_MARKERS Opus advisor flagged that PR #2171's credential prefilter only listed specific DB scheme prefixes and form keys, letting OAuth callback URLs, URL userinfo, signed-URL query params bypass the hard agent redactor. Adding the generic '://' marker restores the WebUI-as-hard-safety-boundary contract. Plain URLs without sensitive substrings still pass through unchanged because the redactor itself only mutates sensitive substrings. Regression-pinned with 5 new parametric cases in test_security_redaction.py plus 1 negative-case companion. Verified test FAILS without the fix and PASSES with it.
The original tests asserted on the final output of _redact_text(), which exercises agent.redact.redact_sensitive_text() from the hermes-agent venv. That function's URL-userinfo / query-param redaction is available locally but not in the CI test environment (different agent install version). Rewrite the tests to assert on the prefilter routing decision instead: _might_contain_sensitive_text() must return True for URL-shaped strings. That's the actual contract #2171 establishes and the regression Opus flagged. The downstream agent redactor behavior is its own contract. Sanity-checked: 5 of 6 URL cases fail when '://' marker reverted, all pass when restored. 62 redaction tests total pass.
SysAdminDoc
pushed a commit
to SysAdminDoc/hermes-webui
that referenced
this pull request
Jun 26, 2026
stage-348: 9-PR contributor batch — docs/onboarding + compress fixes + steer badge + perf + thinking-card state + nesquena#2171 prefilter URL-marker patch
bernyforce
pushed a commit
to bernyforce/hermes-webui
that referenced
this pull request
Jul 29, 2026
stage-348: 9-PR contributor batch — docs/onboarding + compress fixes + steer badge + perf + thinking-card state + nesquena#2171 prefilter URL-marker patch
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
stage-348 — 9-PR contributor batch (v0.51.55)
Per Nathan's standing "no high-risk merges today" directive: 9 low/medium-low-risk PRs ship; 13 deferred to tomorrow; 2 closed-as-superseded.
Composition
_sendInProgresssync flag for concurrent send guard (split from #2164)Stage-348 maintainer fix (Opus SHOULD-FIX-pre-merge)
api/helpers.py:_SENSITIVE_LOWER_MARKERS— add"://"URL marker. Opus advisor flagged that Trim session tail response overhead #2171's credential prefilter only listed specific DB scheme prefixes (postgres://,mysql://, …) and a closed set of form keys, so OAuth callback URLs (?code=...), URL userinfo (https://admin:pw@…), and signed-URL query params (?signature=...,?session=...) bypassed the hard agent redactor entirely — defeating the "WebUI API responses are a hard safety boundary" contract. Adding the generic"://"marker routes every http(s)/ws(s)/ftp URL to the hard redactor. Pinned with 5 new URL/userinfo/query-param regression cases + 1 negative-case for plain URLs.Closed as superseded
Deferred to tomorrow
show_cli_sessions=Truedefault flip, behavior-policy decision.Verification
run-browser-tests.sh: 20/20 QA + 11/11 API checks PASSED in 109s/api/session/compress/status?session_id=fake→ 200 ✓ (was 404 in edge cases pre-fix: prevent 404 on /api/session/compress/status during session switch #2185)_sendInProgresspresent 4× in messages.js ✓ (fix: prevent concurrent send() from losing messages or swallowing stream output #2186)steerin style.css ✓ (feat: show steer messages in chat with visual badge #2187)_live_usage_snapshot()in compressed SSE event ✓ (fix: refresh context ring after compression #2188 — api/streaming.py:3426)S.lastUsage = {...d.usage}on compressed event ✓ (fix: refresh context ring after compression #2188)python -m py_compileclean on all modified.pyfilesnode --checkclean on all modified.jsfiles"://"prefilter fix. Applied inline with regression pin. Zero remaining concerns.Stats