Commit graph

6297 commits

Author SHA1 Message Date
nesquena-hermes
eaf7d1e9ab gate-fix #5466: stamp anchor attrs on incremental node + teardown on all terminal paths
Codex gate findings (2 SILENT, both fixed):
- ui.js: incremental prose node now flows through the shared row-decoration
  block (data-anchor-scene-row/-row-id/-row-role/-source-event-type) instead of
  returning early, so live incremental rows keep the identity attrs the scene
  reconciler matches on.
- messages.js: _cancelThrottledSnapshotTimer() + _clearAnchorProseIncrementalNode()
  now run on apperror, cancel, _handleStreamError, and _restoreSettledSession
  terminal paths (previously only fallback/done/stream_end) — closes the
  snapshot-timer/anchor-cache/window-global teardown gap.
- test: extend test_messages_js_stream_perf_cleanup_lifecycle to pin teardown on
  all four additional terminal paths.

CORE equivalence (Codex flagged smd != renderMd): reconciled — Opus's 1498-frame
harness against real smd.min.js proves incremental-smd == whole-smd byte-identical;
live-smd-vs-renderMd difference is the already-shipped fidelity model (main live
body streams smd, settles renderMd), and the incremental path is gated on !settled
so settled DOM still comes from renderMd. Not a regression.
2026-07-03 21:24:08 +00:00
nesquena-hermes
819f1a1e7b Merge PR #5466 from ai-ag2026: reduce O(n^2) streaming render to O(n) (#5455) 2026-07-03 21:04:16 +00:00
nesquena-hermes
b9813af66c
Merge pull request #5476 from nesquena/release/stage-p1c
Release v0.51.838 — sidebar read-only projection (#5464) + pause hidden-tab polling (#5465)
2026-07-03 13:48:00 -07:00
nesquena-hermes
8fe2d63ec0 Merge remote-tracking branch 'origin/master' into release/stage-p1c
# Conflicts:
#	CHANGELOG.md
2026-07-03 20:44:31 +00:00
nesquena-hermes
bc0a3b299a docs(changelog): note hidden-tab attention-chime timing delta (Opus advisor) 2026-07-03 20:43:42 +00:00
nesquena-hermes
2fd2d0951f docs(changelog): Batch C — #5464 read-only session-listing projection + #5465 pause hidden-tab polling (#5455) 2026-07-03 20:32:58 +00:00
nesquena-hermes
97821f5b3f
Merge pull request #5475 from nesquena/release/stage-5442
Release v0.51.837 — persist TTS and voice preferences server-side (#5442)
2026-07-03 13:18:16 -07:00
nesquena-hermes
6edcf14bbc Merge PR #5465 from ai-ag2026: pause background session polling while tab hidden (#5455) 2026-07-03 20:16:35 +00:00
nesquena-hermes
797eb4a1b9 Merge PR #5464 from ai-ag2026: open session-listing projection read-only (#5455) 2026-07-03 20:16:35 +00:00
nesquena-hermes
eb59ac8fb3 docs(changelog): #5442 persist TTS/voice preferences server-side (#5435) 2026-07-03 20:14:49 +00:00
nesquena-hermes
8120e69e1d Merge PR #5442 from rodboev: persist TTS and voice preferences server-side (#5435) 2026-07-03 20:04:55 +00:00
nesquena-hermes
8399241bab
Merge pull request #5474 from nesquena/release/stage-p1a
Release v0.51.836 — profile overflow-model validation (#5453) + read-only fork guard (#5449)
2026-07-03 13:02:10 -07:00
nesquena-hermes
fb6606152a docs(changelog): Batch A — #5453 profile overflow-model validation + #5449 read-only fork guard 2026-07-03 19:56:48 +00:00
nesquena-hermes
a1f75a40c9 fix(test): assert branch-guard on the extracted helper, not stale inline text
test_branch_endpoint_consults_foreign_session_guard_on_missing_sidecar
grepped the inline handler block for _claim_or_synthesize_cli_session +
not_claimable + 403 — but #5449 extracted that logic into the
_load_branch_source_or_refuse helper, leaving only a dead comment carrying
the old text to satisfy the grep. Point the test at the helper so it asserts
real post-refactor structure instead of a comment.
2026-07-03 19:46:56 +00:00
nesquena-hermes
f2ab07757f ship-pass: #5453 overflow-path regression test + drop #5449 dead comment
- Add test_profile_model_selection_accepts_model_in_overflow_extra_models
  (the extra_models overflow-bucket regression test the warm dossier flagged
  as the #5453 ship-pass note).
- Drop the stray dead pseudo-code comment left in handle_post branch route
  (#5449 cosmetic nit).
2026-07-03 19:45:37 +00:00
nesquena-hermes
00e7203ec8 Merge PR #5449 from rodboev: hide read-only cron fork affordances (#5439) 2026-07-03 19:44:33 +00:00
nesquena-hermes
fa4b404542 Merge PR #5453 from WallaceWebster: include extra_models in profile model validation (#5453) 2026-07-03 19:44:33 +00:00
nesquena-hermes
d5e1274258
Merge pull request #5470 from nesquena/release/stage-5454
Release v0.51.835 — remove transparent-stream live-row entrance animation (#5454)
2026-07-03 11:35:03 -07:00
nesquena-hermes
0a80aa2296 docs(changelog): #5454 remove transparent-stream live-row entrance animation (residual #5367) 2026-07-03 18:31:13 +00:00
nesquena-hermes
a085f919f2 Merge PR #5454 from rodboev: suppress transparent stream live row entrance animation (residual #5367)
Removes the #liveAssistantTurn .transparent-event-row entrance animation
rule and its now-unused @keyframes transparent-event-enter, eliminating the
entrance-animation replay on streaming rebuilds that remained after the
#5400 identity-reconcile fix. Depth-fade [data-transparent-fade] rules
preserved (avoids the #5406 opacity-clobber). Follow-up to already-closed #5367.

Co-authored-by: Rod Boev <rodboev@users.noreply.github.com>
2026-07-03 18:28:52 +00:00
TARS
3f4ebf18a8 fix(sidebar): refresh timestamp labels on tab return
Add a dedicated visibilitychange hook for the 60s relative-time refresh poll so skipped hidden-tab ticks repaint immediately when the tab becomes visible, even when no streaming poll is active.
2026-07-03 20:13:24 +02:00
TARS
eedbf8b05f fix: clear stream perf cleanup state 2026-07-03 20:10:40 +02:00
TARS
10ecfbb376 fix: encode read-only session DB URI 2026-07-03 20:04:41 +02:00
TARS
2f8e2ba547 test: match optimized live token render path 2026-07-03 19:55:33 +02:00
TARS
47855eed88 test: account for session index heal connection 2026-07-03 19:55:29 +02:00
Rod Boev
af3eb88225 Drop redundant live-row suppression after removing the animation source 2026-07-03 13:48:20 -04:00
TARS
fcf3e23643 perf(sidebar): pause background session polling while the tab is hidden (#5455)
The 30s streaming poll (renderSessionList -> GET /api/sessions + full sidebar
rebuild) and the 60s relative-time refresh (renderSessionListFromCache -> full
DOM rebuild) ran unconditionally, including in hidden background tabs, so a
backgrounded window kept fetching and rebuilding the sidebar it could not show.

Guard both interval callbacks with document.hidden and refresh the list on
visibilitychange when the tab is shown again, mirroring the existing gateway
poll. Visually neutral while the tab is visible; a hidden tab simply stops
burning network and DOM churn and re-syncs the moment it is shown.

Verified: node --check + ESLint runtime guard clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 18:41:49 +02:00
TARS
ed922f4f18 perf(stream): throttle live-turn snapshot and skip redundant per-token parse (#5455)
Two O(n^2) costs on the per-token/per-frame streaming path, both over the
growing answer:

WS2.2 — snapshotLiveTurn() serialized the whole live turn via turn.outerHTML on
every render frame. That snapshot only backs mid-stream session-switch restore,
and the switch path (sessions.js) plus tool/done event boundaries already
capture synchronously, so the per-frame call is throttled to a coarse trailing
snapshot instead of serializing the entire growing DOM each frame.

WS2.3 — the token handler ran _parseStreamState() (strip tool-call XML + extract
inline thinking over the FULL accumulated text) on every token, but _doRender
re-parses once per throttled frame anyway and the only per-token use is the
assistant-row creation gate. Skip the parse once the row exists (the common
case); keep it only until the row is created. Also drop the full-string
toLowerCase() allocation in _stripXmlToolCalls for a non-allocating regex test.

Output-neutral: same rendered DOM; the row-creation gate and snapshot semantics
are preserved (row appears within one 66ms frame; switch/settle snapshots stay
synchronous). node --check + ESLint runtime guard clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 18:41:49 +02:00
TARS
855b7f1ea4 perf(sessions): open the session-listing projection read-only (#5455)
read_importable_agent_session_rows() is a pure read, but it opened a
read-write sqlite connection on the live multi-GB WAL state.db and re-ran a
defensive CREATE INDEX self-heal on every sidebar build. Holding a
write-capable handle while the agent streams into the same DB adds needless
checkpoint/lock surface.

Open the DB read-only (file:...?mode=ro) for the projection, and self-heal a
missing idx_messages_session through a separate short-lived writable
connection only. With the index present (the normal case) the read path
performs zero writes; when it is missing the self-heal still runs and rows
still come back.

Behavior-neutral: identical rows when the index exists; self-heal preserved
when missing; read-only-fs degradation to the pre-aggregated path unchanged.

Tests: tests/test_issue5455_listing_readonly_connection.py (read-only open,
no writable connection when index present, self-heal when missing).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 18:41:49 +02:00
TARS
304a82d9b4 perf(stream): render anchor-scene live prose incrementally via smd (#5455)
In compact-worklog mode the anchor activity scene re-renders every frame, and
its live prose row was rebuilt with renderMd(fullText) each time — re-parsing
the entire growing answer per frame, which is O(n^2) over a long streamed
response (the incremental smd parser that the main body already uses was
bypassed and its segment hidden).

Keep a persistent per-segment smd parser + DOM node (keyed by the prose row's
local_id, using the same safe renderer as the live body) and feed it only the
delta each frame; hand that persistent node back to the scene builder instead
of re-parsing. Turns the per-frame prose cost from O(n) into O(delta), i.e. the
whole answer from O(n^2) to O(n).

Safe by construction: settled rows and any failure (no smd, no stable key,
parser error, text divergence) fall through to the existing renderMd path, so
worst case is identical to today. Cache is bounded (<=32 segments) and self-heals
on non-append text changes, mirroring _smdWrite.

Verified: node --check + ESLint runtime guard clean. Streaming render profiled
in-browser via a per-frame timing probe.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 18:41:49 +02:00
Rod Boev
a9eb90a0d0 test(#5435): preserve raw speech settings between API cases 2026-07-03 09:22:50 -04:00
Rod Boev
8c82ed8f11 fix(#5435): read voice silence timeout at use time 2026-07-03 08:57:44 -04:00
Rod Boev
7a21825722 fix(#5435): keep speech settings payload sparse 2026-07-03 00:22:39 -04:00
Rod Boev
904d741ed2 fix(#5367): suppress transparent stream live row animation 2026-07-02 23:31:57 -04:00
nesquena-hermes
654daf8f2a fix(profiles): include extra_models in profile model validation
Clean rebase of WallaceWebster's #5453 (rebase-first).

Co-authored-by: WallaceWebster <WallaceWebster@users.noreply.github.com>
2026-07-03 03:26:25 +00:00
Rod Boev
fdacb4b922 fix(#5435): stop startup workspace repair from persisting speech defaults 2026-07-02 21:28:46 -04:00
nesquena-hermes
0735a1b853 fix(#5439): hide read-only cron fork affordances
Clean rebase of rodboev's #5449 (rebase-first).

Co-authored-by: rodboev <rodboev@users.noreply.github.com>
2026-07-03 00:58:30 +00:00
Rod Boev
8f7b9c1d0d fix(#5435): drop dead persisted-key state from config load 2026-07-02 19:38:35 -04:00
Rod Boev
3b344b1d9a fix(#5435): preserve local speech prefs until settings.json owns them 2026-07-02 19:33:13 -04:00
nesquena-hermes
312d3faba4
Merge pull request #5448 from nesquena/release/stage-5434
Release — restore readable inline Mermaid sizing (#5434, fixes #5413)
2026-07-02 15:49:01 -07:00
nesquena-hermes
a6504a8c58 fix(#5434): scope new Mermaid sizing to inline only — restore master lightbox behavior + inline Fit button (Codex gate findings)
Codex re-gate found 2 SILENT regressions the certifier missed:
- inline lost the 'Fit to screen' toolbar button (PR gated Fit to lightbox-only)
- the new readable-scale/envelope path leaked into lightbox mode (changed zoom-out floor + fit init for wide diagrams)
Fix: toolbar restored to master shape (Fit for all modes, Fullscreen inline-only);
_minScale() returns the flat _MERMAID_VIEWER_MIN_SCALE for lightbox; lightbox init
restored to master's _fitScale()/box*initialFit; the new readable-height sizing is
now scoped strictly to inline mode. Tests updated to the master-consistent contract.
2026-07-02 22:37:12 +00:00
nesquena-hermes
9f7d7e986b docs(changelog): #5434 inline Mermaid sizing 2026-07-02 22:23:23 +00:00
nesquena-hermes
cb8ab640b5 Merge #5434: restore readable inline Mermaid sizing (#5413) [rodboev] 2026-07-02 22:22:27 +00:00
nesquena-hermes
a4ad03bd68 fix(#5413): restore readable Mermaid sizing (rebased onto current master w/ #5437)
Clean rebase of rodboev's #5434 (rebase-first, re-based post-#5437).

Co-authored-by: rodboev <rodboev@users.noreply.github.com>
2026-07-02 21:56:29 +00:00
nesquena-hermes
2829b2adf7
Merge pull request #5447 from nesquena/release/stage-5437
Release — harden ElevenLabs TTS transport guards (#5437, fixes #5430)
2026-07-02 14:48:04 -07:00
nesquena-hermes
5ca3bc7f3d docs(changelog): #5437 harden ElevenLabs TTS transport (no-redirect/no-proxy opener) 2026-07-02 21:36:08 +00:00
nesquena-hermes
2dcf7f529e Merge #5437: harden ElevenLabs TTS transport guards (#5430) [rodboev] 2026-07-02 21:35:42 +00:00
nesquena-hermes
3ba8f0780c
Merge pull request #5446 from nesquena/release/stage-5441
Release — cap generated update summary cache (#5441, fixes #5435)
2026-07-02 14:27:48 -07:00
nesquena-hermes
f7338f32dd docs(changelog): #5441 cap update summary sessionStorage cache at 256KB 2026-07-02 21:14:32 +00:00
nesquena-hermes
dc7e9e34d2 Merge #5441: cap generated update summary cache (#5435) [rodboev] 2026-07-02 21:14:03 +00:00