explorbot 0.1.13 → 0.1.15
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/dist/package.json +3 -2
- package/dist/src/action.js +3 -2
- package/dist/src/ai/conversation.js +20 -4
- package/dist/src/ai/historian/utils.js +8 -1
- package/dist/src/ai/pilot.js +198 -260
- package/dist/src/ai/provider.js +25 -12
- package/dist/src/ai/quartermaster.js +2 -2
- package/dist/src/ai/rules.js +2 -0
- package/dist/src/ai/session-analyst.js +46 -41
- package/dist/src/ai/tester.js +56 -20
- package/dist/src/ai/tools.js +19 -4
- package/dist/src/commands/explore-command.js +8 -2
- package/dist/src/components/StatusPane.js +6 -1
- package/dist/src/experience-tracker.js +9 -0
- package/dist/src/explorer.js +2 -5
- package/dist/src/reporter.js +41 -1
- package/dist/src/stats.js +2 -1
- package/dist/src/test-plan.js +47 -3
- package/package.json +3 -2
- package/src/action.ts +3 -2
- package/src/ai/conversation.ts +21 -4
- package/src/ai/historian/utils.ts +8 -1
- package/src/ai/pilot.ts +199 -259
- package/src/ai/provider.ts +24 -12
- package/src/ai/quartermaster.ts +2 -2
- package/src/ai/rules.ts +2 -0
- package/src/ai/session-analyst.ts +47 -41
- package/src/ai/tester.ts +48 -18
- package/src/ai/tools.ts +18 -4
- package/src/commands/explore-command.ts +9 -2
- package/src/components/StatusPane.tsx +6 -3
- package/src/experience-tracker.ts +9 -0
- package/src/explorer.ts +1 -4
- package/src/reporter.ts +44 -1
- package/src/stats.ts +3 -1
- package/src/test-plan.ts +62 -3
package/src/stats.ts
CHANGED
|
@@ -4,6 +4,7 @@ interface TokenUsage {
|
|
|
4
4
|
input: number;
|
|
5
5
|
output: number;
|
|
6
6
|
total: number;
|
|
7
|
+
cached?: number;
|
|
7
8
|
}
|
|
8
9
|
|
|
9
10
|
export type ExplorbotMode = 'explore' | 'test' | 'freesail' | 'tui';
|
|
@@ -20,11 +21,12 @@ export class Stats {
|
|
|
20
21
|
|
|
21
22
|
static recordTokens(_agent: string, model: string, usage: TokenUsage): void {
|
|
22
23
|
if (!Stats.models[model]) {
|
|
23
|
-
Stats.models[model] = { input: 0, output: 0, total: 0 };
|
|
24
|
+
Stats.models[model] = { input: 0, output: 0, total: 0, cached: 0 };
|
|
24
25
|
}
|
|
25
26
|
Stats.models[model].input += usage.input;
|
|
26
27
|
Stats.models[model].output += usage.output;
|
|
27
28
|
Stats.models[model].total += usage.total;
|
|
29
|
+
Stats.models[model].cached = (Stats.models[model].cached ?? 0) + (usage.cached ?? 0);
|
|
28
30
|
}
|
|
29
31
|
|
|
30
32
|
static getElapsedTime(): string {
|
package/src/test-plan.ts
CHANGED
|
@@ -26,6 +26,7 @@ export interface Note {
|
|
|
26
26
|
startTime: number;
|
|
27
27
|
endTime: number;
|
|
28
28
|
screenshot?: string;
|
|
29
|
+
log?: string;
|
|
29
30
|
}
|
|
30
31
|
|
|
31
32
|
export class ActiveNote {
|
|
@@ -34,6 +35,7 @@ export class ActiveNote {
|
|
|
34
35
|
message: string;
|
|
35
36
|
status?: TestResultType;
|
|
36
37
|
screenshot?: string;
|
|
38
|
+
log?: string;
|
|
37
39
|
|
|
38
40
|
constructor(task: Task, message: string, status?: TestResultType) {
|
|
39
41
|
this.task = task;
|
|
@@ -73,6 +75,7 @@ export class Task {
|
|
|
73
75
|
steps: Record<string, StepData>;
|
|
74
76
|
states: WebPageState[];
|
|
75
77
|
startUrl: string;
|
|
78
|
+
verification?: Verification;
|
|
76
79
|
protected timestampCounter = 0;
|
|
77
80
|
private activeNote?: ActiveNote;
|
|
78
81
|
|
|
@@ -102,6 +105,7 @@ export class Task {
|
|
|
102
105
|
startTime: activeNote.getStartTime(),
|
|
103
106
|
endTime,
|
|
104
107
|
screenshot: activeNote.screenshot,
|
|
108
|
+
log: activeNote.log,
|
|
105
109
|
};
|
|
106
110
|
this.activeNote = undefined;
|
|
107
111
|
}
|
|
@@ -118,13 +122,28 @@ export class Task {
|
|
|
118
122
|
.join('\n');
|
|
119
123
|
}
|
|
120
124
|
|
|
121
|
-
addNote(message: string, status: TestResultType = null, screenshot?: string): void {
|
|
122
|
-
const isDuplicate = Object.values(this.notes).some((note) => note.message === message && note.status === status);
|
|
125
|
+
addNote(message: string, status: TestResultType = null, screenshot?: string, log?: string): void {
|
|
126
|
+
const isDuplicate = Object.values(this.notes).some((note) => note.message === message && note.status === status && note.log === log);
|
|
123
127
|
if (isDuplicate) return;
|
|
124
128
|
|
|
125
129
|
const now = performance.now();
|
|
126
130
|
const timestamp = `${now}_${this.timestampCounter++}`;
|
|
127
|
-
this.notes[timestamp] = { message, status, startTime: now, endTime: now, screenshot };
|
|
131
|
+
this.notes[timestamp] = { message, status, startTime: now, endTime: now, screenshot, log };
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
addUrlNote(state: UrlNoteState, prevState?: { title?: string; h1?: string; h2?: string }): void {
|
|
135
|
+
const fullUrl = state.fullUrl || state.url;
|
|
136
|
+
if (!fullUrl) return;
|
|
137
|
+
|
|
138
|
+
let label: string | undefined;
|
|
139
|
+
if (state.title && state.title !== prevState?.title) label = state.title;
|
|
140
|
+
else if (state.h1 && state.h1 !== prevState?.h1) label = state.h1;
|
|
141
|
+
else if (state.h2 && state.h2 !== prevState?.h2) label = state.h2;
|
|
142
|
+
else label = state.title || state.h1 || state.h2;
|
|
143
|
+
|
|
144
|
+
if (!label) return;
|
|
145
|
+
|
|
146
|
+
this.addNote(`Navigated to ${label}`, TestResult.PASSED, state.screenshotFile, fullUrl);
|
|
128
147
|
}
|
|
129
148
|
|
|
130
149
|
addState(state: WebPageState): void {
|
|
@@ -136,6 +155,28 @@ export class Task {
|
|
|
136
155
|
this.steps[timestamp] = { text, duration, status, error, log, artifacts, noteStartTime: this.activeNote?.getStartTime() };
|
|
137
156
|
}
|
|
138
157
|
|
|
158
|
+
setActiveNoteScreenshot(screenshotFile?: string): void {
|
|
159
|
+
if (!this.activeNote || !screenshotFile) return;
|
|
160
|
+
this.activeNote.screenshot = screenshotFile;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
setVerification(message: string, status: TestResultType, state?: UrlNoteState): void {
|
|
164
|
+
this.verification ||= { message: '', status: null, details: [] };
|
|
165
|
+
this.verification.message = message;
|
|
166
|
+
this.verification.status = status;
|
|
167
|
+
if (!state) return;
|
|
168
|
+
if (state.screenshotFile) this.verification.screenshot = state.screenshotFile;
|
|
169
|
+
const fullUrl = state.fullUrl || state.url;
|
|
170
|
+
if (fullUrl) this.verification.url = fullUrl;
|
|
171
|
+
this.verification.pageLabel = state.title || state.h1 || state.h2 || undefined;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
addVerificationDetail(detail: string): void {
|
|
175
|
+
if (!detail) return;
|
|
176
|
+
this.verification ||= { message: '', status: null, details: [] };
|
|
177
|
+
this.verification.details.push(detail);
|
|
178
|
+
}
|
|
179
|
+
|
|
139
180
|
getLog(): Array<{ type: 'step' | 'note' | 'artifact'; content: string; timestamp: number }> {
|
|
140
181
|
const merged: Record<string, { type: 'step' | 'note' | 'artifact'; content: string }> = {};
|
|
141
182
|
|
|
@@ -442,3 +483,21 @@ export class Plan {
|
|
|
442
483
|
return planToAiContext(this, options);
|
|
443
484
|
}
|
|
444
485
|
}
|
|
486
|
+
|
|
487
|
+
interface Verification {
|
|
488
|
+
message: string;
|
|
489
|
+
status: TestResultType;
|
|
490
|
+
screenshot?: string;
|
|
491
|
+
url?: string;
|
|
492
|
+
pageLabel?: string;
|
|
493
|
+
details: string[];
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
interface UrlNoteState {
|
|
497
|
+
url?: string;
|
|
498
|
+
fullUrl?: string;
|
|
499
|
+
title?: string;
|
|
500
|
+
h1?: string;
|
|
501
|
+
h2?: string;
|
|
502
|
+
screenshotFile?: string;
|
|
503
|
+
}
|