Skip to content

[feat] Close other session tabs, or the ones to the right [AGE-4188] - #6330

Merged
ashrafchowdury merged 3 commits into
fix/session-tab-close-cancels-runfrom
feat/session-tab-bulk-close
Aug 28, 2026
Merged

ashrafchowdury merged 3 commits into
fix/session-tab-close-cancels-runfrom
feat/session-tab-bulk-close

Conversation

@ardaerzin

Copy link
Copy Markdown
Contributor

Context

The tab strip has one close affordance, the X on a single tab. Clearing a long strip means clicking X over and over.

Changes

A tab's context menu now carries the same bulk closes a browser has: Close, Close other tabs, Close tabs to the right. Each one is disabled when it would do nothing.

Pinned tabs survive "Close other tabs", the way they survive it in Chrome. Pins lead the strip, so they are never to the right of anything, and the carve-out only shows up in that one verb.

The strip computes the ids because "to the right" means the rendered order, which is pin-sorted and only the strip knows. closeSessionsAtomFamily then applies the whole set in one write, with the same rules a single close has. Sessions stay in history and stay reopenable, never-run blanks are discarded, and the active tab moves to the nearest survivor. Closing a running tab still cancels its run.

Tests

  • sessions.bulkClose.test.ts covers the one-write close, history retention, the active tab surviving, the active tab moving right and then falling back left, empty and unknown id sets, and blank-session cleanup.
  • Full slice suite green (26 files, 282 tests). tsc --noEmit and eslint clean on @agenta/oss.
  • Not verified in a browser.

Demo

Outstanding. This adds a visible menu, so it needs a capture from the real app running this branch. I have not run the stack, and a mock-up would not show the real menu, theme, or spacing.

What to QA

  • Right-click a tab in the middle of several. "Close other tabs" leaves only that one. "Close tabs to the right" leaves it and everything left of it.
  • Pin a tab, then run "Close other tabs" from a different tab. The pinned one stays.
  • Right-click the last tab on the right. "Close tabs to the right" is disabled. With only one tab open, "Close" is disabled too.
  • Close the active tab through the menu. Focus lands on a neighbour rather than nothing.
  • Bulk close a set that includes a streaming session. That run stops.
  • Regression: closed sessions still reopen from the rail with their transcripts.

Notes for the reviewer

closeSessionsAtomFamily is a new close path. #5862 requires every close path to remove the id from openIdsByAppAtom before React runs the cleanup, and this one does, since that write comes first. If #5862 lands before this, the new atom also needs its dropSessionRuntime(set, id) call, otherwise a bulk close leaks one chat instance and one stale status dot per tab. It merges clean without it, so nothing will flag it.

The tab strip had one close affordance: the × on a single tab. Clearing a
strip that had grown long meant clicking × over and over.

A tab's context menu now carries Chrome's bulk closes — Close, Close other
tabs, Close tabs to the right — each disabled when it would do nothing.

Pinned tabs survive "close other tabs", as they do in a browser. Since pins
lead the strip they are never to the right of anything, so the carve-out only
shows up in that one verb.

The strip computes the ids because "to the right" means the RENDERED order,
which is pin-sorted and only the strip knows. `closeSessionsAtomFamily` then
applies the whole set in one write, with the same rules a single close has:
sessions stay in history and stay reopenable, never-run husks are discarded,
and the active tab moves to the nearest survivor. Closing a running tab still
cancels its run.
…connect

Reopening a long session was slow, and got slow again every time you came
back to the tab.

The watch relay emits `ready` on every connect, and the relay connects on each
tab activation and each return to a foreground window. `ready` was wired to the
same handler as `records-changed`, so each of those invalidated the records
query and re-read the entire log — a ~200KB fetch at `priority: "low"`, a full
remap, and a `setMessages` that replaces the transcript and re-renders every
row. On reopen that ran right beside the mount's own revalidation, so the log
was read twice within a second.

`ready` now has its own handler that skips a read the mount is already doing,
or one that finished within the relay's own coalescing window.

The skip is safe because of what `ready` is for. A change can land after the
response headers flush but before the Redis subscribe completes, reaching
neither the stream nor a revalidation driven by `onopen` — `ready` closes that
window. A read of the log newer than the connection cannot have missed such a
change, so repeating it buys nothing. A change after the subscribe arrives as
`records-changed`, which is never skipped; that is why the two events needed
separating rather than sharing a deduped handler.

Every full read now reports itself, so "nobody has read this" and "a read is
running right now" are distinguishable — the second is the reopen case, where
the mount's revalidation is still in flight when `ready` lands.
@linear-code

linear-code Bot commented Aug 27, 2026

Copy link
Copy Markdown

AGE-4188

@vercel

vercel Bot commented Aug 27, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
agenta-documentation Ready Ready Preview Aug 28, 2026 1:00pm

Request Review

@coderabbitai

coderabbitai Bot commented Aug 27, 2026 •

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

🗂️ Base branches to auto review (1)
  • release/.*

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: 3960a5d3-3c7f-4489-8f83-334207448442

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@ardaerzin
ardaerzin marked this pull request as ready for review August 28, 2026 09:56
@dosubot dosubot Bot added size:L This PR changes 100-499 lines, ignoring generated files. enhancement New feature or request frontend labels Aug 28, 2026
ashrafchowdury added a commit that referenced this pull request Aug 28, 2026
Only conflict was the mobile TurnRow import block: release added
CollapsibleMessageBody to the @agenta/chat/components import while this branch
added the @agenta/chat/hooks import beside it. Kept both.

Merged rather than rebased because four PRs (#6328, #6329, #6330, #6331) are
stacked on this branch, so rewriting its history would break their bases.
[fix] Stop re-reading a session's record log on every connect [AGE-4189]
@ashrafchowdury
ashrafchowdury merged commit 14ae06f into fix/session-tab-close-cancels-run Aug 28, 2026
34 of 35 checks passed
@github-actions

Copy link
Copy Markdown
Contributor

Railway Preview Environment

Preview URL https://gateway-pr-6330.up.railway.app/w
Project agenta-oss-clone-spike
Image tag pr-6330-ced22e4
Status Deployed
Railway logs Open logs
Workflow logs View workflow run
Updated at 2026-08-28T13:10:33.953Z

This branch was successfully deployed

1 active deployment
Preview — 379be1fa Deployed Aug 28, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request frontend size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants