vzcode 1.41.0 → 1.43.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/{index-DPAeYEiH.js → index-B83lKfVG.js} +86 -86
- package/dist/assets/{index-DKLiE98a.css → index-CP9o_hN5.css} +1 -1
- package/dist/assets/worker-BeBZGG1n.js +136 -0
- package/dist/index.html +2 -2
- package/package.json +6 -6
- package/src/client/App/style.scss +2 -2
- package/src/client/CodeEditor/json1PresenceDisplay.ts +40 -12
- package/src/client/VZRight.tsx +17 -16
- package/src/client/VZSidebar/AIChat/MessageList.tsx +18 -27
- package/src/client/VZSidebar/AIChat/index.tsx +0 -2
- package/src/client/VZSidebar/aiCopyPaste.ts +8 -1
- package/src/client/VZSidebar/index.tsx +10 -8
- 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 +76 -40
- package/src/submitOperation.ts +1 -1
- package/dist/assets/worker-CkHcCP1n.js +0 -136
- 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
|
@@ -4,6 +4,10 @@ import {
|
|
|
4
4
|
} from 'editcodewithai';
|
|
5
5
|
import { formatMarkdownFiles } from 'llm-code-format';
|
|
6
6
|
|
|
7
|
+
// Dev flag for waiting 1 second before starting the LLM function.
|
|
8
|
+
// Useful for debugging and testing purposes, e.g. checking the typing indicator.
|
|
9
|
+
const delayStart = false;
|
|
10
|
+
|
|
7
11
|
/**
|
|
8
12
|
* Performs AI editing operations using streaming with incremental OT operations
|
|
9
13
|
*/
|
|
@@ -25,16 +29,15 @@ export const performAIEditing = async ({
|
|
|
25
29
|
editFormat: 'whole',
|
|
26
30
|
});
|
|
27
31
|
|
|
32
|
+
if (delayStart) {
|
|
33
|
+
await new Promise((resolve) =>
|
|
34
|
+
setTimeout(resolve, 1000),
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
|
|
28
38
|
// Call the LLM function which will handle streaming and incremental file updates
|
|
29
39
|
const result = await llmFunction(fullPrompt);
|
|
30
40
|
|
|
31
|
-
// Clear the scratchpad and update status
|
|
32
|
-
// clearAIScratchpadAndStatus(
|
|
33
|
-
// shareDBDoc,
|
|
34
|
-
// chatId,
|
|
35
|
-
// 'Done editing with AI.',
|
|
36
|
-
// );
|
|
37
|
-
|
|
38
41
|
runCode();
|
|
39
42
|
|
|
40
43
|
return {
|
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
import { dateToTimestamp } from '@vizhub/viz-utils';
|
|
2
|
-
import { diff } from '../../client/diff.js';
|
|
3
2
|
import { randomId } from '../../randomId.js';
|
|
3
|
+
import { ShareDBDoc } from '../../types.js';
|
|
4
|
+
import { diff } from '../../ot.js';
|
|
5
|
+
import {
|
|
6
|
+
VizChatId,
|
|
7
|
+
VizContent,
|
|
8
|
+
VizFileId,
|
|
9
|
+
VizFiles,
|
|
10
|
+
} from '@vizhub/viz-types';
|
|
4
11
|
|
|
5
12
|
/**
|
|
6
13
|
* Ensures the chats object exists in the ShareDB document
|
|
@@ -18,7 +25,10 @@ export const ensureChatsExist = (shareDBDoc) => {
|
|
|
18
25
|
/**
|
|
19
26
|
* Ensures a specific chat exists in the ShareDB document
|
|
20
27
|
*/
|
|
21
|
-
export const ensureChatExists = (
|
|
28
|
+
export const ensureChatExists = (
|
|
29
|
+
shareDBDoc: ShareDBDoc<VizContent>,
|
|
30
|
+
chatId: VizChatId,
|
|
31
|
+
) => {
|
|
22
32
|
if (!shareDBDoc.data.chats[chatId]) {
|
|
23
33
|
const op = diff(shareDBDoc.data, {
|
|
24
34
|
...shareDBDoc.data,
|
|
@@ -40,9 +50,9 @@ export const ensureChatExists = (shareDBDoc, chatId) => {
|
|
|
40
50
|
* Adds a user message to the chat
|
|
41
51
|
*/
|
|
42
52
|
export const addUserMessage = (
|
|
43
|
-
shareDBDoc
|
|
44
|
-
chatId,
|
|
45
|
-
content,
|
|
53
|
+
shareDBDoc: ShareDBDoc<VizContent>,
|
|
54
|
+
chatId: VizChatId,
|
|
55
|
+
content: string,
|
|
46
56
|
) => {
|
|
47
57
|
const userMessage = {
|
|
48
58
|
id: `user-${Date.now()}`,
|
|
@@ -74,9 +84,9 @@ export const addUserMessage = (
|
|
|
74
84
|
* Updates AI status in the chat
|
|
75
85
|
*/
|
|
76
86
|
export const updateAIStatus = (
|
|
77
|
-
shareDBDoc
|
|
78
|
-
chatId,
|
|
79
|
-
status,
|
|
87
|
+
shareDBDoc: ShareDBDoc<VizContent>,
|
|
88
|
+
chatId: VizChatId,
|
|
89
|
+
status: string,
|
|
80
90
|
) => {
|
|
81
91
|
const op = diff(shareDBDoc.data, {
|
|
82
92
|
...shareDBDoc.data,
|
|
@@ -95,9 +105,9 @@ export const updateAIStatus = (
|
|
|
95
105
|
* Updates AI scratchpad content
|
|
96
106
|
*/
|
|
97
107
|
export const updateAIScratchpad = (
|
|
98
|
-
shareDBDoc
|
|
99
|
-
chatId,
|
|
100
|
-
content,
|
|
108
|
+
shareDBDoc: ShareDBDoc<VizContent>,
|
|
109
|
+
chatId: VizChatId,
|
|
110
|
+
content: string,
|
|
101
111
|
) => {
|
|
102
112
|
const op = diff(shareDBDoc.data, {
|
|
103
113
|
...shareDBDoc.data,
|
|
@@ -122,9 +132,9 @@ export const updateAIScratchpad = (
|
|
|
122
132
|
* Clears AI scratchpad and updates status
|
|
123
133
|
*/
|
|
124
134
|
export const clearAIScratchpadAndStatus = (
|
|
125
|
-
shareDBDoc
|
|
126
|
-
chatId,
|
|
127
|
-
status,
|
|
135
|
+
shareDBDoc: ShareDBDoc<VizContent>,
|
|
136
|
+
chatId: VizChatId,
|
|
137
|
+
status: string,
|
|
128
138
|
) => {
|
|
129
139
|
const op = diff(shareDBDoc.data, {
|
|
130
140
|
...shareDBDoc.data,
|
|
@@ -141,12 +151,108 @@ export const clearAIScratchpadAndStatus = (
|
|
|
141
151
|
};
|
|
142
152
|
|
|
143
153
|
/**
|
|
144
|
-
*
|
|
154
|
+
* Creates an initial empty AI message for streaming
|
|
155
|
+
*/
|
|
156
|
+
export const createAIMessage = (
|
|
157
|
+
shareDBDoc: ShareDBDoc<VizContent>,
|
|
158
|
+
chatId: VizChatId,
|
|
159
|
+
) => {
|
|
160
|
+
const aiMessage = {
|
|
161
|
+
id: `assistant-${Date.now()}`,
|
|
162
|
+
role: 'assistant',
|
|
163
|
+
content: '',
|
|
164
|
+
timestamp: dateToTimestamp(new Date()),
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
const messageOp = diff(shareDBDoc.data, {
|
|
168
|
+
...shareDBDoc.data,
|
|
169
|
+
chats: {
|
|
170
|
+
...shareDBDoc.data.chats,
|
|
171
|
+
[chatId]: {
|
|
172
|
+
...shareDBDoc.data.chats[chatId],
|
|
173
|
+
messages: [
|
|
174
|
+
...shareDBDoc.data.chats[chatId].messages,
|
|
175
|
+
aiMessage,
|
|
176
|
+
],
|
|
177
|
+
updatedAt: dateToTimestamp(new Date()),
|
|
178
|
+
},
|
|
179
|
+
},
|
|
180
|
+
});
|
|
181
|
+
shareDBDoc.submitOp(messageOp);
|
|
182
|
+
|
|
183
|
+
return aiMessage.id;
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Updates the content of an AI message during streaming
|
|
188
|
+
*/
|
|
189
|
+
export const updateAIMessageContent = (
|
|
190
|
+
shareDBDoc: ShareDBDoc<VizContent>,
|
|
191
|
+
chatId: VizChatId,
|
|
192
|
+
messageId: string,
|
|
193
|
+
content: string,
|
|
194
|
+
) => {
|
|
195
|
+
const chat = shareDBDoc.data.chats[chatId];
|
|
196
|
+
const messageIndex = chat.messages.findIndex(
|
|
197
|
+
(msg) => msg.id === messageId,
|
|
198
|
+
);
|
|
199
|
+
|
|
200
|
+
if (messageIndex === -1) {
|
|
201
|
+
console.warn(
|
|
202
|
+
`AI message with id ${messageId} not found`,
|
|
203
|
+
);
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
const updatedMessages = [...chat.messages];
|
|
208
|
+
updatedMessages[messageIndex] = {
|
|
209
|
+
...updatedMessages[messageIndex],
|
|
210
|
+
content,
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
const messageOp = diff(shareDBDoc.data, {
|
|
214
|
+
...shareDBDoc.data,
|
|
215
|
+
chats: {
|
|
216
|
+
...shareDBDoc.data.chats,
|
|
217
|
+
[chatId]: {
|
|
218
|
+
...chat,
|
|
219
|
+
messages: updatedMessages,
|
|
220
|
+
updatedAt: dateToTimestamp(new Date()),
|
|
221
|
+
},
|
|
222
|
+
},
|
|
223
|
+
});
|
|
224
|
+
shareDBDoc.submitOp(messageOp);
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Finalizes an AI message by clearing temporary fields
|
|
229
|
+
*/
|
|
230
|
+
export const finalizeAIMessage = (
|
|
231
|
+
shareDBDoc: ShareDBDoc<VizContent>,
|
|
232
|
+
chatId: VizChatId,
|
|
233
|
+
) => {
|
|
234
|
+
const op = diff(shareDBDoc.data, {
|
|
235
|
+
...shareDBDoc.data,
|
|
236
|
+
chats: {
|
|
237
|
+
...shareDBDoc.data.chats,
|
|
238
|
+
[chatId]: {
|
|
239
|
+
...shareDBDoc.data.chats[chatId],
|
|
240
|
+
aiScratchpad: undefined,
|
|
241
|
+
aiStatus: undefined,
|
|
242
|
+
updatedAt: dateToTimestamp(new Date()),
|
|
243
|
+
},
|
|
244
|
+
},
|
|
245
|
+
});
|
|
246
|
+
shareDBDoc.submitOp(op);
|
|
247
|
+
};
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Adds an AI response message to the chat (legacy function, kept for compatibility)
|
|
145
251
|
*/
|
|
146
252
|
export const addAIMessage = (
|
|
147
|
-
shareDBDoc
|
|
148
|
-
chatId,
|
|
149
|
-
content,
|
|
253
|
+
shareDBDoc: ShareDBDoc<VizContent>,
|
|
254
|
+
chatId: VizChatId,
|
|
255
|
+
content?: string,
|
|
150
256
|
) => {
|
|
151
257
|
const aiResponse = {
|
|
152
258
|
id: Date.now() + 1,
|
|
@@ -178,7 +284,10 @@ export const addAIMessage = (
|
|
|
178
284
|
/**
|
|
179
285
|
* Updates files in the ShareDB document
|
|
180
286
|
*/
|
|
181
|
-
export const updateFiles = (
|
|
287
|
+
export const updateFiles = (
|
|
288
|
+
shareDBDoc: ShareDBDoc<VizContent>,
|
|
289
|
+
files: VizFiles,
|
|
290
|
+
) => {
|
|
182
291
|
const filesOp = diff(shareDBDoc.data, {
|
|
183
292
|
...shareDBDoc.data,
|
|
184
293
|
files,
|
|
@@ -186,30 +295,6 @@ export const updateFiles = (shareDBDoc, files) => {
|
|
|
186
295
|
shareDBDoc.submitOp(filesOp);
|
|
187
296
|
};
|
|
188
297
|
|
|
189
|
-
/**
|
|
190
|
-
* Sets isInteracting flag
|
|
191
|
-
*/
|
|
192
|
-
export const setIsInteracting = (
|
|
193
|
-
shareDBDoc,
|
|
194
|
-
isInteracting,
|
|
195
|
-
) => {
|
|
196
|
-
// Only generate an operation if the value is actually changing
|
|
197
|
-
const currentIsInteracting =
|
|
198
|
-
shareDBDoc.data.isInteracting;
|
|
199
|
-
|
|
200
|
-
if (currentIsInteracting === isInteracting) {
|
|
201
|
-
return;
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
const newState = {
|
|
205
|
-
...shareDBDoc.data,
|
|
206
|
-
isInteracting: isInteracting,
|
|
207
|
-
};
|
|
208
|
-
|
|
209
|
-
const interactingOp = diff(shareDBDoc.data, newState);
|
|
210
|
-
shareDBDoc.submitOp(interactingOp);
|
|
211
|
-
};
|
|
212
|
-
|
|
213
298
|
/**
|
|
214
299
|
* Finds a file ID by searching for a matching file name
|
|
215
300
|
*/
|
|
@@ -233,7 +318,10 @@ export const resolveFileId = (
|
|
|
233
318
|
/**
|
|
234
319
|
* Creates a new file with a random ID
|
|
235
320
|
*/
|
|
236
|
-
export const createNewFile = (
|
|
321
|
+
export const createNewFile = (
|
|
322
|
+
shareDBDoc: ShareDBDoc<VizContent>,
|
|
323
|
+
fileName: string,
|
|
324
|
+
) => {
|
|
237
325
|
// Generate a new random file ID
|
|
238
326
|
const newFileId = randomId();
|
|
239
327
|
|
|
@@ -270,7 +358,10 @@ export const ensureFileExists = (shareDBDoc, fileName) => {
|
|
|
270
358
|
/**
|
|
271
359
|
* Clears the content of a file
|
|
272
360
|
*/
|
|
273
|
-
export const clearFileContent = (
|
|
361
|
+
export const clearFileContent = (
|
|
362
|
+
shareDBDoc: ShareDBDoc<VizContent>,
|
|
363
|
+
fileId: VizFileId,
|
|
364
|
+
) => {
|
|
274
365
|
const currentFile = shareDBDoc.data.files[fileId];
|
|
275
366
|
|
|
276
367
|
if (currentFile && currentFile.text) {
|
|
@@ -295,29 +386,24 @@ export const clearFileContent = (shareDBDoc, fileId) => {
|
|
|
295
386
|
* Appends a line to a file using OT operations
|
|
296
387
|
*/
|
|
297
388
|
export const appendLineToFile = (
|
|
298
|
-
shareDBDoc
|
|
299
|
-
fileId,
|
|
300
|
-
line,
|
|
389
|
+
shareDBDoc: ShareDBDoc<VizContent>,
|
|
390
|
+
fileId: VizFileId,
|
|
391
|
+
line: string,
|
|
301
392
|
) => {
|
|
302
393
|
const currentFile = shareDBDoc.data.files[fileId];
|
|
303
394
|
const currentContent = currentFile?.text || '';
|
|
304
395
|
const newContent = currentContent + line + '\n';
|
|
305
396
|
|
|
306
|
-
// Create the new file state
|
|
307
|
-
const newFileState = {
|
|
308
|
-
...currentFile,
|
|
309
|
-
text: newContent,
|
|
310
|
-
};
|
|
311
|
-
|
|
312
397
|
const newDocState = {
|
|
313
398
|
...shareDBDoc.data,
|
|
314
399
|
files: {
|
|
315
400
|
...shareDBDoc.data.files,
|
|
316
|
-
[fileId]:
|
|
401
|
+
[fileId]: {
|
|
402
|
+
...currentFile,
|
|
403
|
+
text: newContent,
|
|
404
|
+
},
|
|
317
405
|
},
|
|
318
406
|
};
|
|
319
407
|
|
|
320
|
-
|
|
321
|
-
const op = diff(shareDBDoc.data, newDocState);
|
|
322
|
-
shareDBDoc.submitOp(op);
|
|
408
|
+
shareDBDoc.submitOp(diff(shareDBDoc.data, newDocState));
|
|
323
409
|
};
|
|
@@ -10,6 +10,7 @@ import { handleError } from './errorHandling.js';
|
|
|
10
10
|
import { createRunCodeFunction } from '../../runCode.js';
|
|
11
11
|
import { ShareDBDoc } from '../../types.js';
|
|
12
12
|
import { VizContent } from '@vizhub/viz-types';
|
|
13
|
+
import { createSubmitOperation } from '../../submitOperation.js';
|
|
13
14
|
|
|
14
15
|
const DEBUG = false;
|
|
15
16
|
|
|
@@ -32,6 +33,8 @@ export const handleAIChatMessage =
|
|
|
32
33
|
content,
|
|
33
34
|
'chatId:',
|
|
34
35
|
chatId,
|
|
36
|
+
'shareDBDoc:',
|
|
37
|
+
shareDBDoc,
|
|
35
38
|
);
|
|
36
39
|
}
|
|
37
40
|
|
|
@@ -55,8 +58,11 @@ export const handleAIChatMessage =
|
|
|
55
58
|
chatId,
|
|
56
59
|
});
|
|
57
60
|
|
|
58
|
-
// Create server-side runCode function using
|
|
59
|
-
const
|
|
61
|
+
// Create server-side runCode function using shareDBDoc
|
|
62
|
+
const submitOperation =
|
|
63
|
+
createSubmitOperation(shareDBDoc);
|
|
64
|
+
const runCode =
|
|
65
|
+
createRunCodeFunction(submitOperation);
|
|
60
66
|
|
|
61
67
|
// Perform AI editing
|
|
62
68
|
const editResult = await performAIEditing({
|
|
@@ -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,13 +63,21 @@ 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
|
};
|
|
@@ -91,22 +106,6 @@ export const createLLMFunction = ({
|
|
|
91
106
|
// (AI will regenerate the entire file content)
|
|
92
107
|
clearFileContent(shareDBDoc, currentEditingFileId);
|
|
93
108
|
|
|
94
|
-
// Update VizBot presence to show it's editing this specific file
|
|
95
|
-
const filePresence = {
|
|
96
|
-
username: 'VizBot',
|
|
97
|
-
start: ['files', currentEditingFileId, 'text', 0],
|
|
98
|
-
end: ['files', currentEditingFileId, 'text', 0],
|
|
99
|
-
};
|
|
100
|
-
|
|
101
|
-
localPresence.submit(filePresence, (error) => {
|
|
102
|
-
if (error) {
|
|
103
|
-
console.warn(
|
|
104
|
-
'VizBot file presence submission error:',
|
|
105
|
-
error,
|
|
106
|
-
);
|
|
107
|
-
}
|
|
108
|
-
});
|
|
109
|
-
|
|
110
109
|
// Update AI status
|
|
111
110
|
updateAIStatus(
|
|
112
111
|
shareDBDoc,
|
|
@@ -117,6 +116,7 @@ export const createLLMFunction = ({
|
|
|
117
116
|
onCodeLine: async (line: string) => {
|
|
118
117
|
DEBUG && console.log(`Code line: ${line}`);
|
|
119
118
|
|
|
119
|
+
// If streaming is enabled, we apply the line immediately
|
|
120
120
|
if (currentEditingFileId) {
|
|
121
121
|
// Apply OT operation for this line immediately
|
|
122
122
|
appendLineToFile(
|
|
@@ -165,7 +165,12 @@ export const createLLMFunction = ({
|
|
|
165
165
|
reportFileEdited();
|
|
166
166
|
}
|
|
167
167
|
fullContent += line + '\n';
|
|
168
|
-
|
|
168
|
+
updateAIMessageContent(
|
|
169
|
+
shareDBDoc,
|
|
170
|
+
chatId,
|
|
171
|
+
aiMessageId,
|
|
172
|
+
fullContent,
|
|
173
|
+
);
|
|
169
174
|
},
|
|
170
175
|
};
|
|
171
176
|
|
|
@@ -176,10 +181,21 @@ export const createLLMFunction = ({
|
|
|
176
181
|
// Stream the response
|
|
177
182
|
const stream = await chatModel.stream(fullPrompt);
|
|
178
183
|
for await (const chunk of stream) {
|
|
179
|
-
if (chunk.content) {
|
|
184
|
+
if (chunk && chunk.content) {
|
|
180
185
|
const chunkContent = String(chunk.content);
|
|
181
186
|
chunks.push(chunkContent);
|
|
182
|
-
|
|
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
|
+
}
|
|
183
199
|
}
|
|
184
200
|
|
|
185
201
|
if (!generationId && chunk.lc_kwargs?.id) {
|
|
@@ -189,7 +205,15 @@ export const createLLMFunction = ({
|
|
|
189
205
|
await parser.flushRemaining();
|
|
190
206
|
reportFileEdited();
|
|
191
207
|
updateAIStatus(shareDBDoc, chatId, 'Done editing.');
|
|
192
|
-
|
|
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);
|
|
193
217
|
|
|
194
218
|
// Clear VizBot presence when done
|
|
195
219
|
DEBUG &&
|
|
@@ -206,6 +230,18 @@ export const createLLMFunction = ({
|
|
|
206
230
|
}
|
|
207
231
|
});
|
|
208
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
|
+
|
|
209
245
|
// Write chunks file for debugging
|
|
210
246
|
if (DEBUG) {
|
|
211
247
|
const chunksFileJSONpath = `./ai-chunks-${chatId}.json`;
|
package/src/submitOperation.ts
CHANGED