Repository navigation
feat(core): discover Azure deployments - #50053
Merged
Merged
Conversation
Discover Azure resources and deployments in the background with stable model IDs, paginated inventories, and connection-bound snapshots. Validate resource access before saving new API-key or Azure CLI connections, report actionable failures, and preserve active credentials on rejected attempts.
3 of 6 tasks
1056674754
added a commit
to 1056674754/opencode
that referenced
this pull request
Oct 5, 2026
Upstream v2.0.21 (014614d lineage, merged at 835531c) -> v2.0.22 (527f0b9), 76 commits / 1759 files. First normal merge on the v2 line — merge base f46fa72 exists (same re-rooted history). Staged delta vs pre-merge HEAD matches the upstream tag-to-tag diff modulo branding. Content highlights: - fix(ai): report mid-stream connection loss instead of a decode error (anomalyco#52634); isolate Groq and Vertex metadata keys (anomalyco#52598); enable Alibaba chat prompt caching (anomalyco#52612); classify Together input token rejections as context overflow (anomalyco#52133). - fix(core): default provider header/chunk timeouts to five minutes (anomalyco#49229); accept partial model capabilities in native provider config; Azure deployments discovery (anomalyco#50053); skip automatic copies of directly read instructions (anomalyco#52382). - feat(cli): 10-minute update checks (anomalyco#52552); feat(app): last-turn changes in review panel (anomalyco#51640). - Large refactor pass deleting unused v1-era helpers and errors (bulk of the -86k lines), ACP SDK 1.6.0, docs/tests. Conflicts resolved: 37 package.json version bumps (rebranded 2.0.22-sscity) + bun.lock (upstream, rebranded via bun install; 2 packages installed) + one hunk in core/src/session/runner/retry.ts — upstream added a MAX_TIMEOUT_RETRIES=3 cap with its own `timeouts` counter alongside the fork's contentPolicyAttempts cap; both counters and both gates are kept. The fork's other port files (zaiGlm scrub, cyber_policy codes, schema fallbacks, normalize, title chain) were untouched upstream and merged clean. Functional markers verified post-merge. Tests: ai zai/openai-chat/provider-error/compatible-chat 150 pass / 0 fail; core session-error/title/prompt/normalization 99 pass / 1 fail (session-revert rename case — pre-existing on pristine v2.0.21, verified in the port round). Full workspace typecheck green. Co-Authored-By: Claude Sonnet 5 <[email protected]>
Ichinose-Kazuki
pushed a commit
to Ichinose-Kazuki/opencode
that referenced
this pull request
Oct 7, 2026
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.
Issue for this PR
Closes #
Type of change
What does this PR do?
Azure only serves a model through a deployment, but OpenCode showed the whole Azure catalog (89 models) and sent the catalog ID as the deployment name. This PR lists the resource's deployments and shows those instead.
What it fixes
prod→gpt-5-mini) needs a manualmodelIDmapping in configazure/prodwith gpt-5-mini's limits and costshttps://${AZURE_RESOURCE_NAME}.services.ai.azure.com/...), so DeepSeek, Grok, Llama and the other Foundry models fail with an unresolved variableStartup
Startup does no network calls and never runs
az. The plugin reads the stored credential and serves the full catalog; discovery runs in a background fiber and narrows the list when it answers. Onv2, loading the plugin resolved the connection, so an expired Azure CLI token was refreshed throughazbefore startup could continue.Measured against a real AIServices resource, with the real
azand the real 89-model catalog, both sides on the samev2commit. "Ready" is the time until the plugin has loaded, which startup waits for. The deployment times come from one fresh process per run, in shuffled order, so every run starts with cold connections like a real startup; medians of 6 runs:v2readyazmanagement token 171 ms, Resource Graph 428 ms, deployment list 849 msazrefresh)azrefresh, 171 msThe two Azure Resource Manager requests vary by a few hundred milliseconds between runs, which hides most of the extra refresh in the medians; the
azcalls themselves stay at 167–176 ms.azanswered from its own token cache here. When that cache has expired too,azrefreshes over the network, and onv2startup waits for all of it, up to the 10 s command timeout. With this PR that time only delays the background list. If discovery fails, orsettings.baseURLis custom, the full catalog stays. Tests assert that no request and noazcall happen before the plugin finishes loading.There is no polling. Discovery runs at startup, after connecting, and after switching accounts, so a deployment added later appears after a restart or reconnect.
How it works
flowchart TD T["startup · connect · account switch"] --> RB["rebind (local, no network)<br/>read the active connection and its resource<br/>tie the provider to that connection"] RB --> D{"credential"} D -- "Azure CLI" --> RG["Resource Graph: resource ID<br/>(cached per resource)"] RG --> MG["management API: every deployment page<br/>(nextLink must stay on management.azure.com)"] MG -- "fails" --> LEG D -- "API key" --> LEG["resource's own list<br/>/openai/deployments?api-version=2022-12-01"] MG -- "ok" --> P LEG -- "ok" --> P{"still the active connection?"} LEG -- "fails" --> KEEP["log a warning, keep the last list<br/>(or the catalog)"] P -- "yes" --> PUB["show the deployed models"] P -- "no" --> DROP["discard"]The management API is Azure's documented deployment list, but Azure Resource Manager only accepts Entra tokens. API keys therefore use the data-plane list, which only exists in
2022-12-01; later versions dropped/deployments, and/openai/v1/modelslists models the resource can deploy rather than its deployments. Links to the Azure docs are next to each caveat in the code.Switching accounts
The previous account's list is never shown for the new one. The interrupted discovery cannot publish, and every discovery checks that its connection is still active before publishing.
Deployments to models
The ID is the deployment name in lowercase; Azure compares names without case, and requests send the name exactly as Azure returned it. Limits, costs, and capabilities come from the catalog model the deployment deploys, or, when Azure spells it differently (
gpt-4for GPT-4 Turbo,gpt-35-turbo), from the catalog model the deployment is named after.gpt-5-mini→gpt-5-miniazure/gpt-5-mini, "GPT-5 Mini"prod→gpt-5-miniazure/prod, "GPT-5 Mini (prod)"GPT-5-Nano→gpt-5-nanoazure/gpt-5-nanogpt-4-turbo→gpt-4azure/gpt-4-turbowith GPT-4 Turbo's detailsft-legal→gpt-4o-mini.ft-123Models configured explicitly are always kept.
Compatibility
azure/<id>. Any deployment named after a catalog ID keeps that ID, so every session that worked before keeps working; only models without any deployment disappear, and those already failed with a 404.settings.resourceNamein config. This only matters if config was changed to another resource after connecting; reconnecting picks it up.How did you verify your code works?
bun test test/plugin/provider-azure.test.tsinpackages/core: 29 tests against a localBun.servefake of Azure, repeated to check the switch timing.bun run checkpasses.gpt-5-miniandDeepSeek-V4-Flashdeployed:DeepSeek-V4-Flash,deepseek-v4-flash, andDEEPSEEK-V4-FLASHas the deployment name.Screenshots / recordings
Not a UI change.
Checklist