Problem
tool_hooks middleware cannot access the Function object of the tool they intercept. This makes it impossible for hooks to dynamically modify tool attributes — most notably stop_after_tool_call — at runtime based on execution context.
Concrete use case: Review/Advisor middleware
Consider a hook that reviews an agent's decision before allowing a tool to execute:
async def review_hook(function_name, function_call, arguments, run_context):
if function_name != "submit_decision":
return await function_call(**arguments)
decision = await ask_advisor(run_context.messages, arguments)
if decision["approve"]:
return await function_call(**arguments) # Execute normally
else:
# Problem: we want the agent to CONTINUE the loop and retry,
# but stop_after_tool_call=True on the Function object means
# the agent will stop regardless.
return "REJECTED: please reconsider and try again"
When a tool has stop_after_tool_call=True, the agent terminates after execution regardless of whether the hook approved or rejected. The hook has no way to override this because it has no access to the Function object.
Current workaround
There is none within the tool_hooks API. Users must either:
- Avoid
stop_after_tool_call entirely (losing the auto-stop feature)
- Use
pre_hook to raise AgentRunException (but this doesn't support async advisor calls or conditional logic cleanly)
Proposed solution
Add tool_definition to _build_hook_args parameter injection, following the existing pattern for agent, team, run_context, and arguments:
# In FunctionCall._build_hook_args():
if "tool_definition" in signature(hook).parameters:
hook_args["tool_definition"] = self.function
This is a 2-line change. Hooks opt in by declaring tool_definition in their signature — fully backward-compatible.
With this fix, the review hook becomes:
async def review_hook(function_name, function_call, arguments, run_context, tool_definition):
if function_name != "submit_decision":
return await function_call(**arguments)
decision = await ask_advisor(run_context.messages, arguments)
if decision["approve"]:
tool_definition.stop_after_tool_call = True
return await function_call(**arguments)
else:
tool_definition.stop_after_tool_call = False # Agent continues loop
return "REJECTED: please reconsider"
Context
Problem
tool_hooksmiddleware cannot access theFunctionobject of the tool they intercept. This makes it impossible for hooks to dynamically modify tool attributes — most notablystop_after_tool_call— at runtime based on execution context.Concrete use case: Review/Advisor middleware
Consider a hook that reviews an agent's decision before allowing a tool to execute:
When a tool has
stop_after_tool_call=True, the agent terminates after execution regardless of whether the hook approved or rejected. The hook has no way to override this because it has no access to theFunctionobject.Current workaround
There is none within the
tool_hooksAPI. Users must either:stop_after_tool_callentirely (losing the auto-stop feature)pre_hookto raiseAgentRunException(but this doesn't support async advisor calls or conditional logic cleanly)Proposed solution
Add
tool_definitionto_build_hook_argsparameter injection, following the existing pattern foragent,team,run_context, andarguments:This is a 2-line change. Hooks opt in by declaring
tool_definitionin their signature — fully backward-compatible.With this fix, the review hook becomes:
Context
_build_hook_argsforagent,team,run_context,arguments, etc.