feat: support mid-session model/provider switching with history handoff#1296
feat: support mid-session model/provider switching with history handoff#1296MichaelMBrown wants to merge 3 commits intopingdotgg:mainfrom
Conversation
- Emit and project thread.model-set events - Add model change activity notices in orchestration - Allow provider switches with handoff history
- Thread the handoff source model through orchestration and contracts - Use it when building reroute prompts so model-switch messages stay accurate - Add coverage for handoff prompt truncation and model switch cases
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment Tip CodeRabbit can use OpenGrep to find security vulnerabilities and bugs across 17+ programming languages.OpenGrep is compatible with Semgrep configurations. Add an |
|
i think we (theo) dont want this because it just looses all the reasoning / traces of the original thread (and also this pr does a "summary" / truncated hand off?? wtf) so this is just a "lossy button" for working threasds. closing rn as not planned / too big sorry |
Why this PR
Made this PR because I had found that working with T3 Code was great, but I'd also found myself switching between threads often with provider specific request or wanting Claude to handle a feature over Codex, and vise versa. This PR integrates functionality to allow switching from one provider to another in the same thread. I completely understand if this is not wanted or in a different direction, I'd only found that this helped me and wanted to push it forward.
Summary
thread.model-setevent: New orchestration event and command so the server can track and project model changes over time, with source attribution (clientvsprovider-reroute).Why this is one PR
The handoff history builder, the provider-switch logic in
ProviderCommandReactor, the newthread.model-setevent, and the UI notice are all interdependent — the history transfer is how the provider switch works, and the notice is driven by the same event. Splitting them would leave non-functional intermediate states.What changed
packages/contracts/src/orchestration.tsThreadModelSetCommand,ThreadModelSetPayload,handoffSourceModelfield, notice typespackages/shared/src/model.ts,shell.tsinferProviderForModel,resolveModelDisplayNamehelpersProviderCommandReactor.ts,providerHandoff.ts,ModelChangeReactor.ts,OrchestrationEngine.ts,decider.ts,projector.tsMessagesTimeline.tsx,ChatView.tsx,session-logic.tsTest plan
bun typecheckpassesbun lintpassesbun fmtpassesProviderCommandReactor.test.ts— covers switching providers mid-session, switching after a stopped session, and handoff prompt injectionproviderHandoff.test.ts— covers transcript building, truncation, attachment summaries, source model threadingModelChangeReactor.test.ts— covers notice emission for user and reroute sourcesOrchestrationEngine.test.ts— covers no-op receipt path typing fixMessagesTimeline.test.tsx— covers notice row renderingsession-logic.test.ts— covers timeline entry derivation for model-change noticesScreenshots
The first screenshot is a flow from Claude to ChatGPT.


This second screenshot is another flow from ChatGPT to Claude.
Screen.Recording.2026-03-21.at.10.35.40.PM.mov
🤖 Generated with (help) from Claude Code & ChatGPT.
Note
Add mid-session model/provider switching with conversation history handoff
thread.model.setcommand andthread.model-setevent in the contracts and orchestration decider, allowing clients and providers to switch models or providers mid-session.ProviderCommandReactor, the turn input is prefixed with a generated handoff prompt (built bybuildProviderHandoffPrompt) that summarizes prior conversation history, capped at 12,000 chars / 24 messages.ModelChangeReactorthat listens forthread.model-setevents and appends athread.model.changedactivity to the thread, recording the model transition, source, and optional reason.MessagesTimeline) now renders model-change notices inline as centered banners showing 'Switched to {model}' or 'Rerouted to {model}' with optional from-model and reason text.ChatViewis no longer locked after a thread has activity; users can switch providers at any time and model search spans all providers.resolveModelDisplayNameto the shared package for converting model slugs to human-readable labels, with fallback humanization for unknown slugs.Macroscope summarized 972758f.