Skip to content

feat(tool-search): support opt-in built-in toolset deferral - #45147

Open
SJG613 wants to merge 2 commits into
NousResearch:mainfrom
SJG613:feature/tool-suitcases
Open

feat(tool-search): support opt-in built-in toolset deferral#45147
SJG613 wants to merge 2 commits into
NousResearch:mainfrom
SJG613:feature/tool-suitcases

Conversation

@SJG613

@SJG613 SJG613 commented Jun 12, 2026

Copy link
Copy Markdown

What does this PR do?

Adds opt-in “tool suitcases” for built-in Hermes toolsets.

Hermes already supports progressive disclosure for MCP/plugin tools through the stable bridge:

  • tool_search
  • tool_describe
  • tool_call

This PR extends that pattern so selected built-in toolsets can also be deferred behind the bridge when explicitly configured.

This reduces always-visible tool schema size for long-running sessions without mutating provider-visible tools mid-conversation.

Type of Change

  • ✨ New feature
  • 📝 Documentation update
  • ✅ Tests

Changes Made

  • Added defer_builtin_toolsets config for Tool Search.
  • Added never_defer_tools escape hatch for individual high-frequency tools.
  • Preserved default behavior: built-in tools still load directly unless explicitly opted in.
  • Kept bridge catalog scoped to the session’s enabled toolsets.
  • Ensured tool_search, tool_describe, and tool_call can resolve opted-in built-in tools.
  • Updated Tool Search docs with config examples and safety notes.
  • Added tests for default behavior, opt-in built-in deferral, escape hatch behavior, and bridge invocation.

Example

yaml
tools:
tool_search:
enabled: on
defer_builtin_toolsets:
- browser
- image_gen
- tts
never_defer_tools:
- browser_navigate

Why This Helps

Long-running Hermes sessions can accumulate many enabled tools. Their schemas are included in the model-visible tool list on every turn, even when only a few tools are relevant.

In one measured configuration:

  • Before: ~61 KB / 35 visible tools
  • After: ~36–37 KB / 16 visible tools
  • Saved: ~24 KB per model call

This is especially useful for gateway sessions and broad personal-agent profiles where rarely used capabilities should remain available but not constantly occupy the active prompt.

How to Test

Targeted tests run locally:
bash
venv/bin/python -m pytest tests/tools/test_tool_search.py tests/test_get_tool_definitions_cache_isolation.py -q
Result:
text
50 passed, 1 warning
Full suite not run locally.

Safety / Compatibility

  • Default behavior is unchanged.
  • Built-in tool deferral is explicit opt-in only.
  • No provider-visible tool schema mutation is required mid-conversation.
  • The bridge catalog remains scoped to the session’s enabled tools.
  • Hooks, guardrails, approvals, and activity display still unwrap to the underlying tool name.

Credit / Origin

Originated from Steven Geller (@SJG613) during a long-running Hermes/Matt Telegram session.

The user-facing abstraction was “tool suitcases”: keep capability bundles packed until needed, use the right suitcase through a stable bridge, and avoid spreading every tool schema across the active context on every turn.

@SJG613 SJG613 changed the title Feature/tool suitcases feat(tool-search): support opt-in built-in toolset deferral Jun 12, 2026
@SJG613

SJG613 commented Jun 12, 2026

Copy link
Copy Markdown
Author

Note: I’m a first-time contributor, so the required workflows appear to be awaiting maintainer approval.

@alt-glitch alt-glitch added type/feature New feature or request comp/tools Tool registry, model_tools, toolsets P3 Low — cosmetic, nice to have duplicate This issue or pull request already exists labels Jun 12, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

Duplicate of #43521 — config-gated built-in toolset deferral via the tool_search bridge is the same approach there (earliest open canonical for built-in deferral). Distinct from the core-tool-deferral cluster (#42551/#41800). Consolidating under #43521.

@SJG613

SJG613 commented Jun 12, 2026

Copy link
Copy Markdown
Author

Thanks — understood. I didn’t realize #43521 was already the canonical thread for config-gated built-in toolset deferral.

Happy to close this PR if maintainers prefer consolidation there. If useful, this branch includes a small tested implementation, docs updates, and local measurements from a long-running gateway session:

  • targeted tests: 50 passed, 1 warning
  • measured visible schema reduction from ~61 KB / 35 tools to ~36–37 KB / 16 tools in one opt-in config
  • implementation keeps built-in deferral explicit opt-in and preserves the stable tool_search / tool_describe / tool_call bridge

Feel free to reuse any wording, tests, docs, measurements, or implementation details from this PR in #43521.

@teknium1 teknium1 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.

Thanks for the focused implementation and documentation. The core approach matches the canonical #43521 discussion, but this branch needs an agent-runtime safety pass before it can be salvaged.

Problems

  • tools/tool_search.py:235-236 permits any configured core-toolset member to defer. That includes memory and session_search; however, current agent/agent_init.py:1196-1198 builds valid_tool_names from the post-assembly schemas, and agent/system_prompt.py:221-225 / agent/turn_context.py:309 use that set to enable their guidance and memory nudge behavior.
  • Current bridge execution also unwraps calls in both executor paths (agent/tool_executor.py:403-405, :1077-1079), in addition to direct dispatch. The PR's three-file scope predates those paths and does not exercise them.

Suggested changes

  • Consolidate the implementation into #43521 with a protected always-direct runtime floor, or carry a distinct available-tool set through prompt construction.
  • Add real agent/executor coverage for deferred memory and session-search tools.

Automated hermes-sweeper review.

Comment thread tools/tool_search.py
toolsets = _registered_toolsets_for_tool(name)

if name in _core_tool_names():
return bool(toolsets & cfg.defer_builtin_toolsets)

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.

This makes every core tool in a configured toolset deferrable, including memory and session_search. Current agent/agent_init.py:1196-1198 derives valid_tool_names from the post-assembly schemas, while agent/system_prompt.py:221-225 and agent/turn_context.py:309 gate their guidance/nudge behavior on that set. Please retain a protected runtime-tool floor or preserve an available-tool set for those gates.

@teknium1 teknium1 added sweeper:risk-caching Sweeper risk: may break/degrade prompt caching or cache-key stability (invariant) sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:blast-contained Sweeper blast radius: contained — one narrow path / opt-in / few users labels Jul 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/tools Tool registry, model_tools, toolsets duplicate This issue or pull request already exists P3 Low — cosmetic, nice to have sweeper:blast-contained Sweeper blast radius: contained — one narrow path / opt-in / few users sweeper:risk-caching Sweeper risk: may break/degrade prompt caching or cache-key stability (invariant) sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants