generated from amazon-archives/__template_Apache-2.0
-
Notifications
You must be signed in to change notification settings - Fork 605
Open
Description
Summary
Add a @hook decorator to enable simple, function-based hook definitions - mirroring the ergonomics of the existing @tool decorator. This would make hooks as easy to define and share via PyPI packages as tools are today.
Motivation
Current State (Class-based):
from strands.hooks import HookProvider, HookRegistry, BeforeToolCallEvent
class MyHooks(HookProvider):
def register_hooks(self, registry: HookRegistry) -> None:
registry.add_callback(BeforeToolCallEvent, self.on_tool_call)
def on_tool_call(self, event: BeforeToolCallEvent) -> None:
print(f"Tool: {event.tool_use}")
agent = Agent(hooks=[MyHooks()])Proposed (Decorator-based):
from strands import Agent, hook
from strands.hooks import BeforeToolCallEvent
@hook
def log_tool_calls(event: BeforeToolCallEvent) -> None:
"""Log all tool calls before execution."""
print(f"Tool: {event.tool_use}")
agent = Agent(hooks=[log_tool_calls])Design
Core Decorator
@hook
def my_hook(event: BeforeToolCallEvent) -> None:
"""Hook description extracted from docstring."""
pass
# Or with explicit event type
@hook(event=BeforeToolCallEvent)
def my_hook(event) -> None:
passEvent Type Detection
- Type hints (preferred): Extract from function signature
- Explicit parameter:
@hook(event=BeforeToolCallEvent) - Validation: Ensure event type inherits from
HookEvent
DecoratedFunctionHook Class
class DecoratedFunctionHook(HookProvider):
"""Wraps a decorated function as a HookProvider."""
def __init__(self, func, event_type, metadata):
self._func = func
self._event_type = event_type
self._metadata = metadata
def register_hooks(self, registry: HookRegistry) -> None:
registry.add_callback(self._event_type, self._func)
def __call__(self, event):
"""Allow direct invocation for testing."""
return self._func(event)Multi-Event Hooks
@hook(events=[BeforeToolCallEvent, AfterToolCallEvent])
def audit_tools(event: BeforeToolCallEvent | AfterToolCallEvent) -> None:
"""Audit both before and after tool execution."""
passPackage Distribution
Enable sharing hooks via PyPI (like tools):
# strands_observability/hooks.py
from strands import hook
from strands.hooks import BeforeInvocationEvent, AfterInvocationEvent
@hook
def trace_requests(event: BeforeInvocationEvent) -> None:
"""Start OpenTelemetry span for agent invocation."""
pass
@hook
def end_trace(event: AfterInvocationEvent) -> None:
"""End OpenTelemetry span."""
passUsage:
from strands_observability.hooks import trace_requests, end_trace
agent = Agent(hooks=[trace_requests, end_trace])API Surface
# New exports from strands
from strands import hook
# New exports from strands.hooks
from strands.hooks import DecoratedFunctionHook, HookMetadataCompatibility
- Backward compatible: Existing
HookProviderclasses continue to work - Mixed usage: Support both class-based and decorator-based hooks
- Async support: Handle both sync and async hook functions
agent = Agent(hooks=[
MyClassBasedHook(), # Existing
log_tool_calls, # New decorator-based
])Implementation Checklist
-
FunctionHookMetadataclass for extracting function metadata -
DecoratedFunctionHookclass implementingHookProvider -
@hookdecorator with event type detection - Support for async hook functions
- Multi-event registration support
- Documentation and examples
- Unit tests
Related
- Tool decorator:
strands/tools/decorator.py - Hook system:
strands/hooks/ - Similar pattern:
@toolenables package distribution of tools
Questions
- Should
@hooksupport context injection like@tool(context=True)? - Should we support hook ordering/priority via decorator params?
- Should hooks be loadable from directories like tools (
load_hooks_from_directory)?
Metadata
Metadata
Assignees
Labels
No labels