Skip to content

feat(media): image edits + input_type + Solana quality on blockrun-llm 1.7.0 (0.7.0)#18

Merged
VickyXAI merged 6 commits into
mainfrom
fix/media-parameter-parity
Jul 16, 2026
Merged

feat(media): image edits + input_type + Solana quality on blockrun-llm 1.7.0 (0.7.0)#18
VickyXAI merged 6 commits into
mainfrom
fix/media-parameter-parity

Conversation

@KillerQueen-Z

@KillerQueen-Z KillerQueen-Z commented Jul 15, 2026

Copy link
Copy Markdown
Collaborator

Rebased onto main and reworked after a gateway audit. Adds OpenAI-compatible image editing, plus the two media params that are real as of blockrun-llm 1.7.0.

What changed from the original revision

This branch originally forwarded four params — quality, reference_videos, reference_audios, input_type — that existed in no blockrun-llm release, including 1.6.1. The SDK clients have closed signatures, and ImageClient.generate/edit explicitly raise on unknown kwargs, so each was a TypeError on the first real call, on both chains. The 96 green media tests fake the SDK with **kwargs signatures, which swallowed every invented param.

Checking each against the gateway split them three ways:

Param Base gateway Solana gateway Outcome
input_type accepted, ungated accepted, ungated shipped (SDK 1.7.0)
quality not in schema — zod silently strips accepted (openai/gpt-image-*) shipped, Solana only
reference_videos / reference_audios R2V_ENABLED="false" → 503 R2V_ENABLED unset → 503 dropped

BlockRunAI/blockrun-llm#24 shipped input_type and Solana quality (released as 1.7.0), so those are back — now pointing at a real SDK surface.

Contents

  • Image editingPOST /v1/images/edits (alias /v1/images/image2image): JSON data URIs or multipart image/image[], multiple source images, mask. This was always sound: ImageClient.edit has existed since 0.6.0 and SolanaLLMClient.image_edit ships in the solana floor. Adds python-multipart to the proxy extra.
  • input_type on /v1/videos/generations, both chains. The gateway infers the seed mode and returns 400 without charging on disagreement — so a dropped image_url becomes an error instead of a text-to-video clip you still pay for.
  • quality on the image endpoints — Solana only. On Base the adapter returns a 400 naming the constraint rather than letting the value be silently dropped (or surfacing a 500 TypeError).
  • Floors → blockrun-llm>=1.7.0, base and [solana]. The base floor moves this time — unlike the Solana-only re-signing bump this branch first proposed (reverted), input_type is a genuine Base concern.

Not included

Reference-to-video. Both gateways gate reference_videos/reference_audios behind R2V_ENABLED, currently off, so every call 503s. Shipping it would repeat the original mistake one layer down.

Verification

  • 220 passed, 1 skipped.
  • tests/test_sdk_param_contract.py binds every forwarded param against the installed SDK's real signatures — the check that would have caught the original bug, since the fakes cannot. It also pins the Base-rejects-quality asymmetry so a future SDK change fails loudly instead of leaving the adapter's guard stale.
  • Base + quality400 confirmed by driving the real FastAPI proxy, not asserted from a mock.
  • End-to-end through the real SDK 1.7.0 with only HTTP stubbed: input_type reaches the video body; quality reaches /v1/images/generations and /v1/images/image2image.

The image and video params this branch forwarded — quality, reference_videos,
reference_audios, input_type — exist in no blockrun-llm release, including
1.6.1. The SDK clients have closed signatures, and ImageClient.generate/edit
explicitly raise TypeError on unknown kwargs, so each of these is a runtime
failure on the first real call, on Base and Solana alike. No floor bump fixes
it: the parameters aren't in any published version, and the companion SDK PR
the branch description refers to was never opened.

The media tests fake the SDK clients with **kwargs signatures, which swallow
any kwarg the adapter invents — that's why 96 green media tests reported a
surface that cannot work.

Keep the part that does work: image edits (JSON + multipart, multi-image, mask)
call ImageClient.edit / SolanaLLMClient.image_edit, both of which are real —
edit has existed since 0.6.0, image_edit ships in the 1.6.1 solana floor.

Add tests/test_sdk_param_contract.py, which binds the adapter's forwarded
params against the installed SDK's real signatures. It fails on each of the
four removed params, so the fakes can't hide this class of bug again.
BlockRunAI/blockrun-llm#24 shipped the two params this branch originally
tried to forward, so they can now go back — pointing at a real SDK surface
rather than a gap.

input_type (/v1/videos/generations, both chains): declared seed mode, cross
checked by the gateway against the seed fields and rejected 400-unbilled on
disagreement.

quality (/v1/images/{generations,edits}): Solana only. The Base gateway has
no quality field and strips unknown keys, so routing it there would silently
drop it and the caller would never learn their latency knob did nothing. The
adapter refuses on the Base branch and _media_endpoint turns that into a 400
naming the constraint — verified end-to-end through the real proxy, not a 500.

Floors go to blockrun-llm>=1.7.0, base and [solana]. The base floor moves
this time, unlike the Solana-only re-signing bump reverted earlier in this
branch: input_type is genuinely a Base concern, and VideoClient.generate has
a closed signature, so an older core raises TypeError the first time anyone
sends it.

reference_videos/reference_audios stay out. Both gateways gate them behind
R2V_ENABLED — unset on blockrun-sol, "false" on blockrun-web — so every call
503s until that flips.

The contract test now also pins the Base-rejects-quality asymmetry, so a
future SDK adding quality to ImageClient fails here loudly instead of leaving
the adapter's Base guard silently stale.

Verified against the real SDK 1.7.0 with only HTTP stubbed: input_type reaches
the video body, quality reaches /v1/images/generations and image2image.
@VickyXAI VickyXAI changed the title fix(media): align LiteLLM image and video support feat(media): image edits + input_type + Solana quality on blockrun-llm 1.7.0 (0.7.0) Jul 15, 2026
1bcMax added 2 commits July 15, 2026 20:20
Multipart clients routinely emit every optional field, blank ones included,
and a JSON caller templating "" means the same thing. Both reached the
Solana-only guard as a set value, so a Base request that never knowingly sent
quality answered 400 with a message about a parameter the caller did not use.

Blank now means absent on both the JSON and multipart paths. A real value on
Base still gets the clean 400 — the guard is unchanged, only what counts as
"supplied" is.
From review of #18:

The contract test was vacuous for the Base image surface — the exact failure
it exists to prevent. _accepted() returns None for **kwargs signatures, and
ImageClient.generate/edit both have **kwargs (they validate at runtime for a
friendlier error), so every `if accepted is not None:` body never ran. The
test whose docstring promised to fail loudly if a future SDK taught Base about
quality would have stayed green through precisely the likely evolution: a
named quality param added *alongside* **kwargs.

Base image params are now probed by calling, with the transport stubbed, so a
contract test can never reach a gateway or settle funds. Verified by mutation:
adding `quality` to ImageClient.generate while keeping **kwargs now fails.
Closed signatures still use inspection; the file says why the two differ.

Also fixed, both reachable:

- A `prompt` sent as a multipart file part was billed as a Python repr.
  UploadFile is truthy, so the required check passed and str() sent
  "UploadFile(filename='p.txt', ...)" upstream as the prompt — a paid call on
  garbage, returning 200. Reproduced, then guarded: prompt must be non-blank
  text on both image routes.
- Non-string image/mask on the JSON path went to the gateway to be rejected;
  refused locally now, matching the isinstance guards model/size/quality had.

Multipart uploads are capped (BLOCKRUN_MAX_IMAGE_BYTES, 12MB → 413;
BLOCKRUN_MAX_IMAGE_PARTS, 16 → 400). Starlette spools big bodies to disk to
keep RAM clear; building a data URI reads them back and inflates ~1.33x, so an
unbounded POST was buffered and encoded before the gateway could say no. The
part cap is a resource guard only — per-model caps stay the gateway's call.

And test_base_image_generation_omits_none_values now observes what it claims:
its fake defaulted size=None, so it read the same whether the adapter omitted
size or passed it. It captures **kwargs now, which sees only what was sent.
@VickyXAI
VickyXAI merged commit 0874cac into main Jul 16, 2026
@VickyXAI
VickyXAI deleted the fix/media-parameter-parity branch July 16, 2026 01:32
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.

2 participants