From da7fb64aa485d537a9841b78ab0fc0e4fa8ca0b3 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sat, 30 May 2026 13:16:22 -0400 Subject: [PATCH] fix(google): bound realtime browser session expiry --- .../google/realtime-voice-provider.test.ts | 14 ++++++++++++++ extensions/google/realtime-voice-provider.ts | 17 +++++++++++++---- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/extensions/google/realtime-voice-provider.test.ts b/extensions/google/realtime-voice-provider.test.ts index 1406f6831ac..3a1f7388f41 100644 --- a/extensions/google/realtime-voice-provider.test.ts +++ b/extensions/google/realtime-voice-provider.test.ts @@ -467,6 +467,20 @@ describe("buildGoogleRealtimeVoiceProvider", () => { expect(createTokenMock).not.toHaveBeenCalled(); }); + it("rejects browser session creation while the process clock is invalid", async () => { + vi.spyOn(Date, "now").mockReturnValue(Number.NaN); + const provider = buildGoogleRealtimeVoiceProvider(); + + await expect( + provider.createBrowserSession?.({ + providerConfig: { + apiKey: "gemini-key", + }, + }), + ).rejects.toThrow("Google realtime browser session expiry is outside the supported Date range"); + expect(createTokenMock).not.toHaveBeenCalled(); + }); + it("can opt out of Google Live session resumption and context compression", async () => { const provider = buildGoogleRealtimeVoiceProvider(); const bridge = provider.createBridge({ diff --git a/extensions/google/realtime-voice-provider.ts b/extensions/google/realtime-voice-provider.ts index bfa847ee8c2..0954866d271 100644 --- a/extensions/google/realtime-voice-provider.ts +++ b/extensions/google/realtime-voice-provider.ts @@ -16,7 +16,10 @@ import type { ThinkingConfig, TurnCoverage, } from "@google/genai"; -import { timestampMsToIsoString } from "openclaw/plugin-sdk/number-runtime"; +import { + resolveExpiresAtMsFromDurationMs, + timestampMsToIsoString, +} from "openclaw/plugin-sdk/number-runtime"; import type { OpenClawConfig } from "openclaw/plugin-sdk/provider-onboard"; import type { RealtimeVoiceAudioFormat, @@ -856,11 +859,17 @@ async function createGoogleRealtimeBrowserSession( const model = req.model ?? config.model ?? GOOGLE_REALTIME_DEFAULT_MODEL; const voice = req.voice ?? config.voice ?? GOOGLE_REALTIME_DEFAULT_VOICE; - const expiresAtMs = Date.now() + GOOGLE_REALTIME_BROWSER_SESSION_TTL_MS; - const newSessionExpiresAtMs = Date.now() + GOOGLE_REALTIME_BROWSER_NEW_SESSION_TTL_MS; + const nowMs = Date.now(); + const expiresAtMs = resolveExpiresAtMsFromDurationMs(GOOGLE_REALTIME_BROWSER_SESSION_TTL_MS, { + nowMs, + }); + const newSessionExpiresAtMs = resolveExpiresAtMsFromDurationMs( + GOOGLE_REALTIME_BROWSER_NEW_SESSION_TTL_MS, + { nowMs }, + ); const expireTime = timestampMsToIsoString(expiresAtMs); const newSessionExpireTime = timestampMsToIsoString(newSessionExpiresAtMs); - if (!expireTime || !newSessionExpireTime) { + if (expiresAtMs === undefined || !expireTime || !newSessionExpireTime) { throw new Error("Google realtime browser session expiry is outside the supported Date range"); } const ai = createGoogleGenAI({