simonw--llm
92a9ca7cbf
The async execute_tool_calls() silently dropped calls to tools that were not in tools= (or had no implementation): output and exception were assigned but no ToolResult was ever appended, so the next provider call carried an assistant tool_call with no matching result - which OpenAI and Anthropic reject. The sync executor already returned an 'Error: tool ... does not exist' result. The async path now mirrors the sync one: before_call fires (and can CancelToolCall) even though the tool is unavailable, and an error ToolResult is appended in call order. Also removes the now-unreachable tool-is-None branch from the inline sync-implementation path. This matters more since chain resume landed: a pending call whose tool is no longer registered would otherwise never resolve. Co-authored-by: Claude Fable 5 <noreply@anthropic.com>