feat(hooks): add @hook decorator for simplified hook definitions#1484
feat(hooks): add @hook decorator for simplified hook definitions#1484strands-agent wants to merge 4 commits intostrands-agents:mainfrom
Conversation
This adds a @hook decorator that transforms Python functions into HookProvider implementations with automatic event type detection from type hints - mirroring the ergonomics of the existing @tool decorator. Features: - Simple decorator syntax: @hook - Automatic event type extraction from type hints - Explicit event type specification: @hook(event=EventType) - Multi-event support: @hook(events=[...]) or Union types - Support for both sync and async hook functions - Preserves function metadata (name, docstring) - Direct invocation for testing New exports: - from strands import hook - from strands.hooks import hook, DecoratedFunctionHook, FunctionHookMetadata, HookMetadata Example: from strands import Agent, hook from strands.hooks import BeforeToolCallEvent @hook def log_tool_calls(event: BeforeToolCallEvent) -> None: print(f'Tool: {event.tool_use}') agent = Agent(hooks=[log_tool_calls]) Fixes strands-agents#1483
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
- Add cast() for HookCallback type in register_hooks method - Add HookCallback import from registry - Use keyword-only arguments in overload signature 2 to satisfy mypy
This enhancement addresses feedback from @cagataycali - the agent instance is now automatically injected to @hook decorated functions when they have an 'agent' parameter in their signature. Usage: @hook def my_hook(event: BeforeToolCallEvent, agent: Agent) -> None: # agent is automatically injected from event.agent print(f'Agent {agent.name} calling tool') Features: - Detect 'agent' parameter in function signature - Automatically extract agent from event.agent when callback is invoked - Works with both sync and async hooks - Backward compatible - hooks without agent param work unchanged - Direct invocation supports explicit agent override for testing Tests added: - test_agent_param_detection - test_agent_injection_in_repr - test_hook_without_agent_param_not_injected - test_hook_with_agent_param_receives_agent - test_direct_call_with_explicit_agent - test_agent_injection_with_registry - test_async_hook_with_agent_injection - test_hook_metadata_includes_agent_param - test_mixed_hooks_with_and_without_agent
Add 13 new test cases to improve code coverage from 89% to 98%: - TestCoverageGaps: Optional type hint, async/sync agent injection via registry, direct call without agent param, hook() empty parentheses, Union types - TestAdditionalErrorCases: Invalid annotation types, invalid explicit event list - TestEdgeCases: get_type_hints exception fallback, empty type hints fallback Coverage improvements: - Lines 139-141: get_type_hints exception handling - Line 157: Annotation fallback when type hints unavailable - Lines 203-205: NoneType skipping in Optional[X] - Line 216: Invalid annotation error path - Lines 313-320: Async/sync callback with agent injection Addresses codecov patch coverage failure in PR strands-agents#1484.
|
Couple of issues found by my review agent Critical Issues Found:
|
|
Closing this PR as it's superseded by #1581 from @mkmeral which implements the same Great work @mkmeral! 🎉 🤖 AI agent response from the Strands team. Strands Agents. Feedback welcome! |
Description
This PR adds a
@hookdecorator that transforms Python functions intoHookProviderimplementations with automatic event type detection from type hints - mirroring the ergonomics of the existing@tooldecorator.Features
@hookextracts event type from type hints@hook(event=EventType)for functions without type hints@hook(events=[...])or Union types (A | B)functools.wrapsBefore (Class-based):
After (Decorator-based):
New Exports
Related Issues
Fixes #1483
Documentation PR
No documentation changes required - follows existing patterns established by
@tool.Type of Change
New feature (non-breaking addition)
Testing
hatch run prepareChecklist
__init__.py)