@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.
- package/dist/components/ui/textarea.js +1 -1
- package/dist/components/ui/textarea.js.map +1 -1
- package/dist/editor/Terminal.js +3 -3
- package/dist/editor/Terminal.js.map +1 -1
- package/dist/editor/ai/AgentCostDisplay.js +2 -2
- package/dist/editor/ai/AgentCostDisplay.js.map +1 -1
- package/dist/editor/ai/AgentHistory.d.ts +4 -4
- package/dist/editor/ai/AgentHistory.js +1 -1
- package/dist/editor/ai/AgentHistory.js.map +1 -1
- package/dist/editor/ai/AgentTerminal.d.ts +4 -0
- package/dist/editor/ai/AgentTerminal.js +753 -0
- package/dist/editor/ai/AgentTerminal.js.map +1 -0
- package/dist/editor/ai/Agents.d.ts +1 -3
- package/dist/editor/ai/Agents.js +213 -353
- package/dist/editor/ai/Agents.js.map +1 -1
- package/dist/editor/ai/AiPromptPopover.js +2 -2
- package/dist/editor/ai/AiPromptPopover.js.map +1 -1
- package/dist/editor/ai/AiResponseMessage.d.ts +0 -1
- package/dist/editor/ai/AiResponseMessage.js +23 -143
- package/dist/editor/ai/AiResponseMessage.js.map +1 -1
- package/dist/editor/ai/AiTerminal.d.ts +5 -23
- package/dist/editor/ai/AiTerminal.js +81 -824
- package/dist/editor/ai/AiTerminal.js.map +1 -1
- package/dist/editor/ai/DancingDots.d.ts +1 -0
- package/dist/editor/ai/DancingDots.js +6 -0
- package/dist/editor/ai/DancingDots.js.map +1 -0
- package/dist/editor/ai/ToolCallDisplay.d.ts +37 -0
- package/dist/editor/ai/ToolCallDisplay.js +154 -0
- package/dist/editor/ai/ToolCallDisplay.js.map +1 -0
- package/dist/editor/client/EditorClient.js +5 -1
- package/dist/editor/client/EditorClient.js.map +1 -1
- package/dist/editor/services/agentService.d.ts +23 -30
- package/dist/editor/services/agentService.js +62 -124
- package/dist/editor/services/agentService.js.map +1 -1
- package/dist/editor/sidebar/GraphQL.js +1 -0
- package/dist/editor/sidebar/GraphQL.js.map +1 -1
- package/dist/editor/sidebar/ViewSelector.js +8 -6
- package/dist/editor/sidebar/ViewSelector.js.map +1 -1
- package/dist/editor/ui/Section.js +4 -3
- package/dist/editor/ui/Section.js.map +1 -1
- package/dist/editor/utils.d.ts +4 -0
- package/dist/editor/utils.js +23 -0
- package/dist/editor/utils.js.map +1 -1
- package/dist/revision.d.ts +2 -2
- package/dist/revision.js +2 -2
- package/dist/styles.css +18 -33
- package/package.json +1 -1
- package/src/components/ui/textarea.tsx +1 -1
- package/src/editor/Terminal.tsx +4 -4
- package/src/editor/ai/AgentCostDisplay.tsx +7 -11
- package/src/editor/ai/AgentHistory.tsx +7 -9
- package/src/editor/ai/AgentTerminal.tsx +1094 -0
- package/src/editor/ai/Agents.tsx +340 -477
- package/src/editor/ai/AiPromptPopover.tsx +2 -2
- package/src/editor/ai/AiResponseMessage.tsx +85 -366
- package/src/editor/ai/AiTerminal.tsx +142 -1213
- package/src/editor/ai/DancingDots.tsx +14 -0
- package/src/editor/ai/ToolCallDisplay.tsx +363 -0
- package/src/editor/client/EditorClient.tsx +6 -1
- package/src/editor/services/agentService.ts +89 -162
- package/src/editor/sidebar/GraphQL.tsx +1 -0
- package/src/editor/sidebar/ViewSelector.tsx +82 -57
- package/src/editor/ui/Section.tsx +4 -3
- package/src/editor/utils.ts +29 -0
- package/src/revision.ts +2 -2
- package/dist/editor/ai/EditorAiTerminal.d.ts +0 -6
- package/dist/editor/ai/EditorAiTerminal.js +0 -7
- package/dist/editor/ai/EditorAiTerminal.js.map +0 -1
- package/src/editor/ai/EditorAiTerminal.tsx +0 -23
package/dist/editor/ai/Agents.js
CHANGED
|
@@ -1,408 +1,268 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useState,
|
|
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,
|
|
4
|
+
import { Plus, X, History, MoreVertical, Trash } from "lucide-react";
|
|
7
5
|
import { cn } from "../../lib/utils";
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
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(
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
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 [
|
|
47
|
-
const
|
|
38
|
+
const [menuPopoverOpen, setMenuPopoverOpen] = useState(false);
|
|
39
|
+
const [loadingAgents, setLoadingAgents] = useState(false);
|
|
40
|
+
const [inactiveAgents, setInactiveAgents] = useState([]);
|
|
48
41
|
const editContext = useEditContext();
|
|
49
|
-
//
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
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
|
-
//
|
|
81
|
+
// Subscribe to websocket messages for agent-started events
|
|
62
82
|
useEffect(() => {
|
|
63
|
-
if (!editContext)
|
|
83
|
+
if (!editContext?.addSocketMessageListener)
|
|
64
84
|
return;
|
|
65
|
-
const
|
|
66
|
-
if (message.type === "agent-started"
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
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
|
|
73
|
-
}, [editContext]);
|
|
121
|
+
return unsubscribe;
|
|
122
|
+
}, [editContext?.addSocketMessageListener]);
|
|
74
123
|
const loadAgentsFromBackend = async () => {
|
|
75
124
|
try {
|
|
76
125
|
setLoadingAgents(true);
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
//
|
|
81
|
-
|
|
82
|
-
if (activeAgentsResult
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
const
|
|
86
|
-
|
|
87
|
-
|
|
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
|
-
//
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
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
|
-
|
|
126
|
-
|
|
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 (
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
};
|
|
158
|
-
const
|
|
159
|
-
const
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
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
|
-
|
|
175
|
-
|
|
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
|
|
198
|
-
const terminal = terminals.find((t) => t.id === terminalId);
|
|
182
|
+
const closeAgent = async (agentId) => {
|
|
199
183
|
try {
|
|
200
|
-
//
|
|
201
|
-
|
|
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
|
-
|
|
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
|
|
237
|
-
if (!
|
|
206
|
+
const closeOtherAgents = async () => {
|
|
207
|
+
if (!activeAgentId)
|
|
238
208
|
return;
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
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
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
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
|
|
330
|
-
if (
|
|
331
|
-
// Switch to existing
|
|
332
|
-
|
|
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
|
-
//
|
|
337
|
-
const
|
|
338
|
-
|
|
339
|
-
|
|
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
|
-
|
|
359
|
-
|
|
241
|
+
setAgents((prev) => [...prev, reopenedAgent]);
|
|
242
|
+
setActiveAgentIdWithStorage(reopenedAgent.id);
|
|
360
243
|
setHistoryPopoverOpen(false);
|
|
361
244
|
};
|
|
362
|
-
const deleteAgentFromHistory = async (
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
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-
|
|
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
|
|
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: () =>
|
|
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
|
-
|
|
397
|
-
}, icon: _jsx(X, { className: "size-
|
|
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
|