Skip to content

Commit a6862c3

Browse files
authored
Merge pull request #1311 from hughiwnl/autosavelogic1
autosave logic
2 parents 2857c52 + 11c66f0 commit a6862c3

File tree

3 files changed

+183
-2
lines changed

3 files changed

+183
-2
lines changed

examples/multi_agent/hiearchical_swarm/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ This directory contains examples demonstrating hierarchical swarm patterns for m
44

55
## Examples
66

7+
- [hierarchical_swarm_autosave_example.py](hierarchical_swarm_autosave_example.py) - **Autosave feature example** - Shows how to automatically save conversation history
78
- [hierarchical_swarm_basic_demo.py](hierarchical_swarm_basic_demo.py) - Basic hierarchical demo
89
- [hierarchical_swarm_batch_demo.py](hierarchical_swarm_batch_demo.py) - Batch processing demo
910
- [hierarchical_swarm_comparison_demo.py](hierarchical_swarm_comparison_demo.py) - Comparison demo
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
#!/usr/bin/env python3
2+
"""
3+
HierarchicalSwarm Autosave Example
4+
5+
This example demonstrates how to use the autosave feature to automatically
6+
save conversation history after swarm execution.
7+
8+
Usage:
9+
python hierarchical_swarm_autosave_example.py
10+
"""
11+
12+
import os
13+
from swarms import Agent, HierarchicalSwarm
14+
15+
16+
def main():
17+
"""Example: Using HierarchicalSwarm with autosave enabled."""
18+
19+
# Create worker agents
20+
writer = Agent(
21+
agent_name="Writer",
22+
agent_description="Content writer",
23+
model_name="gpt-4o-mini",
24+
max_loops=1,
25+
verbose=False,
26+
)
27+
28+
editor = Agent(
29+
agent_name="Editor",
30+
agent_description="Content editor",
31+
model_name="gpt-4o-mini",
32+
max_loops=1,
33+
verbose=False,
34+
)
35+
36+
# Create swarm with autosave enabled
37+
swarm = HierarchicalSwarm(
38+
name="content-team",
39+
description="Content creation team",
40+
agents=[writer, editor],
41+
max_loops=1,
42+
autosave=True, # Enable autosave - conversation will be saved automatically
43+
)
44+
45+
print(f"Workspace directory: {swarm.swarm_workspace_dir}")
46+
47+
# Run a task
48+
result = swarm.run("Write a short paragraph about artificial intelligence.")
49+
50+
# Conversation history is automatically saved to:
51+
# {workspace_dir}/swarms/HierarchicalSwarm/content-team-{timestamp}/conversation_history.json
52+
print(f"\n✅ Task completed! Conversation saved to:")
53+
print(f" {swarm.swarm_workspace_dir}/conversation_history.json")
54+
55+
56+
if __name__ == "__main__":
57+
main()

swarms/structs/hiearchical_swarm.py

Lines changed: 125 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,11 @@
2222
2323
"""
2424

25+
import json
26+
import os
2527
import time
2628
import traceback
27-
from typing import Any, Callable, List, Optional, Union
29+
from typing import Any, Callable, Dict, List, Optional, Union
2830

2931
from loguru import logger
3032
from pydantic import BaseModel, Field
@@ -52,6 +54,8 @@
5254
history_output_formatter,
5355
)
5456
from swarms.utils.output_types import OutputType
57+
from swarms.utils.swarm_autosave import get_swarm_workspace_dir
58+
from swarms.utils.workspace_utils import get_workspace_dir
5559

5660

5761
class HierarchicalSwarmDashboard:
@@ -672,6 +676,8 @@ def __init__(
672676
director_temperature: float = 0.7,
673677
director_top_p: float = 0.9,
674678
planning_enabled: bool = True,
679+
autosave: bool = True,
680+
verbose: bool = False,
675681
*args,
676682
**kwargs,
677683
):
@@ -692,6 +698,8 @@ def __init__(
692698
director_model_name (str): Model name for the main director agent.
693699
add_collaboration_prompt (bool): Whether to add collaboration prompts.
694700
director_feedback_on (bool): Whether director feedback is enabled.
701+
autosave (bool): Whether to enable autosaving of conversation history.
702+
verbose (bool): Whether to enable verbose logging.
695703
*args: Additional positional arguments.
696704
**kwargs: Additional keyword arguments.
697705
@@ -719,6 +727,13 @@ def __init__(
719727
self.director_temperature = director_temperature
720728
self.director_top_p = director_top_p
721729
self.planning_enabled = planning_enabled
730+
self.autosave = autosave
731+
self.verbose = verbose
732+
self.swarm_workspace_dir = None
733+
734+
# Setup autosave workspace if enabled
735+
if self.autosave:
736+
self._setup_autosave()
722737

723738
self.initialize_swarm()
724739

@@ -815,6 +830,91 @@ def init_swarm(self):
815830
if self.multi_agent_prompt_improvements:
816831
self.prepare_worker_agents()
817832

833+
def _setup_autosave(self):
834+
"""
835+
Setup workspace directory for saving conversation history.
836+
837+
Creates the workspace directory structure if autosave is enabled.
838+
Only conversation history will be saved to this directory.
839+
"""
840+
try:
841+
# Set default workspace directory if not set
842+
if not os.getenv("WORKSPACE_DIR"):
843+
default_workspace = os.path.join(os.getcwd(), "agent_workspace")
844+
os.environ["WORKSPACE_DIR"] = default_workspace
845+
# Clear the cache so get_workspace_dir() picks up the new value
846+
get_workspace_dir.cache_clear()
847+
if self.verbose:
848+
logger.info(
849+
f"WORKSPACE_DIR not set, using default: {default_workspace}"
850+
)
851+
852+
class_name = self.__class__.__name__
853+
swarm_name = self.name or "hierarchical-swarm"
854+
self.swarm_workspace_dir = get_swarm_workspace_dir(
855+
class_name, swarm_name, use_timestamp=True
856+
)
857+
858+
if self.swarm_workspace_dir:
859+
if self.verbose:
860+
logger.info(
861+
f"Autosave enabled. Conversation history will be saved to: {self.swarm_workspace_dir}"
862+
)
863+
except Exception as e:
864+
logger.warning(
865+
f"Failed to setup autosave for HierarchicalSwarm: {e}"
866+
)
867+
# Don't raise - autosave failures shouldn't break initialization
868+
self.swarm_workspace_dir = None
869+
870+
def _save_conversation_history(self):
871+
"""
872+
Save conversation history as a separate JSON file to the workspace directory.
873+
874+
Saves the conversation history to:
875+
workspace_dir/swarms/HierarchicalSwarm/{swarm-name}-{id}/conversation_history.json
876+
"""
877+
if not self.swarm_workspace_dir:
878+
return
879+
880+
try:
881+
# Get conversation history
882+
if hasattr(self, "conversation") and self.conversation:
883+
if hasattr(self.conversation, "conversation_history"):
884+
conversation_data = self.conversation.conversation_history
885+
elif hasattr(self.conversation, "to_dict"):
886+
conversation_data = self.conversation.to_dict()
887+
else:
888+
conversation_data = []
889+
890+
# Create conversation history file path
891+
conversation_path = os.path.join(
892+
self.swarm_workspace_dir, "conversation_history.json"
893+
)
894+
895+
# Save conversation history as JSON
896+
with open(conversation_path, "w", encoding="utf-8") as f:
897+
json.dump(
898+
conversation_data,
899+
f,
900+
indent=2,
901+
default=str,
902+
)
903+
904+
if self.verbose:
905+
logger.debug(
906+
f"Saved conversation history to {conversation_path}"
907+
)
908+
else:
909+
if self.verbose:
910+
logger.debug(
911+
"No conversation object found, skipping conversation history save"
912+
)
913+
except Exception as e:
914+
logger.warning(
915+
f"Failed to save conversation history: {e}"
916+
)
917+
818918
def add_context_to_director(self):
819919
"""
820920
Add agent context and collaboration information to the director's conversation.
@@ -1167,20 +1267,41 @@ def run(
11671267
self.dashboard.update_director_status("COMPLETED")
11681268
self.dashboard.stop()
11691269

1170-
return history_output_formatter(
1270+
result = history_output_formatter(
11711271
conversation=self.conversation, type=self.output_type
11721272
)
11731273

1274+
# Save conversation history after successful execution
1275+
if self.autosave and self.swarm_workspace_dir:
1276+
try:
1277+
self._save_conversation_history()
1278+
except Exception as e:
1279+
logger.warning(
1280+
f"Failed to save conversation history: {e}"
1281+
)
1282+
1283+
return result
1284+
11741285
except Exception as e:
11751286
# Stop dashboard on error
11761287
if self.interactive and self.dashboard:
11771288
self.dashboard.update_director_status("ERROR")
11781289
self.dashboard.stop()
11791290

1291+
# Save conversation history on error
1292+
if self.autosave and self.swarm_workspace_dir:
1293+
try:
1294+
self._save_conversation_history()
1295+
except Exception as save_error:
1296+
logger.warning(
1297+
f"Failed to save conversation history on error: {save_error}"
1298+
)
1299+
11801300
error_msg = f"[ERROR] Swarm run failed: {str(e)}"
11811301
logger.error(
11821302
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"
11831303
)
1304+
raise
11841305

11851306
def _get_interactive_task(self) -> str:
11861307
"""
@@ -1610,3 +1731,5 @@ def batched_run(
16101731
logger.error(
16111732
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"
16121733
)
1734+
1735+

0 commit comments

Comments
 (0)