@alpaca-editor/core 1.0.4049 → 1.0.4052

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 (69) hide show
  1. package/dist/components/ui/textarea.js +1 -1
  2. package/dist/components/ui/textarea.js.map +1 -1
  3. package/dist/editor/Terminal.js +3 -3
  4. package/dist/editor/Terminal.js.map +1 -1
  5. package/dist/editor/ai/AgentCostDisplay.js +2 -2
  6. package/dist/editor/ai/AgentCostDisplay.js.map +1 -1
  7. package/dist/editor/ai/AgentHistory.d.ts +4 -4
  8. package/dist/editor/ai/AgentHistory.js +1 -1
  9. package/dist/editor/ai/AgentHistory.js.map +1 -1
  10. package/dist/editor/ai/AgentTerminal.d.ts +4 -0
  11. package/dist/editor/ai/AgentTerminal.js +753 -0
  12. package/dist/editor/ai/AgentTerminal.js.map +1 -0
  13. package/dist/editor/ai/Agents.d.ts +1 -3
  14. package/dist/editor/ai/Agents.js +213 -353
  15. package/dist/editor/ai/Agents.js.map +1 -1
  16. package/dist/editor/ai/AiPromptPopover.js +2 -2
  17. package/dist/editor/ai/AiPromptPopover.js.map +1 -1
  18. package/dist/editor/ai/AiResponseMessage.d.ts +0 -1
  19. package/dist/editor/ai/AiResponseMessage.js +23 -143
  20. package/dist/editor/ai/AiResponseMessage.js.map +1 -1
  21. package/dist/editor/ai/AiTerminal.d.ts +5 -23
  22. package/dist/editor/ai/AiTerminal.js +81 -824
  23. package/dist/editor/ai/AiTerminal.js.map +1 -1
  24. package/dist/editor/ai/DancingDots.d.ts +1 -0
  25. package/dist/editor/ai/DancingDots.js +6 -0
  26. package/dist/editor/ai/DancingDots.js.map +1 -0
  27. package/dist/editor/ai/ToolCallDisplay.d.ts +37 -0
  28. package/dist/editor/ai/ToolCallDisplay.js +154 -0
  29. package/dist/editor/ai/ToolCallDisplay.js.map +1 -0
  30. package/dist/editor/client/EditorClient.js +5 -1
  31. package/dist/editor/client/EditorClient.js.map +1 -1
  32. package/dist/editor/services/agentService.d.ts +23 -30
  33. package/dist/editor/services/agentService.js +62 -124
  34. package/dist/editor/services/agentService.js.map +1 -1
  35. package/dist/editor/sidebar/GraphQL.js +1 -0
  36. package/dist/editor/sidebar/GraphQL.js.map +1 -1
  37. package/dist/editor/sidebar/ViewSelector.js +8 -6
  38. package/dist/editor/sidebar/ViewSelector.js.map +1 -1
  39. package/dist/editor/ui/Section.js +4 -3
  40. package/dist/editor/ui/Section.js.map +1 -1
  41. package/dist/editor/utils.d.ts +4 -0
  42. package/dist/editor/utils.js +23 -0
  43. package/dist/editor/utils.js.map +1 -1
  44. package/dist/revision.d.ts +2 -2
  45. package/dist/revision.js +2 -2
  46. package/dist/styles.css +18 -33
  47. package/package.json +1 -1
  48. package/src/components/ui/textarea.tsx +1 -1
  49. package/src/editor/Terminal.tsx +4 -4
  50. package/src/editor/ai/AgentCostDisplay.tsx +7 -11
  51. package/src/editor/ai/AgentHistory.tsx +7 -9
  52. package/src/editor/ai/AgentTerminal.tsx +1094 -0
  53. package/src/editor/ai/Agents.tsx +340 -477
  54. package/src/editor/ai/AiPromptPopover.tsx +2 -2
  55. package/src/editor/ai/AiResponseMessage.tsx +85 -366
  56. package/src/editor/ai/AiTerminal.tsx +142 -1213
  57. package/src/editor/ai/DancingDots.tsx +14 -0
  58. package/src/editor/ai/ToolCallDisplay.tsx +363 -0
  59. package/src/editor/client/EditorClient.tsx +6 -1
  60. package/src/editor/services/agentService.ts +89 -162
  61. package/src/editor/sidebar/GraphQL.tsx +1 -0
  62. package/src/editor/sidebar/ViewSelector.tsx +82 -57
  63. package/src/editor/ui/Section.tsx +4 -3
  64. package/src/editor/utils.ts +29 -0
  65. package/src/revision.ts +2 -2
  66. package/dist/editor/ai/EditorAiTerminal.d.ts +0 -6
  67. package/dist/editor/ai/EditorAiTerminal.js +0 -7
  68. package/dist/editor/ai/EditorAiTerminal.js.map +0 -1
  69. package/src/editor/ai/EditorAiTerminal.tsx +0 -23
@@ -1,408 +1,268 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useState, useRef, useEffect } from "react";
3
- import { EditorAiTerminal } from "./EditorAiTerminal";
4
- import { AgentHistory } from "./AgentHistory";
2
+ import { useState, useEffect } from "react";
5
3
  import { SimpleIconButton } from "../ui/SimpleIconButton";
6
- import { Plus, X, MoreHorizontal } from "lucide-react";
4
+ import { Plus, X, History, MoreVertical, Trash } from "lucide-react";
7
5
  import { cn } from "../../lib/utils";
8
- import { getAgents, getAgent, getChatHistory, closeAgent, deleteAgent, } from "../services/agentService";
9
- import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, } from "../../components/ui/dropdown-menu";
6
+ import { Popover, PopoverContent, PopoverTrigger, } from "../../components/ui/popover";
7
+ import { getActiveAgents, getClosedAgents, closeAgent as closeAgentService, deleteAgent, } from "../services/agentService";
8
+ import { AgentTerminal } from "./AgentTerminal";
10
9
  import { useEditContext } from "../client/editContext";
11
- function convertAgentMessagesToTerminalMessages(agentMessages) {
12
- return (agentMessages
13
- // Keep all messages including tool results for complete conversation context
14
- .map((msg) => ({
15
- id: msg.id,
16
- content: msg.content,
17
- name: msg.name,
18
- role: msg.role,
19
- tool_calls: msg.toolCalls?.map((toolCall) => ({
20
- id: toolCall.toolCallId,
21
- displayName: toolCall.functionName,
22
- function: {
23
- name: toolCall.functionName,
24
- arguments: toolCall.functionArguments || "",
25
- result: toolCall.functionResult,
26
- error: toolCall.functionError,
27
- },
28
- })) || [],
29
- tool_call_id: msg.toolCallId,
30
- })));
31
- }
32
- function formatDateToLocalTime(dateString) {
33
- // Ensure the date string is treated as UTC if it doesn't have timezone info
34
- const normalizedDate = dateString.includes("Z") ||
35
- dateString.includes("+") ||
36
- dateString.includes("-", 19)
37
- ? dateString
38
- : dateString + "Z";
39
- return new Date(normalizedDate).toLocaleString();
40
- }
41
- export function Agents({ closeButton, initialOptions, }) {
42
- const [terminals, setTerminals] = useState([]);
43
- const [activeTerminalId, setActiveTerminalId] = useState(null);
44
- const [closedAgents, setClosedAgents] = useState([]);
10
+ // function convertAgentMessagesToTerminalMessages(
11
+ // agentMessages: AgentChatMessage[],
12
+ // ): Message[] {
13
+ // return agentMessages.map((msg) => ({
14
+ // id: msg.id,
15
+ // content: msg.content,
16
+ // name: msg.name,
17
+ // role: msg.role,
18
+ // tool_calls: msg.functionName
19
+ // ? [
20
+ // {
21
+ // id: msg.toolCallId || msg.id,
22
+ // displayName: msg.functionName,
23
+ // function: {
24
+ // name: msg.functionName,
25
+ // arguments: msg.functionArguments || "",
26
+ // },
27
+ // },
28
+ // ]
29
+ // : [],
30
+ // tool_call_id: msg.toolCallId,
31
+ // }));
32
+ // }
33
+ const ACTIVE_AGENT_STORAGE_KEY = "editor.activeAgentId";
34
+ export function Agents({ closeButton }) {
35
+ const [agents, setAgents] = useState([]);
36
+ const [activeAgentId, setActiveAgentId] = useState(null);
45
37
  const [historyPopoverOpen, setHistoryPopoverOpen] = useState(false);
46
- const [loadingAgents, setLoadingAgents] = useState(true);
47
- const nextTerminalNumber = useRef(1);
38
+ const [menuPopoverOpen, setMenuPopoverOpen] = useState(false);
39
+ const [loadingAgents, setLoadingAgents] = useState(false);
40
+ const [inactiveAgents, setInactiveAgents] = useState([]);
48
41
  const editContext = useEditContext();
49
- // Create AI context for service calls
50
- const createAgentContext = () => ({
51
- promptData: {
52
- itemid: editContext?.currentItemDescriptor?.id,
53
- language: editContext?.currentItemDescriptor?.language || "en",
54
- version: editContext?.currentItemDescriptor?.version || 1,
55
- },
56
- });
42
+ // Helper function to get the most recently updated agent
43
+ const getMostRecentAgent = (agentList) => {
44
+ if (agentList.length === 0)
45
+ return null;
46
+ return agentList.reduce((mostRecent, current) => {
47
+ return new Date(current.updatedDate) > new Date(mostRecent.updatedDate)
48
+ ? current
49
+ : mostRecent;
50
+ });
51
+ };
52
+ // Helper function to set active agent and persist to localStorage
53
+ const setActiveAgentIdWithStorage = (agentId) => {
54
+ console.log("setActiveAgentIdWithStorage", agentId);
55
+ setActiveAgentId(agentId);
56
+ if (agentId) {
57
+ localStorage.setItem(ACTIVE_AGENT_STORAGE_KEY, agentId);
58
+ }
59
+ else {
60
+ localStorage.removeItem(ACTIVE_AGENT_STORAGE_KEY);
61
+ }
62
+ };
63
+ // Initialize with a default agent if none exist
64
+ useEffect(() => {
65
+ if (agents.length === 0) {
66
+ const defaultAgent = {
67
+ status: "new",
68
+ id: crypto.randomUUID(),
69
+ name: `New Agent`,
70
+ updatedDate: new Date().toISOString(),
71
+ userId: "",
72
+ };
73
+ setAgents([defaultAgent]);
74
+ setActiveAgentId(defaultAgent.id);
75
+ }
76
+ }, [agents.length]);
57
77
  // Load agents from backend on mount
58
78
  useEffect(() => {
59
79
  loadAgentsFromBackend();
60
80
  }, []);
61
- // Listen for WebSocket messages about agent changes
81
+ // Subscribe to websocket messages for agent-started events
62
82
  useEffect(() => {
63
- if (!editContext)
83
+ if (!editContext?.addSocketMessageListener)
64
84
  return;
65
- const removeSocketListener = editContext.addSocketMessageListener((message) => {
66
- if (message.type === "agent-started" ||
67
- message.type === "agent-updated") {
68
- // Refresh agents list when new agents are started or updated
69
- loadAgentsFromBackend();
85
+ const unsubscribe = editContext.addSocketMessageListener((message) => {
86
+ if (message.type === "agent-started") {
87
+ const { agentId, agentName } = message.payload;
88
+ if (!agentId || !agentName) {
89
+ console.warn("Invalid agent-started message payload:", message.payload);
90
+ return;
91
+ }
92
+ setAgents((prevAgents) => {
93
+ // Check if agent already exists
94
+ const existingAgentIndex = prevAgents.findIndex((agent) => agent.id === agentId);
95
+ if (existingAgentIndex !== -1) {
96
+ // Update existing agent name
97
+ const updatedAgents = [...prevAgents];
98
+ const existingAgent = updatedAgents[existingAgentIndex];
99
+ updatedAgents[existingAgentIndex] = {
100
+ ...existingAgent,
101
+ name: agentName,
102
+ status: "running",
103
+ updatedDate: new Date().toISOString(),
104
+ };
105
+ return updatedAgents;
106
+ }
107
+ else {
108
+ // Add new agent to the array
109
+ const newAgent = {
110
+ id: agentId,
111
+ name: agentName,
112
+ status: "running",
113
+ userId: "", // Will be populated from backend if needed
114
+ updatedDate: new Date().toISOString(),
115
+ };
116
+ return [...prevAgents, newAgent];
117
+ }
118
+ });
70
119
  }
71
120
  });
72
- return removeSocketListener;
73
- }, [editContext]);
121
+ return unsubscribe;
122
+ }, [editContext?.addSocketMessageListener]);
74
123
  const loadAgentsFromBackend = async () => {
75
124
  try {
76
125
  setLoadingAgents(true);
77
- const context = createAgentContext();
78
- // Load all non-closed agents
79
- const activeAgentsResult = await getAgents(context);
80
- // Load closed agents for history
81
- const closedAgentsResult = await getChatHistory(context, "closed", 20);
82
- if (activeAgentsResult && Array.isArray(activeAgentsResult)) {
83
- const activeAgents = activeAgentsResult;
84
- // Create terminals for active agents
85
- const activeTerminals = await Promise.all(activeAgents.map(async (agent, index) => {
86
- // Load messages for each active agent
87
- const agentWithMessages = await loadAgentMessages(agent.id);
88
- return {
89
- id: `agent-${agent.id}`,
90
- title: agent.name || "New Agent",
91
- agentId: agent.id,
92
- options: {
93
- ...initialOptions,
94
- // Pass cost information from loaded agent
95
- totalCost: agentWithMessages?.totalCost,
96
- totalInputTokenCost: agentWithMessages?.totalInputTokenCost,
97
- totalOutputTokenCost: agentWithMessages?.totalOutputTokenCost,
98
- totalCachedTokenCost: agentWithMessages?.totalCachedInputTokenCost,
99
- totalInputTokens: agentWithMessages?.totalInputTokens,
100
- totalOutputTokens: agentWithMessages?.totalOutputTokens,
101
- totalCachedTokens: agentWithMessages?.totalCachedInputTokens,
102
- },
103
- messages: agentWithMessages?.messages
104
- ? convertAgentMessagesToTerminalMessages(agentWithMessages.messages)
105
- : [],
106
- };
107
- }));
108
- // Set the first active terminal as active, or create a new one if none exist
109
- if (activeTerminals.length > 0) {
110
- setTerminals(activeTerminals);
111
- setActiveTerminalId(activeTerminals[0].id);
126
+ // Load active agents
127
+ const activeAgentsResult = await getActiveAgents();
128
+ setAgents(activeAgentsResult);
129
+ // Determine which agent to select as active
130
+ let selectedAgentId = null;
131
+ if (activeAgentsResult.length > 0) {
132
+ // Try to restore the previously active agent from localStorage
133
+ const storedAgentId = localStorage.getItem(ACTIVE_AGENT_STORAGE_KEY);
134
+ const storedAgent = activeAgentsResult.find((agent) => agent.id === storedAgentId);
135
+ if (storedAgent) {
136
+ selectedAgentId = storedAgent.id;
112
137
  }
113
138
  else {
114
- // Create a default terminal if no active agents
115
- const defaultTerminal = {
116
- id: `terminal-${nextTerminalNumber.current}`,
117
- title: "New Agent",
118
- options: initialOptions,
119
- };
120
- setTerminals([defaultTerminal]);
121
- setActiveTerminalId(defaultTerminal.id);
122
- nextTerminalNumber.current++;
139
+ // Fall back to the most recently updated agent
140
+ console.log("get most recent agent", activeAgentsResult);
141
+ const mostRecentAgent = getMostRecentAgent(activeAgentsResult);
142
+ selectedAgentId = mostRecentAgent?.id || null;
123
143
  }
124
144
  }
125
- if (closedAgentsResult && Array.isArray(closedAgentsResult)) {
126
- setClosedAgents(closedAgentsResult);
127
- }
145
+ console.log("set selectedAgentId", selectedAgentId);
146
+ setActiveAgentIdWithStorage(selectedAgentId);
147
+ // Load closed agents for history
148
+ const closedAgentsResult = await getClosedAgents();
149
+ setInactiveAgents(closedAgentsResult);
128
150
  }
129
151
  catch (error) {
130
152
  console.error("Failed to load agents:", error);
131
- // Create a default terminal on error
132
- const defaultTerminal = {
133
- id: `terminal-${nextTerminalNumber.current}`,
134
- title: `Agent ${nextTerminalNumber.current}`,
135
- options: initialOptions,
136
- };
137
- setTerminals([defaultTerminal]);
138
- setActiveTerminalId(defaultTerminal.id);
139
- nextTerminalNumber.current++;
140
153
  }
141
154
  finally {
142
155
  setLoadingAgents(false);
143
156
  }
144
157
  };
145
- const loadAgentMessages = async (agentId) => {
146
- try {
147
- const context = createAgentContext();
148
- const result = await getAgent(agentId, context);
149
- if (result && result.id) {
150
- return result;
151
- }
152
- }
153
- catch (error) {
154
- console.error(`Failed to load messages for agent ${agentId}:`, error);
155
- }
156
- return null;
157
- };
158
- const addTerminal = () => {
159
- const newTerminal = {
160
- id: `terminal-${nextTerminalNumber.current}`,
161
- title: `Agent ${nextTerminalNumber.current}`,
162
- options: undefined,
163
- };
164
- setTerminals((prev) => [...prev, newTerminal]);
165
- setActiveTerminalId(newTerminal.id);
166
- nextTerminalNumber.current++;
167
- };
168
- const createNewAgent = (options) => {
169
- const newTerminal = {
170
- id: `terminal-${nextTerminalNumber.current}`,
171
- title: `Agent ${nextTerminalNumber.current}`,
172
- options: options,
158
+ // const loadAgentMessages = async (
159
+ // agentId: string,
160
+ // ): Promise<AgentChat | null> => {
161
+ // try {
162
+ // const result = await getAgent(agentId);
163
+ // if (result.type === "success" && result.data) {
164
+ // return result.data;
165
+ // }
166
+ // } catch (error) {
167
+ // console.error(`Failed to load messages for agent ${agentId}:`, error);
168
+ // }
169
+ // return null;
170
+ // };
171
+ const addAgent = () => {
172
+ const newAgent = {
173
+ status: "new",
174
+ id: crypto.randomUUID(),
175
+ name: `New Agent`,
176
+ updatedDate: new Date().toISOString(),
177
+ userId: "",
173
178
  };
174
- setTerminals((prev) => [...prev, newTerminal]);
175
- setActiveTerminalId(newTerminal.id);
176
- nextTerminalNumber.current++;
177
- };
178
- const closeTerminal = async (terminalId) => {
179
- const terminal = terminals.find((t) => t.id === terminalId);
180
- if (!terminal)
181
- return;
182
- // If this terminal has an associated agent, show confirmation
183
- if (terminal.agentId) {
184
- editContext?.confirm({
185
- header: "Close Agent",
186
- message: "Are you sure you want to close this agent? This will abort any running execution and mark the agent as closed.",
187
- acceptLabel: "Close Agent",
188
- rejectLabel: "Cancel",
189
- accept: () => performCloseTerminal(terminalId),
190
- reject: () => { }, // Do nothing on reject
191
- });
192
- return;
193
- }
194
- // For terminals without agents, close immediately
195
- performCloseTerminal(terminalId);
179
+ setAgents((prev) => [...prev, newAgent]);
180
+ setActiveAgentIdWithStorage(newAgent.id);
196
181
  };
197
- const performCloseTerminal = async (terminalId) => {
198
- const terminal = terminals.find((t) => t.id === terminalId);
182
+ const closeAgent = async (agentId) => {
199
183
  try {
200
- // If this terminal has an associated agent, close it in the backend
201
- if (terminal?.agentId) {
202
- const context = createAgentContext();
203
- await closeAgent(terminal.agentId, context);
204
- }
205
- // Remove terminal from local state
206
- setTerminals((prev) => {
207
- const filtered = prev.filter((t) => t.id !== terminalId);
208
- // If we're closing the active terminal, switch to the first remaining one
209
- // or create a new one if this was the last terminal
210
- if (activeTerminalId === terminalId) {
211
- if (filtered.length > 0) {
212
- setActiveTerminalId(filtered[0].id);
213
- }
214
- else {
215
- // Create a new terminal if this was the last one
216
- const newTerminal = {
217
- id: `terminal-${nextTerminalNumber.current}`,
218
- title: "New Agent",
219
- options: initialOptions,
220
- };
221
- nextTerminalNumber.current++;
222
- setActiveTerminalId(newTerminal.id);
223
- return [newTerminal];
224
- }
225
- }
226
- return filtered;
227
- });
184
+ // Permanently close the agent in the backend
185
+ await closeAgentService(agentId);
228
186
  }
229
187
  catch (error) {
230
188
  console.error("Failed to close agent:", error);
231
- editContext?.showToast("Failed to close agent. Removing from UI.");
232
- // Still remove the terminal from UI even if backend call fails
233
- setTerminals((prev) => prev.filter((t) => t.id !== terminalId));
189
+ // Continue with UI cleanup even if backend call fails
234
190
  }
191
+ setAgents((prev) => {
192
+ const filtered = prev.filter((a) => a.id !== agentId);
193
+ // If we're closing the active terminal, switch to the most recent remaining one or clear storage
194
+ if (activeAgentId === agentId) {
195
+ if (filtered.length > 0) {
196
+ const mostRecentAgent = getMostRecentAgent(filtered);
197
+ setActiveAgentIdWithStorage(mostRecentAgent?.id || null);
198
+ }
199
+ else {
200
+ setActiveAgentIdWithStorage(null);
201
+ }
202
+ }
203
+ return filtered;
204
+ });
235
205
  };
236
- const closeOtherTerminals = async () => {
237
- if (!activeTerminalId || terminals.length <= 1) {
206
+ const closeOtherAgents = async () => {
207
+ if (!activeAgentId)
238
208
  return;
239
- }
240
- // Get all terminals except the active one
241
- const otherTerminals = terminals.filter((t) => t.id !== activeTerminalId);
242
- // Show confirmation if any of the other terminals have agents
243
- const hasAgents = otherTerminals.some((t) => t.agentId);
244
- if (hasAgents) {
245
- editContext?.confirm({
246
- header: "Close Other Agents",
247
- 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.`,
248
- acceptLabel: "Close Others",
249
- rejectLabel: "Cancel",
250
- accept: async () => {
251
- // Close all other terminals
252
- for (const terminal of otherTerminals) {
253
- try {
254
- if (terminal.agentId) {
255
- const context = createAgentContext();
256
- await closeAgent(terminal.agentId, context);
257
- }
258
- }
259
- catch (error) {
260
- console.error("Failed to close agent:", error);
261
- }
262
- }
263
- // Keep only the active terminal
264
- const activeTerminal = terminals.find((t) => t.id === activeTerminalId);
265
- if (activeTerminal) {
266
- setTerminals([activeTerminal]);
267
- }
268
- },
269
- reject: () => { }, // Do nothing on reject
270
- });
271
- }
272
- else {
273
- // No agents, just close immediately
274
- const activeTerminal = terminals.find((t) => t.id === activeTerminalId);
275
- if (activeTerminal) {
276
- setTerminals([activeTerminal]);
209
+ // Get agents to close (all except active)
210
+ const agentsToClose = agents.filter((a) => a.id !== activeAgentId);
211
+ // Permanently close each agent in the backend
212
+ const closePromises = agentsToClose.map(async (agent) => {
213
+ try {
214
+ await closeAgentService(agent.id);
277
215
  }
278
- }
279
- };
280
- const closeAllTerminals = async () => {
281
- // Show confirmation if any terminals have agents
282
- const hasAgents = terminals.some((t) => t.agentId);
283
- if (hasAgents) {
284
- editContext?.confirm({
285
- header: "Close All Agents",
286
- 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.`,
287
- acceptLabel: "Close All",
288
- rejectLabel: "Cancel",
289
- accept: async () => {
290
- // Close all terminals with agents
291
- for (const terminal of terminals) {
292
- try {
293
- if (terminal.agentId) {
294
- const context = createAgentContext();
295
- await closeAgent(terminal.agentId, context);
296
- }
297
- }
298
- catch (error) {
299
- console.error("Failed to close agent:", error);
300
- }
301
- }
302
- // Create a new default terminal
303
- const defaultTerminal = {
304
- id: `terminal-${nextTerminalNumber.current}`,
305
- title: "New Agent",
306
- options: initialOptions,
307
- };
308
- setTerminals([defaultTerminal]);
309
- setActiveTerminalId(defaultTerminal.id);
310
- nextTerminalNumber.current++;
311
- },
312
- reject: () => { }, // Do nothing on reject
313
- });
314
- }
315
- else {
316
- // No agents, just create a new default terminal
317
- const defaultTerminal = {
318
- id: `terminal-${nextTerminalNumber.current}`,
319
- title: "New Agent",
320
- options: initialOptions,
321
- };
322
- setTerminals([defaultTerminal]);
323
- setActiveTerminalId(defaultTerminal.id);
324
- nextTerminalNumber.current++;
325
- }
216
+ catch (error) {
217
+ console.error(`Failed to close agent ${agent.id}:`, error);
218
+ }
219
+ });
220
+ // Wait for all close operations to complete
221
+ await Promise.all(closePromises);
222
+ setAgents((prev) => {
223
+ return prev.filter((a) => a.id === activeAgentId);
224
+ });
225
+ setMenuPopoverOpen(false);
326
226
  };
327
227
  const openAgentFromHistory = async (agent) => {
328
228
  // Check if this agent is already open as a terminal
329
- const existingTerminal = terminals.find((t) => t.agentId === agent.id);
330
- if (existingTerminal) {
331
- // Switch to existing terminal
332
- setActiveTerminalId(existingTerminal.id);
229
+ const existingAgent = agents.find((a) => a.id === agent.id);
230
+ if (existingAgent) {
231
+ // Switch to existing agent
232
+ setActiveAgentIdWithStorage(existingAgent.id);
333
233
  setHistoryPopoverOpen(false);
334
234
  return;
335
235
  }
336
- // Load the agent with messages
337
- const agentWithMessages = await loadAgentMessages(agent.id);
338
- // Create new terminal for this agent
339
- const newTerminal = {
340
- id: `agent-${agent.id}`,
341
- title: agent.name,
342
- agentId: agent.id,
343
- options: {
344
- ...initialOptions,
345
- // Pass cost information from loaded agent
346
- totalCost: agentWithMessages?.totalCost,
347
- totalInputTokenCost: agentWithMessages?.totalInputTokenCost,
348
- totalOutputTokenCost: agentWithMessages?.totalOutputTokenCost,
349
- totalCachedTokenCost: agentWithMessages?.totalCachedInputTokenCost,
350
- totalInputTokens: agentWithMessages?.totalInputTokens,
351
- totalOutputTokens: agentWithMessages?.totalOutputTokens,
352
- totalCachedTokens: agentWithMessages?.totalCachedInputTokens,
353
- },
354
- messages: agentWithMessages?.messages
355
- ? convertAgentMessagesToTerminalMessages(agentWithMessages.messages)
356
- : [],
236
+ // Add the closed agent to the active agents list
237
+ const reopenedAgent = {
238
+ ...agent,
239
+ // Keep the original status to allow AgentTerminal to load the full agent data
357
240
  };
358
- setTerminals((prev) => [...prev, newTerminal]);
359
- setActiveTerminalId(newTerminal.id);
241
+ setAgents((prev) => [...prev, reopenedAgent]);
242
+ setActiveAgentIdWithStorage(reopenedAgent.id);
360
243
  setHistoryPopoverOpen(false);
361
244
  };
362
- const deleteAgentFromHistory = async (agent) => {
363
- editContext?.confirm({
364
- header: "Delete Agent",
365
- 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.`,
366
- acceptLabel: "Delete Permanently",
367
- rejectLabel: "Cancel",
368
- accept: async () => {
369
- try {
370
- const context = createAgentContext();
371
- await deleteAgent(agent.id, context);
372
- // Remove from closed agents list
373
- setClosedAgents((prev) => prev.filter((a) => a.id !== agent.id));
374
- // If this agent is currently open as a terminal, close it
375
- const existingTerminal = terminals.find((t) => t.agentId === agent.id);
376
- if (existingTerminal) {
377
- performCloseTerminal(existingTerminal.id);
378
- }
379
- editContext?.showToast("Agent deleted successfully");
380
- }
381
- catch (error) {
382
- console.error("Failed to delete agent:", error);
383
- editContext?.showToast("Failed to delete agent. Please try again.");
384
- }
385
- },
386
- reject: () => { }, // Do nothing on reject
387
- });
245
+ const deleteAgentFromHistory = async (agentId, event) => {
246
+ event.stopPropagation(); // Prevent opening the agent when clicking delete
247
+ try {
248
+ // Permanently delete the agent from the backend
249
+ await deleteAgent(agentId);
250
+ // Remove from inactive agents list
251
+ setInactiveAgents((prev) => prev.filter((agent) => agent.id !== agentId));
252
+ }
253
+ catch (error) {
254
+ console.error("Failed to delete agent:", error);
255
+ // You might want to show a user-facing error message here
256
+ }
388
257
  };
389
258
  if (loadingAgents) {
390
- return (_jsx("div", { className: "flex h-full items-center justify-center", children: _jsx("div", { className: "text-xs text-gray-500", children: "Loading agents..." }) }));
259
+ return (_jsx("div", { className: "flex h-full items-center justify-center", children: _jsx("div", { className: "text-sm text-gray-500", children: "Loading agents..." }) }));
391
260
  }
392
- return (_jsxs("div", { className: "flex h-full flex-col", children: [_jsxs("div", { className: "flex items-center border-b border-gray-200 bg-gray-50", children: [_jsx("div", { className: "flex flex-1 overflow-x-auto [-ms-overflow-style:none] [scrollbar-width:none] [&::-webkit-scrollbar]:hidden", children: terminals.map((terminal) => (_jsxs("div", { className: cn("flex min-w-0 cursor-pointer items-center gap-1 border-r border-gray-200 px-3 py-2 text-xs", activeTerminalId === terminal.id
261
+ return (_jsxs("div", { className: "flex h-full flex-col", children: [_jsxs("div", { className: "flex items-center border-b border-gray-200 bg-gray-50", children: [_jsx("div", { className: "flex flex-1 overflow-x-auto", children: agents.map((agent) => (_jsxs("div", { className: cn("flex min-w-0 cursor-pointer items-center gap-1 border-r border-gray-200 px-3 py-2 text-xs", activeAgentId === agent.id
393
262
  ? "border-b-white bg-white"
394
- : "hover:bg-gray-100"), onClick: () => setActiveTerminalId(terminal.id), children: [_jsx("span", { className: "truncate", children: terminal.title }), _jsx(SimpleIconButton, { onClick: (e) => {
263
+ : "hover:bg-gray-100"), onClick: () => setActiveAgentIdWithStorage(agent.id), children: [_jsx("span", { className: "truncate", children: agent.name }), agents.length > 1 && (_jsx(SimpleIconButton, { onClick: (e) => {
395
264
  e.stopPropagation();
396
- closeTerminal(terminal.id);
397
- }, icon: _jsx(X, { className: "size-3" }), label: "Close", className: "ml-1 opacity-60 hover:opacity-100" })] }, terminal.id))) }), _jsx("div", { className: "flex items-center px-1", children: _jsx(SimpleIconButton, { onClick: addTerminal, icon: _jsx(Plus, { className: "size-4" }), label: "Add Agent", className: "text-gray-600 hover:text-gray-800" }) }), _jsx("div", { className: "flex items-center px-1", children: _jsx(AgentHistory, { closedAgents: closedAgents, isOpen: historyPopoverOpen, onOpenChange: setHistoryPopoverOpen, onOpenAgent: openAgentFromHistory, onDeleteAgent: deleteAgentFromHistory, formatDateToLocalTime: formatDateToLocalTime }) }), _jsx("div", { className: "flex items-center px-1", children: _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx(SimpleIconButton, { onClick: () => { }, icon: _jsx(MoreHorizontal, { className: "size-4" }), label: "More Options", className: "text-gray-600 hover:text-gray-800" }) }), _jsxs(DropdownMenuContent, { align: "end", children: [_jsx(DropdownMenuItem, { onClick: closeOtherTerminals, disabled: terminals.length <= 1, className: "cursor-pointer", children: "Close Other" }), _jsx(DropdownMenuItem, { onClick: closeAllTerminals, className: "cursor-pointer", children: "Close All" })] })] }) }), closeButton && (_jsx("div", { className: "flex items-center px-2", children: closeButton }))] }), _jsx("div", { className: "relative flex-1", children: terminals.map((terminal) => (_jsx("div", { className: cn("absolute inset-0", activeTerminalId === terminal.id ? "block" : "hidden"), children: _jsx(EditorAiTerminal, { options: {
398
- ...terminal.options,
399
- // Pass the pre-loaded messages to the terminal
400
- initialMessages: terminal.messages,
401
- // Pass the agentId to maintain continuity
402
- agentId: terminal.agentId,
403
- }, onAgentNameUpdate: (name) => {
404
- // Update the terminal title when agent name is updated
405
- setTerminals((prev) => prev.map((t) => t.id === terminal.id ? { ...t, title: name } : t));
406
- } }) }, terminal.id))) })] }));
265
+ closeAgent(agent.id);
266
+ }, icon: _jsx(X, { className: "size-2", strokeWidth: 1 }), label: "Close", className: "ml-1 opacity-60 hover:opacity-100" }))] }, agent.id))) }), _jsx("div", { className: "flex items-center px-1", children: _jsxs(Popover, { open: historyPopoverOpen, onOpenChange: setHistoryPopoverOpen, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsx(SimpleIconButton, { onClick: () => { }, icon: _jsx(History, { className: "size-4", strokeWidth: 1 }), label: "Agent History", className: "text-gray-600 hover:text-gray-800" }) }), _jsxs(PopoverContent, { className: "w-64 p-0", align: "end", children: [_jsx("div", { className: "border-b border-gray-100 px-3 py-2 text-xs font-medium text-gray-500", children: "Closed Agents" }), _jsx("div", { className: "max-h-80 overflow-y-auto", children: inactiveAgents.length === 0 ? (_jsx("div", { className: "px-3 py-2 text-xs text-gray-500", children: "No closed agents found" })) : (inactiveAgents.map((agent) => (_jsx("div", { className: "cursor-pointer border-b border-gray-50 px-3 py-2 text-xs hover:bg-gray-50", onClick: () => openAgentFromHistory(agent), children: _jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("div", { className: "truncate font-medium text-gray-900", children: agent.name }), _jsx("div", { className: "text-xs text-gray-400", children: new Date(agent.updatedDate).toLocaleString() })] }), _jsx(SimpleIconButton, { onClick: (e) => deleteAgentFromHistory(agent.id, e), icon: _jsx(Trash, { className: "size-3", strokeWidth: 1 }), label: "Delete Agent", className: "ml-2 text-red-600 opacity-60 hover:text-red-700 hover:opacity-100" })] }) }, agent.id)))) })] })] }) }), _jsx("div", { className: "flex items-center px-1", children: _jsxs(Popover, { open: menuPopoverOpen, onOpenChange: setMenuPopoverOpen, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsx(SimpleIconButton, { onClick: () => { }, icon: _jsx(MoreVertical, { className: "size-4", strokeWidth: 1 }), label: "Menu", className: "text-gray-600 hover:text-gray-800" }) }), _jsx(PopoverContent, { className: "w-48 p-0", align: "end", children: _jsx("div", { className: "py-1", children: _jsx("button", { onClick: closeOtherAgents, disabled: agents.length <= 1, className: "w-full px-3 py-2 text-left text-xs hover:bg-gray-50 disabled:cursor-not-allowed disabled:text-gray-400", children: "Close Other" }) }) })] }) }), _jsx("div", { className: "flex items-center px-1", children: _jsx(SimpleIconButton, { onClick: addAgent, icon: _jsx(Plus, { className: "size-4", strokeWidth: 1 }), label: "Add Terminal", className: "text-gray-600 hover:text-gray-800" }) }), closeButton && (_jsx("div", { className: "flex items-center px-2", children: closeButton }))] }), _jsx("div", { className: "relative flex-1", children: agents.map((agent) => (_jsx("div", { className: cn("absolute inset-0", activeAgentId === agent.id ? "block" : "hidden"), children: _jsx(AgentTerminal, { agentStub: agent }) }, agent.id))) })] }));
407
267
  }
408
268
  //# sourceMappingURL=Agents.js.map