Repository navigation
fix(server): make Auto routing actually apply to turns sent from the app - #100
Merged
Merged
Conversation
… again Interactive auto routing (tier/kind judgment, sticky continuations, the Opus 5.5 defaults) lives in OrchestrationCommandDispatcher's resolveEfficiency, which only runs inside dispatchNormalized. When the fork started, ws.ts dispatched every client command through that dispatcher. The upstream T3 Code v0.0.32 merge (84b585b, PR #18) replaced it with ws.ts's own dispatchBootstrapTurnStart / dispatchFromClient path straight to the engine, so since then no turn sent from the app has been routed: none carry an efficiency decision, and a thread started as "Auto" was created manual because ws.ts's bootstrap thread.create also dropped routingMode and efficiencyTier. Expose the resolution step as OrchestrationCommandDispatcher.resolve and run it in ws.ts's dispatchNormalizedCommand (inside the startup command gate, before choosing bootstrap vs direct dispatch), which covers both the dispatchCommand RPC and Command Center run dispatch, as before the merge. The ws bootstrap thread.create now forwards routingMode and efficiencyTier, so the resolved createThread fields reach the new thread. Everything else ws.ts does (client origin, analytics, deletion fence, archive/session stop, its own bootstrap cleanup) is unchanged. Manual turns and turns with efficiency disabled are dispatched unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Thread transfer impact✅ Thread transfer remains within every enforced ceiling.
Baseline: Scenario and decoded snapshot size10 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.
Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed. |
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.
Andrew set a new thread to Auto · Balanced. The next message showed Manual again, and no routing had happened. It turns out auto routing has never run for turns sent from the app since the upstream T3 Code v0.0.32 merge (#18, 2026-08-08). Production has zero turns with an
efficiency_decision_json.Cause. Auto routing (Jev tier and kind judgment, sticky continuations, the Opus 5.5 defaults) lives in
OrchestrationCommandDispatcher. The fork's first PR (#1) hadws.tsdispatch through it. The v0.0.32 merge replaced that with a directorchestrationEngine.dispatchpath, so client commands skipped routing, and nothing reported it. The bootstrapthread.createinws.tsalso droppedroutingModeandefficiencyTier, so even a routed first turn would have created a manual thread. That is why the composer snapped back to Manual.Fix. It is the smallest change that restores the pre-merge behaviour:
resolve(command).ws.tsruns it on every normalized command (inside the same startup gate) before its own bootstrap or direct dispatch. Client origin, analytics, the deletion fence and archive handling are unchanged.thread.createnow forwardsroutingModeandefficiencyTier.startup.enqueueCommandruns commands inline, so a Jev call doesn't queue other clients' commands.Tests. There are new router-seam tests in
server.test.tsthat go through the realdispatchCommandRPC:efficiencyDecisionand creates anautothread with the decided model and tier;All three fail if only the
ws.tschange is reverted.Verification (in
apps/server):vp test run src/efficiency src/server.test.ts: 238/238vp test run src/orchestration: 415/415vp test run src/command-center: 304 pass, 11 skippedtsgo --noEmit: exit 0server.test.tsandProviderCommandReactor.test.tseach have one test that fails when the host'sT3CODE_WEB_PUSH_SUBJECTorT3_SANDBOX_*variables leak into the test environment. That is pre-existing and not touched here.Found but deliberately not changed.
ensureThreadSandbox, the dispatcher's thread-creation sandbox setup, is bypassed on the same path. As a result, app-created threads recordsandbox: nulland any clientsandboxConfigis dropped. When an image is configured,ProviderCommandReactor.ensureExecutionTargetstill provisions a sandbox lazily at the first turn, so sandboxes work. The differences are that the base commit is pinned at first turn instead of at creation, and per-threadsandboxConfigis lost. That is a separate decision.Diagnosis and review: claude-opus-5-5 via Claude Code. Implementation: claude-opus-5-5 subagent.
🤖 Generated with Claude Code