| ... | ... | @@ -513,6 +513,67 @@ function startLifecycleRuntime() { |
| 513 | 513 | } |
| 514 | 514 | |
| 515 | 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 | 577 | it.effect("maps completed agent message items to canonical item.completed events", () => |
| 517 | 578 | Effect.gen(function* () { |
| 518 | 579 | const { adapter, runtime } = yield* startLifecycleRuntime(); |