@hasna/testers 0.0.4 → 0.0.5
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 +84 -5
- package/dist/index.js +30 -4
- 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 +30 -4
- package/dist/server/index.js +30 -4
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -3641,7 +3641,8 @@ async function runAgentLoop(options) {
|
|
|
3641
3641
|
screenshotter,
|
|
3642
3642
|
model,
|
|
3643
3643
|
runId,
|
|
3644
|
-
maxTurns = 30
|
|
3644
|
+
maxTurns = 30,
|
|
3645
|
+
onStep
|
|
3645
3646
|
} = options;
|
|
3646
3647
|
const systemPrompt = [
|
|
3647
3648
|
"You are an expert QA testing agent. Your job is to thoroughly test web application scenarios.",
|
|
@@ -3700,8 +3701,8 @@ async function runAgentLoop(options) {
|
|
|
3700
3701
|
}
|
|
3701
3702
|
const toolUseBlocks = response.content.filter((block) => block.type === "tool_use");
|
|
3702
3703
|
if (toolUseBlocks.length === 0 && response.stop_reason === "end_turn") {
|
|
3703
|
-
const
|
|
3704
|
-
const textReasoning =
|
|
3704
|
+
const textBlocks2 = response.content.filter((block) => block.type === "text");
|
|
3705
|
+
const textReasoning = textBlocks2.map((b) => b.text).join(`
|
|
3705
3706
|
`);
|
|
3706
3707
|
return {
|
|
3707
3708
|
status: "error",
|
|
@@ -3712,10 +3713,22 @@ async function runAgentLoop(options) {
|
|
|
3712
3713
|
};
|
|
3713
3714
|
}
|
|
3714
3715
|
const toolResults = [];
|
|
3716
|
+
const textBlocks = response.content.filter((block) => block.type === "text");
|
|
3717
|
+
if (textBlocks.length > 0 && onStep) {
|
|
3718
|
+
const thinking = textBlocks.map((b) => b.text).join(`
|
|
3719
|
+
`);
|
|
3720
|
+
onStep({ type: "thinking", thinking, stepNumber });
|
|
3721
|
+
}
|
|
3715
3722
|
for (const toolBlock of toolUseBlocks) {
|
|
3716
3723
|
stepNumber++;
|
|
3717
3724
|
const toolInput = toolBlock.input;
|
|
3725
|
+
if (onStep) {
|
|
3726
|
+
onStep({ type: "tool_call", toolName: toolBlock.name, toolInput, stepNumber });
|
|
3727
|
+
}
|
|
3718
3728
|
const execResult = await executeTool(page, screenshotter, toolBlock.name, toolInput, { runId, scenarioSlug, stepNumber });
|
|
3729
|
+
if (onStep) {
|
|
3730
|
+
onStep({ type: "tool_result", toolName: toolBlock.name, toolResult: execResult.result, stepNumber });
|
|
3731
|
+
}
|
|
3719
3732
|
if (execResult.screenshot) {
|
|
3720
3733
|
screenshots.push({
|
|
3721
3734
|
...execResult.screenshot,
|
|
@@ -3824,6 +3837,9 @@ function loadConfig() {
|
|
|
3824
3837
|
|
|
3825
3838
|
// src/lib/runner.ts
|
|
3826
3839
|
var eventHandler = null;
|
|
3840
|
+
function onRunEvent(handler) {
|
|
3841
|
+
eventHandler = handler;
|
|
3842
|
+
}
|
|
3827
3843
|
function emit(event) {
|
|
3828
3844
|
if (eventHandler)
|
|
3829
3845
|
eventHandler(event);
|
|
@@ -3858,7 +3874,20 @@ async function runSingleScenario(scenario, runId, options) {
|
|
|
3858
3874
|
screenshotter,
|
|
3859
3875
|
model,
|
|
3860
3876
|
runId,
|
|
3861
|
-
maxTurns: 30
|
|
3877
|
+
maxTurns: 30,
|
|
3878
|
+
onStep: (stepEvent) => {
|
|
3879
|
+
emit({
|
|
3880
|
+
type: `step:${stepEvent.type}`,
|
|
3881
|
+
scenarioId: scenario.id,
|
|
3882
|
+
scenarioName: scenario.name,
|
|
3883
|
+
runId,
|
|
3884
|
+
toolName: stepEvent.toolName,
|
|
3885
|
+
toolInput: stepEvent.toolInput,
|
|
3886
|
+
toolResult: stepEvent.toolResult,
|
|
3887
|
+
thinking: stepEvent.thinking,
|
|
3888
|
+
stepNumber: stepEvent.stepNumber
|
|
3889
|
+
});
|
|
3890
|
+
}
|
|
3862
3891
|
});
|
|
3863
3892
|
for (const ss of agentResult.screenshots) {
|
|
3864
3893
|
createScreenshot({
|
|
@@ -5362,8 +5391,17 @@ function deleteAuthPreset(name) {
|
|
|
5362
5391
|
|
|
5363
5392
|
// src/cli/index.tsx
|
|
5364
5393
|
import { existsSync as existsSync7, mkdirSync as mkdirSync4 } from "fs";
|
|
5394
|
+
function formatToolInput(input) {
|
|
5395
|
+
const parts = [];
|
|
5396
|
+
for (const [key, value] of Object.entries(input)) {
|
|
5397
|
+
const str = typeof value === "string" ? value : JSON.stringify(value);
|
|
5398
|
+
const truncated = str.length > 60 ? str.slice(0, 60) + "..." : str;
|
|
5399
|
+
parts.push(`${key}="${truncated}"`);
|
|
5400
|
+
}
|
|
5401
|
+
return parts.join(" ");
|
|
5402
|
+
}
|
|
5365
5403
|
var program2 = new Command;
|
|
5366
|
-
program2.name("testers").version("0.0.
|
|
5404
|
+
program2.name("testers").version("0.0.4").description("AI-powered browser testing CLI");
|
|
5367
5405
|
var CONFIG_DIR2 = join6(process.env["HOME"] ?? "~", ".testers");
|
|
5368
5406
|
var CONFIG_PATH2 = join6(CONFIG_DIR2, "config.json");
|
|
5369
5407
|
function getActiveProject() {
|
|
@@ -5543,6 +5581,47 @@ program2.command("run <url> [description]").description("Run test scenarios agai
|
|
|
5543
5581
|
console.log(chalk4.dim(` Check progress: testers results ${runId.slice(0, 8)}`));
|
|
5544
5582
|
process.exit(0);
|
|
5545
5583
|
}
|
|
5584
|
+
if (!opts.json && !opts.output) {
|
|
5585
|
+
onRunEvent((event) => {
|
|
5586
|
+
switch (event.type) {
|
|
5587
|
+
case "scenario:start":
|
|
5588
|
+
console.log(chalk4.blue(` [start] ${event.scenarioName ?? event.scenarioId}`));
|
|
5589
|
+
break;
|
|
5590
|
+
case "step:thinking":
|
|
5591
|
+
if (event.thinking) {
|
|
5592
|
+
const preview = event.thinking.length > 120 ? event.thinking.slice(0, 120) + "..." : event.thinking;
|
|
5593
|
+
console.log(chalk4.dim(` [think] ${preview}`));
|
|
5594
|
+
}
|
|
5595
|
+
break;
|
|
5596
|
+
case "step:tool_call":
|
|
5597
|
+
console.log(chalk4.cyan(` [step ${event.stepNumber}] ${event.toolName}${event.toolInput ? ` ${formatToolInput(event.toolInput)}` : ""}`));
|
|
5598
|
+
break;
|
|
5599
|
+
case "step:tool_result":
|
|
5600
|
+
if (event.toolName === "report_result") {
|
|
5601
|
+
console.log(chalk4.bold(` [result] ${event.toolResult}`));
|
|
5602
|
+
} else {
|
|
5603
|
+
const resultPreview = (event.toolResult ?? "").length > 100 ? (event.toolResult ?? "").slice(0, 100) + "..." : event.toolResult ?? "";
|
|
5604
|
+
console.log(chalk4.dim(` [done] ${resultPreview}`));
|
|
5605
|
+
}
|
|
5606
|
+
break;
|
|
5607
|
+
case "screenshot:captured":
|
|
5608
|
+
console.log(chalk4.dim(` [screenshot] ${event.screenshotPath}`));
|
|
5609
|
+
break;
|
|
5610
|
+
case "scenario:pass":
|
|
5611
|
+
console.log(chalk4.green(` [PASS] ${event.scenarioName}`));
|
|
5612
|
+
break;
|
|
5613
|
+
case "scenario:fail":
|
|
5614
|
+
console.log(chalk4.red(` [FAIL] ${event.scenarioName}`));
|
|
5615
|
+
break;
|
|
5616
|
+
case "scenario:error":
|
|
5617
|
+
console.log(chalk4.yellow(` [ERR] ${event.scenarioName}: ${event.error}`));
|
|
5618
|
+
break;
|
|
5619
|
+
}
|
|
5620
|
+
});
|
|
5621
|
+
console.log("");
|
|
5622
|
+
console.log(chalk4.bold(` Running tests against ${url}`));
|
|
5623
|
+
console.log("");
|
|
5624
|
+
}
|
|
5546
5625
|
if (description) {
|
|
5547
5626
|
const scenario = createScenario({
|
|
5548
5627
|
name: description,
|
package/dist/index.js
CHANGED
|
@@ -1951,7 +1951,8 @@ async function runAgentLoop(options) {
|
|
|
1951
1951
|
screenshotter,
|
|
1952
1952
|
model,
|
|
1953
1953
|
runId,
|
|
1954
|
-
maxTurns = 30
|
|
1954
|
+
maxTurns = 30,
|
|
1955
|
+
onStep
|
|
1955
1956
|
} = options;
|
|
1956
1957
|
const systemPrompt = [
|
|
1957
1958
|
"You are an expert QA testing agent. Your job is to thoroughly test web application scenarios.",
|
|
@@ -2010,8 +2011,8 @@ async function runAgentLoop(options) {
|
|
|
2010
2011
|
}
|
|
2011
2012
|
const toolUseBlocks = response.content.filter((block) => block.type === "tool_use");
|
|
2012
2013
|
if (toolUseBlocks.length === 0 && response.stop_reason === "end_turn") {
|
|
2013
|
-
const
|
|
2014
|
-
const textReasoning =
|
|
2014
|
+
const textBlocks2 = response.content.filter((block) => block.type === "text");
|
|
2015
|
+
const textReasoning = textBlocks2.map((b) => b.text).join(`
|
|
2015
2016
|
`);
|
|
2016
2017
|
return {
|
|
2017
2018
|
status: "error",
|
|
@@ -2022,10 +2023,22 @@ async function runAgentLoop(options) {
|
|
|
2022
2023
|
};
|
|
2023
2024
|
}
|
|
2024
2025
|
const toolResults = [];
|
|
2026
|
+
const textBlocks = response.content.filter((block) => block.type === "text");
|
|
2027
|
+
if (textBlocks.length > 0 && onStep) {
|
|
2028
|
+
const thinking = textBlocks.map((b) => b.text).join(`
|
|
2029
|
+
`);
|
|
2030
|
+
onStep({ type: "thinking", thinking, stepNumber });
|
|
2031
|
+
}
|
|
2025
2032
|
for (const toolBlock of toolUseBlocks) {
|
|
2026
2033
|
stepNumber++;
|
|
2027
2034
|
const toolInput = toolBlock.input;
|
|
2035
|
+
if (onStep) {
|
|
2036
|
+
onStep({ type: "tool_call", toolName: toolBlock.name, toolInput, stepNumber });
|
|
2037
|
+
}
|
|
2028
2038
|
const execResult = await executeTool(page, screenshotter, toolBlock.name, toolInput, { runId, scenarioSlug, stepNumber });
|
|
2039
|
+
if (onStep) {
|
|
2040
|
+
onStep({ type: "tool_result", toolName: toolBlock.name, toolResult: execResult.result, stepNumber });
|
|
2041
|
+
}
|
|
2029
2042
|
if (execResult.screenshot) {
|
|
2030
2043
|
screenshots.push({
|
|
2031
2044
|
...execResult.screenshot,
|
|
@@ -2115,7 +2128,20 @@ async function runSingleScenario(scenario, runId, options) {
|
|
|
2115
2128
|
screenshotter,
|
|
2116
2129
|
model,
|
|
2117
2130
|
runId,
|
|
2118
|
-
maxTurns: 30
|
|
2131
|
+
maxTurns: 30,
|
|
2132
|
+
onStep: (stepEvent) => {
|
|
2133
|
+
emit({
|
|
2134
|
+
type: `step:${stepEvent.type}`,
|
|
2135
|
+
scenarioId: scenario.id,
|
|
2136
|
+
scenarioName: scenario.name,
|
|
2137
|
+
runId,
|
|
2138
|
+
toolName: stepEvent.toolName,
|
|
2139
|
+
toolInput: stepEvent.toolInput,
|
|
2140
|
+
toolResult: stepEvent.toolResult,
|
|
2141
|
+
thinking: stepEvent.thinking,
|
|
2142
|
+
stepNumber: stepEvent.stepNumber
|
|
2143
|
+
});
|
|
2144
|
+
}
|
|
2119
2145
|
});
|
|
2120
2146
|
for (const ss of agentResult.screenshots) {
|
|
2121
2147
|
createScreenshot({
|
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,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"}
|
package/dist/mcp/index.js
CHANGED
|
@@ -5565,7 +5565,8 @@ async function runAgentLoop(options) {
|
|
|
5565
5565
|
screenshotter,
|
|
5566
5566
|
model,
|
|
5567
5567
|
runId,
|
|
5568
|
-
maxTurns = 30
|
|
5568
|
+
maxTurns = 30,
|
|
5569
|
+
onStep
|
|
5569
5570
|
} = options;
|
|
5570
5571
|
const systemPrompt = [
|
|
5571
5572
|
"You are an expert QA testing agent. Your job is to thoroughly test web application scenarios.",
|
|
@@ -5624,8 +5625,8 @@ async function runAgentLoop(options) {
|
|
|
5624
5625
|
}
|
|
5625
5626
|
const toolUseBlocks = response.content.filter((block) => block.type === "tool_use");
|
|
5626
5627
|
if (toolUseBlocks.length === 0 && response.stop_reason === "end_turn") {
|
|
5627
|
-
const
|
|
5628
|
-
const textReasoning =
|
|
5628
|
+
const textBlocks2 = response.content.filter((block) => block.type === "text");
|
|
5629
|
+
const textReasoning = textBlocks2.map((b) => b.text).join(`
|
|
5629
5630
|
`);
|
|
5630
5631
|
return {
|
|
5631
5632
|
status: "error",
|
|
@@ -5636,10 +5637,22 @@ async function runAgentLoop(options) {
|
|
|
5636
5637
|
};
|
|
5637
5638
|
}
|
|
5638
5639
|
const toolResults = [];
|
|
5640
|
+
const textBlocks = response.content.filter((block) => block.type === "text");
|
|
5641
|
+
if (textBlocks.length > 0 && onStep) {
|
|
5642
|
+
const thinking = textBlocks.map((b) => b.text).join(`
|
|
5643
|
+
`);
|
|
5644
|
+
onStep({ type: "thinking", thinking, stepNumber });
|
|
5645
|
+
}
|
|
5639
5646
|
for (const toolBlock of toolUseBlocks) {
|
|
5640
5647
|
stepNumber++;
|
|
5641
5648
|
const toolInput = toolBlock.input;
|
|
5649
|
+
if (onStep) {
|
|
5650
|
+
onStep({ type: "tool_call", toolName: toolBlock.name, toolInput, stepNumber });
|
|
5651
|
+
}
|
|
5642
5652
|
const execResult = await executeTool(page, screenshotter, toolBlock.name, toolInput, { runId, scenarioSlug, stepNumber });
|
|
5653
|
+
if (onStep) {
|
|
5654
|
+
onStep({ type: "tool_result", toolName: toolBlock.name, toolResult: execResult.result, stepNumber });
|
|
5655
|
+
}
|
|
5643
5656
|
if (execResult.screenshot) {
|
|
5644
5657
|
screenshots.push({
|
|
5645
5658
|
...execResult.screenshot,
|
|
@@ -5781,7 +5794,20 @@ async function runSingleScenario(scenario, runId, options) {
|
|
|
5781
5794
|
screenshotter,
|
|
5782
5795
|
model,
|
|
5783
5796
|
runId,
|
|
5784
|
-
maxTurns: 30
|
|
5797
|
+
maxTurns: 30,
|
|
5798
|
+
onStep: (stepEvent) => {
|
|
5799
|
+
emit({
|
|
5800
|
+
type: `step:${stepEvent.type}`,
|
|
5801
|
+
scenarioId: scenario.id,
|
|
5802
|
+
scenarioName: scenario.name,
|
|
5803
|
+
runId,
|
|
5804
|
+
toolName: stepEvent.toolName,
|
|
5805
|
+
toolInput: stepEvent.toolInput,
|
|
5806
|
+
toolResult: stepEvent.toolResult,
|
|
5807
|
+
thinking: stepEvent.thinking,
|
|
5808
|
+
stepNumber: stepEvent.stepNumber
|
|
5809
|
+
});
|
|
5810
|
+
}
|
|
5785
5811
|
});
|
|
5786
5812
|
for (const ss of agentResult.screenshots) {
|
|
5787
5813
|
createScreenshot({
|
package/dist/server/index.js
CHANGED
|
@@ -1499,7 +1499,8 @@ async function runAgentLoop(options) {
|
|
|
1499
1499
|
screenshotter,
|
|
1500
1500
|
model,
|
|
1501
1501
|
runId,
|
|
1502
|
-
maxTurns = 30
|
|
1502
|
+
maxTurns = 30,
|
|
1503
|
+
onStep
|
|
1503
1504
|
} = options;
|
|
1504
1505
|
const systemPrompt = [
|
|
1505
1506
|
"You are an expert QA testing agent. Your job is to thoroughly test web application scenarios.",
|
|
@@ -1558,8 +1559,8 @@ async function runAgentLoop(options) {
|
|
|
1558
1559
|
}
|
|
1559
1560
|
const toolUseBlocks = response.content.filter((block) => block.type === "tool_use");
|
|
1560
1561
|
if (toolUseBlocks.length === 0 && response.stop_reason === "end_turn") {
|
|
1561
|
-
const
|
|
1562
|
-
const textReasoning =
|
|
1562
|
+
const textBlocks2 = response.content.filter((block) => block.type === "text");
|
|
1563
|
+
const textReasoning = textBlocks2.map((b) => b.text).join(`
|
|
1563
1564
|
`);
|
|
1564
1565
|
return {
|
|
1565
1566
|
status: "error",
|
|
@@ -1570,10 +1571,22 @@ async function runAgentLoop(options) {
|
|
|
1570
1571
|
};
|
|
1571
1572
|
}
|
|
1572
1573
|
const toolResults = [];
|
|
1574
|
+
const textBlocks = response.content.filter((block) => block.type === "text");
|
|
1575
|
+
if (textBlocks.length > 0 && onStep) {
|
|
1576
|
+
const thinking = textBlocks.map((b) => b.text).join(`
|
|
1577
|
+
`);
|
|
1578
|
+
onStep({ type: "thinking", thinking, stepNumber });
|
|
1579
|
+
}
|
|
1573
1580
|
for (const toolBlock of toolUseBlocks) {
|
|
1574
1581
|
stepNumber++;
|
|
1575
1582
|
const toolInput = toolBlock.input;
|
|
1583
|
+
if (onStep) {
|
|
1584
|
+
onStep({ type: "tool_call", toolName: toolBlock.name, toolInput, stepNumber });
|
|
1585
|
+
}
|
|
1576
1586
|
const execResult = await executeTool(page, screenshotter, toolBlock.name, toolInput, { runId, scenarioSlug, stepNumber });
|
|
1587
|
+
if (onStep) {
|
|
1588
|
+
onStep({ type: "tool_result", toolName: toolBlock.name, toolResult: execResult.result, stepNumber });
|
|
1589
|
+
}
|
|
1577
1590
|
if (execResult.screenshot) {
|
|
1578
1591
|
screenshots.push({
|
|
1579
1592
|
...execResult.screenshot,
|
|
@@ -1715,7 +1728,20 @@ async function runSingleScenario(scenario, runId, options) {
|
|
|
1715
1728
|
screenshotter,
|
|
1716
1729
|
model,
|
|
1717
1730
|
runId,
|
|
1718
|
-
maxTurns: 30
|
|
1731
|
+
maxTurns: 30,
|
|
1732
|
+
onStep: (stepEvent) => {
|
|
1733
|
+
emit({
|
|
1734
|
+
type: `step:${stepEvent.type}`,
|
|
1735
|
+
scenarioId: scenario.id,
|
|
1736
|
+
scenarioName: scenario.name,
|
|
1737
|
+
runId,
|
|
1738
|
+
toolName: stepEvent.toolName,
|
|
1739
|
+
toolInput: stepEvent.toolInput,
|
|
1740
|
+
toolResult: stepEvent.toolResult,
|
|
1741
|
+
thinking: stepEvent.thinking,
|
|
1742
|
+
stepNumber: stepEvent.stepNumber
|
|
1743
|
+
});
|
|
1744
|
+
}
|
|
1719
1745
|
});
|
|
1720
1746
|
for (const ss of agentResult.screenshots) {
|
|
1721
1747
|
createScreenshot({
|