You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[Bug]: Mobile: a model pick that was already delivered moves the thread back on a later message #24564
I searched existing issues and did not find a duplicate.
I included enough detail to reproduce or investigate the problem.
Area
apps/mobile
Steps to reproduce
On the mobile app, open a thread running on model B.
Pick model A in the composer and send. Lock the phone right away, before the app receives the thread update showing the thread on model A.
On desktop or web, switch the thread to model C and send a message.
Unlock the phone, type a follow-up without touching the model picker, and send it.
Expected behavior
The follow-up runs on model C, the thread's current model. A pick should apply to the message it was sent with, not to later ordinary messages.
Actual behavior
The follow-up carries model A, and the server switches the thread back to A with a context handoff.
Cause: the composer keeps a pick in the draft until the app sees the thread on that exact model (subscribeComposerDraftModelReconciliation in apps/mobile/src/state/use-composer-drafts.ts). An app that slept through that moment, while another client moved the thread, never sees it, so the pick stays and rides along with the next message. The client can't release the pick from the shell alone: a pick is applied to the thread only when its run starts, and the shell doesn't say whether a run is still waiting (held behind a failed run, a Stop, or a reordered queue).
I hit this too: 4 machines, several provider accounts, iOS app. I had picked a model on the phone for a thread earlier. Later I continued the thread on another machine, then sent a follow-up from the phone without touching the picker. The thread switched back to my old pick with a context handoff.
Why the client can't release the pick safely today: the server fixes each queued message's model when the message arrives (command.modelSelection ?? projection.thread.modelSelection in Orchestrator.ts). thread.modelSelection changes only when a run starts. So if the app released the pick when the message was accepted, a quick follow-up queued behind the picked message would go back to the old model. Keeping the pick until the thread shows it avoids that, but a phone that sleeps through that moment keeps the pick forever.
Proposed fix (two small parts):
Server: a user message with no model that is queued (not steering) follows the newest queued run's model, not thread.modelSelection. Steering and server-created messages are unchanged.
Mobile: release the draft pick once the outbox delivers a message carrying it. The pick then applies to the message it was sent with, which is the expected behaviour above.
This needs #24562 (follow-ups carry a model only when picked); otherwise unpicked follow-ups still send the cached model. I have this working on top of #24562 with a server integration test (an unpicked follow-up queued behind a Claude pick runs on Claude) and a mobile draft test. Happy to open it as a PR if the direction looks right.
Activity
vitalyiegorov commentedon Oct 26, 2026
I hit this too: 4 machines, several provider accounts, iOS app. I had picked a model on the phone for a thread earlier. Later I continued the thread on another machine, then sent a follow-up from the phone without touching the picker. The thread switched back to my old pick with a context handoff.
Why the client can't release the pick safely today: the server fixes each queued message's model when the message arrives (
command.modelSelection ?? projection.thread.modelSelectioninOrchestrator.ts).thread.modelSelectionchanges only when a run starts. So if the app released the pick when the message was accepted, a quick follow-up queued behind the picked message would go back to the old model. Keeping the pick until the thread shows it avoids that, but a phone that sleeps through that moment keeps the pick forever.Proposed fix (two small parts):
thread.modelSelection. Steering and server-created messages are unchanged.This needs #24562 (follow-ups carry a model only when picked); otherwise unpicked follow-ups still send the cached model. I have this working on top of #24562 with a server integration test (an unpicked follow-up queued behind a Claude pick runs on Claude) and a mobile draft test. Happy to open it as a PR if the direction looks right.