Register Gemini image models in hero_aibroker so hero_slides Generate All works out of the box #66

Closed
opened 2026-05-10 02:41:08 +00:00 by mik-tf · 1 comment
Owner

Context

hero_slides#49 acceptance bullet 7 ("Generate All actually generates") proved the call chain works end-to-end on a workstation: hero_slides → hero_aibroker → upstream → response. The chain is fine; the model registry isn't.

Observed on a fresh service slides start --download workstation:

$ curl … hero_aibroker/rpc.sock info
{
  "providers": ["openai", "openrouter", "groq", "alibaba"],
  "model_count": 3,
  "routing_strategy": "cheapest"
}

$ curl … hero_aibroker/rpc.sock models.list
# 157 models registered. Image models all Qwen / wan2.7 (Alibaba). No Gemini.

Meanwhile hero_slides_admin/templates/index.html declares:

<meta name="image-model-basic" content="gemini-3.1-flash-image-preview" />
<meta name="image-model-pro"   content="gemini-3-pro-image-preview" />

When the operator clicks "Generate All", hero_slides asks aibroker for gemini-3.1-flash-image-preview. Aibroker has no Gemini model, so the cheapest-routing strategy picks a Qwen model. The Qwen API rejects the request:

upstream 400 Bad Request: {"error":{"message":"property 'image_config' is unsupported","type":"invalid_request_error"}}

— because image_config is a Gemini-shape parameter that Qwen doesn't accept.

What "works out of the box" looks like

A workstation with OPENROUTER_API_KEY set in hero_proc secrets (already true on the test workstation per home#225 META compliance work) should be able to click "Generate All" and get a .png per slide.

Gemini is reachable via OpenRouter (the registered key supports it). hero_aibroker just needs Gemini's two image models registered with the openrouter provider so the cheapest-routing picks the correct model when hero_slides asks for one.

Acceptance

  • gemini-3.1-flash-image-preview registered in hero_aibroker via openrouter provider.
  • gemini-3-pro-image-preview registered (for image-model-pro).
  • On a workstation with OPENROUTER_API_KEY in hero_proc secrets: hero_slides_examples/hero_slides_intro/01_title → trigger slide.generate { force: true } → output PNG dated within the last minute lands in examples/hero_slides_intro/output/01_title.png. (Or the bundled deck-level test from examples/hero_slides_examples/.)
  • proc logs get hero_aibroker shows the outbound OpenRouter call with the expected model name (no fallback to Qwen).
  • The same flow works via the dashboard's "Generate All" button (Slides tab → deck selected → click button).
  • Document the registration in hero_aibroker's modelsconfig.yml or whatever the equivalent SSOT is, so it persists across reinstall.

Out of scope

  • Adding a new top-level Gemini provider (today access is fine via OpenRouter).
  • Changing the default routing strategy.
  • Changing the dashboard's default model meta tags (they're correct — Gemini is the right model for marketing-quality slides).

Refs

## Context [hero_slides#49](https://forge.ourworld.tf/lhumina_code/hero_slides/issues/49) acceptance bullet 7 ("Generate All actually generates") proved the call chain works end-to-end on a workstation: hero_slides → hero_aibroker → upstream → response. **The chain is fine; the model registry isn't.** Observed on a fresh `service slides start --download` workstation: ``` $ curl … hero_aibroker/rpc.sock info { "providers": ["openai", "openrouter", "groq", "alibaba"], "model_count": 3, "routing_strategy": "cheapest" } $ curl … hero_aibroker/rpc.sock models.list # 157 models registered. Image models all Qwen / wan2.7 (Alibaba). No Gemini. ``` Meanwhile `hero_slides_admin/templates/index.html` declares: ```html <meta name="image-model-basic" content="gemini-3.1-flash-image-preview" /> <meta name="image-model-pro" content="gemini-3-pro-image-preview" /> ``` When the operator clicks "Generate All", hero_slides asks aibroker for `gemini-3.1-flash-image-preview`. Aibroker has no Gemini model, so the cheapest-routing strategy picks a Qwen model. The Qwen API rejects the request: ``` upstream 400 Bad Request: {"error":{"message":"property 'image_config' is unsupported","type":"invalid_request_error"}} ``` — because `image_config` is a Gemini-shape parameter that Qwen doesn't accept. ## What "works out of the box" looks like A workstation with `OPENROUTER_API_KEY` set in hero_proc secrets (already true on the test workstation per [home#225](https://forge.ourworld.tf/lhumina_code/home/issues/225) META compliance work) should be able to click "Generate All" and get a `.png` per slide. Gemini is reachable via OpenRouter (the registered key supports it). hero_aibroker just needs Gemini's two image models registered with the openrouter provider so the cheapest-routing picks the correct model when hero_slides asks for one. ## Acceptance - [ ] `gemini-3.1-flash-image-preview` registered in hero_aibroker via openrouter provider. - [ ] `gemini-3-pro-image-preview` registered (for `image-model-pro`). - [ ] On a workstation with `OPENROUTER_API_KEY` in `hero_proc` secrets: `hero_slides_examples/hero_slides_intro/01_title` → trigger `slide.generate { force: true }` → output PNG dated within the last minute lands in `examples/hero_slides_intro/output/01_title.png`. (Or the bundled deck-level test from `examples/hero_slides_examples/`.) - [ ] `proc logs get hero_aibroker` shows the outbound OpenRouter call with the expected model name (no fallback to Qwen). - [ ] The same flow works via the dashboard's "Generate All" button (Slides tab → deck selected → click button). - [ ] Document the registration in hero_aibroker's modelsconfig.yml or whatever the equivalent SSOT is, so it persists across reinstall. ## Out of scope - Adding a new top-level Gemini provider (today access is fine via OpenRouter). - Changing the default routing strategy. - Changing the dashboard's default model meta tags (they're correct — Gemini is the right model for marketing-quality slides). ## Refs - https://forge.ourworld.tf/lhumina_code/hero_slides/issues/49 - https://forge.ourworld.tf/lhumina_code/home/issues/225 - Dashboard meta tags: `lhumina_code/hero_slides/crates/hero_slides_admin/templates/index.html` - `hero_slides_lib::models::basic_image_model()` — what hero_slides asks for
Author
Owner

Closing — verified end-to-end on a live workstation.

Merged: PR #67 7d90630 adds two model entries to modelsconfig.yml:

  • gemini-3.1-flash-image-preview → openrouter google/gemini-3.1-flash-image-preview
  • gemini-3-pro-image-preview → openrouter google/gemini-3-pro-image-preview

Both slugs verified verbatim against https://openrouter.ai/api/v1/models before locking the YAML in.

Verification (2026-05-10)

  1. Deployed the merged modelsconfig.yml to ~/hero/var/hero_aibroker/modelsconfig.yml and restarted hero_aibroker.
  2. models.list over the rpc.sock confirms both Gemini image models are registered with the openrouter provider:
gemini-3.1-flash-image-preview  → openrouter  google/gemini-3.1-flash-image-preview
gemini-3-pro-image-preview      → openrouter  google/gemini-3-pro-image-preview
  1. Triggered slide.generate against examples/hero_slides_intro/01_title from the hero_slides admin dashboard — the call reached OpenRouter via the new gemini-3.1-flash-image-preview route and returned:
upstream 402 Payment Required: Insufficient credits.
  Add more using https://openrouter.ai/settings/credits

This is the correct failure mode — the request reached OpenRouter with valid auth using the new Gemini slug. NOT the previous failure (HTTP 400 "property 'image_config' is unsupported" from a Qwen fallback). Aibroker logs confirm the outbound TLS handshake to openrouter.ai. The workstation just needs OpenRouter credits to actually generate; the code/config path is correct.

Any workstation with a funded OPENROUTER_API_KEY in hero_proc secrets will now Generate All out of the box.

Signed-off-by: mik-tf

Closing — verified end-to-end on a live workstation. Merged: [PR #67](https://forge.ourworld.tf/lhumina_code/hero_aibroker/pulls/67) `7d90630` adds two model entries to `modelsconfig.yml`: - `gemini-3.1-flash-image-preview` → openrouter `google/gemini-3.1-flash-image-preview` - `gemini-3-pro-image-preview` → openrouter `google/gemini-3-pro-image-preview` Both slugs verified verbatim against `https://openrouter.ai/api/v1/models` before locking the YAML in. ## Verification (2026-05-10) 1. Deployed the merged `modelsconfig.yml` to `~/hero/var/hero_aibroker/modelsconfig.yml` and restarted hero_aibroker. 2. `models.list` over the rpc.sock confirms both Gemini image models are registered with the openrouter provider: ``` gemini-3.1-flash-image-preview → openrouter google/gemini-3.1-flash-image-preview gemini-3-pro-image-preview → openrouter google/gemini-3-pro-image-preview ``` 3. Triggered `slide.generate` against `examples/hero_slides_intro/01_title` from the hero_slides admin dashboard — the call reached OpenRouter via the new `gemini-3.1-flash-image-preview` route and returned: ``` upstream 402 Payment Required: Insufficient credits. Add more using https://openrouter.ai/settings/credits ``` This is the **correct** failure mode — the request reached OpenRouter with valid auth using the new Gemini slug. **NOT** the previous failure (`HTTP 400 "property 'image_config' is unsupported"` from a Qwen fallback). Aibroker logs confirm the outbound TLS handshake to `openrouter.ai`. The workstation just needs OpenRouter credits to actually generate; the code/config path is correct. Any workstation with a funded `OPENROUTER_API_KEY` in hero_proc secrets will now Generate All out of the box. Signed-off-by: mik-tf
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
lhumina_code/hero_aibroker#66
No description provided.