@alpaca-editor/core 1.0.4176 → 1.0.4179

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 (32) hide show
  1. package/dist/agents-view/AgentsView.d.ts +2 -2
  2. package/dist/agents-view/AgentsView.js +105 -62
  3. package/dist/agents-view/AgentsView.js.map +1 -1
  4. package/dist/editor/ai/Agents.js +15 -7
  5. package/dist/editor/ai/Agents.js.map +1 -1
  6. package/dist/editor/ai/useAgentStatus.js +6 -1
  7. package/dist/editor/ai/useAgentStatus.js.map +1 -1
  8. package/dist/editor/services/agentService.d.ts +24 -2
  9. package/dist/editor/services/agentService.js +25 -18
  10. package/dist/editor/services/agentService.js.map +1 -1
  11. package/dist/editor/services/aiService.d.ts +1 -0
  12. package/dist/editor/services/aiService.js +9 -6
  13. package/dist/editor/services/aiService.js.map +1 -1
  14. package/dist/page-wizard/steps/ContentStep.js +8 -1
  15. package/dist/page-wizard/steps/ContentStep.js.map +1 -1
  16. package/dist/page-wizard/steps/SelectStep.js +7 -3
  17. package/dist/page-wizard/steps/SelectStep.js.map +1 -1
  18. package/dist/page-wizard/steps/usePageCreator.js +5 -0
  19. package/dist/page-wizard/steps/usePageCreator.js.map +1 -1
  20. package/dist/revision.d.ts +2 -2
  21. package/dist/revision.js +2 -2
  22. package/dist/styles.css +12 -0
  23. package/package.json +1 -1
  24. package/src/agents-view/AgentsView.tsx +303 -208
  25. package/src/editor/ai/Agents.tsx +17 -7
  26. package/src/editor/ai/useAgentStatus.ts +6 -1
  27. package/src/editor/services/agentService.ts +54 -23
  28. package/src/editor/services/aiService.ts +16 -6
  29. package/src/page-wizard/steps/ContentStep.tsx +9 -4
  30. package/src/page-wizard/steps/SelectStep.tsx +8 -3
  31. package/src/page-wizard/steps/usePageCreator.ts +5 -0
  32. package/src/revision.ts +2 -2
@@ -1,61 +1,106 @@
1
- import React, { useState, useEffect } from "react";
1
+ import React, { useState, useEffect, useCallback, useRef } from "react";
2
2
  import {
3
- AgentDetails,
3
+ Agent,
4
4
  getActiveAgents,
5
+ GetAgentsParams,
5
6
  getAgent,
6
7
  closeAgent,
7
8
  deleteAgent,
8
9
  } from "../editor/services/agentService";
9
10
  import { getAgentStatusConfig } from "../editor/ai/AgentStatusBadge";
10
11
  import { cn } from "../lib/utils";
11
- import { Trash, X, RefreshCw, Play } from "lucide-react";
12
+ import {
13
+ Trash,
14
+ X,
15
+ RefreshCw,
16
+ Play,
17
+ Search,
18
+ Users,
19
+ XCircle,
20
+ } from "lucide-react";
12
21
  import { SimpleIconButton } from "../editor/ui/SimpleIconButton";
13
22
  import { useEditContext } from "../editor/client/editContext";
14
23
  import { SecretAgentIcon } from "../editor/ui/Icons";
15
24
 
16
25
  /**
17
- * Agents overview view that displays all non-closed agents for the current user
18
- * grouped by profile with interactive controls
26
+ * Agents overview view that displays all agents for the current user
27
+ * (including closed and shared agents) grouped by profile with interactive controls
19
28
  */
20
29
  export function AgentsView() {
21
30
  const editContext = useEditContext();
22
- const [agents, setAgents] = useState<AgentDetails[]>([]);
31
+ const [agents, setAgents] = useState<Agent[]>([]);
32
+ const [totalCount, setTotalCount] = useState(0);
33
+ const [hasMore, setHasMore] = useState(false);
23
34
  const [loading, setLoading] = useState(true);
35
+ const [loadingMore, setLoadingMore] = useState(false);
24
36
  const [error, setError] = useState<string | null>(null);
25
37
  const [refreshing, setRefreshing] = useState(false);
26
38
  const [searchTerm, setSearchTerm] = useState("");
39
+ const [debouncedSearchTerm, setDebouncedSearchTerm] = useState("");
40
+ const [showOnlyMyAgents, setShowOnlyMyAgents] = useState(false);
41
+ const agentsRef = useRef<Agent[]>([]);
27
42
 
28
- const loadAgents = async () => {
29
- try {
30
- setError(null);
31
- // Get basic agent list
32
- const basicAgents = await getActiveAgents(1000);
43
+ // Keep ref in sync with state
44
+ useEffect(() => {
45
+ agentsRef.current = agents;
46
+ }, [agents]);
33
47
 
34
- // Fetch full details for each agent
35
- const detailsPromises = basicAgents.map((agent) =>
36
- getAgent(agent.id).catch(() => null),
37
- );
38
- const agentDetails = await Promise.all(detailsPromises);
48
+ // Debounce search term
49
+ useEffect(() => {
50
+ const timer = setTimeout(() => {
51
+ setDebouncedSearchTerm(searchTerm);
52
+ }, 400);
39
53
 
40
- // Filter out any failed fetches and set the agents
41
- const validAgents = agentDetails.filter(
42
- (a): a is AgentDetails => a !== null,
43
- );
44
- setAgents(validAgents);
45
- } catch (err: any) {
46
- console.error("Failed to load agents:", err);
47
- setError(
48
- err?.message || "Failed to load agents. Please try again later.",
49
- );
50
- } finally {
51
- setLoading(false);
52
- setRefreshing(false);
53
- }
54
- };
54
+ return () => clearTimeout(timer);
55
+ }, [searchTerm]);
56
+
57
+ const loadAgents = useCallback(
58
+ async (reset: boolean = false) => {
59
+ try {
60
+ if (reset) {
61
+ setLoading(true);
62
+ setError(null);
63
+ } else {
64
+ setLoadingMore(true);
65
+ }
66
+
67
+ const skip = reset ? 0 : agentsRef.current.length;
68
+ const params: GetAgentsParams = {
69
+ skip,
70
+ limit: 50,
71
+ includeShared: !showOnlyMyAgents,
72
+ includeOwned: true,
73
+ searchTerm: debouncedSearchTerm || undefined,
74
+ };
55
75
 
76
+ const response = await getActiveAgents(params);
77
+
78
+ if (reset) {
79
+ setAgents(response.agents);
80
+ } else {
81
+ setAgents((prev) => [...prev, ...response.agents]);
82
+ }
83
+
84
+ setTotalCount(response.totalCount);
85
+ setHasMore(response.hasMore);
86
+ } catch (err: any) {
87
+ console.error("Failed to load agents:", err);
88
+ setError(
89
+ err?.message || "Failed to load agents. Please try again later.",
90
+ );
91
+ } finally {
92
+ setLoading(false);
93
+ setLoadingMore(false);
94
+ setRefreshing(false);
95
+ }
96
+ },
97
+ [showOnlyMyAgents, debouncedSearchTerm],
98
+ );
99
+
100
+ // Initial load
56
101
  useEffect(() => {
57
- loadAgents();
58
- }, []);
102
+ loadAgents(true);
103
+ }, [showOnlyMyAgents, debouncedSearchTerm]);
59
104
 
60
105
  // Subscribe to websocket messages for real-time agent updates
61
106
  useEffect(() => {
@@ -97,25 +142,48 @@ export function AgentsView() {
97
142
  return prevAgents;
98
143
  }
99
144
  });
100
- } else if (message.type === "agent:run:closed") {
101
- // Remove agent from list when closed
102
- const { agentId } = message.payload || {};
145
+ } else if (message.type === "agent:info:updated") {
146
+ const { agentId, agentName, agentDescription } =
147
+ message.payload || {};
103
148
  if (!agentId) return;
104
-
105
- setAgents((prevAgents) => prevAgents.filter((a) => a.id !== agentId));
149
+ // Update the agent name and/or description in the list
150
+ setAgents((prevAgents) => {
151
+ const existingIndex = prevAgents.findIndex((a) => a.id === agentId);
152
+ if (existingIndex === -1) return prevAgents;
153
+ const updatedAgents = [...prevAgents];
154
+ const existingAgent = updatedAgents[existingIndex]!;
155
+ updatedAgents[existingIndex] = {
156
+ ...existingAgent,
157
+ ...(agentName !== undefined && { name: agentName }),
158
+ ...(agentDescription !== undefined && {
159
+ description: agentDescription,
160
+ }),
161
+ updatedDate: new Date().toISOString(),
162
+ };
163
+ return updatedAgents;
164
+ });
165
+ } else if (message.type === "agent:run:closed") {
166
+ // Reload agents when one is closed - it should still appear in the list
167
+ loadAgents(true);
106
168
  }
107
169
  },
108
170
  );
109
171
 
110
172
  return unsubscribe;
111
- }, [editContext?.addSocketMessageListener]);
173
+ }, [editContext?.addSocketMessageListener, loadAgents]);
112
174
 
113
175
  const handleRefresh = async () => {
114
176
  setRefreshing(true);
115
- await loadAgents();
177
+ await loadAgents(true);
116
178
  };
117
179
 
118
- const handleResumeAgent = (agent: AgentDetails) => {
180
+ const handleLoadMore = () => {
181
+ if (!loadingMore && hasMore) {
182
+ loadAgents(false);
183
+ }
184
+ };
185
+
186
+ const handleResumeAgent = (agent: Agent) => {
119
187
  editContext?.switchView("page-editor");
120
188
  editContext?.setShowAgentsPanel?.(true);
121
189
  // Delay for panel mount, then dispatch event to open existing agent
@@ -183,35 +251,10 @@ export function AgentsView() {
183
251
  }
184
252
  };
185
253
 
186
- const filteredAgents = agents.filter((agent) => {
187
- if (!searchTerm.trim()) return true;
188
- const search = searchTerm.toLowerCase();
189
- return (
190
- agent.name.toLowerCase().includes(search) ||
191
- agent.profileName?.toLowerCase().includes(search) ||
192
- agent.id.toLowerCase().includes(search)
193
- );
194
- });
195
-
196
- // Group agents by profile
197
- const groupedAgents = filteredAgents.reduce(
198
- (acc, agent) => {
199
- const profileName = agent.profileName || "Unknown Profile";
200
- if (!acc[profileName]) {
201
- acc[profileName] = [];
202
- }
203
- acc[profileName].push(agent);
204
- return acc;
205
- },
206
- {} as Record<string, AgentDetails[]>,
207
- );
208
-
209
- // Sort profile groups by name
210
- const sortedProfileGroups = Object.entries(groupedAgents).sort(([a], [b]) =>
211
- a.localeCompare(b),
212
- );
254
+ // No client-side filtering needed - backend handles it
255
+ // Just display the agents as returned from the API
213
256
 
214
- if (loading) {
257
+ if (loading && (!agents || agents.length === 0)) {
215
258
  return (
216
259
  <div className="flex h-full items-center justify-center">
217
260
  <div className="text-sm text-gray-500">Loading agents...</div>
@@ -241,171 +284,223 @@ export function AgentsView() {
241
284
  <div className="border-b border-gray-200 bg-white p-4">
242
285
  <div className="mb-3 flex items-center justify-between">
243
286
  <div>
244
- <h2 className="text-lg font-semibold text-gray-900">My Agents</h2>
287
+ <h2 className="text-lg font-semibold text-gray-900">Agents</h2>
245
288
  <p className="text-xs text-gray-500">
246
- Showing {filteredAgents.length} active agent
247
- {filteredAgents.length !== 1 ? "s" : ""}
289
+ Showing {agents?.length || 0} of {totalCount} agent
290
+ {totalCount !== 1 ? "s" : ""}
248
291
  </p>
249
292
  </div>
250
- <SimpleIconButton
251
- onClick={handleRefresh}
252
- icon={
253
- <RefreshCw
254
- className={cn("size-4", refreshing && "animate-spin")}
255
- strokeWidth={1.5}
256
- />
257
- }
258
- label="Refresh"
259
- disabled={refreshing}
260
- className="text-gray-600 hover:text-gray-800"
261
- />
293
+ <div className="flex items-center gap-2">
294
+ <SimpleIconButton
295
+ onClick={handleRefresh}
296
+ icon={
297
+ <RefreshCw
298
+ className={cn("size-4", refreshing && "animate-spin")}
299
+ strokeWidth={1}
300
+ />
301
+ }
302
+ label="Refresh"
303
+ disabled={refreshing}
304
+ className="text-gray-600 hover:text-gray-800"
305
+ />
306
+ </div>
307
+ </div>
308
+
309
+ {/* Filter Toggle */}
310
+ <div className="mb-3">
311
+ <label className="flex cursor-pointer items-center gap-2 text-sm">
312
+ <input
313
+ type="checkbox"
314
+ checked={showOnlyMyAgents}
315
+ onChange={(e) => setShowOnlyMyAgents(e.target.checked)}
316
+ className="h-4 w-4 rounded border-gray-300 text-blue-600 focus:ring-blue-500"
317
+ />
318
+ <span className="text-gray-700">Show only my agents</span>
319
+ </label>
262
320
  </div>
263
321
 
264
322
  {/* Search */}
265
- <input
266
- type="text"
267
- placeholder="Search by name, profile, or agent ID..."
268
- value={searchTerm}
269
- onChange={(e) => setSearchTerm(e.target.value)}
270
- className="w-full rounded border border-gray-200 px-3 py-2 text-sm focus:border-blue-500 focus:outline-none"
271
- />
323
+ <div className="relative">
324
+ <Search
325
+ className="absolute top-1/2 left-3 size-4 -translate-y-1/2 text-gray-400"
326
+ strokeWidth={1}
327
+ />
328
+ <input
329
+ type="text"
330
+ placeholder="Search by name or description..."
331
+ value={searchTerm}
332
+ onChange={(e) => setSearchTerm(e.target.value)}
333
+ className="w-full rounded border border-gray-200 py-2 pr-10 pl-10 text-sm focus:border-blue-500 focus:outline-none"
334
+ />
335
+ {searchTerm && (
336
+ <button
337
+ onClick={() => setSearchTerm("")}
338
+ className="absolute top-1/2 right-3 -translate-y-1/2 text-gray-400 hover:text-gray-600"
339
+ >
340
+ <XCircle className="size-4" strokeWidth={1} />
341
+ </button>
342
+ )}
343
+ </div>
272
344
  </div>
273
345
 
274
346
  {/* Agents List */}
275
347
  <div className="flex-1 overflow-auto">
276
- {filteredAgents.length === 0 ? (
348
+ {!agents || agents.length === 0 ? (
277
349
  <div className="flex h-full items-center justify-center text-sm text-gray-500">
278
350
  {searchTerm.trim()
279
351
  ? "No agents match your search"
280
- : "No active agents found"}
352
+ : "No agents found"}
281
353
  </div>
282
354
  ) : (
283
- <div className="space-y-6 p-4">
284
- {sortedProfileGroups.map(([profileName, profileAgents]) => (
285
- <div key={profileName}>
286
- <h3 className="mb-2 text-xs font-semibold tracking-wide text-gray-500 uppercase">
287
- {profileName} ({profileAgents.length})
288
- </h3>
289
- <div className="space-y-2">
290
- {profileAgents.map((agent) => {
291
- const statusConfig = getAgentStatusConfig(agent);
292
- return (
293
- <div
294
- key={agent.id}
295
- className="cursor-pointer rounded-lg border border-gray-200 bg-white p-3 shadow-sm transition-shadow hover:shadow-md"
296
- onClick={() => {
297
- // Only select the agent in the agents panel; do not switch views
298
- window.dispatchEvent(
299
- new CustomEvent("editor:selectAgent", {
300
- detail: { agentId: agent.id },
301
- }),
302
- );
303
- }}
304
- >
305
- <div className="flex items-start justify-between">
306
- {/* Agent Icon */}
307
- <div className="mr-3 flex-shrink-0">
308
- {agent.profileSvgIcon ? (
309
- <div
310
- className="flex h-6 w-6 items-center justify-center text-gray-400 [&>svg]:h-full [&>svg]:w-full"
311
- dangerouslySetInnerHTML={{
312
- __html: agent.profileSvgIcon,
313
- }}
314
- />
315
- ) : (
316
- <SecretAgentIcon
317
- size={24}
318
- strokeWidth={1}
319
- className="text-gray-400"
320
- />
321
- )}
355
+ <div className="space-y-2 p-4">
356
+ {agents.map((agent) => {
357
+ const statusConfig = getAgentStatusConfig(agent);
358
+ return (
359
+ <div
360
+ key={agent.id}
361
+ className="cursor-pointer rounded-lg border border-gray-200 bg-white p-3 shadow-sm transition-shadow hover:shadow-md"
362
+ onClick={() => {
363
+ // Only select the agent in the agents panel; do not switch views
364
+ window.dispatchEvent(
365
+ new CustomEvent("editor:selectAgent", {
366
+ detail: { agentId: agent.id },
367
+ }),
368
+ );
369
+ }}
370
+ >
371
+ <div className="flex items-start justify-between">
372
+ {/* Agent Icon */}
373
+ <div className="mr-3 flex-shrink-0">
374
+ {agent.profileSvgIcon ? (
375
+ <div
376
+ className="flex h-6 w-6 items-center justify-center text-gray-400 [&>svg]:h-full [&>svg]:w-full"
377
+ dangerouslySetInnerHTML={{
378
+ __html: agent.profileSvgIcon,
379
+ }}
380
+ />
381
+ ) : (
382
+ <SecretAgentIcon
383
+ size={24}
384
+ strokeWidth={1}
385
+ className="text-gray-400"
386
+ />
387
+ )}
388
+ </div>
389
+
390
+ <div className="min-w-0 flex-1">
391
+ {/* Agent Name & Status */}
392
+ <div className="mb-1 flex items-center gap-2">
393
+ <div
394
+ className={cn(
395
+ "h-2 w-2 flex-shrink-0 rounded-full",
396
+ statusConfig.color,
397
+ statusConfig.shouldPulse && "animate-pulse",
398
+ )}
399
+ title={statusConfig.label}
400
+ />
401
+ <h4 className="truncate font-medium text-gray-900">
402
+ {agent.name}
403
+ </h4>
404
+ {agent.isShared && (
405
+ <div className="flex items-center gap-1 rounded bg-blue-50 px-2 py-0.5 text-xs text-blue-700">
406
+ <Users className="size-3" strokeWidth={1} />
407
+ <span>Shared</span>
322
408
  </div>
409
+ )}
410
+ </div>
323
411
 
324
- <div className="min-w-0 flex-1">
325
- {/* Agent Name & Status */}
326
- <div className="mb-1 flex items-center gap-2">
327
- <div
328
- className={cn(
329
- "h-2 w-2 flex-shrink-0 rounded-full",
330
- statusConfig.color,
331
- statusConfig.shouldPulse && "animate-pulse",
332
- )}
333
- title={statusConfig.label}
334
- />
335
- <h4 className="truncate font-medium text-gray-900">
336
- {agent.name}
337
- </h4>
338
- </div>
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
+ )}
339
418
 
340
- {/* Agent Details */}
341
- <div className="space-y-1 text-xs text-gray-600">
342
- <div className="flex items-center gap-2">
343
- <span className="font-medium">Updated:</span>
344
- <span>{formatDateTime(agent.updatedDate)}</span>
345
- </div>
346
- {agent.messageCount > 0 && (
347
- <div className="flex items-center gap-2">
348
- <span className="font-medium">Messages:</span>
349
- <span>{agent.messageCount}</span>
350
- </div>
351
- )}
352
- {agent.totalCost > 0 && (
353
- <div className="flex items-center gap-2">
354
- <span className="font-medium">Cost:</span>
355
- <span>${agent.totalCost.toFixed(4)}</span>
356
- <span className="text-gray-400">
357
- ({agent.totalTokensUsed.toLocaleString()}{" "}
358
- tokens)
359
- </span>
360
- </div>
361
- )}
362
- </div>
363
- </div>
419
+ {/* Agent Description */}
420
+ {agent.description && (
421
+ <p className="mb-2 truncate text-xs text-gray-500">
422
+ {agent.description}
423
+ </p>
424
+ )}
364
425
 
365
- {/* Actions */}
366
- <div className="ml-3 flex gap-1">
367
- <SimpleIconButton
368
- onClick={(e) => {
369
- e.stopPropagation();
370
- handleResumeAgent(agent);
371
- }}
372
- icon={
373
- <Play className="size-3" strokeWidth={1.5} />
374
- }
375
- label="Resume Agent"
376
- className="text-blue-600 opacity-60 hover:text-blue-700 hover:opacity-100"
377
- />
378
- <SimpleIconButton
379
- onClick={(e) => {
380
- e.stopPropagation();
381
- handleCloseAgent(agent.id, agent.name);
382
- }}
383
- icon={<X className="size-3" strokeWidth={1.5} />}
384
- label="Close Agent"
385
- className="text-gray-600 opacity-60 hover:text-gray-800 hover:opacity-100"
386
- />
387
- <SimpleIconButton
388
- onClick={(e) =>
389
- handleDeleteAgent(agent.id, agent.name, e)
390
- }
391
- icon={
392
- <Trash className="size-3" strokeWidth={1.5} />
393
- }
394
- label="Delete Agent"
395
- className="text-red-600 opacity-60 hover:text-red-700 hover:opacity-100"
396
- />
397
- </div>
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>
398
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
+ )}
399
452
  </div>
400
- );
401
- })}
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>
402
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>
403
499
  </div>
404
- ))}
500
+ )}
405
501
  </div>
406
502
  )}
407
503
  </div>
408
504
  </div>
409
505
  );
410
506
  }
411
-
@@ -332,10 +332,11 @@ export const Agents = React.memo(function Agents({
332
332
  return [...prevAgents, newAgent];
333
333
  }
334
334
  });
335
- } else if (message.type === "agent:name:updated") {
336
- const { agentId, agentName } = message.payload || {};
337
- if (!agentId || !agentName) return;
338
- // Update the agent name in the tabs list
335
+ } else if (message.type === "agent:info:updated") {
336
+ const { agentId, agentName, agentDescription } =
337
+ message.payload || {};
338
+ if (!agentId) return;
339
+ // Update the agent name and/or description in the tabs list
339
340
  setAgents((prevAgents) => {
340
341
  const existingIndex = prevAgents.findIndex((a) => a.id === agentId);
341
342
  if (existingIndex === -1) return prevAgents;
@@ -343,7 +344,10 @@ export const Agents = React.memo(function Agents({
343
344
  const existingAgent = updatedAgents[existingIndex]!;
344
345
  updatedAgents[existingIndex] = {
345
346
  ...existingAgent,
346
- name: agentName,
347
+ ...(agentName !== undefined && { name: agentName }),
348
+ ...(agentDescription !== undefined && {
349
+ description: agentDescription,
350
+ }),
347
351
  updatedDate: new Date().toISOString(),
348
352
  };
349
353
  return updatedAgents;
@@ -457,8 +461,14 @@ export const Agents = React.memo(function Agents({
457
461
 
458
462
  setLoadingAgents(true);
459
463
 
460
- // Load active agents
461
- const activeAgentsResult = await getActiveAgents();
464
+ // Load active agents (exclude shared agents for the agent panel)
465
+ const activeAgentsResponse = await getActiveAgents({
466
+ limit: 1000,
467
+ includeShared: false, // Agent panel only shows user's own agents
468
+ includeOwned: true,
469
+ });
470
+
471
+ const activeAgentsResult = activeAgentsResponse.agents;
462
472
 
463
473
  setAgents(activeAgentsResult);
464
474
 
@@ -21,7 +21,12 @@ export function useAgentStatus(): AgentStatusSummary {
21
21
 
22
22
  const fetchAgentStatus = useCallback(async () => {
23
23
  try {
24
- const activeAgents = await getActiveAgents();
24
+ const response = await getActiveAgents({
25
+ limit: 1000,
26
+ includeShared: false, // Only show user's own agents in status
27
+ includeOwned: true,
28
+ });
29
+ const activeAgents = response.agents;
25
30
  // Filter out completed, error, and closed agents to match WebSocket behavior
26
31
  // Note: Backend sends status as both enum numbers (0-7) and strings
27
32
  // Enum: New=0, Running=1, WaitingForApproval=2, Completed=3, Error=4, Closed=5, Idle=6, CostLimitReached=7