From dfaa9ee87e3011b9df37a2fd19df1939239e768a Mon Sep 17 00:00:00 2001 From: Longbiao CHEN Date: Mon, 13 Apr 2026 03:04:06 +0800 Subject: [PATCH] fix(gateway): keep explicit agent main sessions stable --- src/gateway/server-methods/agent.test.ts | 49 ++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/src/gateway/server-methods/agent.test.ts b/src/gateway/server-methods/agent.test.ts index 76dfabd8831..5c48829b02a 100644 --- a/src/gateway/server-methods/agent.test.ts +++ b/src/gateway/server-methods/agent.test.ts @@ -89,6 +89,7 @@ vi.mock("../../agents/agent-scope.js", () => ({ resolveAgentWorkspaceDir: (cfg: { agents?: { defaults?: { workspace?: string } } }) => cfg?.agents?.defaults?.workspace ?? "/tmp/workspace", resolveAgentEffectiveModelPrimary: () => undefined, + resolveDefaultAgentId: () => "main", })); vi.mock("../../auto-reply/reply/session-reset-prompt.js", async () => { @@ -1682,6 +1683,54 @@ describe("gateway agent handler", () => { expect(mocks.resolveVoiceWakeRouteByTrigger).not.toHaveBeenCalled(); }); + it("does not auto-route voice wake requests with another agent's explicit main session", async () => { + mocks.loadVoiceWakeRoutingConfig.mockResolvedValue({ + version: 1, + defaultTarget: { sessionKey: "agent:main:voice" }, + routes: [], + updatedAtMs: 0, + }); + mocks.resolveVoiceWakeRouteByTrigger.mockReturnValue({ sessionKey: "agent:main:voice" }); + + mocks.loadSessionEntry.mockImplementation((sessionKey: string) => ({ + cfg: {}, + storePath: "/tmp/sessions.json", + entry: { + sessionId: "voice-session-id", + updatedAt: Date.now(), + }, + canonicalKey: sessionKey, + })); + mocks.updateSessionStore.mockResolvedValue(undefined); + mocks.agentCommand.mockResolvedValue({ + payloads: [{ text: "ok" }], + meta: { durationMs: 100 }, + }); + mocks.loadVoiceWakeRoutingConfig.mockClear(); + mocks.resolveVoiceWakeRouteByTrigger.mockClear(); + + const respond = vi.fn(); + await agentHandlers.agent({ + params: { + message: "do thing", + sessionKey: "agent:ops:main", + voiceWakeTrigger: "robot wake", + idempotencyKey: "test-voice-route-explicit-other-agent-main", + }, + respond, + context: makeContext(), + req: { type: "req", id: "voice-5b", method: "agent" }, + client: null, + isWebchatConnect: () => false, + }); + + await vi.waitFor(() => expect(mocks.agentCommand).toHaveBeenCalled()); + const callArgs = mocks.agentCommand.mock.calls.at(-1)?.[0] as { sessionKey?: string }; + expect(callArgs.sessionKey).toBe("agent:ops:main"); + expect(mocks.loadVoiceWakeRoutingConfig).not.toHaveBeenCalled(); + expect(mocks.resolveVoiceWakeRouteByTrigger).not.toHaveBeenCalled(); + }); + it("treats explicit sessionId as an opt-out for voice wake auto-routing", async () => { mocks.loadVoiceWakeRoutingConfig.mockResolvedValue({ version: 1,