fix(plugins): discover nested category plugins in 'plugins list' (#41066)#41076
Closed
Elshayib wants to merge 1 commit into
Closed
fix(plugins): discover nested category plugins in 'plugins list' (#41066)#41076Elshayib wants to merge 1 commit into
Elshayib wants to merge 1 commit into
Conversation
NousResearch#41066) _discover_all_plugins() previously did a flat iterdir() scan, missing all category-namespaced plugins (web/*, image_gen/*, browser/*, video_gen/*). Now recurses up to 2 levels deep, matching PluginManager._scan_directory_level(). Also fixes _plugin_status() to check both manifest name AND path-derived key against enabled/disabled sets, so category plugins like 'web/tavily' show correct status when enabled via config.
kshitijk4poor
added a commit
to kshitijk4poor/hermes-agent
that referenced
this pull request
Jun 8, 2026
…ble/disable (NousResearch#41066) Salvage consolidating three complementary community PRs into one coherent fix: - NousResearch#41076 (islam666): made `hermes plugins list` discover nested category plugins (e.g. `observability/nemo_relay`, `image_gen/openai`). - NousResearch#41613 (mnajafian-nv): the superset — nested discovery aligned with the runtime loader (reuses `PluginManager._scan_directory`/`_scan_entry_points` so list state can't drift from what actually loads), PLUS the enable/disable mutation side NousResearch#41076 left flat. - NousResearch#41081 (annguyenNous): identified the `web_server.py` dashboard plugins-hub caller of `_discover_all_plugins()`, which must also be updated for the new tuple shape + key-aware status. This combines the best of all three and fixes the mutation-side gap that made nested bundled plugins untoggleable: $ hermes plugins enable nemo_relay Plugin 'nemo_relay' is not installed or bundled. # exit 1 (before) Now `enable`/`disable`/`toggle`, the `hermes plugins list` views, the dashboard plugins-hub endpoint, and the dashboard enable/disable helpers all resolve a bare manifest name OR a full path-derived key to the canonical key the loader gates on, via a single `_resolve_plugin_reference()` normalization point, and persist that key while clearing any stale legacy bare-name alias so the two can't drift. `_plugin_status` is key+legacy-name aware. `_discover_all_plugins` now returns 6-tuples `(key, legacy_name, version, description, source, dir_path)`; ALL call sites (`cmd_list` table/plain/JSON, `_filter_plugin_entries`, `cmd_toggle`, `dashboard_remove_user_plugin`, and `web_server._merged_plugins_hub`) and the `test_plugins_cmd_list.py` fixtures are updated to match. Updating the `web_server.py` caller prevents a `ValueError: too many values to unpack` crash in the dashboard plugins-hub endpoint. Verified e2e on the real CLI + runtime loader (isolated HERMES_HOME): `hermes plugins enable nemo_relay` writes `observability/nemo_relay` to config.yaml and the loader then loads it (`enabled=True, error=None`); a stale bare-name alias is cleared on disable (no contradictory state); the dashboard `_merged_plugins_hub()` runs and lists nested plugins by canonical key. Full `tests/hermes_cli/test_plugins_cmd*` + web_server plugin tests green. Closes NousResearch#41066. Supersedes NousResearch#41076, NousResearch#41081, and NousResearch#41613. Co-authored-by: islam666 <islam666@users.noreply.github.com> Co-authored-by: mnajafian-nv <mnajafian@nvidia.com> Co-authored-by: annguyenNous <annguyenNous@users.noreply.github.com> Co-authored-by: kshitijk4poor <82637225+kshitijk4poor@users.noreply.github.com>
2 tasks
kshitijk4poor
added a commit
to kshitijk4poor/hermes-agent
that referenced
this pull request
Jun 8, 2026
…ins (follow-up to NousResearch#41076) NousResearch#41076 makes `hermes plugins list` discover nested category plugins (e.g. observability/nemo_relay). This adds the missing enable/disable mutation path so those plugins can actually be toggled, and fixes two incomplete-update breakages on the NousResearch#41076 base. Before: `hermes plugins enable nemo_relay` -> "Plugin 'nemo_relay' is not installed or bundled." (exit 1), because cmd_enable/cmd_disable went through _plugin_exists(), which only checked top-level plugins/<name>/. Changes: - Add _resolve_plugin_key(): resolve a bare manifest/leaf name OR a full path-derived key (observability/nemo_relay) to the canonical key the runtime loader gates on, reusing NousResearch#41076's _discover_all_plugins(). A bare leaf name ambiguous across two categories resolves to None rather than silently picking one. - cmd_enable/cmd_disable resolve first, persist the canonical key, and drop any stale legacy bare-name alias so the enabled/disabled lists can't drift into a contradictory state. _plugin_exists delegates to the same resolver. - Fix NousResearch#41076 base breakages: _discover_all_plugins now returns 6-tuples, but web_server._merged_plugins_hub() still unpacked 5 (ValueError on the dashboard plugins-hub endpoint) and several test_plugins_cmd_list.py fixtures were still 5-tuples. Both updated; the hub status check is now key-aware. Verified e2e on the real CLI + runtime loader (isolated HERMES_HOME): `hermes plugins enable nemo_relay` writes observability/nemo_relay to config.yaml and the loader then loads it (enabled=True, error=None); a stale bare-name alias is cleared on disable; the dashboard _merged_plugins_hub() runs without crashing. Adds resolution + enable/disable tests; full tests/hermes_cli/test_plugins_cmd* + web_server plugin tests green. Follow-up to NousResearch#41076 (NousResearch#41066). Branched from that PR's head.
kshitijk4poor
added a commit
that referenced
this pull request
Jun 8, 2026
…ble/disable (#41066) Merge #42076: nested category plugin discovery + alias-normalized enable/disable (#41066) Lands the complete nested category plugin fix: - Discovery in `hermes plugins list` (from @islam666's #41076, carried in this PR) - Alias-normalized enable/disable mutation path so nested plugins can be toggled - Fixes the #41076 base breakages (web_server 6-tuple unpack + stale test fixtures) Co-authored work: discovery by @islam666 (#41076). Closes #41066.
Collaborator
|
The nested category plugin discovery from this PR landed on main via #42076 (merge commit b99c6c4) — your discovery commit is included as-is and credited. #42076 built on it to add the enable/disable mutation path and fix a few caller/fixture spots that needed the new 6-tuple shape ( |
jhjaggars-hermes
pushed a commit
to jhjaggars/hermes-agent
that referenced
this pull request
Jun 8, 2026
…ins (follow-up to NousResearch#41076) NousResearch#41076 makes `hermes plugins list` discover nested category plugins (e.g. observability/nemo_relay). This adds the missing enable/disable mutation path so those plugins can actually be toggled, and fixes two incomplete-update breakages on the NousResearch#41076 base. Before: `hermes plugins enable nemo_relay` -> "Plugin 'nemo_relay' is not installed or bundled." (exit 1), because cmd_enable/cmd_disable went through _plugin_exists(), which only checked top-level plugins/<name>/. Changes: - Add _resolve_plugin_key(): resolve a bare manifest/leaf name OR a full path-derived key (observability/nemo_relay) to the canonical key the runtime loader gates on, reusing NousResearch#41076's _discover_all_plugins(). A bare leaf name ambiguous across two categories resolves to None rather than silently picking one. - cmd_enable/cmd_disable resolve first, persist the canonical key, and drop any stale legacy bare-name alias so the enabled/disabled lists can't drift into a contradictory state. _plugin_exists delegates to the same resolver. - Fix NousResearch#41076 base breakages: _discover_all_plugins now returns 6-tuples, but web_server._merged_plugins_hub() still unpacked 5 (ValueError on the dashboard plugins-hub endpoint) and several test_plugins_cmd_list.py fixtures were still 5-tuples. Both updated; the hub status check is now key-aware. Verified e2e on the real CLI + runtime loader (isolated HERMES_HOME): `hermes plugins enable nemo_relay` writes observability/nemo_relay to config.yaml and the loader then loads it (enabled=True, error=None); a stale bare-name alias is cleared on disable; the dashboard _merged_plugins_hub() runs without crashing. Adds resolution + enable/disable tests; full tests/hermes_cli/test_plugins_cmd* + web_server plugin tests green. Follow-up to NousResearch#41076 (NousResearch#41066). Branched from that PR's head.
changman
pushed a commit
to changman/hermes-agent
that referenced
this pull request
Jun 10, 2026
…ins (follow-up to NousResearch#41076) NousResearch#41076 makes `hermes plugins list` discover nested category plugins (e.g. observability/nemo_relay). This adds the missing enable/disable mutation path so those plugins can actually be toggled, and fixes two incomplete-update breakages on the NousResearch#41076 base. Before: `hermes plugins enable nemo_relay` -> "Plugin 'nemo_relay' is not installed or bundled." (exit 1), because cmd_enable/cmd_disable went through _plugin_exists(), which only checked top-level plugins/<name>/. Changes: - Add _resolve_plugin_key(): resolve a bare manifest/leaf name OR a full path-derived key (observability/nemo_relay) to the canonical key the runtime loader gates on, reusing NousResearch#41076's _discover_all_plugins(). A bare leaf name ambiguous across two categories resolves to None rather than silently picking one. - cmd_enable/cmd_disable resolve first, persist the canonical key, and drop any stale legacy bare-name alias so the enabled/disabled lists can't drift into a contradictory state. _plugin_exists delegates to the same resolver. - Fix NousResearch#41076 base breakages: _discover_all_plugins now returns 6-tuples, but web_server._merged_plugins_hub() still unpacked 5 (ValueError on the dashboard plugins-hub endpoint) and several test_plugins_cmd_list.py fixtures were still 5-tuples. Both updated; the hub status check is now key-aware. Verified e2e on the real CLI + runtime loader (isolated HERMES_HOME): `hermes plugins enable nemo_relay` writes observability/nemo_relay to config.yaml and the loader then loads it (enabled=True, error=None); a stale bare-name alias is cleared on disable; the dashboard _merged_plugins_hub() runs without crashing. Adds resolution + enable/disable tests; full tests/hermes_cli/test_plugins_cmd* + web_server plugin tests green. Follow-up to NousResearch#41076 (NousResearch#41066). Branched from that PR's head.
alt-glitch
pushed a commit
that referenced
this pull request
Jun 14, 2026
…ins (follow-up to #41076) #41076 makes `hermes plugins list` discover nested category plugins (e.g. observability/nemo_relay). This adds the missing enable/disable mutation path so those plugins can actually be toggled, and fixes two incomplete-update breakages on the #41076 base. Before: `hermes plugins enable nemo_relay` -> "Plugin 'nemo_relay' is not installed or bundled." (exit 1), because cmd_enable/cmd_disable went through _plugin_exists(), which only checked top-level plugins/<name>/. Changes: - Add _resolve_plugin_key(): resolve a bare manifest/leaf name OR a full path-derived key (observability/nemo_relay) to the canonical key the runtime loader gates on, reusing #41076's _discover_all_plugins(). A bare leaf name ambiguous across two categories resolves to None rather than silently picking one. - cmd_enable/cmd_disable resolve first, persist the canonical key, and drop any stale legacy bare-name alias so the enabled/disabled lists can't drift into a contradictory state. _plugin_exists delegates to the same resolver. - Fix #41076 base breakages: _discover_all_plugins now returns 6-tuples, but web_server._merged_plugins_hub() still unpacked 5 (ValueError on the dashboard plugins-hub endpoint) and several test_plugins_cmd_list.py fixtures were still 5-tuples. Both updated; the hub status check is now key-aware. Verified e2e on the real CLI + runtime loader (isolated HERMES_HOME): `hermes plugins enable nemo_relay` writes observability/nemo_relay to config.yaml and the loader then loads it (enabled=True, error=None); a stale bare-name alias is cleared on disable; the dashboard _merged_plugins_hub() runs without crashing. Adds resolution + enable/disable tests; full tests/hermes_cli/test_plugins_cmd* + web_server plugin tests green. Follow-up to #41076 (#41066). Branched from that PR's head.
alt-glitch
pushed a commit
that referenced
this pull request
Jun 14, 2026
…ble/disable (#41066) Merge #42076: nested category plugin discovery + alias-normalized enable/disable (#41066) Lands the complete nested category plugin fix: - Discovery in `hermes plugins list` (from @islam666's #41076, carried in this PR) - Alias-normalized enable/disable mutation path so nested plugins can be toggled - Fixes the #41076 base breakages (web_server 6-tuple unpack + stale test fixtures) Co-authored work: discovery by @islam666 (#41076). Closes #41066.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Issue #41066:
hermes plugins listonly scans immediate subdirectories of~/.hermes/plugins/and the bundledplugins/directory. It does not recurse into nested category directories (web/tavily,image_gen/openai,browser/browser_use, etc.).This means 12+ bundled category plugins are invisible to the CLI listing, even though they load correctly at runtime via
PluginManager._scan_directory_level().Additionally,
_plugin_status()only checks the manifestnameagainst enabled/disabled sets, but for category plugins the config key is path-derived (e.g.web/tavily) while the manifest name differs (e.g.web-tavily). This causes enabled category plugins to show as "not enabled".Root Cause
Two separate code paths implement plugin discovery:
PluginManager._scan_directory_level()_discover_all_plugins()Fix
_discover_all_plugins(): Replaced flatiterdir()loop with a recursive_scan_level()helper that mirrorsPluginManager._scan_directory_level()— recurses into directories withoutplugin.yamlup to 2 levels deep, computing the path-derived key with the accumulated prefix._plugin_status(): Added optionalkeyparameter. Now checks both manifestnameAND path-derivedkeyagainst the enabled/disabled sets.All callers updated:
_filter_plugin_entries,cmd_list(JSON, plain, table paths),cmd_toggle,dashboard_remove_user_plugin— all now pass the 6-tuple with key.Testing
tests/hermes_cli/test_plugins_cmd_category_discovery.py_read_manifest_info: flat, category, no manifest, .yml extension_discover_all_plugins: flat, category, mixed, depth cap, 6-tuple, user overrides bundled_plugin_status: name/key in enabled/disabled, precedence_filter_plugin_entries: key-aware enabled filtercmd_listJSON: category plugins included, status uses keytest_plugins_cmd.pytests pass (0 regressions)test_plugins.pytests pass (0 regressions)Fixes #41066