@alpaca-editor/core 1.0.4184 → 1.0.4185
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/agents-view/AgentCard.d.ts +12 -0
- package/dist/agents-view/AgentCard.js +30 -0
- package/dist/agents-view/AgentCard.js.map +1 -0
- package/dist/agents-view/AgentsView.d.ts +2 -2
- package/dist/agents-view/AgentsView.js +102 -85
- package/dist/agents-view/AgentsView.js.map +1 -1
- package/dist/agents-view/ProfileAgentsGroup.d.ts +17 -0
- package/dist/agents-view/ProfileAgentsGroup.js +13 -0
- package/dist/agents-view/ProfileAgentsGroup.js.map +1 -0
- package/dist/editor/ai/AgentProfilesOverview.js +1 -1
- package/dist/editor/ai/AgentProfilesOverview.js.map +1 -1
- package/dist/editor/commands/componentCommands.js +19 -1
- package/dist/editor/commands/componentCommands.js.map +1 -1
- package/dist/editor/page-editor-chrome/FrameMenu.js +7 -3
- package/dist/editor/page-editor-chrome/FrameMenu.js.map +1 -1
- package/dist/editor/page-viewer/PageViewerFrame.js +7 -28
- package/dist/editor/page-viewer/PageViewerFrame.js.map +1 -1
- package/dist/editor/reviews/Comment.js +56 -4
- package/dist/editor/reviews/Comment.js.map +1 -1
- package/dist/editor/services/agentService.d.ts +19 -0
- package/dist/editor/services/agentService.js +39 -0
- package/dist/editor/services/agentService.js.map +1 -1
- package/dist/editor/services/serviceHelper.d.ts +1 -0
- package/dist/editor/services/serviceHelper.js +58 -4
- package/dist/editor/services/serviceHelper.js.map +1 -1
- package/dist/revision.d.ts +2 -2
- package/dist/revision.js +2 -2
- package/dist/styles.css +4 -6
- package/dist/tour/default-tour.js +24 -9
- package/dist/tour/default-tour.js.map +1 -1
- package/package.json +1 -1
- package/src/agents-view/AgentCard.tsx +162 -0
- package/src/agents-view/AgentsView.tsx +218 -253
- package/src/agents-view/ProfileAgentsGroup.tsx +123 -0
- package/src/editor/ai/AgentProfilesOverview.tsx +1 -2
- package/src/editor/commands/componentCommands.tsx +19 -1
- package/src/editor/page-editor-chrome/FrameMenu.tsx +9 -3
- package/src/editor/page-viewer/PageViewerFrame.tsx +7 -36
- package/src/editor/reviews/Comment.tsx +85 -4
- package/src/editor/services/agentService.ts +77 -0
- package/src/editor/services/serviceHelper.ts +92 -28
- package/src/revision.ts +2 -2
- package/src/tour/default-tour.tsx +63 -48
|
@@ -1,49 +1,40 @@
|
|
|
1
|
-
import React, { useState, useEffect, useCallback
|
|
1
|
+
import React, { useState, useEffect, useCallback } from "react";
|
|
2
2
|
import {
|
|
3
3
|
Agent,
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
getAgentsGrouped,
|
|
5
|
+
getClosedAgentsByProfile,
|
|
6
|
+
ProfileAgentsGroup as ProfileGroup,
|
|
7
7
|
closeAgent,
|
|
8
8
|
deleteAgent,
|
|
9
9
|
} from "../editor/services/agentService";
|
|
10
|
-
import { getAgentStatusConfig } from "../editor/ai/AgentStatusBadge";
|
|
11
10
|
import { cn } from "../lib/utils";
|
|
12
|
-
import {
|
|
13
|
-
Trash,
|
|
14
|
-
X,
|
|
15
|
-
RefreshCw,
|
|
16
|
-
Play,
|
|
17
|
-
Search,
|
|
18
|
-
Users,
|
|
19
|
-
XCircle,
|
|
20
|
-
} from "lucide-react";
|
|
11
|
+
import { RefreshCw, Search, XCircle } from "lucide-react";
|
|
21
12
|
import { SimpleIconButton } from "../editor/ui/SimpleIconButton";
|
|
22
13
|
import { useEditContext } from "../editor/client/editContext";
|
|
23
|
-
import {
|
|
14
|
+
import { AgentCard } from "./AgentCard";
|
|
15
|
+
import { ProfileAgentsGroup } from "./ProfileAgentsGroup";
|
|
24
16
|
|
|
25
17
|
/**
|
|
26
|
-
* Agents overview view that displays
|
|
27
|
-
*
|
|
18
|
+
* Agents overview view that displays active agents at the top
|
|
19
|
+
* and closed agents grouped by profile below with interactive controls
|
|
28
20
|
*/
|
|
29
21
|
export function AgentsView() {
|
|
30
22
|
const editContext = useEditContext();
|
|
31
|
-
const [
|
|
32
|
-
const [
|
|
33
|
-
const [
|
|
23
|
+
const [activeAgents, setActiveAgents] = useState<Agent[]>([]);
|
|
24
|
+
const [profileGroups, setProfileGroups] = useState<ProfileGroup[]>([]);
|
|
25
|
+
const [expandedProfiles, setExpandedProfiles] = useState<Set<string>>(
|
|
26
|
+
new Set(),
|
|
27
|
+
);
|
|
28
|
+
const [loadingMoreForProfile, setLoadingMoreForProfile] = useState<
|
|
29
|
+
string | null
|
|
30
|
+
>(null);
|
|
34
31
|
const [loading, setLoading] = useState(true);
|
|
35
|
-
const [
|
|
32
|
+
const [initialLoad, setInitialLoad] = useState(true);
|
|
36
33
|
const [error, setError] = useState<string | null>(null);
|
|
37
34
|
const [refreshing, setRefreshing] = useState(false);
|
|
38
35
|
const [searchTerm, setSearchTerm] = useState("");
|
|
39
36
|
const [debouncedSearchTerm, setDebouncedSearchTerm] = useState("");
|
|
40
37
|
const [showOnlyMyAgents, setShowOnlyMyAgents] = useState(false);
|
|
41
|
-
const agentsRef = useRef<Agent[]>([]);
|
|
42
|
-
|
|
43
|
-
// Keep ref in sync with state
|
|
44
|
-
useEffect(() => {
|
|
45
|
-
agentsRef.current = agents;
|
|
46
|
-
}, [agents]);
|
|
47
38
|
|
|
48
39
|
// Debounce search term
|
|
49
40
|
useEffect(() => {
|
|
@@ -54,53 +45,35 @@ export function AgentsView() {
|
|
|
54
45
|
return () => clearTimeout(timer);
|
|
55
46
|
}, [searchTerm]);
|
|
56
47
|
|
|
57
|
-
const loadAgents = useCallback(
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
setLoading(true);
|
|
62
|
-
setError(null);
|
|
63
|
-
} else {
|
|
64
|
-
setLoadingMore(true);
|
|
65
|
-
}
|
|
48
|
+
const loadAgents = useCallback(async () => {
|
|
49
|
+
try {
|
|
50
|
+
setLoading(true);
|
|
51
|
+
setError(null);
|
|
66
52
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
includeOwned: true,
|
|
73
|
-
searchTerm: debouncedSearchTerm || undefined,
|
|
74
|
-
};
|
|
75
|
-
|
|
76
|
-
const response = await getActiveAgents(params);
|
|
77
|
-
|
|
78
|
-
if (reset) {
|
|
79
|
-
setAgents(response.agents);
|
|
80
|
-
} else {
|
|
81
|
-
setAgents((prev) => [...prev, ...response.agents]);
|
|
82
|
-
}
|
|
53
|
+
const response = await getAgentsGrouped(
|
|
54
|
+
debouncedSearchTerm || undefined,
|
|
55
|
+
!showOnlyMyAgents, // includeShared
|
|
56
|
+
true, // includeOwned
|
|
57
|
+
);
|
|
83
58
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
[showOnlyMyAgents, debouncedSearchTerm],
|
|
98
|
-
);
|
|
59
|
+
setActiveAgents(response.activeAgents);
|
|
60
|
+
setProfileGroups(response.closedAgentsByProfile);
|
|
61
|
+
} catch (err: any) {
|
|
62
|
+
console.error("Failed to load agents:", err);
|
|
63
|
+
setError(
|
|
64
|
+
err?.message || "Failed to load agents. Please try again later.",
|
|
65
|
+
);
|
|
66
|
+
} finally {
|
|
67
|
+
setLoading(false);
|
|
68
|
+
setRefreshing(false);
|
|
69
|
+
setInitialLoad(false);
|
|
70
|
+
}
|
|
71
|
+
}, [showOnlyMyAgents, debouncedSearchTerm]);
|
|
99
72
|
|
|
100
|
-
// Initial load
|
|
73
|
+
// Initial load and reload when filters change
|
|
101
74
|
useEffect(() => {
|
|
102
|
-
loadAgents(
|
|
103
|
-
}, [
|
|
75
|
+
loadAgents();
|
|
76
|
+
}, [loadAgents]);
|
|
104
77
|
|
|
105
78
|
// Subscribe to websocket messages for real-time agent updates
|
|
106
79
|
useEffect(() => {
|
|
@@ -119,8 +92,8 @@ export function AgentsView() {
|
|
|
119
92
|
return;
|
|
120
93
|
}
|
|
121
94
|
|
|
122
|
-
|
|
123
|
-
|
|
95
|
+
// Update or add agent in active agents list
|
|
96
|
+
setActiveAgents((prevAgents) => {
|
|
124
97
|
const existingAgentIndex = prevAgents.findIndex(
|
|
125
98
|
(agent) => agent.id === agentId,
|
|
126
99
|
);
|
|
@@ -137,7 +110,7 @@ export function AgentsView() {
|
|
|
137
110
|
};
|
|
138
111
|
return updatedAgents;
|
|
139
112
|
} else {
|
|
140
|
-
//
|
|
113
|
+
// Agent not found - reload to get full details
|
|
141
114
|
loadAgents();
|
|
142
115
|
return prevAgents;
|
|
143
116
|
}
|
|
@@ -146,10 +119,12 @@ export function AgentsView() {
|
|
|
146
119
|
const { agentId, agentName, agentDescription } =
|
|
147
120
|
message.payload || {};
|
|
148
121
|
if (!agentId) return;
|
|
149
|
-
|
|
150
|
-
|
|
122
|
+
|
|
123
|
+
// Update agent in active agents list
|
|
124
|
+
setActiveAgents((prevAgents) => {
|
|
151
125
|
const existingIndex = prevAgents.findIndex((a) => a.id === agentId);
|
|
152
126
|
if (existingIndex === -1) return prevAgents;
|
|
127
|
+
|
|
153
128
|
const updatedAgents = [...prevAgents];
|
|
154
129
|
const existingAgent = updatedAgents[existingIndex]!;
|
|
155
130
|
updatedAgents[existingIndex] = {
|
|
@@ -163,8 +138,8 @@ export function AgentsView() {
|
|
|
163
138
|
return updatedAgents;
|
|
164
139
|
});
|
|
165
140
|
} else if (message.type === "agent:run:closed") {
|
|
166
|
-
// Reload agents when one is closed - it should
|
|
167
|
-
loadAgents(
|
|
141
|
+
// Reload agents when one is closed - it should move to closed section
|
|
142
|
+
loadAgents();
|
|
168
143
|
}
|
|
169
144
|
},
|
|
170
145
|
);
|
|
@@ -174,12 +149,61 @@ export function AgentsView() {
|
|
|
174
149
|
|
|
175
150
|
const handleRefresh = async () => {
|
|
176
151
|
setRefreshing(true);
|
|
177
|
-
await loadAgents(
|
|
152
|
+
await loadAgents();
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
const handleToggleProfile = (profileId: string | null) => {
|
|
156
|
+
const key = profileId || "null";
|
|
157
|
+
setExpandedProfiles((prev) => {
|
|
158
|
+
const newSet = new Set(prev);
|
|
159
|
+
if (newSet.has(key)) {
|
|
160
|
+
newSet.delete(key);
|
|
161
|
+
} else {
|
|
162
|
+
newSet.add(key);
|
|
163
|
+
}
|
|
164
|
+
return newSet;
|
|
165
|
+
});
|
|
178
166
|
};
|
|
179
167
|
|
|
180
|
-
const
|
|
181
|
-
if (!
|
|
182
|
-
|
|
168
|
+
const handleLoadMoreForProfile = async (profileId: string | null) => {
|
|
169
|
+
if (!profileId || loadingMoreForProfile) return;
|
|
170
|
+
|
|
171
|
+
try {
|
|
172
|
+
setLoadingMoreForProfile(profileId);
|
|
173
|
+
|
|
174
|
+
// Find the current profile group
|
|
175
|
+
const profileGroup = profileGroups.find((g) => g.profileId === profileId);
|
|
176
|
+
if (!profileGroup) return;
|
|
177
|
+
|
|
178
|
+
const currentCount = profileGroup.agents.length;
|
|
179
|
+
|
|
180
|
+
// Load more agents for this profile
|
|
181
|
+
const response = await getClosedAgentsByProfile(
|
|
182
|
+
profileId,
|
|
183
|
+
currentCount,
|
|
184
|
+
10,
|
|
185
|
+
debouncedSearchTerm || undefined,
|
|
186
|
+
);
|
|
187
|
+
|
|
188
|
+
// Update the profile group with new agents
|
|
189
|
+
setProfileGroups((prevGroups) =>
|
|
190
|
+
prevGroups.map((group) => {
|
|
191
|
+
if (group.profileId === profileId) {
|
|
192
|
+
return {
|
|
193
|
+
...group,
|
|
194
|
+
agents: [...group.agents, ...response.agents],
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
return group;
|
|
198
|
+
}),
|
|
199
|
+
);
|
|
200
|
+
} catch (err: any) {
|
|
201
|
+
console.error("Failed to load more agents:", err);
|
|
202
|
+
editContext?.showToast(
|
|
203
|
+
`Failed to load more agents: ${err?.message || "Unknown error"}`,
|
|
204
|
+
);
|
|
205
|
+
} finally {
|
|
206
|
+
setLoadingMoreForProfile(null);
|
|
183
207
|
}
|
|
184
208
|
};
|
|
185
209
|
|
|
@@ -204,7 +228,8 @@ export function AgentsView() {
|
|
|
204
228
|
accept: async () => {
|
|
205
229
|
try {
|
|
206
230
|
await closeAgent(agentId);
|
|
207
|
-
|
|
231
|
+
// Reload to move agent from active to closed section
|
|
232
|
+
loadAgents();
|
|
208
233
|
} catch (err: any) {
|
|
209
234
|
console.error("Failed to close agent:", err);
|
|
210
235
|
editContext?.showToast(
|
|
@@ -230,7 +255,15 @@ export function AgentsView() {
|
|
|
230
255
|
accept: async () => {
|
|
231
256
|
try {
|
|
232
257
|
await deleteAgent(agentId);
|
|
233
|
-
|
|
258
|
+
// Remove from both active and closed lists
|
|
259
|
+
setActiveAgents((prev) => prev.filter((a) => a.id !== agentId));
|
|
260
|
+
setProfileGroups((prevGroups) =>
|
|
261
|
+
prevGroups.map((group) => ({
|
|
262
|
+
...group,
|
|
263
|
+
agents: group.agents.filter((a) => a.id !== agentId),
|
|
264
|
+
totalClosedCount: Math.max(0, group.totalClosedCount - 1),
|
|
265
|
+
})),
|
|
266
|
+
);
|
|
234
267
|
} catch (err: any) {
|
|
235
268
|
console.error("Failed to delete agent:", err);
|
|
236
269
|
editContext?.showToast(
|
|
@@ -242,6 +275,15 @@ export function AgentsView() {
|
|
|
242
275
|
});
|
|
243
276
|
};
|
|
244
277
|
|
|
278
|
+
const handleAgentClick = (agent: Agent) => {
|
|
279
|
+
// Only select the agent in the agents panel; do not switch views
|
|
280
|
+
window.dispatchEvent(
|
|
281
|
+
new CustomEvent("editor:selectAgent", {
|
|
282
|
+
detail: { agentId: agent.id },
|
|
283
|
+
}),
|
|
284
|
+
);
|
|
285
|
+
};
|
|
286
|
+
|
|
245
287
|
const formatDateTime = (dateString: string) => {
|
|
246
288
|
try {
|
|
247
289
|
const date = new Date(dateString);
|
|
@@ -251,10 +293,8 @@ export function AgentsView() {
|
|
|
251
293
|
}
|
|
252
294
|
};
|
|
253
295
|
|
|
254
|
-
//
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
if (loading) {
|
|
296
|
+
// Show full-screen loading only on initial load
|
|
297
|
+
if (initialLoad && loading) {
|
|
258
298
|
return (
|
|
259
299
|
<div className="flex h-full items-center justify-center">
|
|
260
300
|
<div className="text-sm text-gray-500">Loading agents...</div>
|
|
@@ -262,32 +302,23 @@ export function AgentsView() {
|
|
|
262
302
|
);
|
|
263
303
|
}
|
|
264
304
|
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
onClick={handleRefresh}
|
|
272
|
-
className="rounded bg-blue-500 px-4 py-2 text-xs text-white hover:bg-blue-600"
|
|
273
|
-
>
|
|
274
|
-
Retry
|
|
275
|
-
</button>
|
|
276
|
-
</div>
|
|
277
|
-
</div>
|
|
278
|
-
);
|
|
279
|
-
}
|
|
305
|
+
const totalActiveCount = activeAgents.length;
|
|
306
|
+
const totalClosedCount = profileGroups.reduce(
|
|
307
|
+
(sum, group) => sum + group.totalClosedCount,
|
|
308
|
+
0,
|
|
309
|
+
);
|
|
310
|
+
const totalCount = totalActiveCount + totalClosedCount;
|
|
280
311
|
|
|
281
312
|
return (
|
|
282
|
-
<div className="
|
|
313
|
+
<div className="absolute inset-0 flex flex-col">
|
|
283
314
|
{/* Header */}
|
|
284
|
-
<div className="border-b border-gray-200 bg-white p-4">
|
|
315
|
+
<div className="flex-shrink-0 border-b border-gray-200 bg-white p-4">
|
|
285
316
|
<div className="mb-3 flex items-center justify-between">
|
|
286
317
|
<div>
|
|
287
318
|
<h2 className="text-lg font-semibold text-gray-900">Agents</h2>
|
|
288
319
|
<p className="text-xs text-gray-500">
|
|
289
|
-
|
|
290
|
-
|
|
320
|
+
{totalActiveCount} active, {totalClosedCount} closed ({totalCount}{" "}
|
|
321
|
+
total)
|
|
291
322
|
</p>
|
|
292
323
|
</div>
|
|
293
324
|
<div className="flex items-center gap-2">
|
|
@@ -343,159 +374,93 @@ export function AgentsView() {
|
|
|
343
374
|
</div>
|
|
344
375
|
</div>
|
|
345
376
|
|
|
346
|
-
{/*
|
|
347
|
-
<div className="flex-1 overflow-auto">
|
|
348
|
-
{
|
|
377
|
+
{/* Content */}
|
|
378
|
+
<div className="relative flex-1 overflow-y-auto">
|
|
379
|
+
{/* Loading overlay - shows subtle indicator without hiding content */}
|
|
380
|
+
{loading && !initialLoad && (
|
|
381
|
+
<div className="absolute top-2 left-1/2 z-10 -translate-x-1/2 rounded-md bg-white px-3 py-1.5 shadow-md">
|
|
382
|
+
<div className="flex items-center gap-2 text-sm text-gray-600">
|
|
383
|
+
<RefreshCw className="size-3 animate-spin" strokeWidth={1} />
|
|
384
|
+
<span>Loading...</span>
|
|
385
|
+
</div>
|
|
386
|
+
</div>
|
|
387
|
+
)}
|
|
388
|
+
|
|
389
|
+
{error ? (
|
|
390
|
+
<div className="flex h-full items-center justify-center">
|
|
391
|
+
<div className="max-w-md text-center">
|
|
392
|
+
<div className="mb-4 text-sm text-red-600">{error}</div>
|
|
393
|
+
<button
|
|
394
|
+
onClick={handleRefresh}
|
|
395
|
+
className="rounded bg-blue-500 px-4 py-2 text-xs text-white hover:bg-blue-600"
|
|
396
|
+
>
|
|
397
|
+
Retry
|
|
398
|
+
</button>
|
|
399
|
+
</div>
|
|
400
|
+
</div>
|
|
401
|
+
) : totalCount === 0 && !loading ? (
|
|
349
402
|
<div className="flex h-full items-center justify-center text-sm text-gray-500">
|
|
350
403
|
{searchTerm.trim()
|
|
351
404
|
? "No agents match your search"
|
|
352
405
|
: "No agents found"}
|
|
353
406
|
</div>
|
|
354
407
|
) : (
|
|
355
|
-
<div className="space-y-
|
|
356
|
-
{
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
<
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
{/* Shared Agent Owner */}
|
|
413
|
-
{agent.isShared && agent.ownerName && (
|
|
414
|
-
<p className="mb-1 text-xs text-gray-500">
|
|
415
|
-
Created by {agent.ownerName}
|
|
416
|
-
</p>
|
|
417
|
-
)}
|
|
418
|
-
|
|
419
|
-
{/* Agent Description */}
|
|
420
|
-
{agent.description && (
|
|
421
|
-
<p className="mb-2 truncate text-xs text-gray-500">
|
|
422
|
-
{agent.description}
|
|
423
|
-
</p>
|
|
424
|
-
)}
|
|
425
|
-
|
|
426
|
-
{/* Agent Details */}
|
|
427
|
-
<div className="space-y-1 text-xs text-gray-600">
|
|
428
|
-
<div className="flex items-center gap-2">
|
|
429
|
-
<span className="font-medium">Updated:</span>
|
|
430
|
-
<span>{formatDateTime(agent.updatedDate)}</span>
|
|
431
|
-
</div>
|
|
432
|
-
{agent.messageCount !== undefined &&
|
|
433
|
-
agent.messageCount > 0 && (
|
|
434
|
-
<div className="flex items-center gap-2">
|
|
435
|
-
<span className="font-medium">Messages:</span>
|
|
436
|
-
<span>{agent.messageCount}</span>
|
|
437
|
-
</div>
|
|
438
|
-
)}
|
|
439
|
-
{agent.totalCost !== undefined &&
|
|
440
|
-
agent.totalCost > 0 && (
|
|
441
|
-
<div className="flex items-center gap-2">
|
|
442
|
-
<span className="font-medium">Cost:</span>
|
|
443
|
-
<span>${agent.totalCost.toFixed(4)}</span>
|
|
444
|
-
{agent.totalTokensUsed !== undefined && (
|
|
445
|
-
<span className="text-gray-400">
|
|
446
|
-
({agent.totalTokensUsed.toLocaleString()}{" "}
|
|
447
|
-
tokens)
|
|
448
|
-
</span>
|
|
449
|
-
)}
|
|
450
|
-
</div>
|
|
451
|
-
)}
|
|
452
|
-
</div>
|
|
453
|
-
</div>
|
|
454
|
-
|
|
455
|
-
{/* Actions */}
|
|
456
|
-
<div className="ml-3 flex gap-1">
|
|
457
|
-
<SimpleIconButton
|
|
458
|
-
onClick={(e) => {
|
|
459
|
-
e.stopPropagation();
|
|
460
|
-
handleResumeAgent(agent);
|
|
461
|
-
}}
|
|
462
|
-
icon={<Play className="size-3" strokeWidth={1.5} />}
|
|
463
|
-
label="Resume Agent"
|
|
464
|
-
className="text-blue-600 opacity-60 hover:text-blue-700 hover:opacity-100"
|
|
465
|
-
/>
|
|
466
|
-
<SimpleIconButton
|
|
467
|
-
onClick={(e) => {
|
|
468
|
-
e.stopPropagation();
|
|
469
|
-
handleCloseAgent(agent.id, agent.name);
|
|
470
|
-
}}
|
|
471
|
-
icon={<X className="size-3" strokeWidth={1.5} />}
|
|
472
|
-
label="Close Agent"
|
|
473
|
-
className="text-gray-600 opacity-60 hover:text-gray-800 hover:opacity-100"
|
|
474
|
-
/>
|
|
475
|
-
<SimpleIconButton
|
|
476
|
-
onClick={(e) =>
|
|
477
|
-
handleDeleteAgent(agent.id, agent.name, e)
|
|
478
|
-
}
|
|
479
|
-
icon={<Trash className="size-3" strokeWidth={1.5} />}
|
|
480
|
-
label="Delete Agent"
|
|
481
|
-
className="text-red-600 opacity-60 hover:text-red-700 hover:opacity-100"
|
|
482
|
-
/>
|
|
483
|
-
</div>
|
|
484
|
-
</div>
|
|
485
|
-
</div>
|
|
486
|
-
);
|
|
487
|
-
})}
|
|
488
|
-
|
|
489
|
-
{/* Load More Button */}
|
|
490
|
-
{hasMore && (
|
|
491
|
-
<div className="flex justify-center pt-4">
|
|
492
|
-
<button
|
|
493
|
-
onClick={handleLoadMore}
|
|
494
|
-
disabled={loadingMore}
|
|
495
|
-
className="rounded-lg border border-gray-300 bg-white px-6 py-2 text-sm font-medium text-gray-700 hover:bg-gray-50 disabled:opacity-50"
|
|
496
|
-
>
|
|
497
|
-
{loadingMore ? "Loading..." : "Load More"}
|
|
498
|
-
</button>
|
|
408
|
+
<div className={cn("space-y-4 p-4", loading && "opacity-60")}>
|
|
409
|
+
{/* Active Agents Section */}
|
|
410
|
+
{activeAgents.length > 0 && (
|
|
411
|
+
<div className="space-y-2">
|
|
412
|
+
<h3 className="text-sm font-semibold text-gray-700">
|
|
413
|
+
Active Agents
|
|
414
|
+
</h3>
|
|
415
|
+
{activeAgents.map((agent) => (
|
|
416
|
+
<AgentCard
|
|
417
|
+
key={agent.id}
|
|
418
|
+
agent={agent}
|
|
419
|
+
onClick={handleAgentClick}
|
|
420
|
+
onResume={handleResumeAgent}
|
|
421
|
+
onClose={handleCloseAgent}
|
|
422
|
+
onDelete={handleDeleteAgent}
|
|
423
|
+
formatDateTime={formatDateTime}
|
|
424
|
+
/>
|
|
425
|
+
))}
|
|
426
|
+
</div>
|
|
427
|
+
)}
|
|
428
|
+
|
|
429
|
+
{/* Closed Agents by Profile Section */}
|
|
430
|
+
{profileGroups.length > 0 && (
|
|
431
|
+
<div className="space-y-2">
|
|
432
|
+
<h3 className="text-sm font-semibold text-gray-700">
|
|
433
|
+
Closed Agents by Profile
|
|
434
|
+
</h3>
|
|
435
|
+
{profileGroups.map((profileGroup) => {
|
|
436
|
+
const profileKey = profileGroup.profileId || "null";
|
|
437
|
+
const isExpanded = expandedProfiles.has(profileKey);
|
|
438
|
+
const isLoadingMore =
|
|
439
|
+
loadingMoreForProfile === profileGroup.profileId;
|
|
440
|
+
const hasMore =
|
|
441
|
+
profileGroup.agents.length < profileGroup.totalClosedCount;
|
|
442
|
+
|
|
443
|
+
return (
|
|
444
|
+
<ProfileAgentsGroup
|
|
445
|
+
key={profileKey}
|
|
446
|
+
profileGroup={profileGroup}
|
|
447
|
+
isExpanded={isExpanded}
|
|
448
|
+
isLoadingMore={isLoadingMore}
|
|
449
|
+
hasMore={hasMore}
|
|
450
|
+
onToggle={() =>
|
|
451
|
+
handleToggleProfile(profileGroup.profileId)
|
|
452
|
+
}
|
|
453
|
+
onLoadMore={() =>
|
|
454
|
+
handleLoadMoreForProfile(profileGroup.profileId)
|
|
455
|
+
}
|
|
456
|
+
onAgentClick={handleAgentClick}
|
|
457
|
+
onResumeAgent={handleResumeAgent}
|
|
458
|
+
onCloseAgent={handleCloseAgent}
|
|
459
|
+
onDeleteAgent={handleDeleteAgent}
|
|
460
|
+
formatDateTime={formatDateTime}
|
|
461
|
+
/>
|
|
462
|
+
);
|
|
463
|
+
})}
|
|
499
464
|
</div>
|
|
500
465
|
)}
|
|
501
466
|
</div>
|