Skip to content

hermes tools duplicates built-in toolset rows for plugins attached to existing toolsets #13640

@wysie

Description

@wysie

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    comp/pluginsPlugin system and bundled pluginscomp/toolsTool registry, model_tools, toolsetssweeper:implemented-on-mainSweeper: behavior already present on current maintype/bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions