| 1 | import type { OrchestrationV2HistoricalMessage } from "@t3tools/contracts"; |
| 2 | import { |
| 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"; |
| 36 | import * as Context from "effect/Context"; |
| 37 | import * as Schema from "effect/Schema"; |
| 38 | import type * as Effect from "effect/Effect"; |
| 39 | import type * as Scope from "effect/Scope"; |
| 40 | import type * as Stream from "effect/Stream"; |
| 41 | |
| 42 | import type { |
| 43 | ProviderSelectionTransitionInput, |
| 44 | ProviderSelectionTransitionPlan, |
| 45 | } from "./selectionTransition.ts"; |
| 46 | |
| 47 | export 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 | }); |
| 55 | export type ProviderAdapterV2RuntimePolicy = typeof ProviderAdapterV2RuntimePolicy.Type; |
| 56 | |
| 57 | export 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 | }); |
| 66 | export type ProviderAdapterV2TurnMessage = typeof ProviderAdapterV2TurnMessage.Type; |
| 67 | |
| 68 | export const ProviderAdapterV2SessionStatus = Schema.Literals([ |
| 69 | "starting", |
| 70 | "ready", |
| 71 | "running", |
| 72 | "waiting", |
| 73 | "stopped", |
| 74 | "error", |
| 75 | ]); |
| 76 | export type ProviderAdapterV2SessionStatus = typeof ProviderAdapterV2SessionStatus.Type; |
| 77 | |
| 78 | export 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 | ]); |
| 162 | export type ProviderAdapterV2Event = typeof ProviderAdapterV2Event.Type; |
| 163 | |
| 164 | export 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 | |
| 176 | export 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 | |
| 189 | export 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 | |
| 202 | export 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 | |
| 216 | export 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 | |
| 229 | export 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 | |
| 242 | export 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 | |
| 256 | export 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 | |
| 269 | export 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 | |
| 284 | export 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 | |
| 296 | export 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 | |
| 310 | export 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 | |
| 324 | export 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 | |
| 337 | export 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 | |
| 350 | export 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 | |
| 364 | export 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 | ]); |
| 381 | export type ProviderAdapterV2Error = typeof ProviderAdapterV2Error.Type; |
| 382 | |
| 383 | export 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 | |
| 395 | export 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 | |
| 405 | export 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 | |
| 428 | export interface ProviderAdapterV2SteerInput { |
| 429 | readonly threadId: ThreadId; |
| 430 | readonly runId: RunId; |
| 431 | readonly providerThread: OrchestrationV2ProviderThread; |
| 432 | readonly providerTurnId: ProviderTurnId; |
| 433 | readonly message: ProviderAdapterV2TurnMessage; |
| 434 | } |
| 435 | |
| 436 | export 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 | |
| 443 | export interface ProviderAdapterV2RuntimeRequestResponseInput { |
| 444 | readonly requestId: RuntimeRequestId; |
| 445 | readonly decision?: ProviderApprovalDecision; |
| 446 | readonly answers?: ProviderUserInputAnswers; |
| 447 | readonly response?: unknown; |
| 448 | } |
| 449 | |
| 450 | export 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 | |
| 458 | export interface ProviderAdapterV2ReadThreadSnapshotInput { |
| 459 | readonly providerThread: OrchestrationV2ProviderThread; |
| 460 | } |
| 461 | |
| 462 | export 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 | |
| 475 | export interface ProviderAdapterV2RollbackThreadInput { |
| 476 | readonly providerThread: OrchestrationV2ProviderThread; |
| 477 | readonly target: ProviderAdapterV2RollbackTarget; |
| 478 | readonly providerThreadTurns: ReadonlyArray<OrchestrationV2ProviderTurn>; |
| 479 | } |
| 480 | |
| 481 | export 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 | |
| 491 | export interface ProviderAdapterV2EventSubscription { |
| 492 | readonly events: Stream.Stream<ProviderAdapterV2Event, ProviderAdapterV2Error>; |
| 493 | readonly close: Effect.Effect<void>; |
| 494 | } |
| 495 | |
| 496 | export 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. */ |
| 502 | export interface ProviderAdapterV2McpTool { |
| 503 | readonly name: string; |
| 504 | readonly _meta?: unknown; |
| 505 | readonly annotations?: unknown; |
| 506 | } |
| 507 | |
| 508 | /** MCP `CallToolResult` / `ReadResourceResult` shapes, passed through unchanged. */ |
| 509 | export interface ProviderAdapterV2McpCallToolResult { |
| 510 | readonly content: ReadonlyArray<unknown>; |
| 511 | readonly structuredContent?: unknown; |
| 512 | readonly isError?: boolean; |
| 513 | readonly _meta?: unknown; |
| 514 | } |
| 515 | |
| 516 | export 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. */ |
| 535 | export type ProviderAdapterV2SubagentOutcome = { |
| 536 | readonly status: "completed" | "failed" | "cancelled"; |
| 537 | readonly completedAt: NonNullable<OrchestrationV2Subagent["completedAt"]>; |
| 538 | readonly result: OrchestrationV2Subagent["result"]; |
| 539 | }; |
| 540 | |
| 541 | export 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 | |
| 663 | export 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") {} |