Skip to content

stage-348: 9-PR contributor batch — docs/onboarding + compress fixes + steer badge + perf + thinking-card state + #2171 prefilter URL-marker patch - #2199

Merged
nesquena-hermes merged 27 commits into
masterfrom
stage-348
May 13, 2026
Merged

nesquena-hermes merged 27 commits into
masterfrom
stage-348

Conversation

@nesquena-hermes

Copy link
Copy Markdown
Collaborator

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

PR Author LOC Surface
#2162 franksong2702 433 docs/agent-onboarding refresh (AGENTS.md new, README, ARCHITECTURE, TESTING, onboarding)
#2185 jasonjcwu 144 api/routes.py + commands.js — fix /compress/status 404 on session switch
#2186 jasonjcwu 23 static/messages.js — _sendInProgress sync flag for concurrent send guard (split from #2164)
#2187 jasonjcwu 31 static/commands.js + style.css — steer message visual badge (split from #2164)
#2182 LumenYoung 95 static/ui.js — compression banner placement (2 cases)
#2188 LumenYoung 29 api/streaming.py + messages.js — refresh context ring after compression
#2189 xz-dev 4 static/messages.js — scope live metering to visible session
#2190 xz-dev 11 static/ui.js — preserve thinking-card DOM state during reasoning updates
#2171 franksong2702 331 api/helpers.py + routes.py — session tail response perf (credential prefilter + skip historical tool_calls)

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

Verification

Stats

27 files changed, 1175 insertions(+), 149 deletions(-)

LumenYoung and others added 27 commits May 13, 2026 08:49
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)
…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.
@nesquena-hermes
nesquena-hermes merged commit f5be6e3 into master May 13, 2026
3 checks passed
@nesquena-hermes
nesquena-hermes deleted the stage-348 branch May 13, 2026 17:12
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
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.

4 participants