mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-11-06 05:17:15 +00:00
fix(middleware): preserve pre-Relay tool request snapshot
When Relay rewrites a tool call before Hermes' own pipeline runs,
tool_request middleware received the Relay-rewritten args as
original_args, while tool_execution middleware already got the model's
call (function_args). Pass function_args through as original_args so both
middleware kinds see the same pre-Relay snapshot.
Sequential chaining of request rewrites itself landed in f67d490f71
(#133159); this keeps only the remaining pre-Relay delta of #82092.
This commit is contained in:
1 parent
b47fe6ecc6
commit
78f7db6349
3 files changed
+30
-4
No files matched your search
@@ -811,6 +811,7 @@ def _run_agent_tool_execution_middleware(
|
||||
request_result = apply_tool_request_middleware(
|
||||
function_name,
|
||||
relay_args,
|
||||
original_args=function_args,
|
||||
skip_relay=True,
|
||||
**tool_hook_ids(agent, effective_task_id, tool_call_id),
|
||||
)
|
||||
|
||||
@@ -100,12 +100,13 @@ def apply_llm_request_middleware(request: dict[str, Any], **context: Any) -> Req
|
||||
|
||||
|
||||
def apply_tool_request_middleware(
|
||||
tool_name: str, args: dict[str, Any], **context: Any
|
||||
tool_name: str, args: dict[str, Any], *, original_args: dict[str, Any] | None = None, **context: Any
|
||||
) -> RequestMiddlewareResult:
|
||||
"""Apply registered tool request middleware; ``{"args": {...}}`` replaces the effective tool
|
||||
arguments before hooks, guardrails, approvals, and execution see them."""
|
||||
original_args = _safe_copy(args)
|
||||
current_args = _safe_copy(original_args)
|
||||
arguments before hooks, guardrails, approvals, and execution see them. ``original_args`` is the
|
||||
model's pre-Relay call when ``args`` already carries Relay rewrites (defaults to ``args``)."""
|
||||
original_args = _safe_copy(args if original_args is None else original_args)
|
||||
current_args = _safe_copy(args)
|
||||
trace: list[dict[str, Any]] = []
|
||||
|
||||
session_id = str(context.get("session_id") or "")
|
||||
|
||||
@@ -65,3 +65,27 @@ def test_request_middleware_in_place_mutation_does_not_leak(seen, kind, apply):
|
||||
# Each callback gets its own copy of the payload and of the pre-middleware snapshot.
|
||||
assert "meddler" not in result.payload["steps"]
|
||||
assert seen[kind][1] == result.original_payload == original == {"input": ["original"]}
|
||||
|
||||
|
||||
def test_tool_request_original_args_is_the_pre_relay_call(seen, monkeypatch):
|
||||
from types import SimpleNamespace
|
||||
|
||||
from agent import relay_tools, tool_executor
|
||||
|
||||
def relay_rewrites(_name, args, callback, **_kwargs):
|
||||
relay_args = {**args, "relay": True}
|
||||
return callback(relay_args), relay_args
|
||||
|
||||
dispatched = []
|
||||
monkeypatch.setattr(relay_tools, "execute", relay_rewrites)
|
||||
monkeypatch.setattr(tool_executor, "_dispatch_authorized_once", lambda _agent, _state, ref, **_k: dispatched.append(ref.args))
|
||||
|
||||
tool_executor._run_agent_tool_execution_middleware(
|
||||
SimpleNamespace(session_id="s1"), function_name="fixture", function_args={"input": ["original"]},
|
||||
effective_task_id="t1", tool_call_id="c1", execute=None,
|
||||
)
|
||||
|
||||
# Middleware sees Relay's rewrite as ``args`` but the model's own call as ``original_args``.
|
||||
assert seen["tool_request"] == ({"input": ["original"], "relay": True, "steps": ["first"]},
|
||||
{"input": ["original"]})
|
||||
assert dispatched == [{"input": ["original"], "relay": True, "steps": ["first"], "second": True}]
|
||||
Reference in new issue
Block a user