diff --git a/cli-config.yaml.example b/cli-config.yaml.example index 92a194e1bcbb5..4dee7a61f3bc8 100644 --- a/cli-config.yaml.example +++ b/cli-config.yaml.example @@ -1396,7 +1396,7 @@ code_execution: # Supports single tasks and batch mode (default 3 parallel, configurable). delegation: max_iterations: 250 # Max tool-calling turns per child (default: 250) - # max_concurrent_children: 3 # Max parallel child agents per batch (default: 3, floor: 1, no ceiling). + # max_concurrent_children: 10 # Max parallel child agents per batch (default: 10, 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. diff --git a/hermes_cli/config_defaults.py b/hermes_cli/config_defaults.py index 5ffd661354c21..0f29f5059efb4 100644 --- a/hermes_cli/config_defaults.py +++ b/hermes_cli/config_defaults.py @@ -1813,7 +1813,7 @@ # (floor 30s) to enforce a hard cap. "reasoning_effort": "", # subagent effort: "ultra", "max", "xhigh", "high", # "medium", "low", "minimal", "none" (empty = inherit) - "max_concurrent_children": 3, # unified concurrency cap: max parallel children per batch + "max_concurrent_children": 10, # unified concurrency cap: max parallel children per batch # AND max concurrent background (background=true) # delegation units. New async dispatches beyond the cap # fall back to synchronous execution. Floor of 1, no ceiling. @@ -3402,7 +3402,7 @@ }, # Config schema version - bump this when adding new required fields - "_config_version": 36, + "_config_version": 37, } # Optional environment variables that enhance functionality diff --git a/hermes_cli/config_migrations.py b/hermes_cli/config_migrations.py index 54f360c319fd6..b1464604fa436 100644 --- a/hermes_cli/config_migrations.py +++ b/hermes_cli/config_migrations.py @@ -784,6 +784,37 @@ def _migrate_to_36(results: Dict[str, Any], quiet: bool) -> None: ) +def _migrate_to_37(results: Dict[str, Any], quiet: bool) -> None: + # ── Version 36 → 37: raise the delegation concurrency default 3 → 10 ── + # delegation.max_concurrent_children caps how many children run in parallel + # per batch (and concurrent background delegation units). The old default of + # 3 needlessly serialized independent fan-outs (e.g. reviewing N PRs at + # once). The shipped default is now 10, which stays at/below the high-cost + # warning threshold. Configs still pinned at exactly the old default 3 — + # almost always the inherited default rather than a deliberate choice — are + # lifted to 10 so existing installs get the wider fan-out on update. Any + # OTHER explicit value (a deliberate override) is preserved; unset inherits + # 10 at read time. + _c = _cfg() + read_raw_config = _c.read_raw_config + _persist_migration = _c._persist_migration + + config = read_raw_config() + raw_deleg = config.get("delegation") + if isinstance(raw_deleg, dict) and raw_deleg.get("max_concurrent_children") == 3: + raw_deleg["max_concurrent_children"] = 10 + config["delegation"] = raw_deleg + _persist_migration(config) + results["config_added"].append("delegation.max_concurrent_children=10 (was: 3)") + if not quiet: + print( + " ✓ Raised delegation.max_concurrent_children from 3 to 10 — " + "independent delegated children now fan out wider in parallel. " + "Each child consumes API tokens independently; set " + "delegation.max_concurrent_children back to 3 to restore the old cap." + ) + + #: Registry of (target_version, migration_fn), strictly ascending. The driver #: applies every entry whose target version is greater than the on-disk #: observe earlier steps' writes via read_raw_config() (filesystem state). @@ -807,6 +838,7 @@ def _migrate_to_36(results: Dict[str, Any], quiet: bool) -> None: (34, _migrate_to_34), (35, _migrate_to_35), (36, _migrate_to_36), + (37, _migrate_to_37), ) diff --git a/tools/delegate_tool.py b/tools/delegate_tool.py index fd47d15133eb5..a8da6988a5e8e 100644 --- a/tools/delegate_tool.py +++ b/tools/delegate_tool.py @@ -119,7 +119,7 @@ def _get_subagent_approval_callback(): # "delegation" toolset in _build_child_agent), NOT by the model naming toolsets # — the model has no toolsets argument. Subagents inherit the parent's toolsets. -_DEFAULT_MAX_CONCURRENT_CHILDREN = 3 +_DEFAULT_MAX_CONCURRENT_CHILDREN = 10 # One-shot guard: the high-concurrency cost advisory is emitted at most once # per process. _get_max_concurrent_children() runs on every get_definitions() # schema rebuild (via _build_top_level_description / _build_tasks_param_description), @@ -733,7 +733,7 @@ def _normalize_role(r: Optional[str]) -> str: def _get_max_concurrent_children() -> int: """Read delegation.max_concurrent_children from config, falling back to - DELEGATION_MAX_CONCURRENT_CHILDREN env var, then the default (3). + DELEGATION_MAX_CONCURRENT_CHILDREN env var, then the default (10). Users can raise this as high as they want; only the floor (1) is enforced.