From fff11cbb57583df10f8f7395309afe83fffa32a4 Mon Sep 17 00:00:00 2001 From: NOXX - Commiter Date: Tue, 28 Jul 2026 20:37:22 +0300 Subject: [PATCH] fix(adobe-firefly): default gpt-image detailLevel to maximal (5) (#8863) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(adobe-firefly): default gpt-image detailLevel to maximal (5) GPT Image 2 quality is dominated by generationSettings.detailLevel (1-5). The SPA often defaults to 3 (medium); missing/auto quality previously mapped to 3 as well. Default now to 5 (high/max) so API clients and Media without an explicit quality still get maximal detail. Explicit low/medium still honored. * chore(quality): rebaseline adobeFireflyClient + changelog fragment adobeFireflyClient.ts 2317->2322 (+5) — this PR's own growth at the existing payload-build site. Covered by tests/unit/adobe-firefly.test.ts. Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> --------- Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> Co-authored-by: diegosouzapw --- .../8863-firefly-gpt-image-detail-level.md | 1 + config/quality/file-size-baseline.json | 5 ++- open-sse/services/adobeFireflyClient.ts | 17 +++++--- tests/unit/adobe-firefly.test.ts | 42 +++++++++++++++++++ 4 files changed, 57 insertions(+), 8 deletions(-) create mode 100644 changelog.d/fixes/8863-firefly-gpt-image-detail-level.md diff --git a/changelog.d/fixes/8863-firefly-gpt-image-detail-level.md b/changelog.d/fixes/8863-firefly-gpt-image-detail-level.md new file mode 100644 index 0000000000..3a4fb7c333 --- /dev/null +++ b/changelog.d/fixes/8863-firefly-gpt-image-detail-level.md @@ -0,0 +1 @@ +- **Adobe Firefly**: `gpt-image` requests now default `detailLevel` to maximal (5) instead of leaving the upstream default, so generations come back at the quality the model is capable of diff --git a/config/quality/file-size-baseline.json b/config/quality/file-size-baseline.json index b946cd8117..c4e3c54993 100644 --- a/config/quality/file-size-baseline.json +++ b/config/quality/file-size-baseline.json @@ -358,7 +358,7 @@ "open-sse/mcp-server/server.ts": 1407, "open-sse/mcp-server/tools/advancedTools.ts": 1120, "open-sse/services/accountFallback.ts": 1966, - "open-sse/services/adobeFireflyClient.ts": 2317, + "open-sse/services/adobeFireflyClient.ts": 2322, "open-sse/services/claudeCodeCompatible.ts": 1202, "open-sse/services/combo.ts": 3648, "open-sse/services/compression/strategySelector.ts": 1060, @@ -411,5 +411,6 @@ "_rebaseline_2026_07_28_8842_antigravity_projectid_refresh": "PR #8842 (fix/antigravity-projectid-refresh) own growth: open-sse/executors/antigravity.ts 1493->1528 (+35 = projectId discovery in refreshCredentials: import ensureAntigravityProjectAssigned + trim projectId + call ensureAntigravityProjectAssigned with 8s timeout + persistDiscoveredAntigravityProjectId + log success/failure). Irreducible wiring at the existing credential-refresh chokepoint. Covered by tests/unit/executor-antigravity.test.ts (4 new test cases).", "_rebaseline_2026_07_28_8842_antigravity_test": "PR #8842 test growth: tests/unit/executor-antigravity.test.ts new testFrozen 1098 (4 new test cases for projectId discovery during refresh: discovers when empty, skips when set, handles failure, skips when access_token not a string). All above cap 1000 on day one.", "_rebaseline_2026_07_28_8860_tokenrefresh_projectid": "PR #8860 (fix/antigravity-projectid-centralized) own test growth: tests/unit/token-refresh-service.test.ts 1311->1378 (+67 = 4 cases covering projectId discovery on the tokenRefresh.ts path — the Dashboard/health-check refresh route, which #8842 did not reach since that fixed the executor path). Covered by the same file.", - "_rebaseline_2026_07_28_8861_xiaomi_token_plan": "PR #8861 (feat/xiaomi-token-plan-protocol-selector) own growth: EditConnectionModal.tsx 1283->1316 (+33 = the per-connection API-protocol selector field) and open-sse/executors/base.ts 1540->1562 (+22 = alternate-format resolution at the existing buildUrl/headers chokepoint). Both are irreducible wiring at existing call sites." + "_rebaseline_2026_07_28_8861_xiaomi_token_plan": "PR #8861 (feat/xiaomi-token-plan-protocol-selector) own growth: EditConnectionModal.tsx 1283->1316 (+33 = the per-connection API-protocol selector field) and open-sse/executors/base.ts 1540->1562 (+22 = alternate-format resolution at the existing buildUrl/headers chokepoint). Both are irreducible wiring at existing call sites.", + "_rebaseline_2026_07_28_8863_firefly_detail_level": "PR #8863 (fix/adobe-firefly-gpt-detail-level-max) own growth: adobeFireflyClient.ts 2317->2322 (+5 = gpt-image detailLevel defaulting to maximal at the existing payload-build site). Covered by tests/unit/adobe-firefly.test.ts." } diff --git a/open-sse/services/adobeFireflyClient.ts b/open-sse/services/adobeFireflyClient.ts index 777416a29e..b9ee9e1589 100644 --- a/open-sse/services/adobeFireflyClient.ts +++ b/open-sse/services/adobeFireflyClient.ts @@ -660,13 +660,18 @@ export function resolveAdobeVideoModel(model: string): { return { id: "sora-2", spec: ADOBE_FIREFLY_VIDEO_MODELS["sora-2"] }; } +/** + * Map OpenAI/VibeProxy quality tiers onto Firefly gpt-image `generationSettings.detailLevel`. + * Wire range is integer 1–5 (discovery schema). Default is **maximal (5)** — + * the SPA often defaults to 3, but detail is critical for GPT Image 2 output quality. + * Explicit low/medium still honor the caller's choice. + */ function gptDetailLevel(quality: unknown): number { - // Live firefly.adobe.com default for gpt-image is detailLevel 3 (medium). - const q = String(quality ?? "medium").trim().toLowerCase(); - if (q === "high" || q === "4k" || q === "ultra") return 5; - if (q === "low" || q === "1k") return 1; - if (q === "medium" || q === "2k" || q === "standard" || q === "hd" || q === "auto") return 3; - return 3; + const q = String(quality ?? "high").trim().toLowerCase(); + if (q === "low" || q === "1k" || q === "1") return 1; + if (q === "medium" || q === "2k" || q === "standard" || q === "hd" || q === "3") return 3; + // high / 4k / ultra / auto / empty / unknown → max detail + return 5; } export function buildAdobeImagePayload(opts: { diff --git a/tests/unit/adobe-firefly.test.ts b/tests/unit/adobe-firefly.test.ts index 825d7c2dcc..5c30d2a930 100644 --- a/tests/unit/adobe-firefly.test.ts +++ b/tests/unit/adobe-firefly.test.ts @@ -190,6 +190,48 @@ test("buildAdobeImagePayload produces nano and gpt-image shapes", () => { assert.equal((gpt.modelSpecificPayload as Record).size, "auto"); assert.equal(gpt.size, undefined); assert.equal(gpt.outputResolution, undefined); + + // Missing / auto quality → maximal detail (5). Explicit low/medium still honored. + const gptDefault = buildAdobeImagePayload({ + prompt: "a dog", + aspectRatio: "1:1", + outputResolution: "1K", + modelSpec: ADOBE_FIREFLY_IMAGE_MODELS["gpt-image-2"], + }); + assert.equal((gptDefault.generationSettings as Record).detailLevel, 5); + const gptAuto = buildAdobeImagePayload({ + prompt: "a dog", + aspectRatio: "1:1", + outputResolution: "1K", + modelSpec: ADOBE_FIREFLY_IMAGE_MODELS["gpt-image"], + quality: "auto", + }); + assert.equal((gptAuto.generationSettings as Record).detailLevel, 5); + const gptLow = buildAdobeImagePayload({ + prompt: "a dog", + aspectRatio: "1:1", + outputResolution: "1K", + modelSpec: ADOBE_FIREFLY_IMAGE_MODELS["gpt-image"], + quality: "low", + }); + assert.equal((gptLow.generationSettings as Record).detailLevel, 1); + const gptMedium = buildAdobeImagePayload({ + prompt: "a dog", + aspectRatio: "1:1", + outputResolution: "1K", + modelSpec: ADOBE_FIREFLY_IMAGE_MODELS["gpt-image"], + quality: "medium", + }); + assert.equal((gptMedium.generationSettings as Record).detailLevel, 3); + // Firefly UI resolution tiers map onto the same detailLevel scale. + const gpt4k = buildAdobeImagePayload({ + prompt: "a dog", + aspectRatio: "1:1", + outputResolution: "1K", + modelSpec: ADOBE_FIREFLY_IMAGE_MODELS["gpt-image"], + quality: "4k", + }); + assert.equal((gpt4k.generationSettings as Record).detailLevel, 5); }); test("buildAdobeImagePayload attaches referenceBlobs like live adobe_atach_images capture", () => {