Skip to content

feat: support mid-session model/provider switching with history handoff#1296

Closed
MichaelMBrown wants to merge 3 commits intopingdotgg:mainfrom
MichaelMBrown:michael/allow-model-switching
Closed

feat: support mid-session model/provider switching with history handoff#1296
MichaelMBrown wants to merge 3 commits intopingdotgg:mainfrom
MichaelMBrown:michael/allow-model-switching

Conversation

@MichaelMBrown
Copy link

@MichaelMBrown MichaelMBrown commented Mar 22, 2026

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

  • Model switching during a session: Users can now change models (including across providers, e.g. GPT → Claude) mid-conversation. The orchestration layer detects when the requested model belongs to a different provider, tears down the current provider session, and starts a new one — instead of rejecting the request.
  • Conversation history handoff: When switching providers, a transcript of the prior conversation (up to 24 messages / 12k chars) is injected into the new provider's first turn so it has full context. The transcript includes attachment summaries and is truncated gracefully.
  • Model-change UI notice: A visual divider appears in the chat timeline showing which model was switched to (and from), so the user knows when a handoff occurred. Distinguishes user-initiated switches from provider reroutes.
  • thread.model-set event: New orchestration event and command so the server can track and project model changes over time, with source attribution (client vs provider-reroute).

Why this is one PR

The handoff history builder, the provider-switch logic in ProviderCommandReactor, the new thread.model-set event, 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

Area Files What
Contracts packages/contracts/src/orchestration.ts ThreadModelSetCommand, ThreadModelSetPayload, handoffSourceModel field, notice types
Shared packages/shared/src/model.ts, shell.ts inferProviderForModel, resolveModelDisplayName helpers
Server orchestration ProviderCommandReactor.ts, providerHandoff.ts, ModelChangeReactor.ts, OrchestrationEngine.ts, decider.ts, projector.ts Provider switch detection, handoff prompt builder, model-set event emission/projection
Web UI MessagesTimeline.tsx, ChatView.tsx, session-logic.ts Model-change notice row, session-logic timeline derivation
Tests 8 test files Unit + integration coverage for handoff prompt building, provider switching (including after stopped sessions), model-set projection, and UI timeline derivation

Test plan

  • bun typecheck passes
  • bun lint passes
  • bun fmt passes
  • ProviderCommandReactor.test.ts — covers switching providers mid-session, switching after a stopped session, and handoff prompt injection
  • providerHandoff.test.ts — covers transcript building, truncation, attachment summaries, source model threading
  • ModelChangeReactor.test.ts — covers notice emission for user and reroute sources
  • OrchestrationEngine.test.ts — covers no-op receipt path typing fix
  • MessagesTimeline.test.tsx — covers notice row rendering
  • session-logic.test.ts — covers timeline entry derivation for model-change notices

Note: This is a larger-than-typical first contribution because the feature requires coordinated changes across server orchestration, contracts, shared utilities, and web UI. Each layer depends on the one below it.

Screenshots

The first screenshot is a flow from Claude to ChatGPT.
image
This second screenshot is another flow from ChatGPT to Claude.
image

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

  • Introduces a thread.model.set command and thread.model-set event in the contracts and orchestration decider, allowing clients and providers to switch models or providers mid-session.
  • When a provider switch is detected in ProviderCommandReactor, the turn input is prefixed with a generated handoff prompt (built by buildProviderHandoffPrompt) that summarizes prior conversation history, capped at 12,000 chars / 24 messages.
  • Adds a ModelChangeReactor that listens for thread.model-set events and appends a thread.model.changed activity to the thread, recording the model transition, source, and optional reason.
  • The chat timeline (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.
  • Provider selection in ChatView is no longer locked after a thread has activity; users can switch providers at any time and model search spans all providers.
  • Adds resolveModelDisplayName to the shared package for converting model slugs to human-readable labels, with fallback humanization for unknown slugs.
  • Behavioral Change: commands that resolve to no events (e.g. setting the same model) are now accepted as no-ops with a recorded receipt instead of throwing an invariant error.

Macroscope summarized 972758f.

- 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
@coderabbitai
Copy link

coderabbitai bot commented Mar 22, 2026

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 00052004-6b25-47c4-a4c9-57f89ec94358

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Tip

CodeRabbit can use OpenGrep to find security vulnerabilities and bugs across 17+ programming languages.

OpenGrep is compatible with Semgrep configurations. Add an opengrep.yml or semgrep.yml configuration file to your project to enable OpenGrep analysis.

@github-actions github-actions bot added size:XXL 1,000+ changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list. labels Mar 22, 2026
@MichaelMBrown MichaelMBrown marked this pull request as ready for review March 22, 2026 02:45
@maria-rcks
Copy link
Collaborator

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

@maria-rcks maria-rcks closed this Mar 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL 1,000+ changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants