Skip to content

fix(orchestration): keep MT Auto selected and routable mid-thread - #19

Merged
sheehanmunim merged 1 commit into
mainfrom
fix/mt-auto-sticky-picker
Aug 19, 2026
Merged

fix(orchestration): keep MT Auto selected and routable mid-thread#19
sheehanmunim merged 1 commit into
mainfrom
fix/mt-auto-sticky-picker

Conversation

@sheehanmunim

Copy link
Copy Markdown
Member

Problem

Reported in-app: a thread on MT Auto showed GPT-5.6-Terra in the composer, with the banner "Thread '06df88b7…' references unknown provider instance 'mt'. The instance is not configured in this build."

Three separate defects, all reachable from one thread:

  1. mt reached the registry. The router id is virtual — nothing answers getInstanceInfo("mt"). Resolving the turn's current instance fell back to the thread's saved selection, which for an MT Auto thread is the router id. Any turn that picked a real model then died on the lookup.
  2. Two error paths stamped the router id onto the session. setThreadSessionErrorOnTurnStartFailure and recoverAmbiguousQueuedTurnHandoff synthesize a session with providerInstanceId: thread.modelSelection.instanceId. On an MT Auto thread that writes mt into the session, poisoning every later turn.
  3. The composer lost the MT Auto label. The sticky-selection branch accepted only composerDraft.activeProvider === undefined, but an untouched draft carries null. As soon as any draft existed for the thread, the routed backend took the picker over — so MT Auto appeared to have "switched itself" to a fixed model.

Also tightened the offer gate: MT Auto was shown whenever capabilities.modelRouting !== false, so an older server (absent capability) got offered a router it rejects. It now requires an explicit true, while still showing the entry until an environment's config arrives, so a reconnect doesn't yank a sticky MT selection out of the picker.

Behavior after this change

The picker keeps saying MT Auto. Routing stays a per-turn decision — the router re-scores every turn and can move the thread to a different backend mid-conversation without a new thread.

Why no test caught this

The reactor's test harness resolved every instance id, mt included, so the failing lookup was unreachable from tests. The harness now rejects the router id the way the real registry does, and the new test fails on main with the exact production error.

Verification

vp test run src/orchestration440 passing, 36 files. Server + web typecheck clean. New test verified red before the fix, green after.

Model: Claude Opus 5, harness: Claude Code

Picking a real model in a thread whose saved selection is MT Auto failed the
turn with "Thread '…' references unknown provider instance 'mt'", and the
composer then showed the backend instead of MT Auto.

- The router id is virtual: no registry entry answers for `mt`. Resolving the
  turn's *current* instance handed it straight to the registry whenever the
  thread's saved selection was MT Auto and this turn picked something real.
  It now resolves to the routed backend, or to the model the user just picked.
- Two session-error paths stamped `providerInstanceId` from the thread's saved
  selection, which for an MT Auto thread is the router id itself — poisoning
  every later turn. They now leave it unset rather than write a router id.
- The composer treated only `undefined` as "no explicit pick", but an untouched
  draft carries `null`, so the routed backend took the picker over as soon as
  any draft existed for the thread. MT Auto stays selected; routing stays a
  per-turn decision, so it can still switch models mid-thread.
- MT Auto is now only offered to an environment that *says* it can route.
  Absent `modelRouting` means an older server that rejects `mt` outright; the
  entry stays until the environment's config arrives, so a reconnect no longer
  yanks a sticky MT selection out of the picker.

The reactor test harness resolved every instance id, including `mt`, so none of
this could fail in tests. It now rejects the router id the way the real
registry does.

Orchestration suite: 440 passing.

Model: Claude Opus 5, harness: Claude Code
@sheehanmunim
sheehanmunim merged commit acc0178 into main Aug 19, 2026
@sheehanmunim
sheehanmunim deleted the fix/mt-auto-sticky-picker branch August 19, 2026 20:17
@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:M labels Aug 19, 2026
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