explorbot 0.2.4 → 0.3.0
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/bin/explorbot-cli.ts +19 -7
- package/boat/api-tester/src/cli.ts +17 -0
- package/boat/doc-collector/src/cli.ts +14 -1
- package/boat/prima/README.md +96 -0
- package/boat/prima/package.json +14 -10
- package/boat/prima/src/cli.ts +29 -12
- package/boat/prima/src/envelope.ts +35 -13
- package/boat/prima/src/prima.ts +78 -45
- package/dist/bin/explorbot-cli.js +19 -7
- package/dist/boat/api-tester/src/cli.js +17 -0
- package/dist/boat/doc-collector/src/cli.js +14 -1
- package/dist/boat/prima/src/cli.js +26 -7
- package/dist/boat/prima/src/envelope.js +32 -8
- package/dist/boat/prima/src/prima.js +75 -43
- package/dist/models.json +4 -4
- package/dist/package.json +6 -2
- package/dist/src/action-result.d.ts +13 -0
- package/dist/src/action-result.js +46 -15
- package/dist/src/action.d.ts +5 -2
- package/dist/src/action.js +53 -18
- package/dist/src/ai/captain/web-mode.js +1 -2
- package/dist/src/ai/captain.d.ts +20 -0
- package/dist/src/ai/captain.js +10 -1
- package/dist/src/ai/driller.js +6 -2
- package/dist/src/ai/fisherman-tools.d.ts +40 -1
- package/dist/src/ai/fisherman-tools.js +39 -0
- package/dist/src/ai/fisherman.js +2 -1
- package/dist/src/ai/navigator.d.ts +28 -0
- package/dist/src/ai/navigator.js +223 -175
- package/dist/src/ai/pilot.d.ts +7 -4
- package/dist/src/ai/pilot.js +89 -30
- package/dist/src/ai/planner/subpages.js +2 -16
- package/dist/src/ai/planner.js +1 -1
- package/dist/src/ai/provider.d.ts +2 -2
- package/dist/src/ai/provider.js +28 -22
- package/dist/src/ai/researcher/cache.d.ts +10 -3
- package/dist/src/ai/researcher/cache.js +23 -10
- package/dist/src/ai/researcher/deep-analysis.js +1 -1
- package/dist/src/ai/researcher/fingerprint-worker.js +21 -4
- package/dist/src/ai/researcher.js +6 -4
- package/dist/src/ai/rules.js +1 -5
- package/dist/src/ai/session-analyst.js +2 -0
- package/dist/src/ai/tester.d.ts +6 -3
- package/dist/src/ai/tester.js +30 -35
- package/dist/src/ai/tools.d.ts +8 -5
- package/dist/src/ai/tools.js +83 -57
- package/dist/src/commands/config-command.d.ts +51 -0
- package/dist/src/commands/config-command.js +117 -0
- package/dist/src/commands/index.js +2 -0
- package/dist/src/commands/init-command.js +13 -20
- package/dist/src/config.d.ts +8 -1
- package/dist/src/config.js +43 -1
- package/dist/src/experience-tracker.d.ts +2 -0
- package/dist/src/experience-tracker.js +12 -0
- package/dist/src/explorbot.js +5 -2
- package/dist/src/playwright-recorder.js +6 -12
- package/dist/src/remote.d.ts +3 -2
- package/dist/src/remote.js +8 -2
- package/dist/src/state-manager.d.ts +1 -1
- package/dist/src/state-manager.js +3 -1
- package/dist/src/test-plan.d.ts +9 -0
- package/dist/src/test-plan.js +30 -0
- package/dist/src/utils/html-diff.d.ts +5 -0
- package/dist/src/utils/html-diff.js +65 -6
- package/dist/src/utils/logger.d.ts +1 -1
- package/dist/src/utils/logger.js +8 -0
- package/dist/src/utils/strings.d.ts +2 -0
- package/dist/src/utils/strings.js +32 -0
- package/dist/src/utils/url-matcher.d.ts +1 -0
- package/dist/src/utils/url-matcher.js +31 -2
- package/docs/basics/getting-started.md +33 -10
- package/docs/basics/providers.md +6 -4
- package/docs/contributing/npm-package.md +73 -4
- package/docs/index.json +2 -1
- package/docs/reference/commands.md +3 -0
- package/docs/reference/websocket.md +50 -0
- package/docs/superpowers/specs/2026-08-18-prima-false-verdicts.md +159 -0
- package/models.json +4 -4
- package/package.json +6 -2
- package/src/action-result.ts +61 -16
- package/src/action.ts +56 -18
- package/src/ai/captain/web-mode.ts +1 -2
- package/src/ai/captain.ts +9 -1
- package/src/ai/driller.ts +6 -2
- package/src/ai/fisherman-tools.ts +35 -0
- package/src/ai/fisherman.ts +2 -1
- package/src/ai/navigator.ts +238 -179
- package/src/ai/pilot.ts +104 -36
- package/src/ai/planner/subpages.ts +2 -13
- package/src/ai/planner.ts +1 -1
- package/src/ai/provider.ts +29 -21
- package/src/ai/researcher/cache.ts +29 -11
- package/src/ai/researcher/deep-analysis.ts +1 -1
- package/src/ai/researcher/fingerprint-worker.ts +23 -5
- package/src/ai/researcher.ts +6 -4
- package/src/ai/rules.ts +1 -5
- package/src/ai/session-analyst.ts +2 -0
- package/src/ai/tester.ts +33 -34
- package/src/ai/tools.ts +88 -61
- package/src/commands/config-command.ts +146 -0
- package/src/commands/index.ts +2 -0
- package/src/commands/init-command.ts +14 -20
- package/src/config.ts +47 -2
- package/src/experience-tracker.ts +13 -0
- package/src/explorbot.ts +4 -2
- package/src/playwright-recorder.ts +6 -11
- package/src/remote.ts +8 -2
- package/src/state-manager.ts +5 -2
- package/src/test-plan.ts +38 -0
- package/src/utils/html-diff.ts +72 -7
- package/src/utils/logger.ts +9 -1
- package/src/utils/strings.ts +36 -0
- package/src/utils/url-matcher.ts +27 -2
|
@@ -13,7 +13,7 @@ import { mdq } from "../utils/markdown-query.js";
|
|
|
13
13
|
import { RulesLoader } from "../utils/rules-loader.js";
|
|
14
14
|
import { annotatePageElements } from "../utils/web-annotate.js";
|
|
15
15
|
import { ContextLengthError } from './provider.js';
|
|
16
|
-
import { findSimilarResearch, getCachedResearch, saveResearch } from "./researcher/cache.js";
|
|
16
|
+
import { findSimilarResearch, getCachedResearch, reportResearch, saveResearch } from "./researcher/cache.js";
|
|
17
17
|
import { WithCoordinates } from "./researcher/coordinates.js";
|
|
18
18
|
import { WithDeepAnalysis } from "./researcher/deep-analysis.js";
|
|
19
19
|
import { detectFocusedSection, hasFocusedSection, markSectionAsFocused, pickDefaultFocusedSection } from "./researcher/focus.js";
|
|
@@ -72,10 +72,12 @@ export class Researcher extends ResearcherBase {
|
|
|
72
72
|
let retriesLeft = opts._retriesLeft ?? maxRetries;
|
|
73
73
|
this.actionResult = ActionResult.fromState(state);
|
|
74
74
|
const stateHash = state.hash || this.actionResult.getStateHash();
|
|
75
|
+
const researchState = { ...state, hash: stateHash };
|
|
75
76
|
if (!force && stateHash) {
|
|
76
77
|
const cached = getCachedResearch(stateHash);
|
|
77
78
|
if (cached) {
|
|
78
79
|
debugLog('Previous research result found');
|
|
80
|
+
reportResearch(stateHash, cached);
|
|
79
81
|
return cached;
|
|
80
82
|
}
|
|
81
83
|
}
|
|
@@ -104,11 +106,11 @@ export class Researcher extends ResearcherBase {
|
|
|
104
106
|
debugLog('Researching web page:', this.actionResult.url);
|
|
105
107
|
const combinedHtml = await this.actionResult.combinedHtml();
|
|
106
108
|
if (!deep && !force) {
|
|
107
|
-
const similar = await findSimilarResearch(combinedHtml);
|
|
109
|
+
const similar = await findSimilarResearch(combinedHtml, state.url);
|
|
108
110
|
if (similar) {
|
|
109
111
|
tag('operation').log('Similar research found, reusing cached result');
|
|
110
112
|
if (stateHash)
|
|
111
|
-
saveResearch(
|
|
113
|
+
saveResearch(researchState, similar, combinedHtml);
|
|
112
114
|
tag('multiline').log(formatResearchSummary(similar));
|
|
113
115
|
tag('success').log('Research complete (reused)');
|
|
114
116
|
await this.hooksRunner.runAfterHook('researcher', state.url);
|
|
@@ -237,7 +239,7 @@ export class Researcher extends ResearcherBase {
|
|
|
237
239
|
result.cleanup();
|
|
238
240
|
let researchFile = null;
|
|
239
241
|
if (stateHash) {
|
|
240
|
-
researchFile = saveResearch(
|
|
242
|
+
researchFile = saveResearch(researchState, result.text, combinedHtml);
|
|
241
243
|
}
|
|
242
244
|
const summaryText = mdq(result.text).query('section2(/^summary/)').query('paragraph[0]').text().trim();
|
|
243
245
|
const summaryLine = summaryText.split('\n')[0]?.trim().slice(0, 200);
|
package/dist/src/ai/rules.js
CHANGED
|
@@ -2,10 +2,6 @@ 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
|
-
|
|
9
5
|
Use the following priority when selecting locators:
|
|
10
6
|
|
|
11
7
|
1. ARIA locators (first choice) - target browser's accessibility tree, most reliable
|
|
@@ -76,7 +72,7 @@ const locatorStrategyRule = dedent `
|
|
|
76
72
|
|
|
77
73
|
NEVER include \`eidx\` attribute in any locator (ARIA, CSS, XPath). It is an internal annotation.
|
|
78
74
|
|
|
79
|
-
If
|
|
75
|
+
If the element is not found in the ARIA snapshot, fall back to CSS/XPath locators from page HTML.
|
|
80
76
|
|
|
81
77
|
Stick to semantic attributes like role, aria-*, id, class, name, data-id, etc.
|
|
82
78
|
Avoid IDs that follow framework auto-generation patterns (these change on every page load):
|
|
@@ -3,6 +3,7 @@ import path from 'node:path';
|
|
|
3
3
|
import dedent from 'dedent';
|
|
4
4
|
import { outputPath } from "../config.js";
|
|
5
5
|
import { Stats } from "../stats.js";
|
|
6
|
+
import { tag } from "../utils/logger.js";
|
|
6
7
|
export class SessionAnalyst {
|
|
7
8
|
emoji = '🧐';
|
|
8
9
|
provider;
|
|
@@ -103,6 +104,7 @@ export class SessionAnalyst {
|
|
|
103
104
|
if (!existsSync(dir))
|
|
104
105
|
mkdirSync(dir, { recursive: true });
|
|
105
106
|
writeFileSync(filePath, markdown);
|
|
107
|
+
tag('data').log('report', { path: filePath, content: markdown });
|
|
106
108
|
return filePath;
|
|
107
109
|
}
|
|
108
110
|
serializeTest(test, ref) {
|
package/dist/src/ai/tester.d.ts
CHANGED
|
@@ -11,6 +11,7 @@ import { Researcher } from './researcher.js';
|
|
|
11
11
|
import { TaskAgent } from './task-agent.js';
|
|
12
12
|
export declare class Tester extends TaskAgent implements Agent {
|
|
13
13
|
readonly ACTION_TOOLS: string[];
|
|
14
|
+
readonly DELEGATED_ACTION_TOOLS: string[];
|
|
14
15
|
readonly SPECIAL_CONTEXT_ACTION_TOOLS: string[];
|
|
15
16
|
emoji: string;
|
|
16
17
|
requestStore: RequestStore;
|
|
@@ -39,17 +40,16 @@ export declare class Tester extends TaskAgent implements Agent {
|
|
|
39
40
|
getCurrentState(): ActionResult;
|
|
40
41
|
get progressCheckInterval(): number;
|
|
41
42
|
getConversation(): Conversation | null;
|
|
42
|
-
test(task: Test): Promise<{
|
|
43
|
+
test(task: Test, opts?: TestOptions): Promise<{
|
|
43
44
|
success: boolean;
|
|
44
45
|
}>;
|
|
45
|
-
runTestSession(task: Test, initialState: ActionResult, conversation: Conversation, handlers: TestSessionHandlers): Promise<{
|
|
46
|
+
runTestSession(task: Test, initialState: ActionResult, conversation: Conversation, handlers: TestSessionHandlers, opts: TestOptions): Promise<{
|
|
46
47
|
success: boolean;
|
|
47
48
|
}>;
|
|
48
49
|
shouldAnalyzeProgress(iteration: number, currentState: ActionResult): boolean;
|
|
49
50
|
shouldStopForStalledExecution(task: Test, previousState: ActionResult, toolExecutions: any[]): boolean;
|
|
50
51
|
prepareInstructionsForNextStep(task: Test): Promise<string>;
|
|
51
52
|
reinjectContextIfNeeded(iteration: number, currentState: ActionResult): Promise<string>;
|
|
52
|
-
interactiveAriaWithRefs(state: ActionResult): Promise<string>;
|
|
53
53
|
finishTest(task: Test): void;
|
|
54
54
|
abortStartedTestOnErrorPage(task: Test, actionResult: ActionResult): Promise<{
|
|
55
55
|
success: boolean;
|
|
@@ -93,4 +93,7 @@ export declare class Tester extends TaskAgent implements Agent {
|
|
|
93
93
|
interface TestSessionHandlers {
|
|
94
94
|
offFailedRequest?: () => void;
|
|
95
95
|
}
|
|
96
|
+
export interface TestOptions {
|
|
97
|
+
startOnCurrentPage?: boolean;
|
|
98
|
+
}
|
|
96
99
|
export {};
|
package/dist/src/ai/tester.js
CHANGED
|
@@ -8,10 +8,11 @@ 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 { 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
|
+
import { compactErrorMessage } from "../utils/strings.js";
|
|
15
16
|
import { actionRule, capabilityGroundingRule, dataProtectionRules, focusedElementRule, formRequirementsRule, locatorRule, multipleTabsRule, sectionContextRule } from "./rules.js";
|
|
16
17
|
import { TaskAgent } from "./task-agent.js";
|
|
17
18
|
import { createCodeceptJSTools, createIframeTools, withdrawVisionTools } from "./tools.js";
|
|
@@ -28,6 +29,7 @@ const SAMPLE_FILES = {
|
|
|
28
29
|
};
|
|
29
30
|
export class Tester extends TaskAgent {
|
|
30
31
|
ACTION_TOOLS = ['click', 'hover', 'pressKey', 'form'];
|
|
32
|
+
DELEGATED_ACTION_TOOLS = ['interact'];
|
|
31
33
|
SPECIAL_CONTEXT_ACTION_TOOLS = ['exitIframe'];
|
|
32
34
|
emoji = '🧪';
|
|
33
35
|
requestStore;
|
|
@@ -74,7 +76,7 @@ export class Tester extends TaskAgent {
|
|
|
74
76
|
getConversation() {
|
|
75
77
|
return this.currentConversation;
|
|
76
78
|
}
|
|
77
|
-
async test(task) {
|
|
79
|
+
async test(task, opts = {}) {
|
|
78
80
|
Stats.tests++;
|
|
79
81
|
const state = this.stateManager.getCurrentState();
|
|
80
82
|
if (!state)
|
|
@@ -120,9 +122,9 @@ export class Tester extends TaskAgent {
|
|
|
120
122
|
startUrl: task.startUrl,
|
|
121
123
|
expected: task.expected,
|
|
122
124
|
},
|
|
123
|
-
}, async () => this.runTestSession(task, initialState, conversation, { offFailedRequest }));
|
|
125
|
+
}, async () => this.runTestSession(task, initialState, conversation, { offFailedRequest }, opts));
|
|
124
126
|
}
|
|
125
|
-
async runTestSession(task, initialState, conversation, handlers) {
|
|
127
|
+
async runTestSession(task, initialState, conversation, handlers, opts) {
|
|
126
128
|
const { offFailedRequest } = handlers;
|
|
127
129
|
if (this.pilot) {
|
|
128
130
|
try {
|
|
@@ -151,16 +153,20 @@ export class Tester extends TaskAgent {
|
|
|
151
153
|
await this.cleanupStartedTest(task);
|
|
152
154
|
return { success: task.isSuccessful };
|
|
153
155
|
}
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
await this.
|
|
163
|
-
|
|
156
|
+
if (opts.startOnCurrentPage)
|
|
157
|
+
debugLog(`Starting on the page already open at ${task.startUrl}`);
|
|
158
|
+
if (!opts.startOnCurrentPage) {
|
|
159
|
+
debugLog(`Navigating to ${task.startUrl}`);
|
|
160
|
+
try {
|
|
161
|
+
await this.explorer.visit(task.startUrl);
|
|
162
|
+
}
|
|
163
|
+
catch (error) {
|
|
164
|
+
const result = await this.handleLoopError(task, error);
|
|
165
|
+
if (result === 'stop') {
|
|
166
|
+
offFailedRequest?.();
|
|
167
|
+
await this.cleanupStartedTest(task);
|
|
168
|
+
return { success: task.isSuccessful };
|
|
169
|
+
}
|
|
164
170
|
}
|
|
165
171
|
}
|
|
166
172
|
const startState = this.stateManager.getCurrentState();
|
|
@@ -228,8 +234,6 @@ export class Tester extends TaskAgent {
|
|
|
228
234
|
`);
|
|
229
235
|
}
|
|
230
236
|
conversation.cleanupTag('page_aria', '...cleaned aria snapshot...', 1);
|
|
231
|
-
conversation.cleanupTag('page_html', '...cleaned HTML snapshot...', 1);
|
|
232
|
-
conversation.cleanupTag('experience', '...cleaned experience...', 1);
|
|
233
237
|
conversation.cleanupTag('applied_experience', '...cleaned past experience...', 1);
|
|
234
238
|
conversation.cleanupTag('page_ui_map', '...cleaned UI map...', 1);
|
|
235
239
|
conversation.cleanupTag('page_ui_map_overlay', '...cleaned UI overlay...', 1);
|
|
@@ -355,8 +359,6 @@ export class Tester extends TaskAgent {
|
|
|
355
359
|
this.stalledIterations = 0;
|
|
356
360
|
tag('info').log(`Pilot extending test (${extensions}/${this.MAX_EXTENSIONS})`);
|
|
357
361
|
conversation.cleanupTag('page_aria', '...trimmed...', 1);
|
|
358
|
-
conversation.cleanupTag('page_html', '...trimmed...', 0);
|
|
359
|
-
conversation.cleanupTag('experience', '...trimmed...', 0);
|
|
360
362
|
conversation.cleanupTag('page_ui_map', '...trimmed...', 0);
|
|
361
363
|
conversation.cleanupTag('page_ui_map_overlay', '...trimmed...', 0);
|
|
362
364
|
conversation.compactToolResults(1);
|
|
@@ -394,7 +396,7 @@ export class Tester extends TaskAgent {
|
|
|
394
396
|
return false;
|
|
395
397
|
const currentState = this.getCurrentState();
|
|
396
398
|
const stateChanged = previousState.url !== currentState.url || previousState.hash !== currentState.hash;
|
|
397
|
-
const actionTools = [...this.ACTION_TOOLS, ...this.SPECIAL_CONTEXT_ACTION_TOOLS];
|
|
399
|
+
const actionTools = [...this.ACTION_TOOLS, ...this.DELEGATED_ACTION_TOOLS, ...this.SPECIAL_CONTEXT_ACTION_TOOLS];
|
|
398
400
|
const hasSuccessfulAction = toolExecutions.some((execution) => execution.wasSuccessful && actionTools.includes(execution.toolName));
|
|
399
401
|
const hasSuccessfulAssertion = toolExecutions.some((execution) => execution.wasSuccessful && this.ASSERTION_TOOLS.includes(execution.toolName));
|
|
400
402
|
if (stateChanged || hasSuccessfulAction || hasSuccessfulAssertion) {
|
|
@@ -418,6 +420,7 @@ export class Tester extends TaskAgent {
|
|
|
418
420
|
|
|
419
421
|
<rules>
|
|
420
422
|
Use tools ${this.ACTION_TOOLS.join(', ')} to interact with the page.
|
|
423
|
+
Fall back to interact() when those fail, when the step needs a sequence of actions, or when your context is not enough to locate the element.
|
|
421
424
|
Use tool names exactly as listed in this prompt. Do not invent combined tool names, aliases, or names with channel markers such as "commentary".
|
|
422
425
|
Match each tool input schema exactly. Do not invent parameter names or pass extra fields.
|
|
423
426
|
Do not do unsuccesful clicks again.
|
|
@@ -528,13 +531,13 @@ export class Tester extends TaskAgent {
|
|
|
528
531
|
</page>
|
|
529
532
|
|
|
530
533
|
<page_aria>
|
|
531
|
-
${
|
|
534
|
+
${currentState.getInteractiveARIA()}
|
|
532
535
|
</page_aria>
|
|
533
536
|
${uiMapSection}
|
|
534
537
|
|
|
535
538
|
Use <page_ui_map> to understand the page structure and its main elements.
|
|
536
|
-
However, <page_ui_map> is not always up to date, use <page_aria>
|
|
537
|
-
Do not interact with elements that are not listed in <page_aria>
|
|
539
|
+
However, <page_ui_map> is not always up to date, use <page_aria> to understand the ACTUAL state of the page
|
|
540
|
+
Do not interact with elements that are not listed in <page_aria> or in HTML returned by tools
|
|
538
541
|
Refer to information on page sections in <page_ui_map> and use container CSS locators to interact with elements inside sections
|
|
539
542
|
`;
|
|
540
543
|
return context;
|
|
@@ -563,16 +566,10 @@ export class Tester extends TaskAgent {
|
|
|
563
566
|
</page>
|
|
564
567
|
|
|
565
568
|
<page_aria>
|
|
566
|
-
${
|
|
569
|
+
${currentState.getInteractiveARIA()}
|
|
567
570
|
</page_aria>
|
|
568
571
|
`;
|
|
569
572
|
}
|
|
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
|
-
}
|
|
576
573
|
finishTest(task) {
|
|
577
574
|
if (!task.result) {
|
|
578
575
|
if (task.hasAchievedAll())
|
|
@@ -642,7 +639,7 @@ export class Tester extends TaskAgent {
|
|
|
642
639
|
|
|
643
640
|
<rules>
|
|
644
641
|
- Refer to UI Map from <page_ui_map> to understand the page structure and its main elements
|
|
645
|
-
- Use only elements that exist in
|
|
642
|
+
- Use only elements that exist in <page_aria> or in HTML returned by tools
|
|
646
643
|
- Use tool input schemas exactly as documented. Do not invent parameter names or add fields not listed by the tool schema.
|
|
647
644
|
- Use click() for buttons, links, and clickable elements ONLY - do NOT include I.fillField() or I.type() commands in click() tool
|
|
648
645
|
- click() commands array is for FALLBACK LOCATORS of the SAME element, NOT for clicking different elements in sequence. If you need to click two different elements, make two separate click() calls.
|
|
@@ -665,7 +662,8 @@ export class Tester extends TaskAgent {
|
|
|
665
662
|
- Check for error messages to understand if there are issues
|
|
666
663
|
- Verify if data was correctly saved and changes are reflected on the page
|
|
667
664
|
- By default, you receive accessibility tree data which shows interactive elements and page structure
|
|
668
|
-
-
|
|
665
|
+
- Full page HTML is never injected automatically. When ARIA is not enough, delegate to the tools that read it: verify() to assert, interact() to act
|
|
666
|
+
- Understand current context by following <page_aria> and <page_ui_map>
|
|
669
667
|
- Before submitting form, check all inputs were filled in correctly using see() tool
|
|
670
668
|
- When you interact with form with inputs, ensure that you click corresponding button to save its data
|
|
671
669
|
- Follow <locator_priority> rules when selecting locators for all tools
|
|
@@ -716,7 +714,6 @@ export class Tester extends TaskAgent {
|
|
|
716
714
|
}
|
|
717
715
|
buildScenarioBlock(task, actionResult) {
|
|
718
716
|
const knowledge = this.getKnowledge(actionResult);
|
|
719
|
-
const experience = this.getExperience(actionResult);
|
|
720
717
|
return dedent `
|
|
721
718
|
<task>
|
|
722
719
|
SCENARIO GOAL: ${task.scenario}
|
|
@@ -745,8 +742,6 @@ export class Tester extends TaskAgent {
|
|
|
745
742
|
${this.buildAvailableFiles()}
|
|
746
743
|
|
|
747
744
|
${knowledge}
|
|
748
|
-
|
|
749
|
-
${experience}
|
|
750
745
|
`;
|
|
751
746
|
}
|
|
752
747
|
getDeletableSessionNames(task) {
|
|
@@ -856,7 +851,7 @@ export class Tester extends TaskAgent {
|
|
|
856
851
|
explanation,
|
|
857
852
|
};
|
|
858
853
|
if (resetAction.lastError) {
|
|
859
|
-
result.error = resetAction.lastError
|
|
854
|
+
result.error = compactErrorMessage(resetAction.lastError);
|
|
860
855
|
}
|
|
861
856
|
return result;
|
|
862
857
|
},
|
package/dist/src/ai/tools.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ActionResult, type PageDiff } from '../action-result.js';
|
|
2
|
-
import type
|
|
2
|
+
import { type ExperienceTracker } from '../experience-tracker.js';
|
|
3
3
|
import { type Task } from '../test-plan.js';
|
|
4
4
|
import type { ToolDeps } from './agent.js';
|
|
5
5
|
import { Navigator } from './navigator.js';
|
|
@@ -16,10 +16,6 @@ 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>>;
|
|
23
19
|
hover: import("@ai-sdk/provider-utils").ExecutableTool<import("ai").Tool<{
|
|
24
20
|
commands: any;
|
|
25
21
|
explanation: any;
|
|
@@ -34,6 +30,12 @@ export declare function createCodeceptJSTools({ explorer, stateManager, ai }: To
|
|
|
34
30
|
explanation: any;
|
|
35
31
|
}, Record<string, any>, import("@ai-sdk/provider-utils").Context>>;
|
|
36
32
|
};
|
|
33
|
+
export declare function createRefTools({ explorer, stateManager }: ToolDeps, task: Task): {
|
|
34
|
+
clickRef: import("@ai-sdk/provider-utils").ExecutableTool<import("ai").Tool<{
|
|
35
|
+
ref: any;
|
|
36
|
+
element: any;
|
|
37
|
+
}, Record<string, any>, import("@ai-sdk/provider-utils").Context>>;
|
|
38
|
+
};
|
|
37
39
|
export declare function createIframeTools({ explorer, stateManager }: ToolDeps): {
|
|
38
40
|
exitIframe: import("@ai-sdk/provider-utils").ExecutableTool<import("ai").Tool<{
|
|
39
41
|
reason?: string;
|
|
@@ -59,6 +61,7 @@ export declare function successToolResult(action: string, data?: Record<string,
|
|
|
59
61
|
assertionSteps?: any[];
|
|
60
62
|
}): Record<string, any>;
|
|
61
63
|
export declare function isMajorPageChange(pageDiff: PageDiff): boolean;
|
|
64
|
+
export declare function hasFailedRequest(pageDiff: PageDiff): boolean;
|
|
62
65
|
export declare function failedToolResult(action: string, message: string, data?: Record<string, any>, error?: Error | null): Promise<Record<string, any>>;
|
|
63
66
|
export declare function withdrawVisionTools(tools: Record<string, any>): void;
|
|
64
67
|
export declare function clickFailureSuggestion(attempts: Array<{
|