Skip to content
Merged
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
1 change: 1 addition & 0 deletions examples/multi_agent/hiearchical_swarm/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ This directory contains examples demonstrating hierarchical swarm patterns for m

## Examples

- [hierarchical_swarm_autosave_example.py](hierarchical_swarm_autosave_example.py) - **Autosave feature example** - Shows how to automatically save conversation history
- [hierarchical_swarm_basic_demo.py](hierarchical_swarm_basic_demo.py) - Basic hierarchical demo
- [hierarchical_swarm_batch_demo.py](hierarchical_swarm_batch_demo.py) - Batch processing demo
- [hierarchical_swarm_comparison_demo.py](hierarchical_swarm_comparison_demo.py) - Comparison demo
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#!/usr/bin/env python3
"""
HierarchicalSwarm Autosave Example

This example demonstrates how to use the autosave feature to automatically
save conversation history after swarm execution.

Usage:
python hierarchical_swarm_autosave_example.py
"""

import os
from swarms import Agent, HierarchicalSwarm


def main():
"""Example: Using HierarchicalSwarm with autosave enabled."""

# Create worker agents
writer = Agent(
agent_name="Writer",
agent_description="Content writer",
model_name="gpt-4o-mini",
max_loops=1,
verbose=False,
)

editor = Agent(
agent_name="Editor",
agent_description="Content editor",
model_name="gpt-4o-mini",
max_loops=1,
verbose=False,
)

# Create swarm with autosave enabled
swarm = HierarchicalSwarm(
name="content-team",
description="Content creation team",
agents=[writer, editor],
max_loops=1,
autosave=True, # Enable autosave - conversation will be saved automatically
)

print(f"Workspace directory: {swarm.swarm_workspace_dir}")

# Run a task
result = swarm.run("Write a short paragraph about artificial intelligence.")

# Conversation history is automatically saved to:
# {workspace_dir}/swarms/HierarchicalSwarm/content-team-{timestamp}/conversation_history.json
print(f"\n✅ Task completed! Conversation saved to:")
print(f" {swarm.swarm_workspace_dir}/conversation_history.json")


if __name__ == "__main__":
main()
127 changes: 125 additions & 2 deletions swarms/structs/hiearchical_swarm.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,11 @@

"""

import json
import os
import time
import traceback
from typing import Any, Callable, List, Optional, Union
from typing import Any, Callable, Dict, List, Optional, Union

from loguru import logger
from pydantic import BaseModel, Field
Expand Down Expand Up @@ -52,6 +54,8 @@
history_output_formatter,
)
from swarms.utils.output_types import OutputType
from swarms.utils.swarm_autosave import get_swarm_workspace_dir
from swarms.utils.workspace_utils import get_workspace_dir


class HierarchicalSwarmDashboard:
Expand Down Expand Up @@ -672,6 +676,8 @@ def __init__(
director_temperature: float = 0.7,
director_top_p: float = 0.9,
planning_enabled: bool = True,
autosave: bool = True,
verbose: bool = False,
*args,
**kwargs,
):
Expand All @@ -692,6 +698,8 @@ def __init__(
director_model_name (str): Model name for the main director agent.
add_collaboration_prompt (bool): Whether to add collaboration prompts.
director_feedback_on (bool): Whether director feedback is enabled.
autosave (bool): Whether to enable autosaving of conversation history.
verbose (bool): Whether to enable verbose logging.
*args: Additional positional arguments.
**kwargs: Additional keyword arguments.

Expand Down Expand Up @@ -719,6 +727,13 @@ def __init__(
self.director_temperature = director_temperature
self.director_top_p = director_top_p
self.planning_enabled = planning_enabled
self.autosave = autosave
self.verbose = verbose
self.swarm_workspace_dir = None

# Setup autosave workspace if enabled
if self.autosave:
self._setup_autosave()

self.initialize_swarm()

Expand Down Expand Up @@ -815,6 +830,91 @@ def init_swarm(self):
if self.multi_agent_prompt_improvements:
self.prepare_worker_agents()

def _setup_autosave(self):
"""
Setup workspace directory for saving conversation history.

Creates the workspace directory structure if autosave is enabled.
Only conversation history will be saved to this directory.
"""
try:
# Set default workspace directory if not set
if not os.getenv("WORKSPACE_DIR"):
default_workspace = os.path.join(os.getcwd(), "agent_workspace")
os.environ["WORKSPACE_DIR"] = default_workspace
# Clear the cache so get_workspace_dir() picks up the new value
get_workspace_dir.cache_clear()
if self.verbose:
logger.info(
f"WORKSPACE_DIR not set, using default: {default_workspace}"
)

class_name = self.__class__.__name__
swarm_name = self.name or "hierarchical-swarm"
self.swarm_workspace_dir = get_swarm_workspace_dir(
class_name, swarm_name, use_timestamp=True
)

if self.swarm_workspace_dir:
if self.verbose:
logger.info(
f"Autosave enabled. Conversation history will be saved to: {self.swarm_workspace_dir}"
)
except Exception as e:
logger.warning(
f"Failed to setup autosave for HierarchicalSwarm: {e}"
)
# Don't raise - autosave failures shouldn't break initialization
self.swarm_workspace_dir = None

def _save_conversation_history(self):
"""
Save conversation history as a separate JSON file to the workspace directory.

Saves the conversation history to:
workspace_dir/swarms/HierarchicalSwarm/{swarm-name}-{id}/conversation_history.json
"""
if not self.swarm_workspace_dir:
return

try:
# Get conversation history
if hasattr(self, "conversation") and self.conversation:
if hasattr(self.conversation, "conversation_history"):
conversation_data = self.conversation.conversation_history
elif hasattr(self.conversation, "to_dict"):
conversation_data = self.conversation.to_dict()
else:
conversation_data = []

# Create conversation history file path
conversation_path = os.path.join(
self.swarm_workspace_dir, "conversation_history.json"
)

# Save conversation history as JSON
with open(conversation_path, "w", encoding="utf-8") as f:
json.dump(
conversation_data,
f,
indent=2,
default=str,
)

if self.verbose:
logger.debug(
f"Saved conversation history to {conversation_path}"
)
else:
if self.verbose:
logger.debug(
"No conversation object found, skipping conversation history save"
)
except Exception as e:
logger.warning(
f"Failed to save conversation history: {e}"
)

def add_context_to_director(self):
"""
Add agent context and collaboration information to the director's conversation.
Expand Down Expand Up @@ -1167,20 +1267,41 @@ def run(
self.dashboard.update_director_status("COMPLETED")
self.dashboard.stop()

return history_output_formatter(
result = history_output_formatter(
conversation=self.conversation, type=self.output_type
)

# Save conversation history after successful execution
if self.autosave and self.swarm_workspace_dir:
try:
self._save_conversation_history()
except Exception as e:
logger.warning(
f"Failed to save conversation history: {e}"
)

return result

except Exception as e:
# Stop dashboard on error
if self.interactive and self.dashboard:
self.dashboard.update_director_status("ERROR")
self.dashboard.stop()

# Save conversation history on error
if self.autosave and self.swarm_workspace_dir:
try:
self._save_conversation_history()
except Exception as save_error:
logger.warning(
f"Failed to save conversation history on error: {save_error}"
)

error_msg = f"[ERROR] Swarm run failed: {str(e)}"
logger.error(
f"{error_msg}\n[TRACE] Traceback: {traceback.format_exc()}\n[BUG] If this issue persists, please report it at: https://github.com/kyegomez/swarms/issues"
)
raise

def _get_interactive_task(self) -> str:
"""
Expand Down Expand Up @@ -1610,3 +1731,5 @@ def batched_run(
logger.error(
f"{error_msg}\n[TRACE] Traceback: {traceback.format_exc()}\n[BUG] If this issue persists, please report it at: https://github.com/kyegomez/swarms/issues"
)


Loading