
























@@ -183,6 +183,37 @@ async function waitForAssertion(assertion: () => void, timeoutMs = 2_000, stepMs
183183}
184184}
185185186+async function flushScheduledDispatchStep() {
187+await Promise.resolve();
188+if (vi.isFakeTimers()) {
189+await vi.runOnlyPendingTimersAsync();
190+} else {
191+await new Promise<void>((resolve) => setTimeout(resolve, 15));
192+}
193+await Promise.resolve();
194+}
195+196+async function waitForAcceptedRunDispatch(respond: ReturnType<typeof vi.fn>) {
197+const accepted = respond.mock.calls.some(([ok, payload]) => {
198+return ok === true && (payload as { status?: string } | undefined)?.status === "accepted";
199+});
200+if (!accepted) {
201+return;
202+}
203+204+const commandCallCount = mocks.agentCommand.mock.calls.length;
205+const respondCallCount = respond.mock.calls.length;
206+for (let attempt = 0; attempt < 50; attempt++) {
207+await flushScheduledDispatchStep();
208+if (
209+mocks.agentCommand.mock.calls.length > commandCallCount ||
210+respond.mock.calls.length > respondCallCount
211+) {
212+return;
213+}
214+}
215+}
216+186217function mockMainSessionEntry(entry: Record<string, unknown>, cfg: Record<string, unknown> = {}) {
187218mocks.loadSessionEntry.mockReturnValue({
188219 cfg,
@@ -317,6 +348,7 @@ async function invokeAgent(
317348context?: GatewayRequestContext;
318349client?: AgentHandlerArgs["client"];
319350isWebchatConnect?: AgentHandlerArgs["isWebchatConnect"];
351+flushDispatch?: boolean;
320352},
321353) {
322354const respond = options?.respond ?? vi.fn();
@@ -328,6 +360,9 @@ async function invokeAgent(
328360client: options?.client ?? null,
329361isWebchatConnect: options?.isWebchatConnect ?? (() => false),
330362});
363+if (options?.flushDispatch !== false) {
364+await waitForAcceptedRunDispatch(respond);
365+}
331366return respond;
332367}
333368@@ -1717,19 +1752,19 @@ describe("gateway agent handler", () => {
17171752meta: { durationMs: 100 },
17181753});
17191754const respond = vi.fn();
1720-await agentHandlers.agent({
1721-params: {
1755+await invokeAgent(
1756+{
17221757message: "do thing",
17231758sessionKey: "main",
17241759voiceWakeTrigger: "robot wake",
17251760idempotencyKey: "test-voice-route",
17261761},
1727-respond,
1728-context: makeContext(),
1729-req: { type: "req", id: "voice-1", method: "agent" },
1730-client: null,
1731-isWebchatConnect: () => false,
1732-});
1762+{
1763+ respond,
1764+ context: makeContext(),
1765+ reqId: "voice-1",
1766+},
1767+);
1733176817341769await vi.waitFor(() => expect(mocks.agentCommand).toHaveBeenCalled());
17351770const callArgs = mocks.agentCommand.mock.calls.at(-1)?.[0] as { sessionKey?: string };
@@ -1761,19 +1796,19 @@ describe("gateway agent handler", () => {
17611796});
1762179717631798const respond = vi.fn();
1764-await agentHandlers.agent({
1765-params: {
1799+await invokeAgent(
1800+{
17661801message: "do thing",
17671802sessionKey: "main",
17681803voiceWakeTrigger: "robot wake",
17691804idempotencyKey: "test-voice-route-unknown",
17701805},
1771-respond,
1772-context: makeContext(),
1773-req: { type: "req", id: "voice-2", method: "agent" },
1774-client: null,
1775-isWebchatConnect: () => false,
1776-});
1806+{
1807+ respond,
1808+ context: makeContext(),
1809+ reqId: "voice-2",
1810+},
1811+);
1777181217781813await vi.waitFor(() => expect(mocks.agentCommand).toHaveBeenCalled());
17791814const callArgs = mocks.agentCommand.mock.calls.at(-1)?.[0] as { sessionKey?: string };
@@ -1805,19 +1840,19 @@ describe("gateway agent handler", () => {
18051840});
1806184118071842const respond = vi.fn();
1808-await agentHandlers.agent({
1809-params: {
1843+await invokeAgent(
1844+{
18101845message: "do thing",
18111846sessionKey: "main",
18121847voiceWakeTrigger: " ",
18131848idempotencyKey: "test-voice-route-default-target",
18141849},
1815-respond,
1816-context: makeContext(),
1817-req: { type: "req", id: "voice-3", method: "agent" },
1818-client: null,
1819-isWebchatConnect: () => false,
1820-});
1850+{
1851+ respond,
1852+ context: makeContext(),
1853+ reqId: "voice-3",
1854+},
1855+);
1821185618221857await vi.waitFor(() => expect(mocks.agentCommand).toHaveBeenCalled());
18231858const callArgs = mocks.agentCommand.mock.calls.at(-1)?.[0] as { sessionKey?: string };
@@ -1853,21 +1888,21 @@ describe("gateway agent handler", () => {
18531888});
1854188918551890const respond = vi.fn();
1856-await agentHandlers.agent({
1857-params: {
1891+await invokeAgent(
1892+{
18581893message: "do thing",
18591894sessionKey: "main",
18601895to: " ",
18611896replyTo: " ",
18621897voiceWakeTrigger: "robot wake",
18631898idempotencyKey: "test-voice-route-whitespace-delivery",
18641899},
1865-respond,
1866-context: makeContext(),
1867-req: { type: "req", id: "voice-4", method: "agent" },
1868-client: null,
1869-isWebchatConnect: () => false,
1870-});
1900+{
1901+ respond,
1902+ context: makeContext(),
1903+ reqId: "voice-4",
1904+},
1905+);
1871190618721907await vi.waitFor(() => expect(mocks.agentCommand).toHaveBeenCalled());
18731908const callArgs = mocks.agentCommand.mock.calls.at(-1)?.[0] as { sessionKey?: string };
@@ -1905,19 +1940,19 @@ describe("gateway agent handler", () => {
19051940mocks.resolveVoiceWakeRouteByTrigger.mockClear();
1906194119071942const respond = vi.fn();
1908-await agentHandlers.agent({
1909-params: {
1943+await invokeAgent(
1944+{
19101945message: "do thing",
19111946sessionKey: "agent:main:research",
19121947voiceWakeTrigger: "robot wake",
19131948idempotencyKey: "test-voice-route-explicit-session",
19141949},
1915-respond,
1916-context: makeContext(),
1917-req: { type: "req", id: "voice-5", method: "agent" },
1918-client: null,
1919-isWebchatConnect: () => false,
1920-});
1950+{
1951+ respond,
1952+ context: makeContext(),
1953+ reqId: "voice-5",
1954+},
1955+);
1921195619221957await vi.waitFor(() => expect(mocks.agentCommand).toHaveBeenCalled());
19231958const callArgs = mocks.agentCommand.mock.calls.at(-1)?.[0] as { sessionKey?: string };
@@ -1953,19 +1988,19 @@ describe("gateway agent handler", () => {
19531988mocks.resolveVoiceWakeRouteByTrigger.mockClear();
1954198919551990const respond = vi.fn();
1956-await agentHandlers.agent({
1957-params: {
1991+await invokeAgent(
1992+{
19581993message: "do thing",
19591994sessionKey: "agent:ops:main",
19601995voiceWakeTrigger: "robot wake",
19611996idempotencyKey: "test-voice-route-explicit-other-agent-main",
19621997},
1963-respond,
1964-context: makeContext(),
1965-req: { type: "req", id: "voice-5b", method: "agent" },
1966-client: null,
1967-isWebchatConnect: () => false,
1968-});
1998+{
1999+ respond,
2000+ context: makeContext(),
2001+ reqId: "voice-5b",
2002+},
2003+);
1969200419702005await vi.waitFor(() => expect(mocks.agentCommand).toHaveBeenCalled());
19712006const callArgs = mocks.agentCommand.mock.calls.at(-1)?.[0] as { sessionKey?: string };
@@ -2001,20 +2036,20 @@ describe("gateway agent handler", () => {
20012036mocks.resolveVoiceWakeRouteByTrigger.mockClear();
2002203720032038const respond = vi.fn();
2004-await agentHandlers.agent({
2005-params: {
2039+await invokeAgent(
2040+{
20062041message: "do thing",
20072042sessionKey: "main",
20082043sessionId: "caller-selected-session-id",
20092044voiceWakeTrigger: "robot wake",
20102045idempotencyKey: "test-voice-route-explicit-session-id",
20112046},
2012-respond,
2013-context: makeContext(),
2014-req: { type: "req", id: "voice-6", method: "agent" },
2015-client: null,
2016-isWebchatConnect: () => false,
2017-});
2047+{
2048+ respond,
2049+ context: makeContext(),
2050+ reqId: "voice-6",
2051+},
2052+);
2018205320192054await vi.waitFor(() => expect(mocks.agentCommand).toHaveBeenCalled());
20202055const callArgs = mocks.agentCommand.mock.calls.at(-1)?.[0] as { sessionKey?: string };
@@ -2504,7 +2539,7 @@ describe("gateway agent handler chat.abort integration", () => {
25042539sessionKey: "agent:main:main",
25052540idempotencyKey: runId,
25062541},
2507-{ respond, reqId: runId },
2542+{ respond, reqId: runId, flushDispatch: false },
25082543);
2509254425102545await Promise.resolve();
@@ -2521,7 +2556,9 @@ describe("gateway agent handler chat.abort integration", () => {
25212556);
25222557expect(mocks.agentCommand).not.toHaveBeenCalled();
252325582524-await new Promise((resolve) => setImmediate(resolve));
2559+await new Promise<void>((resolve) => setImmediate(resolve));
2560+expect(mocks.agentCommand).not.toHaveBeenCalled();
2561+await new Promise<void>((resolve) => setTimeout(resolve, 15));
25252562await pending;
2526256325272564expect(mocks.agentCommand).toHaveBeenCalledTimes(1);
@@ -2725,20 +2762,25 @@ describe("gateway agent handler chat.abort integration", () => {
2725276227262763const context = makeContext();
27272764const runId = "idem-abort-reactivation-fails";
2728-await expect(
2729-invokeAgent(
2730-{
2731-message: "hi",
2732-agentId: "main",
2733-sessionKey: "agent:main:main",
2734-idempotencyKey: runId,
2735-},
2736-{ context, reqId: runId },
2737-),
2738-).rejects.toThrow("reactivate boom");
2765+const respond = vi.fn();
2766+await invokeAgent(
2767+{
2768+message: "hi",
2769+agentId: "main",
2770+sessionKey: "agent:main:main",
2771+idempotencyKey: runId,
2772+},
2773+{ context, reqId: runId, respond },
2774+);
2739277527402776expect(context.chatAbortControllers.has(runId)).toBe(false);
27412777expect(mocks.agentCommand).not.toHaveBeenCalled();
2778+expect(respond).toHaveBeenCalledWith(
2779+false,
2780+expect.objectContaining({ runId, status: "error" }),
2781+expect.objectContaining({ code: "UNAVAILABLE" }),
2782+expect.objectContaining({ runId }),
2783+);
27422784});
2743278527442786it("does not overwrite or evict a pre-existing chatAbortControllers entry with the same runId", async () => {
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。