mdan-cli 2.6.0 → 2.7.0
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.
- package/AGENTS.md +48 -1
- package/README.md +123 -0
- package/cli/mdan.py +38 -4
- package/cli/mdan_crewai.py +539 -0
- package/core/crewai_orchestrator.md +419 -0
- package/integrations/__init__.py +33 -0
- package/integrations/crewai/__init__.py +27 -0
- package/integrations/crewai/agents/__init__.py +21 -0
- package/integrations/crewai/agents/architect_agent.py +264 -0
- package/integrations/crewai/agents/dev_agent.py +271 -0
- package/integrations/crewai/agents/devops_agent.py +421 -0
- package/integrations/crewai/agents/doc_agent.py +388 -0
- package/integrations/crewai/agents/product_agent.py +203 -0
- package/integrations/crewai/agents/security_agent.py +386 -0
- package/integrations/crewai/agents/test_agent.py +358 -0
- package/integrations/crewai/agents/ux_agent.py +257 -0
- package/integrations/crewai/flows/__init__.py +13 -0
- package/integrations/crewai/flows/auto_flow.py +451 -0
- package/integrations/crewai/flows/build_flow.py +297 -0
- package/integrations/crewai/flows/debate_flow.py +422 -0
- package/integrations/crewai/flows/discovery_flow.py +267 -0
- package/integrations/crewai/orchestrator.py +558 -0
- package/integrations/crewai/skills/__init__.py +8 -0
- package/integrations/crewai/skills/skill_router.py +534 -0
- package/integrations/crewai/tools/__init__.py +11 -0
- package/integrations/crewai/tools/file_tool.py +355 -0
- package/integrations/crewai/tools/serper_tool.py +169 -0
- package/integrations/crewai/tools/sql_tool.py +435 -0
- package/package.json +1 -1
|
@@ -0,0 +1,558 @@
|
|
|
1
|
+
"""CrewAI Orchestrator - Main orchestrator for CrewAI integration
|
|
2
|
+
|
|
3
|
+
Intelligent orchestrator that decides which agent/skill to call based on task analysis.
|
|
4
|
+
Supports auto-mode management, skill routing, and multi-agent debates.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import asyncio
|
|
8
|
+
import json
|
|
9
|
+
import os
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
from typing import Dict, Any, Optional, List, Union
|
|
12
|
+
from enum import Enum
|
|
13
|
+
|
|
14
|
+
from crewai import Crew, Process, Agent, Task
|
|
15
|
+
|
|
16
|
+
from .agents.product_agent import ProductAgent
|
|
17
|
+
from .agents.architect_agent import ArchitectAgent
|
|
18
|
+
from .agents.ux_agent import UXAgent
|
|
19
|
+
from .agents.dev_agent import DevAgent
|
|
20
|
+
from .agents.test_agent import TestAgent
|
|
21
|
+
from .agents.security_agent import SecurityAgent
|
|
22
|
+
from .agents.devops_agent import DevOpsAgent
|
|
23
|
+
from .agents.doc_agent import DocAgent
|
|
24
|
+
|
|
25
|
+
from .tools.sql_tool import SQLTool
|
|
26
|
+
from .tools.serper_tool import SerperTool
|
|
27
|
+
from .tools.file_tool import FileTool
|
|
28
|
+
|
|
29
|
+
from .flows.auto_flow import AutoFlow
|
|
30
|
+
from .flows.discovery_flow import DiscoveryFlow
|
|
31
|
+
from .flows.build_flow import BuildFlow
|
|
32
|
+
from .flows.debate_flow import DebateFlow
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class Phase(Enum):
|
|
36
|
+
"""MDAN development phases."""
|
|
37
|
+
|
|
38
|
+
LOAD = "LOAD"
|
|
39
|
+
DISCOVER = "DISCOVER"
|
|
40
|
+
PLAN = "PLAN"
|
|
41
|
+
ARCHITECT = "ARCHITECT"
|
|
42
|
+
IMPLEMENT = "IMPLEMENT"
|
|
43
|
+
TEST = "TEST"
|
|
44
|
+
DEPLOY = "DEPLOY"
|
|
45
|
+
DOC = "DOC"
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class CrewAIOrchestrator:
|
|
49
|
+
"""Main CrewAI orchestrator for MDAN.
|
|
50
|
+
|
|
51
|
+
Provides intelligent task routing, agent selection, and auto-mode management.
|
|
52
|
+
"""
|
|
53
|
+
|
|
54
|
+
def __init__(
|
|
55
|
+
self,
|
|
56
|
+
project_path: str,
|
|
57
|
+
llm=None,
|
|
58
|
+
sql_config: Optional[Dict[str, Any]] = None,
|
|
59
|
+
serper_api_key: Optional[str] = None,
|
|
60
|
+
auto_mode: bool = False,
|
|
61
|
+
):
|
|
62
|
+
"""Initialize CrewAI Orchestrator.
|
|
63
|
+
|
|
64
|
+
Args:
|
|
65
|
+
project_path: Path to the project directory
|
|
66
|
+
llm: Language model instance
|
|
67
|
+
sql_config: SQL database configuration
|
|
68
|
+
serper_api_key: Serper API key for web search
|
|
69
|
+
auto_mode: Enable autonomous mode
|
|
70
|
+
"""
|
|
71
|
+
self.project_path = Path(project_path)
|
|
72
|
+
self.llm = llm
|
|
73
|
+
self.auto_mode = auto_mode
|
|
74
|
+
|
|
75
|
+
# Initialize tools
|
|
76
|
+
self.sql_tool = SQLTool(**sql_config) if sql_config else None
|
|
77
|
+
self.serper_tool = (
|
|
78
|
+
SerperTool(api_key=serper_api_key) if serper_api_key else None
|
|
79
|
+
)
|
|
80
|
+
self.file_tool = FileTool(base_path=project_path)
|
|
81
|
+
|
|
82
|
+
# Initialize agents
|
|
83
|
+
self.agents = self._initialize_agents()
|
|
84
|
+
|
|
85
|
+
# Initialize flows
|
|
86
|
+
self.flows = self._initialize_flows()
|
|
87
|
+
|
|
88
|
+
# Orchestrator state
|
|
89
|
+
self.state = {
|
|
90
|
+
"current_phase": None,
|
|
91
|
+
"active_agents": [],
|
|
92
|
+
"task_history": [],
|
|
93
|
+
"auto_mode_enabled": auto_mode,
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
def _initialize_agents(self) -> Dict[str, Any]:
|
|
97
|
+
"""Initialize all CrewAI agents.
|
|
98
|
+
|
|
99
|
+
Returns:
|
|
100
|
+
Dictionary of agent instances
|
|
101
|
+
"""
|
|
102
|
+
return {
|
|
103
|
+
"product": ProductAgent(
|
|
104
|
+
sql_tool=self.sql_tool,
|
|
105
|
+
serper_tool=self.serper_tool,
|
|
106
|
+
file_tool=self.file_tool,
|
|
107
|
+
llm=self.llm,
|
|
108
|
+
),
|
|
109
|
+
"architect": ArchitectAgent(
|
|
110
|
+
sql_tool=self.sql_tool,
|
|
111
|
+
serper_tool=self.serper_tool,
|
|
112
|
+
file_tool=self.file_tool,
|
|
113
|
+
llm=self.llm,
|
|
114
|
+
),
|
|
115
|
+
"ux": UXAgent(
|
|
116
|
+
sql_tool=self.sql_tool,
|
|
117
|
+
serper_tool=self.serper_tool,
|
|
118
|
+
file_tool=self.file_tool,
|
|
119
|
+
llm=self.llm,
|
|
120
|
+
),
|
|
121
|
+
"dev": DevAgent(
|
|
122
|
+
sql_tool=self.sql_tool,
|
|
123
|
+
serper_tool=self.serper_tool,
|
|
124
|
+
file_tool=self.file_tool,
|
|
125
|
+
llm=self.llm,
|
|
126
|
+
),
|
|
127
|
+
"test": TestAgent(
|
|
128
|
+
sql_tool=self.sql_tool,
|
|
129
|
+
serper_tool=self.serper_tool,
|
|
130
|
+
file_tool=self.file_tool,
|
|
131
|
+
llm=self.llm,
|
|
132
|
+
),
|
|
133
|
+
"security": SecurityAgent(
|
|
134
|
+
sql_tool=self.sql_tool,
|
|
135
|
+
serper_tool=self.serper_tool,
|
|
136
|
+
file_tool=self.file_tool,
|
|
137
|
+
llm=self.llm,
|
|
138
|
+
),
|
|
139
|
+
"devops": DevOpsAgent(
|
|
140
|
+
sql_tool=self.sql_tool,
|
|
141
|
+
serper_tool=self.serper_tool,
|
|
142
|
+
file_tool=self.file_tool,
|
|
143
|
+
llm=self.llm,
|
|
144
|
+
),
|
|
145
|
+
"doc": DocAgent(
|
|
146
|
+
sql_tool=self.sql_tool,
|
|
147
|
+
serper_tool=self.serper_tool,
|
|
148
|
+
file_tool=self.file_tool,
|
|
149
|
+
llm=self.llm,
|
|
150
|
+
),
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
def _initialize_flows(self) -> Dict[str, Any]:
|
|
154
|
+
"""Initialize all CrewAI flows.
|
|
155
|
+
|
|
156
|
+
Returns:
|
|
157
|
+
Dictionary of flow instances
|
|
158
|
+
"""
|
|
159
|
+
return {
|
|
160
|
+
"auto": AutoFlow(
|
|
161
|
+
project_path=str(self.project_path),
|
|
162
|
+
llm=self.llm,
|
|
163
|
+
sql_config=self.sql_tool.config if self.sql_tool else None,
|
|
164
|
+
serper_api_key=os.getenv("SERPER_API_KEY"),
|
|
165
|
+
),
|
|
166
|
+
"discovery": DiscoveryFlow(
|
|
167
|
+
project_path=str(self.project_path),
|
|
168
|
+
llm=self.llm,
|
|
169
|
+
sql_config=self.sql_tool.config if self.sql_tool else None,
|
|
170
|
+
serper_api_key=os.getenv("SERPER_API_KEY"),
|
|
171
|
+
),
|
|
172
|
+
"build": BuildFlow(
|
|
173
|
+
project_path=str(self.project_path),
|
|
174
|
+
llm=self.llm,
|
|
175
|
+
sql_config=self.sql_tool.config if self.sql_tool else None,
|
|
176
|
+
serper_api_key=os.getenv("SERPER_API_KEY"),
|
|
177
|
+
),
|
|
178
|
+
"debate": DebateFlow(
|
|
179
|
+
project_path=str(self.project_path),
|
|
180
|
+
llm=self.llm,
|
|
181
|
+
sql_config=self.sql_tool.config if self.sql_tool else None,
|
|
182
|
+
serper_api_key=os.getenv("SERPER_API_KEY"),
|
|
183
|
+
),
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
def analyze_task(self, task_description: str) -> Dict[str, Any]:
|
|
187
|
+
"""Analyze task and determine appropriate agent/flow.
|
|
188
|
+
|
|
189
|
+
Args:
|
|
190
|
+
task_description: Description of the task
|
|
191
|
+
|
|
192
|
+
Returns:
|
|
193
|
+
Analysis result with recommended agent/flow
|
|
194
|
+
"""
|
|
195
|
+
task_lower = task_description.lower()
|
|
196
|
+
|
|
197
|
+
# Check for flow-based tasks
|
|
198
|
+
if any(
|
|
199
|
+
keyword in task_lower
|
|
200
|
+
for keyword in ["auto", "autonomous", "full cycle", "complete"]
|
|
201
|
+
):
|
|
202
|
+
return {
|
|
203
|
+
"type": "flow",
|
|
204
|
+
"flow": "auto",
|
|
205
|
+
"reason": "Task requires autonomous full-cycle development",
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
if any(
|
|
209
|
+
keyword in task_lower
|
|
210
|
+
for keyword in ["discover", "requirement", "prd", "user story"]
|
|
211
|
+
):
|
|
212
|
+
return {
|
|
213
|
+
"type": "flow",
|
|
214
|
+
"flow": "discovery",
|
|
215
|
+
"reason": "Task requires discovery phase execution",
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
if any(
|
|
219
|
+
keyword in task_lower
|
|
220
|
+
for keyword in ["build", "implement", "develop", "code"]
|
|
221
|
+
):
|
|
222
|
+
return {
|
|
223
|
+
"type": "flow",
|
|
224
|
+
"flow": "build",
|
|
225
|
+
"reason": "Task requires build phase execution",
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
if any(
|
|
229
|
+
keyword in task_lower
|
|
230
|
+
for keyword in ["debate", "consensus", "discuss", "decide"]
|
|
231
|
+
):
|
|
232
|
+
return {
|
|
233
|
+
"type": "flow",
|
|
234
|
+
"flow": "debate",
|
|
235
|
+
"reason": "Task requires multi-agent debate",
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
# Check for agent-specific tasks
|
|
239
|
+
if any(
|
|
240
|
+
keyword in task_lower
|
|
241
|
+
for keyword in ["prd", "requirement", "user story", "persona", "feature"]
|
|
242
|
+
):
|
|
243
|
+
return {
|
|
244
|
+
"type": "agent",
|
|
245
|
+
"agent": "product",
|
|
246
|
+
"reason": "Task requires product management expertise",
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
if any(
|
|
250
|
+
keyword in task_lower
|
|
251
|
+
for keyword in ["architecture", "tech stack", "design", "api", "schema"]
|
|
252
|
+
):
|
|
253
|
+
return {
|
|
254
|
+
"type": "agent",
|
|
255
|
+
"agent": "architect",
|
|
256
|
+
"reason": "Task requires architecture expertise",
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
if any(
|
|
260
|
+
keyword in task_lower
|
|
261
|
+
for keyword in ["ux", "ui", "user flow", "wireframe", "design system"]
|
|
262
|
+
):
|
|
263
|
+
return {
|
|
264
|
+
"type": "agent",
|
|
265
|
+
"agent": "ux",
|
|
266
|
+
"reason": "Task requires UX design expertise",
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
if any(
|
|
270
|
+
keyword in task_lower
|
|
271
|
+
for keyword in ["implement", "code", "refactor", "debug", "review"]
|
|
272
|
+
):
|
|
273
|
+
return {
|
|
274
|
+
"type": "agent",
|
|
275
|
+
"agent": "dev",
|
|
276
|
+
"reason": "Task requires development expertise",
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
if any(
|
|
280
|
+
keyword in task_lower
|
|
281
|
+
for keyword in ["test", "quality", "verify", "coverage"]
|
|
282
|
+
):
|
|
283
|
+
return {
|
|
284
|
+
"type": "agent",
|
|
285
|
+
"agent": "test",
|
|
286
|
+
"reason": "Task requires testing expertise",
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
if any(
|
|
290
|
+
keyword in task_lower
|
|
291
|
+
for keyword in ["security", "vulnerability", "auth", "encrypt"]
|
|
292
|
+
):
|
|
293
|
+
return {
|
|
294
|
+
"type": "agent",
|
|
295
|
+
"agent": "security",
|
|
296
|
+
"reason": "Task requires security expertise",
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
if any(
|
|
300
|
+
keyword in task_lower
|
|
301
|
+
for keyword in ["deploy", "ci/cd", "infrastructure", "cloud", "azure"]
|
|
302
|
+
):
|
|
303
|
+
return {
|
|
304
|
+
"type": "agent",
|
|
305
|
+
"agent": "devops",
|
|
306
|
+
"reason": "Task requires DevOps expertise",
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
if any(
|
|
310
|
+
keyword in task_lower
|
|
311
|
+
for keyword in ["document", "guide", "readme", "api doc"]
|
|
312
|
+
):
|
|
313
|
+
return {
|
|
314
|
+
"type": "agent",
|
|
315
|
+
"agent": "doc",
|
|
316
|
+
"reason": "Task requires documentation expertise",
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
# Default to product agent for general tasks
|
|
320
|
+
return {
|
|
321
|
+
"type": "agent",
|
|
322
|
+
"agent": "product",
|
|
323
|
+
"reason": "Default agent for general tasks",
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
async def execute_task(
|
|
327
|
+
self, task_description: str, context: Optional[Dict[str, Any]] = None
|
|
328
|
+
) -> Dict[str, Any]:
|
|
329
|
+
"""Execute a task using appropriate agent/flow.
|
|
330
|
+
|
|
331
|
+
Args:
|
|
332
|
+
task_description: Description of the task
|
|
333
|
+
context: Additional context for the task
|
|
334
|
+
|
|
335
|
+
Returns:
|
|
336
|
+
Task execution result
|
|
337
|
+
"""
|
|
338
|
+
# Analyze task
|
|
339
|
+
analysis = self.analyze_task(task_description)
|
|
340
|
+
|
|
341
|
+
# Log task
|
|
342
|
+
self.state["task_history"].append(
|
|
343
|
+
{
|
|
344
|
+
"description": task_description,
|
|
345
|
+
"analysis": analysis,
|
|
346
|
+
"context": context,
|
|
347
|
+
"timestamp": str(asyncio.get_event_loop().time()),
|
|
348
|
+
}
|
|
349
|
+
)
|
|
350
|
+
|
|
351
|
+
# Execute based on analysis
|
|
352
|
+
if analysis["type"] == "flow":
|
|
353
|
+
return await self._execute_flow(analysis["flow"], task_description, context)
|
|
354
|
+
else:
|
|
355
|
+
return await self._execute_agent_task(
|
|
356
|
+
analysis["agent"], task_description, context
|
|
357
|
+
)
|
|
358
|
+
|
|
359
|
+
async def _execute_flow(
|
|
360
|
+
self,
|
|
361
|
+
flow_name: str,
|
|
362
|
+
task_description: str,
|
|
363
|
+
context: Optional[Dict[str, Any]] = None,
|
|
364
|
+
) -> Dict[str, Any]:
|
|
365
|
+
"""Execute a CrewAI flow.
|
|
366
|
+
|
|
367
|
+
Args:
|
|
368
|
+
flow_name: Name of the flow to execute
|
|
369
|
+
task_description: Description of the task
|
|
370
|
+
context: Additional context
|
|
371
|
+
|
|
372
|
+
Returns:
|
|
373
|
+
Flow execution result
|
|
374
|
+
"""
|
|
375
|
+
flow = self.flows.get(flow_name)
|
|
376
|
+
if not flow:
|
|
377
|
+
return {"status": "error", "error": f"Flow '{flow_name}' not found"}
|
|
378
|
+
|
|
379
|
+
try:
|
|
380
|
+
if flow_name == "auto":
|
|
381
|
+
result = await flow.kickoff()
|
|
382
|
+
elif flow_name == "discovery":
|
|
383
|
+
result = await flow.kickoff(task_description)
|
|
384
|
+
elif flow_name == "build":
|
|
385
|
+
result = await flow.kickoff(
|
|
386
|
+
str(context) if context else task_description
|
|
387
|
+
)
|
|
388
|
+
elif flow_name == "debate":
|
|
389
|
+
result = await flow.kickoff(task_description)
|
|
390
|
+
else:
|
|
391
|
+
result = await flow.kickoff()
|
|
392
|
+
|
|
393
|
+
return {"status": "success", "flow": flow_name, "result": result}
|
|
394
|
+
except Exception as e:
|
|
395
|
+
return {"status": "error", "flow": flow_name, "error": str(e)}
|
|
396
|
+
|
|
397
|
+
async def _execute_agent_task(
|
|
398
|
+
self,
|
|
399
|
+
agent_name: str,
|
|
400
|
+
task_description: str,
|
|
401
|
+
context: Optional[Dict[str, Any]] = None,
|
|
402
|
+
) -> Dict[str, Any]:
|
|
403
|
+
"""Execute a task with a specific agent.
|
|
404
|
+
|
|
405
|
+
Args:
|
|
406
|
+
agent_name: Name of the agent
|
|
407
|
+
task_description: Description of the task
|
|
408
|
+
context: Additional context
|
|
409
|
+
|
|
410
|
+
Returns:
|
|
411
|
+
Task execution result
|
|
412
|
+
"""
|
|
413
|
+
agent_wrapper = self.agents.get(agent_name)
|
|
414
|
+
if not agent_wrapper:
|
|
415
|
+
return {"status": "error", "error": f"Agent '{agent_name}' not found"}
|
|
416
|
+
|
|
417
|
+
try:
|
|
418
|
+
# Create task
|
|
419
|
+
task = Task(
|
|
420
|
+
description=task_description,
|
|
421
|
+
agent=agent_wrapper.get_agent(),
|
|
422
|
+
expected_output="Task completion result",
|
|
423
|
+
)
|
|
424
|
+
|
|
425
|
+
# Execute task
|
|
426
|
+
result = await asyncio.to_thread(task.execute)
|
|
427
|
+
|
|
428
|
+
return {"status": "success", "agent": agent_name, "result": result}
|
|
429
|
+
except Exception as e:
|
|
430
|
+
return {"status": "error", "agent": agent_name, "error": str(e)}
|
|
431
|
+
|
|
432
|
+
async def run_auto_mode(self, user_input: str) -> Dict[str, Any]:
|
|
433
|
+
"""Run autonomous mode.
|
|
434
|
+
|
|
435
|
+
Args:
|
|
436
|
+
user_input: Initial user input for the project
|
|
437
|
+
|
|
438
|
+
Returns:
|
|
439
|
+
Auto mode execution result
|
|
440
|
+
"""
|
|
441
|
+
if not self.auto_mode:
|
|
442
|
+
return {"status": "error", "error": "Auto mode is not enabled"}
|
|
443
|
+
|
|
444
|
+
print("🚀 Starting autonomous mode...")
|
|
445
|
+
|
|
446
|
+
try:
|
|
447
|
+
# Execute auto flow
|
|
448
|
+
result = await self.flows["auto"].kickoff()
|
|
449
|
+
|
|
450
|
+
return {"status": "success", "result": result}
|
|
451
|
+
except Exception as e:
|
|
452
|
+
return {"status": "error", "error": str(e)}
|
|
453
|
+
|
|
454
|
+
async def start_debate(self, topic: str) -> Dict[str, Any]:
|
|
455
|
+
"""Start a multi-agent debate.
|
|
456
|
+
|
|
457
|
+
Args:
|
|
458
|
+
topic: Topic to debate
|
|
459
|
+
|
|
460
|
+
Returns:
|
|
461
|
+
Debate result
|
|
462
|
+
"""
|
|
463
|
+
print(f"🎯 Starting debate on: {topic}")
|
|
464
|
+
|
|
465
|
+
try:
|
|
466
|
+
result = await self.flows["debate"].kickoff(topic)
|
|
467
|
+
|
|
468
|
+
return {"status": "success", "result": result}
|
|
469
|
+
except Exception as e:
|
|
470
|
+
return {"status": "error", "error": str(e)}
|
|
471
|
+
|
|
472
|
+
def create_crew(
|
|
473
|
+
self,
|
|
474
|
+
agent_names: List[str],
|
|
475
|
+
process: Process = Process.sequential,
|
|
476
|
+
verbose: bool = True,
|
|
477
|
+
) -> Crew:
|
|
478
|
+
"""Create a Crew with specified agents.
|
|
479
|
+
|
|
480
|
+
Args:
|
|
481
|
+
agent_names: List of agent names to include
|
|
482
|
+
process: Crew process type (sequential or hierarchical)
|
|
483
|
+
verbose: Enable verbose output
|
|
484
|
+
|
|
485
|
+
Returns:
|
|
486
|
+
Crew instance
|
|
487
|
+
"""
|
|
488
|
+
agents = []
|
|
489
|
+
for name in agent_names:
|
|
490
|
+
agent_wrapper = self.agents.get(name)
|
|
491
|
+
if agent_wrapper:
|
|
492
|
+
agents.append(agent_wrapper.get_agent())
|
|
493
|
+
|
|
494
|
+
if not agents:
|
|
495
|
+
raise ValueError(f"No valid agents found in {agent_names}")
|
|
496
|
+
|
|
497
|
+
return Crew(agents=agents, process=process, verbose=verbose)
|
|
498
|
+
|
|
499
|
+
async def execute_crew(self, crew: Crew, tasks: List[Task]) -> Dict[str, Any]:
|
|
500
|
+
"""Execute a Crew with tasks.
|
|
501
|
+
|
|
502
|
+
Args:
|
|
503
|
+
crew: Crew instance
|
|
504
|
+
tasks: List of tasks to execute
|
|
505
|
+
|
|
506
|
+
Returns:
|
|
507
|
+
Crew execution result
|
|
508
|
+
"""
|
|
509
|
+
try:
|
|
510
|
+
result = await asyncio.to_thread(crew.kickoff, tasks)
|
|
511
|
+
|
|
512
|
+
return {"status": "success", "result": result}
|
|
513
|
+
except Exception as e:
|
|
514
|
+
return {"status": "error", "error": str(e)}
|
|
515
|
+
|
|
516
|
+
def get_state(self) -> Dict[str, Any]:
|
|
517
|
+
"""Get orchestrator state.
|
|
518
|
+
|
|
519
|
+
Returns:
|
|
520
|
+
Current orchestrator state
|
|
521
|
+
"""
|
|
522
|
+
return self.state
|
|
523
|
+
|
|
524
|
+
def save_state(self, filepath: str):
|
|
525
|
+
"""Save orchestrator state to file.
|
|
526
|
+
|
|
527
|
+
Args:
|
|
528
|
+
filepath: Path to save state
|
|
529
|
+
"""
|
|
530
|
+
with open(filepath, "w") as f:
|
|
531
|
+
json.dump(self.state, f, indent=2)
|
|
532
|
+
|
|
533
|
+
def load_state(self, filepath: str):
|
|
534
|
+
"""Load orchestrator state from file.
|
|
535
|
+
|
|
536
|
+
Args:
|
|
537
|
+
filepath: Path to load state from
|
|
538
|
+
"""
|
|
539
|
+
with open(filepath, "r") as f:
|
|
540
|
+
self.state = json.load(f)
|
|
541
|
+
|
|
542
|
+
def enable_auto_mode(self):
|
|
543
|
+
"""Enable autonomous mode."""
|
|
544
|
+
self.auto_mode = True
|
|
545
|
+
self.state["auto_mode_enabled"] = True
|
|
546
|
+
|
|
547
|
+
def disable_auto_mode(self):
|
|
548
|
+
"""Disable autonomous mode."""
|
|
549
|
+
self.auto_mode = False
|
|
550
|
+
self.state["auto_mode_enabled"] = False
|
|
551
|
+
|
|
552
|
+
def is_auto_mode_enabled(self) -> bool:
|
|
553
|
+
"""Check if auto mode is enabled.
|
|
554
|
+
|
|
555
|
+
Returns:
|
|
556
|
+
True if auto mode is enabled
|
|
557
|
+
"""
|
|
558
|
+
return self.auto_mode
|