Commit Graph
2808 Commits
Author SHA1 Message Date
rudidev08 6c8d130a7b fix: classify Matrix gateway sessions as messaging 2026-08-07 21:54:52 +00:00
nesquena-hermes 874d62bc3a Merge PR #6486: show final assistant report with tool-limit status card 2026-08-06 01:05:50 +00:00
nesquena-hermes 8ecf391340 Merge PR #6670: don't duplicate active turn's user row on mid-run reload 2026-08-06 00:26:35 +00:00
nesquena-hermes 8fc9a7e2de Merge PR #6706: HTML inline preview no-store (fix stale preview) 2026-08-05 22:22:23 +00:00
nesquena-hermes 0e122174be Merge PR #6763: fix(workspace) open artifacts with Windows backslash paths 2026-08-05 21:39:05 +00:00
fatbee0808 71ee457d7d fix(workspace): normalize backslash paths in artifact open flow
openArtifactPath/_workspacePathExists split on '/' but Windows artifact
paths use backslashes (D:\workspace\dir\file), so prefix-strip failed
and /api/list existence check never matched -> 'cannot open file'.
Normalize both rel and workspace to '/' before stripping.
2026-08-05 11:06:12 +08:00
happy5318 5cda58fc9b fix: match active turn by exact identity (token/epsilon), not 1.5s proximity
Review round 2: the 1.5s timestamp tolerance over-deduped a legitimate
rapid repeat — two identical-text turns <1.5s apart collapsed into one,
hiding the second turn and copying its attachments onto the earlier row
(the mirror risk of #6649).

_pendingActiveTurnUserMessage now matches only on unambiguous identity:
- the row carries the server-stamped _active_turn_token (stream_id +
  started_at, per build_active_turn_token), or
- its timestamp equals pending_started_at within a precision-only
  epsilon (1e-6, absorbs float/state.db drift, never a full second).

Anything wider (whole-second truncation, ~1s rapid repeat) returns null
so getPendingSessionMessage() materializes the pending turn — fail
toward the harmless transient duplicate the settle render clears.

Regressions added: two completed identical-text turns ~1s apart → second
pending row returned + first row's attachments untouched; token-identity
row adopted even when its timestamp is outside the epsilon.
2026-08-03 13:46:56 +08:00
happy5318 bb5e778154 fix: HTML inline preview shows stale content after file update
The /api/media endpoint served all file types with Cache-Control:
private, max-age=3600. For HTML inline previews (rendered via
loadHtmlInline() → fetch() → iframe srcdoc), this meant the browser
cached the response for 1 hour. When an agent edited and re-rendered
the same HTML file, the inline preview showed stale content — only a
manual full-page refresh revealed the update.

Two changes:
- Backend: serve text/html with no-store instead of max-age=3600
  (images and other media keep the 1-hour cache)
- Frontend: loadHtmlInline() fetch with {cache:'no-store'} for
  belt-and-suspenders defense against intermediate caches

Note: the /api/file/raw path already used no-store for HTML; this
fixes the /api/media path which was missed.
2026-08-02 13:41:37 +08:00
webtecnica 6dd1fed8d3 fix(ui): guard all bare _autoScrollFollow reads (#6614) 2026-08-01 17:52:30 -03:00
webtecnica f4f9157f8d fix: guard _autoScrollFollow access against ReferenceError before settings init
Browser race in static/ui.js: _autoScrollFollow can be undefined when
scroll/scrollpin listeners fire before boot.js initializes settings.
Bare global reference (ReferenceError) occurs on the golden path.

Fix: wrap both consumer sites with a typeof guard that defaults to
true (matching the boot.js fallback) when the variable hasn't been set.

Closes #6606
2026-08-01 17:45:43 -03:00
happy5318 55af555846 fix: do not duplicate the active turn's user row on mid-run reload
While a turn is live the server can reconcile that turn's user row into the
transcript returned by /api/session (the sidecar/state.db merge picks it up
from state.db, where the agent writes it immediately) while
pending_user_message is still set. The row is then followed by the same
turn's assistant/tool rows.

_pendingCurrentTailUserMessage() scans the tail backwards and returns null as
soon as it meets a completed assistant, so in that state it reports "the
current turn has no user row". getPendingSessionMessage() then materializes
pending_user_message a second time and the pane renders two identical user
bubbles until the settle render replaces the list wholesale (which is why the
duplicate disappears when the answer lands, and why nothing wrong is ever
persisted).

Scanning past assistant/tool rows on text alone would regress #3300: a user
who submits the same text twice in a row legitimately gets two identical user
turns. Use pending_started_at as the discriminator instead — the server stamps
the active turn's user row with it, and no earlier turn can share it. Text
equality is still required, so a false match needs identical text AND a
near-identical timestamp. Absent/invalid pending_started_at disables the
fallback and keeps the previous strict-tail behaviour.

Verified: the new midRunReloadDedupe assertion fails on the unpatched ui.js
and passes with the fix; the existing repeat-prompt, compaction-boundary and
strict-tail assertions still pass.
2026-08-01 12:07:45 +08:00
nesquena-hermes d85eb85c25 Merge branch 'master' into fix/interim-anchor-final-character 2026-07-31 11:52:58 -07:00
Nathan Esquenazi 94a2091435 Merge branch 'master' into fix/interim-anchor-final-character 2026-07-31 11:11:50 -07:00
Nathan Esquenazi eb1484bede Merge branch 'master' into franksong2702/viewport-scroll-anchor-6414 2026-07-31 11:09:39 -07:00
Frank SongandFrank Song 89023eb191 Live-to-Final: prove historical hydration and fence terminal retry ownership (#6451)
* test: add historical hydration lifecycle proof

* fix: retry anchor persistence after terminal app errors

* fix: fence deferred anchor settlement ownership

* test: cover deferred anchor retry ownership

* fix: preserve terminal anchor retry across refresh

* fix: bind terminal anchor retry to turn owner

---------

Co-authored-by: Frank Song <franksong2702@gmail.com>
2026-07-31 11:04:40 -07:00
Frank Song fd1879418d fix: queue pinned live scroll ownership check 2026-07-31 22:24:25 +08:00
Frank Song cc5cf19710 test: exercise reachable live scroll restore boundary 2026-07-31 22:24:25 +08:00
Frank Song a6a891f079 fix: keep live render harness fallback safe 2026-07-31 22:24:25 +08:00
Frank Song 713418dec0 test: cover live render scroll ownership boundary 2026-07-31 22:24:25 +08:00
Frank Song 7a320bea3c fix: preserve live scroll ownership on snapshot mismatch 2026-07-31 22:24:25 +08:00
Frank Song a55096b81f fix: keep scroll ownership hooks harness-safe 2026-07-31 22:24:25 +08:00
Frank Song 5efc94f4b2 fix: preserve ownership of live scroll snapshots 2026-07-31 22:24:25 +08:00
Frank Song 5c3ead61a2 Restore unpinned desktop stream scroll 2026-07-31 22:24:25 +08:00
Frank Song 1c385e6935 Merge remote-tracking branch 'origin/master' into franksong2702/live-worklog-settle-no-blank 2026-07-31 01:27:57 +08:00
nankingjing 95a1647557 fix(#6419): route every recovery path through one pending_user_message merge helper
The mid-stream reconnect path could render the just-sent user message below
the live streaming assistant response it triggered, because
`refreshSession()` appended `pending_user_message` at the end of
`S.messages` unconditionally while `loadSession()` correctly inserted
it before the first live assistant message. When the client went through
its reconnect/recovery path mid-turn (typical on iOS PWA screen
lock/resume) the live assistant tail rendered above the prompt.

Centralize every recovery/reconnect reinsertion through one
identity-aware helper (`_mergePendingSessionMessage`) that:

- inserts the owning user turn before its live assistant/Worklog tail,
- appends only when no live tail exists,
- deduplicates against the current tail user row,
- remains idempotent across repeated resume probes.

`refreshSession()` now calls the same helper instead of pushing at
the end. `loadSession()` continues to use the helper unchanged.

Adds `tests/test_issue6419_pending_user_reconnect_order.py` pinning:
- the helper is defined exactly once at module top level,
- it inserts before live assistant and falls back to append,
- `refreshSession()` uses the helper and does not push unconditionally,
- `loadSession()` still merges before renderMessages in the INFLIGHT
  reattach branch.

Renames the inner end-marker in
`tests/test_gateway_sse_reconnect_dedupe.py` to a stable inside-loadSession
boundary (`// Phase 2a:`) since the helper is no longer nested.
2026-07-29 22:37:58 +00:00
Anthony Ruiz 127a57e0c5 fix(sessions): fully consume PWA launch action 2026-07-29 21:50:54 +00:00
Anthony Ruiz cd04f5fcc2 fix(sessions): preserve active chat across hard refresh 2026-07-29 21:50:54 +00:00
Rod Boev 1e591aef13 fix(#6467): show final assistant report with tool-limit status card 2026-07-29 20:54:45 +00:00
pxxD1998 e2b052a637 fix(workspace): persist recovered session bindings 2026-07-29 18:22:22 +00:00
starship-s 69b26c1fa5 fix(streaming): complete interim anchor prose
Treat status-less interim assistant events as complete semantic boundaries so streaming Markdown flushes its final lookahead character before tool activity. Add behavior coverage for the real interim-to-tool Anchor pipeline.

Assisted-by: Hermes Agent:gpt-5.6-sol
Assisted-by: Codex:gpt-5.3-codex-spark
2026-07-24 12:30:46 -06:00
Frank Song cbe353fb93 Scope preserveDom to live assistant turn only 2026-07-24 13:43:15 +08:00
Frank Song 30df3ce0fe Restore completion read-state ordering 2026-07-24 13:05:01 +08:00
Frank Song 65121ca1ad Sync viewed state before live settlement cache 2026-07-24 13:03:38 +08:00
Frank Song 7f0099f1f6 Fix live settlement test compatibility 2026-07-24 12:50:05 +08:00
Frank Song ae264f71a3 Preserve live Worklog through final settlement 2026-07-24 12:43:34 +08:00
b3nwandb3nw e93b0c352a feat: render process wakeups as collapsed summary cards (#6350)
Render structured background-process completions and watch matches as accessible collapsed cards while preserving raw fallback, verbatim output, and full watch patterns.

Co-authored-by: b3nw <b3nw@duck.com>
2026-07-23 20:52:51 +00:00
nesquena-hermesandsheldon-im 3157f4cbf2 harden(#6349): strict finite-px min-height parse for the composer fast path
Codex re-gate found the single-row resize fast path used parseFloat on
getComputedStyle(el).minHeight, which reads a bogus pixel value for a
non-px unit (parseFloat('50%')===50) and would wrongly enable the fast
path, leaving an oversized composer stuck tall. Parse with a strict
/^<number>px$/ test so %, auto, empty, and calc() fail closed to the
full resize. Adds red-before-green regression coverage across units.

Co-authored-by: sheldon-im <sheldon-im@users.noreply.github.com>
2026-07-23 04:05:03 +00:00
nesquena-hermes 77d0b8609d Merge remote-tracking branch 'origin/master' into stage/6349 2026-07-23 03:25:14 +00:00
nesquena-hermesandrodboev 575e45f76b polish(#6040): approval-counter CSS cleanup + i18n the pending-count string
Fable UX polish pass on the gateway approval counter:
- Move the crude inline style (font-size:0.75em;opacity:0.6;margin-top:4px) into
  a proper .approval-counter rule: 11px, color:var(--muted) (skin-safe vs opacity),
  margin:0 0 12px (fixes the 0px gap that left it flush against the buttons),
  tabular-nums for stable digits.
- i18n the '1 of N pending' string (was the only hardcoded-English string in an
  otherwise fully-localized approval card): new approval_pending_count key in en
  + 14 locales, wired via t() with an English fallback.

Co-authored-by: rodboev <rodboev@users.noreply.github.com>
2026-07-23 03:12:49 +00:00
nesquena-hermes 0d06ae3467 Merge remote-tracking branch 'origin/master' into stage/6040 2026-07-23 02:26:42 +00:00
starship-s 5bf77d558a fix: finalize sealed anchor prose at completion (#6408)
Anchor-owned process-prose rows kept the newest character as streaming-markdown
lookahead until the turn settled, so Compact Worklog prose immediately before a
tool card appeared one character short mid-stream. Finalize the cached parser
once when the row becomes 'completed' (running the same media/link/table cleanup
as the main body parser), guarded by a 'finalized' flag + self-heal on edit.

Co-authored-by: starship-s <starship-s@users.noreply.github.com>
2026-07-23 01:46:01 +00:00
nesquena-hermes bbb417b3f1 stage: merge #6113 (per-turn used-model chip in transparent footer) 2026-07-22 22:13:08 +00:00
nesquena-hermes 6e2267dd5f stage: merge #6390 (scroll preservation after live-to-final settlement) 2026-07-22 20:43:04 +00:00
Rod Boev 6d9e4ac4c5 fix(#6008): keep stop failure toasts actionable across locales 2026-07-22 12:33:57 -04:00
Rod Boev 0a3a630856 fix(gateway): keep approval and stop acknowledgements honest 2026-07-22 12:31:12 -04:00
Rod Boev f30178e18a fix(gateway): fall back safely without approval identities 2026-07-22 12:31:12 -04:00
Rod Boev 5826d76da0 fix(#6008): publish the authoritative approval head 2026-07-22 12:31:12 -04:00
Rod Boev b907630f8f fix(#6008): keep gateway approvals attached to the right run 2026-07-22 12:31:11 -04:00
sheldon-im a05cb953f2 fix: remeasure oversized composer appends 2026-07-22 13:27:11 +09:00
sheldon-im a383525afe fix: restrict composer resize fast path to appends 2026-07-22 09:45:58 +09:00