hermes - 💡(How to fix) Fix Bug: Plattform-Bundle name `hermes-yuanbao` in `agent.disabled_toolsets` silently kills ALL tools in gateway path (Telegram + cron), CLI unaffected [3 pull requests]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

When a platform-bundle name (e.g. hermes-yuanbao, but presumably any hermes-* bundle) lands in agent.disabled_toolsets in config.yaml, the gateway code path (Telegram, cron, every messaging platform) sends API requests to the model with an empty tools list and tool_choice: null — i.e. the model has no tools available at all. The hermes -z ... CLI path is unaffected and tools work normally there.

There is no error, no warning, no log line indicating anything went wrong. hermes tools list --platform telegram continues to show all individual toolsets as ✓ enabled. hermes doctor is fully green. The only visible symptom from the user side is that the model starts responding with text like "I cannot execute shell commands in this session" because — from the model's perspective — that is now factually true.

For interactive use this is recoverable (you notice the bot is broken). For unattended cron jobs (in our case a 5-minute WhatsApp listener healthcheck) the bot silently fails for days before anyone notices.

Error Message

There is no error, no warning, no log line indicating anything went wrong. hermes tools list --platform telegram continues to show all individual toolsets as ✓ enabled. hermes doctor is fully green. The only visible symptom from the user side is that the model starts responding with text like "I cannot execute shell commands in this session" because — from the model's perspective — that is now factually true. Validation should also check that values are in {BUILTIN_TOOLSETS ∪ PLUGIN_TOOLSETS} and warn otherwise. 2. Warn on read. When _get_platform_tools resolves disabled_toolsets and encounters a hermes-* entry, log a WARNING and skip that entry rather than silently nuking the bundle:

Root Cause

  • Silent failure is the worst class of bug. The bot keeps running, keeps responding, the only signal is that responses are slightly wrong ("I cannot do that") instead of containing real tool output.
  • CLI works, gateway doesn't is maximally confusing because the obvious diagnostic step (try it on the CLI) gives a false-positive "everything looks fine here."
  • Unattended cron jobs can fail for days. Our WhatsApp healthcheck ran every 10 minutes for 5+ hours emitting nothing useful before we noticed the bot was being weird.
  • hermes doctor and hermes tools list both pass. There is no built-in way to detect this state short of inspecting raw API request dumps.

Happy to PR fix (1) if it would be welcome. Also happy to provide raw request-dump JSONs if useful for testing.


Filed: 2026-05-28 Reporter: @morningstarnasser Severity: silent failure across all gateway platforms; effective complete tool loss

Fix Action

Fixed

Code Example

# 1. Verify baseline — cron tool-use works
hermes cron run <some-cron-id>
# Wait, then check agent.log: tool_turns >= 1, api_calls >= 2 — ✓

# 2. Add hermes-yuanbao to disabled_toolsets
hermes config set agent.disabled_toolsets [hermes-yuanbao]
systemctl restart hermes-gateway.service   # or however you run the gateway

# 3. Trigger same cron
hermes cron run <some-cron-id>
# agent.log now shows: tool_turns=0, api_calls=1
# Model reply: "I cannot execute shell commands"

# 4. Enable request dumps to see what actually got sent
echo "HERMES_DUMP_REQUESTS=1" >> /etc/hermes.env   # or ~/.hermes/.env
systemctl restart hermes-gateway.service
hermes cron run <some-cron-id>
# Inspect: ~/.hermes/sessions/request_dump_cron_*.json
python3 -c "
import json, glob, os
f = sorted(glob.glob(os.path.expanduser('~/.hermes/sessions/request_dump_cron_*.json')), key=os.path.getmtime)[-1]
b = json.loads(open(f).read())['request']['body']
print('tools count:', len(b.get('tools') or []))
print('tool_choice:', b.get('tool_choice'))
print('instructions len:', len(b.get('instructions') or ''))
"

---

tools count: 27
tool_choice: auto
instructions len: ~21000

---

tools count: 0
tool_choice: None
instructions len: ~5300

---

"hermes-yuanbao": {
    "description": "...",
    "tools": _HERMES_CORE_TOOLS,   # mirrors hermes-cli
    "includes": []
}

---

disabled_toolsets = agent_cfg.get("disabled_toolsets") or []
if disabled_toolsets:
    disabled_set = {str(ts) for ts in disabled_toolsets}
    enabled_toolsets -= disabled_set

---

'hermes-yuanbao' is a platform-bundle name, not an individual toolset.
  Did you mean 'yuanbao'? (without the 'hermes-' prefix)
  Platform bundles go in `toolsets:` at the top level of config.yaml.

---

WARNING gateway.run: agent.disabled_toolsets contains 'hermes-yuanbao' which is
a platform bundle, not an individual toolset. Ignoring. Use 'yuanbao' to disable
the Tencent Yuanbao chat tool, or remove it from `toolsets:` to disable the bundle.
RAW_BUFFERClick to expand / collapse

Summary

When a platform-bundle name (e.g. hermes-yuanbao, but presumably any hermes-* bundle) lands in agent.disabled_toolsets in config.yaml, the gateway code path (Telegram, cron, every messaging platform) sends API requests to the model with an empty tools list and tool_choice: null — i.e. the model has no tools available at all. The hermes -z ... CLI path is unaffected and tools work normally there.

There is no error, no warning, no log line indicating anything went wrong. hermes tools list --platform telegram continues to show all individual toolsets as ✓ enabled. hermes doctor is fully green. The only visible symptom from the user side is that the model starts responding with text like "I cannot execute shell commands in this session" because — from the model's perspective — that is now factually true.

For interactive use this is recoverable (you notice the bot is broken). For unattended cron jobs (in our case a 5-minute WhatsApp listener healthcheck) the bot silently fails for days before anyone notices.

Environment

  • Hermes Agent v0.14.0 (2026.5.16), installed via pip install hermes-agent
  • Python 3.11.15, venv at /usr/local/lib/hermes-agent/venv
  • Provider: openai-codex (ChatGPT Pro OAuth), endpoint https://chatgpt.com/backend-api/codex/responses
  • Model: gpt-5.5
  • Linux (Debian/Ubuntu), systemd service for the gateway
  • 22 platforms enabled but only Telegram active in our setup; cron same code path

Reproduction

Starting from a working config where Cron + Telegram tools work correctly:

# 1. Verify baseline — cron tool-use works
hermes cron run <some-cron-id>
# Wait, then check agent.log: tool_turns >= 1, api_calls >= 2 — ✓

# 2. Add hermes-yuanbao to disabled_toolsets
hermes config set agent.disabled_toolsets [hermes-yuanbao]
systemctl restart hermes-gateway.service   # or however you run the gateway

# 3. Trigger same cron
hermes cron run <some-cron-id>
# agent.log now shows: tool_turns=0, api_calls=1
# Model reply: "I cannot execute shell commands"

# 4. Enable request dumps to see what actually got sent
echo "HERMES_DUMP_REQUESTS=1" >> /etc/hermes.env   # or ~/.hermes/.env
systemctl restart hermes-gateway.service
hermes cron run <some-cron-id>
# Inspect: ~/.hermes/sessions/request_dump_cron_*.json
python3 -c "
import json, glob, os
f = sorted(glob.glob(os.path.expanduser('~/.hermes/sessions/request_dump_cron_*.json')), key=os.path.getmtime)[-1]
b = json.loads(open(f).read())['request']['body']
print('tools count:', len(b.get('tools') or []))
print('tool_choice:', b.get('tool_choice'))
print('instructions len:', len(b.get('instructions') or ''))
"

Expected:

tools count: 27
tool_choice: auto
instructions len: ~21000

Actual:

tools count: 0
tool_choice: None
instructions len: ~5300

The body keys tools, tool_choice, parallel_tool_calls are also missing from the JSON entirely (not just empty).

Bisect path

We hit this after a config edit session and spent considerable time chasing the wrong cause (suspected the model setting, persona system prompt, approval mode, session pollution). Methodical bisect through 8 disabled_toolsets candidates produced an unambiguous answer:

disabled_toolsets value (singleton)body.tools length
[feishu_doc]27 ✓
[feishu_drive]27 ✓
[homeassistant]27 ✓
[video_gen]27 ✓
[x_search]27 ✓
[hermes-yuanbao]0 ✗
[spotify]27 ✓
[discord_admin]27 ✓

Only hermes-yuanbao (the platform bundle) triggers the failure. The individual toolset is yuanbao (without prefix) — that name works correctly in disabled_toolsets and is visible in hermes tools list.

Root cause hypothesis

Hermes has two distinct toolset namespaces:

  1. Individual toolsets (expected in agent.disabled_toolsets): terminal, file, browser, web, yuanbao, spotify, discord_admin, …
  2. Platform bundles (expected in toolsets: at top level): hermes-cli, hermes-telegram, hermes-discord, hermes-whatsapp, hermes-yuanbao, hermes-slack, …

Defined in toolsets.py:

"hermes-yuanbao": {
    "description": "...",
    "tools": _HERMES_CORE_TOOLS,   # mirrors hermes-cli
    "includes": []
}

hermes-yuanbao is essentially a super-toolset that resolves to the same _HERMES_CORE_TOOLS as hermes-cli.

In hermes_cli/tools_config.py (~L1338) the disable logic is a plain set subtraction:

disabled_toolsets = agent_cfg.get("disabled_toolsets") or []
if disabled_toolsets:
    disabled_set = {str(ts) for ts in disabled_toolsets}
    enabled_toolsets -= disabled_set

This does the right thing only if disabled_toolsets contains individual-toolset names. When it contains a bundle name, the subtraction is silently nonsensical: somewhere downstream the bundle membership gets re-resolved and the bundle's _HERMES_CORE_TOOLS list ends up subtracting itself (or matching the active hermes-cli bundle's tool resolution), and the gateway code path produces an empty tools array for the API request. The CLI path takes a different code path that constructs tools from agent.toolsets directly, so it's unaffected.

(Source-level diagnosis from running install; happy to confirm exact mechanism with a debugger trace if helpful.)

Suggested fix

Three options, in increasing scope:

1. Validate on write (highest leverage, smallest fix). In hermes config set agent.disabled_toolsets [...], reject any value matching ^hermes- with:

✗ 'hermes-yuanbao' is a platform-bundle name, not an individual toolset.
  Did you mean 'yuanbao'? (without the 'hermes-' prefix)
  Platform bundles go in `toolsets:` at the top level of config.yaml.

Validation should also check that values are in {BUILTIN_TOOLSETS ∪ PLUGIN_TOOLSETS} and warn otherwise.

2. Warn on read. When _get_platform_tools resolves disabled_toolsets and encounters a hermes-* entry, log a WARNING and skip that entry rather than silently nuking the bundle:

WARNING gateway.run: agent.disabled_toolsets contains 'hermes-yuanbao' which is
a platform bundle, not an individual toolset. Ignoring. Use 'yuanbao' to disable
the Tencent Yuanbao chat tool, or remove it from `toolsets:` to disable the bundle.

3. Make the subtraction symmetric. If a bundle name in disabled_toolsets is intentional (the user really wants to disable an entire bundle), resolve it to its member tools and subtract those, rather than letting the set-difference produce an empty tools array for unrelated bundles. This is the most permissive fix and arguably the most correct.

In our case (1) alone would have saved us several hours. (2) is a good additional safety net for hand-edited configs. (3) is nice-to-have.

Why this matters

  • Silent failure is the worst class of bug. The bot keeps running, keeps responding, the only signal is that responses are slightly wrong ("I cannot do that") instead of containing real tool output.
  • CLI works, gateway doesn't is maximally confusing because the obvious diagnostic step (try it on the CLI) gives a false-positive "everything looks fine here."
  • Unattended cron jobs can fail for days. Our WhatsApp healthcheck ran every 10 minutes for 5+ hours emitting nothing useful before we noticed the bot was being weird.
  • hermes doctor and hermes tools list both pass. There is no built-in way to detect this state short of inspecting raw API request dumps.

Happy to PR fix (1) if it would be welcome. Also happy to provide raw request-dump JSONs if useful for testing.


Filed: 2026-05-28 Reporter: @morningstarnasser Severity: silent failure across all gateway platforms; effective complete tool loss

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING