| ... | ... | @@ -4925,9 +4925,13 @@ describe("AcpAdapterV2", () => { |
| 4925 | 4925 | const mockAgentPath = yield* path.fromFileUrl( |
| 4926 | 4926 | new URL("../../../scripts/acp-mock-agent.ts", import.meta.url), |
| 4927 | 4927 | ); |
| 4928 | | const protocolEvents = yield* Queue.bounded<EffectAcpProtocol.AcpProtocolLogEvent>(256); |
| 4929 | 4928 | const instanceId = ProviderInstanceId.make("acp-test"); |
| 4929 | const promptSettled = yield* Deferred.make<void>(); |
| 4930 | 4930 | const adapter = makeAcpAdapterV2({ |
| 4931 | testHooks: { |
| 4932 | afterPromptSettledWithBackgroundWork: () => |
| 4933 | Deferred.succeed(promptSettled, undefined).pipe(Effect.asVoid), |
| 4934 | }, |
| 4931 | 4935 | crypto: yield* Crypto.Crypto, |
| 4932 | 4936 | instanceId, |
| 4933 | 4937 | flavor: { |
| ... | ... | @@ -4950,7 +4954,6 @@ describe("AcpAdapterV2", () => { |
| 4950 | 4954 | childProcessSpawner, |
| 4951 | 4955 | mockAgentPath, |
| 4952 | 4956 | environment: { T3_ACP_EMIT_GENERIC_TOOL_PLACEHOLDERS: "1" }, |
| 4953 | | protocolEvents, |
| 4954 | 4957 | }), |
| 4955 | 4958 | }, |
| 4956 | 4959 | fileSystem, |
| ... | ... | @@ -4986,28 +4989,13 @@ describe("AcpAdapterV2", () => { |
| 4986 | 4989 | makeTurnInput({ threadId, providerThread, instanceId, runtimePolicy, now }), |
| 4987 | 4990 | ); |
| 4988 | 4991 | // The still-running subagent defers finalize after session/prompt returns. |
| 4989 | | yield* Stream.fromQueue(protocolEvents).pipe( |
| 4990 | | Stream.filter( |
| 4991 | | (event) => |
| 4992 | | event.direction === "incoming" && |
| 4993 | | event.stage === "raw" && |
| 4994 | | typeof event.payload === "string" && |
| 4995 | | event.payload.includes('"stopReason"'), |
| 4996 | | ), |
| 4997 | | Stream.runHead, |
| 4998 | | ); |
| 4999 | | yield* Effect.yieldNow; |
| 5000 | | yield* Effect.yieldNow; |
| 4992 | yield* Deferred.await(promptSettled); |
| 5001 | 4993 | |
| 5002 | 4994 | const providerTurnId = idAllocator.derive.providerTurn({ |
| 5003 | 4995 | driver: ACP_TEST_DRIVER, |
| 5004 | 4996 | nativeTurnId: acpScopedNativeId(instanceId, "mock-session-1:turn:1"), |
| 5005 | 4997 | }); |
| 5006 | | const interruptFiber = yield* runtime |
| 5007 | | .interruptTurn({ providerThread, providerTurnId }) |
| 5008 | | .pipe(Effect.forkScoped); |
| 5009 | | yield* TestClock.adjust("10 seconds"); |
| 5010 | | yield* Fiber.join(interruptFiber); |
| 4998 | yield* runtime.interruptTurn({ providerThread, providerTurnId }); |
| 5011 | 4999 | |
| 5012 | 5000 | let terminalStatus: string | null = null; |
| 5013 | 5001 | while (terminalStatus === null) { |
| ... | ... | @@ -5033,10 +5021,14 @@ describe("AcpAdapterV2", () => { |
| 5033 | 5021 | const mockAgentPath = yield* path.fromFileUrl( |
| 5034 | 5022 | new URL("../../../scripts/acp-mock-agent.ts", import.meta.url), |
| 5035 | 5023 | ); |
| 5036 | | const protocolEvents = yield* Queue.bounded<EffectAcpProtocol.AcpProtocolLogEvent>(256); |
| 5037 | 5024 | const instanceId = ProviderInstanceId.make("acp-test"); |
| 5038 | 5025 | let subagentPhase: "spawn" | "complete" = "spawn"; |
| 5026 | const promptSettled = yield* Deferred.make<void>(); |
| 5039 | 5027 | const adapter = makeAcpAdapterV2({ |
| 5028 | testHooks: { |
| 5029 | afterPromptSettledWithBackgroundWork: () => |
| 5030 | Deferred.succeed(promptSettled, undefined).pipe(Effect.asVoid), |
| 5031 | }, |
| 5040 | 5032 | crypto: yield* Crypto.Crypto, |
| 5041 | 5033 | instanceId, |
| 5042 | 5034 | flavor: { |
| ... | ... | @@ -5072,7 +5064,6 @@ describe("AcpAdapterV2", () => { |
| 5072 | 5064 | childProcessSpawner, |
| 5073 | 5065 | mockAgentPath, |
| 5074 | 5066 | environment: { T3_ACP_EMIT_GENERIC_TOOL_PLACEHOLDERS: "1" }, |
| 5075 | | protocolEvents, |
| 5076 | 5067 | }), |
| 5077 | 5068 | }, |
| 5078 | 5069 | fileSystem, |
| ... | ... | @@ -5107,28 +5098,13 @@ describe("AcpAdapterV2", () => { |
| 5107 | 5098 | yield* runtime.startTurn( |
| 5108 | 5099 | makeTurnInput({ threadId, providerThread, instanceId, runtimePolicy, now }), |
| 5109 | 5100 | ); |
| 5110 | | yield* Stream.fromQueue(protocolEvents).pipe( |
| 5111 | | Stream.filter( |
| 5112 | | (event) => |
| 5113 | | event.direction === "incoming" && |
| 5114 | | event.stage === "raw" && |
| 5115 | | typeof event.payload === "string" && |
| 5116 | | event.payload.includes('"stopReason"'), |
| 5117 | | ), |
| 5118 | | Stream.runHead, |
| 5119 | | ); |
| 5120 | | yield* Effect.yieldNow; |
| 5121 | | yield* Effect.yieldNow; |
| 5101 | yield* Deferred.await(promptSettled); |
| 5122 | 5102 | |
| 5123 | 5103 | const firstProviderTurnId = idAllocator.derive.providerTurn({ |
| 5124 | 5104 | driver: ACP_TEST_DRIVER, |
| 5125 | 5105 | nativeTurnId: acpScopedNativeId(instanceId, "mock-session-1:turn:1"), |
| 5126 | 5106 | }); |
| 5127 | | const interruptFiber = yield* runtime |
| 5128 | | .interruptTurn({ providerThread, providerTurnId: firstProviderTurnId }) |
| 5129 | | .pipe(Effect.forkScoped); |
| 5130 | | yield* TestClock.adjust("10 seconds"); |
| 5131 | | yield* Fiber.join(interruptFiber); |
| 5107 | yield* runtime.interruptTurn({ providerThread, providerTurnId: firstProviderTurnId }); |
| 5132 | 5108 | |
| 5133 | 5109 | let subagentTurnItemId: string | null = null; |
| 5134 | 5110 | let firstTerminalStatus: string | null = null; |
| ... | ... | @@ -5193,10 +5169,14 @@ describe("AcpAdapterV2", () => { |
| 5193 | 5169 | const mockAgentPath = yield* path.fromFileUrl( |
| 5194 | 5170 | new URL("../../../scripts/acp-mock-agent.ts", import.meta.url), |
| 5195 | 5171 | ); |
| 5196 | | const protocolEvents = yield* Queue.bounded<EffectAcpProtocol.AcpProtocolLogEvent>(256); |
| 5197 | 5172 | const instanceId = ProviderInstanceId.make("acp-test"); |
| 5198 | 5173 | let subagentPhase: "spawn" | "complete" = "spawn"; |
| 5174 | const promptSettled = yield* Deferred.make<void>(); |
| 5199 | 5175 | const adapter = makeAcpAdapterV2({ |
| 5176 | testHooks: { |
| 5177 | afterPromptSettledWithBackgroundWork: () => |
| 5178 | Deferred.succeed(promptSettled, undefined).pipe(Effect.asVoid), |
| 5179 | }, |
| 5200 | 5180 | crypto: yield* Crypto.Crypto, |
| 5201 | 5181 | instanceId, |
| 5202 | 5182 | flavor: { |
| ... | ... | @@ -5230,7 +5210,6 @@ describe("AcpAdapterV2", () => { |
| 5230 | 5210 | childProcessSpawner, |
| 5231 | 5211 | mockAgentPath, |
| 5232 | 5212 | environment: { T3_ACP_EMIT_GENERIC_TOOL_PLACEHOLDERS: "1" }, |
| 5233 | | protocolEvents, |
| 5234 | 5213 | }), |
| 5235 | 5214 | }, |
| 5236 | 5215 | fileSystem, |
| ... | ... | @@ -5272,28 +5251,13 @@ describe("AcpAdapterV2", () => { |
| 5272 | 5251 | yield* runtime.startTurn( |
| 5273 | 5252 | makeTurnInput({ threadId, providerThread, instanceId, runtimePolicy, now }), |
| 5274 | 5253 | ); |
| 5275 | | yield* Stream.fromQueue(protocolEvents).pipe( |
| 5276 | | Stream.filter( |
| 5277 | | (event) => |
| 5278 | | event.direction === "incoming" && |
| 5279 | | event.stage === "raw" && |
| 5280 | | typeof event.payload === "string" && |
| 5281 | | event.payload.includes('"stopReason"'), |
| 5282 | | ), |
| 5283 | | Stream.runHead, |
| 5284 | | ); |
| 5285 | | yield* Effect.yieldNow; |
| 5286 | | yield* Effect.yieldNow; |
| 5254 | yield* Deferred.await(promptSettled); |
| 5287 | 5255 | |
| 5288 | 5256 | const firstProviderTurnId = idAllocator.derive.providerTurn({ |
| 5289 | 5257 | driver: ACP_TEST_DRIVER, |
| 5290 | 5258 | nativeTurnId: acpScopedNativeId(instanceId, "mock-session-1:turn:1"), |
| 5291 | 5259 | }); |
| 5292 | | const interruptFiber = yield* runtime |
| 5293 | | .interruptTurn({ providerThread, providerTurnId: firstProviderTurnId }) |
| 5294 | | .pipe(Effect.forkScoped); |
| 5295 | | yield* TestClock.adjust("10 seconds"); |
| 5296 | | yield* Fiber.join(interruptFiber); |
| 5260 | yield* runtime.interruptTurn({ providerThread, providerTurnId: firstProviderTurnId }); |
| 5297 | 5261 | |
| 5298 | 5262 | let firstTerminalStatus: string | null = null; |
| 5299 | 5263 | while (firstTerminalStatus === null) { |
| ... | ... | @@ -5352,7 +5316,6 @@ describe("AcpAdapterV2", () => { |
| 5352 | 5316 | const mockAgentPath = yield* path.fromFileUrl( |
| 5353 | 5317 | new URL("../../../scripts/acp-mock-agent.ts", import.meta.url), |
| 5354 | 5318 | ); |
| 5355 | | const protocolEvents = yield* Queue.bounded<EffectAcpProtocol.AcpProtocolLogEvent>(256); |
| 5356 | 5319 | const secondPromptWireReturned = yield* Deferred.make<void>(); |
| 5357 | 5320 | const releaseSecondPromptCompletion = yield* Deferred.make<void>(); |
| 5358 | 5321 | const instanceId = ProviderInstanceId.make("acp-test"); |
| ... | ... | @@ -5361,7 +5324,12 @@ describe("AcpAdapterV2", () => { |
| 5361 | 5324 | let subagentPhase: "spawn" | "complete" = "spawn"; |
| 5362 | 5325 | type RuntimeService = AcpSessionRuntime.AcpSessionRuntime["Service"]; |
| 5363 | 5326 | let sessionUpdateHandler: Parameters<RuntimeService["handleSessionUpdate"]>[0] | undefined; |
| 5327 | const promptSettled = yield* Deferred.make<void>(); |
| 5364 | 5328 | const adapter = makeAcpAdapterV2({ |
| 5329 | testHooks: { |
| 5330 | afterPromptSettledWithBackgroundWork: () => |
| 5331 | Deferred.succeed(promptSettled, undefined).pipe(Effect.asVoid), |
| 5332 | }, |
| 5365 | 5333 | crypto: yield* Crypto.Crypto, |
| 5366 | 5334 | instanceId, |
| 5367 | 5335 | flavor: { |
| ... | ... | @@ -5395,7 +5363,6 @@ describe("AcpAdapterV2", () => { |
| 5395 | 5363 | childProcessSpawner, |
| 5396 | 5364 | mockAgentPath, |
| 5397 | 5365 | environment: { T3_ACP_EMIT_GENERIC_TOOL_PLACEHOLDERS: "1" }, |
| 5398 | | protocolEvents, |
| 5399 | 5366 | wrapRuntime: (runtime) => ({ |
| 5400 | 5367 | ...runtime, |
| 5401 | 5368 | handleSessionUpdate: (handler) => |
| ... | ... | @@ -5456,28 +5423,13 @@ describe("AcpAdapterV2", () => { |
| 5456 | 5423 | yield* runtime.startTurn( |
| 5457 | 5424 | makeTurnInput({ threadId, providerThread, instanceId, runtimePolicy, now }), |
| 5458 | 5425 | ); |
| 5459 | | yield* Stream.fromQueue(protocolEvents).pipe( |
| 5460 | | Stream.filter( |
| 5461 | | (event) => |
| 5462 | | event.direction === "incoming" && |
| 5463 | | event.stage === "raw" && |
| 5464 | | typeof event.payload === "string" && |
| 5465 | | event.payload.includes('"stopReason"'), |
| 5466 | | ), |
| 5467 | | Stream.runHead, |
| 5468 | | ); |
| 5469 | | yield* Effect.yieldNow; |
| 5470 | | yield* Effect.yieldNow; |
| 5426 | yield* Deferred.await(promptSettled); |
| 5471 | 5427 | |
| 5472 | 5428 | const firstProviderTurnId = idAllocator.derive.providerTurn({ |
| 5473 | 5429 | driver: ACP_TEST_DRIVER, |
| 5474 | 5430 | nativeTurnId: acpScopedNativeId(instanceId, "mock-session-1:turn:1"), |
| 5475 | 5431 | }); |
| 5476 | | const interruptFiber = yield* runtime |
| 5477 | | .interruptTurn({ providerThread, providerTurnId: firstProviderTurnId }) |
| 5478 | | .pipe(Effect.forkScoped); |
| 5479 | | yield* TestClock.adjust("10 seconds"); |
| 5480 | | yield* Fiber.join(interruptFiber); |
| 5432 | yield* runtime.interruptTurn({ providerThread, providerTurnId: firstProviderTurnId }); |
| 5481 | 5433 | |
| 5482 | 5434 | let firstTerminalStatus: string | null = null; |
| 5483 | 5435 | while (firstTerminalStatus === null) { |
| ... | ... | @@ -5601,7 +5553,6 @@ describe("AcpAdapterV2", () => { |
| 5601 | 5553 | const mockAgentPath = yield* path.fromFileUrl( |
| 5602 | 5554 | new URL("../../../scripts/acp-mock-agent.ts", import.meta.url), |
| 5603 | 5555 | ); |
| 5604 | | const protocolEvents = yield* Queue.bounded<EffectAcpProtocol.AcpProtocolLogEvent>(256); |
| 5605 | 5556 | const baseClock = yield* Clock.Clock; |
| 5606 | 5557 | const finalizationClockRead = yield* Deferred.make<void>(); |
| 5607 | 5558 | const releaseFinalizationClockRead = yield* Deferred.make<void>(); |
| ... | ... | @@ -5629,7 +5580,12 @@ describe("AcpAdapterV2", () => { |
| 5629 | 5580 | let sessionUpdateHandler: |
| 5630 | 5581 | | Parameters<RuntimeService["handleSessionUpdate"]>[0] |
| 5631 | 5582 | | undefined; |
| 5583 | const promptSettled = yield* Deferred.make<void>(); |
| 5632 | 5584 | const adapter = makeAcpAdapterV2({ |
| 5585 | testHooks: { |
| 5586 | afterPromptSettledWithBackgroundWork: () => |
| 5587 | Deferred.succeed(promptSettled, undefined).pipe(Effect.asVoid), |
| 5588 | }, |
| 5633 | 5589 | crypto: yield* Crypto.Crypto, |
| 5634 | 5590 | instanceId, |
| 5635 | 5591 | flavor: { |
| ... | ... | @@ -5668,7 +5624,6 @@ describe("AcpAdapterV2", () => { |
| 5668 | 5624 | childProcessSpawner, |
| 5669 | 5625 | mockAgentPath, |
| 5670 | 5626 | environment: { T3_ACP_EMIT_GENERIC_TOOL_PLACEHOLDERS: "1" }, |
| 5671 | | protocolEvents, |
| 5672 | 5627 | wrapRuntime: (runtime) => ({ |
| 5673 | 5628 | ...runtime, |
| 5674 | 5629 | handleSessionUpdate: (handler) => |
| ... | ... | @@ -5719,18 +5674,7 @@ describe("AcpAdapterV2", () => { |
| 5719 | 5674 | yield* runtime.startTurn( |
| 5720 | 5675 | makeTurnInput({ threadId, providerThread, instanceId, runtimePolicy, now }), |
| 5721 | 5676 | ); |
| 5722 | | yield* Stream.fromQueue(protocolEvents).pipe( |
| 5723 | | Stream.filter( |
| 5724 | | (event) => |
| 5725 | | event.direction === "incoming" && |
| 5726 | | event.stage === "raw" && |
| 5727 | | typeof event.payload === "string" && |
| 5728 | | event.payload.includes('"stopReason"'), |
| 5729 | | ), |
| 5730 | | Stream.runHead, |
| 5731 | | ); |
| 5732 | | yield* Effect.yieldNow; |
| 5733 | | yield* Effect.yieldNow; |
| 5677 | yield* Deferred.await(promptSettled); |
| 5734 | 5678 | yield* TestClock.adjust("1 second"); |
| 5735 | 5679 | assert.isDefined(sessionUpdateHandler, "session update handler must be wired"); |
| 5736 | 5680 | |
| ... | ... | @@ -6451,14 +6395,18 @@ describe("AcpAdapterV2", () => { |
| 6451 | 6395 | const mockAgentPath = yield* path.fromFileUrl( |
| 6452 | 6396 | new URL("../../../scripts/acp-mock-agent.ts", import.meta.url), |
| 6453 | 6397 | ); |
| 6454 | | const protocolEvents = yield* Queue.bounded<EffectAcpProtocol.AcpProtocolLogEvent>(256); |
| 6455 | 6398 | const continuationRequests: Array<ProviderContinuationRequest> = []; |
| 6456 | 6399 | const bufferedAssistantText = "BUFFERED_WAKE_AFTER_USER_ATTACH"; |
| 6457 | 6400 | const instanceId = ProviderInstanceId.make("acp-test"); |
| 6458 | 6401 | let subagentPhase: "spawn" | "complete" = "spawn"; |
| 6459 | 6402 | type RuntimeService = AcpSessionRuntime.AcpSessionRuntime["Service"]; |
| 6460 | 6403 | let sessionUpdateHandler: Parameters<RuntimeService["handleSessionUpdate"]>[0] | undefined; |
| 6404 | const promptSettled = yield* Deferred.make<void>(); |
| 6461 | 6405 | const adapter = makeAcpAdapterV2({ |
| 6406 | testHooks: { |
| 6407 | afterPromptSettledWithBackgroundWork: () => |
| 6408 | Deferred.succeed(promptSettled, undefined).pipe(Effect.asVoid), |
| 6409 | }, |
| 6462 | 6410 | crypto: yield* Crypto.Crypto, |
| 6463 | 6411 | instanceId, |
| 6464 | 6412 | flavor: { |
| ... | ... | @@ -6492,7 +6440,6 @@ describe("AcpAdapterV2", () => { |
| 6492 | 6440 | childProcessSpawner, |
| 6493 | 6441 | mockAgentPath, |
| 6494 | 6442 | environment: { T3_ACP_EMIT_GENERIC_TOOL_PLACEHOLDERS: "1" }, |
| 6495 | | protocolEvents, |
| 6496 | 6443 | wrapRuntime: (runtime) => ({ |
| 6497 | 6444 | ...runtime, |
| 6498 | 6445 | handleSessionUpdate: (handler) => |
| ... | ... | @@ -6548,28 +6495,13 @@ describe("AcpAdapterV2", () => { |
| 6548 | 6495 | yield* runtime.startTurn( |
| 6549 | 6496 | makeTurnInput({ threadId, providerThread, instanceId, runtimePolicy, now }), |
| 6550 | 6497 | ); |
| 6551 | | yield* Stream.fromQueue(protocolEvents).pipe( |
| 6552 | | Stream.filter( |
| 6553 | | (event) => |
| 6554 | | event.direction === "incoming" && |
| 6555 | | event.stage === "raw" && |
| 6556 | | typeof event.payload === "string" && |
| 6557 | | event.payload.includes('"stopReason"'), |
| 6558 | | ), |
| 6559 | | Stream.runHead, |
| 6560 | | ); |
| 6561 | | yield* Effect.yieldNow; |
| 6562 | | yield* Effect.yieldNow; |
| 6498 | yield* Deferred.await(promptSettled); |
| 6563 | 6499 | |
| 6564 | 6500 | const firstProviderTurnId = idAllocator.derive.providerTurn({ |
| 6565 | 6501 | driver: ACP_TEST_DRIVER, |
| 6566 | 6502 | nativeTurnId: acpScopedNativeId(instanceId, "mock-session-1:turn:1"), |
| 6567 | 6503 | }); |
| 6568 | | const interruptFiber = yield* runtime |
| 6569 | | .interruptTurn({ providerThread, providerTurnId: firstProviderTurnId }) |
| 6570 | | .pipe(Effect.forkScoped); |
| 6571 | | yield* TestClock.adjust("10 seconds"); |
| 6572 | | yield* Fiber.join(interruptFiber); |
| 6504 | yield* runtime.interruptTurn({ providerThread, providerTurnId: firstProviderTurnId }); |
| 6573 | 6505 | |
| 6574 | 6506 | let firstTerminalStatus: string | null = null; |
| 6575 | 6507 | while (firstTerminalStatus === null) { |
| ... | ... | @@ -6752,14 +6684,18 @@ describe("AcpAdapterV2", () => { |
| 6752 | 6684 | new URL("../../../scripts/acp-mock-agent.ts", import.meta.url), |
| 6753 | 6685 | ); |
| 6754 | 6686 | const continuationRequests: Array<ProviderContinuationRequest> = []; |
| 6755 | | const protocolEvents = yield* Queue.bounded<EffectAcpProtocol.AcpProtocolLogEvent>(256); |
| 6756 | 6687 | const promptWireReturned = yield* Deferred.make<void>(); |
| 6757 | 6688 | const releasePromptCompletion = yield* Deferred.make<void>(); |
| 6758 | 6689 | const instanceId = ProviderInstanceId.make("acp-test"); |
| 6759 | 6690 | let subagentPhase: "spawn" | "complete" = "spawn"; |
| 6760 | 6691 | type RuntimeService = AcpSessionRuntime.AcpSessionRuntime["Service"]; |
| 6761 | 6692 | let sessionUpdateHandler: Parameters<RuntimeService["handleSessionUpdate"]>[0] | undefined; |
| 6693 | const promptSettled = yield* Deferred.make<void>(); |
| 6762 | 6694 | const adapter = makeAcpAdapterV2({ |
| 6695 | testHooks: { |
| 6696 | afterPromptSettledWithBackgroundWork: () => |
| 6697 | Deferred.succeed(promptSettled, undefined).pipe(Effect.asVoid), |
| 6698 | }, |
| 6763 | 6699 | crypto: yield* Crypto.Crypto, |
| 6764 | 6700 | instanceId, |
| 6765 | 6701 | flavor: { |
| ... | ... | @@ -6795,7 +6731,6 @@ describe("AcpAdapterV2", () => { |
| 6795 | 6731 | childProcessSpawner, |
| 6796 | 6732 | mockAgentPath, |
| 6797 | 6733 | environment: { T3_ACP_EMIT_GENERIC_TOOL_PLACEHOLDERS: "1" }, |
| 6798 | | protocolEvents, |
| 6799 | 6734 | wrapRuntime: (runtime) => ({ |
| 6800 | 6735 | ...runtime, |
| 6801 | 6736 | handleSessionUpdate: (handler) => |
| ... | ... | @@ -6875,18 +6810,13 @@ describe("AcpAdapterV2", () => { |
| 6875 | 6810 | }, |
| 6876 | 6811 | }); |
| 6877 | 6812 | yield* Deferred.succeed(releasePromptCompletion, undefined); |
| 6878 | | yield* Effect.yieldNow; |
| 6879 | | yield* Effect.yieldNow; |
| 6813 | yield* Deferred.await(promptSettled); |
| 6880 | 6814 | |
| 6881 | 6815 | const firstProviderTurnId = idAllocator.derive.providerTurn({ |
| 6882 | 6816 | driver: ACP_TEST_DRIVER, |
| 6883 | 6817 | nativeTurnId: acpScopedNativeId(instanceId, "mock-session-1:turn:1"), |
| 6884 | 6818 | }); |
| 6885 | | const interruptFiber = yield* runtime |
| 6886 | | .interruptTurn({ providerThread, providerTurnId: firstProviderTurnId }) |
| 6887 | | .pipe(Effect.forkScoped); |
| 6888 | | yield* TestClock.adjust("10 seconds"); |
| 6889 | | yield* Fiber.join(interruptFiber); |
| 6819 | yield* runtime.interruptTurn({ providerThread, providerTurnId: firstProviderTurnId }); |
| 6890 | 6820 | |
| 6891 | 6821 | let firstTerminalStatus: string | null = null; |
| 6892 | 6822 | while (firstTerminalStatus === null) { |
| ... | ... | @@ -7223,7 +7153,6 @@ describe("AcpAdapterV2", () => { |
| 7223 | 7153 | const mockAgentPath = yield* path.fromFileUrl( |
| 7224 | 7154 | new URL("../../../scripts/acp-mock-agent.ts", import.meta.url), |
| 7225 | 7155 | ); |
| 7226 | | const protocolEvents = yield* Queue.bounded<EffectAcpProtocol.AcpProtocolLogEvent>(256); |
| 7227 | 7156 | const continuationRequests: Array<ProviderContinuationRequest> = []; |
| 7228 | 7157 | const instanceId = ProviderInstanceId.make("acp-test"); |
| 7229 | 7158 | const childSessionId = "mock-child-session-pending-continuation"; |
| ... | ... | @@ -7231,7 +7160,12 @@ describe("AcpAdapterV2", () => { |
| 7231 | 7160 | let subagentPhase: "spawn" | "complete" = "spawn"; |
| 7232 | 7161 | type RuntimeService = AcpSessionRuntime.AcpSessionRuntime["Service"]; |
| 7233 | 7162 | let sessionUpdateHandler: Parameters<RuntimeService["handleSessionUpdate"]>[0] | undefined; |
| 7163 | const promptSettled = yield* Deferred.make<void>(); |
| 7234 | 7164 | const adapter = makeAcpAdapterV2({ |
| 7165 | testHooks: { |
| 7166 | afterPromptSettledWithBackgroundWork: () => |
| 7167 | Deferred.succeed(promptSettled, undefined).pipe(Effect.asVoid), |
| 7168 | }, |
| 7235 | 7169 | crypto: yield* Crypto.Crypto, |
| 7236 | 7170 | instanceId, |
| 7237 | 7171 | flavor: { |
| ... | ... | @@ -7265,7 +7199,6 @@ describe("AcpAdapterV2", () => { |
| 7265 | 7199 | childProcessSpawner, |
| 7266 | 7200 | mockAgentPath, |
| 7267 | 7201 | environment: { T3_ACP_EMIT_GENERIC_TOOL_PLACEHOLDERS: "1" }, |
| 7268 | | protocolEvents, |
| 7269 | 7202 | wrapRuntime: (runtime) => ({ |
| 7270 | 7203 | ...runtime, |
| 7271 | 7204 | handleSessionUpdate: (handler) => |
| ... | ... | @@ -7321,28 +7254,13 @@ describe("AcpAdapterV2", () => { |
| 7321 | 7254 | yield* runtime.startTurn( |
| 7322 | 7255 | makeTurnInput({ threadId, providerThread, instanceId, runtimePolicy, now }), |
| 7323 | 7256 | ); |
| 7324 | | yield* Stream.fromQueue(protocolEvents).pipe( |
| 7325 | | Stream.filter( |
| 7326 | | (event) => |
| 7327 | | event.direction === "incoming" && |
| 7328 | | event.stage === "raw" && |
| 7329 | | typeof event.payload === "string" && |
| 7330 | | event.payload.includes('"stopReason"'), |
| 7331 | | ), |
| 7332 | | Stream.runHead, |
| 7333 | | ); |
| 7334 | | yield* Effect.yieldNow; |
| 7335 | | yield* Effect.yieldNow; |
| 7257 | yield* Deferred.await(promptSettled); |
| 7336 | 7258 | |
| 7337 | 7259 | const firstProviderTurnId = idAllocator.derive.providerTurn({ |
| 7338 | 7260 | driver: ACP_TEST_DRIVER, |
| 7339 | 7261 | nativeTurnId: acpScopedNativeId(instanceId, "mock-session-1:turn:1"), |
| 7340 | 7262 | }); |
| 7341 | | const interruptFiber = yield* runtime |
| 7342 | | .interruptTurn({ providerThread, providerTurnId: firstProviderTurnId }) |
| 7343 | | .pipe(Effect.forkScoped); |
| 7344 | | yield* TestClock.adjust("10 seconds"); |
| 7345 | | yield* Fiber.join(interruptFiber); |
| 7263 | yield* runtime.interruptTurn({ providerThread, providerTurnId: firstProviderTurnId }); |
| 7346 | 7264 | |
| 7347 | 7265 | let firstTerminalStatus: string | null = null; |
| 7348 | 7266 | while (firstTerminalStatus === null) { |
| ... | ... | @@ -7506,14 +7424,18 @@ describe("AcpAdapterV2", () => { |
| 7506 | 7424 | const mockAgentPath = yield* path.fromFileUrl( |
| 7507 | 7425 | new URL("../../../scripts/acp-mock-agent.ts", import.meta.url), |
| 7508 | 7426 | ); |
| 7509 | | const protocolEvents = yield* Queue.bounded<EffectAcpProtocol.AcpProtocolLogEvent>(256); |
| 7510 | 7427 | const continuationRequests: Array<ProviderContinuationRequest> = []; |
| 7511 | 7428 | const instanceId = ProviderInstanceId.make("acp-test"); |
| 7512 | 7429 | const childSessionId = "mock-child-session-root-then-child"; |
| 7513 | 7430 | let subagentPhase: "spawn" | "complete" = "spawn"; |
| 7514 | 7431 | type RuntimeService = AcpSessionRuntime.AcpSessionRuntime["Service"]; |
| 7515 | 7432 | let sessionUpdateHandler: Parameters<RuntimeService["handleSessionUpdate"]>[0] | undefined; |
| 7433 | const promptSettled = yield* Deferred.make<void>(); |
| 7516 | 7434 | const adapter = makeAcpAdapterV2({ |
| 7435 | testHooks: { |
| 7436 | afterPromptSettledWithBackgroundWork: () => |
| 7437 | Deferred.succeed(promptSettled, undefined).pipe(Effect.asVoid), |
| 7438 | }, |
| 7517 | 7439 | crypto: yield* Crypto.Crypto, |
| 7518 | 7440 | instanceId, |
| 7519 | 7441 | flavor: { |
| ... | ... | @@ -7547,7 +7469,6 @@ describe("AcpAdapterV2", () => { |
| 7547 | 7469 | childProcessSpawner, |
| 7548 | 7470 | mockAgentPath, |
| 7549 | 7471 | environment: { T3_ACP_EMIT_GENERIC_TOOL_PLACEHOLDERS: "1" }, |
| 7550 | | protocolEvents, |
| 7551 | 7472 | wrapRuntime: (runtime) => ({ |
| 7552 | 7473 | ...runtime, |
| 7553 | 7474 | handleSessionUpdate: (handler) => |
| ... | ... | @@ -7603,28 +7524,13 @@ describe("AcpAdapterV2", () => { |
| 7603 | 7524 | yield* runtime.startTurn( |
| 7604 | 7525 | makeTurnInput({ threadId, providerThread, instanceId, runtimePolicy, now }), |
| 7605 | 7526 | ); |
| 7606 | | yield* Stream.fromQueue(protocolEvents).pipe( |
| 7607 | | Stream.filter( |
| 7608 | | (event) => |
| 7609 | | event.direction === "incoming" && |
| 7610 | | event.stage === "raw" && |
| 7611 | | typeof event.payload === "string" && |
| 7612 | | event.payload.includes('"stopReason"'), |
| 7613 | | ), |
| 7614 | | Stream.runHead, |
| 7615 | | ); |
| 7616 | | yield* Effect.yieldNow; |
| 7617 | | yield* Effect.yieldNow; |
| 7527 | yield* Deferred.await(promptSettled); |
| 7618 | 7528 | |
| 7619 | 7529 | const firstProviderTurnId = idAllocator.derive.providerTurn({ |
| 7620 | 7530 | driver: ACP_TEST_DRIVER, |
| 7621 | 7531 | nativeTurnId: acpScopedNativeId(instanceId, "mock-session-1:turn:1"), |
| 7622 | 7532 | }); |
| 7623 | | const interruptFiber = yield* runtime |
| 7624 | | .interruptTurn({ providerThread, providerTurnId: firstProviderTurnId }) |
| 7625 | | .pipe(Effect.forkScoped); |
| 7626 | | yield* TestClock.adjust("10 seconds"); |
| 7627 | | yield* Fiber.join(interruptFiber); |
| 7533 | yield* runtime.interruptTurn({ providerThread, providerTurnId: firstProviderTurnId }); |
| 7628 | 7534 | |
| 7629 | 7535 | let firstTerminalStatus: string | null = null; |
| 7630 | 7536 | while (firstTerminalStatus === null) { |
| ... | ... | @@ -7760,12 +7666,16 @@ describe("AcpAdapterV2", () => { |
| 7760 | 7666 | const mockAgentPath = yield* path.fromFileUrl( |
| 7761 | 7667 | new URL("../../../scripts/acp-mock-agent.ts", import.meta.url), |
| 7762 | 7668 | ); |
| 7763 | | const protocolEvents = yield* Queue.bounded<EffectAcpProtocol.AcpProtocolLogEvent>(256); |
| 7764 | 7669 | const instanceId = ProviderInstanceId.make("acp-test"); |
| 7765 | 7670 | let subagentPhase: "spawn" | "complete" = "spawn"; |
| 7766 | 7671 | let cancelCalled = false; |
| 7767 | 7672 | let runtimeOrdinalSeen = 0; |
| 7673 | const promptSettled = yield* Deferred.make<void>(); |
| 7768 | 7674 | const adapter = makeAcpAdapterV2({ |
| 7675 | testHooks: { |
| 7676 | afterPromptSettledWithBackgroundWork: () => |
| 7677 | Deferred.succeed(promptSettled, undefined).pipe(Effect.asVoid), |
| 7678 | }, |
| 7769 | 7679 | crypto: yield* Crypto.Crypto, |
| 7770 | 7680 | instanceId, |
| 7771 | 7681 | flavor: { |
| ... | ... | @@ -7812,7 +7722,6 @@ describe("AcpAdapterV2", () => { |
| 7812 | 7722 | runtimeOrdinalSeen = Math.max(runtimeOrdinalSeen, runtimeOrdinal); |
| 7813 | 7723 | return { T3_ACP_EMIT_GENERIC_TOOL_PLACEHOLDERS: "1" }; |
| 7814 | 7724 | }, |
| 7815 | | protocolEvents, |
| 7816 | 7725 | wrapCancel: (cancel) => |
| 7817 | 7726 | Effect.sync(() => { |
| 7818 | 7727 | cancelCalled = true; |
| ... | ... | @@ -7853,28 +7762,13 @@ describe("AcpAdapterV2", () => { |
| 7853 | 7762 | ); |
| 7854 | 7763 | // The still-running subagent defers finalize after session/prompt returns, |
| 7855 | 7764 | // so the interrupt below hits a settled turn held open for background work. |
| 7856 | | yield* Stream.fromQueue(protocolEvents).pipe( |
| 7857 | | Stream.filter( |
| 7858 | | (event) => |
| 7859 | | event.direction === "incoming" && |
| 7860 | | event.stage === "raw" && |
| 7861 | | typeof event.payload === "string" && |
| 7862 | | event.payload.includes('"stopReason"'), |
| 7863 | | ), |
| 7864 | | Stream.runHead, |
| 7865 | | ); |
| 7866 | | yield* Effect.yieldNow; |
| 7867 | | yield* Effect.yieldNow; |
| 7765 | yield* Deferred.await(promptSettled); |
| 7868 | 7766 | |
| 7869 | 7767 | const firstProviderTurnId = idAllocator.derive.providerTurn({ |
| 7870 | 7768 | driver: ACP_TEST_DRIVER, |
| 7871 | 7769 | nativeTurnId: acpScopedNativeId(instanceId, "mock-session-1:turn:1"), |
| 7872 | 7770 | }); |
| 7873 | | const interruptFiber = yield* runtime |
| 7874 | | .interruptTurn({ providerThread, providerTurnId: firstProviderTurnId }) |
| 7875 | | .pipe(Effect.forkScoped); |
| 7876 | | yield* TestClock.adjust("10 seconds"); |
| 7877 | | yield* Fiber.join(interruptFiber); |
| 7771 | yield* runtime.interruptTurn({ providerThread, providerTurnId: firstProviderTurnId }); |
| 7878 | 7772 | assert.isFalse( |
| 7879 | 7773 | cancelCalled, |
| 7880 | 7774 | "settled soft steer must not send session/cancel (the real Grok CLI kills background subagents on cancel)", |
| ... | ... | @@ -13725,10 +13619,14 @@ describe("AcpAdapterV2", () => { |
| 13725 | 13619 | const mockAgentPath = yield* path.fromFileUrl( |
| 13726 | 13620 | new URL("../../../scripts/acp-mock-agent.ts", import.meta.url), |
| 13727 | 13621 | ); |
| 13728 | | const protocolEvents = yield* Queue.bounded<EffectAcpProtocol.AcpProtocolLogEvent>(256); |
| 13729 | 13622 | const instanceId = ProviderInstanceId.make("acp-test"); |
| 13730 | 13623 | let subagentPhase: "spawn" | "complete" = "spawn"; |
| 13624 | const promptSettled = yield* Deferred.make<void>(); |
| 13731 | 13625 | const adapter = makeAcpAdapterV2({ |
| 13626 | testHooks: { |
| 13627 | afterPromptSettledWithBackgroundWork: () => |
| 13628 | Deferred.succeed(promptSettled, undefined).pipe(Effect.asVoid), |
| 13629 | }, |
| 13732 | 13630 | crypto: yield* Crypto.Crypto, |
| 13733 | 13631 | instanceId, |
| 13734 | 13632 | flavor: { |
| ... | ... | @@ -13762,7 +13660,6 @@ describe("AcpAdapterV2", () => { |
| 13762 | 13660 | childProcessSpawner, |
| 13763 | 13661 | mockAgentPath, |
| 13764 | 13662 | environment: { T3_ACP_EMIT_GENERIC_TOOL_PLACEHOLDERS: "1" }, |
| 13765 | | protocolEvents, |
| 13766 | 13663 | }), |
| 13767 | 13664 | }, |
| 13768 | 13665 | fileSystem, |
| ... | ... | @@ -13799,32 +13696,17 @@ describe("AcpAdapterV2", () => { |
| 13799 | 13696 | yield* runtime.startTurn( |
| 13800 | 13697 | makeTurnInput({ threadId, providerThread, instanceId, runtimePolicy, now }), |
| 13801 | 13698 | ); |
| 13802 | | yield* Stream.fromQueue(protocolEvents).pipe( |
| 13803 | | Stream.filter( |
| 13804 | | (event) => |
| 13805 | | event.direction === "incoming" && |
| 13806 | | event.stage === "raw" && |
| 13807 | | typeof event.payload === "string" && |
| 13808 | | event.payload.includes('"stopReason"'), |
| 13809 | | ), |
| 13810 | | Stream.runHead, |
| 13811 | | ); |
| 13812 | | yield* Effect.yieldNow; |
| 13813 | | yield* Effect.yieldNow; |
| 13699 | yield* Deferred.await(promptSettled); |
| 13814 | 13700 | |
| 13815 | 13701 | const firstProviderTurnId = idAllocator.derive.providerTurn({ |
| 13816 | 13702 | driver: ACP_TEST_DRIVER, |
| 13817 | 13703 | nativeTurnId: acpScopedNativeId(instanceId, "mock-session-1:turn:1"), |
| 13818 | 13704 | }); |
| 13819 | | const interruptFiber = yield* runtime |
| 13820 | | .interruptTurn({ |
| 13821 | | providerThread, |
| 13822 | | providerTurnId: firstProviderTurnId, |
| 13823 | | requestRuntimeRestart: true, |
| 13824 | | }) |
| 13825 | | .pipe(Effect.forkScoped); |
| 13826 | | yield* TestClock.adjust("10 seconds"); |
| 13827 | | yield* Fiber.join(interruptFiber); |
| 13705 | yield* runtime.interruptTurn({ |
| 13706 | providerThread, |
| 13707 | providerTurnId: firstProviderTurnId, |
| 13708 | requestRuntimeRestart: true, |
| 13709 | }); |
| 13828 | 13710 | |
| 13829 | 13711 | let subagentStatus: string | null = null; |
| 13830 | 13712 | let firstTerminalStatus: string | null = null; |