| ... | ... | @@ -304,6 +304,64 @@ describe("ProviderCommandReactor", () => { |
| 304 | 304 | expect(thread?.session?.sandboxMode).toBe("workspace-write"); |
| 305 | 305 | }); |
| 306 | 306 | |
| 307 | it("does not stop the active session when restart fails before rebind", async () => { |
| 308 | const harness = await createHarness(); |
| 309 | const now = new Date().toISOString(); |
| 310 | |
| 311 | await Effect.runPromise( |
| 312 | harness.engine.dispatch({ |
| 313 | type: "thread.turn.start", |
| 314 | commandId: CommandId.makeUnsafe("cmd-turn-start-restart-failure-1"), |
| 315 | threadId: ThreadId.makeUnsafe("thread-1"), |
| 316 | message: { |
| 317 | messageId: asMessageId("user-message-restart-failure-1"), |
| 318 | role: "user", |
| 319 | text: "first", |
| 320 | attachments: [], |
| 321 | }, |
| 322 | approvalPolicy: "never", |
| 323 | sandboxMode: "danger-full-access", |
| 324 | createdAt: now, |
| 325 | }), |
| 326 | ); |
| 327 | |
| 328 | await waitFor(() => harness.startSession.mock.calls.length === 1); |
| 329 | await waitFor(() => harness.sendTurn.mock.calls.length === 1); |
| 330 | |
| 331 | harness.startSession.mockImplementationOnce((_: unknown, __: unknown) => |
| 332 | Effect.fail(new Error("simulated restart failure")) as never, |
| 333 | ); |
| 334 | |
| 335 | await Effect.runPromise( |
| 336 | harness.engine.dispatch({ |
| 337 | type: "thread.turn.start", |
| 338 | commandId: CommandId.makeUnsafe("cmd-turn-start-restart-failure-2"), |
| 339 | threadId: ThreadId.makeUnsafe("thread-1"), |
| 340 | message: { |
| 341 | messageId: asMessageId("user-message-restart-failure-2"), |
| 342 | role: "user", |
| 343 | text: "second", |
| 344 | attachments: [], |
| 345 | }, |
| 346 | approvalPolicy: "on-request", |
| 347 | sandboxMode: "workspace-write", |
| 348 | createdAt: now, |
| 349 | }), |
| 350 | ); |
| 351 | |
| 352 | await waitFor(() => harness.startSession.mock.calls.length === 2); |
| 353 | await Effect.runPromise(Effect.sleep("30 millis")); |
| 354 | |
| 355 | expect(harness.stopSession.mock.calls.length).toBe(0); |
| 356 | expect(harness.sendTurn.mock.calls.length).toBe(1); |
| 357 | |
| 358 | const readModel = await Effect.runPromise(harness.engine.getReadModel()); |
| 359 | const thread = readModel.threads.find((entry) => entry.id === ThreadId.makeUnsafe("thread-1")); |
| 360 | expect(thread?.session?.providerSessionId).toBe("sess-1"); |
| 361 | expect(thread?.session?.approvalPolicy).toBe("never"); |
| 362 | expect(thread?.session?.sandboxMode).toBe("danger-full-access"); |
| 363 | }); |
| 364 | |
| 307 | 365 | it("reacts to thread.turn.interrupt-requested by calling provider interrupt", async () => { |
| 308 | 366 | const harness = await createHarness(); |
| 309 | 367 | const now = new Date().toISOString(); |