Skip to content

fix(providers): replace shut-down gpt-image-1, correct model prices, catch dead models at boot - #154

Merged
Eslam93 merged 4 commits into
mainfrom
fix/model-catalog-pricing
Nov 7, 2026
Merged

Eslam93 merged 4 commits into
mainfrom
fix/model-catalog-pricing

Conversation

@Eslam93

@Eslam93 Eslam93 commented Nov 6, 2026 •

Copy link
Copy Markdown
Owner

Why

Two bugs, and a gap that let the first one happen:

  1. Image generation was broken. The default OPENAI_IMAGE_MODEL=gpt-image-1 was shut down by OpenAI on 2026-10-23.
  2. Stored costs were 5x to 7.5x too low. gpt-5.4-mini was priced at $0.15 / $0.60 per 1M tokens; OpenAI's price is $0.75 input, $0.075 cached input and $4.50 output.
  3. Nothing caught a dead or unpriced model before money was spent. An unknown model was only rejected after the paid API call, and no check looked ahead to a shutdown date.

Every price, model id and date comes from OpenAI's own docs, read on 2026-11-06: the pricing page, the model pages for gpt-5.4-mini and gpt-image-2.5-flare, the image-generation guide, the Images API reference and the deprecations page.

What changed

Commit Change
fix(pricing) New backend/app/core/model_catalog.py: one dated catalog of model ids, prices, shutdown dates and replacements, each with a source URL. gpt-5.4-mini is priced correctly, and cached prompt tokens bill at the cached rate. Cost lookup tries the snapshot the API reports, then the configured model, so a new snapshot id never fails a call that's already paid for.
fix(images) Default image model is now gpt-image-2.5-flare, OpenAI's named replacement for gpt-image-1 and labelled "Default" on its model page. GPT Image models bill per token, so cost now comes from response.usage: text in $5, image in $8, image out $30 per 1M, with text output unbilled. If usage is ever missing, a clearly labelled per-image estimate is recorded and a warning logged. PNG output is requested explicitly, because storage saves .png. Retry and error handling are unchanged.
feat(config) Boot validation (AI_PROVIDER_MODE=openai only). A shut-down model fails in every environment, with a message naming the env var, the shutdown date and the replacement. Unknown, unpriced or wrong-kind models fail outside local.
ci python -m app.scripts.check_model_lifecycle plus .github/workflows/model-lifecycle.yml, running weekly, manually, and on PRs that touch the catalog, the script or config.py. It checks the configured models against the catalog and against OpenAI's deprecations page. A model that appears only as a substitute there doesn't trip it. If the page can't be fetched or parsed, the job fails loudly instead of passing blind.

Docs updated for current-state claims only: README, ARCHITECTURE and .env.example. DEVLOG history is left alone. The old ~$0.005-per-piece and ~$3–8-per-week estimates were calculated from the wrong price table, so they were removed rather than re-guessed.

Behaviour changes to know about

  • An existing .env with OPENAI_IMAGE_MODEL=gpt-image-1, copied from the old .env.example, now refuses to boot, even in local. The error says to set gpt-image-2.5-flare.
  • New text-generation costs are recorded at the real rates, about 5x to 7.5x higher than before. Rows written earlier keep their old, understated costs.
  • httpx moved from the dev group to the runtime dependencies, because the lifecycle script, which ships in app/, imports it.

Verification

  • ruff check, ruff format --check and mypy app (strict) pass.
  • pytest: 466 passed (331 on main). Coverage is 89.05%, up from 86.84%, with integration tests run against a local Postgres. New modules: model_catalog.py and check_model_lifecycle.py at 100%.
  • Includes a check that 1,000 input + 1,000 output gpt-5.4-mini tokens cost $0.00525.
  • Lifecycle script with a live fetch of OpenAI's deprecations page: 147 rows parsed, both shipped defaults OK, exit 0.
  • Run against a saved copy of the page, it flags gpt-image-1 (2026-10-23) and does not flag gpt-image-2.5-flare.
  • Reviewed by three independent passes (prices and facts, behaviour and tests, CI and script). All 13 low-severity findings were fixed.

Not verified: no live OpenAI API call was made, because no API key was used. Before relying on image generation in production, generate one image with gpt-image-2.5-flare and check that the recorded cost matches the usage tokens.

Stack

This is PR 1 of 3. Next is backend hardening, #155 (stacked on this one), then frontend hardening, #156 (stacked on that). Merge them in order.

🤖 Generated with Claude Code

Eslam93 and others added 4 commits November 6, 2026 20:25
OpenAI bills gpt-5.4-mini at $0.75 input, $0.075 cached input and $4.50
output per 1M tokens; the old $0.15/$0.60 table recorded text costs 5-7.5x
too low. Prices now live in a dated, sourced catalog, cached prompt tokens
bill at the cached rate, and an unpriced response snapshot falls back to
the configured model instead of raising after the call was paid for.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
OpenAI shut gpt-image-1 down on 2026-10-23, so image generation with the
shipped default failed. gpt-image-2.5-flare is OpenAI's named replacement.
GPT Image models bill per token, so cost now comes from response.usage at
catalog rates, falling back to a labelled per-image estimate only when
usage is missing; PNG output is requested to match the stored extension.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An unknown or unpriced model was only discovered after the paid API call,
and nothing flagged a configured model past its shutdown date. Settings
now checks both OpenAI models against the catalog in openai mode: a
shut-down model fails in every environment, and an unknown, wrong-kind or
unpriced one fails outside local. Errors name the env var and replacement.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
gpt-image-1's shutdown went unnoticed until image generation broke.
check_model_lifecycle fails if a configured model is unknown, unpriced,
retired or within --days of a catalogued shutdown, or if OpenAI's
deprecations page lists it as deprecated (substitute-only mentions don't
count; an unreadable page fails as "could not verify"). Runs weekly in CI.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Eslam93
Eslam93 marked this pull request as ready for review November 6, 2026 18:56
@Eslam93
Eslam93 merged commit 57b57d8 into main Nov 7, 2026
2 checks passed
Eslam93 added a commit that referenced this pull request Nov 7, 2026
#154 landed on main as one squash commit (57b57d8) whose tree is this
branch's old base, so this merge keeps this branch's tree unchanged
(-s ours) and makes main its merge base. The PR diff is again only this
branch's own changes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Eslam93
Eslam93 deleted the fix/model-catalog-pricing branch November 7, 2026 03:29
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.

1 participant