open-swarm 0.1.1745019957__py3-none-any.whl → 0.1.1745020084__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.1745019957
3
+ Version: 0.1.1745020084
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
@@ -21,10 +21,10 @@ swarm/blueprints/codey/CODEY.md,sha256=JxGcR0INH0dLk_q4ua1D0YdvX99szyESsbbs4dIy5
21
21
  swarm/blueprints/codey/README.md,sha256=n2Sz1yg1FZp6ATV4W4rmgIYeQFFzlJ_APhCY1j6UR7o,3545
22
22
  swarm/blueprints/codey/blueprint_codey.py,sha256=otjn46MVsmIvHTbE6aHFPwFfcV3kNY_j2vdnt1xCKAo,17205
23
23
  swarm/blueprints/codey/instructions.md,sha256=XMvJngQ23vl7xJQx-Sp5UIME2-JQyyxeZFFtIuOtTOI,1209
24
- swarm/blueprints/digitalbutlers/blueprint_digitalbutlers.py,sha256=sYjbkD7esHrttiRAhd5vqx1_DCtCSHFsMgEXqStsSsc,19088
24
+ swarm/blueprints/digitalbutlers/blueprint_digitalbutlers.py,sha256=frnC-09hrUkg2bTPBFtj_WdQkGGNE1s4Ru35Ec4ag4M,16270
25
25
  swarm/blueprints/divine_code/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
26
26
  swarm/blueprints/divine_code/apps.py,sha256=k615JHdfOuo_GwfVbC7ah8X9OblkAL2XWm9aLBjmMyY,306
27
- swarm/blueprints/divine_code/blueprint_divine_code.py,sha256=YuJ5nThBkWLYN5ty3SiLAJaCs05wiCXHkFiNARUgLiA,21601
27
+ swarm/blueprints/divine_code/blueprint_divine_code.py,sha256=I2WM69x-ILeBUtQn0C5emdumw8Lx2N0mIgjwMMVhDow,19546
28
28
  swarm/blueprints/django_chat/apps.py,sha256=rn1Eu11c4zZ6DYZeFb6AkCDMoM_dcQTzeNwW-IxXpCI,200
29
29
  swarm/blueprints/django_chat/blueprint_django_chat.py,sha256=LY_SOnNpColj1xXw1d6fpyflBF8CZzPqL5IYLRnzSqI,5582
30
30
  swarm/blueprints/django_chat/urls.py,sha256=TTTF3pgymvCYbuxpwi4WRBPv8ftQNH4pEoURT8sEVAg,147
@@ -32,7 +32,7 @@ swarm/blueprints/django_chat/views.py,sha256=MUKjXXjXsq8jMZtAb4RR9g2mEYrwFemN6Bq
32
32
  swarm/blueprints/django_chat/templates/django_chat/django_chat_webpage.html,sha256=wAEOI4Wg0JJ8drXaOcr2Pel6lW3JSHmyIpbocLS5tI8,1649
33
33
  swarm/blueprints/echocraft/blueprint_echocraft.py,sha256=9XNyuMZIBrm9kpnv1aq_W3h-9Zr2dVdzchI2uFXslg0,10988
34
34
  swarm/blueprints/family_ties/apps.py,sha256=EjV7AxDNsLM4gsLr_qMEiLAVbERuo1ZsdU9vPtOEYAY,287
35
- swarm/blueprints/family_ties/blueprint_family_ties.py,sha256=co1rujjvRcDk5qHl94wMpHSQjx7tLxED0RMWJ_lWKC4,10629
35
+ swarm/blueprints/family_ties/blueprint_family_ties.py,sha256=AkYz9_O7QSBhoZAG1jaFlTXEouL1eUfa0y6hw9MqSro,9762
36
36
  swarm/blueprints/family_ties/models.py,sha256=C3_okdVVYuu9xOpoKRsaLoGrM2775cS_cU4UKYAkJ9s,903
37
37
  swarm/blueprints/family_ties/serializers.py,sha256=kH3T6OgXjF534bO3gfAUr6GpXZ5Jx0BQkK58nvuEcqA,325
38
38
  swarm/blueprints/family_ties/settings.py,sha256=5zcVsq7ny3GLWcJnOplZW4fMFNtyC3ba0ZOESRD2gh4,425
@@ -45,10 +45,10 @@ swarm/blueprints/messenger/templates/messenger/messenger.html,sha256=izuFtFn40Gm
45
45
  swarm/blueprints/mission_improbable/blueprint_mission_improbable.py,sha256=fAc672c3XYFwGwrdpDELO3V9k5dqBfyRH7_S7Urmo48,15034
46
46
  swarm/blueprints/monkai_magic/blueprint_monkai_magic.py,sha256=9eE3pf14OjgOPKNapJF8b9OYyK5_AEVZ4UJMRrBeOek,16009
47
47
  swarm/blueprints/nebula_shellz/blueprint_nebula_shellz.py,sha256=1xT6yYhl-sOSODd0E0hSKxtBlNoQe6sPf30d-S9fI6U,11709
48
- swarm/blueprints/omniplex/blueprint_omniplex.py,sha256=iBsSO_CF10kWMkGWfpJ2Aa7d2m60JpQGfMfrDWmFktY,13267
48
+ swarm/blueprints/omniplex/blueprint_omniplex.py,sha256=ESJyKPhz01rw2l3AP5zbDreLUbzhJtwewopmr_WRVNM,13644
49
49
  swarm/blueprints/rue_code/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
50
- swarm/blueprints/rue_code/blueprint_rue_code.py,sha256=4k0mm4i8w-jVSGAV-q2a_KgpPX9M05MyXkX4Li2hwFg,14092
51
- swarm/blueprints/suggestion/blueprint_suggestion.py,sha256=M8pDakR_XBF3P73jgUQxFFIswM2JsC_OkPR_XWh9mrM,13210
50
+ swarm/blueprints/rue_code/blueprint_rue_code.py,sha256=odxqvAIzSESlm9eecZNz-JBsjeoRpFgCZs-7tG1ZkLQ,13273
51
+ swarm/blueprints/suggestion/blueprint_suggestion.py,sha256=Qm5YbP19SETFtXc-gTsmGUh71US7huUyKZKqtRv-Qeg,10846
52
52
  swarm/blueprints/unapologetic_press/blueprint_unapologetic_press.py,sha256=lIq6oGQlVtI8sxCq9DKmpLaHpHv-8_NJ5XHB7TEL_dg,22399
53
53
  swarm/blueprints/whiskeytango_foxtrot/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
54
54
  swarm/blueprints/whiskeytango_foxtrot/apps.py,sha256=V1QKvyb2Vz-EtDNhhNe4tw2W9LYhNDuiaIq_fAU4ilw,334
@@ -271,8 +271,8 @@ swarm/views/message_views.py,sha256=sDUnXyqKXC8WwIIMAlWf00s2_a2T9c75Na5FvYMJwBM,
271
271
  swarm/views/model_views.py,sha256=aAbU4AZmrOTaPeKMWtoKK7FPYHdaN3Zbx55JfKzYTRY,2937
272
272
  swarm/views/utils.py,sha256=8Usc0g0L0NPegNAyY20tJBNBy-JLwODf4VmxV0yUtpw,3627
273
273
  swarm/views/web_views.py,sha256=T1CKe-Nyv1C8aDt6QFTGWo_dkH7ojWAvS_QW9mZnZp0,7371
274
- open_swarm-0.1.1745019957.dist-info/METADATA,sha256=3KsTmrhfQC5EfIMULXc4grReT6v3OqPjlMeXqvuJK2Q,23332
275
- open_swarm-0.1.1745019957.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
276
- open_swarm-0.1.1745019957.dist-info/entry_points.txt,sha256=fo28d0_zJrytRsh8QqkdlWQT_9lyAwYUx1WuSTDI3HM,177
277
- open_swarm-0.1.1745019957.dist-info/licenses/LICENSE,sha256=BU9bwRlnOt_JDIb6OT55Q4leLZx9RArDLTFnlDIrBEI,1062
278
- open_swarm-0.1.1745019957.dist-info/RECORD,,
274
+ open_swarm-0.1.1745020084.dist-info/METADATA,sha256=XtGM3TNBR59a6A3ZK5YOorScI-RtFeNMJxY7L1xMSXk,23332
275
+ open_swarm-0.1.1745020084.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
276
+ open_swarm-0.1.1745020084.dist-info/entry_points.txt,sha256=fo28d0_zJrytRsh8QqkdlWQT_9lyAwYUx1WuSTDI3HM,177
277
+ open_swarm-0.1.1745020084.dist-info/licenses/LICENSE,sha256=BU9bwRlnOt_JDIb6OT55Q4leLZx9RArDLTFnlDIrBEI,1062
278
+ open_swarm-0.1.1745020084.dist-info/RECORD,,
@@ -123,16 +123,8 @@ SPINNER_STATES = ['Generating.', 'Generating..', 'Generating...', 'Running...']
123
123
 
124
124
  # --- Define the Blueprint ---
125
125
  class DigitalButlersBlueprint(BlueprintBase):
126
- def __init__(self, *args, **kwargs):
127
- super().__init__(*args, **kwargs)
128
- class DummyLLM:
129
- def chat_completion_stream(self, messages, **_):
130
- class DummyStream:
131
- def __aiter__(self): return self
132
- async def __anext__(self):
133
- raise StopAsyncIteration
134
- return DummyStream()
135
- self.llm = DummyLLM()
126
+ def __init__(self, blueprint_id: str, config_path: Optional[Path] = None, **kwargs):
127
+ super().__init__(blueprint_id, config_path=config_path, **kwargs)
136
128
 
137
129
  """Blueprint for private web search and home automation using a team of digital butlers."""
138
130
  metadata: ClassVar[Dict[str, Any]] = {
@@ -258,97 +250,28 @@ class DigitalButlersBlueprint(BlueprintBase):
258
250
  logger.debug("Digital Butlers team created: Jeeves (Coordinator), Mycroft (Search), Gutenberg (Home).")
259
251
  return jeeves_agent # Jeeves is the entry point
260
252
 
261
- def render_prompt(self, template_name: str, context: dict) -> str:
262
- return f"User request: {context.get('user_request', '')}\nHistory: {context.get('history', '')}\nAvailable tools: {', '.join(context.get('available_tools', []))}"
263
-
264
- async def _original_run(self, messages: list) -> object:
265
- last_user_message = next((m['content'] for m in reversed(messages) if m['role'] == 'user'), None)
266
- if not last_user_message:
267
- yield {"messages": [{"role": "assistant", "content": "I need a user message to proceed."}]}
268
- return
269
- prompt_context = {
270
- "user_request": last_user_message,
271
- "history": messages[:-1],
272
- "available_tools": ["digital_butler"]
273
- }
274
- rendered_prompt = self.render_prompt("digitalbutlers_prompt.j2", prompt_context)
275
- yield {
276
- "messages": [
277
- {
278
- "role": "assistant",
279
- "content": f"[DigitalButlers LLM] Would respond to: {rendered_prompt}"
280
- }
281
- ]
282
- }
283
- return
284
-
285
- async def run(self, messages):
286
- last_result = None
287
- async for result in self._original_run(messages):
288
- last_result = result
289
- yield result
290
- if last_result is not None:
291
- await self.reflect_and_learn(messages, last_result)
292
-
293
- async def reflect_and_learn(self, messages, result):
294
- log = {
295
- 'task': messages,
296
- 'result': result,
297
- 'reflection': 'Success' if self.success_criteria(result) else 'Needs improvement',
298
- 'alternatives': self.consider_alternatives(messages, result),
299
- 'swarm_lessons': self.query_swarm_knowledge(messages)
300
- }
301
- self.write_to_swarm_log(log)
302
-
303
- def success_criteria(self, result):
304
- if not result or (isinstance(result, dict) and 'error' in result):
305
- return False
306
- if isinstance(result, list) and result and 'error' in result[0].get('messages', [{}])[0].get('content', '').lower():
307
- return False
308
- return True
309
-
310
- def consider_alternatives(self, messages, result):
311
- alternatives = []
312
- if not self.success_criteria(result):
313
- alternatives.append('Delegate to a different butler.')
314
- alternatives.append('Try a simpler or more robust plan.')
315
- else:
316
- alternatives.append('Parallelize tasks for efficiency.')
317
- return alternatives
318
-
319
- def query_swarm_knowledge(self, messages):
320
- import json, os
321
- path = os.path.join(os.path.dirname(__file__), '../../../swarm_knowledge.json')
322
- if not os.path.exists(path):
323
- return []
324
- with open(path, 'r') as f:
325
- knowledge = json.load(f)
326
- task_str = json.dumps(messages)
327
- return [entry for entry in knowledge if entry.get('task_str') == task_str]
328
-
329
- def write_to_swarm_log(self, log):
330
- import json, os, time
331
- from filelock import FileLock, Timeout
332
- path = os.path.join(os.path.dirname(__file__), '../../../swarm_log.json')
333
- lock_path = path + '.lock'
334
- log['task_str'] = json.dumps(log['task'])
335
- for attempt in range(10):
336
- try:
337
- with FileLock(lock_path, timeout=5):
338
- if os.path.exists(path):
339
- with open(path, 'r') as f:
340
- try:
341
- logs = json.load(f)
342
- except json.JSONDecodeError:
343
- logs = []
344
- else:
345
- logs = []
346
- logs.append(log)
347
- with open(path, 'w') as f:
348
- json.dump(logs, f, indent=2)
349
- break
350
- except Timeout:
351
- time.sleep(0.2 * (attempt + 1))
253
+ async def run(self, messages: List[Dict[str, Any]], **kwargs) -> Any:
254
+ """Main execution entry point for the DigitalButlers blueprint."""
255
+ logger.info("DigitalButlersBlueprint run method called.")
256
+ instruction = messages[-1].get("content", "") if messages else ""
257
+ async for chunk in self._run_non_interactive(instruction, **kwargs):
258
+ yield chunk
259
+ logger.info("DigitalButlersBlueprint run method finished.")
260
+
261
+ async def _run_non_interactive(self, instruction: str, **kwargs) -> Any:
262
+ logger.info(f"Running DigitalButlers non-interactively with instruction: '{instruction[:100]}...'")
263
+ mcp_servers = kwargs.get("mcp_servers", [])
264
+ agent = self.create_starting_agent(mcp_servers=mcp_servers)
265
+ # Use Runner.run as a classmethod for portability
266
+ from agents import Runner
267
+ import os
268
+ model_name = os.getenv("LITELLM_MODEL") or os.getenv("DEFAULT_LLM") or "gpt-3.5-turbo"
269
+ try:
270
+ for chunk in Runner.run(agent, instruction):
271
+ yield chunk
272
+ except Exception as e:
273
+ logger.error(f"Error during non-interactive run: {e}", exc_info=True)
274
+ yield {"messages": [{"role": "assistant", "content": f"An error occurred: {e}"}]}
352
275
 
353
276
  # Standard Python entry point
354
277
  if __name__ == "__main__":
@@ -164,14 +164,6 @@ execute_shell_command_tool = PatchedFunctionTool(execute_shell_command, 'execute
164
164
  class DivineOpsBlueprint(BlueprintBase):
165
165
  def __init__(self, blueprint_id: str, config_path: Optional[Path] = None, **kwargs):
166
166
  super().__init__(blueprint_id, config_path=config_path, **kwargs)
167
- class DummyLLM:
168
- def chat_completion_stream(self, messages, **_):
169
- class DummyStream:
170
- def __aiter__(self): return self
171
- async def __anext__(self):
172
- raise StopAsyncIteration
173
- return DummyStream()
174
- self.llm = DummyLLM()
175
167
  # Use serious style for DivineOps
176
168
  self.ux = BlueprintUX(style="serious")
177
169
 
@@ -289,39 +281,13 @@ class DivineOpsBlueprint(BlueprintBase):
289
281
  logger.debug("Divine Ops Team (Zeus & Pantheon) created successfully. Zeus is starting agent.")
290
282
  return zeus_agent
291
283
 
292
- def render_prompt(self, template_name: str, context: dict) -> str:
293
- return f"User request: {context.get('user_request', '')}\nHistory: {context.get('history', '')}\nAvailable tools: {', '.join(context.get('available_tools', []))}"
294
-
295
284
  async def run(self, messages: List[Dict[str, Any]], **kwargs) -> Any:
296
285
  """Main execution entry point for the DivineOps blueprint."""
297
286
  logger.info("DivineOpsBlueprint run method called.")
298
- last_user_message = next((m['content'] for m in reversed(messages) if m['role'] == 'user'), None)
299
- if not last_user_message:
300
- yield {"messages": [{"role": "assistant", "content": self.ux.box("Error", "I need a user message to proceed.")}]}
301
- return
302
- prompt_context = {
303
- "user_request": last_user_message,
304
- "history": messages[:-1],
305
- "available_tools": ["divine_code"]
306
- }
307
- rendered_prompt = self.render_prompt("divine_code_prompt.j2", prompt_context)
308
- import asyncio
309
- for i in range(4):
310
- yield {"messages": [{"role": "assistant", "content": self.ux.box("DivineOps", self.ux.spinner(i), summary="Preparing to process", params=prompt_context["user_request"])}]}
311
- await asyncio.sleep(0.2)
312
- yield {"messages": [{"role": "assistant", "content": self.ux.box("DivineOps", self.ux.spinner(0, taking_long=True), summary="Still working", params=prompt_context["user_request"])}]}
313
- # Simulate code vs semantic search distinction
314
- code_results = ["def divine(): ...", "def ops(): ..."]
315
- semantic_results = ["This function orchestrates SDLC.", "This function demonstrates self-healing."]
316
- yield {"messages": [{"role": "assistant", "content": self.ux.box(
317
- "DivineOps Results",
318
- self.ux.code_vs_semantic("code", code_results) + "\n" + self.ux.code_vs_semantic("semantic", semantic_results),
319
- summary=self.ux.summary("Analyzed codebase", 4, prompt_context["user_request"]),
320
- result_count=4,
321
- params=prompt_context["user_request"]
322
- )}]}
323
- logger.info("DivineOpsBlueprint run finished.")
324
- return
287
+ instruction = messages[-1].get("content", "") if messages else ""
288
+ async for chunk in self._run_non_interactive(instruction, **kwargs):
289
+ yield chunk
290
+ logger.info("DivineOpsBlueprint run method finished.")
325
291
 
326
292
  async def _run_non_interactive(self, instruction: str, **kwargs) -> Any:
327
293
  logger.info(f"Running DivineOps non-interactively with instruction: '{instruction[:100]}...'")
@@ -55,16 +55,8 @@ brian_instructions = (
55
55
 
56
56
  # --- Define the Blueprint ---
57
57
  class FamilyTiesBlueprint(BlueprintBase):
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()
58
+ def __init__(self, blueprint_id: str, config_path: Optional[Path] = None, **kwargs):
59
+ super().__init__(blueprint_id, config_path=config_path, **kwargs)
68
60
 
69
61
  """Manages WordPress content with a Peter/Brian agent team using the `server-wp-mcp` server."""
70
62
  metadata: ClassVar[Dict[str, Any]] = {
@@ -161,29 +153,13 @@ class FamilyTiesBlueprint(BlueprintBase):
161
153
  logger.debug("Agents created: PeterGrifton (Coordinator), BrianGrifton (WordPress Manager).")
162
154
  return peter_agent # Peter is the entry point
163
155
 
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
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.")
187
163
 
188
164
  async def _run_non_interactive(self, instruction: str, **kwargs) -> Any:
189
165
  logger.info(f"Running FamilyTies non-interactively with instruction: '{instruction[:100]}...'")
@@ -231,26 +231,26 @@ class OmniplexBlueprint(BlueprintBase):
231
231
  logger.info(f"Omniplex Coordinator created with tools for: {[t.name for t in team_tools]}")
232
232
  return coordinator_agent
233
233
 
234
- async def run(self, messages: list) -> object:
235
- last_user_message = next((m['content'] for m in reversed(messages) if m['role'] == 'user'), None)
236
- if not last_user_message:
237
- yield {"messages": [{"role": "assistant", "content": "I need a user message to proceed."}]}
238
- return
239
- prompt_context = {
240
- "user_request": last_user_message,
241
- "history": messages[:-1],
242
- "available_tools": ["omniplex"]
243
- }
244
- rendered_prompt = self.render_prompt("omniplex_prompt.j2", prompt_context)
245
- yield {
246
- "messages": [
247
- {
248
- "role": "assistant",
249
- "content": f"[Omniplex LLM] Would respond to: {rendered_prompt}"
250
- }
251
- ]
252
- }
253
- return
234
+ async def run(self, messages: List[Dict[str, Any]], **kwargs) -> Any:
235
+ """Main execution entry point for the Omniplex blueprint."""
236
+ logger.info("OmniplexBlueprint run method called.")
237
+ instruction = messages[-1].get("content", "") if messages else ""
238
+ async for chunk in self._run_non_interactive(instruction, **kwargs):
239
+ yield chunk
240
+ logger.info("OmniplexBlueprint run method finished.")
241
+
242
+ async def _run_non_interactive(self, instruction: str, **kwargs) -> Any:
243
+ logger.info(f"Running OmniplexBlueprint non-interactively with instruction: '{instruction[:100]}...'")
244
+ mcp_servers = kwargs.get("mcp_servers", [])
245
+ agent = self.create_starting_agent(mcp_servers=mcp_servers)
246
+ from agents import Runner
247
+ model_name = os.getenv("LITELLM_MODEL") or os.getenv("DEFAULT_LLM") or "gpt-3.5-turbo"
248
+ try:
249
+ for chunk in Runner.run(agent, instruction):
250
+ yield chunk
251
+ except Exception as e:
252
+ logger.error(f"Error during non-interactive run: {e}", exc_info=True)
253
+ yield {"messages": [{"role": "assistant", "content": f"An error occurred: {e}"}]}
254
254
 
255
255
  # Standard Python entry point
256
256
  if __name__ == "__main__":
@@ -265,20 +265,6 @@ class RueCodeBlueprint(BlueprintBase):
265
265
  params=prompt_context["user_request"]
266
266
  )}]}
267
267
  logger.info("RueCodeBlueprint run finished.")
268
- return
269
-
270
- def create_starting_agent(self, mcp_servers):
271
- read_file_tool = PatchedFunctionTool(read_file_fileops, 'read_file')
272
- write_file_tool = PatchedFunctionTool(write_file_fileops, 'write_file')
273
- list_files_tool = PatchedFunctionTool(list_files_fileops, 'list_files')
274
- execute_shell_command_tool = PatchedFunctionTool(execute_shell_command_fileops, 'execute_shell_command')
275
- rue_agent = self.make_agent(
276
- name="RueCodeAgent",
277
- instructions="You are RueCodeAgent. You can use fileops tools (read_file, write_file, list_files, execute_shell_command) for any file or shell tasks.",
278
- tools=[read_file_tool, write_file_tool, list_files_tool, execute_shell_command_tool],
279
- mcp_servers=mcp_servers
280
- )
281
- return rue_agent
282
268
 
283
269
  if __name__ == "__main__":
284
270
  import asyncio
@@ -138,8 +138,11 @@ class SuggestionBlueprint(BlueprintBase):
138
138
  model_name = profile_data.get("model")
139
139
  if not model_name: raise ValueError(f"Missing 'model' in profile '{profile_name}'.")
140
140
  if provider != "openai": raise ValueError(f"Unsupported provider: {provider}")
141
+ # Remove redundant client instantiation; rely on framework-level default client
142
+ # All blueprints now use the default client set at framework init
141
143
  logger.debug(f"Instantiating OpenAIChatCompletionsModel(model='{model_name}') for '{profile_name}'.")
142
144
  try:
145
+ # Ensure the model selected supports structured output (most recent OpenAI do)
143
146
  model_instance = OpenAIChatCompletionsModel(model=model_name)
144
147
  self._model_instance_cache[profile_name] = model_instance
145
148
  return model_instance
@@ -168,97 +171,27 @@ class SuggestionBlueprint(BlueprintBase):
168
171
  logger.debug("SuggestionAgent created with output_type enforcement.")
169
172
  return suggestion_agent
170
173
 
171
- def render_prompt(self, template_name: str, context: dict) -> str:
172
- return f"User request: {context.get('user_request', '')}\nHistory: {context.get('history', '')}\nAvailable tools: {', '.join(context.get('available_tools', []))}"
173
-
174
- async def _original_run(self, messages: list) -> object:
175
- last_user_message = next((m['content'] for m in reversed(messages) if m['role'] == 'user'), None)
176
- if not last_user_message:
177
- yield {"messages": [{"role": "assistant", "content": "I need a user message to proceed."}]}
178
- return
179
- prompt_context = {
180
- "user_request": last_user_message,
181
- "history": messages[:-1],
182
- "available_tools": ["suggest"]
183
- }
184
- rendered_prompt = self.render_prompt("suggestion_prompt.j2", prompt_context)
185
- yield {
186
- "messages": [
187
- {
188
- "role": "assistant",
189
- "content": f"[Suggestion LLM] Would respond to: {rendered_prompt}"
190
- }
191
- ]
192
- }
193
- return
194
-
195
- async def run(self, messages):
196
- last_result = None
197
- async for result in self._original_run(messages):
198
- last_result = result
199
- yield result
200
- if last_result is not None:
201
- await self.reflect_and_learn(messages, last_result)
202
-
203
- async def reflect_and_learn(self, messages, result):
204
- log = {
205
- 'task': messages,
206
- 'result': result,
207
- 'reflection': 'Success' if self.success_criteria(result) else 'Needs improvement',
208
- 'alternatives': self.consider_alternatives(messages, result),
209
- 'swarm_lessons': self.query_swarm_knowledge(messages)
210
- }
211
- self.write_to_swarm_log(log)
212
-
213
- def success_criteria(self, result):
214
- if not result or (isinstance(result, dict) and 'error' in result):
215
- return False
216
- if isinstance(result, list) and result and 'error' in result[0].get('messages', [{}])[0].get('content', '').lower():
217
- return False
218
- return True
219
-
220
- def consider_alternatives(self, messages, result):
221
- alternatives = []
222
- if not self.success_criteria(result):
223
- alternatives.append('Try a different suggestion agent.')
224
- alternatives.append('Fallback to a simpler suggestion.')
225
- else:
226
- alternatives.append('Expand suggestions with more context.')
227
- return alternatives
228
-
229
- def query_swarm_knowledge(self, messages):
230
- import json, os
231
- path = os.path.join(os.path.dirname(__file__), '../../../swarm_knowledge.json')
232
- if not os.path.exists(path):
233
- return []
234
- with open(path, 'r') as f:
235
- knowledge = json.load(f)
236
- task_str = json.dumps(messages)
237
- return [entry for entry in knowledge if entry.get('task_str') == task_str]
238
-
239
- def write_to_swarm_log(self, log):
240
- import json, os, time
241
- from filelock import FileLock, Timeout
242
- path = os.path.join(os.path.dirname(__file__), '../../../swarm_log.json')
243
- lock_path = path + '.lock'
244
- log['task_str'] = json.dumps(log['task'])
245
- for attempt in range(10):
246
- try:
247
- with FileLock(lock_path, timeout=5):
248
- if os.path.exists(path):
249
- with open(path, 'r') as f:
250
- try:
251
- logs = json.load(f)
252
- except json.JSONDecodeError:
253
- logs = []
254
- else:
255
- logs = []
256
- logs.append(log)
257
- with open(path, 'w') as f:
258
- json.dump(logs, f, indent=2)
259
- break
260
- except Timeout:
261
- time.sleep(0.2 * (attempt + 1))
174
+ async def run(self, messages: List[Dict[str, Any]], **kwargs) -> Any:
175
+ """Main execution entry point for the Suggestion blueprint."""
176
+ logger.info("SuggestionBlueprint run method called.")
177
+ instruction = messages[-1].get("content", "") if messages else ""
178
+ async for chunk in self._run_non_interactive(instruction, **kwargs):
179
+ yield chunk
180
+ logger.info("SuggestionBlueprint run method finished.")
181
+
182
+ async def _run_non_interactive(self, instruction: str, **kwargs) -> Any:
183
+ logger.info(f"Running SuggestionBlueprint non-interactively with instruction: '{instruction[:100]}...'")
184
+ mcp_servers = kwargs.get("mcp_servers", [])
185
+ agent = self.create_starting_agent(mcp_servers=mcp_servers)
186
+ from agents import Runner
187
+ import os
188
+ model_name = os.getenv("LITELLM_MODEL") or os.getenv("DEFAULT_LLM") or "gpt-3.5-turbo"
189
+ try:
190
+ for chunk in Runner.run(agent, instruction):
191
+ yield chunk
192
+ except Exception as e:
193
+ logger.error(f"Error during non-interactive run: {e}", exc_info=True)
194
+ yield {"messages": [{"role": "assistant", "content": f"An error occurred: {e}"}]}
262
195
 
263
196
  if __name__ == "__main__":
264
197
  import asyncio