import { ChatAttachment, CheckpointId, MessageId, ModelSelection, NodeId, OrchestrationV2AppThread, OrchestrationV2ConversationMessage, OrchestrationV2ExecutionNode, OrchestrationV2ProviderSession, OrchestrationV2PlanArtifact, OrchestrationV2ProviderCapabilities, OrchestrationV2ProviderFailure, OrchestrationV2ProviderRetry, OrchestrationV2ProviderThread, OrchestrationV2ProviderTurn, OrchestrationV2RuntimeRequest, OrchestrationV2Subagent, OrchestrationV2TurnItem, ProviderApprovalDecision, ProviderInteractionMode, ProviderDriverKind, ProviderInstanceId, PositiveInt, ProviderUserInputAnswers, ProviderSessionId, ProviderThreadId, ProviderTurnId, RuntimeMode, RuntimeRequestId, RunAttemptId, RunId, ThreadId, } from "@t3tools/contracts"; import * as Context from "effect/Context"; import * as Schema from "effect/Schema"; import type * as Effect from "effect/Effect"; import type * as Scope from "effect/Scope"; import type * as Stream from "effect/Stream"; import type { ProviderSelectionTransitionInput, ProviderSelectionTransitionPlan, } from "./ProviderSelectionTransition.ts"; export const ProviderAdapterV2RuntimePolicy = Schema.Struct({ runtimeMode: RuntimeMode, interactionMode: ProviderInteractionMode, cwd: Schema.NullOr(Schema.String), approvalPolicy: Schema.optional(Schema.Unknown), sandboxPolicy: Schema.optional(Schema.Unknown), reasoningEffort: Schema.optional(Schema.String), }); export type ProviderAdapterV2RuntimePolicy = typeof ProviderAdapterV2RuntimePolicy.Type; export const ProviderAdapterV2TurnMessage = Schema.Struct({ messageId: MessageId, text: Schema.String, attachments: Schema.Array(ChatAttachment), createdBy: OrchestrationV2ConversationMessage.fields.createdBy, creationSource: OrchestrationV2ConversationMessage.fields.creationSource, }); export type ProviderAdapterV2TurnMessage = typeof ProviderAdapterV2TurnMessage.Type; export const ProviderAdapterV2SessionStatus = Schema.Literals([ "starting", "ready", "running", "waiting", "stopped", "error", ]); export type ProviderAdapterV2SessionStatus = typeof ProviderAdapterV2SessionStatus.Type; export const ProviderAdapterV2Event = Schema.Union([ Schema.Struct({ type: Schema.Literal("app_thread.created"), driver: ProviderDriverKind, appThread: OrchestrationV2AppThread, }), Schema.Struct({ type: Schema.Literal("provider_session.updated"), driver: ProviderDriverKind, providerSession: OrchestrationV2ProviderSession, }), Schema.Struct({ type: Schema.Literal("provider_thread.updated"), driver: ProviderDriverKind, providerThread: OrchestrationV2ProviderThread, }), Schema.Struct({ type: Schema.Literal("provider_turn.updated"), driver: ProviderDriverKind, threadId: Schema.optional(ThreadId), providerTurn: OrchestrationV2ProviderTurn, }), Schema.Struct({ type: Schema.Literal("node.updated"), driver: ProviderDriverKind, node: OrchestrationV2ExecutionNode, }), Schema.Struct({ type: Schema.Literal("subagent.updated"), driver: ProviderDriverKind, subagent: OrchestrationV2Subagent, }), Schema.Struct({ type: Schema.Literal("message.updated"), driver: ProviderDriverKind, message: OrchestrationV2ConversationMessage, }), Schema.Struct({ type: Schema.Literal("turn_item.updated"), driver: ProviderDriverKind, turnItem: OrchestrationV2TurnItem, }), Schema.Struct({ type: Schema.Literal("runtime_request.updated"), driver: ProviderDriverKind, threadId: Schema.optional(ThreadId), runtimeRequest: OrchestrationV2RuntimeRequest, }), Schema.Struct({ type: Schema.Literal("plan.updated"), driver: ProviderDriverKind, plan: OrchestrationV2PlanArtifact, }), Schema.Struct({ type: Schema.Literal("turn.terminal"), driver: ProviderDriverKind, providerThreadId: ProviderThreadId, providerTurnId: ProviderTurnId, runOrdinal: PositiveInt, status: Schema.Literals(["completed", "interrupted", "cancelled"]), failure: Schema.Null, threadDisposition: Schema.Literals(["reusable", "broken"]), }), Schema.Struct({ type: Schema.Literal("turn.terminal"), driver: ProviderDriverKind, providerThreadId: ProviderThreadId, providerTurnId: ProviderTurnId, runOrdinal: PositiveInt, failureItemOrdinal: PositiveInt, status: Schema.Literal("failed"), failure: OrchestrationV2ProviderFailure, retry: Schema.optional(OrchestrationV2ProviderRetry), retryStartedAt: Schema.optional(Schema.DateTimeUtc), threadDisposition: Schema.Literals(["reusable", "broken"]), }), ]); export type ProviderAdapterV2Event = typeof ProviderAdapterV2Event.Type; export class ProviderAdapterCapabilitiesError extends Schema.TaggedErrorClass()( "ProviderAdapterCapabilitiesError", { driver: ProviderDriverKind, cause: Schema.optional(Schema.Defect()), }, ) { override get message(): string { return `Failed to read ${this.driver} provider capabilities.`; } } export class ProviderAdapterOpenSessionError extends Schema.TaggedErrorClass()( "ProviderAdapterOpenSessionError", { driver: ProviderDriverKind, providerSessionId: ProviderSessionId, cause: Schema.optional(Schema.Defect()), }, ) { override get message(): string { return `Failed to open ${this.driver} provider session ${this.providerSessionId}.`; } } export class ProviderAdapterCloseSessionError extends Schema.TaggedErrorClass()( "ProviderAdapterCloseSessionError", { driver: ProviderDriverKind, providerSessionId: ProviderSessionId, cause: Schema.optional(Schema.Defect()), }, ) { override get message(): string { return `Failed to close ${this.driver} provider session ${this.providerSessionId}.`; } } export class ProviderAdapterResumeThreadError extends Schema.TaggedErrorClass()( "ProviderAdapterResumeThreadError", { driver: ProviderDriverKind, providerSessionId: ProviderSessionId, providerThreadId: ProviderThreadId, cause: Schema.optional(Schema.Defect()), }, ) { override get message(): string { return `Failed to resume ${this.driver} provider thread ${this.providerThreadId}.`; } } export class ProviderAdapterEnsureThreadError extends Schema.TaggedErrorClass()( "ProviderAdapterEnsureThreadError", { driver: ProviderDriverKind, threadId: ThreadId, cause: Schema.optional(Schema.Defect()), }, ) { override get message(): string { return `Failed to ensure ${this.driver} provider thread for app thread ${this.threadId}.`; } } export class ProviderAdapterReadThreadSnapshotError extends Schema.TaggedErrorClass()( "ProviderAdapterReadThreadSnapshotError", { driver: ProviderDriverKind, providerThreadId: ProviderThreadId, cause: Schema.optional(Schema.Defect()), }, ) { override get message(): string { return `Failed to read ${this.driver} provider thread snapshot ${this.providerThreadId}.`; } } export class ProviderAdapterRollbackThreadError extends Schema.TaggedErrorClass()( "ProviderAdapterRollbackThreadError", { driver: ProviderDriverKind, providerThreadId: ProviderThreadId, checkpointId: Schema.optional(CheckpointId), cause: Schema.optional(Schema.Defect()), }, ) { override get message(): string { return `Failed to roll back ${this.driver} provider thread ${this.providerThreadId}.`; } } export class ProviderAdapterForkThreadError extends Schema.TaggedErrorClass()( "ProviderAdapterForkThreadError", { driver: ProviderDriverKind, providerThreadId: ProviderThreadId, cause: Schema.optional(Schema.Defect()), }, ) { override get message(): string { return `Failed to fork ${this.driver} provider thread ${this.providerThreadId}.`; } } export class ProviderAdapterTurnStartError extends Schema.TaggedErrorClass()( "ProviderAdapterTurnStartError", { driver: ProviderDriverKind, threadId: ThreadId, providerThreadId: ProviderThreadId, runId: RunId, cause: Schema.optional(Schema.Defect()), }, ) { override get message(): string { return `Failed to start run ${this.runId} on ${this.driver} provider thread ${this.providerThreadId}.`; } } export class ProviderAdapterSteerRunUnsupportedError extends Schema.TaggedErrorClass()( "ProviderAdapterSteerRunUnsupportedError", { driver: ProviderDriverKind, providerThreadId: ProviderThreadId, }, ) { override get message(): string { return `${this.driver} provider thread ${this.providerThreadId} does not support active-run steering.`; } } export class ProviderAdapterSteerRunError extends Schema.TaggedErrorClass()( "ProviderAdapterSteerRunError", { driver: ProviderDriverKind, providerThreadId: ProviderThreadId, providerTurnId: ProviderTurnId, cause: Schema.optional(Schema.Defect()), }, ) { override get message(): string { return `Failed to steer active run ${this.providerTurnId} on ${this.driver} provider thread ${this.providerThreadId}.`; } } export class ProviderAdapterInterruptError extends Schema.TaggedErrorClass()( "ProviderAdapterInterruptError", { driver: ProviderDriverKind, providerThreadId: ProviderThreadId, providerTurnId: ProviderTurnId, cause: Schema.optional(Schema.Defect()), }, ) { override get message(): string { return `Failed to interrupt ${this.driver} provider turn ${this.providerTurnId}.`; } } export class ProviderAdapterRuntimeRequestResponseError extends Schema.TaggedErrorClass()( "ProviderAdapterRuntimeRequestResponseError", { driver: ProviderDriverKind, requestId: RuntimeRequestId, cause: Schema.optional(Schema.Defect()), }, ) { override get message(): string { return `Failed to respond to ${this.driver} runtime request ${this.requestId}.`; } } export class ProviderAdapterEventStreamError extends Schema.TaggedErrorClass()( "ProviderAdapterEventStreamError", { driver: ProviderDriverKind, providerSessionId: ProviderSessionId, cause: Schema.optional(Schema.Defect()), }, ) { override get message(): string { return `Failed while streaming ${this.driver} provider session ${this.providerSessionId} events.`; } } export class ProviderAdapterProtocolError extends Schema.TaggedErrorClass()( "ProviderAdapterProtocolError", { driver: ProviderDriverKind, detail: Schema.String, payload: Schema.optional(Schema.Unknown), }, ) { override get message(): string { return `${this.driver} provider protocol error: ${this.detail}.`; } } export const ProviderAdapterV2Error = Schema.Union([ ProviderAdapterCapabilitiesError, ProviderAdapterOpenSessionError, ProviderAdapterCloseSessionError, ProviderAdapterResumeThreadError, ProviderAdapterEnsureThreadError, ProviderAdapterReadThreadSnapshotError, ProviderAdapterRollbackThreadError, ProviderAdapterForkThreadError, ProviderAdapterTurnStartError, ProviderAdapterSteerRunUnsupportedError, ProviderAdapterSteerRunError, ProviderAdapterInterruptError, ProviderAdapterRuntimeRequestResponseError, ProviderAdapterEventStreamError, ProviderAdapterProtocolError, ]); export type ProviderAdapterV2Error = typeof ProviderAdapterV2Error.Type; export interface ProviderAdapterV2OpenSessionInput { readonly threadId: ThreadId; readonly providerSessionId: ProviderSessionId; readonly modelSelection: ModelSelection; readonly runtimePolicy: ProviderAdapterV2RuntimePolicy; readonly resumeFromSession?: OrchestrationV2ProviderSession; } export interface ProviderAdapterV2EnsureThreadInput { readonly threadId: ThreadId; readonly modelSelection: ModelSelection; readonly runtimePolicy: ProviderAdapterV2RuntimePolicy; readonly providerSessionId?: ProviderSessionId; readonly existingProviderThread?: OrchestrationV2ProviderThread; } export interface ProviderAdapterV2TurnInput { readonly appThread: OrchestrationV2AppThread; readonly threadId: ThreadId; readonly runId: RunId; readonly runOrdinal: number; readonly providerTurnOrdinal: number; readonly restartContinuationOfRunId?: RunId; readonly attemptId: RunAttemptId; readonly rootNodeId: NodeId; readonly providerThread: OrchestrationV2ProviderThread; readonly message: ProviderAdapterV2TurnMessage; readonly modelSelection: ModelSelection; readonly runtimePolicy: ProviderAdapterV2RuntimePolicy; } export interface ProviderAdapterV2SteerInput { readonly threadId: ThreadId; readonly runId: RunId; readonly providerThread: OrchestrationV2ProviderThread; readonly providerTurnId: ProviderTurnId; readonly message: ProviderAdapterV2TurnMessage; } export interface ProviderAdapterV2InterruptInput { readonly providerThread: OrchestrationV2ProviderThread; readonly providerTurnId: ProviderTurnId; /** When true, the next `startTurn` may respawn the provider runtime (Grok Stop recovery). */ readonly requestRuntimeRestart?: boolean; } export interface ProviderAdapterV2RuntimeRequestResponseInput { readonly requestId: RuntimeRequestId; readonly decision?: ProviderApprovalDecision; readonly answers?: ProviderUserInputAnswers; readonly response?: unknown; } export interface ProviderAdapterV2ThreadSnapshot { readonly providerThread: OrchestrationV2ProviderThread; readonly providerTurns: ReadonlyArray; readonly messages: ReadonlyArray; readonly runtimeRequests: ReadonlyArray; readonly providerPayload?: unknown; } export interface ProviderAdapterV2ReadThreadSnapshotInput { readonly providerThread: OrchestrationV2ProviderThread; } export type ProviderAdapterV2RollbackTarget = | { readonly type: "thread_start"; readonly checkpointId: CheckpointId; readonly appRunOrdinal: 0; } | { readonly type: "provider_turn"; readonly checkpointId: CheckpointId; readonly appRunOrdinal: number; readonly providerTurn: OrchestrationV2ProviderTurn; }; export interface ProviderAdapterV2RollbackThreadInput { readonly providerThread: OrchestrationV2ProviderThread; readonly target: ProviderAdapterV2RollbackTarget; readonly providerThreadTurns: ReadonlyArray; } export interface ProviderAdapterV2ForkThreadInput { readonly sourceProviderThread: OrchestrationV2ProviderThread; readonly sourceProviderTurns?: ReadonlyArray; readonly providerTurnId?: ProviderTurnId; readonly targetThreadId: ThreadId; readonly ownerNodeId?: NodeId; readonly modelSelection?: ModelSelection; readonly runtimePolicy?: ProviderAdapterV2RuntimePolicy; } export interface ProviderAdapterV2EventSubscription { readonly events: Stream.Stream; readonly close: Effect.Effect; } export interface ProviderAdapterV2SessionRuntime { readonly instanceId: ProviderInstanceId; readonly driver: ProviderDriverKind; readonly providerSessionId: ProviderSessionId; readonly providerSession: OrchestrationV2ProviderSession; readonly events: Stream.Stream; /** * Manager-owned runtimes expose a synchronous subscription so concurrent * provider threads receive independent copies of the process event stream. * Adapter runtimes may omit this and expose only their single-consumer event stream. */ readonly subscribeEvents?: Effect.Effect; /** * Adapters whose native runtime can hold pending work outside an active * turn (for example Claude background tasks and their wake turns) report it * here so the session manager defers idle release while it is pending. */ readonly hasPendingBackgroundWork?: Effect.Effect; /** * Per-provider-thread pending work for root-run ingestion stop gates. When * present, RunExecutionService uses only this probe (never the session-wide * hasPendingBackgroundWork) so sibling native threads cannot pin an * unrelated root subscription open. */ readonly hasPendingBackgroundWorkForThread?: ( providerThread: OrchestrationV2ProviderThread, ) => Effect.Effect; readonly ensureThread: ( input: ProviderAdapterV2EnsureThreadInput, ) => Effect.Effect; readonly resumeThread: (input: { readonly providerThread: OrchestrationV2ProviderThread; readonly threadId?: ThreadId; readonly modelSelection?: ModelSelection; readonly runtimePolicy?: ProviderAdapterV2RuntimePolicy; }) => Effect.Effect; readonly startTurn: ( input: ProviderAdapterV2TurnInput, ) => Effect.Effect; readonly compactThread?: ( input: ProviderAdapterV2TurnInput, ) => Effect.Effect; readonly steerTurn: ( input: ProviderAdapterV2SteerInput, ) => Effect.Effect; readonly interruptTurn: ( input: ProviderAdapterV2InterruptInput, ) => Effect.Effect; readonly respondToRuntimeRequest: ( input: ProviderAdapterV2RuntimeRequestResponseInput, ) => Effect.Effect; readonly readThreadSnapshot: ( input: ProviderAdapterV2ReadThreadSnapshotInput, ) => Effect.Effect; /** * Providers that accept product feedback for a thread (#7949, Codex → OpenAI) * expose it here; absent means the driver has no feedback channel. */ readonly uploadFeedback?: (input: { readonly providerThread: OrchestrationV2ProviderThread; readonly reason?: string; }) => Effect.Effect<{ readonly feedbackId: string }, ProviderAdapterV2Error>; readonly rollbackThread: ( input: ProviderAdapterV2RollbackThreadInput, ) => Effect.Effect; readonly forkThread: ( input: ProviderAdapterV2ForkThreadInput, ) => Effect.Effect; } export interface ProviderAdapterV2Shape { readonly instanceId: ProviderInstanceId; readonly driver: ProviderDriverKind; readonly getCapabilities: () => Effect.Effect< OrchestrationV2ProviderCapabilities, ProviderAdapterV2Error >; readonly planSelectionTransition: ( input: ProviderSelectionTransitionInput, ) => Effect.Effect; readonly openSession: ( input: ProviderAdapterV2OpenSessionInput, ) => Effect.Effect; } export class ProviderAdapterV2 extends Context.Service()( "t3/orchestration-v2/ProviderAdapter/ProviderAdapterV2", ) {}