@empiricalrun/test-gen 0.56.0 → 0.56.2
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 +23 -0
- package/dist/agent/browsing/run.js +4 -4
- package/dist/agent/browsing/utils.d.ts.map +1 -1
- package/dist/agent/browsing/utils.js +22 -21
- package/dist/agent/chat/agent-loop.d.ts.map +1 -1
- package/dist/agent/chat/agent-loop.js +1 -2
- package/dist/agent/chat/exports.d.ts +3 -1
- package/dist/agent/chat/exports.d.ts.map +1 -1
- package/dist/agent/chat/exports.js +32 -1
- package/dist/agent/chat/repo.js +4 -4
- package/dist/agent/chat/state.d.ts +1 -1
- package/dist/agent/chat/state.d.ts.map +1 -1
- package/dist/agent/codegen/fix-ts-errors.js +3 -3
- package/dist/agent/codegen/generate-code-apply-changes.js +4 -4
- package/dist/agent/codegen/repo-edit.js +2 -2
- package/dist/agent/codegen/run.js +4 -4
- package/dist/agent/codegen/update-flow.js +4 -4
- package/dist/agent/codegen/utils.js +11 -11
- package/dist/bin/utils/context.js +12 -12
- package/dist/bin/utils/fs/index.js +4 -4
- package/dist/bin/utils/platform/web/index.js +19 -19
- package/dist/reporter/index.js +5 -5
- package/dist/test-build/index.js +2 -2
- package/dist/tool-call-service/index.d.ts +2 -1
- package/dist/tool-call-service/index.d.ts.map +1 -1
- package/dist/tool-call-service/index.js +18 -7
- package/dist/tools/grep.d.ts.map +1 -1
- package/dist/tools/grep.js +2 -1
- package/dist/tools/str_replace_editor.d.ts.map +1 -1
- package/dist/tools/str_replace_editor.js +20 -9
- package/package.json +3 -9
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,28 @@
|
|
|
1
1
|
# @empiricalrun/test-gen
|
|
2
2
|
|
|
3
|
+
## 0.56.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- d5828e1: feat: including toolCalling in langfuse trace
|
|
8
|
+
- eb84f66: fix: Update environment variable handling
|
|
9
|
+
- 40f6470: feat: added tool execution service
|
|
10
|
+
- f49b645: feat: Add tool response API endpoint
|
|
11
|
+
- Updated dependencies [f8cc82d]
|
|
12
|
+
- Updated dependencies [f49b645]
|
|
13
|
+
- @empiricalrun/llm@0.15.2
|
|
14
|
+
- @empiricalrun/test-run@0.8.3
|
|
15
|
+
|
|
16
|
+
## 0.56.1
|
|
17
|
+
|
|
18
|
+
### Patch Changes
|
|
19
|
+
|
|
20
|
+
- d05bb69: chore: remove fs-extra
|
|
21
|
+
- e1e2564: fix: avoid global promisify calls
|
|
22
|
+
- 803f61f: fix: run type checks for file inserts in text editor tools
|
|
23
|
+
- Updated dependencies [d05bb69]
|
|
24
|
+
- @empiricalrun/test-run@0.8.2
|
|
25
|
+
|
|
3
26
|
## 0.56.0
|
|
4
27
|
|
|
5
28
|
### Minor Changes
|
|
@@ -5,13 +5,13 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.generateTestsUsingMasterAgent = void 0;
|
|
7
7
|
const detect_port_1 = __importDefault(require("detect-port"));
|
|
8
|
-
const
|
|
8
|
+
const fs_1 = __importDefault(require("fs"));
|
|
9
9
|
const web_1 = require("../../bin/utils/platform/web");
|
|
10
10
|
const server_1 = require("../../file/server");
|
|
11
11
|
const exec_1 = require("../../utils/exec");
|
|
12
12
|
const utils_1 = require("./utils");
|
|
13
13
|
async function generateTestsUsingMasterAgent({ testFilePath, filePathToUpdate, pwProjectsFilter, testGenToken, repoDir, editFileWithGeneratedCode, }) {
|
|
14
|
-
if (!
|
|
14
|
+
if (!fs_1.default.existsSync(testFilePath)) {
|
|
15
15
|
throw new Error(`File for master agent to run not found: ${testFilePath}`);
|
|
16
16
|
}
|
|
17
17
|
const pm = new exec_1.ProcessManager();
|
|
@@ -69,9 +69,9 @@ async function generateTestsUsingMasterAgent({ testFilePath, filePathToUpdate, p
|
|
|
69
69
|
// clean up the file if there is any error
|
|
70
70
|
if (isError) {
|
|
71
71
|
try {
|
|
72
|
-
const fileContent =
|
|
72
|
+
const fileContent = fs_1.default.readFileSync(filePathToUpdate, "utf-8");
|
|
73
73
|
const updatedContent = (0, web_1.replaceCreateTestWithNewCode)(filePathToUpdate, fileContent, "");
|
|
74
|
-
|
|
74
|
+
fs_1.default.writeFileSync(filePathToUpdate, updatedContent, "utf-8");
|
|
75
75
|
await (0, web_1.lintErrors)(filePathToUpdate);
|
|
76
76
|
}
|
|
77
77
|
catch (e) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/agent/browsing/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,KAAK,EAAe,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AAIxE,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAClC,OAAO,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAwBvD,wBAAgB,QAAQ,CAAC,GAAG,EAAE,GAAG,GAAG,GAAG,IAAI,MAAM,CAKhD;AAED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,MAAM,EAAE,UAIvD;AAiFD,wBAAsB,yBAAyB,CAAC,EAC9C,YAAY,EACZ,YAAY,EACZ,cAAc,GACf,EAAE;IACD,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,EAAE,CAAC;CAC1B,iBA2BA;AAED,wBAAsB,cAAc,CAAC,EACnC,YAAY,EACZ,cAAc,EACd,QAAQ,GACT,EAAE;IACD,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,QAAQ,EAAE,MAAM,CAAC;CAClB,iBAoBA;AAED,wBAAsB,yBAAyB,CAAC,EAC9C,QAAQ,EACR,QAAQ,EACR,KAAK,GACN,EAAE;IACD,QAAQ,EAAE,QAAQ,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,WAAW,CAAC;CACrB,GAAG,OAAO,CAAC,MAAM,CAAC,CAyDlB;AAyBD,wBAAsB,wBAAwB,CAAC,IAAI,EAAE,IAAI,iBA2HxD;AAED;;;GAGG;AACH,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,oBAAoB,CAAC,
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/agent/browsing/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,KAAK,EAAe,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AAIxE,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAClC,OAAO,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAwBvD,wBAAgB,QAAQ,CAAC,GAAG,EAAE,GAAG,GAAG,GAAG,IAAI,MAAM,CAKhD;AAED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,MAAM,EAAE,UAIvD;AAiFD,wBAAsB,yBAAyB,CAAC,EAC9C,YAAY,EACZ,YAAY,EACZ,cAAc,GACf,EAAE;IACD,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,EAAE,CAAC;CAC1B,iBA2BA;AAED,wBAAsB,cAAc,CAAC,EACnC,YAAY,EACZ,cAAc,EACd,QAAQ,GACT,EAAE;IACD,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,QAAQ,EAAE,MAAM,CAAC;CAClB,iBAoBA;AAED,wBAAsB,yBAAyB,CAAC,EAC9C,QAAQ,EACR,QAAQ,EACR,KAAK,GACN,EAAE;IACD,QAAQ,EAAE,QAAQ,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,WAAW,CAAC;CACrB,GAAG,OAAO,CAAC,MAAM,CAAC,CAyDlB;AAyBD,wBAAsB,wBAAwB,CAAC,IAAI,EAAE,IAAI,iBA2HxD;AAED;;;GAGG;AACH,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,oBAAoB,CAAC,CA2B/B;AAWD,wBAAsB,oBAAoB,CACxC,gBAAgB,EAAE,oBAAoB,GACrC,OAAO,CAAC,MAAM,EAAE,CAAC,CAQnB;AAED;;;;;GAKG;AACH,wBAAsB,iBAAiB,CACrC,YAAY,EAAE,MAAM,EACpB,gBAAgB,EAAE,oBAAoB,EACtC,gBAAgB,GAAE,MAAM,EAAU,GACjC,OAAO,CAAC,MAAM,CAAC,CA+CjB;AAED,qBAAa,eAAe;IACd,OAAO,CAAC,SAAS;gBAAT,SAAS,EAAE,MAAM;IACrC,OAAO,CAAC,aAAa,CAAqB;YAE5B,mBAAmB;YAUnB,gBAAgB;IAsBjB,OAAO;IAoBb,SAAS;CAKjB"}
|
|
@@ -4,7 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.TeardownManager = exports.detectProjectName = exports.getValidProjectNames = exports.readPlaywrightConfig = exports.injectPwLocatorGenerator = exports.prepareFileForMasterAgent = exports.markTestAsOnly = exports.replaceTodoWithCreateTest = exports.prepareBrowsingAgentTask = exports.isRegExp = void 0;
|
|
7
|
-
const
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
8
|
const minimatch_1 = require("minimatch");
|
|
9
9
|
const path_1 = __importDefault(require("path"));
|
|
10
10
|
const ts_morph_1 = require("ts-morph");
|
|
@@ -12,7 +12,7 @@ const ts_morph_1 = require("ts-morph");
|
|
|
12
12
|
let tsxImport = null;
|
|
13
13
|
const logger_1 = require("../../bin/logger");
|
|
14
14
|
const context_1 = require("../../bin/utils/context");
|
|
15
|
-
const
|
|
15
|
+
const fs_2 = require("../../bin/utils/fs");
|
|
16
16
|
const web_1 = require("../../bin/utils/platform/web");
|
|
17
17
|
const create_test_block_1 = require("../codegen/create-test-block");
|
|
18
18
|
const fix_ts_errors_1 = require("../codegen/fix-ts-errors");
|
|
@@ -33,10 +33,10 @@ async function addImportForCreateTest(testFilePath) {
|
|
|
33
33
|
// Instead of using "@empiricalrun/test-gen", we use the local dist file
|
|
34
34
|
// This is to avoid assuming that the test-gen package is installed in the project
|
|
35
35
|
const importSource = path_1.default.join(__dirname, "../../../dist/index.js");
|
|
36
|
-
if (!
|
|
36
|
+
if (!fs_1.default.existsSync(importSource)) {
|
|
37
37
|
throw new Error(`createTest import source not found at ${importSource}`);
|
|
38
38
|
}
|
|
39
|
-
|
|
39
|
+
fs_1.default.writeFileSync(testFilePath, (0, web_1.addNewImport)(fs_1.default.readFileSync(testFilePath, "utf-8"), ["createTest"], importSource));
|
|
40
40
|
}
|
|
41
41
|
async function prepareFileForUpdateScenario({ testCase, specPath, trace, }) {
|
|
42
42
|
const { name, suites } = testCase;
|
|
@@ -62,7 +62,7 @@ async function prepareFileForUpdateScenario({ testCase, specPath, trace, }) {
|
|
|
62
62
|
},
|
|
63
63
|
});
|
|
64
64
|
const scopeVariables = await (0, lexical_scoped_vars_1.getLexicalScopedVars)({
|
|
65
|
-
file:
|
|
65
|
+
file: fs_1.default.readFileSync(createTestFilePath, "utf-8"),
|
|
66
66
|
referencePoint: "await createTest",
|
|
67
67
|
trace: fetchScopeVariablesSpan,
|
|
68
68
|
});
|
|
@@ -92,7 +92,7 @@ async function prepareFileForUpdateScenario({ testCase, specPath, trace, }) {
|
|
|
92
92
|
async function replaceTodoWithCreateTest({ testFilePath, testCaseName, testCaseSuites, }) {
|
|
93
93
|
// This method is an alternative to prepareFileForUpdateScenario
|
|
94
94
|
// TODO: Does not support scoped variables and updates in POM files
|
|
95
|
-
const fileContent =
|
|
95
|
+
const fileContent = fs_1.default.readFileSync(testFilePath, "utf-8");
|
|
96
96
|
const todoRegex = /\/\/ TODO\(agent(?:\s+on\s+(\w+))?\):\s*(.*)/;
|
|
97
97
|
const todoMatch = fileContent.match(todoRegex);
|
|
98
98
|
if (!todoMatch) {
|
|
@@ -100,7 +100,7 @@ async function replaceTodoWithCreateTest({ testFilePath, testCaseName, testCaseS
|
|
|
100
100
|
}
|
|
101
101
|
const [, pageVarName] = todoMatch;
|
|
102
102
|
const pageVariable = pageVarName || "page"; // Default to "page" if not specified
|
|
103
|
-
|
|
103
|
+
fs_1.default.writeFileSync(testFilePath, fileContent.replace(todoRegex, (_, __, todoText) => `await createTest("${todoText.replace(/"/g, '\\"')}", ${pageVariable});`));
|
|
104
104
|
await addImportForCreateTest(testFilePath);
|
|
105
105
|
await markTestAsOnly({
|
|
106
106
|
testCaseName,
|
|
@@ -110,7 +110,7 @@ async function replaceTodoWithCreateTest({ testFilePath, testCaseName, testCaseS
|
|
|
110
110
|
}
|
|
111
111
|
exports.replaceTodoWithCreateTest = replaceTodoWithCreateTest;
|
|
112
112
|
async function markTestAsOnly({ testCaseName, testCaseSuites, specPath, }) {
|
|
113
|
-
const testFileContent =
|
|
113
|
+
const testFileContent = fs_1.default.readFileSync(specPath, "utf-8");
|
|
114
114
|
const { testBlock, testNode } = (0, web_1.getTypescriptTestBlock)({
|
|
115
115
|
scenarioName: testCaseName,
|
|
116
116
|
content: testFileContent,
|
|
@@ -121,7 +121,7 @@ async function markTestAsOnly({ testCaseName, testCaseSuites, specPath, }) {
|
|
|
121
121
|
// add test.only / describe.only to the spec file so that only that block is executed
|
|
122
122
|
if (!isFileMarkedSerial) {
|
|
123
123
|
const updatedTestFileContent = newContentsWithTestOnly(testFileContent, testBlock, testBlock, parentDescribe?.getText() || "");
|
|
124
|
-
|
|
124
|
+
fs_1.default.writeFileSync(specPath, updatedTestFileContent);
|
|
125
125
|
}
|
|
126
126
|
}
|
|
127
127
|
exports.markTestAsOnly = markTestAsOnly;
|
|
@@ -133,17 +133,17 @@ async function prepareFileForMasterAgent({ testCase, specPath, trace, }) {
|
|
|
133
133
|
const { name, suites } = testCase;
|
|
134
134
|
// check if the spec file exists
|
|
135
135
|
// if no then create a new file with test and expect imports
|
|
136
|
-
if (!
|
|
136
|
+
if (!fs_1.default.existsSync(specPath)) {
|
|
137
137
|
const fileCreateSpan = prepareFileSpan?.span({
|
|
138
138
|
name: "create-file",
|
|
139
139
|
input: { specPath },
|
|
140
140
|
});
|
|
141
|
-
|
|
141
|
+
fs_1.default.writeFileSync(specPath, "");
|
|
142
142
|
const fileContentWithImports = (0, web_1.addNewImport)("", ["test", "expect"], (0, web_1.getFixtureImportPath)(specPath));
|
|
143
|
-
|
|
143
|
+
fs_1.default.writeFileSync(specPath, fileContentWithImports, "utf-8");
|
|
144
144
|
fileCreateSpan?.end({ output: { specPath, fileContentWithImports } });
|
|
145
145
|
}
|
|
146
|
-
const existingContents =
|
|
146
|
+
const existingContents = fs_1.default.readFileSync(specPath, "utf-8");
|
|
147
147
|
const { testBlock } = (0, web_1.getTypescriptTestBlock)({
|
|
148
148
|
scenarioName: name,
|
|
149
149
|
suites,
|
|
@@ -155,13 +155,13 @@ async function prepareFileForMasterAgent({ testCase, specPath, trace, }) {
|
|
|
155
155
|
testCase,
|
|
156
156
|
file: specPath,
|
|
157
157
|
});
|
|
158
|
-
|
|
158
|
+
fs_1.default.writeFileSync(specPath, `${existingContents} \n\n ${newTestBlock}`, "utf-8");
|
|
159
159
|
const updatedContent = (0, web_1.injectCodeSnippetBySuiteChain)({
|
|
160
160
|
testFileContent: existingContents,
|
|
161
161
|
suites: testCase.suites,
|
|
162
162
|
codeSnippet: `\n\n${newTestBlock}`,
|
|
163
163
|
});
|
|
164
|
-
|
|
164
|
+
fs_1.default.writeFileSync(specPath, updatedContent, "utf-8");
|
|
165
165
|
}
|
|
166
166
|
const updatePath = await prepareFileForUpdateScenario({
|
|
167
167
|
testCase,
|
|
@@ -190,7 +190,7 @@ async function injectPwLocatorGenerator(page) {
|
|
|
190
190
|
pathToInstalledTestGen = process.cwd();
|
|
191
191
|
}
|
|
192
192
|
const annotateElementPath = path_1.default.join(pathToInstalledTestGen, "dist", "browser-injected-scripts", "annotate-elements.js");
|
|
193
|
-
if (!
|
|
193
|
+
if (!fs_1.default.existsSync(annotateElementPath)) {
|
|
194
194
|
throw new Error(`annotate-elements.js not found at path: ${annotateElementPath}`);
|
|
195
195
|
}
|
|
196
196
|
const remoteScriptResponses = await Promise.all([
|
|
@@ -199,7 +199,7 @@ async function injectPwLocatorGenerator(page) {
|
|
|
199
199
|
].map((url) => fetch(url)));
|
|
200
200
|
const scripts = await Promise.all([
|
|
201
201
|
...remoteScriptResponses.map((r) => r.text()),
|
|
202
|
-
|
|
202
|
+
fs_1.default.readFileSync(annotateElementPath, "utf-8"),
|
|
203
203
|
]);
|
|
204
204
|
page.on("load", async () => {
|
|
205
205
|
try {
|
|
@@ -307,11 +307,12 @@ async function readPlaywrightConfig(repoDir) {
|
|
|
307
307
|
tsxImport = module;
|
|
308
308
|
})
|
|
309
309
|
.catch((err) => {
|
|
310
|
-
console.error("Failed to import tsx:", err);
|
|
310
|
+
console.error("Failed to import tsx: --->", err.message);
|
|
311
311
|
});
|
|
312
312
|
}
|
|
313
313
|
if (!tsxImport) {
|
|
314
|
-
|
|
314
|
+
console.error("tsx module not available");
|
|
315
|
+
return {};
|
|
315
316
|
}
|
|
316
317
|
const [lastDir] = repoDir.split("/").reverse();
|
|
317
318
|
const playwrightConfig = (await tsxImport.require("./playwright.config.ts", `${repoDir}/${lastDir}`)).default;
|
|
@@ -395,7 +396,7 @@ class TeardownManager {
|
|
|
395
396
|
teardownFiles = [];
|
|
396
397
|
async getAllTeardownFiles() {
|
|
397
398
|
const teardownFileRegex = /.*\.teardown\.ts/;
|
|
398
|
-
const teardownFiles = await (0,
|
|
399
|
+
const teardownFiles = await (0, fs_2.readFilesInDirectory)(this.directory, (fileName) => teardownFileRegex.test(fileName));
|
|
399
400
|
return teardownFiles;
|
|
400
401
|
}
|
|
401
402
|
async skipTeardownFile(filePath) {
|
|
@@ -431,7 +432,7 @@ class TeardownManager {
|
|
|
431
432
|
}
|
|
432
433
|
unskipAll() {
|
|
433
434
|
this.teardownFiles.forEach(({ filePath, content }) => {
|
|
434
|
-
|
|
435
|
+
fs_1.default.writeFileSync(filePath, content, "utf-8");
|
|
435
436
|
});
|
|
436
437
|
}
|
|
437
438
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-loop.d.ts","sourceRoot":"","sources":["../../../src/agent/chat/agent-loop.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,
|
|
1
|
+
{"version":3,"file":"agent-loop.d.ts","sourceRoot":"","sources":["../../../src/agent/chat/agent-loop.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAmB,MAAM,wBAAwB,CAAC;AAGrE,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAG1D,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAgBhE,wBAAsB,aAAa,CAAC,EAClC,SAAS,EACT,aAAa,EACb,QAAQ,EACR,KAAK,EACL,eAAe,GAChB,EAAE;IACD,SAAS,EAAE,UAAU,CAAC,GAAG,CAAC,CAAC;IAC3B,aAAa,EAAE,mBAAmB,CAAC;IACnC,eAAe,EAAE,eAAe,CAAC;IACjC,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,KAAK,CAAC,EAAE,WAAW,CAAC;CACrB,iBAoCA"}
|
|
@@ -24,9 +24,8 @@ async function chatAgentLoop({ chatModel, selectedModel, reporter, trace, toolCa
|
|
|
24
24
|
const { tools } = await toolCallService.getTools();
|
|
25
25
|
while (!chatModel.askUserForInput) {
|
|
26
26
|
const toolCalls = chatModel.getPendingToolCalls();
|
|
27
|
-
console.log("toolCalls", toolCalls);
|
|
28
27
|
if (toolCalls.length) {
|
|
29
|
-
const toolResults = await toolCallService.execute(toolCalls, isRemote);
|
|
28
|
+
const toolResults = await toolCallService.execute(toolCalls, isRemote, trace);
|
|
30
29
|
if (isRemote) {
|
|
31
30
|
log(`Tool call remote execution in progress`);
|
|
32
31
|
break;
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { IChatModel } from "@empiricalrun/llm/chat";
|
|
2
2
|
import { chatAgentLoop } from "./agent-loop";
|
|
3
3
|
import { createChatModel } from "./model";
|
|
4
|
+
import * as State from "./state";
|
|
4
5
|
import { ChatStateOnDisk } from "./state";
|
|
5
6
|
import { ReporterFunction, SupportedChatModels } from "./types";
|
|
6
|
-
|
|
7
|
+
declare const createChatState: typeof State.createChatState, createChatStateForMessages: typeof State.createChatStateForMessages, chatStateFromModel: typeof State.chatStateFromModel, loadChatState: typeof State.loadChatState, saveToDisk: typeof State.saveToDisk, CURRENT_CHAT_STATE_VERSION: string;
|
|
8
|
+
export { chatAgentLoop, chatStateFromModel, createChatModel, createChatState, createChatStateForMessages, CURRENT_CHAT_STATE_VERSION, loadChatState, saveToDisk, };
|
|
7
9
|
export type { ChatStateOnDisk, IChatModel, ReporterFunction, SupportedChatModels, };
|
|
8
10
|
//# sourceMappingURL=exports.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"exports.d.ts","sourceRoot":"","sources":["../../../src/agent/chat/exports.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAEpD,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC1C,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC1C,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAEhE,OAAO,
|
|
1
|
+
{"version":3,"file":"exports.d.ts","sourceRoot":"","sources":["../../../src/agent/chat/exports.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAEpD,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC1C,OAAO,KAAK,KAAK,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC1C,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAEhE,QAAA,MACE,eAAe,gCACf,0BAA0B,2CAC1B,kBAAkB,mCAClB,aAAa,8BACb,UAAU,2BACV,0BAA0B,QACnB,CAAC;AAEV,OAAO,EACL,aAAa,EACb,kBAAkB,EAClB,eAAe,EACf,eAAe,EACf,0BAA0B,EAC1B,0BAA0B,EAC1B,aAAa,EACb,UAAU,GACX,CAAC;AAEF,YAAY,EACV,eAAe,EACf,UAAU,EACV,gBAAgB,EAChB,mBAAmB,GACpB,CAAC"}
|
|
@@ -1,7 +1,38 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
2
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.createChatModel = exports.chatAgentLoop = void 0;
|
|
26
|
+
exports.saveToDisk = exports.loadChatState = exports.CURRENT_CHAT_STATE_VERSION = exports.createChatStateForMessages = exports.createChatState = exports.createChatModel = exports.chatStateFromModel = exports.chatAgentLoop = void 0;
|
|
4
27
|
const agent_loop_1 = require("./agent-loop");
|
|
5
28
|
Object.defineProperty(exports, "chatAgentLoop", { enumerable: true, get: function () { return agent_loop_1.chatAgentLoop; } });
|
|
6
29
|
const model_1 = require("./model");
|
|
7
30
|
Object.defineProperty(exports, "createChatModel", { enumerable: true, get: function () { return model_1.createChatModel; } });
|
|
31
|
+
const State = __importStar(require("./state"));
|
|
32
|
+
const { createChatState, createChatStateForMessages, chatStateFromModel, loadChatState, saveToDisk, CURRENT_CHAT_STATE_VERSION, } = State;
|
|
33
|
+
exports.createChatState = createChatState;
|
|
34
|
+
exports.createChatStateForMessages = createChatStateForMessages;
|
|
35
|
+
exports.chatStateFromModel = chatStateFromModel;
|
|
36
|
+
exports.loadChatState = loadChatState;
|
|
37
|
+
exports.saveToDisk = saveToDisk;
|
|
38
|
+
exports.CURRENT_CHAT_STATE_VERSION = CURRENT_CHAT_STATE_VERSION;
|
package/dist/agent/chat/repo.js
CHANGED
|
@@ -4,22 +4,22 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.getRepoContext = void 0;
|
|
7
|
-
const
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
8
|
const path_1 = __importDefault(require("path"));
|
|
9
9
|
const repo_tree_1 = require("../../utils/repo-tree");
|
|
10
10
|
const utils_1 = require("../browsing/utils");
|
|
11
11
|
async function getAllMarkdownFiles() {
|
|
12
12
|
const dir = path_1.default.join(process.cwd(), ".empiricalrun");
|
|
13
|
-
if (!
|
|
13
|
+
if (!fs_1.default.existsSync(dir)) {
|
|
14
14
|
return [];
|
|
15
15
|
}
|
|
16
|
-
const files =
|
|
16
|
+
const files = fs_1.default.readdirSync(dir);
|
|
17
17
|
return files
|
|
18
18
|
.filter((file) => file.endsWith(".md"))
|
|
19
19
|
.map((file) => {
|
|
20
20
|
return {
|
|
21
21
|
name: file,
|
|
22
|
-
content:
|
|
22
|
+
content: fs_1.default.readFileSync(path_1.default.join(dir, file), "utf8"),
|
|
23
23
|
};
|
|
24
24
|
});
|
|
25
25
|
}
|
|
@@ -3,7 +3,7 @@ import { SupportedChatModels } from "./types";
|
|
|
3
3
|
export declare const CURRENT_CHAT_STATE_VERSION = "20250327.1";
|
|
4
4
|
export declare const CHAT_STATE_PATH: string;
|
|
5
5
|
export type ChatStateOnDisk<T> = {
|
|
6
|
-
version:
|
|
6
|
+
version: string;
|
|
7
7
|
model: SupportedChatModels;
|
|
8
8
|
messages: T[];
|
|
9
9
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../../src/agent/chat/state.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAKpD,OAAO,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAE9C,eAAO,MAAM,0BAA0B,eAAe,CAAC;AAEvD,eAAO,MAAM,eAAe,QAI3B,CAAC;AAEF,MAAM,MAAM,eAAe,CAAC,CAAC,IAAI;IAC/B,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../../src/agent/chat/state.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAKpD,OAAO,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAE9C,eAAO,MAAM,0BAA0B,eAAe,CAAC;AAEvD,eAAO,MAAM,eAAe,QAI3B,CAAC;AAEF,MAAM,MAAM,eAAe,CAAC,CAAC,IAAI;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,mBAAmB,CAAC;IAC3B,QAAQ,EAAE,CAAC,EAAE,CAAC;CACf,CAAC;AAEF,wBAAgB,eAAe,CAC7B,UAAU,EAAE,MAAM,EAClB,aAAa,EAAE,eAAe,CAAC,GAAG,CAAC,EACnC,aAAa,EAAE,mBAAmB,4BAMnC;AAED,wBAAgB,0BAA0B,CAAC,CAAC,EAC1C,QAAQ,EAAE,GAAG,EACb,aAAa,EAAE,mBAAmB,GACjC,eAAe,CAAC,CAAC,CAAC,CAOpB;AAED,wBAAgB,kBAAkB,CAAC,CAAC,EAClC,SAAS,EAAE,UAAU,CAAC,CAAC,CAAC,EACxB,aAAa,EAAE,mBAAmB,4BAGnC;AAED,wBAAgB,aAAa,CAAC,CAAC,KAAK,eAAe,CAAC,CAAC,CAAC,GAAG,SAAS,CAajE;AAED,wBAAgB,UAAU,CAAC,CAAC,EAC1B,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC,EAClB,aAAa,EAAE,mBAAmB,QAsBnC"}
|
|
@@ -5,7 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.validateAndFixTypescriptErrors = void 0;
|
|
7
7
|
const llm_1 = require("@empiricalrun/llm");
|
|
8
|
-
const
|
|
8
|
+
const fs_1 = __importDefault(require("fs"));
|
|
9
9
|
const logger_1 = require("../../bin/logger");
|
|
10
10
|
const web_1 = require("../../bin/utils/platform/web");
|
|
11
11
|
const constants_1 = require("../../constants");
|
|
@@ -21,7 +21,7 @@ async function validateAndFixTypescriptErrors({ trace, logger = new logger_1.Cus
|
|
|
21
21
|
const maxIteration = 2;
|
|
22
22
|
let counter = 0;
|
|
23
23
|
while (errors.length > 0) {
|
|
24
|
-
const fileContent =
|
|
24
|
+
const fileContent = fs_1.default.readFileSync(file, "utf-8");
|
|
25
25
|
counter += 1;
|
|
26
26
|
if (counter > maxIteration) {
|
|
27
27
|
trace?.event({ name: "code-fix-iteration-max-out" });
|
|
@@ -58,7 +58,7 @@ async function validateAndFixTypescriptErrors({ trace, logger = new logger_1.Cus
|
|
|
58
58
|
});
|
|
59
59
|
const response = message?.content || "";
|
|
60
60
|
const readWriteFileSpan = trace?.span({ name: "write-to-file" });
|
|
61
|
-
|
|
61
|
+
fs_1.default.writeFileSync(file, response, "utf-8");
|
|
62
62
|
readWriteFileSpan?.end({ output: { response } });
|
|
63
63
|
trace?.event({ name: "lint-file" });
|
|
64
64
|
await (0, web_1.lintErrors)(file);
|
|
@@ -5,7 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.generateCodeAndApplyChanges = exports.systemPromptBuilderForRepoEdit = void 0;
|
|
7
7
|
const llm_1 = require("@empiricalrun/llm");
|
|
8
|
-
const
|
|
8
|
+
const fs_1 = __importDefault(require("fs"));
|
|
9
9
|
const path_1 = require("path");
|
|
10
10
|
const constants_1 = require("../../constants");
|
|
11
11
|
const types_1 = require("./types");
|
|
@@ -348,8 +348,8 @@ async function generateCodeAndApplyChanges({ task, trace, logger, getRelevantFil
|
|
|
348
348
|
newCode: args.code,
|
|
349
349
|
reason: args.reason,
|
|
350
350
|
});
|
|
351
|
-
|
|
352
|
-
|
|
351
|
+
fs_1.default.mkdirSync((0, path_1.dirname)(args.filePath), { recursive: true });
|
|
352
|
+
fs_1.default.writeFileSync(args.filePath, args.code, "utf-8");
|
|
353
353
|
console.log(`Created file: ${args.filePath}`);
|
|
354
354
|
})();
|
|
355
355
|
}));
|
|
@@ -360,7 +360,7 @@ async function generateCodeAndApplyChanges({ task, trace, logger, getRelevantFil
|
|
|
360
360
|
// Filter out the tool calls which are for replacing code in existing files
|
|
361
361
|
const fileChanges = strReplaceToolCalls
|
|
362
362
|
.map((toolCall) => JSON.parse(toolCall.function.arguments))
|
|
363
|
-
.filter((f) => f.filePath &&
|
|
363
|
+
.filter((f) => f.filePath && fs_1.default.existsSync(f.filePath));
|
|
364
364
|
// We add all the suggested changes to the updatedFiles array
|
|
365
365
|
// This is used to validate and format files later
|
|
366
366
|
updatedFiles.push(...fileChanges);
|
|
@@ -4,7 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.repoEditAgent = exports.generateCodeUsingRepoAgent = void 0;
|
|
7
|
-
const
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
8
|
const context_1 = require("../../bin/utils/context");
|
|
9
9
|
const web_1 = require("../../bin/utils/platform/web");
|
|
10
10
|
const reporter_1 = require("../../reporter");
|
|
@@ -75,7 +75,7 @@ async function repoEditAgent({ trace, task, logger, }) {
|
|
|
75
75
|
});
|
|
76
76
|
await Promise.all(updates.map((f) => {
|
|
77
77
|
return (async () => {
|
|
78
|
-
if (
|
|
78
|
+
if (fs_1.default.existsSync(f.filePath)) {
|
|
79
79
|
await (0, web_1.lintErrors)(f.filePath);
|
|
80
80
|
}
|
|
81
81
|
})();
|
|
@@ -5,7 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.generateTestWithCodegen = exports.createTestWithCodeAgent = void 0;
|
|
7
7
|
const llm_1 = require("@empiricalrun/llm");
|
|
8
|
-
const
|
|
8
|
+
const fs_1 = __importDefault(require("fs"));
|
|
9
9
|
const logger_1 = require("../../bin/logger");
|
|
10
10
|
const context_1 = require("../../bin/utils/context");
|
|
11
11
|
const web_1 = require("../../bin/utils/platform/web");
|
|
@@ -67,9 +67,9 @@ ${testCase.steps.join("\n")}`;
|
|
|
67
67
|
exports.createTestWithCodeAgent = createTestWithCodeAgent;
|
|
68
68
|
async function generateTestWithCodegen({ testCase, file, trace, }) {
|
|
69
69
|
const logger = new logger_1.CustomLogger();
|
|
70
|
-
if (!
|
|
70
|
+
if (!fs_1.default.existsSync(file)) {
|
|
71
71
|
logger.log(`Creating a new spec file: ${file}`);
|
|
72
|
-
|
|
72
|
+
fs_1.default.writeFileSync(file, "");
|
|
73
73
|
}
|
|
74
74
|
const context = await (0, context_1.contextForGeneration)(file);
|
|
75
75
|
const { testFileContent } = context;
|
|
@@ -112,7 +112,7 @@ async function generateTestWithCodegen({ testCase, file, trace, }) {
|
|
|
112
112
|
});
|
|
113
113
|
await Promise.all(updates.fileChanges.map((f) => {
|
|
114
114
|
return (async () => {
|
|
115
|
-
if (
|
|
115
|
+
if (fs_1.default.existsSync(f.filePath)) {
|
|
116
116
|
await (0, web_1.lintErrors)(f.filePath);
|
|
117
117
|
}
|
|
118
118
|
})();
|
|
@@ -5,10 +5,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.appendCreateTestBlock = exports.getAppendCreateTestBlockCompletion = exports.updateTest = exports.getUpdateTestCodeCompletion = void 0;
|
|
7
7
|
const llm_1 = require("@empiricalrun/llm");
|
|
8
|
-
const
|
|
8
|
+
const fs_1 = __importDefault(require("fs"));
|
|
9
9
|
const logger_1 = require("../../bin/logger");
|
|
10
10
|
const context_1 = require("../../bin/utils/context");
|
|
11
|
-
const
|
|
11
|
+
const fs_2 = require("../../bin/utils/fs");
|
|
12
12
|
const web_1 = require("../../bin/utils/platform/web");
|
|
13
13
|
const constants_1 = require("../../constants");
|
|
14
14
|
const promptTemplate_0 = "{{#section \"system\"}}\n\nYou are a software test engineer who is given a task to update a test case. You will be provided with steps of a test\ncase scenario and you are given a snippet with interface await createTest(task, playwright_page_instance).\n\nYou need to analyze the request and place createTest snippet at the correct position and pass on the steps to this\n`createTest` method with the correct page instance.\n\nYou will be provided with current tests, fixtures and page object models for you to use and update code as per the\ntask provided to you.\nYou need to respond with file path and updated code block inside the file.\n\nHere is the list of current tests and fixtures:\n\n{{testFiles}}\n\n\nHere is the list of current page object models:\n\n{{pageFiles}}\n{{/section}}\n\n\n{{#section \"user\"}}\nFollowing is the test scenario for which you need to update the test:\n\ntest name:\n{{scenarioName}}\n\nTask:\n{{scenarioSteps}}\n\nFollow these steps to complete the task:\n\n1. Determine the task's intent:\n- The default intent is **\"add steps\"**.\n- If the task explicitly mentions (using words like \"replace\", \"remove\", \"delete\") that existing test steps should\nbe replaced or deleted, the intent is **\"update steps\"**. Identify the specific steps to be replaced or removed.\n- Do not assume that providing new or different steps implies an intent to update or replace existing steps. Unless\nthe task explicitly instructs to replace or remove existing code, interpret the intent as adding new steps to the\nexisting test.\n\n2. Identify the test block that requires updating.\n\n3. Place the `createTest` snippet:\n- Insert the `createTest` snippet at the location determined by the task, and pass the Playwright page instance.\n- If the intent is \"add\", do not alter the existing test code; simply append the `createTest` snippet based on any\nprovided location hints.\n- If the task includes location hints that don't match steps within the test, check dependent methods called from\nthe test for the update.\n- If no location hint is provided, place the `createTest` snippet at the end of the test block.\n- Even if the task includes steps that overlap with or are similar to existing steps, do not modify the existing\ncode. Unless the task explicitly instructs to replace or remove existing code, interpret the intent as adding new\nsteps to the existing test.\n\n4. Strip location hints from the task:\n- Remove any location hints (e.g., \"replace the current assertion and\") before passing the task to the `createTest`\nmethod.\n- The task passed into `createTest` should not contain any location hints. It should only contain actions that\nare required to be performed.\n- For example, if the original task: \"replace the current assertion and add a new assertion\" should be transformed to\n\"add a new assertion\" before passing it to the `createTest` method. This is the \"task_without_location_hints\"\n\nSubmission Guidelines:\n\n- Focus only on the provided test case and any related page object model methods used in the test.\n- Do not modify or add code within the `createTest` snippet.\n- Do not update or modify any other code apart from adding `createTest` code snippet.\n- Since the response will be used for search-and-replace operations, always provide the immediate parent AST node\nfor any code updates.\n- Include the full test block if any part of it is updated, preserving all unchanged code.\n- Do not use markdown syntax or backticks.\n- Respond using the following XML format:\n<reason_for_intent></reason_for_intent>\n<intent></intent>\n<location_of_update></location_of_update>\n<task_without_location_hints></task_without_location_hints>\n<file_path></file_path>\n<old_code_block></old_code_block>\n<new_code_block></new_code_block>\n<change></change>\n\n- Each `<old_code_block>` and `<new_code_block>` should contain only one test block or page object model method\n definition. Provide separate blocks for multiple updates.\n- The `<change></change>` tag should also mention the file path being updated.\n- There should be only one `createTest` block in the `new_code_block`. The `createTest` method should be passed\nwith entire task. Do not split the task while forwarding it to `createTest`.\n- `<new_code_block>` code snippet should be syntactically correct.\n - The code_block should not contain any import statements.\n{{/section}}";
|
|
@@ -214,8 +214,8 @@ async function appendCreateTestBlock({ testCase, file, trace, validateTypes = tr
|
|
|
214
214
|
const logger = new logger_1.CustomLogger({ useReporter: false });
|
|
215
215
|
logger.log("Appending create test block");
|
|
216
216
|
const context = await (0, context_1.contextForGeneration)(file);
|
|
217
|
-
const scenarioFileContent =
|
|
218
|
-
const testCodePrompt = (0,
|
|
217
|
+
const scenarioFileContent = fs_1.default.readFileSync(file, "utf-8");
|
|
218
|
+
const testCodePrompt = (0, fs_2.convertFileContentsToString)([
|
|
219
219
|
{
|
|
220
220
|
filePath: file,
|
|
221
221
|
content: scenarioFileContent,
|
|
@@ -5,7 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.applyFileChanges = exports.searchAndReplaceCode = exports.applyFileChangesForCreateTest = exports.applyFileChangesUsingStrReplace = exports.validateTypesAndFormatCode = exports.extractTestStepsSuggestions = exports.extractAppendTestUpdates = exports.extractCreateTestUpdates = exports.extractTestUpdates = void 0;
|
|
7
7
|
const llm_1 = require("@empiricalrun/llm");
|
|
8
|
-
const
|
|
8
|
+
const fs_1 = __importDefault(require("fs"));
|
|
9
9
|
const ts_morph_1 = require("ts-morph");
|
|
10
10
|
const web_1 = require("../../bin/utils/platform/web");
|
|
11
11
|
const fix_ts_errors_1 = require("./fix-ts-errors");
|
|
@@ -178,7 +178,7 @@ async function applyFileChangesUsingStrReplace({ trace, fileChanges, logger, })
|
|
|
178
178
|
logger?.error(`Unable to find the code to update in ${result.filePath}, full error:`, result);
|
|
179
179
|
}
|
|
180
180
|
else {
|
|
181
|
-
|
|
181
|
+
fs_1.default.writeFileSync(fileChange.filePath, updatedContent, "utf-8");
|
|
182
182
|
readWriteFileSpan?.end({ output: { updatedContent } });
|
|
183
183
|
}
|
|
184
184
|
results.push(result);
|
|
@@ -213,13 +213,13 @@ async function applyFileChangesForCreateTest({ trace, fileChanges, testgenUpdate
|
|
|
213
213
|
},
|
|
214
214
|
});
|
|
215
215
|
if (fileChange.code) {
|
|
216
|
-
const currentContent =
|
|
217
|
-
?
|
|
216
|
+
const currentContent = fs_1.default.existsSync(fileChange.filePath)
|
|
217
|
+
? fs_1.default.readFileSync(fileChange.filePath, "utf-8")
|
|
218
218
|
: "";
|
|
219
|
-
|
|
219
|
+
fs_1.default.writeFileSync(fileChange.filePath, currentContent
|
|
220
220
|
? `${currentContent}\n\n${fileChange.code}`
|
|
221
221
|
: fileChange.code, "utf-8");
|
|
222
|
-
const updatedFileContent =
|
|
222
|
+
const updatedFileContent = fs_1.default.readFileSync(fileChange.filePath, "utf-8");
|
|
223
223
|
readWriteFileSpan?.end({
|
|
224
224
|
output: { fileChange, updatedFile: updatedFileContent },
|
|
225
225
|
});
|
|
@@ -240,7 +240,7 @@ async function applyFileChangesForCreateTest({ trace, fileChanges, testgenUpdate
|
|
|
240
240
|
}
|
|
241
241
|
exports.applyFileChangesForCreateTest = applyFileChangesForCreateTest;
|
|
242
242
|
async function searchAndReplaceCode({ logger, fileChange, }) {
|
|
243
|
-
let contents =
|
|
243
|
+
let contents = fs_1.default.readFileSync(fileChange.filePath, "utf-8");
|
|
244
244
|
// since we dont know what is getting updated,
|
|
245
245
|
// we believe that the patch is correct and contains few before and after lines
|
|
246
246
|
// to make the change unique for search & replace
|
|
@@ -292,7 +292,7 @@ async function applyFileChanges({ trace, testCase, fileChanges, logger, }) {
|
|
|
292
292
|
// assuming the test case getting updated
|
|
293
293
|
// maintaining the previous accuracy of the test case update
|
|
294
294
|
const readWriteFileSpan = trace?.span({ name: "write-to-file" });
|
|
295
|
-
let contents =
|
|
295
|
+
let contents = fs_1.default.readFileSync(fileChange.filePath, "utf-8");
|
|
296
296
|
const [prependContent, strippedContent] = await (0, web_1.stripAndPrependImports)(fileChange.newCode, testCase?.name);
|
|
297
297
|
let updatedContent = prependContent + contents + `\n\n${strippedContent}`;
|
|
298
298
|
const { testBlock } = (0, web_1.getTypescriptTestBlock)({
|
|
@@ -302,12 +302,12 @@ async function applyFileChanges({ trace, testCase, fileChanges, logger, }) {
|
|
|
302
302
|
});
|
|
303
303
|
contents = contents.replace(testBlock, `\n\n${strippedContent}`);
|
|
304
304
|
updatedContent = prependContent + contents;
|
|
305
|
-
|
|
305
|
+
fs_1.default.writeFileSync(fileChange.filePath, updatedContent, "utf-8");
|
|
306
306
|
readWriteFileSpan?.end({ output: { updatedContent } });
|
|
307
307
|
}
|
|
308
308
|
else {
|
|
309
309
|
const readWriteFileSpan = trace?.span({ name: "write-to-file" });
|
|
310
|
-
let contents =
|
|
310
|
+
let contents = fs_1.default.readFileSync(fileChange.filePath, "utf-8");
|
|
311
311
|
const project = new ts_morph_1.Project();
|
|
312
312
|
const sourceFile = project.createSourceFile("updated-code.ts", fileChange.newCode);
|
|
313
313
|
const functions = sourceFile.getFunctions();
|
|
@@ -353,7 +353,7 @@ async function applyFileChanges({ trace, testCase, fileChanges, logger, }) {
|
|
|
353
353
|
contents = updatedContent;
|
|
354
354
|
}
|
|
355
355
|
}
|
|
356
|
-
|
|
356
|
+
fs_1.default.writeFileSync(fileChange.filePath, contents, "utf-8");
|
|
357
357
|
readWriteFileSpan?.end({ output: { contents } });
|
|
358
358
|
results.push({
|
|
359
359
|
filePath: fileChange.filePath,
|
|
@@ -4,14 +4,14 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.fetchAppKnowledge = exports.generateTxtForRepository = exports.createRepoEditFilter = exports.contextForGeneration = exports.createGitIgnoreFileFilter = void 0;
|
|
7
|
-
const
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
8
|
const ignore_1 = __importDefault(require("ignore"));
|
|
9
|
-
const
|
|
9
|
+
const fs_2 = require("./fs");
|
|
10
10
|
async function createGitIgnoreFileFilter() {
|
|
11
11
|
const ignoreFn = (0, ignore_1.default)();
|
|
12
|
-
if (
|
|
12
|
+
if (fs_1.default.existsSync(".gitignore")) {
|
|
13
13
|
// Not checking for nested gitignore
|
|
14
|
-
let gitignore =
|
|
14
|
+
let gitignore = fs_1.default.readFileSync(".gitignore").toString();
|
|
15
15
|
gitignore = `
|
|
16
16
|
${gitignore}
|
|
17
17
|
.git/
|
|
@@ -27,10 +27,10 @@ exports.createGitIgnoreFileFilter = createGitIgnoreFileFilter;
|
|
|
27
27
|
async function contextForGeneration(file) {
|
|
28
28
|
const filter = await createGitIgnoreFileFilter();
|
|
29
29
|
return {
|
|
30
|
-
codePrompt: await (0,
|
|
31
|
-
pomPrompt: await (0,
|
|
32
|
-
nonSpecFilePrompt: await (0,
|
|
33
|
-
testFileContent: file ?
|
|
30
|
+
codePrompt: await (0, fs_2.generatePromptFromDirectory)("./tests", filter),
|
|
31
|
+
pomPrompt: await (0, fs_2.generatePromptFromDirectory)("./pages", filter),
|
|
32
|
+
nonSpecFilePrompt: await (0, fs_2.generatePromptFromNonSpecFiles)("./tests", filter),
|
|
33
|
+
testFileContent: file ? fs_1.default.readFileSync(file, "utf-8") : "",
|
|
34
34
|
};
|
|
35
35
|
}
|
|
36
36
|
exports.contextForGeneration = contextForGeneration;
|
|
@@ -39,14 +39,14 @@ async function createRepoEditFilter() {
|
|
|
39
39
|
const gitIgnoreFilter = await createGitIgnoreFileFilter();
|
|
40
40
|
return (filePath) => {
|
|
41
41
|
return (gitIgnoreFilter(filePath) &&
|
|
42
|
-
(
|
|
42
|
+
(fs_1.default.statSync(filePath).isDirectory() || allowedExtensions.test(filePath)));
|
|
43
43
|
};
|
|
44
44
|
}
|
|
45
45
|
exports.createRepoEditFilter = createRepoEditFilter;
|
|
46
46
|
async function generateTxtForRepository() {
|
|
47
47
|
const filter = await createRepoEditFilter();
|
|
48
48
|
return {
|
|
49
|
-
prompt: await (0,
|
|
49
|
+
prompt: await (0, fs_2.generatePromptFromDirectory)(".", filter),
|
|
50
50
|
};
|
|
51
51
|
}
|
|
52
52
|
exports.generateTxtForRepository = generateTxtForRepository;
|
|
@@ -54,7 +54,7 @@ async function fetchAppKnowledge() {
|
|
|
54
54
|
let fileExists = true;
|
|
55
55
|
const appKnowledgePath = "./app_knowledge.md";
|
|
56
56
|
try {
|
|
57
|
-
|
|
57
|
+
fs_1.default.accessSync(appKnowledgePath);
|
|
58
58
|
}
|
|
59
59
|
catch (e) {
|
|
60
60
|
fileExists = false;
|
|
@@ -62,6 +62,6 @@ async function fetchAppKnowledge() {
|
|
|
62
62
|
if (!fileExists) {
|
|
63
63
|
return "";
|
|
64
64
|
}
|
|
65
|
-
return
|
|
65
|
+
return fs_1.default.readFileSync(appKnowledgePath, "utf-8");
|
|
66
66
|
}
|
|
67
67
|
exports.fetchAppKnowledge = fetchAppKnowledge;
|
|
@@ -4,19 +4,19 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.generatePromptFromNonSpecFiles = exports.generatePromptFromDirectory = exports.convertFileContentsToString = exports.readFilesInDirectory = void 0;
|
|
7
|
-
const
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
8
|
const path_1 = __importDefault(require("path"));
|
|
9
9
|
async function readFilesInDirectory(dir = "", filterFunc) {
|
|
10
10
|
let files = [];
|
|
11
|
-
const items =
|
|
11
|
+
const items = fs_1.default.readdirSync(dir);
|
|
12
12
|
const filteredItems = items.map((i) => path_1.default.join(dir, i)).filter(filterFunc);
|
|
13
13
|
for (const item of filteredItems) {
|
|
14
|
-
const stat =
|
|
14
|
+
const stat = fs_1.default.statSync(item);
|
|
15
15
|
if (stat.isDirectory()) {
|
|
16
16
|
files = files.concat(await readFilesInDirectory(item, filterFunc));
|
|
17
17
|
}
|
|
18
18
|
else if (stat.isFile()) {
|
|
19
|
-
const content =
|
|
19
|
+
const content = fs_1.default.readFileSync(item, "utf-8");
|
|
20
20
|
files.push({ filePath: item, content });
|
|
21
21
|
}
|
|
22
22
|
}
|
|
@@ -6,7 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.isSyntaxValid = exports.getVariableDeclarationsFromCode = exports.buildTestNamePrompt = exports.isTestPresent = exports.appendScopeToCreateTest = exports.addUserContextFixture = exports.importAllExportsStmtFromFilePaths = exports.injectCodeSnippetBySuiteChain = exports.replaceCreateTestWithNewCode = exports.getPageVariableNameFromCreateTest = exports.getFixtureImportPath = exports.removeTestOnly = exports.addNewImport = exports.formatCode = exports.lintErrors = exports.stripAndPrependImports = exports.validateTypescript = exports.appendToTestBlock = exports.findFirstSerialDescribeBlock = exports.hasTopLevelDescribeConfigureWithSerialMode = exports.hasTestBlock = exports.getTypescriptTestBlock = exports.getTestModuleAliasFromSourceFile = void 0;
|
|
7
7
|
const parser_1 = require("@babel/parser");
|
|
8
8
|
const eslint_1 = require("eslint");
|
|
9
|
-
const
|
|
9
|
+
const fs_1 = __importDefault(require("fs"));
|
|
10
10
|
const path_1 = __importDefault(require("path"));
|
|
11
11
|
const prettier_1 = __importDefault(require("prettier"));
|
|
12
12
|
const ts_morph_1 = require("ts-morph");
|
|
@@ -73,12 +73,12 @@ function getTypescriptTestBlock({ scenarioName, suites, content, }) {
|
|
|
73
73
|
}
|
|
74
74
|
exports.getTypescriptTestBlock = getTypescriptTestBlock;
|
|
75
75
|
function hasTestBlock({ testName, testSuites, filePath, }) {
|
|
76
|
-
if (!
|
|
76
|
+
if (!fs_1.default.existsSync(filePath)) {
|
|
77
77
|
return false;
|
|
78
78
|
}
|
|
79
79
|
const { testBlock } = getTypescriptTestBlock({
|
|
80
80
|
scenarioName: testName,
|
|
81
|
-
content:
|
|
81
|
+
content: fs_1.default.readFileSync(filePath, "utf-8"),
|
|
82
82
|
suites: testSuites,
|
|
83
83
|
});
|
|
84
84
|
return Boolean(testBlock);
|
|
@@ -107,7 +107,7 @@ function getParentDescribeNames(node) {
|
|
|
107
107
|
}
|
|
108
108
|
async function hasTopLevelDescribeConfigureWithSerialMode(filePath) {
|
|
109
109
|
const project = new ts_morph_1.Project();
|
|
110
|
-
const content =
|
|
110
|
+
const content = fs_1.default.readFileSync(filePath, "utf-8");
|
|
111
111
|
const sourceFile = project.createSourceFile("test.ts", content);
|
|
112
112
|
const statements = sourceFile.getStatements();
|
|
113
113
|
for (const statement of statements) {
|
|
@@ -188,7 +188,7 @@ exports.appendToTestBlock = appendToTestBlock;
|
|
|
188
188
|
function validateTypescript(filePath) {
|
|
189
189
|
// Create a compiler host to read files
|
|
190
190
|
const compilerHost = typescript_1.default.createCompilerHost({});
|
|
191
|
-
compilerHost.readFile = (file) =>
|
|
191
|
+
compilerHost.readFile = (file) => fs_1.default.readFileSync(file, "utf8");
|
|
192
192
|
// Create a program with a single source file
|
|
193
193
|
const program = typescript_1.default.createProgram([filePath], {
|
|
194
194
|
esModuleInterop: true,
|
|
@@ -245,12 +245,12 @@ async function lintErrors(filePath) {
|
|
|
245
245
|
});
|
|
246
246
|
const [result] = await eslint.lintFiles(filePath);
|
|
247
247
|
if (result?.output) {
|
|
248
|
-
|
|
248
|
+
fs_1.default.writeFileSync(filePath, result.output);
|
|
249
249
|
}
|
|
250
250
|
}
|
|
251
251
|
exports.lintErrors = lintErrors;
|
|
252
252
|
async function formatCode(filePath, trace) {
|
|
253
|
-
const fileContent =
|
|
253
|
+
const fileContent = fs_1.default.readFileSync(filePath, "utf8");
|
|
254
254
|
if (!fileContent) {
|
|
255
255
|
trace?.span({
|
|
256
256
|
name: "prettier-format-output",
|
|
@@ -264,7 +264,7 @@ async function formatCode(filePath, trace) {
|
|
|
264
264
|
filepath: filePath,
|
|
265
265
|
});
|
|
266
266
|
trace?.span({ name: "prettier-format-output", output: formattedContent });
|
|
267
|
-
|
|
267
|
+
fs_1.default.writeFileSync(filePath, formattedContent);
|
|
268
268
|
}
|
|
269
269
|
exports.formatCode = formatCode;
|
|
270
270
|
function addNewImport(contents, modules, pkg) {
|
|
@@ -272,11 +272,11 @@ function addNewImport(contents, modules, pkg) {
|
|
|
272
272
|
}
|
|
273
273
|
exports.addNewImport = addNewImport;
|
|
274
274
|
async function removeTestOnly(filePath) {
|
|
275
|
-
const contents =
|
|
275
|
+
const contents = fs_1.default.readFileSync(filePath, "utf8");
|
|
276
276
|
const updatedContent = contents
|
|
277
277
|
.replace("test.only(", "test(")
|
|
278
278
|
.replace("test.describe.only(", "test.describe(");
|
|
279
|
-
|
|
279
|
+
fs_1.default.writeFileSync(filePath, updatedContent);
|
|
280
280
|
}
|
|
281
281
|
exports.removeTestOnly = removeTestOnly;
|
|
282
282
|
function getFixtureImportPath(filePath) {
|
|
@@ -296,7 +296,7 @@ function getFixtureImportPath(filePath) {
|
|
|
296
296
|
}
|
|
297
297
|
exports.getFixtureImportPath = getFixtureImportPath;
|
|
298
298
|
async function getPageVariableNameFromCreateTest(filePath) {
|
|
299
|
-
const contents =
|
|
299
|
+
const contents = fs_1.default.readFileSync(filePath, "utf-8");
|
|
300
300
|
const project = new ts_morph_1.Project();
|
|
301
301
|
const sourceFile = project.createSourceFile("test.ts", contents);
|
|
302
302
|
const createTestNode = sourceFile.getFirstDescendant((node) => !!(node.isKind(ts_morph_1.SyntaxKind.CallExpression) &&
|
|
@@ -418,7 +418,7 @@ const importAllExportsStmtFromFilePaths = async (repoDir, filePaths, testFilePat
|
|
|
418
418
|
if (!importPath.startsWith(".")) {
|
|
419
419
|
importPath = "./" + importPath;
|
|
420
420
|
}
|
|
421
|
-
const file =
|
|
421
|
+
const file = fs_1.default.readFileSync(fullPath, "utf-8");
|
|
422
422
|
const project = new ts_morph_1.Project();
|
|
423
423
|
const sourceFile = project.createSourceFile("index.ts", file);
|
|
424
424
|
const exportedFunctions = sourceFile
|
|
@@ -440,7 +440,7 @@ async function addUserContextFixture({ scenarioName, filePath, suites, }) {
|
|
|
440
440
|
// TODO: remove this check when we support user context across repos
|
|
441
441
|
let fixtureContent = "";
|
|
442
442
|
try {
|
|
443
|
-
fixtureContent =
|
|
443
|
+
fixtureContent = fs_1.default.readFileSync("./tests/fixtures.ts", "utf-8");
|
|
444
444
|
}
|
|
445
445
|
catch (e) {
|
|
446
446
|
// do nothing
|
|
@@ -448,7 +448,7 @@ async function addUserContextFixture({ scenarioName, filePath, suites, }) {
|
|
|
448
448
|
if (!fixtureContent || !fixtureContent.includes("userContext")) {
|
|
449
449
|
return;
|
|
450
450
|
}
|
|
451
|
-
const fileContent =
|
|
451
|
+
const fileContent = fs_1.default.readFileSync(filePath, "utf-8");
|
|
452
452
|
const { testNode } = getTypescriptTestBlock({
|
|
453
453
|
scenarioName,
|
|
454
454
|
content: fileContent,
|
|
@@ -469,14 +469,14 @@ async function addUserContextFixture({ scenarioName, filePath, suites, }) {
|
|
|
469
469
|
.replace(",}", "}") // Remove any trailing commas
|
|
470
470
|
.replace("}", ", userContext }");
|
|
471
471
|
destructuringParam.replaceWithText(updatedImport);
|
|
472
|
-
|
|
472
|
+
fs_1.default.writeFileSync(filePath, fileContent.replace(currentBlock, testNode.getText()), "utf-8");
|
|
473
473
|
}
|
|
474
474
|
}
|
|
475
475
|
}
|
|
476
476
|
}
|
|
477
477
|
exports.addUserContextFixture = addUserContextFixture;
|
|
478
478
|
async function appendScopeToCreateTest(filePath, scopeVariables) {
|
|
479
|
-
const contents =
|
|
479
|
+
const contents = fs_1.default.readFileSync(filePath, "utf-8");
|
|
480
480
|
const project = new ts_morph_1.Project();
|
|
481
481
|
const sourceFile = project.createSourceFile("test.ts", contents);
|
|
482
482
|
const createTestNode = sourceFile
|
|
@@ -491,17 +491,17 @@ async function appendScopeToCreateTest(filePath, scopeVariables) {
|
|
|
491
491
|
const args = createTestNode.getArguments();
|
|
492
492
|
const scopeArgStr = `{ ${scopeVariables.join(", ")} }`;
|
|
493
493
|
createTestNode.insertArgument(args.length, scopeArgStr);
|
|
494
|
-
|
|
494
|
+
fs_1.default.writeFileSync(filePath, sourceFile.getFullText());
|
|
495
495
|
}
|
|
496
496
|
exports.appendScopeToCreateTest = appendScopeToCreateTest;
|
|
497
497
|
function isTestPresent({ specPath, testCase, }) {
|
|
498
498
|
let isTestPresent = true;
|
|
499
|
-
isTestPresent =
|
|
499
|
+
isTestPresent = fs_1.default.existsSync(specPath);
|
|
500
500
|
if (isTestPresent) {
|
|
501
501
|
const { testBlock } = getTypescriptTestBlock({
|
|
502
502
|
suites: testCase.suites,
|
|
503
503
|
scenarioName: testCase.name,
|
|
504
|
-
content:
|
|
504
|
+
content: fs_1.default.readFileSync(specPath, "utf-8"),
|
|
505
505
|
});
|
|
506
506
|
isTestPresent = Boolean(testBlock);
|
|
507
507
|
}
|
package/dist/reporter/index.js
CHANGED
|
@@ -5,7 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.TestGenUpdatesReporter = exports.setReporterConfig = exports.getReporter = void 0;
|
|
7
7
|
const r2_uploader_1 = require("@empiricalrun/r2-uploader");
|
|
8
|
-
const
|
|
8
|
+
const fs_1 = __importDefault(require("fs"));
|
|
9
9
|
const path_1 = __importDefault(require("path"));
|
|
10
10
|
const logger_1 = require("../bin/logger");
|
|
11
11
|
const uploader_1 = require("../uploader");
|
|
@@ -93,10 +93,10 @@ class TestGenUpdatesReporter {
|
|
|
93
93
|
}
|
|
94
94
|
try {
|
|
95
95
|
// upload current screenshot to r2 and report it to reporter
|
|
96
|
-
if (!
|
|
97
|
-
|
|
96
|
+
if (!fs_1.default.existsSync(path_1.default.join(this.repoDir, "gen-assets"))) {
|
|
97
|
+
fs_1.default.mkdirSync(path_1.default.join(this.repoDir, "gen-assets"));
|
|
98
98
|
}
|
|
99
|
-
|
|
99
|
+
fs_1.default.writeFileSync(path_1.default.join(this.repoDir, "gen-assets", `current-view-${Date.now()}.png`), buffer);
|
|
100
100
|
const uploadDir = (0, uploader_1.getUploadPathForRun)(reporterConfig?.projectRepoName);
|
|
101
101
|
const files = await (0, r2_uploader_1.uploadDirectory)({
|
|
102
102
|
sourceDir: path_1.default.join(this.repoDir, "gen-assets"),
|
|
@@ -110,7 +110,7 @@ class TestGenUpdatesReporter {
|
|
|
110
110
|
type: "current-snapshot",
|
|
111
111
|
message: JSON.stringify({ type: "current-view", url }),
|
|
112
112
|
}));
|
|
113
|
-
|
|
113
|
+
fs_1.default.rmdirSync(path_1.default.join(this.repoDir, "gen-assets"), {
|
|
114
114
|
recursive: true,
|
|
115
115
|
});
|
|
116
116
|
}
|
package/dist/test-build/index.js
CHANGED
|
@@ -4,12 +4,12 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.downloadBuild = exports.hasDownloadScript = void 0;
|
|
7
|
-
const
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
8
|
const logger_1 = require("../bin/logger");
|
|
9
9
|
const exec_1 = require("../utils/exec");
|
|
10
10
|
async function getPackageJSON() {
|
|
11
11
|
const packageJSONPath = "package.json";
|
|
12
|
-
const packageJsonStr =
|
|
12
|
+
const packageJsonStr = fs_1.default.readFileSync(packageJSONPath, "utf-8");
|
|
13
13
|
return JSON.parse(packageJsonStr);
|
|
14
14
|
}
|
|
15
15
|
async function hasDownloadScript() {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { TraceClient } from "@empiricalrun/llm";
|
|
1
2
|
import { PendingToolCall, Tool, ToolResult } from "@empiricalrun/llm/chat";
|
|
2
3
|
import { SupportedChatModels } from "../agent/chat/types";
|
|
3
4
|
export type { SupportedChatModels };
|
|
@@ -13,6 +14,6 @@ export declare class ToolCallService {
|
|
|
13
14
|
getTools(): Promise<{
|
|
14
15
|
tools: Tool[];
|
|
15
16
|
}>;
|
|
16
|
-
execute(toolCalls: PendingToolCall[], isRemote: boolean): Promise<ToolResult[]>;
|
|
17
|
+
execute(toolCalls: PendingToolCall[], isRemote: boolean, trace?: TraceClient): Promise<ToolResult[]>;
|
|
17
18
|
}
|
|
18
19
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tool-call-service/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAE3E,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAa1D,YAAY,EAAE,mBAAmB,EAAE,CAAC;AAEpC,KAAK,aAAa,GAAG;IACnB,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,KAAK,EAAE,GAAG,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC;CACpD,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tool-call-service/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,eAAe,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAE3E,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAa1D,YAAY,EAAE,mBAAmB,EAAE,CAAC;AAEpC,KAAK,aAAa,GAAG;IACnB,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,KAAK,EAAE,GAAG,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC;CACpD,CAAC;AA4BF,qBAAa,eAAe;IAC1B,KAAK,EAAE,IAAI,EAAE,CAAM;IACnB,aAAa,EAAE,aAAa,CAAM;IAClC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,aAAa,EAAE,mBAAmB,CAAC;gBAGjC,aAAa,EAAE,MAAM,GAAG,IAAI,EAC5B,aAAa,EAAE,mBAAmB;IAgB9B,QAAQ;;;IAaR,OAAO,CACX,SAAS,EAAE,eAAe,EAAE,EAC5B,QAAQ,EAAE,OAAO,EACjB,KAAK,CAAC,EAAE,WAAW,GAClB,OAAO,CAAC,UAAU,EAAE,CAAC;CAgDzB"}
|
|
@@ -19,7 +19,10 @@ async function sendToolRequestToRemoteQueue(payload) {
|
|
|
19
19
|
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
|
|
20
20
|
},
|
|
21
21
|
});
|
|
22
|
-
const queueUrl = process.env.
|
|
22
|
+
const queueUrl = process.env.TOOL_EXECUTION_SQS_URL;
|
|
23
|
+
if (!queueUrl) {
|
|
24
|
+
throw new Error("TOOL_EXECUTION_SQS_URL is required for remote execution.");
|
|
25
|
+
}
|
|
23
26
|
await sqs.send(new client_sqs_1.SendMessageCommand({
|
|
24
27
|
QueueUrl: queueUrl,
|
|
25
28
|
MessageBody: JSON.stringify(payload),
|
|
@@ -58,9 +61,8 @@ class ToolCallService {
|
|
|
58
61
|
}
|
|
59
62
|
return { tools: this.tools };
|
|
60
63
|
}
|
|
61
|
-
async execute(toolCalls, isRemote) {
|
|
64
|
+
async execute(toolCalls, isRemote, trace) {
|
|
62
65
|
if (isRemote && this.chatSessionId) {
|
|
63
|
-
console.log("Executing tool remotely", toolCalls);
|
|
64
66
|
await sendToolRequestToRemoteQueue({
|
|
65
67
|
toolCalls,
|
|
66
68
|
requestId: crypto.randomUUID(),
|
|
@@ -75,23 +77,32 @@ class ToolCallService {
|
|
|
75
77
|
else {
|
|
76
78
|
const toolResults = [];
|
|
77
79
|
for (const toolCall of toolCalls) {
|
|
80
|
+
const span = trace?.span({
|
|
81
|
+
name: `tool: ${toolCall.name}`,
|
|
82
|
+
input: toolCall.input,
|
|
83
|
+
});
|
|
78
84
|
const toolExecutor = this.toolExecutors[toolCall.name];
|
|
79
85
|
if (!toolExecutor) {
|
|
80
|
-
|
|
86
|
+
const errorResult = {
|
|
81
87
|
isError: true,
|
|
82
88
|
result: `Invalid function/tool call: invalid_tool_call not found`,
|
|
83
|
-
}
|
|
89
|
+
};
|
|
90
|
+
toolResults.push(errorResult);
|
|
91
|
+
span?.end({ output: errorResult });
|
|
84
92
|
continue;
|
|
85
93
|
}
|
|
86
94
|
try {
|
|
87
95
|
const result = await toolExecutor(toolCall.input);
|
|
88
96
|
toolResults.push(result);
|
|
97
|
+
span?.end({ output: result });
|
|
89
98
|
}
|
|
90
99
|
catch (error) {
|
|
91
|
-
|
|
100
|
+
const errorResult = {
|
|
92
101
|
isError: true,
|
|
93
102
|
result: error instanceof Error ? error.message : String(error),
|
|
94
|
-
}
|
|
103
|
+
};
|
|
104
|
+
toolResults.push(errorResult);
|
|
105
|
+
span?.end({ output: errorResult });
|
|
95
106
|
}
|
|
96
107
|
}
|
|
97
108
|
return toolResults;
|
package/dist/tools/grep.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"grep.d.ts","sourceRoot":"","sources":["../../src/tools/grep.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAc,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"grep.d.ts","sourceRoot":"","sources":["../../src/tools/grep.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAc,MAAM,wBAAwB,CAAC;AAmB/D,eAAO,MAAM,QAAQ,EAAE,IAiDtB,CAAC"}
|
package/dist/tools/grep.js
CHANGED
|
@@ -5,7 +5,6 @@ const child_process_1 = require("child_process");
|
|
|
5
5
|
const util_1 = require("util");
|
|
6
6
|
const zod_1 = require("zod");
|
|
7
7
|
const repo_tree_1 = require("../utils/repo-tree");
|
|
8
|
-
const execAsync = (0, util_1.promisify)(child_process_1.exec);
|
|
9
8
|
const GrepInputSchema = zod_1.z.object({
|
|
10
9
|
pattern: zod_1.z.string().describe("The pattern to search for"),
|
|
11
10
|
directory: zod_1.z
|
|
@@ -40,6 +39,7 @@ exports.grepTool = {
|
|
|
40
39
|
// Using -n to show line numbers and removed -l to show actual matches
|
|
41
40
|
cmd = `find ${dir} ${excludeFind} -name "${input.filePattern}" -exec grep -rin "${input.pattern}" {} \\;`;
|
|
42
41
|
}
|
|
42
|
+
const execAsync = (0, util_1.promisify)(child_process_1.exec);
|
|
43
43
|
const { stdout, stderr } = await execAsync(cmd);
|
|
44
44
|
if (stdout) {
|
|
45
45
|
return {
|
|
@@ -53,6 +53,7 @@ exports.grepTool = {
|
|
|
53
53
|
};
|
|
54
54
|
}
|
|
55
55
|
catch (error) {
|
|
56
|
+
console.error("Error executing grep", error);
|
|
56
57
|
return {
|
|
57
58
|
isError: true,
|
|
58
59
|
result: error instanceof Error ? error.message : String(error),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"str_replace_editor.d.ts","sourceRoot":"","sources":["../../src/tools/str_replace_editor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AA2B1D,UAAU,eAAe;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAwC1D;AAMD;;;GAGG;AACH,wBAAsB,wBAAwB,CAC5C,KAAK,EAAE,eAAe,GACrB,OAAO,CAAC,UAAU,CAAC,
|
|
1
|
+
{"version":3,"file":"str_replace_editor.d.ts","sourceRoot":"","sources":["../../src/tools/str_replace_editor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AA2B1D,UAAU,eAAe;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAwC1D;AAMD;;;GAGG;AACH,wBAAsB,wBAAwB,CAC5C,KAAK,EAAE,eAAe,GACrB,OAAO,CAAC,UAAU,CAAC,CAmJrB;AA+FD,eAAO,MAAM,eAAe,EAAE,IAAI,EAKjC,CAAC"}
|
|
@@ -86,6 +86,7 @@ async function strReplaceEditorExecutor(input) {
|
|
|
86
86
|
let content;
|
|
87
87
|
let lines;
|
|
88
88
|
let newContent;
|
|
89
|
+
let typeCheckErrors;
|
|
89
90
|
switch (input.command) {
|
|
90
91
|
case "view":
|
|
91
92
|
// TODO: This assumes repoDir is process.cwd()
|
|
@@ -150,6 +151,7 @@ async function strReplaceEditorExecutor(input) {
|
|
|
150
151
|
const escapedOldStr = escapeRegExp(input.old_str);
|
|
151
152
|
const occurences = content.match(new RegExp(escapedOldStr, "g"));
|
|
152
153
|
if (occurences && occurences.length > 1) {
|
|
154
|
+
// TODO: Help find unique matches
|
|
153
155
|
return {
|
|
154
156
|
result: `Error: old_str found ${occurences.length} times in file: ${filePath}. Please provide more context to make a unique match.`,
|
|
155
157
|
isError: true,
|
|
@@ -157,10 +159,10 @@ async function strReplaceEditorExecutor(input) {
|
|
|
157
159
|
}
|
|
158
160
|
newContent = content.replace(input.old_str, input.new_str);
|
|
159
161
|
fs_1.default.writeFileSync(filePath, newContent);
|
|
160
|
-
|
|
161
|
-
if (
|
|
162
|
+
typeCheckErrors = (0, web_1.validateTypescript)(filePath);
|
|
163
|
+
if (typeCheckErrors.length > 0) {
|
|
162
164
|
return {
|
|
163
|
-
result: `Edits to file ${filePath} have been applied. However, type checks are failing with errors:\n${
|
|
165
|
+
result: `Edits to file ${filePath} have been applied. However, type checks are failing with errors:\n${typeCheckErrors.join("\n")}`,
|
|
164
166
|
isError: true,
|
|
165
167
|
};
|
|
166
168
|
}
|
|
@@ -180,20 +182,29 @@ async function strReplaceEditorExecutor(input) {
|
|
|
180
182
|
lines = content.split("\n");
|
|
181
183
|
lines.splice(input.insert_line, 0, input.new_str);
|
|
182
184
|
fs_1.default.writeFileSync(filePath, lines.join("\n"));
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
185
|
+
typeCheckErrors = (0, web_1.validateTypescript)(filePath);
|
|
186
|
+
if (typeCheckErrors.length > 0) {
|
|
187
|
+
return {
|
|
188
|
+
result: `Insertion in file ${filePath} was applied. However, type checks are failing with errors:\n${typeCheckErrors.join("\n")}`,
|
|
189
|
+
isError: true,
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
else {
|
|
193
|
+
return {
|
|
194
|
+
result: `Insertion in file ${filePath} was applied. Type checks have also passed.`,
|
|
195
|
+
isError: false,
|
|
196
|
+
};
|
|
197
|
+
}
|
|
187
198
|
case "undo_edit":
|
|
188
199
|
if (hasBackup(filePath)) {
|
|
189
200
|
restoreBackup(filePath);
|
|
190
201
|
return {
|
|
191
|
-
result:
|
|
202
|
+
result: `Successfully restored ${filePath} from backup`,
|
|
192
203
|
isError: false,
|
|
193
204
|
};
|
|
194
205
|
}
|
|
195
206
|
return {
|
|
196
|
-
result:
|
|
207
|
+
result: `No backup file found for ${filePath}`,
|
|
197
208
|
isError: true,
|
|
198
209
|
};
|
|
199
210
|
default:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@empiricalrun/test-gen",
|
|
3
|
-
"version": "0.56.
|
|
3
|
+
"version": "0.56.2",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"registry": "https://registry.npmjs.org/",
|
|
6
6
|
"access": "public"
|
|
@@ -14,10 +14,6 @@
|
|
|
14
14
|
"types": "./dist/agent/master/run.d.ts",
|
|
15
15
|
"default": "./dist/agent/master/run.js"
|
|
16
16
|
},
|
|
17
|
-
"./chat/state": {
|
|
18
|
-
"types": "./dist/agent/chat/state.d.ts",
|
|
19
|
-
"default": "./dist/agent/chat/state.js"
|
|
20
|
-
},
|
|
21
17
|
"./chat": {
|
|
22
18
|
"types": "./dist/agent/chat/exports.d.ts",
|
|
23
19
|
"default": "./dist/agent/chat/exports.js"
|
|
@@ -50,7 +46,6 @@
|
|
|
50
46
|
"dotenv": "^16.4.5",
|
|
51
47
|
"eslint": "^8.57.0",
|
|
52
48
|
"express": "^4.19.2",
|
|
53
|
-
"fs-extra": "^11.2.0",
|
|
54
49
|
"ignore": "^5.3.1",
|
|
55
50
|
"inquirer": "^12.4.2",
|
|
56
51
|
"jsdom": "^26.0.0",
|
|
@@ -65,16 +60,15 @@
|
|
|
65
60
|
"tsx": "^4.16.2",
|
|
66
61
|
"typescript": "^5.3.3",
|
|
67
62
|
"zod": "^3.23.8",
|
|
68
|
-
"@empiricalrun/llm": "^0.15.
|
|
63
|
+
"@empiricalrun/llm": "^0.15.2",
|
|
69
64
|
"@empiricalrun/r2-uploader": "^0.3.8",
|
|
70
|
-
"@empiricalrun/test-run": "^0.8.
|
|
65
|
+
"@empiricalrun/test-run": "^0.8.3"
|
|
71
66
|
},
|
|
72
67
|
"devDependencies": {
|
|
73
68
|
"@playwright/test": "1.47.1",
|
|
74
69
|
"@types/async-retry": "^1.4.8",
|
|
75
70
|
"@types/detect-port": "^1.3.5",
|
|
76
71
|
"@types/express": "^4.17.21",
|
|
77
|
-
"@types/fs-extra": "^11.0.4",
|
|
78
72
|
"@types/js-levenshtein": "^1.1.3",
|
|
79
73
|
"@types/jsdom": "^21.1.7",
|
|
80
74
|
"@types/serve-handler": "^6.1.4",
|