Skip to content

fix(ai-image): refresh model catalogs, unify txt2img requests, expand docs - #3889

Merged
Salazareo merged 4 commits into
mainfrom
fix/ai-image-model-sync-and-normalization
Sep 21, 2026
Merged

Salazareo merged 4 commits into
mainfrom
fix/ai-image-model-sync-and-normalization

Conversation

@404oops

@404oops 404oops commented Sep 16, 2026

Copy link
Copy Markdown
Collaborator

Image-generation maintenance for the standard AI checklist: refresh the model catalogs, normalize how puter.ai.txt2img() requests are built, and expand the docs. Independent of #3887, which carries the chat/video pieces split off this tree — the two touch disjoint areas.

Model catalogs

Every provider's model list was checked against what the vendor actually offers (re-probed on 2026-09-16), and for paid models a live generation sweep across the catalog (114 of 117 succeeded; 3 recorded failures are surfaced when requested):

  • Gemini: use the current stable ids (gemini-3-pro-image, gemini-3.1-flash-image); retired -preview spellings kept as aliases; gemini-3.1-flash-image is now the default. gemini-2.5-flash-image stays available until Google's 2026-10-02 shutdown. Token tables and prices updated.
  • OpenAI: gpt-image-1 and related ids are deprecated upstream, so they're hidden from listing but still usable until their shutdown dates; gpt-image-2 is the new default.
  • xAI: adds grok-imagine-image-2.0 with its low/medium quality tiers and separate resolution option; edit requests now accept up to 5 reference images (previously truncated silently).
  • BytePlus: adds the 3K/4K tiers, per-model size limits, and resolution tables per aspect ratio.
  • Cloudflare: adds SDXL Lightning, SDXL Base 1.0 and SD 1.5 Inpainting (with mask support); per-model step/size bounds; FLUX.2 uploads send real bytes.
  • Replicate: adds 88 models driven by their API schemas, version-pinned predictions, per-tier/second billing with price sources, and retired ids rejected by name.
  • Together: all image routes are disabled (thirdPartySharing data policy) because Together rejects all image models unless the org opts into third-party data sharing; requests fail with bad_request before any upstream call and the models are hidden from discovery. Retired ids are blocked so they can't silently route to Cloudflare.

Request normalization

What you pass is now what each provider interprets by the same rules: the driver turns ratio / width+height / aspect_ratio into one imageSize, validates prompt, quality and resolution once, accepts short provider hints ('openai', 'gemini', …) as well as full driver ids, and hands every provider an immutable copy of your options. Shared helpers standardize prompt checks, aspect snapping, and content-sniffed data URIs so the returned image MIME type is correct on every provider. Replicate predictions are created once, cancelled on abort or deadline, and input fan-out is bounded by count, bytes, concurrency, and time.

About normalize: the image response shape is already uniform across browsers and Node (a single image element, or { src }), so there is no vendor-specific shape to convert. The SDK doesn't send normalize for txt2img(), and the docs say so.

SDK (backward compatible)

txt2img() keeps all three call forms. It now copies your options instead of mutating them (frozen objects work), and rejects missing, blank, or non-string prompts with prompt_required in every form. No option, response field, or error code was renamed.

Docs

txt2img.md rewritten per provider with defaults, discovery, availability notes, and output-size rules; new catalog and pricing page at AI/image-models.md; image-generation limits added to rate-limits-and-quotas.md.

Security notes

No auth or permission changes. Caller-supplied image URLs stay behind secureFetch; Replicate fetches are capped at 30 MB, 30 s, and 10 references. Error messages name the model and provider only.

Verification

  • npx vitest run --config src/backend/vitest.config.ts src/backend/drivers/ai-image src/backend/drivers/util/imageInput.test.ts (597 passed, 3 skipped)
  • npx vitest run src/puter-js/src/modules/ai/ai.test.js (62 passed)
  • npm run build:workerLib && npm run test:puterjs:node (507 passed, 67 skipped)
  • npm run typecheck clean; npm run check:puterjs:types clean; eslint clean on touched sources
  • Vendor listings re-probed 2026-09-16 with configured keys. Deliberate omissions: chatgpt-image-latest, Cloudflare dreamshaper-8-lcm, BytePlus seedream-4-0-20260415 (no published price).

Model sync against every vendor listing and a live generation sweep:
Gemini stable ids replace the retired preview spellings (2.5 Flash Image
delisted ahead of its 2026-10-02 shutdown), OpenAI gpt-image-1/-1-mini/-1.5
are delisted but routable until their shutdown dates with gpt-image-2 as
the default, xAI gains grok-imagine-image-2.0 with its quality tiers,
BytePlus gains the 3K/4K tiers and per-model pixel bounds, Cloudflare
gains SDXL Lightning/Base and SD 1.5 Inpainting, Replicate gains a
schema-driven catalog of 88 additional models with version-pinned
community predictions, and every Together image route is excluded for
the third-party data-sharing requirement.

Request normalization: the driver collapses ratio/width/height/aspect_ratio
into one imageSize with aspect-versus-pixel intent, validates prompt,
quality and resolution once, resolves provider hints (short names or
full driver ids) and aliases with exact ids winning over resellers, and
hands each provider an immutable copy of the caller's args. Providers
share prompt validation, aspect snapping, and content-sniffed data URIs
so responses carry the right MIME type. Replicate predictions are created
once, cancelled on abort or deadline, and bounded in input fan-out.

SDK: txt2img copies caller options, rejects blank prompts with
prompt_required in every call form, and documents that normalize has no
effect because the image return shape is already uniform.

Docs: txt2img options per provider, provider defaults and discovery,
availability notes, a new image model catalog and pricing page, and the
image-generation limits in the quotas page.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Sep 16, 2026

Copy link
Copy Markdown
Contributor

Coverage Report for puter.js SDK

Status Category Percentage Covered / Total
🔵 Lines 62.63%
⬆️ +0.01%
4841 / 7729
🔵 Statements 61.12%
⬆️ +0.01%
5156 / 8435
🔵 Functions 63.56%
🟰 ±0%
916 / 1441
🔵 Branches 54.48%
⬆️ +0.05%
3231 / 5930
File Coverage
File Stmts Branches Functions Lines Uncovered Lines
Changed Files
src/puter-js/src/modules/ai/image.js 94.73%
⬆️ +5.26%
92%
⬆️ +7.00%
100%
🟰 ±0%
94.73%
⬆️ +5.26%
49
Generated in workflow #720 for commit bcfdc45 by the Vitest Coverage Report Action

@github-actions

github-actions Bot commented Sep 16, 2026

Copy link
Copy Markdown
Contributor

Coverage Report

Status Category Percentage Covered / Total
🔵 Lines 94.19%
⬆️ +0.10%
31248 / 33172
🔵 Statements 92.21%
⬆️ +0.13%
34005 / 36876
🔵 Functions 91.34%
⬆️ +0.08%
5770 / 6317
🔵 Branches 81.7%
⬆️ +0.36%
22916 / 28046
File Coverage
File Stmts Branches Functions Lines Uncovered Lines
Changed Files
src/backend/controllers/types.ts 100%
🟰 ±0%
100%
🟰 ±0%
83.33%
🟰 ±0%
100%
🟰 ±0%
src/backend/drivers/meta.ts 94.59%
🟰 ±0%
93.47%
🟰 ±0%
100%
🟰 ±0%
94.77%
🟰 ±0%
41, 63, 80, 88, 98, 133-135, 164-166, 228
src/backend/drivers/types.ts 100%
🟰 ±0%
100%
🟰 ±0%
100%
🟰 ±0%
100%
🟰 ±0%
src/backend/drivers/ai-image/ImageGenerationDriver.ts 94.14%
⬆️ +2.48%
88.63%
⬆️ +9.06%
96.15%
⬆️ +1.42%
93.75%
⬆️ +2.58%
142, 289-293, 439-448, 528-532, 540-544, 571, 574, 605-609
src/backend/drivers/ai-image/imageDimensions.ts 98.03% 98.46% 100% 100% 150
src/backend/drivers/ai-image/imageOutput.ts 100% 100% 100% 100%
src/backend/drivers/ai-image/imageValidation.ts 100% 100% 100% 100%
src/backend/drivers/ai-image/inputImage.ts 100%
🟰 ±0%
100%
🟰 ±0%
100%
🟰 ±0%
100%
🟰 ±0%
src/backend/drivers/ai-image/types.ts 100%
🟰 ±0%
100%
🟰 ±0%
100%
🟰 ±0%
100%
🟰 ±0%
src/backend/drivers/ai-image/providers/byteplus/BytePlusImageProvider.ts 97.87%
⬆️ +0.91%
90%
⬆️ +2.50%
100%
🟰 ±0%
97.8%
⬆️ +0.93%
153-155, 165-167
src/backend/drivers/ai-image/providers/byteplus/models.ts 100%
🟰 ±0%
100%
🟰 ±0%
100%
🟰 ±0%
100%
🟰 ±0%
src/backend/drivers/ai-image/providers/cloudflare/CloudflareImageProvider.ts 85%
⬆️ +4.30%
76.3%
⬆️ +3.95%
100%
🟰 ±0%
89.01%
⬆️ +3.39%
46-48, 91-97, 101-103, 171, 287, 304-307, 309, 333, 360, 391, 394, 396, 398-399, 402, 408-409, 414, 417, 421-423, 432, 439, 441, 450-453
src/backend/drivers/ai-image/providers/cloudflare/models.ts 100%
🟰 ±0%
100%
🟰 ±0%
100%
🟰 ±0%
100%
🟰 ±0%
src/backend/drivers/ai-image/providers/gemini/GeminiImageProvider.ts 92.53%
⬆️ +1.91%
81.57%
⬆️ +7.50%
100%
🟰 ±0%
95.27%
⬆️ +0.36%
49, 72-74, 106-110, 244, 250, 265, 282, 290, 292, 294
src/backend/drivers/ai-image/providers/gemini/models.ts 100%
🟰 ±0%
100%
🟰 ±0%
100%
🟰 ±0%
100%
🟰 ±0%
src/backend/drivers/ai-image/providers/openai/OpenAiImageProvider.ts 78.02%
⬆️ +0.49%
70%
⬆️ +0.16%
96%
⬇️ -0.15%
79.71%
⬆️ +0.55%
79, 97-104, 108-110, 237, 246, 266-299, 320-324, 328, 334, 341, 345, 370, 372-374, 377-379, 387-389, 399-400, 417, 419, 475-481
src/backend/drivers/ai-image/providers/openai/models.ts 100%
🟰 ±0%
100%
🟰 ±0%
100%
🟰 ±0%
100%
🟰 ±0%
src/backend/drivers/ai-image/providers/replicate/ReplicateImageGenerationProvider.ts 93.59%
⬆️ +12.41%
87.17%
⬆️ +14.10%
100%
⬆️ +4.77%
96.21%
⬆️ +11.77%
72, 204-206, 228, 236, 238-239, 248-251, 305-309, 427, 513, 514, 590, 754-756, 779, 796-800, 808-812, 833, 899
src/backend/drivers/ai-image/providers/replicate/catalog.ts 100% 100% 100% 100%
src/backend/drivers/ai-image/providers/replicate/catalogRequest.ts 88.12% 82.14% 88% 88.88% 94, 100, 103, 105, 107, 114, 124, 173-186, 226, 232, 314-321, 390
src/backend/drivers/ai-image/providers/replicate/models.ts 100%
🟰 ±0%
100%
🟰 ±0%
100%
🟰 ±0%
100%
🟰 ±0%
src/backend/drivers/ai-image/providers/together/TogetherImageProvider.ts 92.02%
⬆️ +3.79%
86.39%
⬆️ +12.52%
100%
🟰 ±0%
91.85%
⬆️ +3.46%
63-65, 95-97, 120-122, 130-132, 140, 148, 179-186, 205-212, 272, 274, 282-284
src/backend/drivers/ai-image/providers/together/models.ts 100%
🟰 ±0%
100%
🟰 ±0%
100%
🟰 ±0%
100%
🟰 ±0%
src/backend/drivers/ai-image/providers/xai/XAIImageProvider.ts 96.82%
⬆️ +3.17%
90.54%
⬆️ +10.83%
100%
⬆️ +7.70%
98.3%
⬆️ +3.39%
120-122, 222
src/backend/drivers/ai-image/providers/xai/models.ts 100%
🟰 ±0%
100%
🟰 ±0%
100%
🟰 ±0%
100%
🟰 ±0%
src/backend/drivers/util/imageInput.ts 100%
🟰 ±0%
96.29%
⬆️ +3.70%
100%
🟰 ±0%
100%
🟰 ±0%
src/backend/services/auth/types.ts 100%
🟰 ±0%
100%
🟰 ±0%
100%
🟰 ±0%
100%
🟰 ±0%
src/backend/services/events/workerSeam.ts 83.72%
🟰 ±0%
76.92%
🟰 ±0%
100%
🟰 ±0%
88.57%
🟰 ±0%
139-143, 155, 172
src/backend/util/appIcon.ts 97.26%
🟰 ±0%
97.12%
🟰 ±0%
100%
🟰 ±0%
99.19%
🟰 ±0%
92, 97, 260, 360
Generated in workflow #1923 for commit bcfdc45 by the Vitest Coverage Report Action

…sions

imageDataUri only decoded the first 24 base64 chars (18 bytes) before
sniffImageMime, which cannot see an <svg> root behind an XML prolog -
SVG outputs from recraft-v*-svg models were being labeled image/png.
Decode enough of the payload to cover the 8 KB SVG sniff window.

dimension() accepted string number literals ('0x10', '1e3') as if they
were decimal dimensions; restrict to plain decimal notation.
@404oops 404oops changed the title fix(ai-image): sync image catalogs, unify request shape, document models fix(ai-image): refresh model catalogs, unify txt2img requests, expand docs Sep 16, 2026
@404oops
404oops marked this pull request as ready for review September 16, 2026 20:24
Comment thread src/docs/src/AI/image-models.md Outdated
The image model catalog and pricing page duplicated the always up to date
model directory at developer.puter.com/ai/models. Link to the directory
from txt2img-related docs and keep the Together data-sharing exclusion
note self-contained.

@reynaldichernando reynaldichernando left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

Resolves conflicts with the hardening change (#3904):

- ImageGenerationDriver: keep the driver-scoped metering getter from main
  and the async onServerStart from this branch.
- OpenAI / xAI image providers: keep this branch's 401 guard on a missing
  actor, then derive the upstream user identifier via
  upstreamUserIdentifier() from main.
- xAI: drop the now-unused assertInputImageString import in favour of
  toUrlOrDataUri.
- Provider tests build the actor fixture with makeActor() so effectiveApp
  is derived from app, matching how the helper resolves it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@Salazareo
Salazareo merged commit 027e9a7 into main Sep 21, 2026
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants