Skip to content

fix(plugins): eagerly load platform plugins that declare provides_tools (#78050) - #78538

Closed
Tranquil-Flow wants to merge 1 commit into
NousResearch:mainfrom
Tranquil-Flow:fix/78050-a2a-tools-cli
Closed

fix(plugins): eagerly load platform plugins that declare provides_tools (#78050)#78538
Tranquil-Flow wants to merge 1 commit into
NousResearch:mainfrom
Tranquil-Flow:fix/78050-a2a-tools-cli

Conversation

@Tranquil-Flow

Copy link
Copy Markdown
Contributor

What

A2A client tools (a2a_call, a2a_discover, a2a_list, a2a_history,
a2a_orchestrate) are invisible to CLI/TUI sessions — they never appear in
hermes tools, cannot be opted into, and are absent from the session toolset.
The same tools work correctly in gateway/web/dashboard sessions.

Root cause

The a2a plugin is kind: platform, and all bundled platform plugins are
deferred by design to avoid importing ~20 heavy platform SDKs on every
hermes invocation. Deferred plugins are never imported in CLI/TUI processes,
so register() never fires and the five outbound client tools never register.
resolve_toolset('a2a') returns [], making the opt-in path
unreachable.

The a2a plugin is unique: it ships both an inbound platform adapter and
five lightweight outbound agent tools (stdlib-only, no SDK dependency). The
deferral was designed for heavy inbound adapters, not lightweight outbound tools.

Fix

Reuse the existing provides_tools manifest field (already used in
web_server.py and plugins_cmd.py) as the signal for eager loading:

  • plugins/platforms/a2a/plugin.yaml: declare provides_tools with the
    five tool names.
  • hermes_cli/plugins.py: a bundled platform plugin with non-empty
    provides_tools eagerly loads via _load_plugin() instead of deferring.
    Pure inbound adapters leave provides_tools empty → stay deferred → no
    regression.

Only a2a declares provides_tools; all 21 other platform plugins remain
deferred.

Verification

  • RED: Without the plugins.py change (plugin.yaml applied, production logic
    reverted), the eager-load and toolset-resolution tests fail — plugin is
    deferred, tools unregistered, resolve_toolset('a2a') returns [].
  • GREEN: With the fix, all 5 regression tests pass.
  • Full a2a suite: 121/121 pass.
  • Full plugins suite: 1325 pass, 1 pre-existing cross-file isolation
    failure (test_path_routed_agent_card_uses_prefix_and_canonical_path
    confirmed pre-existing on upstream/main), 1 skipped.

Test coverage

5 new regression tests in TestA2APluginEagerToolRegistration:

  1. a2a plugin eagerly loaded (not deferred)
  2. manifest declares the five provides_tools
  3. all five tools registered after discovery
  4. resolve_toolset('a2a') resolves to the five tools
  5. pure inbound adapter (telegram) stays deferred — negative case

Auto-published by Moonsong via Path B automated pipeline.

…ls (NousResearch#78050)

A platform plugin that also provides outbound agent tools (declared via
provides_tools in plugin.yaml) must load eagerly so those tools are
visible in CLI/TUI sessions, not only in gateway/web processes where the
deferred platform loader fires. Without this, the a2a toolset is in
_DEFAULT_OFF_TOOLSETS (opt-in) but the opt-in UI (hermes tools) never
shows it because no tools are registered — resolve_toolset('a2a')
returns []. Pure inbound adapters (telegram, discord, ...) leave
provides_tools empty and stay deferred to avoid importing ~20 heavy
platform SDKs on every CLI start.
@alt-glitch alt-glitch added type/bug Something isn't working P3 Low — cosmetic, nice to have comp/cli CLI entry point, hermes_cli/, setup wizard comp/plugins Plugin system and bundled plugins labels Aug 4, 2026
@thelonewander3r

Copy link
Copy Markdown
Contributor

Heads-up @Tranquil-Flow — your provides_tools trigger was adopted in #78842 (commit 8f94efb).

That PR was keying discovery-time tool registration off the presence of <plugin>/tools.py, which opts a plugin in by accident (a platform is free to keep internal helpers in a file of that name) and leaves the contract invisible to anyone reading the manifest. Your signal is the better one, and the field already being read by hermes plugins list (plugins_cmd.py:1855) and the web server (web_server.py:16863) made reusing it the obvious call rather than inventing a probe. Credit where it's due.

#79432 was closed today by its author for the same reason, so #78842 now carries all three shapes: your manifest trigger, tools-submodule-only import so the adapter stays deferred, and module-reuse/attribution handling so the package body doesn't execute twice and hermes plugins list still attributes the tools after materialization.

Genuinely happy to close mine instead if you'd rather drive this one — the module-reuse and attribution pieces are small and I'd hand them over. But if you're content with the field landing there, closing this would leave a single PR in front of maintainers, which is the main thing #78050 needs at this point.

One unrelated note while you're here: this PR's body doesn't reference #78050 (only the title does), and GitHub builds cross-links from bodies and comments rather than titles — so it isn't linked from the issue and won't show up for anyone triaging from there.

@teknium1

Copy link
Copy Markdown
Contributor

Merged via PR #86660 (#86660). Your provides_tools manifest mechanism is the opt-in trigger for the discovery-time registration that landed (carried in #78842's commit, as the issue thread converged). Credited in the PR body — thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/cli CLI entry point, hermes_cli/, setup wizard comp/plugins Plugin system and bundled plugins P3 Low — cosmetic, nice to have type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants