1414
1515
1616def recover_message_on_max_tokens_reached (message : Message ) -> Message :
17- """Recover and clean up incomplete messages when max token limits are reached.
17+ """Recover and clean up messages when max token limits are reached.
1818
19- When a model response is truncated due to maximum token limits, tool use blocks may be
20- incomplete or malformed. This function inspects the message content and:
19+ When a model response is truncated due to maximum token limits, all tool use blocks
20+ should be replaced with informative error messages since they may be incomplete or
21+ unreliable. This function inspects the message content and:
2122
22- 1. Identifies incomplete tool use blocks (missing name, input, or toolUseId )
23- 2. Replaces incomplete tool uses with informative error messages
24- 3. Preserves all valid content blocks (text and complete tool uses )
23+ 1. Identifies all tool use blocks (regardless of validity )
24+ 2. Replaces all tool uses with informative error messages
25+ 3. Preserves all non-tool content blocks (text, images, etc. )
2526 4. Returns a cleaned message suitable for conversation history
2627
2728 This recovery mechanism ensures that the conversation can continue gracefully even when
28- model responses are truncated, providing clear feedback about what happened.
29+ model responses are truncated, providing clear feedback about what happened and preventing
30+ potentially incomplete or corrupted tool executions.
31+
32+ TODO: after https://github.com/strands-agents/sdk-python/issues/561 is completed, only the verifiable
33+ invalid tool_use content blocks need to be replaced.
2934
3035 Args:
3136 message: The potentially incomplete message from the model that was truncated
3237 due to max token limits.
3338
3439 Returns:
35- A cleaned Message with incomplete tool uses replaced by explanatory text content.
40+ A cleaned Message with all tool uses replaced by explanatory text content.
3641 The returned message maintains the same role as the input message.
3742
3843 Example:
39- If a message contains an incomplete tool use like :
44+ If a message contains any tool use (complete or incomplete) :
4045 ```
41- {"toolUse": {"name": "calculator"}} # missing input and toolUseId
46+ {"toolUse": {"name": "calculator", " input": {"expression": "2+2"}, " toolUseId": "123"}}
4247 ```
4348
4449 It will be replaced with:
4550 ```
4651 {"text": "The selected tool calculator's tool use was incomplete due to maximum token limits being reached."}
4752 ```
4853 """
49- logger .info ("handling max_tokens stop reason - inspecting incomplete message for invalid tool uses " )
54+ logger .info ("handling max_tokens stop reason - replacing all tool uses with error messages " )
5055
5156 valid_content : list [ContentBlock ] = []
5257 for content in message ["content" ] or []:
@@ -55,15 +60,8 @@ def recover_message_on_max_tokens_reached(message: Message) -> Message:
5560 valid_content .append (content )
5661 continue
5762
58- # Check if tool use is incomplete (missing or empty required fields)
59- tool_name = tool_use .get ("name" )
60- if tool_name and tool_use .get ("input" ) and tool_use .get ("toolUseId" ):
61- # As far as we can tell, tool use is valid if this condition is true
62- valid_content .append (content )
63- continue
64-
65- # Tool use is incomplete due to max_tokens truncation
66- display_name = tool_name if tool_name else "<unknown>"
63+ # Replace all tool uses with error messages when max_tokens is reached
64+ display_name = tool_use .get ("name" , "<unknown>" )
6765 logger .warning ("tool_name=<%s> | replacing with error message due to max_tokens truncation." , display_name )
6866
6967 valid_content .append (
0 commit comments