fix: drop thinking blocks when converting Anthropic Messages requests to Chat Completions (#29849)

* fix: drop thinking blocks when converting Anthropic Messages requests to Chat Completions

Claude Code and other Anthropic SDK clients pointed at /api/v1/messages send the assistant's earlier thinking blocks back with every follow-up request. Since 0.11.0 those blocks were copied into the OpenAI assistant message as content parts of type thinking, a part type Chat Completions does not define. Strict OpenAI-compatible servers such as NVIDIA Dynamo reject the whole request with 400 "data did not match any variant of untagged enum ChatCompletionRequestAssistantMessageContent", so a conversation with a reasoning model died on its second turn. The error reports its position at the very end of the body, which made the request look cut off; it was complete.

Thinking and redacted_thinking blocks are now skipped in the conversion, which is what happened before 0.11.0. An assistant turn that held only thinking blocks is kept as an empty assistant message so the turn order survives. Native Anthropic and LiteLLM connections are unaffected because they receive the request untouched, and thinking blocks in responses are still produced.

Fixes #29799

* fix: keep signed thinking blocks when converting Anthropic Messages requests

Dropping every thinking block also removed the signed ones. Those are the blocks a gateway such as LiteLLM forwards to Anthropic, which needs the signed thinking block of the previous assistant turn when a tool-use turn continues with extended thinking. Only the unsigned blocks are the problem: Open WebUI creates them itself from reasoning_content, and strict Chat Completions backends reject them because thinking is not a content part type they know.

Unsigned thinking blocks are now dropped while signed thinking and redacted_thinking blocks are kept, the same rule LiteLLM applies before forwarding to Anthropic and the rule the native chat path already uses for Anthropic reasoning details. Backends that never emit a signature, such as NVIDIA Dynamo and vLLM, keep receiving requests without thinking parts, so the original failure stays fixed.
This commit is contained in:
Classic298 2026-09-12 22:56:59 +02:00 committed by GitHub
parent c78ad89934
commit 75b1836322
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -202,7 +202,9 @@ def convert_anthropic_to_openai_payload(
)
)
elif block_type in ('thinking', 'redacted_thinking'):
openai_content.append(_copy_cache_control(block, dict(block)))
# Unsigned thinking cannot be replayed upstream
if block_type == 'redacted_thinking' or block.get('signature'):
openai_content.append(_copy_cache_control(block, dict(block)))
elif block_type == 'image':
source = block.get('source', {})
if source.get('type') == 'base64':
@ -369,7 +371,7 @@ def convert_anthropic_to_openai_payload(
msg_dict['content'] = ''
msg_dict['tool_calls'] = tool_calls
messages.append(msg_dict)
elif openai_content:
elif openai_content or role == 'assistant':
messages.append({'role': role, 'content': _finalize_openai_content(openai_content)})
else:
messages.append({'role': role, 'content': str(content) if content else ''})