fix(orchestration): keep MT Auto selected and routable mid-thread - #19
Merged
Conversation
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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:
mtreached the registry. The router id is virtual — nothing answersgetInstanceInfo("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.setThreadSessionErrorOnTurnStartFailureandrecoverAmbiguousQueuedTurnHandoffsynthesize a session withproviderInstanceId: thread.modelSelection.instanceId. On an MT Auto thread that writesmtinto the session, poisoning every later turn.composerDraft.activeProvider === undefined, but an untouched draft carriesnull. 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 explicittrue, 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,
mtincluded, 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 onmainwith the exact production error.Verification
vp test run src/orchestration— 440 passing, 36 files. Server + web typecheck clean. New test verified red before the fix, green after.Model: Claude Opus 5, harness: Claude Code