From 6259f6addcbe9fc3605e4b119fb0bf1cbf6e09d6 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Thu, 23 Apr 2026 23:47:44 +0100 Subject: [PATCH] fix: harden provider and gateway test seams --- extensions/google/google-genai-runtime.ts | 8 ++++++++ .../google/music-generation-provider.test.ts | 14 +++++++------- extensions/google/music-generation-provider.ts | 4 ++-- .../google/video-generation-provider.test.ts | 14 +++++++------- extensions/google/video-generation-provider.ts | 6 +++--- src/agents/tools/embedded-gateway-stub.ts | 3 +-- 6 files changed, 28 insertions(+), 21 deletions(-) create mode 100644 extensions/google/google-genai-runtime.ts diff --git a/extensions/google/google-genai-runtime.ts b/extensions/google/google-genai-runtime.ts new file mode 100644 index 00000000000..96875c183bb --- /dev/null +++ b/extensions/google/google-genai-runtime.ts @@ -0,0 +1,8 @@ +import { GoogleGenAI } from "@google/genai"; + +export type GoogleGenAIClient = InstanceType; +export type GoogleGenAIOptions = ConstructorParameters[0]; + +export function createGoogleGenAI(options: GoogleGenAIOptions): GoogleGenAIClient { + return new GoogleGenAI(options); +} diff --git a/extensions/google/music-generation-provider.test.ts b/extensions/google/music-generation-provider.test.ts index 58ebaeff3de..2c0dbc451fe 100644 --- a/extensions/google/music-generation-provider.test.ts +++ b/extensions/google/music-generation-provider.test.ts @@ -1,19 +1,19 @@ import { afterEach, describe, expect, it, vi } from "vitest"; -const { GoogleGenAIMock, generateContentMock } = vi.hoisted(() => { +const { createGoogleGenAIMock, generateContentMock } = vi.hoisted(() => { const generateContentMock = vi.fn(); - const GoogleGenAIMock = vi.fn(function GoogleGenAI() { + const createGoogleGenAIMock = vi.fn(() => { return { models: { generateContent: generateContentMock, }, }; }); - return { GoogleGenAIMock, generateContentMock }; + return { createGoogleGenAIMock, generateContentMock }; }); -vi.mock("@google/genai", () => ({ - GoogleGenAI: GoogleGenAIMock, +vi.mock("./google-genai-runtime.js", () => ({ + createGoogleGenAI: createGoogleGenAIMock, })); import * as providerAuthRuntime from "openclaw/plugin-sdk/provider-auth-runtime"; @@ -24,7 +24,7 @@ describe("google music generation provider", () => { afterEach(() => { vi.restoreAllMocks(); generateContentMock.mockReset(); - GoogleGenAIMock.mockClear(); + createGoogleGenAIMock.mockClear(); }); it("declares explicit mode capabilities", () => { @@ -75,7 +75,7 @@ describe("google music generation provider", () => { expect(result.tracks).toHaveLength(1); expect(result.tracks[0]?.mimeType).toBe("audio/mpeg"); expect(result.lyrics).toEqual(["wake the city up"]); - expect(GoogleGenAIMock).toHaveBeenCalledWith( + expect(createGoogleGenAIMock).toHaveBeenCalledWith( expect.objectContaining({ apiKey: "google-key", }), diff --git a/extensions/google/music-generation-provider.ts b/extensions/google/music-generation-provider.ts index e455eec80fe..e5b53e50e2a 100644 --- a/extensions/google/music-generation-provider.ts +++ b/extensions/google/music-generation-provider.ts @@ -1,4 +1,3 @@ -import { GoogleGenAI } from "@google/genai"; import { extensionForMime } from "openclaw/plugin-sdk/media-mime"; import type { GeneratedMusicAsset, @@ -14,6 +13,7 @@ import { GOOGLE_MAX_INPUT_IMAGES, GOOGLE_PRO_MUSIC_MODEL, } from "./generation-provider-metadata.js"; +import { createGoogleGenAI } from "./google-genai-runtime.js"; const DEFAULT_TIMEOUT_MS = 180_000; @@ -128,7 +128,7 @@ export function buildGoogleMusicGenerationProvider(): MusicGenerationProvider { } } - const client = new GoogleGenAI({ + const client = createGoogleGenAI({ apiKey: auth.apiKey, httpOptions: { ...(resolveConfiguredGoogleMusicBaseUrl(req) diff --git a/extensions/google/video-generation-provider.test.ts b/extensions/google/video-generation-provider.test.ts index d5f7d69c775..5b0ad93c0d4 100644 --- a/extensions/google/video-generation-provider.test.ts +++ b/extensions/google/video-generation-provider.test.ts @@ -1,9 +1,9 @@ import { afterEach, describe, expect, it, vi } from "vitest"; -const { GoogleGenAIMock, generateVideosMock, getVideosOperationMock } = vi.hoisted(() => { +const { createGoogleGenAIMock, generateVideosMock, getVideosOperationMock } = vi.hoisted(() => { const generateVideosMock = vi.fn(); const getVideosOperationMock = vi.fn(); - const GoogleGenAIMock = vi.fn(function GoogleGenAI() { + const createGoogleGenAIMock = vi.fn(() => { return { models: { generateVideos: generateVideosMock, @@ -16,11 +16,11 @@ const { GoogleGenAIMock, generateVideosMock, getVideosOperationMock } = vi.hoist }, }; }); - return { GoogleGenAIMock, generateVideosMock, getVideosOperationMock }; + return { createGoogleGenAIMock, generateVideosMock, getVideosOperationMock }; }); -vi.mock("@google/genai", () => ({ - GoogleGenAI: GoogleGenAIMock, +vi.mock("./google-genai-runtime.js", () => ({ + createGoogleGenAI: createGoogleGenAIMock, })); import * as providerAuthRuntime from "openclaw/plugin-sdk/provider-auth-runtime"; @@ -32,7 +32,7 @@ describe("google video generation provider", () => { vi.restoreAllMocks(); generateVideosMock.mockReset(); getVideosOperationMock.mockReset(); - GoogleGenAIMock.mockClear(); + createGoogleGenAIMock.mockClear(); }); it("declares explicit mode capabilities", () => { @@ -89,7 +89,7 @@ describe("google video generation provider", () => { expect(request?.config).not.toHaveProperty("numberOfVideos"); expect(result.videos).toHaveLength(1); expect(result.videos[0]?.mimeType).toBe("video/mp4"); - expect(GoogleGenAIMock).toHaveBeenCalledWith( + expect(createGoogleGenAIMock).toHaveBeenCalledWith( expect.objectContaining({ apiKey: "google-key", httpOptions: expect.not.objectContaining({ diff --git a/extensions/google/video-generation-provider.ts b/extensions/google/video-generation-provider.ts index 2de8fb6f63a..365a0fb5c03 100644 --- a/extensions/google/video-generation-provider.ts +++ b/extensions/google/video-generation-provider.ts @@ -1,6 +1,5 @@ import { mkdtemp, readFile, rm } from "node:fs/promises"; import path from "node:path"; -import { GoogleGenAI } from "@google/genai"; import { resolveApiKeyForProvider } from "openclaw/plugin-sdk/provider-auth-runtime"; import { createProviderOperationDeadline, @@ -22,6 +21,7 @@ import { GOOGLE_VIDEO_MAX_DURATION_SECONDS, GOOGLE_VIDEO_MIN_DURATION_SECONDS, } from "./generation-provider-metadata.js"; +import { createGoogleGenAI, type GoogleGenAIClient } from "./google-genai-runtime.js"; const DEFAULT_TIMEOUT_MS = 180_000; const POLL_INTERVAL_MS = 10_000; @@ -126,7 +126,7 @@ function resolveInputVideo(req: VideoGenerationRequest) { } async function downloadGeneratedVideo(params: { - client: GoogleGenAI; + client: GoogleGenAIClient; file: unknown; index: number; }): Promise { @@ -181,7 +181,7 @@ export function buildGoogleVideoGenerationProvider(): VideoGenerationProvider { timeoutMs: req.timeoutMs, label: "Google video generation", }); - const client = new GoogleGenAI({ + const client = createGoogleGenAI({ apiKey: auth.apiKey, httpOptions: { ...(configuredBaseUrl ? { baseUrl: configuredBaseUrl } : {}), diff --git a/src/agents/tools/embedded-gateway-stub.ts b/src/agents/tools/embedded-gateway-stub.ts index b301c2b686f..594c08fa7b4 100644 --- a/src/agents/tools/embedded-gateway-stub.ts +++ b/src/agents/tools/embedded-gateway-stub.ts @@ -59,8 +59,7 @@ let runtimeMod: EmbeddedGatewayRuntime | undefined; async function getRuntime(): Promise { if (!runtimeMod) { - const modPath = [".", "embedded-gateway-stub.runtime.js"].join("/"); - runtimeMod = (await import(modPath)) as EmbeddedGatewayRuntime; + runtimeMod = (await import("./embedded-gateway-stub.runtime.js")) as EmbeddedGatewayRuntime; } return runtimeMod; }