| author | |
| committer | |
| log | d668ffcd64d74daba16520cbbfb0fdb431983eac |
| tree | 7e0fb246a931f311db73f19abca9a905a081b8c8 |
| parent | 3a7058da50c91906158c89fc3f845e6c04379414 |
| signature | Signed by PGP key B5690EEEBB952194 |
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>2 files changed, 34 insertions(+), 0 deletions(-)
apps/server/src/relay/AgentAwarenessRelay.test.ts+24| ... | ... | @@ -659,6 +659,30 @@ describe("AgentAwarenessRelay", () => { |
| 659 | 659 | }), |
| 660 | 660 | ); |
| 661 | 661 | |
| 662 | it.effect.each([ | |
| 663 | { label: "live", archived: false }, | |
| 664 | { label: "archived", archived: true }, | |
| 665 | ])("never publishes tombstones for $label subagent threads", ({ archived }) => | |
| 666 | Effect.gen(function* () { | |
| 667 | const { relay, currentShell, publications } = yield* makeTestRelay(); | |
| 668 | yield* Ref.set( | |
| 669 | currentShell, | |
| 670 | shell({ | |
| 671 | lineage: { | |
| 672 | rootThreadId: THREAD_ID, | |
| 673 | parentThreadId: THREAD_ID, | |
| 674 | relationshipToParent: "subagent", | |
| 675 | }, | |
| 676 | ...(archived ? { archivedAt: yield* DateTime.now } : {}), | |
| 677 | }), | |
| 678 | ); | |
| 679 | yield* relay.publishThread(THREAD_ID); | |
| 680 | yield* TestClock.adjust("5 seconds"); | |
| 681 | yield* relay.drain; | |
| 682 | assert.equal(publications.length, 0); | |
| 683 | }), | |
| 684 | ); | |
| 685 | ||
| 662 | 686 | it.effect("confirms a first completed state and respects disabling during confirmation", () => |
| 663 | 687 | Effect.gen(function* () { |
| 664 | 688 | const { relay, secrets, currentShell, publications } = yield* makeTestRelay(); |
apps/server/src/relay/AgentAwarenessRelay.ts+10| ... | ... | @@ -522,6 +522,16 @@ export const make = Effect.gen(function* () { |
| 522 | 522 | // domain event, so materializing the full shell here would make the cost |
| 523 | 523 | // of one thread's activity proportional to how many threads exist. |
| 524 | 524 | const threadShell = yield* threads.getThreadShell(threadId); |
| 525 | if ( | |
| 526 | threadShell?.lineage.relationshipToParent === "subagent" && | |
| 527 | !(yield* Ref.get(publishedStateByThreadRef)).has(threadId) | |
| 528 | ) { | |
| 529 | // Subagents never project activity, so the relay holds no row to clear. | |
| 530 | // Their events would otherwise publish a tombstone each, and every | |
| 531 | // publish re-delivers the user's aggregate. Checked before the archive | |
| 532 | // filter so archiving one stays quiet too. | |
| 533 | return; | |
| 534 | } | |
| 525 | 535 | const thread = |
| 526 | 536 | threadShell === null || threadShell.archivedAt !== null |
| 527 | 537 | ? Option.none<OrchestrationV2ThreadShell>() |