Summary
providerCompatMatrix.ts defines a complete per-provider compatibility layer, but nothing imports it. The request path never applies it, so the fields it exists to strip are still sent.
Evidence
COMPAT_PROFILES and applyCompatRule have no consumers outside their own file:
$ grep -rn "COMPAT_PROFILES\|applyCompatRule" src packages | grep -v providerCompatMatrix
(no output)
compatRule appears only where it is declared — the four built-in providers in loader.ts and the schema in types.ts — never where a request body is built.
What this costs
isOpenAIThinkingEnabled() in requestBody.ts enables thinking from the model name alone:
return modelLower.includes('deepseek') || modelLower.includes('mimo')
That is a claim about the model, not about the endpoint serving it. Azure AI Foundry hosts DeepSeek models under names like DeepSeek-V4-Flash, and its deployment rejects the field:
API Error: 400 Unrecognized request argument supplied: thinking
COMPAT_PROFILES already encodes the right answer — strict-openai has supportsThinkingField: false, and lines 131-142 hold the stripping logic. Wiring it in would have handled this case. OPENAI_ENABLE_THINKING=0 works as a manual override, but it requires the user to first diagnose a 400 from a field they did not know was being sent.
The same gap applies to the profile's other fields: supportsStreamUsageOption and reasoningContentEcho are equally unenforced, so strict endpoints that reject unknown top-level keys will hit the same class of error.
Reproduce
CLAUDE_CODE_USE_OPENAI=1 \
OPENAI_BASE_URL=https://<resource>.openai.azure.com/openai/v1 \
OPENAI_API_KEY=<key> \
OPENAI_MODEL=DeepSeek-V4-Flash \
bun run scripts/dev.ts -p "hi"
Expected: the request succeeds. Actual: HTTP 400 on the thinking argument.
Adding OPENAI_ENABLE_THINKING=0 makes it pass, which confirms the field is the cause.
Suggestion
Call applyCompatRule on the outgoing body in the OpenAI path, resolving the profile from the active provider's compatRule and defaulting to strict-openai for user-defined providers. Auto-detecting capability from a model name cannot be right in general — the same model is served by endpoints that differ in what they accept.
Verified against v2.6.9 and current main; the file is identical in both.
Summary
providerCompatMatrix.tsdefines a complete per-provider compatibility layer, but nothing imports it. The request path never applies it, so the fields it exists to strip are still sent.Evidence
COMPAT_PROFILESandapplyCompatRulehave no consumers outside their own file:compatRuleappears only where it is declared — the four built-in providers inloader.tsand the schema intypes.ts— never where a request body is built.What this costs
isOpenAIThinkingEnabled()inrequestBody.tsenables thinking from the model name alone:That is a claim about the model, not about the endpoint serving it. Azure AI Foundry hosts DeepSeek models under names like
DeepSeek-V4-Flash, and its deployment rejects the field:COMPAT_PROFILESalready encodes the right answer —strict-openaihassupportsThinkingField: false, and lines 131-142 hold the stripping logic. Wiring it in would have handled this case.OPENAI_ENABLE_THINKING=0works as a manual override, but it requires the user to first diagnose a 400 from a field they did not know was being sent.The same gap applies to the profile's other fields:
supportsStreamUsageOptionandreasoningContentEchoare equally unenforced, so strict endpoints that reject unknown top-level keys will hit the same class of error.Reproduce
Expected: the request succeeds. Actual: HTTP 400 on the
thinkingargument.Adding
OPENAI_ENABLE_THINKING=0makes it pass, which confirms the field is the cause.Suggestion
Call
applyCompatRuleon the outgoing body in the OpenAI path, resolving the profile from the active provider'scompatRuleand defaulting tostrict-openaifor user-defined providers. Auto-detecting capability from a model name cannot be right in general — the same model is served by endpoints that differ in what they accept.Verified against v2.6.9 and current main; the file is identical in both.