# FLUX.2 Klein generation provider ## Status and audited worker MediaRouter optionally integrates the FLUX worker as provider `flux`, model **`flux.2-klein-4b`**, modality `image`, task `text-to-image`. The audited worker reports Apache-2.0 and loads these FLUX.2 Klein 4B variants once: - `black-forest-labs/FLUX.2-klein-4B` (`Distilled (4 steps)`) - `black-forest-labs/FLUX.2-klein-base-4B` (`Base (50 steps)`) The worker contract is: | Method | Endpoint | Auth | Meaning | | --- | --- | --- | --- | | `GET` | `/health` | public | Liveness; `{"status":"ok"}` does not mean a model is ready | | `GET` | `/ready` | public | `ready`, `model_loaded`, `model`, `accepting_jobs`; returns `503` when not ready | | `GET` | `/v1/info` | public | Exact model ID, image type, Apache-2.0 license, and base/distilled variant map | | `POST` | `/v1/generate` | Bearer | Form or multipart asynchronous generation submission | | `GET` | `/v1/jobs/{id}` | Bearer | `queued`, `running`, `completed`, `failed`, or `cancelled` | | `POST` | `/v1/jobs/{id}/cancel` | Bearer | Cancels queued jobs only | | `GET` | `/v1/jobs/{id}/output` | Bearer | Streams a completed PNG | Availability requires configured credentials, healthy liveness, `ready` with a loaded/accepting model, exact `flux.2-klein-4b` image identity, Apache-2.0, and the two audited variant IDs. A health response alone never advertises FLUX. ## Backend configuration Set these backend-only values in deployment secrets: ```dotenv FLUX_SPACE_URL=https://your-flux-worker.hf.space FLUX_SPACE_TOKEN=replace-with-worker-secret AI_WORKER_CONNECT_TIMEOUT_SECONDS=10 AI_WORKER_REQUEST_TIMEOUT_SECONDS=60 AI_WORKER_READ_TIMEOUT_SECONDS=300 AI_WORKER_MAX_RETRIES=3 AI_WORKER_RETRY_BACKOFF_SECONDS=0.5 GENERATION_WORKER_ENABLED=true ``` `FLUX_SPACE_URL` and `FLUX_SPACE_TOKEN` must be configured together. The token must be 32–512 characters and is never returned by REST, MCP, n8n, SDKs, the frontend, audit records, or logs. Missing/malformed FLUX configuration leaves only FLUX unavailable; it does not block WAN, social providers, or startup. ## Typed request mapping MediaRouter retains the existing `/v1/generation/requests` API and required `Idempotency-Key`. It never exposes a FLUX URL, worker header, path, or job ID. ```json { "provider": "flux", "model_id": "flux.2-klein-4b", "modality": "image", "prompt": "A futuristic city at sunrise, cinematic architecture", "flux": { "mode_choice": "Distilled (4 steps)", "seed": 42, "randomize_seed": false, "width": 1024, "height": 1024, "num_inference_steps": 4, "guidance_scale": 1.0, "prompt_upsampling": false } } ``` The closed Pydantic `flux` schema supports only: | Field | Constraint/default | | --- | --- | | `prompt` | Required, nonblank, 1–4,000 characters | | `mode_choice` | `Distilled (4 steps)` (default) or `Base (50 steps)` | | `seed` | Integer 0–2,147,483,647; default 42 | | `randomize_seed` | Boolean; default false | | `width`, `height` | 256–1,024, multiples of 8; default 1,024 | | `num_inference_steps` | Integer 1–100; default 4 | | `guidance_scale` | Number 0–10; default 1.0 | | `prompt_upsampling` | Boolean; default false | Negative prompts and schedulers are not worker-supported and are rejected. Unknown fields are rejected before GPU work; no arbitrary provider payload is passed through. The worker accepts optional image-editing inputs, but the existing MediaRouter contract exposes zero or one workspace-owned canonical `input_asset_id`. That image must be readable, use image MIME, and be at most 20 MiB. The worker further validates decoded inputs (16,384 pixels per side, 40 million pixels, and 80 MiB aggregate decoded RGB). Text-only jobs use form fields; optional-image jobs use one `input_images` multipart field. ## Job, retry, and cancellation behavior ```text MediaRouter durable job ID ↓ FLUX form/multipart submission ↓ opaque FLUX provider job ID (internal only) ↓ bounded status polling ↓ fixed authenticated output endpoint ↓ canonical workspace-owned asset ``` FLUX states map to the existing MediaRouter state machine: `queued`, `running`, `completed` → output finalization → `succeeded`, `failed`, and `cancelled`. `(provider, external_job_id)` uniqueness and workspace-scoped repository operations prevent cross-workspace polling, cancellation, or output attachment. FLUX has no submission-idempotency or request lookup. A lost response after a connection failure, timeout, `502`, or `504` is terminal `GENERATION_SUBMISSION_AMBIGUOUS`, never a blind re-submit. Received `429` and `503` rejection responses can use bounded durable retries. Polling retries connection failures, timeouts, `429`, `502`, `503`, and `504`; validation, `400`, `401`, `403`, invalid worker jobs, generic `500`, and programming exceptions do not retry automatically. Only queued worker jobs can be confirmed cancelled. `409 FLUX_JOB_NOT_CANCELLABLE` for a running inference is a failed cancellation, not a cancellation success. The shared service retains requested, confirmed, unsupported, and failed cancellation distinctions. ## Output and security The worker reports only `type: image` and `output.png`. The adapter derives the fixed relative `/v1/jobs/{id}/output` path, requires `image/png`, and never trusts worker filesystem paths, output URLs, or client paths. Shared transport rules disable redirects/proxy environment use and reject unsafe worker origins, private literal IPs, traversal, query strings, fragments, and client-selected workers. PNG bytes are streamed to controlled staging, size/checksum-checked where the worker provides them, and verified through the PNG signature/IHDR dimensions. `CleanupService` and `CanonicalAssetService` publish a workspace-owned asset with SHA-256, MIME, output dimensions, safe metadata, and generation linkage. No provider-specific durable storage exists. ## Limitations and verification - Worker jobs/outputs are in-memory and disappear after a worker restart. - MediaRouter intentionally supports one optional edit image although the worker can accept four, preserving the established single-asset contract. - A live smoke test is **not verified** until `FLUX_SPACE_URL` and `FLUX_SPACE_TOKEN` are supplied to the backend; mocked tests need no HF credentials.