editcodewithai 1.1.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +49 -61
- package/dist/fileUtils.d.ts +15 -0
- package/dist/fileUtils.js +102 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +28 -5
- package/dist/prompt.d.ts +3 -1
- package/dist/prompt.js +55 -17
- package/dist/types.d.ts +2 -1
- package/package.json +10 -10
package/README.md
CHANGED
|
@@ -10,6 +10,8 @@ See also [vizhub-benchmarks](https://github.com/vizhub-core/vizhub-benchmarks).
|
|
|
10
10
|
|
|
11
11
|
The library is designed to be model-agnostic, allowing you to use any LLM provider while handling the prompt engineering, file parsing, and response processing for you.
|
|
12
12
|
|
|
13
|
+
Edit formats inspired by [Aider](https://aider.chat/). See [Aider: Edit Formats](https://aider.chat/docs/more/edit-formats.html) for details.
|
|
14
|
+
|
|
13
15
|
## Installation
|
|
14
16
|
|
|
15
17
|
```bash
|
|
@@ -18,93 +20,79 @@ npm install editcodewithai
|
|
|
18
20
|
|
|
19
21
|
## Usage
|
|
20
22
|
|
|
23
|
+
Here's a basic example of how to use `performAiEdit` to update a file:
|
|
24
|
+
|
|
21
25
|
```typescript
|
|
22
|
-
import { performAiEdit } from "editcodewithai";
|
|
26
|
+
import { performAiEdit, LlmFunction } from "editcodewithai";
|
|
23
27
|
import { VizFiles } from "@vizhub/viz-types";
|
|
24
28
|
|
|
25
|
-
//
|
|
26
|
-
const myLlmFunction = async (prompt: string) => {
|
|
27
|
-
//
|
|
28
|
-
|
|
29
|
-
const response = await fetch(
|
|
30
|
-
"https://openrouter.ai/api/v1/chat/completions",
|
|
31
|
-
{
|
|
32
|
-
method: "POST",
|
|
33
|
-
headers: {
|
|
34
|
-
"Content-Type": "application/json",
|
|
35
|
-
Authorization: `Bearer ${apiKey}`,
|
|
36
|
-
},
|
|
37
|
-
body: JSON.stringify({
|
|
38
|
-
model: "anthropic/claude-3.5-sonnet",
|
|
39
|
-
messages: [{ role: "user", content: prompt }],
|
|
40
|
-
}),
|
|
41
|
-
},
|
|
42
|
-
);
|
|
43
|
-
|
|
44
|
-
const data = await response.json();
|
|
29
|
+
// Your function to call the LLM
|
|
30
|
+
const myLlmFunction: LlmFunction = async (prompt: string) => {
|
|
31
|
+
// ... call your LLM API with the prompt
|
|
32
|
+
const llmResponse = "...";
|
|
45
33
|
return {
|
|
46
|
-
content:
|
|
47
|
-
generationId:
|
|
34
|
+
content: llmResponse, // The raw string response from the LLM
|
|
35
|
+
generationId: "some-generation-id", // Optional, for cost tracking with OpenRouter
|
|
48
36
|
};
|
|
49
37
|
};
|
|
50
38
|
|
|
51
|
-
// Your files
|
|
52
39
|
const files: VizFiles = {
|
|
53
40
|
file1: {
|
|
54
41
|
name: "index.js",
|
|
55
|
-
text:
|
|
42
|
+
text: 'console.log("Hello, World!");',
|
|
56
43
|
},
|
|
57
44
|
};
|
|
58
45
|
|
|
59
|
-
|
|
60
|
-
const result = await performAiEdit({
|
|
61
|
-
prompt: "Update the code to use async/await",
|
|
62
|
-
files: files,
|
|
63
|
-
llmFunction: myLlmFunction,
|
|
64
|
-
apiKey: "your-openrouter-api-key",
|
|
65
|
-
});
|
|
46
|
+
const prompt = 'Change the greeting to "Hello, Universe!"';
|
|
66
47
|
|
|
67
|
-
|
|
68
|
-
|
|
48
|
+
async function main() {
|
|
49
|
+
const result = await performAiEdit({
|
|
50
|
+
prompt,
|
|
51
|
+
files,
|
|
52
|
+
llmFunction: myLlmFunction,
|
|
53
|
+
editFormat: "diff", // Specify the desired edit format
|
|
54
|
+
});
|
|
69
55
|
|
|
70
|
-
|
|
56
|
+
console.log(result.changedFiles["file1"].text);
|
|
57
|
+
// Expected output: console.log("Hello, Universe!");
|
|
58
|
+
}
|
|
71
59
|
|
|
72
|
-
|
|
60
|
+
main();
|
|
61
|
+
```
|
|
73
62
|
|
|
74
|
-
|
|
63
|
+
## Edit Formats
|
|
75
64
|
|
|
76
|
-
|
|
65
|
+
This library supports several "edit formats" that instruct the LLM on how to specify file changes. Different models may perform better with different formats. You can specify the format using the `editFormat` parameter in `performAiEdit`.
|
|
77
66
|
|
|
78
|
-
|
|
79
|
-
| ------------- | ------------- | ----------------------------------------------------------------- |
|
|
80
|
-
| `prompt` | `string` | Instructions for the AI on how to modify the code |
|
|
81
|
-
| `files` | `VizFiles` | Object containing file information (see below) |
|
|
82
|
-
| `llmFunction` | `LlmFunction` | Function that sends the prompt to an LLM and returns the response |
|
|
83
|
-
| `apiKey` | `string` | OpenRouter API key for retrieving cost metadata |
|
|
67
|
+
### `whole` (default)
|
|
84
68
|
|
|
85
|
-
The
|
|
69
|
+
The LLM returns the complete, updated content for each file that needs changes. This is simple but can be inefficient for large files with small changes.
|
|
86
70
|
|
|
87
|
-
|
|
88
|
-
- `text`: The file contents as a string
|
|
71
|
+
**Example:**
|
|
89
72
|
|
|
90
|
-
|
|
73
|
+
````
|
|
74
|
+
index.js
|
|
75
|
+
```js
|
|
76
|
+
console.log("Hello, Universe!");
|
|
77
|
+
```
|
|
78
|
+
````
|
|
91
79
|
|
|
92
|
-
|
|
93
|
-
- `generationId`: A unique ID for the generation (used for cost tracking)
|
|
80
|
+
### `diff`
|
|
94
81
|
|
|
95
|
-
|
|
82
|
+
The LLM returns a series of search-and-replace blocks. This is efficient as it only includes the changed portions of the files.
|
|
96
83
|
|
|
97
|
-
|
|
84
|
+
**Example:**
|
|
98
85
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
86
|
+
````
|
|
87
|
+
index.js
|
|
88
|
+
```
|
|
89
|
+
<<<<<<< SEARCH
|
|
90
|
+
console.log("Hello, World!");
|
|
91
|
+
=======
|
|
92
|
+
console.log("Hello, Universe!");
|
|
93
|
+
>>>>>>> REPLACE
|
|
94
|
+
```
|
|
95
|
+
````
|
|
108
96
|
|
|
109
97
|
### File Operations
|
|
110
98
|
|
package/dist/fileUtils.d.ts
CHANGED
|
@@ -12,3 +12,18 @@ export declare function prepareFilesForPrompt(files: VizFiles): FileCollection;
|
|
|
12
12
|
* Merges original files with changes from the LLM
|
|
13
13
|
*/
|
|
14
14
|
export declare function mergeFileChanges(originalFiles: VizFiles, parsedFiles: FileCollection): VizFiles;
|
|
15
|
+
export interface Diff {
|
|
16
|
+
fileName: string;
|
|
17
|
+
search: string;
|
|
18
|
+
replace: string;
|
|
19
|
+
}
|
|
20
|
+
export declare function parseDiffs(responseText: string): Diff[];
|
|
21
|
+
export declare function applyDiffs(originalFiles: VizFiles, diffs: Diff[]): VizFiles;
|
|
22
|
+
export declare function parseDiffFenced(responseText: string): Diff[];
|
|
23
|
+
export interface UdiffHunk {
|
|
24
|
+
fileName: string;
|
|
25
|
+
original: string;
|
|
26
|
+
updated: string;
|
|
27
|
+
}
|
|
28
|
+
export declare function parseUdiffs(responseText: string): UdiffHunk[];
|
|
29
|
+
export declare function applyUdiffs(originalFiles: VizFiles, hunks: UdiffHunk[]): VizFiles;
|
package/dist/fileUtils.js
CHANGED
|
@@ -3,6 +3,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.shouldDeleteFile = shouldDeleteFile;
|
|
4
4
|
exports.prepareFilesForPrompt = prepareFilesForPrompt;
|
|
5
5
|
exports.mergeFileChanges = mergeFileChanges;
|
|
6
|
+
exports.parseDiffs = parseDiffs;
|
|
7
|
+
exports.applyDiffs = applyDiffs;
|
|
8
|
+
exports.parseDiffFenced = parseDiffFenced;
|
|
9
|
+
exports.parseUdiffs = parseUdiffs;
|
|
10
|
+
exports.applyUdiffs = applyUdiffs;
|
|
6
11
|
const viz_utils_1 = require("@vizhub/viz-utils");
|
|
7
12
|
/**
|
|
8
13
|
* If the LLM outputs empty text for a file, we interpret this
|
|
@@ -64,3 +69,100 @@ function mergeFileChanges(originalFiles, parsedFiles) {
|
|
|
64
69
|
});
|
|
65
70
|
return changedFiles;
|
|
66
71
|
}
|
|
72
|
+
function parseDiffs(responseText) {
|
|
73
|
+
const diffs = [];
|
|
74
|
+
// This regex captures the file path, and the content of the SEARCH and REPLACE blocks.
|
|
75
|
+
const diffRegex = /^(.+)\n```\n<<<<<<< SEARCH\n([\s\S]*?)\n=======\n([\s\S]*?)\n>>>>>>> REPLACE\n```/gm;
|
|
76
|
+
const matches = responseText.matchAll(diffRegex);
|
|
77
|
+
for (const match of matches) {
|
|
78
|
+
const [_, fileName, search, replace] = match;
|
|
79
|
+
diffs.push({
|
|
80
|
+
fileName: fileName.trim(),
|
|
81
|
+
search,
|
|
82
|
+
replace,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
return diffs;
|
|
86
|
+
}
|
|
87
|
+
function applyDiffs(originalFiles, diffs) {
|
|
88
|
+
// Create a mutable copy of the files to avoid side effects.
|
|
89
|
+
const changedFiles = JSON.parse(JSON.stringify(originalFiles));
|
|
90
|
+
for (const diff of diffs) {
|
|
91
|
+
const fileId = Object.keys(changedFiles).find((id) => changedFiles[id].name === diff.fileName);
|
|
92
|
+
if (!fileId) {
|
|
93
|
+
throw new Error(`File not found: ${diff.fileName}`);
|
|
94
|
+
}
|
|
95
|
+
const file = changedFiles[fileId];
|
|
96
|
+
if (!file.text.includes(diff.search)) {
|
|
97
|
+
throw new Error(`Search block not found in file: ${diff.fileName}`);
|
|
98
|
+
}
|
|
99
|
+
// Replace only the first occurrence, which is the standard behavior of string.replace.
|
|
100
|
+
file.text = file.text.replace(diff.search, diff.replace);
|
|
101
|
+
}
|
|
102
|
+
return changedFiles;
|
|
103
|
+
}
|
|
104
|
+
function parseDiffFenced(responseText) {
|
|
105
|
+
const diffs = [];
|
|
106
|
+
const diffRegex = /^```\n(.+)\n<<<<<<< SEARCH\n([\s\S]*?)\n=======\n([\s\S]*?)\n>>>>>>> REPLACE\n```/gm;
|
|
107
|
+
const matches = responseText.matchAll(diffRegex);
|
|
108
|
+
for (const match of matches) {
|
|
109
|
+
const [_, fileName, search, replace] = match;
|
|
110
|
+
diffs.push({
|
|
111
|
+
fileName: fileName.trim(),
|
|
112
|
+
search,
|
|
113
|
+
replace,
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
return diffs;
|
|
117
|
+
}
|
|
118
|
+
function parseUdiffs(responseText) {
|
|
119
|
+
const hunks = [];
|
|
120
|
+
const udiffFileRegex = /```diff\n--- (.+?)\n\+\+\+ \1\n([\s\S]+?)```/g;
|
|
121
|
+
let fileMatch;
|
|
122
|
+
while ((fileMatch = udiffFileRegex.exec(responseText)) !== null) {
|
|
123
|
+
const fileName = fileMatch[1].trim();
|
|
124
|
+
const allHunksContent = fileMatch[2];
|
|
125
|
+
const hunkParts = allHunksContent.split(/^@@ .* @@$/m).slice(1);
|
|
126
|
+
for (const part of hunkParts) {
|
|
127
|
+
if (part.trim() === "")
|
|
128
|
+
continue;
|
|
129
|
+
const lines = part.trim().split("\n");
|
|
130
|
+
const original = [];
|
|
131
|
+
const updated = [];
|
|
132
|
+
for (const line of lines) {
|
|
133
|
+
if (line.startsWith("+")) {
|
|
134
|
+
updated.push(line.substring(1));
|
|
135
|
+
}
|
|
136
|
+
else if (line.startsWith("-")) {
|
|
137
|
+
original.push(line.substring(1));
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
const content = line.startsWith(" ") ? line.substring(1) : line;
|
|
141
|
+
original.push(content);
|
|
142
|
+
updated.push(content);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
hunks.push({
|
|
146
|
+
fileName: fileName,
|
|
147
|
+
original: original.join("\n"),
|
|
148
|
+
updated: updated.join("\n"),
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return hunks;
|
|
153
|
+
}
|
|
154
|
+
function applyUdiffs(originalFiles, hunks) {
|
|
155
|
+
const changedFiles = JSON.parse(JSON.stringify(originalFiles));
|
|
156
|
+
for (const hunk of hunks) {
|
|
157
|
+
const fileId = Object.keys(changedFiles).find((id) => changedFiles[id].name === hunk.fileName);
|
|
158
|
+
if (!fileId) {
|
|
159
|
+
throw new Error(`File not found: ${hunk.fileName}`);
|
|
160
|
+
}
|
|
161
|
+
const file = changedFiles[fileId];
|
|
162
|
+
if (!file.text.includes(hunk.original)) {
|
|
163
|
+
throw new Error(`Original content for hunk not found in file: ${hunk.fileName}`);
|
|
164
|
+
}
|
|
165
|
+
file.text = file.text.replace(hunk.original, hunk.updated);
|
|
166
|
+
}
|
|
167
|
+
return changedFiles;
|
|
168
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { PerformAiEditParams, PerformAiEditResult } from "./types";
|
|
2
|
-
export type { LlmFunction, PerformAiEditParams, PerformAiEditResult, } from "./types";
|
|
2
|
+
export type { LlmFunction, PerformAiEditParams, PerformAiEditResult, EditFormat, } from "./types";
|
|
3
3
|
/**
|
|
4
4
|
* Core AI logic for:
|
|
5
5
|
* - Building the prompt (including context)
|
|
@@ -7,4 +7,4 @@ export type { LlmFunction, PerformAiEditParams, PerformAiEditResult, } from "./t
|
|
|
7
7
|
* - Parsing and merging file changes
|
|
8
8
|
* - Retrieving cost metadata
|
|
9
9
|
*/
|
|
10
|
-
export declare function performAiEdit({ prompt, files, llmFunction, apiKey, }: PerformAiEditParams): Promise<PerformAiEditResult>;
|
|
10
|
+
export declare function performAiEdit({ prompt, files, llmFunction, apiKey, editFormat, }: PerformAiEditParams): Promise<PerformAiEditResult>;
|
package/dist/index.js
CHANGED
|
@@ -13,20 +13,43 @@ const debug = false;
|
|
|
13
13
|
* - Parsing and merging file changes
|
|
14
14
|
* - Retrieving cost metadata
|
|
15
15
|
*/
|
|
16
|
-
async function performAiEdit({ prompt, files, llmFunction, apiKey, }) {
|
|
16
|
+
async function performAiEdit({ prompt, files, llmFunction, apiKey, editFormat = "whole", }) {
|
|
17
17
|
// 1. Format the existing files into the "markdown code block" format
|
|
18
18
|
const preparedFiles = (0, fileUtils_1.prepareFilesForPrompt)(files);
|
|
19
19
|
const filesContext = (0, llm_code_format_1.formatMarkdownFiles)(preparedFiles);
|
|
20
20
|
// 2. Assemble the final prompt
|
|
21
|
-
const fullPrompt = (0, prompt_1.assembleFullPrompt)({ filesContext, prompt });
|
|
21
|
+
const fullPrompt = (0, prompt_1.assembleFullPrompt)({ filesContext, prompt, editFormat });
|
|
22
22
|
debug && console.log("[performAiEdit] fullPrompt:", fullPrompt);
|
|
23
23
|
// 3. Invoke the model via the provided LLM function
|
|
24
24
|
const result = await llmFunction(fullPrompt);
|
|
25
25
|
// 4. We parse the output to figure out which files changed
|
|
26
26
|
const resultString = result.content;
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
let changedFiles;
|
|
28
|
+
switch (editFormat) {
|
|
29
|
+
case "whole": {
|
|
30
|
+
const parsed = (0, llm_code_format_1.parseMarkdownFiles)(resultString, "bold");
|
|
31
|
+
changedFiles = (0, fileUtils_1.mergeFileChanges)(files, parsed.files);
|
|
32
|
+
break;
|
|
33
|
+
}
|
|
34
|
+
case "diff": {
|
|
35
|
+
const diffs = (0, fileUtils_1.parseDiffs)(resultString);
|
|
36
|
+
changedFiles = (0, fileUtils_1.applyDiffs)(files, diffs);
|
|
37
|
+
break;
|
|
38
|
+
}
|
|
39
|
+
case "diff-fenced": {
|
|
40
|
+
const diffs = (0, fileUtils_1.parseDiffFenced)(resultString);
|
|
41
|
+
changedFiles = (0, fileUtils_1.applyDiffs)(files, diffs);
|
|
42
|
+
break;
|
|
43
|
+
}
|
|
44
|
+
case "udiff": {
|
|
45
|
+
const hunks = (0, fileUtils_1.parseUdiffs)(resultString);
|
|
46
|
+
changedFiles = (0, fileUtils_1.applyUdiffs)(files, hunks);
|
|
47
|
+
break;
|
|
48
|
+
}
|
|
49
|
+
default:
|
|
50
|
+
// This will catch any unhandled or unknown edit formats.
|
|
51
|
+
throw new Error(`Unknown edit format: ${editFormat}`);
|
|
52
|
+
}
|
|
30
53
|
// 6. Retrieve cost metadata for charging the user
|
|
31
54
|
const openRouterGenerationId = result.generationId || "";
|
|
32
55
|
let upstreamCostCents = 0;
|
package/dist/prompt.d.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
import type { EditFormat } from "./types";
|
|
1
2
|
export declare const PROMPT_TEMPLATE_VERSION = 1;
|
|
2
3
|
/**
|
|
3
4
|
* Assembles the full prompt by combining task, files context, and formatting instructions
|
|
4
5
|
*/
|
|
5
|
-
export declare function assembleFullPrompt({ filesContext, prompt, }: {
|
|
6
|
+
export declare function assembleFullPrompt({ filesContext, prompt, editFormat, }: {
|
|
6
7
|
filesContext: string;
|
|
7
8
|
prompt: string;
|
|
9
|
+
editFormat?: EditFormat;
|
|
8
10
|
}): string;
|
package/dist/prompt.js
CHANGED
|
@@ -7,25 +7,63 @@ exports.PROMPT_TEMPLATE_VERSION = 1;
|
|
|
7
7
|
// Template pieces
|
|
8
8
|
const TASK = (prompt) => `## Your Task\n\n${prompt}`;
|
|
9
9
|
const FILES = (filesContext) => `## Original Files\n\n${filesContext}`;
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
10
|
+
const FORMAT_INSTRUCTIONS = {
|
|
11
|
+
whole: [
|
|
12
|
+
"## Formatting Instructions\n\n",
|
|
13
|
+
"Suggest changes to the original files using this exact format:\n\n",
|
|
14
|
+
"**fileA.js**\n\n```js\n// Entire updated code for fileA\n```\n\n",
|
|
15
|
+
"**fileB.js**\n\n```js\n// Entire updated code for fileB\n```\n\n",
|
|
16
|
+
"Only include the files that need to be updated or created.\n\n",
|
|
17
|
+
"To suggest changes you MUST include the ENTIRE content of the updated file.\n\n",
|
|
18
|
+
'NEVER leave out sections as in "... rest of the code remain the same ...".\n\n',
|
|
19
|
+
"Refactor large files into smaller files in the same directory.\n\n",
|
|
20
|
+
"Delete all unused files, but we need to keep `README.md`. ",
|
|
21
|
+
"Files can be deleted by setting their content to empty, for example:\n\n",
|
|
22
|
+
"**fileToDelete.js**\n\n```\n```\n\n",
|
|
23
|
+
"For D3 logic, make sure it remains idempotent (use data joins), ",
|
|
24
|
+
"and prefer function signatures like `someFunction(selection, options)` ",
|
|
25
|
+
"where `selection` is a D3 selection and `options` is an object.\n\n",
|
|
26
|
+
].join(""),
|
|
27
|
+
diff: [
|
|
28
|
+
"## Formatting Instructions\n\n",
|
|
29
|
+
"Suggest changes to the original files using this search/replace block format:\n\n",
|
|
30
|
+
"path/to/filename.ext\n",
|
|
31
|
+
"```\n",
|
|
32
|
+
"<<<<<<< SEARCH\n",
|
|
33
|
+
"// code to be replaced\n",
|
|
34
|
+
"=======\n",
|
|
35
|
+
"// new code\n",
|
|
36
|
+
">>>>>>> REPLACE\n",
|
|
37
|
+
"```\n",
|
|
38
|
+
].join(""),
|
|
39
|
+
"diff-fenced": [
|
|
40
|
+
"## Formatting Instructions\n\n",
|
|
41
|
+
"Suggest changes to the original files using this search/replace block format with the file path inside the fence:\n\n",
|
|
42
|
+
"```\n",
|
|
43
|
+
"path/to/filename.ext\n",
|
|
44
|
+
"<<<<<<< SEARCH\n",
|
|
45
|
+
"// code to be replaced\n",
|
|
46
|
+
"=======\n",
|
|
47
|
+
"// new code\n",
|
|
48
|
+
">>>>>>> REPLACE\n",
|
|
49
|
+
"```\n",
|
|
50
|
+
].join(""),
|
|
51
|
+
udiff: [
|
|
52
|
+
"## Formatting Instructions\n\n",
|
|
53
|
+
"Suggest changes to the original files using the unified diff format:\n\n",
|
|
54
|
+
"```diff\n",
|
|
55
|
+
"--- path/to/filename.ext\n",
|
|
56
|
+
"+++ path/to/filename.ext\n",
|
|
57
|
+
"@@ ... @@\n",
|
|
58
|
+
"-// line to be removed\n",
|
|
59
|
+
"+// line to be added\n",
|
|
60
|
+
"```\n",
|
|
61
|
+
].join(""),
|
|
62
|
+
};
|
|
26
63
|
/**
|
|
27
64
|
* Assembles the full prompt by combining task, files context, and formatting instructions
|
|
28
65
|
*/
|
|
29
|
-
function assembleFullPrompt({ filesContext, prompt, }) {
|
|
66
|
+
function assembleFullPrompt({ filesContext, prompt, editFormat = "whole", }) {
|
|
67
|
+
const FORMAT = FORMAT_INSTRUCTIONS[editFormat];
|
|
30
68
|
return [TASK(prompt), FILES(filesContext), FORMAT].join("\n\n");
|
|
31
69
|
}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { VizFiles } from "@vizhub/viz-types";
|
|
2
|
+
export type EditFormat = "whole" | "diff" | "diff-fenced" | "udiff";
|
|
2
3
|
export type LlmFunction = (prompt: string) => Promise<{
|
|
3
4
|
content: string;
|
|
4
5
|
generationId?: string;
|
|
@@ -8,7 +9,7 @@ export interface PerformAiEditParams {
|
|
|
8
9
|
files: VizFiles;
|
|
9
10
|
llmFunction: LlmFunction;
|
|
10
11
|
apiKey?: string;
|
|
11
|
-
|
|
12
|
+
editFormat?: EditFormat;
|
|
12
13
|
}
|
|
13
14
|
export interface PerformAiEditResult {
|
|
14
15
|
changedFiles: VizFiles;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "editcodewithai",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "Edit Code With AI",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -41,21 +41,21 @@
|
|
|
41
41
|
"homepage": "https://github.com/vizhub-core/editcodewithai#readme",
|
|
42
42
|
"dependencies": {
|
|
43
43
|
"@vizhub/viz-types": "^0.1.0",
|
|
44
|
-
"@vizhub/viz-utils": "^1.0
|
|
45
|
-
"dotenv": "^
|
|
44
|
+
"@vizhub/viz-utils": "^1.1.0",
|
|
45
|
+
"dotenv": "^17.0.1",
|
|
46
46
|
"llm-code-format": "^2.0.1"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
|
-
"@langchain/core": "^0.3.
|
|
50
|
-
"@langchain/openai": "^0.5.
|
|
51
|
-
"langchain": "^0.3.
|
|
49
|
+
"@langchain/core": "^0.3.61",
|
|
50
|
+
"@langchain/openai": "^0.5.16",
|
|
51
|
+
"langchain": "^0.3.29",
|
|
52
52
|
"cors": "^2.8.5",
|
|
53
53
|
"express": "^5.1.0",
|
|
54
|
-
"npm-check-updates": "^
|
|
55
|
-
"prettier": "^3.
|
|
56
|
-
"puppeteer": "^24.
|
|
54
|
+
"npm-check-updates": "^18.0.1",
|
|
55
|
+
"prettier": "^3.6.2",
|
|
56
|
+
"puppeteer": "^24.11.2",
|
|
57
57
|
"ts-node": "^10.9.2",
|
|
58
58
|
"typescript": "^5.8.3",
|
|
59
|
-
"vitest": "^3.
|
|
59
|
+
"vitest": "^3.2.4"
|
|
60
60
|
}
|
|
61
61
|
}
|