Commit graph

2826 commits

Author SHA1 Message Date
Orange Pi Vietnam
d341f2084c
Merge branch 'nesquena:master' into master 2026-06-24 15:12:44 +07:00
nesquena-hermes
22b98e3922 Merge branch 'peek-4828' into gate/4828-reasoning-echo
# Conflicts:
#	CHANGELOG.md
2026-06-24 07:57:31 +00:00
nesquena-hermes
dcce509e7b Merge remote-tracking branch 'origin/master' into gate/4809-worklog-dur
# Conflicts:
#	CHANGELOG.md
2026-06-24 07:49:32 +00:00
Frank Song
2aaad7a282 Fix final answer reasoning echo 2026-06-24 15:29:25 +08:00
nesquena-hermes
f3086f4974 Merge branch 'peek-4809' into gate/4809-worklog-dur
# Conflicts:
#	CHANGELOG.md
2026-06-24 07:25:32 +00:00
nesquena-hermes
92b3ca7046 Merge branch 'peek-4818' into gate/4818-mobile-scroll 2026-06-24 06:59:17 +00:00
nesquena-hermes
988acdb441 Merge remote-tracking branch 'origin/master' into gate/4803-recycle-harden 2026-06-24 06:49:41 +00:00
Orange Pi Vietnam
e42d308245
Merge branch 'master' into master 2026-06-24 13:42:54 +07:00
akrhin
d89cfea45e
Merge branch 'master' into fix/mobile-scroll-jank-clean 2026-06-24 09:41:54 +03:00
Orange Pi Vietnam
b12f541394
Merge branch 'nesquena:master' into master 2026-06-24 13:41:38 +07:00
akrhin
98688491c1 fix(#MOBILESCROLL): prevent scrollTop jank to top on mobile during streaming DOM rebuild
Root cause: .messages had overflow-anchor:none unconditionally. On mobile
touch devices (iOS Safari, Android Chrome), the compositor can paint a frame
with scrollTop=0 between innerHTML='' and snapshot restore, scroll-janking
the user to the top of the transcript.

Three-layer fix:

1. CSS (style.css): Use overflow-anchor:auto on touch devices (mobile),
   keep overflow-anchor:none on desktop (mouse-driven) via
   @media (hover:hover) and (pointer:fine) — preserves the existing
   behavior where tool/card inserts don't yank a reading user.

2. JS guard (ui.js): Add window._fixMobileScrollJank() that temporarily
   sets overflowAnchor='auto' on #messages before innerHTML='' and
   clears it one rAF later — prevents the compositor frame with scrollTop=0.

3. Streaming protection (messages.js): Call _fixMobileScrollJank() at the
   top of each _doRender() tick so streaming DOM growth doesn't jank the
   viewport position.

Tests:
- Updated test_issue1360_streaming_scroll_hardening.py: split the
  overflow-anchor test into desktop (none) and mobile (auto) variants.
- Added test_mobile_scroll_jank.html: interactive visual test that
  simulates the scroll jank on a mobile-sized viewport.
2026-06-24 09:37:55 +03:00
nesquena-hermes
05cf44ffca Merge branch 'peek-4803' into gate/4803-recycle-harden 2026-06-24 06:37:38 +00:00
nesquena-hermes
b9f1491de7 Merge branch 'peek-4798-v2' into gate/4798-v2 2026-06-24 06:25:59 +00:00
Frank Song
cafeda63ca Preserve processed Worklog duration during message merges 2026-06-24 11:32:27 +08:00
nesquena-hermes
5253724f90 rebase(#2814): resolve i18n onto current master + add kanban_view_* keys to all 13 locales
Took master's i18n.js as base (it has all 13 locale blocks + had reorganized the
kanban keys, so the stale-branch conflict block would have duplicated them in
zh-Hant), then inserted #2814's 5 kanban_view_* keys into every locale block after
kanban_new_task — real translations for it/ja/zh/zh-Hant/fr (from the PR), English
fallback elsewhere. All 13 locales now have exactly 1 of each key; locale-parity +
kanban tests green (291 passed).
2026-06-23 23:40:45 +00:00
nesquena-hermes
86c3e67a46 test(#4800): accept _scheduleRender(parsed) in the token-handler anchor-registry assertion
#4800 changed the token SSE handler's call from _scheduleRender() to
_scheduleRender(parsed) (passes the pre-computed parse into the cache — the perf
optimization). The slice6 anchor-registry test asserted the literal no-arg call;
relaxed to _scheduleRender( so it matches the call regardless of args. Behavior
(token handler schedules a render) preserved + improved. Co-authored-by: wlknight
2026-06-23 23:07:15 +00:00
Rod Boev
6cf4f7a5d0 test(#4793): decouple recycle reset assertions 2026-06-23 18:49:50 -04:00
nesquena-hermes
643eb2e396 test(#4800): make _scheduleRender guard test signature-agnostic
#4800 changed _scheduleRender() -> _scheduleRender(parsed) (parse-result cache).
test_streaming_race_fix's regex hardcoded the empty-arg signature so it couldn't
find the function ('_scheduleRender not found') even though the _streamFinalized
guard it checks is intact (line 3759). Regex now matches any args. Co-authored-by: wlknight
2026-06-23 22:46:49 +00:00
nesquena-hermes
1dbff4e708 Merge branch 'peek-4800' into gate/4800-stream-perf 2026-06-23 22:46:14 +00:00
nesquena-hermes
e8b33066ec Merge remote-tracking branch 'origin/master' into stage/rodboev-4797-4796
# Conflicts:
#	CHANGELOG.md
2026-06-23 22:32:36 +00:00
Rod Boev
a4f33f7687 test(#4793): tighten recycle reset regressions 2026-06-23 18:25:39 -04:00
Rod Boev
004c9774d0 fix(#4793): harden recycled assistant turns and messages scrollbar drag 2026-06-23 18:19:23 -04:00
nesquena-hermes
edbe676b0d Merge branch 'peek-4796' into stage/rodboev-4797-4796 2026-06-23 22:19:13 +00:00
nesquena-hermes
e26a6e47c0 Merge branch 'peek-4797' into stage/rodboev-4797-4796 2026-06-23 22:19:12 +00:00
Rod Boev
bad9fd7e2b fix(#4793): harden recycled assistant turns and messages scrollbar drag 2026-06-23 18:14:05 -04:00
wlknight
20a900be60 fix(perf): eliminate O(DOM) streaming render freeze on long agent answers
Introduce _safeSmdRenderer — a renderer wrapper that hooks smd's set_attr
to validate URL schemes inline as each DOM node is created, eliminating
the per-token _sanitizeSmdLinks(assistantBody) full-DOM scan that caused
progressive freezing on answers of 30,000+ chars (5,000+ DOM nodes).

Also add parse-result caching to _scheduleRender to avoid redundant
_extractInlineThinkingFromContent scans between the token event handler
and the rAF render callback.

Changes:
- New _safeSmdRenderer(el): URL scheme safety inline via set_attr hook
  (identical algorithm to proven _streamFadeRenderer.set_attr, no animation)
- _smdNewParser: non-fade path uses _safeSmdRenderer instead of bare
  default_renderer
- _smdWrite: removed _sanitizeSmdLinks(assistantBody) call — safety now
  handled by renderer's set_attr at node-creation time
- _scheduleRender(parsed): accepts optional cached parse result from
  token handler to avoid duplicate O(n) text scans
- Token handler: passes _parseStreamState() result to _scheduleRender

_sanitizeSmdLinks is preserved at _smdEndParser (stream-end safety net)
and in fallback paths where smd is not available.

All 166 existing tests pass.
2026-06-24 06:09:44 +08:00
Rod Boev
53f18556fb Keep model refresh builds authoritative until cache save completes 2026-06-23 17:53:36 -04:00
Rod Boev
fdedb2078a Keep session-visit model refresh from restamping stale catalogs 2026-06-23 17:40:09 -04:00
nesquena-hermes
48663a4af3 Merge branch 'peek-4788' into gate/4788-json-view 2026-06-23 21:19:18 +00:00
Rod Boev
94e25ad494 fix(#4753): notify background desktop tabs without hiding streams 2026-06-23 17:10:03 -04:00
nesquena-hermes
7db3aa123f Merge branch 'peek-4656' into stage/4656-escape-readonly 2026-06-23 20:43:53 +00:00
nesquena-hermes
2d6b3c067f Merge branch 'peek-4781' into stage/4781-worklog-collapse
# Conflicts:
#	CHANGELOG.md
2026-06-23 20:27:38 +00:00
nesquena-hermes
ca368cc166 Merge branch 'peek-4478' into stage/4478-dom-recycle 2026-06-23 20:07:56 +00:00
nesquena-hermes
e617acfc79 test(#4748): stub _recordSessionProfileCount in the #4766 node harness
#4748 added a _recordSessionProfileCount() call inside _applySessionListPayload();
the pre-existing #4766 test isolates that function in node and must stub the new
helper (same pattern as the other stubbed helpers) or it ReferenceErrors. Not a
weakened assertion — the test still verifies old+new payload tab-count coverage.
2026-06-23 17:58:39 +00:00
Charles Bine
dd66640fae
feat(#484): configurable default view for JSON/YAML code blocks
The JSON/YAML tree viewer (#484) hardcoded its default: valid json/yaml
fenced blocks opened in Tree view at 10+ lines (`const showTree=lineCount>=10;`).
Make that default user-configurable while preserving current behavior.

- New settings (persisted via /api/settings -> settings.json):
  - structured_code_default_view: auto | on | off  (default auto)
  - structured_code_auto_tree_lines: int 1..1000    (default 10)
- ui.js: replace the hardcode with a sanitized, unit-testable decision
  helper _structuredCodeShowTree(mode, threshold, lineCount); Tree/Raw
  toggle, Raw <pre><code>, parse-failure fallback, and YAML lazy-load
  are unchanged.
- Appearance settings: 'JSON/YAML code blocks' select + 'Auto threshold
  lines' input (disabled outside auto mode); wired through the existing
  appearance-autosave and explicit-save paths; live re-render on change.
- boot.js seeds window globals; i18n labels added to all 13 locales.
- Default (auto + 10) reproduces the original >=10 behavior exactly.
2026-06-23 13:51:45 -04:00
nesquena-hermes
e89977d270 test(#4748): widen skeleton-flag slice to full _applySessionListPayload body (Codex gate)
#4748 added lines inside _applySessionListPayload() that pushed the
'_sessionListSkeletonActive = false;' assertion past the test's fixed 4000-char
window. Anchor the slice on the next function def (_mergeRenderSessionListOptions)
instead — robust to future additions. Assertion unchanged.
2026-06-23 17:47:43 +00:00
nesquena-hermes
a7eb7de83f Merge remote-tracking branch 'origin/master' into peek-4748
# Conflicts:
#	CHANGELOG.md
2026-06-23 17:43:38 +00:00
nesquena-hermes
18e252d59c test(#4741): update #4766 mock to accept the new redact_enabled kwarg
#4741 added redact_enabled= to _sidebar_session_response_item's call site
(routes.py:2199); the pre-existing #4766 test mocked it with a bare 'lambda row: row'
that rejects the kwarg -> full-suite TypeError. Mock now accepts the keyword-only
arg. Not a weakened assertion — the test still asserts bucket-count omission.
2026-06-23 17:17:17 +00:00
nesquena-hermes
50f7f7fcd3 test(#4741): add two #798 isolation regression guards (Opus gate hardening)
- env-change-with-unchanged-mtime must re-expand (proves the cache stores raw
  un-expanded YAML, not the expanded result -> no stale cross-profile expansion)
- no-cross-serve between two profile config paths (proves the parse cache is
  path-keyed). Both pass on the current impl; locks down the highest-risk
  cross-profile credential-bleed invariant per Opus's non-blocking note.
2026-06-23 17:13:22 +00:00
nesquena-hermes
235bfffaf0 Merge remote-tracking branch 'origin/master' into peek-4741
# Conflicts:
#	CHANGELOG.md
2026-06-23 17:06:17 +00:00
Rod Boev
e5aa548d67 fix(#4756): refresh stale model catalogs on session visit 2026-06-23 12:50:28 -04:00
nesquena-hermes
98e672551a Merge branch 'peek-4782' into gate/4782-sidebar-trim 2026-06-23 16:46:10 +00:00
Rod Boev
2504eb90d7 fix(#4755): honor profile default workspace on fresh sessions 2026-06-23 12:18:44 -04:00
nesquena-hermes
f4af6d8419 fix(#4778): scroll-rebuild guard must not reclassify a pinned follower as unpinned
Codex regression gate caught: the guard predicate keyed on a raw messagesEl.scrollTop>0,
so a pinned reader transiently at bottomDistance>250 mid-render (assistant body grows
before the anchor scene re-renders) got flipped to _messageUserUnpinned=true/_scrollPinned=false
and lost auto-follow. Require an explicit non-follow signal (_messageUserUnpinned || _scrollPinned===false)
instead. Updated the existing guard test to a genuine unpinned reader + added a pinned-large-growth
regression. Co-authored-by: franksong2702
2026-06-23 16:17:01 +00:00
nesquena-hermes
c6d633fd2c Merge branch 'peek-4777' into stage/livestream-chat-scroll-4778-4777-4780
# Conflicts:
#	CHANGELOG.md
2026-06-23 16:09:00 +00:00
Rod Boev
165433fea6 Keep legacy sidebar tests aligned with visible-row filtering 2026-06-23 11:56:25 -04:00
Rod Boev
75016c99f6 test(sidebar): align legacy list checks with visible-session filtering (#4775) 2026-06-23 11:46:37 -04:00
Frank Song
f653b1b8d9 feat: allow live worklog summary collapse 2026-06-23 23:22:16 +08:00
Rod Boev
bd72c785b5 fix(sidebar): reject cached fallback rows from the wrong hidden-filter mode (#4775) 2026-06-23 11:13:33 -04:00
Frank Song
4c8e88ab2d fix: dedupe live compact worklog process prose 2026-06-23 23:03:04 +08:00