hermes - ✅(Solved) Fix hermes tools duplicates built-in toolset rows for plugins attached to existing toolsets [1 pull requests, 3 comments, 2 participants]

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…
GitHub stats
NousResearch/hermes-agent#13640Fetched 2026-04-22 08:05:08
View on GitHub
Comments
3
Participants
2
Timeline
7
Reactions
0
Author
Participants
Timeline (top)
commented ×3labeled ×3cross-referenced ×1

Root Cause

There appear to be two related problems in hermes_cli/tools_config.py / plugin toolset discovery:

  1. Plugin toolsets are appended into the configurable toolset list without deduping against built-in toolset keys.

    • built-in CONFIGURABLE_TOOLSETS already contains web
    • plugin discovery also returns web
    • result: duplicate rows for the same key
  2. Configuration routing is keyed only by ts_key.

    • _configure_toolset(ts_key, config) uses TOOL_CATEGORIES.get(ts_key)
    • for ts_key == "web", both rows resolve to the built-in web config
    • this makes the plugin-derived row masquerade as a second built-in config surface

Relevant code paths:

  • hermes_cli/tools_config.py::_get_effective_configurable_toolsets()
  • hermes_cli/plugins.py::get_plugin_toolsets()
  • hermes_cli/tools_config.py::_configure_toolset()
  • hermes_cli/tools_config.py::_toolset_needs_configuration_prompt()

Fix Action

Fix / Workaround

Workarounds

Current workarounds are imperfect:

PR fix notes

PR #13804: fix(cli): deduplicate plugin toolsets against built-in keys in hermes tools (Closes #13640)

Description (problem / solution / changelog)

Summary

When a plugin registers a tool into an existing built-in toolset (e.g. toolset="web"), hermes tools showed duplicate rows for the same toolset key. The built-in row and plugin-derived row both appeared, even though they mapped to the same underlying web key.

Fix: In _get_effective_configurable_toolsets(), skip plugin toolsets whose key already exists in CONFIGURABLE_TOOLSETS. Plugin-added tools now extend the existing toolset instead of creating a second top-level row.

Changes

  • hermes_cli/tools_config.py: Filter plugin toolsets against built-in keys before appending

Testing

Install a plugin that registers a tool with toolset="web"hermes tools now shows only one web row (not two)

Closes #13640

Changed files

  • agent/prompt_builder.py (modified, +7/-1)
  • hermes_cli/model_normalize.py (modified, +17/-0)
  • hermes_cli/tools_config.py (modified, +9/-1)
  • tests/agent/test_prompt_builder.py (modified, +18/-0)
RAW_BUFFERClick to expand / collapse

Bug Description

When a plugin registers a tool into an existing built-in toolset (for example toolset="web"), hermes tools can show duplicate rows for the same logical toolset key.

In the web_search_plus case, this creates two visible web entries in the tools UI:

  • the built-in web row
  • a plugin-derived web row

These rows are not actually independent:

  • both map to the same underlying toolset key (web)
  • disabling one does not behave independently from the other
  • both rows open the same built-in web config panel
  • the plugin-specific configuration surface is not represented correctly

So the UI is duplicating the toolset row while also conflating toolset identity, tool membership, and provider/config handling.

Steps to Reproduce

  1. Install/enable a plugin that registers a tool into the built-in web toolset
    • example: web_search_plus registers web_search_plus with toolset="web"
  2. Open hermes tools
  3. Observe that two web-related rows appear
  4. Toggle only one of them off
  5. Re-open hermes tools
  6. Observe that behavior is inconsistent because both rows ultimately map to the same web key
  7. Open configuration for either row
  8. Observe that both rows route to the built-in web config (TOOL_CATEGORIES["web"])

Expected Behavior

If a plugin adds tools to an existing built-in toolset:

  • only one row should appear for that toolset
  • the row should represent the single logical toolset key (web)
  • plugin-added tools should extend that toolset rather than create a second top-level row
  • configuration should not pretend the plugin row is a separate configurable surface

Actual Behavior

  • duplicate rows appear for the same web toolset key
  • the enable/disable behavior is coupled because both rows save/load via the same key
  • both rows open the same built-in web config panel
  • plugin-specific env/config is not surfaced cleanly, but the UI suggests there are two configurable web entries

Root Cause

There appear to be two related problems in hermes_cli/tools_config.py / plugin toolset discovery:

  1. Plugin toolsets are appended into the configurable toolset list without deduping against built-in toolset keys.

    • built-in CONFIGURABLE_TOOLSETS already contains web
    • plugin discovery also returns web
    • result: duplicate rows for the same key
  2. Configuration routing is keyed only by ts_key.

    • _configure_toolset(ts_key, config) uses TOOL_CATEGORIES.get(ts_key)
    • for ts_key == "web", both rows resolve to the built-in web config
    • this makes the plugin-derived row masquerade as a second built-in config surface

Relevant code paths:

  • hermes_cli/tools_config.py::_get_effective_configurable_toolsets()
  • hermes_cli/plugins.py::get_plugin_toolsets()
  • hermes_cli/tools_config.py::_configure_toolset()
  • hermes_cli/tools_config.py::_toolset_needs_configuration_prompt()

Why This Matters

This creates confusing and misleading UX:

  • users see two web entries and expect them to be independent
  • toggling one does not cleanly disable only one thing
  • config behavior is misleading because both rows point to the same built-in config
  • plugin-added tools attached to existing built-in toolsets are treated like new top-level configurable toolsets instead of extensions

Possible Solutions

Option A — Deduplicate plugin rows against built-in toolset keys

When building the configurable toolset list, do not append plugin toolsets whose key already exists in built-in CONFIGURABLE_TOOLSETS.

Pros:

  • minimal and low-risk
  • immediately fixes duplicate rows
  • preserves existing behavior for plugin-only toolsets

Cons:

  • plugin-added tools/config still may not be surfaced richly in the UI

Option B — Treat plugin tools on existing toolsets as extensions, not new configurable toolsets

Keep a single row for web, but augment its metadata in the UI. For example, show something like:

  • web (includes plugin tools: web_search_plus)

Pros:

  • best conceptual model
  • preserves one logical toolset row
  • clearer to users that plugin tools extend the built-in toolset

Cons:

  • slightly more UI work

Option C — Add a separate plugin-config section without duplicating the toolset row

If plugin-specific env/setup needs to be configurable, surface it separately from the top-level toolset checklist. For example:

  • one web toolset row
  • separate plugin settings/details area for plugin tools extending web

Pros:

  • clean separation between toolset enablement and provider/plugin configuration
  • avoids lying to the user about there being two independent web toolsets

Cons:

  • broader design change

Recommended Fix

I think the best near-term fix is:

  1. Deduplicate plugin toolset rows when the key already exists in built-ins
  2. Treat plugin-added tools on existing built-in toolsets as extensions of that toolset, not separate configurable toolsets
  3. Optionally annotate the single built-in row with plugin-added tools

Workarounds

Current workarounds are imperfect:

  1. Ignore the duplicate row and treat web as a single logical toolset

    • works mentally, but UI remains confusing
  2. Use plugin-specific env configuration outside hermes tools

    • for example, configure the plugin via its own .env / plugin config
    • avoids relying on the duplicated built-in config rows
  3. Avoid registering plugin tools into existing built-in toolset names

    • for example, use a distinct toolset key
    • but this changes UX and may run into other toolset/config limitations depending on platform configuration

Related Context

There is a separate core issue/PR about plugin-registered tools being omitted from existing built-in toolsets during toolset resolution. This issue is specifically about the hermes tools UI/config behavior when a plugin is attached to an existing built-in toolset key.

extent analysis

TL;DR

Deduplicate plugin toolset rows against built-in toolset keys to prevent duplicate rows for the same logical toolset key.

Guidance

  • Review the hermes_cli/tools_config.py file, specifically the _get_effective_configurable_toolsets() function, to ensure that plugin toolsets are not appended to the configurable toolset list if their key already exists in built-in CONFIGURABLE_TOOLSETS.
  • Consider treating plugin-added tools on existing built-in toolsets as extensions of that toolset, rather than separate configurable toolsets, to improve the user experience.
  • Annotate the single built-in row with plugin-added tools to provide clear visibility into the tools included in each toolset.
  • Verify that the configuration routing is updated to handle the deduplicated toolset rows correctly, using the ts_key to resolve to the correct configuration.

Example

# hermes_cli/tools_config.py
def _get_effective_configurable_toolsets():
    # ...
    built_in_toolsets = CONFIGURABLE_TOOLSETS
    plugin_toolsets = get_plugin_toolsets()
    # Deduplicate plugin toolsets against built-in toolset keys
    effective_toolsets = built_in_toolsets + [ts for ts in plugin_toolsets if ts not in built_in_toolsets]
    # ...

Notes

The provided solution focuses on deduplicating plugin toolset rows and treating plugin-added tools as extensions of existing built-in toolsets. However, a more comprehensive solution may require additional changes to the UI and configuration routing to fully address the issue.

Recommendation

Apply the workaround of deduplicating plugin toolset rows against built-in toolset keys, as it is a minimal and low-risk change that immediately fixes the duplicate rows issue. This will provide a better user experience and prevent confusing UX.

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

hermes - ✅(Solved) Fix hermes tools duplicates built-in toolset rows for plugins attached to existing toolsets [1 pull requests, 3 comments, 2 participants]