Skip to content

feat(hooks): pre_tool_call content transformation via modify directive - #87482

Merged
teknium1 merged 3 commits into
mainfrom
salvage/pre-tool-call-modify
Aug 16, 2026
Merged

feat(hooks): pre_tool_call content transformation via modify directive#87482
teknium1 merged 3 commits into
mainfrom
salvage/pre-tool-call-modify

Conversation

@teknium1

Copy link
Copy Markdown
Contributor

Summary

pre_tool_call hooks can now transform tool arguments before execution via a modify directive, instead of repairing results afterwards through post_tool_call. Salvage of #28953 by @NikolaRHristov onto current main, with a follow-up refactor.

Changes

  • hermes_cli/plugins.py: _dispatch_pre_tool_call_hooks() fires hooks once and returns (block_message, modified_args); modify directives shallow-merge into an accumulated dict (later hook wins per key). Follow-up: extracted _resolve_block_from_details() so the dispatcher and resolve_pre_tool_block share ONE fail-closed approval-gate implementation (this also gives the dispatcher the observability-context wrapping around the human-approval gate that the original inlined copy lacked).
  • agent/shell_hooks.py: _parse_response() accepts both {"action": "modify", "args": {...}} and Claude Code-compatible {"decision": "modify", "tool_input": {...}}.
  • model_tools.py, agent/tool_executor.py, agent/agent_runtime_helpers.py: dispatch sites migrated; modified args applied before execution. Single-fire hook contract preserved.
  • Sibling tests at the migrated sites updated to the new tuple contract; 10 new tests for merge semantics, precedence, block interplay; docs updated (hooks.md, observability README).

Validation

Result
Targeted suites (plugins, shell_hooks, run_agent, guardrail runtime, authorization gate, relay metrics, approval) 448 passed
E2E (isolated HERMES_HOME, real shell hook registered via register_from_config) live write_file through handle_function_call rewrote path DECOY→REWRITTEN + prepended banner; decoy never written; block + negative paths intact
ruff on all touched modules clean

Best fix for #18988. Credit also to @elasticdotventures whose #19305 proposed the same capability earlier — this implementation was chosen as the cleaner of the two.

Infographic

pre_tool_call modify infographic

NikolaRHristov and others added 3 commits August 15, 2026 22:48
Adds a `modify` response type to pre_tool_call hooks so a hook can
transform tool arguments before the tool executes, instead of repairing
results afterwards via post_tool_call.

- hermes_cli/plugins.py: _dispatch_pre_tool_call_hooks() fires hooks once
  and returns (block_message, modified_args); modify directives
  shallow-merge into an accumulated dict built from the original args.
- agent/shell_hooks.py: _parse_response() accepts both the canonical
  {"action": "modify", "args": {...}} and Claude Code-compatible
  {"decision": "modify", "tool_input": {...}} wire formats.
- model_tools.py, agent/tool_executor.py, agent/agent_runtime_helpers.py:
  dispatch sites migrated; modified args applied before execution.
- Docs + 10 new tests (merge semantics, precedence, block interplay).

Salvaged from PR #28953. Best fix for #18988.
Follow-up to the #28953 salvage:

- Extract _resolve_block_from_details() so resolve_pre_tool_block and
  _dispatch_pre_tool_call_hooks share ONE fail-closed approval-gate
  implementation. This also gives the new dispatcher the observability
  context wrapping around request_tool_approval that the original PR's
  inlined copy lacked.
- Update sibling tests that patched resolve_pre_tool_block at the three
  migrated dispatch sites to patch _dispatch_pre_tool_call_hooks with the
  (block_message, modified_args) tuple contract.

Verified: 448 targeted tests green; E2E with a real shell hook in an
isolated HERMES_HOME rewrote a live write_file call (path + content)
through handle_function_call, with block and negative paths intact.
@github-actions

github-actions Bot commented Aug 16, 2026

Copy link
Copy Markdown
Contributor

૮ >ﻌ< ა ci review

ran on 033a11b — chore: contributor mapping for NikolaRHristov

⚠️ Warnings

OSV vulnerability scan · View job

5 known vulnerabilities found in pinned dependencies.

How to fix:

Review the findings in the Security tab. Update the affected dependencies if a patched version is available.


debug info

CI timings

CI timings · View report · View job

Wall time 3m25s vs 3m25s (+0.0%). 8 job(s) slower, 13 faster, 4 unchanged.

  • Python tests / Run tests slice 7/12: -11.0s
  • Python tests / Run tests slice 9/12: +10.0s
  • Python tests / Run tests slice 8/12: -9.0s
  • Python tests / Run tests slice 3/12: -9.0s
  • Python tests / e2e: -7.0s

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants