Skip to content

Commit 3e5eb89

Browse files
fix: preserve tool results in context on cancellation
When user presses Ctrl+C during tool execution, tool results that already completed must be saved to context. Otherwise, the next LLM request fails with 'tool_use ids were found without tool_result blocks' errors from providers like Anthropic. After asyncio.gather() completes with tool results, we now add them to context BEFORE returning on cancellation (previously skipped this step). 🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier) Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
1 parent 0b9d040 commit 3e5eb89

File tree

1 file changed

+13
-3
lines changed

1 file changed

+13
-3
lines changed

amplifier_module_loop_basic/__init__.py

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -353,10 +353,20 @@ async def execute_single_tool(tc: Any, group_id: str) -> tuple[str, str]:
353353
*[execute_single_tool(tc, parallel_group_id) for tc in tool_calls]
354354
)
355355

356-
# Check for immediate cancellation - synthesize results for any pending tools
356+
# Check for immediate cancellation
357357
if coordinator and coordinator.cancellation.is_immediate:
358-
# Any tools that didn't complete will have been handled by gather
359-
# Just break out of the loop
358+
# MUST add tool results to context before returning
359+
# Otherwise we leave orphaned tool_calls without matching tool_results
360+
# which violates provider API contracts (Anthropic, OpenAI)
361+
for tool_call_id, content in tool_results:
362+
if hasattr(context, "add_message"):
363+
await context.add_message(
364+
{
365+
"role": "tool",
366+
"tool_call_id": tool_call_id,
367+
"content": content,
368+
}
369+
)
360370
await hooks.emit(
361371
ORCHESTRATOR_COMPLETE,
362372
{

0 commit comments

Comments
 (0)