Unified · Split
| @@ -180,6 +180,7 @@ function makeDeterministicAdapter(input: { · 179 unmodified lines | |||
| 180 | readonly capabilities: OrchestrationV2ProviderCapabilities; | 180 | readonly capabilities: OrchestrationV2ProviderCapabilities; |
| 181 | readonly capturedTurns: Ref.Ref<ReadonlyArray<CapturedTurn>>; | 181 | readonly capturedTurns: Ref.Ref<ReadonlyArray<CapturedTurn>>; |
| 182 | readonly shouldComplete: (turn: ProviderAdapterV2TurnInput) => boolean; | 182 | readonly shouldComplete: (turn: ProviderAdapterV2TurnInput) => boolean; |
| 183 | readonly startedGate?: (turn: ProviderAdapterV2TurnInput) => Deferred.Deferred<void> | undefined; | ||
| 183 | readonly terminalGate?: (turn: ProviderAdapterV2TurnInput) => Deferred.Deferred<void> | undefined; | 184 | readonly terminalGate?: (turn: ProviderAdapterV2TurnInput) => Deferred.Deferred<void> | undefined; |
| 184 | readonly response: (turn: ProviderAdapterV2TurnInput) => string; | 185 | readonly response: (turn: ProviderAdapterV2TurnInput) => string; |
| 185 | }): ProviderAdapterV2Shape { | 186 | }): ProviderAdapterV2Shape { |
| @@ -282,6 +283,10 @@ function makeDeterministicAdapter(input: { · 96 unmodified lines | |||
| 282 | }, | 283 | }, |
| 283 | }, | 284 | }, |
| 284 | ]); | 285 | ]); |
| 286 | const startedGate = input.startedGate?.(turnInput); | ||
| 287 | if (startedGate !== undefined) { | ||
| 288 | yield* Deferred.succeed(startedGate, undefined); | ||
| 289 | } | ||
| 285 | const terminalGate = input.terminalGate?.(turnInput); | 290 | const terminalGate = input.terminalGate?.(turnInput); |
| 286 | if (terminalGate !== undefined) { | 291 | if (terminalGate !== undefined) { |
| 287 | yield* Deferred.await(terminalGate); | 292 | yield* Deferred.await(terminalGate); |
| @@ -477,6 +482,7 @@ describe("orchestrator MCP toolkit", () => { · 189 unmodified lines | |||
| 477 | Effect.gen(function* () { | 482 | Effect.gen(function* () { |
| 478 | const cwd = yield* checkpointWorkspace("orchestrator-mcp-toolkit"); | 483 | const cwd = yield* checkpointWorkspace("orchestrator-mcp-toolkit"); |
| 479 | const capturedTurns = yield* Ref.make<ReadonlyArray<CapturedTurn>>([]); | 484 | const capturedTurns = yield* Ref.make<ReadonlyArray<CapturedTurn>>([]); |
| 485 | const providerStartGates = new Map<string, Deferred.Deferred<void>>(); | ||
| 480 | const parentTerminalGates = new Map<ThreadId, Deferred.Deferred<void>>(); | 486 | const parentTerminalGates = new Map<ThreadId, Deferred.Deferred<void>>(); |
| 481 | const deliveryTerminalGates = new Map<ThreadId, Deferred.Deferred<void>>(); | 487 | const deliveryTerminalGates = new Map<ThreadId, Deferred.Deferred<void>>(); |
| 482 | const registryLayer = makeProviderAdapterRegistryLayer([ | 488 | const registryLayer = makeProviderAdapterRegistryLayer([ |
| @@ -487,6 +493,7 @@ describe("orchestrator MCP toolkit", () => { · 4 unmodified lines | |||
| 487 | capturedTurns, | 493 | capturedTurns, |
| 488 | shouldComplete: (turn) => | 494 | shouldComplete: (turn) => |
| 489 | turn.threadId !== parentThreadId && turn.message.text !== cancellationPrompt, | 495 | turn.threadId !== parentThreadId && turn.message.text !== cancellationPrompt, |
| 496 | startedGate: (turn) => providerStartGates.get(turn.message.text), | ||
| 490 | terminalGate: (turn) => | 497 | terminalGate: (turn) => |
| 491 | turn.message.text.startsWith("Delegated task") || | 498 | turn.message.text.startsWith("Delegated task") || |
| 492 | turn.message.text.startsWith("Delegated tasks") | 499 | turn.message.text.startsWith("Delegated tasks") |
| @@ -2236,6 +2243,8 @@ describe("orchestrator MCP toolkit", () => { · 1743 unmodified lines | |||
| 2236 | state: { archivedAt: null }, | 2243 | state: { archivedAt: null }, |
| 2237 | }); | 2244 | }); |
| 2238 | 2245 | ||
| 2246 | const blockedThreadStarted = yield* Deferred.make<void>(); | ||
| 2247 | providerStartGates.set(cancellationPrompt, blockedThreadStarted); | ||
| 2239 | const blockedThreadCall = yield* invoke("create_threads", { | 2248 | const blockedThreadCall = yield* invoke("create_threads", { |
| 2240 | threads: [{ prompt: cancellationPrompt, title: "Organization blockers" }], | 2249 | threads: [{ prompt: cancellationPrompt, title: "Organization blockers" }], |
| 2241 | clientRequestId: "organize-blockers-create", | 2250 | clientRequestId: "organize-blockers-create", |
| @@ -2243,9 +2252,8 @@ describe("orchestrator MCP toolkit", () => { · 1 unmodified line | |||
| 2243 | const blockedThread = (yield* decodeCreateThreadsResult( | 2252 | const blockedThread = (yield* decodeCreateThreadsResult( |
| 2244 | blockedThreadCall.structuredContent, | 2253 | blockedThreadCall.structuredContent, |
| 2245 | ).pipe(Effect.orDie)).threads[0]!; | 2254 | ).pipe(Effect.orDie)).threads[0]!; |
| 2246 | yield* waitForProjection(orchestrator, blockedThread.threadId, (projection) => | 2255 | yield* Deferred.await(blockedThreadStarted); |
| 2247 | projection.runs.some((run) => run.status === "running"), | 2256 | providerStartGates.delete(cancellationPrompt); |
| 2248 | ); | ||
| 2249 | yield* invoke("t3_thread_send", { | 2257 | yield* invoke("t3_thread_send", { |
| 2250 | threadId: blockedThread.threadId, | 2258 | threadId: blockedThread.threadId, |
| 2251 | message: "Queue this behind the active run.", | 2259 | message: "Queue this behind the active run.", |