Skip to content

Support bring-your-own LLM (hosted OpenAI-compatible / Azure OpenAI) - #2035

Open
waldekmastykarz wants to merge 4 commits into
dotnet:mainfrom
waldekmastykarz:bring-your-own-llm
Open

waldekmastykarz wants to merge 4 commits into
dotnet:mainfrom
waldekmastykarz:bring-your-own-llm

Conversation

@waldekmastykarz

Copy link
Copy Markdown
Collaborator

Closes #2034

Changes

  • apiKey in languageModel config, with @env:VAR_NAME support so keys stay out of config files. Sent as Authorization: Bearer for OpenAI (any OpenAI-compatible endpoint: OpenAI, GitHub Models, OpenRouter) and Ollama clients, and as the api-key header for AzureOpenAI. The key is never logged.
  • AzureOpenAI client that reuses the OpenAI client against the Azure OpenAI v1 API (https://<resource>.openai.azure.com/openai/v1/, model = deployment name). It requires an API key.
  • Non-billable availability check: the startup probe now calls GET {url}/models:
    • 2xx and the configured model is listed (incl. Ollama's :latest tag) → enabled, no completion sent
    • 401/403 → disabled with a clear error
    • Azure OpenAI 2xx → enabled (Azure lists base models, not deployments)
    • otherwise (endpoint unsupported, model not listed) → falls back to the previous completion probe
  • Updated schemas/v4.0.0/rc.schema.json and docs in skills/dev-proxy/references.

Extends the existing clients (no new dependencies) rather than switching to Microsoft.Extensions.AI.

Validation

  • New unit tests in DevProxy.Abstractions.Tests/LanguageModel (headers, @env: resolution, probe paths)
  • E2E with local Ollama + OpenAIMockResponsePlugin: the startup check used only /models, mocked completions worked, and the key didn't appear in the logs

…net#2034

- Add `apiKey` to `languageModel` config with `@env:VAR_NAME` support.
  Sent as a Bearer token (OpenAI-compatible, Ollama) or `api-key` header
  (Azure OpenAI). The key is never logged.
- Add `AzureOpenAI` client targeting the Azure OpenAI v1 API.
- Check availability with `GET /models` instead of a billable completion,
  falling back to the completion probe when /models is unsupported or
  doesn't list the configured model.
- Update v4.0.0 rc.schema.json and docs.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI balanced review requested due to automatic review settings October 31, 2026 09:37
@waldekmastykarz
waldekmastykarz requested a review from a team as a code owner October 31, 2026 09:37

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Provider error logging can expose configured API keys, while model-discovery handling can incorrectly disable working completion endpoints.

3 open issues
What changed in this PR

Extends Dev Proxy’s language model integration to support hosted OpenAI-compatible services and Azure OpenAI while retaining local model support.

Changes:

  • Adds API-key authentication with environment-variable references and Azure OpenAI client selection.
  • Introduces a model-list availability probe with a completion fallback.
  • Adds authentication and probe tests, plus configuration schema and documentation updates.
File Description
skills/​dev-proxy/​references/​test-llm-apps.md Documents hosted clients and API-key options.
skills/​dev-proxy/​references/​configuration.md Adds hosted-model guidance and an Azure example.
schemas/​v4.0.0/​rc.schema.json Defines API-key and Azure OpenAI configuration options.
DevProxy.Abstractions/​LanguageModel/​OpenAILanguageModelClient.cs Adds authentication and model-list availability checks.
DevProxy.Abstractions/​LanguageModel/​OllamaLanguageModelClient.cs Adds authentication to completion requests.
DevProxy.Abstractions/​LanguageModel/​LanguageModelConfiguration.cs Adds API-key configuration, Azure selection, and masked string output.
DevProxy.Abstractions/​LanguageModel/​LanguageModelClientFactory.cs Routes Azure OpenAI to the OpenAI-compatible client.
DevProxy.Abstractions/​LanguageModel/​BaseLanguageModelClient.cs Centralizes key resolution and authentication headers.
DevProxy.Abstractions.Tests/​LanguageModel/​OpenAILanguageModelClientTests.cs Tests authentication, environment resolution, probes, and key masking.

Review effort: Balanced

- Redact the configured API key from logged provider errors
- Fall back to a completion probe on /models 403 (restricted keys); 401 still disables
- Disable the LM when the fallback completion fails
- Guard /models JSON parsing against unexpected payload shapes

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The language-model HttpClient can leak Azure API keys through cross-origin redirects and trigger recursive requests when Dev Proxy intercepts hosted completions.

1 open issue
1 previously missed issue

In code that hasn't changed since last review

Medium severity Bypass Dev Proxy for language-model client requests

DevProxy.Abstractions/​LanguageModel/​OpenAILanguageModelClient.cs:278

The language-model client uses the default proxy-aware HttpClient registered in DevProxy/Extensions/IServiceCollectionExtensions.cs:85–89. If its proxy settings route the hosted endpoint through Dev Proxy and the URL is watched by OpenAIMockResponsePlugin, an uncached completion is intercepted and calls the same client again, creating recursive requests instead of reaching the provider. Use a dedicated language-model handler that bypasses Dev Proxy, or add an explicit internal-request bypass in the proxy pipeline.

3 resolved since last review

Review effort: Balanced

Prevents forwarding the api-key header to another origin on redirect.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Unresolved issues can incorrectly enable case-mismatched models, leave dedicated HTTP clients undisposed across reloads, and cause redirect tests to fail from reused ports.

2 open issues
1 previously missed issue

In code that hasn't changed since last review

Medium severity Use case-sensitive comparisons for model IDs and aliases

DevProxy.Abstractions/​LanguageModel/​OpenAILanguageModelClient.cs:249

For endpoints with case-sensitive model IDs, this comparison accepts an invalid configuration such as GPT-4.1-mini when /models lists gpt-4.1-mini. The shortcut then caches the client as enabled, while completion requests send the configured name unchanged and fail. Use ordinal, case-sensitive comparisons for both the exact ID and the :latest alias.

1 resolved since last review

Review effort: Balanced

… match, stable test ports

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

No active review issues remain for the hosted OpenAI-compatible and Azure OpenAI integration.

No open issues 🎉

2 resolved since last review

Review effort: Balanced

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support bring-your-own LLM (hosted OpenAI-compatible / Azure OpenAI) for language model integration

2 participants