When an LLM Returns Multiple Tool Calls, Parallel Execution Is Not the Default Answer
Agent frameworks that default to `Promise.all()` for all tool calls will silently corrupt state when tools share resources. The scheduling logic belongs in the runtime, not in the model's natural-language reasoning, and getting it wrong produces bugs that are intermittent and hard to reproduce.
Models return tool call arrays with no awareness of runtime constraints. Parallel execution with `Promise.all()` cuts latency for independent reads like fetching multiple files or API endpoints, but it breaks when calls modify the same resource or depend on side effects from a previous step. Sequential execution inside a `for...of` loop preserves order for writes, CLI workflows, and browser automation, yet it still cannot solve true logical dependencies where a later call's parameters must be regenerated from an earlier result.
The real distinction is between three execution modes: parallel for independent I/O, sequential within a single round to control side effects, and cross-round loops where the model sees a ToolMessage and re-plans. A runtime that blindly parallelizes everything will produce race conditions on shared files, unpredictable browser states, and corrupted database transactions.
Error handling also differs. Wrapping each tool invocation in try/catch and returning error strings keeps `Promise.all()` from failing fast, giving the model a complete result array with both successes and failures to reason about in the next turn.
The core confusion in Agent tool execution is conflating two different kinds of 'order': the temporal order of side effects within a single turn, and the logical order of re-planning across turns. Sequential execution only solves the first.
Error handling design changes the entire execution model. Catching errors per-tool and returning strings instead of throwing turns `Promise.all()` from a brittle fail-fast mechanism into a resilient batch processor that surfaces partial failures to the model.
The article's decision table — parallel for independent reads, sequential for shared state, cross-round for true dependencies — is a minimal viable runtime policy that most Agent frameworks still lack.