Skip to content

Decode a data: URIContent to Gemini InlineData instead of passing it as FileData.FileURI - #751

Merged
George Adams (gdams) merged 2 commits into
microsoft:mainfrom
PratikDhanaveFork:gemini-datauri-inlinedata
Jul 28, 2026
Merged

Decode a data: URIContent to Gemini InlineData instead of passing it as FileData.FileURI#751
George Adams (gdams) merged 2 commits into
microsoft:mainfrom
PratikDhanaveFork:gemini-datauri-inlinedata

Conversation

@PratikDhanave

Copy link
Copy Markdown
Contributor

What

In provider/geminiprovider/agent.go, the *message.URIContent arm of buildRequestParts emitted the URI unconditionally as FileData.FileURI. A data: URI is a perfectly valid URIContent value (validateURIContentURI only requires IsAbs(), and url.Parse of a data: URI yields Scheme=data, so IsAbs() is true), so it flowed down this path.

Gemini's file_data.file_uri requires an external reference (gs:// or http(s)://); a data:image/...;base64,... string is not a valid file URI, so Gemini rejects/ignores it and the multimodal input is silently dropped.

This change branches on the URI scheme in the URIContent arm:

  • data: URIs are decoded (media type + bytes) and emitted as InlineData, mirroring the existing DataContent arm directly above.
  • True external URIs (gs://, http(s)://) keep the existing FileData mapping.

It adds a small exported message.DecodeDataURI helper that reuses the package's existing RFC 2397 parser, so both base64 and percent-encoded payloads are handled correctly instead of hand-rolling a parse.

Why (cross-SDK parity)

This matches the Python reference, which uses from_bytes for data: URIs and from_uri otherwise. It is also the Gemini analogue of the same fix already applied for the other providers: #667 (openai-chat), #615 (anthropic), #559 (openai). Gemini was never given this handling.

Tests

TestDataURIContentInRequest in provider/geminiprovider/agent_test.go drives the exported Run API through the existing fake-transport harness and asserts:

  • a URIContent with data:image/png;base64,... produces a part with inlineData (correct mimeType and decoded data) and no fileData;
  • a companion https://example.com/x.png case still maps to fileData.fileUri.

The test fails before the fix (the data URI is sent as fileData.fileUri) and passes after. go build ./..., go vet, and go test for the geminiprovider and message packages are green.

@PratikDhanave
PratikDhanave (PratikDhanave) requested a review from a team as a code owner July 24, 2026 04:15
Copilot AI review requested due to automatic review settings July 24, 2026 04:15

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes Gemini multimodal request construction so that data: URIs carried via *message.URIContent are decoded and sent as inlineData (instead of incorrectly being forwarded as fileData.fileUri, which Gemini expects to be an external URI).

Changes:

  • Update Gemini request-part building to branch on URIContent.URI scheme and decode data: URIs into InlineData.
  • Add an exported message.DecodeDataURI helper built on the existing RFC 2397 parser.
  • Add a Gemini provider test to assert data: URIs become inlineData and external URIs remain fileData.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.

File Description
provider/geminiprovider/agent.go Decode data: URIContent into InlineData instead of sending as FileData.FileURI.
provider/geminiprovider/agent_test.go Add coverage to ensure data: URIs map to inlineData and external URIs map to fileData.
message/datauri.go Export DecodeDataURI to decode RFC2397 data: URIs for provider use.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread provider/geminiprovider/agent.go Outdated
Comment thread message/datauri.go
Comment thread message/datauri.go
@github-actions

This comment has been minimized.

@github-actions github-actions Bot added parity-approved Go API consistency review found no parity issues public-api-change Pull Request changes public APIs labels Jul 24, 2026
A data: URI is a valid URIContent value, but the URIContent arm emitted it
unconditionally as FileData.FileURI. Gemini's file_data.file_uri only accepts
external references (gs://, http(s)://), so a data: URI is rejected/ignored and
the multimodal input is silently dropped.

Branch on the URI scheme: decode data: URIs into InlineData (mirroring the
DataContent arm and the Python SDK's from_bytes/from_uri split) and keep the
FileData mapping for true external URIs. Add an exported message.DecodeDataURI
helper that reuses the existing RFC 2397 parser.
@github-actions

Copy link
Copy Markdown
Contributor

Cross-SDK Parity Review — Approved

PR: Decode data: URIContent to Gemini InlineData instead of passing it as FileData.FileURI

Scope

4 files changed:

  • provider/geminiprovider/agent.go — bug fix: branch on URI scheme in URIContent arm of buildRequestParts
  • message/datauri.go — new exported helper DecodeDataURI
  • provider/geminiprovider/agent_test.go — TestDataURIContentInRequest

Parity Assessment

Python upstream (python/packages/gemini/agent_framework_gemini/_chat_client.py):

The Python implementation checks uri.startswith("(redacted) and uses types.Part.from_bytes for data URIs vs types.Part.from_uri for external ones. The Go implementation does exactly the same: data: URIs become InlineData blobs, external URIs ((redacted) https://, ...) become FileData. Both use the content MediaType when set and fall back to the parsed media type from the URI for data: URIs.

.NET: No Gemini provider was found in dotnet/src/; the fix is Go/Python only, no .NET divergence applies.

New Public API

message.DecodeDataURI(uri string) ([]byte, string, error) — thin, well-scoped RFC 2397 helper reusing the package existing internal parser. Concept is aligned with Pythons _get_data_bytes + from_bytes pattern. No cross-SDK divergence.

Verdict

This change brings the Gemini provider into parity with the Python SDK and mirrors analogous fixes already applied for other providers (#667, #615, #559). Labels public-api-change and parity-approved are both correct and retained.

Warning

Firewall blocked 1 domain

The following domain was blocked by the firewall during workflow execution:

  • awmgmcpg

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "awmgmcpg"

See Network Configuration for more information.

Generated by Go API Consistency Review Agent · 51.5 AIC · ⌖ 5.7 AIC · ⊞ 5.9K ·

@gdams
George Adams (gdams) added this pull request to the merge queue Jul 28, 2026
Merged via the queue into microsoft:main with commit 2d91f2f Jul 28, 2026
20 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

parity-approved Go API consistency review found no parity issues public-api-change Pull Request changes public APIs

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants