From 7a3497c8bd05dfa1c8ccc32c0f6b635693c6a80c Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Mon, 6 Apr 2026 21:58:21 +0100 Subject: [PATCH] refactor: dedupe image generation runtime surface --- .../image-generation-core/src/runtime.ts | 137 +----------------- package.json | 4 + scripts/lib/plugin-sdk-entrypoints.json | 1 + src/plugin-sdk/image-generation-runtime.ts | 6 + 4 files changed, 17 insertions(+), 131 deletions(-) create mode 100644 src/plugin-sdk/image-generation-runtime.ts diff --git a/extensions/image-generation-core/src/runtime.ts b/extensions/image-generation-core/src/runtime.ts index 47782c1252d..224489654ee 100644 --- a/extensions/image-generation-core/src/runtime.ts +++ b/extensions/image-generation-core/src/runtime.ts @@ -1,131 +1,6 @@ -import { - buildNoCapabilityModelConfiguredMessage, - resolveCapabilityModelCandidates, - throwCapabilityGenerationFailure, -} from "openclaw/plugin-sdk/media-generation-runtime-shared"; -import { - createSubsystemLogger, - describeFailoverError, - getImageGenerationProvider, - isFailoverError, - listImageGenerationProviders, - parseImageGenerationModelRef, - type AuthProfileStore, - type FallbackAttempt, - type GeneratedImageAsset, - type ImageGenerationResolution, - type ImageGenerationResult, - type ImageGenerationSourceImage, - type OpenClawConfig, -} from "../api.js"; - -const log = createSubsystemLogger("image-generation"); - -export type GenerateImageParams = { - cfg: OpenClawConfig; - prompt: string; - agentDir?: string; - authStore?: AuthProfileStore; - modelOverride?: string; - count?: number; - size?: string; - aspectRatio?: string; - resolution?: ImageGenerationResolution; - inputImages?: ImageGenerationSourceImage[]; -}; - -export type GenerateImageRuntimeResult = { - images: GeneratedImageAsset[]; - provider: string; - model: string; - attempts: FallbackAttempt[]; - metadata?: Record; -}; - -function buildNoImageGenerationModelConfiguredMessage(cfg: OpenClawConfig): string { - return buildNoCapabilityModelConfiguredMessage({ - capabilityLabel: "image-generation", - modelConfigKey: "imageGenerationModel", - providers: listImageGenerationProviders(cfg), - fallbackSampleRef: "google/gemini-3-pro-image-preview", - }); -} - -export function listRuntimeImageGenerationProviders(params?: { config?: OpenClawConfig }) { - return listImageGenerationProviders(params?.config); -} - -export async function generateImage( - params: GenerateImageParams, -): Promise { - const candidates = resolveCapabilityModelCandidates({ - cfg: params.cfg, - modelConfig: params.cfg.agents?.defaults?.imageGenerationModel, - modelOverride: params.modelOverride, - parseModelRef: parseImageGenerationModelRef, - }); - if (candidates.length === 0) { - throw new Error(buildNoImageGenerationModelConfiguredMessage(params.cfg)); - } - - const attempts: FallbackAttempt[] = []; - let lastError: unknown; - - for (const candidate of candidates) { - const provider = getImageGenerationProvider(candidate.provider, params.cfg); - if (!provider) { - const error = `No image-generation provider registered for ${candidate.provider}`; - attempts.push({ - provider: candidate.provider, - model: candidate.model, - error, - }); - lastError = new Error(error); - continue; - } - - try { - const result: ImageGenerationResult = await provider.generateImage({ - provider: candidate.provider, - model: candidate.model, - prompt: params.prompt, - cfg: params.cfg, - agentDir: params.agentDir, - authStore: params.authStore, - count: params.count, - size: params.size, - aspectRatio: params.aspectRatio, - resolution: params.resolution, - inputImages: params.inputImages, - }); - if (!Array.isArray(result.images) || result.images.length === 0) { - throw new Error("Image generation provider returned no images."); - } - return { - images: result.images, - provider: candidate.provider, - model: result.model ?? candidate.model, - attempts, - metadata: result.metadata, - }; - } catch (err) { - lastError = err; - const described = isFailoverError(err) ? describeFailoverError(err) : undefined; - attempts.push({ - provider: candidate.provider, - model: candidate.model, - error: described?.message ?? (err instanceof Error ? err.message : String(err)), - reason: described?.reason, - status: described?.status, - code: described?.code, - }); - log.debug(`image-generation candidate failed: ${candidate.provider}/${candidate.model}`); - } - } - - throwCapabilityGenerationFailure({ - capabilityLabel: "image generation", - attempts, - lastError, - }); -} +export { + generateImage, + listRuntimeImageGenerationProviders, + type GenerateImageParams, + type GenerateImageRuntimeResult, +} from "openclaw/plugin-sdk/image-generation-runtime"; diff --git a/package.json b/package.json index b5fa4cf405b..586867ba9ff 100644 --- a/package.json +++ b/package.json @@ -580,6 +580,10 @@ "types": "./dist/plugin-sdk/image-generation.d.ts", "default": "./dist/plugin-sdk/image-generation.js" }, + "./plugin-sdk/image-generation-runtime": { + "types": "./dist/plugin-sdk/image-generation-runtime.d.ts", + "default": "./dist/plugin-sdk/image-generation-runtime.js" + }, "./plugin-sdk/image-generation-core": { "types": "./dist/plugin-sdk/image-generation-core.d.ts", "default": "./dist/plugin-sdk/image-generation-core.js" diff --git a/scripts/lib/plugin-sdk-entrypoints.json b/scripts/lib/plugin-sdk-entrypoints.json index 7af86b62846..7325e422673 100644 --- a/scripts/lib/plugin-sdk-entrypoints.json +++ b/scripts/lib/plugin-sdk-entrypoints.json @@ -134,6 +134,7 @@ "googlechat-runtime-shared", "media-generation-runtime-shared", "image-generation", + "image-generation-runtime", "image-generation-core", "music-generation", "music-generation-core", diff --git a/src/plugin-sdk/image-generation-runtime.ts b/src/plugin-sdk/image-generation-runtime.ts new file mode 100644 index 00000000000..d3b83ae4316 --- /dev/null +++ b/src/plugin-sdk/image-generation-runtime.ts @@ -0,0 +1,6 @@ +export { + generateImage, + listRuntimeImageGenerationProviders, + type GenerateImageParams, + type GenerateImageRuntimeResult, +} from "../image-generation/runtime.js";