| ... | @@ -513,6 +513,67 @@ function startLifecycleRuntime() { | ... | @@ -513,6 +513,67 @@ function startLifecycleRuntime() { |
| 513 | } | 513 | } |
| 514 | | 514 | |
| 515 | lifecycleLayer("CodexAdapterLive lifecycle", (it) => { | 515 | lifecycleLayer("CodexAdapterLive lifecycle", (it) => { |
| | 516 | it.effect("does not reactivate an idle child after a parent interaction", () => |
| | 517 | Effect.gen(function* () { |
| | 518 | const { adapter, runtime } = yield* startLifecycleRuntime(); |
| | 519 | const eventsFiber = yield* Stream.runCollect(Stream.take(adapter.streamEvents, 3)).pipe( |
| | 520 | Effect.forkChild, |
| | 521 | ); |
| | 522 | |
| | 523 | const childEvent = (id: string, method: string, payload: Record<string, unknown>) => ({ |
| | 524 | id: asEventId(id), |
| | 525 | kind: "notification" as const, |
| | 526 | provider: ProviderDriverKind.make("codex"), |
| | 527 | createdAt: "2026-01-01T00:00:00.000Z", |
| | 528 | method, |
| | 529 | threadId: asThreadId("thread-1"), |
| | 530 | turnId: asTurnId("turn-1"), |
| | 531 | payload, |
| | 532 | }); |
| | 533 | |
| | 534 | yield* runtime.emit( |
| | 535 | childEvent("evt-child-running", "collabAgent/turnStarted", { |
| | 536 | agentThreadId: "child-1", |
| | 537 | agentPath: "/root/audit", |
| | 538 | }), |
| | 539 | ); |
| | 540 | yield* runtime.emit( |
| | 541 | childEvent("evt-child-idle", "collabAgent/turnCompleted", { |
| | 542 | agentThreadId: "child-1", |
| | 543 | agentPath: "/root/audit", |
| | 544 | turn: { status: "completed" }, |
| | 545 | }), |
| | 546 | ); |
| | 547 | yield* runtime.emit( |
| | 548 | childEvent("evt-child-interacted", "collabAgent/activity", { |
| | 549 | agentThreadId: "child-1", |
| | 550 | agentPath: "/root/audit", |
| | 551 | activityKind: "interacted", |
| | 552 | }), |
| | 553 | ); |
| | 554 | yield* runtime.emit( |
| | 555 | childEvent("evt-other-child-running", "collabAgent/turnStarted", { |
| | 556 | agentThreadId: "child-2", |
| | 557 | agentPath: "/root/other", |
| | 558 | }), |
| | 559 | ); |
| | 560 | |
| | 561 | const events = Array.from(yield* Fiber.join(eventsFiber)); |
| | 562 | NodeAssert.deepStrictEqual( |
| | 563 | events.map((event) => |
| | 564 | event.type === "task.updated" |
| | 565 | ? { taskId: event.payload.taskId, status: event.payload.status } |
| | 566 | : { type: event.type }, |
| | 567 | ), |
| | 568 | [ |
| | 569 | { taskId: "child-1", status: "running" }, |
| | 570 | { taskId: "child-1", status: "idle" }, |
| | 571 | { taskId: "child-2", status: "running" }, |
| | 572 | ], |
| | 573 | ); |
| | 574 | }), |
| | 575 | ); |
| | 576 | |
| 516 | it.effect("maps completed agent message items to canonical item.completed events", () => | 577 | it.effect("maps completed agent message items to canonical item.completed events", () => |
| 517 | Effect.gen(function* () { | 578 | Effect.gen(function* () { |
| 518 | const { adapter, runtime } = yield* startLifecycleRuntime(); | 579 | const { adapter, runtime } = yield* startLifecycleRuntime(); |