@eidra-umain/greenlight 0.1.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/README.md +391 -0
- package/dist/browser/browser.d.ts +24 -0
- package/dist/browser/browser.d.ts.map +1 -0
- package/dist/browser/browser.js +44 -0
- package/dist/browser/browser.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +140 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/run.d.ts +9 -0
- package/dist/cli/run.d.ts.map +1 -0
- package/dist/cli/run.js +277 -0
- package/dist/cli/run.js.map +1 -0
- package/dist/config.d.ts +48 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +107 -0
- package/dist/config.js.map +1 -0
- package/dist/globals.d.ts +21 -0
- package/dist/globals.d.ts.map +1 -0
- package/dist/globals.js +24 -0
- package/dist/globals.js.map +1 -0
- package/dist/parser/loader.d.ts +7 -0
- package/dist/parser/loader.d.ts.map +1 -0
- package/dist/parser/loader.js +43 -0
- package/dist/parser/loader.js.map +1 -0
- package/dist/parser/schema.d.ts +42 -0
- package/dist/parser/schema.d.ts.map +1 -0
- package/dist/parser/schema.js +33 -0
- package/dist/parser/schema.js.map +1 -0
- package/dist/parser/steps.d.ts +13 -0
- package/dist/parser/steps.d.ts.map +1 -0
- package/dist/parser/steps.js +44 -0
- package/dist/parser/steps.js.map +1 -0
- package/dist/parser/variables.d.ts +18 -0
- package/dist/parser/variables.d.ts.map +1 -0
- package/dist/parser/variables.js +44 -0
- package/dist/parser/variables.js.map +1 -0
- package/dist/pilot/a11y-parser.d.ts +26 -0
- package/dist/pilot/a11y-parser.d.ts.map +1 -0
- package/dist/pilot/a11y-parser.js +195 -0
- package/dist/pilot/a11y-parser.js.map +1 -0
- package/dist/pilot/assertions.d.ts +30 -0
- package/dist/pilot/assertions.d.ts.map +1 -0
- package/dist/pilot/assertions.js +219 -0
- package/dist/pilot/assertions.js.map +1 -0
- package/dist/pilot/checkbox.d.ts +12 -0
- package/dist/pilot/checkbox.d.ts.map +1 -0
- package/dist/pilot/checkbox.js +104 -0
- package/dist/pilot/checkbox.js.map +1 -0
- package/dist/pilot/executor.d.ts +17 -0
- package/dist/pilot/executor.d.ts.map +1 -0
- package/dist/pilot/executor.js +462 -0
- package/dist/pilot/executor.js.map +1 -0
- package/dist/pilot/form-fields.d.ts +34 -0
- package/dist/pilot/form-fields.d.ts.map +1 -0
- package/dist/pilot/form-fields.js +139 -0
- package/dist/pilot/form-fields.js.map +1 -0
- package/dist/pilot/llm.d.ts +49 -0
- package/dist/pilot/llm.d.ts.map +1 -0
- package/dist/pilot/llm.js +188 -0
- package/dist/pilot/llm.js.map +1 -0
- package/dist/pilot/locator.d.ts +58 -0
- package/dist/pilot/locator.d.ts.map +1 -0
- package/dist/pilot/locator.js +248 -0
- package/dist/pilot/locator.js.map +1 -0
- package/dist/pilot/message-builder.d.ts +31 -0
- package/dist/pilot/message-builder.d.ts.map +1 -0
- package/dist/pilot/message-builder.js +112 -0
- package/dist/pilot/message-builder.js.map +1 -0
- package/dist/pilot/network.d.ts +23 -0
- package/dist/pilot/network.d.ts.map +1 -0
- package/dist/pilot/network.js +92 -0
- package/dist/pilot/network.js.map +1 -0
- package/dist/pilot/pilot.d.ts +27 -0
- package/dist/pilot/pilot.d.ts.map +1 -0
- package/dist/pilot/pilot.js +249 -0
- package/dist/pilot/pilot.js.map +1 -0
- package/dist/pilot/prompts.d.ts +8 -0
- package/dist/pilot/prompts.d.ts.map +1 -0
- package/dist/pilot/prompts.js +163 -0
- package/dist/pilot/prompts.js.map +1 -0
- package/dist/pilot/providers/anthropic.d.ts +6 -0
- package/dist/pilot/providers/anthropic.d.ts.map +1 -0
- package/dist/pilot/providers/anthropic.js +45 -0
- package/dist/pilot/providers/anthropic.js.map +1 -0
- package/dist/pilot/providers/gemini.d.ts +6 -0
- package/dist/pilot/providers/gemini.d.ts.map +1 -0
- package/dist/pilot/providers/gemini.js +55 -0
- package/dist/pilot/providers/gemini.js.map +1 -0
- package/dist/pilot/providers/index.d.ts +10 -0
- package/dist/pilot/providers/index.d.ts.map +1 -0
- package/dist/pilot/providers/index.js +25 -0
- package/dist/pilot/providers/index.js.map +1 -0
- package/dist/pilot/providers/openai-compatible.d.ts +7 -0
- package/dist/pilot/providers/openai-compatible.d.ts.map +1 -0
- package/dist/pilot/providers/openai-compatible.js +34 -0
- package/dist/pilot/providers/openai-compatible.js.map +1 -0
- package/dist/pilot/providers/types.d.ts +12 -0
- package/dist/pilot/providers/types.d.ts.map +1 -0
- package/dist/pilot/providers/types.js +2 -0
- package/dist/pilot/providers/types.js.map +1 -0
- package/dist/pilot/response-parser.d.ts +31 -0
- package/dist/pilot/response-parser.d.ts.map +1 -0
- package/dist/pilot/response-parser.js +188 -0
- package/dist/pilot/response-parser.js.map +1 -0
- package/dist/pilot/state.d.ts +19 -0
- package/dist/pilot/state.d.ts.map +1 -0
- package/dist/pilot/state.js +67 -0
- package/dist/pilot/state.js.map +1 -0
- package/dist/pilot/trace.d.ts +16 -0
- package/dist/pilot/trace.d.ts.map +1 -0
- package/dist/pilot/trace.js +117 -0
- package/dist/pilot/trace.js.map +1 -0
- package/dist/planner/hasher.d.ts +14 -0
- package/dist/planner/hasher.d.ts.map +1 -0
- package/dist/planner/hasher.js +21 -0
- package/dist/planner/hasher.js.map +1 -0
- package/dist/planner/plan-generator.d.ts +23 -0
- package/dist/planner/plan-generator.d.ts.map +1 -0
- package/dist/planner/plan-generator.js +56 -0
- package/dist/planner/plan-generator.js.map +1 -0
- package/dist/planner/plan-runner.d.ts +16 -0
- package/dist/planner/plan-runner.d.ts.map +1 -0
- package/dist/planner/plan-runner.js +375 -0
- package/dist/planner/plan-runner.js.map +1 -0
- package/dist/planner/plan-store.d.ts +22 -0
- package/dist/planner/plan-store.d.ts.map +1 -0
- package/dist/planner/plan-store.js +71 -0
- package/dist/planner/plan-store.js.map +1 -0
- package/dist/planner/plan-types.d.ts +64 -0
- package/dist/planner/plan-types.d.ts.map +1 -0
- package/dist/planner/plan-types.js +7 -0
- package/dist/planner/plan-types.js.map +1 -0
- package/dist/reporter/types.d.ts +130 -0
- package/dist/reporter/types.d.ts.map +1 -0
- package/dist/reporter/types.js +5 -0
- package/dist/reporter/types.js.map +1 -0
- package/dist/types.d.ts +51 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +23 -0
- package/dist/types.js.map +1 -0
- package/package.json +64 -0
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Pilot — core AI agent loop.
|
|
3
|
+
* Iterates through test steps: capture state → LLM → execute → record result.
|
|
4
|
+
*/
|
|
5
|
+
import { validatePlanReferences } from "./response-parser.js";
|
|
6
|
+
import { capturePageState } from "./state.js";
|
|
7
|
+
import { resetRefCounter } from "./a11y-parser.js";
|
|
8
|
+
import { executeAction } from "./executor.js";
|
|
9
|
+
import { globals } from "../globals.js";
|
|
10
|
+
/**
|
|
11
|
+
* Run all steps of a test case sequentially.
|
|
12
|
+
* Fails fast: stops on the first failed step.
|
|
13
|
+
*/
|
|
14
|
+
export async function runTestCase(page, testCase, llm, options) {
|
|
15
|
+
const startTime = performance.now();
|
|
16
|
+
const stepResults = [];
|
|
17
|
+
// Fresh conversation history, stable ref map, and value store for each test case
|
|
18
|
+
llm.resetHistory();
|
|
19
|
+
resetRefCounter();
|
|
20
|
+
globals.valueStore.clear();
|
|
21
|
+
const trace = globals.trace;
|
|
22
|
+
const recorder = options.recorder;
|
|
23
|
+
// Pre-plan all steps: the LLM interprets the full spec and returns
|
|
24
|
+
// structured actions for steps it can resolve without page state.
|
|
25
|
+
// Compound steps may be split into multiple atomic actions.
|
|
26
|
+
trace.log("plan:start", `${String(testCase.steps.length)} steps`);
|
|
27
|
+
if (globals.debug) {
|
|
28
|
+
console.log(`\n Plan input:`);
|
|
29
|
+
for (const s of testCase.steps) {
|
|
30
|
+
console.log(` - ${s}`);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
const planStart = performance.now();
|
|
34
|
+
let plan;
|
|
35
|
+
try {
|
|
36
|
+
plan = await llm.planSteps(testCase.steps);
|
|
37
|
+
}
|
|
38
|
+
catch (err) {
|
|
39
|
+
// If planning fails, fall back to runtime resolution for all steps
|
|
40
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
41
|
+
trace.log("plan:error", msg);
|
|
42
|
+
if (globals.debug) {
|
|
43
|
+
console.log(` Plan error: ${msg}`);
|
|
44
|
+
}
|
|
45
|
+
plan = testCase.steps.map((s) => ({ step: s, action: null }));
|
|
46
|
+
}
|
|
47
|
+
trace.log("plan:done", `${String(Math.round(performance.now() - planStart))}ms`);
|
|
48
|
+
if (globals.debug) {
|
|
49
|
+
console.log(`\n Plan output (${String(plan.length)} actions):`);
|
|
50
|
+
for (let i = 0; i < plan.length; i++) {
|
|
51
|
+
const p = plan[i];
|
|
52
|
+
const label = p.action ? JSON.stringify(p.action) : "(needs page state)";
|
|
53
|
+
console.log(` ${String(i + 1)}. ${p.step} → ${label}`);
|
|
54
|
+
}
|
|
55
|
+
console.log();
|
|
56
|
+
}
|
|
57
|
+
// Validate that every COMPARE has a matching REMEMBER before it
|
|
58
|
+
const planErrors = validatePlanReferences(plan);
|
|
59
|
+
if (planErrors.length > 0) {
|
|
60
|
+
if (globals.debug) {
|
|
61
|
+
for (const err of planErrors)
|
|
62
|
+
console.log(` Plan error: ${err}`);
|
|
63
|
+
}
|
|
64
|
+
// Log the errors but don't fail — the LLM may have made a mistake
|
|
65
|
+
// that the runtime can still handle
|
|
66
|
+
}
|
|
67
|
+
// Build the execution queue — EXPAND steps get expanded at runtime
|
|
68
|
+
// and their sub-steps are spliced into the queue.
|
|
69
|
+
const queue = [...plan];
|
|
70
|
+
let queueIndex = 0;
|
|
71
|
+
let failed = false;
|
|
72
|
+
while (queueIndex < queue.length && !failed) {
|
|
73
|
+
const planned = queue[queueIndex];
|
|
74
|
+
queueIndex++;
|
|
75
|
+
const { step, action: plannedAction, needsExpansion, rememberAs, compare: plannedCompare } = planned;
|
|
76
|
+
// ── EXPAND: runtime step expansion (e.g. form filling) ────────
|
|
77
|
+
if (needsExpansion) {
|
|
78
|
+
trace.log("expand:start", step);
|
|
79
|
+
if (globals.debug) {
|
|
80
|
+
console.log(`\n Expanding compound step: ${step}`);
|
|
81
|
+
}
|
|
82
|
+
// Capture page state for expansion
|
|
83
|
+
if (options.waitForNetworkIdle) {
|
|
84
|
+
await options.waitForNetworkIdle();
|
|
85
|
+
}
|
|
86
|
+
const state = await capturePageState(page, options.consoleDrain);
|
|
87
|
+
try {
|
|
88
|
+
const t0 = performance.now();
|
|
89
|
+
const expandedSteps = await llm.expandStep(step, state, page);
|
|
90
|
+
const expandDuration = performance.now() - t0;
|
|
91
|
+
trace.log("expand:done", `${String(Math.round(expandDuration))}ms → ${String(expandedSteps.length)} sub-steps`);
|
|
92
|
+
if (globals.debug) {
|
|
93
|
+
console.log(`\n Expanded into ${String(expandedSteps.length)} sub-steps:`);
|
|
94
|
+
for (const es of expandedSteps) {
|
|
95
|
+
const label = es.action ? JSON.stringify(es.action) : "(needs page state)";
|
|
96
|
+
console.log(` - ${es.step} → ${label}`);
|
|
97
|
+
}
|
|
98
|
+
console.log();
|
|
99
|
+
}
|
|
100
|
+
// Splice expanded sub-steps into the queue at the current position
|
|
101
|
+
queue.splice(queueIndex, 0, ...expandedSteps);
|
|
102
|
+
}
|
|
103
|
+
catch (err) {
|
|
104
|
+
stepResults.push({
|
|
105
|
+
step,
|
|
106
|
+
action: null,
|
|
107
|
+
status: "failed",
|
|
108
|
+
duration: 0,
|
|
109
|
+
error: `Failed to expand step: ${err instanceof Error ? err.message : String(err)}`,
|
|
110
|
+
});
|
|
111
|
+
failed = true;
|
|
112
|
+
}
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
// ── Normal step execution (same as before) ───────────────────
|
|
116
|
+
trace.log("step:start", step);
|
|
117
|
+
const stepStart = performance.now();
|
|
118
|
+
let action = null;
|
|
119
|
+
const timing = {
|
|
120
|
+
capture: 0,
|
|
121
|
+
llm: 0,
|
|
122
|
+
execute: 0,
|
|
123
|
+
postCapture: 0,
|
|
124
|
+
};
|
|
125
|
+
try {
|
|
126
|
+
let a11yTree = [];
|
|
127
|
+
if (plannedAction) {
|
|
128
|
+
// Pre-planned: skip page capture and LLM call
|
|
129
|
+
action = plannedAction;
|
|
130
|
+
trace.log("plan:hit", JSON.stringify(action));
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
// Needs page state: wait for async requests to settle, then capture
|
|
134
|
+
if (options.waitForNetworkIdle) {
|
|
135
|
+
await options.waitForNetworkIdle();
|
|
136
|
+
}
|
|
137
|
+
trace.log("capture:start");
|
|
138
|
+
let t0 = performance.now();
|
|
139
|
+
const state = await capturePageState(page, options.consoleDrain);
|
|
140
|
+
timing.capture = performance.now() - t0;
|
|
141
|
+
trace.log("capture:done", `${String(Math.round(timing.capture))}ms`);
|
|
142
|
+
trace.log("llm:start");
|
|
143
|
+
t0 = performance.now();
|
|
144
|
+
action = await llm.resolveStep(step, state);
|
|
145
|
+
timing.llm = performance.now() - t0;
|
|
146
|
+
trace.log("llm:done", `${String(Math.round(timing.llm))}ms → ${JSON.stringify(action)}`);
|
|
147
|
+
a11yTree = state.a11yTree;
|
|
148
|
+
}
|
|
149
|
+
// Propagate rememberAs from planned step to action
|
|
150
|
+
if (rememberAs) {
|
|
151
|
+
action.rememberAs = rememberAs;
|
|
152
|
+
// If the LLM didn't return a "remember" action for a REMEMBER step,
|
|
153
|
+
// wrap it as one so the executor captures the value
|
|
154
|
+
if (action.action !== "remember") {
|
|
155
|
+
action = { action: "remember", ref: action.ref, text: action.text, rememberAs };
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
// Propagate compare metadata from planned step to action.
|
|
159
|
+
// The LLM resolves the element ref at runtime; we inject the
|
|
160
|
+
// comparison operator and variable from the plan.
|
|
161
|
+
if (plannedCompare) {
|
|
162
|
+
action.compare ??= {
|
|
163
|
+
variable: plannedCompare.variable,
|
|
164
|
+
operator: plannedCompare.operator,
|
|
165
|
+
};
|
|
166
|
+
action.assertion ??= { type: "compare", expected: step };
|
|
167
|
+
action.action = "assert";
|
|
168
|
+
}
|
|
169
|
+
if (globals.debug) {
|
|
170
|
+
console.log(` Action: ${JSON.stringify(action)}`);
|
|
171
|
+
}
|
|
172
|
+
// Execute the action
|
|
173
|
+
trace.log("execute:start", action.action);
|
|
174
|
+
let t0 = performance.now();
|
|
175
|
+
const result = await executeAction(page, action, a11yTree);
|
|
176
|
+
timing.execute = performance.now() - t0;
|
|
177
|
+
trace.log("execute:done", `${String(Math.round(timing.execute))}ms ${result.success ? "ok" : `FAIL: ${result.error ?? ""}`}`);
|
|
178
|
+
if (!result.success) {
|
|
179
|
+
stepResults.push({
|
|
180
|
+
step,
|
|
181
|
+
action,
|
|
182
|
+
status: "failed",
|
|
183
|
+
duration: performance.now() - stepStart,
|
|
184
|
+
timing,
|
|
185
|
+
error: result.error,
|
|
186
|
+
});
|
|
187
|
+
failed = true;
|
|
188
|
+
continue;
|
|
189
|
+
}
|
|
190
|
+
// Store remembered value if this was a remember action
|
|
191
|
+
if (result.rememberedValue !== undefined && action.rememberAs) {
|
|
192
|
+
globals.valueStore.set(action.rememberAs, result.rememberedValue);
|
|
193
|
+
}
|
|
194
|
+
// Capture post-action screenshot for reporting
|
|
195
|
+
// Retry once if the page is mid-navigation
|
|
196
|
+
trace.log("postCapture:start");
|
|
197
|
+
t0 = performance.now();
|
|
198
|
+
let postState;
|
|
199
|
+
try {
|
|
200
|
+
postState = await capturePageState(page, options.consoleDrain, {
|
|
201
|
+
screenshot: true,
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
catch {
|
|
205
|
+
await page.waitForLoadState("domcontentloaded");
|
|
206
|
+
postState = await capturePageState(page, options.consoleDrain, {
|
|
207
|
+
screenshot: true,
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
timing.postCapture = performance.now() - t0;
|
|
211
|
+
trace.log("postCapture:done", `${String(Math.round(timing.postCapture))}ms`);
|
|
212
|
+
// Record step for heuristic plan if recorder is active
|
|
213
|
+
if (recorder) {
|
|
214
|
+
recorder.recordStep(step, action, result, {
|
|
215
|
+
url: postState.url,
|
|
216
|
+
title: postState.title,
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
stepResults.push({
|
|
220
|
+
step,
|
|
221
|
+
action,
|
|
222
|
+
status: "passed",
|
|
223
|
+
duration: performance.now() - stepStart,
|
|
224
|
+
timing,
|
|
225
|
+
screenshot: postState.screenshot,
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
catch (err) {
|
|
229
|
+
stepResults.push({
|
|
230
|
+
step,
|
|
231
|
+
action,
|
|
232
|
+
status: "failed",
|
|
233
|
+
duration: performance.now() - stepStart,
|
|
234
|
+
timing,
|
|
235
|
+
error: err instanceof Error ? err.message : String(err),
|
|
236
|
+
});
|
|
237
|
+
failed = true;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
const allPassed = stepResults.every((s) => s.status === "passed") && !failed;
|
|
241
|
+
const status = allPassed ? "passed" : "failed";
|
|
242
|
+
return {
|
|
243
|
+
name: testCase.name,
|
|
244
|
+
status,
|
|
245
|
+
steps: stepResults,
|
|
246
|
+
duration: performance.now() - startTime,
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
//# sourceMappingURL=pilot.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pilot.js","sourceRoot":"","sources":["../../src/pilot/pilot.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prompt constants for the LLM client.
|
|
3
|
+
*/
|
|
4
|
+
/** System prompt that defines the Pilot's persona and expected response format. */
|
|
5
|
+
export declare const SYSTEM_PROMPT = "You are The Pilot, an AI agent that executes end-to-end tests in a web browser.\n\nYou receive a plain-English test step and the current page state.\n\nThe page state may be provided in different levels of detail:\n- Full state: complete accessibility tree + visible page text (first step and after navigation).\n- Tree diff: only the added/removed lines from the accessibility tree (when a small part of the page changed, e.g. a form wizard step). Combine this with the full tree from earlier in the conversation \u2014 unchanged elements keep the same refs.\n- Unchanged: the page is identical to the previous step.\n\nElement refs (e1, e2, ...) are STABLE within a test case \u2014 the same element always keeps the same ref across captures. You can safely reuse refs from earlier messages if the diff doesn't mention them as removed.\n\nYour job is to determine the SINGLE browser action needed to execute the step.\n\nAvailable actions:\n- click: Click an element. Requires \"ref\" or \"text\".\n- check: Check a checkbox. Requires \"ref\" or \"text\". Use this instead of click for checkboxes.\n- uncheck: Uncheck a checkbox. Requires \"ref\" or \"text\".\n- type: Type text into an input. Requires \"ref\" or \"text\", and \"value\".\n- select: Select an option from a dropdown. Requires \"ref\" or \"text\", and \"value\" (the option label).\n- autocomplete: Type into an autocomplete/typeahead field, wait for suggestions to appear, and click one. Requires \"ref\" or \"text\", \"value\" (the text to type), and optionally \"option\" (the suggestion to select \u2014 defaults to the first suggestion if omitted).\n- scroll: Scroll the page. Requires \"value\" (\"up\" or \"down\"). Optional \"ref\" to scroll a specific element.\n- navigate: Navigate to a URL. Requires \"value\" (the URL or path).\n- press: Press a keyboard key. Requires \"value\" (key name, e.g. \"Enter\", \"Tab\", \"Escape\").\n- wait: Wait for a condition. Requires \"value\" (description of what to wait for).\n- remember: Capture a value from the page for later comparison. Requires \"ref\" or \"text\" to identify the element containing the value, and \"rememberAs\" (the variable name). The runtime reads the textContent of the targeted element. IMPORTANT: Target the most specific element that contains the actual value \u2014 not a parent container, heading, or wrapper that includes unrelated text.\n- assert: Check a condition on the page. Requires \"assertion\" with \"type\" and \"expected\".\n Assertion types: \"contains_text\", \"not_contains_text\", \"url_contains\", \"element_visible\", \"element_not_visible\", \"element_exists\", \"link_exists\", \"field_exists\".\n Special type \"compare\": requires additional \"compare\" field with \"variable\" (remembered name) and \"operator\" (less_than, greater_than, equal, not_equal, less_or_equal, greater_or_equal). The \"expected\" field describes what current value to read from the page. Use \"ref\" to target the element containing the current value.\n\nElement targeting:\n- Use \"ref\" when the target element appears in the accessibility tree (preferred).\n- Use \"text\" when the target is NOT in the accessibility tree but is visible on the page. The text value should match the visible text of the element you want to interact with. This is common when page markup lacks proper ARIA roles.\n- Never guess a ref. If the element you need is not in the tree, use \"text\" instead.\n- A \"Visible page text\" section shows what a human actually sees on the page. Use it to find elements that are missing from the accessibility tree \u2014 target them with \"text\" matching their visible label.\n\nIMPORTANT: Any step that starts with \"check that\" is ALWAYS an assertion. Never return a click, type, or other interaction for a \"check that\" step.\n\nIMPORTANT: When the step description contains a word or phrase in quotes (e.g. the \"resultat\" count, the \"Total\" badge), the target element MUST contain that exact quoted text. Use this as a strict filter when choosing which element to target \u2014 do not pick an element that lacks the quoted keyword in its visible text.\n\nRespond with ONLY a JSON object. No markdown, no explanation. Example responses:\n\n{\"action\":\"click\",\"ref\":\"e5\"}\n{\"action\":\"click\",\"text\":\"About us\"}\n{\"action\":\"type\",\"ref\":\"e3\",\"value\":\"jane@example.com\"}\n{\"action\":\"select\",\"ref\":\"e8\",\"value\":\"Canada\"}\n{\"action\":\"autocomplete\",\"ref\":\"e4\",\"value\":\"foo\"}\n{\"action\":\"autocomplete\",\"ref\":\"e4\",\"value\":\"foo\",\"option\":\"foobar inc\"}\n{\"action\":\"check\",\"ref\":\"e12\"}\n{\"action\":\"navigate\",\"value\":\"/products\"}\n{\"action\":\"press\",\"value\":\"Enter\"}\n{\"action\":\"remember\",\"ref\":\"e15\",\"rememberAs\":\"product_count\"}\n{\"action\":\"assert\",\"assertion\":{\"type\":\"compare\",\"expected\":\"product count\"},\"compare\":{\"variable\":\"product_count\",\"operator\":\"less_than\"},\"ref\":\"e15\"}\n{\"action\":\"assert\",\"assertion\":{\"type\":\"contains_text\",\"expected\":\"Welcome back\"}}\n{\"action\":\"scroll\",\"value\":\"down\"}\n";
|
|
6
|
+
export declare const PLAN_SYSTEM_PROMPT = "We are processing a test description for an automated E2E testing tool.\n\nIt has a list of test steps in natural language that you should convert into actions using a simple line-based format. Output one line per action. A single input step may produce multiple output lines if it describes a sequence of actions.\n\nAction syntax (one per line):\n- PAGE \"description\" \u2014 needs the live page to resolve (click, type, select interactions). The description should be a clear, atomic instruction.\n- EXPAND \"description\" \u2014 a compound step that requires seeing the live page to decompose into multiple actions. Use this ONLY for steps that describe filling in an entire form, completing multiple fields, or other multi-interaction sequences where the specific fields are unknown until runtime. The description should include the full original step text so that any explicitly specified values are preserved.\n- REMEMBER \"what to capture from the page\" as \"variable_name\" \u2014 captures a value from the page for later comparison. The description tells the runtime what to extract (e.g. \"the number of products shown\", \"the total price\", \"the item count badge text\"). The variable name is a short identifier.\n- COMPARE \"what to read now\" \"operator\" remembered \"variable_name\" \u2014 compares a current page value against a previously remembered value. Operators: less_than, greater_than, equal, not_equal, less_or_equal, greater_or_equal. The first description tells the runtime what current value to read.\n- assert contains_text \"text\"\n- assert not_contains_text \"text\"\n- assert url_contains \"text\"\n- assert element_visible \"text\"\n- assert element_not_visible \"text\"\n- assert link_exists \"href\"\n- assert field_exists \"label\"\n- navigate \"url\" \u2014 ONLY for explicit URLs or paths starting with \"/\" or \"http\". Example: navigate \"/about\", navigate \"https://example.com\". Do NOT use navigate for steps like \"go to the About page\" or \"navigate to Contact from menu\" \u2014 those describe clicking a link or menu item and should be PAGE instead.\n- press \"key\"\n- scroll \"up|down\"\n\nRules:\n- Any step that says \"check that\" or \"verify\" or similar language is ALWAYS an assertion.\n- Assertions with explicit quoted strings (e.g. check that the page contains \"Welcome\") can be resolved as literal assertions: assert contains_text \"Welcome\"\n- Assertions WITHOUT quoted strings describe something conceptual (e.g. \"check that the page contains a Leads form\", \"check that there is a contact section\"). These CANNOT be pre-resolved because the actual page text may differ from the description. Output PAGE with the full step as description so the runtime LLM can inspect the page.\n- For assertions that CAN be resolved, preserve the FULL expected text exactly as written. Never truncate or shorten it.\n- Steps that require seeing the page to identify interactive elements \u2192 PAGE with a description.\n- References to earlier steps: When a step uses pronouns or references like \"that form\", \"the same page\", \"this dropdown\", resolve them using context from earlier steps. Replace the reference with the concrete name from the earlier step. For example, if step 6 says 'check that the page contains a \"Vad beh\u00F6ver du hj\u00E4lp med?\" form' and step 7 says 'Select F\u00F6retag in that form', resolve \"that form\" to the \"Vad beh\u00F6ver du hj\u00E4lp med?\" form.\n- IMPORTANT: Each output line must describe exactly ONE atomic interaction (one click, one type, one select). If an input step describes or implies multiple interactions \u2014 whether separated by dashes, commas, slashes, \"then\", \"and\", or simply listing several values/items/choices \u2014 split it into one PAGE line per interaction. Always err on the side of splitting: if a step could be multiple actions, it IS multiple actions.\n- When a step lists multiple values separated by dashes (e.g. \"Select A - B - C in the form\"), these are sequential CLICKS on buttons or tabs \u2014 NOT dropdown selections. Split into separate click steps. Use \"click\" in the description, not \"select\".\n- When splitting a step into multiple actions, PRESERVE the full original context in each sub-step description. The runtime LLM will see each sub-step independently without knowledge of the others, so each description must be self-contained and unambiguous. Include enough detail to identify the correct element (e.g. mention the form name, section, or UI context).\n For example:\n Input: \"Select Category - Subcategory - Option in the filter form\" \u2192 three lines:\n PAGE \"click the 'Category' button/tab in the filter form (first selection in the sequence Category - Subcategory - Option)\"\n PAGE \"click 'Subcategory' in the filter form (second selection after Category was selected)\"\n PAGE \"click 'Option' in the filter form (third selection after Category and Subcategory were selected)\"\n Input: \"Fill in name, email and phone\" \u2192 three lines:\n PAGE \"fill in the name field\"\n PAGE \"fill in the email field\"\n PAGE \"fill in the phone field\"\n- EXCEPTION: Selecting a value from a dropdown or filter is ALWAYS a single PAGE step. Do NOT split \"select X in Y\" into \"open Y\" + \"select X\" \u2014 the runtime handles opening and selecting atomically. Example:\n Input: \"select Elektriker in V\u00E4lj tj\u00E4nst\" \u2192 one line:\n PAGE \"select 'Elektriker' in 'V\u00E4lj tj\u00E4nst'\"\n Input: \"choose Red from the color dropdown\" \u2192 one line:\n PAGE \"select 'Red' from the color dropdown\"\n- EXCEPTION: If a step describes filling in an entire form without listing specific fields\n (e.g. \"fill in the form with some test data and submit it\", \"complete the contact form with email foo@bar.com\"),\n use a single EXPAND line instead of splitting. EXPAND means the runtime will inspect the actual form fields on the page\n and generate appropriate actions. Include the full original text so any explicit values are preserved.\n For example:\n Input: \"fill in the form with some test data and submit it\" \u2192 one line:\n EXPAND \"fill in the form with some test data and submit it\"\n Input: \"fill in the form with email foo@example.com and some test data\" \u2192 one line:\n EXPAND \"fill in the form with email foo@example.com and some test data\"\n- REMEMBER/COMPARE: When a step describes saving, noting, or remembering a value for later comparison, output a REMEMBER line. The REMEMBER line MUST always have the format: REMEMBER \"description\" as \"variable_name\" \u2014 both parts are required. Choose a short, descriptive variable name based on what is being captured.\n When a step describes comparing a current value against a previously saved one (e.g. \"check that X is less than before\", \"verify the count decreased\"), output a COMPARE line. The COMPARE MUST reference the exact variable name used in the earlier REMEMBER.\n Any language implying \"before vs after\" comparison requires a REMEMBER before the action and a COMPARE after.\n For example:\n Input: \"note the number of search results\" \u2192 REMEMBER \"the number of search results\" as \"result_count\"\n Input: \"check that the number of results is less than before filtering\" \u2192 COMPARE \"the number of search results\" \"less_than\" remembered \"result_count\"\n Input: \"remember the total price\" \u2192 REMEMBER \"the total price shown\" as \"total_price\"\n Input: \"verify the price didn't change\" \u2192 COMPARE \"the total price shown\" \"equal\" remembered \"total_price\"\n Input: \"remember the number of search results\" \u2192 REMEMBER \"the number of search results\" as \"search_result_count\"\n Input: \"check that the search results count has decreased\" \u2192 COMPARE \"the number of search results\" \"less_than\" remembered \"search_result_count\"\n- No blank lines, no numbering, no explanation. Only action lines.\n";
|
|
7
|
+
export declare const EXPAND_SYSTEM_PROMPT = "You are expanding a high-level test step into concrete atomic actions based on the actual form fields visible on the page.\n\nYou receive:\n1. The original step instruction (which may specify some values explicitly and leave others to your judgement).\n2. The accessibility tree of the current page (with element refs).\n3. A detailed list of form fields with their label, placeholder, input type, required status, and available options.\n\nYour job is to produce one action line per interaction needed to fulfill the step. Use the same line-based format:\n- PAGE \"type <value> into the <field label/placeholder> field\" \u2014 for regular text input fields. Always reference the field by its label or placeholder as shown in the form fields list.\n- PAGE \"type <value> into the <field label/placeholder> autocomplete field and select the first suggestion\" \u2014 for fields marked [autocomplete]. This tells the runtime to type, wait for the dropdown, and click the first option.\n- PAGE \"type <value> into the <field label/placeholder> autocomplete field and select <specific option>\" \u2014 when the step specifies a particular option to pick from the autocomplete suggestions.\n- PAGE \"select <option> in the <field label> dropdown\" \u2014 for select fields.\n- PAGE \"check the <label> checkbox\" \u2014 for checkboxes.\n- PAGE \"click the <button text> button\" \u2014 for submit or other buttons.\n- press \"Enter\" \u2014 if the form should be submitted via Enter key.\n\nRules for autocomplete fields (marked [autocomplete] in the field list):\n- These are typeahead/combobox fields that show a dropdown of suggestions as the user types.\n- ALWAYS use the \"autocomplete field\" phrasing so the runtime knows to wait for and interact with the dropdown.\n- By default, select the first suggestion unless the step explicitly names a different choice.\n- Type a short search term that is likely to produce relevant results (e.g. first few characters of an expected value).\n\nRules for choosing test data:\n- If the step explicitly provides a value for a field (e.g. \"with email foo@example.com\"), use that EXACT value for the matching field. Match by field purpose \u2014 the step may say \"email\" while the field label says \"E-post\" or \"Mail address\".\n- For fields NOT explicitly specified, generate realistic fake test data appropriate for the field. Use the field's label, placeholder, and input type to determine what kind of data to generate:\n - Use the input type attribute (email, tel, url, number, etc.) to pick the right format.\n - Read the label and placeholder text (in whatever language they are written) to understand what the field expects, then generate a plausible value.\n - For free-text or message fields, use a short generic test string like \"Test message\".\n- For select/dropdown fields: pick the first non-empty option unless the step specifies a value.\n- For checkbox fields: check them if it sounds like it is needed. This includes consent checkboxes such as terms of service, privacy policy, data processing agreements, cookie consent, or similar \u2014 these must be checked for the form submission to succeed.\n- For required fields: always include them.\n- For optional fields: include them too (fill the whole form).\n- If the step says \"submit\" or similar, include a click on the submit button as the last action.\n\nOutput ONLY action lines, one per line. No blank lines, no numbering, no explanation.\n";
|
|
8
|
+
//# sourceMappingURL=prompts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../../src/pilot/prompts.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,mFAAmF;AACnF,eAAO,MAAM,aAAa,0gKAsDzB,CAAA;AAID,eAAO,MAAM,kBAAkB,uyPAgE9B,CAAA;AAID,eAAO,MAAM,oBAAoB,+4GAmChC,CAAA"}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prompt constants for the LLM client.
|
|
3
|
+
*/
|
|
4
|
+
/** System prompt that defines the Pilot's persona and expected response format. */
|
|
5
|
+
export const SYSTEM_PROMPT = `You are The Pilot, an AI agent that executes end-to-end tests in a web browser.
|
|
6
|
+
|
|
7
|
+
You receive a plain-English test step and the current page state.
|
|
8
|
+
|
|
9
|
+
The page state may be provided in different levels of detail:
|
|
10
|
+
- Full state: complete accessibility tree + visible page text (first step and after navigation).
|
|
11
|
+
- Tree diff: only the added/removed lines from the accessibility tree (when a small part of the page changed, e.g. a form wizard step). Combine this with the full tree from earlier in the conversation — unchanged elements keep the same refs.
|
|
12
|
+
- Unchanged: the page is identical to the previous step.
|
|
13
|
+
|
|
14
|
+
Element refs (e1, e2, ...) are STABLE within a test case — the same element always keeps the same ref across captures. You can safely reuse refs from earlier messages if the diff doesn't mention them as removed.
|
|
15
|
+
|
|
16
|
+
Your job is to determine the SINGLE browser action needed to execute the step.
|
|
17
|
+
|
|
18
|
+
Available actions:
|
|
19
|
+
- click: Click an element. Requires "ref" or "text".
|
|
20
|
+
- check: Check a checkbox. Requires "ref" or "text". Use this instead of click for checkboxes.
|
|
21
|
+
- uncheck: Uncheck a checkbox. Requires "ref" or "text".
|
|
22
|
+
- type: Type text into an input. Requires "ref" or "text", and "value".
|
|
23
|
+
- select: Select an option from a dropdown. Requires "ref" or "text", and "value" (the option label).
|
|
24
|
+
- autocomplete: Type into an autocomplete/typeahead field, wait for suggestions to appear, and click one. Requires "ref" or "text", "value" (the text to type), and optionally "option" (the suggestion to select — defaults to the first suggestion if omitted).
|
|
25
|
+
- scroll: Scroll the page. Requires "value" ("up" or "down"). Optional "ref" to scroll a specific element.
|
|
26
|
+
- navigate: Navigate to a URL. Requires "value" (the URL or path).
|
|
27
|
+
- press: Press a keyboard key. Requires "value" (key name, e.g. "Enter", "Tab", "Escape").
|
|
28
|
+
- wait: Wait for a condition. Requires "value" (description of what to wait for).
|
|
29
|
+
- remember: Capture a value from the page for later comparison. Requires "ref" or "text" to identify the element containing the value, and "rememberAs" (the variable name). The runtime reads the textContent of the targeted element. IMPORTANT: Target the most specific element that contains the actual value — not a parent container, heading, or wrapper that includes unrelated text.
|
|
30
|
+
- assert: Check a condition on the page. Requires "assertion" with "type" and "expected".
|
|
31
|
+
Assertion types: "contains_text", "not_contains_text", "url_contains", "element_visible", "element_not_visible", "element_exists", "link_exists", "field_exists".
|
|
32
|
+
Special type "compare": requires additional "compare" field with "variable" (remembered name) and "operator" (less_than, greater_than, equal, not_equal, less_or_equal, greater_or_equal). The "expected" field describes what current value to read from the page. Use "ref" to target the element containing the current value.
|
|
33
|
+
|
|
34
|
+
Element targeting:
|
|
35
|
+
- Use "ref" when the target element appears in the accessibility tree (preferred).
|
|
36
|
+
- Use "text" when the target is NOT in the accessibility tree but is visible on the page. The text value should match the visible text of the element you want to interact with. This is common when page markup lacks proper ARIA roles.
|
|
37
|
+
- Never guess a ref. If the element you need is not in the tree, use "text" instead.
|
|
38
|
+
- A "Visible page text" section shows what a human actually sees on the page. Use it to find elements that are missing from the accessibility tree — target them with "text" matching their visible label.
|
|
39
|
+
|
|
40
|
+
IMPORTANT: Any step that starts with "check that" is ALWAYS an assertion. Never return a click, type, or other interaction for a "check that" step.
|
|
41
|
+
|
|
42
|
+
IMPORTANT: When the step description contains a word or phrase in quotes (e.g. the "resultat" count, the "Total" badge), the target element MUST contain that exact quoted text. Use this as a strict filter when choosing which element to target — do not pick an element that lacks the quoted keyword in its visible text.
|
|
43
|
+
|
|
44
|
+
Respond with ONLY a JSON object. No markdown, no explanation. Example responses:
|
|
45
|
+
|
|
46
|
+
{"action":"click","ref":"e5"}
|
|
47
|
+
{"action":"click","text":"About us"}
|
|
48
|
+
{"action":"type","ref":"e3","value":"jane@example.com"}
|
|
49
|
+
{"action":"select","ref":"e8","value":"Canada"}
|
|
50
|
+
{"action":"autocomplete","ref":"e4","value":"foo"}
|
|
51
|
+
{"action":"autocomplete","ref":"e4","value":"foo","option":"foobar inc"}
|
|
52
|
+
{"action":"check","ref":"e12"}
|
|
53
|
+
{"action":"navigate","value":"/products"}
|
|
54
|
+
{"action":"press","value":"Enter"}
|
|
55
|
+
{"action":"remember","ref":"e15","rememberAs":"product_count"}
|
|
56
|
+
{"action":"assert","assertion":{"type":"compare","expected":"product count"},"compare":{"variable":"product_count","operator":"less_than"},"ref":"e15"}
|
|
57
|
+
{"action":"assert","assertion":{"type":"contains_text","expected":"Welcome back"}}
|
|
58
|
+
{"action":"scroll","value":"down"}
|
|
59
|
+
`;
|
|
60
|
+
// ── Step planning prompt ─────────────────────────────────────────────
|
|
61
|
+
export const PLAN_SYSTEM_PROMPT = `We are processing a test description for an automated E2E testing tool.
|
|
62
|
+
|
|
63
|
+
It has a list of test steps in natural language that you should convert into actions using a simple line-based format. Output one line per action. A single input step may produce multiple output lines if it describes a sequence of actions.
|
|
64
|
+
|
|
65
|
+
Action syntax (one per line):
|
|
66
|
+
- PAGE "description" — needs the live page to resolve (click, type, select interactions). The description should be a clear, atomic instruction.
|
|
67
|
+
- EXPAND "description" — a compound step that requires seeing the live page to decompose into multiple actions. Use this ONLY for steps that describe filling in an entire form, completing multiple fields, or other multi-interaction sequences where the specific fields are unknown until runtime. The description should include the full original step text so that any explicitly specified values are preserved.
|
|
68
|
+
- REMEMBER "what to capture from the page" as "variable_name" — captures a value from the page for later comparison. The description tells the runtime what to extract (e.g. "the number of products shown", "the total price", "the item count badge text"). The variable name is a short identifier.
|
|
69
|
+
- COMPARE "what to read now" "operator" remembered "variable_name" — compares a current page value against a previously remembered value. Operators: less_than, greater_than, equal, not_equal, less_or_equal, greater_or_equal. The first description tells the runtime what current value to read.
|
|
70
|
+
- assert contains_text "text"
|
|
71
|
+
- assert not_contains_text "text"
|
|
72
|
+
- assert url_contains "text"
|
|
73
|
+
- assert element_visible "text"
|
|
74
|
+
- assert element_not_visible "text"
|
|
75
|
+
- assert link_exists "href"
|
|
76
|
+
- assert field_exists "label"
|
|
77
|
+
- navigate "url" — ONLY for explicit URLs or paths starting with "/" or "http". Example: navigate "/about", navigate "https://example.com". Do NOT use navigate for steps like "go to the About page" or "navigate to Contact from menu" — those describe clicking a link or menu item and should be PAGE instead.
|
|
78
|
+
- press "key"
|
|
79
|
+
- scroll "up|down"
|
|
80
|
+
|
|
81
|
+
Rules:
|
|
82
|
+
- Any step that says "check that" or "verify" or similar language is ALWAYS an assertion.
|
|
83
|
+
- Assertions with explicit quoted strings (e.g. check that the page contains "Welcome") can be resolved as literal assertions: assert contains_text "Welcome"
|
|
84
|
+
- Assertions WITHOUT quoted strings describe something conceptual (e.g. "check that the page contains a Leads form", "check that there is a contact section"). These CANNOT be pre-resolved because the actual page text may differ from the description. Output PAGE with the full step as description so the runtime LLM can inspect the page.
|
|
85
|
+
- For assertions that CAN be resolved, preserve the FULL expected text exactly as written. Never truncate or shorten it.
|
|
86
|
+
- Steps that require seeing the page to identify interactive elements → PAGE with a description.
|
|
87
|
+
- References to earlier steps: When a step uses pronouns or references like "that form", "the same page", "this dropdown", resolve them using context from earlier steps. Replace the reference with the concrete name from the earlier step. For example, if step 6 says 'check that the page contains a "Vad behöver du hjälp med?" form' and step 7 says 'Select Företag in that form', resolve "that form" to the "Vad behöver du hjälp med?" form.
|
|
88
|
+
- IMPORTANT: Each output line must describe exactly ONE atomic interaction (one click, one type, one select). If an input step describes or implies multiple interactions — whether separated by dashes, commas, slashes, "then", "and", or simply listing several values/items/choices — split it into one PAGE line per interaction. Always err on the side of splitting: if a step could be multiple actions, it IS multiple actions.
|
|
89
|
+
- When a step lists multiple values separated by dashes (e.g. "Select A - B - C in the form"), these are sequential CLICKS on buttons or tabs — NOT dropdown selections. Split into separate click steps. Use "click" in the description, not "select".
|
|
90
|
+
- When splitting a step into multiple actions, PRESERVE the full original context in each sub-step description. The runtime LLM will see each sub-step independently without knowledge of the others, so each description must be self-contained and unambiguous. Include enough detail to identify the correct element (e.g. mention the form name, section, or UI context).
|
|
91
|
+
For example:
|
|
92
|
+
Input: "Select Category - Subcategory - Option in the filter form" → three lines:
|
|
93
|
+
PAGE "click the 'Category' button/tab in the filter form (first selection in the sequence Category - Subcategory - Option)"
|
|
94
|
+
PAGE "click 'Subcategory' in the filter form (second selection after Category was selected)"
|
|
95
|
+
PAGE "click 'Option' in the filter form (third selection after Category and Subcategory were selected)"
|
|
96
|
+
Input: "Fill in name, email and phone" → three lines:
|
|
97
|
+
PAGE "fill in the name field"
|
|
98
|
+
PAGE "fill in the email field"
|
|
99
|
+
PAGE "fill in the phone field"
|
|
100
|
+
- EXCEPTION: Selecting a value from a dropdown or filter is ALWAYS a single PAGE step. Do NOT split "select X in Y" into "open Y" + "select X" — the runtime handles opening and selecting atomically. Example:
|
|
101
|
+
Input: "select Elektriker in Välj tjänst" → one line:
|
|
102
|
+
PAGE "select 'Elektriker' in 'Välj tjänst'"
|
|
103
|
+
Input: "choose Red from the color dropdown" → one line:
|
|
104
|
+
PAGE "select 'Red' from the color dropdown"
|
|
105
|
+
- EXCEPTION: If a step describes filling in an entire form without listing specific fields
|
|
106
|
+
(e.g. "fill in the form with some test data and submit it", "complete the contact form with email foo@bar.com"),
|
|
107
|
+
use a single EXPAND line instead of splitting. EXPAND means the runtime will inspect the actual form fields on the page
|
|
108
|
+
and generate appropriate actions. Include the full original text so any explicit values are preserved.
|
|
109
|
+
For example:
|
|
110
|
+
Input: "fill in the form with some test data and submit it" → one line:
|
|
111
|
+
EXPAND "fill in the form with some test data and submit it"
|
|
112
|
+
Input: "fill in the form with email foo@example.com and some test data" → one line:
|
|
113
|
+
EXPAND "fill in the form with email foo@example.com and some test data"
|
|
114
|
+
- REMEMBER/COMPARE: When a step describes saving, noting, or remembering a value for later comparison, output a REMEMBER line. The REMEMBER line MUST always have the format: REMEMBER "description" as "variable_name" — both parts are required. Choose a short, descriptive variable name based on what is being captured.
|
|
115
|
+
When a step describes comparing a current value against a previously saved one (e.g. "check that X is less than before", "verify the count decreased"), output a COMPARE line. The COMPARE MUST reference the exact variable name used in the earlier REMEMBER.
|
|
116
|
+
Any language implying "before vs after" comparison requires a REMEMBER before the action and a COMPARE after.
|
|
117
|
+
For example:
|
|
118
|
+
Input: "note the number of search results" → REMEMBER "the number of search results" as "result_count"
|
|
119
|
+
Input: "check that the number of results is less than before filtering" → COMPARE "the number of search results" "less_than" remembered "result_count"
|
|
120
|
+
Input: "remember the total price" → REMEMBER "the total price shown" as "total_price"
|
|
121
|
+
Input: "verify the price didn't change" → COMPARE "the total price shown" "equal" remembered "total_price"
|
|
122
|
+
Input: "remember the number of search results" → REMEMBER "the number of search results" as "search_result_count"
|
|
123
|
+
Input: "check that the search results count has decreased" → COMPARE "the number of search results" "less_than" remembered "search_result_count"
|
|
124
|
+
- No blank lines, no numbering, no explanation. Only action lines.
|
|
125
|
+
`;
|
|
126
|
+
// ── Step expansion prompt (runtime, with page context) ──────────────
|
|
127
|
+
export const EXPAND_SYSTEM_PROMPT = `You are expanding a high-level test step into concrete atomic actions based on the actual form fields visible on the page.
|
|
128
|
+
|
|
129
|
+
You receive:
|
|
130
|
+
1. The original step instruction (which may specify some values explicitly and leave others to your judgement).
|
|
131
|
+
2. The accessibility tree of the current page (with element refs).
|
|
132
|
+
3. A detailed list of form fields with their label, placeholder, input type, required status, and available options.
|
|
133
|
+
|
|
134
|
+
Your job is to produce one action line per interaction needed to fulfill the step. Use the same line-based format:
|
|
135
|
+
- PAGE "type <value> into the <field label/placeholder> field" — for regular text input fields. Always reference the field by its label or placeholder as shown in the form fields list.
|
|
136
|
+
- PAGE "type <value> into the <field label/placeholder> autocomplete field and select the first suggestion" — for fields marked [autocomplete]. This tells the runtime to type, wait for the dropdown, and click the first option.
|
|
137
|
+
- PAGE "type <value> into the <field label/placeholder> autocomplete field and select <specific option>" — when the step specifies a particular option to pick from the autocomplete suggestions.
|
|
138
|
+
- PAGE "select <option> in the <field label> dropdown" — for select fields.
|
|
139
|
+
- PAGE "check the <label> checkbox" — for checkboxes.
|
|
140
|
+
- PAGE "click the <button text> button" — for submit or other buttons.
|
|
141
|
+
- press "Enter" — if the form should be submitted via Enter key.
|
|
142
|
+
|
|
143
|
+
Rules for autocomplete fields (marked [autocomplete] in the field list):
|
|
144
|
+
- These are typeahead/combobox fields that show a dropdown of suggestions as the user types.
|
|
145
|
+
- ALWAYS use the "autocomplete field" phrasing so the runtime knows to wait for and interact with the dropdown.
|
|
146
|
+
- By default, select the first suggestion unless the step explicitly names a different choice.
|
|
147
|
+
- Type a short search term that is likely to produce relevant results (e.g. first few characters of an expected value).
|
|
148
|
+
|
|
149
|
+
Rules for choosing test data:
|
|
150
|
+
- If the step explicitly provides a value for a field (e.g. "with email foo@example.com"), use that EXACT value for the matching field. Match by field purpose — the step may say "email" while the field label says "E-post" or "Mail address".
|
|
151
|
+
- For fields NOT explicitly specified, generate realistic fake test data appropriate for the field. Use the field's label, placeholder, and input type to determine what kind of data to generate:
|
|
152
|
+
- Use the input type attribute (email, tel, url, number, etc.) to pick the right format.
|
|
153
|
+
- Read the label and placeholder text (in whatever language they are written) to understand what the field expects, then generate a plausible value.
|
|
154
|
+
- For free-text or message fields, use a short generic test string like "Test message".
|
|
155
|
+
- For select/dropdown fields: pick the first non-empty option unless the step specifies a value.
|
|
156
|
+
- For checkbox fields: check them if it sounds like it is needed. This includes consent checkboxes such as terms of service, privacy policy, data processing agreements, cookie consent, or similar — these must be checked for the form submission to succeed.
|
|
157
|
+
- For required fields: always include them.
|
|
158
|
+
- For optional fields: include them too (fill the whole form).
|
|
159
|
+
- If the step says "submit" or similar, include a click on the submit button as the last action.
|
|
160
|
+
|
|
161
|
+
Output ONLY action lines, one per line. No blank lines, no numbering, no explanation.
|
|
162
|
+
`;
|
|
163
|
+
//# sourceMappingURL=prompts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompts.js","sourceRoot":"","sources":["../../src/pilot/prompts.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,mFAAmF;AACnF,MAAM,CAAC,MAAM,aAAa,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsD5B,CAAA;AAED,wEAAwE;AAExE,MAAM,CAAC,MAAM,kBAAkB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgEjC,CAAA;AAED,uEAAuE;AAEvE,MAAM,CAAC,MAAM,oBAAoB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmCnC,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anthropic.d.ts","sourceRoot":"","sources":["../../../src/pilot/providers/anthropic.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAe,WAAW,EAAkB,MAAM,YAAY,CAAA;AAE1E;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW,CAuDpE"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Native Anthropic Messages API provider.
|
|
3
|
+
*/
|
|
4
|
+
export function createAnthropicProvider(baseUrl) {
|
|
5
|
+
const endpoint = `${baseUrl.replace(/\/+$/, "")}/v1/messages`;
|
|
6
|
+
return {
|
|
7
|
+
async chatCompletion(messages, config) {
|
|
8
|
+
// Extract system message into separate field
|
|
9
|
+
const systemMessages = messages.filter((m) => m.role === "system");
|
|
10
|
+
const nonSystemMessages = messages.filter((m) => m.role !== "system");
|
|
11
|
+
const systemText = systemMessages
|
|
12
|
+
.map((m) => m.content)
|
|
13
|
+
.join("\n\n");
|
|
14
|
+
const response = await fetch(endpoint, {
|
|
15
|
+
method: "POST",
|
|
16
|
+
headers: {
|
|
17
|
+
"content-type": "application/json",
|
|
18
|
+
"x-api-key": config.apiKey,
|
|
19
|
+
"anthropic-version": "2023-06-01",
|
|
20
|
+
},
|
|
21
|
+
body: JSON.stringify({
|
|
22
|
+
model: config.model,
|
|
23
|
+
max_tokens: 4096,
|
|
24
|
+
temperature: 0,
|
|
25
|
+
...(systemText ? { system: systemText } : {}),
|
|
26
|
+
messages: nonSystemMessages.map((m) => ({
|
|
27
|
+
role: m.role,
|
|
28
|
+
content: m.content,
|
|
29
|
+
})),
|
|
30
|
+
}),
|
|
31
|
+
});
|
|
32
|
+
if (!response.ok) {
|
|
33
|
+
const body = await response.text();
|
|
34
|
+
throw new Error(`LLM API error ${String(response.status)}: ${body}`);
|
|
35
|
+
}
|
|
36
|
+
const data = (await response.json());
|
|
37
|
+
const content = data.content[0]?.text;
|
|
38
|
+
if (!content) {
|
|
39
|
+
throw new Error("LLM returned empty response");
|
|
40
|
+
}
|
|
41
|
+
return content;
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=anthropic.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anthropic.js","sourceRoot":"","sources":["../../../src/pilot/providers/anthropic.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,MAAM,UAAU,uBAAuB,CAAC,OAAe;IACtD,MAAM,QAAQ,GAAG,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,cAAc,CAAA;IAE7D,OAAO;QACN,KAAK,CAAC,cAAc,CACnB,QAAuB,EACvB,MAAsB;YAEtB,6CAA6C;YAC7C,MAAM,cAAc,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAA;YAClE,MAAM,iBAAiB,GAAG,QAAQ,CAAC,MAAM,CACxC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,QAAQ,CAC1B,CAAA;YACD,MAAM,UAAU,GAAG,cAAc;iBAC/B,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;iBACrB,IAAI,CAAC,MAAM,CAAC,CAAA;YAEd,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,QAAQ,EAAE;gBACtC,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE;oBACR,cAAc,EAAE,kBAAkB;oBAClC,WAAW,EAAE,MAAM,CAAC,MAAM;oBAC1B,mBAAmB,EAAE,YAAY;iBACjC;gBACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;oBACpB,KAAK,EAAE,MAAM,CAAC,KAAK;oBACnB,UAAU,EAAE,IAAI;oBAChB,WAAW,EAAE,CAAC;oBACd,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;oBAC7C,QAAQ,EAAE,iBAAiB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;wBACvC,IAAI,EAAE,CAAC,CAAC,IAAI;wBACZ,OAAO,EAAE,CAAC,CAAC,OAAO;qBAClB,CAAC,CAAC;iBACH,CAAC;aACF,CAAC,CAAA;YAEF,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;gBAClB,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAA;gBAClC,MAAM,IAAI,KAAK,CACd,iBAAiB,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,IAAI,EAAE,CACnD,CAAA;YACF,CAAC;YAED,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAElC,CAAA;YAED,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,IAAI,CAAA;YACrC,IAAI,CAAC,OAAO,EAAE,CAAC;gBACd,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAA;YAC/C,CAAC;YAED,OAAO,OAAO,CAAA;QACf,CAAC;KACD,CAAA;AACF,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gemini.d.ts","sourceRoot":"","sources":["../../../src/pilot/providers/gemini.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAe,WAAW,EAAkB,MAAM,YAAY,CAAA;AAI1E;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,eAAe,CAAC,EAAE,MAAM,GAAG,WAAW,CA0E1E"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
const DEFAULT_BASE_URL = "https://generativelanguage.googleapis.com";
|
|
2
|
+
/**
|
|
3
|
+
* Native Google Gemini API provider.
|
|
4
|
+
*/
|
|
5
|
+
export function createGeminiProvider(baseUrlOverride) {
|
|
6
|
+
return {
|
|
7
|
+
async chatCompletion(messages, config) {
|
|
8
|
+
const baseUrl = (baseUrlOverride ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
|
|
9
|
+
const endpoint = `${baseUrl}/v1beta/models/${config.model}:generateContent?key=${config.apiKey}`;
|
|
10
|
+
// Separate system messages from conversation messages
|
|
11
|
+
const systemMessages = messages.filter((m) => m.role === "system");
|
|
12
|
+
const conversationMessages = messages.filter((m) => m.role !== "system");
|
|
13
|
+
// Build system instruction
|
|
14
|
+
const systemInstruction = systemMessages.length > 0
|
|
15
|
+
? {
|
|
16
|
+
parts: systemMessages.map((m) => ({
|
|
17
|
+
text: m.content,
|
|
18
|
+
})),
|
|
19
|
+
}
|
|
20
|
+
: undefined;
|
|
21
|
+
// Map messages to Gemini format (assistant → model)
|
|
22
|
+
const contents = conversationMessages.map((m) => ({
|
|
23
|
+
role: m.role === "assistant" ? "model" : m.role,
|
|
24
|
+
parts: [{ text: m.content }],
|
|
25
|
+
}));
|
|
26
|
+
const body = {
|
|
27
|
+
contents,
|
|
28
|
+
generationConfig: {
|
|
29
|
+
temperature: 0,
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
if (systemInstruction) {
|
|
33
|
+
body.systemInstruction = systemInstruction;
|
|
34
|
+
}
|
|
35
|
+
const response = await fetch(endpoint, {
|
|
36
|
+
method: "POST",
|
|
37
|
+
headers: {
|
|
38
|
+
"content-type": "application/json",
|
|
39
|
+
},
|
|
40
|
+
body: JSON.stringify(body),
|
|
41
|
+
});
|
|
42
|
+
if (!response.ok) {
|
|
43
|
+
const respBody = await response.text();
|
|
44
|
+
throw new Error(`LLM API error ${String(response.status)}: ${respBody}`);
|
|
45
|
+
}
|
|
46
|
+
const data = (await response.json());
|
|
47
|
+
const content = data.candidates[0]?.content?.parts[0]?.text;
|
|
48
|
+
if (!content) {
|
|
49
|
+
throw new Error("LLM returned empty response");
|
|
50
|
+
}
|
|
51
|
+
return content;
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=gemini.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gemini.js","sourceRoot":"","sources":["../../../src/pilot/providers/gemini.ts"],"names":[],"mappings":"AAEA,MAAM,gBAAgB,GAAG,2CAA2C,CAAA;AAEpE;;GAEG;AACH,MAAM,UAAU,oBAAoB,CAAC,eAAwB;IAC5D,OAAO;QACN,KAAK,CAAC,cAAc,CACnB,QAAuB,EACvB,MAAsB;YAEtB,MAAM,OAAO,GAAG,CAAC,eAAe,IAAI,gBAAgB,CAAC,CAAC,OAAO,CAC5D,MAAM,EACN,EAAE,CACF,CAAA;YACD,MAAM,QAAQ,GAAG,GAAG,OAAO,kBAAkB,MAAM,CAAC,KAAK,wBAAwB,MAAM,CAAC,MAAM,EAAE,CAAA;YAEhG,sDAAsD;YACtD,MAAM,cAAc,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAA;YAClE,MAAM,oBAAoB,GAAG,QAAQ,CAAC,MAAM,CAC3C,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,QAAQ,CAC1B,CAAA;YAED,2BAA2B;YAC3B,MAAM,iBAAiB,GACtB,cAAc,CAAC,MAAM,GAAG,CAAC;gBACxB,CAAC,CAAC;oBACA,KAAK,EAAE,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;wBACjC,IAAI,EAAE,CAAC,CAAC,OAAO;qBACf,CAAC,CAAC;iBACH;gBACF,CAAC,CAAC,SAAS,CAAA;YAEb,oDAAoD;YACpD,MAAM,QAAQ,GAAG,oBAAoB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;gBACjD,IAAI,EAAE,CAAC,CAAC,IAAI,KAAK,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI;gBAC/C,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC;aAC5B,CAAC,CAAC,CAAA;YAEH,MAAM,IAAI,GAA4B;gBACrC,QAAQ;gBACR,gBAAgB,EAAE;oBACjB,WAAW,EAAE,CAAC;iBACd;aACD,CAAA;YAED,IAAI,iBAAiB,EAAE,CAAC;gBACvB,IAAI,CAAC,iBAAiB,GAAG,iBAAiB,CAAA;YAC3C,CAAC;YAED,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,QAAQ,EAAE;gBACtC,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE;oBACR,cAAc,EAAE,kBAAkB;iBAClC;gBACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;aAC1B,CAAC,CAAA;YAEF,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;gBAClB,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAA;gBACtC,MAAM,IAAI,KAAK,CACd,iBAAiB,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,QAAQ,EAAE,CACvD,CAAA;YACF,CAAC;YAED,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAIlC,CAAA;YAED,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,IAAI,CAAA;YAC3D,IAAI,CAAC,OAAO,EAAE,CAAC;gBACd,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAA;YAC/C,CAAC;YAED,OAAO,OAAO,CAAA;QACf,CAAC;KACD,CAAA;AACF,CAAC"}
|