Commit Graph
10 Commits
Author SHA1 Message Date
Ruben FiszelandClaude Opus 5 6e56ce11db fix(ai): make the proxy and the AI agent step read a resource the same way (#10359)
The two paths derive the endpoint and the credential header independently, so a
resource could authenticate in one and 401 in the other. A parity test pins them
together across the provider/platform matrix and fails on each divergence below.

- Anthropic base URLs were read differently: the proxy trimmed and re-appended
  `/v1` while the agent step appended `/messages` to the stored value, so a
  `.../anthropic` base worked in workspace settings and 404'd in an agent step.
  `build_anthropic_api_url` accepts both forms for both paths, and the URL no
  longer depends on the client-supplied `X-Anthropic-SDK` header, which is gone.
- A base URL stored with a trailing slash doubled it in an agent step.
- An OpenAI resource pointed at Azure got Azure's URL layout and `api-key`
  header from the proxy but bearer auth and the plain path from the agent step,
  where `OpenAIQueryBuilder` ignored `is_azure`.
- The agent step sent an empty credential when the resource had no api key,
  where the proxy sends none at all. `retain_effective_credentials` gives both
  the same rule, so an endpoint that authenticates another way still works.
- An OAuth resource cannot resolve to a token in a worker: there is no client
  credentials exchange there, so it now fails with that reason unless it carries
  the credential header its provider reads.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 16:38:13 +02:00
Ruben FiszelandClaude Opus 5 ebf68d7970 fix(ai): support OpenAI/Anthropic-compatible gateways in workspace AI settings (#10356)
* fix(ai): stop breaking OpenAI-compatible gateways in workspace AI settings

The workspace/instance AI proxy sent credentials in a shape that
OpenAI-compatible and Anthropic-compatible gateways reject, while the same
resource worked in an AI agent step:

- `is_azure` treated *any* OpenAI base URL other than api.openai.com as Azure,
  so a gateway got the Azure `api-key` header instead of `Authorization: Bearer`
  and an `/openai/v1/`-rewritten path. Match on the host instead.
- The Anthropic proxy sent both `authorization: Bearer` and `X-API-Key`.
  Gateways reject ambiguous credentials; send only the header the endpoint
  expects, matching `get_auth_headers` and the agent-step path.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(ai): match Azure on the endpoint and let resource headers own auth

Review follow-ups:
- Azure OpenAI reached through a custom domain keeps its `/openai/deployments`
  path, which `openai_azure_base_path` documents; match on it so those
  instance-wide settings are not reclassified as plain OpenAI-compatible.
- Cover the sovereign-cloud API Management suffixes and FQDNs with a trailing
  dot.
- A resource that supplies its own `authorization`/`x-api-key` header now
  suppresses the built-in one. Outgoing headers are appended rather than
  replaced, so both credentials used to travel, which is exactly what gateways
  reject; this is the escape hatch for endpoints wanting bearer auth.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(ai): give the agent step the same resource-header credential rule

Review round follow-ups:
- `ai_executor` appended the query builder's credential header alongside the
  resource's, so an AI agent step still sent two credentials where the proxy now
  sends one. Both paths share `resource_owns_credentials`/`CREDENTIAL_HEADERS`;
  non-credential headers such as `anthropic-version` are kept.
- Cover the OpenAI-compatible proxy's suppression branch with a test.
- Match the Azure deployments path case-insensitively, like the host.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(ai): scope the credential override to the header the provider uses

A resource header now replaces the built-in credential only when it is the same
header the provider authenticates with, or an `authorization` one (which every
endpoint reads as the credential). Matching any credential-shaped header let an
OpenAI-compatible resource's `x-api-key` routing header suppress the bearer
token. Google AI's `x-goog-api-key` joins the list so the override reaches that
provider too.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* refactor(ai): share credential and trailing header assembly across AI paths

The proxy and the AI agent step each assembled outbound headers themselves, so
this fix had to be applied at three sites and the rules could drift apart
silently. Two pieces move into `proxy`:

- `credential_header` picks the credential to send, applying the resource
  override. `authorization` carries a bearer token and every other credential
  header carries the raw key, which holds for every provider.
- `common_outbound_headers` yields Windmill's own headers then the resource's,
  the tail every outbound request shares.

A resource resolves to an api key or an OAuth token, never both, so selecting
one drops the branch that could emit two `authorization` headers.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(ai): keep OAuth tokens on the bearer header

An OAuth resource resolves to an access token, which every provider reads from
`authorization` — Azure OpenAI accepts api keys in `api-key` but Entra ID tokens
only as a bearer. Sending it in the provider's key header left Azure OpenAI and
Foundry Claude OAuth resources unauthenticated.

Also covers the credential-override narrowing: a credential-shaped header the
provider does not authenticate with is an ordinary header and must not suppress
the built-in credential.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 15:23:49 +02:00
hugocasaandClaude Opus 4.8 d600c7ecfe fix(ai): route Azure Foundry Claude models via Anthropic Messages API (#9908)
* fix(ai): route Azure Foundry Claude models via Anthropic Messages API

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(ai): keep explicit Azure OpenAI deployment base URLs intact

build_azure_openai_url only appends /openai/v1 for a bare resource root; any base with an explicit path (e.g. .../openai/deployments/<id>) is preserved. Adds a regression test and a unit test for usesAnthropicMessagesApi.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat(ai): enable Claude extended thinking on Azure Foundry

Route azure_foundry+Claude through the Anthropic reasoning branch (adaptive thinking + output_config.effort) instead of the gpt/o gate, and recognize claude-sonnet-5. Live-verified: sonnet-5 and opus-4-8 on Foundry accept the low/medium/high/xhigh/max ladder and render summarized thinking.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-03 18:26:12 +02:00
hugocasaandClaude Opus 4.8 d9b080f57f feat(ai): add Azure AI Foundry as a native AI provider (#9879)
* feat(ai): add Azure AI Foundry as a native AI provider

Adds `azure_foundry` as a new AIProvider variant wired through the AI
chat (copilot) and AI agent flow steps. Foundry's chat completions API
is OpenAI-compatible and uses Azure conventions (api-key header, Azure
URL building), so it reuses the existing OpenAI-compatible query builder
and proxy path via the shared `is_azure` helper (renamed from
`is_azure_openai`).

Backend (windmill-ai):
- New `AzureFoundry` enum variant (serde `azure_foundry`)
- `get_base_url` requires a resource base URL (like Azure OpenAI / Custom)
- `is_azure()` covers Azure OpenAI + Foundry (api-key auth, Azure URL)
- Added to OpenAI-compatible proxy support and HttpForward proxy mode
- New proxy URL unit test

Frontend (copilot):
- New provider entry, completion config, model-token handling, streamed
  usage tracking, and reasoning registry (all model-id-gated, so a no-op
  for Foundry's non-OpenAI catalog)
- Treated as a chat-completions provider, not the OpenAI Responses API

OpenAPI:
- `azure_foundry` added to AIProvider (openapi.yaml) and AIProviderKind
  (openflow.openapi.yaml); regenerated CLI guidance

Note: the `azure_foundry` resource type (base_url + optional api_key) is
hub-managed and must be published to the Windmill Hub separately.

Fixes WIN-2122

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(ai): add azure_foundry to copilot flow Zod provider enum

The tracked copilot flow schema (openFlowZod.gen.ts and its openFlow.json
source) still carried the old AIProvider enum, so validateFlowModules /
validateSpecialFlowModule rejected AI-generated flow edits that create or
update an aiagent module with provider kind "azure_foundry" before they
could be saved. Add the value to both (preserving the generated single-line
format) and a regression test over the flow-module validation path.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat(ai): lead provider list with OpenAI, Anthropic, Google AI

Reorder AI_PROVIDERS so the three primary direct providers come first. The
AIProviderPicker renders the first three entries as quick-access buttons, so
these become the defaults (previously OpenAI, Azure OpenAI, Azure Foundry);
Azure OpenAI / Azure Foundry stay adjacent right after. No logic depends on
provider order (only per-provider defaultModels[0] is read).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-02 23:42:44 +02:00
centdixandClaude Opus 4.6 82e2197922 chore: remove deprecated enable_1m_context from AI providers (#9580)
* chore: remove deprecated enable_1m_context from AI provider code

1M context is now standard on Anthropic models — the beta header
`anthropic-beta: context-1m-2025-08-07` is no longer needed.

Remove the field from ProviderCredentials and AnthropicQueryBuilder,
and stop injecting the beta header in both the API proxy and worker
query builder paths.

The field is kept (as `_enable_1m_context`) on the ProviderResource
deserialization structs in both windmill-api and windmill-ai so
existing resources with the field still deserialize without error.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* refactor: drop vestigial _enable_1m_context field from AI resources

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* test: assert legacy enable_1m_context keys still deserialize

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-06-15 18:58:19 +02:00
centdix a7d85a39ff refactor: clean up ai provider proxy logic (#9360)
* refactor: clean up ai provider proxy logic

* docs: remove completed ai refactor plan

* fix: audit failed google global proxy calls
2026-05-28 16:05:04 +00:00
centdix 4be930f585 refactor: unify AI provider credentials (#9317)
* refactor: use provider credentials for worker builders

* refactor: resolve api proxy credentials directly

* fix: lazy load frontend eval modes
2026-05-26 05:51:32 +00:00
centdix 289549a048 refactor: move google ai proxy handling to windmill-ai (#9260)
* refactor: add ai proxy execution mode

* refactor: move google ai proxy handling

* refactor: share google ai request building
2026-05-20 15:24:07 +00:00
centdix 55dcee2424 refactor: move anthropic proxy building (#9238) 2026-05-19 14:23:31 +00:00
centdix bd32c5f951 refactor: move openai-compatible proxy building (#9133)
* refactor: introduce ai proxy request types

* refactor: move openai-compatible proxy building
2026-05-18 10:24:16 +00:00