Skip to content

feat(openrouter): surface generated images from assistant responses#1804

Open
jimmiebfulton wants to merge 1 commit into
0xPlaygrounds:mainfrom
anemnez:pr/openrouter-image-gen
Open

feat(openrouter): surface generated images from assistant responses#1804
jimmiebfulton wants to merge 1 commit into
0xPlaygrounds:mainfrom
anemnez:pr/openrouter-image-gen

Conversation

@jimmiebfulton
Copy link
Copy Markdown
Contributor

Summary

OpenRouter image-generation models (e.g. google/gemini-flash-image-preview) return generated images as a sibling images array on the assistant message rather than embedding them inside content. Without this change, those images are silently dropped and callers have no way to access them.

This PR captures the images array and converts each entry into a completion::AssistantContent::Image block alongside the text response.

Changes

  • ResponseImage struct mirroring the image_url content-part shape (inbound only).
  • parse_data_uri private helper to split data:<mime>;base64,<payload> URIs.
  • Message::Assistant gains images: Vec<ResponseImage> with #[serde(default, skip_serializing)] — received from responses, never serialized back into requests.
  • Conversion in TryFrom<CompletionResponse>: base64 data URIs become inline image_base64 blocks; plain URLs become URL-sourced Image blocks.
  • Three tests: base64 extraction, plain URL extraction, and verifying images is absent from serialized requests.

AI Assistance

This implementation was developed with significant AI assistance (Claude). The design, tests, and edge cases were reviewed and validated by the author before submission.

Issue

Fixes #807

OpenRouter image-generation models (e.g. google/gemini-flash-image-preview)
return generated images as a sibling `images` array on the assistant message
rather than embedding them inside `content`. This change captures those images
and converts them into `completion::AssistantContent::Image` blocks alongside
the text response, making them accessible to callers without any extra parsing.

- Add `ResponseImage` struct (mirrors the `image_url` content-part shape).
- Add private `parse_data_uri` helper to split data URIs into (mime, payload).
- Add `images: Vec<ResponseImage>` field on `Message::Assistant` with
  `#[serde(default, skip_serializing)]` — inbound only, never sent in requests.
- Extend the `CompletionResponse → completion::CompletionResponse` conversion
  to append each ResponseImage as an inline base64 block (data URIs) or a
  URL-sourced image (plain URLs).
- Add `images: Vec::new()` to the two `Message::Assistant` construction sites
  in the `TryFrom` impls so they keep compiling.
- Add three tests: base64 data URI extraction, plain URL extraction, and
  verification that the images field is absent from serialized requests.
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.

feat: OpenRouter Image Generation

1 participant