Skip to content

Forward a data: URIContent to Anthropic as an inline base64 block - #939

Open
PratikDhanave (PratikDhanave) wants to merge 3 commits into
microsoft:mainfrom
PratikDhanaveFork:anthropic-datauri-uricontent-base64
Open

Forward a data: URIContent to Anthropic as an inline base64 block#939
PratikDhanave (PratikDhanave) wants to merge 3 commits into
microsoft:mainfrom
PratikDhanaveFork:anthropic-datauri-uricontent-base64

Conversation

@PratikDhanave

Copy link
Copy Markdown
Contributor

Problem

In provider/anthropicprovider/agent.go, buildMessageParam's *message.URIContent case handles image and PDF only as URL sources (anthropic.URLImageSourceParam / URLPDFSourceParam), which require an external http(s) reference. A URIContent carrying a data: URI is sent with the entire data:image/png;base64,... string as the url, which Anthropic rejects (400 invalid image source). The identical payload as DataContent succeeds — a cross-provider and intra-file inconsistency.

Fix

Detect a data: URI, decode it with message.DecodeDataURI, and emit an inline base64 image/PDF block using the same primitives as the DataContent branch (anthropic.NewImageBlockBase64 / anthropic.Base64PDFSourceParam). Non-data: http(s) URLs keep the URL source.

This mirrors the sibling providers that already special-case data: URIs on URIContent: Gemini (data:InlineData) and OpenAI chat (data: → inline DataContent mapping).

Test

TestBuildMessageParam_DataURIImageForwardedAsBase64 sends a URIContent with a data:image/png;base64,... URI and asserts the outgoing content block is a base64 image source. Fails before the fix (source.type == "url" with the data URI), passes after.

buildMessageParam's URIContent case only handled image and PDF as URL
sources (anthropic.URLImageSourceParam / URLPDFSourceParam), which require
an external http(s) reference. A URIContent carrying a data: URI was sent
with the whole data: string as the url, which Anthropic rejects (400).

Decode the data: URI and emit a base64 image/PDF block instead, reusing the
same primitives as the DataContent branch (NewImageBlockBase64 /
Base64PDFSourceParam). This mirrors the Gemini provider (data: -> InlineData)
and the OpenAI chat provider (data: -> inline), which already special-case
data: URIs on URIContent. Non-data http(s) URLs keep the URL source.
@PratikDhanave
PratikDhanave (PratikDhanave) requested a review from a team as a code owner August 28, 2026 08:41
Copilot AI lite review requested due to automatic review settings August 28, 2026 08:41
@github-actions github-actions Bot added area:provider Changes files in the provider area area:provider/anthropic Changes files in the provider / anthropic area size:medium At most 100 changed lines across at most 5 files pending-auto-risk Automatic risk classification is in progress labels Aug 28, 2026

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

Fixes Anthropic provider handling of message.URIContent that contains data: URIs by converting them into inline base64 image/PDF blocks (instead of incorrectly sending the full data: URI as a URL source, which Anthropic rejects).

Changes:

  • Detect data: URIs in buildMessageParam and map them to Anthropic base64 image/PDF content blocks.
  • Add a regression test asserting data:-URI URIContent images are forwarded as base64 sources.

Reviewed changes

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

File Description
provider/anthropicprovider/agent.go Adds data: URI detection/decoding and forwards inline content as base64 blocks for Anthropic.
provider/anthropicprovider/agent_test.go Adds a regression test for data: URI image forwarding behavior.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +695 to +711
case strings.HasPrefix(strings.ToLower(c.URI), "data:"):
// A data: URI carries the bytes inline. Anthropic's URL image/PDF
// sources require an external http(s) reference, so a data: URI sent
// as a url source is rejected; decode it and send a base64 block
// instead, mirroring the DataContent branch and the Gemini/OpenAI
// data: handling.
data, mediaType, err := message.DecodeDataURI(c.URI)
if err != nil {
break
}
encoded := base64.StdEncoding.EncodeToString(data)
switch {
case strings.HasPrefix(mediaType, "image/"):
content = append(content, anthropic.NewImageBlockBase64(mediaType, encoded))
case isPDFMediaType(mediaType):
content = append(content, anthropic.NewDocumentBlock(anthropic.Base64PDFSourceParam{Data: encoded}))
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed — a DecodeDataURI failure now returns an explicit error (anthropicprovider: failed to decode data URI content) instead of break-ing and dropping the content, matching geminiprovider. Also added the URIContent.MediaType override and case-insensitive media-type matching.

for _, b := range blocks {
block, _ := b.(map[string]any)
source, _ := block["source"].(map[string]any)
if block["type"] == "image" && source["type"] == "base64" && source["media_type"] == "image/png" {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Strengthened the test to assert the forwarded base64 payload (source["data"] == "aGVsbG8="), so it would now fail if the wrong bytes were encoded/forwarded.

@github-actions

This comment has been minimized.

@github-actions github-actions Bot added parity-approved Go API consistency review found no parity issues risk:medium Contained production impact requiring normal review depth and removed pending-auto-risk Automatic risk classification is in progress labels Aug 28, 2026
@qmuntal

Copy link
Copy Markdown
Member

Fix codereview comments.

@qmuntal Quim Muntal (qmuntal) left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Fix codereview findings.

- Return an explicit error (matching geminiprovider) instead of swallowing a
  DecodeDataURI failure with break, which would drop the content and send a
  request with missing blocks.
- Let an explicit URIContent.MediaType override the media type parsed from the
  data: URI, and match media types case-insensitively (mirrors gemini).
- Strengthen the test to assert the forwarded base64 payload, not just the
  source type/media_type.
@github-actions github-actions Bot added pending-auto-risk Automatic risk classification is in progress and removed risk:medium Contained production impact requiring normal review depth labels Sep 6, 2026
@github-actions

github-actions Bot commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

Scope: internal-only (bugfix), no exported Go API change

Changed Go contract: None. buildMessageParam in provider/anthropicprovider/agent.go (unexported) gains a (redacted) URI branch in the *message.URIContentcase that decodes inline base64 content via the existingmessage.DecodeDataURIhelper and emitsanthropic.NewImageBlockBase64/anthropic.Base64PDFSourceParam, instead of passing the raw data URI string as a URLImageSourceParam/URLPDFSourceParam (which Anthropic rejects). No new exported functions, types, or options; the added test (TestBuildMessageParam_DataURIImageForwardedAsBase64) only exercises existing behavior via Run`.

Upstream evidence reviewed: This PR does not introduce a Go-only public feature or diverge from .NET/Python — it fixes a Go-internal cross-provider inconsistency. Within the Go repo itself, provider/openaiprovider/chat.go:695 (strings.HasPrefix(strings.ToLower(uri), "(redacted) already special-cases (redacted) URIs for URIContent, and the PR description states the Gemini provider does the same ((redacted) → InlineData`), so the fix brings Anthropic in line with the other two Go providers' existing observable behavior. No corresponding upstream .NET/Python file was needed since this doesn't add or change any capability beyond what Go's own OpenAI/Gemini providers already do — it only corrects a bug where Anthropic diverged from the rest of the Go implementation.

Result: aligned. This is a targeted bugfix that removes an intra-repo inconsistency (Anthropic previously mishandled (redacted) URIContent while OpenAI/Gemini providers already handled it correctly and DataContent succeeded with identical bytes). No public API surface changed, so public-api-changeshould not be applied. No parity issues found; recommendparity-approved`.

Warning

Firewall blocked 1 domain

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

  • github.com

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

network:
  allowed:
    - defaults
    - "github.com"

See Network Configuration for more information.

Generated by Go API Consistency Review Agent · copilot · auto · 32 AIC · ⌖ 9.13 AIC · ⊞ 9.5K ·

@github-actions github-actions Bot added risk:low Limited blast radius and straightforward rollback and removed pending-auto-risk Automatic risk classification is in progress labels Sep 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:provider/anthropic Changes files in the provider / anthropic area area:provider Changes files in the provider area parity-approved Go API consistency review found no parity issues risk:low Limited blast radius and straightforward rollback size:medium At most 100 changed lines across at most 5 files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants