You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
OpenAI Compatible: setting to disable strict tool schemas (strict: true rejected by strict-unaware proxies) #1827
Using the OpenAI Compatible provider (custom base URL) against an OpenAI-compatible proxy that does not support strict structured tool output fails every request with:
400 strict=true requires generated function arguments to satisfy the declared JSON Schema, which <proxy> cannot guarantee
The proxy rejects requests containing strict: true on tools because its backend cannot guarantee schema-conforming generated arguments. There is currently no client-side workaround.
Root cause
OpenAiHandler sends every request with tools: this.convertToolsForOpenAI(metadata?.tools) (src/api/providers/openai.ts, lines 173/241/377/412). BaseProvider.convertToolsForOpenAI (src/api/providers/base-provider.ts) hard-codes:
strict: true for all non-MCP tools
schema normalization: every property forced into required, additionalProperties: false
The codebase already sends strict: false elsewhere - MCP tools (base-provider.ts) and the NanoGPT provider (src/api/providers/nanogpt.ts, lines 138-140) - so this is a hard-coded per-provider choice, not a protocol requirement.
Proposal
Add a provider setting openAiStrictToolSchemas (boolean, default true = current behavior), scoped to the OpenAI Compatible provider:
false: tools are sent with strict: false and the declared schemas are preserved as-is (no all-required / additionalProperties coercion) - same shape as the NanoGPT path.
default true: no behavior change for OpenAI and strict-capable gateways.
The declared tool schemas are already strict-mode compatible (e.g. read_file declares required: ["path"] and additionalProperties: false), so skipping normalization does not loosen real required constraints - optional parameters simply stay optional.
Implementation plan (per the AGENTS.md persisted-setting checklist)
webview-ui/src/components/settings/providers/OpenAICompatible.tsx: checkbox following the openAiR1FormatEnabled wiring + i18n label
src/api/providers/openai.ts: read this.options.openAiStrictToolSchemas ?? true, thread the flag through convertToolsForOpenAI, skip the schema conversion when off
The important distinction here is between the OpenAI wire format and a gateway's structured-tool capability. I would make this a per-connection or per-model capability, rather than a global provider switch.
A focused implementation/test contract could be:
Keep the current strict normalization as the default for OpenAI and strict-capable connections.
For an OpenAI-compatible connection with openAiStrictToolSchemas=false, preserve the declared required and additionalProperties fields and send strict: false (or omit the field if that is the gateway's accepted form).
Decide this from explicit connection/model configuration, not from the provider name. Two endpoints using the same OpenAI-compatible protocol can have different tool-schema behavior.
Cover both a root URL and a URL already ending in /v1; normalize once so the request path cannot become /v1/v1/chat/completions.
Add fixtures for strict success, a 400 caused by strict-schema rejection, optional-property preservation, MCP tools remaining non-strict, and a normal non-tool request. Redact keys and request content from diagnostics.
For an optional external check of the ordinary OpenAI-compatible Chat Completions path, I operate AI Router with the API root https://api.ai-router.dev/v1. This should be treated only as an independent transport/control endpoint; the strict-tool behavior must be tested against the specific account-visible model and must not be assumed from the endpoint name.
Disclosure: I represent AI Router. I am not requesting a provider-specific branch or default, and I have not verified that AI Router supports this issue's strict: true behavior.
Thanks for the detailed review — most of the contract matches what the fix for this issue implements:
Per-connection scope: openAiStrictToolSchemas lives on the OpenAI Compatible connection's own settings (the same configuration that holds the base URL and API key). It is an explicit per-connection value, never inferred from the provider name or the endpoint, and it does not affect any other provider (openai-native, openai-codex, xai, ...). Two endpoints speaking the same OpenAI-compatible protocol can behave differently by configuring the flag independently per connection.
Behavior when disabled: with openAiStrictToolSchemas: false, each tool is sent with strict: false and the declared JSON schema passes through untouched — declared required and additionalProperties preserved, no normalization applied. This mirrors the existing precedent for MCP tools. An explicit strict: false is sent rather than omitting the field, since the Chat Completions API accepts both and the explicit form is easier to reason about.
Base URL / /v1: the handler passes the configured base URL straight to the OpenAI SDK, which owns request-path joining; the strict flag is orthogonal to the request path, so no /v1/v1/chat/completions doubling is introduced. Base-URL handling already has existing coverage (e.g. the Azure OpenAI base-URL normalization tests).
Test contract: the implementation adds fixtures for the strict default (normalized schema on the wire), strict disabled with the declared schema preserved (including optional properties), MCP tools remaining non-strict, a gateway 400 caused by strict-schema rejection propagating with its status preserved, and a normal non-tool request that carries no tools. Error diagnostics are unchanged by this work, so nothing new leaks keys or request content.
Disclosure noted — thank you for flagging it. No AI-Router-specific branch, default, or endpoint handling goes into this change. https://api.ai-router.dev/v1 can be used to manually verify the ordinary Chat Completions transport path; since strict-tool behavior is account/model-visible, any such check is transport verification only and is not assumed from the endpoint name.
Activity
airouter-dev commentedon Sep 27, 2026
The important distinction here is between the OpenAI wire format and a gateway's structured-tool capability. I would make this a per-connection or per-model capability, rather than a global provider switch.
A focused implementation/test contract could be:
For an optional external check of the ordinary OpenAI-compatible Chat Completions path, I operate AI Router with the API root https://api.ai-router.dev/v1. This should be treated only as an independent transport/control endpoint; the strict-tool behavior must be tested against the specific account-visible model and must not be assumed from the endpoint name.
Disclosure: I represent AI Router. I am not requesting a provider-specific branch or default, and I have not verified that AI Router supports this issue's strict: true behavior.
easonLiangWorldedtech commentedon Sep 27, 2026
Thanks for the detailed review — most of the contract matches what the fix for this issue implements:
openAiStrictToolSchemaslives on the OpenAI Compatible connection's own settings (the same configuration that holds the base URL and API key). It is an explicit per-connection value, never inferred from the provider name or the endpoint, and it does not affect any other provider (openai-native, openai-codex, xai, ...). Two endpoints speaking the same OpenAI-compatible protocol can behave differently by configuring the flag independently per connection.openAiStrictToolSchemas: false, each tool is sent withstrict: falseand the declared JSON schema passes through untouched — declaredrequiredandadditionalPropertiespreserved, no normalization applied. This mirrors the existing precedent for MCP tools. An explicitstrict: falseis sent rather than omitting the field, since the Chat Completions API accepts both and the explicit form is easier to reason about./v1: the handler passes the configured base URL straight to the OpenAI SDK, which owns request-path joining; the strict flag is orthogonal to the request path, so no/v1/v1/chat/completionsdoubling is introduced. Base-URL handling already has existing coverage (e.g. the Azure OpenAI base-URL normalization tests).tools. Error diagnostics are unchanged by this work, so nothing new leaks keys or request content.Disclosure noted — thank you for flagging it. No AI-Router-specific branch, default, or endpoint handling goes into this change.
https://api.ai-router.dev/v1can be used to manually verify the ordinary Chat Completions transport path; since strict-tool behavior is account/model-visible, any such check is transport verification only and is not assumed from the endpoint name.fix(api): add openAiStrictToolSchemas setting for OpenAI-compatible g…