You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Adds Microsoft Entra ID through the Azure CLI as a login method for the existing Azure provider. OpenCode uses the active az login session to find the resource group and deployed models, keeps only successful deployments that exactly match the Azure models.dev catalog, and preserves each deployment name for inference.
Requests use cached Azure CLI tokens with the correct audience for Azure OpenAI/model inference and Foundry-native endpoints. The existing API-key flow is unchanged, and discovery failures make Azure unavailable without blocking startup.
How did you verify your code works?
bun test test/provider/provider.test.ts test/plugin/azure.test.ts (106 passing)
bun typecheck
bun dev models azure discovered both GPT-5 Mini and DeepSeek V4 Flash from the active Azure subscription
Screenshots / recordings
If this is a UI change, please include a screenshot or recording.
Checklist
I have tested my changes locally
I have not included unrelated changes in this PR
If you do not follow this template your PR will be automatically rejected.
AI code review — automated review for reference; please use your judgment.
packages/opencode/src/plugin/azure.ts:31 — expires_on is typed Schema.Number, but az account get-access-token --output json has returned expires_on as a string of unix seconds on several Azure CLI versions (and expiresOn as a locale datetime string); on those installs every decode fails and the whole OAuth path breaks at first use — accept both shapes (Schema.Union([Schema.Number, Schema.NumberFromString]) or explicit coercion) and add a fixture test using the string form.
packages/opencode/src/plugin/azure.ts:52 — the token cache has no single-flight: after expiry, N concurrent requests launch N parallel az account get-access-token child processes (~hundreds of ms each) before any result lands in the Map — memoize the in-flight promise per scope (tokens.set(scope, pending) pattern) so concurrent misses share one CLI call.
packages/opencode/src/plugin/azure.ts:88 — .catch(() => ({})) makes CLI/discovery failures completely invisible: a user with the wrong subscription sees an empty model list with zero diagnostics — log at debug/warning (resource name + error class) so support can tell "no deployments" apart from "az not logged in".
packages/opencode/src/plugin/azure.ts:63 — headers.delete("api-key")/x-api-key then unconditional Bearer overwrite is right for defense-in-depth, but note it also strips any user-configured static api-key header a custom model entry might have intentionally supplied for hybrid setups — probably intended (Entra-only enforcement), just document it in providers.mdx next to the new section.
Nit — packages/opencode/src/plugin/azure.ts:150 — scopeForRequest sends anything that isn't Foundry to the Cognitive Services scope, including non-Azure hosts; harmless while this fetch is bound to azure-provider routes only, but a comment stating that assumption would prevent misuse if the loader ever gets reused for other base URLs.
Overall: well-built feature — clean separation of createAzureAuthHooks(shell, request) makes the 259-line test suite possible, scope selection matches Microsoft's documented split, and the resourceName fallback chain (provider options → api metadata → oauth accountId → env) closes a real gap in provider.ts. Item 1 is the ship-blocker to verify; 2–3 are quick wins. Thanks!
AI code review — automated review for reference; please use your judgment.
packages/opencode/src/plugin/azure.ts:118 (discoverAzureModels) — .catch(() => ({})) silently swallows every discovery failure, including RBAC denials and az not being installed. The user just sees an empty model list with no explanation; consider logging a warning (or surfacing the error message in the UI) so misconfiguration is diagnosable.
packages/opencode/src/plugin/azure.ts:33 (token) — cache is keyed by scope only; if the user runs az account set --subscription other mid-session, requests keep using the old tenant's token until it lapses near the 60s refresh buffer. Probably rare, worth a comment or cache invalidation hook.
The dummy 365-day expires on the stored oauth entry is clever (real freshness lives in the CLI), but it also means the client will never prompt for re-auth when az login itself has lapsed — the docs do call this out ("sign in again when the CLI session expires"), good.
Scope routing in scopeForRequest (foundry vs cognitiveservices by hostname/path) is well-tested, including header stripping of api-key/x-api-key while preserving unrelated headers.
Test suite is excellent — mocked shell/fetch seams, negative cases (discovery failure keeps startup alive), and exact az command assertions.
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
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.
Issue for this PR
N/A
Type of change
What does this PR do?
Adds Microsoft Entra ID through the Azure CLI as a login method for the existing Azure provider. OpenCode uses the active
az loginsession to find the resource group and deployed models, keeps only successful deployments that exactly match the Azure models.dev catalog, and preserves each deployment name for inference.Requests use cached Azure CLI tokens with the correct audience for Azure OpenAI/model inference and Foundry-native endpoints. The existing API-key flow is unchanged, and discovery failures make Azure unavailable without blocking startup.
How did you verify your code works?
bun test test/provider/provider.test.ts test/plugin/azure.test.ts(106 passing)bun typecheckbun dev models azurediscovered both GPT-5 Mini and DeepSeek V4 Flash from the active Azure subscriptionScreenshots / recordings
If this is a UI change, please include a screenshot or recording.
Checklist
If you do not follow this template your PR will be automatically rejected.