mirror of
https://github.com/hanzoai/python-sdk.git
synced 2026-10-26 11:49:36 +00:00
fix(mcp): ensure tool_result blocks for all tool_use blocks to prevent API errors
Fixes critical issue where tool_use blocks could be orphaned without corresponding tool_result blocks, causing Claude API 400 errors: "tool_use ids were found without tool_result blocks immediately after" Changes: - Collect tool results atomically before adding to messages - Add error recovery to append tool_result for any orphaned tool_use blocks - Ensures 1:1 pairing of tool_use and tool_result even on exceptions Location: hanzo_mcp/tools/agent/agent_tool_v1_deprecated.py:449-603
This commit is contained in:
@@ -450,6 +450,9 @@ AGENT RESPONSES:
|
||||
tool_call_count = len(message.tool_calls)
|
||||
await tool_ctx.info(f"Processing {tool_call_count} tool calls")
|
||||
|
||||
# Track which tool calls we've processed to ensure all get results
|
||||
tool_results_to_add = []
|
||||
|
||||
for tool_call in message.tool_calls:
|
||||
total_tool_use_count += 1
|
||||
function_name = tool_call.function.name
|
||||
@@ -542,8 +545,8 @@ AGENT RESPONSES:
|
||||
await tool_ctx.info(
|
||||
f"tool {function_name} run with args {function_args} and return {tool_result[: min(100, len(tool_result))]}"
|
||||
)
|
||||
# Add the tool result to messages
|
||||
messages.append(
|
||||
# Add the tool result to the list
|
||||
tool_results_to_add.append(
|
||||
{
|
||||
"role": "tool",
|
||||
"tool_call_id": tool_call.id,
|
||||
@@ -552,6 +555,9 @@ AGENT RESPONSES:
|
||||
}
|
||||
)
|
||||
|
||||
# Add all tool results to messages atomically
|
||||
messages.extend(tool_results_to_add)
|
||||
|
||||
# Log progress
|
||||
await tool_ctx.info(f"Processed {len(message.tool_calls)} tool calls. Total: {total_tool_use_count}")
|
||||
|
||||
@@ -559,6 +565,41 @@ AGENT RESPONSES:
|
||||
await tool_ctx.error(f"Error in model call: {str(e)}")
|
||||
# Avoid trying to JSON serialize message objects
|
||||
await tool_ctx.error(f"Message count: {len(messages)}")
|
||||
|
||||
# CRITICAL FIX: Ensure we add tool_result messages for any tool_use blocks that were added
|
||||
# Get the last assistant message (which has the tool_calls)
|
||||
last_assistant_msg = None
|
||||
for msg in reversed(messages):
|
||||
if msg.get("role") == "assistant" and hasattr(msg, "tool_calls"):
|
||||
last_assistant_msg = msg
|
||||
break
|
||||
|
||||
# If there are orphaned tool calls, add error results for them
|
||||
if last_assistant_msg and hasattr(last_assistant_msg, "tool_calls"):
|
||||
# Count how many tool results we already have after this message
|
||||
tool_results_count = 0
|
||||
found_assistant = False
|
||||
for msg in reversed(messages):
|
||||
if msg == last_assistant_msg:
|
||||
found_assistant = True
|
||||
break
|
||||
if found_assistant and msg.get("role") == "tool":
|
||||
tool_results_count += 1
|
||||
|
||||
# Add error results for any missing tool calls
|
||||
expected_results = len(last_assistant_msg.tool_calls)
|
||||
if tool_results_count < expected_results:
|
||||
for i in range(tool_results_count, expected_results):
|
||||
tool_call = last_assistant_msg.tool_calls[i]
|
||||
messages.append(
|
||||
{
|
||||
"role": "tool",
|
||||
"tool_call_id": tool_call.id,
|
||||
"name": tool_call.function.name,
|
||||
"content": f"Error: Tool execution interrupted - {str(e)}",
|
||||
}
|
||||
)
|
||||
|
||||
return f"Error in agent execution: {str(e)}"
|
||||
|
||||
# If we've reached the limit, add a warning and get final response
|
||||
|
||||
Reference in New Issue
Block a user