vzcode 2.15.0 → 2.17.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-9w8E-TmY.wasm → bindings_wasm_bg-D9vNLG9F.wasm} +0 -0
- package/dist/assets/buildWorker-DL4wXpRr.js +695 -0
- package/dist/assets/index-BiPmUreW.js +474 -0
- package/dist/assets/{index-DLm5FQ0E.css → index-BvGPtSrr.css} +1 -1
- package/dist/assets/worker-RJ-cjbld.js +327 -0
- package/dist/index.html +2 -2
- package/dist/server/aiChatHandler/chatOperations.js +168 -35
- package/dist/server/aiChatHandler/index.js +11 -30
- package/dist/server/aiChatHandler/llmStreaming.js +105 -118
- package/package.json +11 -11
- package/src/client/AIAssist/AIAssistWidget/index.tsx +12 -1
- package/src/client/App/useShareDB.ts +1 -1
- package/src/client/CodeEditor/index.tsx +9 -10
- package/src/client/VZCodeContext/types.ts +3 -1
- package/src/client/VZCodeContext/useVZCodeState.ts +7 -5
- package/src/client/VZRight.tsx +10 -2
- package/src/client/VZSidebar/AIChat/ChatInput.tsx +1 -7
- package/src/client/VZSidebar/AIChat/DiffView.scss +1 -0
- package/src/client/VZSidebar/AIChat/DiffView.tsx +72 -29
- package/src/client/VZSidebar/AIChat/FileEditingIndicator.tsx +89 -0
- package/src/client/VZSidebar/AIChat/IndividualFileDiff.tsx +86 -0
- package/src/client/VZSidebar/AIChat/JumpToLatestButton.tsx +64 -0
- package/src/client/VZSidebar/AIChat/Message.tsx +124 -56
- package/src/client/VZSidebar/AIChat/MessageList.tsx +155 -114
- package/src/client/VZSidebar/AIChat/ThinkingScratchpad.tsx +4 -118
- package/src/client/VZSidebar/AIChat/index.tsx +59 -19
- package/src/client/VZSidebar/AIChat/styles.scss +190 -43
- package/src/client/VZSidebar/Item.tsx +2 -2
- package/src/client/VZSidebar/Search.tsx +13 -6
- package/src/client/VZSidebar/VisualEditor/VisualEditor.tsx +39 -23
- package/src/client/VZSidebar/VisualEditor/utils.ts +1 -1
- package/src/client/VZSidebar/index.tsx +12 -10
- package/src/client/VZSidebar/useDragAndDrop.tsx +225 -214
- package/src/client/featureFlags.ts +3 -0
- package/src/client/hooks/useAutoScroll.ts +328 -0
- package/src/client/tabsSearchParameters.ts +1 -17
- package/src/client/useFileCRUD.ts +5 -2
- package/src/client/useKeyboardShortcuts.ts +7 -0
- package/src/client/useOpenDirectories.ts +2 -1
- package/src/client/usePrettier/index.ts +1 -1
- package/src/client/useURLSync.ts +1 -0
- package/src/client/utils/scrollUtils.ts +170 -0
- package/src/client/vzReducer/searchReducer.ts +6 -3
- package/src/server/aiChatHandler/chatOperations.ts +224 -43
- package/src/server/aiChatHandler/index.ts +8 -48
- package/src/server/aiChatHandler/llmStreaming.ts +149 -170
- package/src/types.ts +81 -1
- package/dist/assets/buildWorker-Bi6wsfQk.js +0 -695
- package/dist/assets/index-BpUpNto4.js +0 -461
- package/dist/assets/worker-BSzbM0Uo.js +0 -330
- package/src/client/VZSidebar/AIChat/StreamingMessage.tsx +0 -35
|
@@ -1,54 +1,30 @@
|
|
|
1
|
-
import fs from 'fs';
|
|
2
1
|
import OpenAI from 'openai';
|
|
3
2
|
import {
|
|
4
3
|
parseMarkdownFiles,
|
|
5
4
|
StreamingMarkdownParser,
|
|
6
5
|
} from 'llm-code-format';
|
|
7
6
|
import { mergeFileChanges } from 'editcodewithai';
|
|
8
|
-
import { VizChatId
|
|
7
|
+
import { VizChatId } from '@vizhub/viz-types';
|
|
9
8
|
import { generateRunId } from '@vizhub/viz-utils';
|
|
10
9
|
import {
|
|
11
|
-
updateAIStatus,
|
|
12
|
-
createAIMessage,
|
|
13
|
-
updateAIMessageContent,
|
|
14
|
-
finalizeAIMessage,
|
|
15
|
-
ensureFileExists,
|
|
16
|
-
clearFileContent,
|
|
17
|
-
appendLineToFile,
|
|
18
10
|
updateFiles,
|
|
19
11
|
updateAIScratchpad,
|
|
12
|
+
createStreamingAIMessage,
|
|
13
|
+
addStreamingEvent,
|
|
14
|
+
updateStreamingStatus,
|
|
15
|
+
finalizeStreamingMessage,
|
|
20
16
|
} from './chatOperations.js';
|
|
21
17
|
import { diff } from '../../ot.js';
|
|
22
|
-
import {
|
|
18
|
+
import {
|
|
19
|
+
ShareDBDoc,
|
|
20
|
+
ExtendedVizContent,
|
|
21
|
+
} from '../../types.js';
|
|
23
22
|
|
|
24
23
|
const DEBUG = false;
|
|
25
24
|
|
|
26
25
|
// Useful for testing/debugging the streaming behavior
|
|
27
26
|
const slowMode = false;
|
|
28
27
|
|
|
29
|
-
// Throttle the streaming updates, so that we don't
|
|
30
|
-
// overwhelm the ShareDB server with too many updates.
|
|
31
|
-
// It happened actually, before adding this.
|
|
32
|
-
// MongoDB VizHub server got in fact overloaded with
|
|
33
|
-
// too many updates from the AI streaming response, with
|
|
34
|
-
// warning: "Replication Oplog Window has gone below 1 hour"
|
|
35
|
-
const THROTTLE_INTERVAL_MS = 500;
|
|
36
|
-
|
|
37
|
-
// Feature flag to enable/disable streaming editing.
|
|
38
|
-
// * If `true`, the AI streaming response will be used to
|
|
39
|
-
// edit files in real-time by submitting ShareDB ops.
|
|
40
|
-
// * If `false`, the updates to code files will be applied
|
|
41
|
-
// only after the AI has finished generating the entire response.
|
|
42
|
-
//
|
|
43
|
-
// Current status: there's a tricky bug with the streaming
|
|
44
|
-
// where the AI edits sometimes don't apply correctly in CodeMirror.
|
|
45
|
-
// It seems that sometimes the op that clears the file content
|
|
46
|
-
// is not applied correctly in the front end, leading to
|
|
47
|
-
// a situation where the AI streaming edits are concatenated into the middle
|
|
48
|
-
// of the file instead of replacing it.
|
|
49
|
-
// See https://github.com/codemirror/codemirror.next/issues/1234
|
|
50
|
-
const enableStreamingEditing = false;
|
|
51
|
-
|
|
52
28
|
/**
|
|
53
29
|
* Creates and configures the LLM function for streaming with reasoning tokens
|
|
54
30
|
*/
|
|
@@ -62,7 +38,7 @@ export const createLLMFunction = ({
|
|
|
62
38
|
model,
|
|
63
39
|
aiRequestOptions,
|
|
64
40
|
}: {
|
|
65
|
-
shareDBDoc: ShareDBDoc<
|
|
41
|
+
shareDBDoc: ShareDBDoc<ExtendedVizContent>;
|
|
66
42
|
chatId: VizChatId;
|
|
67
43
|
enableReasoningTokens?: boolean;
|
|
68
44
|
model?: string;
|
|
@@ -83,70 +59,67 @@ export const createLLMFunction = ({
|
|
|
83
59
|
|
|
84
60
|
let fullContent = '';
|
|
85
61
|
let generationId = '';
|
|
86
|
-
let currentEditingFileId = null;
|
|
87
62
|
let currentEditingFileName = null;
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
63
|
+
let accumulatedTextChunk = '';
|
|
64
|
+
let currentFileContent = '';
|
|
65
|
+
|
|
66
|
+
// Create streaming AI message
|
|
67
|
+
createStreamingAIMessage(shareDBDoc, chatId);
|
|
68
|
+
|
|
69
|
+
// Set initial content generation status
|
|
70
|
+
updateStreamingStatus(
|
|
71
|
+
shareDBDoc,
|
|
72
|
+
chatId,
|
|
73
|
+
'Formulating a plan...',
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
// Helper to get original file content
|
|
77
|
+
const getOriginalFileContent = (
|
|
78
|
+
fileName: string,
|
|
79
|
+
): string => {
|
|
80
|
+
const files = shareDBDoc.data.files;
|
|
81
|
+
for (const file of Object.values(files)) {
|
|
82
|
+
if ((file as any).name === fileName) {
|
|
83
|
+
return (file as any).text || '';
|
|
84
|
+
}
|
|
106
85
|
}
|
|
86
|
+
return '';
|
|
87
|
+
};
|
|
107
88
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
} else if (!timer) {
|
|
116
|
-
// schedule for later
|
|
117
|
-
timer = setTimeout(
|
|
118
|
-
() => {
|
|
119
|
-
timer = null;
|
|
120
|
-
invoke();
|
|
121
|
-
},
|
|
122
|
-
THROTTLE_INTERVAL_MS - (now - lastCall),
|
|
89
|
+
// Helper to emit text chunk when accumulated
|
|
90
|
+
const emitTextChunk = async () => {
|
|
91
|
+
if (accumulatedTextChunk.trim()) {
|
|
92
|
+
DEBUG &&
|
|
93
|
+
console.log(
|
|
94
|
+
'LLMStreaming: Emitting text chunk:',
|
|
95
|
+
accumulatedTextChunk.substring(0, 100) + '...',
|
|
123
96
|
);
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
}
|
|
133
|
-
invoke();
|
|
134
|
-
};
|
|
135
|
-
|
|
136
|
-
return fn;
|
|
137
|
-
}
|
|
97
|
+
await addStreamingEvent(shareDBDoc, chatId, {
|
|
98
|
+
type: 'text_chunk',
|
|
99
|
+
content: accumulatedTextChunk,
|
|
100
|
+
timestamp: Date.now(),
|
|
101
|
+
});
|
|
102
|
+
accumulatedTextChunk = '';
|
|
103
|
+
}
|
|
104
|
+
};
|
|
138
105
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
106
|
+
// Helper to complete file editing
|
|
107
|
+
const completeFileEditing = async (
|
|
108
|
+
fileName: string,
|
|
109
|
+
) => {
|
|
110
|
+
if (fileName && currentFileContent) {
|
|
111
|
+
DEBUG &&
|
|
112
|
+
console.log(
|
|
113
|
+
`LLMStreaming: Completing file editing for ${fileName}`,
|
|
114
|
+
);
|
|
115
|
+
await addStreamingEvent(shareDBDoc, chatId, {
|
|
116
|
+
type: 'file_complete',
|
|
117
|
+
fileName,
|
|
118
|
+
beforeContent: getOriginalFileContent(fileName),
|
|
119
|
+
afterContent: currentFileContent,
|
|
120
|
+
timestamp: Date.now(),
|
|
121
|
+
});
|
|
122
|
+
currentFileContent = '';
|
|
150
123
|
}
|
|
151
124
|
};
|
|
152
125
|
|
|
@@ -158,51 +131,57 @@ export const createLLMFunction = ({
|
|
|
158
131
|
) => {
|
|
159
132
|
DEBUG &&
|
|
160
133
|
console.log(
|
|
161
|
-
`File changed to: ${fileName} (${format})`,
|
|
134
|
+
`LLMStreaming: File changed to: ${fileName} (${format})`,
|
|
162
135
|
);
|
|
163
136
|
|
|
164
|
-
//
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
)
|
|
137
|
+
// Emit any accumulated text chunk first
|
|
138
|
+
await emitTextChunk();
|
|
139
|
+
|
|
140
|
+
// Complete previous file if any
|
|
141
|
+
if (currentEditingFileName) {
|
|
142
|
+
await completeFileEditing(currentEditingFileName);
|
|
143
|
+
}
|
|
169
144
|
|
|
170
|
-
|
|
145
|
+
// Start new file
|
|
171
146
|
currentEditingFileName = fileName;
|
|
147
|
+
currentFileContent = '';
|
|
172
148
|
|
|
173
|
-
//
|
|
174
|
-
|
|
175
|
-
|
|
149
|
+
// Emit file start event
|
|
150
|
+
await addStreamingEvent(shareDBDoc, chatId, {
|
|
151
|
+
type: 'file_start',
|
|
152
|
+
fileName,
|
|
153
|
+
timestamp: Date.now(),
|
|
154
|
+
});
|
|
176
155
|
|
|
177
|
-
// Update
|
|
178
|
-
|
|
156
|
+
// Update status
|
|
157
|
+
updateStreamingStatus(
|
|
179
158
|
shareDBDoc,
|
|
180
159
|
chatId,
|
|
181
|
-
|
|
160
|
+
`Editing ${fileName}...`,
|
|
182
161
|
);
|
|
183
162
|
},
|
|
184
163
|
onCodeLine: async (line: string) => {
|
|
185
164
|
DEBUG && console.log(`Code line: ${line}`);
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
if (currentEditingFileId) {
|
|
189
|
-
// Apply OT operation for this line immediately
|
|
190
|
-
appendLineToFile(
|
|
191
|
-
shareDBDoc,
|
|
192
|
-
currentEditingFileId,
|
|
193
|
-
line,
|
|
194
|
-
);
|
|
195
|
-
}
|
|
165
|
+
// Accumulate code content for the current file
|
|
166
|
+
currentFileContent += line + '\n';
|
|
196
167
|
},
|
|
197
168
|
onNonCodeLine: async (line: string) => {
|
|
198
|
-
|
|
199
|
-
//
|
|
200
|
-
// declaration and th
|
|
169
|
+
DEBUG && console.log(`Non-code line: ${line}`);
|
|
170
|
+
// Accumulate non-code content as text chunk
|
|
201
171
|
if (line.trim() !== '') {
|
|
202
|
-
|
|
172
|
+
accumulatedTextChunk += line + '\n';
|
|
173
|
+
|
|
174
|
+
// Update status for subsequent non-code chunks
|
|
175
|
+
if (firstNonCodeChunkProcessed) {
|
|
176
|
+
updateStreamingStatus(
|
|
177
|
+
shareDBDoc,
|
|
178
|
+
chatId,
|
|
179
|
+
'Describing changes...',
|
|
180
|
+
);
|
|
181
|
+
} else {
|
|
182
|
+
firstNonCodeChunkProcessed = true;
|
|
183
|
+
}
|
|
203
184
|
}
|
|
204
|
-
fullContent += line + '\n';
|
|
205
|
-
throttledUpdateAIMessageContent(fullContent);
|
|
206
185
|
},
|
|
207
186
|
};
|
|
208
187
|
|
|
@@ -240,6 +219,7 @@ export const createLLMFunction = ({
|
|
|
240
219
|
|
|
241
220
|
let reasoningStarted = false;
|
|
242
221
|
let contentStarted = false;
|
|
222
|
+
let firstNonCodeChunkProcessed = false;
|
|
243
223
|
|
|
244
224
|
for await (const chunk of stream) {
|
|
245
225
|
if (slowMode) {
|
|
@@ -253,7 +233,11 @@ export const createLLMFunction = ({
|
|
|
253
233
|
// Handle reasoning tokens (thinking) - only if enabled
|
|
254
234
|
if (!reasoningStarted) {
|
|
255
235
|
reasoningStarted = true;
|
|
256
|
-
|
|
236
|
+
updateStreamingStatus(
|
|
237
|
+
shareDBDoc,
|
|
238
|
+
chatId,
|
|
239
|
+
'Thinking...',
|
|
240
|
+
);
|
|
257
241
|
}
|
|
258
242
|
reasoningContent += delta.reasoning;
|
|
259
243
|
updateAIScratchpad(
|
|
@@ -263,26 +247,25 @@ export const createLLMFunction = ({
|
|
|
263
247
|
);
|
|
264
248
|
} else if (delta?.content) {
|
|
265
249
|
// Handle regular content tokens
|
|
266
|
-
if (
|
|
267
|
-
// Clear reasoning when content starts
|
|
250
|
+
if (!contentStarted) {
|
|
268
251
|
contentStarted = true;
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
shareDBDoc,
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
252
|
+
if (reasoningStarted) {
|
|
253
|
+
// Clear reasoning when content starts
|
|
254
|
+
updateAIScratchpad(shareDBDoc, chatId, '');
|
|
255
|
+
}
|
|
256
|
+
// // Set initial content generation status
|
|
257
|
+
// updateStreamingStatus(
|
|
258
|
+
// shareDBDoc,
|
|
259
|
+
// chatId,
|
|
260
|
+
// 'Formulating a plan...',
|
|
261
|
+
// );
|
|
275
262
|
}
|
|
276
263
|
|
|
277
264
|
const chunkContent = delta.content;
|
|
278
265
|
chunks.push(chunkContent);
|
|
279
266
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
} else {
|
|
283
|
-
fullContent += chunkContent;
|
|
284
|
-
throttledUpdateAIMessageContent(fullContent);
|
|
285
|
-
}
|
|
267
|
+
await parser.processChunk(chunkContent);
|
|
268
|
+
fullContent += chunkContent;
|
|
286
269
|
} else if (chunk.usage) {
|
|
287
270
|
// Handle usage information
|
|
288
271
|
DEBUG && console.log('Usage:', chunk.usage);
|
|
@@ -293,31 +276,27 @@ export const createLLMFunction = ({
|
|
|
293
276
|
}
|
|
294
277
|
}
|
|
295
278
|
await parser.flushRemaining();
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
// Flush to ensure the final content is written immediately
|
|
304
|
-
throttledUpdateAIMessageContent.flush();
|
|
305
|
-
|
|
306
|
-
// Finalize the AI message by clearing temporary fields
|
|
307
|
-
finalizeAIMessage(shareDBDoc, chatId);
|
|
308
|
-
|
|
309
|
-
// If streaming editing is not enabled, we need to
|
|
310
|
-
// apply all the edits at once
|
|
311
|
-
if (!enableStreamingEditing) {
|
|
312
|
-
updateFiles(
|
|
313
|
-
shareDBDoc,
|
|
314
|
-
mergeFileChanges(
|
|
315
|
-
shareDBDoc.data.files,
|
|
316
|
-
parseMarkdownFiles(fullContent, 'bold').files,
|
|
317
|
-
),
|
|
318
|
-
);
|
|
279
|
+
|
|
280
|
+
// Emit any remaining text chunk
|
|
281
|
+
await emitTextChunk();
|
|
282
|
+
|
|
283
|
+
// Complete final file if any
|
|
284
|
+
if (currentEditingFileName) {
|
|
285
|
+
await completeFileEditing(currentEditingFileName);
|
|
319
286
|
}
|
|
320
287
|
|
|
288
|
+
// Apply all the edits at once
|
|
289
|
+
updateFiles(
|
|
290
|
+
shareDBDoc,
|
|
291
|
+
mergeFileChanges(
|
|
292
|
+
shareDBDoc.data.files,
|
|
293
|
+
parseMarkdownFiles(fullContent, 'bold').files,
|
|
294
|
+
),
|
|
295
|
+
);
|
|
296
|
+
|
|
297
|
+
// Finalize streaming message
|
|
298
|
+
await finalizeStreamingMessage(shareDBDoc, chatId);
|
|
299
|
+
|
|
321
300
|
// Generate a new runId to trigger a run when AI finishes editing
|
|
322
301
|
// This will trigger a re-run without hot reloading
|
|
323
302
|
const newRunId = generateRunId();
|
|
@@ -341,16 +320,16 @@ export const createLLMFunction = ({
|
|
|
341
320
|
});
|
|
342
321
|
|
|
343
322
|
// Write chunks file for debugging
|
|
344
|
-
if (DEBUG) {
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
}
|
|
323
|
+
// if (DEBUG) {
|
|
324
|
+
// const chunksFileJSONpath = `./ai-chunks-${chatId}.json`;
|
|
325
|
+
// fs.writeFileSync(
|
|
326
|
+
// chunksFileJSONpath,
|
|
327
|
+
// JSON.stringify(chunks, null, 2),
|
|
328
|
+
// );
|
|
329
|
+
// console.log(
|
|
330
|
+
// `AI chunks written to ${chunksFileJSONpath}`,
|
|
331
|
+
// );
|
|
332
|
+
// }
|
|
354
333
|
|
|
355
334
|
return {
|
|
356
335
|
content: fullContent,
|
package/src/types.ts
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
VizContent,
|
|
3
|
+
VizFileId,
|
|
4
|
+
VizChat,
|
|
5
|
+
VizChatMessage,
|
|
6
|
+
VizChatId,
|
|
7
|
+
} from '@vizhub/viz-types';
|
|
2
8
|
|
|
3
9
|
// ItemId
|
|
4
10
|
// * A unique ID for an item in the sidebar.
|
|
@@ -215,3 +221,77 @@ export type VisualEditorConfigEntry =
|
|
|
215
221
|
options: string[];
|
|
216
222
|
}
|
|
217
223
|
| { type: 'color'; property: string; label: string };
|
|
224
|
+
|
|
225
|
+
// ============================================================================
|
|
226
|
+
// AI Chat Streaming Types
|
|
227
|
+
// ============================================================================
|
|
228
|
+
|
|
229
|
+
// Streaming Events for Progressive AI Chat
|
|
230
|
+
export type StreamingEvent =
|
|
231
|
+
| {
|
|
232
|
+
type: 'text_chunk';
|
|
233
|
+
content: string;
|
|
234
|
+
timestamp: number;
|
|
235
|
+
}
|
|
236
|
+
| {
|
|
237
|
+
type: 'file_start';
|
|
238
|
+
fileName: string;
|
|
239
|
+
timestamp: number;
|
|
240
|
+
}
|
|
241
|
+
| {
|
|
242
|
+
type: 'file_complete';
|
|
243
|
+
fileName: string;
|
|
244
|
+
beforeContent: string;
|
|
245
|
+
afterContent: string;
|
|
246
|
+
timestamp: number;
|
|
247
|
+
}
|
|
248
|
+
| {
|
|
249
|
+
type: 'status_update';
|
|
250
|
+
status: string;
|
|
251
|
+
timestamp: number;
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
// Extended VizChat with streaming capabilities
|
|
255
|
+
export interface ExtendedVizChat extends VizChat {
|
|
256
|
+
streamingEvents?: StreamingEvent[];
|
|
257
|
+
currentStatus?: string;
|
|
258
|
+
isStreaming?: boolean;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// Extended VizChatMessage with progressive rendering support
|
|
262
|
+
export interface ExtendedVizChatMessage
|
|
263
|
+
extends VizChatMessage {
|
|
264
|
+
streamingEvents?: StreamingEvent[];
|
|
265
|
+
isProgressive?: boolean; // Flag to indicate this message uses progressive rendering
|
|
266
|
+
isComplete?: boolean; // Flag to indicate if streaming is complete
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// Extended VizContent that uses our extended chat types
|
|
270
|
+
export interface ExtendedVizContent
|
|
271
|
+
extends Omit<VizContent, 'chats'> {
|
|
272
|
+
chats?: { [chatId: VizChatId]: ExtendedVizChat };
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// File diff data for individual files (not the combined diff)
|
|
276
|
+
export interface IndividualFileDiff {
|
|
277
|
+
fileName: string;
|
|
278
|
+
beforeContent: string;
|
|
279
|
+
afterContent: string;
|
|
280
|
+
unifiedDiff?: string; // Generated on demand
|
|
281
|
+
timestamp: number;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// Streaming Chat Message Format (simplified)
|
|
285
|
+
export interface StreamingChatMessage {
|
|
286
|
+
id: string;
|
|
287
|
+
role: 'user' | 'assistant';
|
|
288
|
+
timestamp: number;
|
|
289
|
+
|
|
290
|
+
// For user messages
|
|
291
|
+
content?: string;
|
|
292
|
+
|
|
293
|
+
// For assistant messages (streaming)
|
|
294
|
+
events?: StreamingEvent[];
|
|
295
|
+
currentStatus?: string;
|
|
296
|
+
isComplete?: boolean;
|
|
297
|
+
}
|