vzcode 2.13.0 → 2.15.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 +0 -0
- package/dist/assets/buildWorker-Bi6wsfQk.js +695 -0
- package/dist/assets/{index-858eZSOF.js → index-BpUpNto4.js} +96 -92
- package/dist/assets/worker-CmHJK_do.js +136 -0
- package/dist/index.html +1 -1
- package/dist/server/aiChatHandler/aiEditing.js +4 -4
- package/dist/server/aiChatHandler/index.js +8 -13
- package/dist/server/aiChatHandler/llmStreaming.js +5 -46
- package/dist/server/index.js +0 -9
- package/package.json +19 -19
- package/src/server/aiChatHandler/aiEditing.ts +4 -4
- package/src/server/aiChatHandler/index.ts +8 -17
- package/src/server/aiChatHandler/llmStreaming.ts +5 -64
- package/src/server/index.ts +0 -17
- package/dist/assets/bindings_wasm_bg-CH5ekNIA.wasm +0 -0
- package/dist/assets/buildWorker-D4WATavZ.js +0 -682
- package/dist/assets/worker-CHvi_bXc.js +0 -136
package/dist/index.html
CHANGED
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap"
|
|
21
21
|
rel="stylesheet"
|
|
22
22
|
/>
|
|
23
|
-
<script type="module" crossorigin src="/assets/index-
|
|
23
|
+
<script type="module" crossorigin src="/assets/index-BpUpNto4.js"></script>
|
|
24
24
|
<link rel="stylesheet" crossorigin href="/assets/index-DLm5FQ0E.css">
|
|
25
25
|
</head>
|
|
26
26
|
<body>
|
|
@@ -10,8 +10,8 @@ const delayStart = false;
|
|
|
10
10
|
* Performs AI chat without editing - just generates a response
|
|
11
11
|
*/
|
|
12
12
|
export const performAIChat = async ({ prompt, shareDBDoc, llmFunction, }) => {
|
|
13
|
-
const
|
|
14
|
-
const filesContext = formatMarkdownFiles(
|
|
13
|
+
const { files } = prepareFilesForPrompt(shareDBDoc.data.files);
|
|
14
|
+
const filesContext = formatMarkdownFiles(files);
|
|
15
15
|
// 2. Assemble the final prompt for Q&A mode
|
|
16
16
|
const fullPrompt = assembleFullPrompt({
|
|
17
17
|
filesContext,
|
|
@@ -35,8 +35,8 @@ export const performAIChat = async ({ prompt, shareDBDoc, llmFunction, }) => {
|
|
|
35
35
|
export const performAIEditing = async ({ prompt, shareDBDoc, llmFunction, runCode, }) => {
|
|
36
36
|
// 1. Capture the current state of files before editing
|
|
37
37
|
const beforeFiles = createFilesSnapshot(shareDBDoc.data.files);
|
|
38
|
-
const
|
|
39
|
-
const filesContext = formatMarkdownFiles(
|
|
38
|
+
const { files } = prepareFilesForPrompt(shareDBDoc.data.files);
|
|
39
|
+
const filesContext = formatMarkdownFiles(files);
|
|
40
40
|
// 2. Assemble the final prompt
|
|
41
41
|
const fullPrompt = assembleFullPrompt({
|
|
42
42
|
filesContext,
|
|
@@ -5,8 +5,9 @@ import { performAIEditing, performAIChat, } from './aiEditing.js';
|
|
|
5
5
|
import { handleError, handleBackgroundError, } from './errorHandling.js';
|
|
6
6
|
import { createRunCodeFunction } from '../../runCode.js';
|
|
7
7
|
import { createSubmitOperation } from '../../submitOperation.js';
|
|
8
|
+
import { getGenerationMetadata } from 'editcodewithai';
|
|
8
9
|
const DEBUG = false;
|
|
9
|
-
export const handleAIChatMessage = ({ shareDBDoc,
|
|
10
|
+
export const handleAIChatMessage = ({ shareDBDoc, onCreditDeduction, getCurrentCommitId, model, aiRequestOptions, }) => async (req, res) => {
|
|
10
11
|
const { content, chatId, mode = 'edit' } = req.body;
|
|
11
12
|
if (DEBUG) {
|
|
12
13
|
console.log('[handleAIChatMessage] content:', content, 'chatId:', chatId, 'shareDBDoc:', shareDBDoc);
|
|
@@ -31,7 +32,6 @@ export const handleAIChatMessage = ({ shareDBDoc, createAIEditLocalPresence, onC
|
|
|
31
32
|
chatId,
|
|
32
33
|
content,
|
|
33
34
|
mode,
|
|
34
|
-
createAIEditLocalPresence,
|
|
35
35
|
getCurrentCommitId,
|
|
36
36
|
model,
|
|
37
37
|
aiRequestOptions,
|
|
@@ -49,7 +49,7 @@ export const handleAIChatMessage = ({ shareDBDoc, createAIEditLocalPresence, onC
|
|
|
49
49
|
/**
|
|
50
50
|
* Processes the AI request asynchronously in the background
|
|
51
51
|
*/
|
|
52
|
-
const processAIRequestAsync = async ({ shareDBDoc, chatId, content, mode,
|
|
52
|
+
const processAIRequestAsync = async ({ shareDBDoc, chatId, content, mode, getCurrentCommitId, model, aiRequestOptions, onCreditDeduction, }) => {
|
|
53
53
|
try {
|
|
54
54
|
// Capture the current commit ID before making changes (for VizHub integration)
|
|
55
55
|
const beforeCommitId = getCurrentCommitId
|
|
@@ -58,7 +58,6 @@ const processAIRequestAsync = async ({ shareDBDoc, chatId, content, mode, create
|
|
|
58
58
|
// Create LLM function for streaming
|
|
59
59
|
const llmFunction = createLLMFunction({
|
|
60
60
|
shareDBDoc,
|
|
61
|
-
createAIEditLocalPresence,
|
|
62
61
|
chatId,
|
|
63
62
|
model,
|
|
64
63
|
aiRequestOptions,
|
|
@@ -85,16 +84,12 @@ const processAIRequestAsync = async ({ shareDBDoc, chatId, content, mode, create
|
|
|
85
84
|
addDiffToAIMessage(shareDBDoc, chatId, editResult.diffData, beforeCommitId);
|
|
86
85
|
}
|
|
87
86
|
// Handle credit deduction if callback is provided
|
|
88
|
-
if (onCreditDeduction &&
|
|
89
|
-
editResult.upstreamCostCents) {
|
|
87
|
+
if (onCreditDeduction && editResult.generationId) {
|
|
90
88
|
try {
|
|
91
|
-
await onCreditDeduction({
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
inputTokens: editResult.inputTokens,
|
|
96
|
-
outputTokens: editResult.outputTokens,
|
|
97
|
-
});
|
|
89
|
+
await onCreditDeduction(await getGenerationMetadata({
|
|
90
|
+
apiKey: process.env.VZCODE_EDIT_WITH_AI_API_KEY,
|
|
91
|
+
generationId: editResult.generationId,
|
|
92
|
+
}));
|
|
98
93
|
}
|
|
99
94
|
catch (creditError) {
|
|
100
95
|
console.error('Credit deduction error:', creditError);
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { parseMarkdownFiles, StreamingMarkdownParser, } from 'llm-code-format';
|
|
2
|
-
import OpenAI from 'openai';
|
|
3
1
|
import fs from 'fs';
|
|
2
|
+
import OpenAI from 'openai';
|
|
3
|
+
import { parseMarkdownFiles, StreamingMarkdownParser, } from 'llm-code-format';
|
|
4
|
+
import { mergeFileChanges } from 'editcodewithai';
|
|
4
5
|
import { generateRunId } from '@vizhub/viz-utils';
|
|
5
6
|
import { updateAIStatus, createAIMessage, updateAIMessageContent, finalizeAIMessage, ensureFileExists, clearFileContent, appendLineToFile, updateFiles, updateAIScratchpad, } from './chatOperations.js';
|
|
6
|
-
import { mergeFileChanges } from 'editcodewithai';
|
|
7
7
|
import { diff } from '../../ot.js';
|
|
8
8
|
const DEBUG = false;
|
|
9
9
|
// Useful for testing/debugging the streaming behavior
|
|
@@ -14,7 +14,7 @@ const slowMode = false;
|
|
|
14
14
|
// MongoDB VizHub server got in fact overloaded with
|
|
15
15
|
// too many updates from the AI streaming response, with
|
|
16
16
|
// warning: "Replication Oplog Window has gone below 1 hour"
|
|
17
|
-
const THROTTLE_INTERVAL_MS =
|
|
17
|
+
const THROTTLE_INTERVAL_MS = 500;
|
|
18
18
|
// Feature flag to enable/disable streaming editing.
|
|
19
19
|
// * If `true`, the AI streaming response will be used to
|
|
20
20
|
// edit files in real-time by submitting ShareDB ops.
|
|
@@ -32,15 +32,12 @@ const enableStreamingEditing = false;
|
|
|
32
32
|
/**
|
|
33
33
|
* Creates and configures the LLM function for streaming with reasoning tokens
|
|
34
34
|
*/
|
|
35
|
-
export const createLLMFunction = ({ shareDBDoc,
|
|
35
|
+
export const createLLMFunction = ({ shareDBDoc, chatId,
|
|
36
36
|
// Feature flag to enable/disable reasoning tokens.
|
|
37
37
|
// When false, reasoning tokens are not requested from the API
|
|
38
38
|
// and reasoning content is not processed in the streaming response.
|
|
39
39
|
enableReasoningTokens = false, model, aiRequestOptions, }) => {
|
|
40
40
|
return async (fullPrompt) => {
|
|
41
|
-
const localPresence = enableStreamingEditing
|
|
42
|
-
? createAIEditLocalPresence()
|
|
43
|
-
: null;
|
|
44
41
|
// Create OpenRouter client for reasoning token support
|
|
45
42
|
const openRouterClient = new OpenAI({
|
|
46
43
|
apiKey: process.env.VZCODE_EDIT_WITH_AI_API_KEY,
|
|
@@ -123,33 +120,6 @@ enableReasoningTokens = false, model, aiRequestOptions, }) => {
|
|
|
123
120
|
if (currentEditingFileId) {
|
|
124
121
|
// Apply OT operation for this line immediately
|
|
125
122
|
appendLineToFile(shareDBDoc, currentEditingFileId, line);
|
|
126
|
-
// Update AI presence to show cursor at the end of the file
|
|
127
|
-
const currentFile = shareDBDoc.data.files[currentEditingFileId];
|
|
128
|
-
if (currentFile && currentFile.text) {
|
|
129
|
-
const textLength = currentFile.text.length;
|
|
130
|
-
const filePresence = {
|
|
131
|
-
username: 'AI Editor',
|
|
132
|
-
start: [
|
|
133
|
-
'files',
|
|
134
|
-
currentEditingFileId,
|
|
135
|
-
'text',
|
|
136
|
-
textLength,
|
|
137
|
-
],
|
|
138
|
-
end: [
|
|
139
|
-
'files',
|
|
140
|
-
currentEditingFileId,
|
|
141
|
-
'text',
|
|
142
|
-
textLength,
|
|
143
|
-
],
|
|
144
|
-
};
|
|
145
|
-
if (localPresence) {
|
|
146
|
-
localPresence.submit(filePresence, (error) => {
|
|
147
|
-
if (error) {
|
|
148
|
-
console.warn('AI Editor line presence submission error:', error);
|
|
149
|
-
}
|
|
150
|
-
});
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
123
|
}
|
|
154
124
|
},
|
|
155
125
|
onNonCodeLine: async (line) => {
|
|
@@ -238,17 +208,6 @@ enableReasoningTokens = false, model, aiRequestOptions, }) => {
|
|
|
238
208
|
throttledUpdateAIMessageContent.flush();
|
|
239
209
|
// Finalize the AI message by clearing temporary fields
|
|
240
210
|
finalizeAIMessage(shareDBDoc, chatId);
|
|
241
|
-
// Clear AI Editor presence when done
|
|
242
|
-
DEBUG &&
|
|
243
|
-
console.log('AI editing done, clearing AI Editor presence');
|
|
244
|
-
if (localPresence) {
|
|
245
|
-
localPresence.submit(null, (error) => {
|
|
246
|
-
DEBUG && console.log('AI Editor presence cleared');
|
|
247
|
-
if (error) {
|
|
248
|
-
console.warn('AI Editor presence cleanup error:', error);
|
|
249
|
-
}
|
|
250
|
-
});
|
|
251
|
-
}
|
|
252
211
|
// If streaming editing is not enabled, we need to
|
|
253
212
|
// apply all the edits at once
|
|
254
213
|
if (!enableStreamingEditing) {
|
package/dist/server/index.js
CHANGED
|
@@ -78,14 +78,6 @@ app.use(express.static(dir));
|
|
|
78
78
|
// which is a representation of files on disk.
|
|
79
79
|
const shareDBConnection = shareDBBackend.connect();
|
|
80
80
|
const shareDBDoc = shareDBConnection.get('documents', '1');
|
|
81
|
-
// Set up presence for AI editing following the same pattern as useShareDB.ts
|
|
82
|
-
const docPresence = shareDBConnection.getDocPresence('documents', '1');
|
|
83
|
-
// Create local presence for AI editing with a unique ID
|
|
84
|
-
const generateAIEditId = () => {
|
|
85
|
-
const timestamp = Date.now().toString(36);
|
|
86
|
-
return `ai-edit-${timestamp}`;
|
|
87
|
-
};
|
|
88
|
-
const createAIEditLocalPresence = () => docPresence.create(generateAIEditId());
|
|
89
81
|
shareDBDoc.create(initialDocument, json1Presence.type.uri);
|
|
90
82
|
// Handle AI Assist requests.
|
|
91
83
|
app.post('/ai-assist', bodyParser.json(), handleAIAssist(shareDBDoc));
|
|
@@ -94,7 +86,6 @@ app.post('/ai-copilot', bodyParser.json(), handleAICopilot());
|
|
|
94
86
|
// Handle AI Chat Message requests.
|
|
95
87
|
app.post('/ai-chat-message', bodyParser.json(), handleAIChatMessage({
|
|
96
88
|
shareDBDoc,
|
|
97
|
-
createAIEditLocalPresence,
|
|
98
89
|
onCreditDeduction: undefined,
|
|
99
90
|
}));
|
|
100
91
|
// Livekit Token Generator
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vzcode",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.15.0",
|
|
4
4
|
"description": "Multiplayer code editor system",
|
|
5
5
|
"main": "src/index.ts",
|
|
6
6
|
"type": "module",
|
|
@@ -112,7 +112,7 @@
|
|
|
112
112
|
"dependencies": {
|
|
113
113
|
"@codemirror/autocomplete": "^6.18.7",
|
|
114
114
|
"@codemirror/lang-css": "^6.3.1",
|
|
115
|
-
"@codemirror/lang-html": "^6.4.
|
|
115
|
+
"@codemirror/lang-html": "^6.4.10",
|
|
116
116
|
"@codemirror/lang-javascript": "^6.2.4",
|
|
117
117
|
"@codemirror/lang-json": "^6.0.2",
|
|
118
118
|
"@codemirror/lang-markdown": "^6.3.4",
|
|
@@ -120,7 +120,7 @@
|
|
|
120
120
|
"@codemirror/state": "^6.5.2",
|
|
121
121
|
"@codemirror/theme-one-dark": "^6.1.3",
|
|
122
122
|
"@codemirror/view": "^6.38.2",
|
|
123
|
-
"@langchain/core": "^0.3.
|
|
123
|
+
"@langchain/core": "^0.3.75",
|
|
124
124
|
"@langchain/openai": "^0.6.11",
|
|
125
125
|
"@lezer/highlight": "^1.2.1",
|
|
126
126
|
"@livekit/components-react": "^2.9.14",
|
|
@@ -140,7 +140,7 @@
|
|
|
140
140
|
"@uiw/codemirror-theme-xcode": "^4.25.1",
|
|
141
141
|
"@uiw/codemirror-themes": "^4.25.1",
|
|
142
142
|
"@valtown/codemirror-ts": "^2.3.1",
|
|
143
|
-
"@vizhub/runtime": "^4.
|
|
143
|
+
"@vizhub/runtime": "^4.5.0",
|
|
144
144
|
"@vizhub/viz-types": "^0.5.0",
|
|
145
145
|
"@vizhub/viz-utils": "^1.5.0",
|
|
146
146
|
"body-parser": "^2.2.0",
|
|
@@ -156,16 +156,16 @@
|
|
|
156
156
|
"diff-match-patch": "^1.0.5",
|
|
157
157
|
"diff2html": "^3.4.52",
|
|
158
158
|
"dotenv": "^17.2.2",
|
|
159
|
-
"editcodewithai": "^2.
|
|
160
|
-
"eslint-linter-browserify": "^9.
|
|
159
|
+
"editcodewithai": "^2.4.0",
|
|
160
|
+
"eslint-linter-browserify": "^9.35.0",
|
|
161
161
|
"express": "^5.1.0",
|
|
162
162
|
"ignore": "^7.0.5",
|
|
163
163
|
"json0-ot-diff": "^1.1.2",
|
|
164
164
|
"jszip": "^3.10.1",
|
|
165
165
|
"livekit-server-sdk": "^2.13.3",
|
|
166
166
|
"llm-code-format": "^3.0.0",
|
|
167
|
-
"lucide-react": "^0.
|
|
168
|
-
"npm": "^11.
|
|
167
|
+
"lucide-react": "^0.544.0",
|
|
168
|
+
"npm": "^11.6.0",
|
|
169
169
|
"open": "^10.2.0",
|
|
170
170
|
"prettier-plugin-svelte": "^3.4.0",
|
|
171
171
|
"react": "^18",
|
|
@@ -176,36 +176,36 @@
|
|
|
176
176
|
"remark-gfm": "^4.0.1",
|
|
177
177
|
"sharedb": "^5.2.2",
|
|
178
178
|
"sharedb-client-browser": "^5.2.2",
|
|
179
|
-
"uuid": "^
|
|
179
|
+
"uuid": "^13.0.0",
|
|
180
180
|
"vizhub-ui": "^3.24.0",
|
|
181
181
|
"ws": "^8.18.3"
|
|
182
182
|
},
|
|
183
183
|
"devDependencies": {
|
|
184
|
-
"@eslint/js": "^9.
|
|
184
|
+
"@eslint/js": "^9.35.0",
|
|
185
185
|
"@tauri-apps/cli": "^2.8.4",
|
|
186
186
|
"@types/d3-color": "^3.1.3",
|
|
187
187
|
"@types/react": "^18",
|
|
188
188
|
"@types/react-dom": "^18",
|
|
189
|
-
"@typescript-eslint/eslint-plugin": "^8.
|
|
190
|
-
"@typescript-eslint/parser": "^8.
|
|
189
|
+
"@typescript-eslint/eslint-plugin": "^8.43.0",
|
|
190
|
+
"@typescript-eslint/parser": "^8.43.0",
|
|
191
191
|
"@vitejs/plugin-react": "^5.0.2",
|
|
192
192
|
"concurrently": "^9.2.1",
|
|
193
193
|
"cross-env": "^10.0.0",
|
|
194
|
-
"eslint": "^9.
|
|
194
|
+
"eslint": "^9.35.0",
|
|
195
195
|
"eslint-plugin-jsx-a11y": "^6.10.2",
|
|
196
196
|
"eslint-plugin-react": "^7.37.5",
|
|
197
197
|
"eslint-plugin-react-hooks": "^5.2.0",
|
|
198
|
-
"globals": "^16.
|
|
199
|
-
"npm-check-updates": "^18.0
|
|
198
|
+
"globals": "^16.4.0",
|
|
199
|
+
"npm-check-updates": "^18.1.0",
|
|
200
200
|
"prettier": "^3.6.2",
|
|
201
|
-
"sass": "^1.92.
|
|
201
|
+
"sass": "^1.92.1",
|
|
202
202
|
"ts-node": "^10.9.2",
|
|
203
203
|
"typescript": "^5.9.2",
|
|
204
|
-
"vite": "^7.1.
|
|
204
|
+
"vite": "^7.1.5",
|
|
205
205
|
"vitest": "^3.2.4"
|
|
206
206
|
},
|
|
207
207
|
"optionalDependencies": {
|
|
208
|
-
"@rollup/rollup-darwin-arm64": "^4.50.
|
|
209
|
-
"@rollup/rollup-win32-x64-msvc": "^4.50.
|
|
208
|
+
"@rollup/rollup-darwin-arm64": "^4.50.1",
|
|
209
|
+
"@rollup/rollup-win32-x64-msvc": "^4.50.1"
|
|
210
210
|
}
|
|
211
211
|
}
|
|
@@ -23,10 +23,10 @@ export const performAIChat = async ({
|
|
|
23
23
|
shareDBDoc,
|
|
24
24
|
llmFunction,
|
|
25
25
|
}) => {
|
|
26
|
-
const
|
|
26
|
+
const { files } = prepareFilesForPrompt(
|
|
27
27
|
shareDBDoc.data.files,
|
|
28
28
|
);
|
|
29
|
-
const filesContext = formatMarkdownFiles(
|
|
29
|
+
const filesContext = formatMarkdownFiles(files);
|
|
30
30
|
|
|
31
31
|
// 2. Assemble the final prompt for Q&A mode
|
|
32
32
|
const fullPrompt = assembleFullPrompt({
|
|
@@ -65,10 +65,10 @@ export const performAIEditing = async ({
|
|
|
65
65
|
shareDBDoc.data.files,
|
|
66
66
|
);
|
|
67
67
|
|
|
68
|
-
const
|
|
68
|
+
const { files } = prepareFilesForPrompt(
|
|
69
69
|
shareDBDoc.data.files,
|
|
70
70
|
);
|
|
71
|
-
const filesContext = formatMarkdownFiles(
|
|
71
|
+
const filesContext = formatMarkdownFiles(files);
|
|
72
72
|
|
|
73
73
|
// 2. Assemble the final prompt
|
|
74
74
|
const fullPrompt = assembleFullPrompt({
|
|
@@ -19,20 +19,19 @@ import { createRunCodeFunction } from '../../runCode.js';
|
|
|
19
19
|
import { ShareDBDoc } from '../../types.js';
|
|
20
20
|
import { VizContent } from '@vizhub/viz-types';
|
|
21
21
|
import { createSubmitOperation } from '../../submitOperation.js';
|
|
22
|
+
import { getGenerationMetadata } from 'editcodewithai';
|
|
22
23
|
|
|
23
24
|
const DEBUG = false;
|
|
24
25
|
|
|
25
26
|
export const handleAIChatMessage =
|
|
26
27
|
({
|
|
27
28
|
shareDBDoc,
|
|
28
|
-
createAIEditLocalPresence,
|
|
29
29
|
onCreditDeduction,
|
|
30
30
|
getCurrentCommitId,
|
|
31
31
|
model,
|
|
32
32
|
aiRequestOptions,
|
|
33
33
|
}: {
|
|
34
34
|
shareDBDoc: ShareDBDoc<VizContent>;
|
|
35
|
-
createAIEditLocalPresence: () => any;
|
|
36
35
|
onCreditDeduction?: any;
|
|
37
36
|
getCurrentCommitId?: () => string | null;
|
|
38
37
|
model?: string;
|
|
@@ -77,7 +76,6 @@ export const handleAIChatMessage =
|
|
|
77
76
|
chatId,
|
|
78
77
|
content,
|
|
79
78
|
mode,
|
|
80
|
-
createAIEditLocalPresence,
|
|
81
79
|
getCurrentCommitId,
|
|
82
80
|
model,
|
|
83
81
|
aiRequestOptions,
|
|
@@ -103,7 +101,6 @@ const processAIRequestAsync = async ({
|
|
|
103
101
|
chatId,
|
|
104
102
|
content,
|
|
105
103
|
mode,
|
|
106
|
-
createAIEditLocalPresence,
|
|
107
104
|
getCurrentCommitId,
|
|
108
105
|
model,
|
|
109
106
|
aiRequestOptions,
|
|
@@ -113,7 +110,6 @@ const processAIRequestAsync = async ({
|
|
|
113
110
|
chatId: string;
|
|
114
111
|
content: string;
|
|
115
112
|
mode: string;
|
|
116
|
-
createAIEditLocalPresence: () => any;
|
|
117
113
|
getCurrentCommitId?: () => string | null;
|
|
118
114
|
model?: string;
|
|
119
115
|
aiRequestOptions?: any;
|
|
@@ -128,7 +124,6 @@ const processAIRequestAsync = async ({
|
|
|
128
124
|
// Create LLM function for streaming
|
|
129
125
|
const llmFunction = createLLMFunction({
|
|
130
126
|
shareDBDoc,
|
|
131
|
-
createAIEditLocalPresence,
|
|
132
127
|
chatId,
|
|
133
128
|
model,
|
|
134
129
|
aiRequestOptions,
|
|
@@ -168,18 +163,14 @@ const processAIRequestAsync = async ({
|
|
|
168
163
|
}
|
|
169
164
|
|
|
170
165
|
// Handle credit deduction if callback is provided
|
|
171
|
-
if (
|
|
172
|
-
onCreditDeduction &&
|
|
173
|
-
(editResult as any).upstreamCostCents
|
|
174
|
-
) {
|
|
166
|
+
if (onCreditDeduction && editResult.generationId) {
|
|
175
167
|
try {
|
|
176
|
-
await onCreditDeduction(
|
|
177
|
-
|
|
178
|
-
.
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
});
|
|
168
|
+
await onCreditDeduction(
|
|
169
|
+
await getGenerationMetadata({
|
|
170
|
+
apiKey: process.env.VZCODE_EDIT_WITH_AI_API_KEY,
|
|
171
|
+
generationId: editResult.generationId,
|
|
172
|
+
}),
|
|
173
|
+
);
|
|
183
174
|
} catch (creditError) {
|
|
184
175
|
console.error(
|
|
185
176
|
'Credit deduction error:',
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import OpenAI from 'openai';
|
|
1
3
|
import {
|
|
2
4
|
parseMarkdownFiles,
|
|
3
5
|
StreamingMarkdownParser,
|
|
4
6
|
} from 'llm-code-format';
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
+
import { mergeFileChanges } from 'editcodewithai';
|
|
8
|
+
import { VizChatId, VizContent } from '@vizhub/viz-types';
|
|
7
9
|
import { generateRunId } from '@vizhub/viz-utils';
|
|
8
10
|
import {
|
|
9
11
|
updateAIStatus,
|
|
@@ -16,9 +18,7 @@ import {
|
|
|
16
18
|
updateFiles,
|
|
17
19
|
updateAIScratchpad,
|
|
18
20
|
} from './chatOperations.js';
|
|
19
|
-
import { mergeFileChanges } from 'editcodewithai';
|
|
20
21
|
import { diff } from '../../ot.js';
|
|
21
|
-
import { VizChatId, VizContent } from '@vizhub/viz-types';
|
|
22
22
|
import { ShareDBDoc } from '../../types.js';
|
|
23
23
|
|
|
24
24
|
const DEBUG = false;
|
|
@@ -32,7 +32,7 @@ const slowMode = false;
|
|
|
32
32
|
// MongoDB VizHub server got in fact overloaded with
|
|
33
33
|
// too many updates from the AI streaming response, with
|
|
34
34
|
// warning: "Replication Oplog Window has gone below 1 hour"
|
|
35
|
-
const THROTTLE_INTERVAL_MS =
|
|
35
|
+
const THROTTLE_INTERVAL_MS = 500;
|
|
36
36
|
|
|
37
37
|
// Feature flag to enable/disable streaming editing.
|
|
38
38
|
// * If `true`, the AI streaming response will be used to
|
|
@@ -54,7 +54,6 @@ const enableStreamingEditing = false;
|
|
|
54
54
|
*/
|
|
55
55
|
export const createLLMFunction = ({
|
|
56
56
|
shareDBDoc,
|
|
57
|
-
createAIEditLocalPresence,
|
|
58
57
|
chatId,
|
|
59
58
|
// Feature flag to enable/disable reasoning tokens.
|
|
60
59
|
// When false, reasoning tokens are not requested from the API
|
|
@@ -64,17 +63,12 @@ export const createLLMFunction = ({
|
|
|
64
63
|
aiRequestOptions,
|
|
65
64
|
}: {
|
|
66
65
|
shareDBDoc: ShareDBDoc<VizContent>;
|
|
67
|
-
createAIEditLocalPresence: () => any;
|
|
68
66
|
chatId: VizChatId;
|
|
69
67
|
enableReasoningTokens?: boolean;
|
|
70
68
|
model?: string;
|
|
71
69
|
aiRequestOptions?: any;
|
|
72
70
|
}) => {
|
|
73
71
|
return async (fullPrompt: string) => {
|
|
74
|
-
const localPresence = enableStreamingEditing
|
|
75
|
-
? createAIEditLocalPresence()
|
|
76
|
-
: null;
|
|
77
|
-
|
|
78
72
|
// Create OpenRouter client for reasoning token support
|
|
79
73
|
const openRouterClient = new OpenAI({
|
|
80
74
|
apiKey: process.env.VZCODE_EDIT_WITH_AI_API_KEY,
|
|
@@ -198,42 +192,6 @@ export const createLLMFunction = ({
|
|
|
198
192
|
currentEditingFileId,
|
|
199
193
|
line,
|
|
200
194
|
);
|
|
201
|
-
|
|
202
|
-
// Update AI presence to show cursor at the end of the file
|
|
203
|
-
const currentFile =
|
|
204
|
-
shareDBDoc.data.files[currentEditingFileId];
|
|
205
|
-
if (currentFile && currentFile.text) {
|
|
206
|
-
const textLength = currentFile.text.length;
|
|
207
|
-
const filePresence = {
|
|
208
|
-
username: 'AI Editor',
|
|
209
|
-
start: [
|
|
210
|
-
'files',
|
|
211
|
-
currentEditingFileId,
|
|
212
|
-
'text',
|
|
213
|
-
textLength,
|
|
214
|
-
],
|
|
215
|
-
end: [
|
|
216
|
-
'files',
|
|
217
|
-
currentEditingFileId,
|
|
218
|
-
'text',
|
|
219
|
-
textLength,
|
|
220
|
-
],
|
|
221
|
-
};
|
|
222
|
-
|
|
223
|
-
if (localPresence) {
|
|
224
|
-
localPresence.submit(
|
|
225
|
-
filePresence,
|
|
226
|
-
(error) => {
|
|
227
|
-
if (error) {
|
|
228
|
-
console.warn(
|
|
229
|
-
'AI Editor line presence submission error:',
|
|
230
|
-
error,
|
|
231
|
-
);
|
|
232
|
-
}
|
|
233
|
-
},
|
|
234
|
-
);
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
195
|
}
|
|
238
196
|
},
|
|
239
197
|
onNonCodeLine: async (line: string) => {
|
|
@@ -348,23 +306,6 @@ export const createLLMFunction = ({
|
|
|
348
306
|
// Finalize the AI message by clearing temporary fields
|
|
349
307
|
finalizeAIMessage(shareDBDoc, chatId);
|
|
350
308
|
|
|
351
|
-
// Clear AI Editor presence when done
|
|
352
|
-
DEBUG &&
|
|
353
|
-
console.log(
|
|
354
|
-
'AI editing done, clearing AI Editor presence',
|
|
355
|
-
);
|
|
356
|
-
if (localPresence) {
|
|
357
|
-
localPresence.submit(null, (error) => {
|
|
358
|
-
DEBUG && console.log('AI Editor presence cleared');
|
|
359
|
-
if (error) {
|
|
360
|
-
console.warn(
|
|
361
|
-
'AI Editor presence cleanup error:',
|
|
362
|
-
error,
|
|
363
|
-
);
|
|
364
|
-
}
|
|
365
|
-
});
|
|
366
|
-
}
|
|
367
|
-
|
|
368
309
|
// If streaming editing is not enabled, we need to
|
|
369
310
|
// apply all the edits at once
|
|
370
311
|
if (!enableStreamingEditing) {
|
package/src/server/index.ts
CHANGED
|
@@ -14,7 +14,6 @@ import { computeInitialDocument } from './computeInitialDocument.js';
|
|
|
14
14
|
import { handleAIAssist } from './handleAIAssist.js';
|
|
15
15
|
import { handleAICopilot } from './handleAICopilot.js';
|
|
16
16
|
import { handleAIChatMessage } from './handleAIChatMessage.js';
|
|
17
|
-
|
|
18
17
|
import { isDirectory } from './isDirectory.js';
|
|
19
18
|
import { createToken } from './livekit.js';
|
|
20
19
|
import './setupEnv.js';
|
|
@@ -100,21 +99,6 @@ app.use(express.static(dir));
|
|
|
100
99
|
const shareDBConnection = shareDBBackend.connect();
|
|
101
100
|
const shareDBDoc = shareDBConnection.get('documents', '1');
|
|
102
101
|
|
|
103
|
-
// Set up presence for AI editing following the same pattern as useShareDB.ts
|
|
104
|
-
const docPresence = shareDBConnection.getDocPresence(
|
|
105
|
-
'documents',
|
|
106
|
-
'1',
|
|
107
|
-
);
|
|
108
|
-
|
|
109
|
-
// Create local presence for AI editing with a unique ID
|
|
110
|
-
const generateAIEditId = () => {
|
|
111
|
-
const timestamp = Date.now().toString(36);
|
|
112
|
-
return `ai-edit-${timestamp}`;
|
|
113
|
-
};
|
|
114
|
-
|
|
115
|
-
const createAIEditLocalPresence = () =>
|
|
116
|
-
docPresence.create(generateAIEditId());
|
|
117
|
-
|
|
118
102
|
shareDBDoc.create(initialDocument, json1Presence.type.uri);
|
|
119
103
|
|
|
120
104
|
// Handle AI Assist requests.
|
|
@@ -137,7 +121,6 @@ app.post(
|
|
|
137
121
|
bodyParser.json(),
|
|
138
122
|
handleAIChatMessage({
|
|
139
123
|
shareDBDoc,
|
|
140
|
-
createAIEditLocalPresence,
|
|
141
124
|
onCreditDeduction: undefined,
|
|
142
125
|
}),
|
|
143
126
|
);
|
|
Binary file
|