1import type { OrchestrationV2HistoricalMessage } from "@t3tools/contracts";
2import {
3 ChatAttachment,
4 CheckpointId,
5 MessageId,
6 ModelSelection,
7 NodeId,
8 OrchestrationV2AppThread,
9 OrchestrationV2ConversationMessage,
10 OrchestrationV2ExecutionNode,
11 OrchestrationV2ProviderSession,
12 OrchestrationV2PlanArtifact,
13 OrchestrationV2ProviderCapabilities,
14 OrchestrationV2ProviderFailure,
15 OrchestrationV2ProviderRetry,
16 OrchestrationV2ProviderThread,
17 OrchestrationV2ProviderTurn,
18 OrchestrationV2RuntimeRequest,
19 OrchestrationV2Subagent,
20 OrchestrationV2TurnItem,
21 ProviderApprovalDecision,
22 ProviderInteractionMode,
23 ProviderDriverKind,
24 ProviderInstanceId,
25 PositiveInt,
26 ProviderUserInputAnswers,
27 ProviderSessionId,
28 ProviderThreadId,
29 ProviderTurnId,
30 RuntimeMode,
31 RuntimeRequestId,
32 RunAttemptId,
33 RunId,
34 ThreadId,
35} from "@t3tools/contracts";
36import * as Context from "effect/Context";
37import * as Schema from "effect/Schema";
38import type * as Effect from "effect/Effect";
39import type * as Scope from "effect/Scope";
40import type * as Stream from "effect/Stream";
41
42import type {
43 ProviderSelectionTransitionInput,
44 ProviderSelectionTransitionPlan,
45} from "./selectionTransition.ts";
46
47export const ProviderAdapterV2RuntimePolicy = Schema.Struct({
48 runtimeMode: RuntimeMode,
49 interactionMode: ProviderInteractionMode,
50 cwd: Schema.NullOr(Schema.String),
51 approvalPolicy: Schema.optional(Schema.Unknown),
52 sandboxPolicy: Schema.optional(Schema.Unknown),
53 reasoningEffort: Schema.optional(Schema.String),
54});
55export type ProviderAdapterV2RuntimePolicy = typeof ProviderAdapterV2RuntimePolicy.Type;
56
57export const ProviderAdapterV2TurnMessage = Schema.Struct({
58 messageId: MessageId,
59 text: Schema.String,
60 attachments: Schema.Array(ChatAttachment),
61 createdBy: OrchestrationV2ConversationMessage.fields.createdBy,
62 creationSource: OrchestrationV2ConversationMessage.fields.creationSource,
63 scheduledTaskId: OrchestrationV2ConversationMessage.fields.scheduledTaskId,
64 senderThreadId: OrchestrationV2ConversationMessage.fields.senderThreadId,
65});
66export type ProviderAdapterV2TurnMessage = typeof ProviderAdapterV2TurnMessage.Type;
67
68export const ProviderAdapterV2SessionStatus = Schema.Literals([
69 "starting",
70 "ready",
71 "running",
72 "waiting",
73 "stopped",
74 "error",
75]);
76export type ProviderAdapterV2SessionStatus = typeof ProviderAdapterV2SessionStatus.Type;
77
78export const ProviderAdapterV2Event = Schema.Union([
79 Schema.Struct({
80 type: Schema.Literal("app_thread.created"),
81 driver: ProviderDriverKind,
82 appThread: OrchestrationV2AppThread,
83 }),
84 Schema.Struct({
85 type: Schema.Literal("provider_session.updated"),
86 driver: ProviderDriverKind,
87 providerSession: OrchestrationV2ProviderSession,
88 }),
89 Schema.Struct({
90 type: Schema.Literal("provider_thread.updated"),
91 driver: ProviderDriverKind,
92 providerThread: OrchestrationV2ProviderThread,
93 /**
94 * Set when the provider rewound its own conversation outside T3, for
95 * example a Pi extension moving the session-tree leaf back. Lists every
96 * native turn id still on the active branch; the ingestor rolls back
97 * earlier runs whose turns fell off it.
98 */
99 retainedNativeTurnIds: Schema.optional(Schema.Array(Schema.String)),
100 }),
101 Schema.Struct({
102 type: Schema.Literal("provider_turn.updated"),
103 driver: ProviderDriverKind,
104 threadId: Schema.optional(ThreadId),
105 providerTurn: OrchestrationV2ProviderTurn,
106 }),
107 Schema.Struct({
108 type: Schema.Literal("node.updated"),
109 driver: ProviderDriverKind,
110 node: OrchestrationV2ExecutionNode,
111 }),
112 Schema.Struct({
113 type: Schema.Literal("subagent.updated"),
114 driver: ProviderDriverKind,
115 subagent: OrchestrationV2Subagent,
116 }),
117 Schema.Struct({
118 type: Schema.Literal("message.updated"),
119 driver: ProviderDriverKind,
120 message: OrchestrationV2ConversationMessage,
121 }),
122 Schema.Struct({
123 type: Schema.Literal("turn_item.updated"),
124 driver: ProviderDriverKind,
125 turnItem: OrchestrationV2TurnItem,
126 }),
127 Schema.Struct({
128 type: Schema.Literal("runtime_request.updated"),
129 driver: ProviderDriverKind,
130 threadId: Schema.optional(ThreadId),
131 runtimeRequest: OrchestrationV2RuntimeRequest,
132 }),
133 Schema.Struct({
134 type: Schema.Literal("plan.updated"),
135 driver: ProviderDriverKind,
136 plan: OrchestrationV2PlanArtifact,
137 }),
138 Schema.Struct({
139 type: Schema.Literal("turn.terminal"),
140 driver: ProviderDriverKind,
141 providerThreadId: ProviderThreadId,
142 providerTurnId: ProviderTurnId,
143 runOrdinal: PositiveInt,
144 status: Schema.Literals(["completed", "interrupted", "cancelled"]),
145 failure: Schema.Null,
146 threadDisposition: Schema.Literals(["reusable", "broken"]),
147 }),
148 Schema.Struct({
149 type: Schema.Literal("turn.terminal"),
150 driver: ProviderDriverKind,
151 providerThreadId: ProviderThreadId,
152 providerTurnId: ProviderTurnId,
153 runOrdinal: PositiveInt,
154 failureItemOrdinal: PositiveInt,
155 status: Schema.Literal("failed"),
156 failure: OrchestrationV2ProviderFailure,
157 retry: Schema.optional(OrchestrationV2ProviderRetry),
158 retryStartedAt: Schema.optional(Schema.DateTimeUtc),
159 threadDisposition: Schema.Literals(["reusable", "broken"]),
160 }),
161]);
162export type ProviderAdapterV2Event = typeof ProviderAdapterV2Event.Type;
163
164export class ProviderAdapterCapabilitiesError extends Schema.TaggedError<ProviderAdapterCapabilitiesError>()(
165 "ProviderAdapterCapabilitiesError",
166 {
167 driver: ProviderDriverKind,
168 cause: Schema.optional(Schema.Defect()),
169 },
170) {
171 override get message(): string {
172 return `Failed to read ${this.driver} provider capabilities.`;
173 }
174}
175
176export class ProviderAdapterOpenSessionError extends Schema.TaggedError<ProviderAdapterOpenSessionError>()(
177 "ProviderAdapterOpenSessionError",
178 {
179 driver: ProviderDriverKind,
180 providerSessionId: ProviderSessionId,
181 cause: Schema.optional(Schema.Defect()),
182 },
183) {
184 override get message(): string {
185 return `Failed to open ${this.driver} provider session ${this.providerSessionId}.`;
186 }
187}
188
189export class ProviderAdapterCloseSessionError extends Schema.TaggedError<ProviderAdapterCloseSessionError>()(
190 "ProviderAdapterCloseSessionError",
191 {
192 driver: ProviderDriverKind,
193 providerSessionId: ProviderSessionId,
194 cause: Schema.optional(Schema.Defect()),
195 },
196) {
197 override get message(): string {
198 return `Failed to close ${this.driver} provider session ${this.providerSessionId}.`;
199 }
200}
201
202export class ProviderAdapterResumeThreadError extends Schema.TaggedError<ProviderAdapterResumeThreadError>()(
203 "ProviderAdapterResumeThreadError",
204 {
205 driver: ProviderDriverKind,
206 providerSessionId: ProviderSessionId,
207 providerThreadId: ProviderThreadId,
208 cause: Schema.optional(Schema.Defect()),
209 },
210) {
211 override get message(): string {
212 return `Failed to resume ${this.driver} provider thread ${this.providerThreadId}.`;
213 }
214}
215
216export class ProviderAdapterEnsureThreadError extends Schema.TaggedError<ProviderAdapterEnsureThreadError>()(
217 "ProviderAdapterEnsureThreadError",
218 {
219 driver: ProviderDriverKind,
220 threadId: ThreadId,
221 cause: Schema.optional(Schema.Defect()),
222 },
223) {
224 override get message(): string {
225 return `Failed to ensure ${this.driver} provider thread for app thread ${this.threadId}.`;
226 }
227}
228
229export class ProviderAdapterReadThreadSnapshotError extends Schema.TaggedError<ProviderAdapterReadThreadSnapshotError>()(
230 "ProviderAdapterReadThreadSnapshotError",
231 {
232 driver: ProviderDriverKind,
233 providerThreadId: ProviderThreadId,
234 cause: Schema.optional(Schema.Defect()),
235 },
236) {
237 override get message(): string {
238 return `Failed to read ${this.driver} provider thread snapshot ${this.providerThreadId}.`;
239 }
240}
241
242export class ProviderAdapterRollbackThreadError extends Schema.TaggedError<ProviderAdapterRollbackThreadError>()(
243 "ProviderAdapterRollbackThreadError",
244 {
245 driver: ProviderDriverKind,
246 providerThreadId: ProviderThreadId,
247 checkpointId: Schema.optional(CheckpointId),
248 cause: Schema.optional(Schema.Defect()),
249 },
250) {
251 override get message(): string {
252 return `Failed to roll back ${this.driver} provider thread ${this.providerThreadId}.`;
253 }
254}
255
256export class ProviderAdapterForkThreadError extends Schema.TaggedError<ProviderAdapterForkThreadError>()(
257 "ProviderAdapterForkThreadError",
258 {
259 driver: ProviderDriverKind,
260 providerThreadId: ProviderThreadId,
261 cause: Schema.optional(Schema.Defect()),
262 },
263) {
264 override get message(): string {
265 return `Failed to fork ${this.driver} provider thread ${this.providerThreadId}.`;
266 }
267}
268
269export class ProviderAdapterTurnStartError extends Schema.TaggedError<ProviderAdapterTurnStartError>()(
270 "ProviderAdapterTurnStartError",
271 {
272 driver: ProviderDriverKind,
273 threadId: ThreadId,
274 providerThreadId: ProviderThreadId,
275 runId: RunId,
276 cause: Schema.optional(Schema.Defect()),
277 },
278) {
279 override get message(): string {
280 return `Failed to start run ${this.runId} on ${this.driver} provider thread ${this.providerThreadId}.`;
281 }
282}
283
284export class ProviderAdapterSteerRunUnsupportedError extends Schema.TaggedError<ProviderAdapterSteerRunUnsupportedError>()(
285 "ProviderAdapterSteerRunUnsupportedError",
286 {
287 driver: ProviderDriverKind,
288 providerThreadId: ProviderThreadId,
289 },
290) {
291 override get message(): string {
292 return `${this.driver} provider thread ${this.providerThreadId} does not support active-run steering.`;
293 }
294}
295
296export class ProviderAdapterSteerRunError extends Schema.TaggedError<ProviderAdapterSteerRunError>()(
297 "ProviderAdapterSteerRunError",
298 {
299 driver: ProviderDriverKind,
300 providerThreadId: ProviderThreadId,
301 providerTurnId: ProviderTurnId,
302 cause: Schema.optional(Schema.Defect()),
303 },
304) {
305 override get message(): string {
306 return `Failed to steer active run ${this.providerTurnId} on ${this.driver} provider thread ${this.providerThreadId}.`;
307 }
308}
309
310export class ProviderAdapterInterruptError extends Schema.TaggedError<ProviderAdapterInterruptError>()(
311 "ProviderAdapterInterruptError",
312 {
313 driver: ProviderDriverKind,
314 providerThreadId: ProviderThreadId,
315 providerTurnId: ProviderTurnId,
316 cause: Schema.optional(Schema.Defect()),
317 },
318) {
319 override get message(): string {
320 return `Failed to interrupt ${this.driver} provider turn ${this.providerTurnId}.`;
321 }
322}
323
324export class ProviderAdapterRuntimeRequestResponseError extends Schema.TaggedError<ProviderAdapterRuntimeRequestResponseError>()(
325 "ProviderAdapterRuntimeRequestResponseError",
326 {
327 driver: ProviderDriverKind,
328 requestId: RuntimeRequestId,
329 cause: Schema.optional(Schema.Defect()),
330 },
331) {
332 override get message(): string {
333 return `Failed to respond to ${this.driver} runtime request ${this.requestId}.`;
334 }
335}
336
337export class ProviderAdapterEventStreamError extends Schema.TaggedError<ProviderAdapterEventStreamError>()(
338 "ProviderAdapterEventStreamError",
339 {
340 driver: ProviderDriverKind,
341 providerSessionId: ProviderSessionId,
342 cause: Schema.optional(Schema.Defect()),
343 },
344) {
345 override get message(): string {
346 return `Failed while streaming ${this.driver} provider session ${this.providerSessionId} events.`;
347 }
348}
349
350export class ProviderAdapterProtocolError extends Schema.TaggedError<ProviderAdapterProtocolError>()(
351 "ProviderAdapterProtocolError",
352 {
353 driver: ProviderDriverKind,
354 detail: Schema.String,
355 cause: Schema.optional(Schema.Defect()),
356 payload: Schema.optional(Schema.Unknown),
357 },
358) {
359 override get message(): string {
360 return `${this.driver} provider protocol error: ${this.detail}.`;
361 }
362}
363
364export const ProviderAdapterV2Error = Schema.Union([
365 ProviderAdapterCapabilitiesError,
366 ProviderAdapterOpenSessionError,
367 ProviderAdapterCloseSessionError,
368 ProviderAdapterResumeThreadError,
369 ProviderAdapterEnsureThreadError,
370 ProviderAdapterReadThreadSnapshotError,
371 ProviderAdapterRollbackThreadError,
372 ProviderAdapterForkThreadError,
373 ProviderAdapterTurnStartError,
374 ProviderAdapterSteerRunUnsupportedError,
375 ProviderAdapterSteerRunError,
376 ProviderAdapterInterruptError,
377 ProviderAdapterRuntimeRequestResponseError,
378 ProviderAdapterEventStreamError,
379 ProviderAdapterProtocolError,
380]);
381export type ProviderAdapterV2Error = typeof ProviderAdapterV2Error.Type;
382
383export interface ProviderAdapterV2OpenSessionInput {
384 readonly threadId: ThreadId;
385 readonly providerSessionId: ProviderSessionId;
386 readonly modelSelection: ModelSelection;
387 readonly runtimePolicy: ProviderAdapterV2RuntimePolicy;
388 readonly resumeFromSession?: OrchestrationV2ProviderSession;
389 /** Native thread to activate while an eager adapter opens its provider process. */
390 readonly initialNativeThreadId?: string;
391 /** Preserves provider item identity across eager activation of a persisted thread. */
392 readonly initialProviderItemIdentityVersion?: 2;
393}
394
395export interface ProviderAdapterV2EnsureThreadInput {
396 readonly threadId: ThreadId;
397 /** The app thread's title, for providers that name their native sessions. */
398 readonly title?: string;
399 readonly modelSelection: ModelSelection;
400 readonly runtimePolicy: ProviderAdapterV2RuntimePolicy;
401 readonly providerSessionId?: ProviderSessionId;
402 readonly existingProviderThread?: OrchestrationV2ProviderThread;
403}
404
405export interface ProviderAdapterV2TurnInput {
406 readonly appThread: OrchestrationV2AppThread;
407 readonly threadId: ThreadId;
408 readonly runId: RunId;
409 readonly runOrdinal: number;
410 /** Whether the current native session has an accepted turn; omitted when unknown. */
411 readonly nativeThreadHasTurns?: boolean;
412 readonly providerTurnOrdinal: number;
413 readonly restartContinuationOfRunId?: RunId;
414 readonly attemptId: RunAttemptId;
415 readonly rootNodeId: NodeId;
416 readonly providerThread: OrchestrationV2ProviderThread;
417 readonly message: ProviderAdapterV2TurnMessage;
418 readonly modelSelection: ModelSelection;
419 readonly runtimePolicy: ProviderAdapterV2RuntimePolicy;
420 /**
421 * What the thread's MCP Apps want the agent to know (`ui/update-model-context`),
422 * latest per app, keyed stably per app. Adapters that host apps deliver it as
423 * application context; others never receive any.
424 */
425 readonly appContext?: ReadonlyArray<{ readonly key: string; readonly text: string }>;
426}
427
428export interface ProviderAdapterV2SteerInput {
429 readonly threadId: ThreadId;
430 readonly runId: RunId;
431 readonly providerThread: OrchestrationV2ProviderThread;
432 readonly providerTurnId: ProviderTurnId;
433 readonly message: ProviderAdapterV2TurnMessage;
434}
435
436export interface ProviderAdapterV2InterruptInput {
437 readonly providerThread: OrchestrationV2ProviderThread;
438 readonly providerTurnId: ProviderTurnId;
439 /** When true, the next `startTurn` may respawn the provider runtime (Grok Stop recovery). */
440 readonly requestRuntimeRestart?: boolean;
441}
442
443export interface ProviderAdapterV2RuntimeRequestResponseInput {
444 readonly requestId: RuntimeRequestId;
445 readonly decision?: ProviderApprovalDecision;
446 readonly answers?: ProviderUserInputAnswers;
447 readonly response?: unknown;
448}
449
450export interface ProviderAdapterV2ThreadSnapshot {
451 readonly providerThread: OrchestrationV2ProviderThread;
452 readonly providerTurns: ReadonlyArray<OrchestrationV2ProviderTurn>;
453 readonly messages: ReadonlyArray<OrchestrationV2ConversationMessage>;
454 readonly runtimeRequests: ReadonlyArray<OrchestrationV2RuntimeRequest>;
455 readonly providerPayload?: unknown;
456}
457
458export interface ProviderAdapterV2ReadThreadSnapshotInput {
459 readonly providerThread: OrchestrationV2ProviderThread;
460}
461
462export type ProviderAdapterV2RollbackTarget =
463 | {
464 readonly type: "thread_start";
465 readonly checkpointId: CheckpointId;
466 readonly appRunOrdinal: 0;
467 }
468 | {
469 readonly type: "provider_turn";
470 readonly checkpointId: CheckpointId;
471 readonly appRunOrdinal: number;
472 readonly providerTurn: OrchestrationV2ProviderTurn;
473 };
474
475export interface ProviderAdapterV2RollbackThreadInput {
476 readonly providerThread: OrchestrationV2ProviderThread;
477 readonly target: ProviderAdapterV2RollbackTarget;
478 readonly providerThreadTurns: ReadonlyArray<OrchestrationV2ProviderTurn>;
479}
480
481export interface ProviderAdapterV2ForkThreadInput {
482 readonly sourceProviderThread: OrchestrationV2ProviderThread;
483 readonly sourceProviderTurns?: ReadonlyArray<OrchestrationV2ProviderTurn>;
484 readonly providerTurnId?: ProviderTurnId;
485 readonly targetThreadId: ThreadId;
486 readonly ownerNodeId?: NodeId;
487 readonly modelSelection?: ModelSelection;
488 readonly runtimePolicy?: ProviderAdapterV2RuntimePolicy;
489}
490
491export interface ProviderAdapterV2EventSubscription {
492 readonly events: Stream.Stream<ProviderAdapterV2Event, ProviderAdapterV2Error>;
493 readonly close: Effect.Effect<void>;
494}
495
496export interface ProviderAdapterV2HistoricalContext {
497 readonly messages: ReadonlyArray<OrchestrationV2HistoricalMessage>;
498 readonly context: string;
499}
500
501/** An MCP tool as the provider's MCP client lists it. */
502export interface ProviderAdapterV2McpTool {
503 readonly name: string;
504 readonly _meta?: unknown;
505 readonly annotations?: unknown;
506}
507
508/** MCP `CallToolResult` / `ReadResourceResult` shapes, passed through unchanged. */
509export interface ProviderAdapterV2McpCallToolResult {
510 readonly content: ReadonlyArray<unknown>;
511 readonly structuredContent?: unknown;
512 readonly isError?: boolean;
513 readonly _meta?: unknown;
514}
515
516export interface ProviderAdapterV2McpApps {
517 readonly listTools: (input: {
518 readonly providerThread: OrchestrationV2ProviderThread;
519 readonly server: string;
520 }) => Effect.Effect<ReadonlyArray<ProviderAdapterV2McpTool>, ProviderAdapterV2Error>;
521 readonly callTool: (input: {
522 readonly providerThread: OrchestrationV2ProviderThread;
523 readonly server: string;
524 readonly tool: string;
525 readonly arguments: Record<string, unknown>;
526 }) => Effect.Effect<ProviderAdapterV2McpCallToolResult, ProviderAdapterV2Error>;
527 readonly readResource: (input: {
528 readonly providerThread: OrchestrationV2ProviderThread;
529 readonly server: string;
530 readonly uri: string;
531 }) => Effect.Effect<{ readonly contents: ReadonlyArray<unknown> }, ProviderAdapterV2Error>;
532}
533
534/** A terminal task outcome observed by the provider, not inferred from a stop timeout. */
535export type ProviderAdapterV2SubagentOutcome = {
536 readonly status: "completed" | "failed" | "cancelled";
537 readonly completedAt: NonNullable<OrchestrationV2Subagent["completedAt"]>;
538 readonly result: OrchestrationV2Subagent["result"];
539};
540
541export interface ProviderAdapterV2SessionRuntime {
542 readonly instanceId: ProviderInstanceId;
543 readonly driver: ProviderDriverKind;
544 readonly providerSessionId: ProviderSessionId;
545 readonly providerSession: OrchestrationV2ProviderSession;
546 readonly events: Stream.Stream<ProviderAdapterV2Event, ProviderAdapterV2Error>;
547 /**
548 * Manager-owned runtimes expose a synchronous subscription so concurrent
549 * provider threads receive independent copies of the process event stream.
550 * Adapter runtimes may omit this and expose only their single-consumer event stream.
551 */
552 readonly subscribeEvents?: Effect.Effect<ProviderAdapterV2EventSubscription>;
553 /**
554 * Adapters whose native runtime can hold pending work outside an active
555 * turn (for example Claude background tasks and their wake turns) report it
556 * here so the session manager defers idle release while it is pending.
557 */
558 readonly hasPendingBackgroundWork?: Effect.Effect<boolean>;
559 /**
560 * Per-provider-thread pending work for root-run ingestion stop gates. When
561 * present, RunExecutionService uses only this probe (never the session-wide
562 * hasPendingBackgroundWork) so sibling native threads cannot pin an
563 * unrelated root subscription open.
564 */
565 readonly hasPendingBackgroundWorkForThread?: (
566 providerThread: OrchestrationV2ProviderThread,
567 ) => Effect.Effect<boolean>;
568 /**
569 * Set when every background task this session lists on its provider threads
570 * runs inside the session's own process and ends when it closes. The session
571 * manager then clears those tasks when it releases the session (#15239).
572 * Leave unset when a task can outlive the session, for example on a shared
573 * server, so its thread keeps showing Waiting.
574 */
575 readonly backgroundTasksEndWithProcess?: true;
576 /**
577 * Capacity for the requested model/options, independent of native thread usage.
578 * `cwd` is the thread's working directory, for providers whose project config
579 * can change a model's limits.
580 */
581 readonly getModelContextWindow?: (
582 modelSelection: ModelSelection,
583 cwd?: string | null,
584 ) => number | undefined;
585 /** Whether an option-only change preserves measured native usage and capacity.
586 * Compaction thresholds are still discarded. Unknown transitions invalidate usage.
587 */
588 readonly canReuseContextUsage?: (previous: ModelSelection, next: ModelSelection) => boolean;
589 readonly ensureThread: (
590 input: ProviderAdapterV2EnsureThreadInput,
591 ) => Effect.Effect<OrchestrationV2ProviderThread, ProviderAdapterV2Error>;
592 readonly resumeThread: (input: {
593 readonly providerThread: OrchestrationV2ProviderThread;
594 readonly threadId?: ThreadId;
595 readonly modelSelection?: ModelSelection;
596 readonly runtimePolicy?: ProviderAdapterV2RuntimePolicy;
597 }) => Effect.Effect<OrchestrationV2ProviderThread, ProviderAdapterV2Error>;
598 /** False means the native protocol explicitly does not support history injection. */
599 readonly injectHistory?: (
600 input: ProviderAdapterV2HistoricalContext & {
601 readonly providerThread: OrchestrationV2ProviderThread;
602 },
603 ) => Effect.Effect<boolean, ProviderAdapterV2Error>;
604 readonly startTurn: (
605 input: ProviderAdapterV2TurnInput,
606 ) => Effect.Effect<void, ProviderAdapterV2Error>;
607 readonly compactThread?: (
608 input: ProviderAdapterV2TurnInput,
609 ) => Effect.Effect<void, ProviderAdapterV2Error>;
610 readonly steerTurn: (
611 input: ProviderAdapterV2SteerInput,
612 ) => Effect.Effect<void, ProviderAdapterV2Error>;
613 readonly stopTask?: (input: {
614 readonly providerThread: OrchestrationV2ProviderThread;
615 readonly taskId: string;
616 }) => Effect.Effect<void, ProviderAdapterV2Error>;
617 readonly interruptTurn: (
618 input: ProviderAdapterV2InterruptInput,
619 ) => Effect.Effect<void, ProviderAdapterV2Error>;
620 /** Stops one native child through its owning runtime; the owner keeps running. */
621 readonly stopSubagent?: (input: {
622 readonly providerThread: OrchestrationV2ProviderThread;
623 readonly nativeTaskId: string;
624 /** A delayed Stop must not interrupt a task resumed after this request. */
625 readonly requestedAt?: NonNullable<OrchestrationV2Subagent["startedAt"]>;
626 }) => Effect.Effect<void | ProviderAdapterV2SubagentOutcome, ProviderAdapterV2Error>;
627 /**
628 * Lets a runtime shared by several app threads unload one provider thread's
629 * native state (and its MCP servers) when that app thread detaches, while
630 * the runtime keeps serving the others. A later resume reloads it.
631 */
632 readonly unloadThread?: (input: {
633 readonly providerThread: OrchestrationV2ProviderThread;
634 }) => Effect.Effect<void, ProviderAdapterV2Error>;
635 readonly respondToRuntimeRequest: (
636 input: ProviderAdapterV2RuntimeRequestResponseInput,
637 ) => Effect.Effect<void, ProviderAdapterV2Error>;
638 readonly readThreadSnapshot: (
639 input: ProviderAdapterV2ReadThreadSnapshotInput,
640 ) => Effect.Effect<ProviderAdapterV2ThreadSnapshot, ProviderAdapterV2Error>;
641 /**
642 * Providers that accept product feedback for a thread (#7949, Codex → OpenAI)
643 * expose it here; absent means the driver has no feedback channel.
644 */
645 readonly uploadFeedback?: (input: {
646 readonly providerThread: OrchestrationV2ProviderThread;
647 readonly reason?: string;
648 }) => Effect.Effect<{ readonly feedbackId: string }, ProviderAdapterV2Error>;
649 /**
650 * MCP Apps host operations through the provider's own MCP client, for
651 * drivers whose protocol exposes them (Codex). Absent means apps from this
652 * provider are not interactive and their tool calls stay plain tool rows.
653 */
654 readonly mcpApps?: ProviderAdapterV2McpApps;
655 readonly rollbackThread: (
656 input: ProviderAdapterV2RollbackThreadInput,
657 ) => Effect.Effect<ProviderAdapterV2ThreadSnapshot, ProviderAdapterV2Error>;
658 readonly forkThread: (
659 input: ProviderAdapterV2ForkThreadInput,
660 ) => Effect.Effect<OrchestrationV2ProviderThread, ProviderAdapterV2Error>;
661}
662
663export class ProviderAdapterV2 extends Context.Service<
664 ProviderAdapterV2,
665 {
666 readonly instanceId: ProviderInstanceId;
667 readonly driver: ProviderDriverKind;
668 readonly getCapabilities: () => Effect.Effect<
669 OrchestrationV2ProviderCapabilities,
670 ProviderAdapterV2Error
671 >;
672 readonly planSelectionTransition: (
673 input: ProviderSelectionTransitionInput,
674 ) => Effect.Effect<ProviderSelectionTransitionPlan, ProviderAdapterV2Error>;
675 readonly openSession: (
676 input: ProviderAdapterV2OpenSessionInput,
677 ) => Effect.Effect<ProviderAdapterV2SessionRuntime, ProviderAdapterV2Error, Scope.Scope>;
678 }
679>()("@t3tools/provider-core/server/ProviderAdapter/ProviderAdapterV2") {}