@fleettools/server 0.1.1 → 0.2.0
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/package.json +6 -2
- package/tsconfig.json +7 -1
- package/dist/agent-lifecycle.js +0 -148
- package/dist/agent-spawner.js +0 -460
- package/dist/agent-validation.js +0 -111
- package/dist/index.js +0 -255
- package/dist/task-queue.js +0 -377
- package/dist/validation.js +0 -188
package/dist/task-queue.js
DELETED
|
@@ -1,377 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Task Queue for FleetTools Coordination System
|
|
3
|
-
*
|
|
4
|
-
* Manages task queuing, assignment, and completion tracking
|
|
5
|
-
* Uses SQLite for persistence with tsk_ prefixed IDs
|
|
6
|
-
*/
|
|
7
|
-
import Database from 'bun:sqlite';
|
|
8
|
-
import { randomUUID } from 'node:crypto';
|
|
9
|
-
import path from 'node:path';
|
|
10
|
-
// Using local types to avoid import issues
|
|
11
|
-
export var TaskStatus;
|
|
12
|
-
(function (TaskStatus) {
|
|
13
|
-
TaskStatus["PENDING"] = "pending";
|
|
14
|
-
TaskStatus["ASSIGNED"] = "assigned";
|
|
15
|
-
TaskStatus["IN_PROGRESS"] = "in_progress";
|
|
16
|
-
TaskStatus["COMPLETED"] = "completed";
|
|
17
|
-
TaskStatus["FAILED"] = "failed";
|
|
18
|
-
TaskStatus["CANCELLED"] = "cancelled";
|
|
19
|
-
})(TaskStatus || (TaskStatus = {}));
|
|
20
|
-
export class TaskQueue {
|
|
21
|
-
db;
|
|
22
|
-
config;
|
|
23
|
-
constructor(config = {}) {
|
|
24
|
-
this.config = {
|
|
25
|
-
maxRetries: 3,
|
|
26
|
-
retryDelay: 5000,
|
|
27
|
-
dbPath: path.join(process.cwd(), '.flightline', 'tasks.db'),
|
|
28
|
-
...config
|
|
29
|
-
};
|
|
30
|
-
this.db = new Database(this.config.dbPath);
|
|
31
|
-
this.initializeDatabase();
|
|
32
|
-
}
|
|
33
|
-
/**
|
|
34
|
-
* Initialize database schema
|
|
35
|
-
*/
|
|
36
|
-
initializeDatabase() {
|
|
37
|
-
// Create tasks table
|
|
38
|
-
this.db.exec(`
|
|
39
|
-
CREATE TABLE IF NOT EXISTS tasks (
|
|
40
|
-
id TEXT PRIMARY KEY,
|
|
41
|
-
type TEXT NOT NULL,
|
|
42
|
-
title TEXT NOT NULL,
|
|
43
|
-
description TEXT,
|
|
44
|
-
status TEXT NOT NULL DEFAULT 'pending',
|
|
45
|
-
priority TEXT NOT NULL DEFAULT 'medium',
|
|
46
|
-
assigned_to TEXT,
|
|
47
|
-
mission_id TEXT,
|
|
48
|
-
dependencies TEXT, -- JSON array
|
|
49
|
-
metadata TEXT, -- JSON object
|
|
50
|
-
created_at TEXT NOT NULL,
|
|
51
|
-
updated_at TEXT NOT NULL,
|
|
52
|
-
completed_at TEXT,
|
|
53
|
-
retry_count INTEGER DEFAULT 0,
|
|
54
|
-
last_retry_at TEXT
|
|
55
|
-
)
|
|
56
|
-
`);
|
|
57
|
-
// Create indexes for performance
|
|
58
|
-
this.db.exec(`
|
|
59
|
-
CREATE INDEX IF NOT EXISTS idx_tasks_status ON tasks(status);
|
|
60
|
-
CREATE INDEX IF NOT EXISTS idx_tasks_priority ON tasks(priority);
|
|
61
|
-
CREATE INDEX IF NOT EXISTS idx_tasks_assigned_to ON tasks(assigned_to);
|
|
62
|
-
CREATE INDEX IF NOT EXISTS idx_tasks_mission_id ON tasks(mission_id);
|
|
63
|
-
CREATE INDEX IF NOT EXISTS idx_tasks_created_at ON tasks(created_at);
|
|
64
|
-
`);
|
|
65
|
-
}
|
|
66
|
-
/**
|
|
67
|
-
* Enqueue a new task
|
|
68
|
-
*/
|
|
69
|
-
async enqueue(task) {
|
|
70
|
-
const taskId = `tsk_${randomUUID()}`;
|
|
71
|
-
const now = new Date().toISOString();
|
|
72
|
-
try {
|
|
73
|
-
const stmt = this.db.prepare(`
|
|
74
|
-
INSERT INTO tasks (
|
|
75
|
-
id, type, title, description, status, priority,
|
|
76
|
-
assigned_to, mission_id, dependencies, metadata,
|
|
77
|
-
created_at, updated_at
|
|
78
|
-
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
79
|
-
`);
|
|
80
|
-
stmt.run(taskId, task.type, task.title, task.description, task.status || TaskStatus.PENDING, task.priority, task.assignedTo || null, task.missionId || null, JSON.stringify(task.dependencies || []), JSON.stringify(task.metadata || {}), now, now);
|
|
81
|
-
console.log(`✓ Task enqueued: ${taskId} (${task.title})`);
|
|
82
|
-
return taskId;
|
|
83
|
-
}
|
|
84
|
-
catch (error) {
|
|
85
|
-
console.error(`✗ Failed to enqueue task:`, error.message);
|
|
86
|
-
throw new Error(`Task enqueue failed: ${error.message}`);
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
/**
|
|
90
|
-
* Dequeue next available task for agent type
|
|
91
|
-
*/
|
|
92
|
-
async dequeue(agentType, limit = 1) {
|
|
93
|
-
try {
|
|
94
|
-
let whereClause = 'status = ?';
|
|
95
|
-
const params = [TaskStatus.PENDING];
|
|
96
|
-
if (agentType) {
|
|
97
|
-
whereClause += ' AND (type = ? OR type = ?)';
|
|
98
|
-
params.push(agentType, 'general'); // Allow general tasks
|
|
99
|
-
}
|
|
100
|
-
whereClause += ' ORDER BY priority DESC, created_at ASC LIMIT ?';
|
|
101
|
-
params.push(limit);
|
|
102
|
-
const stmt = this.db.prepare(`
|
|
103
|
-
SELECT * FROM tasks
|
|
104
|
-
WHERE ${whereClause}
|
|
105
|
-
`);
|
|
106
|
-
const rows = stmt.all(...params);
|
|
107
|
-
if (rows.length === 0) {
|
|
108
|
-
return [];
|
|
109
|
-
}
|
|
110
|
-
// Mark tasks as assigned
|
|
111
|
-
const taskIds = rows.map(row => row.id);
|
|
112
|
-
await this.markAsAssigned(taskIds);
|
|
113
|
-
// Convert rows to Task objects
|
|
114
|
-
const tasks = rows.map(row => this.rowToTask(row));
|
|
115
|
-
console.log(`✓ Dequeued ${tasks.length} task(s)`);
|
|
116
|
-
return tasks;
|
|
117
|
-
}
|
|
118
|
-
catch (error) {
|
|
119
|
-
console.error(`✗ Failed to dequeue tasks:`, error.message);
|
|
120
|
-
throw new Error(`Task dequeue failed: ${error.message}`);
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
/**
|
|
124
|
-
* Mark task as in progress
|
|
125
|
-
*/
|
|
126
|
-
async markAsInProgress(taskId) {
|
|
127
|
-
await this.updateTaskStatus(taskId, TaskStatus.IN_PROGRESS);
|
|
128
|
-
}
|
|
129
|
-
/**
|
|
130
|
-
* Complete a task
|
|
131
|
-
*/
|
|
132
|
-
async complete(taskId, result) {
|
|
133
|
-
try {
|
|
134
|
-
const now = new Date().toISOString();
|
|
135
|
-
const stmt = this.db.prepare(`
|
|
136
|
-
UPDATE tasks
|
|
137
|
-
SET status = ?, updated_at = ?, completed_at = ?, metadata = ?
|
|
138
|
-
WHERE id = ?
|
|
139
|
-
`);
|
|
140
|
-
// Add result to metadata
|
|
141
|
-
const currentTask = await this.getTask(taskId);
|
|
142
|
-
const updatedMetadata = {
|
|
143
|
-
...currentTask?.metadata,
|
|
144
|
-
result: result || null
|
|
145
|
-
};
|
|
146
|
-
stmt.run(TaskStatus.COMPLETED, now, now, JSON.stringify(updatedMetadata), taskId);
|
|
147
|
-
console.log(`✓ Task completed: ${taskId}`);
|
|
148
|
-
}
|
|
149
|
-
catch (error) {
|
|
150
|
-
await this.fail(taskId, `Completion failed: ${error.message}`);
|
|
151
|
-
throw new Error(`Task completion failed: ${error.message}`);
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
/**
|
|
155
|
-
* Mark task as failed
|
|
156
|
-
*/
|
|
157
|
-
async fail(taskId, error) {
|
|
158
|
-
try {
|
|
159
|
-
const now = new Date().toISOString();
|
|
160
|
-
const stmt = this.db.prepare(`
|
|
161
|
-
UPDATE tasks
|
|
162
|
-
SET status = ?, updated_at = ?, retry_count = retry_count + 1, last_retry_at = ?
|
|
163
|
-
WHERE id = ?
|
|
164
|
-
`);
|
|
165
|
-
stmt.run(TaskStatus.FAILED, now, now, taskId);
|
|
166
|
-
console.log(`✗ Task failed: ${taskId} - ${error}`);
|
|
167
|
-
}
|
|
168
|
-
catch (error) {
|
|
169
|
-
console.error(`✗ Failed to mark task as failed:`, error.message);
|
|
170
|
-
throw new Error(`Task failure marking failed: ${error.message}`);
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
/**
|
|
174
|
-
* Get task by ID
|
|
175
|
-
*/
|
|
176
|
-
async getTask(taskId) {
|
|
177
|
-
try {
|
|
178
|
-
const stmt = this.db.prepare('SELECT * FROM tasks WHERE id = ?');
|
|
179
|
-
const row = stmt.get(taskId);
|
|
180
|
-
return row ? this.rowToTask(row) : null;
|
|
181
|
-
}
|
|
182
|
-
catch (error) {
|
|
183
|
-
console.error(`✗ Failed to get task:`, error.message);
|
|
184
|
-
return null;
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
/**
|
|
188
|
-
* Get tasks by status
|
|
189
|
-
*/
|
|
190
|
-
async getTasksByStatus(status) {
|
|
191
|
-
try {
|
|
192
|
-
const stmt = this.db.prepare('SELECT * FROM tasks WHERE status = ? ORDER BY created_at DESC');
|
|
193
|
-
const rows = stmt.all(status);
|
|
194
|
-
return rows.map(row => this.rowToTask(row));
|
|
195
|
-
}
|
|
196
|
-
catch (error) {
|
|
197
|
-
console.error(`✗ Failed to get tasks by status:`, error.message);
|
|
198
|
-
return [];
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
/**
|
|
202
|
-
* Get tasks for mission
|
|
203
|
-
*/
|
|
204
|
-
async getTasksByMission(missionId) {
|
|
205
|
-
try {
|
|
206
|
-
const stmt = this.db.prepare('SELECT * FROM tasks WHERE mission_id = ? ORDER BY priority DESC, created_at ASC');
|
|
207
|
-
const rows = stmt.all(missionId);
|
|
208
|
-
return rows.map(row => this.rowToTask(row));
|
|
209
|
-
}
|
|
210
|
-
catch (error) {
|
|
211
|
-
console.error(`✗ Failed to get mission tasks:`, error.message);
|
|
212
|
-
return [];
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
/**
|
|
216
|
-
* Get tasks assigned to agent
|
|
217
|
-
*/
|
|
218
|
-
async getTasksByAgent(agentId) {
|
|
219
|
-
try {
|
|
220
|
-
const stmt = this.db.prepare('SELECT * FROM tasks WHERE assigned_to = ? ORDER BY created_at DESC');
|
|
221
|
-
const rows = stmt.all(agentId);
|
|
222
|
-
return rows.map(row => this.rowToTask(row));
|
|
223
|
-
}
|
|
224
|
-
catch (error) {
|
|
225
|
-
console.error(`✗ Failed to get agent tasks:`, error.message);
|
|
226
|
-
return [];
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
/**
|
|
230
|
-
* Retry failed tasks
|
|
231
|
-
*/
|
|
232
|
-
async retryFailedTasks() {
|
|
233
|
-
try {
|
|
234
|
-
const stmt = this.db.prepare(`
|
|
235
|
-
SELECT * FROM tasks
|
|
236
|
-
WHERE status = ? AND retry_count < ?
|
|
237
|
-
ORDER BY priority DESC, created_at ASC
|
|
238
|
-
`);
|
|
239
|
-
const rows = stmt.all(TaskStatus.FAILED, this.config.maxRetries);
|
|
240
|
-
let retriedCount = 0;
|
|
241
|
-
for (const row of rows) {
|
|
242
|
-
// Check dependencies
|
|
243
|
-
if (row.dependencies) {
|
|
244
|
-
const dependencies = JSON.parse(row.dependencies);
|
|
245
|
-
const pendingDeps = await this.checkDependencies(dependencies);
|
|
246
|
-
if (pendingDeps.length > 0) {
|
|
247
|
-
continue; // Skip if dependencies not met
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
await this.resetTask(row.id);
|
|
251
|
-
retriedCount++;
|
|
252
|
-
}
|
|
253
|
-
if (retriedCount > 0) {
|
|
254
|
-
console.log(`✓ Retried ${retriedCount} failed tasks`);
|
|
255
|
-
}
|
|
256
|
-
return retriedCount;
|
|
257
|
-
}
|
|
258
|
-
catch (error) {
|
|
259
|
-
console.error(`✗ Failed to retry tasks:`, error.message);
|
|
260
|
-
return 0;
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
/**
|
|
264
|
-
* Get queue statistics
|
|
265
|
-
*/
|
|
266
|
-
async getStats() {
|
|
267
|
-
try {
|
|
268
|
-
const stats = {
|
|
269
|
-
total: 0,
|
|
270
|
-
pending: 0,
|
|
271
|
-
assigned: 0,
|
|
272
|
-
inProgress: 0,
|
|
273
|
-
completed: 0,
|
|
274
|
-
failed: 0
|
|
275
|
-
};
|
|
276
|
-
const stmt = this.db.prepare('SELECT status, COUNT(*) as count FROM tasks GROUP BY status');
|
|
277
|
-
const rows = stmt.all();
|
|
278
|
-
rows.forEach(row => {
|
|
279
|
-
stats.total += row.count;
|
|
280
|
-
switch (row.status) {
|
|
281
|
-
case TaskStatus.PENDING:
|
|
282
|
-
stats.pending = row.count;
|
|
283
|
-
break;
|
|
284
|
-
case TaskStatus.ASSIGNED:
|
|
285
|
-
stats.assigned = row.count;
|
|
286
|
-
break;
|
|
287
|
-
case TaskStatus.IN_PROGRESS:
|
|
288
|
-
stats.inProgress = row.count;
|
|
289
|
-
break;
|
|
290
|
-
case TaskStatus.COMPLETED:
|
|
291
|
-
stats.completed = row.count;
|
|
292
|
-
break;
|
|
293
|
-
case TaskStatus.FAILED:
|
|
294
|
-
stats.failed = row.count;
|
|
295
|
-
break;
|
|
296
|
-
}
|
|
297
|
-
});
|
|
298
|
-
return stats;
|
|
299
|
-
}
|
|
300
|
-
catch (error) {
|
|
301
|
-
console.error(`✗ Failed to get stats:`, error.message);
|
|
302
|
-
return {
|
|
303
|
-
total: 0,
|
|
304
|
-
pending: 0,
|
|
305
|
-
assigned: 0,
|
|
306
|
-
inProgress: 0,
|
|
307
|
-
completed: 0,
|
|
308
|
-
failed: 0
|
|
309
|
-
};
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
// ========================================================================
|
|
313
|
-
// Private Helper Methods
|
|
314
|
-
// ========================================================================
|
|
315
|
-
async markAsAssigned(taskIds) {
|
|
316
|
-
if (taskIds.length === 0)
|
|
317
|
-
return;
|
|
318
|
-
const placeholders = taskIds.map(() => '?').join(',');
|
|
319
|
-
const stmt = this.db.prepare(`
|
|
320
|
-
UPDATE tasks
|
|
321
|
-
SET status = ?, updated_at = ?
|
|
322
|
-
WHERE id IN (${placeholders})
|
|
323
|
-
`);
|
|
324
|
-
const now = new Date().toISOString();
|
|
325
|
-
stmt.run(TaskStatus.ASSIGNED, now, ...taskIds);
|
|
326
|
-
}
|
|
327
|
-
async updateTaskStatus(taskId, status) {
|
|
328
|
-
const stmt = this.db.prepare(`
|
|
329
|
-
UPDATE tasks
|
|
330
|
-
SET status = ?, updated_at = ?
|
|
331
|
-
WHERE id = ?
|
|
332
|
-
`);
|
|
333
|
-
stmt.run(status, new Date().toISOString(), taskId);
|
|
334
|
-
}
|
|
335
|
-
async resetTask(taskId) {
|
|
336
|
-
const stmt = this.db.prepare(`
|
|
337
|
-
UPDATE tasks
|
|
338
|
-
SET status = ?, updated_at = ?, completed_at = NULL
|
|
339
|
-
WHERE id = ?
|
|
340
|
-
`);
|
|
341
|
-
stmt.run(TaskStatus.PENDING, new Date().toISOString(), taskId);
|
|
342
|
-
}
|
|
343
|
-
async checkDependencies(dependencies) {
|
|
344
|
-
if (dependencies.length === 0)
|
|
345
|
-
return [];
|
|
346
|
-
const placeholders = dependencies.map(() => '?').join(',');
|
|
347
|
-
const stmt = this.db.prepare(`
|
|
348
|
-
SELECT id FROM tasks
|
|
349
|
-
WHERE id IN (${placeholders}) AND status != ?
|
|
350
|
-
`);
|
|
351
|
-
const incompleteRows = stmt.all(...dependencies, TaskStatus.COMPLETED);
|
|
352
|
-
return incompleteRows.map((row) => row.id);
|
|
353
|
-
}
|
|
354
|
-
rowToTask(row) {
|
|
355
|
-
return {
|
|
356
|
-
id: row.id,
|
|
357
|
-
type: row.type,
|
|
358
|
-
title: row.title,
|
|
359
|
-
description: row.description || '',
|
|
360
|
-
status: row.status,
|
|
361
|
-
priority: row.priority,
|
|
362
|
-
assignedTo: row.assigned_to,
|
|
363
|
-
missionId: row.mission_id,
|
|
364
|
-
dependencies: row.dependencies ? JSON.parse(row.dependencies) : [],
|
|
365
|
-
metadata: row.metadata ? JSON.parse(row.metadata) : {},
|
|
366
|
-
createdAt: row.created_at,
|
|
367
|
-
updatedAt: row.updated_at,
|
|
368
|
-
completedAt: row.completed_at
|
|
369
|
-
};
|
|
370
|
-
}
|
|
371
|
-
/**
|
|
372
|
-
* Close database connection
|
|
373
|
-
*/
|
|
374
|
-
close() {
|
|
375
|
-
this.db.close();
|
|
376
|
-
}
|
|
377
|
-
}
|
package/dist/validation.js
DELETED
|
@@ -1,188 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Agent Types and Validation Schemas
|
|
3
|
-
*
|
|
4
|
-
* Zod validation schemas for agent coordination
|
|
5
|
-
*/
|
|
6
|
-
import { z } from 'zod';
|
|
7
|
-
// Define AgentType locally to avoid import conflicts
|
|
8
|
-
export var AgentType;
|
|
9
|
-
(function (AgentType) {
|
|
10
|
-
AgentType["FRONTEND"] = "frontend";
|
|
11
|
-
AgentType["BACKEND"] = "backend";
|
|
12
|
-
AgentType["TESTING"] = "testing";
|
|
13
|
-
AgentType["DOCUMENTATION"] = "documentation";
|
|
14
|
-
AgentType["SECURITY"] = "security";
|
|
15
|
-
AgentType["PERFORMANCE"] = "performance";
|
|
16
|
-
})(AgentType || (AgentType = {}));
|
|
17
|
-
// Enhanced AgentType with validation
|
|
18
|
-
export const AgentTypeSchema = z.enum([
|
|
19
|
-
AgentType.FRONTEND,
|
|
20
|
-
AgentType.BACKEND,
|
|
21
|
-
AgentType.TESTING,
|
|
22
|
-
AgentType.DOCUMENTATION,
|
|
23
|
-
AgentType.SECURITY,
|
|
24
|
-
AgentType.PERFORMANCE
|
|
25
|
-
]);
|
|
26
|
-
// Agent Configuration Schema
|
|
27
|
-
export const AgentConfigSchema = z.object({
|
|
28
|
-
timeout: z.number().int().positive().optional(),
|
|
29
|
-
retries: z.number().int().min(0).max(10).optional(),
|
|
30
|
-
resources: z.object({
|
|
31
|
-
memory: z.string().optional(),
|
|
32
|
-
cpu: z.string().optional(),
|
|
33
|
-
}).optional(),
|
|
34
|
-
environment: z.record(z.string()).optional(),
|
|
35
|
-
});
|
|
36
|
-
// Agent Spawn Request Schema
|
|
37
|
-
export const AgentSpawnRequestSchema = z.object({
|
|
38
|
-
type: AgentTypeSchema,
|
|
39
|
-
task: z.string().optional(),
|
|
40
|
-
metadata: z.record(z.unknown()).optional(),
|
|
41
|
-
config: AgentConfigSchema.optional(),
|
|
42
|
-
});
|
|
43
|
-
// Agent Update Request Schema
|
|
44
|
-
export const AgentUpdateRequestSchema = z.object({
|
|
45
|
-
status: z.enum(['idle', 'busy', 'error']).optional(),
|
|
46
|
-
metadata: z.record(z.unknown()).optional(),
|
|
47
|
-
heartbeat: z.boolean().optional(),
|
|
48
|
-
});
|
|
49
|
-
// Agent Capability Schema
|
|
50
|
-
export const AgentCapabilitySchema = z.object({
|
|
51
|
-
id: z.string().uuid(),
|
|
52
|
-
agentId: z.string(),
|
|
53
|
-
capability: z.string(),
|
|
54
|
-
version: z.string(),
|
|
55
|
-
enabled: z.boolean(),
|
|
56
|
-
config: z.record(z.unknown()).optional(),
|
|
57
|
-
});
|
|
58
|
-
// Agent Specialization Schema
|
|
59
|
-
export const AgentSpecializationSchema = z.object({
|
|
60
|
-
id: z.string().uuid(),
|
|
61
|
-
agentId: z.string(),
|
|
62
|
-
specialization: z.string(),
|
|
63
|
-
proficiency: z.number().min(0).max(1), // 0-1 scale
|
|
64
|
-
experience: z.number().int().min(0), // years
|
|
65
|
-
certifications: z.array(z.string()).optional(),
|
|
66
|
-
});
|
|
67
|
-
// Task Assignment Schema
|
|
68
|
-
export const TaskAssignmentSchema = z.object({
|
|
69
|
-
taskId: z.string(),
|
|
70
|
-
agentId: z.string(),
|
|
71
|
-
assignedAt: z.string().datetime(),
|
|
72
|
-
deadline: z.string().datetime().optional(),
|
|
73
|
-
priority: z.enum(['low', 'medium', 'high', 'critical']),
|
|
74
|
-
requirements: z.object({
|
|
75
|
-
skills: z.array(z.string()).optional(),
|
|
76
|
-
tools: z.array(z.string()).optional(),
|
|
77
|
-
resources: z.record(z.string()).optional(),
|
|
78
|
-
}).optional(),
|
|
79
|
-
});
|
|
80
|
-
// Agent Performance Schema
|
|
81
|
-
export const AgentPerformanceSchema = z.object({
|
|
82
|
-
agentId: z.string(),
|
|
83
|
-
taskId: z.string().optional(),
|
|
84
|
-
metrics: z.object({
|
|
85
|
-
executionTime: z.number().min(0),
|
|
86
|
-
accuracy: z.number().min(0).max(1),
|
|
87
|
-
efficiency: z.number().min(0).max(1),
|
|
88
|
-
resourceUsage: z.object({
|
|
89
|
-
memory: z.number().min(0),
|
|
90
|
-
cpu: z.number().min(0),
|
|
91
|
-
disk: z.number().min(0).optional(),
|
|
92
|
-
}),
|
|
93
|
-
}),
|
|
94
|
-
timestamp: z.string().datetime(),
|
|
95
|
-
});
|
|
96
|
-
// Validation functions
|
|
97
|
-
export class AgentValidator {
|
|
98
|
-
/**
|
|
99
|
-
* Validate agent spawn request
|
|
100
|
-
*/
|
|
101
|
-
static validateSpawnRequest(data) {
|
|
102
|
-
const result = AgentSpawnRequestSchema.safeParse(data);
|
|
103
|
-
if (!result.success) {
|
|
104
|
-
throw new Error(`Invalid spawn request: ${result.error.message}`);
|
|
105
|
-
}
|
|
106
|
-
return result.data;
|
|
107
|
-
}
|
|
108
|
-
/**
|
|
109
|
-
* Validate agent configuration
|
|
110
|
-
*/
|
|
111
|
-
static validateConfig(data) {
|
|
112
|
-
const result = AgentConfigSchema.safeParse(data);
|
|
113
|
-
if (!result.success) {
|
|
114
|
-
throw new Error(`Invalid agent config: ${result.error.message}`);
|
|
115
|
-
}
|
|
116
|
-
return result.data;
|
|
117
|
-
}
|
|
118
|
-
/**
|
|
119
|
-
* Validate agent type
|
|
120
|
-
*/
|
|
121
|
-
static validateAgentType(type) {
|
|
122
|
-
const result = AgentTypeSchema.safeParse(type);
|
|
123
|
-
if (!result.success) {
|
|
124
|
-
throw new Error(`Invalid agent type: ${result.error.message}`);
|
|
125
|
-
}
|
|
126
|
-
return result.data;
|
|
127
|
-
}
|
|
128
|
-
/**
|
|
129
|
-
* Validate agent ID format
|
|
130
|
-
*/
|
|
131
|
-
static validateAgentId(id) {
|
|
132
|
-
// Agent IDs should follow pattern: agt_<uuid>
|
|
133
|
-
const agentIdPattern = /^agt_[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/;
|
|
134
|
-
return agentIdPattern.test(id);
|
|
135
|
-
}
|
|
136
|
-
/**
|
|
137
|
-
* Validate task assignment
|
|
138
|
-
*/
|
|
139
|
-
static validateTaskAssignment(data) {
|
|
140
|
-
const result = TaskAssignmentSchema.safeParse(data);
|
|
141
|
-
if (!result.success) {
|
|
142
|
-
throw new Error(`Invalid task assignment: ${result.error.message}`);
|
|
143
|
-
}
|
|
144
|
-
return result.data;
|
|
145
|
-
}
|
|
146
|
-
/**
|
|
147
|
-
* Check if agent type is suitable for task type
|
|
148
|
-
*/
|
|
149
|
-
static isAgentSuitableForTask(agentType, taskType) {
|
|
150
|
-
const suitabilityMap = {
|
|
151
|
-
[AgentType.FRONTEND]: ['ui', 'frontend', 'component', 'interface'],
|
|
152
|
-
[AgentType.BACKEND]: ['api', 'backend', 'server', 'database'],
|
|
153
|
-
[AgentType.TESTING]: ['test', 'testing', 'qa', 'validation'],
|
|
154
|
-
[AgentType.DOCUMENTATION]: ['docs', 'documentation', 'readme', 'guide'],
|
|
155
|
-
[AgentType.SECURITY]: ['security', 'audit', 'vulnerability', 'scan'],
|
|
156
|
-
[AgentType.PERFORMANCE]: ['performance', 'optimization', 'benchmark', 'metrics']
|
|
157
|
-
};
|
|
158
|
-
const agentCapabilities = suitabilityMap[agentType] || [];
|
|
159
|
-
return AgentCapabilities.includes(taskType.toLowerCase());
|
|
160
|
-
}
|
|
161
|
-
/**
|
|
162
|
-
* Get recommended agents for task type
|
|
163
|
-
*/
|
|
164
|
-
static getRecommendedAgents(taskType) {
|
|
165
|
-
const taskToAgents = {
|
|
166
|
-
'ui': [AgentType.FRONTEND],
|
|
167
|
-
'frontend': [AgentType.FRONTEND],
|
|
168
|
-
'api': [AgentType.BACKEND],
|
|
169
|
-
'backend': [AgentType.BACKEND],
|
|
170
|
-
'test': [AgentType.TESTING],
|
|
171
|
-
'security': [AgentType.SECURITY],
|
|
172
|
-
'docs': [AgentType.DOCUMENTATION],
|
|
173
|
-
'performance': [AgentType.PERFORMANCE],
|
|
174
|
-
'general': [AgentType.BACKEND, AgentType.FRONTEND] // General tasks can go to multiple types
|
|
175
|
-
};
|
|
176
|
-
return taskToAgents[taskType.toLowerCase()] || [AgentType.BACKEND]; // Default to backend
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
// Common task categories for validation
|
|
180
|
-
const AgentCapabilities = [
|
|
181
|
-
'ui', 'frontend', 'component', 'interface',
|
|
182
|
-
'api', 'backend', 'server', 'database',
|
|
183
|
-
'test', 'testing', 'qa', 'validation',
|
|
184
|
-
'docs', 'documentation', 'readme', 'guide',
|
|
185
|
-
'security', 'audit', 'vulnerability', 'scan',
|
|
186
|
-
'performance', 'optimization', 'benchmark', 'metrics',
|
|
187
|
-
'general', 'utility', 'helper', 'tool'
|
|
188
|
-
];
|