diff --git a/CHANGELOG.md b/CHANGELOG.md index 317e27d01f8..6d706788edf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -67,6 +67,7 @@ Docs: https://docs.openclaw.ai - Google Meet: clear queued Gemini Live playback when realtime interruptions arrive, restart Chrome command-pair audio output after clears, and expose Google Live interruption/VAD config knobs for Meet and Voice Call realtime bridges. Fixes #72523. (#72524) Thanks @BsnizND. - Google Meet: add `realtime.agentId` so live meeting consults can target a named OpenClaw agent instead of always using `main`. (#72381) Thanks @BsnizND. - Google Meet: route stateful `google_meet` tool actions through the gateway-owned runtime so created or joined realtime sessions remain visible to status, speak, and leave after the agent turn ends. Fixes #72440. (#72441) Thanks @BsnizND. +- Google Meet: preserve Gemini Live function names when replying to realtime tool calls so Google SDK validation accepts the `FunctionResponse` payload. Fixes #72425. (#72426) Thanks @BsnizND. - Matrix/E2EE: stabilize recovery and broken-device QA flows while avoiding Matrix device-cleanup sync races that could leave shutdown-time crypto work running. Thanks @gumadeiras. - Cron: apply `cron.maxConcurrentRuns` to a dedicated `cron-nested` isolated agent-turn lane as well as cron dispatch, so parallel cron jobs no longer serialize on inner LLM execution while non-cron nested flows keep their existing lane behavior. Fixes #72707. Thanks @kagura-agent. - Cron: treat isolated run-level agent failures as job errors even when no reply payload is produced, synthesizing a safe error payload so model/provider failures increment error counters and trigger failure notifications instead of clearing as successful. Fixes #43604; carries forward #43631. Thanks @SPFAdvisors. diff --git a/extensions/google/realtime-voice-provider.test.ts b/extensions/google/realtime-voice-provider.test.ts index be99695e981..1ffba7d1153 100644 --- a/extensions/google/realtime-voice-provider.test.ts +++ b/extensions/google/realtime-voice-provider.test.ts @@ -414,4 +414,44 @@ describe("buildGoogleRealtimeVoiceProvider", () => { }), ); }); + + it("reports Google Live tool response send failures without losing the call name", async () => { + const provider = buildGoogleRealtimeVoiceProvider(); + const onError = vi.fn(); + const bridge = provider.createBridge({ + providerConfig: { apiKey: "gemini-key" }, + onAudio: vi.fn(), + onClearAudio: vi.fn(), + onError, + }); + + await bridge.connect(); + lastConnectParams().callbacks.onmessage({ + setupComplete: { sessionId: "session-1" }, + toolCall: { + functionCalls: [{ id: "call-1", name: "lookup", args: { query: "hi" } }], + }, + }); + + const sendError = new Error("SDK send failed"); + session.sendToolResponse.mockImplementationOnce(() => { + throw sendError; + }); + + bridge.submitToolResult("call-1", ["retryable"]); + + expect(onError).toHaveBeenCalledWith(sendError); + + bridge.submitToolResult("call-1", { result: "ok" }); + + expect(session.sendToolResponse).toHaveBeenLastCalledWith({ + functionResponses: [ + { + id: "call-1", + name: "lookup", + response: { result: "ok" }, + }, + ], + }); + }); }); diff --git a/extensions/google/realtime-voice-provider.ts b/extensions/google/realtime-voice-provider.ts index 8a8ccfae708..feb73835570 100644 --- a/extensions/google/realtime-voice-provider.ts +++ b/extensions/google/realtime-voice-provider.ts @@ -461,19 +461,25 @@ class GoogleRealtimeVoiceBridge implements RealtimeVoiceBridge { ); return; } - this.pendingFunctionNames.delete(callId); - this.session.sendToolResponse({ - functionResponses: [ - { - id: callId, - name, - response: - result && typeof result === "object" - ? (result as Record) - : { output: result }, - }, - ], - }); + try { + this.session.sendToolResponse({ + functionResponses: [ + { + id: callId, + name, + response: + result && typeof result === "object" && !Array.isArray(result) + ? (result as Record) + : { output: result }, + }, + ], + }); + this.pendingFunctionNames.delete(callId); + } catch (error) { + this.config.onError?.( + error instanceof Error ? error : new Error("Failed to send Google Live function response"), + ); + } } acknowledgeMark(): void {}