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.
Files changed (35) hide show
  1. package/dist/assets/bindings_wasm_bg-BQfW5T_2.wasm +0 -0
  2. package/dist/assets/buildWorker-B-vXZ9gA.js +579 -0
  3. package/dist/assets/{index-DKLiE98a.css → index-CP9o_hN5.css} +1 -1
  4. package/dist/assets/index-kPLgjbcb.js +329 -0
  5. package/dist/index.html +2 -2
  6. package/package.json +17 -16
  7. package/src/client/App/style.scss +2 -2
  8. package/src/client/CodeEditor/getOrCreateEditor.ts +2 -5
  9. package/src/client/CodeEditor/index.tsx +1 -1
  10. package/src/client/CodeEditor/json1PresenceDisplay.ts +40 -12
  11. package/src/client/VZRight.tsx +68 -6
  12. package/src/client/VZSidebar/AIChat/ChatInput.tsx +17 -5
  13. package/src/client/VZSidebar/AIChat/Message.tsx +21 -8
  14. package/src/client/VZSidebar/AIChat/MessageList.tsx +29 -31
  15. package/src/client/VZSidebar/AIChat/StreamingMessage.tsx +6 -1
  16. package/src/client/VZSidebar/AIChat/TypingIndicator.tsx +7 -1
  17. package/src/client/VZSidebar/AIChat/index.tsx +22 -9
  18. package/src/client/VZSidebar/aiCopyPaste.ts +8 -1
  19. package/src/client/VZSidebar/index.tsx +10 -8
  20. package/src/client/buildWorker.ts +3 -0
  21. package/src/client/vzReducer/searchReducer.test.ts +250 -0
  22. package/src/client/vzReducer/searchReducer.ts +3 -1
  23. package/src/{ot.js → ot.ts} +11 -0
  24. package/src/runCode.ts +4 -23
  25. package/src/server/aiChatHandler/aiEditing.ts +10 -7
  26. package/src/server/aiChatHandler/chatOperations.ts +144 -58
  27. package/src/server/aiChatHandler/errorHandling.ts +1 -1
  28. package/src/server/aiChatHandler/index.ts +8 -2
  29. package/src/server/aiChatHandler/llmStreaming.ts +83 -44
  30. package/src/submitOperation.ts +1 -1
  31. package/dist/assets/index-ubSLcdJf.js +0 -327
  32. package/src/client/diff.js +0 -12
  33. package/src/runCode.js +0 -48
  34. package/src/submitOperation.js +0 -16
  35. /package/src/{randomId.js → randomId.ts} +0 -0
@@ -1,16 +1,38 @@
1
- import { StreamingMarkdownParser } from 'llm-code-format';
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
- updateAIScratchpad,
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 scratchpad with the file name.
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
- updateAIScratchpad(shareDBDoc, chatId, fullContent);
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: (fileName, format) => {
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
- updateAIScratchpad(shareDBDoc, chatId, fullContent);
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
- parser.processChunk(chunkContent);
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
- updateAIScratchpad(shareDBDoc, chatId, fullContent);
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`;
@@ -1,4 +1,4 @@
1
- import { diff } from './client/diff';
1
+ import { diff } from './ot.js';
2
2
 
3
3
  /**
4
4
  * Creates a submitOperation function that can be used to submit diff-based operations to ShareDB.