Skip to content

feat(gateway): Azure and key-in-URL upstreams on top of exact endpoints - #6101

Open
t0saki wants to merge 4 commits into
volcengine:mainfrom
t0saki:feat/gateway-full-endpoint
Open

t0saki wants to merge 4 commits into
volcengine:mainfrom
t0saki:feat/gateway-full-endpoint

Conversation

@t0saki

@t0saki t0saki commented Oct 15, 2026 •

Copy link
Copy Markdown
Collaborator

Description

#6100 added append_endpoint_path so an upstream can use its Base URL as the complete request endpoint. That is not enough for the endpoints that motivated it:

  • Azure OpenAI deployments (https://RES.openai.azure.com/openai/deployments/DEP/chat/completions?api-version=2024-10-21) need a query string, which Upstream.validate_url still rejects, and take the key in an api-key header, while upstream_headers() always sends Authorization: Bearer.
  • Providers or proxies that take the key in the URL have no way to put it there without storing it in plain text in base_url, which is returned to read-only callers, shown in the upstream list and echoed by the connection test. The key field is also mandatory and always sent as Bearer.
  • With path appending off, every request went to the same URL: count_tokens was sent to the messages endpoint, /v1/responses/{id} to the create endpoint, embeddings and other protocol-less requests to the chat endpoint, and the connection test sent GET /v1/models there and reported the 404/405 as "models unavailable".

For the same reasons the VLM import skipped every Azure credential.

This PR builds on #6100 (keeping its field, toggle and wording) and fills these gaps.

Human Involvement

  • A human participated in the implementation or review loop
  • This PR was generated entirely by AI agents without human participation in the loop

Related Issue

Follow-up to #6100. User feedback: the gateway cannot use fully custom endpoints such as Azure OpenAI or URLs that embed the key.

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update
  • Refactoring (no functional changes)
  • Performance improvement
  • Test update

Changes Made

  • Queries in base_url: allowed in both modes (credentials and fragments are still rejected; the trailing slash is stripped from the path only). Stored parameters come first and win over client parameters with the same name, so a client cannot override api-version.
  • {api_key} placeholder: the only brace text allowed, never in the host. The key is URL-encoded into the stored address at send time only (never into the client's path or query), and no auth header is sent. Stored, listed and test-result URLs keep the placeholder.
  • key_header: authorization (default, unchanged behavior), api-key or x-api-key; the latter two send only that header.
  • Exact endpoints (append_endpoint_path=False): the protocol's primary path goes to the URL, its sub-paths continue after it (…/messages/count_tokens, …/responses/{id}), other paths return 404, and protocol-less requests (embeddings, files, …) never select such an upstream; stored responses still find an exact responses upstream. The connection test returns exact_endpoint_untestable without sending anything; in base mode it keeps the stored query and fills the key.
  • VLM import: azure and LiteLLM azure/<deployment> credentials become exact-endpoint chat upstreams at {api_base}/openai/deployments/{deployment}/chat/completions?api-version={api_version or 2025-01-01-preview} with key_header="api-key". append_endpoint_path and key_header are refreshed on re-import.
  • Studio: a "Send the key as" select for the Generic provider (disabled with an explanation when the URL contains {api_key}, reset when switching providers), URL validation and preview that accept queries and the placeholder, and a disabled connection test for exact endpoints. en and zh-CN strings stay in sync.
  • Docs (en/zh 22-gateway-operations.md, 25-gateway.md): queries, {api_key}, the key header, an Azure OpenAI deployment example, which requests an exact endpoint serves, Azure OpenAI v1 / Claude in Microsoft Foundry / Gemini OpenAI-compatible base URLs, the corrected passthrough description, Azure import, and the removed azure skip reason.

Testing

  • I have added tests that prove my fix is effective or that my feature works

  • New and existing unit tests pass locally with my changes

  • I have tested this on the following platforms:

    • Linux
    • macOS
    • Windows
  • pytest tests/gateway tests/server/test_gateway_vlm.py: 746 passed. New shared URL vectors in tests/fixtures/gateway_upstream_urls.json cover stored queries, query merging, exact-endpoint sub-paths, the embeddings 404 and the placeholder; app tests cover an Azure-style request (api-key only, merged query), a key-in-query request with no auth header, and a stored response fetched through an exact responses endpoint.

  • Studio: vitest run src/routes/gateway src/i18n 370 passed, including an upstream stored before append_endpoint_path existed (its test button stays enabled). tsc reports no errors in gateway files; ESLint and Prettier are clean on changed files.

  • ruff format --check and ruff check pass on changed Python files.

Checklist

  • My code follows the project's coding style
  • I have performed a self-review of my code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • Any dependent changes have been merged and published

Screenshots (if applicable)

N/A

Additional Notes

  • Changing any part of base_url, including its query, still clears the stored key and headers, as before.
  • The Azure import has not been exercised against a live Azure resource yet.

Copilot AI balanced review requested due to automatic review settings October 15, 2026 04:32

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

An organization owner can choose the repository organization as the billing source for reviews requested by members with a paid Copilot license. Learn about Copilot code review billing.

Builds on append_endpoint_path: base_url may carry a query (stored
parameters win over client ones), {api_key} fills the key into the URL
with no auth header, and key_header picks Bearer, api-key or x-api-key.
Exact endpoints serve their protocol's path and its sub-paths only, so
count_tokens and stored responses continue after the endpoint while
embeddings and the connection test no longer reach them.
@t0saki
t0saki force-pushed the feat/gateway-full-endpoint branch from 177e8ce to 9b00c23 Compare October 15, 2026 06:03
@t0saki t0saki changed the title feat(gateway): support full custom endpoints for upstreams (Azure OpenAI, key-in-URL) feat(gateway): Azure and key-in-URL upstreams on top of exact endpoints Oct 15, 2026

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

Status: Backlog

Development

Successfully merging this pull request may close these issues.

2 participants