@hasna/testers 0.0.4 → 0.0.6
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/cli/index.js +490 -9
- package/dist/db/database.d.ts.map +1 -1
- package/dist/db/flows.d.ts +12 -0
- package/dist/db/flows.d.ts.map +1 -0
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +295 -8
- package/dist/lib/ai-client.d.ts +9 -0
- package/dist/lib/ai-client.d.ts.map +1 -1
- package/dist/lib/runner.d.ts +6 -1
- package/dist/lib/runner.d.ts.map +1 -1
- package/dist/mcp/index.js +955 -669
- package/dist/server/index.js +380 -85
- package/dist/types/index.d.ts +31 -0
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -124,7 +124,18 @@ function scheduleFromRow(row) {
|
|
|
124
124
|
updatedAt: row.updated_at
|
|
125
125
|
};
|
|
126
126
|
}
|
|
127
|
-
|
|
127
|
+
function flowFromRow(row) {
|
|
128
|
+
return {
|
|
129
|
+
id: row.id,
|
|
130
|
+
projectId: row.project_id,
|
|
131
|
+
name: row.name,
|
|
132
|
+
description: row.description,
|
|
133
|
+
scenarioIds: JSON.parse(row.scenario_ids),
|
|
134
|
+
createdAt: row.created_at,
|
|
135
|
+
updatedAt: row.updated_at
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
var MODEL_MAP, ScenarioNotFoundError, RunNotFoundError, ResultNotFoundError, VersionConflictError, BrowserError, AIClientError, TodosConnectionError, ProjectNotFoundError, AgentNotFoundError, ScheduleNotFoundError, FlowNotFoundError, DependencyCycleError;
|
|
128
139
|
var init_types = __esm(() => {
|
|
129
140
|
MODEL_MAP = {
|
|
130
141
|
quick: "claude-haiku-4-5-20251001",
|
|
@@ -191,6 +202,18 @@ var init_types = __esm(() => {
|
|
|
191
202
|
this.name = "ScheduleNotFoundError";
|
|
192
203
|
}
|
|
193
204
|
};
|
|
205
|
+
FlowNotFoundError = class FlowNotFoundError extends Error {
|
|
206
|
+
constructor(id) {
|
|
207
|
+
super(`Flow not found: ${id}`);
|
|
208
|
+
this.name = "FlowNotFoundError";
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
DependencyCycleError = class DependencyCycleError extends Error {
|
|
212
|
+
constructor(scenarioId, dependsOn) {
|
|
213
|
+
super(`Adding dependency ${dependsOn} to ${scenarioId} would create a cycle`);
|
|
214
|
+
this.name = "DependencyCycleError";
|
|
215
|
+
}
|
|
216
|
+
};
|
|
194
217
|
});
|
|
195
218
|
|
|
196
219
|
// src/db/database.ts
|
|
@@ -260,6 +283,8 @@ function resetDatabase() {
|
|
|
260
283
|
const database = getDatabase();
|
|
261
284
|
database.exec("DELETE FROM screenshots");
|
|
262
285
|
database.exec("DELETE FROM results");
|
|
286
|
+
database.exec("DELETE FROM scenario_dependencies");
|
|
287
|
+
database.exec("DELETE FROM flows");
|
|
263
288
|
database.exec("DELETE FROM webhooks");
|
|
264
289
|
database.exec("DELETE FROM auth_presets");
|
|
265
290
|
database.exec("DELETE FROM schedules");
|
|
@@ -433,6 +458,28 @@ var init_database = __esm(() => {
|
|
|
433
458
|
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
434
459
|
);
|
|
435
460
|
CREATE INDEX IF NOT EXISTS idx_webhooks_active ON webhooks(active);
|
|
461
|
+
`,
|
|
462
|
+
`
|
|
463
|
+
CREATE TABLE IF NOT EXISTS scenario_dependencies (
|
|
464
|
+
scenario_id TEXT NOT NULL REFERENCES scenarios(id) ON DELETE CASCADE,
|
|
465
|
+
depends_on TEXT NOT NULL REFERENCES scenarios(id) ON DELETE CASCADE,
|
|
466
|
+
PRIMARY KEY (scenario_id, depends_on),
|
|
467
|
+
CHECK (scenario_id != depends_on)
|
|
468
|
+
);
|
|
469
|
+
|
|
470
|
+
CREATE TABLE IF NOT EXISTS flows (
|
|
471
|
+
id TEXT PRIMARY KEY,
|
|
472
|
+
project_id TEXT REFERENCES projects(id) ON DELETE CASCADE,
|
|
473
|
+
name TEXT NOT NULL,
|
|
474
|
+
description TEXT,
|
|
475
|
+
scenario_ids TEXT NOT NULL DEFAULT '[]',
|
|
476
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
477
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
478
|
+
);
|
|
479
|
+
|
|
480
|
+
CREATE INDEX IF NOT EXISTS idx_deps_scenario ON scenario_dependencies(scenario_id);
|
|
481
|
+
CREATE INDEX IF NOT EXISTS idx_deps_depends ON scenario_dependencies(depends_on);
|
|
482
|
+
CREATE INDEX IF NOT EXISTS idx_flows_project ON flows(project_id);
|
|
436
483
|
`
|
|
437
484
|
];
|
|
438
485
|
});
|
|
@@ -569,6 +616,157 @@ var init_runs = __esm(() => {
|
|
|
569
616
|
init_database();
|
|
570
617
|
});
|
|
571
618
|
|
|
619
|
+
// src/db/flows.ts
|
|
620
|
+
var exports_flows = {};
|
|
621
|
+
__export(exports_flows, {
|
|
622
|
+
topologicalSort: () => topologicalSort,
|
|
623
|
+
removeDependency: () => removeDependency,
|
|
624
|
+
listFlows: () => listFlows,
|
|
625
|
+
getTransitiveDependencies: () => getTransitiveDependencies,
|
|
626
|
+
getFlow: () => getFlow,
|
|
627
|
+
getDependents: () => getDependents,
|
|
628
|
+
getDependencies: () => getDependencies,
|
|
629
|
+
deleteFlow: () => deleteFlow,
|
|
630
|
+
createFlow: () => createFlow,
|
|
631
|
+
addDependency: () => addDependency
|
|
632
|
+
});
|
|
633
|
+
function addDependency(scenarioId, dependsOn) {
|
|
634
|
+
const db2 = getDatabase();
|
|
635
|
+
const visited = new Set;
|
|
636
|
+
const queue = [dependsOn];
|
|
637
|
+
while (queue.length > 0) {
|
|
638
|
+
const current = queue.shift();
|
|
639
|
+
if (current === scenarioId) {
|
|
640
|
+
throw new DependencyCycleError(scenarioId, dependsOn);
|
|
641
|
+
}
|
|
642
|
+
if (visited.has(current))
|
|
643
|
+
continue;
|
|
644
|
+
visited.add(current);
|
|
645
|
+
const deps = db2.query("SELECT depends_on FROM scenario_dependencies WHERE scenario_id = ?").all(current);
|
|
646
|
+
for (const dep of deps) {
|
|
647
|
+
if (!visited.has(dep.depends_on)) {
|
|
648
|
+
queue.push(dep.depends_on);
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
db2.query("INSERT OR IGNORE INTO scenario_dependencies (scenario_id, depends_on) VALUES (?, ?)").run(scenarioId, dependsOn);
|
|
653
|
+
}
|
|
654
|
+
function removeDependency(scenarioId, dependsOn) {
|
|
655
|
+
const db2 = getDatabase();
|
|
656
|
+
const result = db2.query("DELETE FROM scenario_dependencies WHERE scenario_id = ? AND depends_on = ?").run(scenarioId, dependsOn);
|
|
657
|
+
return result.changes > 0;
|
|
658
|
+
}
|
|
659
|
+
function getDependencies(scenarioId) {
|
|
660
|
+
const db2 = getDatabase();
|
|
661
|
+
const rows = db2.query("SELECT depends_on FROM scenario_dependencies WHERE scenario_id = ?").all(scenarioId);
|
|
662
|
+
return rows.map((r) => r.depends_on);
|
|
663
|
+
}
|
|
664
|
+
function getDependents(scenarioId) {
|
|
665
|
+
const db2 = getDatabase();
|
|
666
|
+
const rows = db2.query("SELECT scenario_id FROM scenario_dependencies WHERE depends_on = ?").all(scenarioId);
|
|
667
|
+
return rows.map((r) => r.scenario_id);
|
|
668
|
+
}
|
|
669
|
+
function getTransitiveDependencies(scenarioId) {
|
|
670
|
+
const db2 = getDatabase();
|
|
671
|
+
const visited = new Set;
|
|
672
|
+
const queue = [scenarioId];
|
|
673
|
+
while (queue.length > 0) {
|
|
674
|
+
const current = queue.shift();
|
|
675
|
+
const deps = db2.query("SELECT depends_on FROM scenario_dependencies WHERE scenario_id = ?").all(current);
|
|
676
|
+
for (const dep of deps) {
|
|
677
|
+
if (!visited.has(dep.depends_on)) {
|
|
678
|
+
visited.add(dep.depends_on);
|
|
679
|
+
queue.push(dep.depends_on);
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
return Array.from(visited);
|
|
684
|
+
}
|
|
685
|
+
function topologicalSort(scenarioIds) {
|
|
686
|
+
const db2 = getDatabase();
|
|
687
|
+
const idSet = new Set(scenarioIds);
|
|
688
|
+
const inDegree = new Map;
|
|
689
|
+
const dependents = new Map;
|
|
690
|
+
for (const id of scenarioIds) {
|
|
691
|
+
inDegree.set(id, 0);
|
|
692
|
+
dependents.set(id, []);
|
|
693
|
+
}
|
|
694
|
+
for (const id of scenarioIds) {
|
|
695
|
+
const deps = db2.query("SELECT depends_on FROM scenario_dependencies WHERE scenario_id = ?").all(id);
|
|
696
|
+
for (const dep of deps) {
|
|
697
|
+
if (idSet.has(dep.depends_on)) {
|
|
698
|
+
inDegree.set(id, (inDegree.get(id) ?? 0) + 1);
|
|
699
|
+
dependents.get(dep.depends_on).push(id);
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
const queue = [];
|
|
704
|
+
for (const [id, deg] of inDegree) {
|
|
705
|
+
if (deg === 0)
|
|
706
|
+
queue.push(id);
|
|
707
|
+
}
|
|
708
|
+
const sorted = [];
|
|
709
|
+
while (queue.length > 0) {
|
|
710
|
+
const current = queue.shift();
|
|
711
|
+
sorted.push(current);
|
|
712
|
+
for (const dep of dependents.get(current) ?? []) {
|
|
713
|
+
const newDeg = (inDegree.get(dep) ?? 1) - 1;
|
|
714
|
+
inDegree.set(dep, newDeg);
|
|
715
|
+
if (newDeg === 0)
|
|
716
|
+
queue.push(dep);
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
if (sorted.length !== scenarioIds.length) {
|
|
720
|
+
throw new DependencyCycleError("multiple", "multiple");
|
|
721
|
+
}
|
|
722
|
+
return sorted;
|
|
723
|
+
}
|
|
724
|
+
function createFlow(input) {
|
|
725
|
+
const db2 = getDatabase();
|
|
726
|
+
const id = uuid();
|
|
727
|
+
const timestamp = now();
|
|
728
|
+
db2.query(`
|
|
729
|
+
INSERT INTO flows (id, project_id, name, description, scenario_ids, created_at, updated_at)
|
|
730
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
731
|
+
`).run(id, input.projectId ?? null, input.name, input.description ?? null, JSON.stringify(input.scenarioIds), timestamp, timestamp);
|
|
732
|
+
return getFlow(id);
|
|
733
|
+
}
|
|
734
|
+
function getFlow(id) {
|
|
735
|
+
const db2 = getDatabase();
|
|
736
|
+
let row = db2.query("SELECT * FROM flows WHERE id = ?").get(id);
|
|
737
|
+
if (row)
|
|
738
|
+
return flowFromRow(row);
|
|
739
|
+
const fullId = resolvePartialId("flows", id);
|
|
740
|
+
if (fullId) {
|
|
741
|
+
row = db2.query("SELECT * FROM flows WHERE id = ?").get(fullId);
|
|
742
|
+
if (row)
|
|
743
|
+
return flowFromRow(row);
|
|
744
|
+
}
|
|
745
|
+
return null;
|
|
746
|
+
}
|
|
747
|
+
function listFlows(projectId) {
|
|
748
|
+
const db2 = getDatabase();
|
|
749
|
+
if (projectId) {
|
|
750
|
+
const rows2 = db2.query("SELECT * FROM flows WHERE project_id = ? ORDER BY created_at DESC").all(projectId);
|
|
751
|
+
return rows2.map(flowFromRow);
|
|
752
|
+
}
|
|
753
|
+
const rows = db2.query("SELECT * FROM flows ORDER BY created_at DESC").all();
|
|
754
|
+
return rows.map(flowFromRow);
|
|
755
|
+
}
|
|
756
|
+
function deleteFlow(id) {
|
|
757
|
+
const db2 = getDatabase();
|
|
758
|
+
const flow = getFlow(id);
|
|
759
|
+
if (!flow)
|
|
760
|
+
return false;
|
|
761
|
+
const result = db2.query("DELETE FROM flows WHERE id = ?").run(flow.id);
|
|
762
|
+
return result.changes > 0;
|
|
763
|
+
}
|
|
764
|
+
var init_flows = __esm(() => {
|
|
765
|
+
init_database();
|
|
766
|
+
init_database();
|
|
767
|
+
init_types();
|
|
768
|
+
});
|
|
769
|
+
|
|
572
770
|
// src/index.ts
|
|
573
771
|
init_types();
|
|
574
772
|
init_database();
|
|
@@ -1043,6 +1241,10 @@ function updateLastRun(id, runId, nextRunAt) {
|
|
|
1043
1241
|
UPDATE schedules SET last_run_id = ?, last_run_at = ?, next_run_at = ?, updated_at = ? WHERE id = ?
|
|
1044
1242
|
`).run(runId, timestamp, nextRunAt, timestamp, id);
|
|
1045
1243
|
}
|
|
1244
|
+
|
|
1245
|
+
// src/index.ts
|
|
1246
|
+
init_flows();
|
|
1247
|
+
|
|
1046
1248
|
// src/lib/config.ts
|
|
1047
1249
|
init_types();
|
|
1048
1250
|
import { homedir as homedir2 } from "os";
|
|
@@ -1951,7 +2153,8 @@ async function runAgentLoop(options) {
|
|
|
1951
2153
|
screenshotter,
|
|
1952
2154
|
model,
|
|
1953
2155
|
runId,
|
|
1954
|
-
maxTurns = 30
|
|
2156
|
+
maxTurns = 30,
|
|
2157
|
+
onStep
|
|
1955
2158
|
} = options;
|
|
1956
2159
|
const systemPrompt = [
|
|
1957
2160
|
"You are an expert QA testing agent. Your job is to thoroughly test web application scenarios.",
|
|
@@ -2010,8 +2213,8 @@ async function runAgentLoop(options) {
|
|
|
2010
2213
|
}
|
|
2011
2214
|
const toolUseBlocks = response.content.filter((block) => block.type === "tool_use");
|
|
2012
2215
|
if (toolUseBlocks.length === 0 && response.stop_reason === "end_turn") {
|
|
2013
|
-
const
|
|
2014
|
-
const textReasoning =
|
|
2216
|
+
const textBlocks2 = response.content.filter((block) => block.type === "text");
|
|
2217
|
+
const textReasoning = textBlocks2.map((b) => b.text).join(`
|
|
2015
2218
|
`);
|
|
2016
2219
|
return {
|
|
2017
2220
|
status: "error",
|
|
@@ -2022,10 +2225,22 @@ async function runAgentLoop(options) {
|
|
|
2022
2225
|
};
|
|
2023
2226
|
}
|
|
2024
2227
|
const toolResults = [];
|
|
2228
|
+
const textBlocks = response.content.filter((block) => block.type === "text");
|
|
2229
|
+
if (textBlocks.length > 0 && onStep) {
|
|
2230
|
+
const thinking = textBlocks.map((b) => b.text).join(`
|
|
2231
|
+
`);
|
|
2232
|
+
onStep({ type: "thinking", thinking, stepNumber });
|
|
2233
|
+
}
|
|
2025
2234
|
for (const toolBlock of toolUseBlocks) {
|
|
2026
2235
|
stepNumber++;
|
|
2027
2236
|
const toolInput = toolBlock.input;
|
|
2237
|
+
if (onStep) {
|
|
2238
|
+
onStep({ type: "tool_call", toolName: toolBlock.name, toolInput, stepNumber });
|
|
2239
|
+
}
|
|
2028
2240
|
const execResult = await executeTool(page, screenshotter, toolBlock.name, toolInput, { runId, scenarioSlug, stepNumber });
|
|
2241
|
+
if (onStep) {
|
|
2242
|
+
onStep({ type: "tool_result", toolName: toolBlock.name, toolResult: execResult.result, stepNumber });
|
|
2243
|
+
}
|
|
2029
2244
|
if (execResult.screenshot) {
|
|
2030
2245
|
screenshots.push({
|
|
2031
2246
|
...execResult.screenshot,
|
|
@@ -2115,7 +2330,20 @@ async function runSingleScenario(scenario, runId, options) {
|
|
|
2115
2330
|
screenshotter,
|
|
2116
2331
|
model,
|
|
2117
2332
|
runId,
|
|
2118
|
-
maxTurns: 30
|
|
2333
|
+
maxTurns: 30,
|
|
2334
|
+
onStep: (stepEvent) => {
|
|
2335
|
+
emit({
|
|
2336
|
+
type: `step:${stepEvent.type}`,
|
|
2337
|
+
scenarioId: scenario.id,
|
|
2338
|
+
scenarioName: scenario.name,
|
|
2339
|
+
runId,
|
|
2340
|
+
toolName: stepEvent.toolName,
|
|
2341
|
+
toolInput: stepEvent.toolInput,
|
|
2342
|
+
toolResult: stepEvent.toolResult,
|
|
2343
|
+
thinking: stepEvent.thinking,
|
|
2344
|
+
stepNumber: stepEvent.stepNumber
|
|
2345
|
+
});
|
|
2346
|
+
}
|
|
2119
2347
|
});
|
|
2120
2348
|
for (const ss of agentResult.screenshots) {
|
|
2121
2349
|
createScreenshot({
|
|
@@ -2168,24 +2396,70 @@ async function runBatch(scenarios, options) {
|
|
|
2168
2396
|
projectId: options.projectId
|
|
2169
2397
|
});
|
|
2170
2398
|
updateRun(run.id, { status: "running", total: scenarios.length });
|
|
2399
|
+
let sortedScenarios = scenarios;
|
|
2400
|
+
try {
|
|
2401
|
+
const { topologicalSort: topologicalSort2 } = await Promise.resolve().then(() => (init_flows(), exports_flows));
|
|
2402
|
+
const scenarioIds = scenarios.map((s) => s.id);
|
|
2403
|
+
const sortedIds = topologicalSort2(scenarioIds);
|
|
2404
|
+
const scenarioMap = new Map(scenarios.map((s) => [s.id, s]));
|
|
2405
|
+
sortedScenarios = sortedIds.map((id) => scenarioMap.get(id)).filter((s) => s !== undefined);
|
|
2406
|
+
for (const s of scenarios) {
|
|
2407
|
+
if (!sortedIds.includes(s.id))
|
|
2408
|
+
sortedScenarios.push(s);
|
|
2409
|
+
}
|
|
2410
|
+
} catch {}
|
|
2171
2411
|
const results = [];
|
|
2412
|
+
const failedScenarioIds = new Set;
|
|
2413
|
+
const canRun = async (scenario) => {
|
|
2414
|
+
try {
|
|
2415
|
+
const { getDependencies: getDependencies2 } = await Promise.resolve().then(() => (init_flows(), exports_flows));
|
|
2416
|
+
const deps = getDependencies2(scenario.id);
|
|
2417
|
+
for (const depId of deps) {
|
|
2418
|
+
if (failedScenarioIds.has(depId))
|
|
2419
|
+
return false;
|
|
2420
|
+
}
|
|
2421
|
+
} catch {}
|
|
2422
|
+
return true;
|
|
2423
|
+
};
|
|
2172
2424
|
if (parallel <= 1) {
|
|
2173
|
-
for (const scenario of
|
|
2425
|
+
for (const scenario of sortedScenarios) {
|
|
2426
|
+
if (!await canRun(scenario)) {
|
|
2427
|
+
const result2 = createResult({ runId: run.id, scenarioId: scenario.id, model, stepsTotal: 0 });
|
|
2428
|
+
const skipped = updateResult(result2.id, { status: "skipped", error: "Skipped: dependency failed" });
|
|
2429
|
+
results.push(skipped);
|
|
2430
|
+
failedScenarioIds.add(scenario.id);
|
|
2431
|
+
emit({ type: "scenario:error", scenarioId: scenario.id, scenarioName: scenario.name, error: "Dependency failed \u2014 skipped", runId: run.id });
|
|
2432
|
+
continue;
|
|
2433
|
+
}
|
|
2174
2434
|
const result = await runSingleScenario(scenario, run.id, options);
|
|
2175
2435
|
results.push(result);
|
|
2436
|
+
if (result.status === "failed" || result.status === "error") {
|
|
2437
|
+
failedScenarioIds.add(scenario.id);
|
|
2438
|
+
}
|
|
2176
2439
|
}
|
|
2177
2440
|
} else {
|
|
2178
|
-
const queue = [...
|
|
2441
|
+
const queue = [...sortedScenarios];
|
|
2179
2442
|
const running = [];
|
|
2180
2443
|
const processNext = async () => {
|
|
2181
2444
|
const scenario = queue.shift();
|
|
2182
2445
|
if (!scenario)
|
|
2183
2446
|
return;
|
|
2447
|
+
if (!await canRun(scenario)) {
|
|
2448
|
+
const result2 = createResult({ runId: run.id, scenarioId: scenario.id, model, stepsTotal: 0 });
|
|
2449
|
+
const skipped = updateResult(result2.id, { status: "skipped", error: "Skipped: dependency failed" });
|
|
2450
|
+
results.push(skipped);
|
|
2451
|
+
failedScenarioIds.add(scenario.id);
|
|
2452
|
+
await processNext();
|
|
2453
|
+
return;
|
|
2454
|
+
}
|
|
2184
2455
|
const result = await runSingleScenario(scenario, run.id, options);
|
|
2185
2456
|
results.push(result);
|
|
2457
|
+
if (result.status === "failed" || result.status === "error") {
|
|
2458
|
+
failedScenarioIds.add(scenario.id);
|
|
2459
|
+
}
|
|
2186
2460
|
await processNext();
|
|
2187
2461
|
};
|
|
2188
|
-
const workers = Math.min(parallel,
|
|
2462
|
+
const workers = Math.min(parallel, sortedScenarios.length);
|
|
2189
2463
|
for (let i = 0;i < workers; i++) {
|
|
2190
2464
|
running.push(processNext());
|
|
2191
2465
|
}
|
|
@@ -4488,6 +4762,7 @@ export {
|
|
|
4488
4762
|
updateRun,
|
|
4489
4763
|
updateResult,
|
|
4490
4764
|
updateLastRun,
|
|
4765
|
+
topologicalSort,
|
|
4491
4766
|
testWebhook,
|
|
4492
4767
|
taskToScenarioInput,
|
|
4493
4768
|
startWatcher,
|
|
@@ -4509,6 +4784,7 @@ export {
|
|
|
4509
4784
|
resolveModel as resolveModelConfig,
|
|
4510
4785
|
resolveModel2 as resolveModel,
|
|
4511
4786
|
resetDatabase,
|
|
4787
|
+
removeDependency,
|
|
4512
4788
|
registerAgent,
|
|
4513
4789
|
pullTasks,
|
|
4514
4790
|
projectFromRow,
|
|
@@ -4527,6 +4803,7 @@ export {
|
|
|
4527
4803
|
listRuns,
|
|
4528
4804
|
listResults,
|
|
4529
4805
|
listProjects,
|
|
4806
|
+
listFlows,
|
|
4530
4807
|
listAuthPresets,
|
|
4531
4808
|
listAgents,
|
|
4532
4809
|
launchBrowser,
|
|
@@ -4535,6 +4812,7 @@ export {
|
|
|
4535
4812
|
importFromTodos,
|
|
4536
4813
|
imageToBase64,
|
|
4537
4814
|
getWebhook,
|
|
4815
|
+
getTransitiveDependencies,
|
|
4538
4816
|
getTemplate,
|
|
4539
4817
|
getStarterScenarios,
|
|
4540
4818
|
getScreenshotsByResult,
|
|
@@ -4550,8 +4828,11 @@ export {
|
|
|
4550
4828
|
getProject,
|
|
4551
4829
|
getPage,
|
|
4552
4830
|
getNextRunTime,
|
|
4831
|
+
getFlow,
|
|
4553
4832
|
getExitCode,
|
|
4554
4833
|
getEnabledSchedules,
|
|
4834
|
+
getDependents,
|
|
4835
|
+
getDependencies,
|
|
4555
4836
|
getDefaultConfig,
|
|
4556
4837
|
getDatabase,
|
|
4557
4838
|
getCostSummary,
|
|
@@ -4572,6 +4853,7 @@ export {
|
|
|
4572
4853
|
formatDiffJSON,
|
|
4573
4854
|
formatCostsTerminal,
|
|
4574
4855
|
formatCostsJSON,
|
|
4856
|
+
flowFromRow,
|
|
4575
4857
|
executeTool,
|
|
4576
4858
|
ensureProject,
|
|
4577
4859
|
ensureDir,
|
|
@@ -4582,6 +4864,7 @@ export {
|
|
|
4582
4864
|
deleteSchedule,
|
|
4583
4865
|
deleteScenario,
|
|
4584
4866
|
deleteRun,
|
|
4867
|
+
deleteFlow,
|
|
4585
4868
|
deleteAuthPreset,
|
|
4586
4869
|
createWebhook,
|
|
4587
4870
|
createScreenshot,
|
|
@@ -4590,6 +4873,7 @@ export {
|
|
|
4590
4873
|
createRun,
|
|
4591
4874
|
createResult,
|
|
4592
4875
|
createProject,
|
|
4876
|
+
createFlow,
|
|
4593
4877
|
createClient,
|
|
4594
4878
|
createAuthPreset,
|
|
4595
4879
|
connectToTodos,
|
|
@@ -4597,6 +4881,7 @@ export {
|
|
|
4597
4881
|
closeBrowser,
|
|
4598
4882
|
checkBudget,
|
|
4599
4883
|
agentFromRow,
|
|
4884
|
+
addDependency,
|
|
4600
4885
|
VersionConflictError,
|
|
4601
4886
|
TodosConnectionError,
|
|
4602
4887
|
Screenshotter,
|
|
@@ -4608,6 +4893,8 @@ export {
|
|
|
4608
4893
|
ResultNotFoundError,
|
|
4609
4894
|
ProjectNotFoundError,
|
|
4610
4895
|
MODEL_MAP,
|
|
4896
|
+
FlowNotFoundError,
|
|
4897
|
+
DependencyCycleError,
|
|
4611
4898
|
BrowserPool,
|
|
4612
4899
|
BrowserError,
|
|
4613
4900
|
BROWSER_TOOLS,
|
package/dist/lib/ai-client.d.ts
CHANGED
|
@@ -31,6 +31,14 @@ interface ToolExecutionResult {
|
|
|
31
31
|
* Returns the result string and an optional screenshot capture.
|
|
32
32
|
*/
|
|
33
33
|
export declare function executeTool(page: Page, screenshotter: Screenshotter, toolName: string, toolInput: Record<string, unknown>, context: ToolContext): Promise<ToolExecutionResult>;
|
|
34
|
+
export type StepEventHandler = (event: {
|
|
35
|
+
type: "tool_call" | "tool_result" | "thinking";
|
|
36
|
+
toolName?: string;
|
|
37
|
+
toolInput?: Record<string, unknown>;
|
|
38
|
+
toolResult?: string;
|
|
39
|
+
thinking?: string;
|
|
40
|
+
stepNumber: number;
|
|
41
|
+
}) => void;
|
|
34
42
|
interface AgentLoopOptions {
|
|
35
43
|
client: Anthropic;
|
|
36
44
|
page: Page;
|
|
@@ -39,6 +47,7 @@ interface AgentLoopOptions {
|
|
|
39
47
|
model: string;
|
|
40
48
|
runId: string;
|
|
41
49
|
maxTurns?: number;
|
|
50
|
+
onStep?: StepEventHandler;
|
|
42
51
|
}
|
|
43
52
|
interface AgentLoopResult {
|
|
44
53
|
status: "passed" | "failed" | "error";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ai-client.d.ts","sourceRoot":"","sources":["../../src/lib/ai-client.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,mBAAmB,CAAC;AAC1C,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAExD,OAAO,KAAK,EAAe,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAI/D;;;GAGG;AACH,wBAAgB,YAAY,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAKzD;AAID,eAAO,MAAM,aAAa,EAAE,SAAS,CAAC,IAAI,EAyTzC,CAAC;AAIF,UAAU,WAAW;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,UAAU,gBAAgB;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAED,UAAU,mBAAmB;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,gBAAgB,CAAC;CAC/B;AAED;;;GAGG;AACH,wBAAsB,WAAW,CAC/B,IAAI,EAAE,IAAI,EACV,aAAa,EAAE,aAAa,EAC5B,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAClC,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC,mBAAmB,CAAC,CA8P9B;AAID,UAAU,gBAAgB;IACxB,MAAM,EAAE,SAAS,CAAC;IAClB,IAAI,EAAE,IAAI,CAAC;IACX,QAAQ,EAAE,QAAQ,CAAC;IACnB,aAAa,EAAE,aAAa,CAAC;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"ai-client.d.ts","sourceRoot":"","sources":["../../src/lib/ai-client.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/runner.d.ts
CHANGED
|
@@ -10,13 +10,18 @@ export interface RunOptions {
|
|
|
10
10
|
screenshotDir?: string;
|
|
11
11
|
}
|
|
12
12
|
export interface RunEvent {
|
|
13
|
-
type: "scenario:start" | "scenario:pass" | "scenario:fail" | "scenario:error" | "screenshot:captured" | "run:complete";
|
|
13
|
+
type: "scenario:start" | "scenario:pass" | "scenario:fail" | "scenario:error" | "screenshot:captured" | "run:complete" | "step:tool_call" | "step:tool_result" | "step:thinking";
|
|
14
14
|
scenarioId?: string;
|
|
15
15
|
scenarioName?: string;
|
|
16
16
|
resultId?: string;
|
|
17
17
|
runId?: string;
|
|
18
18
|
error?: string;
|
|
19
19
|
screenshotPath?: string;
|
|
20
|
+
toolName?: string;
|
|
21
|
+
toolInput?: Record<string, unknown>;
|
|
22
|
+
toolResult?: string;
|
|
23
|
+
thinking?: string;
|
|
24
|
+
stepNumber?: number;
|
|
20
25
|
}
|
|
21
26
|
export type RunEventHandler = (event: RunEvent) => void;
|
|
22
27
|
export declare function onRunEvent(handler: RunEventHandler): void;
|
package/dist/lib/runner.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../src/lib/runner.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAW/D,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,
|
|
1
|
+
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../src/lib/runner.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAW/D,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,EACA,gBAAgB,GAChB,eAAe,GACf,eAAe,GACf,gBAAgB,GAChB,qBAAqB,GACrB,cAAc,GACd,gBAAgB,GAChB,kBAAkB,GAClB,eAAe,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACpC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,MAAM,eAAe,GAAG,CAAC,KAAK,EAAE,QAAQ,KAAK,IAAI,CAAC;AAIxD,wBAAgB,UAAU,CAAC,OAAO,EAAE,eAAe,GAAG,IAAI,CAEzD;AAMD,wBAAsB,iBAAiB,CACrC,QAAQ,EAAE,QAAQ,EAClB,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,UAAU,GAClB,OAAO,CAAC,MAAM,CAAC,CAiGjB;AAED,wBAAsB,QAAQ,CAC5B,SAAS,EAAE,QAAQ,EAAE,EACrB,OAAO,EAAE,UAAU,GAClB,OAAO,CAAC;IAAE,GAAG,EAAE,GAAG,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,CAoH1C;AAED,wBAAsB,WAAW,CAC/B,OAAO,EAAE,UAAU,GAAG;IAAE,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,GACnF,OAAO,CAAC;IAAE,GAAG,EAAE,GAAG,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,CAuB1C;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,UAAU,GAAG;IAAE,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,GACnF;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAE,CA+E1C"}
|