Loading...
Loading...
Parallel Agent Orchestration is the discipline of dispatching, coordinating, and aggregating results from multiple concurrent subagents to dramatically accelerate complex tasks.
npx skill4agent add itallstartedwithaidea/agent-skills parallel-agent-orchestrationgraph TD
A[Complex Task] --> B[Task Decomposer]
B --> C[Subtask 1]
B --> D[Subtask 2]
B --> E[Subtask 3]
B --> F[Subtask N]
C --> G[Subagent 1]
D --> H[Subagent 2]
E --> I[Subagent 3]
F --> J[Subagent N]
G --> K[Result Aggregator]
H --> K
I --> K
J --> K
K --> L{Conflicts?}
L -->|Yes| M[Conflict Resolver]
L -->|No| N[Unified Result]
M --> N
O[Resource Monitor] --> G
O --> H
O --> I
O --> Jinterface SubTask {
id: string;
description: string;
context: Record<string, unknown>;
dependencies: string[];
priority: number;
}
class TaskDecomposer {
decompose(task: string, context: Record<string, unknown>): SubTask[] {
const patterns: Record<string, (ctx: Record<string, unknown>) => SubTask[]> = {
account_audit: (ctx) => {
const campaigns = ctx.campaigns as string[];
return campaigns.map((campaign, i) => ({
id: `campaign_${i}`,
description: `Analyze campaign: ${campaign}`,
context: { campaign, metrics: ctx.metrics },
dependencies: [],
priority: 1,
}));
},
code_review: (ctx) => {
const files = ctx.changedFiles as string[];
return files.map((file, i) => ({
id: `review_${i}`,
description: `Review changes in ${file}`,
context: { file, diff: ctx.diffs?.[file] },
dependencies: [],
priority: file.includes("test") ? 2 : 1,
}));
},
};
const taskType = this.classifyTask(task);
const decomposer = patterns[taskType];
return decomposer ? decomposer(context) : [{ id: "single", description: task, context, dependencies: [], priority: 1 }];
}
private classifyTask(task: string): string {
if (task.includes("audit") || task.includes("account")) return "account_audit";
if (task.includes("review") || task.includes("PR")) return "code_review";
return "generic";
}
}import asyncio
class ParallelOrchestrator:
def __init__(self, max_concurrency=5, budget_limit=None):
self.semaphore = asyncio.Semaphore(max_concurrency)
self.budget_limit = budget_limit
self.total_tokens = 0
self.results = {}
async def execute(self, subtasks: list[dict], agent_factory) -> dict:
dependency_graph = self.build_dependency_graph(subtasks)
ready = [t for t in subtasks if not t["dependencies"]]
pending = [t for t in subtasks if t["dependencies"]]
while ready or pending:
batch_results = await asyncio.gather(*[
self.run_subtask(task, agent_factory) for task in ready
], return_exceptions=True)
for task, result in zip(ready, batch_results):
if isinstance(result, Exception):
self.results[task["id"]] = {"success": False, "error": str(result)}
else:
self.results[task["id"]] = {"success": True, "result": result}
completed_ids = set(self.results.keys())
ready = [t for t in pending if all(d in completed_ids for d in t["dependencies"])]
pending = [t for t in pending if t not in ready]
return self.results
async def run_subtask(self, task: dict, agent_factory):
async with self.semaphore:
if self.budget_limit and self.total_tokens >= self.budget_limit:
raise BudgetExceededError(f"Token budget {self.budget_limit} exceeded")
agent = agent_factory(task)
result = await agent.execute(task["description"], task["context"])
self.total_tokens += result.get("tokens_used", 0)
return result
def build_dependency_graph(self, subtasks):
return {t["id"]: t["dependencies"] for t in subtasks}class ResultAggregator:
def aggregate(self, results: dict, strategy: str = "merge") -> dict:
successful = {k: v for k, v in results.items() if v["success"]}
failed = {k: v for k, v in results.items() if not v["success"]}
if strategy == "merge":
merged = self.merge_results(successful)
elif strategy == "vote":
merged = self.majority_vote(successful)
else:
merged = self.concatenate_results(successful)
conflicts = self.detect_conflicts(successful)
if conflicts:
merged = self.resolve_conflicts(merged, conflicts)
return {
"aggregated_result": merged,
"subtask_count": len(results),
"success_count": len(successful),
"failure_count": len(failed),
"conflicts_resolved": len(conflicts),
"failed_tasks": list(failed.keys()),
}
def detect_conflicts(self, results: dict) -> list[dict]:
conflicts = []
recommendations = {}
for task_id, result in results.items():
for rec in result.get("result", {}).get("recommendations", []):
key = rec.get("target")
if key in recommendations:
if recommendations[key]["action"] != rec["action"]:
conflicts.append({
"target": key,
"conflict": [recommendations[key], rec],
"tasks": [recommendations[key]["source"], task_id],
})
recommendations[key] = {**rec, "source": task_id}
return conflicts
def resolve_conflicts(self, merged: dict, conflicts: list) -> dict:
for conflict in conflicts:
higher_confidence = max(conflict["conflict"], key=lambda c: c.get("confidence", 0))
merged["recommendations"] = [
r for r in merged.get("recommendations", [])
if r.get("target") != conflict["target"]
]
merged["recommendations"].append(higher_confidence)
merged.setdefault("conflict_notes", []).append(
f"Conflict on {conflict['target']}: chose {higher_confidence['action']} (confidence: {higher_confidence.get('confidence', 'N/A')})"
)
return merged| Feature | Claude Code | Cursor | Codex | Gemini CLI |
|---|---|---|---|---|
| Subagent dispatch | ✅ Native subagents | ✅ Task tool | ✅ Async tasks | ✅ Async tasks |
| Parallel execution | ✅ Full | ✅ Full | ✅ Full | ✅ Full |
| Concurrency control | ✅ Custom | ✅ Custom | ✅ Custom | ✅ Custom |
| Result aggregation | ✅ Full | ✅ Full | ✅ Full | ✅ Full |
| Progress monitoring | ✅ Status updates | ✅ Background tasks | ✅ Custom | ✅ Custom |