mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 15:40:44 +00:00
feat(openai): default images to gpt-image-2
This commit is contained in:
@@ -6,7 +6,7 @@ import {
|
||||
|
||||
export const OPENAI_DEFAULT_MODEL = "openai/gpt-5.4";
|
||||
export const OPENAI_CODEX_DEFAULT_MODEL = "openai-codex/gpt-5.4";
|
||||
export const OPENAI_DEFAULT_IMAGE_MODEL = "gpt-image-1";
|
||||
export const OPENAI_DEFAULT_IMAGE_MODEL = "gpt-image-2";
|
||||
export const OPENAI_DEFAULT_TTS_MODEL = "gpt-4o-mini-tts";
|
||||
export const OPENAI_DEFAULT_TTS_VOICE = "alloy";
|
||||
export const OPENAI_DEFAULT_AUDIO_TRANSCRIPTION_MODEL = "gpt-4o-transcribe";
|
||||
|
||||
@@ -48,13 +48,23 @@ describe("openai image generation provider", () => {
|
||||
vi.unstubAllEnvs();
|
||||
});
|
||||
|
||||
it("advertises the current OpenAI image model and 2K/4K size hints", () => {
|
||||
const provider = buildOpenAIImageGenerationProvider();
|
||||
|
||||
expect(provider.defaultModel).toBe("gpt-image-2");
|
||||
expect(provider.models).toEqual(["gpt-image-2"]);
|
||||
expect(provider.capabilities.geometry?.sizes).toEqual(
|
||||
expect.arrayContaining(["2048x2048", "3840x2160", "2160x3840"]),
|
||||
);
|
||||
});
|
||||
|
||||
it("does not auto-allow local baseUrl overrides for image requests", async () => {
|
||||
mockGeneratedPngResponse();
|
||||
|
||||
const provider = buildOpenAIImageGenerationProvider();
|
||||
const result = await provider.generateImage({
|
||||
provider: "openai",
|
||||
model: "gpt-image-1",
|
||||
model: "gpt-image-2",
|
||||
prompt: "Draw a QA lighthouse",
|
||||
cfg: {
|
||||
models: {
|
||||
@@ -82,13 +92,40 @@ describe("openai image generation provider", () => {
|
||||
expect(result.images).toHaveLength(1);
|
||||
});
|
||||
|
||||
it("forwards generation count and custom size overrides", async () => {
|
||||
mockGeneratedPngResponse();
|
||||
|
||||
const provider = buildOpenAIImageGenerationProvider();
|
||||
const result = await provider.generateImage({
|
||||
provider: "openai",
|
||||
model: "gpt-image-2",
|
||||
prompt: "Create two landscape campaign variants",
|
||||
cfg: {},
|
||||
count: 2,
|
||||
size: "3840x2160",
|
||||
});
|
||||
|
||||
expect(postJsonRequestMock).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
url: "https://api.openai.com/v1/images/generations",
|
||||
body: {
|
||||
model: "gpt-image-2",
|
||||
prompt: "Create two landscape campaign variants",
|
||||
n: 2,
|
||||
size: "3840x2160",
|
||||
},
|
||||
}),
|
||||
);
|
||||
expect(result.images).toHaveLength(1);
|
||||
});
|
||||
|
||||
it("allows loopback image requests for the synthetic mock-openai provider", async () => {
|
||||
mockGeneratedPngResponse();
|
||||
|
||||
const provider = buildOpenAIImageGenerationProvider();
|
||||
const result = await provider.generateImage({
|
||||
provider: "mock-openai",
|
||||
model: "gpt-image-1",
|
||||
model: "gpt-image-2",
|
||||
prompt: "Draw a QA lighthouse",
|
||||
cfg: {
|
||||
models: {
|
||||
@@ -123,7 +160,7 @@ describe("openai image generation provider", () => {
|
||||
const provider = buildOpenAIImageGenerationProvider();
|
||||
const result = await provider.generateImage({
|
||||
provider: "openai",
|
||||
model: "gpt-image-1",
|
||||
model: "gpt-image-2",
|
||||
prompt: "Draw a QA lighthouse",
|
||||
cfg: {
|
||||
models: {
|
||||
@@ -150,21 +187,28 @@ describe("openai image generation provider", () => {
|
||||
expect(result.images).toHaveLength(1);
|
||||
});
|
||||
|
||||
it("uses JSON image_url edits for input-image requests", async () => {
|
||||
it("forwards edit count, custom size, and multiple input images", async () => {
|
||||
mockGeneratedPngResponse();
|
||||
|
||||
const provider = buildOpenAIImageGenerationProvider();
|
||||
const result = await provider.generateImage({
|
||||
provider: "openai",
|
||||
model: "gpt-image-1",
|
||||
model: "gpt-image-2",
|
||||
prompt: "Change only the background to pale blue",
|
||||
cfg: {},
|
||||
count: 2,
|
||||
size: "1024x1536",
|
||||
inputImages: [
|
||||
{
|
||||
buffer: Buffer.from("png-bytes"),
|
||||
mimeType: "image/png",
|
||||
fileName: "reference.png",
|
||||
},
|
||||
{
|
||||
buffer: Buffer.from("jpeg-bytes"),
|
||||
mimeType: "image/jpeg",
|
||||
fileName: "style.jpg",
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
@@ -172,12 +216,17 @@ describe("openai image generation provider", () => {
|
||||
expect.objectContaining({
|
||||
url: "https://api.openai.com/v1/images/edits",
|
||||
body: expect.objectContaining({
|
||||
model: "gpt-image-1",
|
||||
model: "gpt-image-2",
|
||||
prompt: "Change only the background to pale blue",
|
||||
n: 2,
|
||||
size: "1024x1536",
|
||||
images: [
|
||||
{
|
||||
image_url: "data:image/png;base64,cG5nLWJ5dGVz",
|
||||
},
|
||||
{
|
||||
image_url: "data:image/jpeg;base64,anBlZy1ieXRlcw==",
|
||||
},
|
||||
],
|
||||
}),
|
||||
}),
|
||||
|
||||
@@ -13,7 +13,15 @@ import { resolveConfiguredOpenAIBaseUrl, toOpenAIDataUrl } from "./shared.js";
|
||||
const DEFAULT_OPENAI_IMAGE_BASE_URL = "https://api.openai.com/v1";
|
||||
const DEFAULT_OUTPUT_MIME = "image/png";
|
||||
const DEFAULT_SIZE = "1024x1024";
|
||||
const OPENAI_SUPPORTED_SIZES = ["1024x1024", "1024x1536", "1536x1024"] as const;
|
||||
const OPENAI_SUPPORTED_SIZES = [
|
||||
"1024x1024",
|
||||
"1536x1024",
|
||||
"1024x1536",
|
||||
"2048x2048",
|
||||
"2048x1152",
|
||||
"3840x2160",
|
||||
"2160x3840",
|
||||
] as const;
|
||||
const OPENAI_MAX_INPUT_IMAGES = 5;
|
||||
const MOCK_OPENAI_PROVIDER_ID = "mock-openai";
|
||||
|
||||
|
||||
@@ -141,10 +141,12 @@ describe("openai plugin", () => {
|
||||
const authStore = { version: 1, profiles: {} };
|
||||
const result = await provider.generateImage({
|
||||
provider: "openai",
|
||||
model: "gpt-image-1",
|
||||
model: "gpt-image-2",
|
||||
prompt: "draw a cat",
|
||||
cfg: {},
|
||||
authStore,
|
||||
count: 2,
|
||||
size: "2048x2048",
|
||||
});
|
||||
|
||||
expect(resolveApiKeySpy).toHaveBeenCalledWith(
|
||||
@@ -157,10 +159,10 @@ describe("openai plugin", () => {
|
||||
expect.objectContaining({
|
||||
url: "https://api.openai.com/v1/images/generations",
|
||||
body: {
|
||||
model: "gpt-image-1",
|
||||
model: "gpt-image-2",
|
||||
prompt: "draw a cat",
|
||||
n: 1,
|
||||
size: "1024x1024",
|
||||
n: 2,
|
||||
size: "2048x2048",
|
||||
},
|
||||
}),
|
||||
);
|
||||
@@ -178,7 +180,7 @@ describe("openai plugin", () => {
|
||||
revisedPrompt: "revised",
|
||||
},
|
||||
],
|
||||
model: "gpt-image-1",
|
||||
model: "gpt-image-2",
|
||||
});
|
||||
});
|
||||
|
||||
@@ -193,10 +195,12 @@ describe("openai plugin", () => {
|
||||
|
||||
const result = await provider.generateImage({
|
||||
provider: "openai",
|
||||
model: "gpt-image-1",
|
||||
model: "gpt-image-2",
|
||||
prompt: "Edit this image",
|
||||
cfg: {},
|
||||
authStore,
|
||||
count: 2,
|
||||
size: "1536x1024",
|
||||
inputImages: [
|
||||
{ buffer: Buffer.from("x"), mimeType: "image/png" },
|
||||
{ buffer: Buffer.from("y"), mimeType: "image/jpeg", fileName: "ref.jpg" },
|
||||
@@ -213,10 +217,10 @@ describe("openai plugin", () => {
|
||||
expect.objectContaining({
|
||||
url: "https://api.openai.com/v1/images/edits",
|
||||
body: {
|
||||
model: "gpt-image-1",
|
||||
model: "gpt-image-2",
|
||||
prompt: "Edit this image",
|
||||
n: 1,
|
||||
size: "1024x1024",
|
||||
n: 2,
|
||||
size: "1536x1024",
|
||||
images: [
|
||||
{
|
||||
image_url: "data:image/png;base64,eA==",
|
||||
@@ -236,7 +240,7 @@ describe("openai plugin", () => {
|
||||
fileName: "image-1.png",
|
||||
},
|
||||
],
|
||||
model: "gpt-image-1",
|
||||
model: "gpt-image-2",
|
||||
});
|
||||
});
|
||||
|
||||
@@ -253,7 +257,7 @@ describe("openai plugin", () => {
|
||||
await expect(
|
||||
provider.generateImage({
|
||||
provider: "openai",
|
||||
model: "gpt-image-1",
|
||||
model: "gpt-image-2",
|
||||
prompt: "draw a cat",
|
||||
cfg: {
|
||||
models: {
|
||||
|
||||
@@ -17,7 +17,7 @@ import plugin from "./index.js";
|
||||
|
||||
const OPENAI_API_KEY = process.env.OPENAI_API_KEY ?? "";
|
||||
const LIVE_MODEL_ID = process.env.OPENCLAW_LIVE_OPENAI_PLUGIN_MODEL?.trim() || "gpt-5.4-nano";
|
||||
const LIVE_IMAGE_MODEL = process.env.OPENCLAW_LIVE_OPENAI_IMAGE_MODEL?.trim() || "gpt-image-1";
|
||||
const LIVE_IMAGE_MODEL = process.env.OPENCLAW_LIVE_OPENAI_IMAGE_MODEL?.trim() || "gpt-image-2";
|
||||
const LIVE_VISION_MODEL = process.env.OPENCLAW_LIVE_OPENAI_VISION_MODEL?.trim() || "gpt-4.1-mini";
|
||||
const liveEnabled = OPENAI_API_KEY.trim().length > 0 && process.env.OPENCLAW_LIVE_TEST === "1";
|
||||
const describeLive = liveEnabled ? describe : describe.skip;
|
||||
@@ -262,8 +262,9 @@ describeLive("openai plugin live", () => {
|
||||
cfg,
|
||||
agentDir,
|
||||
authStore: EMPTY_AUTH_STORE,
|
||||
timeoutMs: 45_000,
|
||||
size: "1024x1024",
|
||||
timeoutMs: 180_000,
|
||||
count: 1,
|
||||
size: "1536x1024",
|
||||
});
|
||||
|
||||
expect(generated.model).toBe(LIVE_IMAGE_MODEL);
|
||||
@@ -273,7 +274,7 @@ describeLive("openai plugin live", () => {
|
||||
} finally {
|
||||
await fs.rm(agentDir, { recursive: true, force: true });
|
||||
}
|
||||
}, 60_000);
|
||||
}, 240_000);
|
||||
|
||||
it("edits a reference image through the registered image provider", async () => {
|
||||
const { imageProviders } = await registerOpenAIPlugin();
|
||||
@@ -291,8 +292,9 @@ describeLive("openai plugin live", () => {
|
||||
cfg,
|
||||
agentDir,
|
||||
authStore: EMPTY_AUTH_STORE,
|
||||
timeoutMs: 45_000,
|
||||
size: "1024x1024",
|
||||
timeoutMs: 180_000,
|
||||
count: 1,
|
||||
size: "1024x1536",
|
||||
inputImages: [
|
||||
{
|
||||
buffer: createReferencePng(),
|
||||
@@ -309,7 +311,7 @@ describeLive("openai plugin live", () => {
|
||||
} finally {
|
||||
await fs.rm(agentDir, { recursive: true, force: true });
|
||||
}
|
||||
}, 60_000);
|
||||
}, 240_000);
|
||||
|
||||
it("describes a deterministic image through the registered media provider", async () => {
|
||||
const { mediaProviders } = await registerOpenAIPlugin();
|
||||
|
||||
Reference in New Issue
Block a user