Skip to content

feat(tools): add consult tool — second opinion from a reference model - #82103

Open
adurham wants to merge 1 commit into
NousResearch:mainfrom
adurham:upstream-pr/consult-tool
Open

feat(tools): add consult tool — second opinion from a reference model#82103
adurham wants to merge 1 commit into
NousResearch:mainfrom
adurham:upstream-pr/consult-tool

Conversation

@adurham

@adurham adurham commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Summary

Lets the agent (main or delegated subagent) ask a configurable reference model for a second opinion on a specific, bounded question before committing to something risky or uncertain — sanity-check a plan, review a diff for structural issues, or get a pointed answer on a genuinely uncertain judgment call. Not for routine work; it costs one full call to a (usually more expensive, sometimes slower) model.

Routes through the existing agent.auxiliary_client.call_llm plumbing with task="consult", configured via auxiliary.consult in config.yaml independently of the main chat model — the canonical use case is pointing it at an expensive frontier model that would make a bad MAIN model (slow, prone to over-cautious refusals) but is a great second opinion for a narrow question.

Design

A plain registry tool with no agent-loop state, same shape as vision_analyze — it just wraps call_llm. Refusals and empty responses from the reference model are not exceptions; they degrade to {"unavailable": true, "reason": "..."} so the calling agent proceeds on its own judgment instead of stalling or retrying in a loop. Reasoning-heavy or safety-tuned models refuse often enough that this has to be a first-class outcome, not an error path.

Also guards against a real observed failure shape: a local/open-weight aux model returning the consult request itself (wrapped in raw tool-call template markup) as its "answer", which a naive caller would paraphrase and present as a fabricated reference-model opinion. _degenerate_answer_reason() detects both leaked template markup and high-similarity echoes and forces unavailable=true rather than a garbage answer.

Registered as a new opt-in "consult" toolset (not added to _HERMES_CORE_TOOLS), matching how vision/video are opt-in rather than always-on — keeps the narrow-waist core tool schema unaffected for users who don't enable it.

Auto-discovered by tools/registry.py's existing module-scan mechanism (any tools/*.py file that calls registry.register() at module level); no additional core wiring needed beyond the new file + one toolsets.py entry.

Test plan

  • 19 tests in tests/tools/test_consult_tool.py: success path, graceful degradation on refusal/empty/malformed-response/call-exception, question/context truncation, registry registration + dispatch, toolset resolution.
  • 6 tests in tests/tools/test_consult_degenerate_guard.py: template-markup leak, plain echo, leading control token, real answer passes, short answers not falsely flagged, incidental sentinel mention passes.
  • ruff check clean.
  • 86/86 passed across the new tests + tests/test_toolsets.py + tests/tools/test_registry.py.
  • Live boot smoke test confirms the tool auto-registers with zero manual wiring: import model_tools; registry.get_entry("consult") is not NoneTrue, toolset == "consult".

Searched existing issues/PRs first — no existing report or competing PR for this tool.

Lets the agent (main or delegated subagent) ask a configurable reference
model for a second opinion on a specific, bounded question before
committing to something risky or uncertain -- sanity-check a plan, review
a diff for structural issues, or get a pointed answer on a genuinely
uncertain judgment call. Not for routine work; it costs one full call to
a (usually more expensive, sometimes slower) model.

Routes through the existing agent.auxiliary_client.call_llm plumbing with
task="consult", configured via auxiliary.consult in config.yaml
independently of the main chat model -- the canonical use case is
pointing it at an expensive frontier model that would make a bad MAIN
model (slow, prone to over-cautious refusals) but is a great second
opinion for a narrow question.

Design: a plain registry tool with no agent-loop state, same shape as
vision_analyze -- it just wraps call_llm. Refusals and empty responses
from the reference model are NOT exceptions; they degrade to
{"unavailable": true, "reason": "..."} so the calling agent proceeds on
its own judgment instead of stalling or retrying in a loop. Reasoning-
heavy or safety-tuned models refuse often enough that this has to be a
first-class outcome, not an error path. Also guards against a real
observed failure shape: a local/open-weight aux model returning the
consult request itself (wrapped in raw tool-call template markup) as its
"answer", which a naive caller would paraphrase and present as a
fabricated reference-model opinion -- _degenerate_answer_reason() detects
both leaked template markup and high-similarity echoes and forces
unavailable=true rather than a garbage answer.

Registered as a new opt-in "consult" toolset (not added to
_HERMES_CORE_TOOLS), matching how vision/video are opt-in rather than
always-on -- keeps the narrow-waist core tool schema unaffected for
users who don't enable it.

Auto-discovered by tools/registry.py's existing module-scan mechanism;
no additional core wiring needed beyond the new file + one toolsets.py
entry.

Tests: 19 in tests/tools/test_consult_tool.py (success path, graceful
degradation on refusal/empty/malformed-response/call-exception,
question/context truncation, registry registration + dispatch, toolset
resolution) + 6 in tests/tools/test_consult_degenerate_guard.py (template-
markup leak, plain echo, leading control token, real answer passes, short
answers not falsely flagged, incidental sentinel mention passes).

Verified: ruff clean; 86/86 across the new tests + tests/test_toolsets.py
+ tests/tools/test_registry.py; live boot smoke test confirms the tool
auto-registers with zero manual wiring (import model_tools; registry.
get_entry("consult") is not None). Searched issues/PRs first -- no
existing report or competing PR for this tool.
adurham pushed a commit to adurham/hermes-agent that referenced this pull request Aug 9, 2026
…ch#82103)

De-forked tools/consult_tool.py (stripped Fable/DSML-specific wording,
verified auxiliary_client.call_llm is genuinely shared infra, registered
as an opt-in toolset instead of always-on core per upstream's narrow-
waist philosophy). The periodic-nudge companion stays fork-only --
depends on agent/fork/skill_recall.py infrastructure with no upstream
equivalent.
@alt-glitch alt-glitch added type/feature New feature or request comp/tools Tool registry, model_tools, toolsets P3 Low — cosmetic, nice to have labels Aug 9, 2026
@spfcraze

spfcraze commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

This was generated by AI during triage.

Summary:
The consult toolset is absent from CONFIGURABLE_TOOLSETS in hermes_cli/tools_config.py, so hermes tools enable consult is rejected as an unknown toolset — unlike vision/video, the opt-in precedent the description cites.

Problems:

  • hermes_cli/tools_config.py:102-103 lists vision and video — the opt-in toolsets the description says consult matches — in CONFIGURABLE_TOOLSETS; the diff registers consult in toolsets.py only.
  • hermes_cli/tools_config.py:5431 validates enable/disable targets against CONFIGURABLE_TOOLSETS plus plugin keys; consult is in neither, so hermes tools enable consult prints "Unknown toolset 'consult'" (:5435) and drops the target. The picker enumerates the same list (_get_effective_configurable_toolsets, :245-268).
  • hermes_cli/tools_config.py is absent from the diff, so the toolset is only reachable by hand-editing platform_toolsets (explicit passthrough, :2474-2480) or --toolsets consult, not through the hermes tools flow.

Solution:
Add a ("consult", ...) entry to CONFIGURABLE_TOOLSETS in hermes_cli/tools_config.py, mirroring the vision/video tuples, so the toolset appears in hermes tools.


Checked against c9a2a53 — the tip of upstream-pr/consult-tool when this was written — and 934546f, main at the same moment.

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 P3 Low — cosmetic, nice to have type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants