explorbot 0.2.2 → 0.2.4
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/README.md +1 -1
- package/bin/explorbot-cli.ts +59 -38
- package/boat/api-tester/src/apibot.ts +4 -2
- package/boat/api-tester/src/cli.ts +2 -2
- package/boat/api-tester/src/config.ts +43 -10
- package/boat/doc-collector/bin/doc-collector-cli.ts +2 -0
- package/boat/doc-collector/src/ai/documentarian.ts +61 -31
- package/boat/doc-collector/src/cli.ts +1 -0
- package/boat/doc-collector/src/config.ts +4 -2
- package/boat/doc-collector/src/docs-renderer.ts +18 -4
- package/boat/doc-collector/src/state-diagram.ts +61 -14
- package/boat/prima/bin/prima-cli.ts +5 -0
- package/boat/prima/package.json +16 -0
- package/boat/prima/src/activity-line.ts +33 -0
- package/boat/prima/src/cli.ts +251 -0
- package/boat/prima/src/envelope.ts +169 -0
- package/boat/prima/src/prima.ts +1124 -0
- package/boat/prima/src/pw-parser.ts +27 -0
- package/boat/prima/src/pw-registry.ts +74 -0
- package/boat/prima/src/session-log.ts +126 -0
- package/dist/bin/explorbot-cli.js +51 -32
- package/dist/boat/api-tester/bin/apibot-cli.js +2 -0
- package/dist/boat/api-tester/src/apibot.js +3 -2
- package/dist/boat/api-tester/src/cli.js +2 -2
- package/dist/boat/api-tester/src/config.js +40 -10
- package/dist/boat/doc-collector/bin/doc-collector-cli.js +2 -0
- package/dist/boat/doc-collector/src/ai/documentarian.js +44 -19
- package/dist/boat/doc-collector/src/cli.js +1 -0
- package/dist/boat/doc-collector/src/config.js +4 -2
- package/dist/boat/doc-collector/src/docs-renderer.js +17 -3
- package/dist/boat/doc-collector/src/state-diagram.js +57 -13
- package/dist/boat/prima/bin/prima-cli.js +4 -0
- package/dist/boat/prima/src/activity-line.js +30 -0
- package/dist/boat/prima/src/cli.js +220 -0
- package/dist/boat/prima/src/envelope.js +142 -0
- package/dist/boat/prima/src/prima.js +1031 -0
- package/dist/boat/prima/src/pw-parser.js +30 -0
- package/dist/boat/prima/src/pw-registry.js +65 -0
- package/dist/boat/prima/src/session-log.js +108 -0
- package/dist/models.json +3 -0
- package/dist/package.json +8 -3
- package/dist/rules/navigator/verification-actions.md +20 -0
- package/dist/src/action-result.d.ts +7 -0
- package/dist/src/action-result.js +4 -0
- package/dist/src/action.d.ts +7 -2
- package/dist/src/action.js +41 -6
- package/dist/src/ai/captain/mixin.js +3 -4
- package/dist/src/ai/captain/web-mode.js +7 -4
- package/dist/src/ai/captain.js +2 -0
- package/dist/src/ai/navigator.d.ts +11 -0
- package/dist/src/ai/navigator.js +21 -12
- package/dist/src/ai/pilot.d.ts +4 -0
- package/dist/src/ai/pilot.js +48 -2
- package/dist/src/ai/planner.d.ts +1 -0
- package/dist/src/ai/planner.js +6 -0
- package/dist/src/ai/provider.js +2 -2
- package/dist/src/ai/rerunner.js +2 -1
- package/dist/src/ai/researcher.js +2 -2
- package/dist/src/ai/rules.js +17 -10
- package/dist/src/ai/task-agent.js +5 -2
- package/dist/src/ai/tester.d.ts +1 -0
- package/dist/src/ai/tester.js +33 -20
- package/dist/src/ai/tools.d.ts +14 -0
- package/dist/src/ai/tools.js +113 -36
- package/dist/src/application-spec-contract.d.ts +8 -0
- package/dist/src/application-spec-contract.js +8 -0
- package/dist/src/application-spec.d.ts +15 -0
- package/dist/src/application-spec.js +71 -0
- package/dist/src/browser-server.d.ts +12 -6
- package/dist/src/browser-server.js +74 -19
- package/dist/src/commands/clean-command.js +2 -7
- package/dist/src/commands/init-command.d.ts +5 -0
- package/dist/src/commands/init-command.js +119 -1
- package/dist/src/commands/navigate-command.js +1 -1
- package/dist/src/commands/research-command.js +1 -1
- package/dist/src/commands/sites-command.d.ts +6 -0
- package/dist/src/commands/sites-command.js +23 -0
- package/dist/src/components/InitWizard.d.ts +10 -0
- package/dist/src/components/InitWizard.js +133 -0
- package/dist/src/components/InputReadline.d.ts +1 -0
- package/dist/src/components/InputReadline.js +7 -4
- package/dist/src/config.d.ts +25 -5
- package/dist/src/config.js +158 -40
- package/dist/src/execution-controller.d.ts +2 -0
- package/dist/src/execution-controller.js +6 -0
- package/dist/src/explorbot.d.ts +11 -1
- package/dist/src/explorbot.js +27 -6
- package/dist/src/explorer.d.ts +4 -1
- package/dist/src/explorer.js +42 -9
- package/dist/src/global-config.d.ts +22 -0
- package/dist/src/global-config.js +117 -0
- package/dist/src/knowledge-tracker.d.ts +5 -1
- package/dist/src/knowledge-tracker.js +14 -1
- package/dist/src/playwright-recorder.js +30 -0
- package/dist/src/remote.d.ts +54 -0
- package/dist/src/remote.js +229 -0
- package/dist/src/reporter.d.ts +1 -0
- package/dist/src/reporter.js +7 -1
- package/dist/src/state-manager.d.ts +2 -1
- package/dist/src/stats.d.ts +1 -0
- package/dist/src/stats.js +1 -0
- package/dist/src/test-plan.d.ts +2 -0
- package/dist/src/test-plan.js +7 -0
- package/dist/src/utils/aria.d.ts +2 -8
- package/dist/src/utils/aria.js +69 -40
- package/dist/src/utils/cli-name.js +6 -2
- package/dist/src/utils/html.js +1 -0
- package/dist/src/utils/logger.d.ts +6 -0
- package/dist/src/utils/logger.js +24 -0
- package/dist/src/utils/page-readiness.js +18 -1
- package/dist/src/utils/test-files.js +1 -2
- package/dist/src/utils/url-matcher.d.ts +1 -0
- package/dist/src/utils/url-matcher.js +12 -0
- package/dist/src/utils/web-element.d.ts +2 -0
- package/dist/src/utils/web-element.js +8 -0
- package/dist/src/utils/web-sandbox.d.ts +1 -1
- package/dist/src/utils/web-sandbox.js +2 -3
- package/docs/api-testing/basics.md +90 -0
- package/docs/api-testing/planning.md +57 -0
- package/docs/api-testing/running-tests.md +55 -0
- package/docs/assets/cloud-report.png +0 -0
- package/docs/assets/html-report.png +0 -0
- package/docs/assets/langfuse-trace.png +0 -0
- package/docs/assets/successful-explore-run.png +0 -0
- package/docs/basics/getting-started.md +140 -0
- package/docs/basics/prerequisites.md +63 -0
- package/docs/basics/providers.md +362 -0
- package/docs/basics/running.md +78 -0
- package/docs/contributing/ai-integration-tests.md +57 -0
- package/docs/contributing/contributing.md +90 -0
- package/docs/contributing/demo-videos.md +36 -0
- package/docs/contributing/npm-package.md +138 -0
- package/docs/contributing/observability.md +227 -0
- package/docs/contributing/regression-tests.md +103 -0
- package/docs/contributing/testing.md +95 -0
- package/docs/doc-collection/basics.md +128 -0
- package/docs/doc-collection/crawling.md +67 -0
- package/docs/doc-collection/interactive-mode.md +99 -0
- package/docs/index.json +86 -0
- package/docs/reference/commands.md +994 -0
- package/docs/reference/configuration.md +569 -0
- package/docs/reference/scripting.md +303 -0
- package/docs/superpowers/plans/2026-08-01-actor-boat.md +925 -0
- package/docs/superpowers/plans/2026-08-01-prima-boat.md +1120 -0
- package/docs/superpowers/reviews/2026-08-06-prima-vs-playwright-cli.md +268 -0
- package/docs/superpowers/specs/2026-08-01-actor-boat-design.md +204 -0
- package/docs/superpowers/specs/2026-08-01-prima-boat-design.md +242 -0
- package/docs/superpowers/specs/2026-08-03-global-config-design.md +138 -0
- package/docs/superpowers/specs/2026-08-07-prima-fixes-design.md +394 -0
- package/docs/web-testing/agents.md +158 -0
- package/docs/web-testing/automated-tests.md +134 -0
- package/docs/web-testing/basics.md +91 -0
- package/docs/web-testing/customization.md +131 -0
- package/docs/web-testing/hooks.md +238 -0
- package/docs/web-testing/page-interaction.md +84 -0
- package/docs/web-testing/planner.md +122 -0
- package/docs/web-testing/rerun.md +164 -0
- package/docs/web-testing/researcher.md +380 -0
- package/docs/workflow/agentic-usage.md +233 -0
- package/docs/workflow/application-spec.md +73 -0
- package/docs/workflow/ci.md +202 -0
- package/docs/workflow/knowledge.md +310 -0
- package/docs/workflow/planning-styles.md +67 -0
- package/docs/workflow/reporting.md +133 -0
- package/docs/workflow/test-plans.md +90 -0
- package/models.json +3 -0
- package/package.json +8 -3
- package/rules/navigator/verification-actions.md +20 -0
- package/src/action-result.ts +11 -0
- package/src/action.ts +47 -7
- package/src/ai/captain/mixin.ts +3 -3
- package/src/ai/captain/web-mode.ts +7 -4
- package/src/ai/captain.ts +3 -0
- package/src/ai/navigator.ts +26 -15
- package/src/ai/pilot.ts +53 -2
- package/src/ai/planner.ts +7 -0
- package/src/ai/provider.ts +2 -4
- package/src/ai/rerunner.ts +2 -1
- package/src/ai/researcher.ts +2 -2
- package/src/ai/rules.ts +17 -10
- package/src/ai/task-agent.ts +4 -2
- package/src/ai/tester.ts +32 -18
- package/src/ai/tools.ts +132 -36
- package/src/application-spec-contract.ts +10 -0
- package/src/application-spec.ts +87 -0
- package/src/browser-server.ts +74 -19
- package/src/commands/clean-command.ts +1 -6
- package/src/commands/init-command.ts +146 -1
- package/src/commands/navigate-command.ts +1 -1
- package/src/commands/research-command.ts +1 -1
- package/src/commands/sites-command.ts +27 -0
- package/src/components/InitWizard.tsx +166 -0
- package/src/components/InputReadline.tsx +8 -4
- package/src/config.ts +177 -43
- package/src/execution-controller.ts +8 -0
- package/src/explorbot.ts +34 -7
- package/src/explorer.ts +47 -9
- package/src/global-config.ts +148 -0
- package/src/knowledge-tracker.ts +17 -1
- package/src/playwright-recorder.ts +23 -0
- package/src/remote.ts +238 -0
- package/src/reporter.ts +7 -1
- package/src/state-manager.ts +2 -1
- package/src/stats.ts +1 -0
- package/src/test-plan.ts +9 -0
- package/src/utils/aria.ts +65 -45
- package/src/utils/cli-name.ts +5 -2
- package/src/utils/html.ts +1 -0
- package/src/utils/logger.ts +24 -1
- package/src/utils/page-readiness.ts +24 -1
- package/src/utils/test-files.ts +1 -2
- package/src/utils/url-matcher.ts +13 -0
- package/src/utils/web-element.ts +9 -0
- package/src/utils/web-sandbox.ts +3 -4
package/dist/src/ai/navigator.js
CHANGED
|
@@ -3,12 +3,13 @@ import dedent from 'dedent';
|
|
|
3
3
|
import { z } from 'zod';
|
|
4
4
|
import { ActionResult } from '../action-result.js';
|
|
5
5
|
import { normalizeUrl } from '../state-manager.js';
|
|
6
|
+
import { renderAssertion } from "../playwright-recorder.js";
|
|
6
7
|
import { extractCodeBlocks } from '../utils/code-extractor.js';
|
|
7
8
|
import { HooksRunner } from "../utils/hooks-runner.js";
|
|
8
9
|
import { createDebug, pluralize, tag } from '../utils/logger.js';
|
|
9
10
|
import { loop, pause } from '../utils/loop.js';
|
|
10
11
|
import { RulesLoader } from "../utils/rules-loader.js";
|
|
11
|
-
import { extractStatePath } from '../utils/url-matcher.js';
|
|
12
|
+
import { extractStatePath, matchesNavigationUrl } from '../utils/url-matcher.js';
|
|
12
13
|
import { Researcher } from "./researcher.js";
|
|
13
14
|
import { actionRule, locatorRule, unexpectedPopupRule } from './rules.js';
|
|
14
15
|
import { isInteractive } from './task-agent.js';
|
|
@@ -118,7 +119,7 @@ class Navigator {
|
|
|
118
119
|
return false;
|
|
119
120
|
}
|
|
120
121
|
const currentUrl = this.getComparableCurrentUrl(stateManager, expectedUrl);
|
|
121
|
-
return
|
|
122
|
+
return matchesNavigationUrl(expectedUrl, currentUrl);
|
|
122
123
|
}
|
|
123
124
|
async visit(url) {
|
|
124
125
|
return this.visitOnce(url);
|
|
@@ -167,11 +168,13 @@ class Navigator {
|
|
|
167
168
|
}
|
|
168
169
|
}
|
|
169
170
|
async resolveState(message, actionResult, opts) {
|
|
171
|
+
if (!this.provider)
|
|
172
|
+
throw new Error('AI-assisted recovery is unavailable: no AI model is configured.');
|
|
170
173
|
tag('info').log('AI Navigator resolving state at', actionResult.url);
|
|
171
174
|
debugLog('Resolution message:', message);
|
|
172
175
|
const action = opts?.action ?? this.explorer.action();
|
|
173
176
|
const expectedUrl = opts?.expectedUrl;
|
|
174
|
-
const knowledge = this.knowledgeTracker.
|
|
177
|
+
const knowledge = this.knowledgeTracker.renderRelevantContext(actionResult);
|
|
175
178
|
let experience = '';
|
|
176
179
|
if (!actionResult.isInsideIframe) {
|
|
177
180
|
const successful = this.experienceTracker.getSuccessfulExperience(actionResult);
|
|
@@ -328,16 +331,19 @@ class Navigator {
|
|
|
328
331
|
// Navigation did not reach 'load' state within timeout; continue and verify URL
|
|
329
332
|
}
|
|
330
333
|
}
|
|
334
|
+
if (attemptOk)
|
|
335
|
+
opts?.onAttempt?.({ code: codeBlock });
|
|
331
336
|
if (!attemptOk) {
|
|
332
337
|
const raw = action.lastError?.message || 'attempt failed';
|
|
333
338
|
const firstMeaningful = raw.split('\n').find((l) => l.trim() && !l.trim().startsWith('at ')) || raw;
|
|
334
339
|
const shortErr = firstMeaningful.replace(/\s+/g, ' ').trim().slice(0, 220);
|
|
335
340
|
batchFailures.push({ code: codeBlock, error: shortErr });
|
|
341
|
+
opts?.onAttempt?.({ code: codeBlock, error: shortErr });
|
|
336
342
|
}
|
|
337
343
|
if (expectedUrl) {
|
|
338
344
|
if (page) {
|
|
339
345
|
try {
|
|
340
|
-
await page.waitForURL((url) =>
|
|
346
|
+
await page.waitForURL((url) => matchesNavigationUrl(expectedUrl, `${url.pathname}${url.search}${url.hash}`), { timeout: 5000 });
|
|
341
347
|
}
|
|
342
348
|
catch {
|
|
343
349
|
// URL did not transition to expectedUrl within timeout
|
|
@@ -345,7 +351,7 @@ class Navigator {
|
|
|
345
351
|
}
|
|
346
352
|
const freshState = await this.explorer.capture();
|
|
347
353
|
const currentUrl = /^https?:\/\//i.test(expectedUrl) ? freshState.fullUrl || freshState.url || '' : freshState.url || '';
|
|
348
|
-
const urlMatches = this.isSameExpectedOrigin(expectedUrl, action.stateManager) &&
|
|
354
|
+
const urlMatches = this.isSameExpectedOrigin(expectedUrl, action.stateManager) && matchesNavigationUrl(expectedUrl, currentUrl);
|
|
349
355
|
const stateChanged = freshState.getStateHash() !== actionResult.getStateHash();
|
|
350
356
|
resolved = urlMatches && stateChanged;
|
|
351
357
|
if (!resolved && attemptOk) {
|
|
@@ -562,7 +568,7 @@ class Navigator {
|
|
|
562
568
|
tag('operation').log(`Reusing cached verification: ${cachedVerification ? 'PASS' : 'FAIL'}`);
|
|
563
569
|
return { verified: cachedVerification, successfulCodes: [], assertionSteps: [], totalAttempted: 0 };
|
|
564
570
|
}
|
|
565
|
-
const knowledge = this.knowledgeTracker.
|
|
571
|
+
const knowledge = this.knowledgeTracker.renderRelevantContext(actionResult);
|
|
566
572
|
let experience = '';
|
|
567
573
|
if (!actionResult.isInsideIframe) {
|
|
568
574
|
experience = this.experienceTracker.renderExperienceTocFor(actionResult);
|
|
@@ -623,6 +629,7 @@ class Navigator {
|
|
|
623
629
|
const tools = this.buildExperienceTools();
|
|
624
630
|
let codeBlocks = [];
|
|
625
631
|
const successfulCodes = [];
|
|
632
|
+
const results = [];
|
|
626
633
|
const assertionSteps = [];
|
|
627
634
|
const action = this.explorer.action();
|
|
628
635
|
let failures = 0;
|
|
@@ -655,6 +662,8 @@ class Navigator {
|
|
|
655
662
|
}
|
|
656
663
|
await action.exitIframe();
|
|
657
664
|
const verified = await action.attempt(codeBlock, message);
|
|
665
|
+
const proof = action.assertionSteps.map(renderAssertion).filter(Boolean);
|
|
666
|
+
results.push({ code: codeBlock, passed: verified, proof });
|
|
658
667
|
if (verified) {
|
|
659
668
|
tag('success').log('Verification passed');
|
|
660
669
|
successfulCodes.push(codeBlock);
|
|
@@ -663,11 +672,6 @@ class Navigator {
|
|
|
663
672
|
else {
|
|
664
673
|
failures++;
|
|
665
674
|
}
|
|
666
|
-
const target = Math.min(codeBlocks.length, this.verifyAttempts);
|
|
667
|
-
const majorityNeeded = Math.floor(target / 2) + 1;
|
|
668
|
-
if (successfulCodes.length >= majorityNeeded || failures > target - majorityNeeded) {
|
|
669
|
-
stop();
|
|
670
|
-
}
|
|
671
675
|
}, {
|
|
672
676
|
maxAttempts: this.verifyAttempts,
|
|
673
677
|
observability: {
|
|
@@ -686,9 +690,14 @@ class Navigator {
|
|
|
686
690
|
let verified = successfulCodes.length >= majorityNeeded;
|
|
687
691
|
if (alreadyVerified)
|
|
688
692
|
verified = true;
|
|
693
|
+
const inexpressible = !alreadyVerified && totalAttempted === 0;
|
|
694
|
+
if (inexpressible) {
|
|
695
|
+
tag('warning').log('No assertion could express this claim');
|
|
696
|
+
return { verified: false, inexpressible, results, successfulCodes, assertionSteps, totalAttempted };
|
|
697
|
+
}
|
|
689
698
|
actionResult.addVerification(message, verified);
|
|
690
699
|
this.stateManager.updateState(actionResult);
|
|
691
|
-
return { verified, successfulCodes, assertionSteps, totalAttempted };
|
|
700
|
+
return { verified, inexpressible, results, successfulCodes, assertionSteps, totalAttempted };
|
|
692
701
|
}
|
|
693
702
|
checkAlreadyVerified(aiResponse, actionResult) {
|
|
694
703
|
const verifiedMatch = aiResponse.match(/ALREADY_VERIFIED:\s*(.+)/i);
|
package/dist/src/ai/pilot.d.ts
CHANGED
|
@@ -40,6 +40,10 @@ export declare class Pilot implements Agent {
|
|
|
40
40
|
planTest(task: Test, currentState: ActionResult): Promise<string>;
|
|
41
41
|
reviewNewPage(task: Test, currentState: ActionResult, testerConversation: Conversation): Promise<string>;
|
|
42
42
|
analyzeProgress(task: Test, currentState: ActionResult, testerConversation: Conversation): Promise<string>;
|
|
43
|
+
settleExpectations(task: Test): Promise<Array<{
|
|
44
|
+
text: string;
|
|
45
|
+
status: 'passed' | 'failed' | 'unverified';
|
|
46
|
+
}>>;
|
|
43
47
|
formatExpectations(task: Test): string;
|
|
44
48
|
sendToPilot(userText: string, functionId: string, opts: {
|
|
45
49
|
tools?: boolean;
|
package/dist/src/ai/pilot.js
CHANGED
|
@@ -4,13 +4,14 @@ import { z } from 'zod';
|
|
|
4
4
|
import { ActionResult } from "../action-result.js";
|
|
5
5
|
import { ConfigParser } from "../config.js";
|
|
6
6
|
import { TestResult } from "../test-plan.js";
|
|
7
|
-
import { collectInteractiveNodes, detectFocusArea
|
|
7
|
+
import { collectInteractiveNodes, detectFocusArea } from "../utils/aria.js";
|
|
8
8
|
import { ErrorPageError } from "../utils/error-page.js";
|
|
9
9
|
import { createDebug, tag } from "../utils/logger.js";
|
|
10
10
|
const debugLog = createDebug('explorbot:pilot');
|
|
11
11
|
import { truncateJson } from "../utils/strings.js";
|
|
12
12
|
import { capabilityGroundingRule, dataProtectionRules } from "./rules.js";
|
|
13
13
|
import { isInteractive } from "./task-agent.js";
|
|
14
|
+
import { withdrawVisionTools } from "./tools.js";
|
|
14
15
|
const CHECK_TOOLS = ['verify', 'see', 'research', 'context'];
|
|
15
16
|
const META_TOOLS = ['record', 'reset', 'stop', 'finish'];
|
|
16
17
|
export class Pilot {
|
|
@@ -484,6 +485,50 @@ export class Pilot {
|
|
|
484
485
|
}
|
|
485
486
|
return text;
|
|
486
487
|
}
|
|
488
|
+
async settleExpectations(task) {
|
|
489
|
+
const undecided = task.expected.filter((text) => !task.getCheckedExpectations().includes(text));
|
|
490
|
+
const decided = (text) => {
|
|
491
|
+
if (task.hasAchievedAny() && !task.getRemainingExpectations().includes(text))
|
|
492
|
+
return 'passed';
|
|
493
|
+
return 'failed';
|
|
494
|
+
};
|
|
495
|
+
if (!undecided.length)
|
|
496
|
+
return task.expected.map((text) => ({ text, status: decided(text) }));
|
|
497
|
+
const schema = z.object({
|
|
498
|
+
outcomes: z.array(z.object({
|
|
499
|
+
expectation: z.string().describe('The expected outcome, repeated exactly as it was given'),
|
|
500
|
+
status: z.enum(['passed', 'failed', 'unverified']).describe('passed = the log shows it happened, failed = the log shows it did not, unverified = the run never established either way'),
|
|
501
|
+
})),
|
|
502
|
+
});
|
|
503
|
+
const userContent = dedent `
|
|
504
|
+
A test run has finished. Decide, for each expected outcome, what the run established about it.
|
|
505
|
+
|
|
506
|
+
<expected_outcomes>
|
|
507
|
+
${undecided.map((text) => `- ${text}`).join('\n')}
|
|
508
|
+
</expected_outcomes>
|
|
509
|
+
|
|
510
|
+
<run_log>
|
|
511
|
+
${task.notesToString() || 'No steps recorded.'}
|
|
512
|
+
</run_log>
|
|
513
|
+
|
|
514
|
+
The log is written in the tester's own words, so an outcome can be satisfied by a step that describes it
|
|
515
|
+
differently. Judge by what the steps show happened, not by whether the wording matches.
|
|
516
|
+
Choose "unverified" only when the log neither shows the outcome happening nor shows it failing —
|
|
517
|
+
that is a statement about the run, not about the application.
|
|
518
|
+
`;
|
|
519
|
+
const response = await this.provider
|
|
520
|
+
.generateObject([{ role: 'user', content: userContent }], schema, this.provider.getAgenticModel('pilot'), {
|
|
521
|
+
agentName: 'pilot',
|
|
522
|
+
telemetry: { functionId: 'pilot.settleExpectations' },
|
|
523
|
+
})
|
|
524
|
+
.catch(() => null);
|
|
525
|
+
const judged = new Map((response?.object?.outcomes || []).map((outcome) => [outcome.expectation, outcome.status]));
|
|
526
|
+
return task.expected.map((text) => {
|
|
527
|
+
if (!undecided.includes(text))
|
|
528
|
+
return { text, status: decided(text) };
|
|
529
|
+
return { text, status: judged.get(text) || 'unverified' };
|
|
530
|
+
});
|
|
531
|
+
}
|
|
487
532
|
formatExpectations(task) {
|
|
488
533
|
const checked = task.getCheckedExpectations();
|
|
489
534
|
const remaining = task.getRemainingExpectations();
|
|
@@ -547,6 +592,7 @@ export class Pilot {
|
|
|
547
592
|
planning.learnExperience = learnExperience;
|
|
548
593
|
if (askUser)
|
|
549
594
|
planning.askUser = askUser;
|
|
595
|
+
withdrawVisionTools(planning);
|
|
550
596
|
return planning;
|
|
551
597
|
}
|
|
552
598
|
buildPreconditionTool(task) {
|
|
@@ -624,7 +670,7 @@ export class Pilot {
|
|
|
624
670
|
const lines = [];
|
|
625
671
|
lines.push(`url: ${state.url}`);
|
|
626
672
|
lines.push(`title: ${state.title || 'unknown'}`);
|
|
627
|
-
const focused =
|
|
673
|
+
const focused = state.focusedElement;
|
|
628
674
|
if (focused) {
|
|
629
675
|
const valuePart = focused.value ? ` (value: "${focused.value}")` : '';
|
|
630
676
|
lines.push(`focused: ${focused.role} "${focused.name}"${valuePart}`);
|
package/dist/src/ai/planner.d.ts
CHANGED
|
@@ -50,6 +50,7 @@ export declare class Planner extends PlannerBase implements Agent {
|
|
|
50
50
|
provider: Provider;
|
|
51
51
|
stateManager: StateManager;
|
|
52
52
|
experienceTracker: ExperienceTracker;
|
|
53
|
+
knowledgeTracker: AgentDeps['knowledgeTracker'];
|
|
53
54
|
MIN_TASKS: number;
|
|
54
55
|
MAX_TASKS: number;
|
|
55
56
|
currentPlan: Plan | null;
|
package/dist/src/ai/planner.js
CHANGED
|
@@ -41,6 +41,7 @@ export class Planner extends PlannerBase {
|
|
|
41
41
|
provider;
|
|
42
42
|
stateManager;
|
|
43
43
|
experienceTracker;
|
|
44
|
+
knowledgeTracker;
|
|
44
45
|
MIN_TASKS = 3;
|
|
45
46
|
MAX_TASKS = 12;
|
|
46
47
|
currentPlan = null;
|
|
@@ -56,6 +57,7 @@ export class Planner extends PlannerBase {
|
|
|
56
57
|
this.researcher = researcher;
|
|
57
58
|
this.stateManager = deps.stateManager;
|
|
58
59
|
this.experienceTracker = deps.stateManager.getExperienceTracker();
|
|
60
|
+
this.knowledgeTracker = deps.knowledgeTracker;
|
|
59
61
|
}
|
|
60
62
|
setFisherman(fisherman) {
|
|
61
63
|
this.fisherman = fisherman;
|
|
@@ -368,6 +370,10 @@ export class Planner extends PlannerBase {
|
|
|
368
370
|
${plannerResearch}
|
|
369
371
|
</page_research>
|
|
370
372
|
`);
|
|
373
|
+
const applicationContext = this.knowledgeTracker.renderApplicationSpec(state);
|
|
374
|
+
if (applicationContext) {
|
|
375
|
+
conversation.addUserText(applicationContext);
|
|
376
|
+
}
|
|
371
377
|
conversation.addUserText(dedent `
|
|
372
378
|
${this.buildApproach(style)}
|
|
373
379
|
|
package/dist/src/ai/provider.js
CHANGED
|
@@ -290,6 +290,7 @@ export class Provider {
|
|
|
290
290
|
try {
|
|
291
291
|
const response = await withRetry(async () => {
|
|
292
292
|
const result = await generateText({ messages, ...config });
|
|
293
|
+
this.recordUsage(options.agentName || 'unknown', modelName, result.usage);
|
|
293
294
|
if (!result.text) {
|
|
294
295
|
debugLog(result);
|
|
295
296
|
if (result.finishReason === 'length') {
|
|
@@ -304,7 +305,6 @@ export class Provider {
|
|
|
304
305
|
}, this.getRetryOptions(options));
|
|
305
306
|
clearActivity();
|
|
306
307
|
responseLog(response.text);
|
|
307
|
-
this.recordUsage(options.agentName || 'unknown', modelName, response.usage);
|
|
308
308
|
return response;
|
|
309
309
|
}
|
|
310
310
|
catch (error) {
|
|
@@ -340,6 +340,7 @@ export class Provider {
|
|
|
340
340
|
try {
|
|
341
341
|
const response = await withRetry(async () => {
|
|
342
342
|
const result = (await this.raceWithIdleTimeout((signal) => generateText({ messages, ...config, abortSignal: signal }), config.timeout || 30000));
|
|
343
|
+
this.recordUsage(options.agentName || 'unknown', modelName, result.usage);
|
|
343
344
|
const hasToolCall = (result.toolCalls?.length || 0) > 0;
|
|
344
345
|
if (!result.text && !hasToolCall && result.finishReason === 'length') {
|
|
345
346
|
throw new ContextLengthError('AI response empty: output truncated at maxTokens. Increase maxOutputTokens in config or use a model with higher output capacity.');
|
|
@@ -355,7 +356,6 @@ export class Provider {
|
|
|
355
356
|
});
|
|
356
357
|
}
|
|
357
358
|
responseLog(response.text);
|
|
358
|
-
this.recordUsage(options.agentName || 'unknown', modelName, response.usage);
|
|
359
359
|
return response;
|
|
360
360
|
}
|
|
361
361
|
catch (error) {
|
package/dist/src/ai/rerunner.js
CHANGED
|
@@ -21,7 +21,7 @@ import { RulesLoader } from "../utils/rules-loader.js";
|
|
|
21
21
|
import { toolExecutionLabel } from "./conversation.js";
|
|
22
22
|
import { actionRule, locatorRule, sectionContextRule } from "./rules.js";
|
|
23
23
|
import { TaskAgent } from "./task-agent.js";
|
|
24
|
-
import { createCodeceptJSTools } from "./tools.js";
|
|
24
|
+
import { createCodeceptJSTools, withdrawVisionTools } from "./tools.js";
|
|
25
25
|
const debugLog = createDebug('explorbot:rerunner');
|
|
26
26
|
export class Rerunner extends TaskAgent {
|
|
27
27
|
ACTION_TOOLS = ['click', 'pressKey', 'form'];
|
|
@@ -322,6 +322,7 @@ export class Rerunner extends TaskAgent {
|
|
|
322
322
|
},
|
|
323
323
|
}),
|
|
324
324
|
};
|
|
325
|
+
withdrawVisionTools(tools);
|
|
325
326
|
const conversation = this.provider.startConversation(this.getHealSystemPrompt(), 'rerunner');
|
|
326
327
|
conversation.addUserText(this.getHealUserPrompt(failedCode, error));
|
|
327
328
|
await loop(async ({ stop }) => {
|
|
@@ -76,7 +76,7 @@ export class Researcher extends ResearcherBase {
|
|
|
76
76
|
const cached = getCachedResearch(stateHash);
|
|
77
77
|
if (cached) {
|
|
78
78
|
debugLog('Previous research result found');
|
|
79
|
-
return
|
|
79
|
+
return cached;
|
|
80
80
|
}
|
|
81
81
|
}
|
|
82
82
|
Stats.researches++;
|
|
@@ -379,7 +379,7 @@ export class Researcher extends ResearcherBase {
|
|
|
379
379
|
if (!this.actionResult)
|
|
380
380
|
throw new Error('actionResult is not set');
|
|
381
381
|
const html = await this.actionResult.combinedHtml();
|
|
382
|
-
const knowledge = this.knowledgeTracker.
|
|
382
|
+
const knowledge = this.knowledgeTracker.renderRelevantContext(this.actionResult);
|
|
383
383
|
const ariaSnapshot = this.actionResult.getCompactARIA();
|
|
384
384
|
return dedent `
|
|
385
385
|
Analyze this web page and provide a comprehensive research report in markdown format.
|
package/dist/src/ai/rules.js
CHANGED
|
@@ -2,13 +2,18 @@ import dedent from 'dedent';
|
|
|
2
2
|
export const recommendedCodeceptCommands = ['I.click', 'I.type', 'I.fillField', 'I.see', 'I.seeElement'];
|
|
3
3
|
const locatorPriorityRule = dedent `
|
|
4
4
|
<locator_priority>
|
|
5
|
+
When the page context shows the element a ref, such as [ref=e14], there is no locator to select: click it with clickRef
|
|
6
|
+
and that ref. A ref names one exact element, so it never matches the wrong one and never has to be narrowed. Everything
|
|
7
|
+
below is for elements the context gives no ref for.
|
|
8
|
+
|
|
5
9
|
Use the following priority when selecting locators:
|
|
6
10
|
|
|
7
11
|
1. ARIA locators (first choice) - target browser's accessibility tree, most reliable
|
|
8
12
|
Use JSON format: { "role": "button", "text": "Login" }
|
|
9
|
-
|
|
13
|
+
Copy role and text VERBATIM from the ARIA snapshot or UI map — never guess the pair.
|
|
14
|
+
If the element is absent from the snapshot, do not invent one; use text or CSS instead.
|
|
10
15
|
|
|
11
|
-
2. Text locators (second choice) - use only when
|
|
16
|
+
2. Text locators (second choice) - exact visible text, use only when unique on the page
|
|
12
17
|
Example: 'Login', 'Submit', 'Username'
|
|
13
18
|
Skip if the same text appears multiple times on the page
|
|
14
19
|
|
|
@@ -23,10 +28,10 @@ const locatorPriorityRule = dedent `
|
|
|
23
28
|
`;
|
|
24
29
|
const contextSimplificationRule = dedent `
|
|
25
30
|
<context_simplification>
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
-
|
|
29
|
-
-
|
|
31
|
+
- Add a container when the target may match several elements, or the UI map gives a verified
|
|
32
|
+
section container: I.click('Save', '.modal')
|
|
33
|
+
- Skip the container when the locator is already unique (XPath, unique ID, unique text)
|
|
34
|
+
- A wrong or stale container guarantees failure: always add one fallback command WITHOUT a container
|
|
30
35
|
- No need for complex ARIA when container narrows scope sufficiently
|
|
31
36
|
</context_simplification>
|
|
32
37
|
`;
|
|
@@ -55,7 +60,7 @@ const locatorStrategyRule = dedent `
|
|
|
55
60
|
|
|
56
61
|
<good_aria_locator_example>
|
|
57
62
|
{ "role": "button", "text": "Login" },
|
|
58
|
-
{ "role": "
|
|
63
|
+
{ "role": "textbox", "text": "Name" },
|
|
59
64
|
{ "role": "link", "text": "Forgot your password?" },
|
|
60
65
|
{ "role": "link", "text": "Sign Up" },
|
|
61
66
|
{ "role": "button", "text": "Sign In" },
|
|
@@ -101,7 +106,7 @@ const locatorStrategyRule = dedent `
|
|
|
101
106
|
</xpath_rules>
|
|
102
107
|
|
|
103
108
|
<good locator example>
|
|
104
|
-
'
|
|
109
|
+
'input[placeholder="Name"]'
|
|
105
110
|
'[aria-label="Name"]'
|
|
106
111
|
'form#user_form input[name="name"]'
|
|
107
112
|
'#content-top #user_name'
|
|
@@ -231,7 +236,8 @@ export const unexpectedPopupRule = dedent `
|
|
|
231
236
|
`;
|
|
232
237
|
export const sectionContextRule = dedent `
|
|
233
238
|
<section_context_rule>
|
|
234
|
-
|
|
239
|
+
Use a container from UI map sections when the target may match several elements. A container that is
|
|
240
|
+
wrong or stale guarantees failure, so prefer a verified one and keep a containerless fallback.
|
|
235
241
|
|
|
236
242
|
1. Identify which section contains the target element
|
|
237
243
|
2. Get the Context Locator from that section in the UI map
|
|
@@ -249,9 +255,10 @@ export const sectionContextRule = dedent `
|
|
|
249
255
|
For CSS locators - prepend section context:
|
|
250
256
|
- I.click('.main button.submit') // instead of I.click('button.submit')
|
|
251
257
|
|
|
252
|
-
|
|
258
|
+
Omit context when the locator already resolves to one element:
|
|
253
259
|
- Locator is XPath (already includes path context)
|
|
254
260
|
- Locator is a unique ID (#specific-element)
|
|
261
|
+
- Text or ARIA that appears only once on the page
|
|
255
262
|
</section_context_rule>
|
|
256
263
|
|
|
257
264
|
${unexpectedPopupRule}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
|
+
import { executionController } from "../execution-controller.js";
|
|
1
2
|
import { HooksRunner } from "../utils/hooks-runner.js";
|
|
2
3
|
export function isInteractive() {
|
|
3
|
-
|
|
4
|
+
if (process.env.INK_RUNNING === 'true')
|
|
5
|
+
return true;
|
|
6
|
+
return executionController.hasInputCallback();
|
|
4
7
|
}
|
|
5
8
|
function createNullProxy() {
|
|
6
9
|
return new Proxy({}, {
|
|
@@ -49,7 +52,7 @@ export class TaskAgent {
|
|
|
49
52
|
return this.provider;
|
|
50
53
|
}
|
|
51
54
|
getKnowledge(actionResult) {
|
|
52
|
-
return this.getKnowledgeTracker().
|
|
55
|
+
return this.getKnowledgeTracker().renderRelevantContext(actionResult);
|
|
53
56
|
}
|
|
54
57
|
getExperience(actionResult) {
|
|
55
58
|
return this.getExperienceTracker().renderExperienceTocFor(actionResult);
|
package/dist/src/ai/tester.d.ts
CHANGED
|
@@ -49,6 +49,7 @@ export declare class Tester extends TaskAgent implements Agent {
|
|
|
49
49
|
shouldStopForStalledExecution(task: Test, previousState: ActionResult, toolExecutions: any[]): boolean;
|
|
50
50
|
prepareInstructionsForNextStep(task: Test): Promise<string>;
|
|
51
51
|
reinjectContextIfNeeded(iteration: number, currentState: ActionResult): Promise<string>;
|
|
52
|
+
interactiveAriaWithRefs(state: ActionResult): Promise<string>;
|
|
52
53
|
finishTest(task: Test): void;
|
|
53
54
|
abortStartedTestOnErrorPage(task: Test, actionResult: ActionResult): Promise<{
|
|
54
55
|
success: boolean;
|
package/dist/src/ai/tester.js
CHANGED
|
@@ -8,13 +8,13 @@ import { clearActivity, setActivity } from "../activity.js";
|
|
|
8
8
|
import { Observability } from "../observability.js";
|
|
9
9
|
import { Stats } from "../stats.js";
|
|
10
10
|
import { TestResult } from "../test-plan.js";
|
|
11
|
-
import {
|
|
11
|
+
import { compactAriaSnapshot, detectFocusArea } from "../utils/aria.js";
|
|
12
12
|
import { ErrorPageError, isErrorPage } from "../utils/error-page.js";
|
|
13
13
|
import { createDebug, tag } from "../utils/logger.js";
|
|
14
14
|
import { loop } from "../utils/loop.js";
|
|
15
15
|
import { actionRule, capabilityGroundingRule, dataProtectionRules, focusedElementRule, formRequirementsRule, locatorRule, multipleTabsRule, sectionContextRule } from "./rules.js";
|
|
16
16
|
import { TaskAgent } from "./task-agent.js";
|
|
17
|
-
import { createCodeceptJSTools, createIframeTools } from "./tools.js";
|
|
17
|
+
import { createCodeceptJSTools, createIframeTools, withdrawVisionTools } from "./tools.js";
|
|
18
18
|
const debugLog = createDebug('explorbot:tester');
|
|
19
19
|
const SAMPLE_FILES_DIR = resolve(dirname(fileURLToPath(import.meta.url)), '../../assets/sample-files');
|
|
20
20
|
const SAMPLE_FILES = {
|
|
@@ -93,7 +93,7 @@ export class Tester extends TaskAgent {
|
|
|
93
93
|
const requestStore = this.requestStore;
|
|
94
94
|
requestStore.clear();
|
|
95
95
|
const offFailedRequest = requestStore.onFailedRequest((r) => {
|
|
96
|
-
task.
|
|
96
|
+
task.addObservation(`Network error: ${r.method} ${r.path} → ${r.status}`);
|
|
97
97
|
});
|
|
98
98
|
const initialState = ActionResult.fromState(state);
|
|
99
99
|
if (isErrorPage(initialState)) {
|
|
@@ -206,6 +206,7 @@ export class Tester extends TaskAgent {
|
|
|
206
206
|
if (currentState.isInsideIframe) {
|
|
207
207
|
Object.assign(tools, createIframeTools(this.toolDeps));
|
|
208
208
|
}
|
|
209
|
+
withdrawVisionTools(tools);
|
|
209
210
|
debugLog(`Test ${task.scenario} iteration ${iteration}`);
|
|
210
211
|
if (this.stateManager.isInDeadLoop()) {
|
|
211
212
|
task.addNote('Dead loop detected. Stopped');
|
|
@@ -351,6 +352,7 @@ export class Tester extends TaskAgent {
|
|
|
351
352
|
if (extensions >= this.MAX_EXTENSIONS)
|
|
352
353
|
break;
|
|
353
354
|
extensions++;
|
|
355
|
+
this.stalledIterations = 0;
|
|
354
356
|
tag('info').log(`Pilot extending test (${extensions}/${this.MAX_EXTENSIONS})`);
|
|
355
357
|
conversation.cleanupTag('page_aria', '...trimmed...', 1);
|
|
356
358
|
conversation.cleanupTag('page_html', '...trimmed...', 0);
|
|
@@ -405,8 +407,7 @@ export class Tester extends TaskAgent {
|
|
|
405
407
|
this.stalledIterations++;
|
|
406
408
|
if (this.stalledIterations < this.MAX_STALLED_ITERATIONS)
|
|
407
409
|
return false;
|
|
408
|
-
task.addNote('No browser progress
|
|
409
|
-
task.finish(TestResult.FAILED);
|
|
410
|
+
task.addNote('No further browser progress on unchanged page; requesting final review');
|
|
410
411
|
return true;
|
|
411
412
|
}
|
|
412
413
|
async prepareInstructionsForNextStep(task) {
|
|
@@ -424,7 +425,8 @@ export class Tester extends TaskAgent {
|
|
|
424
425
|
</rules>
|
|
425
426
|
`;
|
|
426
427
|
if (task.getPrintableNotes()) {
|
|
427
|
-
outcomeStatus
|
|
428
|
+
outcomeStatus += dedent `
|
|
429
|
+
|
|
428
430
|
Your current log:
|
|
429
431
|
<notes>
|
|
430
432
|
${task.notesToString()}
|
|
@@ -445,7 +447,7 @@ export class Tester extends TaskAgent {
|
|
|
445
447
|
this.previousStateHash = currentStateHash;
|
|
446
448
|
let context = '';
|
|
447
449
|
const focusArea = detectFocusArea(currentState.ariaSnapshot);
|
|
448
|
-
const focusedElement =
|
|
450
|
+
const focusedElement = currentState.focusedElement;
|
|
449
451
|
if (focusedElement) {
|
|
450
452
|
const isTextInput = ['textbox', 'combobox', 'searchbox'].includes(focusedElement.role);
|
|
451
453
|
context += dedent `
|
|
@@ -526,7 +528,7 @@ export class Tester extends TaskAgent {
|
|
|
526
528
|
</page>
|
|
527
529
|
|
|
528
530
|
<page_aria>
|
|
529
|
-
${
|
|
531
|
+
${await this.interactiveAriaWithRefs(currentState)}
|
|
530
532
|
</page_aria>
|
|
531
533
|
${uiMapSection}
|
|
532
534
|
|
|
@@ -561,26 +563,32 @@ export class Tester extends TaskAgent {
|
|
|
561
563
|
</page>
|
|
562
564
|
|
|
563
565
|
<page_aria>
|
|
564
|
-
${
|
|
566
|
+
${await this.interactiveAriaWithRefs(currentState)}
|
|
565
567
|
</page_aria>
|
|
566
568
|
`;
|
|
567
569
|
}
|
|
570
|
+
async interactiveAriaWithRefs(state) {
|
|
571
|
+
const withRefs = await Promise.resolve(this.explorer?.withPage?.((page) => page.locator('body').ariaSnapshot({ mode: 'ai' }))).catch(() => null);
|
|
572
|
+
if (!withRefs)
|
|
573
|
+
return state.getInteractiveARIA();
|
|
574
|
+
return compactAriaSnapshot(withRefs, false);
|
|
575
|
+
}
|
|
568
576
|
finishTest(task) {
|
|
569
|
-
if (!task.
|
|
570
|
-
task.
|
|
577
|
+
if (!task.result) {
|
|
578
|
+
if (task.hasAchievedAll())
|
|
579
|
+
task.finish(TestResult.PASSED);
|
|
580
|
+
else
|
|
581
|
+
task.finish(TestResult.FAILED);
|
|
571
582
|
}
|
|
572
583
|
if (task.isSuccessful) {
|
|
573
584
|
tag('success').log(`Successful test: ${task.scenario}`);
|
|
585
|
+
return;
|
|
574
586
|
}
|
|
575
|
-
|
|
587
|
+
if (task.isSkipped) {
|
|
576
588
|
tag('warning').log(`Skipped test: ${task.scenario}`);
|
|
589
|
+
return;
|
|
577
590
|
}
|
|
578
|
-
|
|
579
|
-
tag('error').log(`Failed test: ${task.scenario}`);
|
|
580
|
-
}
|
|
581
|
-
else {
|
|
582
|
-
tag('warning').log(`Test with no result: ${task.scenario}`);
|
|
583
|
-
}
|
|
591
|
+
tag('error').log(`Failed test: ${task.scenario}`);
|
|
584
592
|
}
|
|
585
593
|
async abortStartedTestOnErrorPage(task, actionResult) {
|
|
586
594
|
const error = new ErrorPageError(actionResult.url || task.startUrl || '', actionResult.title, actionResult.httpStatus);
|
|
@@ -721,6 +729,9 @@ export class Tester extends TaskAgent {
|
|
|
721
729
|
${task.expected.map((e) => `- ${e}`).join('\n')}
|
|
722
730
|
</expected_results>
|
|
723
731
|
|
|
732
|
+
An expected result counts as settled only when you record it back word for word as it is written above.
|
|
733
|
+
A note in your own wording is a general note and leaves that result unsettled.
|
|
734
|
+
|
|
724
735
|
Your goal is to perform actions on the web page and verify the expected outcomes.
|
|
725
736
|
Try to achieve as many goals as possible.
|
|
726
737
|
If goal is not achievable, log that and skip to next one.
|
|
@@ -955,6 +966,9 @@ export class Tester extends TaskAgent {
|
|
|
955
966
|
- You unsuccessfully tried multiple iterations and failed
|
|
956
967
|
- If the expected result was expected to fail, use status="success" instead
|
|
957
968
|
|
|
969
|
+
When a note settles one of the expected results, that note must repeat the expected result word
|
|
970
|
+
for word. Paraphrasing it leaves the expected result unsettled and it is reported as unverified.
|
|
971
|
+
|
|
958
972
|
Example:
|
|
959
973
|
- record({ notes: ["clicked login button", "login form appeared", "fill credentials"], status: "success" })
|
|
960
974
|
`,
|
|
@@ -1032,8 +1046,7 @@ export class Tester extends TaskAgent {
|
|
|
1032
1046
|
this.stalledIterations++;
|
|
1033
1047
|
if (this.stalledIterations < this.MAX_STALLED_ITERATIONS)
|
|
1034
1048
|
return false;
|
|
1035
|
-
task.addNote('No browser progress after repeated execution errors'
|
|
1036
|
-
task.finish(TestResult.FAILED);
|
|
1049
|
+
task.addNote('No browser progress after repeated execution errors; requesting final review');
|
|
1037
1050
|
return true;
|
|
1038
1051
|
}
|
|
1039
1052
|
async cleanupStartedTest(task) {
|
package/dist/src/ai/tools.d.ts
CHANGED
|
@@ -16,6 +16,10 @@ export declare function createCodeceptJSTools({ explorer, stateManager, ai }: To
|
|
|
16
16
|
commands: any;
|
|
17
17
|
explanation: any;
|
|
18
18
|
}, Record<string, any>, import("@ai-sdk/provider-utils").Context>>;
|
|
19
|
+
clickRef: import("@ai-sdk/provider-utils").ExecutableTool<import("ai").Tool<{
|
|
20
|
+
ref: any;
|
|
21
|
+
element: any;
|
|
22
|
+
}, Record<string, any>, import("@ai-sdk/provider-utils").Context>>;
|
|
19
23
|
hover: import("@ai-sdk/provider-utils").ExecutableTool<import("ai").Tool<{
|
|
20
24
|
commands: any;
|
|
21
25
|
explanation: any;
|
|
@@ -49,5 +53,15 @@ export declare function createLearnExperienceTool({ getExperienceTracker, getSta
|
|
|
49
53
|
error: string;
|
|
50
54
|
}, import("@ai-sdk/provider-utils").Context>>;
|
|
51
55
|
export declare function createAgentTools({ explorer, stateManager, ai, researcher, navigator, supervisor, withExperience }: AgentToolDeps): any;
|
|
56
|
+
export declare function commitNote(activeNote: any, result: TestResult, toolResult: any, action: any): Promise<void>;
|
|
57
|
+
export declare function successToolResult(action: string, data?: Record<string, any>, source?: {
|
|
58
|
+
playwrightGroupId?: string | null;
|
|
59
|
+
assertionSteps?: any[];
|
|
60
|
+
}): Record<string, any>;
|
|
52
61
|
export declare function isMajorPageChange(pageDiff: PageDiff): boolean;
|
|
62
|
+
export declare function failedToolResult(action: string, message: string, data?: Record<string, any>, error?: Error | null): Promise<Record<string, any>>;
|
|
63
|
+
export declare function withdrawVisionTools(tools: Record<string, any>): void;
|
|
64
|
+
export declare function clickFailureSuggestion(attempts: Array<{
|
|
65
|
+
error?: string;
|
|
66
|
+
}>): string;
|
|
53
67
|
export {};
|