Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 6 additions & 29 deletions lib/crewai/src/crewai/agents/crew_agent_executor.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@
)
from crewai.hooks.tool_hooks import (
ToolCallHookContext,
get_after_tool_call_hooks,
get_before_tool_call_hooks,
run_after_tool_call_hooks,
run_before_tool_call_hooks,
)
from crewai.types.callback import SerializableCallable
from crewai.utilities.agent_utils import (
Expand Down Expand Up @@ -951,7 +951,6 @@ def _execute_single_native_tool_call(

track_delegation_if_needed(func_name, args_dict or {}, self.task)

hook_blocked = False
before_hook_context = ToolCallHookContext(
tool_name=func_name,
tool_input=args_dict or {},
Expand All @@ -960,19 +959,7 @@ def _execute_single_native_tool_call(
task=self.task,
crew=self.crew,
)
before_hooks = get_before_tool_call_hooks()
try:
for hook in before_hooks:
hook_result = hook(before_hook_context)
if hook_result is False:
hook_blocked = True
break
except Exception as hook_error:
if self.agent.verbose:
PRINTER.print(
content=f"Error in before_tool_call hook: {hook_error}",
color="red",
)
hook_blocked = run_before_tool_call_hooks(before_hook_context)

if hook_blocked:
result = f"Tool execution blocked by hook. Tool: {func_name}"
Expand Down Expand Up @@ -1033,19 +1020,9 @@ def _execute_single_native_tool_call(
tool_result=result,
raw_tool_result=raw_tool_result,
)
after_hooks = get_after_tool_call_hooks()
try:
for after_hook in after_hooks:
after_hook_result = after_hook(after_hook_context)
if after_hook_result is not None:
result = after_hook_result
after_hook_context.tool_result = result
except Exception as hook_error:
if self.agent.verbose:
PRINTER.print(
content=f"Error in after_tool_call hook: {hook_error}",
color="red",
)
modified_result = run_after_tool_call_hooks(after_hook_context)
if modified_result is not None:
result = modified_result

if not error_event_emitted:
crewai_event_bus.emit(
Expand Down
19 changes: 19 additions & 0 deletions lib/crewai/src/crewai/events/types/hook_events.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from typing import Literal

from crewai.events.base_events import BaseEvent


class HookDispatchedEvent(BaseEvent):
"""Event emitted whenever an interception point dispatches to hooks.

Only emitted when at least one hook is registered for the point, so the
no-op fast path stays free of event overhead.
"""

type: Literal["hook_dispatched"] = "hook_dispatched"
interception_point: str
outcome: Literal["proceeded", "modified", "aborted"]
hook_count: int
duration_ms: float
abort_reason: str | None = None
abort_source: str | None = None
35 changes: 6 additions & 29 deletions lib/crewai/src/crewai/experimental/agent_executor.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,8 @@
)
from crewai.hooks.tool_hooks import (
ToolCallHookContext,
get_after_tool_call_hooks,
get_before_tool_call_hooks,
run_after_tool_call_hooks,
run_before_tool_call_hooks,
)
from crewai.hooks.types import (
AfterLLMCallHookCallable,
Expand Down Expand Up @@ -1975,7 +1975,6 @@ def _execute_single_native_tool_call(self, tool_call: Any) -> dict[str, Any]:

track_delegation_if_needed(func_name, args_dict, self.task)

hook_blocked = False
before_hook_context = ToolCallHookContext(
tool_name=func_name,
tool_input=args_dict,
Expand All @@ -1984,19 +1983,7 @@ def _execute_single_native_tool_call(self, tool_call: Any) -> dict[str, Any]:
task=self.task,
crew=self.crew,
)
before_hooks = get_before_tool_call_hooks()
try:
for hook in before_hooks:
hook_result = hook(before_hook_context)
if hook_result is False:
hook_blocked = True
break
except Exception as hook_error:
if self.agent.verbose:
PRINTER.print(
content=f"Error in before_tool_call hook: {hook_error}",
color="red",
)
hook_blocked = run_before_tool_call_hooks(before_hook_context)

if hook_blocked:
result = f"Tool execution blocked by hook. Tool: {func_name}"
Expand Down Expand Up @@ -2060,19 +2047,9 @@ def _execute_single_native_tool_call(self, tool_call: Any) -> dict[str, Any]:
tool_result=result,
raw_tool_result=raw_tool_result,
)
after_hooks = get_after_tool_call_hooks()
try:
for after_hook in after_hooks:
after_hook_result = after_hook(after_hook_context)
if after_hook_result is not None:
result = after_hook_result
after_hook_context.tool_result = result
except Exception as hook_error:
if self.agent.verbose:
PRINTER.print(
content=f"Error in after_tool_call hook: {hook_error}",
color="red",
)
modified_result = run_after_tool_call_hooks(after_hook_context)
if modified_result is not None:
result = modified_result

if not error_event_emitted:
crewai_event_bus.emit(
Expand Down
20 changes: 20 additions & 0 deletions lib/crewai/src/crewai/hooks/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,17 @@
before_llm_call,
before_tool_call,
)
from crewai.hooks.dispatch import (
HookAborted,
InterceptionPoint,
clear as clear_hooks,
clear_all as clear_all_hooks,
dispatch,
get_hooks,
on,
register as register_hook,
unregister as unregister_hook,
)
from crewai.hooks.llm_hooks import (
LLMCallHookContext,
clear_after_llm_call_hooks,
Expand Down Expand Up @@ -74,6 +85,8 @@ def clear_all_global_hooks() -> dict[str, tuple[int, int]]:


__all__ = [
"HookAborted",
Comment thread
cursor[bot] marked this conversation as resolved.
"InterceptionPoint",
"LLMCallHookContext",
"ToolCallHookContext",
"after_llm_call",
Expand All @@ -83,20 +96,27 @@ def clear_all_global_hooks() -> dict[str, tuple[int, int]]:
"clear_after_llm_call_hooks",
"clear_after_tool_call_hooks",
"clear_all_global_hooks",
"clear_all_hooks",
"clear_all_llm_call_hooks",
"clear_all_tool_call_hooks",
"clear_before_llm_call_hooks",
"clear_before_tool_call_hooks",
"clear_hooks",
"dispatch",
"get_after_llm_call_hooks",
"get_after_tool_call_hooks",
"get_before_llm_call_hooks",
"get_before_tool_call_hooks",
"get_hooks",
"on",
"register_after_llm_call_hook",
"register_after_tool_call_hook",
"register_before_llm_call_hook",
"register_before_tool_call_hook",
"register_hook",
"unregister_after_llm_call_hook",
"unregister_after_tool_call_hook",
"unregister_before_llm_call_hook",
"unregister_before_tool_call_hook",
"unregister_hook",
]
Loading
Loading