feat(agent): add call_agents_parallel tool for concurrent sub-agent fan-out - #47
Conversation
…an-out callable_agents delegation previously only supported one child session at a time via call_agent_* (blocking until idle). Adds a call_agents_parallel derived tool that fans out N delegate calls concurrently (worker-pool limiter, no new dependency), aggregates per-child success/failure + thread id, and caps concurrency via the new max_parallel_subagents agent config field (default 5, hard ceiling 10 regardless of config). Closes #20 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0153JT4zR2YdjkGwMkCaGmF9
|
Warning Review limit reached
Next review available in: 29 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (9)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Code Review
This pull request introduces the call_agents_parallel tool, enabling agents to delegate tasks to multiple sub-agents concurrently and aggregate their results. It adds support for a configurable concurrency cap (max_parallel_subagents) with a default of 5 and a hard ceiling of 10, along with detailed delegation capabilities to surface child thread IDs. Feedback was provided regarding a potential edge case where an invalid or non-finite concurrency configuration could evaluate to NaN and cause silent execution failures, along with a suggested fix to sanitize the input.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| const configuredLimit = agentConfig.max_parallel_subagents; | ||
| const concurrencyLimit = Math.min( | ||
| MAX_PARALLEL_SUBAGENTS_HARD_CAP, | ||
| Math.max(1, configuredLimit ?? DEFAULT_MAX_PARALLEL_SUBAGENTS), | ||
| ); |
There was a problem hiding this comment.
If agentConfig.max_parallel_subagents is configured with an invalid value (such as NaN or a non-finite number), concurrencyLimit can evaluate to NaN. This propagates to runWithConcurrencyLimit and causes workerCount to be NaN, resulting in an empty worker array and a silent failure where no sub-agents are executed. Sanitizing the configured limit to ensure it is a finite integer prevents this.
const configuredLimit = agentConfig.max_parallel_subagents;
const concurrencyLimit = Math.min(
MAX_PARALLEL_SUBAGENTS_HARD_CAP,
Math.max(
1,
typeof configuredLimit === "number" && Number.isFinite(configuredLimit)
? Math.floor(configuredLimit)
: DEFAULT_MAX_PARALLEL_SUBAGENTS
),
);
Summary
call_agents_parallelderived tool (alongside the existingcall_agent_*single-call tools) generated whenevercallable_agentshas 1+ entries. It accepts{ calls: [{ agent_id, message }, ...] }and runs the delegate calls concurrently via a small worker-pool limiter (runWithConcurrencyLimitinapps/agent/src/harness/tools.ts— no new dependency).success/error/response/thread_id— one child failing never fails the whole tool call.max_parallel_subagentsfield onAgentConfig(default 5, hard ceiling 10 regardless of config) — plumbed throughpackages/api-types,packages/agents-store(create/update/detectChanges), andpackages/http-routes/src/agents.session-do.ts'srunSubAgentgained an optionalonThreadStartedcallback so the newdelegateToAgentDetailedenv hook can surface the child'ssession_thread_id(for Console deep-linking) without changing the existingdelegateToAgentreturn contract used bycall_agent_*.call_agents_parallelclassified as a builtin tool indefault-loop.ts(emitsagent.tool_use, notagent.custom_tool_use).AGENTS.md(Derived Tools table + new "Parallel Delegation" section +max_parallel_subagentsconfig field).Closes #20
Test plan
pnpm typecheckcleantest/unit/harness.test.ts(describe("call_agents_parallel", ...), 8 cases): tool generation gating, concurrent timing (3 children ~1x delay not 3x), partial-failure aggregation, unknownagent_idrejection without aborting the batch, concurrency-cap enforcement (max_parallel_subagents), per-childthread_idsurfacing viadelegateToAgentDetailed, and the no-delegate fallbackpnpm vitest run test/unit/harness.test.ts test/unit/agents-store-service.test.ts— 72 passedpnpm run test:packages(session-runtime, main-node, cap, integrations-adapters-node, sandbox) — all passedpnpm vitest run(all 120 files) is flaky in this sandbox regardless of this change — reran it twice and got two different sets of failing files (20 vs 11), all unrelated timeouts in files this PR doesn't touch (skills.test.ts,stress.test.ts,core.test.ts,implementation.test.ts,unit.test.ts). Verified viagit stashthat the same resource-contention timeouts reproduce on a clean baseline checkout too, and that all 5 of those files pass cleanly (133/141, 0 failed) when run in a smaller batch instead of the full 120-file suite at once.Note: per the task, another agent was concurrently working on issue #19 (long-running harness) which also touches
apps/agent/src/harness/— some merge conflicts against that PR are expected.🤖 Generated with Claude Code
https://claude.ai/code/session_0153JT4zR2YdjkGwMkCaGmF9