Skip to content

BYOK Custom Endpoint with DeepSeek reasoning models fails with HTTP 400 on multi-turn tool calling (reasoning_content not echoed back) #318920

@ziqiangai

Description

@ziqiangai
Image

Bug Description

When using the Custom Endpoint BYOK feature with DeepSeek reasoning models (or similar providers like Moonshot/Minimax that emit reasoning_content without an explicit ID), the first LLM turn succeeds, but any subsequent turn (after a tool call) fails with:

400 {"error":{"message":"The `reasoning_content` in the thinking mode must be passed back to the API.","type":"invalid_request_error",...}}

The Copilot extension already contains logic in OpenAIEndpoint.createRequestBody() to echo back reasoning_content on assistant messages, but this logic is gated on data.id being present. DeepSeek does not send an id alongside reasoning_content, so the echo-back is silently skipped, and DeepSeek rejects the second turn.

This makes Agent mode (multi-turn tool calling) unusable with DeepSeek reasoning models via BYOK.

Version

  • VS Code: 1.122 (latest main)
  • GitHub Copilot Chat extension: bundled
  • OS: all (reproducible on Windows, macOS, Linux)

Steps to Reproduce

  1. Configure a Custom Endpoint with DeepSeek:
    {
      "name": "DeepSeek",
      "vendor": "customendpoint",
      "apiKey": "sk-...",
      "apiType": "chat-completions",
      "url": "https://api.deepseek.com/chat/completions",
      "models": [{
        "id": "deepseek-v4-flash",
        "toolCalling": true,
        "thinking": true,
        "maxInputTokens": 128000,
        "maxOutputTokens": 8192
      }]
    }
  2. Open Chat, select the DeepSeek model
  3. Send a prompt that triggers tool calling (e.g. "Create a file named test.txt with some content")
  4. Observe: first turn succeeds, model returns reasoning_content + tool call
  5. After tool executes, second turn is sent
  6. Observe: HTTP 400 from DeepSeek

Expected Behavior

The reasoning_content from the first turn should be echoed back in the assistant message of the second turn, so DeepSeek accepts the request.

Actual Behavior

The reasoning_content is silently dropped because it has no id, and the second turn fails with HTTP 400.

Logs

2026-05-29 07:10:17.012 [info] message 0 returned. finish reason: [tool_calls]
2026-05-29 07:10:17.019 [info] ccreq:d3c749f5.copilotmd | success | deepseek-v4-flash | 1336ms
2026-05-29 07:10:17.392 [info] Request ID for failed request: 1d4d4316-...
2026-05-29 07:10:17.396 [error] Server error: 400 {"error":{"message":"The `reasoning_content` in the thinking mode must be passed back to the API.","type":"invalid_request_error","param":null,"code":"invalid_request_error"}}
2026-05-29 07:10:17.399 [info] ccreq:0a452385.copilotmd | failed | deepseek-v4-flash | 225ms

Affected Providers

  • DeepSeek (V4, V3 reasoning mode)

Any OpenAI-compatible provider that sends reasoning_content without an accompanying id field will hit this issue.

Metadata

Metadata

Assignees

Labels

info-neededIssue requires more information from postermodel-byok

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions