Skip to content
Source
Sign inSign up

provider-capability-system.md

284 lines9.3 KB

1# Provider Capability System
2​
3V2 must not assume every provider can do what Codex can do. Provider behavior should be expressed through capabilities and policies, not provider-name conditionals spread across orchestration.
4​
5## Capability Shape
6​
7```ts
8type ProviderCapabilities = {
9 sessions: SessionCapabilities;
10 threads: ThreadCapabilities;
11 turns: TurnCapabilities;
12 streaming: StreamingCapabilities;
13 tools: ToolCapabilities;
14 approvals: ApprovalCapabilities;
15 planning: PlanningCapabilities;
16 subagents: SubagentCapabilities;
17 context: ContextCapabilities;
18 checkpointing: CheckpointCapabilities;
19 identity: IdentityCapabilities;
20};
21```
22​
23Capabilities should be versioned and emitted by each adapter at session start.
24​
25## Session Capabilities
26​
27```ts
28type SessionCapabilities = {
29 supportsMultipleProviderThreadsPerSession: boolean;
30 supportsModelSwitchInSession: boolean;
31 supportsProviderSwitchingViaHandoff: boolean;
32 supportsRuntimeModeSwitchInSession: boolean;
33 pendingRequestsSurviveRestart: boolean;
34};
35```
36​
37Policy examples:
38​
39- If model switching is unsupported, start a new provider session.
40- If pending requests do not survive restart, mark old requests `not_resumable`.
41​
42Provider-thread resumption is not a capability. It is a required adapter primitive. Adapters must be able to start from a stored provider cursor/session/thread handle or return a runtime resume failure.
43​
44## Thread Capabilities
45​
46```ts
47type ThreadCapabilities = {
48 canCreateEmptyThread: boolean;
49 canReadThreadSnapshot: boolean;
50 canRollbackThread: boolean;
51 canForkThread: boolean;
52 canForkFromTurn: boolean;
53 canForkFromSubagentThread: boolean;
54 exposesNativeThreadId: boolean;
55};
56```
57​
58Codex can expose strong thread ids and rollback snapshots. Claude may support native forking through its own model/session primitives. Other providers may only support synthetic app forks.
59​
60## Turn Capabilities
61​
62```ts
63type TurnCapabilities = {
64 exposesNativeTurnId: boolean;
65 emitsTurnStarted: boolean;
66 emitsTurnCompleted: boolean;
67 supportsInterrupt: boolean;
68 supportsActiveSteering: boolean;
69 supportsSteeringByInterruptRestart: boolean;
70 supportsQueuedMessages: boolean;
71 terminalStatusQuality: "strong" | "weak" | "none";
72};
73```
74​
75If `terminalStatusQuality` is weak, V2 should use adapter policy to infer terminal state, but still mark correlation strength accordingly.
76​
77`supportsActiveSteering` means the provider can modify an in-flight turn directly. `supportsSteeringByInterruptRestart` means V2 can implement app-level steering by interrupting the active turn and starting a replacement attempt. Most providers should support the latter if they support interruption and normal follow-up turns.
78​
79## Streaming Capabilities
80​
81```ts
82type StreamingCapabilities = {
83 streamsAssistantText: boolean;
84 streamsReasoning: boolean;
85 streamsToolOutput: boolean;
86 streamsPlanText: boolean;
87 emitsMessageCompleted: boolean;
88};
89```
90​
91If message completion is not emitted, the normalizer closes assistant messages at root run terminal.
92​
93## Tool Capabilities
94​
95```ts
96type ToolCapabilities = {
97 exposesToolItemIds: boolean;
98 emitsToolStarted: boolean;
99 emitsToolCompleted: boolean;
100 emitsToolOutput: boolean;
101 supportsMcpTools: boolean;
102 supportsDynamicToolCallbacks: boolean;
103};
104```
105​
106Weak providers may produce only textual tool summaries. The adapter can still create ordered `turnItems` and execution nodes by scoped ordinal.
107​
108## Approval Capabilities
109​
110```ts
111type ApprovalCapabilities = {
112 supportsCommandApproval: boolean;
113 supportsFileReadApproval: boolean;
114 supportsFileChangeApproval: boolean;
115 supportsApplyPatchApproval: boolean;
116 approvalsHaveNativeRequestIds: boolean;
117 approvalCallbacksAreLiveOnly: boolean;
118 approvalsCanOriginateFromSubagents: boolean;
119};
120```
121​
122The UI should show pending approvals from any execution node, including subagents, if they are respondable.
123​
124## Planning Capabilities
125​
126```ts
127type PlanningCapabilities = {
128 emitsPlanUpdated: boolean;
129 emitsTodoList: boolean;
130 emitsProposedPlan: boolean;
131 supportsStructuredQuestions: boolean;
132 planDeltasHaveItemIds: boolean;
133};
134```
135​
136Mapping policy:
137​
138- `emitsTodoList`: update live run progress.
139- `emitsProposedPlan`: create accept/implementable plan artifacts.
140- `supportsStructuredQuestions`: create respondable user-input requests.
141​
142If a provider only emits plain assistant text, the app should not pretend it has structured plans.
143​
144## Subagent Capabilities
145​
146```ts
147type SubagentCapabilities = {
148 supportsSubagents: boolean;
149 exposesSubagentThreadIds: boolean;
150 emitsSubagentLifecycle: boolean;
151 canWaitForSubagents: boolean;
152 canCloseSubagents: boolean;
153 canForkSubagentThread: boolean;
154};
155```
156​
157When `exposesSubagentThreadIds` is true, subagent provider threads become addressable `ProviderThread` records. When false, subagents can still be shown as nested execution nodes if the provider exposes enough lifecycle information.
158​
159## Context Handoff Capabilities
160​
161Context handoff controls provider switching and provider-thread reconstruction.
162​
163```ts
164type ContextCapabilities = {
165 acceptsSystemContext: boolean;
166 acceptsDeveloperContext: boolean;
167 acceptsSyntheticUserContext: boolean;
168 canGenerateSummaries: boolean;
169 canConsumeHandoffSummaries: boolean;
170 supportsDeltaHandoff: boolean;
171 supportsFullThreadHandoff: boolean;
172 maxRecommendedHandoffChars: number | null;
173};
174```
175​
176Policy examples:
177​
178- If `supportsDeltaHandoff` is available, return to a previous provider thread with a summary of only off-provider runs.
179- If delta handoff is unsupported or low quality, create a new provider thread with a full thread summary.
180- If the provider cannot accept explicit context, provider switching should require synthetic user context or be marked unsupported.
181- If no provider can generate summaries, use the app's configured summarization provider or a local summarizer capability.
182​
183## Checkpoint Capabilities
184​
185Checkpointing is primarily app-owned, but provider conversation rollback is provider-dependent.
186​
187```ts
188type CheckpointCapabilities = {
189 appCanCheckpointFilesystem: boolean;
190 supportsNestedCheckpointScopes: boolean;
191 providerCanRollbackConversation: boolean;
192 providerRollbackReturnsSnapshot: boolean;
193 providerCanReadConversationSnapshot: boolean;
194};
195```
196​
197If provider rollback is unsupported, filesystem rollback can still happen, but provider conversation state must be restarted or marked divergent. Nested checkpoint scopes are app-owned; providers only affect whether their nested provider conversations can be rolled back to match restored filesystem state.
198​
199## Identity Capabilities
200​
201```ts
202type IdentityCapabilities = {
203 nativeThreadIds: "strong" | "weak" | "none";
204 nativeTurnIds: "strong" | "weak" | "none";
205 nativeItemIds: "strong" | "weak" | "none";
206 nativeRequestIds: "strong" | "weak" | "none";
207};
208```
209​
210This controls how the normalizer correlates events:
211​
212- `strong`: use native id as scoped provider ref.
213- `weak`: use native id plus ordinal/fingerprint.
214- `none`: allocate by scoped ordinal.
215​
216## Degradation Policies
217​
218Every feature should declare what happens when capability is missing.
219​
220Examples:
221​
222```text
223interrupt unsupported
224 -> stop session if allowed, otherwise mark unsupported
225​
226active steering unsupported
227 -> interrupt active turn and restart the run as a steering replacement attempt
228​
229fork unsupported
230 -> synthetic fork from app projection if policy allows
231​
232rollback unsupported
233 -> restore filesystem checkpoint, restart provider context, mark provider state divergent
234​
235nested checkpoint unsupported
236 -> capture only root-run checkpoint and record child filesystem activity as uncheckpointed
237​
238provider switch return unsupported
239 -> create fresh provider thread with full app-thread summary
240​
241structured approvals unsupported
242 -> provider runs under configured sandbox policy; no approval UI
243​
244plan_updated unsupported
245 -> no live todo UI; rely on assistant messages
246```
247​
248The UI should not hide unsupported behavior behind provider-specific errors. It should receive typed capability results.
249​
250## Adapter Contract
251​
252Each provider adapter should expose:
253​
254```ts
255type ProviderAdapter = {
256 getCapabilities(): ProviderCapabilities;
257 startSession(input): ProviderSession;
258 ensureProviderThread(input): ProviderThread;
259 sendRun(input): ProviderTurnStartResult;
260 steerRun?(input): void;
261 interrupt(input): void;
262 respondToRequest(input): void;
263 readThreadSnapshot?(input): ProviderThreadSnapshot;
264 rollbackThread?(input): ProviderThreadSnapshot | void;
265 forkThread?(input): ProviderThread;
266 streamEvents(): Stream<ProviderAdapterEvent>;
267};
268```
269​
270Optional methods are guarded by capabilities. The orchestration layer should not call optional methods without checking capability or going through a policy wrapper.
271​
272Raw provider frames should be logged by the provider transport/runtime as bounded diagnostics. Adapter streams should expose normalized provider events that the V2 normalizer can turn into app orchestration events.
273​
274## Capability-Driven UI
275​
276The UI should receive capability-informed affordances:
277​
278- show or hide fork action by fork source.
279- show interrupt as available, destructive fallback, or unavailable.
280- show approvals as respondable or expired.
281- show plan/todo panels only when structured plan artifacts exist.
282- show rollback only when app checkpoint exists, and annotate provider rollback support.
283​
284This keeps the product predictable across Codex, Claude, Cursor, OpenCode, and future providers.