Commit graph

1196 commits

Author SHA1 Message Date
Dennis Soong
143d9d8ef7 fix: reconcile stale sidebar display titles 2026-05-14 16:18:53 +08:00
Jordan SkyLF
a291ffdde6 fix: refine update summary category handling
Keep distinct generated summary categories, route update-summary generation through the configured auxiliary model first, disclose capped large-range summary input, and constrain long summary panels.
2026-05-14 01:07:47 -07:00
Frank Song
6beb59d61f Improve mobile sidebar panel navigation 2026-05-14 15:16:33 +08:00
Hermes Agent
b8e9951492 Merge pull request #2236 into stage-354
fix: silent failure detection scans only new messages (jasonjcwu)
2026-05-14 07:15:16 +00:00
Hermes Agent
efad585b86 Merge pull request #2228 into stage-354
Add model picker to profile creation (franksong2702, refs #749)
2026-05-14 07:15:14 +00:00
Jordan SkyLF
afbcc9a6d5 fix: wrap update banner on mobile 2026-05-13 23:51:48 -07:00
fxd-jason
1e80b51560 fix: align usage-overwrite test FakeAgent with real agent message format
The FakeAgent in test_issue1857_usage_overwrite returned only 2 messages
(user + assistant) without the conversation history. The real agent always
returns the full history plus new messages. This mismatch caused the new
_has_new_assistant_reply helper (which checks only messages beyond the
pre-turn offset) to see len(result)==len(prev) and incorrectly flag the
turn as a silent failure.

Fix: prepend conversation_history to the FakeAgent's response so the
message list mirrors production behavior.
2026-05-14 14:48:08 +08:00
fxd-jason
120ec5eba2 fix: silent failure detection scans only new messages, not full history
When a provider error (401/429/rate-limit) causes the agent to return
without producing a new assistant reply, the WebUI should emit an
apperror event so the user sees an inline error. However, the detection
logic scanned ALL messages in result['messages'] — which includes the
full conversation history. If any prior turn had an assistant response,
_assistant_added would be True and the apperror would be silently
skipped, leaving the user staring at a blank response.

Extract a helper _has_new_assistant_reply(all_messages, prev_count)
that only inspects messages beyond the pre-turn history offset. Apply
it to both the main detection path and the self-heal/retry path.

Tests: 15 new cases covering history masking, empty content, whitespace,
edge-case shrinks, and multi-assistant scenarios.
2026-05-14 14:34:19 +08:00
Jordan SkyLF
62eb703dcf fix: avoid duplicate update summary bullets 2026-05-13 22:54:45 -07:00
Frank Song
8b30ade923 Add profile creation model picker 2026-05-14 12:13:49 +08:00
Hermes Agent
3d34a72ee8 stage-353: apply Opus SHOULD-FIX — unconditional parent_session_id stamp on compression rotation
Opus identified that PR #2227's preservation block had two related bugs in
the parent_session_id handling:

1. During preservation save: code did
     _old_parent = s.parent_session_id
     s.parent_session_id = None
     s.save(touch_updated_at=False, skip_index=True)
     s.parent_session_id = _old_parent
   The save persisted parent=None to disk. The in-memory restoration didn't
   reach the disk copy. Result: a /branch fork session that subsequently
   compressed lost its 'Forked from X' badge on the preserved old snapshot.

2. Stamping the continuation: code did
     if not s.parent_session_id:
         s.parent_session_id = old_sid
   The 'if not' guard skipped the stamp when the session already had a
   parent_session_id from a prior fork. Result: fork-of-fork compression
   broke lineage — the continuation jumped back to the original fork parent
   instead of the just-preserved immediate predecessor snapshot.

Fix (matches Opus's recommendation):
  - Remove the parent clearing during preservation save (preserve as-is)
  - Drop the 'if not' guard; always stamp continuation to old_sid

This makes the lineage chain consistent: new → old → old.parent → ... root.
Traversal from the continuation always walks through the just-preserved
snapshot to get to its parent's parent, never jumping over the snapshot.

Two new regression tests pin both invariants:
  - test_parent_session_id_stamped_unconditionally (no 'if not' guard)
  - test_old_session_parent_preserved_during_archive_save (no parent=None)

Both pass against the fix. All 8 tests in the file pass.
2026-05-14 03:59:02 +00:00
Hermes Agent
bfb62abe35 Merge pull request #2225 into stage-353
Add extra-large Appearance font size option (franksong2702)
2026-05-14 03:43:52 +00:00
Hermes Agent
5a447604b6 Merge pull request #2227 into stage-353
fix: preserve session history during compression rotation (theh4v0c, closes #2223 — critical data-loss)
+ duplicate Appearance label-markup fix overlapping with #2222

Conflict resolution:

(1) static/index.html line ~896 — PR #2222 and PR #2227 both fix the same
    endless-scroll checkbox label issue with different structures.
    - #2222 (HEAD): wraps the input+span in an in-place <label> inside the
      shared session-jump settings-field div.
    - #2227 (incoming): closes the existing settings-field, opens a NEW
      settings-field for endless-scroll, then wraps in <label>. Strictly
      better — each preference owns its own settings-field, matching the
      rest of the Settings → Appearance layout.

    Adopted #2227's structural variant. Regression test
    test_session_endless_scroll.py was updated by #2222 to match the new
    structure and passes against the resolved markup.

(2) CHANGELOG.md — both PRs added a Fixed entry. Merged both attributions,
    leading with the critical #2223 data-loss fix from #2227 (immutable
    pre-compression archive + parent_session_id lineage stamping) and
    noting that the maintainer chose #2227's structural variant for the
    label-markup overlap.

11/11 tests pass across test_session_endless_scroll.py +
test_issue2223_compression_no_rename.py after resolution.
2026-05-14 03:43:45 +00:00
Frank Song
e2f319d730 Add extra large font size option 2026-05-14 11:09:21 +08:00
RØG3R L!M4
5bbf18324c fix: preserve session history during compression rotation (#2223)
The previous implementation renamed old_sid.json → new_sid.json during
context compression, destroying the only persistent copy of the full
conversation history. If the summarisation LLM call also failed, the
user was left with zero recoverable messages.

Fix:
- Remove the destructive old_path.rename(new_path) call
- Preserve old_sid.json as an immutable pre-compression archive
- Create new_sid.json as a fresh file via s.save()
- Set parent_session_id on the continuation session for lineage
- Save in-memory messages to old_sid.json if they're newer than disk

Test: test_issue2223_compression_no_rename.py (6 tests, all passing)
2026-05-14 03:02:44 +00:00
Frank Song
3d2f9cf699 Fix Appearance endless scroll label markup 2026-05-14 10:44:16 +08:00
Hermes Agent
426cf7115e Merge pull request #2219 into stage-352
Hide prior-turn lineage metadata in compact sidebar (franksong2702, closes #2218)
2026-05-14 02:22:10 +00:00
Hermes Agent
549140df31 Merge pull request #2216 into stage-352
fix: cap _summary_cache with LRU (max 16 entries) (franksong2702, closes #2215 Fix A — closes #2215)
2026-05-14 02:22:08 +00:00
Frank Song
996d4f9a8c Hide session lineage metadata in compact sidebar 2026-05-14 10:14:15 +08:00
Frank Song
9681761cdf fix: cap _summary_cache with OrderedDict LRU
Refs #2215 Fix A: replace plain dict _summary_cache with OrderedDict-based LRU capped at 16 entries to prevent unbounded memory growth from long-running update summary generations.

Add regression coverage for the bounded LRU behavior: cache hits refresh recency, a new entry at capacity evicts the least-recently used key, and cache size never exceeds the cap.
2026-05-14 09:14:28 +08:00
Frank Song
28ec3af697 fix: strip only leading user-asking wrapper line
Refs #2215 Fix B: remove the mid-response stripping hazard without losing leading multi-line wrapper cleanup.

The pattern now strips only a leading 'the user is asking' wrapper line and preserves the visible answer that follows. Add regression coverage for both the leading-wrapper and mid-response prose cases.
2026-05-14 09:14:28 +08:00
starship-s
ab663cdfc8 fix(providers): avoid caching transient quota probe failures 2026-05-13 19:01:47 -06:00
Hermes Agent
2accf6335c Merge pull request #2149 into stage-351
perf(sessions): cache CLI session scans (starship-s)

Conflict resolution on api/routes.py:
  (1) Master grew a new helper '_messages_include_tool_metadata()' that
      pr-2149 doesn't have. Kept it (unrelated function — detects whether
      returned messages contain tool metadata, used elsewhere).
  (2) pr-2149 renames the CLI-metadata gate from '_needs_cli_session_metadata'
      to '_session_requires_cli_metadata_lookup' AND broadens it to cover
      legacy-imported sidecars with 'read_only=False' but persisted 'is_cli_session'
      or session_source markers. The new gate is strictly more inclusive than
      the master version — covers (a) is_cli_session, (b) read_only=True,
      (c) session_source in {messaging, external_agent}, AND (d) source_tag,
      raw_source, source, source_label, platform markers. All sessions that
      previously took the slow path still do, plus a few more legacy shapes
      that needed CLI metadata for correct display.
  (3) Removed the obsolete '_needs_cli_session_metadata()' definition from
      master (only consumer migrated to the new name).

29/29 tests pass across test_session_cli_scan_fast_path (new), claude_code
session import, session_index, and session_lineage_full_transcript.
2026-05-13 23:54:15 +00:00
Hermes Agent
70f09aaeb6 Merge pull request #2207 into stage-351
feat: add per-target update summaries with separate WebUI/Agent What's-new links (Jordan-SkyLF, fixes #1579)
2026-05-13 23:51:28 +00:00
Hermes Agent
f1fee3aea8 Merge pull request #2210 into stage-351
Fix MCP tools list overflow with pagination/search (Jordan-SkyLF)
2026-05-13 23:51:25 +00:00
Jordan SkyLF
25ce490e24 docs: add update banner summary mode screenshots 2026-05-13 16:27:06 -07:00
Frank Song
dc213d47b8 fix: preserve literal thinking tags 2026-05-14 07:13:34 +08:00
Jordan SkyLF
f0d2ebccd9 Persist generated summary button state 2026-05-13 15:53:01 -07:00
Jordan SkyLF
7925a15211 Clarify generated summary button states 2026-05-13 15:53:01 -07:00
Jordan SkyLF
90c2ee7e04 Split What's New summaries by target 2026-05-13 15:53:01 -07:00
Jordan SkyLF
cae007b069 Refine What's New summary sections 2026-05-13 15:53:01 -07:00
Jordan SkyLF
623dfef499 Stabilize What's New summaries 2026-05-13 15:53:01 -07:00
Jordan SkyLF
bec21eafa0 Add What's New summary toggle 2026-05-13 15:53:01 -07:00
Jordan SkyLF
cfc0f68d23 fix: show update whats-new links for webui and agent 2026-05-13 15:53:01 -07:00
Jordan SkyLF
4b455822cb Fix MCP tools list overflow 2026-05-13 15:33:54 -07:00
Hermes Agent
7209e89ef4 stage-350: apply Opus SHOULD-FIX — tighten _partial_already_present dedup scope
Opus flagged that PR #2151's cancel-handler partial-dedup loop used a
substring check that was too broad: any short prior assistant reply
('OK', 'Here is the answer:') would dedup a longer new partial containing
it, silently dropping the partial and resurrecting the #893 data-loss bug.

Tightened to only dedup against actual prior _partial=True markers with
exact (whitespace-stripped) content match. Three new regression tests
added (short-non-partial-prefix-does-not-dedup, exact-partial-match-still-
dedups, same-content-non-partial-does-not-dedup).

10/10 partial-cancel tests pass after the fix. Also updated CHANGELOG with
the conflict-resolution notes for #2151 vs #2136 and the #2178 test-fix.
2026-05-13 21:11:01 +00:00
Hermes Agent
43f86d038e stage-350: fix #2178 CI — update Ollama test assertion to match new allowOllamaFormat guard
PR #2178 added an 'allowOllamaFormat' guard (resolves to false for non-ollama
@-provider prefixes like '@custom:ai_gateway') to stop the ollama label
formatter from reformatting custom-provider model IDs with dashes. The
existing test asserted on the pre-PR code shape and didn't pick up the new
guard.

Updated the assertion to match the actual post-PR code at static/ui.js:2202,
with an extended docstring explaining the bug class the guard fixes (bare
custom-provider model IDs like 'Qwen3.6-35B-A3B' had hyphens stripped to
spaces + last letter lowercased by the formatter).
2026-05-13 20:45:44 +00:00
Hermes Agent
3f851051cf Merge pull request #2151 into stage-350
fix: clarify cancelled chat turn status (Jordan-SkyLF)

Conflict resolution on api/streaming.py:4549-4567 (the cancel-handler
ownership guard). Both this PR and the already-shipped PR #2136 add a
guard at the same site against stale stream writebacks, from different
angles:

  - PR #2136 (HEAD): _stream_writeback_is_current(_cs, stream_id) — strictly
    dominates by checking the active_stream_id token equality.
  - PR #2151: 'worker won the race' check via (active_stream_id != stream_id
    and not pending_user_message), with _emit_cancel_event = False to suppress
    the terminal cancel event.

Resolution merges both: keep #2136's strictly-stronger condition for skip
detection, and adopt #2151's _emit_cancel_event = False semantic so the
cancel event isn't emitted in addition to skipping the writeback (when
client may have already received the successful done payload).

55/55 tests pass across cancelled-turn-status + stale-stream-writeback +
the four cancel/data-loss sibling test files.
2026-05-13 20:44:44 +00:00
Hermes Agent
df3352eae3 Merge pull request #2192 into stage-350
fix(auth) 2/3: invalidate password hash cache when password changes via Settings panel (lucasrc, depends on #2191)
2026-05-13 20:42:52 +00:00
Hermes Agent
5f8b834833 Merge pull request #2193 into stage-350
fix(auth) 3/3: full HMAC digest with upgrade migration bridge + restore Secure cookie heuristic (lucasrc)
2026-05-13 20:41:38 +00:00
Hermes Agent
ca82f60144 Merge pull request #2191 into stage-350
fix(auth) 1/3: thread-safe login rate limiter + PBKDF2 key separation + transparent migration (lucasrc)
2026-05-13 20:41:36 +00:00
Hermes Agent
73b47ec4b5 Merge pull request #2203 into stage-350
Activity highlight animation (dobby-d-elf)
2026-05-13 20:41:35 +00:00
Hermes Agent
f94314e164 Merge pull request #2204 into stage-350
Fix opencode-go custom provider overlap routing (Michaelyklam, closes #1894)
2026-05-13 20:41:33 +00:00
Lucas Coutinho
fe4689e280 test(auth): merge invalidation tests into hash cache test file, remove duplicate 2026-05-13 16:17:44 -03:00
Michael Lam
1e17760a04 Fix opencode-go provider overlap routing
Closes #1894
2026-05-13 12:13:37 -07:00
dobby-d-elf
efce9ebdd6 Merge remote-tracking branch 'origin/master' into tools-animation-version-b
# Conflicts:
#	static/ui.js
2026-05-13 13:11:35 -06:00
Hermes Agent
7150e9fe70 Merge pull request #2202 into stage-349
feat: show early session titles on chat start (Jordan-SkyLF)
2026-05-13 19:03:03 +00:00
Hermes Agent
26e726c17e Merge pull request #2200 into stage-349
fix: stabilize Firefox session sidebar scrolling (Jordan-SkyLF)
2026-05-13 19:03:01 +00:00
Hermes Agent
97b60c68b8 Merge pull request #2198 into stage-349
Fix fork-from-here keep count for truncated sessions (Michaelyklam)
2026-05-13 19:02:59 +00:00
Jordan SkyLF
0381294f1c feat: add early session provisional titles 2026-05-13 11:37:11 -07:00
Jordan SkyLF
2dfe765b60 fix: stabilize Firefox session sidebar scrolling 2026-05-13 11:30:06 -07:00
Lucas Coutinho
2a96fb4a5b fix(auth): update HMAC sig length assertion to 64 chars and rebase on PR1 2026-05-13 14:19:09 -03:00
Lucas Coutinho
b734d95bc0 test(auth): add regression tests for HMAC migration bridge (32→64 char) 2026-05-13 14:18:47 -03:00
Lucas Coutinho
3daa12ceb0 test(auth): add cache invalidation regression tests for save_settings() 2026-05-13 14:09:39 -03: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
Michael Lam
c522384c6d Fix fork-from-here keep count for truncated sessions 2026-05-13 09:57:40 -07: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
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
Lucas Coutinho
8ca29618fe fix(auth): tighten except to OSError, add type hints, fix test imports 2026-05-13 12:27:27 -03:00
dobby-d-elf
a60c222e76 Version A: tune Activity sweep animation 2026-05-13 08:07:52 -06: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
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
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
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
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
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
Lumen Yang
d13a174fe1 fix: keep compression anchor stable in windowed transcript 2026-05-13 08:49:25 +02: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
starship-s
cc3080d5ac fix(providers): localize pooled quota retry text 2026-05-12 22:27:51 -06:00
Lucas Coutinho
7acbb3d99d Cache PBKDF2 password hash to eliminate ~1s overhead on every HTTP request
get_password_hash() computes PBKDF2-SHA256 with 600k iterations to
hash the HERMES_WEBUI_PASSWORD env var.  This is called on nearly every
HTTP request via check_auth -> is_auth_enabled -> get_password_hash.

Before: ~1s of PBKDF2 per request, regardless of how many times the
same env-var value has already been hashed.  A page load hitting 5+
API endpoints would burn 5+ seconds purely on password hashing.

After: compute once on first call, cache the hex result in a module-
level variable.  Subsequent calls are a single global-variable read
(~50ns).  The env var is immutable for the process lifetime, so there
is nothing to invalidate.

Thread-safe: double-checked locking ensures that under a burst of
concurrent requests only one thread computes PBKDF2, while the fast
path (after initialisation) requires zero locks.

10 unit tests covering all branches, cache-lifetime semantics, and
concurrent burst safety (8 threads, exactly 1 PBKDF2 call).
Test isolation: reloads only api.auth via importlib.reload, leaving
api.config untouched so test_pytest_state_isolation.py is unaffected.

Security analysis: zero regression.  The hash is derived from a static
env var and a static signing key — both already readable from process
memory.  Caching does not introduce any new disclosure or replay
vector.  PBKDF2 is still used for the initial computation and for
verify_password() on login.

AI: deepseek/deepseek-v4-flash
2026-05-13 00:54:50 -03:00
Frank Song
02ca306ffc Consolidate session post-render processing 2026-05-13 11:50:31 +08:00
Lucas Coutinho
bc3f4e54a6 Cache PBKDF2 password hash to eliminate ~1s overhead on every HTTP request
get_password_hash() computes PBKDF2-SHA256 with 600k iterations to
hash the HERMES_WEBUI_PASSWORD env var.  This is called on nearly every
HTTP request via check_auth -> is_auth_enabled -> get_password_hash.

Before: ~1s of PBKDF2 per request, regardless of how many times the
same env-var value has already been hashed.  A page load hitting 5+
API endpoints would burn 5+ seconds purely on password hashing.

After: compute once on first call, cache the hex result in a module-
level variable.  Subsequent calls are a single global-variable read
(~50ns).  The env var is immutable for the process lifetime, so there
is nothing to invalidate.

Thread-safe: double-checked locking ensures that under a burst of
concurrent requests only one thread computes PBKDF2, while the fast
path (after initialisation) requires zero locks.

Security analysis: zero regression.  The hash is derived from a static
env var and a static signing key — both already readable from process
memory.  Caching does not introduce any new disclosure or replay
vector.  PBKDF2 is still used for the initial computation and for
verify_password() on login.

AI: deepseek/deepseek-v4-flash
2026-05-13 00:25:41 -03:00
starship-s
c562ce2e8c fix(providers): preserve quota cache on refresh failure 2026-05-12 21:16:34 -06:00
starship-s
a166625e02 fix(providers): refresh pooled Codex quota state 2026-05-12 21:00:24 -06:00
Frank Song
f1ca07c186 Localize logs severity filters 2026-05-13 10:55:59 +08:00
Frank Song
57ee0ce069 Add CSP report collector endpoint 2026-05-13 10:52:59 +08:00
dobby-d-elf
f23ee79938 Scale fade duration with playback speed 2026-05-12 20:50:38 -06:00
Frank Song
5ae63ddd13 Fix stale stream state in session list 2026-05-13 10:28:12 +08:00
Frank Song
9ea4f1145d Fix stale stream exception writeback guards 2026-05-13 10:23:03 +08:00
starship-s
1904eaed6b fix(providers): show fallback pool cooldown times 2026-05-12 20:05:20 -06:00
Frank Song
46c62851ad Harden worktree removal safeguards 2026-05-13 09:49:15 +08:00
Frank Song
93b7d35bfa Issue #2057 Slice 2: Add worktree remove action
Backend:
- POST /api/session/worktree/remove — removes a session's git worktree
- Guards: stream/terminal lock, dirty/untracked without force
- remove_worktree_for_session() in api/worktrees.py

Frontend:
- 'Remove Worktree' context menu item + confirm modal
- i18n keys for all 11 locales

Tests:
- 5 tests: clean remove, missing worktree, no-path, route success, 404
2026-05-13 09:11:55 +08:00
starship-s
0eb9dbc3e5 fix(providers): skip exhausted Codex quota probes 2026-05-12 19:09:05 -06:00
starship-s
b87548b68e fix(providers): show pooled Codex quota status 2026-05-12 19:09:05 -06:00
dobby-d-elf
0b51245bd3 Optimize smooth fade word append path 2026-05-12 18:20:08 -06:00
dobby-d-elf
5e2350e128 Harden smooth text fade before merge 2026-05-12 18:18:07 -06:00
Hermes Agent
5f33901b6a Merge pull request #2150 into stage-345
feat: add manual provider usage refresh (Jordan-SkyLF)

Adds a 'Refresh usage' button on the Provider quota card in Settings → Providers,
with cache: 'no-store' fetch + browser cache-bust query string. Pure browser-side
cache-busting; the server-side /api/provider/quota endpoint has no cache layer
yet (refresh=1 query param is currently a no-op server-side; the win is bypassing
browser/proxy/SW caches).
2026-05-12 23:11:49 +00:00
Hermes Agent
20717a0d0a Merge pull request #2136 into stage-345
fix: guard stale stream writebacks (LumenYoung)

Prevents stale WebUI stream workers from writing old results into a session
after that session has already moved on to another stream. Adds new helper
_stream_writeback_is_current() (a token equality check against the session's
active_stream_id) and short-circuits the two finalize/cancel paths when the
worker no longer owns the session writeback.
2026-05-12 23:11:48 +00:00
Jordan SkyLF
112eadc209 fix: address cancelled turn review feedback
- classify string-only CancelledError payloads as cancelled
- centralize cancel marker substring matching
- add targeted regression coverage
2026-05-12 15:43:36 -07:00
Jordan SkyLF
062ef74ec0 fix: guard provider quota refresh fallback button state 2026-05-12 15:41:19 -07:00
Lumen Yang
4b57b202a0 fix: guard stale stream writebacks 2026-05-13 00:05:09 +02:00
dobby-d-elf
00517b431e Merge branch 'master' into smooth-text-fade 2026-05-12 14:46:57 -06:00
Jordan SkyLF
e4d16e93c7 fix: clarify cancelled chat turn status 2026-05-12 13:26:49 -07:00
Jordan SkyLF
b1f752ad3f feat: add provider quota refresh control 2026-05-12 13:17:27 -07:00
starship-s
4084c3cf56 perf(sessions): cache CLI session scans 2026-05-12 11:24:29 -06:00
Hermes Agent
7116c680df stage-344: maintainer fix for #2142 fr locale — add LOCALES tuple entries + _LOGIN_LOCALE block
#2142 (legeantbleu) added the fr locale to static/i18n.js but didn't update:
1. tests/test_issue1488_composer_voice_buttons.py: two TestComposerVoiceButtonI18n + TestVoiceModePreferenceGate LOCALES tuples needed 'fr'
2. api/routes.py: _LOGIN_LOCALE needed an 'fr' block so the login page localizes for French users (issue #1442 parity contract)
3. tests/test_login_locale_parity.py: the test asserting 'fr' falls-back-to-'en' is inverted — fr now resolves to fr, with sibling assertions for fr-FR and fr-CA

Mirrors the stage-340 fix for the it locale (PR #2067 → maintainer adds tuple entries). 46/46 i18n tests pass after fix.
2026-05-12 16:14:47 +00:00
Hermes Agent
c677c19a8f Merge pull request #2128 into stage-344
Fix manual compression proxy timeouts (closes #2087)

# Conflicts:
#	CHANGELOG.md
2026-05-12 16:13:01 +00:00
Hermes Agent
1ee8627acb Merge pull request #2135 into stage-344
Fix custom live model scoping (closes #2126, refs #2131)

# Conflicts:
#	CHANGELOG.md
2026-05-12 16:13:00 +00:00
Hermes Agent
aa85bd2e7c Merge pull request #2138 into stage-344
fix: recover from stale deleted workspaces
2026-05-12 16:12:58 +00:00
Hermes Agent
23425b23c8 Merge pull request #2129 into stage-344
fix: purge missing inflight sessions (closes #2092)
2026-05-12 16:12:57 +00:00
Hermes Agent
8dd0b4ec31 Merge pull request #2139 into stage-344
fix: audit turn journal terminal collisions
2026-05-12 16:12:56 +00:00
Hermes Agent
a06952ab00 Merge pull request #2140 into stage-344
Preserve fallback provider credential hints (closes #2133)

# Conflicts:
#	CHANGELOG.md
2026-05-12 16:12:54 +00:00
Hermes Agent
4c5a246647 Merge pull request #2125 into stage-344
docs: clarify compression anchor helpers (closes #2093)
2026-05-12 16:12:53 +00:00
Hermes Agent
8520755bd2 Merge pull request #2130 into stage-344
feat: load full lineage segments on demand
2026-05-12 16:12:52 +00:00
Hermes Agent
13c3646c55 Merge pull request #2121 into stage-344
fix: stack analytics usage cards on mobile (refs #2104) — TEST CONFLICT EXPECTED

# Conflicts:
#	tests/test_insights.py
2026-05-12 16:12:40 +00:00
Hermes Agent
2cccb8abcc Merge pull request #2120 into stage-344
fix: bucket long-range daily token charts (closes #2103)
2026-05-12 16:12:11 +00:00
Hermes Agent
56032151f7 Merge pull request #2143 into stage-344
Fix iPhone PWA chat bottom scroll stutter
2026-05-12 16:12:09 +00:00
Hermes Agent
45ac810a37 Merge pull request #2141 into stage-344
Fix Settings System mobile version wrapping (closes #2102)

# Conflicts:
#	CHANGELOG.md
2026-05-12 16:11:55 +00:00
Hermes Agent
76cf06a1a1 Merge pull request #2137 into stage-344
Fix login health probe credentials (closes #2122)
2026-05-12 16:11:42 +00:00
dobby-d-elf
c9c70fc1c5 improve smoothness with punctiotion rules & performance optimizations 2026-05-12 09:06:08 -06:00
dobby-d-elf
099fdaf012 fix(ui): stabilize chat bottom scrolling on iPhone PWA 2026-05-12 07:47:21 -06:00
Frank Song
76e611d49f Preserve fallback provider credential hints 2026-05-12 20:42:55 +08:00
Frank Song
b3f8bee96f Fix settings system mobile version wrapping 2026-05-12 20:42:55 +08:00
dobby-d-elf
516d942d6a refactor: reduce stale workspace recovery fix 2026-05-12 06:28:35 -06:00
Michael Lam
f5f59a5813 fix: audit turn journal terminal collisions 2026-05-12 05:20:06 -07:00
Frank Song
b718220077 Fix login health probe credentials 2026-05-12 20:09:54 +08:00
Frank Song
b7c5ba640c Fix custom live model scoping 2026-05-12 20:05:28 +08:00
dobby-d-elf
e03c197cdf fix: recover from stale deleted workspaces 2026-05-12 05:52:16 -06:00
Dennis Soong
f1b2a21bd4 feat: lazy-load full lineage segments 2026-05-12 18:02:49 +08:00
Michael Lam
dd543e4175 fix: purge missing inflight sessions 2026-05-12 02:57:37 -07:00
Frank Song
8fa92c680f Fix manual compression proxy timeouts 2026-05-12 17:33:59 +08:00
Michael Lam
265496782a docs: clarify compression anchor helpers 2026-05-12 01:43:16 -07:00
Michael Lam
7a16d09f10 fix: add Portuguese session management i18n 2026-05-11 23:23:41 -07:00
Michael Lam
a41b4d5afc fix: stack analytics usage cards on mobile 2026-05-11 23:07:35 -07:00
Michael Lam
245288c00d fix: bucket long-range daily token charts 2026-05-11 23:01:13 -07:00
Hermes Agent
8b8fa0b885 stage-343: add bash 3.2 compat regression tests + CHANGELOG
- New tests/test_ctl_bash32_compat.py (5 static-pattern assertions):
  * strict-mode is enabled (set -euo pipefail)
  * preserved[@] iteration is length-guarded (PR #2117)
  * CTL_BOOTSTRAP_ARGS[@] uses +alt expansion (commit 025f137f)
  * defense-in-depth: catch any future raw "${arr[@]}" w/o whitelist
  * denylist of bash 4+ features (declare -A, mapfile, [[ -v ]], etc.)
- Verified test fails when fix reverted, passes when restored.
- CHANGELOG: close v0.51.49, open Unreleased for #2117.
2026-05-12 05:36:31 +00:00
Hermes Agent
4d64f6eee9 Merge pull request #2116 from starship-s/fix/codex-quota-pool-usage
fix(providers): load Codex quota from credential pool
2026-05-12 05:10:23 +00:00
Hermes Agent
1c659f374f Merge pull request #2109 from franksong2702/issue-2057-worktree-status
Add read-only worktree status endpoint (refs #2057)
2026-05-12 05:10:18 +00:00