Skip to main content
Concurrency controls let you limit parallel agent execution and set timeouts for tool calls to prevent resource exhaustion.
The user runs parallel work; concurrency controls cap simultaneous operations and tool timeouts.

Quick Start

1

Limit parallel runs of an agent

Control how many instances of the same agent can run concurrently:
2

Same, async

Use async context for better resource utilization:
3

Bound tool time with ToolConfig

Prevent slow tools from blocking agent execution:

How It Works


Sync vs Async Rule

The concurrency registry enforces strict separation between sync and async contexts:
Calling acquire_sync() from an async context raises RuntimeError("acquire_sync('<agent_name>') cannot be called with a running event loop; use async acquire() in async contexts."). Use await acquire() instead.
Example error:

Tool Timeout Behavior

When tool_config=ToolConfig(timeout=...) is set, tools run in a dedicated executor with these characteristics: In YAML the field name is still tool_timeout:; in Python use tool_config=ToolConfig(timeout=…).

Timeout Return Shape

On timeout, each layer surfaces the timeout differently:

Effective Timeout Precedence

When multiple tool_timeout values are declared, the wrapper resolves a single effective timeout applied to every tool in the shared tool dict:
  1. CLI wins. An explicit --tool-timeout N on the command line (or cli_config={"tool_timeout": N} when embedding) is used verbatim.
  2. Otherwise, the largest per-role/per-agent value. The wrapper picks max(tool_timeout) across every entry under roles: and agents: in the YAML. This is the safest default for a shared tool dict — a slow-tool role won’t have its tools killed by another role’s stricter timeout.
  3. Otherwise, no wrapping. If nothing declares a timeout, tools run without wrapper-layer enforcement (the SDK executor-layer enforcement still applies if tool_config=ToolConfig(timeout=…) is set in Python).
The resolver is AgentsGenerator._resolve_effective_tool_timeout(config) — see praisonai/agents_generator.py.
YAML boolean values are ignored, not coerced. Because bool subclasses int in Python, tool_timeout: yes or tool_timeout: true used to silently become a 1-second cap on every tool. As of PR #2609 the resolver explicitly rejects bool values — such entries are treated as “not declared” and fall through to the next precedence level. Use an integer or float (e.g. tool_timeout: 30).

Executor Details

  • One executor per Agent instance (lazy creation)
  • max_workers=2 threads per agent
  • Thread name prefix: tool-<agent_name> — useful for log filtering
  • Reused across calls — no resource leak
Which timeout to choose:

Common Patterns

Limit FastAPI Route Concurrency

Async Context Manager Helper

Timeout Selection by Tool Type


Best Practices

Prevents deadlocks when exceptions occur:
Keep acquisition method consistent with execution context:
Any tool that does network IO should have a timeout:
Filter logs by agent name using the thread prefix:

Retries

Tool failures can be automatically retried using the retry policy feature. This works alongside timeouts to handle transient errors:
For complete retry configuration and error handling strategies, see Tool Retry Policy.

Tool Retry Policy

Automatically retry failed tool calls with exponential backoff

Tool Configuration

Tool timeout settings and performance tuning

Async Bridge

Safe sync↔async boundary crossing utilities

Thread Safety

Chat history and state protection mechanisms