Skip to content

Azure provider: select deployment (and model) from a dropdown instead of free-text #286

Description

@PotatoParser

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions