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
- 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"
- Open
hermes tools
- Observe that two
web-related rows appear
- Toggle only one of them off
- Re-open
hermes tools
- Observe that behavior is inconsistent because both rows ultimately map to the same
web key
- Open configuration for either row
- 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:
-
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
-
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:
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:
Recommended Fix
I think the best near-term fix is:
- Deduplicate plugin toolset rows when the key already exists in built-ins
- Treat plugin-added tools on existing built-in toolsets as extensions of that toolset, not separate configurable toolsets
- Optionally annotate the single built-in row with plugin-added tools
Workarounds
Current workarounds are imperfect:
-
Ignore the duplicate row and treat web as a single logical toolset
- works mentally, but UI remains confusing
-
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
-
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.
Bug Description
When a plugin registers a tool into an existing built-in toolset (for example
toolset="web"),hermes toolscan show duplicate rows for the same logical toolset key.In the
web_search_pluscase, this creates two visiblewebentries in the tools UI:webrowwebrowThese rows are not actually independent:
web)So the UI is duplicating the toolset row while also conflating toolset identity, tool membership, and provider/config handling.
Steps to Reproduce
webtoolsetweb_search_plusregistersweb_search_pluswithtoolset="web"hermes toolsweb-related rows appearhermes toolswebkeywebconfig (TOOL_CATEGORIES["web"])Expected Behavior
If a plugin adds tools to an existing built-in toolset:
web)Actual Behavior
webtoolset keyRoot Cause
There appear to be two related problems in
hermes_cli/tools_config.py/ plugin toolset discovery:Plugin toolsets are appended into the configurable toolset list without deduping against built-in toolset keys.
CONFIGURABLE_TOOLSETSalready containswebwebConfiguration routing is keyed only by
ts_key._configure_toolset(ts_key, config)usesTOOL_CATEGORIES.get(ts_key)ts_key == "web", both rows resolve to the built-inwebconfigRelevant 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:
webentries and expect them to be independentPossible 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:
Cons:
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:
Cons:
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:
webtoolset rowwebPros:
webtoolsetsCons:
Recommended Fix
I think the best near-term fix is:
Workarounds
Current workarounds are imperfect:
Ignore the duplicate row and treat
webas a single logical toolsetUse plugin-specific env configuration outside
hermes tools.env/ plugin configAvoid registering plugin tools into existing built-in toolset names
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 toolsUI/config behavior when a plugin is attached to an existing built-in toolset key.