Custom Endpoint Models (Messages API) Never Send thinking Parameter
Environment
- VS Code: 1.122.0-insider (build
4459d58b54)
- Copilot Extension: v0.50.2026052902 (GitHub Copilot Chat)
- OS: Windows 11 (23H2)
- Extensions: Issue reproduces with all non-Copilot extensions disabled
- Custom Endpoint: Anthropic Messages API via proxy (
/v1/messages)
- Dev Tools Console: No errors related to this issue (requests succeed with 200 OK, but response lacks thinking content)
Bug Summary
When using a custom endpoint model configured with apiType: "messages", the thinking parameter is never included in the request body sent to the upstream API - even when the model is configured with "thinking": true and "adaptiveThinking": true in chatLanguageModels.json. The model responds as if extended thinking is not enabled because the parameter is absent from the wire request.
In contrast, the built-in GitHub-hosted Claude models (e.g. claude-opus-4.6 via panel/editAgent) correctly send thinking: {type: "adaptive", display: "summarized"} and receive thinking blocks in responses.
Reproduction Steps
- Configure a custom endpoint model in VS Code settings with Messages API:
{
"github.copilot.chat.models": [
{
"name": "my-anthropic-proxy",
"vendor": "customendpoint",
"apiKey": "...",
"apiType": "messages",
"models": [
{
"id": "claude-opus-4-6",
"name": "Claude Opus 4.6",
"url": "https://my-proxy.example.com/v1/messages",
"toolCalling": true,
"vision": true,
"thinking": true,
"adaptiveThinking": true,
"maxInputTokens": 200000,
"maxOutputTokens": 128000,
"supportsReasoningEffort": ["low", "medium", "high"]
}
]
}
]
}
- Start a chat using the custom endpoint model.
- Inspect the HTTP request body sent to the proxy (e.g. via proxy logs).
Expected: Request body includes "thinking": {"type": "adaptive"} (or "adaptive" with display: "summarized").
Actual: Request body has no thinking field. The model responds without extended thinking.
Root Cause Analysis
Note: The following analysis is based on observing the request body at the proxy and inspecting the bundled extension.js to understand the code paths involved. Variable names are from the minified bundle.
The issue is caused by two gaps in the code path for custom endpoint models:
Issue 1: copilotLanguageModelWrapper does not pass enableThinking
When a custom endpoint model is invoked via the VS Code Language Model API (extensions calling lm.sendRequest()), the request flows through copilotLanguageModelWrapper. This wrapper constructs a modelCapabilities object that is passed to the internal request pipeline:
// In copilotLanguageModelWrapper (approx. offset 13807981 in extension.js)
modelCapabilities: {
reasoningEffort: typeof o.modelConfiguration?.reasoningEffort == "string"
? o.modelConfiguration.reasoningEffort
: void 0
}
Notice that enableThinking is not included in modelCapabilities. This is the first gate that prevents thinking.
Issue 2: LSn (Messages API body builder) requires enableThinking to set thinking
The function that constructs the Anthropic Messages API request body (minified as LSn, approx. offset 13555239) contains:
if (e.modelCapabilities?.enableThinking) {
if (r.supportsAdaptiveThinking)
m = { type: "adaptive", display: "summarized" };
else if (r.maxThinkingBudget && r.minThinkingBudget) {
let O = e.postOptions.max_tokens ?? 1024;
let Q = r.minThinkingBudget ?? 1024;
let F = 16e3 < Q ? Q : 16e3;
let B = r.maxThinkingBudget ?? 32e3;
let M = Math.min(B, O - 1, F);
M && (m = { type: "enabled", budget_tokens: M });
}
// No else clause — m stays undefined if neither condition matches
}
Since enableThinking is never set (Issue 1), this entire block is skipped and m (the thinking config) remains undefined. Even if enableThinking were passed, the function has no fallback: if supportsAdaptiveThinking is falsy and maxThinkingBudget/minThinkingBudget are not set, m still stays undefined.
Contrast with built-in agent path
The built-in agent (panel/editAgent) uses a separate code path that constructs the request body directly:
// panel/editAgent path (approx. offset 13825471)
thinking: Q ? { type: "adaptive" } : P ? { type: "enabled", budget_tokens: P } : void 0
Here Q is derived from _knownModels (populated for GitHub-hosted models). For custom endpoints, _knownModels is void 0, so this also falls through to void 0.
Data Flow Summary
Custom Endpoint Model Request Flow:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
copilotLanguageModelWrapper
→ modelCapabilities: { reasoningEffort: "high" } ← missing enableThinking!
→ makeChatRequest2()
→ chatMLFetcher.fetchOne()
→ endpoint.createRequestBody(e)
→ LSn(n, e, model, endpoint)
→ if (e.modelCapabilities?.enableThinking) ← FALSE, skipped
→ thinking: m ← m is undefined
→ Request body: { model, messages, ..., thinking: undefined }
Built-in GitHub Model Request Flow:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
panel/editAgent
→ Reads _knownModels for model capabilities
→ Q = supportsAdaptiveThinking from _knownModels
→ thinking: Q ? {type:"adaptive"} : P ? {type:"enabled",...} : void 0
→ Request body: { ..., thinking: {type:"adaptive", display:"summarized"} }
Proposed Fix
Fix 1: Pass enableThinking from model configuration
In copilotLanguageModelWrapper, include the model's thinking capability:
modelCapabilities: {
reasoningEffort: typeof o.modelConfiguration?.reasoningEffort == "string"
? o.modelConfiguration.reasoningEffort
: void 0,
enableThinking: !!endpoint.supportsThinking || !!endpoint.supportsAdaptiveThinking
}
Fix 2: Add fallback in LSn for models that declare thinking: true but lack budget metadata
if (e.modelCapabilities?.enableThinking) {
if (r.supportsAdaptiveThinking)
m = { type: "adaptive", display: "summarized" };
else if (r.maxThinkingBudget && r.minThinkingBudget) {
// ... existing budget logic ...
} else {
// Fallback: if model declares thinking support but has no
// adaptive/budget metadata, default to adaptive
m = { type: "adaptive" };
}
}
Fix 3 (panel/editAgent path): Respect user config thinking: true
The ternary that gates thinking on _knownModels should also check the endpoint's declared capabilities:
thinking: Q ? { type: "adaptive" }
: P ? { type: "enabled", budget_tokens: P }
: endpoint.supportsAdaptiveThinking ? { type: "adaptive" }
: void 0
Impact
This affects all users of custom endpoint models (BYOK/enterprise proxy setups) who configure Anthropic-compatible endpoints with extended thinking. The model config correctly declares thinking: true and adaptiveThinking: true, but these values are never used in the request body construction for the copilotLanguageModelWrapper code path.
Workaround
Manually patching the minified extension.js to (1) add enableThinking: true to the wrapper's modelCapabilities and (2) add an else m = {type: "adaptive"} fallback in the Messages API body builder restores thinking for custom endpoints. This must be reapplied after every VS Code update.
Related
- Custom endpoint model configuration:
apiType: "messages" with thinking: true
- The
supportsAdaptiveThinking property IS correctly resolved from user config → vD() → capabilities.supports.adaptive_thinking → endpoint property. The gap is only that it's never consulted by the wrapper/request builder.
Checklist
Custom Endpoint Models (Messages API) Never Send
thinkingParameterEnvironment
4459d58b54)/v1/messages)Bug Summary
When using a custom endpoint model configured with
apiType: "messages", thethinkingparameter is never included in the request body sent to the upstream API - even when the model is configured with"thinking": trueand"adaptiveThinking": trueinchatLanguageModels.json. The model responds as if extended thinking is not enabled because the parameter is absent from the wire request.In contrast, the built-in GitHub-hosted Claude models (e.g.
claude-opus-4.6viapanel/editAgent) correctly sendthinking: {type: "adaptive", display: "summarized"}and receive thinking blocks in responses.Reproduction Steps
{ "github.copilot.chat.models": [ { "name": "my-anthropic-proxy", "vendor": "customendpoint", "apiKey": "...", "apiType": "messages", "models": [ { "id": "claude-opus-4-6", "name": "Claude Opus 4.6", "url": "https://my-proxy.example.com/v1/messages", "toolCalling": true, "vision": true, "thinking": true, "adaptiveThinking": true, "maxInputTokens": 200000, "maxOutputTokens": 128000, "supportsReasoningEffort": ["low", "medium", "high"] } ] } ] }Expected: Request body includes
"thinking": {"type": "adaptive"}(or"adaptive"withdisplay: "summarized").Actual: Request body has no
thinkingfield. The model responds without extended thinking.Root Cause Analysis
The issue is caused by two gaps in the code path for custom endpoint models:
Issue 1:
copilotLanguageModelWrapperdoes not passenableThinkingWhen a custom endpoint model is invoked via the VS Code Language Model API (extensions calling
lm.sendRequest()), the request flows throughcopilotLanguageModelWrapper. This wrapper constructs amodelCapabilitiesobject that is passed to the internal request pipeline:Notice that
enableThinkingis not included inmodelCapabilities. This is the first gate that prevents thinking.Issue 2:
LSn(Messages API body builder) requiresenableThinkingto setthinkingThe function that constructs the Anthropic Messages API request body (minified as
LSn, approx. offset 13555239) contains:Since
enableThinkingis never set (Issue 1), this entire block is skipped andm(the thinking config) remainsundefined. Even ifenableThinkingwere passed, the function has no fallback: ifsupportsAdaptiveThinkingis falsy andmaxThinkingBudget/minThinkingBudgetare not set,mstill staysundefined.Contrast with built-in agent path
The built-in agent (
panel/editAgent) uses a separate code path that constructs the request body directly:Here
Qis derived from_knownModels(populated for GitHub-hosted models). For custom endpoints,_knownModelsisvoid 0, so this also falls through tovoid 0.Data Flow Summary
Proposed Fix
Fix 1: Pass
enableThinkingfrom model configurationIn
copilotLanguageModelWrapper, include the model's thinking capability:Fix 2: Add fallback in
LSnfor models that declarethinking: truebut lack budget metadataFix 3 (panel/editAgent path): Respect user config
thinking: trueThe ternary that gates
thinkingon_knownModelsshould also check the endpoint's declared capabilities:Impact
This affects all users of custom endpoint models (BYOK/enterprise proxy setups) who configure Anthropic-compatible endpoints with extended thinking. The model config correctly declares
thinking: trueandadaptiveThinking: true, but these values are never used in the request body construction for thecopilotLanguageModelWrappercode path.Workaround
Manually patching the minified
extension.jsto (1) addenableThinking: trueto the wrapper'smodelCapabilitiesand (2) add anelse m = {type: "adaptive"}fallback in the Messages API body builder restores thinking for custom endpoints. This must be reapplied after every VS Code update.Related
apiType: "messages"withthinking: truesupportsAdaptiveThinkingproperty IS correctly resolved from user config →vD()→capabilities.supports.adaptive_thinking→ endpoint property. The gap is only that it's never consulted by the wrapper/request builder.Checklist
microsoft/vscode(Copilot extension is bundled in VS Code;vscode-copilot-releaseis archived)