Skip to content
Open
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
2 changes: 2 additions & 0 deletions src/strands/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@
from .agent.agent import Agent
from .agent.base import AgentBase
from .event_loop._retry import ModelRetryStrategy
from .hooks.decorator import hook
from .tools.decorator import tool
from .types.tools import ToolContext

__all__ = [
"Agent",
"AgentBase",
"agent",
"hook",
"models",
"ModelRetryStrategy",
"tool",
Expand Down
39 changes: 30 additions & 9 deletions src/strands/hooks/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
built-in SDK components and user code to react to or modify agent behavior
through strongly-typed event callbacks.

Example Usage:
Example Usage with Class-Based Hooks:
```python
from strands.hooks import HookProvider, HookRegistry
from strands.hooks.events import BeforeInvocationEvent, AfterInvocationEvent
Expand All @@ -25,10 +25,24 @@ def log_end(self, event: AfterInvocationEvent) -> None:
agent = Agent(hooks=[LoggingHooks()])
```

This replaces the older callback_handler approach with a more composable,
type-safe system that supports multiple subscribers per event type.
Example Usage with Decorator-Based Hooks:
```python
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])
```

This module supports both the class-based HookProvider approach and the newer
decorator-based @hook approach for maximum flexibility.
"""

from .decorator import DecoratedFunctionHook, FunctionHookMetadata, HookMetadata, hook
from .events import (
AfterInvocationEvent,
AfterModelCallEvent,
Expand All @@ -48,6 +62,7 @@ def log_end(self, event: AfterInvocationEvent) -> None:
from .registry import BaseHookEvent, HookCallback, HookEvent, HookProvider, HookRegistry

__all__ = [
# Events
"AgentInitializedEvent",
"BeforeInvocationEvent",
"BeforeToolCallEvent",
Expand All @@ -56,15 +71,21 @@ def log_end(self, event: AfterInvocationEvent) -> None:
"AfterModelCallEvent",
"AfterInvocationEvent",
"MessageAddedEvent",
"HookEvent",
"HookProvider",
"HookCallback",
"HookRegistry",
"HookEvent",
"BaseHookEvent",
# Multiagent events
"AfterMultiAgentInvocationEvent",
"AfterNodeCallEvent",
"BeforeMultiAgentInvocationEvent",
"BeforeNodeCallEvent",
"MultiAgentInitializedEvent",
# Registry
"HookEvent",
"HookProvider",
"HookCallback",
"HookRegistry",
"BaseHookEvent",
# Decorator
"hook",
"DecoratedFunctionHook",
"FunctionHookMetadata",
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Question: Should FunctionHookMetadata and HookMetadata be part of the public API?

Looking at the @tool decorator pattern, FunctionToolMetadata is not exported publicly. These classes appear to be implementation details used internally by the decorator.

Suggestion: Consider either:

  1. Removing from __all__ to keep them internal (consistent with @tool)
  2. If there's a valid use case for introspection, document why they're public

The DecoratedFunctionHook class is appropriately public since users may need isinstance checks.

"HookMetadata",
]
Loading
Loading