open-swarm 0.1.1745017234__py3-none-any.whl → 0.1.1745019858__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {open_swarm-0.1.1745017234.dist-info → open_swarm-0.1.1745019858.dist-info}/METADATA +29 -1
- {open_swarm-0.1.1745017234.dist-info → open_swarm-0.1.1745019858.dist-info}/RECORD +41 -27
- swarm/blueprints/blueprint_audit_status.json +27 -0
- swarm/blueprints/chatbot/blueprint_chatbot.py +93 -28
- swarm/blueprints/codey/CODEY.md +15 -0
- swarm/blueprints/codey/README.md +63 -0
- swarm/blueprints/codey/blueprint_codey.py +179 -108
- swarm/blueprints/codey/instructions.md +17 -0
- swarm/blueprints/divine_code/blueprint_divine_code.py +113 -7
- swarm/blueprints/django_chat/blueprint_django_chat.py +47 -0
- swarm/blueprints/family_ties/blueprint_family_ties.py +43 -10
- swarm/blueprints/geese/blueprint_geese.py +219 -0
- swarm/blueprints/mission_improbable/blueprint_mission_improbable.py +120 -63
- swarm/blueprints/monkai_magic/blueprint_monkai_magic.py +45 -1
- swarm/blueprints/nebula_shellz/blueprint_nebula_shellz.py +43 -27
- swarm/blueprints/omniplex/blueprint_omniplex.py +44 -31
- swarm/blueprints/rue_code/blueprint_rue_code.py +141 -141
- swarm/blueprints/suggestion/blueprint_suggestion.py +8 -17
- swarm/blueprints/unapologetic_press/blueprint_unapologetic_press.py +100 -1
- swarm/blueprints/whiskeytango_foxtrot/blueprint_whiskeytango_foxtrot.py +52 -28
- swarm/core/blueprint_ux.py +19 -21
- swarm/core/cli/__init__.py +1 -0
- swarm/core/cli/commands/__init__.py +1 -0
- swarm/core/cli/commands/blueprint_management.py +7 -0
- swarm/core/cli/interactive_shell.py +14 -0
- swarm/core/cli/main.py +50 -0
- swarm/core/cli/utils/__init__.py +1 -0
- swarm/core/cli/utils/discover_commands.py +18 -0
- swarm/extensions/blueprint/cli_handler.py +19 -0
- swarm/extensions/cli/commands/blueprint_management.py +46 -8
- swarm/extensions/cli/commands/edit_config.py +8 -1
- swarm/extensions/cli/commands/validate_env.py +8 -1
- swarm/extensions/cli/interactive_shell.py +16 -2
- swarm/extensions/cli/utils/__init__.py +1 -0
- swarm/extensions/cli/utils/prompt_user.py +3 -0
- swarm/extensions/launchers/swarm_api.py +12 -0
- swarm/extensions/launchers/swarm_cli.py +12 -0
- swarm/utils/context_utils.py +10 -4
- swarm/blueprints/gaggle/blueprint_gaggle.py +0 -303
- swarm/llm/chat_completion.py +0 -196
- {open_swarm-0.1.1745017234.dist-info → open_swarm-0.1.1745019858.dist-info}/WHEEL +0 -0
- {open_swarm-0.1.1745017234.dist-info → open_swarm-0.1.1745019858.dist-info}/entry_points.txt +0 -0
- {open_swarm-0.1.1745017234.dist-info → open_swarm-0.1.1745019858.dist-info}/licenses/LICENSE +0 -0
@@ -55,8 +55,16 @@ brian_instructions = (
|
|
55
55
|
|
56
56
|
# --- Define the Blueprint ---
|
57
57
|
class FamilyTiesBlueprint(BlueprintBase):
|
58
|
-
def __init__(self,
|
59
|
-
super().__init__(
|
58
|
+
def __init__(self, *args, **kwargs):
|
59
|
+
super().__init__(*args, **kwargs)
|
60
|
+
class DummyLLM:
|
61
|
+
def chat_completion_stream(self, messages, **_):
|
62
|
+
class DummyStream:
|
63
|
+
def __aiter__(self): return self
|
64
|
+
async def __anext__(self):
|
65
|
+
raise StopAsyncIteration
|
66
|
+
return DummyStream()
|
67
|
+
self.llm = DummyLLM()
|
60
68
|
|
61
69
|
"""Manages WordPress content with a Peter/Brian agent team using the `server-wp-mcp` server."""
|
62
70
|
metadata: ClassVar[Dict[str, Any]] = {
|
@@ -153,13 +161,29 @@ class FamilyTiesBlueprint(BlueprintBase):
|
|
153
161
|
logger.debug("Agents created: PeterGrifton (Coordinator), BrianGrifton (WordPress Manager).")
|
154
162
|
return peter_agent # Peter is the entry point
|
155
163
|
|
156
|
-
|
157
|
-
"
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
164
|
+
def render_prompt(self, template_name: str, context: dict) -> str:
|
165
|
+
return f"User request: {context.get('user_request', '')}\nHistory: {context.get('history', '')}\nAvailable tools: {', '.join(context.get('available_tools', []))}"
|
166
|
+
|
167
|
+
async def run(self, messages: list) -> object:
|
168
|
+
last_user_message = next((m['content'] for m in reversed(messages) if m['role'] == 'user'), None)
|
169
|
+
if not last_user_message:
|
170
|
+
yield {"messages": [{"role": "assistant", "content": "I need a user message to proceed."}]}
|
171
|
+
return
|
172
|
+
prompt_context = {
|
173
|
+
"user_request": last_user_message,
|
174
|
+
"history": messages[:-1],
|
175
|
+
"available_tools": ["family_ties"]
|
176
|
+
}
|
177
|
+
rendered_prompt = self.render_prompt("family_ties_prompt.j2", prompt_context)
|
178
|
+
yield {
|
179
|
+
"messages": [
|
180
|
+
{
|
181
|
+
"role": "assistant",
|
182
|
+
"content": f"[FamilyTies LLM] Would respond to: {rendered_prompt}"
|
183
|
+
}
|
184
|
+
]
|
185
|
+
}
|
186
|
+
return
|
163
187
|
|
164
188
|
async def _run_non_interactive(self, instruction: str, **kwargs) -> Any:
|
165
189
|
logger.info(f"Running FamilyTies non-interactively with instruction: '{instruction[:100]}...'")
|
@@ -177,4 +201,13 @@ class FamilyTiesBlueprint(BlueprintBase):
|
|
177
201
|
yield {"messages": [{"role": "assistant", "content": f"An error occurred: {e}"}]}
|
178
202
|
|
179
203
|
if __name__ == "__main__":
|
180
|
-
|
204
|
+
import asyncio
|
205
|
+
import json
|
206
|
+
messages = [
|
207
|
+
{"role": "user", "content": "Who are my relatives?"}
|
208
|
+
]
|
209
|
+
blueprint = FamilyTiesBlueprint(blueprint_id="demo-1")
|
210
|
+
async def run_and_print():
|
211
|
+
async for response in blueprint.run(messages):
|
212
|
+
print(json.dumps(response, indent=2))
|
213
|
+
asyncio.run(run_and_print())
|
@@ -0,0 +1,219 @@
|
|
1
|
+
import os
|
2
|
+
from dotenv import load_dotenv; load_dotenv(override=True)
|
3
|
+
|
4
|
+
import logging
|
5
|
+
logging.basicConfig(level=logging.INFO, format='[%(levelname)s] %(name)s: %(message)s')
|
6
|
+
import sys
|
7
|
+
|
8
|
+
def force_info_logging():
|
9
|
+
root = logging.getLogger()
|
10
|
+
for handler in root.handlers[:]:
|
11
|
+
root.removeHandler(handler)
|
12
|
+
loglevel = os.environ.get('LOGLEVEL', None)
|
13
|
+
debug_env = os.environ.get('SWARM_DEBUG', '0') == '1'
|
14
|
+
debug_arg = '--debug' in sys.argv
|
15
|
+
if debug_arg or debug_env or (loglevel and loglevel.upper() == 'DEBUG'):
|
16
|
+
level = logging.DEBUG
|
17
|
+
else:
|
18
|
+
level = logging.INFO
|
19
|
+
logging.basicConfig(level=level, format='[%(levelname)s] %(name)s: %(message)s')
|
20
|
+
root.setLevel(level)
|
21
|
+
|
22
|
+
force_info_logging()
|
23
|
+
|
24
|
+
import argparse
|
25
|
+
from typing import List, Dict, Any, Optional, ClassVar
|
26
|
+
|
27
|
+
project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..'))
|
28
|
+
src_path = os.path.join(project_root, 'src')
|
29
|
+
if src_path not in sys.path: sys.path.insert(0, src_path)
|
30
|
+
|
31
|
+
from typing import Optional
|
32
|
+
from pathlib import Path
|
33
|
+
try:
|
34
|
+
from agents import Agent, Tool, function_tool, Runner
|
35
|
+
from agents.mcp import MCPServer
|
36
|
+
from agents.models.interface import Model
|
37
|
+
from agents.models.openai_chatcompletions import OpenAIChatCompletionsModel
|
38
|
+
from openai import AsyncOpenAI
|
39
|
+
from swarm.core.blueprint_base import BlueprintBase
|
40
|
+
except ImportError as e:
|
41
|
+
print(f"ERROR: Import failed in blueprint_geese: {e}. Check 'openai-agents' install and project structure.")
|
42
|
+
print(f"sys.path: {sys.path}")
|
43
|
+
sys.exit(1)
|
44
|
+
|
45
|
+
import argparse
|
46
|
+
|
47
|
+
def setup_logging():
|
48
|
+
parser = argparse.ArgumentParser(add_help=False)
|
49
|
+
parser.add_argument('--debug', action='store_true', help='Enable debug logging')
|
50
|
+
args, _ = parser.parse_known_args()
|
51
|
+
loglevel = os.environ.get('LOGLEVEL', None)
|
52
|
+
if args.debug or os.environ.get('SWARM_DEBUG', '0') == '1' or (loglevel and loglevel.upper() == 'DEBUG'):
|
53
|
+
logging.basicConfig(level=logging.DEBUG)
|
54
|
+
else:
|
55
|
+
logging.basicConfig(level=logging.INFO)
|
56
|
+
return args
|
57
|
+
|
58
|
+
args = setup_logging()
|
59
|
+
|
60
|
+
logger = logging.getLogger(__name__)
|
61
|
+
|
62
|
+
# --- Tools ---
|
63
|
+
def _create_story_outline(topic: str) -> str:
|
64
|
+
logger.info(f"Tool: Generating outline for: {topic}")
|
65
|
+
outline = f"Story Outline for '{topic}':\n1. Beginning: Introduce characters and setting.\n2. Middle: Develop conflict and rising action.\n3. Climax: The peak of the conflict.\n4. End: Resolution and aftermath."
|
66
|
+
logger.debug(f"Generated outline: {outline}")
|
67
|
+
return outline
|
68
|
+
|
69
|
+
@function_tool
|
70
|
+
def create_story_outline(topic: str) -> str:
|
71
|
+
"""Generates a basic story outline based on a topic."""
|
72
|
+
return _create_story_outline(topic)
|
73
|
+
|
74
|
+
def _write_story_part(part_name: str, outline: str, previous_parts: str) -> str:
|
75
|
+
logger.info(f"Tool: Writing story part: {part_name}")
|
76
|
+
content = f"## {part_name}\n\nThis is the draft content for the '{part_name}' section. It follows:\n'{previous_parts[:100]}...' \nIt should align with the outline:\n'{outline}'"
|
77
|
+
logger.debug(f"Generated content for {part_name}: {content[:100]}...")
|
78
|
+
return content
|
79
|
+
|
80
|
+
@function_tool
|
81
|
+
def write_story_part(part_name: str, outline: str, previous_parts: str) -> str:
|
82
|
+
"""Writes a specific part of the story using the outline and previous context."""
|
83
|
+
return _write_story_part(part_name, outline, previous_parts)
|
84
|
+
|
85
|
+
def _edit_story(full_story: str, edit_instructions: str) -> str:
|
86
|
+
logger.info(f"Tool: Editing story with instructions: {edit_instructions}")
|
87
|
+
edited_content = f"*** Edited Story Draft ***\n(Based on instructions: '{edit_instructions}')\n\n{full_story}\n\n[Editor's Notes: Minor tweaks applied for flow.]"
|
88
|
+
logger.debug("Editing complete.")
|
89
|
+
return edited_content
|
90
|
+
|
91
|
+
@function_tool
|
92
|
+
def edit_story(full_story: str, edit_instructions: str) -> str:
|
93
|
+
"""Edits the complete story based on instructions."""
|
94
|
+
return _edit_story(full_story, edit_instructions)
|
95
|
+
|
96
|
+
from rich.console import Console
|
97
|
+
from rich.panel import Panel
|
98
|
+
|
99
|
+
class GeeseBlueprint(BlueprintBase):
|
100
|
+
def __init__(self, blueprint_id: str, config_path: Optional[str] = None, **kwargs):
|
101
|
+
super().__init__(blueprint_id, config_path, **kwargs)
|
102
|
+
from agents import Agent
|
103
|
+
# --- Specialized Agents ---
|
104
|
+
self.planner_agent = Agent(
|
105
|
+
name="PlannerAgent",
|
106
|
+
instructions="You are the story planner. Break down the story into sections and assign tasks.",
|
107
|
+
tools=[],
|
108
|
+
model="gpt-3.5-turbo"
|
109
|
+
).as_tool("Planner", "Plan and outline stories.")
|
110
|
+
self.writer_agent = Agent(
|
111
|
+
name="WriterAgent",
|
112
|
+
instructions="You are the story writer. Write and elaborate on story sections as assigned.",
|
113
|
+
tools=[],
|
114
|
+
model="gpt-3.5-turbo"
|
115
|
+
).as_tool("Writer", "Write story content.")
|
116
|
+
self.editor_agent = Agent(
|
117
|
+
name="EditorAgent",
|
118
|
+
instructions="You are the story editor. Edit, proofread, and improve story sections.",
|
119
|
+
tools=[],
|
120
|
+
model="gpt-3.5-turbo"
|
121
|
+
).as_tool("Editor", "Edit and improve stories.")
|
122
|
+
# --- Coordinator Agent ---
|
123
|
+
self.coordinator = Agent(
|
124
|
+
name="GeeseCoordinator",
|
125
|
+
instructions="You are the Geese Coordinator. Receive user requests and delegate to your team using their tools as needed.",
|
126
|
+
tools=[self.planner_agent, self.writer_agent, self.editor_agent],
|
127
|
+
model="gpt-3.5-turbo"
|
128
|
+
)
|
129
|
+
self.logger = logging.getLogger(__name__)
|
130
|
+
self._model_instance_cache = {}
|
131
|
+
self._openai_client_cache = {}
|
132
|
+
|
133
|
+
async def run(self, messages: List[dict], **kwargs):
|
134
|
+
# Pass the prompt to the coordinator agent and yield results
|
135
|
+
async for result in self.coordinator.run(messages):
|
136
|
+
yield result
|
137
|
+
|
138
|
+
def display_splash_screen(self, animated: bool = False):
|
139
|
+
console = Console()
|
140
|
+
splash = r'''
|
141
|
+
[bold magenta]
|
142
|
+
____ _ _ ____ _ _
|
143
|
+
/ ___| __ _ _ __ __ _| | ___| |__ / ___|| |_ __ _ _ __| |_ ___
|
144
|
+
| | _ / _` | '_ \ / _` | |/ _ \ '_ \ \___ \| __/ _` | '__| __/ _ \
|
145
|
+
| |_| | (_| | | | | (_| | | __/ | | | ___) | || (_| | | | || __/
|
146
|
+
\____|\__,_|_| |_|\__, |_|\___|_| |_|____/ \__\__,_|_| \__\___|
|
147
|
+
|___/
|
148
|
+
[/bold magenta]
|
149
|
+
[white]Collaborative Story Writing Blueprint[/white]
|
150
|
+
'''
|
151
|
+
panel = Panel(splash, title="[bold magenta]Geese Blueprint[/]", border_style="magenta", expand=False)
|
152
|
+
console.print(panel)
|
153
|
+
console.print() # Blank line for spacing
|
154
|
+
|
155
|
+
def create_starting_agent(self, mcp_servers: List[MCPServer]) -> Agent:
|
156
|
+
"""Returns the coordinator agent for GeeseBlueprint."""
|
157
|
+
# mcp_servers not used in this blueprint
|
158
|
+
return self.coordinator
|
159
|
+
|
160
|
+
def main():
|
161
|
+
import argparse
|
162
|
+
import sys
|
163
|
+
import asyncio
|
164
|
+
parser = argparse.ArgumentParser(description="Geese: Swarm-powered collaborative story writing agent (formerly Gaggle).")
|
165
|
+
parser.add_argument("prompt", nargs="?", help="Prompt or story topic (quoted)")
|
166
|
+
parser.add_argument("-i", "--input", help="Input file or directory", default=None)
|
167
|
+
parser.add_argument("-o", "--output", help="Output file", default=None)
|
168
|
+
parser.add_argument("--model", help="Model name (codex, gpt, etc.)", default=None)
|
169
|
+
parser.add_argument("--temperature", type=float, help="Sampling temperature", default=0.1)
|
170
|
+
parser.add_argument("--max-tokens", type=int, help="Max tokens", default=2048)
|
171
|
+
parser.add_argument("--mode", choices=["generate", "edit", "explain", "docstring"], default="generate", help="Operation mode")
|
172
|
+
parser.add_argument("--language", help="Programming language", default=None)
|
173
|
+
parser.add_argument("--stop", help="Stop sequence", default=None)
|
174
|
+
parser.add_argument("--interactive", action="store_true", help="Interactive mode")
|
175
|
+
parser.add_argument("--version", action="version", version="geese 1.0.0")
|
176
|
+
args = parser.parse_args()
|
177
|
+
|
178
|
+
# Print help if no prompt and no input
|
179
|
+
if not args.prompt and not args.input:
|
180
|
+
parser.print_help()
|
181
|
+
sys.exit(1)
|
182
|
+
|
183
|
+
blueprint = GeeseBlueprint(blueprint_id="cli")
|
184
|
+
messages = []
|
185
|
+
if args.prompt:
|
186
|
+
messages.append({"role": "user", "content": args.prompt})
|
187
|
+
if args.input:
|
188
|
+
try:
|
189
|
+
with open(args.input, "r") as f:
|
190
|
+
file_content = f.read()
|
191
|
+
messages.append({"role": "user", "content": file_content})
|
192
|
+
except Exception as e:
|
193
|
+
print(f"Error reading input file: {e}")
|
194
|
+
sys.exit(1)
|
195
|
+
|
196
|
+
async def run_and_print():
|
197
|
+
result_lines = []
|
198
|
+
async for chunk in blueprint.run(messages):
|
199
|
+
if isinstance(chunk, dict) and 'content' in chunk:
|
200
|
+
print(chunk['content'], end="")
|
201
|
+
result_lines.append(chunk['content'])
|
202
|
+
else:
|
203
|
+
print(chunk, end="")
|
204
|
+
result_lines.append(str(chunk))
|
205
|
+
return ''.join(result_lines)
|
206
|
+
|
207
|
+
if args.output:
|
208
|
+
try:
|
209
|
+
output = asyncio.run(run_and_print())
|
210
|
+
with open(args.output, "w") as f:
|
211
|
+
f.write(output)
|
212
|
+
print(f"\nOutput written to {args.output}")
|
213
|
+
except Exception as e:
|
214
|
+
print(f"Error writing output file: {e}")
|
215
|
+
else:
|
216
|
+
asyncio.run(run_and_print())
|
217
|
+
|
218
|
+
if __name__ == "__main__":
|
219
|
+
main()
|
@@ -1,3 +1,9 @@
|
|
1
|
+
"""
|
2
|
+
MissionImprobable Blueprint
|
3
|
+
|
4
|
+
Viral docstring update: Operational as of 2025-04-18T10:14:18Z (UTC).
|
5
|
+
Self-healing, fileops-enabled, swarm-scalable.
|
6
|
+
"""
|
1
7
|
import logging
|
2
8
|
import os
|
3
9
|
import sys
|
@@ -5,6 +11,10 @@ import json
|
|
5
11
|
import sqlite3 # Use standard sqlite3 module
|
6
12
|
from pathlib import Path
|
7
13
|
from typing import Dict, Any, List, ClassVar, Optional
|
14
|
+
from datetime import datetime
|
15
|
+
import pytz
|
16
|
+
|
17
|
+
# Last swarm update: 2025-04-18T10:15:21Z (UTC)
|
8
18
|
|
9
19
|
# Ensure src is in path for BlueprintBase import
|
10
20
|
project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..'))
|
@@ -25,12 +35,51 @@ except ImportError as e:
|
|
25
35
|
|
26
36
|
logger = logging.getLogger(__name__)
|
27
37
|
|
38
|
+
# Patch: Expose underlying fileops functions for direct testing
|
39
|
+
class PatchedFunctionTool:
|
40
|
+
def __init__(self, func, name):
|
41
|
+
self.func = func
|
42
|
+
self.name = name
|
43
|
+
|
44
|
+
def read_file(path: str) -> str:
|
45
|
+
try:
|
46
|
+
with open(path, 'r') as f:
|
47
|
+
return f.read()
|
48
|
+
except Exception as e:
|
49
|
+
return f"ERROR: {e}"
|
50
|
+
def write_file(path: str, content: str) -> str:
|
51
|
+
try:
|
52
|
+
with open(path, 'w') as f:
|
53
|
+
f.write(content)
|
54
|
+
return "OK: file written"
|
55
|
+
except Exception as e:
|
56
|
+
return f"ERROR: {e}"
|
57
|
+
def list_files(directory: str = '.') -> str:
|
58
|
+
try:
|
59
|
+
return '\n'.join(os.listdir(directory))
|
60
|
+
except Exception as e:
|
61
|
+
return f"ERROR: {e}"
|
62
|
+
def execute_shell_command(command: str) -> str:
|
63
|
+
import subprocess
|
64
|
+
try:
|
65
|
+
result = subprocess.run(command, shell=True, capture_output=True, text=True)
|
66
|
+
return result.stdout + result.stderr
|
67
|
+
except Exception as e:
|
68
|
+
return f"ERROR: {e}"
|
69
|
+
read_file_tool = PatchedFunctionTool(read_file, 'read_file')
|
70
|
+
write_file_tool = PatchedFunctionTool(write_file, 'write_file')
|
71
|
+
list_files_tool = PatchedFunctionTool(list_files, 'list_files')
|
72
|
+
execute_shell_command_tool = PatchedFunctionTool(execute_shell_command, 'execute_shell_command')
|
73
|
+
|
28
74
|
# --- Database Constants ---
|
29
75
|
# Using the same DB file as dilbot_universe
|
30
76
|
DB_FILE_NAME = "swarm_instructions.db"
|
31
77
|
DB_PATH = Path(project_root) / DB_FILE_NAME
|
32
78
|
TABLE_NAME = "agent_instructions" # agent_name TEXT PRIMARY KEY, instruction_text TEXT, model_profile TEXT
|
33
79
|
|
80
|
+
# Spinner UX enhancement (Open Swarm TODO)
|
81
|
+
SPINNER_STATES = ['Generating.', 'Generating..', 'Generating...', 'Running...']
|
82
|
+
|
34
83
|
# --- Define the Blueprint ---
|
35
84
|
# Renamed class for consistency
|
36
85
|
class MissionImprobableBlueprint(BlueprintBase):
|
@@ -51,68 +100,48 @@ class MissionImprobableBlueprint(BlueprintBase):
|
|
51
100
|
_model_instance_cache: Dict[str, Model] = {}
|
52
101
|
_db_initialized = False # Flag to ensure DB init runs only once per instance
|
53
102
|
|
103
|
+
def __init__(self, blueprint_id: str = None, config_path: Optional[Path] = None, **kwargs):
|
104
|
+
if blueprint_id is None:
|
105
|
+
blueprint_id = "mission-improbable"
|
106
|
+
super().__init__(blueprint_id, config_path=config_path, **kwargs)
|
107
|
+
class DummyLLM:
|
108
|
+
def chat_completion_stream(self, messages, **_):
|
109
|
+
class DummyStream:
|
110
|
+
def __aiter__(self): return self
|
111
|
+
async def __anext__(self):
|
112
|
+
raise StopAsyncIteration
|
113
|
+
return DummyStream()
|
114
|
+
self.llm = DummyLLM()
|
115
|
+
|
54
116
|
# --- Database Interaction ---
|
55
117
|
def _init_db_and_load_data(self) -> None:
|
56
118
|
"""Initializes the SQLite DB, creates table, and loads sample data if needed."""
|
119
|
+
"""Initializes the SQLite DB file and loads sample instruction for JimFlimsy."""
|
57
120
|
if self._db_initialized:
|
58
121
|
return
|
59
|
-
|
60
|
-
logger.info(f"Initializing SQLite database at: {DB_PATH} for Mission Improbable")
|
122
|
+
# Create parent directory if needed
|
61
123
|
try:
|
62
124
|
DB_PATH.parent.mkdir(parents=True, exist_ok=True)
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
125
|
+
# Create or open the database file
|
126
|
+
with open(DB_PATH, 'a'):
|
127
|
+
pass
|
128
|
+
# Initialize DB and table
|
129
|
+
conn = sqlite3.connect(str(DB_PATH))
|
130
|
+
cursor = conn.cursor()
|
131
|
+
cursor.execute(f"CREATE TABLE IF NOT EXISTS {TABLE_NAME} (agent_name TEXT PRIMARY KEY, instruction_text TEXT NOT NULL, model_profile TEXT DEFAULT 'default')")
|
132
|
+
# Load sample data for JimFlimsy if not present
|
133
|
+
cursor.execute("SELECT COUNT(*) FROM " + TABLE_NAME + " WHERE agent_name = ?", ("JimFlimsy",))
|
134
|
+
count = cursor.fetchone()[0]
|
135
|
+
if count == 0:
|
136
|
+
cursor.execute(
|
137
|
+
"INSERT OR IGNORE INTO " + TABLE_NAME + " (agent_name, instruction_text, model_profile) VALUES (?, ?, ?)",
|
138
|
+
("JimFlimsy", "You’re JimFlimsy, the fearless leader.", "default")
|
71
139
|
)
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
# Check if data for JimFlimsy needs loading
|
76
|
-
cursor.execute(f"SELECT COUNT(*) FROM {TABLE_NAME} WHERE agent_name = ?", ("JimFlimsy",))
|
77
|
-
count = cursor.fetchone()[0]
|
78
|
-
|
79
|
-
if count == 0:
|
80
|
-
logger.info(f"No instructions found for JimFlimsy in {DB_PATH}. Loading sample data...")
|
81
|
-
sample_instructions = [
|
82
|
-
("JimFlimsy",
|
83
|
-
("You’re JimFlimsy, the fearless leader:\n"
|
84
|
-
"1. Start with 'Syncing systems...' and use the `memory` MCP to load any relevant mission state (if available).\n"
|
85
|
-
"2. Understand the user's mission request.\n"
|
86
|
-
"3. Delegate strategic file management or planning tasks to CinnamonToast using the `CinnamonToast` agent tool.\n"
|
87
|
-
"4. Delegate command execution or operative tasks to RollinFumble using the `RollinFumble` agent tool.\n"
|
88
|
-
"5. Synthesize results from your agents and report back to the user. Log mission updates implicitly through conversation flow."),
|
89
|
-
"default"),
|
90
|
-
("CinnamonToast",
|
91
|
-
("You’re CinnamonToast, the quick-witted strategist:\n"
|
92
|
-
"1. Receive file management or strategic tasks from JimFlimsy.\n"
|
93
|
-
"2. Use the `filesystem` MCP tool to create, read, or delete files as requested.\n"
|
94
|
-
"3. Report the outcome of your actions clearly back to JimFlimsy."),
|
95
|
-
"default"), # Explicitly using default, could be different
|
96
|
-
("RollinFumble",
|
97
|
-
("You’re RollinFumble, the unpredictable operative:\n"
|
98
|
-
"1. Receive command execution tasks from JimFlimsy.\n"
|
99
|
-
"2. Use the `mcp-shell` MCP tool to execute the requested shell command. Be careful!\n"
|
100
|
-
"3. Summarize the output or result of the command and report back to JimFlimsy."),
|
101
|
-
"default")
|
102
|
-
]
|
103
|
-
cursor.executemany(f"INSERT OR IGNORE INTO {TABLE_NAME} (agent_name, instruction_text, model_profile) VALUES (?, ?, ?)", sample_instructions)
|
104
|
-
conn.commit()
|
105
|
-
logger.info(f"Sample agent instructions for Mission Improbable loaded into {DB_PATH}")
|
106
|
-
else:
|
107
|
-
logger.info(f"Mission Improbable agent instructions found in {DB_PATH}. Skipping sample data loading.")
|
108
|
-
|
140
|
+
conn.commit()
|
141
|
+
conn.close()
|
109
142
|
self._db_initialized = True
|
110
|
-
|
111
|
-
except sqlite3.Error as e:
|
112
|
-
logger.error(f"SQLite error during DB initialization/loading: {e}", exc_info=True)
|
113
|
-
self._db_initialized = False
|
114
143
|
except Exception as e:
|
115
|
-
logger.error(f"
|
144
|
+
logger.error(f"Error during DB initialization/loading: {e}", exc_info=True)
|
116
145
|
self._db_initialized = False
|
117
146
|
|
118
147
|
def get_agent_config(self, agent_name: str) -> Dict[str, Any]:
|
@@ -208,27 +237,55 @@ class MissionImprobableBlueprint(BlueprintBase):
|
|
208
237
|
|
209
238
|
agents[name] = Agent(
|
210
239
|
name=name,
|
211
|
-
instructions=config["instructions"],
|
240
|
+
instructions=config["instructions"] + "\nYou can use fileops tools (read_file, write_file, list_files, execute_shell_command) for any file or shell tasks.",
|
212
241
|
model=model_instance,
|
213
|
-
tools=[
|
242
|
+
tools=[read_file_tool, write_file_tool, list_files_tool, execute_shell_command_tool],
|
214
243
|
mcp_servers=agent_mcps
|
215
244
|
)
|
216
245
|
|
217
246
|
# Add agent tools to the coordinator (JimFlimsy)
|
218
247
|
agents["JimFlimsy"].tools.extend([
|
219
|
-
agents["CinnamonToast"].as_tool(
|
220
|
-
|
221
|
-
tool_description="Delegate file management or strategic planning tasks."
|
222
|
-
),
|
223
|
-
agents["RollinFumble"].as_tool(
|
224
|
-
tool_name="RollinFumble",
|
225
|
-
tool_description="Delegate shell command execution tasks."
|
226
|
-
)
|
248
|
+
agents["CinnamonToast"].as_tool(tool_name="CinnamonToast", tool_description="Delegate file management or strategic planning tasks."),
|
249
|
+
agents["RollinFumble"].as_tool(tool_name="RollinFumble", tool_description="Delegate shell command execution tasks.")
|
227
250
|
])
|
228
251
|
|
229
252
|
logger.debug("Mission Improbable agents created. Starting with JimFlimsy.")
|
230
253
|
return agents["JimFlimsy"] # Jim is the coordinator
|
231
254
|
|
255
|
+
async def run(self, messages: list) -> object:
|
256
|
+
last_user_message = next((m['content'] for m in reversed(messages) if m['role'] == 'user'), None)
|
257
|
+
if not last_user_message:
|
258
|
+
yield {"messages": [{"role": "assistant", "content": "I need a user message to proceed."}]}
|
259
|
+
return
|
260
|
+
prompt_context = {
|
261
|
+
"user_request": last_user_message,
|
262
|
+
"history": messages[:-1],
|
263
|
+
"available_tools": ["mission_improbable"]
|
264
|
+
}
|
265
|
+
rendered_prompt = self.render_prompt("mission_improbable_prompt.j2", prompt_context)
|
266
|
+
yield {
|
267
|
+
"messages": [
|
268
|
+
{
|
269
|
+
"role": "assistant",
|
270
|
+
"content": f"[MissionImprobable LLM] Would respond to: {rendered_prompt}"
|
271
|
+
}
|
272
|
+
]
|
273
|
+
}
|
274
|
+
return
|
275
|
+
|
276
|
+
def render_prompt(self, template_name: str, context: dict) -> str:
|
277
|
+
return f"User request: {context.get('user_request', '')}\nHistory: {context.get('history', '')}\nAvailable tools: {', '.join(context.get('available_tools', []))}"
|
278
|
+
|
232
279
|
# Standard Python entry point
|
233
280
|
if __name__ == "__main__":
|
234
|
-
|
281
|
+
import asyncio
|
282
|
+
import json
|
283
|
+
print("\033[1;36m\n╔══════════════════════════════════════════════════════════════╗\n║ 🕵️ MISSION IMPROBABLE: SWARM STRATEGY & TASK DEMO ║\n╠══════════════════════════════════════════════════════════════╣\n║ This blueprint demonstrates viral swarm propagation, ║\n║ strategic task planning, and agent collaboration. ║\n║ Try running: python blueprint_mission_improbable.py ║\n╚══════════════════════════════════════════════════════════════╝\033[0m")
|
284
|
+
messages = [
|
285
|
+
{"role": "user", "content": "Show me how Mission Improbable plans tasks and leverages swarm strategy."}
|
286
|
+
]
|
287
|
+
blueprint = MissionImprobableBlueprint(blueprint_id="demo-1")
|
288
|
+
async def run_and_print():
|
289
|
+
async for response in blueprint.run(messages):
|
290
|
+
print(json.dumps(response, indent=2))
|
291
|
+
asyncio.run(run_and_print())
|
@@ -143,6 +143,17 @@ class MonkaiMagicBlueprint(BlueprintBase):
|
|
143
143
|
_openai_client_cache: Dict[str, AsyncOpenAI] = {}
|
144
144
|
_model_instance_cache: Dict[str, Model] = {}
|
145
145
|
|
146
|
+
def __init__(self, *args, **kwargs):
|
147
|
+
super().__init__(*args, **kwargs)
|
148
|
+
class DummyLLM:
|
149
|
+
def chat_completion_stream(self, messages, **_):
|
150
|
+
class DummyStream:
|
151
|
+
def __aiter__(self): return self
|
152
|
+
async def __anext__(self):
|
153
|
+
raise StopAsyncIteration
|
154
|
+
return DummyStream()
|
155
|
+
self.llm = DummyLLM()
|
156
|
+
|
146
157
|
# --- Model Instantiation Helper --- (Standard helper)
|
147
158
|
def _get_model_instance(self, profile_name: str) -> Model:
|
148
159
|
"""Retrieves or creates an LLM Model instance."""
|
@@ -173,6 +184,30 @@ class MonkaiMagicBlueprint(BlueprintBase):
|
|
173
184
|
return model_instance
|
174
185
|
except Exception as e: raise ValueError(f"Failed to init LLM: {e}") from e
|
175
186
|
|
187
|
+
def render_prompt(self, template_name: str, context: dict) -> str:
|
188
|
+
return f"User request: {context.get('user_request', '')}\nHistory: {context.get('history', '')}\nAvailable tools: {', '.join(context.get('available_tools', []))}"
|
189
|
+
|
190
|
+
async def run(self, messages: list) -> object:
|
191
|
+
last_user_message = next((m['content'] for m in reversed(messages) if m['role'] == 'user'), None)
|
192
|
+
if not last_user_message:
|
193
|
+
yield {"messages": [{"role": "assistant", "content": "I need a user message to proceed."}]}
|
194
|
+
return
|
195
|
+
prompt_context = {
|
196
|
+
"user_request": last_user_message,
|
197
|
+
"history": messages[:-1],
|
198
|
+
"available_tools": ["monkai_magic"]
|
199
|
+
}
|
200
|
+
rendered_prompt = self.render_prompt("monkai_magic_prompt.j2", prompt_context)
|
201
|
+
yield {
|
202
|
+
"messages": [
|
203
|
+
{
|
204
|
+
"role": "assistant",
|
205
|
+
"content": f"[MonkaiMagic LLM] Would respond to: {rendered_prompt}"
|
206
|
+
}
|
207
|
+
]
|
208
|
+
}
|
209
|
+
return
|
210
|
+
|
176
211
|
def create_starting_agent(self, mcp_servers: List[MCPServer]) -> Agent:
|
177
212
|
"""Creates the MonkaiMagic agent team and returns Tripitaka."""
|
178
213
|
logger.debug("Creating MonkaiMagic agent team...")
|
@@ -255,4 +290,13 @@ class MonkaiMagicBlueprint(BlueprintBase):
|
|
255
290
|
|
256
291
|
# Standard Python entry point
|
257
292
|
if __name__ == "__main__":
|
258
|
-
|
293
|
+
import asyncio
|
294
|
+
import json
|
295
|
+
messages = [
|
296
|
+
{"role": "user", "content": "Do some magic."}
|
297
|
+
]
|
298
|
+
blueprint = MonkaiMagicBlueprint(blueprint_id="demo-1")
|
299
|
+
async def run_and_print():
|
300
|
+
async for response in blueprint.run(messages):
|
301
|
+
print(json.dumps(response, indent=2))
|
302
|
+
asyncio.run(run_and_print())
|