mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-06-07 08:02:23 +00:00
refactor(run_agent): extract tool execution to agent/tool_executor.py
Move the two big tool-dispatch methods out of run_agent.py: * execute_tool_calls_concurrent — 408-line concurrent path (interrupt pre-flight, guardrail+plugin block, callback fan-out, ContextVar- preserving ThreadPoolExecutor, periodic heartbeats for the gateway inactivity monitor, per-tool result handling with subdir hints + guardrail observations + checkpoint, /steer drain) * execute_tool_calls_sequential — 441-line sequential path (the original behavior used for single-tool batches and interactive tools) Both take the parent AIAgent as their first argument; AIAgent keeps thin forwarders so call sites unchanged. handle_function_call is routed through _ra() so tests that patch run_agent.handle_function_call keep working. _set_interrupt likewise. The AST guard in test_tool_executor_contextvar_propagation.py is updated to scan both run_agent.py AND agent/tool_executor.py so it still catches the executor.submit(_run_tool, ...) regression regardless of which file the body lives in. tests/run_agent/ + tests/agent/: 4313 passed (same pre-existing test_auxiliary_client failure as before). run_agent.py: 14309 -> 13461 lines (-848).
This commit is contained in:
parent
2d2cd5e904
commit
79559214a6
3 changed files with 945 additions and 855 deletions
|
|
@ -152,19 +152,28 @@ def test_run_agent_concurrent_executor_wraps_submit_with_copy_context():
|
|||
import inspect
|
||||
|
||||
import run_agent
|
||||
from agent import tool_executor as tool_executor_module
|
||||
|
||||
src_path = inspect.getsourcefile(run_agent)
|
||||
assert src_path is not None
|
||||
tree = ast.parse(open(src_path, encoding="utf-8").read())
|
||||
# Source for both modules — the concurrent-executor body lives in
|
||||
# ``agent/tool_executor.py`` after the run_agent.py refactor (PR
|
||||
# following #16660). Search both so this guard keeps firing
|
||||
# regardless of where the call site lives.
|
||||
sources = []
|
||||
for mod in (run_agent, tool_executor_module):
|
||||
src_path = inspect.getsourcefile(mod)
|
||||
assert src_path is not None
|
||||
sources.append((src_path, open(src_path, encoding="utf-8").read()))
|
||||
|
||||
submit_calls_in_agent: list[ast.Call] = []
|
||||
for node in ast.walk(tree):
|
||||
if not isinstance(node, ast.Call):
|
||||
continue
|
||||
func = node.func
|
||||
# Match executor.submit(...) style calls.
|
||||
if isinstance(func, ast.Attribute) and func.attr == "submit":
|
||||
submit_calls_in_agent.append(node)
|
||||
for _src_path, src_text in sources:
|
||||
tree = ast.parse(src_text)
|
||||
for node in ast.walk(tree):
|
||||
if not isinstance(node, ast.Call):
|
||||
continue
|
||||
func = node.func
|
||||
# Match executor.submit(...) style calls.
|
||||
if isinstance(func, ast.Attribute) and func.attr == "submit":
|
||||
submit_calls_in_agent.append(node)
|
||||
|
||||
# Filter to the submit call inside the concurrent tool executor —
|
||||
# identifiable by passing `_run_tool` as its target. Other submit()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue