Skip to content

fix(zen): strip images for the Zen models that reject them (#1043) - #1070

Open
lidge-jun wants to merge 1 commit into
codex/1057-deepseek-effort-ladderfrom
codex/1043-zen-text-only
Open

fix(zen): strip images for the Zen models that reject them (#1043)#1070
lidge-jun wants to merge 1 commit into
codex/1057-deepseek-effort-ladderfrom
codex/1043-zen-text-only

Conversation

@lidge-jun

Copy link
Copy Markdown
Owner

Stacked on #1069 (codex/1057-deepseek-effort-ladder). Both PRs edit the same opencode-free provider object two lines apart, so they are ordered rather than parallel. Retarget to dev once #1069 lands.

Summary

The opencode-zen entry declared no noVisionModels and no modality metadata, and both the vision sidecar and the fail-closed strip key on that list. So an image_url part went upstream verbatim and the whole request came back 400.

Zen publishes nothing to derive this from. Its /v1/models returns only id, object, created, owned_by — no capability field at all, which is the root cause rather than the evidence. The reporter's suggested fix (strip whenever inputModalities lacks "image") would therefore do nothing for exactly the provider that motivated the issue: the metadata is undefined there, and live-discovered modalities are never copied into the request-time provider config. It would also flip a deliberate regression guard asserting that unlisted models keep forwarding images.

So each of the eight Zen free models was measured against the live endpoint on 2026-08-05, text control first, then a 1×1 PNG:

model image request verdict
big-pickle invalid_request_error … unknown variant 'image_url' text-only
nemotron-3-ultra-free [404] No endpoints found that support image input text-only
ling-3.0-flash-free same 404 text-only
north-mini-code-free same 404 text-only
laguna-s-2.1-free same 404 text-only
deepseek-v4-flash-free [400] Model only supports text input text-only
mimo-v2.5-free 200, narrates the image vision-capable
longcat-2.0-free 200, completion vision-capable

big-pickle reproduces the reported error verbatim, so the defect is confirmed end to end rather than by analogy.

Two models accept images and are deliberately excluded. A community report claimed the free MiMo model refuses them; it does not. Listing it would have silently swapped a working image for a caption — a worse failure than the 400 this fixes, because nothing surfaces it. The parity test carries a negative assertion so a future "classify all the free models" patch fails loudly instead of shipping.

This is a dated exception list, not a capability model. Zen discovers its roster live while this list is static, so the constant carries its measurement date and the docs say to re-probe before extending it. The general modality-driven default remains a follow-up, and it needs live modality metadata to become canonical first.

Closes #1043. This also closes the Zen half of #1024; that issue's TR / moonshotai/kimi-k3-free half depends on reporter configuration for a provider that is not in the registry, so #1024 stays open.

Residual worth naming. The probe ran unauthenticated while opencode-zen is key-auth. Re-probing with the client header removed entirely gave identical results, and a bogus bearer token returns AuthError before any model logic — so capability is enforced upstream of authentication and the header was never load-bearing. What is still unproven is whether an authenticated account is served a different roster under the same ids. A reviewer with a Zen key can settle that in one command; the fallback, if it differs, is to scope the list to opencode-free alone.

Verification

$ bun run typecheck
(clean)

$ bun test tests/vision-sidecar-e2e.test.ts tests/provider-registry-parity.test.ts
 39 pass, 0 fail

$ bun test <provider/vision/catalog scope, 11 files>
 179 pass, 0 fail

$ bun run privacy:scan
Privacy scan passed

Activation evidence: the new e2e case drives a listed Zen model end to end and asserts the effect — image bytes absent from the captured upstream body, omission marker present — not merely a 200. Removing the registry classification fails 3 tests; restoring it returns 39 pass / 0 fail.

Checklist

  • Scope stays focused and avoids unrelated cleanup.
  • Docs or release notes were updated when needed.
  • Security-sensitive changes were reviewed for secrets, auth, and unsafe defaults.

The opencode-zen entry declared no noVisionModels and no modality metadata, and
both the sidecar and the fail-closed strip key on that list. So an image part
went to the upstream verbatim and the whole request came back 400.

Zen publishes nothing to derive this from - its /v1/models returns only id,
object, created, owned_by, which is the root cause rather than the evidence. So
each of the eight free models was probed against the live endpoint with a text
control first: six reject images, and big-pickle rejects them with the exact
deserialize error quoted in the issue.

Two models accept images and are deliberately excluded. A community report
claimed the free MiMo model refuses them; it does not, and listing it would
have silently swapped a working image for a caption - a worse failure than the
400 this fixes, because nothing surfaces it. The negative assertion in the
parity test exists to make a future classify-everything patch fail loudly.

This is a dated exception list, not a capability model. Zen discovers its
roster live while this list is static, so re-probe before extending it.

Closes #1043. The Zen half of #1024 goes with it; that issue's TR half depends
on reporter configuration for a provider that is not in the registry.
@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

🗂️ Base branches to auto review (2)
  • ^dev$
  • ^preview$

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 33aa8f99-83e7-4165-aa85-1b6b7c03f51f

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Aug 5, 2026

Copy link
Copy Markdown

Deterministic PR hygiene checks passed.

@github-actions github-actions Bot added the bug Something isn't working label Aug 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant