Fix infinite loop in fix_message_list when assistant has multiple tool_calls

When an assistant message has multiple tool_calls and the tool responses
arrive out of order, the second pass of fix_message_list enters an
infinite loop. This happens because the validity check only looks at the
immediately preceding message (which may be a sibling tool response)
rather than walking backward past sibling tool messages to find the
parent assistant message.

The fix walks backward past sibling tool messages to locate the nearest
assistant message before checking whether the sequence is valid. This
correctly handles the case where multiple tool responses follow the same
assistant message.

Fixes #410
This commit is contained in:
Julio Cesar Suastegui 2026-03-27 13:47:16 -06:00
parent fd5ca01b7e
commit cf9cc4b39e
1 changed files with 12 additions and 2 deletions

View File

@ -1244,9 +1244,19 @@ def fix_message_list(messages): # pylint: disable=R0914,R0915,R0912
# If this isn't the first message, check if the previous message is a matching assistant message
if i > 0:
prev_msg = processed_messages[i - 1]
# Walk backward past sibling tool messages to find the nearest
# assistant. This avoids an infinite loop when an assistant has
# multiple tool_calls and their responses arrive out of order:
# the previous message may be a sibling tool response rather
# than the parent assistant message, which is still valid.
k = i - 1
while k >= 0 and processed_messages[k].get("role") == "tool":
k -= 1
# Check if the previous message is an assistant message with matching tool_call_id
prev_msg = processed_messages[k] if k >= 0 else {}
# Check if the nearest non-tool ancestor is an assistant message
# with a matching tool_call_id
is_valid_sequence = (
prev_msg.get("role") == "assistant"
and prev_msg.get("tool_calls")