vzcode 1.58.0 → 1.59.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,8 +20,8 @@
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-CtGus8Qk.js"></script>
24
- <link rel="stylesheet" crossorigin href="/assets/index-CE_xP06t.css">
23
+ <script type="module" crossorigin src="/assets/index-BJI4JLx9.js"></script>
24
+ <link rel="stylesheet" crossorigin href="/assets/index-afP-wJTZ.css">
25
25
  </head>
26
26
  <body>
27
27
  <div id="root"></div>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vzcode",
3
- "version": "1.58.0",
3
+ "version": "1.59.0",
4
4
  "description": "Multiplayer code editor system",
5
5
  "main": "src/index.ts",
6
6
  "type": "module",
@@ -117,8 +117,8 @@
117
117
  "@codemirror/state": "^6.5.2",
118
118
  "@codemirror/theme-one-dark": "^6.1.3",
119
119
  "@codemirror/view": "^6.38.1",
120
- "@langchain/core": "^0.3.66",
121
- "@langchain/openai": "^0.6.3",
120
+ "@langchain/core": "^0.3.67",
121
+ "@langchain/openai": "^0.6.4",
122
122
  "@lezer/highlight": "^1.2.1",
123
123
  "@livekit/components-react": "^2.9.14",
124
124
  "@replit/codemirror-indentation-markers": "^6.5.3",
@@ -179,7 +179,7 @@
179
179
  "@tauri-apps/cli": "^2.7.1",
180
180
  "@types/react": "^18",
181
181
  "@types/react-dom": "^18",
182
- "@vitejs/plugin-react": "^4.7.0",
182
+ "@vitejs/plugin-react": "^5.0.0",
183
183
  "concurrently": "^9.2.0",
184
184
  "cross-env": "^10.0.0",
185
185
  "eslint": "^9.32.0",
@@ -189,7 +189,7 @@
189
189
  "sass": "^1.90.0",
190
190
  "ts-node": "^10.9.2",
191
191
  "typescript": "^5.9.2",
192
- "vite": "^7.0.6",
192
+ "vite": "^7.1.0",
193
193
  "vitest": "^3.2.4"
194
194
  },
195
195
  "optionalDependencies": {
@@ -202,7 +202,10 @@ export type VZCodeContextValue = {
202
202
  currentChatId: string;
203
203
  aiErrorMessage: string | null;
204
204
  setAIErrorMessage: (state: string | null) => void;
205
- handleSendMessage: (messageToSend?: string) => void;
205
+ handleSendMessage: (
206
+ messageToSend?: string,
207
+ options?: Record<string, string>,
208
+ ) => void;
206
209
 
207
210
  // Auto-fork functions for VizHub integration
208
211
  autoForkAndRetryAI?: (
@@ -221,6 +224,10 @@ export type VZCodeContextValue = {
221
224
  messageId: string;
222
225
  chatId: string;
223
226
  canUndo: boolean;
227
+ handleSendMessage?: (
228
+ messageToSend?: string,
229
+ options?: Record<string, string>,
230
+ ) => void;
224
231
  }>;
225
232
  };
226
233
 
@@ -510,7 +517,10 @@ export const VZCodeProvider = ({
510
517
  >(null);
511
518
 
512
519
  const handleSendMessage = useCallback(
513
- async (messageToSend?: string) => {
520
+ async (
521
+ messageToSend?: string,
522
+ options?: Record<string, string>,
523
+ ) => {
514
524
  DEBUG &&
515
525
  console.log(
516
526
  'AIChat: handleSendMessage called with:',
@@ -544,10 +554,10 @@ export const VZCodeProvider = ({
544
554
  },
545
555
  body: JSON.stringify({
546
556
  ...aiChatOptions,
547
- vizId: aiChatOptions.vizId,
548
557
  content: messageContent.trim(),
549
558
  chatId: currentChatId,
550
559
  mode: aiChatMode,
560
+ ...options,
551
561
  }),
552
562
  });
553
563
 
@@ -40,6 +40,7 @@ const MessageComponent = ({
40
40
  aiChatUndoEndpoint,
41
41
  aiChatOptions = {},
42
42
  additionalWidgets,
43
+ handleSendMessage,
43
44
  } = useContext(VZCodeContext);
44
45
 
45
46
  // Memoize date formatting to avoid repeated computation
@@ -117,6 +118,7 @@ const MessageComponent = ({
117
118
  messageId: id,
118
119
  chatId: chatId,
119
120
  canUndo: canUndo,
121
+ handleSendMessage,
120
122
  })}
121
123
  {!additionalWidgets && canUndo && beforeFiles && (
122
124
  <div className="undo-button-container">
@@ -12,13 +12,11 @@ import { VizChatMessage } from '@vizhub/viz-types';
12
12
 
13
13
  const MessageListComponent = ({
14
14
  messages,
15
- aiStatus,
16
15
  isLoading,
17
16
  chatId, // Add chatId prop
18
17
  aiScratchpad, // Add aiScratchpad prop
19
18
  }: {
20
19
  messages: VizChatMessage[];
21
- aiStatus?: string;
22
20
  isLoading: boolean;
23
21
  chatId?: string; // Add chatId to the type
24
22
  aiScratchpad?: string; // Add aiScratchpad to the type
@@ -1,4 +1,10 @@
1
- import { memo } from 'react';
1
+ import {
2
+ memo,
3
+ useRef,
4
+ useEffect,
5
+ useCallback,
6
+ useState,
7
+ } from 'react';
2
8
  import Markdown from 'react-markdown';
3
9
  import remarkGfm from 'remark-gfm';
4
10
 
@@ -11,6 +17,115 @@ const ThinkingScratchpadComponent = ({
11
17
  content,
12
18
  isVisible,
13
19
  }: ThinkingScratchpadProps) => {
20
+ const contentRef = useRef<HTMLDivElement>(null);
21
+ const [isUserScrolled, setIsUserScrolled] =
22
+ useState(false);
23
+ const [autoScrollEnabled, setAutoScrollEnabled] =
24
+ useState(true);
25
+ const scrollTimeoutRef =
26
+ useRef<ReturnType<typeof setTimeout>>();
27
+
28
+ // Check if the user is scrolled to the bottom
29
+ const isScrolledToBottom = useCallback(() => {
30
+ const container = contentRef.current;
31
+ if (!container) return true;
32
+
33
+ const threshold = 10; // Allow 10px tolerance for "at bottom"
34
+ const { scrollTop, scrollHeight, clientHeight } =
35
+ container;
36
+ return (
37
+ scrollHeight - scrollTop - clientHeight < threshold
38
+ );
39
+ }, []);
40
+
41
+ // Smooth scroll to bottom
42
+ const scrollToBottom = useCallback(() => {
43
+ if (!autoScrollEnabled) return;
44
+
45
+ const container = contentRef.current;
46
+ if (container) {
47
+ container.scrollTo({
48
+ top: container.scrollHeight,
49
+ behavior: 'smooth',
50
+ });
51
+ }
52
+ }, [autoScrollEnabled]);
53
+
54
+ // Handle scroll events to detect user manual scrolling
55
+ const handleScroll = useCallback(() => {
56
+ const container = contentRef.current;
57
+ if (!container) return;
58
+
59
+ const isAtBottom = isScrolledToBottom();
60
+
61
+ // Clear any existing timeout
62
+ if (scrollTimeoutRef.current) {
63
+ clearTimeout(scrollTimeoutRef.current);
64
+ }
65
+
66
+ // If user scrolled up from bottom, disable auto-scroll
67
+ if (!isAtBottom && !isUserScrolled) {
68
+ setIsUserScrolled(true);
69
+ setAutoScrollEnabled(false);
70
+ }
71
+
72
+ // If user scrolled back to bottom, re-enable auto-scroll after a brief delay
73
+ if (isAtBottom && isUserScrolled) {
74
+ scrollTimeoutRef.current = setTimeout(() => {
75
+ setIsUserScrolled(false);
76
+ setAutoScrollEnabled(true);
77
+ }, 300); // 300ms delay to prevent flickering
78
+ }
79
+ }, [isUserScrolled, isScrolledToBottom]);
80
+
81
+ // Auto-scroll when content changes, but only if auto-scroll is enabled
82
+ useEffect(() => {
83
+ if (
84
+ autoScrollEnabled &&
85
+ !isUserScrolled &&
86
+ isVisible &&
87
+ content
88
+ ) {
89
+ // Use a short debounce to prevent multiple scroll calls during rapid updates
90
+ if (scrollTimeoutRef.current) {
91
+ clearTimeout(scrollTimeoutRef.current);
92
+ }
93
+
94
+ scrollTimeoutRef.current = setTimeout(() => {
95
+ scrollToBottom();
96
+ }, 50); // 50ms debounce
97
+ }
98
+
99
+ return () => {
100
+ if (scrollTimeoutRef.current) {
101
+ clearTimeout(scrollTimeoutRef.current);
102
+ }
103
+ };
104
+ }, [
105
+ content,
106
+ autoScrollEnabled,
107
+ isUserScrolled,
108
+ isVisible,
109
+ scrollToBottom,
110
+ ]);
111
+
112
+ // Clean up timeout on unmount
113
+ useEffect(() => {
114
+ return () => {
115
+ if (scrollTimeoutRef.current) {
116
+ clearTimeout(scrollTimeoutRef.current);
117
+ }
118
+ };
119
+ }, []);
120
+
121
+ // Reset scroll state when component becomes visible
122
+ useEffect(() => {
123
+ if (isVisible) {
124
+ setIsUserScrolled(false);
125
+ setAutoScrollEnabled(true);
126
+ }
127
+ }, [isVisible]);
128
+
14
129
  if (!isVisible || !content) {
15
130
  return null;
16
131
  }
@@ -23,7 +138,11 @@ const ThinkingScratchpadComponent = ({
23
138
  AI is thinking...
24
139
  </span>
25
140
  </div>
26
- <div className="thinking-scratchpad-content">
141
+ <div
142
+ className="thinking-scratchpad-content"
143
+ ref={contentRef}
144
+ onScroll={handleScroll}
145
+ >
27
146
  <Markdown remarkPlugins={[remarkGfm]}>
28
147
  {content}
29
148
  </Markdown>
@@ -1,18 +1,9 @@
1
- import {
2
- useContext,
3
- useState,
4
- useCallback,
5
- useMemo,
6
- useEffect,
7
- } from 'react';
1
+ import { useContext, useMemo, useEffect } from 'react';
8
2
  import { VZCodeContext } from '../../VZCodeContext';
9
- import { v4 as uuidv4 } from 'uuid';
10
3
  import { MessageList } from './MessageList';
11
4
  import { ChatInput } from './ChatInput';
12
5
  import './styles.scss';
13
6
 
14
- const defaultAIChatEndpoint = '/api/ai-chat/';
15
-
16
7
  const DEBUG = false;
17
8
 
18
9
  const showSuggestedRequests = true;
@@ -21,20 +12,16 @@ export const AIChat = () => {
21
12
  const {
22
13
  aiChatFocused,
23
14
  content,
24
- aiChatEndpoint = defaultAIChatEndpoint,
25
- aiChatOptions = {},
26
15
  aiChatMode,
27
16
  aiChatMessage,
28
17
  isLoading,
29
18
  currentChatId,
30
19
  aiErrorMessage,
31
20
  setAIChatMode,
32
- autoForkAndRetryAI,
33
21
  clearStoredAIPrompt,
34
22
  getStoredAIPrompt,
35
23
  setAIChatMessage,
36
24
  handleSendMessage,
37
- setIsLoading,
38
25
  setAIErrorMessage,
39
26
  } = useContext(VZCodeContext);
40
27
 
@@ -182,6 +182,7 @@
182
182
  .undo-button-container {
183
183
  display: flex;
184
184
  justify-content: flex-end;
185
+ gap: 8px;
185
186
  margin-top: 16px;
186
187
  }
187
188
 
@@ -560,6 +561,21 @@
560
561
  max-height: 200px;
561
562
  overflow-y: auto;
562
563
  background: var(--vh-color-neutral-02);
564
+ scroll-behavior: smooth;
565
+
566
+ &::-webkit-scrollbar {
567
+ width: 6px;
568
+ }
569
+
570
+ &::-webkit-scrollbar-track {
571
+ background: var(--vh-color-neutral-02);
572
+ border-radius: 3px;
573
+ }
574
+
575
+ &::-webkit-scrollbar-thumb {
576
+ background: var(--vh-color-neutral-04);
577
+ border-radius: 3px;
578
+ }
563
579
 
564
580
  // Style markdown content in thinking scratchpad
565
581
  p {
@@ -24,11 +24,13 @@ export const handleAIChatMessage =
24
24
  createAIEditLocalPresence,
25
25
  onCreditDeduction,
26
26
  getCurrentCommitId,
27
+ model,
27
28
  }: {
28
29
  shareDBDoc: ShareDBDoc<VizContent>;
29
30
  createAIEditLocalPresence: () => any;
30
31
  onCreditDeduction?: any;
31
32
  getCurrentCommitId?: () => string | null;
33
+ model?: string;
32
34
  }) =>
33
35
  async (req: any, res: any) => {
34
36
  const { content, chatId, mode = 'edit' } = req.body;
@@ -67,6 +69,7 @@ export const handleAIChatMessage =
67
69
  shareDBDoc,
68
70
  createAIEditLocalPresence,
69
71
  chatId,
72
+ model,
70
73
  });
71
74
 
72
75
  // Create server-side runCode function using shareDBDoc
@@ -49,11 +49,13 @@ export const createLLMFunction = ({
49
49
  // When false, reasoning tokens are not requested from the API
50
50
  // and reasoning content is not processed in the streaming response.
51
51
  enableReasoningTokens = false,
52
+ model,
52
53
  }: {
53
54
  shareDBDoc: ShareDBDoc<VizContent>;
54
55
  createAIEditLocalPresence: () => any;
55
56
  chatId: VizChatId;
56
57
  enableReasoningTokens?: boolean;
58
+ model?: string;
57
59
  }) => {
58
60
  return async (fullPrompt: string) => {
59
61
  const localPresence = enableStreamingEditing
@@ -200,6 +202,7 @@ export const createLLMFunction = ({
200
202
 
201
203
  // Stream the response with reasoning tokens
202
204
  const modelName =
205
+ model ||
203
206
  process.env.VIZHUB_EDIT_WITH_AI_MODEL_NAME ||
204
207
  'anthropic/claude-3.5-sonnet';
205
208