Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions examples/hierarchical_auto_demo.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
"""Hierarchical Swarm Auto-Build Demo

Demonstrates:
- Auto-building agents from a natural-language prompt using `AutoSwarmBuilder`
- Adding built agents to departments via `DepartmentManager`
- Running the hierarchical swarm with parallel order execution

Note: This demo requires LLM credentials/configuration used by the project's LiteLLM/AutoSwarmBuilder.
"""

import logging

from swarms.structs.hiearchical_swarm import HierarchicalSwarm


logging.basicConfig(level=logging.INFO)


def main():
swarm = HierarchicalSwarm(
name="HierarchicalAutoDemo",
description="Demo: auto-build agents and run hierarchical swarm",
max_loops=1,
interactive=False,
use_parallel_execution=True,
max_workers=8,
)

prompt = (
"Design a small 3-agent team for market analysis: "
"(1) Researcher: gathers background and raw data, "
"(2) DataAnalyst: analyzes numeric trends, and "
"(3) Summarizer: writes executive summary and action items. "
"For each agent provide name, description, system_prompt, and role."
)

print("Auto-building agents from prompt...")
new_agents = swarm.auto_build_agents_from_prompt(prompt, department_name="Market")

print("Created agents:")
for a in new_agents:
try:
print(f" - {a.agent_name}: {getattr(a, 'agent_description', '')}")
except Exception:
print(" - <unknown agent>")

print("Running hierarchical swarm task...")
try:
result = swarm.run(task="Analyze Q1 market trends and provide top 5 action items.")
print("Swarm result:\n", result)
except Exception as e:
print("Error running swarm:", e)


if __name__ == "__main__":
main()
84 changes: 84 additions & 0 deletions examples/hierarchical_benchmark.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
"""Simple benchmark for HierarchicalSwarm order execution.

Creates fake agents whose `run` method sleeps for a short duration to
simulate work. Compares sequential vs parallel execution using
`HierarchicalSwarm.execute_orders`.

Run:
python examples/hierarchical_benchmark.py

"""
import time
import random

from concurrent.futures import ThreadPoolExecutor, as_completed


class FakeAgent:
def __init__(self, name: str, latency: float = 0.5):
self.agent_name = name
self.latency = latency

def run(self, task: str, *args, **kwargs):
# Simulate work
time.sleep(self.latency)
return f"{self.agent_name} done ({task})"


def build_agents_and_orders(num_agents: int, latency_mean: float = 0.5):
agents = [FakeAgent(f"agent_{i}", latency=random.uniform(latency_mean * 0.8, latency_mean * 1.2)) for i in range(num_agents)]
orders = [(a.agent_name, f"task_{i}") for i, a in enumerate(agents)]
agents_map = {a.agent_name: a for a in agents}
return agents_map, orders


def sequential_execute_orders(orders, agents_map):
outputs = []
for agent_name, task in orders:
agent = agents_map[agent_name]
out = agent.run(task)
outputs.append(out)
return outputs


def parallel_execute_orders(orders, agents_map, max_workers=None):
outputs = [None] * len(orders)
with ThreadPoolExecutor(max_workers=max_workers) as exc:
future_to_idx = {}
for idx, (agent_name, task) in enumerate(orders):
agent = agents_map[agent_name]
fut = exc.submit(agent.run, task)
future_to_idx[fut] = idx

for fut in as_completed(future_to_idx):
idx = future_to_idx[fut]
try:
outputs[idx] = fut.result()
except Exception as e:
outputs[idx] = f"[ERROR] {e}"

return outputs


def run_benchmark(num_agents=8, latency_mean=0.5, max_workers=None):
agents_map, orders = build_agents_and_orders(num_agents, latency_mean=latency_mean)

# Sequential
t0 = time.time()
out_seq = sequential_execute_orders(orders, agents_map)
seq_time = time.time() - t0

# Parallel
t0 = time.time()
out_par = parallel_execute_orders(orders, agents_map, max_workers=max_workers)
par_time = time.time() - t0

print(f"Agents: {num_agents}, mean_latency: {latency_mean:.2f}s")
print(f"Sequential time: {seq_time:.2f}s")
print(f"Parallel time: {par_time:.2f}s")
print("Sequential outputs sample:", out_seq[:2])
print("Parallel outputs sample: ", out_par[:2])


if __name__ == "__main__":
run_benchmark(num_agents=12, latency_mean=0.4)
52 changes: 52 additions & 0 deletions examples/hierarchical_ui_demo.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
"""Interactive Hierarchical Swarm UI Demo

This demo runs `HierarchicalSwarm` in interactive mode to show the
`HierarchicalSwarmDashboard` UI (Rich Live). It optionally auto-builds agents
from a prompt if LLM credentials are configured.

Run:
python examples/hierarchical_ui_demo.py

"""

import time
import logging

from swarms.structs.hiearchical_swarm import HierarchicalSwarm

logging.basicConfig(level=logging.INFO)


def main():
swarm = HierarchicalSwarm(
name="HierarchicalUI",
description="Interactive UI demo for hierarchical swarm",
max_loops=2,
interactive=True,
use_parallel_execution=True,
max_workers=6,
)

# Optionally auto-build a couple of agents if AutoSwarmBuilder is available
prompt = (
"Create 2 lightweight agents: (1) NoteTaker that summarizes notes, "
"(2) Researcher that finds 3 data points. Return name, description, and system_prompt."
)

try:
swarm.auto_build_agents_from_prompt(prompt, department_name="DemoTeam")
except Exception:
pass

# Run interactive loop - will prompt when needed
try:
result = swarm.run(task="Gather facts about the latest AI research breakthroughs.")
print("Run completed. Result:\n", result)
except KeyboardInterrupt:
print("Interrupted by user")
except Exception as e:
print("Error during interactive run:", e)


if __name__ == "__main__":
main()
65 changes: 65 additions & 0 deletions swarms/cli/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -764,6 +764,7 @@
"auto-upgrade",
"book-call",
"autoswarm",
"hierarchical-auto",
"setup-check",
"llm-council",
"heavy-swarm",
Expand Down Expand Up @@ -945,6 +946,27 @@
type=str,
help="Model name for autoswarm command",
)
parser.add_argument(
"--auto-build",
action="store_true",
help="Auto-build agents from the provided task prompt before running the hierarchical swarm",
)
parser.add_argument(
"--department",
type=str,
help="Department name to add auto-built agents to (optional)",
)
parser.add_argument(
"--no-parallel",
dest="parallel",
action="store_false",
help="Disable parallel execution of orders",
)
parser.add_argument(
"--max-workers",
type=int,
help="Maximum number of parallel workers when executing orders",
)
return parser


Expand Down Expand Up @@ -1351,6 +1373,48 @@
)


def handle_hierarchical_auto(args: argparse.Namespace) -> None:
"""
Handle the hierarchical-auto command.
Optionally auto-builds agents from the task prompt using AutoSwarmBuilder,
then runs `HierarchicalSwarm` with the generated/available agents.
"""
if not args.task:
show_error(
"Missing required argument: --task",
"Example usage: swarms hierarchical-auto --task 'Analyze market trends' --auto-build --department Market",
)
exit(1)

# Initialize swarm
swarm = HierarchicalSwarm(

Check failure

Code scanning / Pyre

Unbound name Error

Unbound name [10]: Name HierarchicalSwarm is used but not defined in the current scope.
name="hierarchical-auto",
description="Auto-built hierarchical swarm via CLI",
max_loops=1 if not args.max_loops else int(args.max_loops) if args.max_loops.isdigit() else 1,
interactive=False,
use_parallel_execution=getattr(args, "parallel", True),
max_workers=getattr(args, "max_workers", None),
)

# Auto-build if requested
if args.auto_build:
try:
swarm.auto_build_agents_from_prompt(args.task, department_name=getattr(args, "department", None))
console.print("[green]βœ“ Auto-built agents and added to swarm[/green]")
except Exception as e:
show_error("Auto-build failed", str(e))
return

# Run the swarm
try:
console.print(f"[yellow]Running hierarchical swarm for task: {args.task}[/yellow]")
result = swarm.run(task=args.task)
console.print(Panel(result or "No result", title="Hierarchical Swarm Result", border_style="green"))
except Exception as e:
show_error("Hierarchical swarm run failed", str(e))


def handle_chat(args: argparse.Namespace) -> Optional[Agent]:
"""
Handle the chat command for interactive chat agent.
Expand Down Expand Up @@ -1483,6 +1547,7 @@
"https://cal.com/swarms/swarms-strategy-session"
),
"autoswarm": handle_autoswarm,
"hierarchical-auto": handle_hierarchical_auto,
"setup-check": lambda args: run_setup_check(
verbose=args.verbose
),
Expand Down
14 changes: 14 additions & 0 deletions swarms/structs/auto_swarm_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,8 @@ def __init__(
self.additional_llm_args = additional_llm_args
self.conversation = Conversation()
self.agents_pool = []
# simple in-memory cache to avoid repeated LLM calls for identical prompts
self._create_agents_cache: dict[str, Any] = {}

self.reliability_check()

Expand Down Expand Up @@ -402,13 +404,25 @@ def create_agents(self, task: str):
Exception: If there's an error during agent creation
"""
try:
# return cached response when possible
if task in self._create_agents_cache:
logger.debug("AutoSwarmBuilder: returning cached agent spec for prompt")
return self._create_agents_cache[task]

logger.info("Creating agents from specifications")
model = self.build_llm_agent(config=Agents)

agents_dictionary = model.run(task)

agents_dictionary = json.loads(agents_dictionary)

# cache the result
try:
self._create_agents_cache[task] = agents_dictionary
except Exception:
# non-cacheable; ignore
pass

return agents_dictionary

except Exception as e:
Expand Down
30 changes: 30 additions & 0 deletions swarms/structs/department_manager.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
"""DepartmentManager: manage named departments of agents."""
from typing import Any, Optional


class DepartmentManager:
"""Manage departments (list of agent lists) for hierarchical swarms.

Departments are named groups of agents. This manager provides helpers to
add agents, list departments, and flatten agents for swarm execution.
"""

def __init__(self):
self.departments: dict[str, list[Any]] = {}

def add_department(self, name: str, agents: Optional[list[Any]] = None):
self.departments[name] = agents or []

def add_agent_to_department(self, dept_name: str, agent: Any):
if dept_name not in self.departments:
self.add_department(dept_name)
self.departments[dept_name].append(agent)

def list_departments(self) -> list[str]:
return list(self.departments.keys())

def flatten_agents(self) -> list[Any]:
out: list[Any] = []
for agents in self.departments.values():
out.extend(agents)
return out
Loading
Loading