Skip to content

fix: pass through gs:// image URLs on Vertex Gemini closes #4402#4568

Open
G-XD wants to merge 1 commit into
maximhq:devfrom
G-XD:fix/issue_4402
Open

fix: pass through gs:// image URLs on Vertex Gemini closes #4402#4568
G-XD wants to merge 1 commit into
maximhq:devfrom
G-XD:fix/issue_4402

Conversation

@G-XD

@G-XD G-XD commented Jun 20, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes Vertex Gemini support for gs:// image URLs.

Vertex AI accepts Google Cloud Storage URIs in Gemini FileData.fileUri, but Bifrost’s Vertex Gemini
path reused Gemini converters that only allowed http/https image URLs. This caused gs:// image blocks
to be rejected or dropped before reaching Vertex.

This PR adds explicit provider-level image URL scheme handling so Vertex can opt into gs:// while
Gemini keeps its default http/https behavior.

Changes

  • Added schemas.SanitizeImageURLWithAllowedSchemes to support provider-specific image URL scheme
    allowlists.
    • Kept schemas.SanitizeImageURL restricted to the default http/https behavior.
    • Updated Gemini chat and responses converters to accept an explicit image URL scheme allowlist.
    • Preserved the latest upstream ctx-based canonical model resolution in Gemini converters.
    • Added Vertex-local Gemini image URL allowlist:
      • http
      • https
      • gs
    • Updated Vertex Gemini request paths to pass the Vertex allowlist explicitly:
      • ChatCompletion
      • ChatCompletionStream
      • Responses
      • ResponsesStream
      • CountTokens
    • Changed Gemini image URL conversion to return explicit errors for invalid URLs instead of silently
      skipping image blocks. (This intentionally surfaces invalid image URL inputs instead of silently sending a request with missing image content.)
    • Updated Gemini batch conversion to propagate message conversion errors.
    • Added tests for:
      • default sanitizer rejecting non-HTTP schemes
      • explicit gs:// opt-in
      • empty allowlist behavior
      • data URL behavior
      • Gemini rejecting gs://
      • Vertex preserving gs:// as FileData.fileUri
      • Vertex rejecting unsupported schemes like file://
      • Vertex Gemini allowlist contract

Type of change

  • Bug fix
  • Feature
  • Refactor
  • Documentation
  • Chore/CI

Affected areas

  • Core (Go)
  • Transports (HTTP)
  • Providers/Integrations
  • Plugins
  • UI (React)
  • Docs

How to test

cd core
go test ./schemas ./providers/gemini ./providers/vertex

Expected outcome: all tests pass.

Screenshots/Recordings

N/A. No UI changes.

Breaking changes

  • Yes
  • No

Invalid or unsupported image URL schemes in Gemini chat/responses inputs now return an explicit conversion error instead of silently dropping the image block. This may affect callers that relied on the previous partial-success behavior.

Related issues

Fixes #4402

Security considerations

The default image URL sanitizer remains restricted to http/https. Support for additional schemes such as
gs:// is explicit and scoped to the Vertex provider path, avoiding accidental broadening of URL handling
behavior across other providers.

Checklist

  • I read docs/contributing/README.md and followed the guidelines
  • I added/updated tests where appropriate
  • I updated documentation where needed
  • I verified builds succeed (Go and UI)
  • I verified the CI pipeline passes locally if applicable

@coderabbitai

coderabbitai Bot commented Jun 20, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: f57fa475-4686-4890-b06f-92840d04e75c

📥 Commits

Reviewing files that changed from the base of the PR and between a2034ce and eb37e25.

📒 Files selected for processing (11)
  • core/providers/gemini/batch.go
  • core/providers/gemini/chat.go
  • core/providers/gemini/gemini_test.go
  • core/providers/gemini/responses.go
  • core/providers/gemini/utils.go
  • core/providers/gemini/videos.go
  • core/providers/vertex/utils_test.go
  • core/providers/vertex/vertex.go
  • core/providers/vertex/vertex_test.go
  • core/schemas/utils.go
  • core/schemas/utils_test.go
🚧 Files skipped from review as they are similar to previous changes (8)
  • core/providers/gemini/videos.go
  • core/providers/gemini/batch.go
  • core/providers/vertex/utils_test.go
  • core/providers/gemini/utils.go
  • core/schemas/utils_test.go
  • core/schemas/utils.go
  • core/providers/vertex/vertex_test.go
  • core/providers/gemini/responses.go

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Image URL scheme validation is now customizable per provider.
    • Google Cloud Storage URLs are now supported for Vertex AI Gemini requests.
  • Bug Fixes

    • Message conversion failures now properly propagate errors instead of silently failing with invalid requests.
  • Tests

    • Added comprehensive tests for image URL scheme validation across providers.
    • Added regression tests for Google Cloud Storage image URL support.

Walkthrough

Fixes a bug where Vertex AI image blocks with gs:// URLs were silently dropped. Refactors SanitizeImageURL in core/schemas/utils.go to support a caller-supplied scheme allowlist, threads this allowlist through all Gemini message/content conversion internals, exposes WithImageURLSchemes public variants, and wires Vertex with an expanded [http, https, gs] allowlist.

Changes

GCS image URL scheme allowlist for Gemini/Vertex converters

Layer / File(s) Summary
Schema image URL sanitizer allowlist refactor
core/schemas/utils.go, core/schemas/utils_test.go
SanitizeImageURL delegates to a new internal sanitizeImageURL helper; new exported SanitizeImageURLWithAllowedSchemes accepts a caller-supplied allowlist; scheme validation switches from hardcoded http/https to case-insensitive allowlist membership with errors for empty allowlists. Tests cover all branches including data: passthrough.
Gemini converter internals: allowlist threading and error propagation
core/providers/gemini/utils.go, core/providers/gemini/videos.go, core/providers/gemini/batch.go, core/providers/gemini/responses.go
defaultGeminiImageURLSchemes (http, https) defined in utils.go; convertBifrostMessagesToGemini gains variadic allowlist parameter and now returns an error, failing hard on sanitization failure instead of silently skipping. convertContentBlockToGeminiPart, convertResponsesMessagesToGeminiContents, video and batch paths updated to use SanitizeImageURLWithAllowedSchemes with the allowlist.
Gemini public WithImageURLSchemes API
core/providers/gemini/chat.go, core/providers/gemini/responses.go, core/providers/gemini/gemini_test.go
ToGeminiChatCompletionRequest and ToGeminiResponsesRequest become thin wrappers delegating to new exported WithImageURLSchemes variants that accept a scheme allowlist. Tests assert that gs:// URLs are rejected by the default wrappers with the expected error message.
Vertex geminiImageURLSchemes wiring and tests
core/providers/vertex/vertex.go, core/providers/vertex/utils_test.go, core/providers/vertex/vertex_test.go
Vertex defines geminiImageURLSchemes = []string{"http","https","gs"} and replaces all five Gemini converter call sites with the WithImageURLSchemes variant. Tests confirm gs:// image URLs are preserved as FileData in both chat and responses paths, unsupported schemes are rejected, and the allowlist contract is pinned via reflect.DeepEqual.

Sequence Diagram

sequenceDiagram
    rect rgba(173, 216, 230, 0.5)
        Note over Caller,SanitizeImageURLWithAllowedSchemes: Vertex Provider (gs:// allowed)
        Caller->>vertex.go: ChatCompletion with gs://bucket/img.png
        vertex.go->>ToGeminiChatCompletionRequestWithImageURLSchemes: allowedSchemes=[http,https,gs]
        ToGeminiChatCompletionRequestWithImageURLSchemes->>convertBifrostMessagesToGemini: allowedSchemes=[http,https,gs]
        convertBifrostMessagesToGemini->>SanitizeImageURLWithAllowedSchemes: url=gs://..., schemes=[http,https,gs]
        SanitizeImageURLWithAllowedSchemes-->>convertBifrostMessagesToGemini: sanitized URL
        convertBifrostMessagesToGemini-->>ToGeminiChatCompletionRequestWithImageURLSchemes: FileData{FileURI: gs://...}
        ToGeminiChatCompletionRequestWithImageURLSchemes-->>vertex.go: GeminiGenerationRequest
        vertex.go-->>Caller: request forwarded with FileData intact
    end
    rect rgba(255, 200, 150, 0.5)
        Note over Caller,SanitizeImageURLWithAllowedSchemes: Direct Gemini Provider (gs:// rejected)
        Caller->>ToGeminiChatCompletionRequest: ChatCompletion with gs://bucket/img.png
        ToGeminiChatCompletionRequest->>convertBifrostMessagesToGemini: allowedSchemes=[http,https]
        convertBifrostMessagesToGemini->>SanitizeImageURLWithAllowedSchemes: url=gs://..., schemes=[http,https]
        SanitizeImageURLWithAllowedSchemes-->>convertBifrostMessagesToGemini: error: scheme "gs" not allowed
        convertBifrostMessagesToGemini-->>ToGeminiChatCompletionRequest: error
        ToGeminiChatCompletionRequest-->>Caller: nil, error
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • maximhq/bifrost#4386: Modifies the same ToGeminiBatchGenerateContentRequest conversion path in core/providers/gemini/batch.go that this PR adds error handling to.
  • maximhq/bifrost#4520: Introduces canonical-model/capModel gating that this PR's convertParamsToGenerationConfigResponses change depends on for thinking-feature validation.

Suggested reviewers

  • danpiths
  • akshaydeo

🐇 A bunny hops through the GCS lane,
No more silent drops in the image chain!
gs:// schemes now pass the gate,
With Vertex's allowlist keeping them straight.
The schema knows which schemes belong —
http, https, gs all sing along! 🎉

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 47.06% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: fixing gs:// image URL support on Vertex Gemini, which directly addresses the issue in #4402.
Description check ✅ Passed The description comprehensively covers all major sections of the template including summary, changes, type of change, affected areas, testing instructions, breaking changes, related issues, and security considerations.
Linked Issues check ✅ Passed All code changes directly implement the objectives from #4402: adding SanitizeImageURLWithAllowedSchemes to support provider-specific scheme handling, updating Gemini converters to accept image URL scheme allowlists, adding Vertex-local allowlist for gs:// support, and converting silent failures to explicit errors.
Out of Scope Changes check ✅ Passed All changes are in scope: core/schemas utilities for image URL sanitization, Gemini provider converters, Vertex provider integration, comprehensive test coverage, and batch conversion error handling—all directly supporting gs:// URL support on Vertex Gemini.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 golangci-lint (2.12.2)

level=error msg="[linters_context] typechecking error: pattern ./...: directory prefix . does not contain main module or its selected dependencies"


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@coderabbitai coderabbitai Bot requested review from akshaydeo and danpiths June 20, 2026 02:13
@greptile-apps

greptile-apps Bot commented Jun 20, 2026

Copy link
Copy Markdown
Contributor

Confidence Score: 4/5

Safe to merge after acknowledging the intentional behavior change in the chat converter; the Vertex gs:// fix itself is correct and well-tested.

The chat-completion converter now returns an error for image blocks with non-http/https URL schemes where it previously silently dropped those blocks and returned a successful response. This is a deliberate design improvement documented in the PR description, but the PR checklist marks No for breaking changes. Any existing caller sending image URLs with non-standard schemes through the Gemini ChatCompletion path will start seeing errors after upgrading. The responses path was already returning errors on invalid URLs, so only the chat path is affected. All other aspects of the change — the allowlist abstraction, Vertex wiring, and test coverage — are clean.

core/providers/gemini/utils.go — the silent-skip-to-error change in convertBifrostMessagesToGemini is the only callsite worth a second look before merging.

Important Files Changed

Filename Overview
core/schemas/utils.go Adds SanitizeImageURLWithAllowedSchemes alongside the original SanitizeImageURL; data URLs correctly bypass the allowlist; scheme comparison uses EqualFold for safety; empty allowlist is a deliberate deny-all and documented.
core/providers/gemini/utils.go convertBifrostMessagesToGemini now propagates scheme errors instead of silently skipping invalid image blocks — a user-visible API contract change for the chat path that may break existing callers and is incorrectly marked as non-breaking.
core/providers/gemini/responses.go Correctly threads allowedImageURLSchemes through convertResponsesMessagesToGeminiContents and all four convertContentBlockToGeminiPart call-sites; responses path already returned errors on invalid URLs before this PR.
core/providers/gemini/chat.go Adds ToGeminiChatCompletionRequestWithImageURLSchemes and delegates the default path to it; delegation pattern is clean and backwards-compatible at the call signature level.
core/providers/vertex/vertex.go All five Gemini-family paths (ChatCompletion, ChatCompletionStream, Responses, ResponsesStream, CountTokens) updated to pass geminiImageURLSchemes; geminiImageURLSchemes is a well-scoped package-level variable.
core/providers/gemini/batch.go Error from convertBifrostMessagesToGemini now propagates correctly; batch path uses http/https defaults which is appropriate since Vertex batch uses gs:// for file I/O, not inline image URLs.
core/providers/gemini/videos.go Correctly migrated to SanitizeImageURLWithAllowedSchemes with the Gemini default list; video input reference still restricted to http/https as expected.
core/providers/vertex/utils_test.go TestGeminiImageURLSchemesContract pins the exact allowlist, catching any future regression that drops gs or adds unexpected schemes without requiring end-to-end tests.
core/providers/vertex/vertex_test.go Covers gs:// preserve, http/https preserve, and unsupported-scheme rejection for both ChatCompletion and Responses paths; test cases are clear and assertions are specific.
core/schemas/utils_test.go New test file thoroughly covers default policy, opt-in allowlist, unlisted-scheme rejection, empty-allowlist deny-all, and data URL passthrough.
core/providers/gemini/gemini_test.go Two tests added confirming Gemini rejects gs:// in both ChatCompletion and Responses paths; assertions on error message text are tight.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Image URL in message] --> B{Is data: URL?}
    B -- Yes --> C[Pass through — bypass allowlist]
    B -- No --> D{Parse URL scheme}
    D --> E{Provider?}
    E -- Gemini --> F[allowedSchemes = http, https]
    E -- Vertex --> G[allowedSchemes = http, https, gs]
    F --> H{scheme in allowlist?}
    G --> H
    H -- Yes --> I[SanitizeImageURL returns cleaned URL]
    H -- No --> J[Return error — request fails]
    I --> K{Type?}
    K -- base64 data URL --> L[InlineData Blob]
    K -- regular URL incl. gs:// --> M[FileData with FileURI]
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    A[Image URL in message] --> B{Is data: URL?}
    B -- Yes --> C[Pass through — bypass allowlist]
    B -- No --> D{Parse URL scheme}
    D --> E{Provider?}
    E -- Gemini --> F[allowedSchemes = http, https]
    E -- Vertex --> G[allowedSchemes = http, https, gs]
    F --> H{scheme in allowlist?}
    G --> H
    H -- Yes --> I[SanitizeImageURL returns cleaned URL]
    H -- No --> J[Return error — request fails]
    I --> K{Type?}
    K -- base64 data URL --> L[InlineData Blob]
    K -- regular URL incl. gs:// --> M[FileData with FileURI]
Loading

Reviews (2): Last reviewed commit: "fix: pass through gs:// image URLs on Ve..." | Re-trigger Greptile

coderabbitai[bot]
coderabbitai Bot previously approved these changes Jun 20, 2026
@akshaydeo akshaydeo dismissed coderabbitai[bot]’s stale review June 21, 2026 11:44

The merge-base changed after approval.

@akshaydeo akshaydeo requested a review from a team as a code owner June 21, 2026 11:44
@G-XD G-XD force-pushed the fix/issue_4402 branch from a2034ce to 4c8006d Compare June 22, 2026 02:38
@CLAassistant

CLAassistant commented Jun 22, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@G-XD G-XD force-pushed the fix/issue_4402 branch from 4c8006d to eb37e25 Compare June 22, 2026 02:46
Comment on lines +2008 to 2011
sanitizedURL, err := schemas.SanitizeImageURLWithAllowedSchemes(imageURL, allowedImageURLSchemes...)
if err != nil {
// Skip this block if URL is invalid
continue
return nil, nil, fmt.Errorf("failed to sanitize image URL: %w", err)
}

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.

P1 Silent skip → error changes the ChatCompletion API contract

Before this PR, convertBifrostMessagesToGemini called SanitizeImageURL and on error did continue — silently dropping the image block and letting the request succeed. Now it returns an error, so any caller that sends a ChatMessage with a non-http/https image URL will receive an error where they previously received a (partial) success. ToGeminiChatCompletionRequest is a public, exported symbol, so any consumer relying on the old silent-skip behavior will break.

The PR description explicitly calls this out, but the checklist marks "No" for breaking changes. That's inaccurate: a request that previously returned a successful response now returns an error. Consider marking this as a breaking change in the PR, or guarding the new error with a release note so operators upgrading Bifrost are warned.

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.

Thanks, agreed. I updated the PR description to mark this as a breaking/behavioral change and added a note that invalid or unsupported Gemini image URL schemes now return an explicit conversion error instead of silently dropping the image block.

The code behavior is intentional so callers don’t get a successful response with missing image content, but the upgrade impact should be called out clearly.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@core/providers/vertex/vertex.go`:
- Around line 439-443: The issue is that when Content-Type is missing, the code
attempts to call SanitizeImageURL on raw base64-encoded bytes (the encoded
variable), but SanitizeImageURL expects a URL string, not raw bytes. To fix this
fallback media-type branch, instead of sanitizing the encoded bytes as a URL,
construct a proper data URL by prepending a data URL scheme with a default media
type (such as "data:image/jpeg;base64,") to the base64-encoded data before
assigning it to img.URL, which will inline the image correctly without requiring
sanitization.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: f57fa475-4686-4890-b06f-92840d04e75c

📥 Commits

Reviewing files that changed from the base of the PR and between a2034ce and eb37e25.

📒 Files selected for processing (11)
  • core/providers/gemini/batch.go
  • core/providers/gemini/chat.go
  • core/providers/gemini/gemini_test.go
  • core/providers/gemini/responses.go
  • core/providers/gemini/utils.go
  • core/providers/gemini/videos.go
  • core/providers/vertex/utils_test.go
  • core/providers/vertex/vertex.go
  • core/providers/vertex/vertex_test.go
  • core/schemas/utils.go
  • core/schemas/utils_test.go
🚧 Files skipped from review as they are similar to previous changes (8)
  • core/providers/gemini/videos.go
  • core/providers/gemini/batch.go
  • core/providers/vertex/utils_test.go
  • core/providers/gemini/utils.go
  • core/schemas/utils_test.go
  • core/schemas/utils.go
  • core/providers/vertex/vertex_test.go
  • core/providers/gemini/responses.go

@coderabbitai coderabbitai Bot 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.

Caution

Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@core/providers/vertex/vertex.go`:
- Around line 439-443: The issue is that when Content-Type is missing, the code
attempts to call SanitizeImageURL on raw base64-encoded bytes (the encoded
variable), but SanitizeImageURL expects a URL string, not raw bytes. To fix this
fallback media-type branch, instead of sanitizing the encoded bytes as a URL,
construct a proper data URL by prepending a data URL scheme with a default media
type (such as "data:image/jpeg;base64,") to the base64-encoded data before
assigning it to img.URL, which will inline the image correctly without requiring
sanitization.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: f57fa475-4686-4890-b06f-92840d04e75c

📥 Commits

Reviewing files that changed from the base of the PR and between a2034ce and eb37e25.

📒 Files selected for processing (11)
  • core/providers/gemini/batch.go
  • core/providers/gemini/chat.go
  • core/providers/gemini/gemini_test.go
  • core/providers/gemini/responses.go
  • core/providers/gemini/utils.go
  • core/providers/gemini/videos.go
  • core/providers/vertex/utils_test.go
  • core/providers/vertex/vertex.go
  • core/providers/vertex/vertex_test.go
  • core/schemas/utils.go
  • core/schemas/utils_test.go
🚧 Files skipped from review as they are similar to previous changes (8)
  • core/providers/gemini/videos.go
  • core/providers/gemini/batch.go
  • core/providers/vertex/utils_test.go
  • core/providers/gemini/utils.go
  • core/schemas/utils_test.go
  • core/schemas/utils.go
  • core/providers/vertex/vertex_test.go
  • core/providers/gemini/responses.go
🛑 Comments failed to post (1)
core/providers/vertex/vertex.go (1)

439-443: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Fallback media-type branch currently rejects valid remote images.

At Line 439, schemas.SanitizeImageURL(encoded) is called with raw base64 bytes (not a URL), so this path errors when Content-Type is missing instead of inlining the image.

Suggested fix
@@
-				} else {
-					// Content-Type header absent; sniff the media type from the
-					// fetched bytes so we never emit a malformed "data:;base64,..."
-					// URI, which Anthropic-on-Vertex rejects.
-					sanitized, sErr := schemas.SanitizeImageURL(encoded)
-					if sErr != nil {
-						return sErr
-					}
-					img.URL = sanitized
-				}
+				} else {
+					// Content-Type header absent; sniff media type from bytes and
+					// still emit a valid data URI.
+					decoded, decodeErr := base64.StdEncoding.DecodeString(encoded)
+					if decodeErr != nil {
+						return fmt.Errorf("failed to decode fetched image for data URI: %w", decodeErr)
+					}
+					detectedType := http.DetectContentType(decoded)
+					img.URL = "data:" + detectedType + ";base64," + encoded
+				}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@core/providers/vertex/vertex.go` around lines 439 - 443, The issue is that
when Content-Type is missing, the code attempts to call SanitizeImageURL on raw
base64-encoded bytes (the encoded variable), but SanitizeImageURL expects a URL
string, not raw bytes. To fix this fallback media-type branch, instead of
sanitizing the encoded bytes as a URL, construct a proper data URL by prepending
a data URL scheme with a default media type (such as "data:image/jpeg;base64,")
to the base64-encoded data before assigning it to img.URL, which will inline the
image correctly without requiring sanitization.

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.

[Bug]: Vertex provider drops image blocks whose URL uses gs:// scheme

2 participants