@empiricalrun/test-gen 0.55.0 → 0.56.1
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 +27 -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 +39 -21
- package/dist/agent/chat/agent-loop.d.ts +3 -1
- package/dist/agent/chat/agent-loop.d.ts.map +1 -1
- package/dist/agent/chat/agent-loop.js +7 -23
- package/dist/agent/chat/exports.d.ts +8 -0
- package/dist/agent/chat/exports.d.ts.map +1 -0
- package/dist/agent/chat/exports.js +7 -0
- package/dist/agent/chat/index.d.ts.map +1 -1
- package/dist/agent/chat/index.js +5 -0
- package/dist/agent/chat/repo.js +4 -4
- 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/index.js +4 -2
- 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.d.ts +2 -9
- package/dist/test-build/index.d.ts.map +1 -1
- package/dist/test-build/index.js +18 -17
- package/dist/tool-call-service/index.d.ts +6 -9
- package/dist/tool-call-service/index.d.ts.map +1 -1
- package/dist/tool-call-service/index.js +50 -36
- package/dist/tools/download-build.d.ts +3 -0
- package/dist/tools/download-build.d.ts.map +1 -0
- package/dist/tools/download-build.js +39 -0
- package/dist/tools/grep.d.ts.map +1 -1
- package/dist/tools/grep.js +1 -1
- package/dist/tools/str_replace_editor.d.ts.map +1 -1
- package/dist/tools/str_replace_editor.js +20 -9
- package/dist/tools/utils/index.d.ts.map +1 -1
- package/package.json +7 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,32 @@
|
|
|
1
1
|
# @empiricalrun/test-gen
|
|
2
2
|
|
|
3
|
+
## 0.56.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- d05bb69: chore: remove fs-extra
|
|
8
|
+
- e1e2564: fix: avoid global promisify calls
|
|
9
|
+
- 803f61f: fix: run type checks for file inserts in text editor tools
|
|
10
|
+
- Updated dependencies [d05bb69]
|
|
11
|
+
- @empiricalrun/test-run@0.8.2
|
|
12
|
+
|
|
13
|
+
## 0.56.0
|
|
14
|
+
|
|
15
|
+
### Minor Changes
|
|
16
|
+
|
|
17
|
+
- b073084: feat: new APIs and refactor to introduce tool execute service
|
|
18
|
+
|
|
19
|
+
### Patch Changes
|
|
20
|
+
|
|
21
|
+
- 93d7a0b: feat: add tool call for downloading builds
|
|
22
|
+
- a58ac3f: feat: add dashboard agent integration and optimize tsx handling
|
|
23
|
+
- Updated dependencies [87af227]
|
|
24
|
+
- Updated dependencies [3831109]
|
|
25
|
+
- Updated dependencies [a58ac3f]
|
|
26
|
+
- Updated dependencies [f77e33d]
|
|
27
|
+
- @empiricalrun/llm@0.15.1
|
|
28
|
+
- @empiricalrun/test-run@0.8.1
|
|
29
|
+
|
|
3
30
|
## 0.55.0
|
|
4
31
|
|
|
5
32
|
### 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;
|
|
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,CA0B/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,14 +4,15 @@ 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");
|
|
11
|
-
|
|
11
|
+
// For TypeScript type safety
|
|
12
|
+
let tsxImport = null;
|
|
12
13
|
const logger_1 = require("../../bin/logger");
|
|
13
14
|
const context_1 = require("../../bin/utils/context");
|
|
14
|
-
const
|
|
15
|
+
const fs_2 = require("../../bin/utils/fs");
|
|
15
16
|
const web_1 = require("../../bin/utils/platform/web");
|
|
16
17
|
const create_test_block_1 = require("../codegen/create-test-block");
|
|
17
18
|
const fix_ts_errors_1 = require("../codegen/fix-ts-errors");
|
|
@@ -32,10 +33,10 @@ async function addImportForCreateTest(testFilePath) {
|
|
|
32
33
|
// Instead of using "@empiricalrun/test-gen", we use the local dist file
|
|
33
34
|
// This is to avoid assuming that the test-gen package is installed in the project
|
|
34
35
|
const importSource = path_1.default.join(__dirname, "../../../dist/index.js");
|
|
35
|
-
if (!
|
|
36
|
+
if (!fs_1.default.existsSync(importSource)) {
|
|
36
37
|
throw new Error(`createTest import source not found at ${importSource}`);
|
|
37
38
|
}
|
|
38
|
-
|
|
39
|
+
fs_1.default.writeFileSync(testFilePath, (0, web_1.addNewImport)(fs_1.default.readFileSync(testFilePath, "utf-8"), ["createTest"], importSource));
|
|
39
40
|
}
|
|
40
41
|
async function prepareFileForUpdateScenario({ testCase, specPath, trace, }) {
|
|
41
42
|
const { name, suites } = testCase;
|
|
@@ -61,7 +62,7 @@ async function prepareFileForUpdateScenario({ testCase, specPath, trace, }) {
|
|
|
61
62
|
},
|
|
62
63
|
});
|
|
63
64
|
const scopeVariables = await (0, lexical_scoped_vars_1.getLexicalScopedVars)({
|
|
64
|
-
file:
|
|
65
|
+
file: fs_1.default.readFileSync(createTestFilePath, "utf-8"),
|
|
65
66
|
referencePoint: "await createTest",
|
|
66
67
|
trace: fetchScopeVariablesSpan,
|
|
67
68
|
});
|
|
@@ -91,7 +92,7 @@ async function prepareFileForUpdateScenario({ testCase, specPath, trace, }) {
|
|
|
91
92
|
async function replaceTodoWithCreateTest({ testFilePath, testCaseName, testCaseSuites, }) {
|
|
92
93
|
// This method is an alternative to prepareFileForUpdateScenario
|
|
93
94
|
// TODO: Does not support scoped variables and updates in POM files
|
|
94
|
-
const fileContent =
|
|
95
|
+
const fileContent = fs_1.default.readFileSync(testFilePath, "utf-8");
|
|
95
96
|
const todoRegex = /\/\/ TODO\(agent(?:\s+on\s+(\w+))?\):\s*(.*)/;
|
|
96
97
|
const todoMatch = fileContent.match(todoRegex);
|
|
97
98
|
if (!todoMatch) {
|
|
@@ -99,7 +100,7 @@ async function replaceTodoWithCreateTest({ testFilePath, testCaseName, testCaseS
|
|
|
99
100
|
}
|
|
100
101
|
const [, pageVarName] = todoMatch;
|
|
101
102
|
const pageVariable = pageVarName || "page"; // Default to "page" if not specified
|
|
102
|
-
|
|
103
|
+
fs_1.default.writeFileSync(testFilePath, fileContent.replace(todoRegex, (_, __, todoText) => `await createTest("${todoText.replace(/"/g, '\\"')}", ${pageVariable});`));
|
|
103
104
|
await addImportForCreateTest(testFilePath);
|
|
104
105
|
await markTestAsOnly({
|
|
105
106
|
testCaseName,
|
|
@@ -109,7 +110,7 @@ async function replaceTodoWithCreateTest({ testFilePath, testCaseName, testCaseS
|
|
|
109
110
|
}
|
|
110
111
|
exports.replaceTodoWithCreateTest = replaceTodoWithCreateTest;
|
|
111
112
|
async function markTestAsOnly({ testCaseName, testCaseSuites, specPath, }) {
|
|
112
|
-
const testFileContent =
|
|
113
|
+
const testFileContent = fs_1.default.readFileSync(specPath, "utf-8");
|
|
113
114
|
const { testBlock, testNode } = (0, web_1.getTypescriptTestBlock)({
|
|
114
115
|
scenarioName: testCaseName,
|
|
115
116
|
content: testFileContent,
|
|
@@ -120,7 +121,7 @@ async function markTestAsOnly({ testCaseName, testCaseSuites, specPath, }) {
|
|
|
120
121
|
// add test.only / describe.only to the spec file so that only that block is executed
|
|
121
122
|
if (!isFileMarkedSerial) {
|
|
122
123
|
const updatedTestFileContent = newContentsWithTestOnly(testFileContent, testBlock, testBlock, parentDescribe?.getText() || "");
|
|
123
|
-
|
|
124
|
+
fs_1.default.writeFileSync(specPath, updatedTestFileContent);
|
|
124
125
|
}
|
|
125
126
|
}
|
|
126
127
|
exports.markTestAsOnly = markTestAsOnly;
|
|
@@ -132,17 +133,17 @@ async function prepareFileForMasterAgent({ testCase, specPath, trace, }) {
|
|
|
132
133
|
const { name, suites } = testCase;
|
|
133
134
|
// check if the spec file exists
|
|
134
135
|
// if no then create a new file with test and expect imports
|
|
135
|
-
if (!
|
|
136
|
+
if (!fs_1.default.existsSync(specPath)) {
|
|
136
137
|
const fileCreateSpan = prepareFileSpan?.span({
|
|
137
138
|
name: "create-file",
|
|
138
139
|
input: { specPath },
|
|
139
140
|
});
|
|
140
|
-
|
|
141
|
+
fs_1.default.writeFileSync(specPath, "");
|
|
141
142
|
const fileContentWithImports = (0, web_1.addNewImport)("", ["test", "expect"], (0, web_1.getFixtureImportPath)(specPath));
|
|
142
|
-
|
|
143
|
+
fs_1.default.writeFileSync(specPath, fileContentWithImports, "utf-8");
|
|
143
144
|
fileCreateSpan?.end({ output: { specPath, fileContentWithImports } });
|
|
144
145
|
}
|
|
145
|
-
const existingContents =
|
|
146
|
+
const existingContents = fs_1.default.readFileSync(specPath, "utf-8");
|
|
146
147
|
const { testBlock } = (0, web_1.getTypescriptTestBlock)({
|
|
147
148
|
scenarioName: name,
|
|
148
149
|
suites,
|
|
@@ -154,13 +155,13 @@ async function prepareFileForMasterAgent({ testCase, specPath, trace, }) {
|
|
|
154
155
|
testCase,
|
|
155
156
|
file: specPath,
|
|
156
157
|
});
|
|
157
|
-
|
|
158
|
+
fs_1.default.writeFileSync(specPath, `${existingContents} \n\n ${newTestBlock}`, "utf-8");
|
|
158
159
|
const updatedContent = (0, web_1.injectCodeSnippetBySuiteChain)({
|
|
159
160
|
testFileContent: existingContents,
|
|
160
161
|
suites: testCase.suites,
|
|
161
162
|
codeSnippet: `\n\n${newTestBlock}`,
|
|
162
163
|
});
|
|
163
|
-
|
|
164
|
+
fs_1.default.writeFileSync(specPath, updatedContent, "utf-8");
|
|
164
165
|
}
|
|
165
166
|
const updatePath = await prepareFileForUpdateScenario({
|
|
166
167
|
testCase,
|
|
@@ -189,7 +190,7 @@ async function injectPwLocatorGenerator(page) {
|
|
|
189
190
|
pathToInstalledTestGen = process.cwd();
|
|
190
191
|
}
|
|
191
192
|
const annotateElementPath = path_1.default.join(pathToInstalledTestGen, "dist", "browser-injected-scripts", "annotate-elements.js");
|
|
192
|
-
if (!
|
|
193
|
+
if (!fs_1.default.existsSync(annotateElementPath)) {
|
|
193
194
|
throw new Error(`annotate-elements.js not found at path: ${annotateElementPath}`);
|
|
194
195
|
}
|
|
195
196
|
const remoteScriptResponses = await Promise.all([
|
|
@@ -198,7 +199,7 @@ async function injectPwLocatorGenerator(page) {
|
|
|
198
199
|
].map((url) => fetch(url)));
|
|
199
200
|
const scripts = await Promise.all([
|
|
200
201
|
...remoteScriptResponses.map((r) => r.text()),
|
|
201
|
-
|
|
202
|
+
fs_1.default.readFileSync(annotateElementPath, "utf-8"),
|
|
202
203
|
]);
|
|
203
204
|
page.on("load", async () => {
|
|
204
205
|
try {
|
|
@@ -295,8 +296,25 @@ exports.injectPwLocatorGenerator = injectPwLocatorGenerator;
|
|
|
295
296
|
* @return {*} {Promise<PlaywrightTestConfig>}
|
|
296
297
|
*/
|
|
297
298
|
async function readPlaywrightConfig(repoDir) {
|
|
299
|
+
if (typeof window !== "undefined") {
|
|
300
|
+
throw new Error("readPlaywrightConfig cannot be used in browser environments");
|
|
301
|
+
}
|
|
302
|
+
else {
|
|
303
|
+
// Only initialize on server side
|
|
304
|
+
// This will only execute on the server
|
|
305
|
+
await import("tsx/cjs/api")
|
|
306
|
+
.then((module) => {
|
|
307
|
+
tsxImport = module;
|
|
308
|
+
})
|
|
309
|
+
.catch((err) => {
|
|
310
|
+
console.error("Failed to import tsx:", err);
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
if (!tsxImport) {
|
|
314
|
+
throw new Error("tsx module not available");
|
|
315
|
+
}
|
|
298
316
|
const [lastDir] = repoDir.split("/").reverse();
|
|
299
|
-
const playwrightConfig = (await
|
|
317
|
+
const playwrightConfig = (await tsxImport.require("./playwright.config.ts", `${repoDir}/${lastDir}`)).default;
|
|
300
318
|
return playwrightConfig;
|
|
301
319
|
}
|
|
302
320
|
exports.readPlaywrightConfig = readPlaywrightConfig;
|
|
@@ -377,7 +395,7 @@ class TeardownManager {
|
|
|
377
395
|
teardownFiles = [];
|
|
378
396
|
async getAllTeardownFiles() {
|
|
379
397
|
const teardownFileRegex = /.*\.teardown\.ts/;
|
|
380
|
-
const teardownFiles = await (0,
|
|
398
|
+
const teardownFiles = await (0, fs_2.readFilesInDirectory)(this.directory, (fileName) => teardownFileRegex.test(fileName));
|
|
381
399
|
return teardownFiles;
|
|
382
400
|
}
|
|
383
401
|
async skipTeardownFile(filePath) {
|
|
@@ -413,7 +431,7 @@ class TeardownManager {
|
|
|
413
431
|
}
|
|
414
432
|
unskipAll() {
|
|
415
433
|
this.teardownFiles.forEach(({ filePath, content }) => {
|
|
416
|
-
|
|
434
|
+
fs_1.default.writeFileSync(filePath, content, "utf-8");
|
|
417
435
|
});
|
|
418
436
|
}
|
|
419
437
|
}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { TraceClient } from "@empiricalrun/llm";
|
|
2
2
|
import { IChatModel } from "@empiricalrun/llm/chat";
|
|
3
|
+
import { ToolCallService } from "../../tool-call-service";
|
|
3
4
|
import { ReporterFunction, SupportedChatModels } from "./types";
|
|
4
|
-
export declare function chatAgentLoop({ chatModel, selectedModel, reporter, trace, }: {
|
|
5
|
+
export declare function chatAgentLoop({ chatModel, selectedModel, reporter, trace, toolCallService, }: {
|
|
5
6
|
chatModel: IChatModel<any>;
|
|
6
7
|
selectedModel: SupportedChatModels;
|
|
8
|
+
toolCallService: ToolCallService;
|
|
7
9
|
reporter: ReporterFunction;
|
|
8
10
|
trace?: TraceClient;
|
|
9
11
|
}): Promise<void>;
|
|
@@ -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,EACL,UAAU,EAIX,MAAM,wBAAwB,CAAC;
|
|
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,EACL,UAAU,EAIX,MAAM,wBAAwB,CAAC;AAGhC,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"}
|
|
@@ -3,8 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.chatAgentLoop = void 0;
|
|
4
4
|
const chat_1 = require("@empiricalrun/llm/chat");
|
|
5
5
|
const picocolors_1 = require("picocolors");
|
|
6
|
-
const tool_call_service_1 = require("../../tool-call-service");
|
|
7
|
-
const str_replace_editor_1 = require("../../tools/str_replace_editor");
|
|
8
6
|
const prompt_1 = require("./prompt");
|
|
9
7
|
const state_1 = require("./state");
|
|
10
8
|
function getModelName(model) {
|
|
@@ -20,31 +18,18 @@ const log = (...args) => {
|
|
|
20
18
|
console.log((0, picocolors_1.gray)(args.join(" ")));
|
|
21
19
|
};
|
|
22
20
|
const isRemote = process.env.TOOL_EXECUTION_IS_REMOTE === "true" || false;
|
|
23
|
-
async function chatAgentLoop({ chatModel, selectedModel, reporter, trace, }) {
|
|
21
|
+
async function chatAgentLoop({ chatModel, selectedModel, reporter, trace, toolCallService, }) {
|
|
24
22
|
const systemPrompt = await (0, prompt_1.buildSystemPrompt)();
|
|
25
23
|
trace?.update({ input: { systemPrompt } });
|
|
26
|
-
const
|
|
27
|
-
const { tools } = await toolCallService.getTools(selectedModel);
|
|
24
|
+
const { tools } = await toolCallService.getTools();
|
|
28
25
|
while (!chatModel.askUserForInput) {
|
|
29
26
|
const toolCalls = chatModel.getPendingToolCalls();
|
|
27
|
+
console.log("toolCalls", toolCalls);
|
|
30
28
|
if (toolCalls.length) {
|
|
31
|
-
const toolResults =
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
let callResponse = await toolCallService.execute({
|
|
36
|
-
tool: {
|
|
37
|
-
name: call.name,
|
|
38
|
-
input: call.input,
|
|
39
|
-
},
|
|
40
|
-
}, isRemote);
|
|
41
|
-
if (callResponse.isError) {
|
|
42
|
-
log(`Tool ${call.name} failed: ${callResponse.result}`);
|
|
43
|
-
}
|
|
44
|
-
else {
|
|
45
|
-
log(`Tool ${call.name} completed`);
|
|
46
|
-
}
|
|
47
|
-
toolResults.push(callResponse);
|
|
29
|
+
const toolResults = await toolCallService.execute(toolCalls, isRemote);
|
|
30
|
+
if (isRemote) {
|
|
31
|
+
log(`Tool call remote execution in progress`);
|
|
32
|
+
break;
|
|
48
33
|
}
|
|
49
34
|
chatModel.pushToolResultsMessage(toolCalls, toolResults);
|
|
50
35
|
}
|
|
@@ -62,6 +47,5 @@ async function chatAgentLoop({ chatModel, selectedModel, reporter, trace, }) {
|
|
|
62
47
|
const latest = chatModel.getHumanReadableLatestMessage();
|
|
63
48
|
await reporter((0, state_1.chatStateFromModel)(chatModel, selectedModel), latest);
|
|
64
49
|
}
|
|
65
|
-
(0, str_replace_editor_1.cleanupBackupFiles)(process.cwd());
|
|
66
50
|
}
|
|
67
51
|
exports.chatAgentLoop = chatAgentLoop;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { IChatModel } from "@empiricalrun/llm/chat";
|
|
2
|
+
import { chatAgentLoop } from "./agent-loop";
|
|
3
|
+
import { createChatModel } from "./model";
|
|
4
|
+
import { ChatStateOnDisk } from "./state";
|
|
5
|
+
import { ReporterFunction, SupportedChatModels } from "./types";
|
|
6
|
+
export { chatAgentLoop, createChatModel };
|
|
7
|
+
export type { ChatStateOnDisk, IChatModel, ReporterFunction, SupportedChatModels, };
|
|
8
|
+
//# sourceMappingURL=exports.d.ts.map
|
|
@@ -0,0 +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,EAAE,aAAa,EAAE,eAAe,EAAE,CAAC;AAE1C,YAAY,EACV,eAAe,EACf,UAAU,EACV,gBAAgB,EAChB,mBAAmB,GACpB,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createChatModel = exports.chatAgentLoop = void 0;
|
|
4
|
+
const agent_loop_1 = require("./agent-loop");
|
|
5
|
+
Object.defineProperty(exports, "chatAgentLoop", { enumerable: true, get: function () { return agent_loop_1.chatAgentLoop; } });
|
|
6
|
+
const model_1 = require("./model");
|
|
7
|
+
Object.defineProperty(exports, "createChatModel", { enumerable: true, get: function () { return model_1.createChatModel; } });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/agent/chat/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/agent/chat/index.ts"],"names":[],"mappings":"AAaA,OAAO,EAAoB,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAiBhE,wBAAsB,kBAAkB,CAAC,EACvC,mBAAmB,EACnB,aAAa,EACb,oBAAoB,GACrB,EAAE;IACD,aAAa,EAAE,mBAAmB,CAAC;IACnC,mBAAmB,EAAE,OAAO,CAAC;IAC7B,oBAAoB,EAAE,MAAM,GAAG,SAAS,CAAC;CAC1C,iBAsFA;AAuBD,wBAAsB,wBAAwB,CAAC,EAC7C,aAAa,EACb,aAAa,GACd,EAAE;IACD,aAAa,EAAE,mBAAmB,CAAC;IACnC,aAAa,EAAE,MAAM,CAAC;CACvB,iBA2CA"}
|
package/dist/agent/chat/index.js
CHANGED
|
@@ -4,6 +4,7 @@ exports.runChatAgentForDashboard = exports.runChatAgentForCLI = void 0;
|
|
|
4
4
|
const llm_1 = require("@empiricalrun/llm");
|
|
5
5
|
const picocolors_1 = require("picocolors");
|
|
6
6
|
const human_in_the_loop_1 = require("../../human-in-the-loop");
|
|
7
|
+
const tool_call_service_1 = require("../../tool-call-service");
|
|
7
8
|
const git_1 = require("../../utils/git");
|
|
8
9
|
const agent_loop_1 = require("./agent-loop");
|
|
9
10
|
const model_1 = require("./model");
|
|
@@ -83,11 +84,13 @@ async function runChatAgentForCLI({ useDiskForChatState, selectedModel, initialP
|
|
|
83
84
|
}
|
|
84
85
|
else {
|
|
85
86
|
// TODO: Should we pass a loader function? That would allow us to show a spinner
|
|
87
|
+
const toolCallService = new tool_call_service_1.ToolCallService(null, selectedModel);
|
|
86
88
|
await (0, agent_loop_1.chatAgentLoop)({
|
|
87
89
|
chatModel,
|
|
88
90
|
selectedModel,
|
|
89
91
|
reporter: reporterFunc,
|
|
90
92
|
trace,
|
|
93
|
+
toolCallService,
|
|
91
94
|
});
|
|
92
95
|
}
|
|
93
96
|
}
|
|
@@ -125,6 +128,7 @@ async function runChatAgentForDashboard({ chatSessionId, selectedModel, }) {
|
|
|
125
128
|
chatSessionId,
|
|
126
129
|
},
|
|
127
130
|
});
|
|
131
|
+
const toolCallService = new tool_call_service_1.ToolCallService(chatSessionId, selectedModel);
|
|
128
132
|
await (0, git_1.checkoutBranch)(branchName);
|
|
129
133
|
let chatModel = (0, model_1.createChatModel)(chatState.messages, selectedModel);
|
|
130
134
|
let reporterFunc = async (chatState, latest) => {
|
|
@@ -147,6 +151,7 @@ async function runChatAgentForDashboard({ chatSessionId, selectedModel, }) {
|
|
|
147
151
|
selectedModel,
|
|
148
152
|
reporter: reporterFunc,
|
|
149
153
|
trace,
|
|
154
|
+
toolCallService,
|
|
150
155
|
});
|
|
151
156
|
await (0, git_1.commitLocalAndPushBranchToRemote)(branchName);
|
|
152
157
|
}
|
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
|
}
|
|
@@ -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,
|