fix: Go ADK Vertex AI client sends requests to wrong endpoint (missing rawPredict URL rewrite) - #2314
Conversation
There was a problem hiding this comment.
Pull request overview
This PR fixes the Go ADK Anthropic Vertex AI client setup so that requests are routed through Vertex AI’s authenticated client and request rewriting (e.g., /v1/messages → :rawPredict) instead of accidentally being sent via an unauthenticated plain http.Client.
Changes:
- Reorders
option.WithHTTPClient(...)andvertex.WithGoogleAuth(...)so the Vertex option is applied last and cannot be overwritten. - Adds detailed inline commentary explaining the ordering/root-cause to prevent regressions.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // Create HTTP client with timeout, custom headers, and TLS. | ||
| // This must be applied BEFORE vertex.WithGoogleAuth so that the Vertex | ||
| // option (which internally calls WithHTTPClient with an OAuth2-authenticated | ||
| // transport, sets the Vertex AI base URL, and registers middleware that | ||
| // rewrites /v1/messages to the rawPredict endpoint) takes precedence. |
There was a problem hiding this comment.
Good call -- the comment is over-specifying SDK internals that could drift as the anthropic-sdk-go evolves. I'll tighten both comments to focus on the ordering contract (last WithHTTPClient wins) rather than describing internal middleware behavior. Thanks for the suggestion.
5321736 to
31f4afc
Compare
…th2 auth The Vertex AI client option ordering was incorrect: vertex.WithGoogleAuth was applied first, then option.WithHTTPClient was appended after it. Since WithGoogleAuth internally calls WithHTTPClient with an OAuth2-authenticated transport (plus setting the Vertex AI base URL and registering URL-rewriting middleware for rawPredict), the subsequent WithHTTPClient call from BuildHTTPClient overwrote the authenticated client with a plain one. This caused two problems: 1. Requests were sent without OAuth2 credentials (HTTP 401) 2. The URL path remained /v1/messages instead of being rewritten to the correct Vertex AI rawPredict endpoint The fix reorders the options so WithHTTPClient (TLS/headers/timeout) is applied first, then vertex.WithGoogleAuth is applied last, allowing its internal WithHTTPClient to take precedence with the OAuth2-authenticated transport. Signed-off-by: jon waggoner <jon.waggoner@gocaribou.com>
Signed-off-by: jon waggoner <jon.waggoner@gocaribou.com>
6e4f633 to
547190f
Compare
|
Note: I considered adding a unit test for the option ordering fix but decided against it. The Anthropic SDK's |
|
|
||
| // Must be last: last WithHTTPClient wins, so Vertex auth must come after | ||
| // any custom HTTP client. | ||
| opts = append(opts, vertex.WithGoogleAuth(ctx, region, projectID)) |
There was a problem hiding this comment.
heads up, vertex.WithGoogleAuth builds its own http client n calls withhttpclient itself, so it wipes buildhttpclient's custom tls/headers client entirely not just the oauth part, so custom ca cert or headers on a vertex cfg would silently stop applying
There was a problem hiding this comment.
see comment below. thanks for callout. #2314 (comment)
|
@mesutoezdil You were right — reversing the order swapped one bug for another: |
The prior commit reversed the option ordering so vertex.WithGoogleAuth's
OAuth2 client won last, which fixed the 401 but silently discarded the
custom transport stack from BuildHTTPClient (custom TLS CA cert,
TLSInsecureSkipVerify, custom headers, connect timeout, request Timeout).
Compose them instead:
- Resolve Google Application Default Credentials ourselves with the
cloud-platform scope (matching what WithGoogleAuth would do
internally) and return an error on failure rather than panicking.
- Wrap the caller's *http.Client Transport in an oauth2.Transport so
both the custom transport chain AND the OAuth2 bearer token are
applied on the wire. Preserve the caller's http.Client.Timeout.
- Apply vertex.WithCredentials first so its base URL and URL-rewrite
middleware are registered, then apply option.WithHTTPClient last
with the composed client. Only the HTTPClient field is overridden;
the SDK stores base URL on a separate field and middleware is
additive, so the Vertex adaptation still runs.
Extract the composition into composeVertexHTTPClient so it is unit
testable without ADC. New tests cover: OAuth2 Authorization header is
attached, TransportConfig.Headers survive composition, the caller's
transport is preserved as the oauth2.Transport.Base, timeout is
preserved, and nil base.Transport falls back to http.DefaultTransport.
Signed-off-by: jon waggoner <jon.waggoner@gocaribou.com>
Signed-off-by: jon waggoner <jon.waggoner@gocaribou.com>
5db14c5 to
c7ec76b
Compare
Fixes #2315
Summary
Fix the Go ADK Anthropic Vertex AI client to correctly route requests to the Vertex AI
rawPredictendpoint instead of the direct Anthropic API path/v1/messages.Problem
When using Anthropic models via Vertex AI, the Go ADK runtime (
golang-adkimage) sends requests to the wrong URL:The correct Vertex AI endpoint should be:
The Python runtime works correctly because the Python Anthropic SDK properly constructs the Vertex AI URL.
Root Cause
In
NewAnthropicVertexAIModelWithLogger, the SDK options were applied in the wrong order:The
vertex.WithGoogleAuthfunction (fromanthropic-sdk-go) internally does three things viaWithCredentials:WithBaseURLto the Vertex AI endpoint/v1/messagesto therawPredictpathWithHTTPClientwith an OAuth2-authenticated HTTP transportWhen
option.WithHTTPClient(httpClient)was appended afterWithGoogleAuth, it replaced the OAuth2-authenticated client with a plain HTTP client (just TLS + headers + timeout). This meant:Fix
Reorder the options so
WithHTTPClientis applied beforevertex.WithGoogleAuth, allowing the Vertex option to take precedence:This ensures the Vertex AI SDK's authenticated client, base URL, and URL-rewriting middleware all take effect.