Commit Graph
598 Commits
Author SHA1 Message Date
9643cdd5c1 Release exp-v0.52.50: transparent-stream lazy settled DOM + per-turn cap (#5974, #5966) (#5981)
* fix(transparent-stream): defer settled tool-detail DOM + cap per-turn rows (#5966)

Reported by @curtisszmania-cytocync.

Transparent Stream built a DOM node for every activity event of every settled
turn at load, and eagerly materialized each tool row's full detail body — a
15+ prompt reasoning-heavy history produced thousands of subtrees and tipped the
tab into a multi-GB freeze. The #5860/#5839 lazy-worklog fix did not cover
Transparent Stream (it never collapses).

Two-part surgical fix in static/ui.js, mirroring #5860's proven machinery:
- Row-detail deferral: a settled+collapsed transparent tool row renders
  header-only; its heavy .tool-card-detail body builds on first expand
  (_materializeTransparentToolDetail), recovering the tool call from the scene
  after an innerHTML cache round-trip. Same anchor-suppressed post-processing as
  the eager path, so an expanded row is byte-identical.
- Per-turn row cap: a settled turn with >CAP+SLACK (30+10) rows renders the last
  30 behind a clean 'Show earlier steps (N)' affordance that materializes the
  prefix in place with viewport compensation. Just-settled turn (keep-open token)
  and already-revealed turns are exempt; true Trace tool-count is stashed so the
  label stays honest; Expand-all reveals capped rows; cache-restore re-wires the
  affordance. Live rendering is untouched.

Server-side #5858 (scene serialize-after-messages) already covers the container
RSS half on the experimental channel; this is the browser-DOM half.

* style(#5966): compact 'Show earlier steps' pill (hug content, left-aligned)

Constrain the affordance to fit-content width + align-self:flex-start so it
reads as a light inline control on the activity rail, not a full-width bar.

* fix(#5966): address Codex gate findings + Fable UX fast-follows

Codex SHIP-ONLY-WITH-FIXES (3 SILENT defects), all fixed + browser-verified:
- F1: buildToolCard PRE-BUILDS .tool-card-detail when a tool has args/output, so
  the old `!detail` defer guard skipped exactly the heavy rows. Defer now fires on
  settled+collapsed+has-detail and STRIPS any prebuilt body (verified: 400 shell
  tool rows -> 0 detail bodies mounted; expand still materializes byte-identically).
- F2: stamp owner rawIdx on rows + affordance; dataset recovery and cache-restore
  rebind resolve the scene-owning message (multi-segment turns own it on a later
  segment, not the first) with a scene-owning-segment fallback.
- F3: persist revealed-turn state in a session/owner-keyed Set + invalidate the
  session HTML cache on reveal, so a rebuild/switch-away never re-caps a turn the
  user expanded (verified: reveal 30->400, full re-render stays 400).

Fable SHIP-UX fast-follows: t()-with-fallback label (+ en locale keys), 640px
touch breakpoint, stale comment fixed.

Tests: 21 pass (added has-detail deferral+strip, detail-less no-defer, owner-idx
recovery, persistent-reveal, i18n).

* fix(#5966): address Codex re-gate findings (r2)

Codex re-gate SHIP-ONLY-WITH-FIXES — 2 more SILENT defects, both fixed + browser-verified:
- F1(r2): _materializeTransparentToolDetail rebuilt via the thinner
  _transparentToolDetailHtml(), dropping buildToolCard's richer detail (diff
  coloring / show-more / canonical shell-command lead). Now transplants
  buildToolCard(tc)'s own .tool-card-detail node so an expanded deferred row is
  byte-identical to the eager path (verified: canonical structure + 595-char body).
- F2(r2): after an in-session renderMessages() rebuild (next send) an already-open
  settled tool row got re-deferred, and disclosure-restore only toggled .open →
  open-but-empty card. _setWorklogDetailDisclosureOpen now materializes a deferred
  transparent row BEFORE toggling open (verified: expand → rebuild → still open
  WITH content). Likely the same defect the RegressionGate caught intermittently.

Tests: 22 pass (added canonical-detail + disclosure-restore-materialize).

* fix(review): add show_earlier_steps i18n keys to all locales (#5966)

The transparent-stream row-cap "Show N earlier steps" pill added two new
i18n keys (show_earlier_steps, show_earlier_step_one) to the English block
only, so the strict locale-parity tests (zh/ko/ru/zh-Hant/...) failed with
missing-key assertions and CI shard 0 went red across 3.11/3.12/3.13.

Add both keys to all 14 non-English locale blocks with the English string as
fallback (the repo's established add-with-English-fallback convention for new
UI keys). Inserted after each block's collapse_all anchor. All 197 locale
tests + the #5966 suite green; node --check clean.

* fix(review): extract _transparentToolRowHasDetail into the #5700 harness

#5966 added a _transparentToolRowHasDetail() call into the settled transparent
render (_anchorSceneTransparentNodeForRow) to decide whether to defer a
collapsed tool row's detail body. The pre-existing #5700 timestamp test extracts
that render fn into a node harness but didn't extract the new helper, so the
extracted fn hit a ReferenceError → node exited non-zero → 3 #5700 tests failed
(RED across CI shards; the PR updated its own #5966 harness but missed this one).

Add `eval(extractFunc('_transparentToolRowHasDetail'))` to the harness. The
helper self-guards its _toolActionKind/_toolCardAllowsDetail deps (returns true
when absent), and the #5700 timestamp lives on the row HEADER (rendered even when
detail is deferred), so all 20 #5700 assertions pass unchanged — confirming this
was a harness gap, not a timestamp regression.

* fix(#5974): hide Show-earlier-steps pill when a capped transparent turn is collapsed (Fable UX gate)

Fable UX gate SHIP-WITH-UX-FIXES: the .transparent-earlier-steps pill wasn't in the
.assistant-turn[data-transparent-turn-collapsed=1] hide rule, so collapsing a capped
turn via the name-tag toggle left an orphan pill. Added it to the hide rule.
(i18n finding was already resolved — both pill keys present in all 15 locales w/
English fallback + show_earlier_step_one is live at ui.js:12918, not dead.)

* Release exp-v0.52.50: transparent-stream lazy settled DOM + per-turn cap (#5974, #5966)

---------

Co-authored-by: nesquena-hermes <agent@nesquena-hermes>
Co-authored-by: Nathan Esquenazi <nesquena@gmail.com>
2026-07-11 21:56:20 -07:00
nesquena-hermes bdb245346d Merge #5739: worklog event timestamps (+ gate fixes) 2026-07-11 00:43:24 +00:00
nesquena-hermesandrodboev. 97fe772fdb fix(worklog): add full-date tooltip + hide event-time under 420px (Fable UX)
Two non-blocking UX improvements from the Fable gate on #5739:
1. Full date+time tooltip (title attr) on the worklog event-time label — the bare
   clock is date-ambiguous when a settled session is reviewed later or a run crosses
   midnight. New _activityFullClockLabel (range-guarded so a bad epoch never yields
   'Invalid Date' in the tooltip) + test.
2. Hide the time label under 420px — its ~50px of fixed chrome squeezes the
   collapsed row's flexible preview toward zero on phones.

Co-authored-by: rodboev.
2026-07-11 00:38:23 +00:00
nesquena-hermes 0af0a5fcf0 Merge #5746: final answer only activity display mode 2026-07-10 23:50:28 +00:00
tandruizanthony 8949cad20f Merge #5792: keep media downloads visible in CSV previews
Co-authored-by: ruizanthony <ruizanthony@users.noreply.github.com>
2026-07-10 21:33:41 +00:00
8cc2d6f881 Release: model-picker Selected badge + Transparent Stream dupe-prefix suppression (#5757, #5758) (#5850)
Two visible render PRs, gate-passed (deep-review round), Nathan-approved to ship.

- #5757 (rodboev): mark active model with a Selected badge + open its provider group (#5748).
  Screenshot-verified (badge clear + correctly placed on active row).
- #5758 (rodboev): suppress the live-token prose row that is a strict prefix of the final
  answer (#5749). Provenance-gated (live-prose:* token rows after last tool row only) so it
  can't eat legitimate narration; reproduction test proves the dupe is gone.

Codex SAFE + full regression green (1576 render tests). 18 own tests pass together.

Co-authored-by: t <a@b>
Co-authored-by: rodboev <rodboev@users.noreply.github.com>
2026-07-09 12:51:18 -07:00
Isla-Liu bef8fbd3b6 fix: align wakeup notice with message rail 2026-07-09 03:21:44 +00:00
Isla-Liu fa04044e7c fix:[WebUI] 修正 background wakeup 訊息渲染邊界 2026-07-09 03:21:44 +00:00
Rod Boev 837a552746 fix(chat): contain streaming code block layout (#5760) 2026-07-09 03:08:19 +00:00
sheldon-im 06e0df4656 Announce New Chat workspace transiently 2026-07-09 02:40:36 +00:00
t 99bd2930cc fix(updates): mobile badge ellipsis needs display:block (Fable r2)
text-overflow:ellipsis is a no-op on the inline-flex badge; display:block in the
<=768px rule makes the ellipsis actually render for a long experimental describe.
2026-07-08 20:06:34 +00:00
t 0a56f44f5e fix(updates): Fable UX gate — channel re-check race + copy + mobile badge
MUST-FIX: /api/updates/check now accepts an explicit 'channel' in the POST body;
the Settings dropdown passes the just-picked value to checkUpdatesNow(channel) so
the immediate re-check can't race the debounced autosave PUT and answer for the
previous channel (verified live: body channel wins over stale saved setting).

SHOULD-FIX:
- copy: 'soaked' -> 'soak-tested'; append 'Applies to WebUI updates only.' to the
  channel helper text (all 15 locales, native translations)
- mobile: .settings-version-badge gets max-width/overflow/ellipsis in the <=768px
  query so the '· Experimental' suffix can't overflow a 320px viewport

(#5 badge-suffix i18n key deferred — non-blocking fast-follow per Fable, matches
the existing English-only version badge on master.)
2026-07-08 20:01:39 +00:00
Anthony Ruiz 87a9e25e41 fix(csv): keep media downloads visible in previews 2026-07-08 19:51:38 +00:00
nesquena-hermesandrodboev 2717ea0ac5 feat(chat): add final answer only activity display mode (#5706, picker grid fixed)
Clean rebase of rodboev's #5746 (rebase-first).

Co-authored-by: rodboev <rodboev@users.noreply.github.com>
2026-07-07 14:38:08 +00:00
Rod Boev 815d06f10f feat(worklog): show Transparent Stream event timestamps (#5700) 2026-07-07 01:05:59 -04:00
rodboevandnesquena-hermes ae8d0bf3fb fix(#5701): keep the composer above iPad keyboards
On touch-primary devices (iPad Safari) the on-screen keyboard shrinks the
visual viewport but not the layout viewport, so the bottom-pinned composer
sits behind the keyboard. Compute a --keyboard-bottom-inset from visualViewport
and pad the composer up by it; clear it when the keyboard closes / on
non-touch / no-visualViewport. Reuses the existing visualViewport + pageshow
hooks; no-op on desktop/fine-pointer.

Co-authored-by: nesquena-hermes <nesquena-hermes@users.noreply.github.com>
2026-07-07 05:05:11 +00:00
nesquena-hermes 51dffad1ae Merge PR #5594 into visible-batch stage 2026-07-06 05:37:45 +00:00
nesquena-hermes 25e32839a3 Merge PR #5633 into visible-batch stage 2026-07-06 05:37:45 +00:00
nesquena-hermes a2e5dff18e Merge PR #5560 into visible-batch stage 2026-07-06 05:37:44 +00:00
nesquena-hermes 49afd5c0c2 Merge PR #5605 into visible-batch stage 2026-07-06 05:37:44 +00:00
nankingjing 32f1e2317f fix(ui): scope .msg-time responsive rules to .msg-role .msg-time
The responsive font-size overrides for .msg-time were applied globally,
affecting both the role header timestamp (which is only a hover title
tooltip there) AND the message footer timestamp (.msg-foot .msg-time).

Scope to .msg-role .msg-time so the footer row retains its balanced
10.5px base while the role header timestamp scales with font-size.
2026-07-06 10:03:46 +08:00
nankingjing 49d54e0a1d fix(ux): scope mermaid min-height to inline+mobile only
Remove min-height:200px from the global .mermaid-viewer-viewport rule
(it was outside the @media(max-width:640px) block despite the PR title).
Add a properly-scoped .mermaid-viewer--inline .mermaid-viewer-viewport
min-height inside an actual @media(max-width:640px) block, capped at
min(200px, 70vh) so it cannot override the lightbox fit-to-screen envelope.
2026-07-06 10:02:05 +08:00
nesquena-hermesandRod Boev 936c5b051b release: redesign cron preset schedule builder — sentence UI with time picker + day dropdowns (#5554)
Reworks the #5552 preset builder per maintainer UX feedback + Fable design advisory: one natural 'Schedule: [preset] on [day] at [time]' row; native time picker (themed) replacing hour/minute number boxes; day-of-week + day-of-month dropdowns; raw cron field shown only on Custom; live cron preview; Custom last; new jobs default to Daily 09:00; keystroke-clamp + mid-typing-hide bugs fixed. New i18n keys across all 14 locales. Full gate: Codex SAFE, Fable SHIP-UX, suite 12160/0, browser clean.

Co-authored-by: Rod Boev <rod.boev@gmail.com>
2026-07-06 01:35:55 +00:00
nesquena-hermes 13ecbd79fb review: merge #5554 (2e27ff64) 2026-07-06 00:38:30 +00:00
nesquena-hermes e6b2ac9119 review: merge #5506 (0c1bdce0) 2026-07-06 00:16:29 +00:00
nesquena-hermesandRod Boev c2e9277c46 release: reuse the rich model picker in Preferences (#5502)
Generalizes renderModelDropdown() to serve both the composer and Preferences pickers (backward-compatible defaults keep the composer identical). Folded in Fable UX fixes: label->chip association, downward shadow for the down-opening settings picker, and mobile keyboard-pop suppression across all 3 render paths (open/internal-filter/refresh) with focus preserved while typing. Full gate (4 rounds): Codex SAFE, Fable SHIP-UX, suite 12153/0, browser clean; composer picker verified unchanged.

Co-authored-by: Rod Boev <rod.boev@gmail.com>
2026-07-05 23:22:31 +00:00
Rod Boev 9f9ebc9746 fix(#5583): keep mobile nav actions visible 2026-07-05 18:40:41 -04:00
nesquena-hermes d5dae70c43 review: merge #5502 (087c694c) 2026-07-05 22:35:58 +00:00
nesquena-hermesandRod Boev eef981d3dc release: copyable workspace relative paths (#5548)
Adds 'Copy relative path' to the workspace file-tree context menu + preview header. Folded in gate fixes: preview-header button folds to icon-only on a narrow pane via @container rightpanel (not viewport @media), with data-i18n-title/aria-label so the tooltip+accessible name localize. Full gate: Codex SAFE, Fable SHIP-UX, suite 12147/0, browser clean.

Co-authored-by: Rod Boev <rod.boev@gmail.com>
2026-07-05 22:26:31 +00:00
nesquena-hermes f53bfb6c97 review: merge #5548 (bac619e767) 2026-07-05 21:57:42 +00: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
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
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
nankingjing 8dd4d722c0 @
fix(ui): scale model name, icon, and TPS badge with font-size preference

The .msg-role (model name/icon header), .role-icon, .msg-role-name,
.msg-tps-inline, and .msg-time elements did not respond to the
data-font-size attribute on :root, causing them to appear
disproportionately small when users selected larger text sizes.

Add responsive CSS rules for small/large/xlarge font-size modes so
the chat role header scales proportionally alongside .msg-body text.

Also replaces the hardcoded inline style="font-size:12px" on the
assistant name span with a class-based rule (.msg-role-name) so the
responsive overrides can take effect.

Closes #5372

Co-Authored-By: Claude <noreply@anthropic.com>
@
2026-07-05 19:01:56 +08: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 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 94305093d8 Merge latest master into compression recovery action
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-07-05 13:24:10 +08:00
Frank SongandPaperclip 1262148fc8 Merge latest master into compression recovery action
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-07-05 12:43:07 +08:00
nesquena-hermesandrodboev 9be4048c72 fix(#5501): fold in Fable a11y hardening — live region, aria-disabled, focus restore, ellipsis
Fable UX gate SHIP-WITH-UX-FIXES (non-blocking). Applied all: (1) role=status +
aria-live=polite on the error note so retry failure/restore is announced to
screen readers; (2) pending state uses aria-disabled (not the disabled property)
so the button retains keyboard focus, with click/keydown guards keeping it inert;
(3) on a failed retry, the fresh rebuilt Retry button reclaims keyboard focus
(_retryFailedFocus flag, rAF-guarded) so keyboard users aren't dropped to <body>;
(4) label uses a true ellipsis 'Retrying…' matching the app's other progress
string. CSS styles [aria-disabled=true] alongside [aria-busy]. Tests updated +
new a11y assertions; 8/8 pass, node --check clean.

Co-authored-by: rodboev <rodboev@users.noreply.github.com>
2026-07-05 04:39:14 +00:00
nesquena-hermes 7349a9434f fix(#5501): improve session-list retry feedback
The sidebar's load-error Retry button behaved like a raw idle browser button while
the next slow fetch was pending, so it looked broken/unresponsive. Retry now paints
an immediate pending state (label 'Retrying...', disabled, aria-busy), keeps the
retry state local to the error block via _renderSessionListLoadErrorNote(), and
lets the existing success/failure paths replace the error object when the request
settles (restoring 'Retry' on failure). Also adds proper styling.

Contributor stage; gate-pass. Co-authored-by: rodboev <rodboev@users.noreply.github.com>
2026-07-05 04:39:14 +00:00
nesquena-hermes 39a4d67e5c fix(#5385): increase approval card height cap on mobile
The mobile command/tool approval popup rendered too small — options didn't all fit
and required scrolling within the cramped popup to select (Android WebUI wrapper).
Raises the mobile @supports(dvh) .approval-inner max-height cap from
min(52dvh,360px) to min(60dvh,420px) so the options fit without in-popup scrolling;
still overflow-y:auto so very tall content scrolls rather than clipping. Scoped to
the mobile dvh rule; desktop unaffected. Adds a source-level guard test.

Contributor stage; gate-pass. Co-authored-by: nankingjing <nankingjing@users.noreply.github.com>
2026-07-05 04:04:02 +00:00
Rod Boev 2c66f7b65f fix(#5583): keep mobile nav actions visible 2026-07-04 21:23:42 -04:00
Rod Boev 0fc78da5ff fix(#5545): keep center pane readable in three-panel layout 2026-07-04 19:11:05 -04:00
Frank SongandPaperclip 9280c073ba Merge latest master into compression recovery action
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-07-05 06:22:24 +08:00
nesquena-hermesandluperrypf cebfdf41f9 fix(#5541): iOS PWA streaming freeze + SSE reconnect reliability
Two mobile reliability fixes on the crown-jewel chat streaming path:
(1) content-visibility:auto on off-screen .msg-row under @media(pointer:coarse)
so WKWebView skips layout/paint for off-screen rows during streaming (kills the
long-chat freeze). The LIVE turn is kept content-visibility:visible via the
STABLE #liveAssistantTurn id (covers ALL render modes — Compact Worklog,
Transparent Stream, restored-live — not just the Transparent-Stream path that
stamps data-live-assistant-turn), so a normal live turn on touch never blanks
mid-stream and its height keeps growing so the new-message cue still fires.
contain-intrinsic-size:auto 1px preserves flick-scroll momentum. Scoped to
touch — desktop find-in-page untouched. Deliberately does NOT set
overflow-anchor:none (inert on iOS WebKit; re-opens #4856/#5338).
(2) SSE reconnect ladder extended 4->6 steps + a last-ditch
_restoreSettledSession full-session poll (8s watchdog) after retries exhaust, so
a response completed during an iOS Tailscale/VPN reconnect is recovered without
an error banner.

Co-authored-by: luperrypf <luperrypf@users.noreply.github.com>
2026-07-04 21:51:38 +00:00
Rod Boev 71a6259c84 Align copied paths with chat references 2026-07-04 15:26:25 -04:00
nankingjingandClaude 1dd915ce15 fix(ux): add min-height to mermaid diagram viewport on mobile (#5525)
The mermaid-viewer-viewport has position:relative with an
absolutely-positioned canvas child, so it collapses to 0 height
on narrow mobile screens where the SVG hasn't loaded yet.
Add min-height:200px so diagrams are visible while rendering.

Fixes #5525

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-05 02:58:24 +08:00
Rod Boev 9742fd8e60 feat(#5552): add time and day controls to cron presets 2026-07-04 14:32:27 -04:00
Rod Boev 7ebd898c5e feat(#5533): make preview file paths copyable 2026-07-04 13:37:39 -04:00
Rod Boev 26eda1adbd Make appended token fade perceptible 2026-07-04 10:02:39 -04:00