Problem
The Azure provider's setup UI makes the user hand-type the values that are most error-prone to get right. In both the Add Provider and Edit Provider dialogs the Azure section renders Deployment and API version as free-text inputs, and the Default model is a fixed catalog list (web/src/app/settings/_components/EditProviderDialog.tsx:205-259, web/src/app/settings/add-provider/page.tsx:266-316). The model dropdown for every provider is sourced 100% from a static array — for Azure that is ["gpt-5.5","gpt-5.4","gpt-4o","gpt-4o-mini","o3-mini"] (src/provider.ts:214, surfaced via GET /api/providers/catalog at src/http.ts:1616). No code anywhere fetches a live list from a provider.
Because Azure routes chat completions to a deployment name (not a base model id), a user who mistypes the deployment — or simply doesn't remember what they named it in the portal — gets a 404 at chat time rather than at configuration time. The static model list also doesn't reflect what the user has actually deployed. The ask: let users pick their real deployments (and models) from a dropdown instead of typing them.
Proposed solution
Add a server-side gateway endpoint that lists the resource's deployments, and render the Deployment field as a <Select> in the Add/Edit dialogs, with graceful fallback to the current free-text input.
- Mechanism (primary): data-plane
GET {endpoint}/openai/deployments?api-version=2022-12-01 using the credential already stored for the provider (api-key header, or Authorization: Bearer when authScheme=bearer). It returns the user's actual deployments as { id (deployment name), model (base model), status }, which is exactly the dropdown payload. Verified working against a live resource (June 2026) — see Additional context.
- Trust boundary: the call stays server-side in the gateway so the api-key/bearer never reaches the browser (consistent with the existing BFF token boundary). The endpoint returns only deployment metadata (names/models/status), never the secret.
- UX: populate on dialog open and via a small refresh affordance; selecting a deployment auto-fills the Default model from its base
model; non-succeeded deployments are shown disabled.
- Fallback: if the listing call fails (key not entered yet, network error, or Microsoft finally removes the legacy data-plane surface), fall back to the existing free-text input with a hint. Worst case equals today's behavior, so the change is purely additive.
Integration points
- New
[method, RegExp, Handler] route in the routes table in createHandler (src/http.ts:192), next to the POST /api/setup/provider handler, delegating to a new function in src/runtime/setup-api.ts (mirrors the setSetupProvider pattern).
- Wire the
<Select> into the Azure sections of EditProviderDialog.tsx and add-provider/page.tsx.
- No schema change:
ProviderConfig already persists deployment (src/types.ts).
Acceptance criteria
- With a saved Azure endpoint + key, the Deployment field offers a dropdown of the resource's real deployments (label:
deployment · base model), and picking one persists it.
- Selecting a deployment pre-fills the Default model.
- If listing fails, the field degrades to free-text entry with no error wall.
- The api-key/bearer is never sent to the browser.
- Tests cover: successful listing, listing failure → fallback, and the server-side credential handling.
Alternatives considered
- Data-plane
GET /openai/models for a model dropdown — fully supported and GA (works with just the api-key on current api-versions), but it returns the resource's supported base-model catalog (158 entries; 77 chat-capable), not what is deployed. Routing to a listed-but-undeployed model 404s at chat time, so it's noisy and slightly misleading; useful only to enrich the model field, not to solve the deployment problem.
- ARM control-plane deployments list (
management.azure.com/.../Microsoft.CognitiveServices/accounts/{account}/deployments) — the officially supported, durable way to enumerate deployments, but it requires a Microsoft Entra bearer token (https://management.azure.com/.default), an RBAC role (Microsoft.CognitiveServices/accounts/deployments/read), and subscriptionId + resourceGroup + accountName. Only the account name is derivable from the *.openai.azure.com hostname; subscription and resource group are not. That's significant new config + an OAuth/token flow — heavy for a personal runtime. Worth revisiting only if the legacy data-plane endpoint is removed.
- Status quo (manual entry) — what every self-hosted peer does (LibreChat, Open WebUI, LiteLLM all require hand-configured Azure deployment names). Functional but exactly the friction this issue targets.
Additional context
Empirical findings (tested against a live https://<resource>.openai.azure.com, api-key only, June 2026):
| Call |
Result |
GET /openai/deployments?api-version=2022-12-01 |
200 — real deployments {id, model, status} |
GET /openai/deployments?api-version=2023-03-15-preview |
200 — same list |
GET /openai/deployments?api-version=2023-05-15 (and newer) |
404 Resource not found |
GET /openai/models?api-version=2024-10-21 |
200 — 158 base models (77 with chat_completion) |
Deployment object shape:
{ "id": "gpt-5.5", "model": "gpt-5.5", "status": "succeeded",
"scale_settings": { "scale_type": "standard" }, "object": "deployment" }
Note the discrepancy worth calling out for whoever implements this: Microsoft documents the data-plane /openai/deployments listing as retired (last documented working version 2023-03-15-preview), yet it still answers on the legacy 2022-12-01/2023-03-15-preview data-plane versions today. Treat it as undocumented/best-effort and pin the listing call to 2022-12-01 independent of the chat api-version, with the fallback above.
Azure API sources
Data plane (works with the resource api-key):
Control plane / ARM (the supported deployment-listing path; needs Entra auth + IDs):
Prior art (peers require manual Azure deployment config):
Related: ADR docs/adr/azure-provider.md; the Azure provider landed in #284.
Problem
The Azure provider's setup UI makes the user hand-type the values that are most error-prone to get right. In both the Add Provider and Edit Provider dialogs the Azure section renders Deployment and API version as free-text inputs, and the Default model is a fixed catalog list (
web/src/app/settings/_components/EditProviderDialog.tsx:205-259,web/src/app/settings/add-provider/page.tsx:266-316). The model dropdown for every provider is sourced 100% from a static array — for Azure that is["gpt-5.5","gpt-5.4","gpt-4o","gpt-4o-mini","o3-mini"](src/provider.ts:214, surfaced viaGET /api/providers/catalogatsrc/http.ts:1616). No code anywhere fetches a live list from a provider.Because Azure routes chat completions to a deployment name (not a base model id), a user who mistypes the deployment — or simply doesn't remember what they named it in the portal — gets a 404 at chat time rather than at configuration time. The static model list also doesn't reflect what the user has actually deployed. The ask: let users pick their real deployments (and models) from a dropdown instead of typing them.
Proposed solution
Add a server-side gateway endpoint that lists the resource's deployments, and render the Deployment field as a
<Select>in the Add/Edit dialogs, with graceful fallback to the current free-text input.GET {endpoint}/openai/deployments?api-version=2022-12-01using the credential already stored for the provider (api-keyheader, orAuthorization: BearerwhenauthScheme=bearer). It returns the user's actual deployments as{ id (deployment name), model (base model), status }, which is exactly the dropdown payload. Verified working against a live resource (June 2026) — see Additional context.model; non-succeededdeployments are shown disabled.Integration points
[method, RegExp, Handler]route in the routes table increateHandler(src/http.ts:192), next to thePOST /api/setup/providerhandler, delegating to a new function insrc/runtime/setup-api.ts(mirrors thesetSetupProviderpattern).<Select>into the Azure sections ofEditProviderDialog.tsxandadd-provider/page.tsx.ProviderConfigalready persistsdeployment(src/types.ts).Acceptance criteria
deployment· base model), and picking one persists it.Alternatives considered
GET /openai/modelsfor a model dropdown — fully supported and GA (works with just the api-key on current api-versions), but it returns the resource's supported base-model catalog (158 entries; 77 chat-capable), not what is deployed. Routing to a listed-but-undeployed model 404s at chat time, so it's noisy and slightly misleading; useful only to enrich the model field, not to solve the deployment problem.management.azure.com/.../Microsoft.CognitiveServices/accounts/{account}/deployments) — the officially supported, durable way to enumerate deployments, but it requires a Microsoft Entra bearer token (https://management.azure.com/.default), an RBAC role (Microsoft.CognitiveServices/accounts/deployments/read), andsubscriptionId+resourceGroup+accountName. Only the account name is derivable from the*.openai.azure.comhostname; subscription and resource group are not. That's significant new config + an OAuth/token flow — heavy for a personal runtime. Worth revisiting only if the legacy data-plane endpoint is removed.Additional context
Empirical findings (tested against a live
https://<resource>.openai.azure.com, api-key only, June 2026):GET /openai/deployments?api-version=2022-12-01{id, model, status}GET /openai/deployments?api-version=2023-03-15-previewGET /openai/deployments?api-version=2023-05-15(and newer)Resource not foundGET /openai/models?api-version=2024-10-21chat_completion)Deployment object shape:
{ "id": "gpt-5.5", "model": "gpt-5.5", "status": "succeeded", "scale_settings": { "scale_type": "standard" }, "object": "deployment" }Note the discrepancy worth calling out for whoever implements this: Microsoft documents the data-plane
/openai/deploymentslisting as retired (last documented working version2023-03-15-preview), yet it still answers on the legacy2022-12-01/2023-03-15-previewdata-plane versions today. Treat it as undocumented/best-effort and pin the listing call to2022-12-01independent of the chat api-version, with the fallback above.Azure API sources
Data plane (works with the resource api-key):
GET {endpoint}/openai/models, api-key auth, returns base + fine-tuned models with capabilities/lifecycle): https://learn.microsoft.com/en-us/rest/api/azureopenai/models/list?view=rest-azureopenai-2024-10-21GET {endpoint}/openai/v1/models): https://learn.microsoft.com/en-us/azure/foundry/openai/latest/openai/deploymentsretirement (last working2023-03-15-preview): https://learn.microsoft.com/en-us/answers/questions/1371786/get-azure-openai-deployments-in-apiControl plane / ARM (the supported deployment-listing path; needs Entra auth + IDs):
2025-06-01: https://learn.microsoft.com/en-us/rest/api/aifoundry/accountmanagement/deployments/list?view=rest-aifoundry-accountmanagement-2025-06-012024-10-01(request/response shape sample): https://learn.microsoft.com/en-us/rest/api/aiservices/accountmanagement/deployments/list?view=rest-aiservices-accountmanagement-2024-10-01&tabs=HTTPMicrosoft.CognitiveServices/accounts/deploymentsapi-version change log: https://learn.microsoft.com/en-us/azure/templates/microsoft.cognitiveservices/change-log/accounts/deploymentshttps://management.azure.com/.default): https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/manage-resources-restaccounts/deployments/read: https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles/ai-machine-learningPrior art (peers require manual Azure deployment config):
openai-pythondiscussion #920 (control vs data plane;models.list()returns the base catalog, not deployments): `Model` API doesn't retrieve Azure OpenAI deployments openai/openai-python#920deploymentName): https://www.librechat.ai/docs/configuration/azureRelated: ADR
docs/adr/azure-provider.md; the Azure provider landed in #284.