#!/usr/bin/env python3 """ OpenHands SDK Wrapper for n8n Integration (V2 - Uses VENV) Usage: python3 /home/bam/openhands-sdk-wrapper-v2.py "task description" This wrapper uses the SDK venv to ensure all dependencies are available. """ import sys import os import json import argparse import subprocess from datetime import datetime from pathlib import Path def run_openhands_task(task, workspace="/home/bam", verbose=True): """ Execute an OpenHands task using the SDK Args: task: Task description string workspace: Working directory path verbose: Print detailed logs Returns: dict: Results including success status and output """ results = { 'success': False, 'task': task, 'workspace': workspace, 'timestamp': datetime.now().isoformat(), 'error': None, 'files_created': [], 'stdout': '', 'stderr': '' } try: if verbose: print(f"🚀 Starting OpenHands SDK execution...") print(f"📋 Task: {task}") print(f"📁 Workspace: {workspace}") print("-" * 50) # Create workspace directory if it doesn't exist workspace_path = Path(workspace) workspace_path.mkdir(parents=True, exist_ok=True) # Prepare the actual SDK script to run in venv sdk_script = ''' import sys import os from pathlib import Path # Add SDK to path sys.path.insert(0, '/tmp/software-agent-sdk/openhands-sdk') # Load environment env_file = '/home/bam/openhands/.env' if os.path.exists(env_file): with open(env_file, 'r') as f: for line in f: line = line.strip() if line and '=' in line and not line.startswith('#'): key, value = line.split('=', 1) os.environ[key] = value from openhands.sdk import LLM, Agent, Conversation # Configure LLM api_key = os.getenv('MINIMAX_API_KEY') if not api_key: print("ERROR: MINIMAX_API_KEY not found") sys.exit(1) llm = LLM( model="openai/MiniMax-M2", api_key=api_key, base_url="https://api.minimax.io/v1" ) # Create agent agent = Agent(llm=llm) # Start conversation workspace = sys.argv[1] if len(sys.argv) > 1 else '/home/bam' conversation = Conversation(agent=agent, workspace=workspace) # Send and run task task = sys.argv[2] if len(sys.argv) > 2 else '' conversation.send_message(task) conversation.run() # List files created files = [] if os.path.exists(workspace): for item in os.listdir(workspace): item_path = os.path.join(workspace, item) if os.path.isfile(item_path) and not item.startswith('.'): files.append(item) print("SUCCESS") print("Files created: " + str(files)) ''' # Write the SDK script to a temp file import tempfile with tempfile.NamedTemporaryFile(mode='w', suffix='.py', delete=False) as f: f.write(sdk_script) temp_script = f.name # Execute using the venv Python venv_python = '/tmp/software-agent-sdk/.venv/bin/python3' cmd = [venv_python, temp_script, str(workspace_path), task] if verbose: print("⏳ Running SDK in venv...") process = subprocess.run( cmd, capture_output=True, text=True, timeout=300 ) # Clean up temp file os.unlink(temp_script) # Parse output results['stdout'] = process.stdout results['stderr'] = process.stderr if process.returncode == 0: # Check if output contains "SUCCESS" if "SUCCESS" in process.stdout: results['success'] = True # Extract files list for line in process.stdout.split('\n'): if 'Files created:' in line: try: files_str = line.split('Files created:')[1].strip() results['files_created'] = eval(files_str) except: pass if verbose: print("✅ Task completed successfully!") if results['files_created']: print(f"📄 Files created: {results['files_created']}") else: results['error'] = process.stderr or "Unknown error" if verbose: print(f"❌ Task failed: {results['error']}") except subprocess.TimeoutExpired: results['error'] = "Timeout: Task took too long (>5 minutes)" if verbose: print("❌ Task timed out") except Exception as e: results['error'] = str(e) if verbose: print(f"❌ Task failed: {e}") return results def main(): """Main entry point for the wrapper script""" parser = argparse.ArgumentParser(description='OpenHands SDK Wrapper for n8n (V2)') parser.add_argument('task', help='Task description to execute') parser.add_argument('--workspace', default='/home/bam', help='Working directory') parser.add_argument('--quiet', action='store_true', help='Suppress verbose output') parser.add_argument('--json', action='store_true', help='Output results as JSON') args = parser.parse_args() # Run the task results = run_openhands_task( task=args.task, workspace=args.workspace, verbose=not args.quiet ) # Output results if args.json: print(json.dumps(results, indent=2)) else: if results['success']: print("SUCCESS") if results['files_created']: print(f"Files created: {', '.join(results['files_created'])}") else: print("FAILED") if results['error']: print(f"Error: {results['error']}") # Exit with appropriate code sys.exit(0 if results['success'] else 1) if __name__ == "__main__": main()