Skip to content

fix(agent): rebuild api_messages after provider fallback to apply reasoning requirements#21033

Open
bradhallett wants to merge 1 commit intoNousResearch:mainfrom
bradhallett:fix/fallback-rebuild-api-messages
Open

fix(agent): rebuild api_messages after provider fallback to apply reasoning requirements#21033
bradhallett wants to merge 1 commit intoNousResearch:mainfrom
bradhallett:fix/fallback-rebuild-api-messages

Conversation

@bradhallett
Copy link
Copy Markdown

Problem

When Hermes falls back from one provider (e.g. GLM-5.1) to DeepSeek/Kimi via _try_activate_fallback(), the api_messages array is stale — it was built before the fallback with the original provider's settings. Since _copy_reasoning_content_for_api runs with the original provider's model, DeepSeek-required reasoning_content padding is not added to assistant messages.

This causes HTTP 400 from DeepSeek:

The reasoning_content in the thinking mode must be passed back to the API.

Root Cause

The message-building block sits outside the inner retry loop. After _try_activate_fallback() success, the continue loops back to the retry loop top — not the message builder — so stale api_messages is reused with the wrong provider's settings.

Fix

  1. Extract the inline message-building block into _build_api_messages() — an instance method on AIAgent that returns (api_messages, total_chars, approx_tokens).
  2. Replace the inline block with a single call to the new method.
  3. Add a _build_api_messages() call at all 6 _try_activate_fallback() sites in the retry loop to ensure api_messages is rebuilt with the current provider's settings before continuing.

Testing

  • 12 new regression tests in tests/run_agent/test_build_api_messages_fallback.py
  • Covers: DeepSeek padding, GLM mode (no padding), fallback simulation (GLM→DeepSeek, DeepSeek→GLM), method contract, message immutability
  • All 36 existing test_deepseek_reasoning_content_echo.py tests continue to pass

Related

…soning requirements

When Hermes falls back from one provider (e.g. GLM-5.1) to DeepSeek via
_try_activate_fallback(), the api_messages array was stale — built with
the original provider's settings where _copy_reasoning_content_for_api
may not have added reasoning_content padding. DeepSeek requires
reasoning_content on every assistant message in thinking mode, so stale
messages cause HTTP 400.

Extract _build_api_messages() as an instance method so the same build
logic runs both at initial request time and after provider fallback,
always with the current provider's settings.

Add a call to _build_api_messages() at all 6 _try_activate_fallback()
sites in the retry loop to rebuild api_messages before continuing.

Fixes NousResearchGH-17212, NousResearchGH-17825, relates to NousResearchGH-13235.
@alt-glitch alt-glitch added type/bug Something isn't working comp/agent Core agent loop, run_agent.py, prompt builder P1 High — major feature broken, no workaround labels May 7, 2026
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 P1 High — major feature broken, no workaround type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

DeepSeek direct API 400 "reasoning_content must be passed back" on multi-turn tool calls

2 participants