apteva 0.4.3 → 0.4.5
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/App.y11xqt9m.js +227 -0
- package/dist/index.html +1 -1
- package/dist/styles.css +1 -1
- package/package.json +1 -1
- package/src/db.ts +93 -19
- package/src/integrations/agentdojo.ts +350 -0
- package/src/openapi.ts +195 -0
- package/src/providers.ts +78 -7
- package/src/routes/api/agent-utils.ts +638 -0
- package/src/routes/api/agents.ts +743 -0
- package/src/routes/api/helpers.ts +12 -0
- package/src/routes/api/integrations.ts +608 -0
- package/src/routes/api/mcp.ts +377 -0
- package/src/routes/api/meta-agent.ts +145 -0
- package/src/routes/api/projects.ts +95 -0
- package/src/routes/api/providers.ts +269 -0
- package/src/routes/api/skills.ts +538 -0
- package/src/routes/api/system.ts +215 -0
- package/src/routes/api/telemetry.ts +142 -0
- package/src/routes/api/users.ts +148 -0
- package/src/routes/api.ts +32 -3474
- package/src/server.ts +1 -1
- package/src/web/components/api/ApiDocsPage.tsx +259 -0
- package/src/web/components/mcp/IntegrationsPanel.tsx +15 -8
- package/src/web/components/mcp/McpPage.tsx +458 -174
- package/src/web/components/settings/SettingsPage.tsx +275 -36
- package/src/web/components/skills/SkillsPage.tsx +330 -1
- package/src/web/components/tasks/TasksPage.tsx +187 -58
- package/src/web/context/TelemetryContext.tsx +14 -1
- package/src/web/hooks/useAgents.ts +9 -0
- package/src/web/types.ts +22 -4
- package/dist/App.mbp9atpm.js +0 -227
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import React, { useState, useEffect, useCallback } from "react";
|
|
1
|
+
import React, { useState, useEffect, useCallback, useRef } from "react";
|
|
2
2
|
import { TasksIcon, CloseIcon } from "../common/Icons";
|
|
3
3
|
import { useAuth } from "../../context";
|
|
4
|
-
import
|
|
4
|
+
import { useTelemetry } from "../../context/TelemetryContext";
|
|
5
|
+
import type { Task, TaskTrajectoryStep, ToolUseBlock, ToolResultBlock } from "../../types";
|
|
5
6
|
|
|
6
7
|
interface TasksPageProps {
|
|
7
8
|
onSelectAgent?: (agentId: string) => void;
|
|
@@ -13,6 +14,11 @@ export function TasksPage({ onSelectAgent }: TasksPageProps) {
|
|
|
13
14
|
const [loading, setLoading] = useState(true);
|
|
14
15
|
const [filter, setFilter] = useState<string>("all");
|
|
15
16
|
const [selectedTask, setSelectedTask] = useState<Task | null>(null);
|
|
17
|
+
const [loadingTask, setLoadingTask] = useState(false);
|
|
18
|
+
const lastProcessedEventRef = useRef<string | null>(null);
|
|
19
|
+
|
|
20
|
+
// Subscribe to task telemetry events for real-time updates
|
|
21
|
+
const { events: taskEvents } = useTelemetry({ category: "TASK" });
|
|
16
22
|
|
|
17
23
|
const fetchTasks = useCallback(async () => {
|
|
18
24
|
try {
|
|
@@ -26,13 +32,56 @@ export function TasksPage({ onSelectAgent }: TasksPageProps) {
|
|
|
26
32
|
}
|
|
27
33
|
}, [authFetch, filter]);
|
|
28
34
|
|
|
35
|
+
// Initial fetch
|
|
29
36
|
useEffect(() => {
|
|
30
37
|
fetchTasks();
|
|
31
|
-
// Refresh every 10 seconds
|
|
32
|
-
const interval = setInterval(fetchTasks, 10000);
|
|
33
|
-
return () => clearInterval(interval);
|
|
34
38
|
}, [fetchTasks]);
|
|
35
39
|
|
|
40
|
+
// Handle real-time task events from telemetry - use as trigger to refetch
|
|
41
|
+
// since telemetry data is incomplete (missing id, agentId, status, etc.)
|
|
42
|
+
useEffect(() => {
|
|
43
|
+
if (!taskEvents.length) return;
|
|
44
|
+
|
|
45
|
+
const latestEvent = taskEvents[0];
|
|
46
|
+
if (!latestEvent || latestEvent.id === lastProcessedEventRef.current) return;
|
|
47
|
+
|
|
48
|
+
// Only react to task mutation events
|
|
49
|
+
const eventType = latestEvent.type;
|
|
50
|
+
if (eventType === "task_created" || eventType === "task_updated" || eventType === "task_deleted") {
|
|
51
|
+
lastProcessedEventRef.current = latestEvent.id;
|
|
52
|
+
console.log("[TasksPage] Telemetry event:", eventType);
|
|
53
|
+
// Refetch to get complete task data
|
|
54
|
+
fetchTasks();
|
|
55
|
+
}
|
|
56
|
+
}, [taskEvents, fetchTasks]);
|
|
57
|
+
|
|
58
|
+
// Fetch full task details (including trajectory) when selecting a task
|
|
59
|
+
const selectTask = useCallback(async (task: Task) => {
|
|
60
|
+
// Set task immediately for quick feedback
|
|
61
|
+
setSelectedTask(task);
|
|
62
|
+
setLoadingTask(true);
|
|
63
|
+
|
|
64
|
+
try {
|
|
65
|
+
const res = await authFetch(`/api/tasks/${task.agentId}/${task.id}`);
|
|
66
|
+
console.log("[TasksPage] Fetch task response status:", res.status);
|
|
67
|
+
if (res.ok) {
|
|
68
|
+
const data = await res.json();
|
|
69
|
+
console.log("[TasksPage] Task data:", data);
|
|
70
|
+
console.log("[TasksPage] Has trajectory:", !!data.task?.trajectory, "Length:", data.task?.trajectory?.length);
|
|
71
|
+
if (data.task) {
|
|
72
|
+
// Merge with agentId/agentName since API might not include them
|
|
73
|
+
setSelectedTask({ ...data.task, agentId: task.agentId, agentName: task.agentName });
|
|
74
|
+
}
|
|
75
|
+
} else {
|
|
76
|
+
console.error("[TasksPage] Failed to fetch task:", res.status, await res.text());
|
|
77
|
+
}
|
|
78
|
+
} catch (e) {
|
|
79
|
+
console.error("Failed to fetch task details:", e);
|
|
80
|
+
} finally {
|
|
81
|
+
setLoadingTask(false);
|
|
82
|
+
}
|
|
83
|
+
}, [authFetch]);
|
|
84
|
+
|
|
36
85
|
const statusColors: Record<string, string> = {
|
|
37
86
|
pending: "bg-yellow-500/20 text-yellow-400",
|
|
38
87
|
running: "bg-blue-500/20 text-blue-400",
|
|
@@ -93,7 +142,7 @@ export function TasksPage({ onSelectAgent }: TasksPageProps) {
|
|
|
93
142
|
{tasks.map(task => (
|
|
94
143
|
<div
|
|
95
144
|
key={`${task.agentId}-${task.id}`}
|
|
96
|
-
onClick={() =>
|
|
145
|
+
onClick={() => selectTask(task)}
|
|
97
146
|
className={`bg-[#111] border rounded-lg p-4 cursor-pointer transition ${
|
|
98
147
|
selectedTask?.id === task.id && selectedTask?.agentId === task.agentId
|
|
99
148
|
? "border-[#f97316]"
|
|
@@ -143,6 +192,7 @@ export function TasksPage({ onSelectAgent }: TasksPageProps) {
|
|
|
143
192
|
statusColors={statusColors}
|
|
144
193
|
onClose={() => setSelectedTask(null)}
|
|
145
194
|
onSelectAgent={onSelectAgent}
|
|
195
|
+
loading={loadingTask}
|
|
146
196
|
/>
|
|
147
197
|
)}
|
|
148
198
|
</div>
|
|
@@ -154,9 +204,10 @@ interface TaskDetailPanelProps {
|
|
|
154
204
|
statusColors: Record<string, string>;
|
|
155
205
|
onClose: () => void;
|
|
156
206
|
onSelectAgent?: (agentId: string) => void;
|
|
207
|
+
loading?: boolean;
|
|
157
208
|
}
|
|
158
209
|
|
|
159
|
-
function TaskDetailPanel({ task, statusColors, onClose, onSelectAgent }: TaskDetailPanelProps) {
|
|
210
|
+
function TaskDetailPanel({ task, statusColors, onClose, onSelectAgent, loading }: TaskDetailPanelProps) {
|
|
160
211
|
return (
|
|
161
212
|
<div className="w-full md:w-1/2 lg:w-1/3 border-l border-[#1a1a1a] bg-[#0a0a0a] flex flex-col overflow-hidden">
|
|
162
213
|
{/* Header */}
|
|
@@ -249,27 +300,33 @@ function TaskDetailPanel({ task, statusColors, onClose, onSelectAgent }: TaskDet
|
|
|
249
300
|
|
|
250
301
|
{/* Error */}
|
|
251
302
|
{task.status === "failed" && task.error && (
|
|
252
|
-
<div>
|
|
303
|
+
<div className="min-w-0">
|
|
253
304
|
<h4 className="text-xs text-red-400 uppercase tracking-wider mb-1">Error</h4>
|
|
254
|
-
<div className="bg-red-500/10 border border-red-500/20 rounded p-3">
|
|
255
|
-
<
|
|
305
|
+
<div className="bg-red-500/10 border border-red-500/20 rounded p-3 overflow-x-auto">
|
|
306
|
+
<pre className="text-sm text-red-400 whitespace-pre-wrap break-words">{task.error}</pre>
|
|
256
307
|
</div>
|
|
257
308
|
</div>
|
|
258
309
|
)}
|
|
259
310
|
|
|
260
311
|
{/* Result */}
|
|
261
312
|
{task.status === "completed" && task.result && (
|
|
262
|
-
<div>
|
|
313
|
+
<div className="min-w-0">
|
|
263
314
|
<h4 className="text-xs text-green-400 uppercase tracking-wider mb-1">Result</h4>
|
|
264
|
-
<div className="bg-green-500/10 border border-green-500/20 rounded p-3">
|
|
265
|
-
<
|
|
315
|
+
<div className="bg-green-500/10 border border-green-500/20 rounded p-3 overflow-x-auto">
|
|
316
|
+
<pre className="text-sm text-green-400 whitespace-pre-wrap break-words">
|
|
266
317
|
{typeof task.result === "string" ? task.result : JSON.stringify(task.result, null, 2)}
|
|
267
|
-
</
|
|
318
|
+
</pre>
|
|
268
319
|
</div>
|
|
269
320
|
</div>
|
|
270
321
|
)}
|
|
271
322
|
|
|
272
323
|
{/* Trajectory */}
|
|
324
|
+
{loading && !task.trajectory && (
|
|
325
|
+
<div>
|
|
326
|
+
<h4 className="text-xs text-[#666] uppercase tracking-wider mb-2">Trajectory</h4>
|
|
327
|
+
<div className="text-sm text-[#555]">Loading trajectory...</div>
|
|
328
|
+
</div>
|
|
329
|
+
)}
|
|
273
330
|
{task.trajectory && task.trajectory.length > 0 && (
|
|
274
331
|
<div>
|
|
275
332
|
<h4 className="text-xs text-[#666] uppercase tracking-wider mb-2">
|
|
@@ -284,70 +341,142 @@ function TaskDetailPanel({ task, statusColors, onClose, onSelectAgent }: TaskDet
|
|
|
284
341
|
}
|
|
285
342
|
|
|
286
343
|
function TrajectoryView({ trajectory }: { trajectory: TaskTrajectoryStep[] }) {
|
|
287
|
-
const [expanded, setExpanded] = useState<Set<
|
|
344
|
+
const [expanded, setExpanded] = useState<Set<string>>(new Set());
|
|
288
345
|
|
|
289
|
-
const toggleStep = (
|
|
346
|
+
const toggleStep = (id: string) => {
|
|
290
347
|
setExpanded(prev => {
|
|
291
348
|
const next = new Set(prev);
|
|
292
|
-
if (next.has(
|
|
293
|
-
next.delete(
|
|
349
|
+
if (next.has(id)) {
|
|
350
|
+
next.delete(id);
|
|
294
351
|
} else {
|
|
295
|
-
next.add(
|
|
352
|
+
next.add(id);
|
|
296
353
|
}
|
|
297
354
|
return next;
|
|
298
355
|
});
|
|
299
356
|
};
|
|
300
357
|
|
|
301
|
-
const
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
observation: { bg: "bg-green-500/10", text: "text-green-400", icon: "👁" },
|
|
305
|
-
tool_call: { bg: "bg-orange-500/10", text: "text-orange-400", icon: "🔧" },
|
|
306
|
-
tool_result: { bg: "bg-teal-500/10", text: "text-teal-400", icon: "📋" },
|
|
307
|
-
message: { bg: "bg-gray-500/10", text: "text-gray-400", icon: "💬" },
|
|
358
|
+
const roleStyles = {
|
|
359
|
+
user: { bg: "bg-blue-500/10", text: "text-blue-400", icon: "👤", label: "User" },
|
|
360
|
+
assistant: { bg: "bg-purple-500/10", text: "text-purple-400", icon: "🤖", label: "Assistant" },
|
|
308
361
|
};
|
|
309
362
|
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
const colors = stepColors[step.type] || stepColors.message;
|
|
314
|
-
const isExpanded = expanded.has(index);
|
|
315
|
-
const isLong = step.content.length > 150;
|
|
363
|
+
// Render content which can be string or array of blocks
|
|
364
|
+
const renderContent = (step: TaskTrajectoryStep) => {
|
|
365
|
+
const content = step.content;
|
|
316
366
|
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
367
|
+
// String content (text message)
|
|
368
|
+
if (typeof content === "string") {
|
|
369
|
+
const isLong = content.length > 200;
|
|
370
|
+
const isExpanded = expanded.has(step.id);
|
|
371
|
+
|
|
372
|
+
return (
|
|
373
|
+
<div>
|
|
374
|
+
<p className={`text-sm text-[#ccc] whitespace-pre-wrap break-words ${!isExpanded && isLong ? 'line-clamp-4' : ''}`}>
|
|
375
|
+
{content}
|
|
376
|
+
</p>
|
|
377
|
+
{isLong && (
|
|
322
378
|
<button
|
|
323
|
-
onClick={() =>
|
|
324
|
-
className=
|
|
379
|
+
onClick={() => toggleStep(step.id)}
|
|
380
|
+
className="text-xs text-[#666] hover:text-[#888] mt-1"
|
|
325
381
|
>
|
|
326
|
-
|
|
327
|
-
|
|
382
|
+
{isExpanded ? "Show less" : "Show more..."}
|
|
383
|
+
</button>
|
|
384
|
+
)}
|
|
385
|
+
</div>
|
|
386
|
+
);
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
// Array content (tool_use or tool_result blocks)
|
|
390
|
+
return (
|
|
391
|
+
<div className="space-y-2">
|
|
392
|
+
{content.map((block, idx) => {
|
|
393
|
+
if (block.type === "tool_use") {
|
|
394
|
+
const inputStr = JSON.stringify(block.input, null, 2);
|
|
395
|
+
const isLong = inputStr.length > 150;
|
|
396
|
+
const blockId = `${step.id}-${idx}`;
|
|
397
|
+
const isExpanded = expanded.has(blockId);
|
|
398
|
+
|
|
399
|
+
return (
|
|
400
|
+
<div key={idx} className="bg-orange-500/10 border border-orange-500/20 rounded p-2">
|
|
328
401
|
<div className="flex items-center gap-2 mb-1">
|
|
329
|
-
<span className=
|
|
330
|
-
|
|
331
|
-
</span>
|
|
332
|
-
{step.tool && (
|
|
333
|
-
<span className="text-xs text-[#666]">· {step.tool}</span>
|
|
334
|
-
)}
|
|
335
|
-
{step.timestamp && (
|
|
336
|
-
<span className="text-xs text-[#555]">
|
|
337
|
-
· {new Date(step.timestamp).toLocaleTimeString()}
|
|
338
|
-
</span>
|
|
339
|
-
)}
|
|
402
|
+
<span className="text-orange-400">🔧</span>
|
|
403
|
+
<span className="text-xs font-medium text-orange-400">Tool Call</span>
|
|
404
|
+
<span className="text-xs text-[#888]">{block.name}</span>
|
|
340
405
|
</div>
|
|
341
|
-
<
|
|
342
|
-
{
|
|
343
|
-
</
|
|
406
|
+
<pre className={`text-xs text-[#888] overflow-x-auto ${!isExpanded && isLong ? 'line-clamp-3' : ''}`}>
|
|
407
|
+
{inputStr}
|
|
408
|
+
</pre>
|
|
344
409
|
{isLong && (
|
|
345
|
-
<
|
|
346
|
-
{
|
|
410
|
+
<button
|
|
411
|
+
onClick={() => toggleStep(blockId)}
|
|
412
|
+
className="text-xs text-[#666] hover:text-[#888] mt-1"
|
|
413
|
+
>
|
|
414
|
+
{isExpanded ? "Show less" : "Show more..."}
|
|
415
|
+
</button>
|
|
416
|
+
)}
|
|
417
|
+
</div>
|
|
418
|
+
);
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
if (block.type === "tool_result") {
|
|
422
|
+
const isError = block.is_error;
|
|
423
|
+
const blockId = `${step.id}-${idx}`;
|
|
424
|
+
const isExpanded = expanded.has(blockId);
|
|
425
|
+
const isLong = block.content.length > 150;
|
|
426
|
+
|
|
427
|
+
return (
|
|
428
|
+
<div
|
|
429
|
+
key={idx}
|
|
430
|
+
className={`${isError ? 'bg-red-500/10 border-red-500/20' : 'bg-teal-500/10 border-teal-500/20'} border rounded p-2`}
|
|
431
|
+
>
|
|
432
|
+
<div className="flex items-center gap-2 mb-1">
|
|
433
|
+
<span>{isError ? "❌" : "📋"}</span>
|
|
434
|
+
<span className={`text-xs font-medium ${isError ? 'text-red-400' : 'text-teal-400'}`}>
|
|
435
|
+
Tool Result
|
|
347
436
|
</span>
|
|
437
|
+
</div>
|
|
438
|
+
<pre className={`text-xs text-[#888] overflow-x-auto whitespace-pre-wrap break-words ${!isExpanded && isLong ? 'line-clamp-3' : ''}`}>
|
|
439
|
+
{block.content}
|
|
440
|
+
</pre>
|
|
441
|
+
{isLong && (
|
|
442
|
+
<button
|
|
443
|
+
onClick={() => toggleStep(blockId)}
|
|
444
|
+
className="text-xs text-[#666] hover:text-[#888] mt-1"
|
|
445
|
+
>
|
|
446
|
+
{isExpanded ? "Show less" : "Show more..."}
|
|
447
|
+
</button>
|
|
348
448
|
)}
|
|
349
449
|
</div>
|
|
350
|
-
|
|
450
|
+
);
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
return null;
|
|
454
|
+
})}
|
|
455
|
+
</div>
|
|
456
|
+
);
|
|
457
|
+
};
|
|
458
|
+
|
|
459
|
+
return (
|
|
460
|
+
<div className="space-y-2">
|
|
461
|
+
{trajectory.map((step) => {
|
|
462
|
+
const style = roleStyles[step.role] || roleStyles.assistant;
|
|
463
|
+
|
|
464
|
+
return (
|
|
465
|
+
<div
|
|
466
|
+
key={step.id}
|
|
467
|
+
className={`${style.bg} border border-[#1a1a1a] rounded overflow-hidden p-3`}
|
|
468
|
+
>
|
|
469
|
+
<div className="flex items-center gap-2 mb-2">
|
|
470
|
+
<span>{style.icon}</span>
|
|
471
|
+
<span className={`text-xs font-medium ${style.text}`}>{style.label}</span>
|
|
472
|
+
{step.model && (
|
|
473
|
+
<span className="text-xs text-[#555]">· {step.model}</span>
|
|
474
|
+
)}
|
|
475
|
+
<span className="text-xs text-[#555]">
|
|
476
|
+
· {new Date(step.created_at).toLocaleTimeString()}
|
|
477
|
+
</span>
|
|
478
|
+
</div>
|
|
479
|
+
{renderContent(step)}
|
|
351
480
|
</div>
|
|
352
481
|
);
|
|
353
482
|
})}
|
|
@@ -19,6 +19,7 @@ interface TelemetryContextValue {
|
|
|
19
19
|
events: TelemetryEvent[];
|
|
20
20
|
lastActivityByAgent: Record<string, { timestamp: string; category: string; type: string }>;
|
|
21
21
|
activeAgents: Record<string, { type: string; expiresAt: number }>;
|
|
22
|
+
statusChangeCounter: number;
|
|
22
23
|
clearEvents: () => void;
|
|
23
24
|
}
|
|
24
25
|
|
|
@@ -31,6 +32,7 @@ export function TelemetryProvider({ children }: { children: React.ReactNode }) {
|
|
|
31
32
|
const [events, setEvents] = useState<TelemetryEvent[]>([]);
|
|
32
33
|
const [lastActivityByAgent, setLastActivityByAgent] = useState<Record<string, { timestamp: string; category: string; type: string }>>({});
|
|
33
34
|
const [activeAgents, setActiveAgents] = useState<Record<string, { type: string; expiresAt: number }>>({});
|
|
35
|
+
const [statusChangeCounter, setStatusChangeCounter] = useState(0);
|
|
34
36
|
const eventSourceRef = useRef<EventSource | null>(null);
|
|
35
37
|
const reconnectTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
|
36
38
|
|
|
@@ -110,6 +112,11 @@ export function TelemetryProvider({ children }: { children: React.ReactNode }) {
|
|
|
110
112
|
}
|
|
111
113
|
return updated;
|
|
112
114
|
});
|
|
115
|
+
|
|
116
|
+
// Detect agent status change events (system-emitted)
|
|
117
|
+
if (data.some((e: TelemetryEvent) => e.category === "system" && (e.type === "agent_started" || e.type === "agent_stopped"))) {
|
|
118
|
+
setStatusChangeCounter(c => c + 1);
|
|
119
|
+
}
|
|
113
120
|
}
|
|
114
121
|
} catch {
|
|
115
122
|
// Ignore parse errors (likely keepalive or empty message)
|
|
@@ -155,7 +162,7 @@ export function TelemetryProvider({ children }: { children: React.ReactNode }) {
|
|
|
155
162
|
}, []);
|
|
156
163
|
|
|
157
164
|
return (
|
|
158
|
-
<TelemetryContext.Provider value={{ connected, events, lastActivityByAgent, activeAgents, clearEvents }}>
|
|
165
|
+
<TelemetryContext.Provider value={{ connected, events, lastActivityByAgent, activeAgents, statusChangeCounter, clearEvents }}>
|
|
159
166
|
{children}
|
|
160
167
|
</TelemetryContext.Provider>
|
|
161
168
|
);
|
|
@@ -222,3 +229,9 @@ export function useAgentActivity(agentId: string) {
|
|
|
222
229
|
type: activity?.type,
|
|
223
230
|
};
|
|
224
231
|
}
|
|
232
|
+
|
|
233
|
+
// Hook to trigger agent list refetch on status changes (started/stopped/crashed)
|
|
234
|
+
export function useAgentStatusChange(): number {
|
|
235
|
+
const { statusChangeCounter } = useTelemetryContext();
|
|
236
|
+
return statusChangeCounter;
|
|
237
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { useState, useEffect, useCallback } from "react";
|
|
2
2
|
import type { Agent, AgentFeatures } from "../types";
|
|
3
3
|
import { useAuth } from "../context";
|
|
4
|
+
import { useAgentStatusChange } from "../context/TelemetryContext";
|
|
4
5
|
|
|
5
6
|
export function useAgents(enabled: boolean) {
|
|
6
7
|
const { accessToken } = useAuth();
|
|
@@ -22,6 +23,14 @@ export function useAgents(enabled: boolean) {
|
|
|
22
23
|
setLoading(false);
|
|
23
24
|
}, [getHeaders]);
|
|
24
25
|
|
|
26
|
+
// Auto-refetch when agents start/stop/crash (via SSE telemetry)
|
|
27
|
+
const statusChangeCounter = useAgentStatusChange();
|
|
28
|
+
useEffect(() => {
|
|
29
|
+
if (enabled && statusChangeCounter > 0) {
|
|
30
|
+
fetchAgents();
|
|
31
|
+
}
|
|
32
|
+
}, [enabled, statusChangeCounter, fetchAgents]);
|
|
33
|
+
|
|
25
34
|
useEffect(() => {
|
|
26
35
|
if (enabled) {
|
|
27
36
|
fetchAgents();
|
package/src/web/types.ts
CHANGED
|
@@ -145,11 +145,29 @@ export interface OnboardingStatus {
|
|
|
145
145
|
|
|
146
146
|
export type Route = "dashboard" | "agents" | "tasks" | "mcp" | "skills" | "telemetry" | "settings" | "api";
|
|
147
147
|
|
|
148
|
-
|
|
149
|
-
|
|
148
|
+
// Tool use content block in trajectory
|
|
149
|
+
export interface ToolUseBlock {
|
|
150
|
+
type: "tool_use";
|
|
151
|
+
id: string;
|
|
152
|
+
name: string;
|
|
153
|
+
input: Record<string, unknown>;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Tool result content block in trajectory
|
|
157
|
+
export interface ToolResultBlock {
|
|
158
|
+
type: "tool_result";
|
|
159
|
+
tool_use_id: string;
|
|
150
160
|
content: string;
|
|
151
|
-
|
|
152
|
-
|
|
161
|
+
is_error?: boolean;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Trajectory step from the agent API (chat message format)
|
|
165
|
+
export interface TaskTrajectoryStep {
|
|
166
|
+
id: string;
|
|
167
|
+
role: "user" | "assistant";
|
|
168
|
+
content: string | Array<ToolUseBlock | ToolResultBlock>;
|
|
169
|
+
created_at: string;
|
|
170
|
+
model?: string;
|
|
153
171
|
}
|
|
154
172
|
|
|
155
173
|
export interface Task {
|