@alpaca-editor/core 1.0.4033 → 1.0.4037

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 (187) hide show
  1. package/dist/components/index.d.ts +1 -0
  2. package/dist/components/index.js +1 -0
  3. package/dist/components/index.js.map +1 -1
  4. package/dist/{editor/menubar → components/ui}/LanguageSelector.d.ts +1 -1
  5. package/dist/{editor/menubar → components/ui}/LanguageSelector.js +8 -8
  6. package/dist/components/ui/LanguageSelector.js.map +1 -0
  7. package/dist/components/ui/button.d.ts +1 -1
  8. package/dist/components/ui/dropdown-menu.d.ts +1 -1
  9. package/dist/components/ui/dropdown-menu.js +2 -2
  10. package/dist/components/ui/dropdown-menu.js.map +1 -1
  11. package/dist/components/ui/sonner.js +3 -1
  12. package/dist/components/ui/sonner.js.map +1 -1
  13. package/dist/config/config.js +5 -5
  14. package/dist/config/config.js.map +1 -1
  15. package/dist/editor/ContentTree.d.ts +2 -1
  16. package/dist/editor/ContentTree.js +33 -9
  17. package/dist/editor/ContentTree.js.map +1 -1
  18. package/dist/editor/PictureEditor.js +2 -2
  19. package/dist/editor/PictureEditor.js.map +1 -1
  20. package/dist/editor/ScrollingContentTree.d.ts +2 -1
  21. package/dist/editor/ScrollingContentTree.js +2 -2
  22. package/dist/editor/ScrollingContentTree.js.map +1 -1
  23. package/dist/editor/Terminal.d.ts +2 -0
  24. package/dist/editor/Terminal.js +2 -2
  25. package/dist/editor/Terminal.js.map +1 -1
  26. package/dist/editor/ai/AgentHistory.d.ts +11 -0
  27. package/dist/editor/ai/AgentHistory.js +12 -0
  28. package/dist/editor/ai/AgentHistory.js.map +1 -0
  29. package/dist/editor/ai/Agents.js +187 -24
  30. package/dist/editor/ai/Agents.js.map +1 -1
  31. package/dist/editor/ai/AiResponseMessage.d.ts +2 -1
  32. package/dist/editor/ai/AiResponseMessage.js +6 -6
  33. package/dist/editor/ai/AiResponseMessage.js.map +1 -1
  34. package/dist/editor/ai/AiTerminal.d.ts +1 -0
  35. package/dist/editor/ai/AiTerminal.js +330 -43
  36. package/dist/editor/ai/AiTerminal.js.map +1 -1
  37. package/dist/editor/client/itemsRepository.js +19 -7
  38. package/dist/editor/client/itemsRepository.js.map +1 -1
  39. package/dist/editor/field-types/InternalLinkFieldEditor.js +48 -1
  40. package/dist/editor/field-types/InternalLinkFieldEditor.js.map +1 -1
  41. package/dist/editor/field-types/richtext/contextMenuFactory.js +1 -1
  42. package/dist/editor/field-types/richtext/contextMenuFactory.js.map +1 -1
  43. package/dist/editor/menubar/ItemLanguageVersion.js +1 -1
  44. package/dist/editor/menubar/ItemLanguageVersion.js.map +1 -1
  45. package/dist/editor/menubar/PageSelector.js +1 -1
  46. package/dist/editor/menubar/PageSelector.js.map +1 -1
  47. package/dist/editor/page-editor-chrome/FieldActionIndicator.js +1 -1
  48. package/dist/editor/page-editor-chrome/FieldActionIndicator.js.map +1 -1
  49. package/dist/editor/page-editor-chrome/FieldEditedIndicator.js +2 -2
  50. package/dist/editor/page-editor-chrome/FieldEditedIndicator.js.map +1 -1
  51. package/dist/editor/page-editor-chrome/FrameMenu.js +2 -2
  52. package/dist/editor/page-editor-chrome/FrameMenu.js.map +1 -1
  53. package/dist/editor/page-editor-chrome/InlineEditor.js +9 -9
  54. package/dist/editor/page-editor-chrome/InlineEditor.js.map +1 -1
  55. package/dist/editor/page-editor-chrome/LockedFieldIndicator.js +2 -2
  56. package/dist/editor/page-editor-chrome/LockedFieldIndicator.js.map +1 -1
  57. package/dist/editor/page-editor-chrome/PageEditorChrome.js +1 -1
  58. package/dist/editor/page-editor-chrome/PageEditorChrome.js.map +1 -1
  59. package/dist/editor/page-editor-chrome/PictureEditorOverlay.js +1 -1
  60. package/dist/editor/page-editor-chrome/PictureEditorOverlay.js.map +1 -1
  61. package/dist/editor/page-editor-chrome/PlaceholderDropZone.js +1 -1
  62. package/dist/editor/page-editor-chrome/PlaceholderDropZones.js +2 -2
  63. package/dist/editor/page-editor-chrome/PlaceholderDropZones.js.map +1 -1
  64. package/dist/editor/page-editor-chrome/useInlineAICompletion.js +12 -12
  65. package/dist/editor/page-editor-chrome/useInlineAICompletion.js.map +1 -1
  66. package/dist/editor/page-viewer/EditorForm.js +1 -1
  67. package/dist/editor/page-viewer/EditorForm.js.map +1 -1
  68. package/dist/editor/page-viewer/MiniMap.js +10 -11
  69. package/dist/editor/page-viewer/MiniMap.js.map +1 -1
  70. package/dist/editor/page-viewer/PageViewer.js +2 -2
  71. package/dist/editor/page-viewer/PageViewer.js.map +1 -1
  72. package/dist/editor/page-viewer/PageViewerFrame.js +4 -4
  73. package/dist/editor/page-viewer/PageViewerFrame.js.map +1 -1
  74. package/dist/editor/page-viewer/pageViewContext.d.ts +2 -2
  75. package/dist/editor/page-viewer/pageViewContext.js +11 -14
  76. package/dist/editor/page-viewer/pageViewContext.js.map +1 -1
  77. package/dist/editor/services/agentService.d.ts +21 -1
  78. package/dist/editor/services/agentService.js +101 -0
  79. package/dist/editor/services/agentService.js.map +1 -1
  80. package/dist/editor/services/aiService.d.ts +1 -1
  81. package/dist/editor/services/aiService.js +1 -2
  82. package/dist/editor/services/aiService.js.map +1 -1
  83. package/dist/editor/sidebar/GraphQL.js +5 -6
  84. package/dist/editor/sidebar/GraphQL.js.map +1 -1
  85. package/dist/editor/sidebar/MainContentTree.d.ts +2 -1
  86. package/dist/editor/sidebar/MainContentTree.js +9 -5
  87. package/dist/editor/sidebar/MainContentTree.js.map +1 -1
  88. package/dist/editor/ui/Icons.d.ts +5 -0
  89. package/dist/editor/ui/Icons.js +3 -0
  90. package/dist/editor/ui/Icons.js.map +1 -1
  91. package/dist/editor/ui/ItemNameDialogNew.js +26 -14
  92. package/dist/editor/ui/ItemNameDialogNew.js.map +1 -1
  93. package/dist/editor/ui/PerfectTree.js +54 -2
  94. package/dist/editor/ui/PerfectTree.js.map +1 -1
  95. package/dist/editor/views/CompareView.js +3 -3
  96. package/dist/editor/views/CompareView.js.map +1 -1
  97. package/dist/editor/views/EditView.js +1 -1
  98. package/dist/editor/views/EditView.js.map +1 -1
  99. package/dist/editor/views/ItemEditor.js +1 -1
  100. package/dist/editor/views/ItemEditor.js.map +1 -1
  101. package/dist/index.d.ts +3 -4
  102. package/dist/index.js +3 -4
  103. package/dist/index.js.map +1 -1
  104. package/dist/page-wizard/steps/ContentStep.js +5 -5
  105. package/dist/page-wizard/steps/ContentStep.js.map +1 -1
  106. package/dist/page-wizard/steps/FindItemsStep.js +1 -1
  107. package/dist/page-wizard/steps/ImagesStep.js +1 -1
  108. package/dist/page-wizard/steps/ImagesStep.js.map +1 -1
  109. package/dist/page-wizard/steps/LayoutStep.js +1 -1
  110. package/dist/page-wizard/steps/LayoutStep.js.map +1 -1
  111. package/dist/page-wizard/steps/MetaDataStep.js +1 -1
  112. package/dist/page-wizard/steps/MetaDataStep.js.map +1 -1
  113. package/dist/page-wizard/steps/SelectStep.js +1 -1
  114. package/dist/page-wizard/steps/StructureStep.js +28 -11
  115. package/dist/page-wizard/steps/StructureStep.js.map +1 -1
  116. package/dist/page-wizard/steps/TranslateStep.d.ts +1 -0
  117. package/dist/page-wizard/steps/TranslateStep.js +67 -73
  118. package/dist/page-wizard/steps/TranslateStep.js.map +1 -1
  119. package/dist/revision.d.ts +2 -2
  120. package/dist/revision.js +2 -2
  121. package/dist/splash-screen/NewPage.js +1 -1
  122. package/dist/splash-screen/NewPage.js.map +1 -1
  123. package/dist/splash-screen/OpenPage.js +1 -1
  124. package/dist/splash-screen/OpenPage.js.map +1 -1
  125. package/dist/styles.css +71 -8
  126. package/package.json +1 -1
  127. package/src/components/index.ts +1 -0
  128. package/src/{editor/menubar → components/ui}/LanguageSelector.tsx +12 -12
  129. package/src/components/ui/dropdown-menu.tsx +3 -1
  130. package/src/components/ui/sonner.tsx +5 -1
  131. package/src/config/config.tsx +4 -3
  132. package/src/editor/ContentTree.tsx +41 -12
  133. package/src/editor/PictureEditor.tsx +2 -2
  134. package/src/editor/ScrollingContentTree.tsx +3 -0
  135. package/src/editor/Terminal.tsx +16 -7
  136. package/src/editor/ai/AgentHistory.tsx +85 -0
  137. package/src/editor/ai/Agents.tsx +256 -88
  138. package/src/editor/ai/AiResponseMessage.tsx +25 -11
  139. package/src/editor/ai/AiTerminal.tsx +571 -73
  140. package/src/editor/client/itemsRepository.ts +29 -12
  141. package/src/editor/field-types/InternalLinkFieldEditor.tsx +52 -1
  142. package/src/editor/field-types/richtext/components/SimpleRichTextEditor.css +64 -0
  143. package/src/editor/field-types/richtext/contextMenuFactory.tsx +7 -8
  144. package/src/editor/menubar/ItemLanguageVersion.tsx +1 -1
  145. package/src/editor/menubar/PageSelector.tsx +1 -0
  146. package/src/editor/page-editor-chrome/FieldActionIndicator.tsx +1 -1
  147. package/src/editor/page-editor-chrome/FieldEditedIndicator.tsx +3 -3
  148. package/src/editor/page-editor-chrome/FrameMenu.tsx +2 -2
  149. package/src/editor/page-editor-chrome/InlineEditor.tsx +9 -12
  150. package/src/editor/page-editor-chrome/LockedFieldIndicator.tsx +3 -3
  151. package/src/editor/page-editor-chrome/PageEditorChrome.tsx +3 -3
  152. package/src/editor/page-editor-chrome/PictureEditorOverlay.tsx +1 -1
  153. package/src/editor/page-editor-chrome/PlaceholderDropZone.tsx +1 -1
  154. package/src/editor/page-editor-chrome/PlaceholderDropZones.tsx +2 -2
  155. package/src/editor/page-editor-chrome/useInlineAICompletion.tsx +12 -18
  156. package/src/editor/page-viewer/EditorForm.tsx +1 -1
  157. package/src/editor/page-viewer/MiniMap.tsx +10 -11
  158. package/src/editor/page-viewer/PageViewer.tsx +8 -3
  159. package/src/editor/page-viewer/PageViewerFrame.tsx +4 -4
  160. package/src/editor/page-viewer/pageViewContext.ts +71 -66
  161. package/src/editor/services/agentService.ts +129 -1
  162. package/src/editor/services/aiService.ts +2 -4
  163. package/src/editor/sidebar/GraphQL.tsx +16 -15
  164. package/src/editor/sidebar/MainContentTree.tsx +12 -4
  165. package/src/editor/ui/Icons.tsx +35 -0
  166. package/src/editor/ui/ItemNameDialogNew.tsx +29 -13
  167. package/src/editor/ui/PerfectTree.tsx +70 -4
  168. package/src/editor/views/CompareView.tsx +3 -3
  169. package/src/editor/views/EditView.tsx +1 -1
  170. package/src/editor/views/ItemEditor.tsx +1 -1
  171. package/src/index.ts +10 -4
  172. package/src/page-wizard/steps/ContentStep.tsx +5 -5
  173. package/src/page-wizard/steps/FindItemsStep.tsx +1 -1
  174. package/src/page-wizard/steps/ImagesStep.tsx +1 -1
  175. package/src/page-wizard/steps/LayoutStep.tsx +1 -1
  176. package/src/page-wizard/steps/MetaDataStep.tsx +1 -1
  177. package/src/page-wizard/steps/SelectStep.tsx +1 -1
  178. package/src/page-wizard/steps/StructureStep.tsx +41 -17
  179. package/src/page-wizard/steps/TranslateStep.tsx +326 -222
  180. package/src/revision.ts +2 -2
  181. package/src/splash-screen/NewPage.tsx +1 -0
  182. package/src/splash-screen/OpenPage.tsx +1 -0
  183. package/dist/components/SimpleLanguageSelector.d.ts +0 -10
  184. package/dist/components/SimpleLanguageSelector.js +0 -59
  185. package/dist/components/SimpleLanguageSelector.js.map +0 -1
  186. package/dist/editor/menubar/LanguageSelector.js.map +0 -1
  187. package/src/components/SimpleLanguageSelector.tsx +0 -113
@@ -1,23 +1,27 @@
1
1
  import React, { useState, useRef, useEffect } from "react";
2
2
  import { AiTerminalOptions } from "./AiTerminal";
3
3
  import { EditorAiTerminal } from "./EditorAiTerminal";
4
+ import { AgentHistory } from "./AgentHistory";
4
5
  import { SimpleIconButton } from "../ui/SimpleIconButton";
5
- import { Plus, X, History } from "lucide-react";
6
+ import { Plus, X, MoreHorizontal } from "lucide-react";
6
7
  import { cn } from "../../lib/utils";
7
8
  import {
8
9
  getAgents,
9
10
  getAgent,
10
11
  getChatHistory,
12
+ closeAgent,
13
+ deleteAgent,
11
14
  AgentChat,
12
15
  AgentChatMessage,
13
16
  } from "../services/agentService";
14
17
  import { Message } from "./AiTerminal";
15
18
  import {
16
- Popover,
17
- PopoverContent,
18
- PopoverTrigger,
19
- } from "../../components/ui/popover";
20
- import { Button } from "../../components/ui/button";
19
+ DropdownMenu,
20
+ DropdownMenuContent,
21
+ DropdownMenuItem,
22
+ DropdownMenuTrigger,
23
+ } from "../../components/ui/dropdown-menu";
24
+
21
25
  import { useEditContext } from "../client/editContext";
22
26
  import { AiContext } from "./AiTerminal";
23
27
 
@@ -76,9 +80,10 @@ export function Agents({
76
80
  }) {
77
81
  const [terminals, setTerminals] = useState<TerminalInstance[]>([]);
78
82
  const [activeTerminalId, setActiveTerminalId] = useState<string | null>(null);
79
- const [inactiveAgents, setInactiveAgents] = useState<AgentChat[]>([]);
83
+ const [closedAgents, setClosedAgents] = useState<AgentChat[]>([]);
80
84
  const [historyPopoverOpen, setHistoryPopoverOpen] = useState(false);
81
85
  const [loadingAgents, setLoadingAgents] = useState(true);
86
+
82
87
  const nextTerminalNumber = useRef(1);
83
88
  const editContext = useEditContext();
84
89
 
@@ -101,15 +106,11 @@ export function Agents({
101
106
  setLoadingAgents(true);
102
107
  const context = createAgentContext();
103
108
 
104
- // Load active agents
105
- const activeAgentsResult = await getAgents(context, "active");
109
+ // Load all non-closed agents
110
+ const activeAgentsResult = await getAgents(context);
106
111
 
107
- // Load inactive agents for history
108
- const inactiveAgentsResult = await getChatHistory(
109
- context,
110
- "completed",
111
- 20,
112
- );
112
+ // Load closed agents for history
113
+ const closedAgentsResult = await getChatHistory(context, "closed", 20);
113
114
 
114
115
  if (activeAgentsResult && Array.isArray(activeAgentsResult)) {
115
116
  const activeAgents = activeAgentsResult;
@@ -162,8 +163,8 @@ export function Agents({
162
163
  }
163
164
  }
164
165
 
165
- if (inactiveAgentsResult && Array.isArray(inactiveAgentsResult)) {
166
- setInactiveAgents(inactiveAgentsResult);
166
+ if (closedAgentsResult && Array.isArray(closedAgentsResult)) {
167
+ setClosedAgents(closedAgentsResult);
167
168
  }
168
169
  } catch (error) {
169
170
  console.error("Failed to load agents:", error);
@@ -218,22 +219,165 @@ export function Agents({
218
219
  nextTerminalNumber.current++;
219
220
  };
220
221
 
221
- const closeTerminal = (terminalId: string) => {
222
- if (terminals.length <= 1) {
223
- // Don't close the last terminal
222
+ const closeTerminal = async (terminalId: string) => {
223
+ const terminal = terminals.find((t) => t.id === terminalId);
224
+ if (!terminal) return;
225
+
226
+ // If this terminal has an associated agent, show confirmation
227
+ if (terminal.agentId) {
228
+ editContext?.confirm({
229
+ header: "Close Agent",
230
+ message:
231
+ "Are you sure you want to close this agent? This will abort any running execution and mark the agent as closed.",
232
+ acceptLabel: "Close Agent",
233
+ rejectLabel: "Cancel",
234
+ accept: () => performCloseTerminal(terminalId),
235
+ reject: () => {}, // Do nothing on reject
236
+ });
224
237
  return;
225
238
  }
226
239
 
227
- setTerminals((prev) => {
228
- const filtered = prev.filter((t) => t.id !== terminalId);
240
+ // For terminals without agents, close immediately
241
+ performCloseTerminal(terminalId);
242
+ };
229
243
 
230
- // If we're closing the active terminal, switch to the first remaining one
231
- if (activeTerminalId === terminalId && filtered.length > 0) {
232
- setActiveTerminalId(filtered[0]!.id);
244
+ const performCloseTerminal = async (terminalId: string) => {
245
+ const terminal = terminals.find((t) => t.id === terminalId);
246
+
247
+ try {
248
+ // If this terminal has an associated agent, close it in the backend
249
+ if (terminal?.agentId) {
250
+ const context = createAgentContext();
251
+ await closeAgent(terminal.agentId, context);
233
252
  }
234
253
 
235
- return filtered;
236
- });
254
+ // Remove terminal from local state
255
+ setTerminals((prev) => {
256
+ const filtered = prev.filter((t) => t.id !== terminalId);
257
+
258
+ // If we're closing the active terminal, switch to the first remaining one
259
+ // or create a new one if this was the last terminal
260
+ if (activeTerminalId === terminalId) {
261
+ if (filtered.length > 0) {
262
+ setActiveTerminalId(filtered[0]!.id);
263
+ } else {
264
+ // Create a new terminal if this was the last one
265
+ const newTerminal: TerminalInstance = {
266
+ id: `terminal-${nextTerminalNumber.current}`,
267
+ title: "New Agent",
268
+ options: initialOptions,
269
+ };
270
+ nextTerminalNumber.current++;
271
+ setActiveTerminalId(newTerminal.id);
272
+ return [newTerminal];
273
+ }
274
+ }
275
+
276
+ return filtered;
277
+ });
278
+ } catch (error) {
279
+ console.error("Failed to close agent:", error);
280
+ editContext?.showToast("Failed to close agent. Removing from UI.");
281
+ // Still remove the terminal from UI even if backend call fails
282
+ setTerminals((prev) => prev.filter((t) => t.id !== terminalId));
283
+ }
284
+ };
285
+
286
+ const closeOtherTerminals = async () => {
287
+ if (!activeTerminalId || terminals.length <= 1) {
288
+ return;
289
+ }
290
+
291
+ // Get all terminals except the active one
292
+ const otherTerminals = terminals.filter((t) => t.id !== activeTerminalId);
293
+
294
+ // Show confirmation if any of the other terminals have agents
295
+ const hasAgents = otherTerminals.some((t) => t.agentId);
296
+
297
+ if (hasAgents) {
298
+ editContext?.confirm({
299
+ header: "Close Other Agents",
300
+ message: `Are you sure you want to close ${otherTerminals.length} other agent${otherTerminals.length > 1 ? "s" : ""}? This will abort any running executions and mark them as closed.`,
301
+ acceptLabel: "Close Others",
302
+ rejectLabel: "Cancel",
303
+ accept: async () => {
304
+ // Close all other terminals
305
+ for (const terminal of otherTerminals) {
306
+ try {
307
+ if (terminal.agentId) {
308
+ const context = createAgentContext();
309
+ await closeAgent(terminal.agentId, context);
310
+ }
311
+ } catch (error) {
312
+ console.error("Failed to close agent:", error);
313
+ }
314
+ }
315
+
316
+ // Keep only the active terminal
317
+ const activeTerminal = terminals.find(
318
+ (t) => t.id === activeTerminalId,
319
+ );
320
+ if (activeTerminal) {
321
+ setTerminals([activeTerminal]);
322
+ }
323
+ },
324
+ reject: () => {}, // Do nothing on reject
325
+ });
326
+ } else {
327
+ // No agents, just close immediately
328
+ const activeTerminal = terminals.find((t) => t.id === activeTerminalId);
329
+ if (activeTerminal) {
330
+ setTerminals([activeTerminal]);
331
+ }
332
+ }
333
+ };
334
+
335
+ const closeAllTerminals = async () => {
336
+ // Show confirmation if any terminals have agents
337
+ const hasAgents = terminals.some((t) => t.agentId);
338
+
339
+ if (hasAgents) {
340
+ editContext?.confirm({
341
+ header: "Close All Agents",
342
+ message: `Are you sure you want to close all ${terminals.length} agent${terminals.length > 1 ? "s" : ""}? This will abort any running executions and mark them as closed.`,
343
+ acceptLabel: "Close All",
344
+ rejectLabel: "Cancel",
345
+ accept: async () => {
346
+ // Close all terminals with agents
347
+ for (const terminal of terminals) {
348
+ try {
349
+ if (terminal.agentId) {
350
+ const context = createAgentContext();
351
+ await closeAgent(terminal.agentId, context);
352
+ }
353
+ } catch (error) {
354
+ console.error("Failed to close agent:", error);
355
+ }
356
+ }
357
+
358
+ // Create a new default terminal
359
+ const defaultTerminal: TerminalInstance = {
360
+ id: `terminal-${nextTerminalNumber.current}`,
361
+ title: "New Agent",
362
+ options: initialOptions,
363
+ };
364
+ setTerminals([defaultTerminal]);
365
+ setActiveTerminalId(defaultTerminal.id);
366
+ nextTerminalNumber.current++;
367
+ },
368
+ reject: () => {}, // Do nothing on reject
369
+ });
370
+ } else {
371
+ // No agents, just create a new default terminal
372
+ const defaultTerminal: TerminalInstance = {
373
+ id: `terminal-${nextTerminalNumber.current}`,
374
+ title: "New Agent",
375
+ options: initialOptions,
376
+ };
377
+ setTerminals([defaultTerminal]);
378
+ setActiveTerminalId(defaultTerminal.id);
379
+ nextTerminalNumber.current++;
380
+ }
237
381
  };
238
382
 
239
383
  const openAgentFromHistory = async (agent: AgentChat) => {
@@ -276,10 +420,42 @@ export function Agents({
276
420
  setHistoryPopoverOpen(false);
277
421
  };
278
422
 
423
+ const deleteAgentFromHistory = async (agent: AgentChat) => {
424
+ editContext?.confirm({
425
+ header: "Delete Agent",
426
+ message: `Are you sure you want to permanently delete "${agent.name}"? This action cannot be undone and will remove the agent and all its messages from the database.`,
427
+ acceptLabel: "Delete Permanently",
428
+ rejectLabel: "Cancel",
429
+ accept: async () => {
430
+ try {
431
+ const context = createAgentContext();
432
+ await deleteAgent(agent.id, context);
433
+
434
+ // Remove from closed agents list
435
+ setClosedAgents((prev) => prev.filter((a) => a.id !== agent.id));
436
+
437
+ // If this agent is currently open as a terminal, close it
438
+ const existingTerminal = terminals.find(
439
+ (t) => t.agentId === agent.id,
440
+ );
441
+ if (existingTerminal) {
442
+ performCloseTerminal(existingTerminal.id);
443
+ }
444
+
445
+ editContext?.showToast("Agent deleted successfully");
446
+ } catch (error) {
447
+ console.error("Failed to delete agent:", error);
448
+ editContext?.showToast("Failed to delete agent. Please try again.");
449
+ }
450
+ },
451
+ reject: () => {}, // Do nothing on reject
452
+ });
453
+ };
454
+
279
455
  if (loadingAgents) {
280
456
  return (
281
457
  <div className="flex h-full items-center justify-center">
282
- <div className="text-sm text-gray-500">Loading agents...</div>
458
+ <div className="text-xs text-gray-500">Loading agents...</div>
283
459
  </div>
284
460
  );
285
461
  }
@@ -288,7 +464,7 @@ export function Agents({
288
464
  <div className="flex h-full flex-col">
289
465
  {/* Tab Header */}
290
466
  <div className="flex items-center border-b border-gray-200 bg-gray-50">
291
- <div className="flex flex-1 overflow-x-auto">
467
+ <div className="flex flex-1 overflow-x-auto [-ms-overflow-style:none] [scrollbar-width:none] [&::-webkit-scrollbar]:hidden">
292
468
  {terminals.map((terminal) => (
293
469
  <div
294
470
  key={terminal.id}
@@ -301,66 +477,17 @@ export function Agents({
301
477
  onClick={() => setActiveTerminalId(terminal.id)}
302
478
  >
303
479
  <span className="truncate">{terminal.title}</span>
304
- {terminals.length > 1 && (
305
- <SimpleIconButton
306
- onClick={(e) => {
307
- e.stopPropagation();
308
- closeTerminal(terminal.id);
309
- }}
310
- icon={<X className="size-2" />}
311
- label="Close"
312
- className="ml-1 opacity-60 hover:opacity-100"
313
- />
314
- )}
315
- </div>
316
- ))}
317
- </div>
318
-
319
- {/* History Popover */}
320
- <div className="flex items-center px-1">
321
- <Popover
322
- open={historyPopoverOpen}
323
- onOpenChange={setHistoryPopoverOpen}
324
- >
325
- <PopoverTrigger asChild>
326
480
  <SimpleIconButton
327
- onClick={() => {}}
328
- icon={<History className="size-4" />}
329
- label="Agent History"
330
- className="text-gray-600 hover:text-gray-800"
481
+ onClick={(e) => {
482
+ e.stopPropagation();
483
+ closeTerminal(terminal.id);
484
+ }}
485
+ icon={<X className="size-3" />}
486
+ label="Close"
487
+ className="ml-1 opacity-60 hover:opacity-100"
331
488
  />
332
- </PopoverTrigger>
333
- <PopoverContent className="w-64 p-0" align="end">
334
- <div className="border-b border-gray-100 px-3 py-2 text-xs font-medium text-gray-500">
335
- Agent History
336
- </div>
337
- <div className="max-h-80 overflow-y-auto">
338
- {inactiveAgents.length === 0 ? (
339
- <div className="px-3 py-2 text-xs text-gray-500">
340
- No previous agents found
341
- </div>
342
- ) : (
343
- inactiveAgents.map((agent) => (
344
- <div
345
- key={agent.id}
346
- className="cursor-pointer border-b border-gray-50 px-3 py-2 text-xs hover:bg-gray-50"
347
- onClick={() => openAgentFromHistory(agent)}
348
- >
349
- <div className="truncate font-medium text-gray-900">
350
- {agent.name}
351
- </div>
352
- <div className="truncate text-gray-500">
353
- {agent.profileName}
354
- </div>
355
- <div className="text-xs text-gray-400">
356
- {formatDateToLocalTime(agent.updatedDate)}
357
- </div>
358
- </div>
359
- ))
360
- )}
361
- </div>
362
- </PopoverContent>
363
- </Popover>
489
+ </div>
490
+ ))}
364
491
  </div>
365
492
 
366
493
  {/* Add Terminal Button */}
@@ -368,11 +495,52 @@ export function Agents({
368
495
  <SimpleIconButton
369
496
  onClick={addTerminal}
370
497
  icon={<Plus className="size-4" />}
371
- label="Add Terminal"
498
+ label="Add Agent"
372
499
  className="text-gray-600 hover:text-gray-800"
373
500
  />
374
501
  </div>
375
502
 
503
+ {/* Agent History */}
504
+ <div className="flex items-center px-1">
505
+ <AgentHistory
506
+ closedAgents={closedAgents}
507
+ isOpen={historyPopoverOpen}
508
+ onOpenChange={setHistoryPopoverOpen}
509
+ onOpenAgent={openAgentFromHistory}
510
+ onDeleteAgent={deleteAgentFromHistory}
511
+ formatDateToLocalTime={formatDateToLocalTime}
512
+ />
513
+ </div>
514
+
515
+ {/* More Options Menu */}
516
+ <div className="flex items-center px-1">
517
+ <DropdownMenu>
518
+ <DropdownMenuTrigger asChild>
519
+ <SimpleIconButton
520
+ onClick={() => {}}
521
+ icon={<MoreHorizontal className="size-4" />}
522
+ label="More Options"
523
+ className="text-gray-600 hover:text-gray-800"
524
+ />
525
+ </DropdownMenuTrigger>
526
+ <DropdownMenuContent align="end">
527
+ <DropdownMenuItem
528
+ onClick={closeOtherTerminals}
529
+ disabled={terminals.length <= 1}
530
+ className="cursor-pointer"
531
+ >
532
+ Close Other
533
+ </DropdownMenuItem>
534
+ <DropdownMenuItem
535
+ onClick={closeAllTerminals}
536
+ className="cursor-pointer"
537
+ >
538
+ Close All
539
+ </DropdownMenuItem>
540
+ </DropdownMenuContent>
541
+ </DropdownMenu>
542
+ </div>
543
+
376
544
  {/* Main Close Button */}
377
545
  {closeButton && (
378
546
  <div className="flex items-center px-2">{closeButton}</div>
@@ -78,10 +78,12 @@ export function AiResponseMessage({
78
78
  messages,
79
79
  finished,
80
80
  editOperations,
81
+ error,
81
82
  }: {
82
83
  messages: Message[];
83
84
  finished: boolean;
84
85
  editOperations: EditOperation[];
86
+ error?: string;
85
87
  }) {
86
88
  const editContext = useEditContext();
87
89
  if (!editContext) return <></>;
@@ -206,11 +208,9 @@ export function AiResponseMessage({
206
208
  id: `input-${toolCall.id}`,
207
209
  label: "Input",
208
210
  content: (
209
- <div className="relative h-full w-full p-2">
210
- <div className="absolute inset-2 overflow-auto">
211
- <div className="text-xs">
212
- {renderJsonOrText(toolCall.function.arguments)}
213
- </div>
211
+ <div className="h-[250px] w-full overflow-auto p-2">
212
+ <div className="text-xs">
213
+ {renderJsonOrText(toolCall.function.arguments)}
214
214
  </div>
215
215
  </div>
216
216
  ),
@@ -222,10 +222,8 @@ export function AiResponseMessage({
222
222
  id: `output-${toolCall.id}`,
223
223
  label: "Output",
224
224
  content: (
225
- <div className="relative h-full w-full p-2">
226
- <div className="absolute inset-2 overflow-y-auto">
227
- <div className="text-xs">{renderJsonOrText(result || "")}</div>
228
- </div>
225
+ <div className="h-[250px] w-full overflow-auto p-2">
226
+ <div className="text-xs">{renderJsonOrText(result || "")}</div>
229
227
  </div>
230
228
  ),
231
229
  });
@@ -248,7 +246,7 @@ export function AiResponseMessage({
248
246
  const tabs = createToolCallTabs(toolCall, result || "");
249
247
 
250
248
  return (
251
- <div className="h-[400px]">
249
+ <div className="flex flex-col p-3">
252
250
  <div className="mb-3 flex items-center justify-between border-b border-gray-200 px-2 pb-1">
253
251
  <div className="flex items-center gap-2 text-sm font-semibold text-gray-800">
254
252
  {getToolIcon(toolCall?.function?.name || "")}
@@ -275,6 +273,22 @@ export function AiResponseMessage({
275
273
 
276
274
  return (
277
275
  <div>
276
+ {error && (
277
+ <div
278
+ className="mb-3 rounded-lg border-l-4 border-red-500 bg-red-50 p-3"
279
+ data-testid="agent-error"
280
+ >
281
+ <div className="flex items-start">
282
+ <div className="flex-shrink-0">
283
+ <X className="h-5 w-5 text-red-400" strokeWidth={1} />
284
+ </div>
285
+ <div className="ml-3">
286
+ <p className="text-sm font-medium text-red-800">Agent Error</p>
287
+ <p className="mt-1 text-sm text-red-700">{error}</p>
288
+ </div>
289
+ </div>
290
+ </div>
291
+ )}
278
292
  {messages
279
293
  .filter((x) => x.role !== "tool" && x.role !== "user")
280
294
  .map((message, filteredIndex) => {
@@ -334,7 +348,7 @@ export function AiResponseMessage({
334
348
  </div>
335
349
  </PopoverTrigger>
336
350
  <PopoverContent
337
- className="w-[400px] p-3"
351
+ className="w-[450px] p-0"
338
352
  align="start"
339
353
  side="bottom"
340
354
  sideOffset={8}