Skip to content

fix(web): cloud chats keep the model you picked - #77

Merged
andrewcai8 merged 4 commits into
mainfrom
fix/cloud-handoff-keeps-model
Sep 26, 2026
Merged

andrewcai8 merged 4 commits into
mainfrom
fix/cloud-handoff-keeps-model

Conversation

@andrewcai8

Copy link
Copy Markdown
Owner

Problem

On a host that runs no agents locally, a new cloud chat ran on the provider's default model instead of the one picked in the draft. Picking Claude Opus 5.5 and pressing Enter started the chat on Claude Fable 5.1, and the picked options (effort, context window) were dropped too.

Root cause

The draft handed its model selection to the box keyed by the host's account id, for example claude_work. The box names its one account per driver by the driver's default instance id (claudeAgent, codex, cursor), set in ProvisionPreparation.ts. On the box, the composer resolved to claudeAgent, found no saved selection under that key, and fell back to the provider default. Every host account whose id is not the driver default hit this.

Two smaller problems made it worse:

  • The handoff swapped the picked model for the host account's default whenever the host's catalog lacked it. The host's catalog follows the host's CLI version, which says nothing about the box.
  • The pending Claude snapshot lists the whole catalog. Once the probe filtered models by CLI version, the merge appended the filtered ones back, so a model the CLI cannot run showed up last in the picker.

Fix

  • buildCloudHandoff re-keys the selection to defaultInstanceIdForDriver(agentDriver) and keeps the model and options. The host account id still goes to provision as the routing hint.
  • The handoff sends the picked model as is. The box's catalog resolves it, and the box's existing fallback applies if it does not offer it.
  • Claude now keeps models missing from a probe only while the probe is pending or has failed, like Codex.

Mobile starts the machine first and opens the draft on the box, so it never carries a host selection across. packages/client-runtime only passes the account id as the routing hint. Neither needed a change.

The first commit adds a test that drives the draft store, provider-selection resolution, and effective-model derivation through a handoff, and fails before the fix.

Claude Opus 5.5 (1M context) in Claude Code.

🤖 Generated with Claude Code

andrewcai8 and others added 4 commits September 26, 2026 10:53
The draft hands its selection to the box keyed by the host's account id
(claude_work), but the box names its only Claude instance claudeAgent, so
the box composer falls back to the provider default and drops the options.

Extracts the handoff builder unchanged so the test drives the real flow.
This test fails until the next commit.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The box provisioned for a cloud chat names each driver's account by the
driver's default instance id (claudeAgent, codex, cursor). The handoff kept
the manager's account id (claude_work), so the box composer found no saved
selection for its instance and sent the provider default with no options.
Re-key the handoff to the box's instance. The manager's account id is still
sent to provision as the routing hint.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The handoff swapped the picked model for the host account's default when
the host's catalog lacked it. The host's catalog reflects the host's CLI
version, which says nothing about the box that runs the chat. Send the
picked model and let the box's catalog resolve it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The pending Claude snapshot lists the whole catalog. When the probe then
filtered models by CLI version, the merge appended the filtered ones back
from the pending snapshot, so a model the CLI cannot run showed up last in
the picker. Claude now keeps missing models only while its probe is pending
or has failed, like Codex.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:M labels Sep 26, 2026
@github-actions

Copy link
Copy Markdown

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

Provider Metric Main baseline This PR Impact PR ceiling
Codex Total thread wire 13.5 KiB 13.5 KiB −2 B (−0.0%) 15.1 KiB ✅
Codex Thread snapshot wire 7.1 KiB 7.1 KiB +1 B (+0.0%) 7.3 KiB ✅
Codex Live turn WebSocket wire 6.5 KiB 6.5 KiB −3 B (−0.0%) 7.8 KiB ✅
Codex Live turn WebSocket decoded 56.3 KiB 56.3 KiB 0 B (0.0%) 66.4 KiB ✅
Codex Live turn messages 10 10 0 (0.0%) 21 ✅
Claude Total thread wire 13.5 KiB 13.5 KiB −11 B (−0.1%) 15.1 KiB ✅
Claude Thread snapshot wire 7.1 KiB 7.1 KiB 0 B (0.0%) 7.3 KiB ✅
Claude Live turn WebSocket wire 6.4 KiB 6.4 KiB −11 B (−0.2%) 7.8 KiB ✅
Claude Live turn WebSocket decoded 57.0 KiB 57.0 KiB 0 B (0.0%) 66.4 KiB ✅
Claude Live turn messages 9 9 0 (0.0%) 21 ✅

Baseline: 32a708c · PR result: e1af9f7 · Source CI: success

Scenario and decoded snapshot size

10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.

  • Codex decoded thread snapshot: 113.9 KiB
  • Claude decoded thread snapshot: 114.6 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

@andrewcai8
andrewcai8 merged commit c1cf4b5 into main Sep 26, 2026
17 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant