Commit Graph
28 Commits
Author SHA1 Message Date
webtecnica b36fbdd633 fix(regeneration): refuse bounded tail on in-tail duplicate keys + real WAL interleaving test (#6826 r5) 2026-08-26 00:24:07 +00:00
webtecnica b33aff9d09 fix(regeneration): occurrence-count guard + single-snapshot (no TOCTOU) for bounded tail read (#6826 r3 round-3) 2026-08-26 00:24:07 +00:00
webtecnica 40ff74b6fc fix(regeneration): bounded tail read only when skipped state.db prefix is provably identical; compression-anchor coverage (#6826 r3) 2026-08-26 00:24:07 +00:00
webtecnica 3672e0038b fix(regeneration): bounded sidecar-anchored tail read instead of full transcript refetch (#6826) 2026-08-26 00:24:07 +00:00
webtecnica 8c9f505fab fix(ui): avoid full transcript fetch on regenerate (#6826) 2026-08-26 00:24:07 +00:00
4d03578192 fix(#6611): make regeneration start atomic (#6677)
* fix(#6611): make regeneration transaction canonical

* fix(#6611): close cross-provider regeneration blockers

* fix(#6611): harden regeneration transaction boundaries

* fix(#6611): bind canonical context and fork lineage

* fix(#6611): restore active turn token stamping

* test(#6611): make regeneration regressions CI portable

* test(#6611): preserve the tracked regeneration error fixture

* fix(#6611): preserve extracted session harness contracts

* fix(regeneration): preserve concurrent and imported turn ownership (#6611)

* fix(regeneration): honor imported turn ownership safely (#6611)

* test(regeneration): cover both session lock outcomes (#6611)

* test(regeneration): clear unused transaction fixtures (#6611)

* fix(#6611): consume public active-turn marker

* ci: re-trigger (Playwright install hung ~2.5h on GH runners, warm-cache retry)

---------

Co-authored-by: nesquena-hermes <nesquena+hermes@gmail.com>
Co-authored-by: n <a@n>
2026-08-19 11:11:53 +00:00
92c790ffe5 Batch release exp-v0.52.235 — cancelling-run reattach (#7096) + GPT-5.6 max reasoning (#7083) + test order-independence (#7101) (#7102)
* fix(tests): make mtime_invalidation and glm_5_3 tests order-independent (#7100)

* fix: expose max reasoning for GPT-5.6 models

* fix(recovery): do not reattach cancelling runs

ACTIVE_RUNS tracks worker lifecycle, which is deliberately broader than
"a turn a browser may attach to". cancel_stream() keeps the row as
phase="cancelling" while the worker unwinds so a successor turn cannot
start on top of it, but the client has already reached a terminal state
for that stream: its run journal ends in a terminal event.

The recovery lookups treated every same-session ACTIVE_RUNS row as
attachable. An idle session holding a cancelling row therefore received a
recovered server_turn_started on every /api/session/stream subscription:
the client attached, replayed the terminal event, tore the renderer down,
resubscribed, and the server replayed the same frame again. The result is
an endless attach/replay loop that rebuilds the transcript repeatedly.

Separate the two meanings instead of narrowing one call site:

- api/config.py gains active_run_is_attachable() and
  active_run_cancel_is_stale() as the shared predicates.
- active_stream_id_for_session() (browser recovery) returns attachable
  rows only; _session_has_active_turn() (busy check) keeps counting a
  fresh cancellation so a successor cannot overlap the unwinding worker.
- _live_active_stream_id() applies the same rule to the hidden-tab
  status poller, on both the STREAMS and ACTIVE_RUNS paths.
- routes._cancelled_run_is_stale() now delegates to the shared predicate
  rather than keeping a parallel copy of the staleness rule.
- A cancelling row past a bounded unwind window with no live STREAMS
  channel is reclaimed from ACTIVE_RUNS and its stream owner released, so
  a wedged worker cannot suppress background wakeups forever. Age alone
  does not reclaim a row that still owns a live channel.

Staleness anchors on cancelled_at, falling back to started_at, so a
long-running turn cancelled moments ago is never treated as an orphan.

tests/test_cancelling_run_not_attachable.py covers both directions of
each rule. The six behavioral tests fail on the unpatched tree and pass
with the fix; two targeted mutations (forcing the attachability predicate
true, and disabling the staleness reaper) each turn the suite red.

* docs(rfc): document cancellation attach/admission split

Records the runtime contract introduced by the recovery fix in the WebUI
run-state consistency RFC, so the distinction is discoverable instead of
living only in code comments.

- Adds ACTIVE_RUNS to the State Layers table as the worker-lifecycle
  registry, explicitly not the set of runs a browser may attach to.
- Adds invariant 9: lifecycle-busy is not client-attachable. Cancellation
  splits the two meanings, recovery paths must exclude cancelling rows,
  and admission checks must keep counting them.
- Documents the bounded cancellation-unwind window: reclamation needs
  both age and the absence of a live STREAMS channel, and staleness is
  anchored on the cancellation timestamp.
- Extends the review checklist with the admission-vs-attachment question
  and the evidence required when changing a reclamation window.

* docs(changelog): note #7096 cancelling-run reattach, #7083 GPT-5.6 max reasoning, #7101 test order-independence

---------

Co-authored-by: webtecnica <webtecnica@gmail.com>
Co-authored-by: Abdulrahman Elkenany <boudy.elkenany123@gmail.com>
Co-authored-by: allenliang2022 <allenliang2022@users.noreply.github.com>
Co-authored-by: n <a@n>
2026-08-17 05:37:00 +00:00
5b0246de61 Release: preserve intentional transcript shrinks (#6954) (#6997)
* fix(session): preserve intentional transcript shrinks

* fix(session): validate shrink generations

* docs(changelog): stamp #6954 (preserve intentional transcript shrinks)

---------

Co-authored-by: Frank Song <franksong2702@gmail.com>
Co-authored-by: nesquena-hermes <nesquena-hermes@users.noreply.github.com>
2026-08-13 20:44:06 +00:00
Hermes Agent 64f98dadd0 fix: preserve lazy alignment semantics 2026-07-17 15:36:55 -06:00
Hermes Agent d8360bfe7d refactor: clarify alignment safety checks 2026-07-17 15:36:55 -06:00
Hermes Agent 509263e161 perf: linearize session truncate alignment 2026-07-17 15:36:55 -06:00
nesquena-hermesandb3nw 322c9fdb62 fix(#5563): align forked context to display for large (compacted) sessions
Fork ("Fork from here") on a large/compacted session could cut context off a
real turn boundary — slicing mid-turn or leaving a dangling tool call, feeding
a malformed context to the model. Align the fork cut to a resolved turn boundary
via a signature matcher handling both compacted and non-compacted display
coordinate spaces; errs toward under-keeping with send-time sanitization backstop.

Co-authored-by: b3nw <b3nw@users.noreply.github.com>
2026-07-04 20:55:06 +00:00
Rod Boev 07a8c7dc6f fix(session): preserve kept tool rows on ambiguous truncate (#5134) 2026-06-30 01:40:07 +00:00
Rod Boev e9387f8aa5 fix(session): fail closed on ambiguous truncate context matches (#5134) 2026-06-30 01:40:07 +00:00
Rod Boev 02a3750488 fix(session): keep truncate rewind on complete turns (#5134) 2026-06-30 01:40:07 +00:00
Rod Boev 3627c9e5d8 fix(session): drop interleaved tool rows after mid-history truncate (#5134) 2026-06-30 01:40:07 +00:00
allenliang2022 ada8c262ca fix(webui): render server-initiated turns in a hidden tab without a refresh
A turn started SERVER-SIDE (self-wake, cron, restart hook) fans a
`server_turn_started` frame onto the per-session live-view SSE channel so an
open tab renders it live. But while a tab is HIDDEN the WebUI deliberately does
NOT hold that persistent SSE open (connection-pool budget — #3992 / #4151), so
`get_session_channel()` returns None at fan-out time and the turn is dropped for
that tab. The user only saw the turn after a manual interaction (refresh / send)
re-subscribed the channel and replayed it.

Bridge the gap with a lightweight poll of `/api/session/status` (one short GET
per ~6s tick — NOT a held connection, so the connection-pool budget the hidden
guard protects is preserved) that attaches the existing live renderer when it
sees a *live* active stream.

Backend (`api/session_ops.py`):
- `session_status()` now exposes `active_stream_id`, derived through a new
  `_live_active_stream_id()` helper that only returns the id when the stream is
  genuinely live (present in STREAMS / ACTIVE_RUNS). A stale id left by a
  crashed/restarted run surfaces as None, so the poller never attaches a
  renderer to a dead stream. Additive field — existing consumers ignore it.

Frontend (`static/messages.js`):
- `_startHiddenActiveStreamPoll` / `_stopHiddenActiveStreamPoll` /
  `_attachServerInitiatedStream` implement the poll lifecycle. The poll fires
  one immediate tick on hide (so an in-flight turn is caught without waiting a
  full interval), attaches mid-flight turns via the reconnecting/replay path,
  and stops on re-show (the real SSE takes over), session switch, or once a
  stream is rendering.
- Started on BOTH hidden paths: the `visibilitychange` hook's hidden branch (a
  visible tab going to background) and `startSessionStream`'s hidden
  early-return skip (a session opened while already hidden). The visible path
  and `stopSessionStream` clear it.

Tests:
- `tests/test_hidden_tab_server_initiated_turn.py` — backend live-validation
  (stale id → None; STREAMS/ACTIVE_RUNS id returned) and frontend lifecycle /
  both-hidden-paths / replay-attach source locks.
- Widened the brittle fixed-width source-window slices in
  `tests/test_issue3996_sse_visibility.py` (1600/1700 → 2400) so the existing
  `visibilitychange` / hidden-skip assertions still find their markers after the
  poll-start lines were inserted into `startSessionStream`.
2026-06-29 16:28:30 +00:00
nesquena-hermes aae7cc58d2 Merge branch 'pr-5126-head' into stage/brick-5096
# Conflicts:
#	api/session_ops.py
2026-06-28 18:14:03 +00:00
b3nwandb3nw 6e499eb1dd fix(session): semantic context truncate on rewind + evict agent
Refs nesquena/hermes-webui#5096

Co-authored-by: b3nw <b3nw@users.noreply.github.com>
2026-06-28 18:01:56 +00:00
b3nwandb3nw aacf860ccc fix(session): truncate context_messages when branching from fork point
Refs nesquena/hermes-webui#5096

Co-authored-by: b3nw <b3nw@users.noreply.github.com>
2026-06-28 17:59:46 +00:00
AlexeyDsov 037253e4fc fix(#4767): review fixes - more edge cases 2026-06-24 18:08:50 +00:00
87084dfebf Release v0.51.276 — Release IR (stage-p3e — preserve manually-named session titles #3542) (#3682)
* feat(sessions): skip adaptive auto-rename for manually-named sessions (#3542, #3230)

Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>

* docs(changelog): v0.51.276 — Release IR (stage-p3e)

* fix(sessions): clear manual_title lock on /api/session/clear (#3542)

Codex regression-gate follow-up: the clear endpoint reset the title to
Untitled directly, stranding manual_title=True so the reused session never
auto-named again. Route the reset through apply_session_title_rename (which
clears the lock for auto-labels) + add a behavioral and a static-guard test.

---------

Co-authored-by: nesquena-hermes <[email protected]>
Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
2026-06-05 13:34:54 -07:00
Frank Song 459286830b fix(session): preserve sidecar truncation boundary 2026-05-25 21:21:15 +08:00
Hermes Agent e36def33cd Show profile home in /status command (refs #463) (#1380) 2026-05-01 04:46:37 +00:00
Frank Song 1ed1ce219d Preserve transcript across context compaction 2026-04-29 16:37:08 +08:00
nesquena-hermes 8b8ff3328a fix: batch triage — 12 contributor PRs (v0.50.227) (#1168)
Merged as v0.50.227. 2634 tests passing, browser QA 21/21 (desktop + mobile). Full attribution below.

Thanks to all 12 contributors:
@jundev0001 (#1138), @franksong2702 (#1142, #1157, #1162), @dso2ng (#1143), @bergeouss (#1145, #1146, #1156, #1159), @jasonjcwu (#1149), @ccqqlo (#1161), @frap129 (#1165)

Two fixes applied during integration and two more by the independent reviewer (@nesquena):
- messages.js: per-turn cost delta capture order (#1159)
- workspace.py: symlink target blocked-roots check + HOME sanity guard (#1149, #1165)
- panels.js: cron unread counter bookkeeping (in-loop increment bug)
- tests/test_symlink_cycle_detection.py: register workspace before session/new
2026-04-27 13:34:59 -07:00
5b923a9502 fix: harden session persistence and per-session lock handling during streaming (v0.50.175, #910) (#910)
Co-authored-by: starship-s

Co-authored-by: nesquena-hermes <nesquena-hermes@users.noreply.github.com>
2026-04-23 14:25:43 -07:00
0386dc261a feat: slash command parity + skill autocomplete — v0.50.91 (PR #711)
Combines PR #618 (@renheqiang) slash command parity (/retry /undo /stop /title /status /voice) with PR #701 (@franksong2702) skill autocomplete. 1469 tests pass. Closes #460.

Co-authored-by: renheqiang <renheqiang@users.noreply.github.com>
Co-authored-by: franksong2702 <franksong2702@users.noreply.github.com>
2026-04-19 05:37:44 +00:00