apteva 0.4.1 โ†’ 0.4.3

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.
@@ -1,7 +1,7 @@
1
1
  import React, { useState, useEffect, useCallback } from "react";
2
- import { TasksIcon } from "../common/Icons";
2
+ import { TasksIcon, CloseIcon } from "../common/Icons";
3
3
  import { useAuth } from "../../context";
4
- import type { Task } from "../../types";
4
+ import type { Task, TaskTrajectoryStep } from "../../types";
5
5
 
6
6
  interface TasksPageProps {
7
7
  onSelectAgent?: (agentId: string) => void;
@@ -12,6 +12,7 @@ export function TasksPage({ onSelectAgent }: TasksPageProps) {
12
12
  const [tasks, setTasks] = useState<Task[]>([]);
13
13
  const [loading, setLoading] = useState(true);
14
14
  const [filter, setFilter] = useState<string>("all");
15
+ const [selectedTask, setSelectedTask] = useState<Task | null>(null);
15
16
 
16
17
  const fetchTasks = useCallback(async () => {
17
18
  try {
@@ -49,83 +50,307 @@ export function TasksPage({ onSelectAgent }: TasksPageProps) {
49
50
  ];
50
51
 
51
52
  return (
52
- <div className="flex-1 p-4 md:p-6 overflow-auto">
53
- <div className="max-w-4xl">
54
- <div className="mb-6">
55
- <div className="mb-4">
56
- <h1 className="text-xl md:text-2xl font-semibold mb-1">Tasks</h1>
57
- <p className="text-sm text-[#666]">
58
- View tasks from all running agents
59
- </p>
53
+ <div className="flex-1 flex overflow-hidden">
54
+ {/* Task List */}
55
+ <div className={`flex-1 p-4 md:p-6 overflow-auto ${selectedTask ? 'hidden md:block md:w-1/2 lg:w-2/3' : ''}`}>
56
+ <div className="max-w-4xl">
57
+ <div className="mb-6">
58
+ <div className="mb-4">
59
+ <h1 className="text-xl md:text-2xl font-semibold mb-1">Tasks</h1>
60
+ <p className="text-sm text-[#666]">
61
+ View tasks from all running agents
62
+ </p>
63
+ </div>
64
+ <div className="flex gap-2 overflow-x-auto scrollbar-hide pb-1">
65
+ {filterOptions.map(opt => (
66
+ <button
67
+ key={opt.value}
68
+ onClick={() => setFilter(opt.value)}
69
+ className={`px-3 py-1.5 rounded text-sm transition whitespace-nowrap ${
70
+ filter === opt.value
71
+ ? "bg-[#f97316] text-black"
72
+ : "bg-[#1a1a1a] hover:bg-[#222]"
73
+ }`}
74
+ >
75
+ {opt.label}
76
+ </button>
77
+ ))}
78
+ </div>
60
79
  </div>
61
- <div className="flex gap-2 overflow-x-auto scrollbar-hide pb-1">
62
- {filterOptions.map(opt => (
63
- <button
64
- key={opt.value}
65
- onClick={() => setFilter(opt.value)}
66
- className={`px-3 py-1.5 rounded text-sm transition whitespace-nowrap ${
67
- filter === opt.value
68
- ? "bg-[#f97316] text-black"
69
- : "bg-[#1a1a1a] hover:bg-[#222]"
70
- }`}
71
- >
72
- {opt.label}
73
- </button>
74
- ))}
75
- </div>
76
- </div>
77
80
 
78
- {loading ? (
79
- <div className="text-center py-12 text-[#666]">Loading tasks...</div>
80
- ) : tasks.length === 0 ? (
81
- <div className="text-center py-12">
82
- <TasksIcon className="w-12 h-12 mx-auto mb-4 text-[#333]" />
83
- <p className="text-[#666]">No tasks found</p>
84
- <p className="text-sm text-[#444] mt-1">
85
- Tasks will appear here when agents create them
86
- </p>
87
- </div>
88
- ) : (
89
- <div className="space-y-3">
90
- {tasks.map(task => (
91
- <div
92
- key={`${task.agentId}-${task.id}`}
93
- className="bg-[#111] border border-[#1a1a1a] rounded-lg p-4 hover:border-[#333] transition"
94
- >
95
- <div className="flex items-start justify-between mb-2">
96
- <div className="flex-1">
97
- <h3 className="font-medium">{task.title}</h3>
98
- <p className="text-sm text-[#666]">
99
- {task.agentName}
100
- {task.execute_at && (
101
- <span className="ml-2">
102
- ยท Scheduled: {new Date(task.execute_at).toLocaleString()}
103
- </span>
104
- )}
81
+ {loading ? (
82
+ <div className="text-center py-12 text-[#666]">Loading tasks...</div>
83
+ ) : tasks.length === 0 ? (
84
+ <div className="text-center py-12">
85
+ <TasksIcon className="w-12 h-12 mx-auto mb-4 text-[#333]" />
86
+ <p className="text-[#666]">No tasks found</p>
87
+ <p className="text-sm text-[#444] mt-1">
88
+ Tasks will appear here when agents create them
89
+ </p>
90
+ </div>
91
+ ) : (
92
+ <div className="space-y-3">
93
+ {tasks.map(task => (
94
+ <div
95
+ key={`${task.agentId}-${task.id}`}
96
+ onClick={() => setSelectedTask(task)}
97
+ className={`bg-[#111] border rounded-lg p-4 cursor-pointer transition ${
98
+ selectedTask?.id === task.id && selectedTask?.agentId === task.agentId
99
+ ? "border-[#f97316]"
100
+ : "border-[#1a1a1a] hover:border-[#333]"
101
+ }`}
102
+ >
103
+ <div className="flex items-start justify-between mb-2">
104
+ <div className="flex-1">
105
+ <h3 className="font-medium">{task.title}</h3>
106
+ <p className="text-sm text-[#666]">
107
+ {task.agentName}
108
+ {task.execute_at && (
109
+ <span className="ml-2">
110
+ ยท Scheduled: {new Date(task.execute_at).toLocaleString()}
111
+ </span>
112
+ )}
113
+ </p>
114
+ </div>
115
+ <span className={`px-2 py-1 rounded text-xs font-medium ${statusColors[task.status] || statusColors.pending}`}>
116
+ {task.status}
117
+ </span>
118
+ </div>
119
+
120
+ {task.description && (
121
+ <p className="text-sm text-[#888] mb-2 line-clamp-2">
122
+ {task.description}
105
123
  </p>
124
+ )}
125
+
126
+ <div className="flex flex-wrap items-center gap-x-4 gap-y-1 text-xs text-[#555]">
127
+ <span>Type: {task.type}</span>
128
+ <span>Priority: {task.priority}</span>
129
+ {task.recurrence && <span>Recurrence: {task.recurrence}</span>}
130
+ <span>Created: {new Date(task.created_at).toLocaleString()}</span>
106
131
  </div>
107
- <span className={`px-2 py-1 rounded text-xs font-medium ${statusColors[task.status] || statusColors.pending}`}>
108
- {task.status}
109
- </span>
110
132
  </div>
133
+ ))}
134
+ </div>
135
+ )}
136
+ </div>
137
+ </div>
111
138
 
112
- {task.description && (
113
- <p className="text-sm text-[#888] mb-2 line-clamp-2">
114
- {task.description}
115
- </p>
116
- )}
139
+ {/* Task Detail Panel */}
140
+ {selectedTask && (
141
+ <TaskDetailPanel
142
+ task={selectedTask}
143
+ statusColors={statusColors}
144
+ onClose={() => setSelectedTask(null)}
145
+ onSelectAgent={onSelectAgent}
146
+ />
147
+ )}
148
+ </div>
149
+ );
150
+ }
117
151
 
118
- <div className="flex flex-wrap items-center gap-x-4 gap-y-1 text-xs text-[#555]">
119
- <span>Type: {task.type}</span>
120
- <span>Priority: {task.priority}</span>
121
- {task.recurrence && <span>Recurrence: {task.recurrence}</span>}
122
- <span>Created: {new Date(task.created_at).toLocaleString()}</span>
123
- </div>
124
- </div>
125
- ))}
152
+ interface TaskDetailPanelProps {
153
+ task: Task;
154
+ statusColors: Record<string, string>;
155
+ onClose: () => void;
156
+ onSelectAgent?: (agentId: string) => void;
157
+ }
158
+
159
+ function TaskDetailPanel({ task, statusColors, onClose, onSelectAgent }: TaskDetailPanelProps) {
160
+ return (
161
+ <div className="w-full md:w-1/2 lg:w-1/3 border-l border-[#1a1a1a] bg-[#0a0a0a] flex flex-col overflow-hidden">
162
+ {/* Header */}
163
+ <div className="flex items-center justify-between p-4 border-b border-[#1a1a1a]">
164
+ <h2 className="font-medium truncate pr-2">Task Details</h2>
165
+ <button onClick={onClose} className="text-[#666] hover:text-[#e0e0e0] transition">
166
+ <CloseIcon />
167
+ </button>
168
+ </div>
169
+
170
+ {/* Content */}
171
+ <div className="flex-1 overflow-auto p-4 space-y-4">
172
+ {/* Title & Status */}
173
+ <div>
174
+ <div className="flex items-start justify-between gap-2 mb-2">
175
+ <h3 className="text-lg font-medium">{task.title}</h3>
176
+ <span className={`px-2 py-1 rounded text-xs font-medium flex-shrink-0 ${statusColors[task.status]}`}>
177
+ {task.status}
178
+ </span>
179
+ </div>
180
+ <button
181
+ onClick={() => onSelectAgent?.(task.agentId)}
182
+ className="text-sm text-[#f97316] hover:underline"
183
+ >
184
+ {task.agentName}
185
+ </button>
186
+ </div>
187
+
188
+ {/* Description */}
189
+ {task.description && (
190
+ <div>
191
+ <h4 className="text-xs text-[#666] uppercase tracking-wider mb-1">Description</h4>
192
+ <p className="text-sm text-[#888] whitespace-pre-wrap">{task.description}</p>
193
+ </div>
194
+ )}
195
+
196
+ {/* Metadata */}
197
+ <div className="grid grid-cols-2 gap-3 text-sm">
198
+ <div>
199
+ <span className="text-[#666]">Type</span>
200
+ <p className="capitalize">{task.type}</p>
201
+ </div>
202
+ <div>
203
+ <span className="text-[#666]">Priority</span>
204
+ <p>{task.priority}</p>
205
+ </div>
206
+ <div>
207
+ <span className="text-[#666]">Source</span>
208
+ <p className="capitalize">{task.source}</p>
209
+ </div>
210
+ {task.recurrence && (
211
+ <div>
212
+ <span className="text-[#666]">Recurrence</span>
213
+ <p>{task.recurrence}</p>
214
+ </div>
215
+ )}
216
+ </div>
217
+
218
+ {/* Timestamps */}
219
+ <div className="space-y-2 text-sm">
220
+ <div className="flex justify-between">
221
+ <span className="text-[#666]">Created</span>
222
+ <span>{new Date(task.created_at).toLocaleString()}</span>
223
+ </div>
224
+ {task.execute_at && (
225
+ <div className="flex justify-between">
226
+ <span className="text-[#666]">Scheduled</span>
227
+ <span>{new Date(task.execute_at).toLocaleString()}</span>
228
+ </div>
229
+ )}
230
+ {task.executed_at && (
231
+ <div className="flex justify-between">
232
+ <span className="text-[#666]">Started</span>
233
+ <span>{new Date(task.executed_at).toLocaleString()}</span>
234
+ </div>
235
+ )}
236
+ {task.completed_at && (
237
+ <div className="flex justify-between">
238
+ <span className="text-[#666]">Completed</span>
239
+ <span>{new Date(task.completed_at).toLocaleString()}</span>
240
+ </div>
241
+ )}
242
+ {task.next_run && (
243
+ <div className="flex justify-between">
244
+ <span className="text-[#666]">Next Run</span>
245
+ <span>{new Date(task.next_run).toLocaleString()}</span>
246
+ </div>
247
+ )}
248
+ </div>
249
+
250
+ {/* Error */}
251
+ {task.status === "failed" && task.error && (
252
+ <div>
253
+ <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
+ <p className="text-sm text-red-400 whitespace-pre-wrap">{task.error}</p>
256
+ </div>
257
+ </div>
258
+ )}
259
+
260
+ {/* Result */}
261
+ {task.status === "completed" && task.result && (
262
+ <div>
263
+ <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
+ <p className="text-sm text-green-400 whitespace-pre-wrap">
266
+ {typeof task.result === "string" ? task.result : JSON.stringify(task.result, null, 2)}
267
+ </p>
268
+ </div>
269
+ </div>
270
+ )}
271
+
272
+ {/* Trajectory */}
273
+ {task.trajectory && task.trajectory.length > 0 && (
274
+ <div>
275
+ <h4 className="text-xs text-[#666] uppercase tracking-wider mb-2">
276
+ Trajectory ({task.trajectory.length} steps)
277
+ </h4>
278
+ <TrajectoryView trajectory={task.trajectory} />
126
279
  </div>
127
280
  )}
128
281
  </div>
129
282
  </div>
130
283
  );
131
284
  }
285
+
286
+ function TrajectoryView({ trajectory }: { trajectory: TaskTrajectoryStep[] }) {
287
+ const [expanded, setExpanded] = useState<Set<number>>(new Set());
288
+
289
+ const toggleStep = (index: number) => {
290
+ setExpanded(prev => {
291
+ const next = new Set(prev);
292
+ if (next.has(index)) {
293
+ next.delete(index);
294
+ } else {
295
+ next.add(index);
296
+ }
297
+ return next;
298
+ });
299
+ };
300
+
301
+ const stepColors: Record<string, { bg: string; text: string; icon: string }> = {
302
+ thought: { bg: "bg-purple-500/10", text: "text-purple-400", icon: "๐Ÿ’ญ" },
303
+ action: { bg: "bg-blue-500/10", text: "text-blue-400", icon: "โšก" },
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: "๐Ÿ’ฌ" },
308
+ };
309
+
310
+ return (
311
+ <div className="space-y-2">
312
+ {trajectory.map((step, index) => {
313
+ const colors = stepColors[step.type] || stepColors.message;
314
+ const isExpanded = expanded.has(index);
315
+ const isLong = step.content.length > 150;
316
+
317
+ return (
318
+ <div
319
+ key={index}
320
+ className={`${colors.bg} border border-[#1a1a1a] rounded overflow-hidden`}
321
+ >
322
+ <button
323
+ onClick={() => isLong && toggleStep(index)}
324
+ className={`w-full p-2 text-left flex items-start gap-2 ${isLong ? 'cursor-pointer' : ''}`}
325
+ >
326
+ <span className="flex-shrink-0">{colors.icon}</span>
327
+ <div className="flex-1 min-w-0">
328
+ <div className="flex items-center gap-2 mb-1">
329
+ <span className={`text-xs font-medium ${colors.text} capitalize`}>
330
+ {step.type.replace("_", " ")}
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
+ )}
340
+ </div>
341
+ <p className={`text-sm text-[#888] whitespace-pre-wrap ${!isExpanded && isLong ? 'line-clamp-3' : ''}`}>
342
+ {step.content}
343
+ </p>
344
+ {isLong && (
345
+ <span className="text-xs text-[#666] mt-1 inline-block">
346
+ {isExpanded ? "Click to collapse" : "Click to expand..."}
347
+ </span>
348
+ )}
349
+ </div>
350
+ </button>
351
+ </div>
352
+ );
353
+ })}
354
+ </div>
355
+ );
356
+ }
package/src/web/types.ts CHANGED
@@ -145,6 +145,13 @@ export interface OnboardingStatus {
145
145
 
146
146
  export type Route = "dashboard" | "agents" | "tasks" | "mcp" | "skills" | "telemetry" | "settings" | "api";
147
147
 
148
+ export interface TaskTrajectoryStep {
149
+ type: "thought" | "action" | "observation" | "tool_call" | "tool_result" | "message";
150
+ content: string;
151
+ tool?: string;
152
+ timestamp?: string;
153
+ }
154
+
148
155
  export interface Task {
149
156
  id: string;
150
157
  title: string;
@@ -156,9 +163,12 @@ export interface Task {
156
163
  created_at: string;
157
164
  execute_at?: string;
158
165
  executed_at?: string;
166
+ completed_at?: string;
159
167
  recurrence?: string;
160
168
  next_run?: string;
161
169
  result?: any;
170
+ error?: string;
171
+ trajectory?: TaskTrajectoryStep[];
162
172
  agentId: string;
163
173
  agentName: string;
164
174
  }