Skip to content
Source
Sign inSign up

provider-switching-and-context.md

233 lines8.6 KB

1# Provider Switching And Context Handoff
2​
3Provider switching is a first-class V2 feature. An app thread may contain runs from multiple providers while preserving each provider's native conversation handles and the app's canonical conversation history.
4​
5This document describes the provider-switching specialization of the broader [Thread Lineage And Context Transfer](./thread-lineage-and-context-transfer.md) model. Provider switching is a context transfer where the source and target app thread are usually the same thread. Forking, merge-back, and subagents use the same source-point/resolution concepts with different product lifecycles.
6​
7## Recommendation
8​
9When returning to a provider that was used earlier, default to resuming that provider's previous provider thread and inject a delta summary covering the runs that happened while the provider was inactive.
10​
11Create a fresh provider thread with a full app-thread summary only when resuming the prior provider thread fails, settings are incompatible, or delta handoff is likely to produce poor context.
12​
13This gives the best default tradeoff:
14​
15- preserves native continuity for provider-specific prior work,
16- avoids repeatedly summarizing everything,
17- lets each provider keep its own tool/history affordances,
18- makes cross-provider context explicit and auditable,
19- keeps a clean fallback when old provider context is stale.
20​
21## Example
22​
23```text
24runs 1-5: Codex, ProviderThread C1
25switch to Claude for run 6
26 -> ContextHandoff H1 covers runs 1-5
27 -> create ProviderThread L1
28 -> run 6 uses L1 with H1
29runs 6-8: Claude, ProviderThread L1
30switch back to Codex for run 9
31 -> ContextHandoff H2 covers runs 6-8
32 -> resume ProviderThread C1
33 -> run 9 uses C1 with H2
34```
35​
36ProviderThread C1 is not expected to natively contain Claude's runs. It contains Codex's native conversation plus explicit handoff artifacts that summarize external progress.
37​
38## Why Not Always Create A Fresh Provider Thread?
39​
40Always creating a fresh provider thread is simpler but loses useful provider-native continuity:
41​
42- prior hidden reasoning/context that is only available in the provider thread,
43- provider-side thread metadata,
44- native tool state where available,
45- continuity for provider-specific behavior.
46​
47It also forces every switch to depend on full summarization quality. Full summaries are useful fallback artifacts, but they should not be the default when a previous provider thread can be safely resumed.
48​
49## Why Not Resume Without Summary?
50​
51Because the app thread moved on while the provider was inactive. The resumed provider would not know what another provider did. That creates wrong answers, stale plans, and unsafe file assumptions.
52​
53Returning to a provider requires a handoff summary unless no runs happened since that provider last participated.
54​
55## Provider Thread Coverage
56​
57Provider threads have native coverage and handoff coverage.
58​
59```ts
60type ProviderThreadCoverage = {
61 providerThreadId: ProviderThreadId;
62 nativeRunOrdinals: number[];
63 handoffIds: ContextHandoffId[];
64};
65```
66​
67For the example above:
68​
69```text
70C1 native runs: 1,2,3,4,5,9
71C1 handoffs: H2 covering 6-8
72​
73L1 native runs: 6,7,8
74L1 handoffs: H1 covering 1-5
75```
76​
77The app thread remains the source of truth for full history.
78​
79## Handoff Artifact
80​
81A handoff is explicit graph data. In the broader model, `ContextTransfer` records source, target, relationship type, and resolution status. `ContextHandoff` is the materialized portable context artifact used when the transfer cannot be satisfied by native provider continuity.
82​
83```ts
84type ContextHandoff = {
85 id: ContextHandoffId;
86 transferId: ContextTransferId;
87 threadId: ThreadId;
88 targetRunId: RunId;
89 fromProviderThreadIds: ProviderThreadId[];
90 toProviderThreadId: ProviderThreadId;
91 coveredRunOrdinals: { from: number; to: number };
92 strategy:
93 | "delta_since_target_last_seen"
94 | "full_thread_summary"
95 | "checkpoint_summary"
96 | "manual_context";
97 summaryText: string;
98 status: "pending" | "ready" | "failed" | "superseded";
99 createdByProvider: ProviderKind | null;
100 createdAt: string;
101 updatedAt: string;
102};
103```
104​
105The handoff should be linked to the run that consumes it. If the same summary is regenerated, the old handoff is superseded rather than mutated invisibly.
106​
107## Switch Flow
108​
109```text
110start run with target provider P
111 -> find current app thread history
112 -> find best ProviderThread for P
113 -> decide handoff strategy
114 -> generate ContextHandoff if needed
115 -> ensure ProviderSession for P
116 -> ensure/resume/create target ProviderThread
117 -> send provider turn with handoff context + user message
118```
119​
120The user message remains the actual run input. The handoff context is a separate preamble/system/developer/synthetic-user context depending on provider capability.
121​
122## Strategy Selection
123​
124Recommended strategy order:
125​
1261. No handoff: target provider thread already has current app run coverage.
1272. Delta handoff into existing provider thread: target provider thread can resume and only missed a run range.
1283. Full thread handoff into existing provider thread: target provider can resume, but delta chain is too complex.
1294. Full thread handoff into new provider thread: target provider resume failed, settings are incompatible, or old context is stale.
1305. Unsupported: provider cannot accept handoff context and no safe reconstruction path exists.
131​
132## Staleness Policy
133​
134The app should be able to decide that returning to an old provider thread is no longer appropriate.
135​
136Possible staleness signals:
137​
138- too many off-provider runs since last use,
139- too many chained handoffs,
140- target provider model/runtime mode changed incompatibly,
141- provider thread resume failed,
142- prior provider thread was rolled back or forked in a conflicting way,
143- user selected "clean context",
144- handoff summary would exceed provider context policy.
145​
146When stale, create a new provider thread with `full_thread_summary`.
147​
148## Summarization Source
149​
150Summaries can be generated by:
151​
152- the provider being left,
153- the provider being entered,
154- a configured summarization provider,
155- a local deterministic summarizer for structured artifacts.
156​
157The summary generator is not necessarily the target provider. The handoff records `createdByProvider` so quality and provenance can be inspected later.
158​
159## What The Summary Should Contain
160​
161The summary should be app-thread canonical, not provider transcript-only.
162​
163Include:
164​
165- user goals and constraints,
166- decisions made,
167- files changed,
168- commands/tests run,
169- plans/todo state,
170- unresolved approvals/questions,
171- current checkpoint/diff summary,
172- known failures,
173- relevant subagent results.
174​
175Do not include:
176​
177- irrelevant provider protocol noise,
178- hidden chain-of-thought,
179- stale tool output that is superseded by later runs,
180- large diffs when a file summary is enough.
181​
182## Checkpoint Interaction
183​
184Provider switching does not change checkpoint ownership. Checkpoints still attach to app runs.
185​
186However, handoff generation should reference the latest checkpoint and diff summary so the next provider has a correct workspace-state picture.
187​
188```text
189run N completed
190 -> checkpoint N captured
191switch provider for run N+1
192 -> handoff includes summary through checkpoint N
193```
194​
195## Rollback Interaction
196​
197Rollback invalidates handoffs that cover rolled-back runs.
198​
199```text
200rollback to run 5
201 -> runs 6+ marked rolled_back
202 -> handoffs covering 6+ marked superseded
203 -> provider threads whose native/handoff coverage includes 6+ marked divergent or rolled back by capability
204```
205​
206If the active provider supports provider rollback, call it. Otherwise, create a new provider thread from the retained app-thread summary when work resumes.
207​
208## Forking Interaction
209​
210Forking from a mixed-provider app thread should record app-thread lineage and a source point without requiring provider selection at fork time. Provider context is resolved lazily when the first run starts on the fork.
211​
212Examples:
213​
214- Fork from run 5 on Codex, first fork run uses Codex: prefer Codex native fork if the source refs are strong.
215- Fork from run 5 on Codex, first fork run uses Claude: build portable context lazily at first dispatch.
216- Fork from app checkpoint with no provider-native thread: create target provider thread with checkpoint/full-thread context.
217- Fork from subagent provider thread: use the subagent's provider thread directly if stable, otherwise fall back to portable context.
218​
219## Data Model Changes
220​
221Provider switching requires:
222​
223- `Run.provider`
224- `Run.providerThreadId`
225- `Run.contextHandoffId`
226- `ContextTransfer`
227- `ProviderThread.firstRunOrdinal`
228- `ProviderThread.lastRunOrdinal`
229- `ProviderThread.handoffIds`
230- `ContextHandoff`
231- provider capabilities for handoff support
232​
233The app does not need separate conversation threads for provider switches. It needs multiple provider threads attached to the same app thread.