chore(img-gen): Drop dalle-3 as a image gen provider (#11032)

This commit is contained in:
Danelegend authored and GitHub committed 2026-05-12 22:28:13 +00:00
1 parent 3a1309ab9a
commit 5ec0fe43db
12 files changed
+134 -126

No files matched your search

@@ -0,0 +1,79 @@
"""dalle3 deprecation
Revision ID: 37b5864e9cff
Revises: 2c7f9d3a84a0
Create Date: 2026-05-12 10:29:16.985208
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = "37b5864e9cff"
down_revision = "2c7f9d3a84a0"
branch_labels = None
depends_on = None
_DEPRECATED_IMAGE_PROVIDER_IDS = ("openai_dalle_3", "azure_dalle_3")
_NEW_IMAGE_GENERATION_TOOL_DESCRIPTION = (
"The Image Generation Action allows the agent to use GPT-IMAGE-1 to generate images. "
"The action will be used when the user asks the agent to generate an image."
)
def upgrade() -> None:
conn = op.get_bind()
# Collect llm_provider IDs that back the deprecated image generation configs
# so we can clean them up after deleting the configs. Each image gen config
# owns its own LLM provider (created exclusively for image gen), and the
# LLMProvider -> ModelConfiguration FK cascade-deletes the model configuration.
llm_provider_ids = [
row[0]
for row in conn.execute(
sa.text("""
SELECT mc.llm_provider_id
FROM image_generation_config igc
JOIN model_configuration mc
ON mc.id = igc.model_configuration_id
WHERE igc.image_provider_id = ANY(:provider_ids)
"""),
{"provider_ids": list(_DEPRECATED_IMAGE_PROVIDER_IDS)},
).fetchall()
]
conn.execute(
sa.text(
"DELETE FROM image_generation_config "
"WHERE image_provider_id = ANY(:provider_ids)"
),
{"provider_ids": list(_DEPRECATED_IMAGE_PROVIDER_IDS)},
)
if llm_provider_ids:
conn.execute(
sa.text(
"DELETE FROM llm_provider__user_group "
"WHERE llm_provider_id = ANY(:llm_provider_ids)"
),
{"llm_provider_ids": llm_provider_ids},
)
conn.execute(
sa.text("DELETE FROM llm_provider WHERE id = ANY(:llm_provider_ids)"),
{"llm_provider_ids": llm_provider_ids},
)
conn.execute(
sa.text(
"UPDATE tool SET description = :description "
"WHERE in_code_tool_id = 'ImageGenerationTool'"
),
{"description": _NEW_IMAGE_GENERATION_TOOL_DESCRIPTION},
)
def downgrade() -> None:
pass
+4 -12
View File
@@ -1103,18 +1103,10 @@ ENTERPRISE_EDITION_ENABLED = (
# To configure image generation, please visit the Image Generation page in the Admin Panel.
#####
# Azure Image Configurations
AZURE_IMAGE_API_VERSION = os.environ.get("AZURE_IMAGE_API_VERSION") or os.environ.get(
"AZURE_DALLE_API_VERSION"
)
AZURE_IMAGE_API_KEY = os.environ.get("AZURE_IMAGE_API_KEY") or os.environ.get(
"AZURE_DALLE_API_KEY"
)
AZURE_IMAGE_API_BASE = os.environ.get("AZURE_IMAGE_API_BASE") or os.environ.get(
"AZURE_DALLE_API_BASE"
)
AZURE_IMAGE_DEPLOYMENT_NAME = os.environ.get(
"AZURE_IMAGE_DEPLOYMENT_NAME"
) or os.environ.get("AZURE_DALLE_DEPLOYMENT_NAME")
AZURE_IMAGE_API_VERSION = os.environ.get("AZURE_IMAGE_API_VERSION")
AZURE_IMAGE_API_KEY = os.environ.get("AZURE_IMAGE_API_KEY")
AZURE_IMAGE_API_BASE = os.environ.get("AZURE_IMAGE_API_BASE")
AZURE_IMAGE_DEPLOYMENT_NAME = os.environ.get("AZURE_IMAGE_DEPLOYMENT_NAME")
# configurable image model
IMAGE_MODEL_NAME = os.environ.get("IMAGE_MODEL_NAME", "gpt-image-1")
@@ -40,15 +40,12 @@ def _get_test_quality_for_model(model_name: str) -> str | None:
"""Returns the fastest quality setting for credential testing.
- gpt-image-*: 'low' (fastest)
- dall-e-3: 'standard' (faster than 'hd')
- Other models: None (use API default)
"""
model_lower = model_name.lower()
if "gpt-image-" in model_lower:
return "low"
elif "dall-e-3" in model_lower or "dalle-3" in model_lower:
return "standard"
return None
@@ -23,7 +23,7 @@ class TestImageGenerationRequest(BaseModel):
2. From existing provider: Provide source_llm_provider_id (backend fetches API key)
"""
model_name: str # e.g., "gpt-image-1", "dall-e-3"
model_name: str # e.g., "gpt-image-1"
# Option 1: Direct API key
provider: str | None = None # e.g., "openai", "azure"
@@ -55,7 +55,7 @@ class ImageGenerationConfigCreate(BaseModel):
# Required for both modes
image_provider_id: str # Static unique key (e.g., "openai_gpt_image_1")
model_name: str # e.g., "gpt-image-1", "dall-e-3"
model_name: str # e.g., "gpt-image-1"
# Option 1: Clone mode - use credentials from existing provider
source_llm_provider_id: int | None = None
@@ -79,7 +79,7 @@ class ImageGenerationConfigUpdate(BaseModel):
"""
# Required
model_name: str # e.g., "gpt-image-1", "dall-e-3"
model_name: str # e.g., "gpt-image-1"
# Note: image_provider_id cannot be changed during update
# Option 1: Clone mode - use credentials from existing provider
@@ -43,7 +43,7 @@ def test_create_image_generation_config(
config = ImageGenerationConfigManager.create(
image_provider_id="test-openai-dalle",
model_name="dall-e-3",
model_name="gpt-image-1",
provider="openai",
api_key="sk-test-key-12345",
is_default=False,
@@ -51,7 +51,7 @@ def test_create_image_generation_config(
)
assert config.image_provider_id == "test-openai-dalle"
assert config.model_name == "dall-e-3"
assert config.model_name == "gpt-image-1"
assert config.is_default is False
# Verify it exists in the list
@@ -96,7 +96,7 @@ def test_create_duplicate_config_fails(
# Create first config
ImageGenerationConfigManager.create(
image_provider_id="duplicate-test-id",
model_name="dall-e-3",
model_name="gpt-image-1",
provider="openai",
api_key="sk-test-key-1",
user_performing_action=admin_user,
@@ -127,7 +127,7 @@ def test_get_all_configs(
# Create multiple configs
config1 = ImageGenerationConfigManager.create(
image_provider_id="config-1",
model_name="dall-e-3",
model_name="gpt-image-1",
provider="openai",
api_key="sk-key-1",
user_performing_action=admin_user,
@@ -160,7 +160,7 @@ def test_get_config_credentials(
test_api_key = "sk-test-credentials-key-12345"
config = ImageGenerationConfigManager.create(
image_provider_id="credentials-test",
model_name="dall-e-3",
model_name="gpt-image-1",
provider="openai",
api_key=test_api_key,
user_performing_action=admin_user,
@@ -202,26 +202,26 @@ def test_update_config_direct_key_entry(
# Create initial config
config = ImageGenerationConfigManager.create(
image_provider_id="update-direct-test",
model_name="dall-e-3",
model_name="gpt-image-1",
provider="openai",
api_key="sk-initial-key",
user_performing_action=admin_user,
)
assert config.model_name == "dall-e-3"
assert config.model_name == "gpt-image-1"
# Update with new credentials and model
new_api_key = "sk-updated-key-12345"
updated_config = ImageGenerationConfigManager.update(
image_provider_id=config.image_provider_id,
model_name="dall-e-3",
model_name="gpt-image-1",
provider="openai",
api_key=new_api_key,
user_performing_action=admin_user,
)
assert updated_config.image_provider_id == config.image_provider_id
assert updated_config.model_name == "dall-e-3"
assert updated_config.model_name == "gpt-image-1"
# Verify credentials were updated (masked: first 4 + **** + last 4)
credentials = ImageGenerationConfigManager.get_credentials(
@@ -240,13 +240,13 @@ def test_update_config_clone_mode(
# Create initial config with direct credentials
config = ImageGenerationConfigManager.create(
image_provider_id="update-clone-test",
model_name="dall-e-3",
model_name="gpt-image-1",
provider="openai",
api_key="sk-initial-direct-key",
user_performing_action=admin_user,
)
assert config.model_name == "dall-e-3"
assert config.model_name == "gpt-image-1"
# Update by cloning from LLM provider
updated_config = ImageGenerationConfigManager.update(
@@ -275,7 +275,7 @@ def test_update_config_source_provider_not_found(
# Create initial config
config = ImageGenerationConfigManager.create(
image_provider_id="update-bad-source-test",
model_name="dall-e-3",
model_name="gpt-image-1",
provider="openai",
api_key="sk-initial-key",
user_performing_action=admin_user,
@@ -304,7 +304,7 @@ def test_delete_config(
# Create a config
config = ImageGenerationConfigManager.create(
image_provider_id="delete-test",
model_name="dall-e-3",
model_name="gpt-image-1",
provider="openai",
api_key="sk-delete-key",
user_performing_action=admin_user,
@@ -353,7 +353,7 @@ def test_set_default_config(
# Create a config that is not default
config = ImageGenerationConfigManager.create(
image_provider_id="default-test",
model_name="dall-e-3",
model_name="gpt-image-1",
provider="openai",
api_key="sk-test-key",
is_default=False,
@@ -387,7 +387,7 @@ def test_set_default_clears_previous(
# Create first config as default
config1 = ImageGenerationConfigManager.create(
image_provider_id="first-default",
model_name="dall-e-3",
model_name="gpt-image-1",
provider="openai",
api_key="sk-key-1",
is_default=True,
@@ -462,7 +462,7 @@ def test_create_config_missing_credentials(
f"{API_SERVER_URL}/admin/image-generation/config",
json={
"image_provider_id": "no-creds-test",
"model_name": "dall-e-3",
"model_name": "gpt-image-1",
},
headers=admin_user.headers,
)
@@ -481,7 +481,7 @@ def test_create_config_source_provider_not_found(
f"{API_SERVER_URL}/admin/image-generation/config",
json={
"image_provider_id": "bad-source-test",
"model_name": "dall-e-3",
"model_name": "gpt-image-1",
"source_llm_provider_id": 999999, # Non-existent ID
},
headers=admin_user.headers,
@@ -2205,7 +2205,7 @@ def test_all_three_provider_types_no_mixup(reset: None) -> None: # noqa: ARG001
_create_image_gen_config(
admin_user=admin_user,
image_provider_id=image_gen_provider_id,
model_name="dall-e-3",
model_name="gpt-image-1",
source_llm_provider_id=regular_provider["id"],
is_default=True,
)
@@ -2268,7 +2268,7 @@ def test_all_three_provider_types_no_mixup(reset: None) -> None: # noqa: ARG001
image_gen_config_data["is_default"] is True
), "Image gen config should be the default"
assert (
image_gen_config_data["model_name"] == "dall-e-3"
image_gen_config_data["model_name"] == "gpt-image-1"
), "Image gen config should have correct model name"
# Step 5: Verify no mixup - image gen providers don't appear in LLM provider lists
@@ -204,32 +204,13 @@ def test_openai_provider_rejects_reference_images_for_unsupported_model() -> Non
with pytest.raises(ValueError):
provider.generate_image(
prompt="edit this image",
model="dall-e-3",
model="unsupported-model",
size="1024x1024",
n=1,
reference_images=[ReferenceImage(data=b"image-1", mime_type="image/png")],
)
def test_openai_provider_rejects_multiple_reference_images_for_dalle3() -> None:
provider = OpenAIImageGenerationProvider(api_key="test-key")
with pytest.raises(
ValueError,
match="does not support image edits with reference images",
):
provider.generate_image(
prompt="edit this image",
model="dall-e-3",
size="1024x1024",
n=1,
reference_images=[
ReferenceImage(data=b"image-1", mime_type="image/png"),
ReferenceImage(data=b"image-2", mime_type="image/png"),
],
)
def test_azure_provider_uses_image_generation_without_reference_images() -> None:
provider = AzureImageGenerationProvider(
api_key="test-key",
@@ -303,31 +284,8 @@ def test_azure_provider_rejects_reference_images_for_unsupported_model() -> None
with pytest.raises(ValueError):
provider.generate_image(
prompt="edit this image",
model="dall-e-3",
model="unsupported-model",
size="1024x1024",
n=1,
reference_images=[ReferenceImage(data=b"image-1", mime_type="image/png")],
)
def test_azure_provider_rejects_multiple_reference_images_for_dalle3() -> None:
provider = AzureImageGenerationProvider(
api_key="test-key",
api_base="https://azure.example.com",
api_version="2024-05-01-preview",
)
with pytest.raises(
ValueError,
match="does not support image edits with reference images",
):
provider.generate_image(
prompt="edit this image",
model="dall-e-3",
size="1024x1024",
n=1,
reference_images=[
ReferenceImage(data=b"image-1", mime_type="image/png"),
ReferenceImage(data=b"image-2", mime_type="image/png"),
],
)
@@ -277,8 +277,8 @@ class TestIsEmbeddingModel:
def test_gpt4_not_embedding(self) -> None:
assert is_embedding_model("gpt-4") is False
def test_dall_e_not_embedding(self) -> None:
assert is_embedding_model("dall-e-3") is False
def test_image_model_not_embedding(self) -> None:
assert is_embedding_model("gpt-image-1") is False
def test_unknown_custom_model_not_embedding(self) -> None:
"""Custom/local models not in litellm's model DB should default to False."""
@@ -38,14 +38,6 @@ export const IMAGE_PROVIDER_GROUPS: ProviderGroup[] = [
description:
"A capable image generation model from OpenAI with strong prompt adherence.",
},
{
image_provider_id: "openai_dalle_3",
model_name: "dall-e-3",
provider_name: "openai",
title: "DALL-E 3",
description:
"OpenAI image generation model capable of generating rich and expressive images.",
},
],
},
{
@@ -75,14 +67,6 @@ export const IMAGE_PROVIDER_GROUPS: ProviderGroup[] = [
description:
"GPT Image 1 image generation model hosted on Microsoft Azure.",
},
{
image_provider_id: "azure_dalle_3",
model_name: "", // Extracted from deployment in target URI
provider_name: "azure",
title: "Azure OpenAI DALL-E 3",
description:
"DALL-E 3 image generation model hosted on Microsoft Azure.",
},
],
},
{
@@ -5,11 +5,11 @@ import { expectElementScreenshot } from "@tests/e2e/utils/visualRegression";
const IMAGE_GENERATION_URL = "/admin/configuration/image-generation";
const FAKE_CONNECTED_CONFIG = {
image_provider_id: "openai_dalle_3",
image_provider_id: "openai_gpt_image_1_5",
model_configuration_id: 100,
model_name: "dall-e-3",
model_name: "gpt-image-1.5",
llm_provider_id: 100,
llm_provider_name: "openai-dalle3",
llm_provider_name: "openai-gpt-image-1-5",
is_default: false,
};
@@ -71,7 +71,7 @@ test.describe("Image Generation Provider Disconnect", () => {
timeout: 20000,
});
const card = getProviderCard(page, "openai_dalle_3");
const card = getProviderCard(page, "openai_gpt_image_1_5");
await card.waitFor({ state: "visible", timeout: 10000 });
await expectElementScreenshot(mainContainer(page), {
@@ -81,14 +81,14 @@ test.describe("Image Generation Provider Disconnect", () => {
// Hover to reveal disconnect button, then verify
await card.hover();
const disconnectButton = card.getByRole("button", {
name: "Disconnect DALL-E 3",
name: "Disconnect GPT Image 1.5",
});
await expect(disconnectButton).toBeVisible();
await expect(disconnectButton).toBeEnabled();
// Mock the DELETE to succeed and update the config list
await page.route(
"**/api/admin/image-generation/config/openai_dalle_3",
"**/api/admin/image-generation/config/openai_gpt_image_1_5",
async (route) => {
if (route.request().method() === "DELETE") {
// Update the GET mock to return only the default config
@@ -119,7 +119,7 @@ test.describe("Image Generation Provider Disconnect", () => {
// Verify confirmation modal appears
const confirmDialog = page.getByRole("dialog");
await expect(confirmDialog).toBeVisible({ timeout: 5000 });
await expect(confirmDialog).toContainText("Disconnect DALL-E 3");
await expect(confirmDialog).toContainText("Disconnect GPT Image 1.5");
await expectElementScreenshot(confirmDialog, {
name: "image-gen-disconnect-non-default-modal",
@@ -233,12 +233,12 @@ test.describe("Image Generation Provider Disconnect", () => {
timeout: 20000,
});
// DALL-E 3 is not configured — should not have a disconnect button
const card = getProviderCard(page, "openai_dalle_3");
// GPT Image 1.5 is not configured — should not have a disconnect button
const card = getProviderCard(page, "openai_gpt_image_1_5");
await card.waitFor({ state: "visible", timeout: 10000 });
const disconnectButton = card.getByRole("button", {
name: "Disconnect DALL-E 3",
name: "Disconnect GPT Image 1.5",
});
await expect(disconnectButton).not.toBeVisible();
@@ -9,8 +9,6 @@ const IMAGE_GENERATION_URL =
const PROVIDERS = [
{ id: "openai_gpt_image_1_5", title: "GPT Image 1.5" },
{ id: "openai_gpt_image_1", title: "GPT Image 1" },
{ id: "openai_dalle_3", title: "DALL-E 3" },
{ id: "azure_dalle_3", title: "Azure OpenAI DALL-E 3" },
];
// Helper to find a provider card by its aria-label
@@ -82,7 +80,7 @@ test.describe("Image Generation Provider Configuration", () => {
);
});
test.describe("OpenAI DALL-E 3 Configuration", () => {
test.describe("OpenAI GPT Image 1 Configuration", () => {
const OPENAI_API_KEY = process.env.OPENAI_API_KEY;
test.skip(!OPENAI_API_KEY, "OPENAI_API_KEY environment variable not set");
@@ -91,22 +89,22 @@ test.describe("Image Generation Provider Configuration", () => {
// Clean up the image generation config created during the test
const apiClient = new OnyxApiClient(page.request);
try {
await apiClient.deleteImageGenerationConfig("openai_dalle_3");
console.log("[image-gen-test] Cleaned up DALL-E 3 config");
await apiClient.deleteImageGenerationConfig("openai_gpt_image_1");
console.log("[image-gen-test] Cleaned up GPT Image 1 config");
} catch (error) {
console.warn(
`[image-gen-test] Failed to clean up DALL-E 3 config: ${error}`
`[image-gen-test] Failed to clean up GPT Image 1 config: ${error}`
);
}
});
test.skip("should configure DALL-E 3 with API key", async ({ page }) => {
// Click Connect on DALL-E 3 card using aria-label
await openProviderModal(page, "openai_dalle_3");
test.skip("should configure GPT Image 1 with API key", async ({ page }) => {
// Click Connect on GPT Image 1 card using aria-label
await openProviderModal(page, "openai_gpt_image_1");
// Wait for modal to open
const modalDialog = page.getByRole("dialog", {
name: /connect dall-e 3/i,
name: /connect gpt image 1/i,
});
await expect(modalDialog).toBeVisible({ timeout: 10000 });
@@ -141,13 +139,13 @@ test.describe("Image Generation Provider Configuration", () => {
// Wait for page to update
await page.waitForLoadState("networkidle");
// Verify DALL-E 3 is now configured - should show "Current Default"
const dalleCard = getProviderCard(page, "openai_dalle_3");
// Verify GPT Image 1 is now configured - should show "Current Default"
const gptImageCard = getProviderCard(page, "openai_gpt_image_1");
await expect(
dalleCard.getByRole("button", { name: "Current Default" })
gptImageCard.getByRole("button", { name: "Current Default" })
).toBeVisible({ timeout: 15000 });
console.log("[image-gen-test] DALL-E 3 configured successfully");
console.log("[image-gen-test] GPT Image 1 configured successfully");
});
});
});
+3 -3
View File
@@ -943,20 +943,20 @@ export class OnyxApiClient {
* API: POST /api/admin/image-generation/config
* Schema (ImageGenerationConfigCreate):
* - image_provider_id: string (required) - unique key
* - model_name: string (required) - e.g., "dall-e-3"
* - model_name: string (required) - e.g., "gpt-image-1"
* - provider: string - e.g., "openai"
* - api_key: string
* - is_default: boolean
*
* @param imageProviderId - Unique identifier for the image generation config
* @param modelName - Model name (defaults to "dall-e-3")
* @param modelName - Model name (defaults to "gpt-image-1")
* @param provider - Provider name (defaults to "openai")
* @param isDefault - Whether this should be the default config (defaults to true)
* @returns The image_provider_id
*/
async createImageGenerationConfig(
imageProviderId: string,
modelName: string = "dall-e-3",
modelName: string = "gpt-image-1",
provider: string = "openai",
isDefault: boolean = true
): Promise<string> {