Skip to content

feat(desktop): add "Delete all chats" button to the chat sidebar - #55957

Open
MaxFreedomPollard wants to merge 1 commit into
NousResearch:mainfrom
MaxFreedomPollard:feat/desktop-delete-all-chats
Open

feat(desktop): add "Delete all chats" button to the chat sidebar#55957
MaxFreedomPollard wants to merge 1 commit into
NousResearch:mainfrom
MaxFreedomPollard:feat/desktop-delete-all-chats

Conversation

@MaxFreedomPollard

@MaxFreedomPollard MaxFreedomPollard commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Re-ported onto the contribution shell (desktop-controller was retired in 369d0ee) and extended per the sweeper review:

Feature: a hover-revealed destructive trash action in the recents header opens a ConfirmDialog; on confirm, clearAllSessions pages the active scope in ≤500-id chunks through the existing explicit-ID POST /api/sessions/bulk-delete endpoint until empty (bounded, with a zero-progress bail), grouping ids by owning profile. The open chat is torn down to a fresh draft first and the orphaned runtime is closed in a finally — the same teardown removeSession does for a single chat, lifted to the whole list. Wiring lives in ContribWiring, published through the WiringActions bag like every other sidebar verb.

Review ask 1 — remote-profile mutation contract: interceptSessionRequestForRemote now has an explicit POST /api/sessions/bulk-delete branch mirroring the single-session mutation split: per-profile remote override → body scope stripped (delete body.profile) and posted to that profile's remote (native-db contract); global remote → profile scoping kept in query + body; local → generic routing. Declared explicitly rather than trusting the {id}-segment regex to keep matching the literal bulk-delete path.

Review ask 2 — failure-path reconciliation: the page-and-delete loop is wrapped so the session-list refresh runs in finally; a batch that rejects after earlier optimistic removals still reconciles against the authoritative list while the rejection propagates to the dialog. New regression: page 1 succeeds, page 2 rejects → rejection surfaces, refresh ran, store equals the authoritative survivor set.

Tests: upstream's existing use-session-list-actions cases kept verbatim; the PR's cases re-ported to the current renderHook style + the partial-failure case; hermes bridge tests included. Touched files 33/33 pass; renderer/electron/e2e typechecks and eslint clean; full desktop vitest matches the upstream baseline (no attributable regressions).

@alt-glitch alt-glitch added type/feature New feature or request P3 Low — cosmetic, nice to have comp/desktop Electron desktop app (apps/desktop/*) labels Jul 1, 2026
@teknium1

Copy link
Copy Markdown
Contributor

Thanks for building this on the existing explicit-ID bulk-delete endpoint. The requested affordance is still absent on current main: the recents header currently has only the new-chat and folder/list controls (apps/desktop/src/app/chat/sidebar/index.tsx:1249-1288).

Problems

  • The bulk bridge in 121a6822da94 needs the current remote-profile mutation contract. Per-profile remote session mutations strip body.profile before forwarding (apps/desktop/electron/main.ts:7794-7812), but the current interceptor does not cover /api/sessions/bulk-delete; it falls through generic routing (apps/desktop/electron/main.ts:7903-7945). The endpoint then opens the profile named in the body (hermes_cli/web_server.py:9614), which is not the remote override's native-db contract.
  • clearAllSessions in 121a6822da94 refreshes only after its page loop. A rejected later batch bypasses that refresh after earlier optimistic removals; add failure-path reconciliation coverage.

Suggested changes

  • Route bulk delete through the same remote-profile split as single-session mutations: strip the body scope for per-profile remote overrides, while preserving global-remote profile scoping.
  • Refresh in finally and test a partial-success/later-failure sequence.

This is an automated hermes-sweeper review.

@teknium1 teknium1 added sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform labels Jul 15, 2026
@MaxFreedomPollard
MaxFreedomPollard force-pushed the feat/desktop-delete-all-chats branch from 121a682 to 6c81c9a Compare July 25, 2026 04:37
@MaxFreedomPollard
MaxFreedomPollard force-pushed the feat/desktop-delete-all-chats branch 2 times, most recently from 80c79a9 to 2c566f2 Compare July 31, 2026 04:27
Re-ported onto the contribution shell after desktop-controller was retired. Bulk delete now routes through the same remote-profile split as single-session mutations (body scope stripped for per-profile remote overrides, global-remote scoping preserved), and clearAllSessions reconciles the session list in a finally so a failed later batch cannot strand optimistic removals. Includes partial-success/later-failure regression coverage.
@MaxFreedomPollard
MaxFreedomPollard force-pushed the feat/desktop-delete-all-chats branch from 2c566f2 to 7d1b4ce Compare August 13, 2026 21:31
@MaxFreedomPollard

Copy link
Copy Markdown
Contributor Author

Rebased onto current main at 7d1b4ce. This one needed more than a mechanical conflict resolution, so noting what changed.

Main has removed the per-profile session totals that this branch leaned on. The store comment explains why: rendering loaded/total in the sidebar was not worth what it cost. Three things followed from that.

The confirm dialog used Math.max(sessionsTotal, agentSessions.length + pinnedSessions.length). sessionsTotal no longer exists, so the count is now just agentSessions.length + pinnedSessions.length, which is the honest number the sidebar actually has. The wording still reads correctly for both the single and plural cases.

loadMoreSessionsForProfile and profileLoadMorePending were deleted on main. Git left the function body in place because it sat outside the conflict region, so taking my side of the hunks would have reintroduced a dead function and destructured a name that no longer exists. Both are gone now, and nothing in apps/desktop/src references either.

The test file used setSessionsTotal and passed total / profile_totals into the sidebar() helper. None of those survive on main, so they are removed.

Separately, latest-actions.ts and its test now forward onDeleteAllSessions. That file mirrors every member of SidebarActions, so adding a prop to the type without adding it there fails the typecheck.

The i18n side is a straight both-sides merge: main's noFilterMatches and this branch's deleteAll block coexist, and all four locales plus types.ts carry the same six keys.

npm run typecheck is clean across all three tsconfigs, and npm run test:ui is 3809 tests passing across 423 files. I could not run eslint, it is not installed in this workspace, so that one is unverified on my end.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/desktop Electron desktop app (apps/desktop/*) P3 Low — cosmetic, nice to have sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants