fix(anthropic_adapter): preserve reasoning_content for Kimi /coding tool-call messages#13897
fix(anthropic_adapter): preserve reasoning_content for Kimi /coding tool-call messages#13897HiddenPuppy wants to merge 2 commits into
Conversation
…call messages for Kimi /coding Fixes NousResearch#13848 Kimi's /coding endpoint speaks the Anthropic Messages protocol but has its own thinking semantics: when thinking is enabled, Kimi validates message history and requires every prior assistant tool-call message to carry OpenAI-style reasoning_content. The Anthropic path never populated that field, and convert_messages_to_anthropic strips all Anthropic thinking blocks on third-party endpoints — so the request failed with HTTP 400: "thinking is enabled but reasoning_content is missing in assistant tool call message at index N" Now, when an assistant message contains tool_calls and a reasoning_content string, we append a {"type": "thinking", ...} block to the Anthropic content so Kimi can validate the history. This only affects assistant messages with tool_calls + reasoning_content; plain text assistant messages are unchanged.
Map tsuijinglei@gmail.com → hiddenpuppy.
… block ordering Follow-up to the cherry-picked PR #13897 fix. Three issues found: 1. CRITICAL: The thinking block synthesised from reasoning_content was immediately stripped by the third-party signature management code (Kimi is classified as _is_third_party_anthropic_endpoint). Added a Kimi-specific carve-out that preserves unsigned thinking blocks while still stripping Anthropic-signed blocks Kimi can't validate. 2. Empty-string reasoning_content was silently dropped because the truthiness check ('if reasoning_content and ...') evaluates to False for ''. Changed to 'isinstance(reasoning_content, str)' so the tier-3 fallback from _copy_reasoning_content_for_api (which injects '' for Kimi tool-call messages with no reasoning) actually produces a thinking block. 3. The thinking block was appended AFTER tool_use blocks. Anthropic protocol requires thinking -> text -> tool_use ordering. Changed to blocks.insert(0, ...) to prepend.
… block ordering Follow-up to the cherry-picked PR #13897 fix. Three issues found: 1. CRITICAL: The thinking block synthesised from reasoning_content was immediately stripped by the third-party signature management code (Kimi is classified as _is_third_party_anthropic_endpoint). Added a Kimi-specific carve-out that preserves unsigned thinking blocks while still stripping Anthropic-signed blocks Kimi can't validate. 2. Empty-string reasoning_content was silently dropped because the truthiness check ('if reasoning_content and ...') evaluates to False for ''. Changed to 'isinstance(reasoning_content, str)' so the tier-3 fallback from _copy_reasoning_content_for_api (which injects '' for Kimi tool-call messages with no reasoning) actually produces a thinking block. 3. The thinking block was appended AFTER tool_use blocks. Anthropic protocol requires thinking -> text -> tool_use ordering. Changed to blocks.insert(0, ...) to prepend.
|
Merged via PR #14018. Your commit was cherry-picked onto current main with your authorship preserved in git log. We added follow-up fixes on top: a Kimi-specific carve-out in the signature stripping code (your thinking block was being stripped as a third-party endpoint), empty-string reasoning_content handling, correct block ordering, and a guard to prevent duplicate thinking content on native Anthropic. Thanks for the fix! |
Thanks a lot for the merge and the detailed follow-up fixes — really appreciate the improvements you added on top. I’ve been actively contributing to the project and would love to get more involved going forward. If possible, I’d be interested in becoming a collaborator to help review PRs and contribute more efficiently. Happy to continue contributing either way — thanks again for the support! |
… block ordering Follow-up to the cherry-picked PR NousResearch#13897 fix. Three issues found: 1. CRITICAL: The thinking block synthesised from reasoning_content was immediately stripped by the third-party signature management code (Kimi is classified as _is_third_party_anthropic_endpoint). Added a Kimi-specific carve-out that preserves unsigned thinking blocks while still stripping Anthropic-signed blocks Kimi can't validate. 2. Empty-string reasoning_content was silently dropped because the truthiness check ('if reasoning_content and ...') evaluates to False for ''. Changed to 'isinstance(reasoning_content, str)' so the tier-3 fallback from _copy_reasoning_content_for_api (which injects '' for Kimi tool-call messages with no reasoning) actually produces a thinking block. 3. The thinking block was appended AFTER tool_use blocks. Anthropic protocol requires thinking -> text -> tool_use ordering. Changed to blocks.insert(0, ...) to prepend.
… block ordering Follow-up to the cherry-picked PR NousResearch#13897 fix. Three issues found: 1. CRITICAL: The thinking block synthesised from reasoning_content was immediately stripped by the third-party signature management code (Kimi is classified as _is_third_party_anthropic_endpoint). Added a Kimi-specific carve-out that preserves unsigned thinking blocks while still stripping Anthropic-signed blocks Kimi can't validate. 2. Empty-string reasoning_content was silently dropped because the truthiness check ('if reasoning_content and ...') evaluates to False for ''. Changed to 'isinstance(reasoning_content, str)' so the tier-3 fallback from _copy_reasoning_content_for_api (which injects '' for Kimi tool-call messages with no reasoning) actually produces a thinking block. 3. The thinking block was appended AFTER tool_use blocks. Anthropic protocol requires thinking -> text -> tool_use ordering. Changed to blocks.insert(0, ...) to prepend.
… block ordering Follow-up to the cherry-picked PR NousResearch#13897 fix. Three issues found: 1. CRITICAL: The thinking block synthesised from reasoning_content was immediately stripped by the third-party signature management code (Kimi is classified as _is_third_party_anthropic_endpoint). Added a Kimi-specific carve-out that preserves unsigned thinking blocks while still stripping Anthropic-signed blocks Kimi can't validate. 2. Empty-string reasoning_content was silently dropped because the truthiness check ('if reasoning_content and ...') evaluates to False for ''. Changed to 'isinstance(reasoning_content, str)' so the tier-3 fallback from _copy_reasoning_content_for_api (which injects '' for Kimi tool-call messages with no reasoning) actually produces a thinking block. 3. The thinking block was appended AFTER tool_use blocks. Anthropic protocol requires thinking -> text -> tool_use ordering. Changed to blocks.insert(0, ...) to prepend.
… block ordering Follow-up to the cherry-picked PR NousResearch#13897 fix. Three issues found: 1. CRITICAL: The thinking block synthesised from reasoning_content was immediately stripped by the third-party signature management code (Kimi is classified as _is_third_party_anthropic_endpoint). Added a Kimi-specific carve-out that preserves unsigned thinking blocks while still stripping Anthropic-signed blocks Kimi can't validate. 2. Empty-string reasoning_content was silently dropped because the truthiness check ('if reasoning_content and ...') evaluates to False for ''. Changed to 'isinstance(reasoning_content, str)' so the tier-3 fallback from _copy_reasoning_content_for_api (which injects '' for Kimi tool-call messages with no reasoning) actually produces a thinking block. 3. The thinking block was appended AFTER tool_use blocks. Anthropic protocol requires thinking -> text -> tool_use ordering. Changed to blocks.insert(0, ...) to prepend.
… block ordering Follow-up to the cherry-picked PR NousResearch#13897 fix. Three issues found: 1. CRITICAL: The thinking block synthesised from reasoning_content was immediately stripped by the third-party signature management code (Kimi is classified as _is_third_party_anthropic_endpoint). Added a Kimi-specific carve-out that preserves unsigned thinking blocks while still stripping Anthropic-signed blocks Kimi can't validate. 2. Empty-string reasoning_content was silently dropped because the truthiness check ('if reasoning_content and ...') evaluates to False for ''. Changed to 'isinstance(reasoning_content, str)' so the tier-3 fallback from _copy_reasoning_content_for_api (which injects '' for Kimi tool-call messages with no reasoning) actually produces a thinking block. 3. The thinking block was appended AFTER tool_use blocks. Anthropic protocol requires thinking -> text -> tool_use ordering. Changed to blocks.insert(0, ...) to prepend.
Summary
Fixes #13848
Problem
When using
kimi-for-coding(Kimi's/codingendpoint via Anthropic Messages protocol), any session that triggers tool calls becomes permanently broken after several rounds.The Moonshot API returns HTTP 400:
This happens because:
/codingendpoint speaks Anthropic Messages protocol but has its own thinking semanticsthinking.enabledis sent, Kimi validates message history and requires every prior assistant tool-call message to carry OpenAI-stylereasoning_contentconvert_messages_to_anthropicstrips all Anthropic thinking blocks on third-party endpointsFix
In
convert_messages_to_anthropic, when processing an assistant message that contains bothtool_callsandreasoning_content, preserve thereasoning_contentas a{"type": "thinking", "thinking": ...}block appended to the Anthropic content blocks.This allows Kimi to validate the message history while keeping the change minimal and only affecting messages that have both tool_calls and reasoning_content.
Changes
agent/anthropic_adapter.py:convert_messages_to_anthropic()— added reasoning_content preservation for assistant tool-call messagesVerification
pnpm check/pytestpassesChecklist