diff --git a/extensions/voice-call/src/response-generator.test.ts b/extensions/voice-call/src/response-generator.test.ts index f508297b8a7..83e37dd4936 100644 --- a/extensions/voice-call/src/response-generator.test.ts +++ b/extensions/voice-call/src/response-generator.test.ts @@ -3,14 +3,31 @@ import { VoiceCallConfigSchema } from "./config.js"; import type { CoreAgentDeps, CoreConfig } from "./core-bridge.js"; import { generateVoiceResponse } from "./response-generator.js"; +type TestSessionEntry = { + sessionId: string; + updatedAt: number; + providerOverride?: string; + modelOverride?: string; + modelOverrideSource?: string; +}; + +type EmbeddedAgentArgs = { + extraSystemPrompt: string; + provider?: string; + model?: string; + sessionKey?: string; + sandboxSessionKey?: string; + agentDir?: string; + agentId?: string; + workspaceDir?: string; + sessionFile?: string; +}; + function createAgentRuntime(payloads: Array>) { - const sessionStore: Record = {}; + const sessionStore: Record = {}; const saveSessionStore = vi.fn(async () => {}); const updateSessionStore = vi.fn( - async ( - _storePath: string, - mutator: (store: Record) => unknown, - ) => { + async (_storePath: string, mutator: (store: Record) => unknown) => { return await mutator(sessionStore); }, ); @@ -77,17 +94,11 @@ function requireEmbeddedAgentArgs(runEmbeddedPiAgent: ReturnType) if (!firstCall) { throw new Error("voice response generator did not invoke the embedded agent"); } - const args = firstCall[0] as - | { - extraSystemPrompt?: string; - provider?: string; - model?: string; - } - | undefined; + const args = firstCall[0] as Partial | undefined; if (!args?.extraSystemPrompt) { throw new Error("voice response generator did not pass the spoken-output contract prompt"); } - return args; + return args as EmbeddedAgentArgs; } async function runGenerateVoiceResponse( @@ -186,21 +197,17 @@ describe("generateVoiceResponse", () => { }); expect(result.text).toBe("Pinned model works."); - expect(sessionStore["voice:15550001111"]).toMatchObject({ - providerOverride: "openai", - modelOverride: "gpt-4.1-nano", - modelOverrideSource: "auto", - }); + const pinnedSessionEntry = sessionStore["voice:15550001111"]; + expect(pinnedSessionEntry?.providerOverride).toBe("openai"); + expect(pinnedSessionEntry?.modelOverride).toBe("gpt-4.1-nano"); + expect(pinnedSessionEntry?.modelOverrideSource).toBe("auto"); const updateSessionStoreCall = updateSessionStore.mock.calls[0]; expect(updateSessionStoreCall?.[0]).toBe("/tmp/openclaw/main/sessions.json"); expect(updateSessionStoreCall?.[1]).toBeTypeOf("function"); - expect(runEmbeddedPiAgent).toHaveBeenCalledWith( - expect.objectContaining({ - provider: "openai", - model: "gpt-4.1-nano", - sessionKey: "voice:15550001111", - }), - ); + const args = requireEmbeddedAgentArgs(runEmbeddedPiAgent); + expect(args.provider).toBe("openai"); + expect(args.model).toBe("gpt-4.1-nano"); + expect(args.sessionKey).toBe("voice:15550001111"); }); it("uses the persisted per-call session key for classic responses", async () => { @@ -224,16 +231,13 @@ describe("generateVoiceResponse", () => { }); expect(result.text).toBe("Fresh call context."); - expect(sessionStore["voice:call:call-123"]).toMatchObject({ - sessionId: expect.stringMatching(/\S/), - }); + const perCallSessionEntry = sessionStore["voice:call:call-123"]; + expect(perCallSessionEntry?.sessionId).toBeTypeOf("string"); + expect(perCallSessionEntry?.sessionId).not.toBe(""); expect(sessionStore["voice:15550001111"]).toBeUndefined(); - expect(runEmbeddedPiAgent).toHaveBeenCalledWith( - expect.objectContaining({ - sessionKey: "voice:call:call-123", - sandboxSessionKey: "agent:main:voice:call:call-123", - }), - ); + const args = requireEmbeddedAgentArgs(runEmbeddedPiAgent); + expect(args.sessionKey).toBe("voice:call:call-123"); + expect(args.sandboxSessionKey).toBe("agent:main:voice:call:call-123"); }); it("uses the main agent workspace when voice config omits agentId", async () => { @@ -272,15 +276,12 @@ describe("generateVoiceResponse", () => { agentId: "main", }, ); - expect(runEmbeddedPiAgent).toHaveBeenCalledWith( - expect.objectContaining({ - agentDir: "/tmp/openclaw/agents/main", - agentId: "main", - sandboxSessionKey: "agent:main:voice:15550001111", - workspaceDir: "/tmp/openclaw/workspace/main", - sessionFile: "/tmp/openclaw/main/sessions/session.jsonl", - }), - ); + const args = requireEmbeddedAgentArgs(runEmbeddedPiAgent); + expect(args.agentDir).toBe("/tmp/openclaw/agents/main"); + expect(args.agentId).toBe("main"); + expect(args.sandboxSessionKey).toBe("agent:main:voice:15550001111"); + expect(args.workspaceDir).toBe("/tmp/openclaw/workspace/main"); + expect(args.sessionFile).toBe("/tmp/openclaw/main/sessions/session.jsonl"); }); it("uses the configured voice response agent workspace", async () => { @@ -323,14 +324,11 @@ describe("generateVoiceResponse", () => { agentId: "voice", }, ); - expect(runEmbeddedPiAgent).toHaveBeenCalledWith( - expect.objectContaining({ - agentDir: "/tmp/openclaw/agents/voice", - agentId: "voice", - sandboxSessionKey: "agent:voice:voice:15550001111", - workspaceDir: "/tmp/openclaw/workspace/voice", - sessionFile: "/tmp/openclaw/voice/sessions/session.jsonl", - }), - ); + const args = requireEmbeddedAgentArgs(runEmbeddedPiAgent); + expect(args.agentDir).toBe("/tmp/openclaw/agents/voice"); + expect(args.agentId).toBe("voice"); + expect(args.sandboxSessionKey).toBe("agent:voice:voice:15550001111"); + expect(args.workspaceDir).toBe("/tmp/openclaw/workspace/voice"); + expect(args.sessionFile).toBe("/tmp/openclaw/voice/sessions/session.jsonl"); }); });