@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/index.js CHANGED
@@ -124,7 +124,18 @@ function scheduleFromRow(row) {
124
124
  updatedAt: row.updated_at
125
125
  };
126
126
  }
127
- var MODEL_MAP, ScenarioNotFoundError, RunNotFoundError, ResultNotFoundError, VersionConflictError, BrowserError, AIClientError, TodosConnectionError, ProjectNotFoundError, AgentNotFoundError, ScheduleNotFoundError;
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 textBlocks = response.content.filter((block) => block.type === "text");
2014
- const textReasoning = textBlocks.map((b) => b.text).join(`
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 scenarios) {
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 = [...scenarios];
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, scenarios.length);
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,
@@ -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;CACnB;AAED,UAAU,eAAe;IACvB,MAAM,EAAE,QAAQ,GAAG,QAAQ,GAAG,OAAO,CAAC;IACtC,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,KAAK,CAAC;QACjB,QAAQ,EAAE,MAAM,CAAC;QACjB,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;QACf,SAAS,EAAE,MAAM,CAAC;QAClB,MAAM,EAAE,MAAM,CAAC;QACf,UAAU,EAAE,MAAM,CAAC;QACnB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;QAC3B,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;QACvB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;KAC9B,CAAC,CAAC;CACJ;AAED;;;;GAIG;AACH,wBAAsB,YAAY,CAChC,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC,eAAe,CAAC,CAyK1B;AAID;;;GAGG;AACH,wBAAgB,YAAY,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAQvD"}
1
+ {"version":3,"file":"ai-client.d.ts","sourceRoot":"","sources":["../../src/lib/ai-client.ts"],"names":[],"mappings":"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"}
@@ -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;
@@ -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,EAAE,gBAAgB,GAAG,eAAe,GAAG,eAAe,GAAG,gBAAgB,GAAG,qBAAqB,GAAG,cAAc,CAAC;IACvH,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;CACzB;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,CAoFjB;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,CA4D1C;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"}
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"}