Skip to content

Commit 8e32040

Browse files
committed
feat: move hook event firing into reduce_context methods
Fire BeforeReduceContextEvent and AfterReduceContextEvent inside each reduce_context() implementation instead of at the call site in the agent's event loop. This ensures hooks are triggered for all reduce_context calls: - From ContextWindowOverflowException handling in event loop - From ConversationManager.apply_management() for proactive reduction Hook callbacks are now synchronous (invoke_callbacks) since reduce_context is synchronous and may be called from sync contexts. Files modified: - agent.py: Remove hook firing from _execute_event_loop_cycle() - sliding_window_conversation_manager.py: Add sync hook calls - summarizing_conversation_manager.py: Add sync hook calls - null_conversation_manager.py: Add sync before hook Addresses reviewer feedback: hooks now fire regardless of reduction source.
1 parent a6732f1 commit 8e32040

File tree

4 files changed

+17
-7
lines changed

4 files changed

+17
-7
lines changed

src/strands/agent/agent.py

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,8 @@
3535
from ..handlers.callback_handler import PrintingCallbackHandler, null_callback_handler
3636
from ..hooks import (
3737
AfterInvocationEvent,
38-
AfterReduceContextEvent,
3938
AgentInitializedEvent,
4039
BeforeInvocationEvent,
41-
BeforeReduceContextEvent,
4240
HookCallback,
4341
HookProvider,
4442
HookRegistry,
@@ -965,13 +963,9 @@ async def _execute_event_loop_cycle(
965963
yield event
966964

967965
except ContextWindowOverflowException as e:
968-
await self.hooks.invoke_callbacks_async(BeforeReduceContextEvent(agent=self, exception=e))
969-
970966
# Try reducing the context size and retrying
971967
self.conversation_manager.reduce_context(self, e=e)
972968

973-
await self.hooks.invoke_callbacks_async(AfterReduceContextEvent(agent=self))
974-
975969
# Sync agent after reduce_context to keep conversation_manager_state up to date in the session
976970
if self._session_manager:
977971
self._session_manager.sync_agent(self)

src/strands/agent/conversation_manager/null_conversation_manager.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ def reduce_context(self, agent: "Agent", e: Exception | None = None, **kwargs: A
4040
e: If provided.
4141
ContextWindowOverflowException: If e is None.
4242
"""
43+
# Fire before event
44+
agent.hooks.invoke_callbacks(BeforeReduceContextEvent(agent=agent, exception=e))
45+
4346
if e:
4447
raise e
4548
else:

src/strands/agent/conversation_manager/sliding_window_conversation_manager.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
if TYPE_CHECKING:
77
from ...agent.agent import Agent
88

9-
from ...hooks import BeforeModelCallEvent, HookRegistry
9+
from ...hooks import BeforeModelCallEvent, BeforeReduceContextEvent, AfterReduceContextEvent, HookRegistry
1010
from ...types.content import ContentBlock, Messages
1111
from ...types.exceptions import ContextWindowOverflowException
1212
from ...types.tools import ToolResultContent
@@ -171,6 +171,9 @@ def reduce_context(self, agent: "Agent", e: Exception | None = None, **kwargs: A
171171
Such as when the conversation is already minimal or when tool result messages cannot be properly
172172
converted.
173173
"""
174+
# Fire before event
175+
agent.hooks.invoke_callbacks(BeforeReduceContextEvent(agent=agent, exception=e))
176+
174177
messages = agent.messages
175178

176179
# Try to truncate the tool result first
@@ -213,6 +216,9 @@ def reduce_context(self, agent: "Agent", e: Exception | None = None, **kwargs: A
213216
# Overwrite message history
214217
messages[:] = messages[trim_index:]
215218

219+
# Fire after event
220+
agent.hooks.invoke_callbacks(AfterReduceContextEvent(agent=agent))
221+
216222
def _truncate_tool_results(self, messages: Messages, msg_idx: int) -> bool:
217223
"""Truncate tool results and replace image blocks in a message to reduce context size.
218224

src/strands/agent/conversation_manager/summarizing_conversation_manager.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
from ...types.exceptions import ContextWindowOverflowException
1414
from ...types.tools import AgentTool
1515
from .conversation_manager import ConversationManager
16+
from ...hooks import BeforeReduceContextEvent, AfterReduceContextEvent
1617

1718
if TYPE_CHECKING:
1819
from ..agent import Agent
@@ -135,6 +136,9 @@ def reduce_context(self, agent: "Agent", e: Exception | None = None, **kwargs: A
135136
Raises:
136137
ContextWindowOverflowException: If the context cannot be summarized.
137138
"""
139+
# Fire before event
140+
agent.hooks.invoke_callbacks(BeforeReduceContextEvent(agent=agent, exception=e))
141+
138142
try:
139143
# Calculate how many messages to summarize
140144
messages_to_summarize_count = max(1, int(len(agent.messages) * self.summary_ratio))
@@ -171,6 +175,9 @@ def reduce_context(self, agent: "Agent", e: Exception | None = None, **kwargs: A
171175
# Replace the summarized messages with the summary
172176
agent.messages[:] = [self._summary_message] + remaining_messages
173177

178+
# Fire after event
179+
agent.hooks.invoke_callbacks(AfterReduceContextEvent(agent=agent))
180+
174181
except Exception as summarization_error:
175182
logger.error("Summarization failed: %s", summarization_error)
176183
raise summarization_error from e

0 commit comments

Comments
 (0)