Skip to content

Hand off to another provider from the follow-up composer - #3434

Merged
brsbl merged 49 commits into
mainfrom
bb/follow-up-handoff-model-thr_rmmwartzsr
Sep 13, 2026
Merged

Hand off to another provider from the follow-up composer#3434
brsbl merged 49 commits into
mainfrom
bb/follow-up-handoff-model-thr_rmmwartzsr

Conversation

@brsbl

@brsbl brsbl commented Sep 10, 2026

Copy link
Copy Markdown
Collaborator

Human comments

What was wrong

The follow-up picker was provider-locked, and handoff opened root compose without carrying over the draft.

What changed

  • Provider tabs and “Handoff to new thread” open handoff in place; model and reasoning selections keep the picker open.
  • “New thread” submits the editable source reference and draft with the chosen provider/model, reusing the source environment.
  • Selecting the source provider returns to follow-up; queued and sent editors remain provider-locked.
  • Thread mention chips display readable titles instead of embedded raw mention tokens.

How you verified

  • Remote CI passed on 9a32f8d07, including all test shards and both package smoke jobs.
  • Chrome for Testing 151.0.7922.71 verified desktop/mobile picker entry, retained model/reasoning selection, and source-provider return on 9a32f8d07.
  • Browser verification also covered draft preservation, permissions, and thread creation.
  • Regression coverage includes keyboard selection, source fallbacks, command scope, and queued-editor isolation; Pi workspace catalogs and fallback timing lack manual coverage.

Before / after screenshots

Branch web app, light theme, 2× pixel density. Mobile: 390×844; desktop: 1280×900.

State Before · Mobile Before · Desktop After · Mobile After · Desktop
Model picker Before — model picker, mobile Before — model picker, desktop After — model picker, mobile After — model picker, desktop
Thread mention Before — thread mention, mobile Before — thread mention, desktop After — thread mention, mobile After — thread mention, desktop

Handoff header — after

Mobile Desktop
Handoff header above provider tabs, mobile Handoff header above provider tabs, desktop

BB-Thread-ID: thr_rmmwartzsr

AGENT GENERATED

🤖 Generated with Claude Code

brsbl and others added 4 commits September 10, 2026 17:00
… is selected

The follow-up composer locked its model picker to the thread's provider, so
handing work to a different model meant leaving the thread through the
"Handoff to new thread" footer action and re-typing the prompt in root compose.

The bottom follow-up composer now exposes the same provider tabs as the
new-thread picker. Selecting a provider other than the thread's own provider
shows a toast explaining that submitting will create a new thread, retitles
the submit control to "Create new thread", and on submit creates a thread on
the selected provider and model that reuses the source environment and starts
with "Continue from @thread:<source>" followed by the typed follow-up, then
navigates to it. Same-provider model changes still send follow-ups to the
current thread. Queued-message inline editors, sent-message edits, and side
chats keep the provider-locked picker; beginning a sent-message edit reverts a
pending cross-provider selection so that edit stays on the thread's provider.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…read

Selecting another provider in the follow-up composer now creates and opens
the new thread directly, so the "Handoff to new thread" footer action in the
model picker duplicated that flow with a worse one: it left the thread and
seeded root compose with a draft that dropped anything already typed.

Remove the footer action and everything that existed only to serve it: the
model picker's footer action slot and its menu action button, the
ExecutionControls prop that forwarded it, root compose's handoff seed
handling, and client-core's handoff location-state helpers. The
ThreadHandoffCreateSeed type and the "Continue from" draft builder stay
because the inline handoff still uses them.

Also fix the CI failures from the previous commit: the provider-switch test
queried a test id that the nested inline editor duplicated, the create-thread
test fixture omitted a required runtime field, and the keystrokes test's
mutation mock lacked useCreateThread.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… submit

Submitting a cross-provider follow-up silently prepended "Continue from
@thread:<source>" to whatever the user typed, so the message that started the
new thread was never the message they saw in the composer.

Selecting another provider now inserts that reference into the draft itself,
followed by a blank line, and focuses the composer so the user can edit or
delete it before submitting. Switching back to the thread's provider removes
the reference again, but only while it is still exactly as inserted. The
create-thread request sends the draft as typed, and the toast now says the
reference was added and can be edited.

client-core gains stripThreadHandoffPrefix as the counterpart of
buildThreadHandoffFollowUpDraft, which also leaves a draft alone when the
reference is already present so re-entering handoff mode never duplicates it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…line

The composer editor stores the seeded "Continue from @thread:<source>" line
followed by a single newline once the user types below it, so the exact
two-newline match never fired: switching back to the thread's provider left
the reference in place and re-entering handoff mode inserted a second copy.

Detect the reference by its intact mention and its own line instead, and
treat any run of newlines after it as the separator when stripping it or
deciding not to insert it again.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@brsbl brsbl changed the title Create a new thread from the follow-up composer when another provider is selected Continue a thread on another provider from the follow-up composer Sep 11, 2026
brsbl and others added 25 commits September 10, 2026 21:36
Resolves the conflict in PluginNewThreadComposer.test.tsx by keeping the
upstream tests and dropping the root-compose handoff test again, since the
location-state helpers it used were removed on this branch.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Bring back the "Handoff to new thread" entry at the bottom of the follow-up
composer's model picker, but keep it inside the thread: clicking it turns the
picker into a two-step flow that lists the other providers, then that
provider's models, with a header showing the step and the chosen provider.
Picking a model commits provider, model, and reasoning atomically through
setProviderModelReasoning, closes the picker, and hands the composer to the
existing handoff mode, which seeds the source-thread reference and explains
that submitting will create a new thread. Back returns to the provider step
and the close control cancels without touching the thread's selection.

The picker reuses its provider preview catalog, menu rows, and hover chrome
for the flow, and only the bottom composer passes the handoff config; inline
queued-message and sent-message editors keep the locked picker.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The step-2 line crammed the provider name and "Choose a model" into one
truncating row. Show the step on its own line and the chosen provider with
its icon on the line below so neither is cut off.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…nd a toast

The stepped flow read like onboarding, and the toast overlapped the submit
button while saying something the composer itself should show.

The picker's "Handoff to new thread" entry now switches the picker into a
handoff mode that keeps the familiar layout: a header replaces the top chrome,
the provider tabs stay with the thread's own provider struck through and
disabled, the first other provider is previewed, and search, models, and
reasoning work as usual. Reasoning changes are held locally until a model is
picked, which commits provider, model, and reasoning atomically, closes the
picker, and enters handoff mode in the composer. The back control returns to
the normal picker without touching the thread's selection.

The composer now shows a cap above the prompt box, built on the same card
chrome as the editing cap, naming the target provider and model and offering
a cancel control that restores the thread's provider and removes the seeded
reference. The submit button reads "New thread" in that state. The toast is
gone. Draft seeding and stripping moved from an effect into the provider
handlers, and a mount-time cleanup removes a stale reference after a remount.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The compact composer sizes its action buttons with a square utility that
outranked the width override, so "New thread" was clipped on phones. Reset
the square size explicitly and keep the height when a label is present.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…izing

The compact-container rule pins the submit action to a two-rem square with
no padding, which clipped the "New thread" label on phones. Mark the button
when it carries a label and give that case auto width with inline padding.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…eanup

The handoff-mode rewrite dropped the picker's plain provider-tab handler, so
tab clicks and provider cycling referenced an undefined function. Bring it
back. Let the composer test's draft mock keep what setDraft writes so the
switch-back and create-thread cases start from an unseeded draft, as they do
in the product now that a stale reference is stripped on mount, and expect
the trigger to keep showing the current model while the picker previews the
handoff target.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The header title already says what the mode is; the second line repeated it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The labeled "New thread" submit button already says what will happen, and a
cap above the composer would collide with the queued-message drawer.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The compact composer drops the label and keeps only the icon so the button
no longer overlaps the draft on narrow layouts.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Clicking the struck-through tab for the thread's own provider now exits
handoff mode and, when the composer was on another provider, switches it
back so the seeded reference and submit button return to normal.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The footer placement was easy to miss. The entry now sits above the provider
tabs as a full-width row filled with the shared selection grey, with the
new-thread icon and a chevron marking that it opens the nested handoff mode.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The header marking that submitting creates a new thread blended into the
picker's own chrome. It now carries the shared selection fill so the mode
is obvious, with its layout and controls unchanged.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
In the compact drawer the grab-handle strip sat above the handoff header in
the plain panel colour, cutting the tinted band off from the top edge. It now
carries the same fill and the drawer's top rounding.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…he-follow-up-handoff-pr-merge-ready-thr_sk6uxnxuh8
…eady-thr_sk6uxnxuh8

# Conflicts:
#	apps/app/src/views/thread-detail/ThreadDetailPromptArea.test.tsx
@brsbl brsbl changed the title Continue a thread on another provider from the follow-up composer Hand off to another provider from the follow-up composer Sep 11, 2026
@brsbl
brsbl merged commit cf51227 into main Sep 13, 2026
16 checks passed
@brsbl
brsbl deleted the bb/follow-up-handoff-model-thr_rmmwartzsr branch September 13, 2026 04:10
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