fix(kimi): preserve reasoning_content in Anthropic adapter for /coding endpoint (salvage #13897)#14018
Merged
Merged
Conversation
added 2 commits
April 22, 2026 18:35
…call messages for Kimi /coding Fixes #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.
Collaborator
Collaborator
… 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.
319ddc9 to
123287d
Compare
This was referenced Apr 22, 2026
Closed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Salvages #13897 by @HiddenPuppy onto current main, with critical follow-up fixes.
Problem
Kimi's
/codingendpoint speaks Anthropic Messages protocol but enables thinking server-side. When replaying conversation history, it requires every assistant tool-call message to carry a thinking block — even when we don't sendthinking.enabledin the request kwargs (PR #13826 correctly suppressed that). Without this, sessions break after tool calls with:PR #13975 fixed the
chat_completionspath inrun_agent.py(_copy_reasoning_content_for_api), but theanthropic_messagespath (convert_messages_to_anthropicinanthropic_adapter.py) was still missing the reasoning_content → thinking block conversion.Issue confirmed real: Brand-new gateway sessions (e.g.
20260422_011800_eea181) fail at message index 2 — the very first replay after an initial tool call. Not stale-session artifacts.Cherry-picked from #13897
convert_messages_to_anthropic(): When an assistant message hasreasoning_content, convert it to a{"type": "thinking", "thinking": ...}block in the Anthropic message format.Follow-up fixes (found during self-review)
Thinking block stripped by signature management (CRITICAL): The thinking block synthesised from
reasoning_contentwas immediately stripped by the third-party signature-stripping code — Kimi is classified as_is_third_party_anthropic_endpoint. Added a Kimi-specific carve-out: preserve unsigned thinking blocks (which we synthesised from reasoning_content) while stripping Anthropic-signed blocks Kimi can't validate.Empty-string reasoning_content silently dropped: The truthiness check (
if reasoning_content and ...) evaluates to False for"". But_copy_reasoning_content_for_api()deliberately injects""as a tier-3 fallback for Kimi tool-call messages with no reasoning. Changed toisinstance(reasoning_content, str)so empty-string reasoning still produces a thinking block.Wrong block ordering: Thinking block was appended AFTER tool_use blocks. Anthropic protocol requires thinking → text → tool_use ordering. Changed to
blocks.insert(0, ...).Duplicate thinking content on native Anthropic (CRITICAL): The reasoning_content → thinking block insertion ran for ALL endpoints, not just Kimi. On native Anthropic where
reasoning_detailsalready contributes signed thinking blocks, this created a second unsigned thinking block with the same text. The unsigned block would be downgraded to a spurious text block on the last assistant message — inflating context and potentially confusing the model. Added a guard: only insert the reasoning_content thinking block when no thinking blocks already exist fromreasoning_details.Scope verification
_is_kimi_coding_endpoint()is confirmed a strict subset of_is_third_party_anthropic_endpoint()— the if/elif ordering is correctFiles changed
agent/anthropic_adapter.py— reasoning_content → thinking block conversion + Kimi carve-out in signature stripping + duplicate guardscripts/release.py— AUTHOR_MAP entries for @HiddenPuppyValidation
Closes #13848. Closes #13897.