feat(plugins): add transform_tool_result hook for generic tool-result rewriting (#12972)
Closes #8933 more fully, extending the per-tool transform_terminal_output hook from #12929 to a generic seam that fires after every tool dispatch. Plugins can rewrite any tool's result string (normalize formats, redact fields, summarize verbose output) without wrapping individual tools. Changes - hermes_cli/plugins.py: add "transform_tool_result" to VALID_HOOKS - model_tools.py: invoke the hook in handle_function_call after post_tool_call (which remains observational); first valid str return replaces the result; fail-open - tests/test_transform_tool_result_hook.py: 9 new tests covering no-op, None return, non-string return, first-match wins, kwargs, hook exception fallback, post_tool_call observation invariant, ordering vs post_tool_call, and an end-to-end real-plugin integration - tests/hermes_cli/test_plugins.py: assert new hook in VALID_HOOKS - tests/test_model_tools.py: extend the hook-call-sequence assertion to include the new hook Design - transform_tool_result runs AFTER post_tool_call so observers always see the original (untransformed) result. This keeps post_tool_call's observational contract. - transform_terminal_output (from #12929) still runs earlier, inside terminal_tool, so plugins can canonicalize BEFORE the 50k truncation drops middle content. Both hooks coexist; they target different layers.
This commit is contained in:
@ -550,6 +550,30 @@ def handle_function_call(
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# Generic tool-result canonicalization seam: plugins receive the
|
||||
# final result string (JSON, usually) and may replace it by
|
||||
# returning a string from transform_tool_result. Runs after
|
||||
# post_tool_call (which stays observational) and before the result
|
||||
# is appended back into conversation context. Fail-open; the first
|
||||
# valid string return wins; non-string returns are ignored.
|
||||
try:
|
||||
from hermes_cli.plugins import invoke_hook
|
||||
hook_results = invoke_hook(
|
||||
"transform_tool_result",
|
||||
tool_name=function_name,
|
||||
args=function_args,
|
||||
result=result,
|
||||
task_id=task_id or "",
|
||||
session_id=session_id or "",
|
||||
tool_call_id=tool_call_id or "",
|
||||
)
|
||||
for hook_result in hook_results:
|
||||
if isinstance(hook_result, str):
|
||||
result = hook_result
|
||||
break
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
return result
|
||||
|
||||
except Exception as e:
|
||||
|
||||
Reference in New Issue
Block a user