Skip to content

feat(protocols): ImageGenerationCall output metadata — action/background/output_format/quality/size (R6.9) - #1377

Merged
slin1237 merged 1 commit into
mainfrom
feat/r6-09-image-gen-output-metadata
Apr 24, 2026
Merged

slin1237 merged 1 commit into
mainfrom
feat/r6-09-image-gen-output-metadata

Conversation

@slin1237

@slin1237 slin1237 commented Apr 24, 2026 •

Copy link
Copy Markdown
Member

Summary

Problem

The OpenAI Rust SDK v2.8.1 we pin (reflected in openai-protocol's
ImageGenerationCall) declares the image_generation_call output
item incompletely — it only carries id, result, revised_prompt,
status. Real OpenAI production responses for this item include
five additional metadata fields:

{
  \"id\": \"ig_...\",
  \"type\": \"image_generation_call\",
  \"status\": \"completed\",
  \"action\": \"generate\",
  \"background\": \"opaque\",
  \"output_format\": \"png\",
  \"quality\": \"high\",
  \"result\": \"<base64>\",
  \"revised_prompt\": \"...\",
  \"size\": \"1024x1024\"
}

Because these fields are not declared on our types:

  • OpenAI cloud passthrough silently drops them (downstream consumers
    lose provider-side metadata).
  • Persistence round-trips (store → reload → replay) lose them.
  • R6.5 cloud-matrix integration tests cannot assert on them because
    they never land in the emitted output item.

Solution

Additive-only changes to both variants of ImageGenerationCall and
the MCP-side transformer that builds the output item from tool-call
results:

  1. Protocol types — crates/protocols/src/responses.rs:
    add action, background, output_format, quality, size to
    both ResponseOutputItem::ImageGenerationCall and
    ResponseInputOutputItem::ImageGenerationCall. All five are
    Option<String> (not narrow enums, so evolving spec values pass
    through unchanged — mirrors ImageGenerationTool on the
    input-tool side) and all use
    #[serde(default, skip_serializing_if = \"Option::is_none\")] so
    a minimal item still serializes spec-compatibly. Placed before
    status to keep the last-field convention.

  2. MCP transformer — crates/mcp/src/transform/transformer.rs:
    extend to_image_generation_call to extract the same five keys
    from the MCP tool-call payload when present (direct object and
    text-block shapes). Refactored extract_image_generation_fields
    to return a named ImageGenerationFields struct so adding
    fields no longer ripples through the call site.

  3. Test-only struct literal —
    model_gateway/src/routers/grpc/regular/responses/conversions.rs:
    updated the one struct literal there with the new fields. No
    router behavior changes.

Out of scope

  • Router wiring (R6.5 covers e2e assertions)
  • Harmony builder / BUILTIN_TOOLS (no change needed)
  • ImageGenerationTool input-side type (already carried these via T4)

Test plan

  • cargo test -p openai-protocol --tests — 10 image-generation
    roundtrip tests all pass, including 4 new ones:
    • image_generation_call_output_item_round_trips_with_full_metadata
    • image_generation_call_output_item_round_trips_minimal_without_metadata
    • image_generation_call_input_item_round_trips_with_full_metadata
    • image_generation_call_input_item_round_trips_minimal_without_metadata
  • cargo test -p smg-mcp --tests — 201 tests pass, including 3 new
    transformer tests that pin metadata forwarding from direct-object
    and text-block MCP payloads plus absent-not-null serialization when
    an MCP server surfaces no metadata.
  • cargo check --workspace --all-targets — clean.
  • cargo clippy --workspace --all-targets -- -D warnings — clean.
  • cargo fmt --check — clean.

Compatibility

  • Purely additive: existing minimal payloads round-trip byte-identically
    (skip_serializing_if keeps nulls off the wire).
  • No router wiring change; R6.5 will layer on top.
  • Input-side variant stays symmetric with the output-side variant so
    stateless multi-turn replay preserves metadata.

Refs: R6.9

Checklist
  • Documentation updated (inline doc comments on new fields)
  • (Optional) Please join us on Slack #sig-smg to discuss, review, and merge PRs

Summary by CodeRabbit

  • New Features

    • Image generation responses now include optional metadata fields: action, background, output_format, quality, and size; these values are preserved through passthrough and persistence and omitted from output when absent.
  • Tests

    • Added and updated tests to validate full metadata round-trips, minimal-wire-shape serialization (no nulls), and correct passthrough behavior.

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

@coderabbitai

coderabbitai Bot commented Apr 24, 2026 •

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 76fe909b-c983-4d19-b9aa-059905c1e749

📥 Commits

Reviewing files that changed from the base of the PR and between 6ecb30b and 0cba1e7.

📒 Files selected for processing (4)
  • crates/mcp/src/transform/transformer.rs
  • crates/protocols/src/responses.rs
  • crates/protocols/tests/responses.rs
  • model_gateway/src/routers/grpc/regular/responses/conversions.rs

📝 Walkthrough

Walkthrough

Refactors MCP image-generation extraction to return an ImageGenerationFields struct and forwards five optional OpenAI image metadata fields (action, background, output_format, quality, size) into ResponseOutputItem::ImageGenerationCall/ResponseInputOutputItem::ImageGenerationCall; tests updated to cover passthrough and minimal-wire behavior.

Changes

Cohort / File(s) Summary
Protocol Type Extensions
crates/protocols/src/responses.rs
Added five optional metadata fields (action, background, output_format, quality, size) to both ResponseInputOutputItem::ImageGenerationCall and ResponseOutputItem::ImageGenerationCall, with serde skip-serializing-if to preserve minimal wire shapes.
Transformer Logic & Extraction
crates/mcp/src/transform/transformer.rs
Refactored extraction from (image_b64, revised_prompt) tuple to ImageGenerationFields struct; extractor now accumulates first-occurrence metadata across MCP payload shapes and preserves absent values as None; to_image_generation_call updated to read new struct and maintain required result wire shape.
Tests & Gateway
crates/protocols/tests/responses.rs, model_gateway/src/routers/grpc/regular/responses/conversions.rs
Updated existing pattern matches to ignore extra fields; added tests verifying full metadata passthrough for both output/input fixtures and that minimal JSON omits absent metadata; gateway test updated to construct variant with new optional fields set to None.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • CatherineSue
  • key4ng
  • zhoug9127

Poem

🐰 I nibbled through payloads, one by one,
Five tiny fields now bounce in the sun,
Action and background, size and more,
Quality and format hop through the door.
From tuple to struct, I twitched with delight.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately and specifically describes the main feature being added: five new optional metadata fields to ImageGenerationCall types.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/r6-09-image-gen-output-metadata

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

@mergify

mergify Bot commented Apr 24, 2026

Copy link
Copy Markdown
Contributor

Hi @slin1237, this PR has merge conflicts that must be resolved before it can be merged. Please rebase your branch:

git fetch origin main
git rebase origin/main
# resolve any conflicts, then:
git push --force-with-lease

@mergify mergify Bot added the needs-rebase PR has merge conflicts that need to be resolved label Apr 24, 2026
@github-actions github-actions Bot added grpc gRPC client and router changes mcp MCP related changes tests Test changes protocols Protocols crate changes model-gateway Model gateway crate changes labels Apr 24, 2026
Real OpenAI production `image_generation_call` output items carry five
metadata fields that the OpenAI Rust SDK v2.8.1 declares incompletely:

    {
      "id": "ig_...",
      "type": "image_generation_call",
      "status": "completed",
      "action": "generate",          // NEW
      "background": "opaque",        // NEW
      "output_format": "png",        // NEW
      "quality": "high",             // NEW
      "result": "<base64>",
      "revised_prompt": "...",
      "size": "1024x1024"            // NEW
    }

Without these fields on our types the gateway silently dropped them on
cloud passthrough, persistence round-trips, and R6.5 integration
assertions couldn't inspect them.

Changes:
  * crates/protocols/src/responses.rs: add `action`, `background`,
    `output_format`, `quality`, `size` (all `Option<String>`, all
    `skip_serializing_if = "Option::is_none"`) to both
    `ResponseOutputItem::ImageGenerationCall` and
    `ResponseInputOutputItem::ImageGenerationCall`. Placed before
    `status` so the last-field convention holds; typed as
    `Option<String>` (not narrow enums) so evolving spec values pass
    through unchanged — mirrors `ImageGenerationTool` on the input-tool
    side.
  * crates/mcp/src/transform/transformer.rs: extend
    `to_image_generation_call` to extract the five new fields from the
    MCP tool result payload (direct object + embedded text-block
    shapes). Introduces a private `ImageGenerationFields` helper struct
    so adding future fields no longer ripples through call sites.
  * model_gateway/src/routers/grpc/regular/responses/conversions.rs:
    one test-only struct literal updated with the new fields.
  * Tests: four new roundtrip tests in crates/protocols/tests/
    responses.rs (full + minimal for both output and input variants)
    plus three new MCP transformer tests covering metadata forwarding
    from direct objects and text-block payloads, and the no-metadata
    case to pin absent-not-null serialization.

Unblocks R6.5 cloud-matrix assertions on these fields.

Refs: R6.9
Signed-off-by: Simo Lin <linsimo.mark@gmail.com>
@slin1237
slin1237 force-pushed the feat/r6-09-image-gen-output-metadata branch from 6ecb30b to 0cba1e7 Compare April 24, 2026 06:27
@mergify mergify Bot removed the needs-rebase PR has merge conflicts that need to be resolved label Apr 24, 2026
@slin1237
slin1237 merged commit b13aef5 into main Apr 24, 2026
47 checks passed
@slin1237
slin1237 deleted the feat/r6-09-image-gen-output-metadata branch April 24, 2026 12:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

grpc gRPC client and router changes mcp MCP related changes model-gateway Model gateway crate changes protocols Protocols crate changes tests Test changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant