explorbot 0.2.0 → 0.2.1
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 +21 -5
- package/bin/explorbot-cli.ts +29 -7
- package/boat/api-tester/src/config.ts +45 -3
- package/boat/doc-collector/src/ai/documentarian.ts +5 -2
- package/boat/doc-collector/src/ai/tools.ts +12 -11
- package/boat/doc-collector/src/cli.ts +1 -6
- package/boat/doc-collector/src/docbot.ts +3 -3
- package/boat/doc-collector/src/screenshots.ts +2 -2
- package/dist/bin/explorbot-cli.js +26 -6
- package/dist/boat/api-tester/src/config.js +43 -4
- package/dist/boat/doc-collector/src/ai/documentarian.js +4 -2
- package/dist/boat/doc-collector/src/ai/tools.js +11 -11
- package/dist/boat/doc-collector/src/cli.js +1 -5
- package/dist/boat/doc-collector/src/docbot.js +3 -3
- package/dist/boat/doc-collector/src/screenshots.js +2 -2
- package/dist/models.json +30 -0
- package/dist/package.json +5 -2
- package/dist/src/action.d.ts +11 -3
- package/dist/src/action.js +22 -5
- package/dist/src/ai/agent.d.ts +17 -0
- package/dist/src/ai/captain/idle-mode.js +1 -1
- package/dist/src/ai/captain/test-mode.js +1 -1
- package/dist/src/ai/captain/web-mode.js +18 -22
- package/dist/src/ai/captain.js +13 -26
- package/dist/src/ai/driller.d.ts +2 -13
- package/dist/src/ai/driller.js +23 -38
- package/dist/src/ai/historian/codeceptjs.js +1 -1
- package/dist/src/ai/historian/playwright.d.ts +3 -2
- package/dist/src/ai/historian/playwright.js +1 -1
- package/dist/src/ai/historian/screencast.d.ts +2 -1
- package/dist/src/ai/historian/screencast.js +2 -2
- package/dist/src/ai/historian.d.ts +5 -4
- package/dist/src/ai/navigator.d.ts +6 -2
- package/dist/src/ai/navigator.js +26 -22
- package/dist/src/ai/pilot.d.ts +13 -6
- package/dist/src/ai/pilot.js +49 -44
- package/dist/src/ai/planner.d.ts +3 -2
- package/dist/src/ai/planner.js +19 -17
- package/dist/src/ai/provider.js +0 -1
- package/dist/src/ai/quartermaster.d.ts +3 -2
- package/dist/src/ai/quartermaster.js +4 -4
- package/dist/src/ai/rerunner.d.ts +2 -11
- package/dist/src/ai/rerunner.js +9 -22
- package/dist/src/ai/researcher/coordinates.js +4 -3
- package/dist/src/ai/researcher/deep-analysis.d.ts +2 -0
- package/dist/src/ai/researcher/deep-analysis.js +6 -6
- package/dist/src/ai/researcher/locators.d.ts +9 -2
- package/dist/src/ai/researcher/locators.js +65 -8
- package/dist/src/ai/researcher/sections.d.ts +2 -0
- package/dist/src/ai/researcher/sections.js +2 -2
- package/dist/src/ai/researcher.js +29 -54
- package/dist/src/ai/task-agent.d.ts +18 -5
- package/dist/src/ai/task-agent.js +35 -6
- package/dist/src/ai/tester.d.ts +6 -12
- package/dist/src/ai/tester.js +37 -51
- package/dist/src/ai/tools.d.ts +11 -10
- package/dist/src/ai/tools.js +24 -36
- package/dist/src/command-handler.js +1 -1
- package/dist/src/commands/context-aria-command.js +1 -1
- package/dist/src/commands/context-command.js +7 -5
- package/dist/src/commands/context-data-command.js +2 -2
- package/dist/src/commands/context-experience-command.js +2 -2
- package/dist/src/commands/context-html-command.js +2 -2
- package/dist/src/commands/context-knowledge-command.js +1 -1
- package/dist/src/commands/drill-command.js +1 -1
- package/dist/src/commands/explore-command.js +4 -3
- package/dist/src/commands/freesail-command.js +2 -2
- package/dist/src/commands/learn-command.js +4 -4
- package/dist/src/commands/path-command.js +1 -1
- package/dist/src/commands/research-command.js +1 -1
- package/dist/src/commands/test-command.js +1 -1
- package/dist/src/components/App.js +1 -1
- package/dist/src/config.d.ts +17 -0
- package/dist/src/config.js +144 -10
- package/dist/src/experience-tracker.js +1 -1
- package/dist/src/explorbot.d.ts +17 -8
- package/dist/src/explorbot.js +74 -36
- package/dist/src/explorer.d.ts +66 -91
- package/dist/src/explorer.js +326 -567
- package/dist/src/state-manager.d.ts +6 -1
- package/dist/src/state-manager.js +1 -0
- package/dist/src/utils/hooks-runner.js +2 -4
- package/dist/src/utils/test-files.js +1 -1
- package/dist/src/utils/web-annotate.d.ts +5 -0
- package/dist/src/utils/web-annotate.js +58 -0
- package/dist/src/utils/web-eidx.d.ts +2 -0
- package/dist/src/utils/web-eidx.js +20 -0
- package/dist/src/utils/web-element.d.ts +1 -0
- package/dist/src/utils/web-element.js +29 -0
- package/models.json +30 -0
- package/package.json +5 -2
- package/src/action.ts +25 -5
- package/src/ai/agent.ts +20 -0
- package/src/ai/captain/idle-mode.ts +1 -1
- package/src/ai/captain/test-mode.ts +1 -1
- package/src/ai/captain/web-mode.ts +18 -23
- package/src/ai/captain.ts +12 -25
- package/src/ai/driller.ts +50 -67
- package/src/ai/historian/codeceptjs.ts +1 -1
- package/src/ai/historian/playwright.ts +4 -3
- package/src/ai/historian/screencast.ts +4 -3
- package/src/ai/historian.ts +3 -2
- package/src/ai/navigator.ts +30 -25
- package/src/ai/pilot.ts +55 -47
- package/src/ai/planner.ts +22 -20
- package/src/ai/provider.ts +0 -1
- package/src/ai/quartermaster.ts +5 -4
- package/src/ai/rerunner.ts +10 -29
- package/src/ai/researcher/coordinates.ts +4 -3
- package/src/ai/researcher/deep-analysis.ts +8 -6
- package/src/ai/researcher/locators.ts +66 -9
- package/src/ai/researcher/sections.ts +4 -2
- package/src/ai/researcher.ts +32 -61
- package/src/ai/task-agent.ts +45 -11
- package/src/ai/tester.ts +40 -57
- package/src/ai/tools.ts +32 -53
- package/src/command-handler.ts +1 -1
- package/src/commands/context-aria-command.ts +1 -1
- package/src/commands/context-command.ts +7 -5
- package/src/commands/context-data-command.ts +2 -2
- package/src/commands/context-experience-command.ts +2 -2
- package/src/commands/context-html-command.ts +2 -2
- package/src/commands/context-knowledge-command.ts +1 -1
- package/src/commands/drill-command.ts +1 -1
- package/src/commands/explore-command.ts +4 -3
- package/src/commands/freesail-command.ts +2 -2
- package/src/commands/learn-command.ts +4 -4
- package/src/commands/path-command.ts +1 -1
- package/src/commands/research-command.ts +1 -1
- package/src/commands/test-command.ts +1 -1
- package/src/components/App.tsx +1 -1
- package/src/config.ts +173 -11
- package/src/experience-tracker.ts +1 -1
- package/src/explorbot.ts +78 -39
- package/src/explorer.ts +389 -628
- package/src/state-manager.ts +7 -1
- package/src/utils/hooks-runner.ts +2 -4
- package/src/utils/test-files.ts +1 -1
- package/src/utils/web-annotate.ts +64 -0
- package/src/utils/web-eidx.ts +21 -0
- package/src/utils/web-element.ts +30 -0
package/dist/src/ai/driller.js
CHANGED
|
@@ -6,10 +6,11 @@ import { setActivity } from "../activity.js";
|
|
|
6
6
|
import { Observability } from "../observability.js";
|
|
7
7
|
import { Plan, Test, TestResult } from "../test-plan.js";
|
|
8
8
|
import { collectInteractiveNodes } from "../utils/aria.js";
|
|
9
|
-
import { HooksRunner } from "../utils/hooks-runner.js";
|
|
10
9
|
import { EXPLORBOT_ATTRS, HTML_COMPOSITE_AREA_HINTS, HTML_COMPOSITE_TARGET_ROLES, HTML_EXTRACTION_LIMITS, HTML_FORM_CONTROL_ROLES, HTML_FORM_CONTROL_TAGS, HTML_INTERACTIVE_ROLES, HTML_SELECTORS, HTML_VISIBILITY_LIMITS, getComponentScopeHtmlExtractorSource, getVisibleOverlayHtmlExtractorSource, inferHtmlRole, } from "../utils/html.js";
|
|
11
10
|
import { createDebug, tag } from "../utils/logger.js";
|
|
12
11
|
import { loop, pause } from "../utils/loop.js";
|
|
12
|
+
import { annotatePageElements } from "../utils/web-annotate.js";
|
|
13
|
+
import { eidxInContainer } from "../utils/web-eidx.js";
|
|
13
14
|
import { WebElement } from "../utils/web-element.js";
|
|
14
15
|
import { drillLocatorRule } from "./rules.js";
|
|
15
16
|
import { TaskAgent, isInteractive } from "./task-agent.js";
|
|
@@ -18,36 +19,21 @@ const debugLog = createDebug('explorbot:driller');
|
|
|
18
19
|
export class Driller extends TaskAgent {
|
|
19
20
|
ACTION_TOOLS = ['click', 'pressKey', 'form'];
|
|
20
21
|
emoji = 'D';
|
|
21
|
-
explorer;
|
|
22
|
-
provider;
|
|
23
22
|
navigator;
|
|
24
|
-
hooksRunner;
|
|
25
23
|
currentPlan;
|
|
26
24
|
allResults = [];
|
|
27
25
|
verifiedAction = null;
|
|
28
26
|
pendingNestedContext = null;
|
|
29
27
|
MAX_COMPONENT_ITERATIONS = 12;
|
|
30
|
-
constructor(
|
|
31
|
-
super();
|
|
32
|
-
this.explorer = explorer;
|
|
33
|
-
this.provider = provider;
|
|
28
|
+
constructor(deps, navigator) {
|
|
29
|
+
super(deps);
|
|
34
30
|
this.navigator = navigator;
|
|
35
|
-
this.hooksRunner = new HooksRunner(explorer, explorer.getConfig());
|
|
36
31
|
}
|
|
37
32
|
getNavigator() {
|
|
38
33
|
return this.navigator;
|
|
39
34
|
}
|
|
40
|
-
getExperienceTracker() {
|
|
41
|
-
return this.explorer.getStateManager().getExperienceTracker();
|
|
42
|
-
}
|
|
43
|
-
getKnowledgeTracker() {
|
|
44
|
-
return this.explorer.getKnowledgeTracker();
|
|
45
|
-
}
|
|
46
|
-
getProvider() {
|
|
47
|
-
return this.provider;
|
|
48
|
-
}
|
|
49
35
|
getSystemMessage(component) {
|
|
50
|
-
const currentUrl = this.
|
|
36
|
+
const currentUrl = this.stateManager.getCurrentState()?.url;
|
|
51
37
|
const customPrompt = this.provider.getSystemPromptForAgent('driller', currentUrl);
|
|
52
38
|
return dedent `
|
|
53
39
|
<role>
|
|
@@ -89,7 +75,7 @@ export class Driller extends TaskAgent {
|
|
|
89
75
|
}
|
|
90
76
|
async drill(opts = {}) {
|
|
91
77
|
const { knowledgePath, maxComponents = 30, interactive = isInteractive() } = opts;
|
|
92
|
-
const currentState = this.
|
|
78
|
+
const currentState = this.stateManager.getCurrentState();
|
|
93
79
|
if (!currentState)
|
|
94
80
|
throw new Error('No page state available');
|
|
95
81
|
const sessionName = `driller_${Date.now().toString(36)}`;
|
|
@@ -130,15 +116,15 @@ export class Driller extends TaskAgent {
|
|
|
130
116
|
}
|
|
131
117
|
async captureAnnotatedState() {
|
|
132
118
|
setActivity(`${this.emoji} Capturing annotated page state...`, 'action');
|
|
133
|
-
const action = this.explorer.
|
|
119
|
+
const action = this.explorer.action();
|
|
134
120
|
try {
|
|
135
121
|
const annotated = await Promise.race([
|
|
136
|
-
this.explorer.
|
|
122
|
+
this.explorer.withPage(annotatePageElements),
|
|
137
123
|
new Promise((_, reject) => {
|
|
138
124
|
setTimeout(() => reject(new Error('annotateElements timeout')), 15000);
|
|
139
125
|
}),
|
|
140
126
|
]);
|
|
141
|
-
return action.capturePageState(
|
|
127
|
+
return action.capturePageState();
|
|
142
128
|
}
|
|
143
129
|
catch (error) {
|
|
144
130
|
tag('warning').log(`Annotated capture failed, falling back to plain page state: ${error instanceof Error ? error.message : error}`);
|
|
@@ -150,9 +136,10 @@ export class Driller extends TaskAgent {
|
|
|
150
136
|
}
|
|
151
137
|
async collectComponents(state, maxComponents) {
|
|
152
138
|
setActivity(`${this.emoji} Collecting components...`, 'action');
|
|
153
|
-
const
|
|
154
|
-
|
|
155
|
-
|
|
139
|
+
const webElements = await this.explorer.withPage(async (page) => {
|
|
140
|
+
const eidxList = await eidxInContainer(page, null);
|
|
141
|
+
return WebElement.fromEidxList(page, eidxList);
|
|
142
|
+
});
|
|
156
143
|
const ariaNodes = collectInteractiveNodes(state.ariaSnapshot);
|
|
157
144
|
const scored = webElements
|
|
158
145
|
.filter((element) => isDrillableElement(element))
|
|
@@ -246,13 +233,13 @@ export class Driller extends TaskAgent {
|
|
|
246
233
|
const conversation = this.provider.startConversation(this.getSystemMessage(component), 'driller');
|
|
247
234
|
conversation.addUserText(await this.buildComponentPrompt(originalState, component));
|
|
248
235
|
let finished = false;
|
|
249
|
-
const actionTools = this.createVerifiedActionTools(createCodeceptJSTools(this.
|
|
236
|
+
const actionTools = this.createVerifiedActionTools(createCodeceptJSTools(this.toolDeps, test), component);
|
|
250
237
|
const tools = { ...actionTools, ...this.createDrillFlowTools(originalState, test, interactive) };
|
|
251
238
|
await loop(async ({ stop, iteration }) => {
|
|
252
239
|
debugLog(`Drilling component ${component.name}, iteration ${iteration}`);
|
|
253
240
|
setActivity(`${this.emoji} Drilling ${component.name}...`, 'action');
|
|
254
241
|
if (iteration > 1) {
|
|
255
|
-
const currentState = ActionResult.fromState(this.
|
|
242
|
+
const currentState = ActionResult.fromState(this.stateManager.getCurrentState() || originalState);
|
|
256
243
|
conversation.addUserText(await this.buildContextUpdate(currentState, component));
|
|
257
244
|
if (this.pendingNestedContext) {
|
|
258
245
|
conversation.addUserText(this.pendingNestedContext);
|
|
@@ -479,7 +466,7 @@ export class Driller extends TaskAgent {
|
|
|
479
466
|
execute: async ({ reason }) => {
|
|
480
467
|
await this.restoreOriginalState(originalState, reason);
|
|
481
468
|
await this.captureAnnotatedState();
|
|
482
|
-
const currentState = this.
|
|
469
|
+
const currentState = this.stateManager.getCurrentState();
|
|
483
470
|
return { success: true, url: currentState?.url || originalState.url };
|
|
484
471
|
},
|
|
485
472
|
}),
|
|
@@ -500,9 +487,9 @@ export class Driller extends TaskAgent {
|
|
|
500
487
|
};
|
|
501
488
|
}
|
|
502
489
|
async restoreOriginalState(originalState, reason) {
|
|
503
|
-
const currentState = this.
|
|
490
|
+
const currentState = this.stateManager.getCurrentState();
|
|
504
491
|
const targetUrl = originalState.fullUrl || originalState.url;
|
|
505
|
-
const action = this.explorer.
|
|
492
|
+
const action = this.explorer.action();
|
|
506
493
|
if (currentState?.url !== originalState.url) {
|
|
507
494
|
await action.attempt(`I.amOnPage(${JSON.stringify(targetUrl)})`, `${reason} (restore URL)`);
|
|
508
495
|
return;
|
|
@@ -558,7 +545,7 @@ export class Driller extends TaskAgent {
|
|
|
558
545
|
const overlayHtml = await this.getVisibleOverlayHtml();
|
|
559
546
|
if (!overlayHtml)
|
|
560
547
|
return null;
|
|
561
|
-
const state = this.
|
|
548
|
+
const state = this.stateManager.getCurrentState();
|
|
562
549
|
if (!state)
|
|
563
550
|
return null;
|
|
564
551
|
const currentState = ActionResult.fromState(state);
|
|
@@ -579,8 +566,7 @@ export class Driller extends TaskAgent {
|
|
|
579
566
|
`;
|
|
580
567
|
}
|
|
581
568
|
async getVisibleOverlayHtml() {
|
|
582
|
-
|
|
583
|
-
return page.evaluate(({ extractorSource, config }) => {
|
|
569
|
+
return this.explorer.withPage((page) => page.evaluate(({ extractorSource, config }) => {
|
|
584
570
|
const extract = new Function(`return ${extractorSource}`)();
|
|
585
571
|
return extract(config);
|
|
586
572
|
}, {
|
|
@@ -591,11 +577,10 @@ export class Driller extends TaskAgent {
|
|
|
591
577
|
overlaySelectors: HTML_SELECTORS.semanticOverlays,
|
|
592
578
|
visibilityLimits: HTML_VISIBILITY_LIMITS,
|
|
593
579
|
},
|
|
594
|
-
});
|
|
580
|
+
}));
|
|
595
581
|
}
|
|
596
582
|
async getComponentScopeHtml(component, originalState) {
|
|
597
|
-
const
|
|
598
|
-
const scopedHtml = await page.evaluate(({ eidx, extractorSource, config }) => {
|
|
583
|
+
const scopedHtml = await this.explorer.withPage((page) => page.evaluate(({ eidx, extractorSource, config }) => {
|
|
599
584
|
const extract = new Function(`return ${extractorSource}`)();
|
|
600
585
|
return extract(eidx, config);
|
|
601
586
|
}, {
|
|
@@ -606,7 +591,7 @@ export class Driller extends TaskAgent {
|
|
|
606
591
|
interactiveControlSelector: HTML_SELECTORS.interactiveControl,
|
|
607
592
|
limits: HTML_EXTRACTION_LIMITS,
|
|
608
593
|
},
|
|
609
|
-
});
|
|
594
|
+
}));
|
|
610
595
|
if (scopedHtml)
|
|
611
596
|
return scopedHtml;
|
|
612
597
|
return await originalState.combinedHtml();
|
|
@@ -4,8 +4,8 @@ import { ActionResult } from "../../action-result.js";
|
|
|
4
4
|
import { ConfigParser } from "../../config.js";
|
|
5
5
|
import { tag } from "../../utils/logger.js";
|
|
6
6
|
import { relativeToCwd } from "../../utils/next-steps.js";
|
|
7
|
-
import { safeFilename } from "../../utils/strings.js";
|
|
8
7
|
import { CODECEPT_TOOLS, isNonReusableCode, stripComments } from "../../utils/step-analyzer.js";
|
|
8
|
+
import { safeFilename } from "../../utils/strings.js";
|
|
9
9
|
import { ASSERTION_TOOLS } from "../tools.js";
|
|
10
10
|
import { escapeString, getExecutionLabel } from "./utils.js";
|
|
11
11
|
export function WithCodeceptJS(Base) {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import type Explorer from '../../explorer.js';
|
|
2
2
|
import { type PlaywrightRecorder } from '../../playwright-recorder.js';
|
|
3
|
+
import type { StateManager } from '../../state-manager.js';
|
|
3
4
|
import type { Plan } from '../../test-plan.js';
|
|
4
5
|
import type { Conversation } from '../conversation.js';
|
|
5
6
|
import type { Constructor } from './mixin.js';
|
|
@@ -11,7 +12,7 @@ export declare function WithPlaywright<T extends Constructor>(Base: T): {
|
|
|
11
12
|
new (...args: any[]): {
|
|
12
13
|
playwright: {
|
|
13
14
|
recorder: PlaywrightRecorder;
|
|
14
|
-
|
|
15
|
+
explorer: Explorer;
|
|
15
16
|
} | undefined;
|
|
16
17
|
savedFiles: Set<string>;
|
|
17
18
|
stateManager?: StateManager;
|
|
@@ -5,8 +5,8 @@ import { ConfigParser } from "../../config.js";
|
|
|
5
5
|
import { renderAssertion, renderCall } from "../../playwright-recorder.js";
|
|
6
6
|
import { tag } from "../../utils/logger.js";
|
|
7
7
|
import { relativeToCwd } from "../../utils/next-steps.js";
|
|
8
|
-
import { safeFilename } from "../../utils/strings.js";
|
|
9
8
|
import { CODECEPT_TOOLS } from "../../utils/step-analyzer.js";
|
|
9
|
+
import { safeFilename } from "../../utils/strings.js";
|
|
10
10
|
import { ASSERTION_TOOLS } from "../tools.js";
|
|
11
11
|
import { escapeString, getExecutionLabel } from "./utils.js";
|
|
12
12
|
const PLAYWRIGHT_EMITTED_TOOLS = [...CODECEPT_TOOLS, ...ASSERTION_TOOLS];
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ExplorbotConfig } from '../../config.js';
|
|
2
|
+
import type Explorer from '../../explorer.js';
|
|
2
3
|
import type { PlaywrightRecorder } from '../../playwright-recorder.js';
|
|
3
4
|
import { type Constructor } from './mixin.js';
|
|
4
5
|
export interface ScreencastMethods {
|
|
@@ -12,7 +13,7 @@ export declare function WithScreencast<T extends Constructor>(Base: T): {
|
|
|
12
13
|
savedFiles: Set<string>;
|
|
13
14
|
playwright: {
|
|
14
15
|
recorder: PlaywrightRecorder;
|
|
15
|
-
|
|
16
|
+
explorer: Explorer;
|
|
16
17
|
} | undefined;
|
|
17
18
|
screencastPage: any;
|
|
18
19
|
screencastActive: boolean;
|
|
@@ -27,7 +27,7 @@ export function WithScreencast(Base) {
|
|
|
27
27
|
return;
|
|
28
28
|
if (!this.config?.ai?.agents?.historian?.screencast)
|
|
29
29
|
return;
|
|
30
|
-
if (!this.playwright?.
|
|
30
|
+
if (!this.playwright?.explorer)
|
|
31
31
|
return;
|
|
32
32
|
this.onTestBefore = (test) => {
|
|
33
33
|
void this.startScreencast(test);
|
|
@@ -46,7 +46,7 @@ export function WithScreencast(Base) {
|
|
|
46
46
|
async startScreencast(test) {
|
|
47
47
|
if (this.screencastActive)
|
|
48
48
|
return;
|
|
49
|
-
const page = this.playwright?.
|
|
49
|
+
const page = this.playwright?.explorer?.page;
|
|
50
50
|
if (!page?.screencast?.start)
|
|
51
51
|
return;
|
|
52
52
|
const task = test?._explorbotTest;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { ExplorbotConfig } from '../config.js';
|
|
2
2
|
import type { ExperienceTracker } from '../experience-tracker.js';
|
|
3
|
+
import type Explorer from '../explorer.js';
|
|
3
4
|
import type { PlaywrightRecorder } from '../playwright-recorder.js';
|
|
4
5
|
import type { Reporter } from '../reporter.js';
|
|
5
6
|
import type { StateManager } from '../state-manager.js';
|
|
@@ -15,7 +16,7 @@ declare const HistorianBase: {
|
|
|
15
16
|
savedFiles: Set<string>;
|
|
16
17
|
playwright: {
|
|
17
18
|
recorder: PlaywrightRecorder;
|
|
18
|
-
|
|
19
|
+
explorer: Explorer;
|
|
19
20
|
};
|
|
20
21
|
screencastPage: any;
|
|
21
22
|
screencastActive: boolean;
|
|
@@ -36,7 +37,7 @@ declare const HistorianBase: {
|
|
|
36
37
|
new (...args: any[]): {
|
|
37
38
|
playwright: {
|
|
38
39
|
recorder: PlaywrightRecorder;
|
|
39
|
-
|
|
40
|
+
explorer: Explorer;
|
|
40
41
|
};
|
|
41
42
|
savedFiles: Set<string>;
|
|
42
43
|
stateManager?: StateManager;
|
|
@@ -91,12 +92,12 @@ export declare class Historian extends HistorianBase {
|
|
|
91
92
|
config: ExplorbotConfig | undefined;
|
|
92
93
|
playwright: {
|
|
93
94
|
recorder: PlaywrightRecorder;
|
|
94
|
-
|
|
95
|
+
explorer: Explorer;
|
|
95
96
|
} | undefined;
|
|
96
97
|
savedFiles: Set<string>;
|
|
97
98
|
constructor(provider: Provider, experienceTracker: ExperienceTracker, reporter?: Reporter, stateManager?: StateManager, config?: ExplorbotConfig, playwright?: {
|
|
98
99
|
recorder: PlaywrightRecorder;
|
|
99
|
-
|
|
100
|
+
explorer: Explorer;
|
|
100
101
|
});
|
|
101
102
|
isPlaywrightFramework(): boolean;
|
|
102
103
|
getSavedFiles(): string[];
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { ActionResult } from '../action-result.js';
|
|
2
2
|
import type Action from '../action.js';
|
|
3
|
+
import type { ExplorbotConfig } from '../config.js';
|
|
3
4
|
import type { ExperienceTracker } from '../experience-tracker.js';
|
|
4
5
|
import Explorer from '../explorer.js';
|
|
5
6
|
import type { KnowledgeTracker } from '../knowledge-tracker.js';
|
|
7
|
+
import { type StateManager } from '../state-manager.js';
|
|
6
8
|
import { HooksRunner } from '../utils/hooks-runner.js';
|
|
7
|
-
import type { Agent } from './agent.js';
|
|
9
|
+
import type { Agent, AgentDeps } from './agent.js';
|
|
8
10
|
import type { Provider } from './provider.js';
|
|
9
11
|
declare class Navigator implements Agent {
|
|
10
12
|
emoji: string;
|
|
@@ -16,7 +18,9 @@ declare class Navigator implements Agent {
|
|
|
16
18
|
systemPrompt: string;
|
|
17
19
|
freeSailSystemPrompt: string;
|
|
18
20
|
explorer: Explorer;
|
|
19
|
-
|
|
21
|
+
config: ExplorbotConfig;
|
|
22
|
+
stateManager: StateManager;
|
|
23
|
+
constructor(deps: AgentDeps);
|
|
20
24
|
get verifyAttempts(): number;
|
|
21
25
|
get verifyTimeout(): number;
|
|
22
26
|
getBaseOrigin(): string | null;
|
package/dist/src/ai/navigator.js
CHANGED
|
@@ -59,21 +59,25 @@ class Navigator {
|
|
|
59
59
|
</rules>
|
|
60
60
|
`;
|
|
61
61
|
explorer;
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
this.
|
|
66
|
-
this.
|
|
67
|
-
this.
|
|
62
|
+
config;
|
|
63
|
+
stateManager;
|
|
64
|
+
constructor(deps) {
|
|
65
|
+
this.provider = deps.ai;
|
|
66
|
+
this.explorer = deps.explorer;
|
|
67
|
+
this.config = deps.config;
|
|
68
|
+
this.stateManager = deps.stateManager;
|
|
69
|
+
this.knowledgeTracker = deps.knowledgeTracker;
|
|
70
|
+
this.experienceTracker = deps.stateManager.getExperienceTracker();
|
|
71
|
+
this.hooksRunner = new HooksRunner(deps.explorer, deps.config);
|
|
68
72
|
}
|
|
69
73
|
get verifyAttempts() {
|
|
70
|
-
return this.
|
|
74
|
+
return this.config.ai?.agents?.navigator?.verifyAttempts ?? 3;
|
|
71
75
|
}
|
|
72
76
|
get verifyTimeout() {
|
|
73
|
-
return this.
|
|
77
|
+
return this.config.ai?.agents?.navigator?.verifyTimeout ?? 1500;
|
|
74
78
|
}
|
|
75
79
|
getBaseOrigin() {
|
|
76
|
-
const baseUrl = this.
|
|
80
|
+
const baseUrl = this.config.playwright.url;
|
|
77
81
|
try {
|
|
78
82
|
return new URL(baseUrl).origin;
|
|
79
83
|
}
|
|
@@ -117,11 +121,11 @@ class Navigator {
|
|
|
117
121
|
return normalizeUrl(currentUrl) === normalizeUrl(expectedUrl);
|
|
118
122
|
}
|
|
119
123
|
async visit(url) {
|
|
120
|
-
return this.
|
|
124
|
+
return this.visitOnce(url);
|
|
121
125
|
}
|
|
122
126
|
async visitOnce(url) {
|
|
123
127
|
try {
|
|
124
|
-
const action = this.explorer.
|
|
128
|
+
const action = this.explorer.action();
|
|
125
129
|
await action.execute(`I.amOnPage('${url}')`);
|
|
126
130
|
const currentUrl = action.stateManager.getCurrentState()?.url || '';
|
|
127
131
|
if (currentUrl === 'about:blank' || currentUrl === '') {
|
|
@@ -149,7 +153,7 @@ class Navigator {
|
|
|
149
153
|
throw new Error(`Navigation to ${url} failed: ${action.lastError?.message}`);
|
|
150
154
|
}
|
|
151
155
|
}
|
|
152
|
-
await this.explorer.
|
|
156
|
+
await this.explorer.capture({ screenshot: true });
|
|
153
157
|
await this.hooksRunner.runAfterHook('navigator', url);
|
|
154
158
|
}
|
|
155
159
|
catch (error) {
|
|
@@ -165,7 +169,7 @@ class Navigator {
|
|
|
165
169
|
async resolveState(message, actionResult, opts) {
|
|
166
170
|
tag('info').log('AI Navigator resolving state at', actionResult.url);
|
|
167
171
|
debugLog('Resolution message:', message);
|
|
168
|
-
const action = opts?.action ?? this.explorer.
|
|
172
|
+
const action = opts?.action ?? this.explorer.action();
|
|
169
173
|
const expectedUrl = opts?.expectedUrl;
|
|
170
174
|
const knowledge = this.knowledgeTracker.renderRelevantKnowledge(actionResult);
|
|
171
175
|
let experience = '';
|
|
@@ -310,7 +314,7 @@ class Navigator {
|
|
|
310
314
|
}
|
|
311
315
|
codeBlockIndex++;
|
|
312
316
|
totalAttempts++;
|
|
313
|
-
await
|
|
317
|
+
await action.exitIframe();
|
|
314
318
|
const prevActionResult = action.actionResult ?? actionResult;
|
|
315
319
|
const prevHash = prevActionResult.getStateHash();
|
|
316
320
|
debugLog(`Attempting resolution: ${codeBlock}`);
|
|
@@ -339,7 +343,7 @@ class Navigator {
|
|
|
339
343
|
// URL did not transition to expectedUrl within timeout
|
|
340
344
|
}
|
|
341
345
|
}
|
|
342
|
-
const freshState = await this.explorer.
|
|
346
|
+
const freshState = await this.explorer.capture();
|
|
343
347
|
const currentUrl = /^https?:\/\//i.test(expectedUrl) ? freshState.fullUrl || freshState.url || '' : freshState.url || '';
|
|
344
348
|
const urlMatches = this.isSameExpectedOrigin(expectedUrl, action.stateManager) && normalizeUrl(currentUrl) === normalizeUrl(expectedUrl);
|
|
345
349
|
const stateChanged = freshState.getStateHash() !== actionResult.getStateHash();
|
|
@@ -434,7 +438,7 @@ class Navigator {
|
|
|
434
438
|
buildExperienceTools() {
|
|
435
439
|
if (!this.experienceTracker)
|
|
436
440
|
return undefined;
|
|
437
|
-
const stateManager = this.
|
|
441
|
+
const stateManager = this.stateManager;
|
|
438
442
|
const getState = () => {
|
|
439
443
|
const s = stateManager.getCurrentState();
|
|
440
444
|
return s ? ActionResult.fromState(s) : null;
|
|
@@ -442,7 +446,7 @@ class Navigator {
|
|
|
442
446
|
return { learnExperience: createLearnExperienceTool({ getExperienceTracker: () => this.experienceTracker, getState }) };
|
|
443
447
|
}
|
|
444
448
|
async freeSail(opts, actionResult) {
|
|
445
|
-
const stateManager = this.
|
|
449
|
+
const stateManager = this.stateManager;
|
|
446
450
|
const state = stateManager.getCurrentState();
|
|
447
451
|
if (!state) {
|
|
448
452
|
return null;
|
|
@@ -620,10 +624,10 @@ class Navigator {
|
|
|
620
624
|
let codeBlocks = [];
|
|
621
625
|
const successfulCodes = [];
|
|
622
626
|
const assertionSteps = [];
|
|
623
|
-
const action = this.explorer.
|
|
627
|
+
const action = this.explorer.action();
|
|
624
628
|
let failures = 0;
|
|
625
|
-
const page = this.explorer.
|
|
626
|
-
const originalTimeout = this.
|
|
629
|
+
const page = this.explorer.page;
|
|
630
|
+
const originalTimeout = this.config.playwright.timeout ?? 3000;
|
|
627
631
|
page?.setDefaultTimeout(this.verifyTimeout);
|
|
628
632
|
try {
|
|
629
633
|
await loop(async ({ stop, iteration }) => {
|
|
@@ -649,7 +653,7 @@ class Navigator {
|
|
|
649
653
|
stop();
|
|
650
654
|
return;
|
|
651
655
|
}
|
|
652
|
-
await
|
|
656
|
+
await action.exitIframe();
|
|
653
657
|
const verified = await action.attempt(codeBlock, message);
|
|
654
658
|
if (verified) {
|
|
655
659
|
tag('success').log('Verification passed');
|
|
@@ -683,7 +687,7 @@ class Navigator {
|
|
|
683
687
|
if (alreadyVerified)
|
|
684
688
|
verified = true;
|
|
685
689
|
actionResult.addVerification(message, verified);
|
|
686
|
-
this.
|
|
690
|
+
this.stateManager.updateState(actionResult);
|
|
687
691
|
return { verified, successfulCodes, assertionSteps, totalAttempted };
|
|
688
692
|
}
|
|
689
693
|
checkAlreadyVerified(aiResponse, actionResult) {
|
package/dist/src/ai/pilot.d.ts
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { ActionResult } from '../action-result.js';
|
|
2
|
+
import type { RequestStore } from '../api/request-store.js';
|
|
2
3
|
import type Explorer from '../explorer.js';
|
|
4
|
+
import type { PlaywrightRecorder } from '../playwright-recorder.js';
|
|
5
|
+
import type { StateManager } from '../state-manager.js';
|
|
3
6
|
import { type Test } from '../test-plan.js';
|
|
4
|
-
import type { Agent } from './agent.js';
|
|
7
|
+
import type { Agent, AgentDeps } from './agent.js';
|
|
5
8
|
import type { Conversation } from './conversation.js';
|
|
6
9
|
import type { Fisherman } from './fisherman.js';
|
|
7
10
|
import type { Navigator } from './navigator.js';
|
|
@@ -14,8 +17,11 @@ export declare class Pilot implements Agent {
|
|
|
14
17
|
conversation: Conversation | null;
|
|
15
18
|
researcher: Researcher;
|
|
16
19
|
explorer: Explorer;
|
|
20
|
+
stateManager: StateManager;
|
|
21
|
+
requestStore: RequestStore;
|
|
22
|
+
playwrightRecorder: PlaywrightRecorder;
|
|
17
23
|
fisherman: Fisherman | null;
|
|
18
|
-
constructor(
|
|
24
|
+
constructor(deps: AgentDeps, agentTools: any, researcher: Researcher);
|
|
19
25
|
setFisherman(fisherman: Fisherman): void;
|
|
20
26
|
get stepsToReview(): number;
|
|
21
27
|
reset(): void;
|
|
@@ -27,17 +33,18 @@ export declare class Pilot implements Agent {
|
|
|
27
33
|
reviewReset(task: Test, currentState: ActionResult, reason: string, testerConversation: Conversation): Promise<boolean>;
|
|
28
34
|
reviewDecision(type: 'finish' | 'stop', task: Test, currentState: ActionResult, testerConversation: Conversation, navigator?: Navigator): Promise<boolean>;
|
|
29
35
|
reviewResetDecision(task: Test, currentState: ActionResult, reason: string, testerConversation: Conversation): Promise<boolean>;
|
|
30
|
-
buildSharedEvidenceRules(
|
|
36
|
+
buildSharedEvidenceRules(): string;
|
|
37
|
+
buildTaskContext(task: Test): string;
|
|
31
38
|
buildResetSystemPrompt(task: Test): string;
|
|
32
|
-
buildVerdictSystemPrompt(
|
|
39
|
+
buildVerdictSystemPrompt(task: Test): string;
|
|
33
40
|
planTest(task: Test, currentState: ActionResult): Promise<string>;
|
|
34
41
|
reviewNewPage(task: Test, currentState: ActionResult, testerConversation: Conversation): Promise<string>;
|
|
35
42
|
analyzeProgress(task: Test, currentState: ActionResult, testerConversation: Conversation): Promise<string>;
|
|
36
43
|
formatExpectations(task: Test): string;
|
|
37
|
-
sendToPilot(userText: string, functionId: string, opts
|
|
44
|
+
sendToPilot(userText: string, functionId: string, opts: {
|
|
38
45
|
tools?: boolean;
|
|
39
46
|
maxToolRoundtrips?: number;
|
|
40
|
-
task
|
|
47
|
+
task: Test;
|
|
41
48
|
}): Promise<string>;
|
|
42
49
|
getExperienceToc(): string;
|
|
43
50
|
pickPlanningTools(): Record<string, unknown>;
|