






















@@ -13,6 +13,7 @@ const {
1313 createAudioResourceMock,
1414 resolveAgentRouteMock,
1515 agentCommandMock,
16+ resolveRealtimeBootstrapContextInstructionsMock,
1617 transcribeAudioFileMock,
1718 textToSpeechStreamMock,
1819 textToSpeechMock,
@@ -130,6 +131,9 @@ const {
130131_runtime?: unknown,
131132): Promise<{ payloads?: Array<{ text?: string }> }> => ({ payloads: [] }),
132133),
134+resolveRealtimeBootstrapContextInstructionsMock: vi.fn<
135+(...args: unknown[]) => Promise<string | undefined>
136+>(async () => undefined),
133137transcribeAudioFileMock: vi.fn(async () => ({ text: "hello from voice" })),
134138textToSpeechStreamMock: vi.fn(
135139async (): Promise<unknown> => ({ success: false, error: "stream unavailable" }),
@@ -188,6 +192,16 @@ vi.mock("openclaw/plugin-sdk/agent-runtime", async () => {
188192};
189193});
190194195+vi.mock("openclaw/plugin-sdk/realtime-bootstrap-context", async () => {
196+const actual = await vi.importActual<
197+typeof import("openclaw/plugin-sdk/realtime-bootstrap-context")
198+>("openclaw/plugin-sdk/realtime-bootstrap-context");
199+return {
200+ ...actual,
201+resolveRealtimeBootstrapContextInstructions: resolveRealtimeBootstrapContextInstructionsMock,
202+};
203+});
204+191205vi.mock("openclaw/plugin-sdk/runtime-env", async () => {
192206const actual = await vi.importActual<typeof import("openclaw/plugin-sdk/runtime-env")>(
193207"openclaw/plugin-sdk/runtime-env",
@@ -300,6 +314,8 @@ describe("DiscordVoiceManager", () => {
300314resolveAgentRouteMock.mockReturnValue({ agentId: "agent-1", sessionKey: "discord:g1:c1" });
301315agentCommandMock.mockReset();
302316agentCommandMock.mockResolvedValue({ payloads: [] });
317+resolveRealtimeBootstrapContextInstructionsMock.mockReset();
318+resolveRealtimeBootstrapContextInstructionsMock.mockResolvedValue(undefined);
303319transcribeAudioFileMock.mockReset();
304320transcribeAudioFileMock.mockResolvedValue({ text: "hello from voice" });
305321textToSpeechStreamMock.mockReset();
@@ -2875,6 +2891,45 @@ describe("DiscordVoiceManager", () => {
28752891]);
28762892});
287728932894+it("adds default bootstrap profile context to realtime voice instructions", async () => {
2895+resolveAgentRouteMock.mockReturnValue({
2896+agentId: "main",
2897+sessionKey: "agent:main:discord:channel:1001",
2898+});
2899+resolveRealtimeBootstrapContextInstructionsMock.mockResolvedValue(
2900+"OpenClaw realtime voice profile context:\n\n### IDENTITY.md\nName: Wilfred",
2901+);
2902+const manager = createManager({
2903+groupPolicy: "open",
2904+voice: {
2905+enabled: true,
2906+mode: "bidi",
2907+realtime: {
2908+provider: "openai",
2909+consultPolicy: "always",
2910+},
2911+},
2912+});
2913+2914+await manager.join({ guildId: "g1", channelId: "1001" });
2915+2916+expect(resolveRealtimeBootstrapContextInstructionsMock).toHaveBeenCalledWith({
2917+config: {},
2918+agentId: "main",
2919+sessionKey: "agent:main:discord:channel:1001",
2920+files: undefined,
2921+warn: expect.any(Function),
2922+});
2923+const bridgeParams = lastRealtimeBridgeParams() as
2924+| {
2925+instructions?: string;
2926+}
2927+| undefined;
2928+expect(bridgeParams?.instructions).toContain("OpenClaw realtime voice profile context");
2929+expect(bridgeParams?.instructions).toContain("Name: Wilfred");
2930+expect(bridgeParams?.instructions).toContain("Call openclaw_agent_consult");
2931+});
2932+28782933it("routes bidi realtime consults through a configured voice agent session target", async () => {
28792934resolveAgentRouteMock.mockImplementation((params?: { peer?: { id?: string } }) => {
28802935if (params?.peer?.id === "maintainers") {
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。