feat(providers): claude on azure (#1009 final cell)#1027
Merged
Conversation
Closes the final cell of the provider × platform matrix.
This is best-endeavors: the URL pattern follows Microsoft's standard
AIServices deployment shape (mirrors openai+azure exactly except
`/messages` instead of `/chat/completions`). The choice is documented
inline (azureAnthropicDeploymentEndpoint) with rationale and a
follow-up note for switching to a vendor-prefixed pattern if the live
deployment uses one. No live verification has been done — the Foundry
Anthropic quota for our subscription is currently 0 in eastus2 and
swedencentral and quota requests are portal-only.
Wire format (planned, to verify on first live run):
- URL: {endpoint}/openai/deployments/{deployment}/messages?api-version={v}
(mirrors openai+azure with /messages instead of /chat/completions;
deployment name comes from spec.Model)
- Auth: Entra Bearer via credentials.AzureCredential — same path as
openai+azure
- Body: standard Anthropic Messages API verbatim (model in body,
stream:true for streaming) — distinct from Bedrock/Vertex
which use the partner shape (no model, anthropic_version body)
- API version: configurable via PlatformConfig.AdditionalConfig
("api_version"); defaults to defaultAzureAPIVersion
("2024-12-01-preview", same as openai+azure)
- No anthropic-version header (api-version query parameter pins the
contract)
Code structure:
- Added `azurePlatform` constant + `defaultAzureAPIVersion` in
claude.go, plus `azureAnthropicDeploymentEndpoint(endpoint,
deployment)` URL builder.
- New `isAzure()` predicate. New `usesCredentialAuth()` predicate
covering Bedrock + Vertex + Azure (the auth-side superset of
isPartnerHosted, which stays Bedrock+Vertex only because Azure
does not use the partner body shape).
- New `azureAPIVersion()` reads PlatformConfig.AdditionalConfig
with defaultAzureAPIVersion fallback.
- `messagesURL()` / `messagesStreamURL()` now branch on Azure to
produce `{baseURL}/messages?api-version={v}`. Both return the
same path because Azure's streaming and non-streaming share an
endpoint (signalled by `stream:true` in body).
- `NewProviderWithCredential` derives the deployment URL from
`PlatformConfig.Endpoint` when `BaseURL == ""` and
`Platform == "azure"`.
- `makeClaudeHTTPRequest` (claude.go): partner-vs-direct dispatch
unchanged; Azure now also skips the anthropic-version header
(api-version pins it instead). Error parsing routes Azure
through `providers.ParsePlatformHTTPError`.
- `applyToolRequestHeaders` (claude_tools.go): switched from
`isPartnerHosted` to `usesCredentialAuth` so Azure also goes
through credential.Apply (Bearer) rather than x-api-key.
- `PredictStream` direct branch (claude_streaming.go): now calls
`messagesStreamURL()` (Azure-aware) and skips the
anthropic-version header for Azure. Body is unchanged since
Azure shares the direct API body shape.
- Registry skips `https://api.anthropic.com` default when
`spec.Platform == "azure"` (regression test added).
Tests:
- azure_unit_test.go covers predicates, URL builder, factory URL
derivation, api-version selection, header omission, and a full
PredictStream wire-format assertion against an httptest server.
- registry_extended_test.go adds the claude+azure regression test
matching the openai+azure / gemini+vertex / claude+vertex
patterns.
Bedrock/Vertex/direct paths unchanged — confirmed via existing
unit tests (all pass) and not regressed by the predicate refactor.
Closes #1009 (final cell)
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Summary
Closes the final cell of the provider × platform matrix. Best-endeavors:
the URL pattern follows Microsoft's standard AIServices deployment shape
(mirrors openai+azure exactly except
/messagesinstead of/chat/completions). No live verification has been done — theFoundry Anthropic quota for our subscription is currently 0 in eastus2
and swedencentral and quota requests are portal-only.
Wire format (planned, to verify on first live run)
{endpoint}/openai/deployments/{deployment}/messages?api-version={v}credentials.AzureCredential(same as openai+azure)stream:truefor streaming. Distinct from Bedrock/Vertex which use the partner shape.PlatformConfig.AdditionalConfig.api_version→ defaults to2024-12-01-preview(same as openai+azure)anthropic-version(api-version query parameter pins the contract)If the Foundry deployment turns out to use a vendor-prefixed pattern
(
{endpoint}/anthropic/v1/messages?api-version=...) instead, the fixis a one-line change to
messagesURL/messagesStreamURL.Code structure
azurePlatformconstant +defaultAzureAPIVersionin claude.go,plus
azureAnthropicDeploymentEndpoint(endpoint, deployment).isAzure()predicate. NewusesCredentialAuth()predicatecovering Bedrock + Vertex + Azure (the auth-side superset of
isPartnerHosted, which stays Bedrock+Vertex only because Azuredoes not use the partner body shape).
azureAPIVersion()readsPlatformConfig.AdditionalConfigwithdefaultAzureAPIVersionfallback.messagesURL()/messagesStreamURL()branch on Azure to produce{baseURL}/messages?api-version={v}. Both return the same path —Azure uses one endpoint signalled by
stream:truein body.NewProviderWithCredentialderives the deployment URL fromPlatformConfig.EndpointwhenBaseURL == ""and Platform="azure".makeClaudeHTTPRequestskips theanthropic-versionheader forAzure (api-version pins it). Errors route through
providers.ParsePlatformHTTPError.applyToolRequestHeadersswitched tousesCredentialAuthso Azuregoes through
credential.Apply(Bearer) rather than x-api-key.PredictStreamdirect branch now callsmessagesStreamURL()(Azure-aware) and skips the
anthropic-versionheader for Azure.https://api.anthropic.comdefault forPlatform == "azure".Tests
azure_unit_test.go— predicates, URL builder, factory URLderivation, api-version selection, header omission, full
PredictStream wire-format assertion against an httptest server.
registry_extended_test.go— claude+azure regression testmatching the openai+azure / gemini+vertex / claude+vertex pattern.
Bedrock / Vertex / direct paths unchanged — confirmed via existing
unit tests (all pass) and not regressed by the predicate refactor.
Pre-commit
88.1%, claude_tools.go 84.1%, registry.go 93.5% (all ≥80%)
Test plan
go test -race -count=1 ./runtime/providers/claude/... ./runtime/providers/...— green/anthropic/v1/messagesper the inline comment.Matrix status after this PR
9 of 9 cells delivered. #1009 is closeable on the code side; one cell flagged as "URL-shape unverified pending live deployment".
Closes #1009