Skip to content

Commit eb2e713

Browse files
fix: handle CancelledError for immediate cancellation during tool execution
When asyncio.gather() is cancelled mid-execution (second Ctrl+C), synthesize 'cancelled' tool results for all tool_calls before re-raising the exception. This maintains the required tool_use/tool_result pairing in the conversation context, preventing API errors from orphaned tool calls. 🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier) Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
1 parent 3e5eb89 commit eb2e713

File tree

1 file changed

+21
-4
lines changed

1 file changed

+21
-4
lines changed

amplifier_module_loop_basic/__init__.py

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -349,11 +349,28 @@ async def execute_single_tool(tc: Any, group_id: str) -> tuple[str, str]:
349349

350350
# Execute all tools in parallel with asyncio.gather
351351
# return_exceptions=False because we handle exceptions inside execute_single_tool
352-
tool_results = await asyncio.gather(
353-
*[execute_single_tool(tc, parallel_group_id) for tc in tool_calls]
354-
)
352+
# Wrap in try/except for CancelledError to handle immediate cancellation
353+
try:
354+
tool_results = await asyncio.gather(
355+
*[execute_single_tool(tc, parallel_group_id) for tc in tool_calls]
356+
)
357+
except asyncio.CancelledError:
358+
# Immediate cancellation (second Ctrl+C) - synthesize cancelled results
359+
# for ALL tool_calls to maintain tool_use/tool_result pairing
360+
logger.info("Tool execution cancelled - synthesizing cancelled results")
361+
for tc in tool_calls:
362+
if hasattr(context, "add_message"):
363+
await context.add_message(
364+
{
365+
"role": "tool",
366+
"tool_call_id": tc.id,
367+
"content": f'{{"error": "Tool execution was cancelled by user", "cancelled": true, "tool": "{tc.name}"}}',
368+
}
369+
)
370+
# Re-raise to let the cancellation propagate
371+
raise
355372

356-
# Check for immediate cancellation
373+
# Check for immediate cancellation (graceful path - tools completed)
357374
if coordinator and coordinator.cancellation.is_immediate:
358375
# MUST add tool results to context before returning
359376
# Otherwise we leave orphaned tool_calls without matching tool_results

0 commit comments

Comments
 (0)