From 2efb0eea211ae214019dac64be5b81002b942483 Mon Sep 17 00:00:00 2001 From: Jerome Date: Wed, 22 Apr 2026 15:18:49 +0800 Subject: [PATCH] fix(anthropic_adapter): preserve reasoning_content on assistant tool-call messages for Kimi /coding MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes NousResearch/hermes-agent#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. --- agent/anthropic_adapter.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/agent/anthropic_adapter.py b/agent/anthropic_adapter.py index e3f23059..3612ce1a 100644 --- a/agent/anthropic_adapter.py +++ b/agent/anthropic_adapter.py @@ -1083,6 +1083,13 @@ def convert_messages_to_anthropic( "name": fn.get("name", ""), "input": parsed_args, }) + # Kimi's /coding endpoint (Anthropic protocol) requires assistant + # tool-call messages to carry reasoning_content when thinking is + # enabled. Preserve it as a thinking block so Kimi can validate + # the message history. See hermes-agent#13848. + reasoning_content = m.get("reasoning_content") + if reasoning_content and isinstance(reasoning_content, str): + blocks.append({"type": "thinking", "thinking": reasoning_content}) # Anthropic rejects empty assistant content effective = blocks or content if not effective or effective == "":