Skip to content

fix(anthropic_adapter): preserve reasoning_content for Kimi /coding tool-call messages#13897

Closed
HiddenPuppy wants to merge 2 commits into
NousResearch:mainfrom
HiddenPuppy:fix/kimi-coding-reasoning-content
Closed

fix(anthropic_adapter): preserve reasoning_content for Kimi /coding tool-call messages#13897
HiddenPuppy wants to merge 2 commits into
NousResearch:mainfrom
HiddenPuppy:fix/kimi-coding-reasoning-content

Conversation

@HiddenPuppy

Copy link
Copy Markdown
Contributor

Summary

Fixes #13848

Problem

When using kimi-for-coding (Kimi's /coding endpoint via Anthropic Messages protocol), any session that triggers tool calls becomes permanently broken after several rounds.

The Moonshot API returns HTTP 400:

thinking is enabled but reasoning_content is missing in assistant tool call message at index 2

This happens because:

  1. Kimi's /coding endpoint speaks Anthropic Messages protocol but has its own thinking semantics
  2. When thinking.enabled is sent, Kimi validates message history and requires every prior assistant tool-call message to carry OpenAI-style reasoning_content
  3. The Anthropic path never populated that field
  4. convert_messages_to_anthropic strips all Anthropic thinking blocks on third-party endpoints
  5. The corrupted message stays in conversation history and gets replayed every subsequent turn

Fix

In convert_messages_to_anthropic, when processing an assistant message that contains both tool_calls and reasoning_content, preserve the reasoning_content as 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 messages

Verification

  • pnpm check / pytest passes
  • Manual: configure Hermes Agent with kimi-for-coding, start a session with tool calls, confirm no HTTP 400 after multiple rounds

Checklist

  • Bug fix (non-breaking change which fixes an issue)
  • New feature
  • Breaking change
  • Requires documentation update

Jerome added 2 commits April 22, 2026 15:18
…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.
@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists comp/agent Core agent loop, run_agent.py, prompt builder provider/kimi Kimi / Moonshot labels Apr 22, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

Related to PR #13864 — both fix the same Kimi reasoning_content issue (#13848) with different approaches. Maintainers should pick one.

kshitijk4poor added a commit that referenced this pull request Apr 22, 2026
… 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.
kshitijk4poor added a commit that referenced this pull request Apr 22, 2026
… 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.
@kshitijk4poor

Copy link
Copy Markdown
Collaborator

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!

@HiddenPuppy

Copy link
Copy Markdown
Contributor Author

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!

ulasbilgen pushed a commit to ulasbilgen/hermes-adhd-agent that referenced this pull request May 1, 2026
… 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.
aj-nt pushed a commit to aj-nt/hermes-agent that referenced this pull request May 1, 2026
… 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.
02356abc pushed a commit to 02356abc/hermes-agent that referenced this pull request May 14, 2026
… 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.
gweeteve pushed a commit to gweeteve/hermes-agent that referenced this pull request Jun 2, 2026
… 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.
Egavasyug pushed a commit to Egavasyug/hermes-agent that referenced this pull request Jun 10, 2026
… 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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/agent Core agent loop, run_agent.py, prompt builder P2 Medium — degraded but workaround exists provider/kimi Kimi / Moonshot type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: 400 error for kimi-for-coding

3 participants