testchimp-runner-core 0.0.21 → 0.0.23
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/VISION_DIAGNOSTICS_IMPROVEMENTS.md +336 -0
- package/dist/credit-usage-service.d.ts +9 -0
- package/dist/credit-usage-service.d.ts.map +1 -1
- package/dist/credit-usage-service.js +20 -5
- package/dist/credit-usage-service.js.map +1 -1
- package/dist/execution-service.d.ts +7 -2
- package/dist/execution-service.d.ts.map +1 -1
- package/dist/execution-service.js +91 -36
- package/dist/execution-service.js.map +1 -1
- package/dist/index.d.ts +30 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +91 -26
- package/dist/index.js.map +1 -1
- package/dist/llm-facade.d.ts +64 -8
- package/dist/llm-facade.d.ts.map +1 -1
- package/dist/llm-facade.js +361 -109
- package/dist/llm-facade.js.map +1 -1
- package/dist/llm-provider.d.ts +39 -0
- package/dist/llm-provider.d.ts.map +1 -0
- package/dist/llm-provider.js +7 -0
- package/dist/llm-provider.js.map +1 -0
- package/dist/model-constants.d.ts +21 -0
- package/dist/model-constants.d.ts.map +1 -0
- package/dist/model-constants.js +24 -0
- package/dist/model-constants.js.map +1 -0
- package/dist/orchestrator/index.d.ts +8 -0
- package/dist/orchestrator/index.d.ts.map +1 -0
- package/dist/orchestrator/index.js +23 -0
- package/dist/orchestrator/index.js.map +1 -0
- package/dist/orchestrator/orchestrator-agent.d.ts +66 -0
- package/dist/orchestrator/orchestrator-agent.d.ts.map +1 -0
- package/dist/orchestrator/orchestrator-agent.js +855 -0
- package/dist/orchestrator/orchestrator-agent.js.map +1 -0
- package/dist/orchestrator/tool-registry.d.ts +74 -0
- package/dist/orchestrator/tool-registry.d.ts.map +1 -0
- package/dist/orchestrator/tool-registry.js +131 -0
- package/dist/orchestrator/tool-registry.js.map +1 -0
- package/dist/orchestrator/tools/check-page-ready.d.ts +13 -0
- package/dist/orchestrator/tools/check-page-ready.d.ts.map +1 -0
- package/dist/orchestrator/tools/check-page-ready.js +72 -0
- package/dist/orchestrator/tools/check-page-ready.js.map +1 -0
- package/dist/orchestrator/tools/extract-data.d.ts +13 -0
- package/dist/orchestrator/tools/extract-data.d.ts.map +1 -0
- package/dist/orchestrator/tools/extract-data.js +84 -0
- package/dist/orchestrator/tools/extract-data.js.map +1 -0
- package/dist/orchestrator/tools/index.d.ts +10 -0
- package/dist/orchestrator/tools/index.d.ts.map +1 -0
- package/dist/orchestrator/tools/index.js +18 -0
- package/dist/orchestrator/tools/index.js.map +1 -0
- package/dist/orchestrator/tools/inspect-page.d.ts +13 -0
- package/dist/orchestrator/tools/inspect-page.d.ts.map +1 -0
- package/dist/orchestrator/tools/inspect-page.js +39 -0
- package/dist/orchestrator/tools/inspect-page.js.map +1 -0
- package/dist/orchestrator/tools/recall-history.d.ts +13 -0
- package/dist/orchestrator/tools/recall-history.d.ts.map +1 -0
- package/dist/orchestrator/tools/recall-history.js +64 -0
- package/dist/orchestrator/tools/recall-history.js.map +1 -0
- package/dist/orchestrator/tools/take-screenshot.d.ts +15 -0
- package/dist/orchestrator/tools/take-screenshot.d.ts.map +1 -0
- package/dist/orchestrator/tools/take-screenshot.js +112 -0
- package/dist/orchestrator/tools/take-screenshot.js.map +1 -0
- package/dist/orchestrator/types.d.ts +133 -0
- package/dist/orchestrator/types.d.ts.map +1 -0
- package/dist/orchestrator/types.js +28 -0
- package/dist/orchestrator/types.js.map +1 -0
- package/dist/playwright-mcp-service.d.ts +9 -0
- package/dist/playwright-mcp-service.d.ts.map +1 -1
- package/dist/playwright-mcp-service.js +20 -5
- package/dist/playwright-mcp-service.js.map +1 -1
- package/dist/progress-reporter.d.ts +97 -0
- package/dist/progress-reporter.d.ts.map +1 -0
- package/dist/progress-reporter.js +18 -0
- package/dist/progress-reporter.js.map +1 -0
- package/dist/prompts.d.ts +24 -0
- package/dist/prompts.d.ts.map +1 -1
- package/dist/prompts.js +593 -68
- package/dist/prompts.js.map +1 -1
- package/dist/providers/backend-proxy-llm-provider.d.ts +25 -0
- package/dist/providers/backend-proxy-llm-provider.d.ts.map +1 -0
- package/dist/providers/backend-proxy-llm-provider.js +76 -0
- package/dist/providers/backend-proxy-llm-provider.js.map +1 -0
- package/dist/providers/local-llm-provider.d.ts +21 -0
- package/dist/providers/local-llm-provider.d.ts.map +1 -0
- package/dist/providers/local-llm-provider.js +35 -0
- package/dist/providers/local-llm-provider.js.map +1 -0
- package/dist/scenario-service.d.ts +27 -1
- package/dist/scenario-service.d.ts.map +1 -1
- package/dist/scenario-service.js +48 -12
- package/dist/scenario-service.js.map +1 -1
- package/dist/scenario-worker-class.d.ts +39 -2
- package/dist/scenario-worker-class.d.ts.map +1 -1
- package/dist/scenario-worker-class.js +614 -86
- package/dist/scenario-worker-class.js.map +1 -1
- package/dist/script-utils.d.ts +2 -0
- package/dist/script-utils.d.ts.map +1 -1
- package/dist/script-utils.js +44 -4
- package/dist/script-utils.js.map +1 -1
- package/dist/types.d.ts +11 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/utils/browser-utils.d.ts +20 -1
- package/dist/utils/browser-utils.d.ts.map +1 -1
- package/dist/utils/browser-utils.js +102 -51
- package/dist/utils/browser-utils.js.map +1 -1
- package/dist/utils/page-info-utils.d.ts +23 -4
- package/dist/utils/page-info-utils.d.ts.map +1 -1
- package/dist/utils/page-info-utils.js +174 -43
- package/dist/utils/page-info-utils.js.map +1 -1
- package/package.json +1 -2
- package/plandocs/HUMAN_LIKE_IMPROVEMENTS.md +642 -0
- package/plandocs/MULTI_AGENT_ARCHITECTURE_REVIEW.md +844 -0
- package/plandocs/ORCHESTRATOR_MVP_SUMMARY.md +539 -0
- package/plandocs/PHASE1_ABSTRACTION_COMPLETE.md +241 -0
- package/plandocs/PHASE1_FINAL_STATUS.md +210 -0
- package/plandocs/PLANNING_SESSION_SUMMARY.md +372 -0
- package/plandocs/SCRIPT_CLEANUP_FEATURE.md +201 -0
- package/plandocs/SCRIPT_GENERATION_ARCHITECTURE.md +364 -0
- package/plandocs/SELECTOR_IMPROVEMENTS.md +139 -0
- package/src/credit-usage-service.ts +23 -5
- package/src/execution-service.ts +152 -42
- package/src/index.ts +169 -26
- package/src/llm-facade.ts +500 -126
- package/src/llm-provider.ts +43 -0
- package/src/model-constants.ts +23 -0
- package/src/orchestrator/index.ts +33 -0
- package/src/orchestrator/orchestrator-agent.ts +1037 -0
- package/src/orchestrator/tool-registry.ts +182 -0
- package/src/orchestrator/tools/check-page-ready.ts +75 -0
- package/src/orchestrator/tools/extract-data.ts +92 -0
- package/src/orchestrator/tools/index.ts +11 -0
- package/src/orchestrator/tools/inspect-page.ts +42 -0
- package/src/orchestrator/tools/recall-history.ts +72 -0
- package/src/orchestrator/tools/take-screenshot.ts +128 -0
- package/src/orchestrator/types.ts +200 -0
- package/src/playwright-mcp-service.ts +23 -5
- package/src/progress-reporter.ts +109 -0
- package/src/prompts.ts +606 -69
- package/src/providers/backend-proxy-llm-provider.ts +91 -0
- package/src/providers/local-llm-provider.ts +38 -0
- package/src/scenario-service.ts +83 -13
- package/src/scenario-worker-class.ts +740 -72
- package/src/script-utils.ts +50 -5
- package/src/types.ts +13 -1
- package/src/utils/browser-utils.ts +123 -51
- package/src/utils/page-info-utils.ts +210 -53
- package/testchimp-runner-core-0.0.22.tgz +0 -0
package/src/execution-service.ts
CHANGED
|
@@ -12,11 +12,15 @@ import {
|
|
|
12
12
|
} from './types';
|
|
13
13
|
import { RepairSuggestionResponse, RepairConfidenceResponse } from './llm-facade';
|
|
14
14
|
import { getEnhancedPageInfo, PageInfo } from './utils/page-info-utils';
|
|
15
|
-
import { initializeBrowser } from './utils/browser-utils';
|
|
15
|
+
import { initializeBrowser, captureOptimizedScreenshot } from './utils/browser-utils';
|
|
16
16
|
import { LLMFacade } from './llm-facade';
|
|
17
17
|
import { AuthConfig } from './auth-config';
|
|
18
18
|
import { addTestChimpComment } from './script-utils';
|
|
19
19
|
import { CreditUsageService } from './credit-usage-service';
|
|
20
|
+
import { DEFAULT_MODEL, VISION_MODEL } from './model-constants';
|
|
21
|
+
import { LLMProvider } from './llm-provider';
|
|
22
|
+
import { ProgressReporter } from './progress-reporter';
|
|
23
|
+
import { BackendProxyLLMProvider } from './providers/backend-proxy-llm-provider';
|
|
20
24
|
|
|
21
25
|
/**
|
|
22
26
|
* Service for orchestrating Playwright script execution
|
|
@@ -24,14 +28,27 @@ import { CreditUsageService } from './credit-usage-service';
|
|
|
24
28
|
export class ExecutionService {
|
|
25
29
|
private playwrightService: PlaywrightService;
|
|
26
30
|
private llmFacade: LLMFacade;
|
|
31
|
+
private llmProvider: LLMProvider;
|
|
32
|
+
private progressReporter?: ProgressReporter;
|
|
27
33
|
private creditUsageService: CreditUsageService;
|
|
28
34
|
private maxConcurrentExecutions: number;
|
|
29
35
|
private activeExecutions: Set<Promise<any>> = new Set();
|
|
30
36
|
private logger?: (message: string, level?: 'log' | 'error' | 'warn') => void;
|
|
31
37
|
|
|
32
|
-
constructor(
|
|
38
|
+
constructor(
|
|
39
|
+
authConfig?: AuthConfig,
|
|
40
|
+
backendUrl?: string,
|
|
41
|
+
maxConcurrentExecutions: number = 10,
|
|
42
|
+
llmProvider?: LLMProvider,
|
|
43
|
+
progressReporter?: ProgressReporter
|
|
44
|
+
) {
|
|
33
45
|
this.playwrightService = new PlaywrightService();
|
|
34
|
-
|
|
46
|
+
|
|
47
|
+
// Use provided LLM provider or default to backend proxy (backward compatible)
|
|
48
|
+
this.llmProvider = llmProvider || new BackendProxyLLMProvider(authConfig, backendUrl);
|
|
49
|
+
this.llmFacade = new LLMFacade(this.llmProvider);
|
|
50
|
+
|
|
51
|
+
this.progressReporter = progressReporter;
|
|
35
52
|
this.creditUsageService = new CreditUsageService(authConfig, backendUrl);
|
|
36
53
|
this.maxConcurrentExecutions = maxConcurrentExecutions;
|
|
37
54
|
}
|
|
@@ -44,20 +61,13 @@ export class ExecutionService {
|
|
|
44
61
|
}
|
|
45
62
|
|
|
46
63
|
/**
|
|
47
|
-
* Log a message using the configured logger
|
|
64
|
+
* Log a message using the configured logger
|
|
48
65
|
*/
|
|
49
66
|
private log(message: string, level: 'log' | 'error' | 'warn' = 'log'): void {
|
|
50
67
|
if (this.logger) {
|
|
51
68
|
this.logger(message, level);
|
|
52
|
-
} else {
|
|
53
|
-
if (level === 'error') {
|
|
54
|
-
console.error(message);
|
|
55
|
-
} else if (level === 'warn') {
|
|
56
|
-
console.warn(message);
|
|
57
|
-
} else {
|
|
58
|
-
console.log(message);
|
|
59
|
-
}
|
|
60
69
|
}
|
|
70
|
+
// No console fallback - logs are routed to consumer
|
|
61
71
|
}
|
|
62
72
|
|
|
63
73
|
/**
|
|
@@ -69,9 +79,12 @@ export class ExecutionService {
|
|
|
69
79
|
|
|
70
80
|
/**
|
|
71
81
|
* Set authentication configuration for the service
|
|
82
|
+
* Note: This recreates the LLM provider with new auth config
|
|
72
83
|
*/
|
|
73
84
|
setAuthConfig(authConfig: AuthConfig): void {
|
|
74
|
-
|
|
85
|
+
// Recreate LLM provider with new auth config
|
|
86
|
+
this.llmProvider = new BackendProxyLLMProvider(authConfig, undefined);
|
|
87
|
+
this.llmFacade = new LLMFacade(this.llmProvider);
|
|
75
88
|
this.creditUsageService.setAuthConfig(authConfig);
|
|
76
89
|
}
|
|
77
90
|
|
|
@@ -102,7 +115,7 @@ export class ExecutionService {
|
|
|
102
115
|
*/
|
|
103
116
|
private async executeScriptInternal(request: ScriptExecutionRequest): Promise<ScriptExecutionResponse> {
|
|
104
117
|
const startTime = Date.now();
|
|
105
|
-
const model = request.model ||
|
|
118
|
+
const model = request.model || DEFAULT_MODEL;
|
|
106
119
|
|
|
107
120
|
try {
|
|
108
121
|
if (request.mode === ExecutionMode.RUN_EXACTLY) {
|
|
@@ -327,7 +340,7 @@ export class ExecutionService {
|
|
|
327
340
|
|
|
328
341
|
// Report credit usage for successful AI repair
|
|
329
342
|
this.creditUsageService.reportAIRepairCredit().catch(error => {
|
|
330
|
-
|
|
343
|
+
this.log(`Failed to report credit usage for AI repair: ${error}`, 'warn');
|
|
331
344
|
});
|
|
332
345
|
|
|
333
346
|
await repairBrowser.close();
|
|
@@ -488,6 +501,7 @@ export class ExecutionService {
|
|
|
488
501
|
let repairSuccess = false;
|
|
489
502
|
const originalDescription = step.description;
|
|
490
503
|
const originalCode = step.code;
|
|
504
|
+
let usedVisionMode = false;
|
|
491
505
|
|
|
492
506
|
for (let attempt = 1; attempt <= maxTries; attempt++) {
|
|
493
507
|
this.log(`Step ${i + 1} repair attempt ${attempt}/${maxTries}`);
|
|
@@ -501,16 +515,109 @@ export class ExecutionService {
|
|
|
501
515
|
// Build recent repairs context for LLM
|
|
502
516
|
const recentRepairsContext = this.buildRecentRepairsContext(recentRepairs);
|
|
503
517
|
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
518
|
+
let repairSuggestion;
|
|
519
|
+
|
|
520
|
+
// VISION-BASED FALLBACK: After 2 regular repair attempts, consider vision diagnostics on final attempt
|
|
521
|
+
if (attempt === maxTries - 1 && repairHistory.length >= 2 && !usedVisionMode) {
|
|
522
|
+
// Ask LLM if screenshot would help for repair diagnostics
|
|
523
|
+
this.log(` 🤔 After ${repairHistory.length} failed repairs: Asking LLM if screenshot would help (last resort)...`);
|
|
524
|
+
|
|
525
|
+
const screenshotNeed = await this.llmFacade.assessScreenshotNeed(
|
|
526
|
+
step.description,
|
|
527
|
+
step.error || 'Unknown error',
|
|
528
|
+
repairHistory.length + 1,
|
|
529
|
+
pageInfo,
|
|
530
|
+
model
|
|
531
|
+
);
|
|
532
|
+
|
|
533
|
+
this.log(` 💭 LLM assessment: ${screenshotNeed.needsScreenshot ? 'SCREENSHOT NEEDED' : 'NO SCREENSHOT'} - ${screenshotNeed.reason}`);
|
|
534
|
+
|
|
535
|
+
if (screenshotNeed.needsScreenshot) {
|
|
536
|
+
// Two-step supervisor pattern for vision-based repair:
|
|
537
|
+
// 1. Supervisor analyzes screenshot and provides diagnostic insights
|
|
538
|
+
// 2. Get repair suggestion with enhanced context from vision analysis
|
|
539
|
+
|
|
540
|
+
this.log(` 📸 Taking screenshot for supervisor analysis...`);
|
|
541
|
+
|
|
542
|
+
// Capture optimized screenshot using utility method
|
|
543
|
+
const imageDataUrl = await captureOptimizedScreenshot(
|
|
544
|
+
page,
|
|
545
|
+
{ timeout: 10000 }, // Uses default quality 60
|
|
546
|
+
(msg) => this.log(msg)
|
|
547
|
+
);
|
|
548
|
+
|
|
549
|
+
this.log(` 👔 STEP 1: Supervisor analyzing screenshot (${VISION_MODEL})...`);
|
|
550
|
+
const supervisorDiagnostics = await this.llmFacade.getVisionDiagnostics(
|
|
551
|
+
step.description,
|
|
552
|
+
pageInfo,
|
|
553
|
+
[], // No previous steps context for repair
|
|
554
|
+
step.error,
|
|
555
|
+
imageDataUrl,
|
|
556
|
+
VISION_MODEL
|
|
557
|
+
);
|
|
558
|
+
|
|
559
|
+
// DEBUG: Log vision diagnostics
|
|
560
|
+
this.log(` 📸 Visual insights: ${supervisorDiagnostics.visualAnalysis}`);
|
|
561
|
+
this.log(` 🔍 Root cause: ${supervisorDiagnostics.rootCause}`);
|
|
562
|
+
this.log(` 💡 Recommended approach: ${supervisorDiagnostics.recommendedApproach}`);
|
|
563
|
+
if (supervisorDiagnostics.elementsFound.length > 0) {
|
|
564
|
+
this.log(` ✅ Elements found: ${supervisorDiagnostics.elementsFound.join(', ')}`);
|
|
565
|
+
}
|
|
566
|
+
if (supervisorDiagnostics.elementsNotFound.length > 0) {
|
|
567
|
+
this.log(` ❌ Elements not found: ${supervisorDiagnostics.elementsNotFound.join(', ')}`);
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
// Get repair suggestion with vision-enhanced context
|
|
571
|
+
this.log(` 🔨 STEP 2: Getting repair suggestion with vision insights...`);
|
|
572
|
+
const visionEnhancedFailureHistory = `${failureHistory}
|
|
573
|
+
|
|
574
|
+
VISION-BASED DIAGNOSTIC INSIGHTS:
|
|
575
|
+
Visual Analysis: ${supervisorDiagnostics.visualAnalysis}
|
|
576
|
+
Root Cause: ${supervisorDiagnostics.rootCause}
|
|
577
|
+
Recommended Approach: ${supervisorDiagnostics.recommendedApproach}
|
|
578
|
+
Elements Found: ${supervisorDiagnostics.elementsFound.join(', ') || 'None'}
|
|
579
|
+
Elements Not Found: ${supervisorDiagnostics.elementsNotFound.join(', ') || 'None'}
|
|
580
|
+
|
|
581
|
+
Use these vision insights to inform your repair strategy.`;
|
|
582
|
+
|
|
583
|
+
repairSuggestion = await this.llmFacade.getRepairSuggestion(
|
|
584
|
+
step.description,
|
|
585
|
+
step.code,
|
|
586
|
+
step.error || 'Unknown error',
|
|
587
|
+
pageInfo,
|
|
588
|
+
visionEnhancedFailureHistory,
|
|
589
|
+
recentRepairsContext,
|
|
590
|
+
model
|
|
591
|
+
);
|
|
592
|
+
|
|
593
|
+
usedVisionMode = true;
|
|
594
|
+
} else {
|
|
595
|
+
// Regular repair without vision
|
|
596
|
+
if (screenshotNeed.alternativeApproach) {
|
|
597
|
+
this.log(` 💡 Alternative approach: ${screenshotNeed.alternativeApproach}`);
|
|
598
|
+
}
|
|
599
|
+
repairSuggestion = await this.llmFacade.getRepairSuggestion(
|
|
600
|
+
step.description,
|
|
601
|
+
step.code,
|
|
602
|
+
step.error || 'Unknown error',
|
|
603
|
+
pageInfo,
|
|
604
|
+
failureHistory,
|
|
605
|
+
recentRepairsContext,
|
|
606
|
+
model
|
|
607
|
+
);
|
|
608
|
+
}
|
|
609
|
+
} else {
|
|
610
|
+
// Regular repair attempt (first 2 attempts or already used vision)
|
|
611
|
+
repairSuggestion = await this.llmFacade.getRepairSuggestion(
|
|
612
|
+
step.description,
|
|
613
|
+
step.code,
|
|
614
|
+
step.error || 'Unknown error',
|
|
615
|
+
pageInfo,
|
|
616
|
+
failureHistory,
|
|
617
|
+
recentRepairsContext,
|
|
618
|
+
model
|
|
619
|
+
);
|
|
620
|
+
}
|
|
514
621
|
|
|
515
622
|
if (!repairSuggestion.shouldContinue) {
|
|
516
623
|
this.log(`AI decided to stop repair at attempt ${attempt}: ${repairSuggestion.reason}`);
|
|
@@ -562,7 +669,7 @@ export class ExecutionService {
|
|
|
562
669
|
repairAction.operation === StepOperation.REMOVE ?
|
|
563
670
|
`REMOVE: step at index ${repairAction.stepIndex}` :
|
|
564
671
|
repairAction.operation;
|
|
565
|
-
this.log(`Step ${i + 1} repair action ${commandInfo} executed successfully on attempt ${attempt}`);
|
|
672
|
+
this.log(`Step ${i + 1} repair action ${commandInfo} executed successfully on attempt ${attempt}${usedVisionMode ? ' (vision-aided)' : ''}`);
|
|
566
673
|
|
|
567
674
|
// Update execution context based on the repair action
|
|
568
675
|
if (repairAction.operation === StepOperation.MODIFY && repairAction.newStep) {
|
|
@@ -661,8 +768,9 @@ export class ExecutionService {
|
|
|
661
768
|
}
|
|
662
769
|
|
|
663
770
|
private async executeStepCode(code: string, page: any): Promise<void> {
|
|
664
|
-
//
|
|
665
|
-
|
|
771
|
+
// Keep default timeout (5 seconds) for fast feedback on wrong selectors
|
|
772
|
+
// Navigation operations should use explicit longer timeouts in generated code
|
|
773
|
+
page.setDefaultTimeout(5000);
|
|
666
774
|
|
|
667
775
|
try {
|
|
668
776
|
// Clean and validate the code before execution
|
|
@@ -680,8 +788,8 @@ export class ExecutionService {
|
|
|
680
788
|
const result = executeCode(page, expect);
|
|
681
789
|
await result;
|
|
682
790
|
} finally {
|
|
683
|
-
//
|
|
684
|
-
page.setDefaultTimeout(
|
|
791
|
+
// Ensure timeout remains consistent
|
|
792
|
+
page.setDefaultTimeout(5000);
|
|
685
793
|
}
|
|
686
794
|
}
|
|
687
795
|
|
|
@@ -709,8 +817,8 @@ export class ExecutionService {
|
|
|
709
817
|
executionContext: string,
|
|
710
818
|
contextVariables: Map<string, any>
|
|
711
819
|
): Promise<void> {
|
|
712
|
-
//
|
|
713
|
-
page.setDefaultTimeout(5000);
|
|
820
|
+
// Keep default timeout (5 seconds) for fast feedback
|
|
821
|
+
page.setDefaultTimeout(5000);
|
|
714
822
|
|
|
715
823
|
try {
|
|
716
824
|
// Execute only the current step code, but make context variables available
|
|
@@ -779,10 +887,9 @@ export class ExecutionService {
|
|
|
779
887
|
return {
|
|
780
888
|
url: page.url(),
|
|
781
889
|
title: 'Unknown',
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
pageStructure: 'Unable to extract'
|
|
890
|
+
ariaSnapshot: null,
|
|
891
|
+
interactiveElements: [],
|
|
892
|
+
formattedElements: 'Unable to extract'
|
|
786
893
|
};
|
|
787
894
|
}
|
|
788
895
|
}
|
|
@@ -1004,11 +1111,14 @@ export class ExecutionService {
|
|
|
1004
1111
|
];
|
|
1005
1112
|
|
|
1006
1113
|
steps.forEach((step, index) => {
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1114
|
+
// Only add step if it has code to execute
|
|
1115
|
+
if (step.code && step.code.trim().length > 0) {
|
|
1116
|
+
scriptLines.push(` // ${step.description}`);
|
|
1117
|
+
const codeLines = step.code.split('\n');
|
|
1118
|
+
codeLines.forEach(line => {
|
|
1119
|
+
scriptLines.push(` ${line}`);
|
|
1120
|
+
});
|
|
1121
|
+
}
|
|
1012
1122
|
});
|
|
1013
1123
|
|
|
1014
1124
|
scriptLines.push('});');
|
|
@@ -1023,7 +1133,7 @@ export class ExecutionService {
|
|
|
1023
1133
|
* Initialize browser with configuration (delegates to utility function)
|
|
1024
1134
|
*/
|
|
1025
1135
|
private async initializeBrowser(playwrightConfig?: string, headless?: boolean, playwrightConfigFilePath?: string): Promise<{ browser: any; context: any; page: any }> {
|
|
1026
|
-
return initializeBrowser(playwrightConfig, headless, playwrightConfigFilePath);
|
|
1136
|
+
return initializeBrowser(playwrightConfig, headless, playwrightConfigFilePath, this.logger);
|
|
1027
1137
|
}
|
|
1028
1138
|
|
|
1029
1139
|
/**
|
package/src/index.ts
CHANGED
|
@@ -18,8 +18,45 @@ export { ExecutionService, ScenarioService, ScenarioWorker, PlaywrightMCPService
|
|
|
18
18
|
import { FileHandler, LocalFileHandler, CIFileHandler, NoOpFileHandler } from './file-handler';
|
|
19
19
|
export { FileHandler, LocalFileHandler, CIFileHandler, NoOpFileHandler };
|
|
20
20
|
|
|
21
|
+
// LLM Provider interfaces
|
|
22
|
+
import { LLMProvider, LLMRequest, LLMResponse } from './llm-provider';
|
|
23
|
+
import { ProgressReporter, StepProgress, JobProgress, StepExecutionStatus } from './progress-reporter';
|
|
24
|
+
import { BackendProxyLLMProvider } from './providers/backend-proxy-llm-provider';
|
|
25
|
+
import { LocalLLMProvider } from './providers/local-llm-provider';
|
|
26
|
+
|
|
27
|
+
export { LLMProvider, LLMRequest, LLMResponse };
|
|
28
|
+
export { ProgressReporter, StepProgress, JobProgress, StepExecutionStatus };
|
|
29
|
+
export { BackendProxyLLMProvider, LocalLLMProvider };
|
|
30
|
+
|
|
31
|
+
// Orchestrator (tool-using agent)
|
|
32
|
+
import type { AgentConfig } from './orchestrator';
|
|
33
|
+
export {
|
|
34
|
+
OrchestratorAgent,
|
|
35
|
+
ToolRegistry,
|
|
36
|
+
Tool,
|
|
37
|
+
ToolParameter,
|
|
38
|
+
ToolExecutionContext,
|
|
39
|
+
AgentConfig,
|
|
40
|
+
AgentContext,
|
|
41
|
+
AgentDecision,
|
|
42
|
+
JourneyMemory,
|
|
43
|
+
MemoryStep,
|
|
44
|
+
OrchestratorStepResult,
|
|
45
|
+
SelfReflection,
|
|
46
|
+
ToolCall,
|
|
47
|
+
ToolResult,
|
|
48
|
+
DEFAULT_AGENT_CONFIG,
|
|
49
|
+
// Tools (information-gathering only)
|
|
50
|
+
TakeScreenshotTool,
|
|
51
|
+
RecallHistoryTool,
|
|
52
|
+
InspectPageTool,
|
|
53
|
+
CheckPageReadyTool,
|
|
54
|
+
ExtractDataTool
|
|
55
|
+
} from './orchestrator';
|
|
56
|
+
|
|
21
57
|
// Types
|
|
22
58
|
export * from './types';
|
|
59
|
+
export { PageInfo, InteractiveElement } from './utils/page-info-utils';
|
|
23
60
|
|
|
24
61
|
// Authentication
|
|
25
62
|
export * from './auth-config';
|
|
@@ -35,39 +72,96 @@ export class TestChimpService {
|
|
|
35
72
|
private executionService: ExecutionService;
|
|
36
73
|
public scenarioService: ScenarioService; // Make public for event listening
|
|
37
74
|
private playwrightService: PlaywrightMCPService;
|
|
38
|
-
private
|
|
75
|
+
private llmProvider: LLMProvider;
|
|
76
|
+
private progressReporter?: ProgressReporter;
|
|
39
77
|
private creditUsageService: CreditUsageService;
|
|
40
78
|
private fileHandler: FileHandler;
|
|
41
79
|
private authConfig: AuthConfig | null;
|
|
42
80
|
private backendUrl: string;
|
|
81
|
+
private logger?: (message: string, level?: 'log' | 'error' | 'warn') => void;
|
|
82
|
+
private orchestratorOptions?: { useOrchestrator?: boolean; orchestratorConfig?: Partial<AgentConfig>; debugMode?: boolean };
|
|
43
83
|
|
|
44
|
-
constructor(
|
|
84
|
+
constructor(
|
|
85
|
+
fileHandler?: FileHandler,
|
|
86
|
+
authConfig?: AuthConfig,
|
|
87
|
+
backendUrl?: string,
|
|
88
|
+
maxWorkers?: number,
|
|
89
|
+
llmProvider?: LLMProvider,
|
|
90
|
+
progressReporter?: ProgressReporter,
|
|
91
|
+
orchestratorOptions?: { useOrchestrator?: boolean; orchestratorConfig?: Partial<AgentConfig>; debugMode?: boolean }
|
|
92
|
+
) {
|
|
45
93
|
this.fileHandler = fileHandler || new NoOpFileHandler();
|
|
46
94
|
this.authConfig = authConfig || null;
|
|
47
95
|
this.backendUrl = backendUrl || 'https://featureservice.testchimp.io'; // Default to production
|
|
96
|
+
this.progressReporter = progressReporter;
|
|
97
|
+
this.orchestratorOptions = orchestratorOptions;
|
|
98
|
+
|
|
99
|
+
// Use provided LLM provider or default to backend proxy (backward compatible)
|
|
100
|
+
this.llmProvider = llmProvider || new BackendProxyLLMProvider(authConfig, backendUrl);
|
|
101
|
+
|
|
48
102
|
this.playwrightService = new PlaywrightMCPService();
|
|
49
|
-
this.llmFacade = new LLMFacade(this.authConfig || undefined, this.backendUrl);
|
|
50
103
|
this.creditUsageService = new CreditUsageService(this.authConfig || undefined, this.backendUrl);
|
|
51
|
-
|
|
52
|
-
//
|
|
53
|
-
this.executionService
|
|
54
|
-
|
|
104
|
+
|
|
105
|
+
// Create services with providers
|
|
106
|
+
this.executionService = new ExecutionService(
|
|
107
|
+
this.authConfig || undefined,
|
|
108
|
+
this.backendUrl,
|
|
109
|
+
maxWorkers || 10,
|
|
110
|
+
this.llmProvider, // Pass the LLM provider
|
|
111
|
+
this.progressReporter // Pass the progress reporter
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
this.scenarioService = new ScenarioService(
|
|
115
|
+
maxWorkers || 2,
|
|
116
|
+
this.fileHandler,
|
|
117
|
+
this.llmProvider,
|
|
118
|
+
this.progressReporter,
|
|
119
|
+
this.authConfig || undefined,
|
|
120
|
+
this.backendUrl,
|
|
121
|
+
this.orchestratorOptions // Pass orchestrator options
|
|
122
|
+
);
|
|
55
123
|
}
|
|
56
124
|
|
|
57
125
|
/**
|
|
58
126
|
* Set authentication configuration for the service
|
|
127
|
+
* Recreates LLM provider and services with new auth config
|
|
59
128
|
*/
|
|
60
129
|
async setAuthConfig(authConfig: AuthConfig): Promise<void> {
|
|
61
130
|
this.authConfig = authConfig;
|
|
62
|
-
this.llmFacade.setAuthConfig(authConfig);
|
|
63
131
|
this.creditUsageService.setAuthConfig(authConfig);
|
|
64
132
|
|
|
65
|
-
// Recreate
|
|
66
|
-
this.
|
|
67
|
-
this.scenarioService = new ScenarioService(2, this.fileHandler, this.authConfig, this.backendUrl);
|
|
133
|
+
// Recreate LLM provider with new auth config
|
|
134
|
+
this.llmProvider = new BackendProxyLLMProvider(authConfig, this.backendUrl);
|
|
68
135
|
|
|
69
|
-
// Set
|
|
70
|
-
this.
|
|
136
|
+
// Set logger on new provider if we have one
|
|
137
|
+
if (this.logger) {
|
|
138
|
+
this.llmProvider.setLogger?.(this.logger);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Recreate services with new provider AND pass llmProvider and progressReporter
|
|
142
|
+
this.executionService = new ExecutionService(
|
|
143
|
+
this.authConfig,
|
|
144
|
+
this.backendUrl,
|
|
145
|
+
10,
|
|
146
|
+
this.llmProvider, // Pass the LLM provider
|
|
147
|
+
this.progressReporter // Pass the progress reporter
|
|
148
|
+
);
|
|
149
|
+
|
|
150
|
+
this.scenarioService = new ScenarioService(
|
|
151
|
+
2,
|
|
152
|
+
this.fileHandler,
|
|
153
|
+
this.llmProvider,
|
|
154
|
+
this.progressReporter,
|
|
155
|
+
this.authConfig,
|
|
156
|
+
this.backendUrl,
|
|
157
|
+
this.orchestratorOptions // Pass orchestrator options
|
|
158
|
+
);
|
|
159
|
+
|
|
160
|
+
// Set logger on recreated services if we have one
|
|
161
|
+
if (this.logger) {
|
|
162
|
+
this.executionService.setLogger(this.logger);
|
|
163
|
+
this.scenarioService.setLogger(this.logger);
|
|
164
|
+
}
|
|
71
165
|
|
|
72
166
|
// Reinitialize the services
|
|
73
167
|
await this.executionService.initialize();
|
|
@@ -76,18 +170,43 @@ export class TestChimpService {
|
|
|
76
170
|
|
|
77
171
|
/**
|
|
78
172
|
* Set backend URL for the service
|
|
173
|
+
* Recreates LLM provider and services with new backend URL
|
|
79
174
|
*/
|
|
80
175
|
setBackendUrl(backendUrl: string): void {
|
|
81
176
|
this.backendUrl = backendUrl;
|
|
82
|
-
|
|
83
|
-
|
|
177
|
+
|
|
178
|
+
// Recreate LLM provider with new backend URL
|
|
179
|
+
this.llmProvider = new BackendProxyLLMProvider(this.authConfig || undefined, backendUrl);
|
|
180
|
+
|
|
181
|
+
// Set logger on new provider if we have one
|
|
182
|
+
if (this.logger) {
|
|
183
|
+
this.llmProvider.setLogger?.(this.logger);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Recreate services with new provider
|
|
84
187
|
this.creditUsageService = new CreditUsageService(this.authConfig || undefined, this.backendUrl);
|
|
85
|
-
this.executionService = new ExecutionService(
|
|
86
|
-
|
|
188
|
+
this.executionService = new ExecutionService(
|
|
189
|
+
this.authConfig || undefined,
|
|
190
|
+
this.backendUrl,
|
|
191
|
+
10,
|
|
192
|
+
this.llmProvider, // Pass the LLM provider
|
|
193
|
+
this.progressReporter // Pass the progress reporter
|
|
194
|
+
);
|
|
195
|
+
|
|
196
|
+
this.scenarioService = new ScenarioService(
|
|
197
|
+
2,
|
|
198
|
+
this.fileHandler,
|
|
199
|
+
this.llmProvider,
|
|
200
|
+
this.progressReporter,
|
|
201
|
+
this.authConfig || undefined,
|
|
202
|
+
this.backendUrl,
|
|
203
|
+
this.orchestratorOptions // Pass orchestrator options
|
|
204
|
+
);
|
|
87
205
|
|
|
88
|
-
// Set
|
|
89
|
-
if (this.
|
|
90
|
-
this.executionService.
|
|
206
|
+
// Set logger on recreated services if we have one
|
|
207
|
+
if (this.logger) {
|
|
208
|
+
this.executionService.setLogger(this.logger);
|
|
209
|
+
this.scenarioService.setLogger(this.logger);
|
|
91
210
|
}
|
|
92
211
|
}
|
|
93
212
|
|
|
@@ -95,7 +214,31 @@ export class TestChimpService {
|
|
|
95
214
|
* Set logger callback for capturing execution logs
|
|
96
215
|
*/
|
|
97
216
|
setLogger(logger: (message: string, level?: 'log' | 'error' | 'warn') => void): void {
|
|
217
|
+
this.logger = logger;
|
|
98
218
|
this.executionService.setLogger(logger);
|
|
219
|
+
this.scenarioService.setLogger(logger);
|
|
220
|
+
this.llmProvider.setLogger?.(logger);
|
|
221
|
+
this.creditUsageService.setLogger(logger);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Set output channel for worker logs (VS Code OutputChannel)
|
|
226
|
+
* This enables orchestrator thinking logs to appear in output console
|
|
227
|
+
*/
|
|
228
|
+
setOutputChannel(outputChannel: any): void {
|
|
229
|
+
if (typeof this.scenarioService?.setOutputChannel === 'function') {
|
|
230
|
+
this.scenarioService.setOutputChannel(outputChannel);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Log a message using the configured logger
|
|
236
|
+
*/
|
|
237
|
+
private log(message: string, level: 'log' | 'error' | 'warn' = 'log'): void {
|
|
238
|
+
if (this.logger) {
|
|
239
|
+
this.logger(message, level);
|
|
240
|
+
}
|
|
241
|
+
// No console fallback - logs are routed to consumer
|
|
99
242
|
}
|
|
100
243
|
|
|
101
244
|
/**
|
|
@@ -127,7 +270,7 @@ export class TestChimpService {
|
|
|
127
270
|
try {
|
|
128
271
|
const resolvedPath = this.fileHandler.resolvePath(request.scriptFilePath);
|
|
129
272
|
request.script = await this.fileHandler.readTestFile(resolvedPath);
|
|
130
|
-
|
|
273
|
+
this.log(`Read script content from file: ${resolvedPath}`);
|
|
131
274
|
} catch (error) {
|
|
132
275
|
throw new Error(`Failed to read script file: ${error}`);
|
|
133
276
|
}
|
|
@@ -138,24 +281,24 @@ export class TestChimpService {
|
|
|
138
281
|
try {
|
|
139
282
|
const resolvedPath = this.fileHandler.resolvePath(request.playwrightConfigFilePath);
|
|
140
283
|
request.playwrightConfig = await this.fileHandler.readTestFile(resolvedPath);
|
|
141
|
-
|
|
284
|
+
this.log(`Read Playwright config content from file: ${resolvedPath}`);
|
|
142
285
|
} catch (error) {
|
|
143
|
-
|
|
286
|
+
this.log(`Failed to read Playwright config file: ${error}. Using default configuration.`, 'warn');
|
|
144
287
|
// Don't throw error, just use default config
|
|
145
288
|
}
|
|
146
289
|
}
|
|
147
290
|
|
|
148
291
|
// Log content status
|
|
149
292
|
if (request.script) {
|
|
150
|
-
|
|
293
|
+
this.log(`Using provided script content (${request.script.length} characters)`);
|
|
151
294
|
} else {
|
|
152
295
|
throw new Error('Script content is required. Provide either script or scriptFilePath.');
|
|
153
296
|
}
|
|
154
297
|
|
|
155
298
|
if (request.playwrightConfig) {
|
|
156
|
-
|
|
299
|
+
this.log(`Using provided Playwright config (${request.playwrightConfig.length} characters)`);
|
|
157
300
|
} else {
|
|
158
|
-
|
|
301
|
+
this.log(`Using default Playwright configuration`);
|
|
159
302
|
}
|
|
160
303
|
|
|
161
304
|
const result = await this.executionService.executeScript(request);
|