fix(desktop): keep recovered actions bound to the selected session - #64673
fix(desktop): keep recovered actions bound to the selected session#6467333hodl wants to merge 2312 commits into
Conversation
|
Thanks — the reported behavior is present on current main. Problems
Suggested changes
Salvageability is high. The PR base predates current main, and current-main changes touch several modified production files, so a maintainer cherry-pick will need focused conflict resolution rather than a blind apply. This is an automated hermes-sweeper review. |
6ce51c7 to
b2d0a35
Compare
|
Addressed the hermes-sweeper review request in commit The branch is rebased onto current |
60b7507 to
71bf366
Compare
|
Rebased the remote Desktop gateway/session resilience series onto current
Validation on the refreshed head:
The branch remains a small upstream-plus-five-commit delta. The macOS build stamp is clean and points to the PR head. |
a8f5c3e to
2256650
Compare
|
@austinpickett This PR has been narrowed to the Desktop session-correctness boundary and rebased onto current |
809f4cd to
bcb972b
Compare
|
Repaired branch is now published at Final gates:
The branch was rebased once onto NousResearch I could not create a formal reviewer request because GitHub returned 404 for this fork PR. @austinpickett, please review when available. |
…tles Name sessions instantly from the opening message, and make the name stick
…et fold-in plugins.manage list rows now carry the canonical registry key and a portable flag (Agent Plugins v1 plugin.json packages), and toggles address the key — bare names collide across category dirs (image_gen/fal vs video_gen/fal), so name-addressed toggles flipped both. Portable packages' in-memory MCP servers also fold into enabled_mcp_server_names(); without that their tools registered with the MCP runtime but never reached the model's schema.
…list A thumb parked on a list you aren't touching is chrome, not information, and the sidebar stacks several scrollers so it draws several of them at once. Fade them in on hover instead, sharing the existing scrollbar colors and the webkit/Firefox split rather than styling a second kind of bar. Only the thumb's color changes, so the reserved gutter still keeps rows from shifting sideways.
… ipynb extraction read_file's .ipynb extraction previously dropped cell outputs entirely, so a notebook's training logs, tracebacks, and printed results were invisible to the model. Ported LobeHub's token-efficient conversion: - stream text and error tracebacks are kept (ANSI-stripped, \r progress-bar rewrites collapsed to the final frame) - execute_result/display_data prefer text/plain over the HTML twin - base64 images become sized placeholders ([image/png output — 3 KB, omitted]); widget state and script-bearing HTML are omitted - legacy nbformat v3 pyout/pyerr flat-field shapes handled - per-cell output block capped at 20k chars
…ousResearch#68392) _live_session_payload() falls back to _fallback_session_info() while a session's agent is still None (lazy/deferred build). That fallback omitted desktop_contract, so session.activate returned lazy metadata with no contract field. Desktop feeds the value straight into reportBackendContract(), where a missing field reads as contract 0 — a current backend is then falsely flagged "Backend out of date" on every activate of a live lazy session. The sibling session.create shape (_lazy_resume_info) was fixed the same way in NousResearch#36112; this closes the remaining session.activate gap by advertising DESKTOP_BACKEND_CONTRACT in the fallback payload. Adds test_session_activate_lazy_info_reports_desktop_contract pinning the session.activate path against a lazy (agent=None) session.
The PR and profile chips rendered in the row body, left of the kebab's own column: they never sat flush right and never handed their space to the kebab on hover, so a row showing only a PR left a hole where the age would have been. Both now join the tokens/cost/age figures in the actions slot, and the kebab covers the end of it — losing whichever item reads last, not the whole slot.
The all-profiles scope defaulted to grouping by profile, so "Reset to defaults" handed back a grouping the user never picked. Both scopes now ship by date, and a reset clears the scope you are not looking at too — otherwise flipping the rail restored the customization the reset was supposed to undo. Hovering a row's PR chip also holds the kebab back now: the chip is a link, and the button that covers the end of the trailing slot was taking the click.
…l-profiles Sidebar: show every profile at once
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
… icons Left cluster gets a macOS-only translate to sit on the traffic-light row. All titlebar tools use 24×24 hit areas with 13.9px Codicons (inline size beats unlayered codicon.css). Clusters share one flex shell with no gap — buttons abut and the hit target is the spacing.
…ontrols-y fix(desktop): titlebar clusters — macOS Y nudge, 24px targets, 13.9px icons
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
…le (NousResearch#83091) * fix(desktop): stop HUD window growing on drag; add corner resize handle The HUD window is created frame:false + transparent:true + resizable:true. On Windows, a transparent frameless window silently grows ~1px per setPosition call (worse at >100% DPI scaling) — every drag of the composer bar accumulated size drift, and the HUD could end up enormous (reported at 1385x1052 against a 620x320 default). Reading the size back mid-drag compounds the drift because getSize() returns the already-drifted value. Fix, mirroring the pet overlay's pattern: - create the HUD window non-resizable (no system edge resize hot-zone) - moveBy uses setBounds with a size snapshotted on the first move of each drag, so the OS can never accumulate drift (verified: 500 moveBy calls with zero size change on Electron 40 / Win11 / 175% DPI) - add a bottom-right corner resize handle (resize-handle.ts) driving a new hermes:hud:set-bounds IPC that flips resizable on for the call, restoring the ability to resize a window that is otherwise non-resizable * fix(desktop): pin HUD drag size in renderer, not main-process globals The superseding pass drops hudDragWidth/hudDragHeight from main: composer drag snapshots outerWidth/outerHeight when the hold arms (pet overlay pattern) and passes them on every moveBy. Adds one test for that contract. Supersedes NousResearch#82455. Co-authored-by: Ringo6107 <199014580+Ringo6107@users.noreply.github.com> * fix(desktop): keep the HUD solid through a corner resize; drop dead handle state The resize handle's `resizing` flag only fed a CSS rule that restated the cursor it already had, so nothing pinned the window mid-gesture: click-through hands the mouse away the moment the growing edge outruns the cursor. Raise the composer drag's existing `data-hud-grabbing` instead — one flag for "a gesture owns the window" — and cover it in click-through's tests. Also drops the hook's always-true `enabled` param and routes teardown through a `reset` callback, matching composer-drag.ts and clearing the atom-mirrored-ref lint rule. --------- Co-authored-by: Ringo6107 <199014580+Ringo6107@users.noreply.github.com>
…ne-resize fix(desktop): in-app browser kept squishing the chat and jamming its resize sash
…retry (transplanted to refactored files)
Keep the current desktop lint spacing around the rebased recovery and drift-guard statements.
bcb972b to
941403d
Compare
|
Rebased onto current
Ready for another pass. |
941403d to
4e370a4
Compare
1|## What does this PR do?
2|
3|Keeps Hermes Desktop's recovered prompt, redirect, and interrupt actions bound to the conversation the user actually selected.
4|
5|After a gateway restart, a stale runtime session can return
session not found. Desktop resumes the durable session and receives a replacement runtime ID. Currentmaincan update only the hot ref while leaving$activeSessionIdstale, and asynchronous recovery can continue after the user switches conversations — including switch-away-and-back cases where the final IDs look unchanged.6|
7|This narrowed PR fixes only that session-correctness boundary:
8|
9|- synchronize recovered runtime IDs into both
activeSessionIdRef.currentand$activeSessionId;10|- make profile-switch fresh-session teardown synchronous before gateway activation can move to another profile;
11|- advance a monotonic selection generation synchronously at the stored-selection write boundary, so batched A → B → A is still observable;
12|- abort prompt-submit, redirect, and interrupt recovery when route, stored selection, runtime selection, or generation changes;
13|- prevent late recovered-submit failures from adding errors to a newly selected session;
14|- preserve a newly selected session's busy/notification state when a recovered interrupt resolves or rejects late;
15|- keep background queued sends pinned to their queued session;
16|- migrate or remove optimistic state only inside the operation's target runtime;
17|- add focused regression coverage for submit, redirect, interrupt, busy retry, optimistic cleanup, profile switch, and switch-away-and-back races.
18|
19|## Why this PR is narrower now
20|
21|The earlier version also changed OAuth-ticket classification and remote liveness. That work overlaps merged PR #68250 and is removed from this branch.
22|
23|Backend-restart connection retry is also intentionally excluded and is tracked separately in #69059 so maintainers can evaluate retry policy independently from this correctness fix.
24|
25|## Related work and attribution
26|
27|- Preserves the atom/ref synchronization contribution from #62471 and its original author via cherry-pick.
28|- Incorporates the profile-switch timing fix from #66889 and preserves its original author via cherry-pick.
29|- Complements #68250; it does not duplicate that merged OAuth/liveness implementation.
30|
31|## Correctness invariants
32|
33|1. The runtime-session ref and reactive atom agree after recovery.
34|2. Recovery never overwrites, reports errors into, or clears state in a conversation selected after the operation began.
35|3. Switching away and back is still observable as user intent.
36|4. A profile switch clears foreground session identity before the active gateway can change.
37|5. Background queued sends remain pinned to their queued destination.
38|6. An intentional recovery runtime-ID rotation is distinguished from a later user selection.
39|
40|## Validation
41|
42|Run from the repository root on current
main(683059feb54f511717c831e0989e0f3c54450785):43|
44|-
npm test --workspace apps/desktop -- --project ui src/app/session/hooks/use-prompt-actions/index.test.tsx src/app/hooks/use-fresh-session-requests.test.tsx src/app/session/hooks/use-background-queue-drain.test.tsx src/store/session.test.ts45| - 121 passed
46|-
npm run typecheck --workspace apps/desktop47| - passed (UI, Electron, and E2E TypeScript projects)
48|-
npm run lint --workspace apps/desktop49| - 0 errors; 21 unrelated existing warnings
50|-
git diff --check origin/main...HEAD51| - passed
52|- changed-line secret-pattern scan
53| - no private keys, GitHub tokens, AWS keys, or generic secret assignments
54|- package/dependency review
55| - no manifest or lockfile changes
56|
57|Independent review was performed after repair against the live-main-rebased head. Publication was held until every blocking finding had a RED regression test and a verified fix.
58|
59|## Scope
60|
61|Desktop renderer/session state and regression tests only. No authentication, liveness, backend-retry, generated artifact, dependency, configuration, or credential changes are included.
62|