Skip to content

fix: parse <tool_call> XML from text content in main agent loop#3518

Open
janovaworkstation wants to merge 1 commit into
NousResearch:mainfrom
janovaworkstation:fix/fallback-tool-call-parsing
Open

fix: parse <tool_call> XML from text content in main agent loop#3518
janovaworkstation wants to merge 1 commit into
NousResearch:mainfrom
janovaworkstation:fix/fallback-tool-call-parsing

Conversation

@janovaworkstation

Copy link
Copy Markdown

Summary

  • Adds fallback <tool_call> XML parsing to the main agent loop in run_agent.py
  • Fixes providers (e.g. Nous Portal with Hermes-4-405B) that return tool calls as text content instead of structured OpenAI tool_calls
  • Reuses the existing HermesToolCallParser from environments/tool_call_parsers/hermes_parser.py — zero new dependencies, 46 lines added

Problem

Models served via providers that don't translate tool calls into structured OpenAI tool_calls (e.g. inference-api.nousresearch.com with Hermes-4-405B) emit <tool_call> XML tags in the text content. The main agent loop only checks assistant_message.tool_calls, finds it empty, treats the response as a final text answer, and returns to the prompt — tools are never executed.

The RL training path (environments/agent_loop.py:260-281) already had a fallback parser for this exact case, but the main agent loop did not.

Fix

Add the same fallback in two places:

  1. Streaming path (~line 3898): After streaming chunks are accumulated into a mock response, if no structured tool_calls were received but the content contains <tool_call> tags, parse them with HermesToolCallParser.

  2. Main agent loop (~line 7157): Before the if assistant_message.tool_calls: check, parse <tool_call> XML from text content when tool_calls is empty.

Both paths reuse the battle-tested HermesToolCallParser already in the codebase — no new files or abstractions needed.

Related

Test plan

  • Verified HermesToolCallParser correctly extracts tool calls from <tool_call> XML
  • Tested with Hermes-4-405B via Nous Portal — tool calls now execute instead of being displayed as text
  • Existing parser tests pass (tests/test_tool_call_parsers.py — 27 passed)
  • Gateway testing (Telegram/Discord) with Hermes-4-405B

🤖 Generated with Claude Code

Models served via providers that don't translate tool calls into
structured OpenAI tool_calls (e.g. Nous Portal with Hermes-4-405B)
return tool calls as <tool_call> XML tags in the text content.

The RL training path (environments/agent_loop.py) already had a
fallback parser for this, but the main agent loop in run_agent.py
did not — causing tool calls to be silently treated as final text
responses and never executed.

Add the same fallback in two places:
1. Streaming path: after chunks are accumulated, parse <tool_call>
   tags from content when no structured tool_calls were streamed.
2. Main loop: before the tool_calls check, parse <tool_call> tags
   from content when assistant_message.tool_calls is empty.

Both reuse the existing HermesToolCallParser from
environments/tool_call_parsers/hermes_parser.py.

Closes NousResearch#2936

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@alt-glitch alt-glitch added type/bug Something isn't working P1 High — major feature broken, no workaround comp/agent Core agent loop, run_agent.py, prompt builder provider/nous Nous Research API (OAuth) labels May 2, 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 provider/nous Nous Research API (OAuth) type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Hermes-4 does not invoke tools via Telegram gateway despite tools being loaded

2 participants