paradiseDev commited on
Commit
dfe2f68
·
verified ·
1 Parent(s): 95747b0

Upload modal_implementation.py

Browse files
Files changed (1) hide show
  1. modal_implementation.py +881 -0
modal_implementation.py ADDED
@@ -0,0 +1,881 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Modal Implementation for AutoGPT-like Agent with MCO Integration
3
+
4
+ This file implements a real AutoGPT-like agent using Modal that integrates with the MCO MCP server
5
+ for orchestration. The agent can perform code review tasks and generate MCO workflow files.
6
+ """
7
+
8
+ import os
9
+ import json
10
+ import subprocess
11
+ import tempfile
12
+ import time
13
+ from pathlib import Path
14
+ import anthropic
15
+ import modal
16
+ import requests
17
+ from bs4 import BeautifulSoup
18
+
19
+ # Define the Modal app
20
+ app = modal.App("mco-autogpt-agent")
21
+
22
+ # Base image with required dependencies
23
+ image = modal.Image.debian_slim().pip_install(
24
+ "anthropic",
25
+ "requests",
26
+ "python-dotenv",
27
+ "beautifulsoup4",
28
+ "numpy",
29
+ "pandas",
30
+ "matplotlib"
31
+ )
32
+
33
+ # Create a volume for persistent storage
34
+ volume = modal.Volume.from_name("mco-agent-volume", create_if_missing=True)
35
+
36
+ # Environment setup
37
+ env = {
38
+ "ANTHROPIC_API_KEY": os.environ.get("ANTHROPIC_API_KEY", ""),
39
+ "MCO_CONFIG_DIR": "/data/mco-config"
40
+ }
41
+
42
+ class MCPClient:
43
+ """Client for interacting with MCO MCP server via subprocess"""
44
+
45
+ def __init__(self, config_dir, orchestration_id=None):
46
+ self.config_dir = config_dir
47
+ self.orchestration_id = orchestration_id
48
+ self.mco_server_process = None
49
+
50
+ def _ensure_server_running(self):
51
+ """Ensure the MCO MCP server is running"""
52
+ if self.mco_server_process is None:
53
+ # Start the MCO MCP server
54
+ env = os.environ.copy()
55
+ env["MCO_CONFIG_DIR"] = self.config_dir
56
+
57
+ # Use MCP Inspector to start the server
58
+ self.mco_server_process = subprocess.Popen(
59
+ ["npx", "@modelcontextprotocol/inspector", "node", "mco-mcp-server.js"],
60
+ env=env,
61
+ stdin=subprocess.PIPE,
62
+ stdout=subprocess.PIPE,
63
+ stderr=subprocess.PIPE,
64
+ text=True
65
+ )
66
+
67
+ # Wait for server to initialize
68
+ time.sleep(2)
69
+
70
+ def _call_tool(self, tool_name, params):
71
+ """Call an MCO tool via MCP Inspector"""
72
+ self._ensure_server_running()
73
+
74
+ # Create temporary file for tool call
75
+ with tempfile.NamedTemporaryFile(mode='w+', suffix='.json', delete=False) as f:
76
+ json.dump({
77
+ "name": tool_name,
78
+ "arguments": params
79
+ }, f)
80
+ tool_file = f.name
81
+
82
+ # Call the tool using MCP Inspector
83
+ result = subprocess.run(
84
+ ["npx", "@modelcontextprotocol/inspector", "call-tool", "--tool-file", tool_file],
85
+ capture_output=True,
86
+ text=True
87
+ )
88
+
89
+ # Clean up temporary file
90
+ os.unlink(tool_file)
91
+
92
+ # Parse and return result
93
+ try:
94
+ return json.loads(result.stdout)
95
+ except json.JSONDecodeError:
96
+ return {"error": "Failed to parse tool result", "stdout": result.stdout, "stderr": result.stderr}
97
+
98
+ def start_orchestration(self, config=None):
99
+ """Start a new orchestration workflow"""
100
+ config = config or {}
101
+ result = self._call_tool("start_orchestration", {"config": config})
102
+
103
+ if "orchestration_id" in result:
104
+ self.orchestration_id = result["orchestration_id"]
105
+
106
+ return result
107
+
108
+ def get_next_directive(self):
109
+ """Get the next directive from the orchestration"""
110
+ if not self.orchestration_id:
111
+ raise ValueError("No active orchestration")
112
+
113
+ return self._call_tool("get_next_directive", {"orchestration_id": self.orchestration_id})
114
+
115
+ def complete_step(self, step_id, result):
116
+ """Complete a step in the orchestration"""
117
+ if not self.orchestration_id:
118
+ raise ValueError("No active orchestration")
119
+
120
+ return self._call_tool("complete_step", {
121
+ "orchestration_id": self.orchestration_id,
122
+ "step_id": step_id,
123
+ "result": result
124
+ })
125
+
126
+ def get_workflow_status(self):
127
+ """Get the current status of the workflow"""
128
+ if not self.orchestration_id:
129
+ raise ValueError("No active orchestration")
130
+
131
+ return self._call_tool("get_workflow_status", {"orchestration_id": self.orchestration_id})
132
+
133
+ def get_persistent_context(self):
134
+ """Get the persistent context for the workflow"""
135
+ if not self.orchestration_id:
136
+ raise ValueError("No active orchestration")
137
+
138
+ return self._call_tool("get_persistent_context", {"orchestration_id": self.orchestration_id})
139
+
140
+ def cleanup(self):
141
+ """Clean up resources"""
142
+ if self.mco_server_process:
143
+ self.mco_server_process.terminate()
144
+ self.mco_server_process = None
145
+
146
+ class AutoGPTAgent:
147
+ """AutoGPT-like agent that can be orchestrated by MCO"""
148
+
149
+ def __init__(self, task, config_dir, orchestration_id=None):
150
+ self.task = task
151
+ self.config_dir = config_dir
152
+ self.mcp_client = MCPClient(config_dir, orchestration_id)
153
+ self.memory = []
154
+ self.thinking_log = []
155
+ self.orchestration_log = []
156
+ self.client = anthropic.Anthropic()
157
+
158
+ def run(self):
159
+ """Run the agent with MCO orchestration"""
160
+ # Log the start of orchestration
161
+ self.orchestration_log.append({
162
+ "timestamp": time.time(),
163
+ "event": "orchestration_start",
164
+ "task": self.task
165
+ })
166
+
167
+ # If no orchestration ID, start new orchestration
168
+ if not self.mcp_client.orchestration_id:
169
+ config = {"task": self.task}
170
+ start_result = self.mcp_client.start_orchestration(config)
171
+
172
+ self.orchestration_log.append({
173
+ "timestamp": time.time(),
174
+ "event": "orchestration_created",
175
+ "orchestration_id": self.mcp_client.orchestration_id
176
+ })
177
+
178
+ results = []
179
+
180
+ # Main agent loop
181
+ while True:
182
+ # Get next directive from MCO
183
+ directive = self.mcp_client.get_next_directive()
184
+
185
+ self.orchestration_log.append({
186
+ "timestamp": time.time(),
187
+ "event": "directive_received",
188
+ "directive_type": directive.get("type"),
189
+ "step_id": directive.get("step_id")
190
+ })
191
+
192
+ if directive.get("type") == "complete":
193
+ # Workflow is complete
194
+ self.orchestration_log.append({
195
+ "timestamp": time.time(),
196
+ "event": "orchestration_complete"
197
+ })
198
+ break
199
+
200
+ # Check for injected context
201
+ if directive.get("injected_context"):
202
+ self.orchestration_log.append({
203
+ "timestamp": time.time(),
204
+ "event": "context_injected",
205
+ "context_type": list(directive.get("injected_context", {}).keys())
206
+ })
207
+
208
+ # Process directive
209
+ result = self._process_directive(directive)
210
+ results.append(result)
211
+
212
+ # Complete step
213
+ complete_result = self.mcp_client.complete_step(directive["step_id"], result)
214
+
215
+ self.orchestration_log.append({
216
+ "timestamp": time.time(),
217
+ "event": "step_completed",
218
+ "step_id": directive["step_id"],
219
+ "status": complete_result.get("status")
220
+ })
221
+
222
+ # Clean up
223
+ self.mcp_client.cleanup()
224
+
225
+ return {
226
+ "results": results,
227
+ "thinking_log": self.thinking_log,
228
+ "orchestration_log": self.orchestration_log
229
+ }
230
+
231
+ def _process_directive(self, directive):
232
+ """Process a directive from MCO"""
233
+ # Extract information from directive
234
+ instruction = directive["instruction"]
235
+ context = directive["persistent_context"]
236
+ injected = directive.get("injected_context", {})
237
+
238
+ # Add to memory
239
+ self.memory.append({
240
+ "role": "system",
241
+ "content": f"Directive: {instruction}\nContext: {json.dumps(context)}"
242
+ })
243
+
244
+ if injected:
245
+ self.memory.append({
246
+ "role": "system",
247
+ "content": f"Additional context: {json.dumps(injected)}"
248
+ })
249
+
250
+ # Generate thinking process
251
+ thinking = self._generate_thinking(instruction, context, injected)
252
+
253
+ # Log thinking
254
+ self.thinking_log.append({
255
+ "timestamp": time.time(),
256
+ "directive": instruction,
257
+ "thinking": thinking
258
+ })
259
+
260
+ # Execute tools based on thinking
261
+ tool_results = self._execute_tools(thinking)
262
+
263
+ # Generate summary
264
+ summary = self._generate_summary(instruction, thinking, tool_results)
265
+
266
+ return {
267
+ "thinking": thinking,
268
+ "tool_results": tool_results,
269
+ "summary": summary
270
+ }
271
+
272
+ def _generate_thinking(self, instruction, context, injected):
273
+ """Generate thinking process using Claude"""
274
+ # Prepare prompt for Claude
275
+ prompt = f"""
276
+ <task>{instruction}</task>
277
+
278
+ <context>
279
+ {json.dumps(context, indent=2)}
280
+ </context>
281
+
282
+ {"<injected>" + json.dumps(injected, indent=2) + "</injected>" if injected else ""}
283
+
284
+ <memory>
285
+ {self._format_memory()}
286
+ </memory>
287
+
288
+ <available_tools>
289
+ - execute_code(code: str, language: str) -> Executes code and returns the result
290
+ - search_web(query: str) -> Searches the web and returns results
291
+ - read_file(path: str) -> Reads a file and returns its content
292
+ - write_file(path: str, content: str) -> Writes content to a file
293
+ - analyze_code(code: str, language: str) -> Analyzes code for issues
294
+ </available_tools>
295
+
296
+ <thinking>
297
+ """
298
+
299
+ # Call Claude API
300
+ message = self.client.messages.create(
301
+ model="claude-3-5-sonnet-20240229",
302
+ max_tokens=2000,
303
+ messages=[{"role": "user", "content": prompt}],
304
+ stop_sequences=["</thinking>"]
305
+ )
306
+
307
+ return message.content[0].text
308
+
309
+ def _execute_tools(self, thinking):
310
+ """Extract and execute tools from thinking"""
311
+ # Extract tool calls
312
+ tool_calls = self._extract_tool_calls(thinking)
313
+
314
+ results = []
315
+ for tool_call in tool_calls:
316
+ tool_name = tool_call["name"]
317
+ tool_args = tool_call["args"]
318
+
319
+ # Execute the appropriate tool
320
+ if tool_name == "execute_code":
321
+ result = self._execute_code(tool_args.get("code", ""), tool_args.get("language", "python"))
322
+ elif tool_name == "search_web":
323
+ result = self._search_web(tool_args.get("query", ""))
324
+ elif tool_name == "read_file":
325
+ result = self._read_file(tool_args.get("path", ""))
326
+ elif tool_name == "write_file":
327
+ result = self._write_file(tool_args.get("path", ""), tool_args.get("content", ""))
328
+ elif tool_name == "analyze_code":
329
+ result = self._analyze_code(tool_args.get("code", ""), tool_args.get("language", ""))
330
+ else:
331
+ result = {"error": f"Unknown tool: {tool_name}"}
332
+
333
+ results.append({
334
+ "tool": tool_name,
335
+ "args": tool_args,
336
+ "result": result
337
+ })
338
+
339
+ # Add to memory
340
+ self.memory.append({
341
+ "role": "function",
342
+ "name": tool_name,
343
+ "content": json.dumps(result)
344
+ })
345
+
346
+ return results
347
+
348
+ def _generate_summary(self, instruction, thinking, tool_results):
349
+ """Generate a summary of the results"""
350
+ # Prepare prompt for Claude
351
+ prompt = f"""
352
+ <instruction>{instruction}</instruction>
353
+
354
+ <thinking>
355
+ {thinking}
356
+ </thinking>
357
+
358
+ <tool_results>
359
+ {json.dumps(tool_results, indent=2)}
360
+ </tool_results>
361
+
362
+ Please provide a concise summary of the results and how they address the instruction.
363
+ """
364
+
365
+ # Call Claude API
366
+ message = self.client.messages.create(
367
+ model="claude-3-5-sonnet-20240229",
368
+ max_tokens=1000,
369
+ messages=[{"role": "user", "content": prompt}]
370
+ )
371
+
372
+ return message.content[0].text
373
+
374
+ def _extract_tool_calls(self, thinking):
375
+ """Extract tool calls from thinking text"""
376
+ tool_calls = []
377
+
378
+ # Simple regex-like extraction (in a real implementation, use proper parsing)
379
+ lines = thinking.split("\n")
380
+ for i, line in enumerate(lines):
381
+ if "execute_code(" in line or "search_web(" in line or "read_file(" in line or "write_file(" in line or "analyze_code(" in line:
382
+ # Extract tool name
383
+ tool_name = line.split("(")[0].strip()
384
+
385
+ # Find the closing parenthesis
386
+ code_block = ""
387
+ j = i
388
+ while j < len(lines) and ")" not in lines[j]:
389
+ code_block += lines[j] + "\n"
390
+ j += 1
391
+
392
+ if j < len(lines):
393
+ code_block += lines[j].split(")")[0]
394
+
395
+ # Parse arguments
396
+ args = {}
397
+ if tool_name == "execute_code":
398
+ args = {"code": code_block, "language": "python"}
399
+ elif tool_name == "search_web":
400
+ args = {"query": code_block.strip()}
401
+ elif tool_name == "read_file":
402
+ args = {"path": code_block.strip()}
403
+ elif tool_name == "write_file":
404
+ parts = code_block.split(",", 1)
405
+ if len(parts) == 2:
406
+ args = {"path": parts[0].strip(), "content": parts[1].strip()}
407
+ elif tool_name == "analyze_code":
408
+ args = {"code": code_block, "language": "python"}
409
+
410
+ tool_calls.append({
411
+ "name": tool_name,
412
+ "args": args
413
+ })
414
+
415
+ return tool_calls
416
+
417
+ def _format_memory(self):
418
+ """Format memory for inclusion in prompt"""
419
+ formatted = ""
420
+ for item in self.memory[-5:]: # Only include the last 5 memory items
421
+ if item["role"] == "system":
422
+ formatted += f"System: {item['content']}\n\n"
423
+ elif item["role"] == "function":
424
+ formatted += f"Function {item['name']}: {item['content']}\n\n"
425
+ return formatted
426
+
427
+ # Tool implementations
428
+ def _execute_code(self, code, language):
429
+ """Execute code in a sandbox environment"""
430
+ if language.lower() != "python":
431
+ return {"error": f"Unsupported language: {language}"}
432
+
433
+ try:
434
+ # Create a temporary file
435
+ with tempfile.NamedTemporaryFile(mode='w+', suffix='.py', delete=False) as f:
436
+ f.write(code)
437
+ temp_file = f.name
438
+
439
+ # Execute the code
440
+ result = subprocess.run(
441
+ ["python", temp_file],
442
+ capture_output=True,
443
+ text=True,
444
+ timeout=10
445
+ )
446
+
447
+ # Clean up
448
+ os.unlink(temp_file)
449
+
450
+ return {
451
+ "stdout": result.stdout,
452
+ "stderr": result.stderr,
453
+ "returncode": result.returncode
454
+ }
455
+ except Exception as e:
456
+ return {"error": str(e)}
457
+
458
+ def _search_web(self, query):
459
+ """Search the web for information"""
460
+ try:
461
+ # Use a search API (simplified for demo)
462
+ response = requests.get(
463
+ "https://api.duckduckgo.com/",
464
+ params={"q": query, "format": "json"}
465
+ )
466
+
467
+ return response.json()
468
+ except Exception as e:
469
+ return {"error": str(e)}
470
+
471
+ def _read_file(self, path):
472
+ """Read a file from the agent's workspace"""
473
+ try:
474
+ full_path = Path(self.config_dir) / path
475
+ with open(full_path, 'r') as f:
476
+ content = f.read()
477
+ return {"content": content}
478
+ except Exception as e:
479
+ return {"error": str(e)}
480
+
481
+ def _write_file(self, path, content):
482
+ """Write content to a file in the agent's workspace"""
483
+ try:
484
+ full_path = Path(self.config_dir) / path
485
+ # Ensure directory exists
486
+ full_path.parent.mkdir(parents=True, exist_ok=True)
487
+
488
+ with open(full_path, 'w') as f:
489
+ f.write(content)
490
+ return {"success": True, "path": str(full_path)}
491
+ except Exception as e:
492
+ return {"error": str(e)}
493
+
494
+ def _analyze_code(self, code, language):
495
+ """Analyze code for issues"""
496
+ # In a real implementation, use a code analysis tool
497
+ # For demo, use Claude to analyze
498
+ prompt = f"""
499
+ <code language="{language}">
500
+ {code}
501
+ </code>
502
+
503
+ Please analyze this code for:
504
+ 1. Bugs and errors
505
+ 2. Security issues
506
+ 3. Performance concerns
507
+ 4. Style and best practices
508
+
509
+ Provide specific line numbers and detailed explanations.
510
+ """
511
+
512
+ message = self.client.messages.create(
513
+ model="claude-3-5-sonnet-20240229",
514
+ max_tokens=1500,
515
+ messages=[{"role": "user", "content": prompt}]
516
+ )
517
+
518
+ return {"analysis": message.content[0].text}
519
+
520
+ class CodeReviewAgent(AutoGPTAgent):
521
+ """Specialized agent for code review tasks"""
522
+
523
+ def __init__(self, task, config_dir, orchestration_id=None):
524
+ super().__init__(task, config_dir, orchestration_id)
525
+
526
+ def review_code(self, code_files):
527
+ """Review multiple code files"""
528
+ results = {}
529
+
530
+ for file_path, code in code_files.items():
531
+ # Determine language
532
+ language = self._detect_language(file_path)
533
+
534
+ # Analyze code
535
+ analysis = self._analyze_code(code, language)
536
+
537
+ # Generate suggestions
538
+ suggestions = self._suggest_improvements(code, analysis, language)
539
+
540
+ # Create test cases
541
+ test_cases = self._generate_test_cases(code, language)
542
+
543
+ # Compile results
544
+ results[file_path] = {
545
+ "language": language,
546
+ "analysis": analysis,
547
+ "suggestions": suggestions,
548
+ "test_cases": test_cases
549
+ }
550
+
551
+ return results
552
+
553
+ def _detect_language(self, file_path):
554
+ """Detect programming language from file extension"""
555
+ ext = Path(file_path).suffix.lower()
556
+
557
+ language_map = {
558
+ ".py": "python",
559
+ ".js": "javascript",
560
+ ".ts": "typescript",
561
+ ".java": "java",
562
+ ".c": "c",
563
+ ".cpp": "c++",
564
+ ".cs": "c#",
565
+ ".go": "go",
566
+ ".rb": "ruby",
567
+ ".php": "php",
568
+ ".swift": "swift",
569
+ ".kt": "kotlin",
570
+ ".rs": "rust",
571
+ ".html": "html",
572
+ ".css": "css",
573
+ ".sql": "sql"
574
+ }
575
+
576
+ return language_map.get(ext, "unknown")
577
+
578
+ def _suggest_improvements(self, code, analysis, language):
579
+ """Generate improvement suggestions"""
580
+ prompt = f"""
581
+ <code language="{language}">
582
+ {code}
583
+ </code>
584
+
585
+ <analysis>
586
+ {analysis.get('analysis', '')}
587
+ </analysis>
588
+
589
+ Please suggest specific improvements to address the issues identified in the analysis.
590
+ Include code snippets showing the improved version.
591
+ """
592
+
593
+ message = self.client.messages.create(
594
+ model="claude-3-5-sonnet-20240229",
595
+ max_tokens=1500,
596
+ messages=[{"role": "user", "content": prompt}]
597
+ )
598
+
599
+ return {"suggestions": message.content[0].text}
600
+
601
+ def _generate_test_cases(self, code, language):
602
+ """Generate test cases for the code"""
603
+ prompt = f"""
604
+ <code language="{language}">
605
+ {code}
606
+ </code>
607
+
608
+ Please generate comprehensive test cases for this code.
609
+ Include:
610
+ 1. Unit tests for individual functions/methods
611
+ 2. Edge case tests
612
+ 3. Integration tests if applicable
613
+
614
+ Provide the test code in the same language as the original code.
615
+ """
616
+
617
+ message = self.client.messages.create(
618
+ model="claude-3-5-sonnet-20240229",
619
+ max_tokens=1500,
620
+ messages=[{"role": "user", "content": prompt}]
621
+ )
622
+
623
+ return {"test_cases": message.content[0].text}
624
+
625
+ def generate_snlp_files(self, review_type, language_focus):
626
+ """Generate MCO SNLP files for a code review workflow"""
627
+ # Generate mco.core
628
+ core_content = self._generate_core_file(review_type, language_focus)
629
+
630
+ # Generate mco.sc
631
+ sc_content = self._generate_sc_file(review_type, language_focus)
632
+
633
+ # Generate mco.features
634
+ features_content = self._generate_features_file(review_type, language_focus)
635
+
636
+ # Generate mco.styles
637
+ styles_content = self._generate_styles_file(review_type, language_focus)
638
+
639
+ # Write files to config directory
640
+ self._write_file("mco.core", core_content)
641
+ self._write_file("mco.sc", sc_content)
642
+ self._write_file("mco.features", features_content)
643
+ self._write_file("mco.styles", styles_content)
644
+
645
+ return {
646
+ "mco.core": core_content,
647
+ "mco.sc": sc_content,
648
+ "mco.features": features_content,
649
+ "mco.styles": styles_content
650
+ }
651
+
652
+ def _generate_core_file(self, review_type, language_focus):
653
+ """Generate mco.core file content"""
654
+ return f"""// MCO Core Configuration
655
+
656
+ @workflow "Code Review Assistant"
657
+ >This is an AI assistant that performs thorough code reviews for {language_focus} code with a focus on {review_type}.
658
+ >The workflow follows a structured progression to ensure comprehensive and reliable code reviews.
659
+
660
+ @description "Multi-step code review workflow with progressive revelation"
661
+ >This workflow demonstrates MCO's progressive revelation capability - core requirements stay persistent while features and styles are strategically injected at optimal moments.
662
+ >The agent should maintain focus on the current step while building upon previous work.
663
+
664
+ @version "1.0.0"
665
+
666
+ // Data Section - Persistent state throughout workflow
667
+ @data
668
+ language: "{language_focus}"
669
+ review_type: "{review_type}"
670
+ code_files: []
671
+ issues_found: {{}}
672
+ suggestions: {{}}
673
+ test_results: {{}}
674
+ >Focus on building reliable, autonomous code review workflows that complete successfully without human intervention.
675
+ >The agent should maintain context across all steps and build upon previous work iteratively.
676
+ >Use the data variables to track state and progress throughout the workflow.
677
+
678
+ // Agents Section - Workflow execution structure
679
+ @agents
680
+ orchestrator:
681
+ name: "MCO Orchestrator"
682
+ description: "Manages workflow state and progressive revelation"
683
+ model: "claude-3-5-sonnet"
684
+ steps:
685
+ - "Understand the code review requirements and scope"
686
+ - "Analyze code structure and organization"
687
+ - "Identify bugs, errors, and potential issues"
688
+ - "Evaluate code quality and adherence to best practices"
689
+ - "Generate improvement suggestions with examples"
690
+ - "Create comprehensive review report with actionable recommendations"
691
+ """
692
+
693
+ def _generate_sc_file(self, review_type, language_focus):
694
+ """Generate mco.sc file content"""
695
+ return f"""// MCO Success Criteria
696
+
697
+ @goal "Create a comprehensive code review system for {language_focus} code"
698
+ >The goal is to build a reliable, autonomous code review system that can analyze {language_focus} code,
699
+ >identify issues, suggest improvements, and generate test cases with a focus on {review_type}.
700
+
701
+ @success_criteria
702
+ - "Correctly identify syntax errors and bugs in {language_focus} code"
703
+ - "Provide specific, actionable suggestions for code improvement"
704
+ - "Generate relevant test cases that cover edge cases"
705
+ - "Maintain consistent focus on {review_type} aspects"
706
+ - "Produce a well-organized, comprehensive review report"
707
+ - "Complete the entire workflow without human intervention"
708
+ >The success criteria define what a successful code review should accomplish.
709
+ >Each criterion should be measurable and verifiable.
710
+
711
+ @target_audience "Software developers and code reviewers"
712
+ >The primary users are software developers who want automated code reviews for their {language_focus} projects.
713
+ >They need detailed, actionable feedback to improve their code quality and reliability.
714
+
715
+ @developer_vision "Reliable, consistent code reviews that improve code quality"
716
+ >The vision is to create a system that provides the same level of detail and insight as a human code reviewer,
717
+ >but with greater consistency and without the limitations of human reviewers (fatigue, bias, etc.).
718
+ """
719
+
720
+ def _generate_features_file(self, review_type, language_focus):
721
+ """Generate mco.features file content"""
722
+ return f"""// MCO Features
723
+
724
+ @feature "Static Analysis"
725
+ >Perform static analysis of {language_focus} code to identify syntax errors, potential bugs, and code smells.
726
+ >Use language-specific rules and best practices to evaluate code quality.
727
+
728
+ @feature "Security Scanning"
729
+ >Scan code for security vulnerabilities such as injection flaws, authentication issues, and data exposure risks.
730
+ >Prioritize findings based on severity and potential impact.
731
+
732
+ @feature "Performance Optimization"
733
+ >Identify performance bottlenecks and inefficient algorithms or data structures.
734
+ >Suggest optimizations that improve execution speed and resource usage.
735
+
736
+ @feature "Code Style Enforcement"
737
+ >Check adherence to coding standards and style guidelines for {language_focus}.
738
+ >Ensure consistent formatting, naming conventions, and documentation.
739
+
740
+ @feature "Test Coverage Analysis"
741
+ >Evaluate the completeness of test coverage for the codebase.
742
+ >Identify untested code paths and suggest additional test cases.
743
+
744
+ @feature "Refactoring Suggestions"
745
+ >Recommend code refactoring to improve maintainability, readability, and extensibility.
746
+ >Provide specific examples of refactored code.
747
+ """
748
+
749
+ def _generate_styles_file(self, review_type, language_focus):
750
+ """Generate mco.styles file content"""
751
+ return f"""// MCO Styles
752
+
753
+ @style "Comprehensive"
754
+ >Provide detailed analysis covering all aspects of the code, including syntax, semantics, style, and architecture.
755
+ >Leave no stone unturned in the review process.
756
+
757
+ @style "Actionable"
758
+ >Focus on providing specific, actionable feedback that can be immediately implemented.
759
+ >Include code examples and clear instructions for addressing issues.
760
+
761
+ @style "Educational"
762
+ >Explain the reasoning behind each suggestion to help developers learn and improve.
763
+ >Reference relevant documentation, best practices, and design patterns.
764
+
765
+ @style "Prioritized"
766
+ >Organize findings by severity and impact to help developers focus on the most important issues first.
767
+ >Clearly distinguish between critical issues and minor suggestions.
768
+
769
+ @style "Balanced"
770
+ >Acknowledge both strengths and weaknesses in the code to provide a balanced perspective.
771
+ >Highlight well-implemented patterns and clever solutions alongside areas for improvement.
772
+
773
+ @style "Collaborative"
774
+ >Frame feedback in a collaborative, constructive manner rather than being overly critical.
775
+ >Use language that encourages improvement rather than assigning blame.
776
+ """
777
+
778
+ # Modal functions
779
+ @app.function(
780
+ image=image,
781
+ volumes={"/data": volume},
782
+ timeout=600,
783
+ secrets=[modal.Secret.from_name("anthropic-api-key")]
784
+ )
785
+ def run_agent(task, config_dir="/data/mco-config", orchestration_id=None):
786
+ """Run the AutoGPT-like agent with MCO orchestration"""
787
+ agent = AutoGPTAgent(task, config_dir, orchestration_id)
788
+ return agent.run()
789
+
790
+ @app.function(
791
+ image=image,
792
+ volumes={"/data": volume},
793
+ timeout=600,
794
+ secrets=[modal.Secret.from_name("anthropic-api-key")]
795
+ )
796
+ def run_code_review(code_files, review_type, language_focus, config_dir="/data/mco-config", orchestration_id=None):
797
+ """Run a code review using the specialized agent"""
798
+ agent = CodeReviewAgent(f"Review {language_focus} code with focus on {review_type}", config_dir, orchestration_id)
799
+
800
+ # Generate SNLP files
801
+ snlp_files = agent.generate_snlp_files(review_type, language_focus)
802
+
803
+ # Run the agent with MCO orchestration
804
+ results = agent.run()
805
+
806
+ # Add code review results
807
+ if code_files:
808
+ review_results = agent.review_code(code_files)
809
+ results["code_review"] = review_results
810
+
811
+ return results
812
+
813
+ @app.function(
814
+ image=image,
815
+ volumes={"/data": volume},
816
+ secrets=[modal.Secret.from_name("anthropic-api-key")]
817
+ )
818
+ def generate_snlp_files(review_type, language_focus, config_dir="/data/mco-config"):
819
+ """Generate SNLP files for a code review workflow"""
820
+ agent = CodeReviewAgent(f"Generate SNLP files for {language_focus} code review", config_dir)
821
+ return agent.generate_snlp_files(review_type, language_focus)
822
+
823
+ @app.function(
824
+ image=image,
825
+ volumes={"/data": volume},
826
+ secrets=[modal.Secret.from_name("anthropic-api-key")]
827
+ )
828
+ def execute_code(code, language="python"):
829
+ """Execute code in a sandbox environment"""
830
+ agent = AutoGPTAgent("Execute code", "/data/mco-config")
831
+ return agent._execute_code(code, language)
832
+
833
+ @app.function(
834
+ image=image,
835
+ secrets=[modal.Secret.from_name("anthropic-api-key")]
836
+ )
837
+ def search_web(query):
838
+ """Search the web for information"""
839
+ agent = AutoGPTAgent("Search web", "/data/mco-config")
840
+ return agent._search_web(query)
841
+
842
+ # FastAPI web app for HTTP endpoints
843
+ @app.function(
844
+ image=image.pip_install("fastapi", "uvicorn"),
845
+ secrets=[modal.Secret.from_name("anthropic-api-key")]
846
+ )
847
+ @modal.asgi_app()
848
+ def fastapi_app():
849
+ from fastapi import FastAPI
850
+
851
+ web_app = FastAPI()
852
+
853
+ @web_app.post("/run_agent")
854
+ async def web_run_agent(request: dict):
855
+ """Run agent via HTTP"""
856
+ try:
857
+ task = request.get("task", "")
858
+ review_type = request.get("review_type")
859
+ language_focus = request.get("language_focus")
860
+ code_files = request.get("code_files")
861
+
862
+ if review_type and language_focus:
863
+ result = run_code_review.remote(code_files or {}, review_type, language_focus)
864
+ else:
865
+ result = run_agent.remote(task)
866
+
867
+ return {"success": True, "result": result}
868
+ except Exception as e:
869
+ return {"success": False, "error": str(e)}
870
+
871
+ @web_app.get("/health")
872
+ async def health():
873
+ return {"status": "healthy"}
874
+
875
+ return web_app
876
+
877
+ if __name__ == "__main__":
878
+ # For local testing
879
+ print("Running agent locally...")
880
+ result = run_agent("Create a simple code review workflow for Python")
881
+ print(json.dumps(result, indent=2))