






















@@ -1,5 +1,9 @@
11import { afterEach, describe, expect, it, vi } from "vitest";
2-import { enqueueAnnounce, resetAnnounceQueuesForTests } from "./subagent-announce-queue.js";
2+import {
3+type AnnounceQueueItem,
4+enqueueAnnounce,
5+resetAnnounceQueuesForTests,
6+} from "./subagent-announce-queue.js";
3748function createRetryingSend() {
59const prompts: string[] = [];
@@ -118,6 +122,131 @@ describe("subagent-announce-queue", () => {
118122expect(sender.prompts[1]).toContain("queued item two");
119123});
120124125+it("waits until a busy parent session becomes idle before draining", async () => {
126+vi.useFakeTimers();
127+vi.setSystemTime(new Date("2026-01-01T00:00:00.000Z"));
128+129+let parentBusy = true;
130+const send = vi.fn(async (_item: AnnounceQueueItem) => {});
131+132+enqueueAnnounce({
133+key: "announce:test:busy-parent",
134+item: {
135+prompt: "child completed",
136+enqueuedAt: Date.now(),
137+sessionKey: "agent:main:telegram:dm:u1",
138+},
139+settings: { mode: "followup", debounceMs: 0 },
140+ send,
141+shouldDefer: () => parentBusy,
142+});
143+144+await vi.advanceTimersByTimeAsync(249);
145+expect(send).not.toHaveBeenCalled();
146+147+await vi.advanceTimersByTimeAsync(1);
148+expect(send).not.toHaveBeenCalled();
149+150+parentBusy = false;
151+await vi.advanceTimersByTimeAsync(250);
152+expect(send).toHaveBeenCalledTimes(1);
153+expect(send.mock.calls[0]?.[0]?.prompt).toBe("child completed");
154+});
155+156+it("preserves an existing defer hook when the same queue is reused without one", async () => {
157+vi.useFakeTimers();
158+vi.setSystemTime(new Date("2026-01-01T00:00:00.000Z"));
159+160+let parentBusy = true;
161+const send = vi.fn(async (_item: AnnounceQueueItem) => {});
162+163+enqueueAnnounce({
164+key: "announce:test:reuse-keeps-defer",
165+item: {
166+prompt: "first child completed",
167+enqueuedAt: Date.now(),
168+sessionKey: "agent:main:telegram:dm:u1",
169+},
170+settings: { mode: "followup", debounceMs: 0 },
171+ send,
172+shouldDefer: () => parentBusy,
173+});
174+175+enqueueAnnounce({
176+key: "announce:test:reuse-keeps-defer",
177+item: {
178+prompt: "second child completed",
179+enqueuedAt: Date.now(),
180+sessionKey: "agent:main:telegram:dm:u1",
181+},
182+settings: { mode: "followup", debounceMs: 0 },
183+ send,
184+});
185+186+await vi.advanceTimersByTimeAsync(250);
187+expect(send).not.toHaveBeenCalled();
188+189+parentBusy = false;
190+await vi.advanceTimersByTimeAsync(250);
191+expect(send).toHaveBeenCalledTimes(2);
192+});
193+194+it("polls deferred items at the configured cadence after the first debounce", async () => {
195+vi.useFakeTimers();
196+vi.setSystemTime(new Date("2026-01-01T00:00:00.000Z"));
197+198+let parentBusy = true;
199+const send = vi.fn(async (_item: AnnounceQueueItem) => {});
200+201+enqueueAnnounce({
202+key: "announce:test:defer-cadence",
203+item: {
204+prompt: "child completed",
205+enqueuedAt: Date.now(),
206+sessionKey: "agent:main:telegram:dm:u1",
207+},
208+settings: { mode: "followup", debounceMs: 1_000 },
209+ send,
210+shouldDefer: () => parentBusy,
211+});
212+213+await vi.advanceTimersByTimeAsync(1_000);
214+expect(send).not.toHaveBeenCalled();
215+216+parentBusy = false;
217+await vi.advanceTimersByTimeAsync(999);
218+expect(send).not.toHaveBeenCalled();
219+220+await vi.advanceTimersByTimeAsync(1);
221+expect(send).toHaveBeenCalledTimes(1);
222+});
223+224+it("falls back to delivery when busy-parent deferral exceeds the safety cap", async () => {
225+vi.useFakeTimers();
226+vi.setSystemTime(new Date("2026-01-01T00:00:00.000Z"));
227+228+const send = vi.fn(async (_item: AnnounceQueueItem) => {});
229+230+enqueueAnnounce({
231+key: "announce:test:busy-parent-timeout",
232+item: {
233+prompt: "child completed after stale busy state",
234+enqueuedAt: Date.now(),
235+sessionKey: "agent:main:telegram:dm:u1",
236+},
237+settings: { mode: "followup", debounceMs: 0 },
238+ send,
239+shouldDefer: () => true,
240+});
241+242+await vi.advanceTimersByTimeAsync(14_999);
243+expect(send).not.toHaveBeenCalled();
244+245+await vi.advanceTimersByTimeAsync(1);
246+expect(send).toHaveBeenCalledTimes(1);
247+expect(send.mock.calls[0]?.[0]?.prompt).toBe("child completed after stale busy state");
248+});
249+121250it("uses debounce floor for retries when debounce exceeds backoff", async () => {
122251vi.useFakeTimers();
123252vi.setSystemTime(new Date("2026-01-01T00:00:00.000Z"));
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。