@empiricalrun/test-gen 0.47.2 → 0.47.4
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/CHANGELOG.md +26 -0
- package/dist/actions/index.d.ts +1 -1
- package/dist/actions/index.js +1 -1
- package/dist/agent/browsing/index.d.ts.map +1 -1
- package/dist/agent/browsing/index.js +2 -3
- package/dist/agent/browsing/run.d.ts +4 -1
- package/dist/agent/browsing/run.d.ts.map +1 -1
- package/dist/agent/browsing/run.js +8 -3
- package/dist/agent/browsing/utils.d.ts +6 -13
- package/dist/agent/browsing/utils.d.ts.map +1 -1
- package/dist/agent/browsing/utils.js +9 -38
- package/dist/agent/chat.d.ts +7 -0
- package/dist/agent/chat.d.ts.map +1 -0
- package/dist/agent/chat.js +89 -0
- package/dist/agent/codegen/create-test-block.d.ts +2 -3
- package/dist/agent/codegen/create-test-block.d.ts.map +1 -1
- package/dist/agent/codegen/create-test-block.js +4 -9
- package/dist/agent/codegen/fix-ts-errors.d.ts +2 -3
- package/dist/agent/codegen/fix-ts-errors.d.ts.map +1 -1
- package/dist/agent/codegen/fix-ts-errors.js +4 -5
- package/dist/agent/codegen/generate-code-apply-changes.d.ts.map +1 -1
- package/dist/agent/codegen/generate-code-apply-changes.js +5 -6
- package/dist/agent/codegen/run.d.ts +6 -4
- package/dist/agent/codegen/run.d.ts.map +1 -1
- package/dist/agent/codegen/run.js +8 -6
- package/dist/agent/codegen/update-flow.d.ts +7 -5
- package/dist/agent/codegen/update-flow.d.ts.map +1 -1
- package/dist/agent/codegen/update-flow.js +9 -49
- package/dist/agent/codegen/utils.d.ts +2 -16
- package/dist/agent/codegen/utils.d.ts.map +1 -1
- package/dist/agent/codegen/utils.js +3 -41
- package/dist/agent/diagnosis-agent/index.d.ts +2 -9
- package/dist/agent/diagnosis-agent/index.d.ts.map +1 -1
- package/dist/agent/diagnosis-agent/index.js +1 -8
- package/dist/agent/enrich-prompt/index.d.ts.map +1 -1
- package/dist/agent/enrich-prompt/index.js +0 -1
- package/dist/agent/infer-agent/index.d.ts.map +1 -1
- package/dist/agent/infer-agent/index.js +0 -9
- package/dist/agent/master/browser-tests/index.spec.js +15 -1
- package/dist/agent/master/element-annotation.d.ts.map +1 -1
- package/dist/agent/master/element-annotation.js +1 -2
- package/dist/agent/master/execute-browser-action.d.ts.map +1 -1
- package/dist/agent/master/execute-browser-action.js +1 -2
- package/dist/agent/master/execute-skill-action.d.ts.map +1 -1
- package/dist/agent/master/execute-skill-action.js +1 -2
- package/dist/agent/master/next-action.d.ts.map +1 -1
- package/dist/agent/master/next-action.js +2 -3
- package/dist/agent/master/planner.d.ts.map +1 -1
- package/dist/agent/master/planner.js +1 -2
- package/dist/agent/master/run.d.ts.map +1 -1
- package/dist/agent/master/run.js +1 -2
- package/dist/agent/master/scroller.d.ts.map +1 -1
- package/dist/agent/master/scroller.js +2 -3
- package/dist/agent/planner/run-time-planner.d.ts.map +1 -1
- package/dist/agent/planner/run-time-planner.js +1 -2
- package/dist/bin/index.js +49 -34
- package/dist/bin/utils/index.d.ts +1 -0
- package/dist/bin/utils/index.d.ts.map +1 -1
- package/dist/bin/utils/index.js +9 -3
- package/dist/file/server.d.ts +2 -0
- package/dist/file/server.d.ts.map +1 -1
- package/dist/file/server.js +18 -1
- package/dist/tools/browser-agent.d.ts +16 -0
- package/dist/tools/browser-agent.d.ts.map +1 -0
- package/dist/tools/browser-agent.js +76 -0
- package/dist/tools/codegen-agent.d.ts +9 -0
- package/dist/tools/codegen-agent.d.ts.map +1 -0
- package/dist/tools/codegen-agent.js +44 -0
- package/dist/tools/test-run.d.ts +10 -0
- package/dist/tools/test-run.d.ts.map +1 -0
- package/dist/tools/test-run.js +35 -0
- package/dist/utils/git.d.ts +2 -0
- package/dist/utils/git.d.ts.map +1 -0
- package/dist/utils/git.js +11 -0
- package/package.json +3 -2
- package/dist/agent/utils.d.ts +0 -2
- package/dist/agent/utils.d.ts.map +0 -1
- package/dist/agent/utils.js +0 -12
|
@@ -4,7 +4,6 @@ exports.runtimePlannerWithScreenshot = void 0;
|
|
|
4
4
|
const llm_1 = require("@empiricalrun/llm");
|
|
5
5
|
const vision_1 = require("@empiricalrun/llm/vision");
|
|
6
6
|
const constants_1 = require("../../constants");
|
|
7
|
-
const utils_1 = require("../utils");
|
|
8
7
|
async function runtimePlannerWithScreenshot({ trace, task, conversation, pages, page, currentPage, }) {
|
|
9
8
|
const buffer = await page.screenshot({
|
|
10
9
|
//This is done to improve element annotation accuracy, anyways it doesn't annotate elements which are out of viewport
|
|
@@ -120,7 +119,7 @@ async function runtimePlannerWithScreenshot({ trace, task, conversation, pages,
|
|
|
120
119
|
});
|
|
121
120
|
const toolCallResp = (response?.tool_calls || [])[0];
|
|
122
121
|
if (toolCallResp) {
|
|
123
|
-
const toolCall =
|
|
122
|
+
const toolCall = JSON.parse(toolCallResp.function.arguments);
|
|
124
123
|
const output = {
|
|
125
124
|
pageName: toolCall.pageName,
|
|
126
125
|
isDone: toolCall.isDone,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../../src/agent/master/run.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,QAAQ,EACR,oBAAoB,EACrB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAelC,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../../src/agent/master/run.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,QAAQ,EACR,oBAAoB,EACrB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAelC,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAUxC,OAAO,EAAE,4BAA4B,EAAE,MAAM,QAAQ,CAAC;AAuBtD,wBAAsB,0BAA0B,CAAC,EAC/C,IAAI,EACJ,IAAI,EACJ,QAAQ,EACR,QAAQ,EACR,OAAO,EACP,SAAS,GACV,EAAE;IACD,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,IAAI,CAAC;IACX,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC,oBAAoB,CAAC,CAAC;IACvC,SAAS,CAAC,EAAE,SAAS,CAAC;CACvB;;;GAwRA"}
|
package/dist/agent/master/run.js
CHANGED
|
@@ -15,7 +15,6 @@ const utils_2 = require("../browsing/utils");
|
|
|
15
15
|
const skills_retriever_1 = require("../codegen/skills-retriever");
|
|
16
16
|
const run_1 = require("../planner/run");
|
|
17
17
|
const run_time_planner_1 = require("../planner/run-time-planner");
|
|
18
|
-
const utils_3 = require("../utils");
|
|
19
18
|
const action_tool_calls_1 = require("./action-tool-calls");
|
|
20
19
|
const execute_browser_action_1 = require("./execute-browser-action");
|
|
21
20
|
const execute_skill_action_1 = require("./execute-skill-action");
|
|
@@ -164,7 +163,7 @@ async function createTestUsingMasterAgent({ task, page, testCase, specPath, opti
|
|
|
164
163
|
await testgenUpdatesReporter.sendMessage("Agent is not able to figure out next action since element is not visible on screen.");
|
|
165
164
|
break;
|
|
166
165
|
}
|
|
167
|
-
const args =
|
|
166
|
+
const args = JSON.parse(nextAction.toolCallArgs);
|
|
168
167
|
const masterAgentActionSpan = masterAgentSpan?.span({
|
|
169
168
|
name: "master-agent-execute-action",
|
|
170
169
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scroller.d.ts","sourceRoot":"","sources":["../../../src/agent/master/scroller.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuB,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErE,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAG7C,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"scroller.d.ts","sourceRoot":"","sources":["../../../src/agent/master/scroller.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuB,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErE,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAG7C,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAahD,MAAM,MAAM,cAAc,GAAG;IAC3B,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,EAAE,MAAM,CAAC;CACzB,CAAC;AA2ZF,wBAAsB,QAAQ,CAAC,EAC7B,kBAAkB,EAClB,IAAI,EACJ,KAAK,EACL,cAAc,EACd,MAAM,GACP,EAAE;IACD,kBAAkB,EAAE,MAAM,CAAC;IAC3B,IAAI,EAAE,IAAI,CAAC;IACX,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,MAAM,CAAC,EAAE,YAAY,CAAC;CACvB,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CA6D5B"}
|
|
@@ -5,7 +5,6 @@ const llm_1 = require("@empiricalrun/llm");
|
|
|
5
5
|
const vision_1 = require("@empiricalrun/llm/vision");
|
|
6
6
|
const constants_1 = require("../../constants");
|
|
7
7
|
const reporter_1 = require("../../reporter");
|
|
8
|
-
const utils_1 = require("../utils");
|
|
9
8
|
const action_tool_calls_1 = require("./action-tool-calls");
|
|
10
9
|
const element_annotation_1 = require("./element-annotation");
|
|
11
10
|
let usedAnnotations = [];
|
|
@@ -165,7 +164,7 @@ Follow the instructions before responding:
|
|
|
165
164
|
const toolCall = completion?.tool_calls?.[0];
|
|
166
165
|
scrollSpan?.end({ output: toolCall });
|
|
167
166
|
if (toolCall) {
|
|
168
|
-
const args =
|
|
167
|
+
const args = JSON.parse(toolCall.function.arguments);
|
|
169
168
|
isVisible = args.is_visible || false;
|
|
170
169
|
}
|
|
171
170
|
else {
|
|
@@ -303,7 +302,7 @@ ${annotationKeysString}`,
|
|
|
303
302
|
const toolCall = completion?.tool_calls?.[0];
|
|
304
303
|
annotationsSpan?.end({ output: toolCall });
|
|
305
304
|
if (toolCall) {
|
|
306
|
-
const args =
|
|
305
|
+
const args = JSON.parse(toolCall.function.arguments);
|
|
307
306
|
const isAnnotationPresentInKeys = annotationKeys.some((annotation) => annotation.elementID === args.element_annotation);
|
|
308
307
|
if (args.element_annotation !== "NA" && isAnnotationPresentInKeys) {
|
|
309
308
|
usedAnnotations.push(args.element_annotation);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-time-planner.d.ts","sourceRoot":"","sources":["../../../src/agent/planner/run-time-planner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACpE,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAGvC,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"run-time-planner.d.ts","sourceRoot":"","sources":["../../../src/agent/planner/run-time-planner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACpE,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAGvC,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1C,wBAAsB,cAAc,CAAC,EACnC,KAAK,EACL,IAAI,EACJ,iBAAiB,EACjB,KAAK,EACL,WAAW,GACZ,EAAE;IACD,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IAC5B,WAAW,EAAE,WAAW,CAAC;CAC1B;;;;GA+FA"}
|
|
@@ -3,7 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.runtimePlanner = void 0;
|
|
4
4
|
const llm_1 = require("@empiricalrun/llm");
|
|
5
5
|
const promptTemplate_0 = "{{#section \"system\"}}\nYou are given a list of successfully executed actions that are done towards completing a task (which\nis also provided to you). Your goal is to analyse the list and determine if the task is completed.\n\nIf the task is not fully completed, identify which specific actions are missing\nand suggest next steps to complete the task. Assume that the conversation provided\nis entirely truthful and no additional actions were performed beyond those listed.\n\nThese actions were executed by AI agents using Playwright on a browser. These agents\nalready have access to browser tabs to execute actions. If there is a pending action,\none of the agents will execute it in the browser. However, they need your help to\nchoose which browser tab (= page) to use for the next action.\n\nTo fulfil your goal, follow these steps:\n- Divide the task into individual actions.\n- Compare each task action against the actions listed in the successfully executed actions list.\n- Identify which actions have been executed and which have not.\n- If all actions are executed, respond with the task as done.\n- If any actions are missing, respond with the task as not done, listing all actions\n and specifying which are complete and which are missing.\n- If provided with list of pages, based on the next pending action and previously executed\n action, identify the page on which next action needs to be taken\n{{/section}}\n\n{{#section \"user\"}}\nTask:\n{{task}}\n\n----\n\nSuccessfully executed actions:\n{{successfulActions}}\n\n----\n\nList of pages with their current URLs:\n{{pagesSummary}}\n\n\n{{/section}}\n";
|
|
6
|
-
const utils_1 = require("../utils");
|
|
7
6
|
async function runtimePlanner({ trace, task, successfulActions, pages, currentPage, }) {
|
|
8
7
|
const runTimePlannerSpan = trace?.span({
|
|
9
8
|
name: "runtime-planner",
|
|
@@ -76,7 +75,7 @@ async function runtimePlanner({ trace, task, successfulActions, pages, currentPa
|
|
|
76
75
|
});
|
|
77
76
|
const toolCallResp = (response?.tool_calls || [])[0];
|
|
78
77
|
if (toolCallResp) {
|
|
79
|
-
const toolCall =
|
|
78
|
+
const toolCall = JSON.parse(toolCallResp.function.arguments);
|
|
80
79
|
const output = {
|
|
81
80
|
pageName: toolCall.pageName,
|
|
82
81
|
isDone: toolCall.isDone,
|
package/dist/bin/index.js
CHANGED
|
@@ -9,6 +9,7 @@ const commander_1 = require("commander");
|
|
|
9
9
|
const dotenv_1 = __importDefault(require("dotenv"));
|
|
10
10
|
const run_1 = require("../agent/browsing/run");
|
|
11
11
|
const utils_1 = require("../agent/browsing/utils");
|
|
12
|
+
const chat_1 = require("../agent/chat");
|
|
12
13
|
const repo_edit_1 = require("../agent/codegen/repo-edit");
|
|
13
14
|
const run_2 = require("../agent/codegen/run");
|
|
14
15
|
const diagnosis_agent_1 = require("../agent/diagnosis-agent");
|
|
@@ -31,14 +32,12 @@ process.on("beforeExit", async () => await flushEvents());
|
|
|
31
32
|
process.on("exit", async () => await flushEvents());
|
|
32
33
|
process.on("SIGINT", async () => await flushEvents());
|
|
33
34
|
process.on("SIGTERM", async () => await flushEvents());
|
|
34
|
-
async function
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
trace,
|
|
35
|
+
async function runChatAgent(prompt) {
|
|
36
|
+
return await (0, chat_1.chatAgent)({
|
|
37
|
+
prompt,
|
|
38
38
|
});
|
|
39
|
-
return response;
|
|
40
39
|
}
|
|
41
|
-
async function
|
|
40
|
+
async function runAgentsWorkflow(testGenConfig, testGenToken) {
|
|
42
41
|
const logger = new logger_1.CustomLogger();
|
|
43
42
|
const { specPath, testCase } = testGenConfig;
|
|
44
43
|
if (process.env.LOG_URL) {
|
|
@@ -89,29 +88,10 @@ async function runAgent(testGenConfig, testGenToken) {
|
|
|
89
88
|
});
|
|
90
89
|
return;
|
|
91
90
|
}
|
|
92
|
-
// TODO: this needs to be moved to an orchestrator which decides what needs to be done first before executing the sub tasks
|
|
93
|
-
if (testGenConfig.testErrorDiagnosis &&
|
|
94
|
-
testGenConfig.testErrorDiagnosis.failingLine &&
|
|
95
|
-
// TODO: fix this hardcoding of user prompt - ideally its an auto fix intent
|
|
96
|
-
testCase.steps[0]?.toLowerCase().trim() == "can you please fix the test") {
|
|
97
|
-
const { task: updatedTask } = await (0, diagnosis_agent_1.createTaskUsingFailureDiagnosis)({
|
|
98
|
-
options: testGenConfig.options,
|
|
99
|
-
trace,
|
|
100
|
-
diagnosis: testGenConfig.testErrorDiagnosis,
|
|
101
|
-
});
|
|
102
|
-
if (updatedTask) {
|
|
103
|
-
testCase.steps = [updatedTask];
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
if (!agent || agent === "auto") {
|
|
107
|
-
agent = await resolveAgentUsingTask({
|
|
108
|
-
testCase,
|
|
109
|
-
trace,
|
|
110
|
-
});
|
|
111
|
-
}
|
|
112
|
-
logger.success(`Generating test using ${agent} agent. ${process.env.LOG_URL ? `[view log](${process.env.LOG_URL})` : ""}`);
|
|
113
91
|
if (testGenConfig.testErrorDiagnosis &&
|
|
114
92
|
testGenConfig.testErrorDiagnosis.failingLine) {
|
|
93
|
+
// If failure context is available, we can enrich the user prompt to contain
|
|
94
|
+
// the failure context
|
|
115
95
|
const requestedChangeResp = await (0, enrich_prompt_1.enrichPromptWithFailingLine)({
|
|
116
96
|
trace,
|
|
117
97
|
testBlock: testGenConfig.testErrorDiagnosis.failingLine,
|
|
@@ -119,7 +99,28 @@ async function runAgent(testGenConfig, testGenToken) {
|
|
|
119
99
|
suggestionForFix: testCase.steps.join("\n"),
|
|
120
100
|
});
|
|
121
101
|
testCase.steps = [requestedChangeResp.output];
|
|
102
|
+
// For "auto-fix" we use the user prompt (which is hard-coded in the dashboard
|
|
103
|
+
// entrypoints), and invoke more interesting enrichment
|
|
104
|
+
if (
|
|
105
|
+
// TODO: fix this hardcoding of user prompt - ideally its an auto fix intent
|
|
106
|
+
testCase.steps[0]?.toLowerCase().trim() == "can you please fix the test") {
|
|
107
|
+
const { task: updatedTask } = await (0, diagnosis_agent_1.createTaskUsingFailureDiagnosis)({
|
|
108
|
+
trace,
|
|
109
|
+
diagnosis: testGenConfig.testErrorDiagnosis,
|
|
110
|
+
});
|
|
111
|
+
if (updatedTask) {
|
|
112
|
+
testCase.steps = [updatedTask];
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
if (!agent || agent === "auto") {
|
|
117
|
+
const { response } = await (0, infer_agent_1.inferAgentBasedTask)({
|
|
118
|
+
task: testCase.steps.join("\n"),
|
|
119
|
+
trace,
|
|
120
|
+
});
|
|
121
|
+
agent = response;
|
|
122
122
|
}
|
|
123
|
+
logger.success(`Generating test using ${agent} agent. ${process.env.LOG_URL ? `[view log](${process.env.LOG_URL})` : ""}`);
|
|
123
124
|
if (agent === "plan") {
|
|
124
125
|
const task = testCase.steps.join("\n");
|
|
125
126
|
const plan = await (0, run_3.planTask)({
|
|
@@ -132,11 +133,18 @@ async function runAgent(testGenConfig, testGenToken) {
|
|
|
132
133
|
await new reporter_1.TestGenUpdatesReporter().sendMessage(plan);
|
|
133
134
|
}
|
|
134
135
|
else if (agent === "code") {
|
|
135
|
-
await (0, run_2.
|
|
136
|
+
await (0, run_2.generateTestWithCodegen)({
|
|
137
|
+
testCase,
|
|
138
|
+
file: specPath,
|
|
139
|
+
trace,
|
|
140
|
+
});
|
|
136
141
|
}
|
|
137
142
|
else {
|
|
138
|
-
|
|
139
|
-
|
|
143
|
+
const filePathToUpdate = await (0, utils_1.prepareFileForMasterAgent)({
|
|
144
|
+
testCase,
|
|
145
|
+
specPath,
|
|
146
|
+
trace,
|
|
147
|
+
});
|
|
140
148
|
void (0, session_1.updateSessionStatus)(testGenConfig.options?.metadata.testSessionId, {
|
|
141
149
|
status: "agent_live_session_started",
|
|
142
150
|
});
|
|
@@ -155,10 +163,11 @@ async function runAgent(testGenConfig, testGenToken) {
|
|
|
155
163
|
const program = new commander_1.Command();
|
|
156
164
|
program
|
|
157
165
|
.option("--token <token>", "Test generation token")
|
|
166
|
+
.option("--prompt <prompt>", "Prompt for the chat agent")
|
|
158
167
|
.option("--name <test-name>", "Name of the test case")
|
|
159
|
-
.option("--prompt <prompt>", "Prompt for the test case")
|
|
160
168
|
.option("--file <test-file>", "File path of the test case (inside tests dir)")
|
|
161
169
|
.option("--suites <suites>", "Comma separated list of describe blocks")
|
|
170
|
+
.option("--use-chat", "Use chat agent (and not the workflow)")
|
|
162
171
|
.parse(process.argv);
|
|
163
172
|
const options = program.opts();
|
|
164
173
|
const completedOptions = await (0, utils_2.validateAndCompleteCliOptions)(options);
|
|
@@ -181,10 +190,16 @@ async function runAgent(testGenConfig, testGenToken) {
|
|
|
181
190
|
});
|
|
182
191
|
let testGenFailed = false;
|
|
183
192
|
let agentUsed;
|
|
193
|
+
// Download the build if repo has a download script
|
|
194
|
+
await (0, test_build_1.downloadBuild)(testGenConfig.build || {});
|
|
184
195
|
try {
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
196
|
+
if (completedOptions.useChat) {
|
|
197
|
+
await runChatAgent(completedOptions.prompt);
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
else {
|
|
201
|
+
agentUsed = await runAgentsWorkflow(testGenConfig, testGenToken);
|
|
202
|
+
}
|
|
188
203
|
}
|
|
189
204
|
catch (e) {
|
|
190
205
|
testGenFailed = true;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/bin/utils/index.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,UAAU;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/bin/utils/index.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,UAAU;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAQD,wBAAsB,6BAA6B,CACjD,OAAO,EAAE,UAAU,GAClB,OAAO,CAAC,UAAU,CAAC,CAyDrB"}
|
package/dist/bin/utils/index.js
CHANGED
|
@@ -6,12 +6,18 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.validateAndCompleteCliOptions = void 0;
|
|
7
7
|
const inquirer_1 = __importDefault(require("inquirer"));
|
|
8
8
|
async function validateAndCompleteCliOptions(options) {
|
|
9
|
+
// For existing flow between dashboard <> test-gen (via ci-worker)
|
|
9
10
|
const hasToken = !!options.token;
|
|
10
11
|
if (hasToken) {
|
|
11
12
|
return options;
|
|
12
13
|
}
|
|
14
|
+
let requiredFields = ["name", "file", "prompt"];
|
|
15
|
+
// For new chat flow in local CLI usage, only prompt is required
|
|
16
|
+
if (options.useChat) {
|
|
17
|
+
requiredFields = ["prompt"];
|
|
18
|
+
}
|
|
13
19
|
const questions = [];
|
|
14
|
-
if (!options.name) {
|
|
20
|
+
if (!options.name && requiredFields.includes("name")) {
|
|
15
21
|
questions.push({
|
|
16
22
|
type: "input",
|
|
17
23
|
name: "name",
|
|
@@ -19,7 +25,7 @@ async function validateAndCompleteCliOptions(options) {
|
|
|
19
25
|
validate: (input) => input.trim().length > 0 || "Test name is required",
|
|
20
26
|
});
|
|
21
27
|
}
|
|
22
|
-
if (!options.file) {
|
|
28
|
+
if (!options.file && requiredFields.includes("file")) {
|
|
23
29
|
questions.push({
|
|
24
30
|
type: "input",
|
|
25
31
|
name: "file",
|
|
@@ -27,7 +33,7 @@ async function validateAndCompleteCliOptions(options) {
|
|
|
27
33
|
validate: (input) => input.trim().length > 0 || "Test file path is required",
|
|
28
34
|
});
|
|
29
35
|
}
|
|
30
|
-
if (!options.prompt) {
|
|
36
|
+
if (!options.prompt && requiredFields.includes("prompt")) {
|
|
31
37
|
questions.push({
|
|
32
38
|
type: "editor",
|
|
33
39
|
name: "prompt",
|
package/dist/file/server.d.ts
CHANGED
|
@@ -2,12 +2,14 @@ export declare class FileService {
|
|
|
2
2
|
private port;
|
|
3
3
|
private filePath;
|
|
4
4
|
private repoDir;
|
|
5
|
+
private server;
|
|
5
6
|
constructor({ port, repoDir }: {
|
|
6
7
|
port: number;
|
|
7
8
|
repoDir: string;
|
|
8
9
|
});
|
|
9
10
|
setFilePath(filePath: string): void;
|
|
10
11
|
startFileService(): Promise<number>;
|
|
12
|
+
stop(): Promise<void>;
|
|
11
13
|
}
|
|
12
14
|
export declare function startFileService(): Promise<void>;
|
|
13
15
|
//# sourceMappingURL=server.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/file/server.ts"],"names":[],"mappings":"AAWA,qBAAa,WAAW;IACtB,OAAO,CAAC,IAAI,CAAa;IACzB,OAAO,CAAC,QAAQ,CAAc;IAC9B,OAAO,CAAC,OAAO,CAAc;
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/file/server.ts"],"names":[],"mappings":"AAWA,qBAAa,WAAW;IACtB,OAAO,CAAC,IAAI,CAAa;IACzB,OAAO,CAAC,QAAQ,CAAc;IAC9B,OAAO,CAAC,OAAO,CAAc;IAC7B,OAAO,CAAC,MAAM,CAA4C;gBAE9C,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE;IAKhE,WAAW,CAAC,QAAQ,EAAE,MAAM;IAItB,gBAAgB,IAAI,OAAO,CAAC,MAAM,CAAC;IA0CnC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAgB5B;AAED,wBAAsB,gBAAgB,kBAAK"}
|
package/dist/file/server.js
CHANGED
|
@@ -13,6 +13,7 @@ class FileService {
|
|
|
13
13
|
port = 0;
|
|
14
14
|
filePath = "";
|
|
15
15
|
repoDir = "";
|
|
16
|
+
server;
|
|
16
17
|
constructor({ port, repoDir }) {
|
|
17
18
|
this.port = port;
|
|
18
19
|
this.repoDir = repoDir;
|
|
@@ -43,7 +44,23 @@ class FileService {
|
|
|
43
44
|
return res.send({ success: false });
|
|
44
45
|
});
|
|
45
46
|
return new Promise((resolve) => {
|
|
46
|
-
app.listen(this.port, () => resolve(this.port));
|
|
47
|
+
this.server = app.listen(this.port, () => resolve(this.port));
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
async stop() {
|
|
51
|
+
return new Promise((resolve, reject) => {
|
|
52
|
+
if (!this.server) {
|
|
53
|
+
resolve();
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
this.server.close((err) => {
|
|
57
|
+
if (err) {
|
|
58
|
+
reject(err);
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
this.server = undefined;
|
|
62
|
+
resolve();
|
|
63
|
+
});
|
|
47
64
|
});
|
|
48
65
|
}
|
|
49
66
|
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { OpenAI } from "openai";
|
|
2
|
+
export declare const schema: OpenAI.Chat.Completions.ChatCompletionTool;
|
|
3
|
+
export declare const generateTestWithBrowserAgentTool: ({ testName, fileName, changeToMake, }: {
|
|
4
|
+
testName: string;
|
|
5
|
+
fileName: string;
|
|
6
|
+
changeToMake: string;
|
|
7
|
+
}) => Promise<{
|
|
8
|
+
result: string;
|
|
9
|
+
gitPatch: string;
|
|
10
|
+
error?: undefined;
|
|
11
|
+
} | {
|
|
12
|
+
result: string;
|
|
13
|
+
error: string;
|
|
14
|
+
gitPatch?: undefined;
|
|
15
|
+
}>;
|
|
16
|
+
//# sourceMappingURL=browser-agent.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser-agent.d.ts","sourceRoot":"","sources":["../../src/tools/browser-agent.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAQhC,eAAO,MAAM,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,kBA0B5C,CAAC;AAEF,eAAO,MAAM,gCAAgC;cAKjC,MAAM;cACN,MAAM;kBACF,MAAM;;;;;;;;;EAsCrB,CAAC"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.generateTestWithBrowserAgentTool = exports.schema = void 0;
|
|
7
|
+
const path_1 = __importDefault(require("path"));
|
|
8
|
+
const run_1 = require("../agent/browsing/run");
|
|
9
|
+
const utils_1 = require("../agent/browsing/utils");
|
|
10
|
+
const scenarios_1 = require("../bin/utils/scenarios");
|
|
11
|
+
const git_1 = require("../utils/git");
|
|
12
|
+
exports.schema = {
|
|
13
|
+
type: "function",
|
|
14
|
+
function: {
|
|
15
|
+
name: "generateTestWithBrowserAgent",
|
|
16
|
+
description: "Create or modify a test case with browser agent. This is useful when the modifications involve changing a selector or executing browser interactions (like click, fill, etc)",
|
|
17
|
+
parameters: {
|
|
18
|
+
type: "object",
|
|
19
|
+
properties: {
|
|
20
|
+
testName: {
|
|
21
|
+
type: "string",
|
|
22
|
+
description: "The name of the test to create or modify",
|
|
23
|
+
},
|
|
24
|
+
fileName: {
|
|
25
|
+
type: "string",
|
|
26
|
+
description: "The name of the file where the test is located. File name must end with .spec.ts",
|
|
27
|
+
},
|
|
28
|
+
changeToMake: {
|
|
29
|
+
type: "string",
|
|
30
|
+
description: "The change to make to the test",
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
required: ["testName", "fileName", "changeToMake"],
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
const generateTestWithBrowserAgentTool = async ({ testName, fileName, changeToMake, }) => {
|
|
38
|
+
const testCase = {
|
|
39
|
+
id: 0,
|
|
40
|
+
name: testName,
|
|
41
|
+
filePath: fileName,
|
|
42
|
+
suites: [], // TODO: Support suites
|
|
43
|
+
steps: [changeToMake],
|
|
44
|
+
};
|
|
45
|
+
const filePathFromCwd = path_1.default.join("tests", fileName);
|
|
46
|
+
const filePathToUpdate = await (0, utils_1.prepareFileForMasterAgent)({
|
|
47
|
+
testCase,
|
|
48
|
+
specPath: filePathFromCwd,
|
|
49
|
+
});
|
|
50
|
+
const { isError, error } = await (0, run_1.generateTestsUsingMasterAgent)({
|
|
51
|
+
testFilePath: filePathFromCwd,
|
|
52
|
+
filePathToUpdate,
|
|
53
|
+
// TODO: Remove this hardcoded project name
|
|
54
|
+
pwProjectsFilter: ["chromium"],
|
|
55
|
+
testGenToken: (0, scenarios_1.buildTokenFromOptions)({
|
|
56
|
+
name: testName,
|
|
57
|
+
file: fileName,
|
|
58
|
+
prompt: changeToMake,
|
|
59
|
+
}),
|
|
60
|
+
repoDir: process.cwd(),
|
|
61
|
+
});
|
|
62
|
+
if (!isError) {
|
|
63
|
+
const gitPatch = (0, git_1.getGitDiff)(filePathFromCwd);
|
|
64
|
+
return {
|
|
65
|
+
result: "Test was generated successfully",
|
|
66
|
+
gitPatch,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
return {
|
|
71
|
+
result: "Test was not generated successfully",
|
|
72
|
+
error,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
exports.generateTestWithBrowserAgentTool = generateTestWithBrowserAgentTool;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { TestCase } from "@empiricalrun/shared-types";
|
|
2
|
+
import { OpenAI } from "openai";
|
|
3
|
+
export declare const schema: OpenAI.Chat.Completions.ChatCompletionTool;
|
|
4
|
+
export declare const generateTestWithCodegenTool: ({ testName, fileName, changeToMake, }: {
|
|
5
|
+
testName: string;
|
|
6
|
+
fileName: string;
|
|
7
|
+
changeToMake: string;
|
|
8
|
+
}) => Promise<void | TestCase[]>;
|
|
9
|
+
//# sourceMappingURL=codegen-agent.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codegen-agent.d.ts","sourceRoot":"","sources":["../../src/tools/codegen-agent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AACtD,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAIhC,eAAO,MAAM,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,kBA0B5C,CAAC;AAEF,eAAO,MAAM,2BAA2B;cAK5B,MAAM;cACN,MAAM;kBACF,MAAM;gCAcrB,CAAC"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateTestWithCodegenTool = exports.schema = void 0;
|
|
4
|
+
const run_1 = require("../agent/codegen/run");
|
|
5
|
+
exports.schema = {
|
|
6
|
+
type: "function",
|
|
7
|
+
function: {
|
|
8
|
+
name: "generateTestWithCodegen",
|
|
9
|
+
description: "Create or modify a test case with code generation. This is useful when modifications can be done with TypeScript only, and don't require any browser interactions or element selectors.",
|
|
10
|
+
parameters: {
|
|
11
|
+
type: "object",
|
|
12
|
+
properties: {
|
|
13
|
+
testName: {
|
|
14
|
+
type: "string",
|
|
15
|
+
description: "The name of the test to create or modify",
|
|
16
|
+
},
|
|
17
|
+
fileName: {
|
|
18
|
+
type: "string",
|
|
19
|
+
description: "The name of the file where the test is located. File name must end with .spec.ts",
|
|
20
|
+
},
|
|
21
|
+
changeToMake: {
|
|
22
|
+
type: "string",
|
|
23
|
+
description: "The change to make to the test",
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
required: ["testName", "fileName", "changeToMake"],
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
const generateTestWithCodegenTool = async ({ testName, fileName, changeToMake, }) => {
|
|
31
|
+
const testCase = {
|
|
32
|
+
id: 0,
|
|
33
|
+
name: testName,
|
|
34
|
+
filePath: fileName,
|
|
35
|
+
suites: [], // TODO: Support suites
|
|
36
|
+
steps: [changeToMake],
|
|
37
|
+
};
|
|
38
|
+
const result = await (0, run_1.generateTestWithCodegen)({
|
|
39
|
+
testCase,
|
|
40
|
+
file: fileName,
|
|
41
|
+
});
|
|
42
|
+
return result;
|
|
43
|
+
};
|
|
44
|
+
exports.generateTestWithCodegenTool = generateTestWithCodegenTool;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { OpenAI } from "openai";
|
|
2
|
+
export declare const schema: OpenAI.Chat.Completions.ChatCompletionTool;
|
|
3
|
+
export declare const runTestTool: ({ testName, fileName, }: {
|
|
4
|
+
testName: string;
|
|
5
|
+
fileName: string;
|
|
6
|
+
}) => Promise<{
|
|
7
|
+
hasTestPassed: boolean;
|
|
8
|
+
summaryJson: any;
|
|
9
|
+
}>;
|
|
10
|
+
//# sourceMappingURL=test-run.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-run.d.ts","sourceRoot":"","sources":["../../src/tools/test-run.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,eAAO,MAAM,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,kBAqB5C,CAAC;AAEF,eAAO,MAAM,WAAW;cAIZ,MAAM;cACN,MAAM;;;;EASjB,CAAC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.runTestTool = exports.schema = void 0;
|
|
4
|
+
const test_run_1 = require("@empiricalrun/test-run");
|
|
5
|
+
exports.schema = {
|
|
6
|
+
type: "function",
|
|
7
|
+
function: {
|
|
8
|
+
name: "runTest",
|
|
9
|
+
description: "Run a test",
|
|
10
|
+
parameters: {
|
|
11
|
+
type: "object",
|
|
12
|
+
properties: {
|
|
13
|
+
testName: {
|
|
14
|
+
type: "string",
|
|
15
|
+
description: "The name of the test to run",
|
|
16
|
+
},
|
|
17
|
+
fileName: {
|
|
18
|
+
type: "string",
|
|
19
|
+
description: "The name of the file where the test is located. File name must end with .spec.ts",
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
required: ["testName", "fileName"],
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
const runTestTool = async ({ testName, fileName, }) => {
|
|
27
|
+
// TODO: Remove this hardcoded project name
|
|
28
|
+
const result = await (0, test_run_1.runSingleTest)({
|
|
29
|
+
testName,
|
|
30
|
+
fileName,
|
|
31
|
+
projects: ["chromium"],
|
|
32
|
+
});
|
|
33
|
+
return result;
|
|
34
|
+
};
|
|
35
|
+
exports.runTestTool = runTestTool;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../../src/utils/git.ts"],"names":[],"mappings":"AAEA,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAKnD"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getGitDiff = void 0;
|
|
4
|
+
const child_process_1 = require("child_process");
|
|
5
|
+
function getGitDiff(filepath) {
|
|
6
|
+
const diff = (0, child_process_1.execSync)(`git diff ${filepath}`, {
|
|
7
|
+
encoding: "utf-8",
|
|
8
|
+
});
|
|
9
|
+
return diff;
|
|
10
|
+
}
|
|
11
|
+
exports.getGitDiff = getGitDiff;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@empiricalrun/test-gen",
|
|
3
|
-
"version": "0.47.
|
|
3
|
+
"version": "0.47.4",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"registry": "https://registry.npmjs.org/",
|
|
6
6
|
"access": "public"
|
|
@@ -75,7 +75,8 @@
|
|
|
75
75
|
"typescript": "^5.3.3",
|
|
76
76
|
"@empiricalrun/llm": "^0.9.36",
|
|
77
77
|
"@empiricalrun/r2-uploader": "^0.3.8",
|
|
78
|
-
"@empiricalrun/reporter": "^0.23.1"
|
|
78
|
+
"@empiricalrun/reporter": "^0.23.1",
|
|
79
|
+
"@empiricalrun/test-run": "^0.7.1"
|
|
79
80
|
},
|
|
80
81
|
"devDependencies": {
|
|
81
82
|
"@playwright/test": "1.47.1",
|
package/dist/agent/utils.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/agent/utils.ts"],"names":[],"mappings":"AAAA,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,OAMrC"}
|
package/dist/agent/utils.js
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.parseJson = void 0;
|
|
4
|
-
function parseJson(args) {
|
|
5
|
-
try {
|
|
6
|
-
return JSON.parse(args);
|
|
7
|
-
}
|
|
8
|
-
catch (e) {
|
|
9
|
-
console.error(`Failed to parse JSON with args ${args}`, e);
|
|
10
|
-
}
|
|
11
|
-
}
|
|
12
|
-
exports.parseJson = parseJson;
|