Tool Executors
Tool executors control whether tools from a single assistant turn run concurrently or sequentially. Both SDKs default to concurrent execution.
Concurrent Executor
Section titled “Concurrent Executor”Concurrent execution runs all tool calls from a single turn in parallel. This is the default in both SDKs — you get it without any extra configuration.
from strands import Agentfrom strands.tools.executors import ConcurrentToolExecutor
agent = Agent( tool_executor=ConcurrentToolExecutor(), tools=[weather_tool, time_tool])# or simply Agent(tools=[weather_tool, time_tool])
agent("What is the weather and time in New York?")import { Agent } from '@strands-agents/sdk'
const agent = new Agent({ tools: [weatherTool, timeTool], toolExecutor: 'concurrent',})// or simply: new Agent({ tools: [weatherTool, timeTool] })
await agent.invoke('What is the weather and time in New York?')Assuming the model returns weather_tool and time_tool use requests, the concurrent executor runs both at the same time. End-to-end latency scales with the slowest tool rather than their sum.
Sequential Behavior
Section titled “Sequential Behavior”On certain prompts, the model may decide to return one tool use request at a time. Under these circumstances, the tools will execute sequentially. Concurrency is only achieved if the model returns multiple tool use requests in a single response. Certain models however offer additional abilities to coerce a desired behavior. For example, Anthropic exposes an explicit parallel tool use setting (docs).
Sequential Executor
Section titled “Sequential Executor”Use sequential execution when tool order matters — for example, when a later tool depends on a side effect of an earlier one:
from strands import Agentfrom strands.tools.executors import SequentialToolExecutor
agent = Agent( tool_executor=SequentialToolExecutor(), tools=[screenshot_tool, email_tool])
agent("Please take a screenshot and then email the screenshot to my friend")import { Agent } from '@strands-agents/sdk'
const agent = new Agent({ tools: [screenshotTool, emailTool], toolExecutor: 'sequential',})
await agent.invoke('Take a screenshot and email it to my friend')Assuming the model returns screenshot_tool and email_tool use requests, the sequential executor runs both in the order given.
Event Ordering
Section titled “Event Ordering”Both modes preserve per-tool event order. In concurrent mode, events from different tools may interleave across that per-tool sequence.
Per-tool event order: BeforeToolCallEvent → ToolStreamEvent* → AfterToolCallEvent → ToolResultEvent.
Per-tool event order: BeforeToolCallEvent → ToolStreamUpdateEvent* → AfterToolCallEvent → ToolResultEvent.
BeforeToolsEvent and AfterToolsEvent bracket the entire batch. AfterToolsEvent.message contains results in the original tool-use-block source order regardless of completion order.
Cancellation
Section titled “Cancellation”Cancellation works identically in both modes. Call agent.cancel() to request cooperative cancellation. In TypeScript, this flips agent.cancelSignal.
- Pre-launch cancel: set
BeforeToolCallEvent.cancel_toolon a per-tool hook to produce an error result for that tool. - Mid-flight cancel in sequential mode short-circuits not-yet-started tools. In concurrent mode, all tools have already launched, so each in-flight tool must cooperatively check for cancellation to stop early.
- Pre-launch cancel: set
BeforeToolsEvent.cancelon the batch-level hook, or callagent.cancel()before tools start, to produce error results for every tool in the batch. - Mid-flight cancel in sequential mode short-circuits not-yet-started tools. In concurrent mode, all tools have already launched, so each in-flight tool must cooperatively observe
agent.cancelSignalto stop early.
Custom Executors
Section titled “Custom Executors”In Python, you can create custom executors by subclassing ToolExecutor. You can track progress on this feature at GitHub Issue #762.