Decode a data: URIContent to Gemini InlineData instead of passing it as FileData.FileURI - #751
Conversation
There was a problem hiding this comment.
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.URIscheme and decodedata:URIs intoInlineData. - Add an exported
message.DecodeDataURIhelper built on the existing RFC 2397 parser. - Add a Gemini provider test to assert
data:URIs becomeinlineDataand external URIs remainfileData.
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.
This comment has been minimized.
This comment has been minimized.
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.
4c40f17 to
508bc08
Compare
Cross-SDK Parity Review — ApprovedPR: Decode data: URIContent to Gemini InlineData instead of passing it as FileData.FileURI Scope4 files changed:
Parity AssessmentPython 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 APImessage.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. VerdictThis 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 domainThe following domain was blocked by the firewall during workflow execution:
network:
allowed:
- defaults
- "awmgmcpg"See Network Configuration for more information.
|
What
In
provider/geminiprovider/agent.go, the*message.URIContentarm ofbuildRequestPartsemitted the URI unconditionally asFileData.FileURI. Adata:URI is a perfectly validURIContentvalue (validateURIContentURIonly requiresIsAbs(), andurl.Parseof adata:URI yieldsScheme=data, soIsAbs()is true), so it flowed down this path.Gemini's
file_data.file_urirequires an external reference (gs://orhttp(s)://); adata: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
URIContentarm:data:URIs are decoded (media type + bytes) and emitted asInlineData, mirroring the existingDataContentarm directly above.gs://,http(s)://) keep the existingFileDatamapping.It adds a small exported
message.DecodeDataURIhelper 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_bytesfordata:URIs andfrom_uriotherwise. 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
TestDataURIContentInRequestinprovider/geminiprovider/agent_test.godrives the exportedRunAPI through the existing fake-transport harness and asserts:URIContentwithdata:image/png;base64,...produces a part withinlineData(correctmimeTypeand decodeddata) and nofileData;https://example.com/x.pngcase still maps tofileData.fileUri.The test fails before the fix (the data URI is sent as
fileData.fileUri) and passes after.go build ./...,go vet, andgo testfor thegeminiproviderandmessagepackages are green.