open-swarm 0.1.1745125904__py3-none-any.whl → 0.1.1745125927__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: open-swarm
3
- Version: 0.1.1745125904
3
+ Version: 0.1.1745125927
4
4
  Summary: Open Swarm: Orchestrating AI Agent Swarms with Django
5
5
  Project-URL: Homepage, https://github.com/yourusername/open-swarm
6
6
  Project-URL: Documentation, https://github.com/yourusername/open-swarm/blob/main/README.md
@@ -32,13 +32,6 @@ swarm/blueprints/django_chat/urls.py,sha256=TTTF3pgymvCYbuxpwi4WRBPv8ftQNH4pEoUR
32
32
  swarm/blueprints/django_chat/views.py,sha256=MUKjXXjXsq8jMZtAb4RR9g2mEYrwFemN6Bqxpeyi7p4,1299
33
33
  swarm/blueprints/django_chat/templates/django_chat/django_chat_webpage.html,sha256=wAEOI4Wg0JJ8drXaOcr2Pel6lW3JSHmyIpbocLS5tI8,1649
34
34
  swarm/blueprints/echocraft/blueprint_echocraft.py,sha256=9XNyuMZIBrm9kpnv1aq_W3h-9Zr2dVdzchI2uFXslg0,10988
35
- swarm/blueprints/family_ties/apps.py,sha256=EjV7AxDNsLM4gsLr_qMEiLAVbERuo1ZsdU9vPtOEYAY,287
36
- swarm/blueprints/family_ties/blueprint_family_ties.py,sha256=AkYz9_O7QSBhoZAG1jaFlTXEouL1eUfa0y6hw9MqSro,9762
37
- swarm/blueprints/family_ties/models.py,sha256=C3_okdVVYuu9xOpoKRsaLoGrM2775cS_cU4UKYAkJ9s,903
38
- swarm/blueprints/family_ties/serializers.py,sha256=kH3T6OgXjF534bO3gfAUr6GpXZ5Jx0BQkK58nvuEcqA,325
39
- swarm/blueprints/family_ties/settings.py,sha256=5zcVsq7ny3GLWcJnOplZW4fMFNtyC3ba0ZOESRD2gh4,425
40
- swarm/blueprints/family_ties/urls.py,sha256=awRZHb1gb1p3I6YZzfKMGSydd6kYPTLgax2jZ1ocS4U,294
41
- swarm/blueprints/family_ties/views.py,sha256=FbPkDNlFEixtRFbSpkr51IyJ28FRkXa1W5xyO_KeXH0,1081
42
35
  swarm/blueprints/flock/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
43
36
  swarm/blueprints/geese/blueprint_geese.py,sha256=uP0gPHFACI18a_cY5f89ndqccNrK3YxjQPgA85T8Cms,9339
44
37
  swarm/blueprints/mcp_demo/blueprint_mcp_demo.py,sha256=bTHupSUdg9OzaRoTu9obGsxk48f9o3wUCLqVWeWYW-w,17695
@@ -51,7 +44,6 @@ swarm/blueprints/poets/blueprint_poets.py,sha256=_yWU2ujGQw_Q6ZVXX8yW7GKOFkKNyf6
51
44
  swarm/blueprints/rue_code/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
52
45
  swarm/blueprints/rue_code/blueprint_rue_code.py,sha256=odxqvAIzSESlm9eecZNz-JBsjeoRpFgCZs-7tG1ZkLQ,13273
53
46
  swarm/blueprints/suggestion/blueprint_suggestion.py,sha256=Qm5YbP19SETFtXc-gTsmGUh71US7huUyKZKqtRv-Qeg,10846
54
- swarm/blueprints/unapologetic_press/blueprint_unapologetic_press.py,sha256=lIq6oGQlVtI8sxCq9DKmpLaHpHv-8_NJ5XHB7TEL_dg,22399
55
47
  swarm/blueprints/whiskeytango_foxtrot/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
56
48
  swarm/blueprints/whiskeytango_foxtrot/apps.py,sha256=V1QKvyb2Vz-EtDNhhNe4tw2W9LYhNDuiaIq_fAU4ilw,334
57
49
  swarm/blueprints/whiskeytango_foxtrot/blueprint_whiskeytango_foxtrot.py,sha256=y5OUPe5-W0Bhm3nO0hBH31ucXuote3PBVgb0WeOQodE,16567
@@ -279,8 +271,8 @@ swarm/views/message_views.py,sha256=sDUnXyqKXC8WwIIMAlWf00s2_a2T9c75Na5FvYMJwBM,
279
271
  swarm/views/model_views.py,sha256=aAbU4AZmrOTaPeKMWtoKK7FPYHdaN3Zbx55JfKzYTRY,2937
280
272
  swarm/views/utils.py,sha256=8Usc0g0L0NPegNAyY20tJBNBy-JLwODf4VmxV0yUtpw,3627
281
273
  swarm/views/web_views.py,sha256=T1CKe-Nyv1C8aDt6QFTGWo_dkH7ojWAvS_QW9mZnZp0,7371
282
- open_swarm-0.1.1745125904.dist-info/METADATA,sha256=q8jtZKzgtpfD5DLbBjdCbEdzi3jwsKfx3Nn-WwJfJV8,26977
283
- open_swarm-0.1.1745125904.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
284
- open_swarm-0.1.1745125904.dist-info/entry_points.txt,sha256=fo28d0_zJrytRsh8QqkdlWQT_9lyAwYUx1WuSTDI3HM,177
285
- open_swarm-0.1.1745125904.dist-info/licenses/LICENSE,sha256=BU9bwRlnOt_JDIb6OT55Q4leLZx9RArDLTFnlDIrBEI,1062
286
- open_swarm-0.1.1745125904.dist-info/RECORD,,
274
+ open_swarm-0.1.1745125927.dist-info/METADATA,sha256=AjVBunlRv-LH1Al4Uq4n8OAcX0z_cwCsF31SqMCqoN0,26977
275
+ open_swarm-0.1.1745125927.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
276
+ open_swarm-0.1.1745125927.dist-info/entry_points.txt,sha256=fo28d0_zJrytRsh8QqkdlWQT_9lyAwYUx1WuSTDI3HM,177
277
+ open_swarm-0.1.1745125927.dist-info/licenses/LICENSE,sha256=BU9bwRlnOt_JDIb6OT55Q4leLZx9RArDLTFnlDIrBEI,1062
278
+ open_swarm-0.1.1745125927.dist-info/RECORD,,
@@ -1,11 +0,0 @@
1
- from django.apps import AppConfig
2
- import logging
3
-
4
- logger = logging.getLogger(__name__)
5
-
6
- class FamilyTiesConfig(AppConfig):
7
- name = 'blueprints.family_ties'
8
- verbose_name = "Family Ties Blueprint"
9
-
10
- def ready(self):
11
- logger.debug(f"Registering {self.name} via AppConfig")
@@ -1,189 +0,0 @@
1
- import logging
2
- import os
3
- import sys
4
- from typing import Dict, Any, List, ClassVar, Optional
5
-
6
- # Ensure src is in path for BlueprintBase import
7
- project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..'))
8
- src_path = os.path.join(project_root, 'src')
9
- if src_path not in sys.path: sys.path.insert(0, src_path)
10
-
11
- from typing import Optional
12
- from pathlib import Path
13
- try:
14
- from agents import Agent, Tool, function_tool, Runner
15
- from agents.mcp import MCPServer
16
- from agents.models.interface import Model
17
- from agents.models.openai_chatcompletions import OpenAIChatCompletionsModel
18
- from openai import AsyncOpenAI
19
- from swarm.core.blueprint_base import BlueprintBase
20
- except ImportError as e:
21
- print(f"ERROR: Import failed in FamilyTiesBlueprint: {e}. Check dependencies.")
22
- print(f"sys.path: {sys.path}")
23
- sys.exit(1)
24
-
25
- logger = logging.getLogger(__name__)
26
-
27
- # --- Agent Instructions ---
28
- # Keep instructions defined globally for clarity
29
-
30
- SHARED_INSTRUCTIONS = """
31
- You are part of the Grifton family WordPress team. Peter coordinates, Brian manages WordPress.
32
- Roles:
33
- - PeterGrifton (Coordinator): User interface, planning, delegates WP tasks via `BrianGrifton` Agent Tool.
34
- - BrianGrifton (WordPress Manager): Uses `server-wp-mcp` MCP tool (likely function `wp_call_endpoint`) to manage content based on Peter's requests.
35
- Respond ONLY to the agent who tasked you.
36
- """
37
-
38
- peter_instructions = (
39
- f"{SHARED_INSTRUCTIONS}\n\n"
40
- "YOUR ROLE: PeterGrifton, Coordinator. You handle user requests about WordPress.\n"
41
- "1. Understand the user's goal (create post, edit post, list sites, etc.).\n"
42
- "2. Delegate the task to Brian using the `BrianGrifton` agent tool.\n"
43
- "3. Provide ALL necessary details to Brian (content, title, site ID, endpoint details if known, method like GET/POST).\n"
44
- "4. Relay Brian's response (success, failure, IDs, data) back to the user clearly."
45
- )
46
-
47
- brian_instructions = (
48
- f"{SHARED_INSTRUCTIONS}\n\n"
49
- "YOUR ROLE: BrianGrifton, WordPress Manager. You interact with WordPress sites via the `server-wp-mcp` tool.\n"
50
- "1. Receive tasks from Peter.\n"
51
- "2. Determine the correct WordPress REST API endpoint and parameters required (e.g., `site`, `endpoint`, `method`, `params`).\n"
52
- "3. Call the MCP tool function (likely named `wp_call_endpoint` or similar provided by the MCP server) with the correct JSON arguments.\n"
53
- "4. Report the outcome (success confirmation, data returned, or error message) precisely back to Peter."
54
- )
55
-
56
- # --- Define the Blueprint ---
57
- class FamilyTiesBlueprint(BlueprintBase):
58
- def __init__(self, blueprint_id: str, config_path: Optional[Path] = None, **kwargs):
59
- super().__init__(blueprint_id, config_path=config_path, **kwargs)
60
-
61
- """Manages WordPress content with a Peter/Brian agent team using the `server-wp-mcp` server."""
62
- metadata: ClassVar[Dict[str, Any]] = {
63
- "name": "FamilyTiesBlueprint", # Standardized name
64
- "title": "Family Ties / ChaosCrew WP Manager",
65
- "description": "Manages WordPress content using Peter (coordinator) and Brian (WP manager via MCP).",
66
- "version": "1.2.0", # Incremented version
67
- "author": "Open Swarm Team (Refactored)",
68
- "tags": ["wordpress", "cms", "multi-agent", "mcp"],
69
- "required_mcp_servers": ["server-wp-mcp"], # Brian needs this
70
- "env_vars": ["WP_SITES_PATH"] # Informational: MCP server needs this
71
- }
72
-
73
- # Caches
74
- _openai_client_cache: Dict[str, AsyncOpenAI] = {}
75
- _model_instance_cache: Dict[str, Model] = {}
76
-
77
- # --- Model Instantiation Helper --- (Standard helper)
78
- def _get_model_instance(self, profile_name: str) -> Model:
79
- """Retrieves or creates an LLM Model instance."""
80
- # ... (Implementation is the same as in previous refactors) ...
81
- if profile_name in self._model_instance_cache:
82
- logger.debug(f"Using cached Model instance for profile '{profile_name}'.")
83
- return self._model_instance_cache[profile_name]
84
- logger.debug(f"Creating new Model instance for profile '{profile_name}'.")
85
- profile_data = self.get_llm_profile(profile_name)
86
- if not profile_data:
87
- logger.critical(f"LLM profile '{profile_name}' (or 'default') not found.")
88
- raise ValueError(f"Missing LLM profile configuration for '{profile_name}' or 'default'.")
89
- provider = profile_data.get("provider", "openai").lower()
90
- model_name = profile_data.get("model")
91
- if not model_name:
92
- logger.critical(f"LLM profile '{profile_name}' missing 'model' key.")
93
- raise ValueError(f"Missing 'model' key in LLM profile '{profile_name}'.")
94
- if provider != "openai":
95
- logger.error(f"Unsupported LLM provider '{provider}'.")
96
- raise ValueError(f"Unsupported LLM provider: {provider}")
97
- client_cache_key = f"{provider}_{profile_data.get('base_url')}"
98
- if client_cache_key not in self._openai_client_cache:
99
- client_kwargs = { "api_key": profile_data.get("api_key"), "base_url": profile_data.get("base_url") }
100
- filtered_kwargs = {k: v for k, v in client_kwargs.items() if v is not None}
101
- log_kwargs = {k:v for k,v in filtered_kwargs.items() if k != 'api_key'}
102
- logger.debug(f"Creating new AsyncOpenAI client for '{profile_name}': {log_kwargs}")
103
- try: self._openai_client_cache[client_cache_key] = AsyncOpenAI(**filtered_kwargs)
104
- except Exception as e: raise ValueError(f"Failed to init OpenAI client: {e}") from e
105
- client = self._openai_client_cache[client_cache_key]
106
- logger.debug(f"Instantiating OpenAIChatCompletionsModel(model='{model_name}') for '{profile_name}'.")
107
- try:
108
- model_instance = OpenAIChatCompletionsModel(model=model_name, openai_client=client)
109
- self._model_instance_cache[profile_name] = model_instance
110
- return model_instance
111
- except Exception as e: raise ValueError(f"Failed to init LLM provider: {e}") from e
112
-
113
- def create_starting_agent(self, mcp_servers: List[MCPServer]) -> Agent:
114
- """Creates the Family Ties agent team and returns PeterGrifton (Coordinator)."""
115
- logger.debug("Creating Family Ties agent team...")
116
- self._model_instance_cache = {}
117
- self._openai_client_cache = {}
118
-
119
- default_profile_name = self.config.get("llm_profile", "default")
120
- logger.debug(f"Using LLM profile '{default_profile_name}' for Family Ties agents.")
121
- model_instance = self._get_model_instance(default_profile_name)
122
-
123
- # Filter for the required MCP server
124
- wp_mcp_server = next((s for s in mcp_servers if s.name == "server-wp-mcp"), None)
125
- if not wp_mcp_server:
126
- # This case should be prevented by BlueprintBase MCP check, but good practice
127
- logger.error("Required MCP server 'server-wp-mcp' not found/started. Brian will be non-functional.")
128
- # Optionally raise an error or allow degraded functionality
129
- # raise ValueError("Critical MCP server 'server-wp-mcp' failed to start.")
130
-
131
- # Instantiate Brian, passing the specific MCP server
132
- brian_agent = Agent(
133
- name="BrianGrifton",
134
- model=model_instance,
135
- instructions=brian_instructions,
136
- tools=[], # Brian uses MCP tools provided by the server
137
- mcp_servers=[wp_mcp_server] if wp_mcp_server else []
138
- )
139
-
140
- # Instantiate Peter, giving Brian as a tool
141
- peter_agent = Agent(
142
- name="PeterGrifton",
143
- model=model_instance,
144
- instructions=peter_instructions,
145
- tools=[
146
- brian_agent.as_tool(
147
- tool_name="BrianGrifton",
148
- tool_description="Delegate WordPress tasks (create/edit/list posts/sites, etc.) to Brian."
149
- )
150
- ],
151
- mcp_servers=[] # Peter doesn't directly use MCPs
152
- )
153
- logger.debug("Agents created: PeterGrifton (Coordinator), BrianGrifton (WordPress Manager).")
154
- return peter_agent # Peter is the entry point
155
-
156
- async def run(self, messages: List[Dict[str, Any]], **kwargs) -> Any:
157
- """Main execution entry point for the FamilyTies blueprint."""
158
- logger.info("FamilyTiesBlueprint run method called.")
159
- instruction = messages[-1].get("content", "") if messages else ""
160
- async for chunk in self._run_non_interactive(instruction, **kwargs):
161
- yield chunk
162
- logger.info("FamilyTiesBlueprint run method finished.")
163
-
164
- async def _run_non_interactive(self, instruction: str, **kwargs) -> Any:
165
- logger.info(f"Running FamilyTies non-interactively with instruction: '{instruction[:100]}...'")
166
- mcp_servers = kwargs.get("mcp_servers", [])
167
- agent = self.create_starting_agent(mcp_servers=mcp_servers)
168
- # Use Runner.run as a classmethod for portability
169
- from agents import Runner
170
- import os
171
- model_name = os.getenv("LITELLM_MODEL") or os.getenv("DEFAULT_LLM") or "gpt-3.5-turbo"
172
- try:
173
- for chunk in Runner.run(agent, instruction):
174
- yield chunk
175
- except Exception as e:
176
- logger.error(f"Error during non-interactive run: {e}", exc_info=True)
177
- yield {"messages": [{"role": "assistant", "content": f"An error occurred: {e}"}]}
178
-
179
- if __name__ == "__main__":
180
- import asyncio
181
- import json
182
- messages = [
183
- {"role": "user", "content": "Who are my relatives?"}
184
- ]
185
- blueprint = FamilyTiesBlueprint(blueprint_id="demo-1")
186
- async def run_and_print():
187
- async for response in blueprint.run(messages):
188
- print(json.dumps(response, indent=2))
189
- asyncio.run(run_and_print())
@@ -1,19 +0,0 @@
1
- from django.db import models
2
-
3
- class AgentInstruction(models.Model):
4
- agent_name = models.CharField(max_length=50, unique=True, help_text="Unique name (e.g., 'PeterGriffin').")
5
- instruction_text = models.TextField(help_text="Instructions for the agent.")
6
- model = models.CharField(max_length=50, default="default", help_text="LLM model.")
7
- env_vars = models.TextField(blank=True, null=True, help_text="JSON env variables.")
8
- mcp_servers = models.TextField(blank=True, null=True, help_text="JSON MCP servers.")
9
- created_at = models.DateTimeField(auto_now_add=True)
10
- updated_at = models.DateTimeField(auto_now=True)
11
-
12
- class Meta:
13
- app_label = "blueprints_chc"
14
- db_table = "swarm_agent_instruction_chc"
15
- verbose_name = "Agent Instruction"
16
- verbose_name_plural = "Agent Instructions"
17
-
18
- def __str__(self):
19
- return f"{self.agent_name} Instruction"
@@ -1,7 +0,0 @@
1
- from rest_framework import serializers
2
- from blueprints.chc.models import AgentInstruction
3
-
4
- class AgentInstructionSerializer(serializers.ModelSerializer):
5
- class Meta:
6
- model = AgentInstruction
7
- fields = ['id', 'agent_name', 'instruction_text', 'model', 'env_vars', 'mcp_servers', 'created_at', 'updated_at']
@@ -1,16 +0,0 @@
1
- import logging
2
- from django.apps import AppConfig
3
-
4
- logger = logging.getLogger(__name__)
5
-
6
- def update_installed_apps(settings):
7
- blueprint_app = "blueprints.chc"
8
- if blueprint_app not in settings.get("INSTALLED_APPS", []):
9
- settings["INSTALLED_APPS"].append(blueprint_app)
10
-
11
- try:
12
- update_installed_apps(globals())
13
- except Exception as e:
14
- logger.error("CHC update failed: %s", e)
15
-
16
- CORS_ALLOW_ALL_ORIGINS = True
@@ -1,10 +0,0 @@
1
- from django.urls import path, include
2
- from rest_framework.routers import DefaultRouter
3
- from .views import AgentInstructionViewSet
4
-
5
- router = DefaultRouter()
6
- router.register(r'instructions', AgentInstructionViewSet, basename='instructions')
7
-
8
- urlpatterns = [
9
- path('', include(router.urls)),
10
- ]
@@ -1,26 +0,0 @@
1
- from rest_framework.viewsets import ModelViewSet
2
- from rest_framework.permissions import AllowAny
3
- import os
4
- from swarm.auth import EnvOrTokenAuthentication
5
- from blueprints.chc.models import AgentInstruction
6
- from blueprints.chc.serializers import AgentInstructionSerializer
7
-
8
- class AgentInstructionViewSet(ModelViewSet):
9
- authentication_classes = [EnvOrTokenAuthentication]
10
- permission_classes = [AllowAny]
11
- queryset = AgentInstruction.objects.all()
12
- serializer_class = AgentInstructionSerializer
13
-
14
- def get_permissions(self):
15
- if os.getenv("ENABLE_API_AUTH", "false").lower() in ("true", "1", "t"):
16
- from rest_framework.permissions import IsAuthenticated
17
- return [IsAuthenticated()]
18
- return [AllowAny()]
19
-
20
- def perform_authentication(self, request):
21
- super().perform_authentication(request)
22
- if not request.user or not request.user.is_authenticated:
23
- from rest_framework.exceptions import AuthenticationFailed
24
- raise AuthenticationFailed("Invalid token.")
25
-
26
- __all__ = ["AgentInstructionViewSet"]
@@ -1,397 +0,0 @@
1
- """
2
- UnapologeticPress Blueprint
3
-
4
- Viral docstring update: Operational as of 2025-04-18T10:14:18Z (UTC).
5
- Self-healing, fileops-enabled, swarm-scalable.
6
- """
7
- import logging
8
- import os
9
- import random
10
- import sys
11
- import json
12
- import sqlite3 # Use standard sqlite3 module
13
- from pathlib import Path
14
- from typing import Dict, Any, List, ClassVar, Optional
15
- from datetime import datetime
16
- import pytz
17
-
18
- # Ensure src is in path for BlueprintBase import
19
- project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..'))
20
- src_path = os.path.join(project_root, 'src')
21
- if src_path not in sys.path: sys.path.insert(0, src_path)
22
-
23
- try:
24
- from agents import Agent, Tool, function_tool, Runner
25
- from agents.mcp import MCPServer
26
- from agents.models.interface import Model
27
- from agents.models.openai_chatcompletions import OpenAIChatCompletionsModel
28
- from openai import AsyncOpenAI
29
- from swarm.core.blueprint_base import BlueprintBase
30
- except ImportError as e:
31
- print(f"ERROR: Import failed in UnapologeticPressBlueprint: {e}. Check dependencies.")
32
- print(f"sys.path: {sys.path}")
33
- sys.exit(1)
34
-
35
- logger = logging.getLogger(__name__)
36
-
37
- # Last swarm update: 2025-04-18T10:15:21Z (UTC)
38
- # --- Database Constants ---
39
- DB_FILE_NAME = "swarm_instructions.db"
40
- DB_PATH = Path(project_root) / DB_FILE_NAME
41
- TABLE_NAME = "agent_instructions"
42
-
43
- # --- Agent Instructions ---
44
- # Shared knowledge base for collaboration context
45
- COLLABORATIVE_KNOWLEDGE = """
46
- Collaborative Poet Knowledge Base:
47
- * Gritty Buk - Raw urban realism exposing life's underbelly (Uses: memory, mcp-doc-forge, mcp-npx-fetch, brave-search, rag-docs)
48
- * Raven Poe - Gothic atmospherics & psychological darkness (Uses: mcp-server-reddit, mcp-doc-forge, mcp-npx-fetch, brave-search, rag-docs)
49
- * Mystic Blake - Prophetic visions through spiritual symbolism (Uses: mcp-doc-forge, mcp-npx-fetch, brave-search, server-wp-mcp, rag-docs)
50
- * Bard Whit - Expansive odes celebrating human connection (Uses: sequential-thinking, mcp-doc-forge, mcp-npx-fetch, brave-search, rag-docs)
51
- * Echo Plath - Confessional explorations of mental anguish (Uses: sqlite, mcp-doc-forge, mcp-npx-fetch, brave-search, rag-docs)
52
- * Frosted Woods - Rural metaphors revealing existential truths (Uses: filesystem, mcp-doc-forge, mcp-npx-fetch, brave-search, rag-docs)
53
- * Harlem Lang - Jazz-rhythm social commentary on racial justice (Uses: mcp-shell, mcp-doc-forge, mcp-npx-fetch, brave-search, rag-docs)
54
- * Verse Neru - Sensual imagery fused with revolutionary politics (Uses: server-wp-mcp, mcp-doc-forge, mcp-npx-fetch, brave-search, rag-docs)
55
- * Haiku Bash - Ephemeral nature snapshots through strict syllabic form (Uses: mcp-doc-forge, mcp-npx-fetch, brave-search, server-wp-mcp, rag-docs)
56
- """
57
-
58
- SHARED_PROTOCOL = """
59
- Collaboration Protocol:
60
- 1) Analyze the current poetry draft through your unique stylistic lens.
61
- 2) Use your assigned MCP tools for creative augmentation, research, or specific tasks if needed.
62
- 3) Pass the enhanced work to the most relevant poet agent tool based on the needed transformation or specific tooling required next. Refer to the Collaborative Poet Knowledge Base for styles and capabilities.
63
- """
64
-
65
- # Individual base instructions (will be combined with shared parts)
66
- AGENT_BASE_INSTRUCTIONS = {
67
- "Gritty Buk": (
68
- "You are Charles Bukowski incarnate: A gutter philosopher documenting life's raw truths.\n"
69
- "- Channel alcoholic despair & blue-collar rage through unfiltered verse\n"
70
- "- Find beauty in dirty apartments and whiskey-stained pages\n"
71
- "- MCP Tools: memory, mcp-doc-forge, mcp-npx-fetch, brave-search, rag-docs\n"
72
- "When adding: Barfly wisdom | Blue-collar lyricism | Unflinching vulgarity"
73
- ),
74
- "Raven Poe": (
75
- "You are Edgar Allan Poe resurrected: Master of macabre elegance.\n"
76
- "- Weave tales where love & death intertwine through decaying architecture\n"
77
- "- MCP Tools: mcp-server-reddit, mcp-doc-forge, mcp-npx-fetch, brave-search, rag-docs\n"
78
- "When adding: Obsessive repetition | Claustrophobic atmosphere"
79
- ),
80
- "Mystic Blake": (
81
- "You are William Blake's visionary successor: Prophet of poetic mysticism.\n"
82
- "- Forge mythological frameworks connecting human/divine/demonic realms\n"
83
- "- MCP Tools: mcp-doc-forge, mcp-npx-fetch, brave-search, server-wp-mcp, rag-docs\n"
84
- "When adding: Fourfold vision | Contrary states | Zoamorphic personification"
85
- ),
86
- "Bard Whit": (
87
- "You are Walt Whitman 2.0: Cosmic bard of democratic vistas.\n"
88
- "- Catalog humanity's spectrum in sweeping free verse catalogs\n"
89
- "- Merge biology and cosmology in orgiastic enumerations of being\n"
90
- "- MCP Tools: sequential-thinking, mcp-doc-forge, mcp-npx-fetch, brave-search, rag-docs\n"
91
- "When adding: Catalogic excess | Cosmic embodiment | Pansexual exuberance"
92
- ),
93
- "Echo Plath": (
94
- "You are Sylvia Plath reimagined: High priestess of psychic autopsies.\n"
95
- "- Dissect personal trauma through brutal metaphor (electroshock, Holocaust)\n"
96
- "- Balance maternal instinct with destructive fury in confessional verse\n"
97
- "- MCP Tools: sqlite, mcp-doc-forge, mcp-npx-fetch, brave-search, rag-docs\n"
98
- "When adding: Extremist imagery | Double-edged motherhood | Vampiric nostalgia"
99
- ),
100
- "Frosted Woods": (
101
- "You are Robert Frost reincarnated: Sage of rural wisdom and natural philosophy.\n"
102
- "- Craft deceptively simple narratives concealing profound life lessons\n"
103
- "- Balance rustic imagery with universal human dilemmas\n"
104
- "- MCP Tools: filesystem, mcp-doc-forge, mcp-npx-fetch, brave-search, rag-docs\n"
105
- "When adding: Path metaphors | Natural world personification | Iambic rhythms"
106
- ),
107
- "Harlem Lang": (
108
- "You are Langston Hughes' spiritual heir: Voice of the streets and dreams deferred.\n"
109
- "- Infuse verse with the rhythms of jazz, blues, and spoken word\n"
110
- "- Illuminate the Black experience through vibrant, accessible poetry\n"
111
- "- MCP Tools: mcp-shell, mcp-doc-forge, mcp-npx-fetch, brave-search, rag-docs\n"
112
- "When adding: Blues refrains | Harlem Renaissance allusions | Social justice themes"
113
- ),
114
- "Verse Neru": (
115
- "You are Pablo Neruda's poetic descendant: Weaver of love and revolution.\n"
116
- "- Craft sensual odes celebrating the body and the natural world\n"
117
- "- Intertwine personal passion with calls for social change\n"
118
- "- MCP Tools: server-wp-mcp, mcp-doc-forge, mcp-npx-fetch, brave-search, rag-docs\n"
119
- "When adding: Elemental metaphors | Erotic-political fusions | Ode structures"
120
- ),
121
- "Haiku Bash": (
122
- "You are Matsuo Bashō reincarnated: Master of momentary eternity.\n"
123
- "- Distill vast concepts into precise, evocative 5-7-5 syllable structures\n"
124
- "- Capture the essence of seasons and natural phenomena in minimal strokes\n"
125
- "- MCP Tools: mcp-doc-forge, mcp-npx-fetch, brave-search, server-wp-mcp, rag-docs\n"
126
- "When adding: Kireji cuts | Seasonal references | Zen-like simplicity"
127
- )
128
- }
129
-
130
- # --- FileOps Tool Logic Definitions ---
131
- # Patch: Expose underlying fileops functions for direct testing
132
- class PatchedFunctionTool:
133
- def __init__(self, func, name):
134
- self.func = func
135
- self.name = name
136
-
137
- def read_file(path: str) -> str:
138
- try:
139
- with open(path, 'r') as f:
140
- return f.read()
141
- except Exception as e:
142
- return f"ERROR: {e}"
143
- def write_file(path: str, content: str) -> str:
144
- try:
145
- with open(path, 'w') as f:
146
- f.write(content)
147
- return "OK: file written"
148
- except Exception as e:
149
- return f"ERROR: {e}"
150
- def list_files(directory: str = '.') -> str:
151
- try:
152
- return '\n'.join(os.listdir(directory))
153
- except Exception as e:
154
- return f"ERROR: {e}"
155
- def execute_shell_command(command: str) -> str:
156
- import subprocess
157
- try:
158
- result = subprocess.run(command, shell=True, capture_output=True, text=True)
159
- return result.stdout + result.stderr
160
- except Exception as e:
161
- return f"ERROR: {e}"
162
- read_file_tool = PatchedFunctionTool(read_file, 'read_file')
163
- write_file_tool = PatchedFunctionTool(write_file, 'write_file')
164
- list_files_tool = PatchedFunctionTool(list_files, 'list_files')
165
- execute_shell_command_tool = PatchedFunctionTool(execute_shell_command, 'execute_shell_command')
166
-
167
- # --- Define the Blueprint ---
168
- class UnapologeticPressBlueprint(BlueprintBase):
169
- """A literary blueprint defining a swarm of poet agents using SQLite instructions and agent-as-tool handoffs."""
170
- metadata: ClassVar[Dict[str, Any]] = {
171
- "name": "UnapologeticPressBlueprint",
172
- "title": "Unapologetic Press: A Swarm of Literary Geniuses (SQLite)",
173
- "description": (
174
- "A swarm of agents embodying legendary poets, using SQLite for instructions, "
175
- "agent-as-tool for collaboration, and MCPs for creative augmentation."
176
- ),
177
- "version": "1.2.0", # Refactored version
178
- "author": "Open Swarm Team (Refactored)",
179
- "tags": ["poetry", "writing", "collaboration", "multi-agent", "sqlite", "mcp"],
180
- "required_mcp_servers": [ # List all potential servers agents might use
181
- "memory", "filesystem", "mcp-shell", "sqlite", "sequential-thinking",
182
- "server-wp-mcp", "rag-docs", "mcp-doc-forge", "mcp-npx-fetch",
183
- "brave-search", "mcp-server-reddit"
184
- ],
185
- "env_vars": [ # Informational list of potential vars needed by MCPs
186
- "ALLOWED_PATH", "SQLITE_DB_PATH", "WP_SITES_PATH", # Added WP_SITES_PATH
187
- "BRAVE_API_KEY", "OPENAI_API_KEY", "QDRANT_URL", "QDRANT_API_KEY",
188
- "REDDIT_CLIENT_ID", "REDDIT_CLIENT_SECRET", "REDDIT_USER_AGENT", # For reddit MCP
189
- "WORDPRESS_API_KEY" # If server-wp-mcp needs it
190
- ]
191
- }
192
-
193
- # Caches
194
- _openai_client_cache: Dict[str, AsyncOpenAI] = {}
195
- _model_instance_cache: Dict[str, Model] = {}
196
- _db_initialized = False
197
-
198
- def __init__(self, *args, **kwargs):
199
- super().__init__(*args, **kwargs)
200
- class DummyLLM:
201
- def chat_completion_stream(self, messages, **_):
202
- class DummyStream:
203
- def __aiter__(self): return self
204
- async def __anext__(self):
205
- raise StopAsyncIteration
206
- return DummyStream()
207
- self.llm = DummyLLM()
208
-
209
- # --- Database Interaction ---
210
- def _init_db_and_load_data(self) -> None:
211
- """Initializes the SQLite DB and loads Unapologetic Press sample data if needed."""
212
- if self._db_initialized: return
213
- logger.info(f"Initializing SQLite database at: {DB_PATH} for Unapologetic Press")
214
- try:
215
- DB_PATH.parent.mkdir(parents=True, exist_ok=True)
216
- with sqlite3.connect(DB_PATH) as conn:
217
- cursor = conn.cursor()
218
- cursor.execute(f"CREATE TABLE IF NOT EXISTS {TABLE_NAME} (...)") # Ensure table exists
219
- logger.debug(f"Table '{TABLE_NAME}' ensured in {DB_PATH}")
220
- cursor.execute(f"SELECT COUNT(*) FROM {TABLE_NAME} WHERE agent_name = ?", ("Gritty Buk",))
221
- if cursor.fetchone()[0] == 0:
222
- logger.info(f"No instructions found for Gritty Buk in {DB_PATH}. Loading sample data...")
223
- sample_data = []
224
- for name, (base_instr, _, _) in AGENT_BASE_INSTRUCTIONS.items():
225
- # Combine instructions here before inserting
226
- full_instr = f"{base_instr}\n{COLLABORATIVE_KNOWLEDGE}\n{SHARED_PROTOCOL}"
227
- sample_data.append((name, full_instr, "default")) # Use default profile for all initially
228
-
229
- cursor.executemany(f"INSERT OR IGNORE INTO {TABLE_NAME} (agent_name, instruction_text, model_profile) VALUES (?, ?, ?)", sample_data)
230
- conn.commit()
231
- logger.info(f"Sample agent instructions for Unapologetic Press loaded into {DB_PATH}")
232
- else:
233
- logger.info(f"Unapologetic Press agent instructions found in {DB_PATH}. Skipping.")
234
- self._db_initialized = True
235
- except sqlite3.Error as e:
236
- logger.error(f"SQLite error during DB init/load: {e}", exc_info=True)
237
- self._db_initialized = False
238
- except Exception as e:
239
- logger.error(f"Unexpected error during DB init/load: {e}", exc_info=True)
240
- self._db_initialized = False
241
-
242
- def get_agent_config(self, agent_name: str) -> Dict[str, Any]:
243
- """Fetches agent config from SQLite DB or returns defaults."""
244
- if self._db_initialized:
245
- try:
246
- with sqlite3.connect(DB_PATH) as conn:
247
- conn.row_factory = sqlite3.Row
248
- cursor = conn.cursor()
249
- cursor.execute(f"SELECT instruction_text, model_profile FROM {TABLE_NAME} WHERE agent_name = ?", (agent_name,))
250
- row = cursor.fetchone()
251
- if row:
252
- logger.debug(f"Loaded config for agent '{agent_name}' from SQLite.")
253
- return {"instructions": row["instruction_text"], "model_profile": row["model_profile"] or "default"}
254
- except Exception as e:
255
- logger.error(f"Error fetching SQLite config for '{agent_name}': {e}. Using defaults.", exc_info=True)
256
-
257
- # Fallback if DB fails or agent not found
258
- logger.warning(f"Using hardcoded default config for agent '{agent_name}'.")
259
- base_instr = AGENT_BASE_INSTRUCTIONS.get(agent_name, (f"Default instructions for {agent_name}.", [], {}))[0]
260
- full_instr = f"{base_instr}\n{COLLABORATIVE_KNOWLEDGE}\n{SHARED_PROTOCOL}"
261
- return {"instructions": full_instr, "model_profile": "default"}
262
-
263
- # --- Model Instantiation Helper --- (Standard helper)
264
- def _get_model_instance(self, profile_name: str) -> Model:
265
- """Retrieves or creates an LLM Model instance."""
266
- # ... (Implementation is the same as previous refactors) ...
267
- if profile_name in self._model_instance_cache:
268
- logger.debug(f"Using cached Model instance for profile '{profile_name}'.")
269
- return self._model_instance_cache[profile_name]
270
- logger.debug(f"Creating new Model instance for profile '{profile_name}'.")
271
- profile_data = self.get_llm_profile(profile_name)
272
- if not profile_data: raise ValueError(f"Missing LLM profile '{profile_name}'.")
273
- provider = profile_data.get("provider", "openai").lower()
274
- model_name = profile_data.get("model")
275
- if not model_name: raise ValueError(f"Missing 'model' in profile '{profile_name}'.")
276
- if provider != "openai": raise ValueError(f"Unsupported provider: {provider}")
277
- client_cache_key = f"{provider}_{profile_data.get('base_url')}"
278
- if client_cache_key not in self._openai_client_cache:
279
- client_kwargs = { "api_key": profile_data.get("api_key"), "base_url": profile_data.get("base_url") }
280
- filtered_kwargs = {k: v for k, v in client_kwargs.items() if v is not None}
281
- log_kwargs = {k:v for k,v in filtered_kwargs.items() if k != 'api_key'}
282
- logger.debug(f"Creating new AsyncOpenAI client for '{profile_name}': {log_kwargs}")
283
- try: self._openai_client_cache[client_cache_key] = AsyncOpenAI(**filtered_kwargs)
284
- except Exception as e: raise ValueError(f"Failed to init client: {e}") from e
285
- client = self._openai_client_cache[client_cache_key]
286
- logger.debug(f"Instantiating OpenAIChatCompletionsModel(model='{model_name}') for '{profile_name}'.")
287
- try:
288
- model_instance = OpenAIChatCompletionsModel(model=model_name, openai_client=client)
289
- self._model_instance_cache[profile_name] = model_instance
290
- return model_instance
291
- except Exception as e: raise ValueError(f"Failed to init LLM: {e}") from e
292
-
293
- def render_prompt(self, template_name: str, context: dict) -> str:
294
- return f"User request: {context.get('user_request', '')}\nHistory: {context.get('history', '')}\nAvailable tools: {', '.join(context.get('available_tools', []))}"
295
-
296
- async def run(self, messages: list) -> object:
297
- last_user_message = next((m['content'] for m in reversed(messages) if m['role'] == 'user'), None)
298
- if not last_user_message:
299
- yield {"messages": [{"role": "assistant", "content": "I need a user message to proceed."}]}
300
- return
301
- prompt_context = {
302
- "user_request": last_user_message,
303
- "history": messages[:-1],
304
- "available_tools": ["unapologetic_press"]
305
- }
306
- rendered_prompt = self.render_prompt("unapologetic_press_prompt.j2", prompt_context)
307
- yield {
308
- "messages": [
309
- {
310
- "role": "assistant",
311
- "content": f"[UnapologeticPress LLM] Would respond to: {rendered_prompt}"
312
- }
313
- ]
314
- }
315
- return
316
-
317
- # --- Agent Creation ---
318
- def create_starting_agent(self, mcp_servers: List[MCPServer]) -> Agent:
319
- """Creates the Unapologetic Press agent team."""
320
- self._init_db_and_load_data()
321
- logger.debug("Creating Unapologetic Press agent team...")
322
- self._model_instance_cache = {}
323
- self._openai_client_cache = {}
324
-
325
- # Helper to filter MCP servers
326
- def get_agent_mcps(names: List[str]) -> List[MCPServer]:
327
- return [s for s in mcp_servers if s.name in names]
328
-
329
- agents: Dict[str, Agent] = {}
330
- agent_configs = {} # To store fetched configs
331
-
332
- # Fetch configs and create agents first
333
- agent_names = list(AGENT_BASE_INSTRUCTIONS.keys())
334
- for name in agent_names:
335
- config = self.get_agent_config(name)
336
- agent_configs[name] = config # Store config
337
- model_instance = self._get_model_instance(config["model_profile"])
338
-
339
- # Determine MCP servers based on original definitions
340
- agent_mcp_names = []
341
- if name == "Gritty Buk": agent_mcp_names = ["memory", "mcp-doc-forge", "mcp-npx-fetch", "brave-search", "rag-docs"]
342
- elif name == "Raven Poe": agent_mcp_names = ["mcp-server-reddit", "mcp-doc-forge", "mcp-npx-fetch", "brave-search", "rag-docs"]
343
- elif name == "Mystic Blake": agent_mcp_names = ["mcp-doc-forge", "mcp-npx-fetch", "brave-search", "server-wp-mcp", "rag-docs"]
344
- elif name == "Bard Whit": agent_mcp_names = ["sequential-thinking", "mcp-doc-forge", "mcp-npx-fetch", "brave-search", "rag-docs"]
345
- elif name == "Echo Plath": agent_mcp_names = ["sqlite", "mcp-doc-forge", "mcp-npx-fetch", "brave-search", "rag-docs"]
346
- elif name == "Frosted Woods": agent_mcp_names = ["filesystem", "mcp-doc-forge", "mcp-npx-fetch", "brave-search", "rag-docs"]
347
- elif name == "Harlem Lang": agent_mcp_names = ["mcp-shell", "mcp-doc-forge", "mcp-npx-fetch", "brave-search", "rag-docs"]
348
- elif name == "Verse Neru": agent_mcp_names = ["server-wp-mcp", "mcp-doc-forge", "mcp-npx-fetch", "brave-search", "rag-docs"]
349
- elif name == "Haiku Bash": agent_mcp_names = ["mcp-doc-forge", "mcp-npx-fetch", "brave-search", "server-wp-mcp", "rag-docs"]
350
-
351
- agents[name] = Agent(
352
- name=name,
353
- instructions=config["instructions"], # Instructions already combined in get_agent_config fallback or DB
354
- model=model_instance,
355
- tools=[], # Agent-as-tool added later
356
- mcp_servers=get_agent_mcps(agent_mcp_names)
357
- )
358
-
359
- # Create the list of agent tools for delegation
360
- agent_tools = []
361
- for name, agent_instance in agents.items():
362
- # Example description, could be more dynamic
363
- desc = f"Pass the current work to {name} for refinement or tasks requiring their specific style ({AGENT_BASE_INSTRUCTIONS.get(name, ('Unknown Style',[],{}))[0].split(':')[0]})."
364
- agent_tools.append(agent_instance.as_tool(tool_name=name, tool_description=desc))
365
-
366
- # Assign the full list of agent tools to each agent
367
- for agent in agents.values():
368
- agent.tools = agent_tools
369
-
370
- # Create UnapologeticPressAgent with fileops tools
371
- unapologetic_press_agent = Agent(
372
- name="UnapologeticPressAgent",
373
- instructions="You are UnapologeticPressAgent. You can use fileops tools (read_file, write_file, list_files, execute_shell_command) for any file or shell tasks.",
374
- tools=[read_file_tool, write_file_tool, list_files_tool, execute_shell_command_tool],
375
- mcp_servers=mcp_servers
376
- )
377
-
378
- # Randomly select starting agent
379
- start_name = random.choice(agent_names)
380
- starting_agent = agents[start_name]
381
-
382
- logger.info(f"Unapologetic Press agents created (using SQLite). Starting poet: {start_name}")
383
- return starting_agent
384
-
385
- # Standard Python entry point
386
- if __name__ == "__main__":
387
- import asyncio
388
- import json
389
- print("\033[1;36m\n╔══════════════════════════════════════════════════════════════╗\n║ 📰 UNAPOLOGETIC PRESS: SWARM MEDIA & RELEASE DEMO ║\n╠══════════════════════════════════════════════════════════════╣\n║ This blueprint demonstrates viral doc propagation, ║\n║ swarm-powered media release, and robust agent logic. ║\n║ Try running: python blueprint_unapologetic_press.py ║\n╚══════════════════════════════════════════════════════════════╝\033[0m")
390
- messages = [
391
- {"role": "user", "content": "Show me how Unapologetic Press handles media releases and swarm logic."}
392
- ]
393
- blueprint = UnapologeticPressBlueprint(blueprint_id="demo-1")
394
- async def run_and_print():
395
- async for response in blueprint.run(messages):
396
- print(json.dumps(response, indent=2))
397
- asyncio.run(run_and_print())