Commit graph

5078 commits

Author SHA1 Message Date
Rod Boev
36fee0c6a4 fix(#4757): add active-drag flags so macOS workspace drag-drop lands 2026-06-24 18:58:33 +00:00
nesquena-hermes
f61de2a178
Release WI (v0.51.628): no ghost messages after edit/retry/undo (#4772, closes #4767)
Release WI (v0.51.628): no ghost messages after edit/retry/undo (#4772, closes #4767)
2026-06-24 11:53:00 -07:00
nesquena-hermes
4816f0a38e Release WI (v0.51.628): no ghost messages after edit/retry/undo (#4772, closes #4767) 2026-06-24 18:48:39 +00:00
nesquena-hermes
6a7fe93e10 fix(#4767): gate boundary-advanced bypass on checkpoint consumption (no stale-suffix resurrection)
Codex final-gate found the boundary<watermark advanced signal made
sidecar_advanced_past_watermark globally true, so a stale ts>watermark suffix
row appearing in state.db BEFORE the edited checkpoint bypassed the skip and
resurrected. Gate the bypass on state_replay_idx >= len(sidecar_visible_sequence)
(checkpoint consumed); apply the same gate to the same-second CORE-B exception.
Regression test added + proven non-vacuous. All legit cases (state-only reply
after checkpoint, CORE-B same-second) still pass.

Co-authored-by: AlexeyDsov <alexeydsov@gmail.com>
2026-06-24 18:39:02 +00:00
nesquena-hermes
695d9ab814 fix(#4767): keep state-only post-edit reply when sidecar tail equals advanced watermark (Codex final gate)
Final-gate Codex repro found a non-empty-sidecar drop: when the post-edit USER
turn is checkpointed into the sidecar (ts == advanced watermark) but its
ASSISTANT reply exists only in state.db (ts > watermark), the
sidecar_advanced_past_watermark guard was False (max_sidecar_timestamp ==
watermark, not >), so the 'timestamp > watermark' skip dropped the legitimate
reply. GET /api/session returned ['first','first reply','edited prompt'] and
omitted the assistant.

Fix: treat truncation_boundary < watermark (genuinely advanced) as advanced too,
so post-watermark state-only rows merge through even when the sidecar tail only
EQUALS the watermark. Conservative skip preserved for boundary None / == watermark.
Hoisted the loop-invariant boundary check out of the per-message loop. Regression
test added + proven non-vacuous.

Co-authored-by: AlexeyDsov <alexeydsov@gmail.com>
2026-06-24 18:21:34 +00:00
nesquena-hermes
7317e29d82 fix(#4767): guard empty-sidecar reconstruction against not-advanced watermark (Opus gate)
Opus deep-gate found a latent data-loss the Codex harnesses missed: the
empty-sidecar branch kept at_or_after (ts>=watermark) UNCONDITIONALLY, which is
only valid once the watermark was ADVANCED strictly past the original cutoff
(a new turn committed -> boundary < watermark). In the not-advanced states the
content above the watermark is the deleted suffix, so it got resurrected — the
same data-loss class this fix exists to kill. Reachable via crash/cold-load
metadata-vs-sidecar divergence.

- Keep at_or_after ONLY when boundary < watermark (genuinely advanced).
- boundary == watermark (just truncated) OR boundary is None (legacy: a positive
  watermark always meant 'frozen at cutoff' pre-#4767) -> conservative ts<=watermark
  filter; never resurrects.
- Replaced the backward-scan heuristic with the provable boundary guard.
- Removed the now-dead 'or (not sidecar_messages and watermark>0)' clause in the
  non-empty-sidecar path (unreachable; empty sidecar returns earlier).
- Added 2 regression tests (boundary==watermark, legacy None-boundary), both proven
  non-vacuous; updated 2 contributor tests that assumed advanced-watermark-without-boundary
  (an unreachable state) to pass the boundary the real persistence path always writes.

Co-authored-by: AlexeyDsov <alexeydsov@gmail.com>
2026-06-24 18:08:50 +00:00
nesquena-hermes
6ce9533d53 test(#4767): route-level CORE-A regression — /api/session full reload honors truncation_boundary
Co-authored-by: AlexeyDsov <alexeydsov@gmail.com>
2026-06-24 18:08:50 +00:00
nesquena-hermes
aac220b625 fix(#4767): thread truncation_boundary through remaining full-load merge call sites (CORE-A)
The contributor's empty-sidecar recovery uses the persisted truncation_boundary
to distinguish a legitimate prefix from a deleted suffix, but two production
call sites still passed only truncation_watermark — the default /api/session
full reload (routes.py ~9504) and _merged_session_messages_for_display
(routes.py ~6098) — so a normal full reload fell back to the old 'drop one
turn pair' heuristic and resurrected deleted suffix turns when an OLDER message
was edited leaving >=2 later turns. Thread truncation_boundary through both.

Co-authored-by: AlexeyDsov <alexeydsov@gmail.com>
2026-06-24 18:08:50 +00:00
AlexeyDsov
037253e4fc fix(#4767): review fixes - more edge cases 2026-06-24 18:08:50 +00:00
AlexeyDsov
195d53ea90 fix(#4767): review fixes - edge cases 2026-06-24 18:08:50 +00:00
AlexeyDsov
0a1c94e5c8 fix(#4767): review fixes 2026-06-24 18:08:50 +00:00
Alexey Denisov
d76abfb734 Update api/streaming.py
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
2026-06-24 18:08:50 +00:00
AlexeyDsov
e1bbf3e807 fix(#4767): advance truncation_watermark instead of clearing to None after edit/retry/undo (#2914, #3831) 2026-06-24 18:08:50 +00:00
nesquena-hermes
3917400c80
Release WH (v0.51.627): cron Task APIs survive a shadowing top-level cron package (#4855)
Release WH (v0.51.627): cron Task APIs survive a shadowing top-level cron package (#4855)
2026-06-24 10:56:25 -07:00
nesquena-hermes
36c92d8bd2 Release WH (v0.51.627): cron Task APIs survive a shadowing top-level cron package (#4855) 2026-06-24 17:53:14 +00:00
Ruyan
a7788792fb fix: prefer agent cron package for task APIs 2026-06-24 17:52:57 +00:00
nesquena-hermes
f22affb638
Release WG (v0.51.626): restore mobile streaming scroll-jank guard (#4857)
Release WG (v0.51.626): restore mobile streaming scroll-jank guard (#4857)
2026-06-24 10:48:15 -07:00
nesquena-hermes
caf36d11dd Release WG (v0.51.626): restore mobile streaming scroll-jank guard (#4857) 2026-06-24 17:40:30 +00:00
Brett Yelverton
2a40ca4240 fix(streaming): restore mobile scroll-jank guard during live renders
A later streaming parse-cache change dropped the #MOBILESCROLL guard from
the live-stream render tick while leaving the helper and CSS in place.
On iOS PWA, Safari can paint a transient scrollTop=0 frame during streamed
DOM rebuilds, forcing the reader to the first/oldest message.

Re-add _fixMobileScrollJank() before streaming DOM work begins and pin it
with a regression test so the third layer of the mobile scroll fix cannot
be silently dropped again.
2026-06-24 17:20:40 +00:00
nesquena-hermes
c70105cf35
Merge pull request #4840 from nesquena/stage/4813-cron-prefix
Release v0.51.625 — cron job model override no longer keeps the @provider: display prefix (#4813)
2026-06-24 04:13:39 -07:00
nesquena-hermes
f84db40a23 test(#4813): resolve node via shutil.which + skip if absent (CI portability)
The hardcoded /home/hermes/.local/bin/node doesn't exist in CI runners. Use
shutil.which('node') with a module-level skipif, matching the repo's other
node-driven tests.
2026-06-24 11:07:54 +00:00
nesquena-hermes
eb331b5163 release: stamp v0.51.625 (#4813 cron model @provider prefix strip) 2026-06-24 11:02:44 +00:00
nesquena-hermes
984fd9557c Merge remote-tracking branch 'origin/master' into gate/4813-cron-prefix 2026-06-24 11:01:50 +00:00
nesquena-hermes
adacf2fb17
Merge pull request #4839 from nesquena/stage/4832-kanban-height
Release v0.51.624 — bound the Kanban column card-list height (#4832)
2026-06-24 03:54:37 -07:00
nesquena-hermes
d755ed1c06 test(#4813): cover _cronModelBareName provider-prefix strip matrix
The contributor PR had no test for the new helper. Adds Node-driven coverage:
matching-provider prefix stripped, unprefixed untouched, no/mismatched provider
untouched, empty/null passthrough. Co-authored-by: luandnh
2026-06-24 10:51:24 +00:00
nesquena-hermes
9493f1640f Merge branch 'peek-4813' into gate/4813-cron-prefix 2026-06-24 10:49:48 +00:00
nesquena-hermes
b9e4e24cbc release: stamp v0.51.624 (#4832 bound kanban column card-list height) 2026-06-24 10:49:28 +00:00
nesquena-hermes
631f1a35da Merge branch 'peek-4832' into gate/4832-kanban-height 2026-06-24 10:38:49 +00:00
nesquena-hermes
a287980799
Merge pull request #4838 from nesquena/fix/4702-portrait-scroll-bottom
Release v0.51.623 — iOS portrait: opening a conversation lands at the bottom (#4702)
2026-06-24 03:28:54 -07:00
nesquena-hermes
718cefc264 release: stamp v0.51.623 (#4702 iOS portrait open-scroll-to-bottom) 2026-06-24 10:25:20 +00:00
nesquena-hermes
7fe6861a54 test(#4702): thread _lastMessageClientHeight through the scroll-pin-reentry JS harness
The #4295 harness runs the extracted scroll-handler body in a Node new Function();
the body now references _lastMessageClientHeight, so it must be a param + threaded
through state (seeded null, samples keep clientHeight stable so grew stays false and
the pin-reentry assertions are unchanged).
2026-06-24 10:15:04 +00:00
Hoang Luan
78cd8798ec
Merge branch 'master' into fix/cron-model-provider-prefix 2026-06-24 17:05:29 +07:00
nesquena-hermes
671f4504ae fix(#4702): co-seed _lastMessageClientHeight with every programmatic _lastScrollTop write (Codex gate)
Codex found the guard had a first-event gap: programmatic seeds of _lastScrollTop
(_setMessageScrollToBottom, scrollToBottom, snapshot restore paths) didn't seed
_lastMessageClientHeight, so the FIRST native toolbar-collapse scroll saw a null
prior height -> grew=false -> the false-unpin still fired. Now every programmatic
_lastScrollTop=el.scrollTop is paired with _lastMessageClientHeight=el.clientHeight.
2026-06-24 10:02:52 +00:00
nesquena-hermes
fe40912eb9 fix(#4702): don't false-unpin a freshly-opened session on iOS portrait toolbar settle
iOS Safari portrait resolves its dynamic toolbar height after first paint; when the
toolbar collapses the #messages scroller grows (clientHeight up), firing a scroll
event with decreased scrollTop that was misread as an upward user scroll -> falsely
set _messageUserUnpinned, and the ResizeObserver settle then self-cancelled, leaving
the reader stranded at the TOP of a freshly-opened conversation (landscape unaffected
since it doesn't resize late). Sibling of #4701.

Fix (touch-safe, no-op on desktop/landscape where clientHeight is stable):
- Track _lastMessageClientHeight; gate movedUp on !grew so a container-height
  INCREASE can't be read as an upward scroll. Reset on session switch.
- For explicit (open) settles, also observe the scroller itself so a late portrait
  toolbar collapse re-anchors the bottom.

Independent of #4818 (overflow-anchor paint-gap) — different mechanism, coexists.
Diagnosis credit: investigation. Co-authored-by: reinocheong <reporter>
2026-06-24 09:56:06 +00:00
nesquena-hermes
dabbf06575
Merge pull request #4837 from nesquena/fix/4768-cron-graceful-degrade
Release v0.51.622 — Tasks tab no longer 500s when the cron package is absent (#4768)
2026-06-24 02:41:04 -07:00
nesquena-hermes
77b59f7c85 test(#4768): drop unused 're' import (ruff F401) 2026-06-24 09:29:15 +00:00
nesquena-hermes
054e39151b release: stamp v0.51.622 (#4768 cron-absent Tasks tab graceful degrade) 2026-06-24 09:24:54 +00:00
nesquena-hermes
f4e150e105 Merge remote-tracking branch 'origin/master' into fix/4768-cron-graceful-degrade 2026-06-24 09:23:37 +00:00
nesquena-hermes
853c367241
Merge pull request #4835 from nesquena/stage/4241-vietnamese
Release v0.51.621 — Vietnamese UI language (#4241)
2026-06-24 02:15:14 -07:00
nesquena-hermes
1e3132376b fix(#4768): only treat absent cron package as unavailable, re-raise real import bugs (Codex gate)
ModuleNotFoundError fires both when cron.jobs is absent AND when an existing
cron/jobs.py fails to import its own dependency. Catch as exc and only return the
graceful {jobs:[],cron_unavailable:true} when exc.name is 'cron'/'cron.jobs';
re-raise otherwise so a real cron bug isn't silently swallowed.
2026-06-24 09:12:46 +00:00
nesquena-hermes
61f3c766df release: stamp v0.51.621 (#4241 Vietnamese UI language) 2026-06-24 09:11:06 +00:00
jkobject
93afd60425 fix(kanban): bound column card list height 2026-06-24 10:57:03 +02:00
nesquena-hermes
1be24e0660 test(#4241): bump remaining hardcoded locale-count assertions for vi (14th locale)
Full-suite caught 7 more per-locale count tests: open_in_vscode (->13, a
pre-existing one-locale gap unrelated to vi), usage_cache_hit_detail/usage_cached_percent
(->14), and the i18n_tooltips LOCALE_COUNT (13->14). vi carries these keys.
2026-06-24 08:50:52 +00:00
nesquena-hermes
34694a1f02 fix(#4768): degrade GET /api/crons gracefully when the cron module is absent
In split-container / minimal Docker deployments the WebUI image may not ship the
agent's cron package on its import path, so the Tasks tab's GET /api/crons did
'from cron.jobs import list_jobs' and 500'd with ModuleNotFoundError — breaking the
whole tab. Now the import is guarded and returns {jobs: [], cron_unavailable: true}
instead, so the Tasks tab loads (empty) instead of erroring. Happy path unchanged.
Co-authored-by: reporter
2026-06-24 08:42:50 +00:00
nesquena-hermes
1fc24ddf68 feat(#4241): add Vietnamese (vi) as 14th UI locale + wire parity
Maintainer-completed @thanhtantran's #4241 (Nathan approved bringing it in):
- vi locale block in static/i18n.js (contributor's 1615-line translation) rebased onto master.
- Added vi to _LOGIN_LOCALE in api/routes.py (login-page localization, issue #1442 parity).
- Bumped the per-locale hardcoded-count assertions 13->14 across the locale-parity
  tests (rtl, quota_chip, hide_suggestions, virtualize_transcript, no_git, help_tab,
  verdigris/zeus skins, auxiliary_models) and added 'vi' to the composer-voice-buttons
  LOCALES tuples. vi already carries all current English keys (verified 14x per key).
All 497 locale/parity tests pass. Co-authored-by: thanhtantran
2026-06-24 08:39:14 +00:00
nesquena-hermes
3de15e53a5 Merge branch 'peek-4241' into gate/4241-vietnamese 2026-06-24 08:26:00 +00:00
nesquena-hermes
d2a64d7fb9
Merge pull request #4831 from nesquena/fix/4808-streaming-sessions-cache-ttl
Release v0.51.620 — fix /api/sessions CPU spike + slowness during streaming (#4808)
2026-06-24 01:23:07 -07:00
nesquena-hermes
c3d2fe4a20 release: stamp v0.51.620 (#4808 streaming /api/sessions cache TTL hotfix) 2026-06-24 08:19:43 +00:00
nesquena-hermes
1fc86a47c7 Merge remote-tracking branch 'origin/master' into fix/4808-streaming-sessions-cache-ttl 2026-06-24 08:18:44 +00:00
Orange Pi Vietnam
d341f2084c
Merge branch 'nesquena:master' into master 2026-06-24 15:12:44 +07:00