@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 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
@@ -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;AA6D1D,wBAAsB,SAAS,CAAC,EAC9B,MAAM,GACP,EAAE;IACD,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,WAAW,CAAC;CACrB,8CAmEA"}
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"}
@@ -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 = [test_run_1.runTestTool, browser_agent_1.browserAgentTool, diagnosis_fetcher_1.diagnosisTool];
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.function.name, tool.execute])),
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":"AAIA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAUpC,eAAO,MAAM,gBAAgB,EAAE,IAkH9B,CAAC"}
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
- exports.browserAgentTool = {
9
- schema: {
10
- type: "function",
11
- function: {
12
- name: "generateTestWithBrowserAgent",
13
- description: `
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
- parameters: {
44
- type: "object",
45
- properties: {
46
- testName: {
47
- type: "string",
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":"AAGA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AASpC,eAAO,MAAM,WAAW,EAAE,IAsDzB,CAAC"}
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
- type: "function",
8
- function: {
9
- name: "generateTestWithCodegen",
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":"AAGA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAMpC,eAAO,MAAM,aAAa,EAAE,IA4F3B,CAAC"}
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
- type: "function",
12
- function: {
13
- name: "fetchDiagnosisDetails",
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", // Using the auth token from test-endpoint.mdc
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[0]?.test_project || "unknown";
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[0]?.failing_line || "No failing line available"}
62
+ - **Failing Line**: ${diagnosis?.failing_line || "No failing line available"}
68
63
 
69
64
  #### Error Stack
70
65
  \`\`\`
71
- ${diagnosis[0]?.failed_run_metadata?.stack?.replace("/runner/_work/shopflo-tests/shopflo-tests/source-repo/", "") || "No error stack available"}
66
+ ${cleanErrorStack || "No error stack available"}
72
67
  \`\`\`
73
68
 
74
69
  #### Error Summary
75
- ${diagnosis[0]?.error_stack_summary?.content || "No error summary available"}
70
+ ${diagnosis?.error_stack_summary?.content || "No error summary available"}
76
71
 
77
72
  #### Visual Analysis
78
- ${diagnosis[0]?.visual_diff_summary?.summary || "No visual analysis available"}
73
+ ${diagnosis?.visual_diff_summary?.summary || "No visual analysis available"}
79
74
 
80
75
  #### Merged Summary
81
- ${diagnosis[0]?.merged_summary?.content || "No merged summary available"}
76
+ ${diagnosis?.merged_summary?.content || "No merged summary available"}
82
77
  `;
83
78
  return {
84
79
  result: markdownResponse,
@@ -0,0 +1,3 @@
1
+ import { Tool } from "./types";
2
+ export declare const grepTool: Tool;
3
+ //# sourceMappingURL=grep.d.ts.map
@@ -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,3 @@
1
+ import type { Tool } from "./types";
2
+ export declare const testRunTool: Tool;
3
+ //# sourceMappingURL=test-run-fetcher.d.ts.map
@@ -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":"AAEA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AASpC,eAAO,MAAM,WAAW,EAAE,IA8CzB,CAAC"}
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"}
@@ -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
- type: "function",
8
- function: {
9
- name: "runTest",
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),
@@ -1,11 +1,38 @@
1
- import type { OpenAI } from "openai";
2
- export type ToolSchema = OpenAI.Chat.Completions.ChatCompletionTool;
3
- export type ToolResult = {
4
- result: string;
5
- isError: boolean;
6
- };
7
- export type Tool = {
8
- schema: ToolSchema;
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,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAErC,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,kBAAkB,CAAC;AAEpE,MAAM,MAAM,UAAU,GAAG;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,IAAI,GAAG;IAIjB,MAAM,EAAE,UAAU,CAAC;IACnB,OAAO,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC;CAC9C,CAAC"}
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"}
@@ -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,2 +1,3 @@
1
+ export declare const DEFAULT_EXCLUDE: (string | RegExp)[];
1
2
  export declare function generateAsciiTree(dirPath: string, options?: {}): string;
2
3
  //# sourceMappingURL=repo-tree.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"repo-tree.d.ts","sourceRoot":"","sources":["../../src/utils/repo-tree.ts"],"names":[],"mappings":"AAYA,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,KAAK,UAsE9D"}
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"}
@@ -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
- const DEFAULT_EXCLUDE = [
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.48.1",
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.2"
80
+ "@empiricalrun/test-run": "^0.7.3"
80
81
  },
81
82
  "devDependencies": {
82
83
  "@playwright/test": "1.47.1",