UNPKG

shipdeck

Version:

Ship MVPs in 48 hours. Fix bugs in 30 seconds. The command deck for developers who ship.

154 lines (136 loc) 4.43 kB
/** * Worker Thread Script for Parallel Agent Execution * This script runs in isolated worker threads to execute agents concurrently */ const { parentPort, workerData } = require('worker_threads'); const path = require('path'); /** * Execute agent in worker thread */ async function executeAgentInWorker() { try { const { agentPath, agentConfig, task, context } = workerData; // Validate worker data if (!agentPath || !task || !context) { throw new Error('Missing required worker data: agentPath, task, or context'); } // Load agent class dynamically let AgentClass; try { const agentModule = require(path.resolve(agentPath)); // Handle different export patterns if (agentModule.default) { AgentClass = agentModule.default; } else if (typeof agentModule === 'function') { AgentClass = agentModule; } else { // Look for common agent class names const possibleClasses = Object.values(agentModule).filter( value => typeof value === 'function' && value.prototype ); if (possibleClasses.length === 1) { AgentClass = possibleClasses[0]; } else { throw new Error(`Could not determine agent class from ${agentPath}`); } } } catch (error) { throw new Error(`Failed to load agent from ${agentPath}: ${error.message}`); } // Initialize agent with configuration const agent = new AgentClass({ ...agentConfig, // Override some settings for worker execution config: { ...agentConfig.config, enableLogging: false, // Reduce logging in workers maxRetries: agentConfig.config?.maxRetries || 1 } }); // Validate agent has required methods if (typeof agent.executeWithRetry !== 'function') { throw new Error(`Agent from ${agentPath} does not implement executeWithRetry method`); } // Execute task with enhanced context const executionContext = { ...context, workerId: process.env.WORKER_ID || 'unknown', workerStartTime: Date.now(), isWorkerThread: true }; const startTime = Date.now(); const result = await agent.executeWithRetry(task, executionContext); const duration = Date.now() - startTime; // Send success result back to main thread parentPort.postMessage({ type: 'success', result: { ...result, duration, workerId: executionContext.workerId, executedAt: new Date().toISOString() }, taskId: context.taskId }); } catch (error) { // Send error back to main thread parentPort.postMessage({ type: 'error', error: { message: error.message, stack: error.stack, name: error.constructor.name, code: error.code, timestamp: new Date().toISOString() }, taskId: workerData.context?.taskId || 'unknown' }); } } // Handle uncaught exceptions in worker process.on('uncaughtException', (error) => { parentPort.postMessage({ type: 'error', error: { message: `Uncaught exception in worker: ${error.message}`, stack: error.stack, name: error.constructor.name, fatal: true, timestamp: new Date().toISOString() }, taskId: workerData.context?.taskId || 'unknown' }); process.exit(1); }); // Handle unhandled promise rejections in worker process.on('unhandledRejection', (reason, promise) => { parentPort.postMessage({ type: 'error', error: { message: `Unhandled promise rejection in worker: ${reason}`, stack: reason?.stack || 'No stack trace available', name: 'UnhandledPromiseRejection', fatal: true, timestamp: new Date().toISOString() }, taskId: workerData.context?.taskId || 'unknown' }); process.exit(1); }); // Start agent execution executeAgentInWorker().catch((error) => { // This should not happen as executeAgentInWorker handles its own errors, // but adding as a safety net parentPort.postMessage({ type: 'error', error: { message: `Fatal error in worker execution: ${error.message}`, stack: error.stack, name: error.constructor.name, fatal: true, timestamp: new Date().toISOString() }, taskId: workerData.context?.taskId || 'unknown' }); process.exit(1); });