Skip to content

fix(desktop): refresh multiplexed profile transcripts - #99333

Closed
StodsEcho5 wants to merge 1 commit into
NousResearch:mainfrom
Echo5-Engineering:fix/bot-chat-recovery
Closed

StodsEcho5 wants to merge 1 commit into
NousResearch:mainfrom
Echo5-Engineering:fix/bot-chat-recovery

Conversation

@StodsEcho5

Copy link
Copy Markdown

fix(desktop): refresh multiplexed profile transcripts

Summary

In a multiplexed gateway, each profile writes to its own session database. The Desktop change watcher only inspected the active profile, so turns written to sibling profiles did not emit sessions.changed. When another event did trigger tile reconciliation, the transcript read omitted the tile's owner route and could query the wrong profile.

The change signature now resolves the shared profiles directory from both root-home and named-profile launches, includes active and named-profile session stores, and ignores symlinked profile directories. Open-tile transcript reads use the tile's connection and target profile. A tile-local busy or awaiting submit is skipped before the read and rechecked after it, preserving optimistic prompts; a completion is also discarded if the tile closes or changes owner while the read is in flight. Tile transcript signatures are keyed by durable ID, runtime ID and complete owner route, with closed-tile entries pruned on each pass. Existing durable-session rebind and canonical tile identity remain unchanged and are included in the regression suite.

Relationship to open work

PR #97887 handles visible-session recovery after a stale runtime RPC. This patch does not modify or duplicate those files; it fixes the two producer paths that leave a multiplexed profile's open transcript stale. A local integration branch combining both commits was tested separately.

Tests

  • scripts/run_tests.sh tests/desktop/test_multiplex_sessions_change_watcher.py
  • scripts/run_tests.sh tests/desktop/test_bots_chat_live_append.py
  • npm --workspace apps/desktop run test:ui -- use-background-sync.test.ts session-states.test.ts session-tile-actions.test.ts use-prompt-actions/utils.test.ts enter-submit-dom-race.test.tsx agent-init-error.test.tsx
  • npm --workspace apps/desktop run test:ui
  • npm --workspace apps/desktop run typecheck
  • npm --workspace apps/desktop exec eslint -- src/app/contrib/hooks/use-background-sync.ts src/app/contrib/hooks/use-background-sync.test.ts src/store/session-states.test.ts

@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists comp/desktop Electron desktop app (apps/desktop/*) comp/tui Terminal UI (ui-tui/ + tui_gateway/) area/profiles Multi-profile isolation, HERMES_HOME scoping area/sessions Session lifecycle, resume, persistence, history sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state labels Aug 31, 2026
@shellybotmoyer

Copy link
Copy Markdown

Heartbeat diagnostic

This PR shows mergeable: MERGEABLE and is 6 commits ahead of main with zero merge conflicts. Test-merge against origin/main succeeds cleanly.

The mergeStateStatus: BLOCKED may reflect CI policy requirements (e.g., required reviewers, branch protection rules) rather than code conflicts. The diff adds targeted desktop session-refresh logic with a comprehensive regression suite covering multiplexed profiles, live append, and tile close/owner-change race conditions.

Recommendation: maintainers can merge when ready — no rebase or conflict resolution needed. Tests are included and pass on the PR branch.

teknium1 added a commit that referenced this pull request Sep 2, 2026
…9333)

Two sites dropped profile ownership on the tile-transcript refresh path:

- tui_gateway/server.py _sessions_sig statted only the launch home's
  state.db, so a turn landing in a served sibling profile's store never
  produced sessions.changed. The watcher now also probes every profile
  home _profile_home() has resolved for this backend (empty set on
  single-profile installs — behavior byte-identical there).
- use-background-sync.ts reconcileTileTranscripts read the tile's
  transcript unscoped; it now passes the tile's ownerRoute scope, the
  same way reconcileActiveTranscript already does for the main pane, and
  keys the change signature by owner.

Reimplemented minimal from PR #99333 (the PR head's commit identity does
not match the GitHub author).

Co-authored-by: StodsEcho5 <250208229+StodsEcho5@users.noreply.github.com>
teknium1 added a commit that referenced this pull request Sep 2, 2026
Salvages the client half of PR #99333. A workspace tile pinned to an exact
owner (connection + target profile) was reconciled via a bare
getLatestSessionMessages(storedId) — the foreground profile's backend — so
a bot tile on another profile never saw its new turns (or saw the wrong
session's). reconcileTileTranscripts now derives a ProfileScope from
tile.ownerRoute and keys the per-tile signature by that route; route-less
tiles keep the legacy local read.

The tui_gateway/server.py `_sessions_sig` cross-profile scan from #99333 is
intentionally not taken: the desktop runs one backend per profile, each with
its own watcher, so scanning sibling profiles would misattribute ticks.

Co-authored-by: stods21 <stods21@users.noreply.github.com>
@teknium1

teknium1 commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator

Thanks — this landed on main via #101214 (6d061ed) with your commit/credit preserved. Only the client half was taken: the desktop runs one backend per profile, each with its own watcher, so the server-side cross-profile signature scan would have misattributed ticks. You are co-authored on the commit. Closing the original in favor of the merged salvage.

@teknium1 teknium1 closed this Sep 2, 2026
teknium1 added a commit that referenced this pull request Sep 2, 2026
…9333)

Two sites dropped profile ownership on the tile-transcript refresh path:

- tui_gateway/server.py _sessions_sig statted only the launch home's
  state.db, so a turn landing in a served sibling profile's store never
  produced sessions.changed. The watcher now also probes every profile
  home _profile_home() has resolved for this backend (empty set on
  single-profile installs — behavior byte-identical there).
- use-background-sync.ts reconcileTileTranscripts read the tile's
  transcript unscoped; it now passes the tile's ownerRoute scope, the
  same way reconcileActiveTranscript already does for the main pane, and
  keys the change signature by owner.

Reimplemented minimal from PR #99333 (the PR head's commit identity does
not match the GitHub author).

Co-authored-by: StodsEcho5 <250208229+StodsEcho5@users.noreply.github.com>
teknium1 added a commit that referenced this pull request Sep 2, 2026
…9333)

Two sites dropped profile ownership on the tile-transcript refresh path:

- tui_gateway/server.py _sessions_sig statted only the launch home's
  state.db, so a turn landing in a served sibling profile's store never
  produced sessions.changed. The watcher now also probes every profile
  home _profile_home() has resolved for this backend (empty set on
  single-profile installs — behavior byte-identical there).
- use-background-sync.ts reconcileTileTranscripts read the tile's
  transcript unscoped; it now passes the tile's ownerRoute scope, the
  same way reconcileActiveTranscript already does for the main pane, and
  keys the change signature by owner.

Reimplemented minimal from PR #99333 (the PR head's commit identity does
not match the GitHub author).

Co-authored-by: StodsEcho5 <250208229+StodsEcho5@users.noreply.github.com>
teknium1 added a commit that referenced this pull request Sep 2, 2026
…9333)

Two sites dropped profile ownership on the tile-transcript refresh path:

- tui_gateway/server.py _sessions_sig statted only the launch home's
  state.db, so a turn landing in a served sibling profile's store never
  produced sessions.changed. The watcher now also probes every profile
  home _profile_home() has resolved for this backend (empty set on
  single-profile installs — behavior byte-identical there).
- use-background-sync.ts reconcileTileTranscripts read the tile's
  transcript unscoped; it now passes the tile's ownerRoute scope, the
  same way reconcileActiveTranscript already does for the main pane, and
  keys the change signature by owner.

Reimplemented minimal from PR #99333 (the PR head's commit identity does
not match the GitHub author).

Co-authored-by: StodsEcho5 <250208229+StodsEcho5@users.noreply.github.com>
teknium1 added a commit that referenced this pull request Sep 2, 2026
…9333)

Two sites dropped profile ownership on the tile-transcript refresh path:

- tui_gateway/server.py _sessions_sig statted only the launch home's
  state.db, so a turn landing in a served sibling profile's store never
  produced sessions.changed. The watcher now also probes every profile
  home _profile_home() has resolved for this backend (empty set on
  single-profile installs — behavior byte-identical there).
- use-background-sync.ts reconcileTileTranscripts read the tile's
  transcript unscoped; it now passes the tile's ownerRoute scope, the
  same way reconcileActiveTranscript already does for the main pane, and
  keys the change signature by owner.

Reimplemented minimal from PR #99333 (the PR head's commit identity does
not match the GitHub author).

Co-authored-by: StodsEcho5 <250208229+StodsEcho5@users.noreply.github.com>
teknium1 added a commit that referenced this pull request Sep 2, 2026
…9333)

Two sites dropped profile ownership on the tile-transcript refresh path:

- tui_gateway/server.py _sessions_sig statted only the launch home's
  state.db, so a turn landing in a served sibling profile's store never
  produced sessions.changed. The watcher now also probes every profile
  home _profile_home() has resolved for this backend (empty set on
  single-profile installs — behavior byte-identical there).
- use-background-sync.ts reconcileTileTranscripts read the tile's
  transcript unscoped; it now passes the tile's ownerRoute scope, the
  same way reconcileActiveTranscript already does for the main pane, and
  keys the change signature by owner.

Reimplemented minimal from PR #99333 (the PR head's commit identity does
not match the GitHub author).

Co-authored-by: StodsEcho5 <250208229+StodsEcho5@users.noreply.github.com>
melon-xf added a commit to melon-xf/hermes-agent that referenced this pull request Sep 3, 2026
Salvages the client half of PR NousResearch#99333. A workspace tile pinned to an exact
owner (connection + target profile) was reconciled via a bare
getLatestSessionMessages(storedId) — the foreground profile's backend — so
a bot tile on another profile never saw its new turns (or saw the wrong
session's). reconcileTileTranscripts now derives a ProfileScope from
tile.ownerRoute and keys the per-tile signature by that route; route-less
tiles keep the legacy local read.

The tui_gateway/server.py `_sessions_sig` cross-profile scan from NousResearch#99333 is
intentionally not taken: the desktop runs one backend per profile, each with
its own watcher, so scanning sibling profiles would misattribute ticks.

Co-authored-by: stods21 <stods21@users.noreply.github.com>
melon-xf added a commit to melon-xf/hermes-agent that referenced this pull request Sep 3, 2026
…usResearch#99333)

Two sites dropped profile ownership on the tile-transcript refresh path:

- tui_gateway/server.py _sessions_sig statted only the launch home's
  state.db, so a turn landing in a served sibling profile's store never
  produced sessions.changed. The watcher now also probes every profile
  home _profile_home() has resolved for this backend (empty set on
  single-profile installs — behavior byte-identical there).
- use-background-sync.ts reconcileTileTranscripts read the tile's
  transcript unscoped; it now passes the tile's ownerRoute scope, the
  same way reconcileActiveTranscript already does for the main pane, and
  keys the change signature by owner.

Reimplemented minimal from PR NousResearch#99333 (the PR head's commit identity does
not match the GitHub author).

Co-authored-by: StodsEcho5 <250208229+StodsEcho5@users.noreply.github.com>
howdeploy added a commit to howdeploy/hermes-agent that referenced this pull request Sep 5, 2026
Rematerialize NousResearch#100758 on main f58fcc8, retaining the tested source-first composition of NousResearch#101057 and the declarative roster from NousResearch#102195, together with durable leases, publication fencing, chain-qualified compression recovery, repeated-step identities and strict configuration policy.

Original development history: 924fce6, retained in backup/pr100758-before-landing-20260905. Source-authority contribution: NousResearch#101057 at 8355ab1. Declarative roster contribution: NousResearch#102195 at 2215b6e. The NousResearch#99333 client salvage and StodsEcho5 credit remain inherited from main via NousResearch#101214.

Validated with scripts/run_tests.sh: 906 passed, 0 failed, 9 skipped across 43 files; retries disabled. Ruff 0.16.4 passed for all changed Python files. Hosted verification must reference this new commit, not earlier tips.

Co-authored-by: Brooklyn Nicholson <brooklyn.bb.nicholson@gmail.com>
Co-authored-by: Ahmett101 <ahmet.tunc@gmail.com>
mikeholownych pushed a commit to mikeholownych/charterforge that referenced this pull request Sep 6, 2026
…usResearch#99333)

Two sites dropped profile ownership on the tile-transcript refresh path:

- tui_gateway/server.py _sessions_sig statted only the launch home's
  state.db, so a turn landing in a served sibling profile's store never
  produced sessions.changed. The watcher now also probes every profile
  home _profile_home() has resolved for this backend (empty set on
  single-profile installs — behavior byte-identical there).
- use-background-sync.ts reconcileTileTranscripts read the tile's
  transcript unscoped; it now passes the tile's ownerRoute scope, the
  same way reconcileActiveTranscript already does for the main pane, and
  keys the change signature by owner.

Reimplemented minimal from PR NousResearch#99333 (the PR head's commit identity does
not match the GitHub author).

Co-authored-by: StodsEcho5 <250208229+StodsEcho5@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/profiles Multi-profile isolation, HERMES_HOME scoping area/sessions Session lifecycle, resume, persistence, history comp/desktop Electron desktop app (apps/desktop/*) comp/tui Terminal UI (ui-tui/ + tui_gateway/) P2 Medium — degraded but workaround exists sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants