Skip to content

fix(agent-mode): preserve composer input when switching agents mid-compose#2664

Draft
zeroliu wants to merge 3 commits into
v4-previewfrom
otacon/impl-preserve-chat-input-on-agent-switch
Draft

fix(agent-mode): preserve composer input when switching agents mid-compose#2664
zeroliu wants to merge 3 commits into
v4-previewfrom
otacon/impl-preserve-chat-input-on-agent-switch

Conversation

@zeroliu

@zeroliu zeroliu commented Jul 5, 2026

Copy link
Copy Markdown
Collaborator

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 had
already typed — prompt text, attached notes, images, selected-text context,
@agent mentions, and queued follow-ups.

Fix — a stable compose lane

Introduce AgentSession.composeLaneId: a stable id a replacement session
inherits 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.

Transition Session Compose lane Composer
swap agent (opencode→claude) new inherited untouched — all input preserved
New Chat new fresh reset (unchanged)
switch tab other that tab's isolated (unchanged)
new tab · load · resume new fresh reset (unchanged)

Because the editor stays mounted across a swap, live pills (notes, URLs,
folders, @agent) survive as-is — no serialization or reparsing needed. This
also let the old migrateDraft handoff be removed.

Phases

  • Phase 1composeLaneId on AgentSession; createSession({ inheritLaneId }); replaceSessionInPlace({ inheritLane, seedSelection }); cross-backend picks route through it (also fixes the tab jumping to the strip's end).
  • Phase 2 — key the composer (draft store + ChatInput remount + selected-text/mention clear) by lane; remove the now-dead migrateDraft / hasDraftPayload.
  • Phase 3 — one-line architecture note + full gates.

Verification

  • Full suite: 4355/4355 tests (301 suites).
  • npm run lint and npm run build (tsc + esbuild): clean.

Plan grilled, reviewed, and approved via otacon (session otc_w8zqpk).

🤖 Generated with Claude Code

zeroliu and others added 3 commits July 5, 2026 12:39
… 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>
@zeroliu zeroliu marked this pull request as draft July 7, 2026 05:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant