Commit graph

2040 commits

Author SHA1 Message Date
nesquena-hermes
f5be6e3a69
Merge pull request #2199 from nesquena/stage-348
stage-348: 9-PR contributor batch — docs/onboarding + compress fixes + steer badge + perf + thinking-card state + #2171 prefilter URL-marker patch
2026-05-13 10:11:12 -07:00
Hermes Agent
32ba73c816 stage-348: fix CI-vs-local divergence on Opus prefilter test
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.
2026-05-13 17:08:53 +00:00
Hermes Agent
7c2b2785e7 stage-348: apply Opus SHOULD-FIX-pre-merge — add '://' to _SENSITIVE_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.
2026-05-13 16:54:36 +00:00
Hermes Agent
3bfa0fc885 docs: CHANGELOG stage-348 — close v0.51.54, open Unreleased for 9-PR contributor batch 2026-05-13 16:35:35 +00:00
Hermes Agent
39df1a1ef3 Merge pull request #2171 into stage-348
Trim session tail response overhead (franksong2702)
2026-05-13 16:34:43 +00:00
Hermes Agent
ef042ad8c2 Merge pull request #2188 into stage-348
fix: refresh context ring after compression (LumenYoung)
2026-05-13 16:34:42 +00:00
Hermes Agent
fbd1e27181 Merge pull request #2185 into stage-348
fix: prevent 404 on /api/session/compress/status during session switch (jasonjcwu)
2026-05-13 16:34:40 +00:00
Hermes Agent
479e388be8 Merge pull request #2182 into stage-348
fix: keep compression banner attached to the compaction marker (LumenYoung)
2026-05-13 16:34:39 +00:00
Hermes Agent
63a1855b95 Merge pull request #2187 into stage-348
feat: show steer messages in chat with visual badge (jasonjcwu, split from #2164)
2026-05-13 16:34:38 +00:00
Hermes Agent
785b1fe7e9 Merge pull request #2186 into stage-348
fix: prevent concurrent send() from losing messages or swallowing stream output (jasonjcwu, split from #2164)
2026-05-13 16:34:36 +00:00
Hermes Agent
5ba097c40b Merge pull request #2162 into stage-348
docs: refresh project snapshot and agent onboarding entrypoint (franksong2702)
2026-05-13 16:34:35 +00:00
Hermes Agent
acefaa180e Merge pull request #2190 into stage-348
fix: preserve thinking card state during reasoning updates (xz-dev)
2026-05-13 16:34:34 +00:00
Hermes Agent
3c20e102df Merge pull request #2189 into stage-348
fix: keep background metering from overwriting visible session usage (xz-dev)
2026-05-13 16:34:32 +00:00
Xiangzhe
0b97f6d7ee
fix: preserve thinking card state during reasoning updates 2026-05-13 20:58:50 +08:00
Xiangzhe
1a4e0522a0
fix: keep background metering from overwriting visible session usage 2026-05-13 20:58:50 +08:00
fxd-jason
2567242e2f test: widen _trySteer capture windows for steer indicator code
_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.
2026-05-13 20:30:53 +08:00
fxd-jason
a8816fe22f feat: show steer indicator as transient DOM element
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).
2026-05-13 20:30:44 +08:00
Lumen Yang
3289c44fb6 fix: refresh context ring after compression 2026-05-13 14:02:28 +02:00
Lumen Yang
7f01abf931 fix: ignore stale compaction markers when placing banner 2026-05-13 13:27:51 +02:00
fxd-jason
676d1f965e fix: prevent concurrent send() from losing messages or swallowing stream 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().
2026-05-13 19:21:50 +08:00
Frank Song
da73c00f06 Harden session tail redaction prefilter 2026-05-13 18:58:49 +08:00
fxd-jason
9e45de463d fix: prevent 404 on /api/session/compress/status during session switch
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.
2026-05-13 18:56:55 +08:00
Lumen Yang
bc6a949272 fix: place compression banner at persisted marker 2026-05-13 10:59:36 +02:00
Frank Song
155a727ec1 docs: refresh current snapshot for v0.51.54 2026-05-13 16:56:21 +08:00
Frank Song
65fa18c7d9 docs: add agent onboarding entrypoint 2026-05-13 16:47:14 +08:00
Frank Song
be32b90cea docs: refresh current project snapshot 2026-05-13 16:47:14 +08:00
Frank Song
b7ac5a8b88 Trim session tail response overhead 2026-05-13 15:57:29 +08:00
nesquena-hermes
86740c425e
Merge pull request #2181 from nesquena/stage-347
stage-347: singleton self-built — preserve nvidia/ prefix on NVIDIA NIM (closes #2177)
2026-05-13 00:44:50 -07:00
Hermes Agent
f03239daf2 docs: CHANGELOG stage-347 — close v0.51.53, open Unreleased for #2179 singleton 2026-05-13 07:34:34 +00:00
Hermes Agent
8060b2ba3a Merge pull request #2179 into stage-347
fix(config): preserve nvidia/ prefix on NVIDIA NIM (closes #2177)

Self-built. nesquena APPROVED with extensive end-to-end trace including
cross-tool agent CLI verification and 12-shape behavioural harness.
2026-05-13 07:33:45 +00:00
nesquena-hermes
fdbbb0d92e
Merge pull request #2180 from nesquena/stage-346
stage-346: 10-PR contributor batch — stale-stream guard extension + guarded worktree remove + CSP report collector + perf + i18n + ctl fix
2026-05-13 00:18:54 -07:00
Hermes Agent
fe3f810b56 stage-346: apply Opus SHOULD-FIX (defense-in-depth) — scope /api/csp-report auth bypass to POST only
Opus advisor flagged that PR #2160's CSP-report auth carve-out covered all
write methods on the path, not just POST. Currently harmless (PATCH/DELETE
fall through to CSRF 403 or routing 404), but defense-in-depth — scope the
bypass to its actual use case.

CSP report regression suite (6 tests) still passes.
2026-05-13 07:15:53 +00:00
nesquena-hermes
9b1d786459 fix(config): preserve nvidia/ prefix on NVIDIA NIM (closes #2177)
Move the `_PORTAL_PROVIDERS` guard in `resolve_model_provider()` to run
BEFORE the `prefix == config_provider` strip branch. The guard was added
for NVIDIA (along with the Nous portal cases in #854 / #894) but was
placed after the strip, so it never fired when `config_provider == "nvidia"`
and the model id started with `nvidia/`.

For `model_id="nvidia/nemotron-3-super-120b-a12b"`,
`config_provider="nvidia"`:
  - prefix = "nvidia", bare = "nemotron-3-super-120b-a12b"
  - prefix == config_provider → True → strip branch returned bare name
  - `_PORTAL_PROVIDERS` guard never reached
  - bare "nemotron-3-super-120b-a12b" sent to NVIDIA NIM → HTTP 404

NIM requires the full namespaced path. The fix moves the portal guard
to run first, so all portal providers (Nous, OpenCode-Zen, OpenCode-Go,
NVIDIA NIM) always preserve the full `provider/model` id regardless of
whether the prefix happens to equal the provider name.

This also closes a latent symmetric bug for the Nous case if a
`nous/<model>` id ever existed in the catalog.

Test plan:
- New `tests/test_issue2177_nvidia_prefix_preservation.py` covers:
  - nvidia/nemotron-... under nvidia (the reported case)
  - cross-namespace qwen/ and meta/ under nvidia (regression pin)
  - every static nvidia model in `_PROVIDER_MODELS` resolves to itself
  - latent nous/<model> under nous (structural ordering pin)
  - non-portal providers (anthropic) still strip — fix doesn't over-correct
- Existing portal-routing suites (test_nous_portal_routing.py,
  test_issue895_894_nous_prefix.py) continue to pass.
- Full test suite: 5320 passed, 4 skipped, 3 xpassed.

Reported on Discord by @vishnu (Nathan forwarded as #2177).
2026-05-13 07:05:57 +00:00
Hermes Agent
55047e19e7 docs: CHANGELOG stage-346 — close v0.51.52, open Unreleased for 10-PR contributor batch 2026-05-13 06:57:22 +00:00
Hermes Agent
afe42b96c1 Merge pull request #2156 into stage-346
Issue #2057 Slice 2: Add guarded worktree remove action
2026-05-13 06:56:25 +00:00
Hermes Agent
cc1df0c6c7 Merge pull request #2166 into stage-346
Consolidate session post-render processing

# Conflicts:
#	CHANGELOG.md
2026-05-13 06:56:24 +00:00
Hermes Agent
2a9d011022 Merge pull request #2160 into stage-346
Add CSP report collector endpoint (closes #2095)
2026-05-13 06:56:22 +00:00
Hermes Agent
4109394cdf Merge pull request #2159 into stage-346
Fix stale stream state in session list (closes #2157)

# Conflicts:
#	CHANGELOG.md
2026-05-13 06:56:21 +00:00
Hermes Agent
7b866df79a Merge pull request #2170 into stage-346
Skip CLI metadata lookup for native session loads

# Conflicts:
#	CHANGELOG.md
2026-05-13 06:56:20 +00:00
Hermes Agent
e665d36847 Merge pull request #2161 into stage-346
Localize logs severity filters (closes #2098)

# Conflicts:
#	CHANGELOG.md
2026-05-13 06:56:18 +00:00
Hermes Agent
129e42873c Merge pull request #2158 into stage-346
Fix stale stream exception writeback guards (closes #2154)

# Conflicts:
#	CHANGELOG.md
2026-05-13 06:56:17 +00:00
Hermes Agent
dcbced9357 Merge pull request #2173 into stage-346
Fix ctl Python wrapper ownership (closes #2172)
2026-05-13 06:56:16 +00:00
Hermes Agent
7e88ba391a Merge pull request #2175 into stage-346
Soften session lineage count badge (refs #2155)
2026-05-13 06:56:14 +00:00
Hermes Agent
77cebdfdd2 Merge pull request #2176 into stage-346
fix: handle dict model entries in provider models list
2026-05-13 06:56:13 +00:00
Lumen Yang
d13a174fe1 fix: keep compression anchor stable in windowed transcript 2026-05-13 08:49:25 +02:00
MrFant
a4417d11f9 fix: handle dict model entries in provider models list
When a provider's 'models' config contains dicts (e.g. {"id": "x", "label": "y"})
instead of plain strings, _apply_provider_prefix() crashes with:
  AttributeError: 'dict' object has no attribute 'startswith'

This happens because the list comprehension at line 3505 passes the raw dict
as the model ID. The fix extracts 'id' and 'label' from dict entries while
keeping string entries as-is.

Fixes the /api/models and /api/onboarding/status 500 errors.
2026-05-13 13:49:40 +08:00
Michael Lam
29f5dea835 Soften session lineage count badge 2026-05-12 22:41:41 -07:00
Frank Song
d5dda03ec2 Fix ctl Python wrapper ownership 2026-05-13 13:09:42 +08:00
Frank Song
e78945e7ca Skip CLI metadata lookup for native sessions 2026-05-13 12:35:12 +08:00
Frank Song
02ca306ffc Consolidate session post-render processing 2026-05-13 11:50:31 +08:00