Skip to content

Commit 43344b9

Browse files
committed
remove legacy steer method
1 parent 5b52895 commit 43344b9

File tree

5 files changed

+28
-94
lines changed

5 files changed

+28
-94
lines changed

src/strands/experimental/steering/core/handler.py

Lines changed: 4 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@
3535
"""
3636

3737
import logging
38-
import warnings
3938
from abc import ABC
4039
from typing import TYPE_CHECKING, Any
4140

@@ -96,7 +95,7 @@ async def _provide_tool_steering_guidance(self, event: BeforeToolCallEvent) -> N
9695
logger.debug("tool_name=<%s> | providing tool steering guidance", tool_name)
9796

9897
try:
99-
action = await self.steer_before_tool(event.agent, event.tool_use)
98+
action = await self.steer_before_tool(agent=event.agent, tool_use=event.tool_use)
10099
except Exception as e:
101100
logger.debug("tool_name=<%s>, error=<%s> | tool steering handler guidance failed", tool_name, e)
102101
return
@@ -141,7 +140,7 @@ async def _provide_model_steering_guidance(self, event: AfterModelCallEvent) ->
141140

142141
try:
143142
action = await self.steer_after_model(
144-
event.agent, event.stop_response.message, event.stop_response.stop_reason
143+
agent=event.agent, message=event.stop_response.message, stop_reason=event.stop_response.stop_reason
145144
)
146145
except Exception as e:
147146
logger.debug("error=<%s> | model steering handler guidance failed", e)
@@ -167,7 +166,7 @@ async def _handle_model_steering_action(self, action: ModelSteeringAction, event
167166
else:
168167
raise ValueError(f"Unknown steering action type for model response: {action}")
169168

170-
async def steer_before_tool(self, agent: "Agent", tool_use: ToolUse, **kwargs: Any) -> ToolSteeringAction:
169+
async def steer_before_tool(self, *, agent: "Agent", tool_use: ToolUse, **kwargs: Any) -> ToolSteeringAction:
171170
"""Provide contextual guidance before tool execution.
172171
173172
This method is called before a tool is executed, allowing the handler to:
@@ -191,7 +190,7 @@ async def steer_before_tool(self, agent: "Agent", tool_use: ToolUse, **kwargs: A
191190
return Proceed(reason="Default implementation: allowing tool execution")
192191

193192
async def steer_after_model(
194-
self, agent: "Agent", message: Message, stop_reason: StopReason, **kwargs: Any
193+
self, *, agent: "Agent", message: Message, stop_reason: StopReason, **kwargs: Any
195194
) -> ModelSteeringAction:
196195
"""Provide contextual guidance after model response.
197196
@@ -216,27 +215,3 @@ async def steer_after_model(
216215
Override this method to implement custom model steering logic
217216
"""
218217
return Proceed(reason="Default implementation: accepting model response")
219-
220-
async def steer(self, agent: "Agent", tool_use: ToolUse, **kwargs: Any) -> SteeringAction:
221-
"""Provide contextual guidance to help agent navigate complex workflows.
222-
223-
.. deprecated::
224-
Use `steer_before_tool` instead. This method will be removed in a future version.
225-
226-
Args:
227-
agent: The agent instance
228-
tool_use: The tool use object with name and arguments
229-
**kwargs: Additional keyword arguments for guidance evaluation
230-
231-
Returns:
232-
SteeringAction indicating how to guide the agent's next action
233-
234-
Note:
235-
Access steering context via self.steering_context
236-
"""
237-
warnings.warn(
238-
"steer() is deprecated and will be removed in a future version. Use steer_before_tool() instead.",
239-
DeprecationWarning,
240-
stacklevel=2,
241-
)
242-
return await self.steer_before_tool(agent, tool_use, **kwargs)

src/strands/experimental/steering/handlers/llm/llm_handler.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ def __init__(
5858
self.prompt_mapper = prompt_mapper or DefaultPromptMapper()
5959
self.model = model
6060

61-
async def steer_before_tool(self, agent: "Agent", tool_use: ToolUse, **kwargs: Any) -> ToolSteeringAction:
61+
async def steer_before_tool(self, *, agent: "Agent", tool_use: ToolUse, **kwargs: Any) -> ToolSteeringAction:
6262
"""Provide contextual guidance for tool usage.
6363
6464
Args:

tests/strands/experimental/steering/core/test_handler.py

Lines changed: 16 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
"""Unit tests for steering handler base class."""
22

3-
import warnings
43
from unittest.mock import AsyncMock, Mock
54

65
import pytest
@@ -15,7 +14,7 @@
1514
class TestSteeringHandler(SteeringHandler):
1615
"""Test implementation of SteeringHandler."""
1716

18-
async def steer_before_tool(self, agent, tool_use, **kwargs):
17+
async def steer_before_tool(self, *, agent, tool_use, **kwargs):
1918
return Proceed(reason="Test proceed")
2019

2120

@@ -66,7 +65,7 @@ async def test_proceed_action_flow():
6665
"""Test complete flow with Proceed action."""
6766

6867
class ProceedHandler(SteeringHandler):
69-
async def steer_before_tool(self, agent, tool_use, **kwargs):
68+
async def steer_before_tool(self, *, agent, tool_use, **kwargs):
7069
return Proceed(reason="Test proceed")
7170

7271
handler = ProceedHandler()
@@ -85,7 +84,7 @@ async def test_guide_action_flow():
8584
"""Test complete flow with Guide action."""
8685

8786
class GuideHandler(SteeringHandler):
88-
async def steer_before_tool(self, agent, tool_use, **kwargs):
87+
async def steer_before_tool(self, *, agent, tool_use, **kwargs):
8988
return Guide(reason="Test guidance")
9089

9190
handler = GuideHandler()
@@ -105,7 +104,7 @@ async def test_interrupt_action_approved_flow():
105104
"""Test complete flow with Interrupt action when approved."""
106105

107106
class InterruptHandler(SteeringHandler):
108-
async def steer_before_tool(self, agent, tool_use, **kwargs):
107+
async def steer_before_tool(self, *, agent, tool_use, **kwargs):
109108
return Interrupt(reason="Need approval")
110109

111110
handler = InterruptHandler()
@@ -124,7 +123,7 @@ async def test_interrupt_action_denied_flow():
124123
"""Test complete flow with Interrupt action when denied."""
125124

126125
class InterruptHandler(SteeringHandler):
127-
async def steer_before_tool(self, agent, tool_use, **kwargs):
126+
async def steer_before_tool(self, *, agent, tool_use, **kwargs):
128127
return Interrupt(reason="Need approval")
129128

130129
handler = InterruptHandler()
@@ -144,7 +143,7 @@ async def test_unknown_action_flow():
144143
"""Test complete flow with unknown action type raises error."""
145144

146145
class UnknownActionHandler(SteeringHandler):
147-
async def steer_before_tool(self, agent, tool_use, **kwargs):
146+
async def steer_before_tool(self, *, agent, tool_use, **kwargs):
148147
return Mock() # Not a valid SteeringAction
149148

150149
handler = UnknownActionHandler()
@@ -160,7 +159,7 @@ def test_register_steering_hooks_override():
160159
"""Test that _register_steering_hooks can be overridden."""
161160

162161
class CustomHandler(SteeringHandler):
163-
async def steer_before_tool(self, agent, tool_use, **kwargs):
162+
async def steer_before_tool(self, *, agent, tool_use, **kwargs):
164163
return Proceed(reason="Custom")
165164

166165
def register_hooks(self, registry, **kwargs):
@@ -201,7 +200,7 @@ def __init__(self, context_callbacks=None):
201200
providers = [MockContextProvider(context_callbacks)] if context_callbacks else None
202201
super().__init__(context_providers=providers)
203202

204-
async def steer_before_tool(self, agent, tool_use, **kwargs):
203+
async def steer_before_tool(self, *, agent, tool_use, **kwargs):
205204
return Proceed(reason="Test proceed")
206205

207206

@@ -285,7 +284,7 @@ async def test_model_steering_proceed_action_flow():
285284
"""Test model steering with Proceed action."""
286285

287286
class ModelProceedHandler(SteeringHandler):
288-
async def steer_after_model(self, agent, message, stop_reason, **kwargs):
287+
async def steer_after_model(self, *, agent, message, stop_reason, **kwargs):
289288
return Proceed(reason="Model response accepted")
290289

291290
handler = ModelProceedHandler()
@@ -309,7 +308,7 @@ async def test_model_steering_guide_action_flow():
309308
"""Test model steering with Guide action sets retry and adds message."""
310309

311310
class ModelGuideHandler(SteeringHandler):
312-
async def steer_after_model(self, agent, message, stop_reason, **kwargs):
311+
async def steer_after_model(self, *, agent, message, stop_reason, **kwargs):
313312
return Guide(reason="Please improve your response")
314313

315314
handler = ModelGuideHandler()
@@ -342,7 +341,7 @@ def __init__(self):
342341
super().__init__()
343342
self.steer_called = False
344343

345-
async def steer_after_model(self, agent, message, stop_reason, **kwargs):
344+
async def steer_after_model(self, *, agent, message, stop_reason, **kwargs):
346345
self.steer_called = True
347346
return Proceed(reason="Should not be called")
348347

@@ -361,7 +360,7 @@ async def test_model_steering_unknown_action_raises_error():
361360
"""Test model steering with unknown action type raises error."""
362361

363362
class UnknownModelActionHandler(SteeringHandler):
364-
async def steer_after_model(self, agent, message, stop_reason, **kwargs):
363+
async def steer_after_model(self, *, agent, message, stop_reason, **kwargs):
365364
return Mock() # Not a valid ModelSteeringAction
366365

367366
handler = UnknownModelActionHandler()
@@ -382,7 +381,7 @@ async def test_model_steering_exception_handling():
382381
"""Test model steering handles exceptions gracefully."""
383382

384383
class ExceptionModelHandler(SteeringHandler):
385-
async def steer_after_model(self, agent, message, stop_reason, **kwargs):
384+
async def steer_after_model(self, *, agent, message, stop_reason, **kwargs):
386385
raise RuntimeError("Test exception")
387386

388387
handler = ExceptionModelHandler()
@@ -407,7 +406,7 @@ async def test_tool_steering_exception_handling():
407406
"""Test tool steering handles exceptions gracefully."""
408407

409408
class ExceptionToolHandler(SteeringHandler):
410-
async def steer_before_tool(self, agent, tool_use, **kwargs):
409+
async def steer_before_tool(self, *, agent, tool_use, **kwargs):
411410
raise RuntimeError("Test exception")
412411

413412
handler = ExceptionToolHandler()
@@ -431,7 +430,7 @@ async def test_default_steer_before_tool_returns_proceed():
431430
tool_use = {"name": "test_tool"}
432431

433432
# Call the parent's default implementation
434-
result = await SteeringHandler.steer_before_tool(handler, agent, tool_use)
433+
result = await SteeringHandler.steer_before_tool(handler, agent=agent, tool_use=tool_use)
435434

436435
assert isinstance(result, Proceed)
437436
assert "Default implementation" in result.reason
@@ -446,30 +445,12 @@ async def test_default_steer_after_model_returns_proceed():
446445
stop_reason = "end_turn"
447446

448447
# Call the parent's default implementation
449-
result = await SteeringHandler.steer_after_model(handler, agent, message, stop_reason)
448+
result = await SteeringHandler.steer_after_model(handler, agent=agent, message=message, stop_reason=stop_reason)
450449

451450
assert isinstance(result, Proceed)
452451
assert "Default implementation" in result.reason
453452

454453

455-
# Deprecated steer() method test
456-
@pytest.mark.asyncio
457-
async def test_deprecated_steer_method_emits_warning():
458-
"""Test deprecated steer() method emits DeprecationWarning."""
459-
handler = TestSteeringHandler()
460-
agent = Mock()
461-
tool_use = {"name": "test_tool"}
462-
463-
with warnings.catch_warnings(record=True) as w:
464-
warnings.simplefilter("always")
465-
result = await handler.steer(agent, tool_use)
466-
467-
assert len(w) == 1
468-
assert issubclass(w[0].category, DeprecationWarning)
469-
assert "steer() is deprecated" in str(w[0].message)
470-
assert isinstance(result, Proceed)
471-
472-
473454
def test_register_hooks_registers_model_steering():
474455
"""Test that register_hooks registers model steering callback."""
475456
handler = TestSteeringHandler()

tests_integ/steering/test_model_steering.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ def __init__(self, should_guide: bool = False, guidance_message: str = ""):
2323
self.call_count = 0
2424

2525
async def steer_after_model(
26-
self, agent: Agent, message: Message, stop_reason: StopReason, **kwargs
26+
self, *, agent: Agent, message: Message, stop_reason: StopReason, **kwargs
2727
) -> ModelSteeringAction:
2828
"""Steer after model response."""
2929
self.call_count += 1
@@ -75,7 +75,7 @@ def __init__(self):
7575
self.retry_done = False
7676

7777
async def steer_after_model(
78-
self, agent: Agent, message: Message, stop_reason: StopReason, **kwargs
78+
self, *, agent: Agent, message: Message, stop_reason: StopReason, **kwargs
7979
) -> ModelSteeringAction:
8080
if not self.retry_done:
8181
self.retry_done = True
@@ -109,7 +109,7 @@ def __init__(self):
109109
self.call_count = 0
110110

111111
async def steer_after_model(
112-
self, agent: Agent, message: Message, stop_reason: StopReason, **kwargs
112+
self, *, agent: Agent, message: Message, stop_reason: StopReason, **kwargs
113113
) -> ModelSteeringAction:
114114
self.call_count += 1
115115

@@ -160,7 +160,7 @@ def __init__(self, required_tool: str):
160160
self.guidance_given = False
161161

162162
async def steer_after_model(
163-
self, agent: Agent, message: Message, stop_reason: StopReason, **kwargs
163+
self, *, agent: Agent, message: Message, stop_reason: StopReason, **kwargs
164164
) -> ModelSteeringAction:
165165
# Only check when model is trying to end the turn
166166
if stop_reason != "end_turn":

tests_integ/steering/test_tool_steering.py

Lines changed: 3 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
"""Integration tests for tool steering (steer_before_tool)."""
22

3-
import warnings
4-
53
import pytest
64

75
from strands import Agent, tool
@@ -32,7 +30,7 @@ async def test_llm_steering_handler_proceed():
3230
agent = Agent(tools=[send_notification])
3331
tool_use = {"name": "send_notification", "input": {"recipient": "user", "message": "hello"}}
3432

35-
effect = await handler.steer_before_tool(agent, tool_use)
33+
effect = await handler.steer_before_tool(agent=agent, tool_use=tool_use)
3634

3735
assert isinstance(effect, Proceed)
3836

@@ -50,7 +48,7 @@ async def test_llm_steering_handler_guide():
5048
agent = Agent(tools=[send_email, send_notification])
5149
tool_use = {"name": "send_email", "input": {"recipient": "user", "message": "hello"}}
5250

53-
effect = await handler.steer_before_tool(agent, tool_use)
51+
effect = await handler.steer_before_tool(agent=agent, tool_use=tool_use)
5452

5553
assert isinstance(effect, Guide)
5654

@@ -66,31 +64,11 @@ async def test_llm_steering_handler_interrupt():
6664
agent = Agent(tools=[send_email])
6765
tool_use = {"name": "send_email", "input": {"recipient": "user", "message": "hello"}}
6866

69-
effect = await handler.steer_before_tool(agent, tool_use)
67+
effect = await handler.steer_before_tool(agent=agent, tool_use=tool_use)
7068

7169
assert isinstance(effect, Interrupt)
7270

7371

74-
@pytest.mark.asyncio
75-
async def test_deprecated_steer_method_emits_warning():
76-
"""Test deprecated steer() method emits DeprecationWarning."""
77-
handler = LLMSteeringHandler(
78-
system_prompt="You MUST always allow send_notification calls. ALWAYS return proceed decision."
79-
)
80-
81-
agent = Agent(tools=[send_notification])
82-
tool_use = {"name": "send_notification", "input": {"recipient": "user", "message": "hello"}}
83-
84-
with warnings.catch_warnings(record=True) as w:
85-
warnings.simplefilter("always")
86-
effect = await handler.steer(agent, tool_use)
87-
88-
assert len(w) == 1
89-
assert issubclass(w[0].category, DeprecationWarning)
90-
assert "steer() is deprecated" in str(w[0].message)
91-
assert isinstance(effect, Proceed)
92-
93-
9472
def test_agent_with_tool_steering_e2e():
9573
"""End-to-end test of agent with steering handler guiding tool choice."""
9674
handler = LLMSteeringHandler(

0 commit comments

Comments
 (0)