@@ -44,14 +44,16 @@ class SlidingWindowConversationManager(ConversationManager):
44
44
invalid window states.
45
45
"""
46
46
47
- def __init__ (self , window_size : int = 40 ):
47
+ def __init__ (self , window_size : int = 40 , should_truncate_results : bool = True ):
48
48
"""Initialize the sliding window conversation manager.
49
49
50
50
Args:
51
51
window_size: Maximum number of messages to keep in the agent's history.
52
52
Defaults to 40 messages.
53
+ should_truncate_results: Truncate tool results when a message is too large for the model's context window
53
54
"""
54
55
self .window_size = window_size
56
+ self .should_truncate_results = should_truncate_results
55
57
56
58
def apply_management (self , agent : "Agent" ) -> None :
57
59
"""Apply the sliding window to the agent's messages array to maintain a manageable history size.
@@ -127,6 +129,19 @@ def reduce_context(self, agent: "Agent", e: Optional[Exception] = None) -> None:
127
129
converted.
128
130
"""
129
131
messages = agent .messages
132
+
133
+ # Try to truncate the tool result first
134
+ last_message_idx_with_tool_results = self ._find_last_message_with_tool_results (messages )
135
+ if last_message_idx_with_tool_results is not None and self .should_truncate_results :
136
+ logger .debug (
137
+ "message_index=<%s> | found message with tool results at index" , last_message_idx_with_tool_results
138
+ )
139
+ results_truncated = self ._truncate_tool_results (messages , last_message_idx_with_tool_results )
140
+ if results_truncated :
141
+ logger .debug ("message_index=<%s> | tool results truncated" , last_message_idx_with_tool_results )
142
+ return
143
+
144
+ # Try to trim index id when tool result cannot be truncated anymore
130
145
# If the number of messages is less than the window_size, then we default to 2, otherwise, trim to window size
131
146
trim_index = 2 if len (messages ) <= self .window_size else len (messages ) - self .window_size
132
147
@@ -151,3 +166,69 @@ def reduce_context(self, agent: "Agent", e: Optional[Exception] = None) -> None:
151
166
152
167
# Overwrite message history
153
168
messages [:] = messages [trim_index :]
169
+
170
+ def _truncate_tool_results (self , messages : Messages , msg_idx : int ) -> bool :
171
+ """Truncate tool results in a message to reduce context size.
172
+
173
+ When a message contains tool results that are too large for the model's context window, this function
174
+ replaces the content of those tool results with a simple error message.
175
+
176
+ Args:
177
+ messages: The conversation message history.
178
+ msg_idx: Index of the message containing tool results to truncate.
179
+
180
+ Returns:
181
+ True if any changes were made to the message, False otherwise.
182
+ """
183
+ if msg_idx >= len (messages ) or msg_idx < 0 :
184
+ return False
185
+
186
+ message = messages [msg_idx ]
187
+ changes_made = False
188
+ tool_result_too_large_message = "The tool result was too large!"
189
+ for i , content in enumerate (message .get ("content" , [])):
190
+ if isinstance (content , dict ) and "toolResult" in content :
191
+ tool_result_content_text = next (
192
+ (item ["text" ] for item in content ["toolResult" ]["content" ] if "text" in item ),
193
+ "" ,
194
+ )
195
+ # make the overwriting logic togglable
196
+ if (
197
+ message ["content" ][i ]["toolResult" ]["status" ] == "error"
198
+ and tool_result_content_text == tool_result_too_large_message
199
+ ):
200
+ logger .info ("ToolResult has already been updated, skipping overwrite" )
201
+ return False
202
+ # Update status to error with informative message
203
+ message ["content" ][i ]["toolResult" ]["status" ] = "error"
204
+ message ["content" ][i ]["toolResult" ]["content" ] = [{"text" : tool_result_too_large_message }]
205
+ changes_made = True
206
+
207
+ return changes_made
208
+
209
+ def _find_last_message_with_tool_results (self , messages : Messages ) -> Optional [int ]:
210
+ """Find the index of the last message containing tool results.
211
+
212
+ This is useful for identifying messages that might need to be truncated to reduce context size.
213
+
214
+ Args:
215
+ messages: The conversation message history.
216
+
217
+ Returns:
218
+ Index of the last message with tool results, or None if no such message exists.
219
+ """
220
+ # Iterate backwards through all messages (from newest to oldest)
221
+ for idx in range (len (messages ) - 1 , - 1 , - 1 ):
222
+ # Check if this message has any content with toolResult
223
+ current_message = messages [idx ]
224
+ has_tool_result = False
225
+
226
+ for content in current_message .get ("content" , []):
227
+ if isinstance (content , dict ) and "toolResult" in content :
228
+ has_tool_result = True
229
+ break
230
+
231
+ if has_tool_result :
232
+ return idx
233
+
234
+ return None
0 commit comments