vzcode 1.40.0 → 1.42.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/dist/assets/bindings_wasm_bg-BQfW5T_2.wasm +0 -0
- package/dist/assets/buildWorker-B-vXZ9gA.js +579 -0
- package/dist/assets/{index-DKLiE98a.css → index-CP9o_hN5.css} +1 -1
- package/dist/assets/index-kPLgjbcb.js +329 -0
- package/dist/index.html +2 -2
- package/package.json +17 -16
- package/src/client/App/style.scss +2 -2
- package/src/client/CodeEditor/getOrCreateEditor.ts +2 -5
- package/src/client/CodeEditor/index.tsx +1 -1
- package/src/client/CodeEditor/json1PresenceDisplay.ts +40 -12
- package/src/client/VZRight.tsx +68 -6
- package/src/client/VZSidebar/AIChat/ChatInput.tsx +17 -5
- package/src/client/VZSidebar/AIChat/Message.tsx +21 -8
- package/src/client/VZSidebar/AIChat/MessageList.tsx +29 -31
- package/src/client/VZSidebar/AIChat/StreamingMessage.tsx +6 -1
- package/src/client/VZSidebar/AIChat/TypingIndicator.tsx +7 -1
- package/src/client/VZSidebar/AIChat/index.tsx +22 -9
- package/src/client/VZSidebar/aiCopyPaste.ts +8 -1
- package/src/client/VZSidebar/index.tsx +10 -8
- package/src/client/buildWorker.ts +3 -0
- package/src/client/vzReducer/searchReducer.test.ts +250 -0
- package/src/client/vzReducer/searchReducer.ts +3 -1
- package/src/{ot.js → ot.ts} +11 -0
- package/src/runCode.ts +4 -23
- package/src/server/aiChatHandler/aiEditing.ts +10 -7
- package/src/server/aiChatHandler/chatOperations.ts +144 -58
- package/src/server/aiChatHandler/errorHandling.ts +1 -1
- package/src/server/aiChatHandler/index.ts +8 -2
- package/src/server/aiChatHandler/llmStreaming.ts +83 -44
- package/src/submitOperation.ts +1 -1
- package/dist/assets/index-ubSLcdJf.js +0 -327
- package/src/client/diff.js +0 -12
- package/src/runCode.js +0 -48
- package/src/submitOperation.js +0 -16
- /package/src/{randomId.js → randomId.ts} +0 -0
|
@@ -1,16 +1,38 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
parseMarkdownFiles,
|
|
3
|
+
StreamingMarkdownParser,
|
|
4
|
+
} from 'llm-code-format';
|
|
2
5
|
import { ChatOpenAI } from '@langchain/openai';
|
|
3
6
|
import fs from 'fs';
|
|
4
7
|
import {
|
|
5
8
|
updateAIStatus,
|
|
6
|
-
|
|
9
|
+
createAIMessage,
|
|
10
|
+
updateAIMessageContent,
|
|
11
|
+
finalizeAIMessage,
|
|
7
12
|
ensureFileExists,
|
|
8
13
|
clearFileContent,
|
|
9
14
|
appendLineToFile,
|
|
15
|
+
updateFiles,
|
|
10
16
|
} from './chatOperations.js';
|
|
17
|
+
import { mergeFileChanges } from 'editcodewithai';
|
|
11
18
|
|
|
12
19
|
const DEBUG = false;
|
|
13
20
|
|
|
21
|
+
// Feature flag to enable/disable streaming editing.
|
|
22
|
+
// * If `true`, the AI streaming response will be used to
|
|
23
|
+
// edit files in real-time by submitting ShareDB ops.
|
|
24
|
+
// * If `false`, the updates to code files will be applied
|
|
25
|
+
// only after the AI has finished generating the entire response.
|
|
26
|
+
//
|
|
27
|
+
// Current status: there's a tricky bug with the streaming
|
|
28
|
+
// where the AI edits sometimes don't apply correctly in CodeMirror.
|
|
29
|
+
// It seems that sometimes the op that clears the file content
|
|
30
|
+
// is not applied correctly in the front end, leading to
|
|
31
|
+
// a situation where the AI streaming edits are concatenated into the middle
|
|
32
|
+
// of the file instead of replacing it.
|
|
33
|
+
// See https://github.com/codemirror/codemirror.next/issues/1234
|
|
34
|
+
const enableStreamingEditing = false;
|
|
35
|
+
|
|
14
36
|
/**
|
|
15
37
|
* Creates and configures the LLM function for streaming
|
|
16
38
|
*/
|
|
@@ -19,23 +41,8 @@ export const createLLMFunction = ({
|
|
|
19
41
|
createVizBotLocalPresence,
|
|
20
42
|
chatId,
|
|
21
43
|
}) => {
|
|
22
|
-
return async (fullPrompt) => {
|
|
44
|
+
return async (fullPrompt: string) => {
|
|
23
45
|
const localPresence = createVizBotLocalPresence();
|
|
24
|
-
// Submit initial presence for VizBot
|
|
25
|
-
const vizBotPresence = {
|
|
26
|
-
username: 'VizBot',
|
|
27
|
-
start: ['files'], // Indicate VizBot is working on files
|
|
28
|
-
end: ['files'],
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
localPresence.submit(vizBotPresence, (error) => {
|
|
32
|
-
if (error) {
|
|
33
|
-
console.warn(
|
|
34
|
-
'VizBot presence submission error:',
|
|
35
|
-
error,
|
|
36
|
-
);
|
|
37
|
-
}
|
|
38
|
-
});
|
|
39
46
|
const chatModel = new ChatOpenAI({
|
|
40
47
|
modelName:
|
|
41
48
|
process.env.VIZHUB_EDIT_WITH_AI_MODEL_NAME ||
|
|
@@ -56,20 +63,31 @@ export const createLLMFunction = ({
|
|
|
56
63
|
let currentEditingFileId = null;
|
|
57
64
|
let currentEditingFileName = null;
|
|
58
65
|
|
|
66
|
+
// Create initial AI message for streaming
|
|
67
|
+
const aiMessageId = createAIMessage(shareDBDoc, chatId);
|
|
68
|
+
|
|
59
69
|
// Function to report file edited
|
|
60
70
|
// This is called when the AI has finished editing a file
|
|
61
|
-
// and we want to update the
|
|
71
|
+
// and we want to update the message content with the file name.
|
|
62
72
|
const reportFileEdited = () => {
|
|
63
73
|
if (currentEditingFileName) {
|
|
64
74
|
fullContent += ` * Edited ${currentEditingFileName}\n`;
|
|
65
|
-
|
|
75
|
+
updateAIMessageContent(
|
|
76
|
+
shareDBDoc,
|
|
77
|
+
chatId,
|
|
78
|
+
aiMessageId,
|
|
79
|
+
fullContent,
|
|
80
|
+
);
|
|
66
81
|
currentEditingFileName = null;
|
|
67
82
|
}
|
|
68
83
|
};
|
|
69
84
|
|
|
70
85
|
// Define callbacks for streaming parser
|
|
71
86
|
const callbacks = {
|
|
72
|
-
onFileNameChange: (
|
|
87
|
+
onFileNameChange: async (
|
|
88
|
+
fileName: string,
|
|
89
|
+
format: string,
|
|
90
|
+
) => {
|
|
73
91
|
DEBUG &&
|
|
74
92
|
console.log(
|
|
75
93
|
`File changed to: ${fileName} (${format})`,
|
|
@@ -88,22 +106,6 @@ export const createLLMFunction = ({
|
|
|
88
106
|
// (AI will regenerate the entire file content)
|
|
89
107
|
clearFileContent(shareDBDoc, currentEditingFileId);
|
|
90
108
|
|
|
91
|
-
// Update VizBot presence to show it's editing this specific file
|
|
92
|
-
const filePresence = {
|
|
93
|
-
username: 'VizBot',
|
|
94
|
-
start: ['files', currentEditingFileId, 'text', 0],
|
|
95
|
-
end: ['files', currentEditingFileId, 'text', 0],
|
|
96
|
-
};
|
|
97
|
-
|
|
98
|
-
localPresence.submit(filePresence, (error) => {
|
|
99
|
-
if (error) {
|
|
100
|
-
console.warn(
|
|
101
|
-
'VizBot file presence submission error:',
|
|
102
|
-
error,
|
|
103
|
-
);
|
|
104
|
-
}
|
|
105
|
-
});
|
|
106
|
-
|
|
107
109
|
// Update AI status
|
|
108
110
|
updateAIStatus(
|
|
109
111
|
shareDBDoc,
|
|
@@ -111,9 +113,10 @@ export const createLLMFunction = ({
|
|
|
111
113
|
'Editing ' + fileName,
|
|
112
114
|
);
|
|
113
115
|
},
|
|
114
|
-
onCodeLine: (line) => {
|
|
116
|
+
onCodeLine: async (line: string) => {
|
|
115
117
|
DEBUG && console.log(`Code line: ${line}`);
|
|
116
118
|
|
|
119
|
+
// If streaming is enabled, we apply the line immediately
|
|
117
120
|
if (currentEditingFileId) {
|
|
118
121
|
// Apply OT operation for this line immediately
|
|
119
122
|
appendLineToFile(
|
|
@@ -154,7 +157,7 @@ export const createLLMFunction = ({
|
|
|
154
157
|
}
|
|
155
158
|
}
|
|
156
159
|
},
|
|
157
|
-
onNonCodeLine: (line) => {
|
|
160
|
+
onNonCodeLine: async (line: string) => {
|
|
158
161
|
// We want to report a file edited only if the line is not empty,
|
|
159
162
|
// because sometimes the LLMs leave a newline between the file name
|
|
160
163
|
// declaration and th
|
|
@@ -162,7 +165,12 @@ export const createLLMFunction = ({
|
|
|
162
165
|
reportFileEdited();
|
|
163
166
|
}
|
|
164
167
|
fullContent += line + '\n';
|
|
165
|
-
|
|
168
|
+
updateAIMessageContent(
|
|
169
|
+
shareDBDoc,
|
|
170
|
+
chatId,
|
|
171
|
+
aiMessageId,
|
|
172
|
+
fullContent,
|
|
173
|
+
);
|
|
166
174
|
},
|
|
167
175
|
};
|
|
168
176
|
|
|
@@ -173,20 +181,39 @@ export const createLLMFunction = ({
|
|
|
173
181
|
// Stream the response
|
|
174
182
|
const stream = await chatModel.stream(fullPrompt);
|
|
175
183
|
for await (const chunk of stream) {
|
|
176
|
-
if (chunk.content) {
|
|
184
|
+
if (chunk && chunk.content) {
|
|
177
185
|
const chunkContent = String(chunk.content);
|
|
178
186
|
chunks.push(chunkContent);
|
|
179
|
-
|
|
187
|
+
|
|
188
|
+
if (enableStreamingEditing) {
|
|
189
|
+
await parser.processChunk(chunkContent);
|
|
190
|
+
} else {
|
|
191
|
+
fullContent += chunkContent;
|
|
192
|
+
updateAIMessageContent(
|
|
193
|
+
shareDBDoc,
|
|
194
|
+
chatId,
|
|
195
|
+
aiMessageId,
|
|
196
|
+
fullContent,
|
|
197
|
+
);
|
|
198
|
+
}
|
|
180
199
|
}
|
|
181
200
|
|
|
182
201
|
if (!generationId && chunk.lc_kwargs?.id) {
|
|
183
202
|
generationId = chunk.lc_kwargs.id;
|
|
184
203
|
}
|
|
185
204
|
}
|
|
186
|
-
parser.flushRemaining();
|
|
205
|
+
await parser.flushRemaining();
|
|
187
206
|
reportFileEdited();
|
|
188
207
|
updateAIStatus(shareDBDoc, chatId, 'Done editing.');
|
|
189
|
-
|
|
208
|
+
updateAIMessageContent(
|
|
209
|
+
shareDBDoc,
|
|
210
|
+
chatId,
|
|
211
|
+
aiMessageId,
|
|
212
|
+
fullContent,
|
|
213
|
+
);
|
|
214
|
+
|
|
215
|
+
// Finalize the AI message by clearing temporary fields
|
|
216
|
+
finalizeAIMessage(shareDBDoc, chatId);
|
|
190
217
|
|
|
191
218
|
// Clear VizBot presence when done
|
|
192
219
|
DEBUG &&
|
|
@@ -203,6 +230,18 @@ export const createLLMFunction = ({
|
|
|
203
230
|
}
|
|
204
231
|
});
|
|
205
232
|
|
|
233
|
+
// If streaming editing is not enabled, we need to
|
|
234
|
+
// apply all the edits at once
|
|
235
|
+
if (!enableStreamingEditing) {
|
|
236
|
+
updateFiles(
|
|
237
|
+
shareDBDoc,
|
|
238
|
+
mergeFileChanges(
|
|
239
|
+
shareDBDoc.data.files,
|
|
240
|
+
parseMarkdownFiles(fullContent, 'bold').files,
|
|
241
|
+
),
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
|
|
206
245
|
// Write chunks file for debugging
|
|
207
246
|
if (DEBUG) {
|
|
208
247
|
const chunksFileJSONpath = `./ai-chunks-${chatId}.json`;
|
package/src/submitOperation.ts
CHANGED