crewai - ✅(Solved) Fix [FEATURE] [UX] before_tool_call decorator's tools parameter should auto-normalize tool names to match ToolCallHookContext.tool_name [2 pull requests, 1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
crewAIInc/crewAI#5335Fetched 2026-04-09 08:01:30
View on GitHub
Comments
0
Participants
1
Timeline
6
Reactions
0
Participants
Timeline (top)
cross-referenced ×2referenced ×2closed ×1labeled ×1

Fix Action

Fixed

PR fix notes

PR #5336: fix: auto-sanitize tool names in hook decorator filters

Description (problem / solution / changelog)

Summary

The tools parameter in @before_tool_call and @after_tool_call decorators now auto-normalizes tool names using sanitize_tool_name() before comparison. This fixes a UX issue where users passing human-readable tool names (e.g., "File Read Tool", "ExaSearchTool") to the tools filter would silently fail to match, because ToolCallHookContext.tool_name contains the sanitized form (e.g., "file_read_tool", "exa_search_tool").

The fix applies sanitize_tool_name() to each entry in the tools list at decoration time inside _create_hook_decorator, so the comparison in filtered_hook always uses sanitized names. Already-sanitized names (e.g., "delete_file") are idempotent through sanitize_tool_name() and continue to work.

Closes #5335

Review & Testing Checklist for Human

  • _filter_tools attribute now stores sanitized names instead of original user-provided names. Any external code that reads func._filter_tools and expects original names will see sanitized ones instead. Verify this is acceptable.
  • Crew-scoped hooks (methods with self): The sanitization path runs before the is_method check, so it should apply equally to class-based hooks registered via CrewBase. Confirm this works in a real crew-scoped scenario.
  • Run uv run pytest lib/crewai/tests/hooks/ -vv to confirm all 95 hook tests pass (including 8 new sanitization tests).

Notes

  • The sanitize_tool_name import is at module level in decorators.py — it's a lightweight utility in the same package, no circular import risk.
  • LLM hook decorators (@before_llm_call, @after_llm_call) are unaffected since they never pass tools.

Link to Devin session: https://app.devin.ai/sessions/21471618894b4e4a892c0ddb9c61dffa

<!-- CURSOR_SUMMARY -->

[!NOTE] Low Risk Low risk behavior change limited to tool hook filtering, but it may affect any code that inspects func._filter_tools since it now stores sanitized values instead of the original strings.

Overview Fixes tool-hook filtering by sanitizing tools entries in _create_hook_decorator via sanitize_tool_name() before storing and comparing, so @before_tool_call/@after_tool_call filters match the sanitized context.tool_name at runtime.

Adds a focused test suite covering human-readable names, CamelCase names, already-sanitized names, mixed lists, non-matches, and interaction with the agents filter; _filter_tools is now asserted to contain the sanitized values.

<sup>Reviewed by Cursor Bugbot for commit 7a649b226e709fbabad05f980689a7e56f84e010. Bugbot is set up for automated code reviews on this repo. Configure here.</sup>

<!-- /CURSOR_SUMMARY -->

Changed files

  • lib/crewai/src/crewai/hooks/decorators.py (modified, +14/-5)
  • lib/crewai/tests/hooks/test_decorators.py (modified, +189/-0)

PR #5342: fix: sanitize tool names in hook decorator filters

Description (problem / solution / changelog)

Summary

  • Auto-sanitizes the tools parameter in before_tool_call/after_tool_call decorators via sanitize_tool_name(), so users can pass BaseTool.name directly without knowing the internal normalization
  • Fixes tool_utils.py to pass the sanitized name to ToolCallHookContext, matching the behavior in crew_agent_executor.py

Closes #5335

Test plan

  • New test test_before_tool_call_tool_filter_sanitizes_names verifies unsanitized names like "Delete File" match sanitized context names like "delete_file"
  • All 14 existing hook decorator tests pass
<!-- CURSOR_SUMMARY -->

[!NOTE] Medium Risk Changes the ToolCallHookContext.tool_name value passed to hooks and normalizes decorator tools filters, which can alter which hooks run for projects relying on unsanitized names.

Overview Tool hook decorators now auto-sanitize the tools filter list via sanitize_tool_name(), allowing users to pass human-readable BaseTool.name values while still matching internal normalized tool names.

Tool execution in tool_utils.py now populates ToolCallHookContext.tool_name with the sanitized name (for both before/after hooks, sync and async), aligning hook filtering and logging behavior. Adds a regression test ensuring unsanitized filter names like "Delete File" match contexts like "delete_file".

<sup>Reviewed by Cursor Bugbot for commit 14b3934bc41cbdafc9c9d1b120e85eeabdc86d59. Bugbot is set up for automated code reviews on this repo. Configure here.</sup>

<!-- /CURSOR_SUMMARY -->

Addresses #5335

Changed files

  • lib/crewai/src/crewai/hooks/decorators.py (modified, +5/-0)
  • lib/crewai/src/crewai/utilities/tool_utils.py (modified, +4/-4)
  • lib/crewai/tests/hooks/test_decorators.py (modified, +32/-0)

Code Example

# In crewai/hooks/decorators.py (pseudocode)
from crewai.utilities.string_utils import sanitize_tool_name

def _create_hook_decorator(
    hook_type: str,
    register_function: Callable[..., Any],
    marker_attribute: str,
) -> Callable[..., Any]:
    """Create a hook decorator with filtering support.

    This factory function eliminates code duplication across the four hook decorators.

    Args:
        hook_type: Type of hook ("llm" or "tool")
        register_function: Function to call for registration (e.g., register_before_llm_call_hook)
        marker_attribute: Attribute name to mark functions (e.g., "is_before_llm_call_hook")

    Returns:
        A decorator function that supports filters and auto-registration
    """
    def decorator_factory(
        func: Callable[..., Any] | None = None,
        *,
        tools: list[str] | None = None,
        agents: list[str] | None = None,
    ) -> Callable[..., Any]:
        tools = [sanitize_tool_name(tool) for tool in tools]
        def decorator(f: Callable[..., Any]) -> Callable[..., Any]:
            setattr(f, marker_attribute, True)

            ...
RAW_BUFFERClick to expand / collapse

Feature Area

Core functionality

Is your feature request related to a an existing bug? Please link it here.

no

Describe the solution you'd like

Modify the before_tool_call decorator (and after_tool_call) to sanitize the tools list parameter using crewai.utilities.string_utils.sanitize_tool_name() before comparison:

# In crewai/hooks/decorators.py (pseudocode)
from crewai.utilities.string_utils import sanitize_tool_name

def _create_hook_decorator(
    hook_type: str,
    register_function: Callable[..., Any],
    marker_attribute: str,
) -> Callable[..., Any]:
    """Create a hook decorator with filtering support.

    This factory function eliminates code duplication across the four hook decorators.

    Args:
        hook_type: Type of hook ("llm" or "tool")
        register_function: Function to call for registration (e.g., register_before_llm_call_hook)
        marker_attribute: Attribute name to mark functions (e.g., "is_before_llm_call_hook")

    Returns:
        A decorator function that supports filters and auto-registration
    """
    def decorator_factory(
        func: Callable[..., Any] | None = None,
        *,
        tools: list[str] | None = None,
        agents: list[str] | None = None,
    ) -> Callable[..., Any]:
        tools = [sanitize_tool_name(tool) for tool in tools]
        def decorator(f: Callable[..., Any]) -> Callable[..., Any]:
            setattr(f, marker_attribute, True)

            ...

Describe alternatives you've considered

No response

Additional context

This inconsistency was discovered while debugging why file operation hooks weren't triggering. The developer expectation is that the string defined in BaseTool.name should be the same string used for filtering in hooks, without needing to understand internal sanitization logic.

Willingness to Contribute

Yes, I'd be happy to submit a pull request

extent analysis

TL;DR

Modify the before_tool_call and after_tool_call decorators to sanitize the tools list parameter using crewai.utilities.string_utils.sanitize_tool_name() before comparison to ensure consistent filtering.

Guidance

  • Review the crewai/hooks/decorators.py file to ensure the sanitize_tool_name function is correctly applied to the tools list parameter in the _create_hook_decorator function.
  • Verify that the BaseTool.name string is being sanitized correctly and matches the expected output of sanitize_tool_name.
  • Test the modified decorators with different tool names to ensure consistent filtering behavior.
  • Consider adding documentation to clarify the sanitization logic and its impact on hook filtering.

Example

tools = [sanitize_tool_name(tool) for tool in tools]

This code snippet demonstrates how to sanitize the tools list parameter using sanitize_tool_name.

Notes

The proposed solution assumes that the sanitize_tool_name function is correctly implemented and behaves as expected. Additional testing may be necessary to ensure the modified decorators work correctly in all scenarios.

Recommendation

Apply workaround: Modify the before_tool_call and after_tool_call decorators to sanitize the tools list parameter using crewai.utilities.string_utils.sanitize_tool_name() before comparison. This will ensure consistent filtering behavior and align with developer expectations.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

crewai - ✅(Solved) Fix [FEATURE] [UX] before_tool_call decorator's tools parameter should auto-normalize tool names to match ToolCallHookContext.tool_name [2 pull requests, 1 participants]