fix(agent-mode): preserve composer input when switching agents mid-compose#2664
Draft
zeroliu wants to merge 3 commits into
Draft
fix(agent-mode): preserve composer input when switching agents mid-compose#2664zeroliu wants to merge 3 commits into
zeroliu wants to merge 3 commits into
Conversation
… swaps Introduce a stable compose-lane id that a replacement session inherits on an in-place swap. createSession mints inheritLaneId ?? uuid; replaceSessionInPlace forwards the old session's lane + seed when inheritLane is set. Cross-backend model picks now route through replaceSessionInPlace(inheritLane, seedSelection), reusing the New Chat in-place path instead of createSession + closeSession. Session-layer plumbing only; the composer is keyed by lane in a follow-up phase. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…on agent switch Key the draft store, the ChatInput remount, and the selected-text/mention clear by composeLaneId instead of session internalId. A cross-backend agent swap inherits the lane, so the editor never remounts and the draft never re-keys — typed text, pills, selected text, images, and the queued follow-ups all survive the switch. New Chat / new tab / load / resume mint a fresh lane, so they still reset the composer. Context-refresh now inherits the lane, so the old migrateDraft handoff is unnecessary; migrateDraft + hasDraftPayload are removed. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… swap path Add a one-line architecture note (AGENTS.md) on the compose lane, and update the cross-backend picker test to assert the new replaceSessionInPlace(inheritLane, seedSelection) path instead of the old createSession + closeSession. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What & why
Switching coding agents at the start of a session by picking a model on a
different backend (e.g. opencode → claude) is a cross-backend pick: it
mints a brand-new session in the same tab. The Agent Mode composer was keyed by
session
internalId, so the new session's key wiped everything the user hadalready typed — prompt text, attached notes, images, selected-text context,
@agentmentions, and queued follow-ups.Fix — a stable compose lane
Introduce
AgentSession.composeLaneId: a stable id a replacement sessioninherits on an in-place swap. The composer (draft store,
<ChatInput>remount, and the selected-text/mention clear) now keys by lane instead of
session id. On a cross-backend swap the lane is unchanged, so the editor never
remounts and the draft never re-keys — all input is preserved natively, no
migration and no reconstruction.
Because the editor stays mounted across a swap, live pills (notes, URLs,
folders,
@agent) survive as-is — no serialization or reparsing needed. Thisalso let the old
migrateDrafthandoff be removed.Phases
composeLaneIdonAgentSession;createSession({ inheritLaneId });replaceSessionInPlace({ inheritLane, seedSelection }); cross-backend picks route through it (also fixes the tab jumping to the strip's end).ChatInputremount + selected-text/mention clear) by lane; remove the now-deadmigrateDraft/hasDraftPayload.Verification
npm run lintandnpm run build(tsc + esbuild): clean.Plan grilled, reviewed, and approved via otacon (session
otc_w8zqpk).🤖 Generated with Claude Code