diff --git a/cli-config.yaml.example b/cli-config.yaml.example index 977acbe927..7808632cda 100644 --- a/cli-config.yaml.example +++ b/cli-config.yaml.example @@ -790,8 +790,11 @@ code_execution: # Supports single tasks and batch mode (default 3 parallel, configurable). delegation: max_iterations: 50 # Max tool-calling turns per child (default: 50) - # max_concurrent_children: 3 # Max parallel child agents (default: 3) - # max_spawn_depth: 1 # Tree depth cap (1-3, default: 1 = flat). Raise to 2 or 3 to allow orchestrator children to spawn their own workers. + max_concurrent_children: 3 # Max parallel child agents per batch (default: 3, floor: 1, no ceiling). + # WARNING: values above 10 multiply API cost linearly. + max_spawn_depth: 1 # Delegation tree depth cap (range: 1-3, default: 1 = flat). + # Raise to 2 to allow workers to spawn their own subagents. + # Requires role="orchestrator" on intermediate agents. # orchestrator_enabled: true # Kill switch for role="orchestrator" children (default: true). # inherit_mcp_toolsets: true # When explicit child toolsets are narrowed, also keep the parent's MCP toolsets (default: true). Set false for strict intersection. # model: "google/gemini-3-flash-preview" # Override model for subagents (empty = inherit parent) diff --git a/tools/delegate_tool.py b/tools/delegate_tool.py index 2bbf354cf7..357452599f 100644 --- a/tools/delegate_tool.py +++ b/tools/delegate_tool.py @@ -276,7 +276,14 @@ def _get_max_concurrent_children() -> int: val = cfg.get("max_concurrent_children") if val is not None: try: - return max(1, int(val)) + result = max(1, int(val)) + if result > 10: + logger.warning( + "delegation.max_concurrent_children=%d: each child consumes API tokens " + "independently. High values multiply cost linearly.", + result, + ) + return result except (TypeError, ValueError): logger.warning( "delegation.max_concurrent_children=%r is not a valid integer; " @@ -2229,8 +2236,8 @@ DELEGATE_TASK_SCHEMA = { "never enter your context window.\n\n" "TWO MODES (one of 'goal' or 'tasks' is required):\n" "1. Single task: provide 'goal' (+ optional context, toolsets)\n" - "2. Batch (parallel): provide 'tasks' array with up to delegation.max_concurrent_children items (default 3). " - "All run concurrently and results are returned together.\n\n" + "2. Batch (parallel): provide 'tasks' array with up to delegation.max_concurrent_children items (default 3, configurable via config.yaml, no hard ceiling). " + "All run concurrently and results are returned together. Nested delegation requires role='orchestrator' and delegation.max_spawn_depth >= 2.\n\n" "WHEN TO USE delegate_task:\n" "- Reasoning-heavy subtasks (debugging, code review, research synthesis)\n" "- Tasks that would flood your context with intermediate data\n" diff --git a/website/docs/guides/delegation-patterns.md b/website/docs/guides/delegation-patterns.md index 11e276b121..b5d54faa40 100644 --- a/website/docs/guides/delegation-patterns.md +++ b/website/docs/guides/delegation-patterns.md @@ -216,8 +216,24 @@ Restricting toolsets keeps the subagent focused and prevents accidental side eff ## Constraints -- **Default 3 parallel tasks** — batches default to 3 concurrent subagents (configurable via `delegation.max_concurrent_children` in config.yaml — no hard ceiling, only a floor of 1) -- **Nested delegation is opt-in** — leaf subagents (default) cannot call `delegate_task`, `clarify`, `memory`, `send_message`, or `execute_code`. Orchestrator subagents (`role="orchestrator"`) retain `delegate_task` for further delegation, but only when `delegation.max_spawn_depth` is raised above the default of 1 (1-3 supported); the other four remain blocked. Disable globally via `delegation.orchestrator_enabled: false`. +- **Default 3 parallel tasks**: batches default to 3 concurrent subagents (configurable via `delegation.max_concurrent_children` in config.yaml, no hard ceiling, only a floor of 1) +- **Nested delegation is opt-in**: leaf subagents (default) cannot call `delegate_task`, `clarify`, `memory`, `send_message`, or `execute_code`. Orchestrator subagents (`role="orchestrator"`) retain `delegate_task` for further delegation, but only when `delegation.max_spawn_depth` is raised above the default of 1 (1-3 supported); the other four remain blocked. Disable globally via `delegation.orchestrator_enabled: false`. + +### Tuning Concurrency and Depth + +| Config | Default | Range | Effect | +|--------|---------|-------|--------| +| `max_concurrent_children` | 3 | >=1 | Parallel batch size per `delegate_task` call | +| `max_spawn_depth` | 1 | 1-3 | How many delegation levels can spawn further | + +Example: running 30 parallel workers with nested subagents: + +```yaml +delegation: + max_concurrent_children: 30 + max_spawn_depth: 2 +``` + - **Separate terminals** — each subagent gets its own terminal session with separate working directory and state - **No conversation history** — subagents see only the `goal` and `context` the parent agent passes when calling `delegate_task` - **Default 50 iterations** — set `max_iterations` lower for simple tasks to save cost