vzcode 2.3.0 → 2.5.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 (198) hide show
  1. package/dist/assets/{index-DuUjtrt6.js → index-DB93Pffa.js} +84 -84
  2. package/dist/index.html +1 -1
  3. package/package.json +3 -2
  4. package/src/cli.ts +208 -0
  5. package/src/client/AIAssist/AIAssistCodeMirrorKeyMap.ts +42 -0
  6. package/src/client/AIAssist/AIAssistWidget/index.tsx +135 -0
  7. package/src/client/AIAssist/AIAssistWidget/style.scss +47 -0
  8. package/src/client/AIAssist/Spinner.jsx +76 -0
  9. package/src/client/AIAssist/formatFile.ts +27 -0
  10. package/src/client/AIAssist/generateFilesContext.ts +25 -0
  11. package/src/client/AIAssist/index.ts +2 -0
  12. package/src/client/AIAssist/startAIAssist.ts +95 -0
  13. package/src/client/App/index.tsx +152 -0
  14. package/src/client/App/style.scss +82 -0
  15. package/src/client/App/usePending.ts +51 -0
  16. package/src/client/App/useShareDB.ts +161 -0
  17. package/src/client/CodeEditor/Copilot/index.ts +74 -0
  18. package/src/client/CodeEditor/InteractiveWidgets/boolToggler.ts +12 -0
  19. package/src/client/CodeEditor/InteractiveWidgets/colorPicker.ts +68 -0
  20. package/src/client/CodeEditor/InteractiveWidgets/colorsInTextPlugin.ts +174 -0
  21. package/src/client/CodeEditor/InteractiveWidgets/highlightWidgets.ts +79 -0
  22. package/src/client/CodeEditor/InteractiveWidgets/index.ts +44 -0
  23. package/src/client/CodeEditor/InteractiveWidgets/markdownCheckboxToggler.ts +12 -0
  24. package/src/client/CodeEditor/InteractiveWidgets/numberDragger.ts +20 -0
  25. package/src/client/CodeEditor/InteractiveWidgets/rotateWidget.ts +143 -0
  26. package/src/client/CodeEditor/InteractiveWidgets/urlClicker.test.ts +48 -0
  27. package/src/client/CodeEditor/InteractiveWidgets/urlClicker.ts +12 -0
  28. package/src/client/CodeEditor/InteractiveWidgets/vec2Slider.ts +25 -0
  29. package/src/client/CodeEditor/basicSetup.ts +73 -0
  30. package/src/client/CodeEditor/getOrCreateEditor.tsx +615 -0
  31. package/src/client/CodeEditor/index.tsx +202 -0
  32. package/src/client/CodeEditor/json1PresenceBroadcast.ts +41 -0
  33. package/src/client/CodeEditor/json1PresenceDisplay.ts +350 -0
  34. package/src/client/CodeEditor/rainbowBrackets.ts +122 -0
  35. package/src/client/CodeEditor/style.scss +156 -0
  36. package/src/client/CodeEditor/typescriptExtension/worker.ts +32 -0
  37. package/src/client/CodeErrorOverlay/index.tsx +77 -0
  38. package/src/client/CodeErrorOverlay/style.scss +33 -0
  39. package/src/client/Fonts/fonts.ts +8 -0
  40. package/src/client/Icons/AdjustmentSVG.tsx +19 -0
  41. package/src/client/Icons/BugSVG.tsx +20 -0
  42. package/src/client/Icons/CloseSVG.tsx +19 -0
  43. package/src/client/Icons/CssSVG.tsx +16 -0
  44. package/src/client/Icons/DirectoryArrowSVG.tsx +19 -0
  45. package/src/client/Icons/EditSVG.tsx +19 -0
  46. package/src/client/Icons/FileSVG.tsx +19 -0
  47. package/src/client/Icons/FolderSVG.tsx +20 -0
  48. package/src/client/Icons/GearSVG.tsx +16 -0
  49. package/src/client/Icons/HtmlSVG.tsx +16 -0
  50. package/src/client/Icons/JavaScriptSVG.tsx +16 -0
  51. package/src/client/Icons/JsonSVG.tsx +16 -0
  52. package/src/client/Icons/MarkdownSVG.tsx +16 -0
  53. package/src/client/Icons/MicOffSVG.tsx +35 -0
  54. package/src/client/Icons/MicSVG.tsx +25 -0
  55. package/src/client/Icons/NewSVG.tsx +19 -0
  56. package/src/client/Icons/PinSVG.tsx +14 -0
  57. package/src/client/Icons/PlaySVG.tsx +16 -0
  58. package/src/client/Icons/QuestionMarkSVG.tsx +18 -0
  59. package/src/client/Icons/ReactSVG.tsx +16 -0
  60. package/src/client/Icons/SearchSVG.tsx +20 -0
  61. package/src/client/Icons/SparklesSVG.tsx +23 -0
  62. package/src/client/Icons/SplitEditorSVG.tsx +34 -0
  63. package/src/client/Icons/StopSVG.tsx +15 -0
  64. package/src/client/Icons/SvelteSVG.tsx +16 -0
  65. package/src/client/Icons/TrashSVG.tsx +19 -0
  66. package/src/client/Icons/TypeScriptSVG.tsx +16 -0
  67. package/src/client/Icons/index.tsx +26 -0
  68. package/src/client/ImageViewer/index.tsx +91 -0
  69. package/src/client/ImageViewer/style.scss +41 -0
  70. package/src/client/PresenceNotifications/PresenceNotifications.test.ts +134 -0
  71. package/src/client/PresenceNotifications/index.tsx +158 -0
  72. package/src/client/PresenceNotifications/style.scss +17 -0
  73. package/src/client/RunCodeWidget/index.tsx +117 -0
  74. package/src/client/RunCodeWidget/style.scss +24 -0
  75. package/src/client/SplitPaneResizeContext.tsx +159 -0
  76. package/src/client/TabList/Tab.tsx +73 -0
  77. package/src/client/TabList/index.tsx +35 -0
  78. package/src/client/TabList/style.scss +51 -0
  79. package/src/client/VZCodeContext/index.tsx +29 -0
  80. package/src/client/VZCodeContext/types.ts +251 -0
  81. package/src/client/VZCodeContext/useVZCodeState.ts +606 -0
  82. package/src/client/VZKeyboardShortcutsDoc.tsx +148 -0
  83. package/src/client/VZLeft.tsx +28 -0
  84. package/src/client/VZMiddle.tsx +172 -0
  85. package/src/client/VZResizer/index.tsx +128 -0
  86. package/src/client/VZResizer/styles.scss +33 -0
  87. package/src/client/VZRight.tsx +113 -0
  88. package/src/client/VZSettings.tsx +275 -0
  89. package/src/client/VZSidebar/AIChat/ChatInput.tsx +243 -0
  90. package/src/client/VZSidebar/AIChat/DiffView.scss +136 -0
  91. package/src/client/VZSidebar/AIChat/DiffView.tsx +176 -0
  92. package/src/client/VZSidebar/AIChat/Message.tsx +79 -0
  93. package/src/client/VZSidebar/AIChat/MessageList.tsx +190 -0
  94. package/src/client/VZSidebar/AIChat/StreamingMessage.tsx +35 -0
  95. package/src/client/VZSidebar/AIChat/ThinkingScratchpad.tsx +156 -0
  96. package/src/client/VZSidebar/AIChat/TypingIndicator.tsx +19 -0
  97. package/src/client/VZSidebar/AIChat/index.tsx +359 -0
  98. package/src/client/VZSidebar/AIChat/styles.scss +646 -0
  99. package/src/client/VZSidebar/AIChat/useSpeechRecognition.ts +117 -0
  100. package/src/client/VZSidebar/CreateDirModal.tsx +111 -0
  101. package/src/client/VZSidebar/CreateFileModal.tsx +111 -0
  102. package/src/client/VZSidebar/DeleteConfirmationModal.tsx +76 -0
  103. package/src/client/VZSidebar/DirectoryListing.tsx +89 -0
  104. package/src/client/VZSidebar/EmptyState.tsx +11 -0
  105. package/src/client/VZSidebar/FileListing.tsx +91 -0
  106. package/src/client/VZSidebar/FileTypeIcon.tsx +49 -0
  107. package/src/client/VZSidebar/Item.tsx +237 -0
  108. package/src/client/VZSidebar/Listing.tsx +47 -0
  109. package/src/client/VZSidebar/Search.tsx +527 -0
  110. package/src/client/VZSidebar/VisualEditor.tsx +282 -0
  111. package/src/client/VZSidebar/VoiceChatModal.tsx +121 -0
  112. package/src/client/VZSidebar/aiCopyPaste.ts +199 -0
  113. package/src/client/VZSidebar/index.tsx +728 -0
  114. package/src/client/VZSidebar/styles.scss +612 -0
  115. package/src/client/VZSidebar/useDragAndDrop.tsx +408 -0
  116. package/src/client/bootstrap.ts +26 -0
  117. package/src/client/buildWorker.ts +3 -0
  118. package/src/client/featureFlags.ts +8 -0
  119. package/src/client/generateRequestId.ts +6 -0
  120. package/src/client/getFileTree.ts +53 -0
  121. package/src/client/index.ts +19 -0
  122. package/src/client/main.jsx +10 -0
  123. package/src/client/presenceColor.ts +8 -0
  124. package/src/client/shouldTriggerRun.ts +31 -0
  125. package/src/client/sortFileTree.ts +21 -0
  126. package/src/client/tabsSearchParameters.test.ts +79 -0
  127. package/src/client/tabsSearchParameters.ts +137 -0
  128. package/src/client/themes/index.ts +7 -0
  129. package/src/client/themes/themes.ts +77 -0
  130. package/src/client/themes/uiwImports.ts +32 -0
  131. package/src/client/themes/useDynamicTheme.ts +29 -0
  132. package/src/client/themes/vizhubTheme/colors.ts +80 -0
  133. package/src/client/themes/vizhubTheme/index.ts +193 -0
  134. package/src/client/useActions.ts +288 -0
  135. package/src/client/useESLint/index.ts +72 -0
  136. package/src/client/useESLint/worker.ts +113 -0
  137. package/src/client/useEditorCache.ts +35 -0
  138. package/src/client/useFileCRUD.ts +228 -0
  139. package/src/client/useKeyboardShortcuts.ts +451 -0
  140. package/src/client/useOpenDirectories.ts +99 -0
  141. package/src/client/usePresenceAutoFollow.ts +85 -0
  142. package/src/client/usePrettier/index.ts +178 -0
  143. package/src/client/usePrettier/worker.ts +109 -0
  144. package/src/client/useRunCode.tsx +15 -0
  145. package/src/client/useRuntimeError.ts +32 -0
  146. package/src/client/useSubmitOperation.ts +15 -0
  147. package/src/client/useURLSync.ts +137 -0
  148. package/src/client/usernameLocalStorage.ts +43 -0
  149. package/src/client/utils/fileExtension.ts +10 -0
  150. package/src/client/utils/isImageFile.ts +12 -0
  151. package/src/client/vzReducer/aiChatReducer.ts +44 -0
  152. package/src/client/vzReducer/closeTabReducer.test.ts +205 -0
  153. package/src/client/vzReducer/closeTabsReducer.ts +96 -0
  154. package/src/client/vzReducer/createInitialState.ts +38 -0
  155. package/src/client/vzReducer/editorNoLongerWantsFocusReducer.ts +9 -0
  156. package/src/client/vzReducer/findPane.ts +19 -0
  157. package/src/client/vzReducer/index.ts +250 -0
  158. package/src/client/vzReducer/openTabReducer.test.ts +127 -0
  159. package/src/client/vzReducer/openTabReducer.ts +74 -0
  160. package/src/client/vzReducer/searchReducer.test.ts +292 -0
  161. package/src/client/vzReducer/searchReducer.ts +181 -0
  162. package/src/client/vzReducer/setActiveFileIdReducer.ts +28 -0
  163. package/src/client/vzReducer/setActiveFileLeftRightReducer.ts +76 -0
  164. package/src/client/vzReducer/setIsDocOpenReducer.ts +9 -0
  165. package/src/client/vzReducer/setIsSettingsOpenReducer.ts +9 -0
  166. package/src/client/vzReducer/setThemeReducer.ts +9 -0
  167. package/src/client/vzReducer/setUsernameReducer.ts +9 -0
  168. package/src/client/vzReducer/splitCurrentPaneReducer.ts +66 -0
  169. package/src/client/vzReducer/toggleAutoFollowReducer.ts +12 -0
  170. package/src/client/vzReducer/updatePane.ts +40 -0
  171. package/src/client/vzReducer/updatePresenceIndicatorReducer.ts +30 -0
  172. package/src/client/vzReducer/visualEditorReducer.ts +9 -0
  173. package/src/ot.ts +24 -0
  174. package/src/randomId.ts +15 -0
  175. package/src/reactRouterExports.ts +15 -0
  176. package/src/runCode.ts +27 -0
  177. package/src/server/aiChatHandler/aiEditing.ts +151 -0
  178. package/src/server/aiChatHandler/chatOperations.ts +476 -0
  179. package/src/server/aiChatHandler/errorHandling.ts +66 -0
  180. package/src/server/aiChatHandler/index.ts +199 -0
  181. package/src/server/aiChatHandler/llmStreaming.ts +419 -0
  182. package/src/server/aiChatHandler/validation.ts +24 -0
  183. package/src/server/computeInitialDocument.ts +220 -0
  184. package/src/server/config.ts +24 -0
  185. package/src/server/featureFlags.ts +8 -0
  186. package/src/server/generateAIResponse.ts +188 -0
  187. package/src/server/handleAIAssist.ts +53 -0
  188. package/src/server/handleAIChatMessage.ts +2 -0
  189. package/src/server/handleAICopilot.ts +97 -0
  190. package/src/server/index.ts +379 -0
  191. package/src/server/isDirectory.ts +1 -0
  192. package/src/server/livekit.ts +24 -0
  193. package/src/server/prettier.ts +115 -0
  194. package/src/server/setupEnv.ts +8 -0
  195. package/src/submitOperation.ts +25 -0
  196. package/src/types.ts +205 -0
  197. package/src/utils/fileDiff.ts +117 -0
  198. package/src/vite-env.d.ts +10 -0
@@ -0,0 +1,359 @@
1
+ import {
2
+ useContext,
3
+ useMemo,
4
+ useEffect,
5
+ useCallback,
6
+ } from 'react';
7
+ import { VZCodeContext } from '../../VZCodeContext';
8
+ import { MessageList } from './MessageList';
9
+ import { ChatInput } from './ChatInput';
10
+ import './styles.scss';
11
+
12
+ const DEBUG = false;
13
+
14
+ const showSuggestedRequests = false;
15
+
16
+ const showPreviousChats = false;
17
+
18
+ // Component for displaying the list of existing chats
19
+ const ChatList = ({
20
+ chats,
21
+ selectedChatId,
22
+ onSelectChat,
23
+ getChatTitle,
24
+ }) => {
25
+ return (
26
+ <div className="ai-chat-list">
27
+ <div className="ai-chat-list-header">
28
+ <h4>Previous Chats</h4>
29
+ </div>
30
+ <div className="ai-chat-suggested-prompts">
31
+ {chats.map((chat) => (
32
+ <button
33
+ key={chat.id}
34
+ className={`ai-chat-suggested-prompt ${
35
+ selectedChatId === chat.id ? 'selected' : ''
36
+ }`}
37
+ onClick={() => onSelectChat(chat.id)}
38
+ >
39
+ {getChatTitle(chat)}
40
+ </button>
41
+ ))}
42
+ </div>
43
+ </div>
44
+ );
45
+ };
46
+
47
+ export const AIChat = () => {
48
+ const {
49
+ aiChatFocused,
50
+ content,
51
+ aiChatMode,
52
+ aiChatMessage,
53
+ isLoading,
54
+ currentChatId,
55
+ selectedChatId,
56
+ setSelectedChatId,
57
+ aiErrorMessage,
58
+ setAIChatMode,
59
+ clearStoredAIPrompt,
60
+ getStoredAIPrompt,
61
+ setAIChatMessage,
62
+ handleSendMessage,
63
+ setAIErrorMessage,
64
+ navigateMessageHistoryUp,
65
+ navigateMessageHistoryDown,
66
+ resetMessageHistoryNavigation,
67
+ } = useContext(VZCodeContext);
68
+
69
+ // Get the active chat ID and chat data
70
+ // If selectedChatId is set, use it; otherwise, if no chat selected, don't default to currentChatId
71
+ const activeChatId = selectedChatId;
72
+ const currentChat = activeChatId
73
+ ? content?.chats?.[activeChatId]
74
+ : null;
75
+ const rawMessages = currentChat?.messages || [];
76
+ const aiStatus = currentChat?.aiStatus;
77
+ const aiScratchpad = currentChat?.aiScratchpad;
78
+
79
+ // Transform messages to ensure they have required id field - memoized to avoid recreation
80
+ const messages = useMemo(
81
+ () =>
82
+ rawMessages.map((msg, index) => ({
83
+ ...msg,
84
+ id: msg.id || `msg-${index}`,
85
+ })),
86
+ [rawMessages],
87
+ );
88
+
89
+ // Check if this is the first time opening the chat (no messages) or no chat selected
90
+ const isEmptyState =
91
+ !selectedChatId || rawMessages.length === 0;
92
+
93
+ // Get all existing chats
94
+ const allChats = content?.chats || {};
95
+ const existingChats = Object.values(allChats).filter(
96
+ (chat) => chat.messages.length > 0,
97
+ );
98
+ const hasExistingChats = existingChats.length > 0;
99
+
100
+ // Generate title for a chat (first 50 characters of first user message)
101
+ const getChatTitle = (chat) => {
102
+ const firstUserMessage = chat.messages.find(
103
+ (msg) => msg.role === 'user',
104
+ );
105
+ if (!firstUserMessage) return 'New Chat';
106
+ return (
107
+ firstUserMessage.content.slice(0, 50) +
108
+ (firstUserMessage.content.length > 50 ? '...' : '')
109
+ );
110
+ };
111
+
112
+ // Wrapper for handleSendMessage to automatically select the chat when sending
113
+ const handleSendMessageWithSelection = useCallback(() => {
114
+ // If no chat is selected, select the currentChatId when sending a message
115
+ if (!selectedChatId) {
116
+ setSelectedChatId(currentChatId);
117
+ }
118
+
119
+ // Call the original handleSendMessage without parameters
120
+ return handleSendMessage();
121
+ }, [
122
+ selectedChatId,
123
+ setSelectedChatId,
124
+ currentChatId,
125
+ handleSendMessage,
126
+ ]);
127
+
128
+ // Check for stored AI prompt on component mount (post-fork restoration)
129
+ useEffect(() => {
130
+ DEBUG &&
131
+ console.log('AIChat: Checking for stored AI prompt');
132
+ if (getStoredAIPrompt) {
133
+ const storedPrompt = getStoredAIPrompt();
134
+ DEBUG &&
135
+ console.log(
136
+ 'AIChat: Stored prompt result:',
137
+ storedPrompt,
138
+ );
139
+ if (storedPrompt) {
140
+ // Restore the prompt and mode
141
+ DEBUG &&
142
+ console.log('AIChat: Restoring prompt and mode');
143
+ setAIChatMessage(storedPrompt.prompt);
144
+ setAIChatMode(
145
+ storedPrompt.modelName === 'ask' ? 'ask' : 'edit',
146
+ );
147
+
148
+ // Clear the stored prompt
149
+ DEBUG &&
150
+ console.log('AIChat: Clearing stored prompt');
151
+ clearStoredAIPrompt();
152
+
153
+ // Auto-submit the restored prompt after a short delay
154
+ DEBUG &&
155
+ console.log('AIChat: Scheduling auto-submit');
156
+ setTimeout(() => {
157
+ DEBUG &&
158
+ console.log(
159
+ 'AIChat: Auto-submitting restored prompt',
160
+ );
161
+ handleSendMessage(storedPrompt.prompt);
162
+ }, 100);
163
+ } else {
164
+ DEBUG &&
165
+ console.log('AIChat: No stored prompt found');
166
+ }
167
+ }
168
+ }, [
169
+ getStoredAIPrompt,
170
+ clearStoredAIPrompt,
171
+ setAIChatMessage,
172
+ setAIChatMode,
173
+ handleSendMessage,
174
+ ]);
175
+
176
+ return (
177
+ <div className="ai-chat-container">
178
+ <div className="ai-chat-content">
179
+ <div className="ai-chat-messages-container">
180
+ {isEmptyState ? (
181
+ <div className="ai-chat-empty">
182
+ <div className="ai-chat-empty-icon">✨</div>
183
+ <h3 className="ai-chat-empty-title">
184
+ Edit with AI
185
+ </h3>
186
+ <div className="ai-chat-empty-text">
187
+ How can I help you?
188
+ </div>
189
+ {hasExistingChats && showPreviousChats && (
190
+ <ChatList
191
+ chats={existingChats}
192
+ selectedChatId={selectedChatId}
193
+ onSelectChat={setSelectedChatId}
194
+ getChatTitle={getChatTitle}
195
+ />
196
+ )}
197
+ {showSuggestedRequests && (
198
+ <div className="ai-chat-empty-examples">
199
+ {aiChatMode === 'ask' ? (
200
+ <>
201
+ <h4>Try asking questions like:</h4>
202
+ <div className="ai-chat-suggested-prompts">
203
+ <button
204
+ className="ai-chat-suggested-prompt"
205
+ onClick={() =>
206
+ handleSendMessage(
207
+ 'Explain how this works',
208
+ )
209
+ }
210
+ >
211
+ "Explain how this works"
212
+ </button>
213
+ <button
214
+ className="ai-chat-suggested-prompt"
215
+ onClick={() =>
216
+ handleSendMessage(
217
+ 'How could I change it so that the circles are bigger?',
218
+ )
219
+ }
220
+ >
221
+ "How could I change it so that the
222
+ circles are bigger?"
223
+ </button>
224
+ <button
225
+ className="ai-chat-suggested-prompt"
226
+ onClick={() =>
227
+ handleSendMessage(
228
+ 'What does this function do?',
229
+ )
230
+ }
231
+ >
232
+ "What does this function do?"
233
+ </button>
234
+ <button
235
+ className="ai-chat-suggested-prompt"
236
+ onClick={() =>
237
+ handleSendMessage(
238
+ 'How can I make this more accessible?',
239
+ )
240
+ }
241
+ >
242
+ "How can I make this more
243
+ accessible?"
244
+ </button>
245
+ </div>
246
+ </>
247
+ ) : (
248
+ <>
249
+ <h4>Try edit requests like these:</h4>
250
+ <div className="ai-chat-suggested-prompts">
251
+ <button
252
+ className="ai-chat-suggested-prompt"
253
+ onClick={() =>
254
+ handleSendMessage(
255
+ 'Change the circles to squares',
256
+ )
257
+ }
258
+ >
259
+ "Change the circles to squares"
260
+ </button>
261
+ <button
262
+ className="ai-chat-suggested-prompt"
263
+ onClick={() =>
264
+ handleSendMessage(
265
+ 'Add a button that toggles the animation',
266
+ )
267
+ }
268
+ >
269
+ "Add a button that toggles the
270
+ animation"
271
+ </button>
272
+ <button
273
+ className="ai-chat-suggested-prompt"
274
+ onClick={() =>
275
+ handleSendMessage(
276
+ 'Fix the CSS so the layout is responsive',
277
+ )
278
+ }
279
+ >
280
+ "Fix the CSS so the layout is
281
+ responsive"
282
+ </button>
283
+ <button
284
+ className="ai-chat-suggested-prompt"
285
+ onClick={() =>
286
+ handleSendMessage(
287
+ 'Refactor this function to use async/await',
288
+ )
289
+ }
290
+ >
291
+ "Refactor this function to use
292
+ async/await"
293
+ </button>
294
+ </div>
295
+ </>
296
+ )}
297
+ </div>
298
+ )}
299
+ {showSuggestedRequests && (
300
+ <div className="ai-chat-empty-text">
301
+ {aiChatMode === 'ask'
302
+ ? 'Type your question below to get started!'
303
+ : 'Type your edit request below to get started!'}
304
+ </div>
305
+ )}
306
+ </div>
307
+ ) : (
308
+ <MessageList
309
+ messages={messages}
310
+ aiStatus={aiStatus}
311
+ isLoading={isLoading}
312
+ chatId={selectedChatId || currentChatId}
313
+ aiScratchpad={aiScratchpad}
314
+ />
315
+ )}
316
+ {aiErrorMessage && (
317
+ <div className="ai-chat-error">
318
+ <div className="ai-chat-error-content">
319
+ <span className="ai-chat-error-icon">
320
+ ⚠️
321
+ </span>
322
+ <span className="ai-chat-error-message">
323
+ {aiErrorMessage}
324
+ </span>
325
+ <button
326
+ className="ai-chat-error-dismiss"
327
+ onClick={() => setAIErrorMessage(null)}
328
+ aria-label="Dismiss error"
329
+ >
330
+ ×
331
+ </button>
332
+ </div>
333
+ </div>
334
+ )}
335
+ </div>
336
+ </div>
337
+ <div className="ai-chat-input-fixed">
338
+ <ChatInput
339
+ aiChatMessage={aiChatMessage}
340
+ setAIChatMessage={setAIChatMessage}
341
+ onSendMessage={handleSendMessageWithSelection}
342
+ isLoading={isLoading}
343
+ focused={aiChatFocused}
344
+ aiChatMode={aiChatMode}
345
+ setAIChatMode={setAIChatMode}
346
+ navigateMessageHistoryUp={
347
+ navigateMessageHistoryUp
348
+ }
349
+ navigateMessageHistoryDown={
350
+ navigateMessageHistoryDown
351
+ }
352
+ resetMessageHistoryNavigation={
353
+ resetMessageHistoryNavigation
354
+ }
355
+ />
356
+ </div>
357
+ </div>
358
+ );
359
+ };