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
17 changes: 13 additions & 4 deletions src/strands/experimental/hooks/__init__.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,26 @@
"""Experimental hook functionality that has not yet reached stability."""

from .events import (
AfterModelInvocationEvent,
AfterToolInvocationEvent,
BeforeModelInvocationEvent,
BeforeToolInvocationEvent,
BidiAfterConnectionRestartEvent,
BidiAfterInvocationEvent,
BidiAfterToolCallEvent,
BidiAgentInitializedEvent,
BidiBeforeConnectionRestartEvent,
BidiBeforeInvocationEvent,
BidiBeforeToolCallEvent,
BidiInterruptionEvent,
BidiMessageAddedEvent,
)

# Deprecated aliases are accessed via __getattr__ to emit warnings only on use


def __getattr__(name: str):
from . import events

return getattr(events, name)


__all__ = [
"BeforeToolInvocationEvent",
"AfterToolInvocationEvent",
Expand All @@ -27,4 +34,6 @@
"BidiBeforeToolCallEvent",
"BidiAfterToolCallEvent",
"BidiInterruptionEvent",
"BidiBeforeConnectionRestartEvent",
"BidiAfterConnectionRestartEvent",
]
32 changes: 20 additions & 12 deletions src/strands/experimental/hooks/events.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

import warnings
from dataclasses import dataclass
from typing import TYPE_CHECKING, Any, Literal, TypeAlias
from typing import TYPE_CHECKING, Any, Literal

from ...hooks.events import AfterModelCallEvent, AfterToolCallEvent, BeforeModelCallEvent, BeforeToolCallEvent
from ...hooks.registry import BaseHookEvent
Expand All @@ -16,17 +16,25 @@
from ..bidi.agent.agent import BidiAgent
from ..bidi.models import BidiModelTimeoutError

warnings.warn(
"BeforeModelCallEvent, AfterModelCallEvent, BeforeToolCallEvent, and AfterToolCallEvent are no longer experimental."
"Import from strands.hooks instead.",
DeprecationWarning,
stacklevel=2,
)

BeforeToolInvocationEvent: TypeAlias = BeforeToolCallEvent
AfterToolInvocationEvent: TypeAlias = AfterToolCallEvent
BeforeModelInvocationEvent: TypeAlias = BeforeModelCallEvent
AfterModelInvocationEvent: TypeAlias = AfterModelCallEvent
# Deprecated aliases - warning emitted on access via __getattr__
_DEPRECATED_ALIASES = {
"BeforeToolInvocationEvent": BeforeToolCallEvent,
"AfterToolInvocationEvent": AfterToolCallEvent,
"BeforeModelInvocationEvent": BeforeModelCallEvent,
"AfterModelInvocationEvent": AfterModelCallEvent,
}


def __getattr__(name: str) -> Any:
if name in _DEPRECATED_ALIASES:
warnings.warn(
f"{name} has been moved to production with an updated name. "
f"Use {_DEPRECATED_ALIASES[name].__name__} from strands.hooks instead.",
DeprecationWarning,
stacklevel=2,
)
return _DEPRECATED_ALIASES[name]
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")


# BidiAgent Hook Events
Expand Down
18 changes: 10 additions & 8 deletions tests/strands/experimental/hooks/test_hook_aliases.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,18 +112,20 @@ def experimental_callback(event: BeforeToolInvocationEvent):
assert received_event is test_event


def test_deprecation_warning_on_import(captured_warnings):
"""Verify that importing from experimental module emits deprecation warning."""
def test_deprecation_warning_on_access(captured_warnings):
"""Verify that accessing deprecated aliases emits deprecation warning."""
import strands.experimental.hooks.events as events_module

module = sys.modules.get("strands.experimental.hooks.events")
if module:
importlib.reload(module)
else:
importlib.import_module("strands.experimental.hooks.events")
# Clear any existing warnings
captured_warnings.clear()

# Access a deprecated alias - this should trigger the warning
_ = events_module.BeforeToolInvocationEvent

assert len(captured_warnings) == 1
assert issubclass(captured_warnings[0].category, DeprecationWarning)
assert "are no longer experimental" in str(captured_warnings[0].message)
assert "BeforeToolInvocationEvent" in str(captured_warnings[0].message)
assert "BeforeToolCallEvent" in str(captured_warnings[0].message)


def test_deprecation_warning_on_import_only_for_experimental(captured_warnings):
Expand Down