explorbot 0.1.32-beta.1 → 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 +35 -19
- package/bin/explorbot-cli.ts +33 -10
- package/boat/api-tester/src/config.ts +45 -3
- package/boat/doc-collector/src/ai/documentarian.ts +26 -28
- package/boat/doc-collector/src/ai/tools.ts +74 -16
- package/boat/doc-collector/src/cli.ts +1 -6
- package/boat/doc-collector/src/docbot.ts +30 -9
- package/boat/doc-collector/src/docs-renderer.ts +19 -24
- package/boat/doc-collector/src/screenshots.ts +34 -2
- package/boat/doc-collector/src/state-diagram.ts +281 -0
- package/dist/bin/explorbot-cli.js +29 -9
- package/dist/boat/api-tester/src/config.js +43 -4
- package/dist/boat/doc-collector/src/ai/documentarian.js +19 -7
- package/dist/boat/doc-collector/src/ai/tools.js +53 -16
- package/dist/boat/doc-collector/src/cli.js +1 -5
- package/dist/boat/doc-collector/src/docbot.js +27 -8
- package/dist/boat/doc-collector/src/docs-renderer.js +18 -3
- package/dist/boat/doc-collector/src/screenshots.js +30 -1
- package/dist/boat/doc-collector/src/state-diagram.js +200 -0
- package/dist/models.json +30 -0
- package/dist/package.json +23 -3
- package/dist/src/action-result.d.ts +8 -10
- package/dist/src/action-result.js +72 -164
- package/dist/src/action.d.ts +13 -12
- package/dist/src/action.js +37 -113
- 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 -29
- package/dist/src/ai/captain.d.ts +1 -3
- package/dist/src/ai/captain.js +17 -45
- package/dist/src/ai/conversation.d.ts +2 -5
- package/dist/src/ai/conversation.js +9 -28
- package/dist/src/ai/driller.d.ts +2 -17
- package/dist/src/ai/driller.js +26 -50
- package/dist/src/ai/experience-compactor.d.ts +2 -2
- package/dist/src/ai/experience-compactor.js +16 -33
- package/dist/src/ai/fisherman-tools.js +1 -1
- package/dist/src/ai/fisherman.d.ts +0 -1
- package/dist/src/ai/fisherman.js +0 -3
- package/dist/src/ai/historian/codeceptjs.d.ts +2 -0
- package/dist/src/ai/historian/codeceptjs.js +4 -3
- package/dist/src/ai/historian/playwright.d.ts +4 -1
- package/dist/src/ai/historian/playwright.js +4 -3
- package/dist/src/ai/historian/screencast.d.ts +2 -1
- package/dist/src/ai/historian/screencast.js +2 -2
- package/dist/src/ai/historian/utils.d.ts +0 -1
- package/dist/src/ai/historian/utils.js +0 -1
- package/dist/src/ai/historian.d.ts +10 -8
- package/dist/src/ai/historian.js +1 -5
- package/dist/src/ai/navigator.d.ts +8 -6
- package/dist/src/ai/navigator.js +34 -65
- package/dist/src/ai/pilot.d.ts +13 -8
- package/dist/src/ai/pilot.js +53 -59
- package/dist/src/ai/planner.d.ts +5 -4
- package/dist/src/ai/planner.js +66 -52
- package/dist/src/ai/provider.d.ts +4 -1
- package/dist/src/ai/provider.js +77 -137
- package/dist/src/ai/quartermaster.d.ts +22 -22
- package/dist/src/ai/quartermaster.js +8 -14
- package/dist/src/ai/rerunner.d.ts +3 -13
- package/dist/src/ai/rerunner.js +23 -44
- package/dist/src/ai/researcher/cache.js +11 -18
- 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 +8 -11
- package/dist/src/ai/researcher/locators.d.ts +9 -2
- package/dist/src/ai/researcher/locators.js +65 -8
- package/dist/src/ai/researcher/parser.js +1 -1
- package/dist/src/ai/researcher/research-result.d.ts +0 -1
- package/dist/src/ai/researcher/research-result.js +0 -19
- package/dist/src/ai/researcher/sections.d.ts +2 -0
- package/dist/src/ai/researcher/sections.js +7 -3
- package/dist/src/ai/researcher.js +40 -106
- package/dist/src/ai/rules.d.ts +1 -0
- package/dist/src/ai/rules.js +22 -15
- package/dist/src/ai/session-analyst.js +8 -5
- package/dist/src/ai/task-agent.d.ts +19 -6
- package/dist/src/ai/task-agent.js +37 -33
- package/dist/src/ai/tester.d.ts +6 -14
- package/dist/src/ai/tester.js +46 -111
- package/dist/src/ai/tools.d.ts +26 -14
- package/dist/src/ai/tools.js +138 -132
- package/dist/src/command-handler.js +1 -1
- package/dist/src/commands/compact-command.d.ts +1 -1
- package/dist/src/commands/compact-command.js +6 -6
- package/dist/src/commands/context-aria-command.js +1 -1
- package/dist/src/commands/context-command.js +8 -6
- 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 +2 -2
- package/dist/src/commands/drill-command.js +1 -1
- package/dist/src/commands/experience-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/knows-command.js +1 -1
- package/dist/src/commands/learn-command.js +5 -3
- 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/AddKnowledge.d.ts +2 -0
- package/dist/src/components/AddKnowledge.js +3 -7
- package/dist/src/components/App.js +3 -3
- package/dist/src/config.d.ts +19 -0
- package/dist/src/config.js +156 -10
- package/dist/src/experience-tracker.d.ts +11 -6
- package/dist/src/experience-tracker.js +82 -155
- package/dist/src/explorbot.d.ts +21 -13
- package/dist/src/explorbot.js +84 -80
- package/dist/src/explorer.d.ts +66 -102
- package/dist/src/explorer.js +332 -623
- package/dist/src/knowledge-tracker.d.ts +2 -2
- package/dist/src/knowledge-tracker.js +38 -45
- package/dist/src/state-manager.d.ts +10 -30
- package/dist/src/state-manager.js +11 -129
- package/dist/src/utils/aria.d.ts +6 -1
- package/dist/src/utils/aria.js +4 -1
- package/dist/src/utils/cache.d.ts +15 -0
- package/dist/src/utils/cache.js +34 -0
- package/dist/src/utils/context-formatter.d.ts +6 -0
- package/dist/src/utils/context-formatter.js +15 -27
- package/dist/src/utils/hooks-runner.js +2 -4
- package/dist/src/utils/html.d.ts +5 -0
- package/dist/src/utils/html.js +71 -0
- package/dist/src/utils/markdown-files.d.ts +10 -0
- package/dist/src/utils/markdown-files.js +21 -0
- package/dist/src/utils/markdown-query.d.ts +6 -0
- package/dist/src/utils/markdown-query.js +14 -1
- package/dist/src/utils/page-readiness.d.ts +1 -0
- package/dist/src/utils/page-readiness.js +1 -1
- package/dist/src/utils/secrets.js +2 -2
- package/dist/src/utils/strings.d.ts +2 -0
- package/dist/src/utils/strings.js +10 -0
- 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 +3 -1
- package/dist/src/utils/web-element.js +32 -0
- package/dist/src/utils/web-sandbox.d.ts +4 -0
- package/dist/src/utils/web-sandbox.js +37 -0
- package/models.json +30 -0
- package/package.json +23 -3
- package/src/action-result.ts +70 -173
- package/src/action.ts +38 -132
- 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 -30
- package/src/ai/captain.ts +17 -42
- package/src/ai/conversation.ts +9 -32
- package/src/ai/driller.ts +53 -83
- package/src/ai/experience-compactor.ts +16 -35
- package/src/ai/fisherman-tools.ts +1 -1
- package/src/ai/fisherman.ts +0 -4
- package/src/ai/historian/codeceptjs.ts +5 -3
- package/src/ai/historian/playwright.ts +7 -4
- package/src/ai/historian/screencast.ts +4 -3
- package/src/ai/historian/utils.ts +0 -1
- package/src/ai/historian.ts +6 -8
- package/src/ai/navigator.ts +39 -70
- package/src/ai/pilot.ts +59 -61
- package/src/ai/planner.ts +76 -62
- package/src/ai/provider.ts +85 -146
- package/src/ai/quartermaster.ts +39 -45
- package/src/ai/rerunner.ts +27 -50
- package/src/ai/researcher/cache.ts +10 -16
- package/src/ai/researcher/coordinates.ts +4 -3
- package/src/ai/researcher/deep-analysis.ts +10 -11
- package/src/ai/researcher/locators.ts +66 -9
- package/src/ai/researcher/parser.ts +1 -1
- package/src/ai/researcher/research-result.ts +0 -18
- package/src/ai/researcher/sections.ts +9 -3
- package/src/ai/researcher.ts +42 -119
- package/src/ai/rules.ts +24 -13
- package/src/ai/session-analyst.ts +8 -5
- package/src/ai/task-agent.ts +45 -38
- package/src/ai/tester.ts +51 -129
- package/src/ai/tools.ts +145 -153
- package/src/command-handler.ts +1 -1
- package/src/commands/compact-command.ts +7 -8
- package/src/commands/context-aria-command.ts +1 -1
- package/src/commands/context-command.ts +8 -6
- 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 +2 -2
- package/src/commands/drill-command.ts +1 -1
- package/src/commands/experience-command.ts +1 -1
- package/src/commands/explore-command.ts +4 -3
- package/src/commands/freesail-command.ts +2 -2
- package/src/commands/knows-command.ts +1 -1
- package/src/commands/learn-command.ts +5 -3
- 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/AddKnowledge.tsx +5 -7
- package/src/components/App.tsx +3 -3
- package/src/config.ts +185 -11
- package/src/experience-tracker.ts +89 -152
- package/src/explorbot.ts +88 -83
- package/src/explorer.ts +402 -693
- package/src/knowledge-tracker.ts +42 -49
- package/src/state-manager.ts +20 -155
- package/src/utils/aria.ts +11 -2
- package/src/utils/cache.ts +40 -0
- package/src/utils/context-formatter.ts +12 -15
- package/src/utils/hooks-runner.ts +2 -4
- package/src/utils/html.ts +79 -0
- package/src/utils/markdown-files.ts +30 -0
- package/src/utils/markdown-query.ts +15 -1
- package/src/utils/page-readiness.ts +1 -1
- package/src/utils/secrets.ts +2 -3
- package/src/utils/strings.ts +12 -0
- 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 +34 -0
- package/src/utils/web-sandbox.ts +43 -0
- package/dist/boat/api-tester/example/apibot.config.js +0 -30
package/dist/src/ai/pilot.js
CHANGED
|
@@ -3,7 +3,6 @@ import dedent from 'dedent';
|
|
|
3
3
|
import { z } from 'zod';
|
|
4
4
|
import { ActionResult } from "../action-result.js";
|
|
5
5
|
import { ConfigParser } from "../config.js";
|
|
6
|
-
import { renderExperienceToc } from "../experience-tracker.js";
|
|
7
6
|
import { TestResult } from "../test-plan.js";
|
|
8
7
|
import { collectInteractiveNodes, detectFocusArea, extractFocusedElement } from "../utils/aria.js";
|
|
9
8
|
import { ErrorPageError } from "../utils/error-page.js";
|
|
@@ -21,14 +20,18 @@ export class Pilot {
|
|
|
21
20
|
conversation = null;
|
|
22
21
|
researcher;
|
|
23
22
|
explorer;
|
|
23
|
+
stateManager;
|
|
24
|
+
requestStore;
|
|
25
|
+
playwrightRecorder;
|
|
24
26
|
fisherman = null;
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
this.provider = provider;
|
|
27
|
+
constructor(deps, agentTools, researcher) {
|
|
28
|
+
this.provider = deps.ai;
|
|
28
29
|
this.agentTools = agentTools;
|
|
29
30
|
this.researcher = researcher;
|
|
30
|
-
this.explorer = explorer;
|
|
31
|
-
this.
|
|
31
|
+
this.explorer = deps.explorer;
|
|
32
|
+
this.stateManager = deps.stateManager;
|
|
33
|
+
this.requestStore = deps.requestStore;
|
|
34
|
+
this.playwrightRecorder = deps.playwrightRecorder;
|
|
32
35
|
}
|
|
33
36
|
setFisherman(fisherman) {
|
|
34
37
|
this.fisherman = fisherman;
|
|
@@ -74,7 +77,7 @@ export class Pilot {
|
|
|
74
77
|
let screenshotState = null;
|
|
75
78
|
if (type === 'finish' && this.provider.hasVision()) {
|
|
76
79
|
try {
|
|
77
|
-
screenshotState = await this.explorer.
|
|
80
|
+
screenshotState = await this.explorer.capture({ screenshot: true });
|
|
78
81
|
if (screenshotState.screenshot) {
|
|
79
82
|
visualAnalysis = (await this.researcher.answerQuestionAboutScreenshot(screenshotState, `Describe current page state relevant to: ${task.scenario}`)) || '';
|
|
80
83
|
}
|
|
@@ -90,7 +93,7 @@ export class Pilot {
|
|
|
90
93
|
requestVerification: z
|
|
91
94
|
.string()
|
|
92
95
|
.nullable()
|
|
93
|
-
.describe('REQUIRED whenever decision is "pass" — a one-sentence natural-language claim about the current page that, if true, proves the scenario goal (e.g., "New
|
|
96
|
+
.describe('REQUIRED whenever decision is "pass" — a one-sentence natural-language claim about the current page that, if true, proves the scenario goal (e.g., "New item \\"Foo\\" is visible in the items list"). NOT code: do not write I.*, expect(), .then(), grabTitle, or any JavaScript. Navigator translates the claim into CodeceptJS assertions and runs them; passing assertions are saved to the generated test file. Also use when evidence is insufficient before deciding pass/fail. Leave null for "continue", "fail", or "skipped".'),
|
|
94
97
|
});
|
|
95
98
|
const userContent = dedent `
|
|
96
99
|
Tester wants to ${type} the test.
|
|
@@ -124,7 +127,7 @@ export class Pilot {
|
|
|
124
127
|
- Mixed evidence + final state shows success → pass. Mixed + final state unclear → continue with guidance.
|
|
125
128
|
|
|
126
129
|
When deciding "pass", you MUST also set requestVerification to a one-sentence natural-language
|
|
127
|
-
claim about the current page (e.g., "New
|
|
130
|
+
claim about the current page (e.g., "New item Foo is visible in the items list"). NOT
|
|
128
131
|
code — do not write I.*, expect(), .then(), or any JavaScript. Choose the strongest single
|
|
129
132
|
piece of evidence (a unique element/text that exists ONLY because the scenario succeeded).
|
|
130
133
|
Navigator translates the claim into CodeceptJS assertions; without it the generated test has
|
|
@@ -133,7 +136,7 @@ export class Pilot {
|
|
|
133
136
|
const messages = [
|
|
134
137
|
{
|
|
135
138
|
role: 'system',
|
|
136
|
-
content: this.buildVerdictSystemPrompt(
|
|
139
|
+
content: this.buildVerdictSystemPrompt(task),
|
|
137
140
|
},
|
|
138
141
|
{ role: 'user', content: userContent },
|
|
139
142
|
];
|
|
@@ -151,7 +154,7 @@ export class Pilot {
|
|
|
151
154
|
tag('substep').log(`Pilot requesting verification: ${result.requestVerification}`);
|
|
152
155
|
const verifyResult = await navigator.verifyState(result.requestVerification, currentState).catch(() => null);
|
|
153
156
|
if (verifyResult?.verified && verifyResult.assertionSteps?.length) {
|
|
154
|
-
this.
|
|
157
|
+
this.playwrightRecorder.recordVerification(verifyResult.assertionSteps);
|
|
155
158
|
}
|
|
156
159
|
}
|
|
157
160
|
tag('info').log(`Pilot: ${result.decision} - ${result.reason}`);
|
|
@@ -261,10 +264,8 @@ export class Pilot {
|
|
|
261
264
|
return true;
|
|
262
265
|
}
|
|
263
266
|
}
|
|
264
|
-
buildSharedEvidenceRules(
|
|
267
|
+
buildSharedEvidenceRules() {
|
|
265
268
|
return dedent `
|
|
266
|
-
SCENARIO: ${task.scenario}
|
|
267
|
-
|
|
268
269
|
EVIDENCE PRIORITY (strict):
|
|
269
270
|
1) Final observable state proving the scenario goal
|
|
270
271
|
2) verify()/see() results in the LAST few actions before stop/finish
|
|
@@ -297,6 +298,11 @@ export class Pilot {
|
|
|
297
298
|
|
|
298
299
|
Expected results are MILESTONES, not the goal. Never fail because a milestone (toast, icon, styling)
|
|
299
300
|
didn't match if the scenario goal IS accomplished.
|
|
301
|
+
`;
|
|
302
|
+
}
|
|
303
|
+
buildTaskContext(task) {
|
|
304
|
+
return dedent `
|
|
305
|
+
SCENARIO: ${task.scenario}
|
|
300
306
|
|
|
301
307
|
${this.buildDeletionScope(task)}
|
|
302
308
|
|
|
@@ -310,7 +316,7 @@ export class Pilot {
|
|
|
310
316
|
iteration's work, but server-side side effects (records created, forms submitted) persist.
|
|
311
317
|
Unnecessary resets create duplicate data and infinite loops.
|
|
312
318
|
|
|
313
|
-
${this.buildSharedEvidenceRules(
|
|
319
|
+
${this.buildSharedEvidenceRules()}
|
|
314
320
|
|
|
315
321
|
DECISION:
|
|
316
322
|
- "allow": current page cannot host the scenario, irrecoverable error, or no path back.
|
|
@@ -327,16 +333,18 @@ export class Pilot {
|
|
|
327
333
|
to verify, how to record. Do not suggest repeating actions that already succeeded.
|
|
328
334
|
If progress is blocked only because the page lacks target data for the scenario, prefer precondition()
|
|
329
335
|
over repeated UI attempts.
|
|
336
|
+
|
|
337
|
+
${this.buildTaskContext(task)}
|
|
330
338
|
`;
|
|
331
339
|
}
|
|
332
|
-
buildVerdictSystemPrompt(
|
|
340
|
+
buildVerdictSystemPrompt(task) {
|
|
333
341
|
return dedent `
|
|
334
|
-
You are Pilot — final decision maker for test pass/fail.
|
|
335
|
-
|
|
342
|
+
You are Pilot — final decision maker for test pass/fail. Review the evidence and commit to a
|
|
343
|
+
verdict; "continue" only when evidence is genuinely insufficient.
|
|
336
344
|
|
|
337
345
|
${capabilityGroundingRule}
|
|
338
346
|
|
|
339
|
-
${this.buildSharedEvidenceRules(
|
|
347
|
+
${this.buildSharedEvidenceRules()}
|
|
340
348
|
|
|
341
349
|
DECISION:
|
|
342
350
|
- "pass": scenario goal is fully accomplished. Set requestVerification to a one-sentence claim about
|
|
@@ -355,6 +363,8 @@ export class Pilot {
|
|
|
355
363
|
reason field: one short sentence, maximum 120 characters. Do NOT restate the decision
|
|
356
364
|
("scenario goal achieved/not achieved"). State what happened: what was verified, what failed,
|
|
357
365
|
or what evidence was found.
|
|
366
|
+
|
|
367
|
+
${this.buildTaskContext(task)}
|
|
358
368
|
`;
|
|
359
369
|
}
|
|
360
370
|
async planTest(task, currentState) {
|
|
@@ -379,10 +389,6 @@ export class Pilot {
|
|
|
379
389
|
|
|
380
390
|
FIRST: Decide if precondition() is needed.
|
|
381
391
|
|
|
382
|
-
${capabilityGroundingRule}
|
|
383
|
-
|
|
384
|
-
${dataProtectionRules}
|
|
385
|
-
|
|
386
392
|
Call precondition() WHEN:
|
|
387
393
|
- The scenario edits/deletes/modifies an item, and you want a DISPOSABLE item to act on safely
|
|
388
394
|
- The scenario needs specific data clearly NOT on the current page (e.g., items with specific statuses for filtering)
|
|
@@ -425,8 +431,6 @@ export class Pilot {
|
|
|
425
431
|
.filter((t) => t.wasSuccessful)
|
|
426
432
|
.slice(-this.stepsToReview);
|
|
427
433
|
const actionsContext = this.formatActions(toolCalls);
|
|
428
|
-
this.conversation.cleanupTag('page_summary', '...trimmed...', 1);
|
|
429
|
-
this.conversation.cleanupTag('recent_actions', '...trimmed...', 2);
|
|
430
434
|
return this.sendToPilot(dedent `
|
|
431
435
|
Navigated to new page.
|
|
432
436
|
START URL: ${task.startUrl}
|
|
@@ -446,7 +450,7 @@ export class Pilot {
|
|
|
446
450
|
${this.formatExpectations(task)}
|
|
447
451
|
|
|
448
452
|
First: evaluate whether this navigation makes sense for the scenario goal. If the page is unrelated, instruct Tester to back() or reset(). Then plan next steps.
|
|
449
|
-
`, 'pilot.reviewNewPage');
|
|
453
|
+
`, 'pilot.reviewNewPage', { task });
|
|
450
454
|
}
|
|
451
455
|
async analyzeProgress(task, currentState, testerConversation) {
|
|
452
456
|
tag('substep').log('Pilot analyzing progress...');
|
|
@@ -458,7 +462,6 @@ export class Pilot {
|
|
|
458
462
|
const toolCalls = testerConversation.getToolExecutions().slice(-this.stepsToReview);
|
|
459
463
|
const actionsContext = this.formatActions(toolCalls);
|
|
460
464
|
const stateContext = this.buildStateContext(currentState);
|
|
461
|
-
this.conversation.cleanupTag('recent_actions', '...trimmed...', 2);
|
|
462
465
|
const hasFailures = toolCalls.length === 0 || toolCalls.some((t) => !t.wasSuccessful);
|
|
463
466
|
const text = await this.sendToPilot(dedent `
|
|
464
467
|
START URL: ${task.startUrl}
|
|
@@ -486,7 +489,7 @@ export class Pilot {
|
|
|
486
489
|
const remaining = task.getRemainingExpectations();
|
|
487
490
|
return `CHECKED: ${checked.length > 0 ? checked.join(', ') : 'none'}\nREMAINING: ${remaining.length > 0 ? remaining.join(', ') : 'none'}`;
|
|
488
491
|
}
|
|
489
|
-
async sendToPilot(userText, functionId, opts
|
|
492
|
+
async sendToPilot(userText, functionId, opts) {
|
|
490
493
|
debugLog(`sendToPilot: ${functionId}, tools: ${!!opts.tools}, roundtrips: ${opts.maxToolRoundtrips ?? 0}`);
|
|
491
494
|
let finalUserText = userText;
|
|
492
495
|
if (opts.tools) {
|
|
@@ -496,17 +499,12 @@ export class Pilot {
|
|
|
496
499
|
}
|
|
497
500
|
}
|
|
498
501
|
this.conversation.addUserText(finalUserText);
|
|
499
|
-
|
|
500
|
-
if (opts.tools) {
|
|
501
|
-
tools = this.pickPlanningTools();
|
|
502
|
-
}
|
|
503
|
-
if (opts.tools && opts.task) {
|
|
504
|
-
tools = { ...tools, ...this.buildPreconditionTool(opts.task) };
|
|
505
|
-
}
|
|
502
|
+
const tools = { ...this.pickPlanningTools(), ...this.buildPreconditionTool(opts.task) };
|
|
506
503
|
const result = await this.provider.invokeConversation(this.conversation, tools, {
|
|
507
504
|
maxToolRoundtrips: opts.maxToolRoundtrips ?? 0,
|
|
505
|
+
toolChoice: opts.tools ? 'auto' : 'none',
|
|
508
506
|
agentName: 'pilot',
|
|
509
|
-
stopWhen:
|
|
507
|
+
stopWhen: () => opts.task.hasFinished,
|
|
510
508
|
telemetry: { functionId },
|
|
511
509
|
});
|
|
512
510
|
const text = result?.response?.text || '';
|
|
@@ -525,14 +523,10 @@ export class Pilot {
|
|
|
525
523
|
`;
|
|
526
524
|
}
|
|
527
525
|
getExperienceToc() {
|
|
528
|
-
|
|
529
|
-
return '';
|
|
530
|
-
const state = this.explorer.getStateManager().getCurrentState();
|
|
526
|
+
const state = this.stateManager.getCurrentState();
|
|
531
527
|
if (!state)
|
|
532
528
|
return '';
|
|
533
|
-
|
|
534
|
-
const toc = this.experienceTracker.getExperienceTableOfContents(actionResult);
|
|
535
|
-
return renderExperienceToc(toc);
|
|
529
|
+
return this.stateManager.getExperienceTracker().renderExperienceTocFor(ActionResult.fromState(state));
|
|
536
530
|
}
|
|
537
531
|
pickPlanningTools() {
|
|
538
532
|
const { see, context, verify, research, getVisitedStates, xpathCheck, learnExperience, askUser } = this.agentTools ?? {};
|
|
@@ -600,7 +594,7 @@ export class Pilot {
|
|
|
600
594
|
async checkDataAvailability(task, requestedData, fishermanReason) {
|
|
601
595
|
if (!this.provider.hasVision())
|
|
602
596
|
return null;
|
|
603
|
-
const screenshotState = await this.explorer.
|
|
597
|
+
const screenshotState = await this.explorer.capture({ screenshot: true }).catch(() => null);
|
|
604
598
|
if (!screenshotState?.screenshot)
|
|
605
599
|
return null;
|
|
606
600
|
const question = dedent `
|
|
@@ -646,8 +640,8 @@ export class Pilot {
|
|
|
646
640
|
else {
|
|
647
641
|
lines.push('modal: none');
|
|
648
642
|
}
|
|
649
|
-
|
|
650
|
-
|
|
643
|
+
const tabs = this.stateManager.otherTabs;
|
|
644
|
+
if (tabs.length > 0) {
|
|
651
645
|
lines.push(`other tabs: ${tabs.length} (${tabs.map((t) => `${t.url} - ${t.title}`).join(', ')})`);
|
|
652
646
|
}
|
|
653
647
|
else {
|
|
@@ -669,7 +663,7 @@ export class Pilot {
|
|
|
669
663
|
else {
|
|
670
664
|
lines.push('console errors: none');
|
|
671
665
|
}
|
|
672
|
-
const failedRequests = this.
|
|
666
|
+
const failedRequests = this.requestStore.getFailedRequests();
|
|
673
667
|
if (failedRequests.length > 0) {
|
|
674
668
|
const sample = failedRequests
|
|
675
669
|
.slice(-5)
|
|
@@ -744,7 +738,7 @@ export class Pilot {
|
|
|
744
738
|
}
|
|
745
739
|
formatSessionLog(testerConversation) {
|
|
746
740
|
const executions = testerConversation.getToolExecutions().filter((t) => !META_TOOLS.includes(t.toolName));
|
|
747
|
-
const stateHistory = this.
|
|
741
|
+
const stateHistory = this.stateManager.getStateHistory();
|
|
748
742
|
const initialUrl = stateHistory[0]?.toState?.url || '';
|
|
749
743
|
let currentUrl = initialUrl;
|
|
750
744
|
const groups = new Map();
|
|
@@ -886,16 +880,6 @@ export class Pilot {
|
|
|
886
880
|
return dedent `
|
|
887
881
|
You are Pilot — a supervisor that detects problems and intervenes only when needed.
|
|
888
882
|
|
|
889
|
-
SCENARIO: ${task.scenario}
|
|
890
|
-
START URL: ${initialState.url}
|
|
891
|
-
PAGE: ${initialState.title || ''} | ${initialState.h1 || ''}
|
|
892
|
-
|
|
893
|
-
EXPECTED RESULTS:
|
|
894
|
-
${task.expected.map((e) => `- ${e}`).join('\n')}
|
|
895
|
-
|
|
896
|
-
PLANNED STEPS:
|
|
897
|
-
${stepsText}
|
|
898
|
-
|
|
899
883
|
Your job: plan, review new pages, detect stuck patterns, suggest concrete next steps. Track which
|
|
900
884
|
expectations are checked. When things go well, encourage briefly and let Tester continue. The current
|
|
901
885
|
page is usually richer than the page summary lists — prefer exploring it before navigating away.
|
|
@@ -957,14 +941,24 @@ export class Pilot {
|
|
|
957
941
|
|
|
958
942
|
${dataProtectionRules}
|
|
959
943
|
|
|
960
|
-
Describe WHAT to create, not what exists. RIGHT: precondition("1
|
|
961
|
-
precondition("1
|
|
944
|
+
Describe WHAT to create, not what exists. RIGHT: precondition("1 post"). WRONG:
|
|
945
|
+
precondition("1 post named Updated Post with existing comments"). Keep descriptions short.
|
|
962
946
|
|
|
963
947
|
Response format:
|
|
964
948
|
PROGRESS: <1 sentence assessment>
|
|
965
949
|
NEXT: <specific actionable instruction for Tester>
|
|
966
950
|
|
|
967
951
|
Keep user-facing reasons concise: one short sentence, maximum 120 characters, evidence only, no repeated verdict wording.
|
|
952
|
+
|
|
953
|
+
SCENARIO: ${task.scenario}
|
|
954
|
+
START URL: ${initialState.url}
|
|
955
|
+
PAGE: ${initialState.title || ''} | ${initialState.h1 || ''}
|
|
956
|
+
|
|
957
|
+
EXPECTED RESULTS:
|
|
958
|
+
${task.expected.map((e) => `- ${e}`).join('\n')}
|
|
959
|
+
|
|
960
|
+
PLANNED STEPS:
|
|
961
|
+
${stepsText}
|
|
968
962
|
`;
|
|
969
963
|
}
|
|
970
964
|
}
|
package/dist/src/ai/planner.d.ts
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { ActionResult } from '../action-result.js';
|
|
2
|
-
import { ExperienceTracker } from '../experience-tracker.js';
|
|
2
|
+
import type { ExperienceTracker } from '../experience-tracker.js';
|
|
3
3
|
import type Explorer from '../explorer.js';
|
|
4
4
|
import type { StateManager } from '../state-manager.js';
|
|
5
5
|
import { Suite } from '../suite.js';
|
|
6
6
|
import { Plan, Test } from '../test-plan.js';
|
|
7
|
-
import type { Agent } from './agent.js';
|
|
7
|
+
import type { Agent, AgentDeps } from './agent.js';
|
|
8
8
|
import { Conversation } from './conversation.js';
|
|
9
9
|
import type { Fisherman } from './fisherman.js';
|
|
10
10
|
import type { Provider } from './provider.js';
|
|
11
|
-
import { Researcher } from './researcher.js';
|
|
11
|
+
import { type Researcher } from './researcher.js';
|
|
12
12
|
declare const PlannerBase: {
|
|
13
13
|
new (...args: any[]): {
|
|
14
14
|
currentPlan: Plan | null;
|
|
@@ -58,7 +58,7 @@ export declare class Planner extends PlannerBase implements Agent {
|
|
|
58
58
|
lastSuite: Suite | null;
|
|
59
59
|
researcher: Researcher;
|
|
60
60
|
fisherman: Fisherman | null;
|
|
61
|
-
constructor(
|
|
61
|
+
constructor(deps: AgentDeps, researcher: Researcher);
|
|
62
62
|
setFisherman(fisherman: Fisherman): void;
|
|
63
63
|
get sectionOrder(): string[];
|
|
64
64
|
getDefaultStartUrl(state: {
|
|
@@ -75,5 +75,6 @@ export declare class Planner extends PlannerBase implements Agent {
|
|
|
75
75
|
cleanExperienceFlows(text: string): string | null;
|
|
76
76
|
buildApproach(style?: string): string;
|
|
77
77
|
buildConversation(state: ActionResult, style?: string, parentPlan?: Plan, feature?: string): Promise<Conversation>;
|
|
78
|
+
getTasksMessage(): string;
|
|
78
79
|
}
|
|
79
80
|
export {};
|
package/dist/src/ai/planner.js
CHANGED
|
@@ -3,7 +3,6 @@ import { z } from 'zod';
|
|
|
3
3
|
import { ActionResult } from "../action-result.js";
|
|
4
4
|
import { setActivity } from "../activity.js";
|
|
5
5
|
import { ConfigParser } from "../config.js";
|
|
6
|
-
import { ExperienceTracker } from "../experience-tracker.js";
|
|
7
6
|
import { Observability } from "../observability.js";
|
|
8
7
|
import { Stats } from "../stats.js";
|
|
9
8
|
import { Suite } from "../suite.js";
|
|
@@ -16,7 +15,7 @@ import { Conversation } from "./conversation.js";
|
|
|
16
15
|
import { WithSessionDedup } from "./planner/session-dedup.js";
|
|
17
16
|
import { getActiveStyle } from "./planner/styles.js";
|
|
18
17
|
import { WithSubPages, getPlannedByStateHash, getRegisteredPlan, registerPlan } from "./planner/subpages.js";
|
|
19
|
-
import { POSSIBLE_SECTIONS
|
|
18
|
+
import { POSSIBLE_SECTIONS } from "./researcher.js";
|
|
20
19
|
import { findSimilarStateHash } from "./researcher/cache.js";
|
|
21
20
|
import { hasFocusedSection } from "./researcher/focus.js";
|
|
22
21
|
import { capabilityGroundingRule, dataProtectionRules, fileUploadRule } from "./rules.js";
|
|
@@ -50,13 +49,13 @@ export class Planner extends PlannerBase {
|
|
|
50
49
|
lastSuite = null;
|
|
51
50
|
researcher;
|
|
52
51
|
fisherman = null;
|
|
53
|
-
constructor(
|
|
52
|
+
constructor(deps, researcher) {
|
|
54
53
|
super();
|
|
55
|
-
this.explorer = explorer;
|
|
56
|
-
this.provider =
|
|
57
|
-
this.researcher =
|
|
58
|
-
this.stateManager =
|
|
59
|
-
this.experienceTracker =
|
|
54
|
+
this.explorer = deps.explorer;
|
|
55
|
+
this.provider = deps.ai;
|
|
56
|
+
this.researcher = researcher;
|
|
57
|
+
this.stateManager = deps.stateManager;
|
|
58
|
+
this.experienceTracker = deps.stateManager.getExperienceTracker();
|
|
60
59
|
}
|
|
61
60
|
setFisherman(fisherman) {
|
|
62
61
|
this.fisherman = fisherman;
|
|
@@ -81,7 +80,7 @@ export class Planner extends PlannerBase {
|
|
|
81
80
|
You are ISTQB certified senior manual QA planning exploratory testing session of a web application.
|
|
82
81
|
Each test scenario must complete a meaningful user workflow — not just open a UI element and verify it exists.
|
|
83
82
|
Bad: "Open the Help panel" — just opens something.
|
|
84
|
-
Good: "Create a new
|
|
83
|
+
Good: "Create a new post and verify it appears in the list" — completes a business action.
|
|
85
84
|
</role>
|
|
86
85
|
<task>
|
|
87
86
|
List possible testing scenarios for the web page.
|
|
@@ -149,6 +148,7 @@ export class Planner extends PlannerBase {
|
|
|
149
148
|
const tags = ['planner'];
|
|
150
149
|
if (style)
|
|
151
150
|
tags.push(style);
|
|
151
|
+
const existingTestScenarios = this.getExistingTestFileScenarios(state.url);
|
|
152
152
|
const result = await Observability.run(`planner: ${state.url}`, { tags, sessionId: state.url }, async () => {
|
|
153
153
|
const actionResult = ActionResult.fromState(state);
|
|
154
154
|
const conversation = await this.buildConversation(actionResult, style, parentPlan, feature);
|
|
@@ -182,7 +182,6 @@ export class Planner extends PlannerBase {
|
|
|
182
182
|
if (parentPlan)
|
|
183
183
|
this.currentPlan.parentPlan = parentPlan;
|
|
184
184
|
const allPreviousScenarios = this.getPreviousSessionScenarios();
|
|
185
|
-
const existingTestScenarios = this.getExistingTestFileScenarios(state.url);
|
|
186
185
|
for (const s of existingTestScenarios)
|
|
187
186
|
allPreviousScenarios.add(s);
|
|
188
187
|
for (const t of tests) {
|
|
@@ -232,6 +231,7 @@ export class Planner extends PlannerBase {
|
|
|
232
231
|
return added;
|
|
233
232
|
}
|
|
234
233
|
getExistingTestFileScenarios(currentUrl) {
|
|
234
|
+
this.lastSuite = null;
|
|
235
235
|
if (!currentUrl)
|
|
236
236
|
return new Set();
|
|
237
237
|
try {
|
|
@@ -244,27 +244,37 @@ export class Planner extends PlannerBase {
|
|
|
244
244
|
}
|
|
245
245
|
}
|
|
246
246
|
cleanExperienceFlows(text) {
|
|
247
|
-
const seenTitles = new Set();
|
|
248
247
|
let result = text;
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
.query(
|
|
253
|
-
.
|
|
254
|
-
.
|
|
255
|
-
.
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
248
|
+
const seenTitles = new Set();
|
|
249
|
+
for (const selector of ['section2', 'section3']) {
|
|
250
|
+
result = mdq(result)
|
|
251
|
+
.query(selector)
|
|
252
|
+
.replaceEach((section) => {
|
|
253
|
+
const heading = section.query('heading').text().trim();
|
|
254
|
+
const withoutHeadings = mdq(section.text()).query('heading').replace('');
|
|
255
|
+
const body = mdq(withoutHeadings).query('hr').replace('').trim();
|
|
256
|
+
if (body && !seenTitles.has(heading)) {
|
|
257
|
+
seenTitles.add(heading);
|
|
258
|
+
return section.text();
|
|
259
|
+
}
|
|
260
|
+
return '';
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
const trimmedTitles = new Set();
|
|
264
|
+
for (const selector of ['section2', 'section3']) {
|
|
265
|
+
result = mdq(result)
|
|
266
|
+
.query(selector)
|
|
267
|
+
.replaceEach((section) => {
|
|
268
|
+
const heading = section.query('heading').text().trim();
|
|
269
|
+
if (trimmedTitles.has(heading))
|
|
270
|
+
return section.text();
|
|
271
|
+
const count = section.query('blockquote').count();
|
|
272
|
+
if (count <= 10)
|
|
273
|
+
return section.text();
|
|
274
|
+
const kept = mdq(section.text()).query('blockquote[10:]').replace('');
|
|
275
|
+
trimmedTitles.add(heading);
|
|
276
|
+
return `${kept.trimEnd()}\n> ... and ${count - 10} more discoveries\n`;
|
|
277
|
+
});
|
|
268
278
|
}
|
|
269
279
|
return result.trim() || null;
|
|
270
280
|
}
|
|
@@ -298,6 +308,7 @@ export class Planner extends PlannerBase {
|
|
|
298
308
|
If there are subpages (pages with same URL path) plan testing of those subpages as well
|
|
299
309
|
If you plan to test CRUD operations, plan them in correct order: create, read, update.
|
|
300
310
|
Do not invent specific route names, success messages, validation texts, badge counts, or welcome messages unless they are visible in research, visited pages, or prior observed flows.
|
|
311
|
+
When validation placement or wording was not observed, require feedback associated with the invalid input without inventing a specific location or message.
|
|
301
312
|
If exact wording is unknown, describe the expected result generically, for example "an authentication error is shown" or "the user stays on the login page" instead of guessing the literal text.
|
|
302
313
|
If exact redirect destination is unknown, describe the destination by visible page identity, for example "the dashboard page opens" or "the current workspace home page opens" instead of inventing a URL slug.
|
|
303
314
|
Only propose scenarios whose prerequisites are evident from page research, visited pages, or API data preparation context.
|
|
@@ -323,31 +334,26 @@ export class Planner extends PlannerBase {
|
|
|
323
334
|
${dataProtectionRules}
|
|
324
335
|
${fileUploadRule}
|
|
325
336
|
</rules>
|
|
326
|
-
|
|
327
|
-
${this.buildApproach(style)}
|
|
328
|
-
|
|
329
|
-
<context>
|
|
330
|
-
URL: ${state.url || 'Unknown'}
|
|
331
|
-
Title: ${state.title || 'Unknown'}
|
|
332
|
-
</context>
|
|
333
337
|
`;
|
|
334
338
|
conversation.addUserText(planningPrompt);
|
|
339
|
+
conversation.addUserText(this.getTasksMessage());
|
|
335
340
|
const currentState = this.stateManager.getCurrentState();
|
|
336
341
|
const research = await this.researcher.research(currentState || state, {
|
|
337
342
|
deep: true,
|
|
338
343
|
});
|
|
339
344
|
let plannerResearch = mdq(research).query('code').replace('');
|
|
340
|
-
|
|
341
|
-
|
|
345
|
+
plannerResearch = mdq(plannerResearch)
|
|
346
|
+
.query('table')
|
|
347
|
+
.replaceEach((table) => {
|
|
342
348
|
const rows = table.toJson();
|
|
343
349
|
if (rows.length === 0 || !rows[0].Element)
|
|
344
|
-
|
|
350
|
+
return table.text();
|
|
345
351
|
const elementWithType = rows.map((r) => ({
|
|
346
352
|
Element: r.Element,
|
|
347
353
|
Type: r.Type || '',
|
|
348
354
|
}));
|
|
349
|
-
|
|
350
|
-
}
|
|
355
|
+
return jsonToTable(elementWithType, ['Element', 'Type']);
|
|
356
|
+
});
|
|
351
357
|
const hasFocusedOverlay = hasFocusedSection(plannerResearch);
|
|
352
358
|
const focusNote = hasFocusedOverlay ? "IMPORTANT: One section is marked as **Focused** — this is the user's current focus area. Concentrate testing on the Focused section FIRST — test all interactions inside it before planning tests for the rest of the page." : '';
|
|
353
359
|
const featureFilter = feature ? `FOCUS FILTER: Only propose scenarios using elements relevant to "${feature}". Ignore all other elements.` : '';
|
|
@@ -361,6 +367,14 @@ export class Planner extends PlannerBase {
|
|
|
361
367
|
|
|
362
368
|
${plannerResearch}
|
|
363
369
|
</page_research>
|
|
370
|
+
`);
|
|
371
|
+
conversation.addUserText(dedent `
|
|
372
|
+
${this.buildApproach(style)}
|
|
373
|
+
|
|
374
|
+
<context>
|
|
375
|
+
URL: ${state.url || 'Unknown'}
|
|
376
|
+
Title: ${state.title || 'Unknown'}
|
|
377
|
+
</context>
|
|
364
378
|
`);
|
|
365
379
|
if (this.fisherman) {
|
|
366
380
|
await this.fisherman.ensureReady(state.url);
|
|
@@ -505,8 +519,10 @@ export class Planner extends PlannerBase {
|
|
|
505
519
|
</parent_page_context>
|
|
506
520
|
`);
|
|
507
521
|
}
|
|
508
|
-
|
|
509
|
-
|
|
522
|
+
return conversation;
|
|
523
|
+
}
|
|
524
|
+
getTasksMessage() {
|
|
525
|
+
return dedent `
|
|
510
526
|
<task>
|
|
511
527
|
Provide testing scenarios as structured data with the following requirements:
|
|
512
528
|
1. Create a short, descriptive plan name that summarizes what will be tested (e.g., "User Authentication Testing", "Product Catalog Navigation", "Form Validation Tests")
|
|
@@ -525,17 +541,17 @@ export class Planner extends PlannerBase {
|
|
|
525
541
|
|
|
526
542
|
STEPS - actionable commands:
|
|
527
543
|
- Each step should be a specific action to perform
|
|
528
|
-
- Good: "Click Create
|
|
529
|
-
- Good: "Click Star icon on '
|
|
544
|
+
- Good: "Click Create Post button", "Enter 'My New Post' as post title", "Click Save button"
|
|
545
|
+
- Good: "Click Star icon on 'Quarterly Report' item"
|
|
530
546
|
- Bad: "Open the dropdown menu" (opening is not a goal, it's a means)
|
|
531
547
|
- Bad: "Verify modal appears" (verification belongs in expected outcomes, not steps)
|
|
532
548
|
- Steps should form a complete workflow, not stop at opening a UI element
|
|
533
549
|
- NEVER split a workflow across two tests. One test = one complete action + its verification
|
|
534
550
|
|
|
535
551
|
EXPECTED OUTCOMES - verifiable results:
|
|
536
|
-
- Good: "New
|
|
537
|
-
- Good: "
|
|
538
|
-
- Good: "Success message '
|
|
552
|
+
- Good: "New post 'My New Post' appears in the posts list"
|
|
553
|
+
- Good: "Item appears under Starred filter tab"
|
|
554
|
+
- Good: "Success message 'Post created' is displayed"
|
|
539
555
|
- Good when wording is unknown: "An authentication error is displayed"
|
|
540
556
|
- Good when route is unknown: "The workspace home page is displayed"
|
|
541
557
|
- Bad: "Modal is displayed" (just verifying existence, no business value)
|
|
@@ -552,10 +568,8 @@ export class Planner extends PlannerBase {
|
|
|
552
568
|
- Do not wrap text in ** or * quotes, ( or ) brackets.
|
|
553
569
|
- Avoid using emojis or special characters.
|
|
554
570
|
7. Only tests that can be tested from web UI should be proposed.
|
|
555
|
-
|
|
571
|
+
8. For a fresh plan propose at least ${this.MIN_TASKS} tests; when expanding an existing plan return ONLY new scenarios not in the tested list, and an empty array if none remain.
|
|
556
572
|
</task>
|
|
557
573
|
`;
|
|
558
|
-
conversation.addUserText(tasksMessage);
|
|
559
|
-
return conversation;
|
|
560
574
|
}
|
|
561
575
|
}
|
|
@@ -12,7 +12,6 @@ export declare class Provider {
|
|
|
12
12
|
telemetryEnabled: boolean;
|
|
13
13
|
otelSdk: NodeSDK | null;
|
|
14
14
|
defaultRetryOptions: RetryOptions;
|
|
15
|
-
static readonly CONTEXT_LENGTH_PATTERNS: string[];
|
|
16
15
|
lastConversation: Conversation | null;
|
|
17
16
|
constructor(config: AIConfig);
|
|
18
17
|
getModelName(model: any): string;
|
|
@@ -26,6 +25,10 @@ export declare class Provider {
|
|
|
26
25
|
getRetryOptions(options?: any): RetryOptions;
|
|
27
26
|
mergeProviderOptions(config: Record<string, any>, agentName?: string): Record<string, any>;
|
|
28
27
|
finalizeConfig(config: Record<string, any>, options: any, telemetry: any): void;
|
|
28
|
+
buildGenerateConfig(defaults: Record<string, any>, overrides: Record<string, any>, options: any): Record<string, any>;
|
|
29
|
+
recordUsage(agentName: string, modelName: string, usage: any): void;
|
|
30
|
+
raceWithIdleTimeout<T>(fn: (signal: AbortSignal) => Promise<T>, timeoutMs: number): Promise<T>;
|
|
31
|
+
recoverFromContextLength(error: any, messages: ModelMessage[], options: any, retry: (messages: ModelMessage[], options: any) => Promise<any>): Promise<any>;
|
|
29
32
|
initLangfuse(): void;
|
|
30
33
|
getTelemetry(options: any): any;
|
|
31
34
|
startConversation(systemMessage: string, agentName?: string, model?: any): Conversation;
|