testchimp-runner-core 0.0.35 → 0.0.37
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/dist/orchestrator/orchestrator-agent.d.ts.map +1 -1
- package/dist/orchestrator/orchestrator-agent.js +7 -4
- package/dist/orchestrator/orchestrator-agent.js.map +1 -1
- package/dist/orchestrator/orchestrator-prompts.d.ts.map +1 -1
- package/dist/orchestrator/orchestrator-prompts.js +73 -15
- package/dist/orchestrator/orchestrator-prompts.js.map +1 -1
- package/dist/orchestrator/page-som-handler.d.ts +1 -2
- package/dist/orchestrator/page-som-handler.d.ts.map +1 -1
- package/dist/orchestrator/page-som-handler.js +51 -25
- package/dist/orchestrator/page-som-handler.js.map +1 -1
- package/package.json +6 -1
- package/plandocs/BEFORE_AFTER_VERIFICATION.md +0 -148
- package/plandocs/COORDINATE_MODE_DIAGNOSIS.md +0 -144
- package/plandocs/CREDIT_CALLBACK_ARCHITECTURE.md +0 -253
- package/plandocs/HUMAN_LIKE_IMPROVEMENTS.md +0 -642
- package/plandocs/IMPLEMENTATION_STATUS.md +0 -108
- package/plandocs/INTEGRATION_COMPLETE.md +0 -322
- package/plandocs/MULTI_AGENT_ARCHITECTURE_REVIEW.md +0 -844
- package/plandocs/ORCHESTRATOR_MVP_SUMMARY.md +0 -539
- package/plandocs/PHASE1_ABSTRACTION_COMPLETE.md +0 -241
- package/plandocs/PHASE1_FINAL_STATUS.md +0 -210
- package/plandocs/PHASE_1_COMPLETE.md +0 -165
- package/plandocs/PHASE_1_SUMMARY.md +0 -184
- package/plandocs/PLANNING_SESSION_SUMMARY.md +0 -372
- package/plandocs/PROMPT_OPTIMIZATION_ANALYSIS.md +0 -120
- package/plandocs/PROMPT_SANITY_CHECK.md +0 -120
- package/plandocs/SCRIPT_CLEANUP_FEATURE.md +0 -201
- package/plandocs/SCRIPT_GENERATION_ARCHITECTURE.md +0 -364
- package/plandocs/SELECTOR_IMPROVEMENTS.md +0 -139
- package/plandocs/SESSION_SUMMARY_v0.0.33.md +0 -151
- package/plandocs/TROUBLESHOOTING_SESSION.md +0 -72
- package/plandocs/VISION_DIAGNOSTICS_IMPROVEMENTS.md +0 -336
- package/plandocs/VISUAL_AGENT_EVOLUTION_PLAN.md +0 -396
- package/plandocs/WHATS_NEW_v0.0.33.md +0 -183
- package/plandocs/exploratory-mode-support-v2.plan.md +0 -953
- package/plandocs/exploratory-mode-support.plan.md +0 -928
- package/plandocs/journey-id-tracking-addendum.md +0 -227
- package/releasenotes/RELEASE_0.0.26.md +0 -165
- package/releasenotes/RELEASE_0.0.27.md +0 -236
- package/releasenotes/RELEASE_0.0.28.md +0 -286
- package/src/auth-config.ts +0 -84
- package/src/credit-usage-service.ts +0 -188
- package/src/env-loader.ts +0 -103
- package/src/execution-service.ts +0 -996
- package/src/file-handler.ts +0 -104
- package/src/index.ts +0 -432
- package/src/llm-facade.ts +0 -821
- package/src/llm-provider.ts +0 -53
- package/src/model-constants.ts +0 -35
- package/src/orchestrator/decision-parser.ts +0 -139
- package/src/orchestrator/index.ts +0 -58
- package/src/orchestrator/orchestrator-agent.ts +0 -1282
- package/src/orchestrator/orchestrator-prompts.ts +0 -786
- package/src/orchestrator/page-som-handler.ts +0 -1565
- package/src/orchestrator/som-types.ts +0 -188
- package/src/orchestrator/tool-registry.ts +0 -184
- package/src/orchestrator/tools/check-page-ready.ts +0 -75
- package/src/orchestrator/tools/extract-data.ts +0 -92
- package/src/orchestrator/tools/index.ts +0 -15
- package/src/orchestrator/tools/inspect-page.ts +0 -42
- package/src/orchestrator/tools/recall-history.ts +0 -72
- package/src/orchestrator/tools/refresh-som-markers.ts +0 -69
- package/src/orchestrator/tools/take-screenshot.ts +0 -128
- package/src/orchestrator/tools/verify-action-result.ts +0 -159
- package/src/orchestrator/tools/view-previous-screenshot.ts +0 -103
- package/src/orchestrator/types.ts +0 -291
- package/src/playwright-mcp-service.ts +0 -224
- package/src/progress-reporter.ts +0 -144
- package/src/prompts.ts +0 -842
- package/src/providers/backend-proxy-llm-provider.ts +0 -91
- package/src/providers/local-llm-provider.ts +0 -38
- package/src/scenario-service.ts +0 -252
- package/src/scenario-worker-class.ts +0 -1110
- package/src/script-utils.ts +0 -203
- package/src/types.ts +0 -239
- package/src/utils/browser-utils.ts +0 -348
- package/src/utils/coordinate-converter.ts +0 -162
- package/src/utils/page-info-retry.ts +0 -65
- package/src/utils/page-info-utils.ts +0 -285
- package/testchimp-runner-core-0.0.35.tgz +0 -0
- package/tsconfig.json +0 -19
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Backend Proxy LLM Provider
|
|
3
|
-
* Calls backend proxy API with authentication
|
|
4
|
-
* Used by VS Extension and GitHub Runner
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import axios from 'axios';
|
|
8
|
-
import { LLMProvider, LLMRequest, LLMResponse } from '../llm-provider';
|
|
9
|
-
import { AuthConfig, getAuthHeaders } from '../auth-config';
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Default LLM provider that calls backend proxy
|
|
13
|
-
* Converts camelCase requests to snake_case for backend API
|
|
14
|
-
*/
|
|
15
|
-
export class BackendProxyLLMProvider implements LLMProvider {
|
|
16
|
-
private authConfig?: AuthConfig;
|
|
17
|
-
private backendUrl: string;
|
|
18
|
-
private logger?: (message: string, level?: 'log' | 'error' | 'warn') => void;
|
|
19
|
-
|
|
20
|
-
constructor(authConfig?: AuthConfig, backendUrl?: string) {
|
|
21
|
-
this.authConfig = authConfig;
|
|
22
|
-
this.backendUrl = backendUrl || 'https://featureservice.testchimp.io';
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
setLogger(logger: (message: string, level?: 'log' | 'error' | 'warn') => void): void {
|
|
26
|
-
this.logger = logger;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
async callLLM(request: LLMRequest): Promise<LLMResponse> {
|
|
30
|
-
if (!this.authConfig) {
|
|
31
|
-
throw new Error('Authentication required for backend proxy LLM provider');
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
const headers = getAuthHeaders(this.authConfig);
|
|
35
|
-
|
|
36
|
-
// Convert camelCase to snake_case for backend API (proto format)
|
|
37
|
-
const backendRequest = {
|
|
38
|
-
model: request.model,
|
|
39
|
-
system_prompt: request.systemPrompt,
|
|
40
|
-
user_prompt: request.userPrompt,
|
|
41
|
-
image_url: request.imageUrl
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
const url = `${this.backendUrl}/localagent/call_llm`;
|
|
45
|
-
|
|
46
|
-
try {
|
|
47
|
-
const response = await axios.post(
|
|
48
|
-
url,
|
|
49
|
-
backendRequest,
|
|
50
|
-
{ headers, timeout: 300000 }
|
|
51
|
-
);
|
|
52
|
-
|
|
53
|
-
// Calculate token usage (heuristic: 4 chars = 1 token)
|
|
54
|
-
const inputText = `${request.systemPrompt || ''}\n${request.userPrompt || ''}`;
|
|
55
|
-
const inputTokens = Math.ceil(inputText.length / 4);
|
|
56
|
-
|
|
57
|
-
// Add image tokens if present (for vision models)
|
|
58
|
-
let imageTokens = 0;
|
|
59
|
-
if (request.imageUrl) {
|
|
60
|
-
imageTokens = this.estimateImageTokens(request.imageUrl);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
const outputTokens = Math.ceil((response.data.answer || '').length / 4);
|
|
64
|
-
|
|
65
|
-
return {
|
|
66
|
-
answer: response.data.answer,
|
|
67
|
-
usage: {
|
|
68
|
-
inputTokens: inputTokens + imageTokens,
|
|
69
|
-
outputTokens
|
|
70
|
-
}
|
|
71
|
-
};
|
|
72
|
-
} catch (error: any) {
|
|
73
|
-
this.logger?.(`LLM call failed: ${error}`, 'error');
|
|
74
|
-
throw error;
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Estimate image token cost based on dimensions
|
|
80
|
-
* For gpt-4.1-mini: patches × 1.62, capped at 1536
|
|
81
|
-
*/
|
|
82
|
-
private estimateImageTokens(imageDataUrl: string): number {
|
|
83
|
-
// For simplicity, estimate common screenshot sizes
|
|
84
|
-
// Viewport (1920x1080): ~1452 tokens (after multiplier and cap)
|
|
85
|
-
// Full page (1920x3000+): ~1536 tokens (capped)
|
|
86
|
-
|
|
87
|
-
// Conservative estimate: assume viewport screenshot
|
|
88
|
-
return 1500; // ~1452-1536 tokens for typical screenshot
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Local LLM Provider
|
|
3
|
-
* Calls LLM directly via callback (not via backend proxy)
|
|
4
|
-
* For future use by Script Service (Phase 2)
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { LLMProvider, LLMRequest, LLMResponse } from '../llm-provider';
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Local LLM provider that calls LLM directly via callback
|
|
11
|
-
* Allows Script Service to use its own OpenAI integration
|
|
12
|
-
*/
|
|
13
|
-
export class LocalLLMProvider implements LLMProvider {
|
|
14
|
-
private llmCallback: (request: LLMRequest) => Promise<string>;
|
|
15
|
-
private logger?: (message: string, level?: 'log' | 'error' | 'warn') => void;
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* @param llmCallback Function that calls LLM (provided by environment)
|
|
19
|
-
*/
|
|
20
|
-
constructor(llmCallback: (request: LLMRequest) => Promise<string>) {
|
|
21
|
-
this.llmCallback = llmCallback;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
setLogger(logger: (message: string, level?: 'log' | 'error' | 'warn') => void): void {
|
|
25
|
-
this.logger = logger;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
async callLLM(request: LLMRequest): Promise<LLMResponse> {
|
|
29
|
-
try {
|
|
30
|
-
const answer = await this.llmCallback(request);
|
|
31
|
-
return { answer };
|
|
32
|
-
} catch (error) {
|
|
33
|
-
this.logger?.(`Local LLM call failed: ${error}`, 'error');
|
|
34
|
-
throw error;
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
package/src/scenario-service.ts
DELETED
|
@@ -1,252 +0,0 @@
|
|
|
1
|
-
import { EventEmitter } from 'events';
|
|
2
|
-
import dotenv from 'dotenv';
|
|
3
|
-
import { ScenarioJob, ScenarioRunJob, ScenarioResponse, PlaywrightConfig } from './types';
|
|
4
|
-
import { ScenarioWorker } from './scenario-worker-class';
|
|
5
|
-
import { FileHandler, NoOpFileHandler } from './file-handler';
|
|
6
|
-
import { AuthConfig } from './auth-config';
|
|
7
|
-
import { CreditUsageService } from './credit-usage-service';
|
|
8
|
-
import { LLMProvider } from './llm-provider';
|
|
9
|
-
import { ProgressReporter } from './progress-reporter';
|
|
10
|
-
import { AgentConfig } from './orchestrator';
|
|
11
|
-
|
|
12
|
-
// Load environment variables
|
|
13
|
-
dotenv.config();
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Service for processing scenarios using LLM + Playwright
|
|
17
|
-
*/
|
|
18
|
-
export class ScenarioService extends EventEmitter {
|
|
19
|
-
private workers: ScenarioWorker[] = [];
|
|
20
|
-
private jobQueue: ScenarioRunJob[] = [];
|
|
21
|
-
private busyWorkers: Set<ScenarioWorker> = new Set();
|
|
22
|
-
private maxWorkers: number;
|
|
23
|
-
private fileHandler: FileHandler;
|
|
24
|
-
private authConfig: AuthConfig | null;
|
|
25
|
-
private backendUrl?: string;
|
|
26
|
-
private creditUsageService: CreditUsageService;
|
|
27
|
-
private logger?: (message: string, level?: 'log' | 'error' | 'warn') => void;
|
|
28
|
-
private llmProvider?: LLMProvider;
|
|
29
|
-
private progressReporter?: ProgressReporter;
|
|
30
|
-
private useOrchestrator: boolean;
|
|
31
|
-
private orchestratorConfig?: Partial<AgentConfig>;
|
|
32
|
-
private debugMode: boolean;
|
|
33
|
-
private outputChannel?: any; // VS Code OutputChannel type
|
|
34
|
-
|
|
35
|
-
constructor(
|
|
36
|
-
maxWorkers: number = 2,
|
|
37
|
-
fileHandler?: FileHandler,
|
|
38
|
-
llmProvider?: LLMProvider,
|
|
39
|
-
progressReporter?: ProgressReporter,
|
|
40
|
-
authConfig?: AuthConfig,
|
|
41
|
-
backendUrl?: string,
|
|
42
|
-
options?: {
|
|
43
|
-
useOrchestrator?: boolean;
|
|
44
|
-
orchestratorConfig?: Partial<AgentConfig>;
|
|
45
|
-
debugMode?: boolean;
|
|
46
|
-
}
|
|
47
|
-
) {
|
|
48
|
-
super();
|
|
49
|
-
this.maxWorkers = maxWorkers;
|
|
50
|
-
this.fileHandler = fileHandler || new NoOpFileHandler();
|
|
51
|
-
this.llmProvider = llmProvider;
|
|
52
|
-
this.progressReporter = progressReporter;
|
|
53
|
-
this.authConfig = authConfig || null;
|
|
54
|
-
this.backendUrl = backendUrl;
|
|
55
|
-
this.creditUsageService = new CreditUsageService(authConfig, backendUrl);
|
|
56
|
-
this.useOrchestrator = options?.useOrchestrator || false;
|
|
57
|
-
this.orchestratorConfig = options?.orchestratorConfig;
|
|
58
|
-
this.debugMode = options?.debugMode || false;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Set a logger callback for capturing execution logs
|
|
63
|
-
*/
|
|
64
|
-
setLogger(logger: (message: string, level?: 'log' | 'error' | 'warn') => void): void {
|
|
65
|
-
this.logger = logger;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Set output channel for worker logs (VS Code OutputChannel)
|
|
70
|
-
*/
|
|
71
|
-
setOutputChannel(outputChannel: any): void {
|
|
72
|
-
this.outputChannel = outputChannel;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* Log a message using the configured logger
|
|
77
|
-
*/
|
|
78
|
-
private log(message: string, level: 'log' | 'error' | 'warn' = 'log'): void {
|
|
79
|
-
if (this.logger) {
|
|
80
|
-
this.logger(message, level);
|
|
81
|
-
}
|
|
82
|
-
// No console fallback - logs are routed to consumer
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
private async initializeWorkers(): Promise<void> {
|
|
86
|
-
for (let i = 0; i < this.maxWorkers; i++) {
|
|
87
|
-
await this.createWorker();
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
private async createWorker(): Promise<void> {
|
|
92
|
-
// Pass providers and orchestrator options to worker
|
|
93
|
-
const worker = new ScenarioWorker(
|
|
94
|
-
this.fileHandler,
|
|
95
|
-
this.llmProvider,
|
|
96
|
-
this.progressReporter,
|
|
97
|
-
this.authConfig || undefined,
|
|
98
|
-
this.backendUrl,
|
|
99
|
-
{
|
|
100
|
-
useOrchestrator: this.useOrchestrator,
|
|
101
|
-
orchestratorConfig: this.orchestratorConfig,
|
|
102
|
-
debugMode: this.debugMode
|
|
103
|
-
},
|
|
104
|
-
this.outputChannel // Pass outputChannel for log routing
|
|
105
|
-
);
|
|
106
|
-
await worker.initialize();
|
|
107
|
-
|
|
108
|
-
// Forward log events from worker to service listeners
|
|
109
|
-
worker.on('log', (jobId: string, message: string) => {
|
|
110
|
-
this.emit('jobLog', jobId, message);
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
this.workers.push(worker);
|
|
114
|
-
// Internal initialization - no need to log worker details
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
async initialize(): Promise<void> {
|
|
118
|
-
// Wait for workers to be initialized
|
|
119
|
-
await this.initializeWorkers();
|
|
120
|
-
// Internal initialization - consumer doesn't need to see this
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
processScenario(
|
|
124
|
-
scenario: string,
|
|
125
|
-
testName?: string,
|
|
126
|
-
config?: PlaywrightConfig,
|
|
127
|
-
model?: string,
|
|
128
|
-
scenarioFileName?: string,
|
|
129
|
-
existingBrowser?: any,
|
|
130
|
-
existingContext?: any,
|
|
131
|
-
existingPage?: any
|
|
132
|
-
): string {
|
|
133
|
-
const jobId = `scenario_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
134
|
-
|
|
135
|
-
// Add job to queue
|
|
136
|
-
const job: ScenarioRunJob = {
|
|
137
|
-
id: jobId,
|
|
138
|
-
scenario,
|
|
139
|
-
testName,
|
|
140
|
-
playwrightConfig: config,
|
|
141
|
-
model,
|
|
142
|
-
scenarioFileName,
|
|
143
|
-
existingBrowser,
|
|
144
|
-
existingContext,
|
|
145
|
-
existingPage
|
|
146
|
-
};
|
|
147
|
-
|
|
148
|
-
this.jobQueue.push(job);
|
|
149
|
-
this.processNextJob();
|
|
150
|
-
|
|
151
|
-
return jobId; // Return job ID for tracking
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
private async processNextJob(): Promise<void> {
|
|
155
|
-
if (this.jobQueue.length === 0) {
|
|
156
|
-
return;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
this.log(`[ScenarioService] Processing next job. Queue length: ${this.jobQueue.length}, Workers: ${this.workers.length}, Busy workers: ${this.busyWorkers.size}`);
|
|
160
|
-
|
|
161
|
-
// Find available worker (proper load balancing)
|
|
162
|
-
const availableWorker = this.workers.find(worker => !this.busyWorkers.has(worker));
|
|
163
|
-
if (!availableWorker) {
|
|
164
|
-
this.log('[ScenarioService] No available workers, waiting...');
|
|
165
|
-
return; // All workers busy, wait for one to become available
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
const job = this.jobQueue.shift();
|
|
169
|
-
if (!job) {
|
|
170
|
-
return;
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
this.log(`[ScenarioService] Processing job ${job.id} with worker`);
|
|
174
|
-
|
|
175
|
-
// Mark worker as busy
|
|
176
|
-
this.busyWorkers.add(availableWorker);
|
|
177
|
-
|
|
178
|
-
try {
|
|
179
|
-
// Process job directly with worker
|
|
180
|
-
const result = await availableWorker.processScenarioJob(job);
|
|
181
|
-
this.log(`[ScenarioService] Job ${job.id} completed with result: ${JSON.stringify(result)}`);
|
|
182
|
-
this.handleJobResult(job.id, result);
|
|
183
|
-
} catch (error) {
|
|
184
|
-
this.log(`Error processing job with worker: ${error}`, 'error');
|
|
185
|
-
this.emit('jobError', job.id, error);
|
|
186
|
-
// Put job back in queue if it failed
|
|
187
|
-
this.jobQueue.unshift(job);
|
|
188
|
-
} finally {
|
|
189
|
-
// Mark worker as available again
|
|
190
|
-
this.busyWorkers.delete(availableWorker);
|
|
191
|
-
// Process next job
|
|
192
|
-
this.processNextJob();
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
private handleJobResult(jobId: string, result: ScenarioResponse): void {
|
|
197
|
-
// Report credit usage for successful script generation
|
|
198
|
-
if (result.success) {
|
|
199
|
-
this.creditUsageService.reportScriptGenerationCredit(jobId).catch(error => {
|
|
200
|
-
this.log(`Failed to report credit usage for script generation (job: ${jobId}): ${error}`, 'warn');
|
|
201
|
-
});
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
// Emit result event
|
|
205
|
-
this.emit('jobComplete', jobId, result);
|
|
206
|
-
|
|
207
|
-
// Mark worker as available and process next job
|
|
208
|
-
this.busyWorkers.clear(); // Simple approach - clear all busy workers
|
|
209
|
-
this.processNextJob();
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
private handleJobError(jobId: string, error: string): void {
|
|
213
|
-
// Emit error event
|
|
214
|
-
this.emit('jobError', jobId, new Error(error));
|
|
215
|
-
|
|
216
|
-
// Mark worker as available and process next job
|
|
217
|
-
this.busyWorkers.clear(); // Simple approach - clear all busy workers
|
|
218
|
-
this.processNextJob();
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
/**
|
|
222
|
-
* Execute exploration mode using orchestrator
|
|
223
|
-
* Requires orchestrator to be enabled via useOrchestrator option
|
|
224
|
-
*/
|
|
225
|
-
async executeExploration(page: any, explorationConfig: any, jobId: string): Promise<any> {
|
|
226
|
-
if (!this.useOrchestrator) {
|
|
227
|
-
throw new Error('Exploration mode requires orchestrator to be enabled');
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
// Get an available worker (or create one if needed)
|
|
231
|
-
let worker = this.workers.find(w => !this.busyWorkers.has(w));
|
|
232
|
-
if (!worker) {
|
|
233
|
-
await this.createWorker();
|
|
234
|
-
worker = this.workers[this.workers.length - 1];
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
// Execute exploration via worker's orchestrator
|
|
238
|
-
return worker.executeExploration(page, explorationConfig, jobId);
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
async shutdown(): Promise<void> {
|
|
242
|
-
this.log('Shutting down scenario service...');
|
|
243
|
-
|
|
244
|
-
// Cleanup all workers
|
|
245
|
-
const cleanupPromises = this.workers.map(worker => worker.cleanup());
|
|
246
|
-
await Promise.all(cleanupPromises);
|
|
247
|
-
|
|
248
|
-
this.workers = [];
|
|
249
|
-
this.busyWorkers.clear();
|
|
250
|
-
this.log('Scenario service shutdown complete');
|
|
251
|
-
}
|
|
252
|
-
}
|