@empiricalrun/test-gen 0.42.12 → 0.42.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @empiricalrun/test-gen
2
2
 
3
+ ## 0.42.14
4
+
5
+ ### Patch Changes
6
+
7
+ - da02df2: fix: added tool call for code generation and writing code updates to file
8
+
9
+ ## 0.42.13
10
+
11
+ ### Patch Changes
12
+
13
+ - 161b404: fix: added colors in annnotations
14
+
3
15
  ## 0.42.12
4
16
 
5
17
  ### Patch Changes
@@ -0,0 +1,13 @@
1
+ import { TraceClient } from "@empiricalrun/llm";
2
+ import { CustomLogger } from "../../bin/logger";
3
+ import { CodeUpdate } from "./types";
4
+ export declare function systemPromptBuilderForRepoEdit(files: string): string;
5
+ export declare function generateCodeAndApplyChanges({ task, trace, logger, getRelevantFiles, }: {
6
+ task: string;
7
+ trace?: TraceClient;
8
+ logger?: CustomLogger;
9
+ getRelevantFiles: () => Promise<{
10
+ prompt: string | undefined;
11
+ }>;
12
+ }): Promise<CodeUpdate[]>;
13
+ //# sourceMappingURL=generate-code-apply-changes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate-code-apply-changes.d.ts","sourceRoot":"","sources":["../../../src/agent/codegen/generate-code-apply-changes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuB,WAAW,EAAE,MAAM,mBAAmB,CAAC;AASrE,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAOhD,OAAO,EAAsB,UAAU,EAAsB,MAAM,SAAS,CAAC;AAqL7E,wBAAgB,8BAA8B,CAAC,KAAK,EAAE,MAAM,UAkD3D;AAgED,wBAAsB,2BAA2B,CAAC,EAChD,IAAI,EACJ,KAAK,EACL,MAAM,EACN,gBAAgB,GACjB,EAAE;IACD,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,gBAAgB,EAAE,MAAM,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,GAAG,SAAS,CAAA;KAAE,CAAC,CAAC;CACjE,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAyLxB"}
@@ -0,0 +1,421 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.generateCodeAndApplyChanges = exports.systemPromptBuilderForRepoEdit = void 0;
7
+ const llm_1 = require("@empiricalrun/llm");
8
+ const fs_extra_1 = __importDefault(require("fs-extra"));
9
+ const path_1 = require("path");
10
+ const constants_1 = require("../../constants");
11
+ const utils_1 = require("../utils");
12
+ const types_1 = require("./types");
13
+ const utils_2 = require("./utils");
14
+ function getCodeEditorToolCalls() {
15
+ const strReplace = {
16
+ name: "code-block-replace",
17
+ description: "replace the code block with the provided code",
18
+ schema: {
19
+ type: "function",
20
+ function: {
21
+ name: types_1.CodeEditorToolCall.STR_REPLACE,
22
+ description: "replace the code block with the provided code",
23
+ parameters: {
24
+ type: "object",
25
+ properties: {
26
+ reason: {
27
+ type: "string",
28
+ description: "reason for why the current block is selected for replacement and why is it needed.",
29
+ },
30
+ filePath: {
31
+ type: "string",
32
+ description: "path of the file where the code block is present",
33
+ },
34
+ oldCode: {
35
+ type: "string",
36
+ description: "old code block to be replaced",
37
+ },
38
+ newCode: {
39
+ type: "string",
40
+ description: "new code block to replace the old code block",
41
+ },
42
+ },
43
+ required: ["reason", "filePath", "oldCode", "newCode"],
44
+ additionalProperties: false,
45
+ },
46
+ },
47
+ },
48
+ };
49
+ const createFile = {
50
+ name: "create_file",
51
+ description: "create a new file with the provided code if the file doesn't exist",
52
+ schema: {
53
+ type: "function",
54
+ function: {
55
+ name: types_1.CodeEditorToolCall.CREATE_FILE,
56
+ description: "create a new file with the provided code if the file doesn't exist",
57
+ parameters: {
58
+ type: "object",
59
+ properties: {
60
+ reason: {
61
+ type: "string",
62
+ description: "reason for why the file is needed and what is the purpose of the file.",
63
+ },
64
+ filePath: {
65
+ type: "string",
66
+ description: "path of the file that needs to be created",
67
+ },
68
+ code: {
69
+ type: "string",
70
+ description: "code to be written to the file",
71
+ },
72
+ },
73
+ required: ["reason", "filePath", "code"],
74
+ additionalProperties: false,
75
+ },
76
+ },
77
+ },
78
+ };
79
+ return [strReplace, createFile].map((tool) => tool.schema);
80
+ }
81
+ function getPlannerToolCalls() {
82
+ const planner = {
83
+ name: "change_plan",
84
+ description: "Provides the plan for the changes to be made",
85
+ schema: {
86
+ type: "function",
87
+ function: {
88
+ name: "change_plan",
89
+ description: "Provides the plan for the changes to be made",
90
+ parameters: {
91
+ type: "object",
92
+ properties: {
93
+ reason: {
94
+ type: "string",
95
+ description: "Reason for providing the plan. Why a certain file needed the change ? Are you sure that all the changes required are present in the plan ?",
96
+ },
97
+ plan: {
98
+ type: "string",
99
+ description: "Plan given to code agent to execute. The plan should be readable and easy to understand.",
100
+ },
101
+ },
102
+ additionalProperties: false,
103
+ required: ["reason", "plan"],
104
+ },
105
+ },
106
+ },
107
+ };
108
+ const exit = {
109
+ name: "exit",
110
+ description: "Called when there are no more changes to be made. All the changes are done.",
111
+ schema: {
112
+ type: "function",
113
+ function: {
114
+ name: "exit",
115
+ description: "Called when there are no more changes to be made. All the changes are done",
116
+ parameters: {
117
+ type: "object",
118
+ properties: {
119
+ reason: {
120
+ type: "string",
121
+ description: "Reason for marking the task as done.",
122
+ },
123
+ },
124
+ additionalProperties: false,
125
+ },
126
+ },
127
+ },
128
+ };
129
+ return [planner, exit].map((tool) => tool.schema);
130
+ }
131
+ async function getPlanForCodeEditorAgent({ prompt, trace, }) {
132
+ const promptSpan = trace?.span({
133
+ name: "planner-agent",
134
+ input: {
135
+ prompt,
136
+ },
137
+ });
138
+ const llm = new llm_1.LLM({
139
+ trace: promptSpan,
140
+ provider: "openai",
141
+ defaultModel: "o3-mini-2025-01-31",
142
+ providerApiKey: constants_1.MODEL_API_KEYS["openai"],
143
+ });
144
+ const completion = await llm.createChatCompletion({
145
+ messages: prompt,
146
+ modelParameters: {
147
+ max_completion_tokens: constants_1.DEFAULT_O1_MODEL_PARAMETERS.max_completion_tokens,
148
+ reasoning_effort: "high",
149
+ tool_choice: "required",
150
+ },
151
+ trace: promptSpan,
152
+ tools: getPlannerToolCalls(),
153
+ });
154
+ promptSpan?.end({ output: { completion } });
155
+ if (!completion?.tool_calls || completion?.tool_calls?.length === 0) {
156
+ return;
157
+ }
158
+ if (completion.tool_calls[0].function.name === "exit") {
159
+ return;
160
+ }
161
+ if (completion.tool_calls[0].function.name === "change_plan") {
162
+ const args = completion.tool_calls[0].function.arguments;
163
+ const plan = (0, utils_1.parseJson)(args).plan;
164
+ return plan;
165
+ }
166
+ }
167
+ function systemPromptBuilderForRepoEdit(files) {
168
+ const prompt = `
169
+ You are an expert QA automation engineer well versed in Playwright and Typescript and is given an objective to update tests in the repository on the basis of task provided.
170
+
171
+ Directory structure for the repository:
172
+ └── /
173
+ ├── tests/
174
+ ├────test-data/
175
+ │ └── index.ts
176
+ ├── pages/
177
+ ├── playwright.config.ts
178
+ ├── app_knowledge.md
179
+ ├── .eslintrc.js
180
+ ├── package.json
181
+ └── tsconfig.json
182
+
183
+ Explanation of repository structure:
184
+ - tests: this is a directory where all tests and fixtures are kept. All spec files here end with ".spec.ts" as naming convention. There is an exception for Playwright fixtures file. Fixtures file is named as "fixtures.ts"
185
+ - test-data: this is a directory where all the test data are kept.
186
+ - pages: this is a directory where all reusable page object model methods are kept. Page object model methods are written in a pure functional convention. These methods are reusable methods created to be used across tests. This is also a directory where all the utility methods are kept which can be executed independent of the Playwright tests.
187
+
188
+ Coding principles and guidelines:
189
+
190
+ ## Code Style and Structure
191
+ - Write concise, maintainable, and technically accurate TypeScript code with relevant examples.
192
+ - Use functional and declarative programming patterns; avoid classes.
193
+ - Use types to describe the shape of data and the behavior of functions.
194
+ - Favour iteration and modularisation to adhere to DRY principles and avoid code duplication.
195
+ - Use descriptive variable names with auxiliary verbs (e.g., isLoading, hasError).
196
+ - Organise files systematically: each file should contain only related content, such as exported components, subcomponents, helpers, static content, and types.
197
+ - Page object models are pure functions and are stateless.
198
+
199
+ ## Naming Conventions
200
+ - Use lowercase with dashes for directories (e.g., tests/auth-wizard).
201
+ - Favour named exports for functions.
202
+
203
+ ## TypeScript Usage
204
+ - Use TypeScript for all code; prefer interfaces over types for their extendability and ability to merge.
205
+ - Avoid enums; use maps instead for better type safety and flexibility.
206
+ - Use functional components with TypeScript interfaces.
207
+
208
+ ## Syntax and Formatting
209
+ - Use the "function" keyword for pure functions to benefit from hoisting and clarity.
210
+
211
+ You will also be provided with current test files, fixtures and page object models for you to use and update code as per the task provided to you.
212
+
213
+ Here is the list of the files in the repository:
214
+ ${files}
215
+ `;
216
+ return prompt;
217
+ }
218
+ exports.systemPromptBuilderForRepoEdit = systemPromptBuilderForRepoEdit;
219
+ function userPromptBuilderForStrReplace(plan) {
220
+ const prompt = `
221
+ You need to work to achieve the plan provided to you.
222
+
223
+ Plan:
224
+ ${plan}
225
+
226
+ In order to execute the plan, FOLLOW BELOW STEPS:
227
+ - First go through the files in the repository and understand the code and the dependencies.
228
+ - Read the plan and figure out what are the changes that needs to be made.
229
+ - List down the changes required to execute the plan.
230
+ - Pick each change and identify the file path which needs the change, the reason for change and the code change they need.
231
+ - Use 'create_file' tool to create a new file if the file doesn't exist.
232
+ - Use separate 'str_replace' tool to make the changes for each update, even if the changes are in the same file.
233
+ - You can provide multiple 'str_replace' tool calls in the response.
234
+ - After making the changes check if the changes are made to all the files if not apply the changes to the remaining files.
235
+ - Also ensure that no extra changes are made to the code.
236
+
237
+ Notes for using the 'str_replace' command:
238
+ * The 'oldCode' parameter should match EXACTLY one or more consecutive lines from the original file. Be mindful of whitespaces!
239
+ * If the 'oldCode' parameter is not unique in the file, the replacement will not be performed. Make sure to include enough context in 'oldCode' to make it unique
240
+ * The 'newCode' parameter should contain the edited lines that should replace the 'oldCode'
241
+
242
+ Notes for using the 'create_file' command:
243
+ * The 'create_file' command cannot be used if the specified 'filePath' already exists as a file.
244
+ `;
245
+ return prompt;
246
+ }
247
+ function userPromptBuilderForPlanner(task) {
248
+ return `
249
+ You need to work towards completing the task provided to you.
250
+
251
+ Task:
252
+ ${task}
253
+
254
+ In order to execute the task, FOLLOW BELOW STEPS:
255
+ - First go through the files in the repository and understand the code and the dependencies.
256
+ - Read the task and figure out what are the changes that needs to be made.
257
+ - List down the changes required for the given task.
258
+ - If there are no changes to be made, respond with "exit" tool call to exit the conversation.
259
+ - Craft a prompt for the agent to make the changes to the code.
260
+ - The plan should be readable and easy to understand.
261
+ - The plan should contain the details of the changes to be made such as file path, test name etc.
262
+ - If there are multiple changes in the same file, mention those separately in the plan.
263
+ `;
264
+ }
265
+ function deDupUpdatedFiles(updatedFiles) {
266
+ return updatedFiles.filter((change, index, self) => index ===
267
+ self.findIndex((existing) => existing.filePath === change.filePath &&
268
+ existing.oldCode === change.oldCode &&
269
+ existing.newCode === change.newCode));
270
+ }
271
+ async function generateCodeAndApplyChanges({ task, trace, logger, getRelevantFiles, }) {
272
+ let planRetries = 5;
273
+ let updatedFiles = [];
274
+ while (planRetries--) {
275
+ const generateCodeAndApplyChangesSpan = trace?.span({
276
+ name: "generate-code-apply-changes",
277
+ input: {
278
+ task,
279
+ },
280
+ });
281
+ const { prompt: files } = await getRelevantFiles();
282
+ if (!files) {
283
+ return deDupUpdatedFiles(updatedFiles);
284
+ }
285
+ let strReplacePlan = await getPlanForCodeEditorAgent({
286
+ prompt: [
287
+ {
288
+ role: "system",
289
+ content: systemPromptBuilderForRepoEdit(files),
290
+ },
291
+ {
292
+ role: "user",
293
+ content: userPromptBuilderForPlanner(task),
294
+ },
295
+ ],
296
+ trace: generateCodeAndApplyChangesSpan,
297
+ logger,
298
+ });
299
+ if (!strReplacePlan) {
300
+ await (0, llm_1.flushAllTraces)();
301
+ return deDupUpdatedFiles(updatedFiles);
302
+ }
303
+ let strReplaceRetries = 3;
304
+ while (strReplaceRetries--) {
305
+ const promptForStrReplace = [
306
+ {
307
+ role: "system",
308
+ content: systemPromptBuilderForRepoEdit(files),
309
+ },
310
+ {
311
+ role: "user",
312
+ content: userPromptBuilderForStrReplace(strReplacePlan),
313
+ },
314
+ ];
315
+ const codeEditorSpan = generateCodeAndApplyChangesSpan?.span({
316
+ name: "code-editor-agent",
317
+ input: {
318
+ prompt: promptForStrReplace,
319
+ },
320
+ });
321
+ const llm = new llm_1.LLM({
322
+ trace: codeEditorSpan,
323
+ provider: "anthropic",
324
+ defaultModel: "claude-3-5-sonnet-20240620",
325
+ providerApiKey: constants_1.MODEL_API_KEYS["anthropic"],
326
+ });
327
+ const completion = await llm.createChatCompletion({
328
+ messages: promptForStrReplace,
329
+ modelParameters: {
330
+ ...constants_1.DEFAULT_MODEL_PARAMETERS,
331
+ temperature: 0.1,
332
+ tool_choice: "required",
333
+ },
334
+ trace: codeEditorSpan,
335
+ tools: getCodeEditorToolCalls(),
336
+ });
337
+ codeEditorSpan?.end({ output: { completion } });
338
+ if (!completion?.tool_calls || completion?.tool_calls?.length === 0) {
339
+ break;
340
+ }
341
+ let codeEditorToolCalls = completion.tool_calls;
342
+ // Filter out the tool calls which are for creating new files
343
+ const createFileToolCalls = completion.tool_calls.filter((tc) => tc.function.name === types_1.CodeEditorToolCall.CREATE_FILE);
344
+ if (createFileToolCalls.length > 0) {
345
+ console.log(`create_file tool calls: `, createFileToolCalls);
346
+ }
347
+ await Promise.all(createFileToolCalls.map((tc) => {
348
+ return (async () => {
349
+ const args = (0, utils_1.parseJson)(tc.function.arguments);
350
+ updatedFiles.push({
351
+ filePath: args.filePath,
352
+ oldCode: "",
353
+ newCode: args.code,
354
+ reason: args.reason,
355
+ });
356
+ await fs_extra_1.default.mkdir((0, path_1.dirname)(args.filePath), { recursive: true });
357
+ await fs_extra_1.default.writeFile(args.filePath, args.code, "utf-8");
358
+ console.log(`Created file: ${args.filePath}`);
359
+ })();
360
+ }));
361
+ const strReplaceToolCalls = completion.tool_calls.filter((tc) => tc.function.name === types_1.CodeEditorToolCall.STR_REPLACE);
362
+ if (strReplaceToolCalls.length > 0) {
363
+ console.log(`str_replace tool calls: `, strReplaceToolCalls);
364
+ }
365
+ // Filter out the tool calls which are for replacing code in existing files
366
+ const fileChanges = strReplaceToolCalls
367
+ .map((toolCall) => (0, utils_1.parseJson)(toolCall.function.arguments))
368
+ .filter((f) => f.filePath && fs_extra_1.default.existsSync(f.filePath));
369
+ updatedFiles.push(...fileChanges);
370
+ let failedCodeUpdates;
371
+ // applyChangesResponse contains the errors occurred while applying the changes
372
+ failedCodeUpdates = await (0, utils_2.applyFileChangesUsingStrReplace)({
373
+ trace: codeEditorSpan,
374
+ fileChanges,
375
+ logger,
376
+ });
377
+ // Filter out the responses having errors
378
+ failedCodeUpdates = failedCodeUpdates.filter((f) => f?.error);
379
+ // Filter out the tool calls which have errors
380
+ const toolCallsWithErrors = codeEditorToolCalls.filter((toolCall) => {
381
+ const args = (0, utils_1.parseJson)(toolCall.function.arguments);
382
+ return failedCodeUpdates.find((response) => response.filePath === args.filePath);
383
+ });
384
+ if (failedCodeUpdates.length === 0) {
385
+ break;
386
+ }
387
+ logger?.log(`Failed to apply changes, retrying...`, failedCodeUpdates);
388
+ const feedback = failedCodeUpdates
389
+ .map((updates) => `For file ${updates.filePath}: ${updates.errorMessage}`)
390
+ .join("\n");
391
+ promptForStrReplace.push({
392
+ role: "assistant",
393
+ tool_calls: toolCallsWithErrors,
394
+ });
395
+ toolCallsWithErrors.forEach((toolCall) => {
396
+ promptForStrReplace.push({
397
+ role: "tool",
398
+ tool_call_id: toolCall.id,
399
+ content: `
400
+ Errors while executing the changes provided in above tool call:
401
+ ${feedback}
402
+
403
+ Please fix the errors and return the updated code.
404
+
405
+ FOLLOW BELOW STEPS TO FIX THE ISSUES:
406
+ - First read the error message and understand the issue.
407
+ - Go through the new code block and current file code, to figure out the root cause of the issue.
408
+ - Compile the steps that you need to follow to fix the issue.
409
+ - Check the test names, to ensure that the changes are applied to the correct test.
410
+ - Use separate 'str_replace' tool to make the changes for each update.
411
+ - Return the updated code in the same format as provided in the tool call.
412
+
413
+ NOTE: ONLY MAKE THE CHANGES TO FIX THE ISSUES MENTIONED IN THE ERROR MESSAGE AND NOTHING ELSE. NO EXTRA CODE REFACTORING IS REQUIRED.
414
+ `,
415
+ });
416
+ });
417
+ }
418
+ }
419
+ return deDupUpdatedFiles(updatedFiles);
420
+ }
421
+ exports.generateCodeAndApplyChanges = generateCodeAndApplyChanges;
@@ -1,32 +1,25 @@
1
1
  import { TraceClient } from "@empiricalrun/llm";
2
2
  import { ChatCompletionMessageParam } from "openai/resources/index.mjs";
3
3
  import { CustomLogger } from "../../bin/logger";
4
- export declare function generateCodeUsingRepoAgent({ task, trace, repoFiles, }: {
4
+ import { CodeUpdate } from "./types";
5
+ export declare function generateCodeUsingRepoAgent({ task, trace, repoFiles, useStrReplace, logger, }: {
5
6
  trace?: TraceClient;
6
7
  task: string;
7
- repoFiles?: string;
8
+ repoFiles: string;
9
+ useStrReplace?: boolean;
10
+ logger?: CustomLogger;
8
11
  }): Promise<{
9
12
  prompt: ChatCompletionMessageParam[];
10
13
  agentResponse: string;
11
- fileChanges: {
12
- filePath: string | undefined;
13
- oldCode: string | undefined;
14
- newCode: string | undefined;
15
- reason: string | undefined;
16
- }[];
14
+ fileChanges: CodeUpdate[];
17
15
  }>;
18
- export declare function repoEditAgent({ trace, task, logger, }: {
16
+ export declare function repoEditAgent({ trace, task, logger, useStrReplace, }: {
19
17
  trace?: TraceClient;
20
18
  task: string;
21
19
  logger?: CustomLogger;
20
+ useStrReplace?: boolean;
22
21
  }): Promise<{
23
22
  prompt: ChatCompletionMessageParam[];
24
- agentResponse: string;
25
- fileChanges: {
26
- filePath: string | undefined;
27
- oldCode: string | undefined;
28
- newCode: string | undefined;
29
- reason: string | undefined;
30
- }[];
23
+ fileChanges: CodeUpdate[];
31
24
  }>;
32
25
  //# sourceMappingURL=repo-edit.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"repo-edit.d.ts","sourceRoot":"","sources":["../../../src/agent/codegen/repo-edit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAO,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD,OAAO,EAAE,0BAA0B,EAAE,MAAM,4BAA4B,CAAC;AAGxE,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAahD,wBAAsB,0BAA0B,CAAC,EAC/C,IAAI,EACJ,KAAK,EACL,SAAS,GACV,EAAE;IACD,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,GAAG,OAAO,CAAC;IACV,MAAM,EAAE,0BAA0B,EAAE,CAAC;IACrC,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE;QACX,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;QAC7B,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;QAC5B,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;QAC5B,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;KAC5B,EAAE,CAAC;CACL,CAAC,CA6GD;AAED,wBAAsB,aAAa,CAAC,EAClC,KAAK,EACL,IAAI,EACJ,MAAM,GACP,EAAE;IACD,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,YAAY,CAAC;CACvB,GAAG,OAAO,CAAC;IACV,MAAM,EAAE,0BAA0B,EAAE,CAAC;IACrC,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE;QACX,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;QAC7B,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;QAC5B,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;QAC5B,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;KAC5B,EAAE,CAAC;CACL,CAAC,CAkED"}
1
+ {"version":3,"file":"repo-edit.d.ts","sourceRoot":"","sources":["../../../src/agent/codegen/repo-edit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAO,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD,OAAO,EAAE,0BAA0B,EAAE,MAAM,4BAA4B,CAAC;AAGxE,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAWhD,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAOrC,wBAAsB,0BAA0B,CAAC,EAC/C,IAAI,EACJ,KAAK,EACL,SAAS,EACT,aAAa,EACb,MAAM,GACP,EAAE;IACD,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,MAAM,CAAC,EAAE,YAAY,CAAC;CACvB,GAAG,OAAO,CAAC;IACV,MAAM,EAAE,0BAA0B,EAAE,CAAC;IACrC,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,UAAU,EAAE,CAAC;CAC3B,CAAC,CAwJD;AAED,wBAAsB,aAAa,CAAC,EAClC,KAAK,EACL,IAAI,EACJ,MAAM,EACN,aAAa,GACd,EAAE;IACD,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB,GAAG,OAAO,CAAC;IACV,MAAM,EAAE,0BAA0B,EAAE,CAAC;IACrC,WAAW,EAAE,UAAU,EAAE,CAAC;CAC3B,CAAC,CA0ED"}
@@ -11,14 +11,55 @@ const context_1 = require("../../bin/utils/context");
11
11
  const web_1 = require("../../bin/utils/platform/web");
12
12
  const constants_1 = require("../../constants");
13
13
  const reporter_1 = require("../../reporter");
14
+ const generate_code_apply_changes_1 = require("./generate-code-apply-changes");
14
15
  const test_update_feedback_1 = require("./test-update-feedback");
15
16
  const utils_1 = require("./utils");
16
- async function generateCodeUsingRepoAgent({ task, trace, repoFiles, }) {
17
+ async function generateCodeUsingRepoAgent({ task, trace, repoFiles, useStrReplace, logger, }) {
17
18
  const repoEditSpan = trace?.span({
18
19
  name: "repo-edit",
19
20
  input: { task },
20
21
  });
21
- // TODO: add support for playwright config and other files
22
+ // TODO: remove this once we test this flow
23
+ if (useStrReplace) {
24
+ const prompt = [
25
+ {
26
+ role: "system",
27
+ content: (0, generate_code_apply_changes_1.systemPromptBuilderForRepoEdit)(repoFiles),
28
+ },
29
+ {
30
+ role: "user",
31
+ content: `
32
+ You need to work towards completing the task provided to you.
33
+
34
+ Task:
35
+ ${task}
36
+
37
+ In order to execute the task, FOLLOW BELOW STEPS:
38
+ - First go through the files in the repository and understand the code and the dependencies.
39
+ - Read the task and figure out what are the changes that needs to be made.
40
+ - List down the changes required for the given task.
41
+ - Create a clear, detailed plan which will be used as a prompt for the code change agent. Include specifics like file paths and test names. If there are multiple changes in one file, list them separately.
42
+ - The plan should be readable and easy to understand.
43
+
44
+ If all the changes are done, respond with "exit" tool call otherwise respond with "change-plan" tool call.
45
+ `,
46
+ },
47
+ ];
48
+ const fileChanges = await (0, generate_code_apply_changes_1.generateCodeAndApplyChanges)({
49
+ task,
50
+ trace: repoEditSpan,
51
+ getRelevantFiles: async () => await (0, context_1.generateTxtForRepository)(),
52
+ logger,
53
+ });
54
+ repoEditSpan?.end({
55
+ output: { fileChanges },
56
+ });
57
+ return {
58
+ prompt,
59
+ fileChanges,
60
+ agentResponse: "",
61
+ };
62
+ }
22
63
  const prompt = [
23
64
  {
24
65
  role: "system",
@@ -122,7 +163,7 @@ Task: ${task}
122
163
  };
123
164
  }
124
165
  exports.generateCodeUsingRepoAgent = generateCodeUsingRepoAgent;
125
- async function repoEditAgent({ trace, task, logger, }) {
166
+ async function repoEditAgent({ trace, task, logger, useStrReplace, }) {
126
167
  const testgenUpdatesReporter = new reporter_1.TestGenUpdatesReporter();
127
168
  void testgenUpdatesReporter.sendMessage(`Updating test code as per the task. \n View [trace](${trace?.getTraceUrl()})`);
128
169
  logger?.log(`Starting repo agent: [trace](${trace?.getTraceUrl()})`);
@@ -130,36 +171,40 @@ async function repoEditAgent({ trace, task, logger, }) {
130
171
  const repoAgentOutput = await generateCodeUsingRepoAgent({
131
172
  task,
132
173
  trace,
133
- repoFiles,
174
+ repoFiles: repoFiles,
175
+ useStrReplace,
176
+ logger,
134
177
  });
135
178
  const updates = repoAgentOutput.fileChanges;
136
- const fileUpdateResponses = await (0, utils_1.applyFileChangesForRepoEdit)({
137
- trace,
138
- fileChanges: updates.filter((f) => f.filePath && fs_extra_1.default.existsSync(f.filePath)),
139
- });
140
- const errorResponses = fileUpdateResponses.filter((f) => f?.error);
141
- if (errorResponses.length > 0) {
142
- const updatedFileChanges = await (0, test_update_feedback_1.applyTestUpdateFeedbacks)({
143
- trace,
144
- oldPrompt: repoAgentOutput.prompt,
145
- agentResponse: repoAgentOutput.agentResponse,
146
- feedbacks: errorResponses.map((e) => ({
147
- filePath: e?.filePath,
148
- errorMessage: e?.errorMessage,
149
- })),
150
- });
151
- await (0, utils_1.applyFileChangesForRepoEdit)({
179
+ if (!useStrReplace) {
180
+ const fileUpdateResponses = await (0, utils_1.applyFileChangesForRepoEdit)({
152
181
  trace,
153
- fileChanges: updatedFileChanges,
182
+ fileChanges: updates.filter((f) => f.filePath && fs_extra_1.default.existsSync(f.filePath)),
154
183
  });
184
+ const errorResponses = fileUpdateResponses.filter((f) => f?.error);
185
+ if (errorResponses.length > 0) {
186
+ const updatedFileChanges = await (0, test_update_feedback_1.applyTestUpdateFeedbacks)({
187
+ trace,
188
+ oldPrompt: repoAgentOutput.prompt,
189
+ agentResponse: repoAgentOutput.agentResponse,
190
+ feedbacks: errorResponses.map((e) => ({
191
+ filePath: e?.filePath,
192
+ errorMessage: e?.errorMessage,
193
+ })),
194
+ });
195
+ await (0, utils_1.applyFileChangesForRepoEdit)({
196
+ trace,
197
+ fileChanges: updatedFileChanges,
198
+ });
199
+ }
200
+ const newFileUpdates = updates.filter((f) => !fs_extra_1.default.existsSync(f.filePath));
201
+ await Promise.all(newFileUpdates.map((f) => {
202
+ return (async () => {
203
+ await fs_extra_1.default.mkdir((0, path_1.dirname)(f.filePath), { recursive: true });
204
+ await fs_extra_1.default.writeFile(f.filePath, f.newCode, "utf-8");
205
+ })();
206
+ }));
155
207
  }
156
- const newFileUpdates = updates.filter((f) => !fs_extra_1.default.existsSync(f.filePath));
157
- await Promise.all(newFileUpdates.map((f) => {
158
- return (async () => {
159
- await fs_extra_1.default.mkdir((0, path_1.dirname)(f.filePath), { recursive: true });
160
- await fs_extra_1.default.writeFile(f.filePath, f.newCode, "utf-8");
161
- })();
162
- }));
163
208
  await (0, utils_1.validateTypesAndFormatCode)({
164
209
  validateTypes: true,
165
210
  trace,
@@ -1 +1 @@
1
- {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../../src/agent/codegen/run.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAMhE,OAAO,EAAE,QAAQ,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAK7D,wBAAsB,YAAY,CAChC,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,oBAAoB,EAC7B,KAAK,CAAC,EAAE,WAAW,GAClB,OAAO,CAAC,QAAQ,EAAE,GAAG,IAAI,CAAC,CAmC5B"}
1
+ {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../../src/agent/codegen/run.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAMhE,OAAO,EAAE,QAAQ,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAK7D,wBAAsB,YAAY,CAChC,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,oBAAoB,EAC7B,KAAK,CAAC,EAAE,WAAW,GAClB,OAAO,CAAC,QAAQ,EAAE,GAAG,IAAI,CAAC,CAsC5B"}
@@ -27,6 +27,7 @@ async function generateTest(testCase, file, options, trace) {
27
27
  });
28
28
  const isUpdate = !!testBlock;
29
29
  if (isUpdate) {
30
+ logger.log(`Updating the test '${testCase.name}': [View trace](${trace?.getTraceUrl()})`);
30
31
  return await (0, update_flow_1.updateTest)(testCase, file, options, true, true, trace);
31
32
  }
32
33
  const createTestSpan = trace?.span({
@@ -8,10 +8,5 @@ export declare function applyTestUpdateFeedbacks({ trace, oldPrompt, feedbacks,
8
8
  errorMessage: string;
9
9
  }[];
10
10
  trace?: TraceClient;
11
- }): Promise<{
12
- filePath: string | undefined;
13
- oldCode: string | undefined;
14
- newCode: string | undefined;
15
- reason: string | undefined;
16
- }[]>;
11
+ }): Promise<import("./types").CodeUpdate[]>;
17
12
  //# sourceMappingURL=test-update-feedback.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"test-update-feedback.d.ts","sourceRoot":"","sources":["../../../src/agent/codegen/test-update-feedback.ts"],"names":[],"mappings":"AAAA,OAAO,EAAO,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAE,0BAA0B,EAAE,MAAM,4BAA4B,CAAC;AAKxE,wBAAsB,wBAAwB,CAAC,EAC7C,KAAK,EACL,SAAS,EACT,SAAS,EACT,aAAa,GACd,EAAE;IACD,SAAS,EAAE,0BAA0B,EAAE,CAAC;IACxC,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE;QACT,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;QAC7B,YAAY,EAAE,MAAM,CAAC;KACtB,EAAE,CAAC;IACJ,KAAK,CAAC,EAAE,WAAW,CAAC;CACrB;;;;;KA4CA"}
1
+ {"version":3,"file":"test-update-feedback.d.ts","sourceRoot":"","sources":["../../../src/agent/codegen/test-update-feedback.ts"],"names":[],"mappings":"AAAA,OAAO,EAAO,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAE,0BAA0B,EAAE,MAAM,4BAA4B,CAAC;AAKxE,wBAAsB,wBAAwB,CAAC,EAC7C,KAAK,EACL,SAAS,EACT,SAAS,EACT,aAAa,GACd,EAAE;IACD,SAAS,EAAE,0BAA0B,EAAE,CAAC;IACxC,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE;QACT,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;QAC7B,YAAY,EAAE,MAAM,CAAC;KACtB,EAAE,CAAC;IACJ,KAAK,CAAC,EAAE,WAAW,CAAC;CACrB,2CA4CA"}