Commit Graph
6574 Commits
Author SHA1 Message Date
nesquena-hermes 6d0ff92fa7 Merge pull request #5647 from nesquena/release/stage-tiny
Release: sidebar auto-refresh (#5632) + composer-divider fix (#5499)
2026-07-05 14:48:29 -07:00
d76d11abb4 release: tiny-fix batch — sidebar auto-refresh on new session (#5632) + composer-divider hidden when left group empty (#5499)
Both gate-clean: Codex SAFE, Fable SHIP-UX, suite 12140/0, browser-smoke clean. #5499 supersedes #5451.

Co-authored-by: nankingjing <1079826437@qq.com>
Co-authored-by: wangyichen <wang.echen@foxmail.com>
2026-07-05 21:39:01 +00:00
nesquena-hermes 57a8467266 stage: merge #5499 (aa201b1550) 2026-07-05 21:21:35 +00:00
nesquena-hermes baddaccca1 stage: merge #5632 (8fc3179a8a) 2026-07-05 21:21:34 +00:00
nesquena-hermes 1870f77839 Merge pull request #5646 from nesquena/ship-5538
Release: compression-recovery action — focused continuation on compression_exhausted (#5538)
2026-07-05 14:19:03 -07:00
nesquena-hermesandFrank Song 76639b34f0 release: compression-recovery action — one-click focused continuation on compression_exhausted (#5538)
Folds in gate fixes: map the stale-card 409 to a neutral info toast + retire the card (finally-guard so it stays retired), + consumed-state CSS. Full gate: Codex SAFE, Fable SHIP-UX, suite 12140/0, browser-smoke clean.

Co-authored-by: Frank Song <franksong2702@gmail.com>
2026-07-05 21:14:53 +00:00
nesquena-hermes 5d81a317ec stage: merge #5538 (d284fcd0) 2026-07-05 20:51:59 +00:00
Frank SongandPaperclip d284fcd034 Merge latest master into compression recovery action
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-07-06 02:24:07 +08:00
nesquena-hermes 9b18ea9f99 Merge pull request #5643 from nesquena/release/stage-i18n2
Release: complete 664 UI translations across 8 locales (#5535)
2026-07-05 10:48:54 -07:00
Frank SongandPaperclip d1ed4a0b49 Merge latest master into compression recovery action
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-07-06 01:44:58 +08:00
nesquena-hermes 665b7b47df release: complete 664 remaining UI translations across 8 locales (#5535) + CHANGELOG 2026-07-05 17:43:45 +00:00
nesquena-hermes 79e485a038 stage: merge #5535 (c1aa45fceb) 2026-07-05 17:43:11 +00:00
nesquena-hermes bb0d33d343 Merge pull request #5642 from nesquena/release/stage-mobile2
Release: fix live mobile scroll jump-back regression (#5638, #5635)
2026-07-05 10:36:12 -07:00
nesquena-hermes adce95d0e3 release: fix live mobile scroll jump-back regression (#5637) — scope content-visibility to user rows + recover recycled virtual-scroll anchor (#5638, #5635) + CHANGELOG 2026-07-05 17:32:53 +00:00
nesquena-hermes 74d807a07c stage: merge #5638 (f657014aa3) 2026-07-05 17:32:22 +00:00
nesquena-hermes c0b0321081 stage: merge #5635 (7811b13f49) 2026-07-05 17:32:22 +00:00
nesquena-hermes 866a25b253 Merge pull request #5640 from nesquena/release/stage-lr1
Release: low-risk docs+tests batch (#5536, #5549, #5537, #5589)
2026-07-05 10:24:13 -07:00
nesquena-hermes c6d957904a release: low-risk docs+tests batch — env var docs (#5536), gateway approval docs (#5549), utf-8 test reads (#5537), messaging-clear watermark test (#5589) + CHANGELOG 2026-07-05 17:19:27 +00:00
nesquena-hermes 2fe1976eac stage: merge #5589 (cc7896cfab) 2026-07-05 17:10:06 +00:00
nesquena-hermes dc4c31ee1b stage: merge #5549 (0ec29b14ec) 2026-07-05 17:10:06 +00:00
nesquena-hermes 278e506468 stage: merge #5537 (0fd954fe78) 2026-07-05 17:10:06 +00:00
nesquena-hermes 806c15b417 stage: merge #5536 (4bfc9c8aad) 2026-07-05 17:10:05 +00:00
allenliang2022 f657014aa3 fix(webui): stop mobile scroll jump-back — scope content-visibility + hold unpinned position (#5637)
Two linked causes of the mobile scroll jump-back, both confirmed by the
maintainer against origin/master in #5637.

Primary (CSS): the @media (pointer: coarse) block applied a flat
`content-visibility: auto; contain-intrinsic-size: auto 1px` to every .msg-row.
Off-screen assistant rows can be multi-thousand px (tool-result / long answers),
so a 1px reservation collapses their off-screen height; scrollHeight lurches down
by tens of thousands of px on a long transcript, the browser force-clamps
scrollTop, and the viewport is thrown to the top. A flat intrinsic-size cannot
both reserve tall rows and keep scrollHeight stable for iOS flick momentum (why
1px was chosen), so content-visibility is scoped to the short, size-predictable
user rows; assistant rows keep real rendered height. Mirrors the existing
#liveAssistantTurn opt-out pattern.

Secondary (JS): _restoreMessageScrollSnapshotSameFrame fell back to an absolute
snapshot.top when the semantic anchor restore failed. During streaming the live
activity-scene refresh fires this every tick; for a reader scrolled up into
history (unpinned), snapping to a stale absolute top nudges the viewport backward
by an amount that grows with scrollHeight. Now: hold position (no scrollTop write)
for the unpinned/anchor-failed case and let the browser's own scroll anchoring
keep the reader put. Pinned/near-bottom readers keep the tail-relative restore.

Adds tests/test_issue5637_mobile_scroll_clamp_jumpback.py (mutation-checked:
reverting either fix fails the matching assertion).
2026-07-05 22:52:59 +08:00
allenliang2022 7811b13f49 test(webui): harden extractFunc to skip braces in string/regex/comment literals
Address greptile P2 on the vscroll recycled-anchor test harness: the
brace-counting function extractor desynced on a bare { or } inside a string,
template, regex, or comment within the extracted function body, silently
truncating the extract. Skip those spans so brace matching runs on real code
structure only, and add a regression test with a function whose string/regex/
comment literals contain unbalanced-looking braces.

Verified: the naive extractor fails all four tests (the compensation function
now contains querySelector attribute-selector strings that desync it); the
hardened extractor passes.
2026-07-05 20:14:38 +08:00
allenliang2022 ad1843f31b fix(webui): recover virtual-scroll compensation when the anchor row is recycled
_compensateScrollForMeasurementDelta re-found its viewport anchor only by
rawIdx and bailed with a bare 'if(!row) return' when that row was recycled
out of the render window. On long sessions containing multi-thousand-px
turns, a large scroll delta recycles the anchor row, so the estimated->measured
topPad swap (a scrollHeight change of tens of thousands of px) hit scrollTop
uncompensated and threw the viewport to the top -- a mobile scroll jump-back
that did not reproduce on desktop (where the anchor row stays rendered).

Fall back when the rawIdx row is gone: (1) re-find the same row by its stable
data-session-msg-idx and compensate by its measured offset delta; (2) if that
row is also unrendered, compensate by the top-spacer (topPad) height delta
captured before the re-render. _captureMessageViewportAnchor now records
topPadBefore so the fallback has a reference.

Adds tests/test_issue4346_vscroll_recycled_anchor_jumpback.py (Node-harness
behavioral tests). All fail on the pre-fix bare-return and pass on the fix;
existing vscroll suites stay green.

Relates to #4346.
2026-07-05 19:53:47 +08:00
nankingjingandClaude 8fc3179a8a fix(#3874): auto-refresh sidebar session list after new session creation
Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-05 18:43:20 +08:00
Frank SongandPaperclip 322e5a44fa Merge latest master into compression recovery action
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-07-05 17:23:05 +08:00
nesquena-hermes 8dc47b83c0 Merge pull request #5629 from nesquena/release/stage-5626
release #5626: ignore inactive compacted state-db rows in context replay
2026-07-05 02:18:28 -07:00
nesquena-hermes 8230785097 release #5626: exclude inactive compacted state-db rows from context replay + CHANGELOG 2026-07-05 09:14:40 +00:00
Frank SongandPaperclip 90b38cf1fe Merge latest master into compression recovery action
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-07-05 17:02:55 +08:00
nesquena-hermes 1165bd9ca2 fix(#5626): ignore inactive compacted state-db rows in context replay
get_state_db_session_messages() returned archived (active=0) rows that in-place
compaction had marked inactive. WebUI reconciliation feeds this reader straight
into the next model-facing context (reconciled_state_db_messages_for_session,
prefer_context=True), so those archived rows got pulled back in — resurrecting
pre-compaction history and making every later turn re-trigger compression. Now,
WHEN the messages table exposes an `active` column, inactive rows are excluded by
default (`AND (active IS NULL OR active != 0)` — NULL/legacy rows preserved), with
an `include_inactive=True` escape hatch for explicit recovery/audit callers.
Schemas without the column are unaffected (guarded by `'active' in available`).

Contributor stage; ungated on arrival. Co-authored-by: ai-ag2026 <ai-ag2026@users.noreply.github.com>
2026-07-05 08:59:21 +00:00
nesquena-hermes 35464be634 Merge pull request #5627 from nesquena/fix/5588-auth-cache-isolation
fix(#5588): reset memoized password-hash cache around every test (isolation flake)
2026-07-05 01:53:12 -07:00
nesquena-hermes 3051dc4dda release #5588: reset memoized password-hash cache around every test (isolation flake) + CHANGELOG 2026-07-05 08:44:41 +00:00
nesquena-hermes 4c9690bf59 fix(#5588): reset memoized password-hash cache around every test (isolation flake)
tests/test_issue803.py::TestProfileCookieHelpers failed when run after
tests/test_session_static_assets.py (passed in isolation). Root cause:
api.auth.get_password_hash() memoizes the resolved hash process-wide
(_AUTH_HASH_CACHE / _AUTH_HASH_COMPUTED) and is NOT keyed on the
HERMES_WEBUI_PASSWORD env var. test_session_static_auth_exemption sets that env
var + populates the cache; monkeypatch pops the env on teardown but the cache
stays populated, so is_auth_enabled() reads stale True and build_profile_cookie
raises "requires a request handler when auth is enabled".

Fix: an autouse conftest fixture (_reset_password_hash_cache) that invalidates the
cache before AND after every test — matching the existing _isolate_hermes_config_path
/ _restore_profile_home_globals autouse-reset convention. Fixes the whole class
regardless of which test sets the password; no-op when auth is off. Adds a
direct regression test (cache a password, pop env, assert auth reads disabled +
build_profile_cookie doesn't raise). Paired-run repro now passes.
2026-07-05 08:35:14 +00:00
Frank SongandPaperclip 0b339a0e8a Merge latest master into compression recovery action
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-07-05 16:22:50 +08:00
nesquena-hermes c922f179f7 Merge pull request #5625 from nesquena/release/stage-5582
release #5582: keep fork children out of compression stitch
2026-07-05 01:20:03 -07:00
nesquena-hermes 4f0b6576b5 release #5582: keep fork children out of compression stitch + CHANGELOG 2026-07-05 08:16:30 +00:00
nesquena-hermes dbc2345fea fix(#5571): keep fork children out of compression stitch
_webui_sidecar_lineage_messages_for_display stitches a session's pre-compression
snapshot parents for full-transcript display. A cleared fork child could resurrect
its ORIGINAL (non-fork) parent's transcript when that parent was later compressed.
Now, when the root session is itself a fork (session_source=='fork'), the stitch
walk allows fork-sourced snapshot parents but stops at the first non-fork
ancestor — so a compressed fork continuation still shows its own pre-compression
turns, while an ordinary fork child stays isolated from the original parent.
Additive guard (one extra break condition); non-fork lineage display unchanged.

Contributor stage; gate-pass. Co-authored-by: rodboev <rodboev@users.noreply.github.com>
2026-07-05 08:07:38 +00:00
wangyichen aa201b1550 chore(#5499): drop redundant post-divider _applyVoiceModePref call
The success branch had two adjacent calls:

  if(typeof window._applyVoiceModePref==='function') window._applyVoiceModePref();   // pre-divider (the actual fix)
  _applyComposerFooterVisibilitySettings();
  if(typeof window._applyVoiceModePref==='function') window._applyVoiceModePref();   // post-divider (redundant)

The post-divider one ran after _applyComposerFooterVisibilitySettings,
so it couldn't affect the divider the PR was meant to fix. It looked
like a defensive double-tap, but the function is idempotent and the
pref source (localStorage) doesn't change between the two synchronous
calls — so it was just dead code that made the diff look bigger than
the actual semantic change.

Drop it. Net PR footprint is now strictly: 'use the window-qualified
name and apply once before divider recompute in both IIFE branches.'

Re-tested: 26/26 pass on test_issue4598_composer_control_visibility
+ test_issue1488_composer_voice_buttons.
2026-07-05 15:55:36 +08:00
wangyichen edce177202 fix(#5499): use window._applyVoiceModePref — bare name is closure-local
Greptile P1: _applyVoiceModePref is declared with 'function' inside the
voice-mode IIFE (line 1205) and exported to window._applyVoiceModePref
at line 1212. The bare identifier _applyVoiceModePref is closure-local
and not visible from the settings-load IIFE branches at line 2997 and
line 3056 — so `typeof _applyVoiceModePref==='function'` was always
'undefined', the guard was permanently false, and the pre-divider call
silently never fired.

This undid the entire boot-order fix: divider was still computed
against the pre-sync #btnVoiceMode visibility, so the round-2 SILENT
race the PR was meant to close remained.

Fix: use window._applyVoiceModePref in both branches, matching the
already-correct call on line 2999 (which worked only by accident —
it ran AFTER _applyComposerFooterVisibilitySettings so it had no
effect on the bug, but at least it ran).

Tests: pytest tests/test_issue4598_composer_control_visibility.py
       tests/test_issue1488_composer_voice_buttons.py — 26/26 pass.
2026-07-05 15:53:56 +08:00
silent-reader-cn 9ff0298b50 fix(#5451): apply voice-mode pref before recomputing composer divider
Clean rebase of silent-reader-cn's #5499 (rebase-first; kept both boot-order
_applyVoiceModePref-before-recompute AND the voice-mode onchange recompute + autosave).

Co-authored-by: silent-reader-cn <silent-reader-cn@users.noreply.github.com>
(cherry picked from commit eeea3868d3b7f069dbf61470d787541b95af9181)
2026-07-05 15:53:56 +08:00
Frank SongandPaperclip 08fc9bd95e Merge latest master into compression recovery action
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-07-05 15:44:44 +08:00
nesquena-hermes f1f4514799 Merge pull request #5623 from nesquena/release/stage-5459
release #5459: include attachments in steer submissions
2026-07-05 00:24:21 -07:00
nesquena-hermes 1e4d237cc2 release #5459: include attachments in steer submissions (+ retry-dedup + identity chip clear) + CHANGELOG 2026-07-05 07:20:24 +00:00
nesquena-hermes c78d5083ad fix(#5459): dedup steer upload on retry + remove only delivered files by identity (gate)
Codex gate found two SILENT defects, fixed:
1) Failed-steer RETRY re-uploaded the same File objects (uploadPendingFiles ran
   again with clearPending:false). Added _steerUploadCache keyed by ownerSid +
   file signature so a retry with the same staged set reuses the uploaded paths;
   invalidated when the staged set changes (signature miss) or on accepted steer.
2) Accepted steer cleared ALL S.pendingFiles, dropping files staged during the
   upload/API await. Now removes ONLY the delivered snapshot by object identity,
   preserving newly staged files.

(The owner-session draft is still cleared on accepted steer — clearing the
delivered session's draft is correct even after a mid-upload switch; the existing
test asserts this.) Tests updated for the identity-based removal + new
cache/dedup guard. 69 steer/composer tests pass, node --check clean.
2026-07-05 07:10:23 +00:00
Frank SongandPaperclip cc816828d2 Merge latest master into compression recovery action
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-07-05 15:03:26 +08:00
nesquena-hermes ceea2438eb fix: include attachments in steer submissions
Steering (submitting mid-stream) dropped any pending composer attachments. Now the
pending files are uploaded before the /steer payload is sent, the uploaded file
paths are appended to the steer text so the active agent can inspect them with
tools, file chips stay staged if the steer fails (so nothing is lost), and
file-only busy submissions are handled.

Contributor stage; gate-pass. Co-authored-by: ruizanthony <ruizanthony@users.noreply.github.com>
2026-07-05 06:50:34 +00:00
nesquena-hermes abdf6c7ae3 Merge pull request #5620 from nesquena/fix/mobile-sidebar-header-icon-align
fix(ui): align mobile sidebar close/new-conversation header icons
2026-07-04 23:49:05 -07:00
nesquena-hermes 7ad9707c4b fix(ui): align mobile sidebar close (X) with the new-conversation (+) button
On the mobile sidebar header the close (X) button rendered an 18px glyph — the
only 18px .panel-head-btn icon — sitting ~6px lower than the adjacent 14px
new-conversation (+) button, an inconsistent pair. Match the X glyph to 14px and
vertically center it on the ~41px panel-head row so both icons share one size and
baseline (top:calc(safe-top - 2px) keeps the existing safe-area offset so the X
still clears the notch, with no extra drawer spacing). 44x44 tap target kept for
mobile touch; mobile @media(max-width:640px) only, and the X is display:none on
desktop, so desktop is unaffected. + CHANGELOG + source-guard tests.
2026-07-05 06:40:26 +00:00
Frank SongandPaperclip 7f3eed0a82 Merge latest master into compression recovery action
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-07-05 14:03:45 +08:00