@empiricalrun/test-gen 0.48.1 → 0.50.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +19 -0
- package/dist/agent/chat.d.ts.map +1 -1
- package/dist/agent/chat.js +16 -3
- package/dist/tools/browser-agent.d.ts.map +1 -1
- package/dist/tools/browser-agent.js +21 -43
- package/dist/tools/codegen-agent.d.ts.map +1 -1
- package/dist/tools/codegen-agent.js +14 -30
- package/dist/tools/diagnosis-fetcher.d.ts.map +1 -1
- package/dist/tools/diagnosis-fetcher.js +18 -23
- package/dist/tools/grep.d.ts +3 -0
- package/dist/tools/grep.d.ts.map +1 -0
- package/dist/tools/grep.js +62 -0
- package/dist/tools/test-run-fetcher.d.ts +3 -0
- package/dist/tools/test-run-fetcher.d.ts.map +1 -0
- package/dist/tools/test-run-fetcher.js +59 -0
- package/dist/tools/test-run.d.ts.map +1 -1
- package/dist/tools/test-run.js +21 -29
- package/dist/tools/types.d.ts +36 -9
- package/dist/tools/types.d.ts.map +1 -1
- package/dist/tools/types.js +10 -0
- package/dist/tools/zod-schema.d.ts +19 -0
- package/dist/tools/zod-schema.d.ts.map +1 -0
- package/dist/tools/zod-schema.js +95 -0
- package/dist/utils/repo-tree.d.ts +1 -0
- package/dist/utils/repo-tree.d.ts.map +1 -1
- package/dist/utils/repo-tree.js +3 -3
- package/package.json +3 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# @empiricalrun/test-gen
|
|
2
2
|
|
|
3
|
+
## 0.50.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 0eeff70: feat: add test-run-fetcher tool call, response body changes
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- b14d5bf: feat: support headed executions of test run tool
|
|
12
|
+
- Updated dependencies [b14d5bf]
|
|
13
|
+
- @empiricalrun/test-run@0.7.3
|
|
14
|
+
|
|
15
|
+
## 0.49.0
|
|
16
|
+
|
|
17
|
+
### Minor Changes
|
|
18
|
+
|
|
19
|
+
- 3d050ec: feat: Add grep tool for case-insensitive code search
|
|
20
|
+
- ec8f23b: feat: Convert agent tools to use Zod schemas
|
|
21
|
+
|
|
3
22
|
## 0.48.1
|
|
4
23
|
|
|
5
24
|
### Patch Changes
|
package/dist/agent/chat.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chat.d.ts","sourceRoot":"","sources":["../../src/agent/chat.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"chat.d.ts","sourceRoot":"","sources":["../../src/agent/chat.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAwE1D,wBAAsB,SAAS,CAAC,EAC9B,MAAM,GACP,EAAE;IACD,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,WAAW,CAAC;CACrB,8CAqEA"}
|
package/dist/agent/chat.js
CHANGED
|
@@ -9,7 +9,10 @@ const path_1 = __importDefault(require("path"));
|
|
|
9
9
|
const human_in_the_loop_1 = require("../human-in-the-loop");
|
|
10
10
|
const browser_agent_1 = require("../tools/browser-agent");
|
|
11
11
|
const diagnosis_fetcher_1 = require("../tools/diagnosis-fetcher");
|
|
12
|
+
const grep_1 = require("../tools/grep");
|
|
12
13
|
const test_run_1 = require("../tools/test-run");
|
|
14
|
+
const test_run_fetcher_1 = require("../tools/test-run-fetcher");
|
|
15
|
+
const zod_schema_1 = require("../tools/zod-schema");
|
|
13
16
|
const repo_tree_1 = require("../utils/repo-tree");
|
|
14
17
|
const systemPrompt = `
|
|
15
18
|
You are a helpful assistant that can answer questions and help with tasks.
|
|
@@ -23,6 +26,9 @@ Summarize the results in a few sentences.
|
|
|
23
26
|
If the user provides a diagnosis URL, you can use the fetchDiagnosisDetails tool
|
|
24
27
|
to get more information about the test case and its results.
|
|
25
28
|
|
|
29
|
+
If the user provides a test run URL, you can use the fetchTestRunDetails tool
|
|
30
|
+
to get detailed information about a specific test run.
|
|
31
|
+
|
|
26
32
|
Or if the user asks you to modify a test, you could use the generateTestWithBrowserAgent tool. If you suspect
|
|
27
33
|
that a UI selector needs to be updated, using the browser agent is a good idea.
|
|
28
34
|
|
|
@@ -38,6 +44,7 @@ The position of the comment is important: the browser agent will look for this c
|
|
|
38
44
|
the actual code to click on the login button. If you are fixing a failing test, your comment should be
|
|
39
45
|
around the failing line of code, so that it can be replaced/modified.
|
|
40
46
|
|
|
47
|
+
# Repo context
|
|
41
48
|
You are running as a CLI tool inside the directory of the repo where this test file is located. Here is
|
|
42
49
|
the repo directory structure:
|
|
43
50
|
|
|
@@ -47,9 +54,15 @@ While specifying paths to files, use relative paths from the current working dir
|
|
|
47
54
|
- Correct path: "tests/lesson.spec.ts"
|
|
48
55
|
- Incorrect path: "/repo/tests/lesson.spec.ts" or "${path_1.default.basename(process.cwd())}/tests/lesson.spec.ts"
|
|
49
56
|
`;
|
|
50
|
-
const tools = [
|
|
57
|
+
const tools = [
|
|
58
|
+
test_run_1.runTestTool,
|
|
59
|
+
browser_agent_1.browserAgentTool,
|
|
60
|
+
diagnosis_fetcher_1.diagnosisTool,
|
|
61
|
+
grep_1.grepTool,
|
|
62
|
+
test_run_fetcher_1.testRunTool,
|
|
63
|
+
];
|
|
51
64
|
const toolExecutors = {
|
|
52
|
-
...Object.fromEntries(tools.map((tool) => [tool.schema.
|
|
65
|
+
...Object.fromEntries(tools.map((tool) => [tool.schema.name, tool.execute])),
|
|
53
66
|
str_replace_editor: claude_1.strReplaceEditorTool,
|
|
54
67
|
};
|
|
55
68
|
async function chatAgent({ prompt, }) {
|
|
@@ -84,7 +97,7 @@ async function chatAgent({ prompt, }) {
|
|
|
84
97
|
continue;
|
|
85
98
|
}
|
|
86
99
|
const response = await (0, claude_1.createChatCompletion)(systemPrompt, chatState.getMessages(), [
|
|
87
|
-
...tools.map((tool) => (0, claude_1.convertOpenAISchemaToAnthropic)(tool.schema)),
|
|
100
|
+
...tools.map((tool) => (0, claude_1.convertOpenAISchemaToAnthropic)((0, zod_schema_1.zodToOpenAITool)(tool.schema))),
|
|
88
101
|
{
|
|
89
102
|
type: "text_editor_20250124",
|
|
90
103
|
name: "str_replace_editor",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"browser-agent.d.ts","sourceRoot":"","sources":["../../src/tools/browser-agent.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"browser-agent.d.ts","sourceRoot":"","sources":["../../src/tools/browser-agent.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAmDpC,eAAO,MAAM,gBAAgB,EAAE,IA6C9B,CAAC"}
|
|
@@ -1,16 +1,25 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.browserAgentTool = void 0;
|
|
4
|
+
const zod_1 = require("zod");
|
|
4
5
|
const run_1 = require("../agent/browsing/run");
|
|
5
6
|
const utils_1 = require("../agent/browsing/utils");
|
|
6
7
|
const scenarios_1 = require("../bin/utils/scenarios");
|
|
7
8
|
const git_1 = require("../utils/git");
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
9
|
+
const BrowserAgentSchema = zod_1.z.object({
|
|
10
|
+
testName: zod_1.z.string().describe("The name of the test to create or modify"),
|
|
11
|
+
testSuites: zod_1.z
|
|
12
|
+
.array(zod_1.z.string())
|
|
13
|
+
.describe("The suites (describe blocks) where the test is located"),
|
|
14
|
+
fileName: zod_1.z
|
|
15
|
+
.string()
|
|
16
|
+
.describe("The name of the file where the test is located. File name must end with .spec.ts"),
|
|
17
|
+
project: zod_1.z
|
|
18
|
+
.string()
|
|
19
|
+
.describe("The Playwright project to run tests against (e.g. 'chromium' or 'firefox')"),
|
|
20
|
+
changeToMake: zod_1.z.string().describe("The change to make to the test"),
|
|
21
|
+
});
|
|
22
|
+
const BROWSER_AGENT_DESCRIPTION = `
|
|
14
23
|
Create or modify a test case with browser agent. The browser agent can take user interactions in a web browser
|
|
15
24
|
and generate Playwright code for that actions. This is a useful tool when the modifications require knowing the
|
|
16
25
|
locator/selector for an element on the page.
|
|
@@ -39,43 +48,12 @@ test("Example test code", async ({ page }) => {
|
|
|
39
48
|
await page.getByRole("button", { name: "Login" }).click();
|
|
40
49
|
});
|
|
41
50
|
\`\`\`
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
description: "The name of the test to create or modify",
|
|
49
|
-
},
|
|
50
|
-
testSuites: {
|
|
51
|
-
type: "array",
|
|
52
|
-
description: "The suites (describe blocks) where the test is located",
|
|
53
|
-
items: {
|
|
54
|
-
type: "string",
|
|
55
|
-
},
|
|
56
|
-
},
|
|
57
|
-
fileName: {
|
|
58
|
-
type: "string",
|
|
59
|
-
description: "The name of the file where the test is located. File name must end with .spec.ts",
|
|
60
|
-
},
|
|
61
|
-
project: {
|
|
62
|
-
type: "string",
|
|
63
|
-
description: "The Playwright project to run tests against (e.g. 'chromium' or 'firefox')",
|
|
64
|
-
},
|
|
65
|
-
changeToMake: {
|
|
66
|
-
type: "string",
|
|
67
|
-
description: "The change to make to the test",
|
|
68
|
-
},
|
|
69
|
-
},
|
|
70
|
-
required: [
|
|
71
|
-
"testName",
|
|
72
|
-
"testSuites",
|
|
73
|
-
"fileName",
|
|
74
|
-
"changeToMake",
|
|
75
|
-
"project",
|
|
76
|
-
],
|
|
77
|
-
},
|
|
78
|
-
},
|
|
51
|
+
`;
|
|
52
|
+
exports.browserAgentTool = {
|
|
53
|
+
schema: {
|
|
54
|
+
name: "generateTestWithBrowserAgent",
|
|
55
|
+
description: BROWSER_AGENT_DESCRIPTION,
|
|
56
|
+
parameters: BrowserAgentSchema,
|
|
79
57
|
},
|
|
80
58
|
execute: async (input) => {
|
|
81
59
|
const { testName, testSuites, fileName, changeToMake, project } = input;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"codegen-agent.d.ts","sourceRoot":"","sources":["../../src/tools/codegen-agent.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"codegen-agent.d.ts","sourceRoot":"","sources":["../../src/tools/codegen-agent.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAepC,eAAO,MAAM,WAAW,EAAE,IAyBzB,CAAC"}
|
|
@@ -1,39 +1,23 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.codegenTool = void 0;
|
|
4
|
+
const zod_1 = require("zod");
|
|
4
5
|
const run_1 = require("../agent/codegen/run");
|
|
6
|
+
const CodegenSchema = zod_1.z.object({
|
|
7
|
+
testName: zod_1.z.string().describe("The name of the test to create or modify"),
|
|
8
|
+
testSuites: zod_1.z
|
|
9
|
+
.array(zod_1.z.string())
|
|
10
|
+
.describe("The suites (describe blocks) where the test is located"),
|
|
11
|
+
fileName: zod_1.z
|
|
12
|
+
.string()
|
|
13
|
+
.describe("The name of the file where the test is located. File name must end with .spec.ts"),
|
|
14
|
+
changeToMake: zod_1.z.string().describe("The change to make to the test"),
|
|
15
|
+
});
|
|
5
16
|
exports.codegenTool = {
|
|
6
17
|
schema: {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
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.",
|
|
11
|
-
parameters: {
|
|
12
|
-
type: "object",
|
|
13
|
-
properties: {
|
|
14
|
-
testName: {
|
|
15
|
-
type: "string",
|
|
16
|
-
description: "The name of the test to create or modify",
|
|
17
|
-
},
|
|
18
|
-
testSuites: {
|
|
19
|
-
type: "array",
|
|
20
|
-
description: "The suites (describe blocks) where the test is located",
|
|
21
|
-
items: {
|
|
22
|
-
type: "string",
|
|
23
|
-
},
|
|
24
|
-
},
|
|
25
|
-
fileName: {
|
|
26
|
-
type: "string",
|
|
27
|
-
description: "The name of the file where the test is located. File name must end with .spec.ts",
|
|
28
|
-
},
|
|
29
|
-
changeToMake: {
|
|
30
|
-
type: "string",
|
|
31
|
-
description: "The change to make to the test",
|
|
32
|
-
},
|
|
33
|
-
},
|
|
34
|
-
required: ["testName", "testSuites", "fileName", "changeToMake"],
|
|
35
|
-
},
|
|
36
|
-
},
|
|
18
|
+
name: "generateTestWithCodegen",
|
|
19
|
+
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.",
|
|
20
|
+
parameters: CodegenSchema,
|
|
37
21
|
},
|
|
38
22
|
execute: async (input) => {
|
|
39
23
|
const { testName, testSuites, fileName, changeToMake } = input;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"diagnosis-fetcher.d.ts","sourceRoot":"","sources":["../../src/tools/diagnosis-fetcher.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"diagnosis-fetcher.d.ts","sourceRoot":"","sources":["../../src/tools/diagnosis-fetcher.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAUpC,eAAO,MAAM,aAAa,EAAE,IAgF3B,CAAC"}
|
|
@@ -6,23 +6,17 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.diagnosisTool = void 0;
|
|
7
7
|
const promises_1 = __importDefault(require("fs/promises"));
|
|
8
8
|
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const zod_1 = require("zod");
|
|
10
|
+
const DiagnosisSchema = zod_1.z.object({
|
|
11
|
+
diagnosisUrl: zod_1.z
|
|
12
|
+
.string()
|
|
13
|
+
.describe("The full URL of the diagnosis (e.g. https://dash.empirical.run/shopflo-tests/diagnosis/split-cod-place-the-order--byynrPjCml57)"),
|
|
14
|
+
});
|
|
9
15
|
exports.diagnosisTool = {
|
|
10
16
|
schema: {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
description: "Fetch details about a test case diagnosis using its URL or slug",
|
|
15
|
-
parameters: {
|
|
16
|
-
type: "object",
|
|
17
|
-
properties: {
|
|
18
|
-
diagnosisUrl: {
|
|
19
|
-
type: "string",
|
|
20
|
-
description: "The full URL of the diagnosis (e.g. https://dash.empirical.run/shopflo-tests/diagnosis/split-cod-place-the-order--byynrPjCml57)",
|
|
21
|
-
},
|
|
22
|
-
},
|
|
23
|
-
required: ["diagnosisUrl"],
|
|
24
|
-
},
|
|
25
|
-
},
|
|
17
|
+
name: "fetchDiagnosisDetails",
|
|
18
|
+
description: "Fetch details about a test case diagnosis using its URL or slug",
|
|
19
|
+
parameters: DiagnosisSchema,
|
|
26
20
|
},
|
|
27
21
|
execute: async (input) => {
|
|
28
22
|
const { diagnosisUrl } = input;
|
|
@@ -31,11 +25,10 @@ exports.diagnosisTool = {
|
|
|
31
25
|
if (!slug) {
|
|
32
26
|
throw new Error("Invalid diagnosis URL - could not extract slug");
|
|
33
27
|
}
|
|
34
|
-
// Make the API call to fetch diagnosis details
|
|
35
28
|
const response = await fetch(`https://dash.empirical.run/api/diagnosis/${slug}/detailed`, {
|
|
36
29
|
method: "GET",
|
|
37
30
|
headers: {
|
|
38
|
-
Authorization: "weQPMWKT",
|
|
31
|
+
Authorization: "weQPMWKT",
|
|
39
32
|
},
|
|
40
33
|
});
|
|
41
34
|
if (!response.ok) {
|
|
@@ -46,8 +39,10 @@ exports.diagnosisTool = {
|
|
|
46
39
|
}
|
|
47
40
|
const data = await response.json();
|
|
48
41
|
const { test_case, diagnosis } = data.data;
|
|
49
|
-
const project = diagnosis
|
|
42
|
+
const project = diagnosis?.test_project || "unknown";
|
|
50
43
|
const sourceContext = await promises_1.default.readFile(path_1.default.join("tests", test_case.file_path), "utf-8");
|
|
44
|
+
const repoName = path_1.default.basename(process.cwd());
|
|
45
|
+
const cleanErrorStack = diagnosis?.failed_run_metadata?.stack?.replace(`"/runner/_work/${repoName}/${repoName}/source-repo/"`, "");
|
|
51
46
|
// Format the response as markdown
|
|
52
47
|
const markdownResponse = `
|
|
53
48
|
# Test Case Diagnosis
|
|
@@ -64,21 +59,21 @@ ${sourceContext}
|
|
|
64
59
|
## What Happened in the Test Run
|
|
65
60
|
|
|
66
61
|
### Failure Details
|
|
67
|
-
- **Failing Line**: ${diagnosis
|
|
62
|
+
- **Failing Line**: ${diagnosis?.failing_line || "No failing line available"}
|
|
68
63
|
|
|
69
64
|
#### Error Stack
|
|
70
65
|
\`\`\`
|
|
71
|
-
${
|
|
66
|
+
${cleanErrorStack || "No error stack available"}
|
|
72
67
|
\`\`\`
|
|
73
68
|
|
|
74
69
|
#### Error Summary
|
|
75
|
-
${diagnosis
|
|
70
|
+
${diagnosis?.error_stack_summary?.content || "No error summary available"}
|
|
76
71
|
|
|
77
72
|
#### Visual Analysis
|
|
78
|
-
${diagnosis
|
|
73
|
+
${diagnosis?.visual_diff_summary?.summary || "No visual analysis available"}
|
|
79
74
|
|
|
80
75
|
#### Merged Summary
|
|
81
|
-
${diagnosis
|
|
76
|
+
${diagnosis?.merged_summary?.content || "No merged summary available"}
|
|
82
77
|
`;
|
|
83
78
|
return {
|
|
84
79
|
result: markdownResponse,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grep.d.ts","sourceRoot":"","sources":["../../src/tools/grep.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,IAAI,EAAc,MAAM,SAAS,CAAC;AAgB3C,eAAO,MAAM,QAAQ,EAAE,IA+CtB,CAAC"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.grepTool = void 0;
|
|
4
|
+
const child_process_1 = require("child_process");
|
|
5
|
+
const util_1 = require("util");
|
|
6
|
+
const zod_1 = require("zod");
|
|
7
|
+
const repo_tree_1 = require("../utils/repo-tree");
|
|
8
|
+
const execAsync = (0, util_1.promisify)(child_process_1.exec);
|
|
9
|
+
const GrepInputSchema = zod_1.z.object({
|
|
10
|
+
pattern: zod_1.z.string().describe("The pattern to search for"),
|
|
11
|
+
directory: zod_1.z
|
|
12
|
+
.string()
|
|
13
|
+
.optional()
|
|
14
|
+
.describe("The directory to search in (defaults to current directory)"),
|
|
15
|
+
filePattern: zod_1.z
|
|
16
|
+
.string()
|
|
17
|
+
.optional()
|
|
18
|
+
.describe("File pattern to search in (e.g., '*.ts' for TypeScript files)"),
|
|
19
|
+
});
|
|
20
|
+
exports.grepTool = {
|
|
21
|
+
schema: {
|
|
22
|
+
name: "grep",
|
|
23
|
+
description: "Search for a pattern in files using grep (case insensitive)",
|
|
24
|
+
parameters: GrepInputSchema,
|
|
25
|
+
},
|
|
26
|
+
execute: async (input) => {
|
|
27
|
+
try {
|
|
28
|
+
const dir = input.directory || process.cwd();
|
|
29
|
+
// Create exclude pattern for grep
|
|
30
|
+
const excludePatterns = repo_tree_1.DEFAULT_EXCLUDE.map((pattern) => typeof pattern === "string" ? pattern : pattern.source)
|
|
31
|
+
.map((pattern) => `--exclude-dir="${pattern}"`)
|
|
32
|
+
.join(" ");
|
|
33
|
+
// Using -n to show line numbers in output
|
|
34
|
+
let cmd = `grep -rin ${excludePatterns} "${input.pattern}" ${dir}`;
|
|
35
|
+
if (input.filePattern) {
|
|
36
|
+
// For file pattern searches, we'll use find with exclusions
|
|
37
|
+
const excludeFind = repo_tree_1.DEFAULT_EXCLUDE.map((pattern) => typeof pattern === "string" ? pattern : pattern.source)
|
|
38
|
+
.map((pattern) => `-not -path "*/${pattern}/*"`)
|
|
39
|
+
.join(" ");
|
|
40
|
+
// Using -n to show line numbers and removed -l to show actual matches
|
|
41
|
+
cmd = `find ${dir} ${excludeFind} -name "${input.filePattern}" -exec grep -rin "${input.pattern}" {} \\;`;
|
|
42
|
+
}
|
|
43
|
+
const { stdout, stderr } = await execAsync(cmd);
|
|
44
|
+
if (stderr) {
|
|
45
|
+
return {
|
|
46
|
+
isError: true,
|
|
47
|
+
result: stderr,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
return {
|
|
51
|
+
isError: false,
|
|
52
|
+
result: stdout,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
return {
|
|
57
|
+
isError: true,
|
|
58
|
+
result: error instanceof Error ? error.message : String(error),
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-run-fetcher.d.ts","sourceRoot":"","sources":["../../src/tools/test-run-fetcher.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAUpC,eAAO,MAAM,WAAW,EAAE,IA0DzB,CAAC"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.testRunTool = void 0;
|
|
4
|
+
const zod_1 = require("zod");
|
|
5
|
+
const TestRunSchema = zod_1.z.object({
|
|
6
|
+
testRunUrl: zod_1.z
|
|
7
|
+
.string()
|
|
8
|
+
.describe("The full URL of the test run (e.g. https://dash.empirical.run/sortment-tests/test-runs/20269 or with query params like ?status=failed)"),
|
|
9
|
+
});
|
|
10
|
+
exports.testRunTool = {
|
|
11
|
+
schema: {
|
|
12
|
+
name: "fetchTestRunDetails",
|
|
13
|
+
description: "Fetch details about a test run using its URL",
|
|
14
|
+
parameters: TestRunSchema,
|
|
15
|
+
},
|
|
16
|
+
execute: async (input) => {
|
|
17
|
+
const { testRunUrl } = input;
|
|
18
|
+
// Remove query parameters if they exist
|
|
19
|
+
const urlWithoutParams = testRunUrl.split("?")[0] || testRunUrl;
|
|
20
|
+
// Extract the run ID and repo name from the URL
|
|
21
|
+
const urlParts = urlWithoutParams.split("/");
|
|
22
|
+
const runId = urlParts.pop(); // Last part is the run ID
|
|
23
|
+
const repoName = urlParts[urlParts.length - 2]; // Second to last part is the repo name
|
|
24
|
+
if (!runId || !repoName) {
|
|
25
|
+
throw new Error("Invalid test run URL - could not extract run ID or repo name");
|
|
26
|
+
}
|
|
27
|
+
// Make the API call to fetch test run details
|
|
28
|
+
const response = await fetch(`https://dash.empirical.run/api/test-runs/${runId}?repo_name=${repoName}`, {
|
|
29
|
+
method: "GET",
|
|
30
|
+
headers: {
|
|
31
|
+
Authorization: "weQPMWKT",
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
if (!response.ok) {
|
|
35
|
+
return {
|
|
36
|
+
result: `Failed to fetch test run details: ${response.statusText}`,
|
|
37
|
+
isError: true,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
const data = await response.json();
|
|
41
|
+
// Format the response as markdown
|
|
42
|
+
const markdownResponse = `
|
|
43
|
+
# Test Run Details
|
|
44
|
+
|
|
45
|
+
## Run Information
|
|
46
|
+
- **Run ID**: ${runId}
|
|
47
|
+
- **Repository**: ${repoName}
|
|
48
|
+
|
|
49
|
+
## Test Run Data
|
|
50
|
+
\`\`\`json
|
|
51
|
+
${JSON.stringify(data, null, 2)}
|
|
52
|
+
\`\`\`
|
|
53
|
+
`;
|
|
54
|
+
return {
|
|
55
|
+
result: markdownResponse,
|
|
56
|
+
isError: false,
|
|
57
|
+
};
|
|
58
|
+
},
|
|
59
|
+
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"test-run.d.ts","sourceRoot":"","sources":["../../src/tools/test-run.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"test-run.d.ts","sourceRoot":"","sources":["../../src/tools/test-run.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAsBpC,eAAO,MAAM,WAAW,EAAE,IAoBzB,CAAC"}
|
package/dist/tools/test-run.js
CHANGED
|
@@ -2,44 +2,36 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.runTestTool = void 0;
|
|
4
4
|
const test_run_1 = require("@empiricalrun/test-run");
|
|
5
|
+
const zod_1 = require("zod");
|
|
6
|
+
const RunTestSchema = zod_1.z.object({
|
|
7
|
+
testName: zod_1.z.string().describe("The name of the test to run"),
|
|
8
|
+
suites: zod_1.z
|
|
9
|
+
.array(zod_1.z.string())
|
|
10
|
+
.describe("The suites (describe blocks) where the test is located."),
|
|
11
|
+
fileName: zod_1.z
|
|
12
|
+
.string()
|
|
13
|
+
.describe("The name of the file where the test is located. File name must end with .spec.ts"),
|
|
14
|
+
project: zod_1.z.string().describe("The project to run the test on"),
|
|
15
|
+
headed: zod_1.z
|
|
16
|
+
.boolean()
|
|
17
|
+
.describe("Whether to run the test in headed mode (default is false, which is headless)")
|
|
18
|
+
.optional()
|
|
19
|
+
.default(false),
|
|
20
|
+
});
|
|
5
21
|
exports.runTestTool = {
|
|
6
22
|
schema: {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
description: "Run a test",
|
|
11
|
-
parameters: {
|
|
12
|
-
type: "object",
|
|
13
|
-
properties: {
|
|
14
|
-
testName: {
|
|
15
|
-
type: "string",
|
|
16
|
-
description: "The name of the test to run",
|
|
17
|
-
},
|
|
18
|
-
suites: {
|
|
19
|
-
type: "array",
|
|
20
|
-
description: "The suites (describe blocks) where the test is located.",
|
|
21
|
-
items: { type: "string" },
|
|
22
|
-
},
|
|
23
|
-
fileName: {
|
|
24
|
-
type: "string",
|
|
25
|
-
description: "The name of the file where the test is located. File name must end with .spec.ts",
|
|
26
|
-
},
|
|
27
|
-
project: {
|
|
28
|
-
type: "string",
|
|
29
|
-
description: "The project to run the test on",
|
|
30
|
-
},
|
|
31
|
-
},
|
|
32
|
-
required: ["testName", "suites", "fileName", "project"],
|
|
33
|
-
},
|
|
34
|
-
},
|
|
23
|
+
name: "runTest",
|
|
24
|
+
description: "Run a test",
|
|
25
|
+
parameters: RunTestSchema,
|
|
35
26
|
},
|
|
36
27
|
execute: async (input) => {
|
|
37
|
-
const { testName, suites, fileName, project } = input;
|
|
28
|
+
const { testName, suites, fileName, project, headed } = input;
|
|
38
29
|
const result = await (0, test_run_1.runSingleTest)({
|
|
39
30
|
testName,
|
|
40
31
|
suites,
|
|
41
32
|
fileName,
|
|
42
33
|
projects: [project],
|
|
34
|
+
headed,
|
|
43
35
|
});
|
|
44
36
|
return {
|
|
45
37
|
result: JSON.stringify(result),
|
package/dist/tools/types.d.ts
CHANGED
|
@@ -1,11 +1,38 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* Base schema for all tools. Each tool should extend this with their specific parameters.
|
|
4
|
+
*/
|
|
5
|
+
export declare const BaseToolSchema: z.ZodObject<{
|
|
6
|
+
name: z.ZodString;
|
|
7
|
+
description: z.ZodString;
|
|
8
|
+
parameters: z.ZodObject<{}, "passthrough", z.ZodTypeAny, z.objectOutputType<{}, z.ZodTypeAny, "passthrough">, z.objectInputType<{}, z.ZodTypeAny, "passthrough">>;
|
|
9
|
+
}, "strip", z.ZodTypeAny, {
|
|
10
|
+
name: string;
|
|
11
|
+
description: string;
|
|
12
|
+
parameters: {} & {
|
|
13
|
+
[k: string]: unknown;
|
|
14
|
+
};
|
|
15
|
+
}, {
|
|
16
|
+
name: string;
|
|
17
|
+
description: string;
|
|
18
|
+
parameters: {} & {
|
|
19
|
+
[k: string]: unknown;
|
|
20
|
+
};
|
|
21
|
+
}>;
|
|
22
|
+
export type ToolSchema = z.infer<typeof BaseToolSchema>;
|
|
23
|
+
/**
|
|
24
|
+
* Interface for creating a tool with its schema and execute function
|
|
25
|
+
*/
|
|
26
|
+
export interface Tool {
|
|
27
|
+
schema: {
|
|
28
|
+
name: string;
|
|
29
|
+
description: string;
|
|
30
|
+
parameters: z.ZodType;
|
|
31
|
+
};
|
|
9
32
|
execute: (input: any) => Promise<ToolResult>;
|
|
10
|
-
}
|
|
33
|
+
}
|
|
34
|
+
export interface ToolResult {
|
|
35
|
+
isError: boolean;
|
|
36
|
+
result: string;
|
|
37
|
+
}
|
|
11
38
|
//# sourceMappingURL=types.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/tools/types.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/tools/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;GAEG;AACH,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;EAIzB,CAAC;AAEH,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAExD;;GAEG;AACH,MAAM,WAAW,IAAI;IACnB,MAAM,EAAE;QACN,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,EAAE,MAAM,CAAC;QACpB,UAAU,EAAE,CAAC,CAAC,OAAO,CAAC;KACvB,CAAC;IACF,OAAO,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC;CAC9C;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;CAChB"}
|
package/dist/tools/types.js
CHANGED
|
@@ -1,2 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BaseToolSchema = void 0;
|
|
4
|
+
const zod_1 = require("zod");
|
|
5
|
+
/**
|
|
6
|
+
* Base schema for all tools. Each tool should extend this with their specific parameters.
|
|
7
|
+
*/
|
|
8
|
+
exports.BaseToolSchema = zod_1.z.object({
|
|
9
|
+
name: zod_1.z.string(),
|
|
10
|
+
description: zod_1.z.string(),
|
|
11
|
+
parameters: zod_1.z.object({}).passthrough(),
|
|
12
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type OpenAI from "openai";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
/**
|
|
4
|
+
* Convert a tool schema to OpenAI tool format
|
|
5
|
+
*/
|
|
6
|
+
export declare function zodToOpenAITool(schema: {
|
|
7
|
+
name: string;
|
|
8
|
+
description: string;
|
|
9
|
+
parameters: z.ZodType;
|
|
10
|
+
}): OpenAI.Chat.Completions.ChatCompletionTool;
|
|
11
|
+
/**
|
|
12
|
+
* Convert Zod schema to JSON Schema
|
|
13
|
+
*/
|
|
14
|
+
export declare function zodToJsonSchema(schema: z.ZodType): any;
|
|
15
|
+
/**
|
|
16
|
+
* Convert specific Zod type to JSON Schema
|
|
17
|
+
*/
|
|
18
|
+
export declare function zodTypeToJsonSchema(zodType: z.ZodType): any;
|
|
19
|
+
//# sourceMappingURL=zod-schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"zod-schema.d.ts","sourceRoot":"","sources":["../../src/tools/zod-schema.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,QAAQ,CAAC;AACjC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,CAAC,CAAC,OAAO,CAAC;CACvB,GAAG,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,kBAAkB,CAS7C;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,GAAG,GAAG,CAuBtD;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,CAAC,CAAC,OAAO,GAAG,GAAG,CAoD3D"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.zodTypeToJsonSchema = exports.zodToJsonSchema = exports.zodToOpenAITool = void 0;
|
|
4
|
+
const zod_1 = require("zod");
|
|
5
|
+
/**
|
|
6
|
+
* Convert a tool schema to OpenAI tool format
|
|
7
|
+
*/
|
|
8
|
+
function zodToOpenAITool(schema) {
|
|
9
|
+
return {
|
|
10
|
+
type: "function",
|
|
11
|
+
function: {
|
|
12
|
+
name: schema.name,
|
|
13
|
+
description: schema.description,
|
|
14
|
+
parameters: zodToJsonSchema(schema.parameters),
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
exports.zodToOpenAITool = zodToOpenAITool;
|
|
19
|
+
/**
|
|
20
|
+
* Convert Zod schema to JSON Schema
|
|
21
|
+
*/
|
|
22
|
+
function zodToJsonSchema(schema) {
|
|
23
|
+
if (schema instanceof zod_1.z.ZodObject) {
|
|
24
|
+
const shape = schema._def.shape();
|
|
25
|
+
const properties = {};
|
|
26
|
+
const required = [];
|
|
27
|
+
Object.entries(shape).forEach(([key, value]) => {
|
|
28
|
+
properties[key] = zodTypeToJsonSchema(value);
|
|
29
|
+
// Check if this field is required
|
|
30
|
+
if (!(value instanceof zod_1.z.ZodOptional)) {
|
|
31
|
+
required.push(key);
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
return {
|
|
35
|
+
type: "object",
|
|
36
|
+
properties,
|
|
37
|
+
...(required.length > 0 ? { required } : {}),
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
return { type: "string" }; // Fallback
|
|
41
|
+
}
|
|
42
|
+
exports.zodToJsonSchema = zodToJsonSchema;
|
|
43
|
+
/**
|
|
44
|
+
* Convert specific Zod type to JSON Schema
|
|
45
|
+
*/
|
|
46
|
+
function zodTypeToJsonSchema(zodType) {
|
|
47
|
+
// Handle string types
|
|
48
|
+
if (zodType instanceof zod_1.z.ZodString) {
|
|
49
|
+
const schema = { type: "string" };
|
|
50
|
+
if (zodType.description)
|
|
51
|
+
schema.description = zodType.description;
|
|
52
|
+
return schema;
|
|
53
|
+
}
|
|
54
|
+
// Handle number types
|
|
55
|
+
if (zodType instanceof zod_1.z.ZodNumber) {
|
|
56
|
+
const schema = { type: "number" };
|
|
57
|
+
if (zodType.description)
|
|
58
|
+
schema.description = zodType.description;
|
|
59
|
+
return schema;
|
|
60
|
+
}
|
|
61
|
+
// Handle boolean
|
|
62
|
+
if (zodType instanceof zod_1.z.ZodBoolean) {
|
|
63
|
+
const schema = { type: "boolean" };
|
|
64
|
+
if (zodType.description)
|
|
65
|
+
schema.description = zodType.description;
|
|
66
|
+
return schema;
|
|
67
|
+
}
|
|
68
|
+
// Handle arrays
|
|
69
|
+
if (zodType instanceof zod_1.z.ZodArray) {
|
|
70
|
+
return {
|
|
71
|
+
type: "array",
|
|
72
|
+
items: zodTypeToJsonSchema(zodType._def.type),
|
|
73
|
+
...(zodType.description ? { description: zodType.description } : {}),
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
// Handle objects
|
|
77
|
+
if (zodType instanceof zod_1.z.ZodObject) {
|
|
78
|
+
return zodToJsonSchema(zodType);
|
|
79
|
+
}
|
|
80
|
+
// Handle enums
|
|
81
|
+
if (zodType instanceof zod_1.z.ZodEnum) {
|
|
82
|
+
return {
|
|
83
|
+
type: "string",
|
|
84
|
+
enum: zodType._def.values,
|
|
85
|
+
...(zodType.description ? { description: zodType.description } : {}),
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
// Handle optional types
|
|
89
|
+
if (zodType instanceof zod_1.z.ZodOptional) {
|
|
90
|
+
return zodTypeToJsonSchema(zodType._def.innerType);
|
|
91
|
+
}
|
|
92
|
+
// Default fallback
|
|
93
|
+
return { type: "string" };
|
|
94
|
+
}
|
|
95
|
+
exports.zodTypeToJsonSchema = zodTypeToJsonSchema;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"repo-tree.d.ts","sourceRoot":"","sources":["../../src/utils/repo-tree.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"repo-tree.d.ts","sourceRoot":"","sources":["../../src/utils/repo-tree.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,eAAe,qBAO3B,CAAC;AAEF,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,KAAK,UAsE9D"}
|
package/dist/utils/repo-tree.js
CHANGED
|
@@ -3,10 +3,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.generateAsciiTree = void 0;
|
|
6
|
+
exports.generateAsciiTree = exports.DEFAULT_EXCLUDE = void 0;
|
|
7
7
|
const fs_1 = __importDefault(require("fs"));
|
|
8
8
|
const path_1 = __importDefault(require("path"));
|
|
9
|
-
|
|
9
|
+
exports.DEFAULT_EXCLUDE = [
|
|
10
10
|
"node_modules",
|
|
11
11
|
"dist",
|
|
12
12
|
"build",
|
|
@@ -17,7 +17,7 @@ const DEFAULT_EXCLUDE = [
|
|
|
17
17
|
function generateAsciiTree(dirPath, options = {}) {
|
|
18
18
|
const defaultOptions = {
|
|
19
19
|
showHidden: false,
|
|
20
|
-
exclude: DEFAULT_EXCLUDE,
|
|
20
|
+
exclude: exports.DEFAULT_EXCLUDE,
|
|
21
21
|
maxDepth: 10,
|
|
22
22
|
};
|
|
23
23
|
const opts = { ...defaultOptions, ...options };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@empiricalrun/test-gen",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.50.0",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"registry": "https://registry.npmjs.org/",
|
|
6
6
|
"access": "public"
|
|
@@ -73,10 +73,11 @@
|
|
|
73
73
|
"ts-morph": "^23.0.0",
|
|
74
74
|
"tsx": "^4.16.2",
|
|
75
75
|
"typescript": "^5.3.3",
|
|
76
|
+
"zod": "^3.23.8",
|
|
76
77
|
"@empiricalrun/llm": "^0.10.1",
|
|
77
78
|
"@empiricalrun/r2-uploader": "^0.3.8",
|
|
78
79
|
"@empiricalrun/reporter": "^0.23.1",
|
|
79
|
-
"@empiricalrun/test-run": "^0.7.
|
|
80
|
+
"@empiricalrun/test-run": "^0.7.3"
|
|
80
81
|
},
|
|
81
82
|
"devDependencies": {
|
|
82
83
|
"@playwright/test": "1.47.1",
|