Skip to content

fix(plugins): re-enable pre_tool_call approve escalation with correct gateway notify path (#59201)#60544

Open
kyssta-exe wants to merge 2 commits into
NousResearch:mainfrom
kyssta-exe:fix/plugin-approval-escalation-gateway-59201
Open

fix(plugins): re-enable pre_tool_call approve escalation with correct gateway notify path (#59201)#60544
kyssta-exe wants to merge 2 commits into
NousResearch:mainfrom
kyssta-exe:fix/plugin-approval-escalation-gateway-59201

Conversation

@kyssta-exe

Copy link
Copy Markdown
Contributor

Summary

Re-enables the pre_tool_call plugin hook "approve" directive (previously reverted) with the critical gateway fix: plugin-triggered approvals now use _await_gateway_decision() instead of submit_pending(), so the notification callback fires and the approval request is visible to users on desktop and messaging gateways.

Problem

When a plugin's pre_tool_call hook returns {"action": "approve", "message": "..."}, the tool call requires human approval. On CLI this worked, but on desktop and gateway bridges, the approval was silently stored via submit_pending() with no notification emitted — the user never saw a prompt, the /approve command found nothing pending, and the tool call timed out after 300s.

Root Cause

The original implementation in commit f512d6f02 (reverted in 9efc24a61) routed the gateway branch through submit_pending(), which only writes to a _pending dict that nothing reads. The working command-guard path uses _await_gateway_decision() with the per-session notify callback (_gateway_notify_cbs) which emits approval.request events to the gateway event stream.

This fix replaces submit_pending() with _await_gateway_decision() in the shared _run_approval_gate() function, giving plugin-triggered approvals the same user-visible treatment as dangerous-command prompts.

Changes

  • tools/approval.py: Added _run_approval_gate() — shared human-approval core extracted from check_dangerous_command(), called by both command and plugin paths. Gateway branch uses _await_gateway_decision() with notify callback. Added request_tool_approval() — entry point for plugin approve escalations.
  • hermes_cli/plugins.py: Added get_pre_tool_call_directive() returning (action, message) for both "block" and "approve" directives. Added resolve_pre_tool_block() as the single dispatch chokepoint that invokes the human gate for "approve". Kept get_pre_tool_call_block_message() as back-compat shim.
  • model_tools.py, agent/agent_runtime_helpers.py, agent/tool_executor.py: All four tool-dispatch sites now call resolve_pre_tool_block() instead of get_pre_tool_call_block_message().

Closes #59201

Hermes Agent Bot added 2 commits July 7, 2026 19:38
…search#60345)

When a MoA reference model's context window is smaller than the
conversation history sent to it (e.g. kimi-k2.7-code @ 262K tokens as
reference, glm-5 @ 1M as aggregator), the reference call would fail with
a hard HTTP 400 that _run_reference's try/except silently converts into
a [failed: ...] label — degrading the MoA turn with no user-visible signal.

This fix adds _fit_to_context_window(), which:
1. Looks up the reference model's context window via get_model_context_length
2. Estimates message token count (~4 chars/token)
3. If the estimate exceeds 90% of the window, drops the oldest non-system
   messages (preserving the system prompt and most recent conversation)
4. If even the last 3 messages + system prompt exceed the window, prepends
   a warning in the system prompt so the aggregator sees the reference was
   constrained

The trimming mirrors what ContextCompressor does for the acting model's
conversation, but applies specifically to the disposable advisory copy
each reference sees — the acting aggregator's transcript is untouched.

Fixes NousResearch#60345
… gateway notify path

Restore the pre_tool_call plugin hook 'approve' directive (reverted in
9efc24a) with the critical gateway fix: plugin-triggered approvals
now use _await_gateway_decision() instead of submit_pending(), so the
notify callback fires and the approval request is visible to users on
desktop and messaging gateways.

Includes:
- get_pre_tool_call_directive() returns (action, message) tuples for
  both 'block' and 'approve' directives
- resolve_pre_tool_block() is the single dispatch chokepoint across
  all four tool-execution paths (model_tools, agent_runtime_helpers,
  tool_executor concurrent + sequential)
- _run_approval_gate() extracted as shared human-approval core for
  both check_dangerous_command() and request_tool_approval()
- request_tool_approval() escalates plugin-flagged tool calls through
  the same gate as Tier-2 dangerous commands
- Gateway path in _run_approval_gate() now properly uses
  _await_gateway_decision() with the registered notify callback,
  resolving NousResearch#59201 where plugin approval prompts silently timed out
  on desktop/gateway because submit_pending() never emitted an
  approval.request event

Closes NousResearch#59201
@alt-glitch alt-glitch added type/feature New feature or request comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint comp/tools Tool registry, model_tools, toolsets comp/plugins Plugin system and bundled plugins area/auth Authentication, OAuth, credential pools sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data P3 Low — cosmetic, nice to have duplicate This issue or pull request already exists labels Jul 7, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

This was generated by AI during triage.

Duplicate of #60504 — that PR (merged 2026-07-07) already re-landed the pre_tool_call "approve" escalation with the same gateway-notify fix (_await_gateway_decision() in a shared _run_approval_gate(), plus request_tool_approval() and resolve_pre_tool_block()). Verified on main: request_tool_approval/_run_approval_gate in tools/approval.py and resolve_pre_tool_block in hermes_cli/plugins.py are already present. Related: #59201 (the bug closed by the merged fix), #59131 (the earlier revert).

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

Labels

area/auth Authentication, OAuth, credential pools comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint comp/plugins Plugin system and bundled plugins comp/tools Tool registry, model_tools, toolsets duplicate This issue or pull request already exists P3 Low — cosmetic, nice to have sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Approval plugin doesn't show approve controls on desktop and gateway (works on CLI)

2 participants