DEV Community

AIHubMix
AIHubMix

Posted on • Originally published at aihubmix.com

DeepSeek V4 Pro (0813) Across 3 APIs: Thinking Passback, Tool Calls, and Hidden 400s

DeepSeek V4 Pro (0813) is available on AIHubMix through three protocol surfaces:

  • OpenAI-compatible Chat Completions
  • OpenAI Responses
  • Claude-compatible Messages

They reach the same model, but the request and response shapes are not interchangeable. The largest production trap is thinking history: on tool-using multi-turn conversations, dropping the previous turn's thinking content causes a hard HTTP 400.

The findings below come from calls made on August 13, 2026 against the AIHubMix production APIs. The full hands-on guide includes complete examples, observed responses, and the full capability matrix.

The short version

Capability Chat Completions Responses Messages
Endpoint /v1/chat/completions /v1/responses /v1/messages
Thinking off thinking.type="disabled" reasoning.effort="none" thinking.type="disabled"
Thinking passback reasoning_content type="reasoning" item thinking block
Tool schema nested function flat definition input_schema
Structured output response_format text.format no native field
Web search no web_search web_search_20250305

The model has a 1M-token context window, accepts text input, and thinks by default. Sending an excessive max_tokens value is rejected instead of silently truncated; a request with max_tokens=9999999 returned 400 and identified the ceiling as 393,216.

One subtle input warning: Responses does not reject image parts. Unsupported image and file inputs are replaced with placeholder text. "No error" does not mean the model saw the image.

1. Preserve thinking history verbatim

In thinking mode, the previous turn's thinking is part of the conversation state. This matters most in agent loops where the model emits a tool call and the client sends the tool result back.

Chat Completions

Preserve reasoning_content on the historical assistant message:

messages = [
    {"role": "user", "content": "What is 1 + 1? Remember the result."},
    {
        "role": "assistant",
        "content": "2",
        "reasoning_content": "<reasoning_content from the previous response>",
    },
    {"role": "user", "content": "Add 1 to the result."},
]
Enter fullscreen mode Exit fullscreen mode

Dropping reasoning_content returned HTTP 400. Restoring it made the same request continue normally.

Responses

Append the prior response.output without filtering its items:

input = previous_input + response.output + [
    {"role": "user", "content": "Add 1 to the result."}
]
Enter fullscreen mode Exit fullscreen mode

A common framework pattern is to retain only items where type == "message". That silently removes the reasoning item and triggers the next-turn 400.

Messages

Pass the previous response.content back as the assistant message:

messages = [
    {"role": "user", "content": "What's the weather in Paris?"},
    {"role": "assistant", "content": response.content},
    {"role": "user", "content": [tool_result_block]},
]
Enter fullscreen mode Exit fullscreen mode

Keep both the thinking and tool_use blocks. Removing the thinking block returned an invalid_request_error.

2. Turning thinking off requires different fields

Thinking is enabled by default. The off switch depends on the protocol:

# Chat Completions
extra_body={"thinking": {"type": "disabled"}}

# Responses
reasoning={"effort": "none"}

# Messages
extra_body={"thinking": {"type": "disabled"}}
Enter fullscreen mode Exit fullscreen mode

The result is observable. Chat and Messages stop returning their thinking fields. Responses reports zero reasoning tokens and omits the reasoning output item.

low, high, and max were accepted, but token counts for the same prompts did not vary monotonically and the selected level was not echoed. The only level whose effect was unambiguous from the caller side was Responses none.

3. Tool schemas are protocol-specific

Chat Completions wraps a function definition inside function:

tools=[{
    "type": "function",
    "function": {
        "name": "get_weather",
        "description": "Get weather for a city",
        "parameters": {
            "type": "object",
            "properties": {"city": {"type": "string"}},
            "required": ["city"],
        },
    },
}]
Enter fullscreen mode Exit fullscreen mode

Responses uses a flat definition:

tools=[{
    "type": "function",
    "name": "get_weather",
    "description": "Get weather for a city",
    "parameters": {
        "type": "object",
        "properties": {"city": {"type": "string"}},
        "required": ["city"],
    },
}]
Enter fullscreen mode Exit fullscreen mode

Messages uses input_schema.

There are two more gotchas:

  1. tool_choice: "required" returns 400 on Chat and Responses while thinking is enabled. Use a named-function choice, or disable thinking before using required.
  2. Parallel tool calling cannot be disabled. DeepSeek documents the relevant switches as ignored on Responses and Messages. Serialize calls in your client if ordering matters.

Tool definitions also consume context in full. A request containing 200 definitions succeeded in testing, but the prompt reached 6,105 tokens. Route only the tools relevant to the current task.

4. Structured output, caching, and web search

Chat Completions supports JSON mode through response_format. Responses supports strict JSON Schema through text.format:

response = client.responses.create(
    model="deepseek-v4-pro-0813",
    input="Return the number 1 under key a.",
    text={
        "format": {
            "type": "json_schema",
            "name": "extract",
            "strict": True,
            "schema": {
                "type": "object",
                "properties": {"a": {"type": "integer"}},
                "required": ["a"],
            },
        }
    },
)
Enter fullscreen mode Exit fullscreen mode

Messages has no equivalent structured-output field. Carrying a schema in a forced tool is possible, but use Chat or Responses when hard schema guarantees are central.

Context caching is automatic. Repeated long prefixes produced cache hits under different usage fields:

  • Chat: prompt_tokens_details.cached_tokens
  • Responses: input_tokens_details.cached_tokens
  • Messages: cache_read_input_tokens

Put stable system instructions, knowledge snippets, and tool definitions at the front of the request.

Server-side web search worked on Responses and Messages. Chat accepted unknown search-like fields without error, but did not perform retrieval. Route search workloads to Responses or Messages.

Production checklist

  • Persist thinking content as normal conversation state.
  • Do not filter Responses output down to message items before passback.
  • Avoid tool_choice: "required" while thinking is enabled.
  • Keep the three tool-definition schemas separate.
  • Do not infer image support from the absence of an error.
  • Serialize parallel tool calls on the client when required.
  • Branch on HTTP status, not only error.type, for Responses errors.
  • Do not use the echoed model field as the sole routing or attribution signal.

DeepSeek V4 Pro's multi-protocol support is useful, but compatibility is a client-side responsibility. Treat thinking as durable conversation state and isolate protocol adapters around history, tools, usage, and errors.

For the complete 3-API matrix, additional code samples, logprobs behavior, current-path deviations, and FAQs, read the full AIHubMix guide. Current pricing and status are on the model page.

Top comments (0)