perf(observability): gate tool-hook emit on has_hook; slim per-tool footprint

The salvaged observer contract gated the API-request hot path on has_hook()
but left the per-tool emit ungated: every tool call ran result-field
derivation + payload dict build + invoke_hook dispatch even with zero
plugins registered.

- _emit_post_tool_call_hook now short-circuits on has_hook("post_tool_call")
  and derives status/error fields lazily (after the gate, only when a
  listener will consume them). status defaults to None -> derived; explicit
  blocked/cancelled callers still pass status through.
- transform_tool_result emit (pre-existing hook) likewise gated on
  has_hook(); skips _tool_result_observer_fields when no listener.
- Removed the now-redundant _tool_result_observer_fields pre-computation at
  the three ok-path call sites (model_tools, agent_runtime_helpers,
  tool_executor) — the helper derives them, so the no-listener path costs
  one dict lookup and the call sites shrink.
- Tests: stub has_hook=True where payload correctness is asserted; add a
  no-listener regression proving post_tool_call/transform_tool_result emit
  is skipped when nothing is registered.
This commit is contained in:
teknium1
2026-06-03 06:05:35 -07:00
committed by Teknium
parent 432325933a
commit 827f251426
5 changed files with 79 additions and 44 deletions

View File

@ -1667,8 +1667,7 @@ def invoke_tool(agent, function_name: str, function_args: dict, effective_task_i
def _finish_agent_tool(result: Any) -> Any:
try:
from model_tools import _emit_post_tool_call_hook, _tool_result_observer_fields
status, error_type, error_message = _tool_result_observer_fields(result)
from model_tools import _emit_post_tool_call_hook
_emit_post_tool_call_hook(
function_name=function_name,
function_args=function_args,
@ -1679,9 +1678,6 @@ def invoke_tool(agent, function_name: str, function_args: dict, effective_task_i
turn_id=getattr(agent, "_current_turn_id", "") or "",
api_request_id=getattr(agent, "_current_api_request_id", "") or "",
duration_ms=int((time.monotonic() - tool_start_time) * 1000),
status=status,
error_type=error_type,
error_message=error_message,
)
except Exception:
pass

View File

@ -72,9 +72,7 @@ def _emit_terminal_post_tool_call(
error_message: str | None = None,
) -> None:
try:
from model_tools import _emit_post_tool_call_hook, _tool_result_observer_fields
if status is None:
status, error_type, error_message = _tool_result_observer_fields(result)
from model_tools import _emit_post_tool_call_hook
_emit_post_tool_call_hook(
function_name=function_name,
function_args=function_args,