55import boto3
66import pytest
77
8- from strands import Agent
8+ from strands import Agent , tool
99from strands .models .bedrock import BedrockModel
1010from strands .session .file_session_manager import FileSessionManager
1111
@@ -189,7 +189,7 @@ def test_guardrail_output_intervention_redact_output(bedrock_guardrail, processi
189189 In async streaming: The buffering is non-blocking.
190190 Tokens are streamed while Guardrails processes the buffered content in the background.
191191 This means the response may be returned before Guardrails has finished processing.
192- As a result, we cannot guarantee that the REDACT_MESSAGE is in the response
192+ As a result, we cannot guarantee that the REDACT_MESSAGE is in the response.
193193 """
194194 if processing_mode == "sync" :
195195 assert REDACT_MESSAGE in str (response1 )
@@ -209,6 +209,67 @@ def test_guardrail_output_intervention_redact_output(bedrock_guardrail, processi
209209 )
210210
211211
212+ @pytest .mark .parametrize ("processing_mode" , ["sync" , "async" ])
213+ def test_guardrail_output_intervention_does_not_redact_tool_result (bedrock_guardrail , processing_mode ):
214+ REDACT_MESSAGE = "Redacted."
215+ bedrock_model = BedrockModel (
216+ guardrail_id = bedrock_guardrail ,
217+ guardrail_version = "DRAFT" ,
218+ guardrail_stream_processing_mode = processing_mode ,
219+ guardrail_redact_output = True ,
220+ guardrail_redact_output_message = REDACT_MESSAGE ,
221+ region_name = "us-east-1" ,
222+ )
223+
224+ @tool
225+ def list_users () -> str :
226+ "List my users"
227+ return """[{"name": "Jerry Merry", "email": "[email protected] "}, 228+ {"name": "CACTUS", "email": "[email protected] "}""" 229+
230+ agent = Agent (
231+ model = bedrock_model ,
232+ system_prompt = "You are a helpful assistant." ,
233+ callback_handler = None ,
234+ load_tools_from_directory = False ,
235+ tools = [list_users ],
236+ )
237+
238+ response1 = agent ("List my users." )
239+ response2 = agent ("Hello!" )
240+
241+ assert response1 .stop_reason == "guardrail_intervened"
242+
243+ """
244+ In async streaming: The buffering is non-blocking.
245+ Tokens are streamed while Guardrails processes the buffered content in the background.
246+ This means the response may be returned before Guardrails has finished processing.
247+ As a result, we cannot guarantee that the REDACT_MESSAGE is in the response
248+ However, response2 should not be blocked anyway.
249+ """
250+ if processing_mode == "sync" :
251+ assert REDACT_MESSAGE in str (response1 )
252+ assert response2 .stop_reason != "guardrail_intervened"
253+ assert REDACT_MESSAGE not in str (response2 )
254+ # Input not redacted being an output intervention
255+ assert agent .messages [0 ]["content" ][0 ]["text" ] != REDACT_MESSAGE
256+ # Tool blocks not redacted
257+ assert any ("toolUse" in block for block in agent .messages [1 ]["content" ])
258+ assert "toolResult" in agent .messages [2 ]["content" ][0 ]
259+ # Output correctly redacted
260+ assert agent .messages [3 ]["content" ][0 ]["text" ] == REDACT_MESSAGE
261+ else :
262+ cactus_returned_in_response1_blocked_by_input_guardrail = BLOCKED_INPUT in str (response2 )
263+ cactus_blocked_in_response1_allows_next_response = (
264+ REDACT_MESSAGE not in str (response2 ) and response2 .stop_reason != "guardrail_intervened"
265+ )
266+ assert (
267+ cactus_returned_in_response1_blocked_by_input_guardrail or cactus_blocked_in_response1_allows_next_response
268+ )
269+ # Output correctly redacted
270+ assert agent .messages [3 ]["content" ][0 ]["text" ] == REDACT_MESSAGE
271+
272+
212273def test_guardrail_input_intervention_properly_redacts_in_session (boto_session , bedrock_guardrail , temp_dir ):
213274 bedrock_model = BedrockModel (
214275 guardrail_id = bedrock_guardrail ,
0 commit comments