

























@@ -7,6 +7,7 @@ import type {
77ImageGenerationSourceImage,
88} from "openclaw/plugin-sdk/image-generation";
99import { createSubsystemLogger } from "openclaw/plugin-sdk/logging-core";
10+import { resolveClosestSize } from "openclaw/plugin-sdk/media-generation-runtime";
1011import {
1112ensureAuthProfileStore,
1213isProviderApiKeyConfigured,
@@ -45,6 +46,7 @@ const OPENAI_SUPPORTED_SIZES = [
4546"3840x2160",
4647"2160x3840",
4748] as const;
49+const OPENAI_LEGACY_IMAGE_SIZES = ["1024x1024", "1536x1024", "1024x1536"] as const;
4850const OPENAI_MAX_INPUT_IMAGES = 5;
4951const OPENAI_MAX_IMAGE_RESULTS = 4;
5052const MAX_CODEX_IMAGE_SSE_BYTES = 64 * 1024 * 1024;
@@ -217,6 +219,46 @@ function resolveOpenAIImageRequestModel(
217219return model;
218220}
219221222+function resolveNativeOpenAIImageSizesForModel(model: string): readonly string[] {
223+switch (model) {
224+case "gpt-image-1":
225+case "gpt-image-1-mini":
226+return OPENAI_LEGACY_IMAGE_SIZES;
227+default:
228+return OPENAI_SUPPORTED_SIZES;
229+}
230+}
231+232+function resolveOpenAIImageRequestSize(params: {
233+model: string;
234+requestedSize?: string;
235+applyNativeLimits: boolean;
236+}): {
237+size: string;
238+metadata?: Record<string, string>;
239+} {
240+const requestedSize = params.requestedSize ?? DEFAULT_SIZE;
241+if (!params.applyNativeLimits) {
242+return { size: requestedSize };
243+}
244+const supportedSizes = resolveNativeOpenAIImageSizesForModel(params.model);
245+const size =
246+resolveClosestSize({
247+ requestedSize,
248+ supportedSizes,
249+}) ?? DEFAULT_SIZE;
250+if (size === requestedSize) {
251+return { size };
252+}
253+return {
254+ size,
255+metadata: {
256+ requestedSize,
257+normalizedSize: size,
258+},
259+};
260+}
261+220262function shouldAllowPrivateImageEndpoint(req: {
221263provider: string;
222264cfg: OpenClawConfig | undefined;
@@ -587,7 +629,12 @@ async function generateOpenAICodexImage(params: {
587629allowTransparentDefaultReroute: true,
588630});
589631const count = resolveOpenAIImageCount(req.count);
590-const size = req.size ?? DEFAULT_SIZE;
632+const sizeResolution = resolveOpenAIImageRequestSize({
633+ model,
634+requestedSize: req.size,
635+applyNativeLimits: true,
636+});
637+const size = sizeResolution.size;
591638const timeoutMs = resolveOpenAIImageTimeoutMs(req.timeoutMs);
592639const openai = req.providerOptions?.openai;
593640const background = openai?.background ?? req.background;
@@ -660,6 +707,7 @@ async function generateOpenAICodexImage(params: {
660707),
661708 model,
662709metadata: {
710+ ...sizeResolution.metadata,
663711responses: results.map((result) => result.metadata).filter(Boolean),
664712},
665713};
@@ -752,8 +800,13 @@ export function buildOpenAIImageGenerationProvider(): ImageGenerationProvider {
752800allowTransparentDefaultReroute: publicOpenAIBaseUrl,
753801});
754802const count = resolveOpenAIImageCount(req.count);
755-const size = req.size ?? DEFAULT_SIZE;
756803const timeoutMs = resolveOpenAIImageTimeoutMs(req.timeoutMs, { isAzure });
804+const sizeResolution = resolveOpenAIImageRequestSize({
805+ model,
806+requestedSize: req.size,
807+applyNativeLimits: publicOpenAIBaseUrl || isAzure,
808+});
809+const size = sizeResolution.size;
757810const url = isAzure
758811 ? buildAzureImageUrl(rawBaseUrl, model, isEdit ? "edits" : "generations")
759812 : `${baseUrl}/images/${isEdit ? "edits" : "generations"}`;
@@ -842,6 +895,7 @@ export function buildOpenAIImageGenerationProvider(): ImageGenerationProvider {
842895return {
843896 images,
844897 model,
898+ ...(sizeResolution.metadata ? { metadata: sizeResolution.metadata } : {}),
845899};
846900} finally {
847901await release();
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。