


























@@ -3,14 +3,31 @@ import { VoiceCallConfigSchema } from "./config.js";
33import type { CoreAgentDeps, CoreConfig } from "./core-bridge.js";
44import { generateVoiceResponse } from "./response-generator.js";
556+type TestSessionEntry = {
7+sessionId: string;
8+updatedAt: number;
9+providerOverride?: string;
10+modelOverride?: string;
11+modelOverrideSource?: string;
12+};
13+14+type EmbeddedAgentArgs = {
15+extraSystemPrompt: string;
16+provider?: string;
17+model?: string;
18+sessionKey?: string;
19+sandboxSessionKey?: string;
20+agentDir?: string;
21+agentId?: string;
22+workspaceDir?: string;
23+sessionFile?: string;
24+};
25+626function createAgentRuntime(payloads: Array<Record<string, unknown>>) {
7-const sessionStore: Record<string, { sessionId: string; updatedAt: number }> = {};
27+const sessionStore: Record<string, TestSessionEntry> = {};
828const saveSessionStore = vi.fn(async () => {});
929const updateSessionStore = vi.fn(
10-async (
11-_storePath: string,
12-mutator: (store: Record<string, { sessionId: string; updatedAt: number }>) => unknown,
13-) => {
30+async (_storePath: string, mutator: (store: Record<string, TestSessionEntry>) => unknown) => {
1431return await mutator(sessionStore);
1532},
1633);
@@ -77,17 +94,11 @@ function requireEmbeddedAgentArgs(runEmbeddedPiAgent: ReturnType<typeof vi.fn>)
7794if (!firstCall) {
7895throw new Error("voice response generator did not invoke the embedded agent");
7996}
80-const args = firstCall[0] as
81-| {
82-extraSystemPrompt?: string;
83-provider?: string;
84-model?: string;
85-}
86-| undefined;
97+const args = firstCall[0] as Partial<EmbeddedAgentArgs> | undefined;
8798if (!args?.extraSystemPrompt) {
8899throw new Error("voice response generator did not pass the spoken-output contract prompt");
89100}
90-return args;
101+return args as EmbeddedAgentArgs;
91102}
9210393104async function runGenerateVoiceResponse(
@@ -186,21 +197,17 @@ describe("generateVoiceResponse", () => {
186197});
187198188199expect(result.text).toBe("Pinned model works.");
189-expect(sessionStore["voice:15550001111"]).toMatchObject({
190-providerOverride: "openai",
191-modelOverride: "gpt-4.1-nano",
192-modelOverrideSource: "auto",
193-});
200+const pinnedSessionEntry = sessionStore["voice:15550001111"];
201+expect(pinnedSessionEntry?.providerOverride).toBe("openai");
202+expect(pinnedSessionEntry?.modelOverride).toBe("gpt-4.1-nano");
203+expect(pinnedSessionEntry?.modelOverrideSource).toBe("auto");
194204const updateSessionStoreCall = updateSessionStore.mock.calls[0];
195205expect(updateSessionStoreCall?.[0]).toBe("/tmp/openclaw/main/sessions.json");
196206expect(updateSessionStoreCall?.[1]).toBeTypeOf("function");
197-expect(runEmbeddedPiAgent).toHaveBeenCalledWith(
198-expect.objectContaining({
199-provider: "openai",
200-model: "gpt-4.1-nano",
201-sessionKey: "voice:15550001111",
202-}),
203-);
207+const args = requireEmbeddedAgentArgs(runEmbeddedPiAgent);
208+expect(args.provider).toBe("openai");
209+expect(args.model).toBe("gpt-4.1-nano");
210+expect(args.sessionKey).toBe("voice:15550001111");
204211});
205212206213it("uses the persisted per-call session key for classic responses", async () => {
@@ -224,16 +231,13 @@ describe("generateVoiceResponse", () => {
224231});
225232226233expect(result.text).toBe("Fresh call context.");
227-expect(sessionStore["voice:call:call-123"]).toMatchObject({
228- sessionId: expect.stringMatching(/\S/),
229-});
234+const perCallSessionEntry = sessionStore["voice:call:call-123"];
235+expect(perCallSessionEntry?.sessionId).toBeTypeOf("string");
236+expect(perCallSessionEntry?.sessionId).not.toBe("");
230237expect(sessionStore["voice:15550001111"]).toBeUndefined();
231-expect(runEmbeddedPiAgent).toHaveBeenCalledWith(
232-expect.objectContaining({
233-sessionKey: "voice:call:call-123",
234-sandboxSessionKey: "agent:main:voice:call:call-123",
235-}),
236-);
238+const args = requireEmbeddedAgentArgs(runEmbeddedPiAgent);
239+expect(args.sessionKey).toBe("voice:call:call-123");
240+expect(args.sandboxSessionKey).toBe("agent:main:voice:call:call-123");
237241});
238242239243it("uses the main agent workspace when voice config omits agentId", async () => {
@@ -272,15 +276,12 @@ describe("generateVoiceResponse", () => {
272276agentId: "main",
273277},
274278);
275-expect(runEmbeddedPiAgent).toHaveBeenCalledWith(
276-expect.objectContaining({
277-agentDir: "/tmp/openclaw/agents/main",
278-agentId: "main",
279-sandboxSessionKey: "agent:main:voice:15550001111",
280-workspaceDir: "/tmp/openclaw/workspace/main",
281-sessionFile: "/tmp/openclaw/main/sessions/session.jsonl",
282-}),
283-);
279+const args = requireEmbeddedAgentArgs(runEmbeddedPiAgent);
280+expect(args.agentDir).toBe("/tmp/openclaw/agents/main");
281+expect(args.agentId).toBe("main");
282+expect(args.sandboxSessionKey).toBe("agent:main:voice:15550001111");
283+expect(args.workspaceDir).toBe("/tmp/openclaw/workspace/main");
284+expect(args.sessionFile).toBe("/tmp/openclaw/main/sessions/session.jsonl");
284285});
285286286287it("uses the configured voice response agent workspace", async () => {
@@ -323,14 +324,11 @@ describe("generateVoiceResponse", () => {
323324agentId: "voice",
324325},
325326);
326-expect(runEmbeddedPiAgent).toHaveBeenCalledWith(
327-expect.objectContaining({
328-agentDir: "/tmp/openclaw/agents/voice",
329-agentId: "voice",
330-sandboxSessionKey: "agent:voice:voice:15550001111",
331-workspaceDir: "/tmp/openclaw/workspace/voice",
332-sessionFile: "/tmp/openclaw/voice/sessions/session.jsonl",
333-}),
334-);
327+const args = requireEmbeddedAgentArgs(runEmbeddedPiAgent);
328+expect(args.agentDir).toBe("/tmp/openclaw/agents/voice");
329+expect(args.agentId).toBe("voice");
330+expect(args.sandboxSessionKey).toBe("agent:voice:voice:15550001111");
331+expect(args.workspaceDir).toBe("/tmp/openclaw/workspace/voice");
332+expect(args.sessionFile).toBe("/tmp/openclaw/voice/sessions/session.jsonl");
335333});
336334});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。