Skip to content

fix(plugins): register deferred platform client tools at discovery (#78050) - #78842

Closed
thelonewander3r wants to merge 1 commit into
NousResearch:mainfrom
thelonewander3r:fix/a2a-client-toolset-deferred-registration
Closed

fix(plugins): register deferred platform client tools at discovery (#78050)#78842
thelonewander3r wants to merge 1 commit into
NousResearch:mainfrom
thelonewander3r:fix/a2a-client-toolset-deferred-registration

Conversation

@thelonewander3r

Copy link
Copy Markdown
Contributor

What does this PR do?

Fixes #78050 — the five 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's toolset, while the same tools work in web/dashboard sessions on the same install.

Root cause

A bundled kind: platform plugin is registered as a deferred loader (_register_deferred_platform, hermes_cli/plugins.py) so hermes chat doesn't pay ~20 platform-SDK imports. That deferral is correct and worth keeping.

The problem is that the a2a plugin ships two independent things behind that one deferral, and its own register() says so:

def register(ctx) -> None:
    # 1) Client tools (outbound). Registering these even when the inbound
    #    platform is disabled lets the agent call peers without exposing itself.
    from .tools import register_tools
    register_tools(ctx)

    # 2) Inbound platform adapter.
    from .adapter import A2AAdapter
    ctx.register_platform(...)

Deferring the plugin defers both. In a CLI/TUI process the module never imports, so register_tools() never runs:

  • resolve_toolset("a2a")[] (the toolset is registry-derived and absent from static TOOLSETS)
  • a2a is missing from _get_effective_configurable_toolsets(), so the hermes tools checklist has nothing to tick
  • resolve_toolset("hermes-a2a") returns core tools but drops a2a's own tools — the bundle path reads the tool registry behind a deliberately cheap is_registered() check that doesn't materialize the platform

Gateway and web-server processes call platform_registry.plugin_entries() / all_entries() at startup, which fires _resolve_all() and imports the module. That is the entire reason the tools exist there and not in the TUI.

a2a sits in _DEFAULT_OFF_TOOLSETS next to homeassistant, spotify, video_gen and x_search. The comment above that set describes the intended contract — "Users who want it opt in via hermes tools". Every other member honours it; a2a was the sole outlier:

toolset          in TOOLSETS  in `hermes tools`  resolves to N tools
----------------------------------------------------------------------
a2a              False        False              0      <-- before
discord          True         True               1
discord_admin    True         True               1
homeassistant    True         True               4
spotify          True         True               7
video            True         True               1
video_gen        True         True               3
x_search         True         True               1

The fix

Client tools that live in a dedicated tools submodule are registered at discovery time. Importing <plugin>/tools.py does not import the adapter, so the platform SDK stays unloaded and the deferral keeps doing its job.

This is the second shape the issue suggested ("registering client tools at discovery time independent of the platform adapter"), and it fixes every facet in one place rather than patching resolve_toolset, the checklist, and the config-expansion path separately.

Two supporting details keep the pre-import invisible:

  • _load_plugin reuses the already-imported package instead of executing its body a second time when the adapter is later materialized.
  • Tools registered at discovery are credited back to the plugin, so hermes plugins list attribution survives materialization (_load_plugin attributes tools by diffing the registry around register(), and pre-registered tools are already in the "before" snapshot).

a2a is currently the only platform plugin with a tools.py. Plugins without one are untouched and stay fully deferred; an import error in tools.py is caught and degrades to today's behaviour.

Cost

The deferral invariant is intact — measured on this branch:

main this PR
discover_plugins() 615 ms 618 ms
heavy platform SDKs imported none none
platforms still deferred 22 22
resolve_toolset("a2a") 0 tools 5 tools

For reference, the blanket alternative (_resolve_all() in the toolset/checklist path) costs 862 ms — that's what this avoids.

How to test

Reproduce on main in a plain CLI process (no gateway):

python -c "
from hermes_cli.plugins import discover_plugins; discover_plugins()
from toolsets import resolve_toolset
print('a2a toolset:', resolve_toolset('a2a'))
from hermes_cli.tools_config import _get_effective_configurable_toolsets
print('in hermes tools:', 'a2a' in {e[0] for e in _get_effective_configurable_toolsets()})
"

main prints a2a toolset: [] / in hermes tools: False. This branch prints all five tools and True, while the plugin stays deferred=True.

New regression tests:

scripts/run_tests.sh tests/hermes_cli/test_deferred_platform_client_tools.py -q

They cover the reported symptom against the real a2a plugin (toolset resolves, checklist entry appears, hermes-a2a bundle includes the tools, adapter stays deferred) and the general mechanism with a synthetic platform plugin (adapter not imported, plugins without tools.py unchanged, package body executes exactly once across discovery + materialization, attribution preserved, broken tools.py doesn't break discovery). 6 of the 8 fail on main; the 2 that pass either way are the negative controls.

Test results

  • New file: 8 passed.
  • tests/hermes_cli/test_plugins.py, test_plugins_cmd_list.py, test_plugin_cli_registration.py, test_startup_plugin_gating.py, test_plugin_auxiliary_tasks.py, test_plugins_tts_registration.py, test_plugins_transcription_registration.py, test_plugins_hub_perf_guard.py, tests/test_toolsets.py — 89 passed.
  • Broader tests/hermes_cli/ sweep shows no new failures: the 6 that fail here (test_plugins_cmd.py::TestResolveSubdirWithin::test_rejects_symlink_escape, TestNoAutoActivation::test_compressor_default_ignores_plugin, test_codex_runtime_plugin_migration.py, 3× test_plugin_runtime_disable_gate.py) fail identically on unmodified main — Windows symlink-privilege and cp1252-decode environment issues, unrelated to this change.

Platform tested: Windows 11, Python 3.11.15. The mechanism is platform-independent (plugin discovery + import), and the change touches no file I/O, process management, or path handling beyond an is_file() existence check.

Relationship to #57063

Open PR #57063 describes the same class of problem for eight other platforms, but it is about hermes-<platform> inbound bundles — resolve_toolset("hermes-a2a") already returns core tools today. This issue is the separate outbound a2a client toolset, which merged in #77109 a month after that PR was last touched (2026-07-15) and is not covered by it. That review thread also pushed back on requiring a static toolsets.py bundle for every platform plugin; this PR deliberately takes the registry-aware route instead.

🤖 Generated with Claude Code

@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
@alt-glitch

Copy link
Copy Markdown
Collaborator

This was generated by AI during triage.

Related: #78538 also fixes #78050 by eagerly loading platform plugins that declare tools. This PR preserves adapter deferral by pre-registering only the tools submodule; maintainers should choose the preferred loading contract.

@thelonewander3r

Copy link
Copy Markdown
Contributor Author

Flagging that #78538 targets the same issue — agreeing on the loading contract seems more useful than two competing shapes.

On cost, in fairness to #78538: I measured the marginal adapter import at ~17 ms in a realistic startup (612 ms discovery → 629 ms). That's small, and not a reason to prefer this PR.

The distinction is the contract for future plugins. #78538's rule is "declares tools → eager-load the whole plugin." a2a's adapter is stdlib-only so that's nearly free today, but a platform plugin shipping client tools alongside a heavy SDK would import that SDK on every hermes invocation. This PR keeps the halves separable.

Suggested hybrid: use #78538's provides_tools manifest field as the trigger — explicit beats a magic tools.py filename — but import only the tools submodule rather than calling _load_plugin(). Happy to rework this PR that way, or fold it into #78538.

@cadamec

cadamec commented Aug 5, 2026

Copy link
Copy Markdown

Hey — I'm the author of #79432, which was flagged as overlapping this one. Fully agree the loading contract question should settle on one shape, so I've split my PR to be a2a-only and I'm standing down on the mechanism itself.

What I'd offer into whichever PR wins (yours or #78538):

  1. Module reuse — the package module imported at discovery time gets reused when the deferred adapter later materializes, so the package body doesn't execute twice. Small but real: for a2a the body is light, but any future platform taking this path would pay double-import.
  2. Tool attribution — discovery-time registrations are credited to the deferred placeholder, so hermes plugins list shows the a2a tools in CLI processes (currently it shows none) and attribution survives the full load.
  3. Lifecycle tests — 7 tests covering CLI visibility, hermes tools checklist presence, adapter-laziness (the deferral contract), and gateway materialization. Happy to paste them into either PR.

Also: my PR adds provides_tools to a2a's plugin.yaml as the explicit trigger (the #78538 side of the hybrid). If the two of you land on eager-loading instead, that field still serves as documentation of intent.

No hard feelings either way — if you'd rather I close #79432 so the field is clear, say the word. Goal is the fix landing.

@alt-glitch alt-glitch added comp/tui Terminal UI (ui-tui/ + tui_gateway/) needs-decision Awaiting maintainer decision before any implementation labels Aug 5, 2026
@thelonewander3r

Copy link
Copy Markdown
Contributor Author

Appreciated — standing down on a mechanism you'd already built is the least fun thing to do in this situation, and it's the right call for getting #78050 closed. Taking you up on the offer, with one correction and one genuine addition.

On pieces 1–3: this PR already has them. I think the comparison was against #78538 — that's accurate there, but not here. Concretely, in hermes_cli/plugins.py:

  • Module reuseself._predeclared_modules is populated in _register_deferred_platform_tools and consumed in _load_plugin via the preloaded branch, which bypasses re-import when the gateway materializes the adapter.
  • Tool attributionself._predeclared_tools, credited back in _load_plugin. The diff around register() would otherwise under-report them, since discovery-time registrations are already in the _tools_before snapshot.
  • Lifecycle tests — your four categories map onto existing tests: test_a2a_toolset_resolves_without_materializing_the_platform (CLI visibility), test_a2a_appears_in_the_hermes_tools_checklist (checklist), test_tools_module_registers_without_importing_the_adapter (adapter laziness), test_package_body_runs_once_across_discovery_and_materialization (gateway materialization), plus test_tools_stay_attributed_after_materialization, test_plugin_without_tools_module_stays_fully_deferred and test_broken_tools_module_does_not_break_discovery.

Not a turf point — two people independently landing on module reuse and attribution as the two things that need handling is decent evidence the shape is right.

The provides_tools trigger was the real gap, and it's now in (8f94efb). You were right that it belongs regardless of which PR wins. This branch was keying 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. provides_tools is already infrastructure for exactly this question (declared on PluginManifest at plugins.py:289, parsed at :1660, read by hermes plugins list at plugins_cmd.py:1855 and web_server.py:16863), so reusing it beats a filesystem probe.

So the trigger is now the manifest field and tools.py is only where the code is imported from. a2a's plugin.yaml declares the five tools, and two tests came with it: test_tools_module_alone_does_not_opt_a_platform_in (a tools.py with no declaration imports nothing — the negative case the probe couldn't express) and test_manifest_declares_the_client_tools (dropping the block would silently revert a2a to #78050 while every synthetic-plugin test kept passing).

Credit for the field goes to @Tranquil-Flow in #78538 — this is their half of the hybrid, and it's the better signal.

On closing #79432 — yes please, if you're still happy to. With the trigger adopted here, all three PRs now point at one shape, and that's the most useful thing a maintainer can walk into. Same offer in reverse: if they prefer #78538's eager-load contract instead, I'll close this one and the module-reuse/attribution pieces should be folded there, because #78538 genuinely does lack them.

Thanks for splitting out #79479 too — that one stands on its own.

@cadamec

cadamec commented Aug 6, 2026

Copy link
Copy Markdown

Validated this PR on Linux (Fedora 44, Python 3.11.15) in a clean worktree with its own venv and editable install — your live install was not touched.

Results:

  • test_deferred_platform_client_tools.py10/10 passed (0.6s)
  • Regression sweep test_plugins.py, test_plugins_cmd_list.py, test_plugin_cli_registration.py, test_toolsets.py65/65 passed
  • TestA2AClientToolsInCliProcess (the exact CLI-process repro, against the real a2a plugin): resolve_toolset("a2a") returns all five tools, a2a appears in the hermes tools checklist, the hermes-a2a bundle includes the tools, and a2a.deferred stays True — i.e. the adapter is not imported in a CLI process. Confirms the deferral invariant holds on Linux.

This corroborates the macOS / Windows 11 / NixOS reproductions from the thread. Confirms the fix is platform-independent in practice as claimed.

Two minor notes:

  1. The runner discovered 10 tests, not the 8 mentioned in the PR body — no failing difference, just a count to update if you care.
  2. Still showing no CI on the branch (fork workflows unapproved). Since this now has positive validation on four OSes, worth asking a maintainer to approve the checks.

Happy to test the final merged version against a live cross-host A2A link once it lands.

@thelonewander3r
thelonewander3r force-pushed the fix/a2a-client-toolset-deferred-registration branch from fb97ec5 to 76c9602 Compare August 6, 2026 16:13
@cadamec

cadamec commented Aug 6, 2026

Copy link
Copy Markdown

Re-validated the latest head (76c96029, the "diagnosable failure" follow-up) on Linux (Fedora 44, Python 3.11.15) in a clean worktree with its own venv — live install untouched.

Results:

  • test_deferred_platform_client_tools.py11/11 passed (0.6s), including the new test_declared_tools_with_no_tools_module_warns and the strengthened test_broken_tools_module_does_not_break_discovery (now asserts the degraded state is visible at WARNING, not silent).
  • Regression sweep test_plugins.py, test_plugins_cmd_list.py, test_plugin_cli_registration.py, test_toolsets.py65/65 passed.

The diagnosable-failure change is a good catch — a silent failure here would have reproduced the exact #78050 symptom with no thread to pull on. Confirmed clean on Linux alongside the earlier macOS / Windows 11 / NixOS reproductions.

Still no CI on the branch (fork workflows unapproved). With positive validation on four OSes across two commits, worth asking a maintainer to approve the checks.

@monerostar monerostar left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Native Win11 check (monerostar) — still needed on this box

Host: Windows 11 build 26200 · tech profile · install %LOCALAPPDATA%\hermes\hermes-agent
PR tip: 76c960296

Gap still on main

  • plugins/platforms/a2a/plugin.yaml has no provides_tools
  • PluginManager has no _register_deferred_platform_tools
  • hermes -p tech tools lista2a count 0 (peers are configured under a2a_agents; inbound gateway works; CLI/TUI outbound client tools do not show up)

So issue #78050 is still live here: deferred platform plugin never registers the five client tools outside a gateway process.

PR

Opt-in is explicit (provides_tools on the a2a manifest) + discovery imports only tools.py for those names. Inbound adapter stays deferred.

pytest tests/hermes_cli/test_deferred_platform_client_tools.py -o addopts=
# 11 passed

Includes checklist coverage that a2a appears in the hermes tools list path without materializing the heavy platform adapter.

Looks good. This is the PR that matches how we actually use A2A from desktop/CLI on a multi-host fleet.

@thelonewander3r

Copy link
Copy Markdown
Contributor Author

Thanks @monerostar — that's a genuinely useful review, and not only because it's positive.

Your run is currently the only execution of this code by anyone but me. No CI has fired on this branch: it's from an outside-contributor fork, so the workflows need a maintainer to approve them before any checks execute. The PR shows zero checks for that reason, not because something failed. So a native Win11 run on a different install, against 76c960296 (the exact tip at the time), is the closest thing to independent verification this has — worth stating plainly for whoever picks it up.

The two things you confirmed that matter most:

Since your review I've pushed 95144b42e, closing the last open item from a separate review pass: register_tools is not transactional, so one that registered a tool and then raised left it live in the registry but attributed to nobody — hermes plugins list under-reported, and _load_plugin couldn't recover it later either since by then it sits inside its own _tools_before snapshot. The failure path now credits whatever survived, and the warning says how many of the declared tools made it. Test count is 12 (was 11 when you ran it); a full discover_and_load() still emits no warnings and resolves a2a's five tools with the adapter deferred.

Also worth recording here: #79432 was closed by its author in favour of this PR, and #78538's provides_tools trigger was adopted into it — credit to @Tranquil-Flow for that field, which is a better signal than the filesystem probe this branch originally used. So all three PRs on #78050 now point at one shape.

@cadamec

cadamec commented Aug 10, 2026

Copy link
Copy Markdown

Re-validated the latest head (6543f9127, the two attribution-follow-up commits) on Linux (Fedora 44, Python 3.11.15) in a clean worktree with its own venv — live install untouched.

Results:

  • test_deferred_platform_client_tools.py13/13 passed (0.7s), up from 11/11 — the new attribution tests for partially-failed register_tools and post-materialization tool naming are covered and green.
  • Regression sweep (test_plugins.py, test_plugins_cmd_list.py, test_plugin_cli_registration.py, test_toolset_validation.py) — 45/45 passed.

The _predeclared_modules / _predeclared_tools bookkeeping is a clean way to keep hermes plugins list attribution honest when the adapter materializes later — and the snapshot-before/after diff for partial failures is exactly the right diagnostic shape. Still no CI on the branch (fork workflows need maintainer approval), so this remains the only independent execution besides the author's.

@thelonewander3r

Copy link
Copy Markdown
Contributor Author

Changed since @monerostar's review

That review was against 76c960296; head is now 6543f9127. Two commits, both from a follow-up review pass, both in the same narrow area — nothing about the fix's shape, the provides_tools trigger, or the a2a manifest has moved. The behaviour monerostar verified on Win11 is unchanged.

hermes_cli/plugins.py +47/-3, tests +69. Test file: 11 → 13.

95144b42e — attribute tools a partially-failed register_tools left behind

register_tools is not transactional. One that registered a tool and then raised left it live in the registry but owned by nobody: hermes plugins list under-reported, and _load_plugin could not recover it later either, because by then those tools sit inside its own _tools_before snapshot and drop out of the diff. The before snapshot moved above the try so the failure path can name what survived.

6543f9127 — keep that attribution when materialization also fails

The first commit only closed half the bug class. _load_plugin merges _predeclared_tools after register_fn(ctx) returns — so when register() raises, or the module has none, a fresh LoadedPlugin with an empty tools_registered replaced the deferred entry that had been crediting them, while the tools stayed live in the registry. Same orphaning, one path over. Both failure paths now carry the attribution across before the entry is replaced.

enabled deliberately stays False with the error intact. The adapter really did not load; the honest state is "failed, but these tools are live" rather than either half alone.

Worth being explicit that a2a is unaffected by both — its own register() catches register_tools failures, so neither path is reachable for it today. This is the contract for the next platform plugin that takes this route.

The warning text also stopped overstating: it said "the rest will be missing" even when nothing had registered (there is no rest) or when everything had (nothing is missing). It now names where the failure landed — before any registration, after N of M, or after all of them — which is what points at the import, one tool's definition, or past the registrations.

Verification

The new materialization test was checked against a reverted production change: it fails without the fix and passes with it, so it pins the behaviour rather than passing vacuously.

  • tests/hermes_cli/test_deferred_platform_client_tools.py — 13 passed
  • tests/plugins/ — identical to the pre-change baseline
  • A real discover_and_load() still emits no warnings and resolves a2a's five tools with the adapter deferred

Standing caveat unchanged: no CI has run on this branch, so monerostar's Win11 run remains the only execution of this code by anyone but me — and it now predates the head by these two commits.

…ousResearch#78050)

Rebased onto current main. `hermes_cli/plugins.py` grew 103KB -> 265KB
across 49 commits since the original branch point, and the attribution
mechanism this change hooks into was replaced along the way: the
`_tools_before` / `_plugin_tool_names` snapshot diff is now a
registration ledger sliced from `registration_start`, and `_plugin_id`
is `plugin_key`.

Re-anchored accordingly:

- Discovery-time pre-registration, module reuse, and the `provides_tools`
  opt-in are unchanged.
- Attribution credits `_predeclared_tools` ahead of the ledger slice,
  since those tools registered before `registration_start` and the slice
  cannot see them.
- A failed materialization no longer carries attribution across. The
  failure path now sweeps the whole ownership ledger for the plugin key,
  not just the `registration_start:` slice, so the pre-registered tools
  are disposed along with the adapter. Attribution and the registry now
  agree at zero instead of reporting tools the process is not serving.

tests/hermes_cli/test_deferred_platform_client_tools.py 13/13.
test_plugins.py, test_plugins_cmd_list.py, test_plugin_cli_registration.py
65/65.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@thelonewander3r
thelonewander3r force-pushed the fix/a2a-client-toolset-deferred-registration branch from 6543f91 to 22b4da5 Compare August 14, 2026 14:47
@thelonewander3r

Copy link
Copy Markdown
Contributor Author

Rebased onto current main — force-pushed

Heads up @cadamec @monerostar: the branch has been rebuilt from current main, so 76c960296 and 6543f9127 are no longer on it. Head is now 22b4da5ab. Your reviews cite SHAs that have been replaced, and one behaviour you validated has deliberately changed — details below.

Why. The PR went CONFLICTING. hermes_cli/plugins.py grew from 103KB to 265KB across 49 commits since the branch point, and the attribution mechanism this change hooks into was replaced along the way.

What did not change. The shape is intact: provides_tools on the a2a manifest as the explicit opt-in, discovery importing only tools.py, and the inbound adapter staying deferred. The manifest diff applied byte-clean, and the test file is untouched apart from the one case below. The deferral invariant monerostar verified on Win11 is unaffected.

What had to be re-anchored.

  • _tools_before no longer exists. _load_plugin_scoped now attributes tools through a registration ledger sliced from registration_start, so the predeclared credit is expressed in ledger terms: discovery-time tools register before registration_start, the slice cannot see them, and they are prepended explicitly.
  • _plugin_id is now plugin_key. Worth flagging that one of those three references sat outside every conflict region and applied cleanly — it would have shipped as a runtime NameError in the failure path with nothing marking it.

One deliberate behaviour change. _load_plugin_scoped's failure path now sweeps the whole ownership ledger for the plugin key — not the registration_start: slice — and disposes it. A failed adapter materialization therefore takes the discovery-time client tools down with it. The old _still_live carry-across is dead code as a result, and test_attribution_survives_a_materialization_that_also_fails is now test_failed_materialization_tears_down_pre_registered_tools, asserting that the registry and attribution agree at zero.

I took that route rather than exempting pre-registrations from the sweep, on the grounds that arguing against a fresh upstream invariant is a bigger ask than this PR needs. The counter-argument is real though, and I would rather a maintainer make the call: those client tools work without the adapter — that is the entire point of #78050 — so wiping them when the adapter fails makes that path worse than the adapter-never-materializes path, which is the common CLI case. Happy to switch if that is preferred.

Tests. test_deferred_platform_client_tools.py 13/13. test_plugins.py, test_plugins_cmd_list.py, test_plugin_cli_registration.py 65/65. That is three of the four suites from the earlier sweeps rather than all four, and CI still has not run — the workflows remain gated at action_required.

Apologies that this invalidates the SHAs you both tested against. Re-validation would be welcome, but genuinely no obligation.

teknium1 pushed a commit that referenced this pull request Aug 15, 2026
…t_platform_tools (#81163)

Layer 2 of the #81163 / #78050 fix: _get_platform_tools computed
plugin_ts_keys = _get_plugin_toolset_keys() but only used
CONFIGURABLE_TOOLSETS in the explicit-config filter, so a user-listed
plugin key like `a2a` in `platform_toolsets.cli: [hermes-cli, a2a]` was
silently dropped. The filter now unions configurable and plugin toolset
keys when evaluating has_explicit_config and when admitting per-key
entries.

Cherry-picked from PR #81190 (Layer 2 hunks only; Layer 1 is covered by
the provides_tools mechanism from PR #78842).
@teknium1

Copy link
Copy Markdown
Contributor

Merged via PR #86660 (#86660). Your commit — discovery-time client-tool registration behind the provides_tools manifest opt-in — was cherry-picked as the Layer 1 carrier with your authorship preserved in git history, including your rebase re-anchoring onto the registration-ledger attribution. Credit also to @Tranquil-Flow for the manifest field (#78538). Thanks for driving the convergence on #78050!

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 comp/tui Terminal UI (ui-tui/ + tui_gateway/) needs-decision Awaiting maintainer decision before any implementation 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.

A2A client tools invisible to CLI/TUI sessions — deferred platform plugin never registers its toolset outside gateway processes

5 participants