Repository navigation
feat(azure_ai): support FLUX.2 flex images - #39424
Conversation
|
PR #39424 labeled |
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
d76a1e7 to
82a9bc1
Compare
|
PR overviewAll previously flagged issues have been addressed. No open security concerns remain on this pull request. Security reviewNo open security issues remain on this pull request. Fixed/addressed: 1 · PR risk: 0/10 |
b75e5de to
911f66a
Compare
|
Rebased onto main and verified the affected tests locally. @greptileai please review the current tip for remaining regressions bugbot run |
|
@veria-ai please review the current tip after rebasing onto main and resolving the overlapping changes from upstream |
|
Resolved the CI compatibility findings and pushed the updated tip. @greptileai @veria-ai please review these latest changes bugbot run |
|
bugbot run |
|
@veria-ai |
|
bugbot run |
|
@veria-ai |
|
bugbot run |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit c0b0ba2. Configure here.
| """ | ||
| model_lower: Final = model.lower().replace(".", "-").replace("_", "-") | ||
| return "flux-2" in model_lower or "flux2" in model_lower |
There was a problem hiding this comment.
Model capabilities are hardcoded
The FLUX.2 capability check and supported-parameter list are hardcoded in this transformation. This violates the repository directive that model-specific flags be stored in model_prices_and_context_window.json and read through get_model_info. As written, adding another FLUX.2 variant or changing its capabilities requires a LiteLLM code release rather than a catalog update. This repository requirement must be satisfied before merging. The same issue applies to the inline parameter list at lines 73–88.
Rule Used: What: Do not hardcode model-specific flags in the codebase. Instead, put them in model_prices_and_context_window.json and then read them in via get_model_info Why: Prevents need for users to upgrade litellm each time a new model supports this featu... (source)
There was a problem hiding this comment.
The name check predates this PR, every image provider config lists params in code, and custom deployment names have no cost map entry
There was a problem hiding this comment.
That's fair. I re-evaluated this and agree the finding is not actionable here.
is_flux2_model in litellm/llms/azure_ai/image_generation/flux_transformation.py:67-75 is endpoint routing, not a model capability flag, and custom deployment names should not need individual cost-map entries. The parameter list at :77-88 is the provider transformation contract; it also encodes mappings and behavior (n → num_images, size parsing, and dropping OpenAI-only fields) that model_prices_and_context_window.json cannot represent. Given the established provider-config pattern, this should not block the PR. No change is needed for this comment.
mateo-berri
left a comment
There was a problem hiding this comment.
LGTM. Thanks for the contribution!
TLDR
Problem this solves:
azure_ai/FLUX.2-flexrequests are sent to the FLUX.2 Pro route, so Azure answers 404 for every generation and editguidance,steps,width,height) and multiple reference images have no mappingHow it solves it:
nandsizeto Azure'snum_images,width, andheightFlex Megapixelmeter in the Azure retail prices API,productName eq 'Azure BFL Flux Models')user,quality,background,moderation, andoutput_compressionare accepted and dropped, andsize: "auto"sends no dimensions so Azure picks its default (1024x1024 in this run)sizethat is notWxHwith a 400 naming the expected format instead of a 500Decisions in this PR, each with the alternative not taken:
user, which most OpenAI SDK callers send, would have broken working Pro traffic)size: "auto"maps to nowidth/heightrather than to a hardcoded 1024x1024, so Azure's own default applies; Flex is then billed at the cost calculator's 1024x1024 default, which matched what Azure generatedsizethat is notWxHis rejected with a 400 rather than dropped: before this PR Azure ignored the field and returned a default-size image, but silently ignoring a size is the bug this PR fixes and OpenAI rejects such values tootest_flux2_flex_rejects_invalid_sizeexpected a bareValueErrorforsize: "large", which the proxy surfaced as a 500APIConnectionError; it is nowtest_flux2_flex_rejects_invalid_size_as_bad_requestand expectslitellm.BadRequestErrorwith status 400, driven throughget_optional_params_image_genthe way the proxy reaches itUser Flow
Before: every FLUX.2 Flex request through Azure AI comes back 404, generation and edit alike, while FLUX.2 Pro works
POST https://litellm-domain/v1/images/generationswith"model": "azure_ai/FLUX.2-flex","prompt": "A red fox in a snowy forest at dawn","n": 2,"size": "1536x1024","guidance": 4.5, and"steps": 32litellm.NotFoundError: NotFoundError: Azure_aiException - NOT FOUND ... Received Model Group=azure_ai/FLUX.2-flexand no imagePOST https://litellm-domain/v1/images/editsas multipart with the same model, twoimagefiles, a prompt,n=1,size=1024x1024,guidance=4.5, andsteps=32x-litellm-response-cost: 0"model": "azure_ai/flux.2-flex"(lowercase) and receive the same HTTP 404"model": "azure_ai/FLUX.2-pro"and receive HTTP 200 with one image andx-litellm-response-cost: 0.04After: the same requests generate and edit FLUX.2 Flex images, each priced per pixel, and FLUX.2 Pro is unchanged
POST https://litellm-domain/v1/images/generationswith"model": "azure_ai/FLUX.2-flex","prompt": "A red fox in a snowy forest at dawn","n": 2,"size": "1536x1024","guidance": 4.5, and"steps": 32dataandx-litellm-response-cost: 0.0786432(1536 x 1024 pixels at $0.05 per megapixel)POST https://litellm-domain/v1/images/editsas multipart with the same model, twoimagefiles, a prompt,n=1,size=1024x1024,guidance=4.5, andsteps=32dataandx-litellm-response-cost: 0.0524288"model": "azure_ai/flux.2-flex"(lowercase) and receive HTTP 200 with one image andx-litellm-response-cost: 0.0524288"model": "azure_ai/FLUX.2-pro"and receive HTTP 200 with one image andx-litellm-response-cost: 0.04Relevant issues
Affected release
Linear ticket
Resolves LIT-5287
Pre-Submission checklist
Please complete all items before asking a LiteLLM maintainer to review your PR
uv run pytest tests/test_litellm/<your_test_file>.py -v. Leave the suites (make test-unit-*,make test-unit) to CI: it finishes in ~15 minutes where a laptop takes an hour or more@greptileaito re-request a review after pushing changes)Delays in PR merge?
If you're seeing a delay in your PR being merged, ping the LiteLLM Team on Slack (#pr-review).
Screenshots / Proof of Fix
Live QA against Azure AI Foundry (eastus resource, GlobalStandard deployments
FLUX.2-flexandFLUX.2-pro, real Azure calls). Both legs run the same script against a DB-less proxy booted with--num_workers 2and amodel_listcarryingazure_ai/FLUX.2-flex,azure_ai/flux.2-flex, andazure_ai/FLUX.2-prowithapi_base/api_keyfrom the environment. Before is the merge base 3ad9a7f on port 43461, After is this PR's head c0b0ba2 on port 32230. Each response is shown asgrep -iE '^HTTP|x-litellm-response-cost'over the saved headers plus ajqsummary that replaces everyb64_jsonwith its character count. The same After leg and the P1, P4, P7, P9, P10, and P11 scenarios were re-run on c0b0ba2 merged into main at a262672 (port 22279) and returned the same statuses and costsBefore (3ad9a7f): Flex 404s on generation, edit, and the lowercase spelling; Pro works
After (c0b0ba2): Flex generates and edits at a per-pixel cost, lowercase spelling included; Pro unchanged
Compatibility re-check on FLUX.2 Pro traffic: OpenAI-only fields, size auto, an invalid size, and edit form fields (Before 3ad9a7f on 43461, After c0b0ba2 on 32230)
Before
After
Observations from the run:
n: 2returns one image; Azure outputs one per request (left alone)api-version=2025-02-01-preview, edits sendpreview; both work (left alone)userorqualitywere 400 before; 200 now (fixed)response_formaton FLUX.2 is 400 on both sides (pre-existing)Type
🆕 New Feature
Caveats (if any)
Low
nabove 1 yields one image and bills one imageflexin it takes the Pro route, so a future third FLUX.2 variant needs its own mapping before it workssizethat is notWxH(for examplelarge) returned a default-size image with 200 before this PR because Azure ignored the field; it now returns 400 naming the expected format. Left as is: dropping the value instead would hide a caller's mistake the same way the old path did, and OpenAI rejects such sizes as wellsize: "auto"or nosize), Flex is billed at 1024x1024, which is what Azure generated in this run; if Azure changes its default, billing would not follow it. Left as is: measuring the returned image would mean decoding every base64 payload in the logging path for a default Azure has not changedFlex Ref Megapixel$0.05 per MP,Flux 2 Ref MP$0.015 per MP on Global Standard), so a Flex edit with one 1024x1024 reference logs about half of what Azure charges. Same gap as the pre-existing Pro and Kontext edit entries. Left for LIT-8140: the cost map has no key for reference-image pixels, and billing them means reading every uploaded reference's dimensions in the shared edit pathlitellm.completion_cost(..., n=2)now billsnimages when the caller passesnexplicitly, where the Azure calculator ignored it before; the proxy never passes it and bills the returned image count (P6 above). Left as is: matches every other provider's image cost calculatorn=abc,guidance=x) or more reference images than the model allows (11 on Flex, 9 on Pro) raises a plainValueError, which the proxy surfaces as a 500, the same path thesizefix moved to a 400. Left as is: no SDK client produces those inputs, and the fix is a behavioral commit that restarts the bot and QA cycle for an edge nobody hitsFinal Attestation