vzcode 1.24.0 → 1.26.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/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-C8aUgAEA.js"></script>
23
+ <script type="module" crossorigin src="/assets/index-CT7aAJ4z.js"></script>
24
24
  <link rel="stylesheet" crossorigin href="/assets/index-zzK6rRiK.css">
25
25
  </head>
26
26
  <body>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vzcode",
3
- "version": "1.24.0",
3
+ "version": "1.26.0",
4
4
  "description": "Multiplayer code editor system",
5
5
  "main": "src/index.ts",
6
6
  "type": "module",
@@ -113,6 +113,8 @@
113
113
  "@codemirror/state": "^6.5.2",
114
114
  "@codemirror/theme-one-dark": "^6.1.2",
115
115
  "@codemirror/view": "^6.36.3",
116
+ "@langchain/core": "^0.3.40",
117
+ "@langchain/openai": "^0.4.4",
116
118
  "@lezer/highlight": "^1.2.1",
117
119
  "@livekit/components-react": "^2.8.1",
118
120
  "@livekit/components-styles": "^1.1.4",
@@ -140,23 +142,25 @@
140
142
  "diff-match-patch": "^1.0.5",
141
143
  "dotenv": "^16.4.7",
142
144
  "express": "^4.21.2",
145
+ "i": "^0.3.7",
143
146
  "ignore": "^7.0.3",
144
147
  "json0-ot-diff": "^1.1.2",
145
- "livekit-client": "^2.9.2",
148
+ "livekit-client": "^2.9.4",
146
149
  "livekit-server-sdk": "^2.10.1",
147
150
  "ngrok": "^4.3.3",
151
+ "npm": "^11.1.0",
148
152
  "open": "^10.1.0",
149
- "openai": "^4.85.1",
153
+ "openai": "^4.85.4",
150
154
  "prettier-plugin-svelte": "^3.3.3",
151
155
  "react": "^18",
152
156
  "react-bootstrap": "^2.10.9",
153
157
  "react-dom": "^18",
154
- "react-router-dom": "^7.1.5",
158
+ "react-router-dom": "^7.2.0",
155
159
  "sharedb": "^5.1.1",
156
160
  "sharedb-client-browser": "^5.1.1",
157
- "uuid": "^11.0.5",
161
+ "uuid": "^11.1.0",
158
162
  "vizhub-ui": "^3.23.0",
159
- "ws": "^8.18.0"
163
+ "ws": "^8.18.1"
160
164
  },
161
165
  "devDependencies": {
162
166
  "@types/react": "^18",
@@ -164,11 +168,11 @@
164
168
  "@vitejs/plugin-react": "^4.3.4",
165
169
  "concurrently": "^9.1.2",
166
170
  "cross-env": "^7.0.3",
167
- "prettier": "^3.5.1",
171
+ "prettier": "^3.5.2",
168
172
  "sass": "^1.85.0",
169
173
  "typescript": "^5.7.3",
170
- "vite": "^6.1.0",
171
- "vitest": "^3.0.6"
174
+ "vite": "^6.1.1",
175
+ "vitest": "^3.0.7"
172
176
  },
173
177
  "optionalDependencies": {
174
178
  "@rollup/rollup-darwin-arm64": "^4.34.8",
@@ -122,7 +122,10 @@ function App() {
122
122
  >
123
123
  <div className="app">
124
124
  <VZLeft />
125
- <VZMiddle allowGlobals={true} />
125
+ <VZMiddle
126
+ allowGlobals={true}
127
+ aiCopilotEndpoint={'/ai-copilot'}
128
+ />
126
129
  {enableRightPanel ? <VZRight /> : null}
127
130
  <VZResizer side="left" />
128
131
  {enableRightPanel ? (
@@ -2,25 +2,71 @@ import { inlineCopilot } from 'codemirror-copilot';
2
2
 
3
3
  const defaultAICopilotEndpoint = '/ai-copilot';
4
4
 
5
+ const DEBUG = false;
6
+
7
+ // If the endpoint is broken, we don't want to keep sending requests
8
+ // to it. This flag will be set to true if we get an error from the
9
+ // server.
10
+ let isEndpointBroken = false;
11
+
5
12
  export const copilot = ({
6
13
  aiCopilotEndpoint = defaultAICopilotEndpoint,
7
14
  }: {
8
15
  aiCopilotEndpoint: string;
9
16
  }) => {
10
17
  return inlineCopilot(async (prefix, suffix) => {
18
+ DEBUG &&
19
+ console.log('[copilot] Executing AI completion...');
20
+ if (isEndpointBroken) {
21
+ DEBUG &&
22
+ console.log(
23
+ '[copilot] Endpoint is broken, not sending request',
24
+ );
25
+ return '';
26
+ }
27
+
28
+ DEBUG &&
29
+ console.log('[copilot] Sending request to server...');
11
30
  const response = await fetch(aiCopilotEndpoint, {
12
31
  method: 'POST',
13
32
  headers: { 'Content-Type': 'application/json' },
14
33
  body: JSON.stringify({ prefix, suffix }),
15
34
  });
16
35
 
36
+ if (!response.ok) {
37
+ DEBUG &&
38
+ console.error(
39
+ '[copilot] Error from server:',
40
+ response.statusText,
41
+ );
42
+ DEBUG &&
43
+ console.error(
44
+ '[copilot] Disabling future requests to the server',
45
+ );
46
+ isEndpointBroken = true;
47
+ return '';
48
+ }
49
+
17
50
  const responseJson = await response.json();
18
51
 
19
- if (responseJson.error) {
20
- console.error(
21
- '[copilot] error from server:',
22
- responseJson.error,
52
+ DEBUG &&
53
+ console.log(
54
+ '[copilot] Response from server:',
55
+ response,
23
56
  );
57
+
58
+ if (responseJson.error) {
59
+ DEBUG &&
60
+ console.error(
61
+ '[copilot] error from server:',
62
+ responseJson.error,
63
+ );
64
+ DEBUG &&
65
+ console.error(
66
+ '[copilot] Disabling future requests to the server',
67
+ );
68
+ isEndpointBroken = true;
69
+ return '';
24
70
  }
25
71
 
26
72
  return responseJson.text;
@@ -50,10 +50,14 @@ import { javascriptLanguage } from '@codemirror/lang-javascript';
50
50
  import { copilot } from './Copilot';
51
51
 
52
52
  // Feature flag to enable TypeScript completions & TypeScript Linter.
53
- const enableTypeScriptLinter = true;
53
+ // This is disabled by default because it's buggy and glitchy.
54
+ // It's overly aggressive and shows warnings where it should not.
55
+ // Path forward:
56
+ // * Remove this entire TypeScript linter implementation
57
+ // * Use val-town/codemirror-ts: https://github.com/vizhub-core/vzcode/issues/844
58
+ const enableTypeScriptLinter = false;
54
59
 
55
- // Feature flag to enable AI copilot
56
- const enableCopilot = true;
60
+ const DEBUG = false;
57
61
 
58
62
  // Enables TypeScript +JSX support in CodeMirror.
59
63
  const tsx = () =>
@@ -135,7 +139,7 @@ export const getOrCreateEditor = ({
135
139
  enableAutoFollowRef,
136
140
  openTab,
137
141
  aiCopilotEndpoint,
138
- rainbowBracketsEnabled = true, // New parameter to enable or disable Rainbow Brackets
142
+ rainbowBracketsEnabled = true,
139
143
  }: {
140
144
  // TODO pass this in from the outside
141
145
  paneId?: PaneId;
@@ -172,7 +176,7 @@ export const getOrCreateEditor = ({
172
176
  // enable auto-following the cursors of remote users.
173
177
  enableAutoFollowRef: React.MutableRefObject<boolean>;
174
178
  openTab: (tabState: TabState) => void;
175
- aiCopilotEndpoint: string;
179
+ aiCopilotEndpoint?: string;
176
180
  rainbowBracketsEnabled?: boolean; // New parameter type
177
181
  }): ExtendedEditorCacheValue => {
178
182
  // Cache hit
@@ -411,8 +415,13 @@ export const getOrCreateEditor = ({
411
415
  ),
412
416
  );
413
417
 
414
- // adds copilot
415
- if (enableCopilot) {
418
+ // Adds copilot completions
419
+ DEBUG &&
420
+ console.log(
421
+ '[getOrCreateEditor] aiCopilotEndpoint: ',
422
+ aiCopilotEndpoint,
423
+ );
424
+ if (aiCopilotEndpoint) {
416
425
  extensions.push(copilot({ aiCopilotEndpoint }));
417
426
  }
418
427
 
@@ -23,7 +23,7 @@ export const CodeEditor = ({
23
23
  }: {
24
24
  customInteractRules?: Array<InteractRule>;
25
25
  allowGlobals: boolean;
26
- aiCopilotEndpoint: string;
26
+ aiCopilotEndpoint?: string;
27
27
  }) => {
28
28
  const {
29
29
  activePane,
@@ -79,7 +79,7 @@ const PaneView = ({
79
79
  // * The presence notifications
80
80
  // * The UI for AI Assist
81
81
  export const VZMiddle = ({
82
- enableAIAssist = true,
82
+ enableAIAssist = false,
83
83
  aiAssistEndpoint,
84
84
  aiAssistOptions,
85
85
  aiAssistTooltipText,
@@ -9,15 +9,15 @@
9
9
  // because there is no "type": "module" field in the package.json
10
10
  // of any of these `@uiw/codemirror-theme-*` packages.
11
11
 
12
- import { okaidia } from '@uiw/codemirror-theme-okaidia/esm/index.js';
13
- import { abcdef } from '@uiw/codemirror-theme-abcdef/esm/index.js';
14
- import { dracula } from '@uiw/codemirror-theme-dracula/esm/index.js';
15
- import { eclipse } from '@uiw/codemirror-theme-eclipse/esm/index.js';
16
- import { githubDark } from '@uiw/codemirror-theme-github/esm/index.js';
17
- import { material } from '@uiw/codemirror-theme-material/esm/index.js';
18
- import { nord } from '@uiw/codemirror-theme-nord/esm/index.js';
19
- import { xcodeLight } from '@uiw/codemirror-theme-xcode/esm/index.js';
20
- import { createTheme } from '@uiw/codemirror-themes/esm/index.js';
12
+ import { okaidia } from '@uiw/codemirror-theme-okaidia';
13
+ import { abcdef } from '@uiw/codemirror-theme-abcdef';
14
+ import { dracula } from '@uiw/codemirror-theme-dracula';
15
+ import { eclipse } from '@uiw/codemirror-theme-eclipse';
16
+ import { githubDark } from '@uiw/codemirror-theme-github';
17
+ import { material } from '@uiw/codemirror-theme-material';
18
+ import { nord } from '@uiw/codemirror-theme-nord';
19
+ import { xcodeLight } from '@uiw/codemirror-theme-xcode';
20
+ import { createTheme } from '@uiw/codemirror-themes';
21
21
 
22
22
  export {
23
23
  okaidia,
@@ -1,45 +1,52 @@
1
- import OpenAI from 'openai';
1
+ import { ChatOpenAI } from '@langchain/openai';
2
+ import { StringOutputParser } from '@langchain/core/output_parsers';
2
3
 
3
- // This module implements the generation of the copilot response,
4
- // using the OpenAI client (but not necessarily the OpenAI service).
4
+ // This module implements the generation of the copilot response.
5
5
 
6
6
  // Debug flag to log more information during development.
7
7
  const debug = false;
8
8
 
9
- // These environment variables are used to configure the OpenAI client.
10
- // See `.env.sample` for the expected values.
11
- const {
12
- VZCODE_AI_COPILOT_API_KEY,
13
- VZCODE_AI_COLIPOT_BASE_URL,
14
- VZCODE_AI_COLIPOT_MODEL,
15
- } = process.env;
9
+ export const handleAICopilot = () => {
10
+ // These environment variables are used to configure the OpenAI client.
11
+ // See `.env.sample` for the expected values.
12
+ const {
13
+ VZCODE_AI_COPILOT_API_KEY,
14
+ VZCODE_AI_COPILOT_BASE_URL,
15
+ VZCODE_AI_COPILOT_MODEL,
16
+ } = process.env;
16
17
 
17
- // If neither of these are not set, the OpenAI client will not be initialized,
18
- // e.g. for local development where no AI is needed.
19
- const isCopilotEnabled =
20
- VZCODE_AI_COPILOT_API_KEY !== undefined &&
21
- VZCODE_AI_COLIPOT_BASE_URL !== undefined &&
22
- VZCODE_AI_COLIPOT_MODEL !== undefined;
18
+ // If neither of these are not set, the OpenAI client will not be initialized,
19
+ // e.g. for local development where no AI is needed.
20
+ const isCopilotEnabled =
21
+ VZCODE_AI_COPILOT_API_KEY !== undefined &&
22
+ VZCODE_AI_COPILOT_BASE_URL !== undefined &&
23
+ VZCODE_AI_COPILOT_MODEL !== undefined;
23
24
 
24
- debug &&
25
- console.log('isCopilotEnabled: ' + isCopilotEnabled);
25
+ debug &&
26
+ console.log('isCopilotEnabled: ' + isCopilotEnabled);
26
27
 
27
- let openai;
28
- if (isCopilotEnabled) {
29
- const openAIOptions = {
30
- apiKey: VZCODE_AI_COPILOT_API_KEY,
31
- baseURL: VZCODE_AI_COLIPOT_BASE_URL,
32
- };
33
28
  debug &&
34
- console.log(
35
- 'openAIOptions: ' +
36
- JSON.stringify(openAIOptions, null, 2),
37
- );
38
- openai = new OpenAI(openAIOptions);
39
- }
29
+ console.log({
30
+ VZCODE_AI_COPILOT_API_KEY,
31
+ VZCODE_AI_COPILOT_BASE_URL,
32
+ VZCODE_AI_COPILOT_MODEL,
33
+ });
34
+
35
+ let chatModel;
36
+ if (isCopilotEnabled) {
37
+ const options = {
38
+ modelName: VZCODE_AI_COPILOT_MODEL,
39
+ configuration: {
40
+ apiKey: VZCODE_AI_COPILOT_API_KEY,
41
+ baseURL: VZCODE_AI_COPILOT_BASE_URL,
42
+ },
43
+ streaming: false,
44
+ };
45
+ debug && console.log('chatModel options:', options);
46
+ chatModel = new ChatOpenAI(options);
47
+ }
40
48
 
41
- export const handleAICopilot = (/*TODO shareDBDoc*/) =>
42
- async (req, res) => {
49
+ return async (req, res) => {
43
50
  // Don't break if the AI is not enabled.
44
51
  // This is useful for local development.
45
52
  if (!isCopilotEnabled) {
@@ -48,23 +55,33 @@ export const handleAICopilot = (/*TODO shareDBDoc*/) =>
48
55
  }
49
56
  const { prefix, suffix } = req.body;
50
57
 
51
- const prompt = `<|fim_prefix|>${prefix}<|fim_suffix|>${suffix}<|fim_middle|>`;
52
-
58
+ const messages = [
59
+ {
60
+ role: 'user',
61
+ content: [
62
+ 'Complete the missing part of the text below:\n\n',
63
+ '\`\`\`\n',
64
+ prefix,
65
+ '<MISSING_PART>',
66
+ suffix,
67
+ '\`\`\`\n\n',
68
+ 'ONLY output the text that replaces <MISSING_PART>.\n\n',
69
+ 'NEVER include \`\`\`javascript or similar code blocks.\n\n',
70
+ ].join(''),
71
+ },
72
+ ];
53
73
  if (debug) {
54
74
  console.log(
55
75
  '[generateAIResponse] prompt:\n```\n' +
56
- prompt +
76
+ messages[0].content +
57
77
  '\n```\n',
58
78
  );
59
79
  }
60
80
  try {
61
- const completion = await openai.completions.create({
62
- model: VZCODE_AI_COLIPOT_MODEL,
63
- prompt,
64
- max_tokens: 150,
65
- stop: ['<|fim_pad|>', '<|file_sep|>'],
66
- });
67
- const text = completion.choices[0].text;
81
+ console.log(messages);
82
+ const result = await chatModel.invoke(messages);
83
+ const parser = new StringOutputParser();
84
+ const text = await parser.invoke(result);
68
85
 
69
86
  res.status(200).send({ text });
70
87
  } catch (error) {
@@ -75,3 +92,4 @@ export const handleAICopilot = (/*TODO shareDBDoc*/) =>
75
92
  });
76
93
  }
77
94
  };
95
+ };
@@ -109,7 +109,7 @@ app.post(
109
109
  app.post(
110
110
  '/ai-copilot',
111
111
  bodyParser.json(),
112
- handleAICopilot(shareDBDoc),
112
+ handleAICopilot(),
113
113
  );
114
114
 
115
115
  // Livekit Token Generator