@cogitator-ai/worker 0.2.0 → 0.2.1
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/README.md +647 -43
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -8,11 +8,22 @@ Distributed job queue for Cogitator agent execution. Built on BullMQ for reliabl
|
|
|
8
8
|
pnpm add @cogitator-ai/worker ioredis
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
##
|
|
11
|
+
## Features
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
- **BullMQ-Based** - Reliable job processing with Redis
|
|
14
|
+
- **Job Types** - Agents, workflows, and swarms
|
|
15
|
+
- **Auto-Retry** - Exponential backoff for failed jobs
|
|
16
|
+
- **Priority Queue** - Process important jobs first
|
|
17
|
+
- **Delayed Jobs** - Schedule jobs for later execution
|
|
18
|
+
- **Prometheus Metrics** - Built-in HPA support
|
|
19
|
+
- **Redis Cluster** - Production-ready scalability
|
|
20
|
+
- **Graceful Shutdown** - Wait for active jobs before stopping
|
|
14
21
|
|
|
15
|
-
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Quick Start
|
|
25
|
+
|
|
26
|
+
### Producer: Add Jobs
|
|
16
27
|
|
|
17
28
|
```typescript
|
|
18
29
|
import { JobQueue } from '@cogitator-ai/worker';
|
|
@@ -21,93 +32,477 @@ const queue = new JobQueue({
|
|
|
21
32
|
redis: { host: 'localhost', port: 6379 },
|
|
22
33
|
});
|
|
23
34
|
|
|
24
|
-
// Agent config (serialized form)
|
|
25
35
|
const agentConfig = {
|
|
26
|
-
|
|
27
|
-
|
|
36
|
+
name: 'Assistant',
|
|
37
|
+
instructions: 'You are a helpful assistant.',
|
|
28
38
|
model: 'openai/gpt-4',
|
|
29
|
-
|
|
39
|
+
provider: 'openai' as const,
|
|
30
40
|
tools: [],
|
|
31
41
|
};
|
|
32
42
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
threadId: 'thread-123',
|
|
43
|
+
const job = await queue.addAgentJob(agentConfig, 'Hello, world!', {
|
|
44
|
+
threadId: 'user-123',
|
|
36
45
|
priority: 1,
|
|
37
46
|
});
|
|
38
47
|
|
|
39
|
-
|
|
40
|
-
const workflowConfig = { name: 'data-pipeline', nodes: [] };
|
|
41
|
-
await queue.addWorkflowJob(workflowConfig, { data: [] }, {
|
|
42
|
-
runId: 'run-456',
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
// Add swarm job
|
|
46
|
-
const swarmConfig = { name: 'research-team', strategy: 'hierarchical', agents: [] };
|
|
47
|
-
await queue.addSwarmJob(swarmConfig, 'Research AI trends');
|
|
48
|
+
console.log(`Job added: ${job.id}`);
|
|
48
49
|
```
|
|
49
50
|
|
|
50
|
-
###
|
|
51
|
-
|
|
52
|
-
Process jobs with configurable concurrency:
|
|
51
|
+
### Consumer: Process Jobs
|
|
53
52
|
|
|
54
53
|
```typescript
|
|
55
54
|
import { WorkerPool } from '@cogitator-ai/worker';
|
|
56
|
-
import { Cogitator } from '@cogitator-ai/core';
|
|
57
55
|
|
|
58
|
-
const
|
|
59
|
-
const pool = new WorkerPool(cogitator, {
|
|
56
|
+
const pool = new WorkerPool({
|
|
60
57
|
redis: { host: 'localhost', port: 6379 },
|
|
61
58
|
concurrency: 5,
|
|
59
|
+
workerCount: 2,
|
|
62
60
|
});
|
|
63
61
|
|
|
64
62
|
await pool.start();
|
|
65
63
|
```
|
|
66
64
|
|
|
67
|
-
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## Job Queue
|
|
68
|
+
|
|
69
|
+
The `JobQueue` class manages job creation and status tracking.
|
|
68
70
|
|
|
69
|
-
|
|
71
|
+
### Creating a Queue
|
|
70
72
|
|
|
71
73
|
```typescript
|
|
72
|
-
import { JobQueue
|
|
74
|
+
import { JobQueue } from '@cogitator-ai/worker';
|
|
73
75
|
|
|
74
76
|
const queue = new JobQueue({
|
|
75
|
-
|
|
77
|
+
name: 'my-queue',
|
|
78
|
+
redis: {
|
|
79
|
+
host: 'localhost',
|
|
80
|
+
port: 6379,
|
|
81
|
+
password: 'secret',
|
|
82
|
+
},
|
|
83
|
+
defaultJobOptions: {
|
|
84
|
+
attempts: 3,
|
|
85
|
+
backoff: { type: 'exponential', delay: 1000 },
|
|
86
|
+
removeOnComplete: 100,
|
|
87
|
+
removeOnFail: 500,
|
|
88
|
+
},
|
|
76
89
|
});
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Queue Configuration
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
interface QueueConfig {
|
|
96
|
+
name?: string; // Default: 'cogitator-jobs'
|
|
97
|
+
redis: {
|
|
98
|
+
host?: string; // Default: 'localhost'
|
|
99
|
+
port?: number; // Default: 6379
|
|
100
|
+
password?: string;
|
|
101
|
+
cluster?: {
|
|
102
|
+
nodes: { host: string; port: number }[];
|
|
103
|
+
};
|
|
104
|
+
};
|
|
105
|
+
defaultJobOptions?: {
|
|
106
|
+
attempts?: number; // Default: 3
|
|
107
|
+
backoff?: {
|
|
108
|
+
type: 'exponential' | 'fixed';
|
|
109
|
+
delay: number; // Delay in ms
|
|
110
|
+
};
|
|
111
|
+
removeOnComplete?: boolean | number; // Default: 100
|
|
112
|
+
removeOnFail?: boolean | number; // Default: 500
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### Adding Jobs
|
|
118
|
+
|
|
119
|
+
**Agent Jobs:**
|
|
120
|
+
|
|
121
|
+
```typescript
|
|
122
|
+
const agentConfig: SerializedAgent = {
|
|
123
|
+
name: 'Researcher',
|
|
124
|
+
instructions: 'Research and summarize topics.',
|
|
125
|
+
model: 'openai/gpt-4',
|
|
126
|
+
provider: 'openai',
|
|
127
|
+
temperature: 0.7,
|
|
128
|
+
maxTokens: 2048,
|
|
129
|
+
tools: [
|
|
130
|
+
{
|
|
131
|
+
name: 'search',
|
|
132
|
+
description: 'Search the web',
|
|
133
|
+
parameters: { type: 'object', properties: { query: { type: 'string' } } },
|
|
134
|
+
},
|
|
135
|
+
],
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
const job = await queue.addAgentJob(agentConfig, 'Research quantum computing', {
|
|
139
|
+
threadId: 'thread-123',
|
|
140
|
+
priority: 1, // Lower = higher priority
|
|
141
|
+
delay: 5000, // Delay 5 seconds
|
|
142
|
+
metadata: { userId: 'user-456' },
|
|
143
|
+
});
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
**Workflow Jobs:**
|
|
147
|
+
|
|
148
|
+
```typescript
|
|
149
|
+
const workflowConfig: SerializedWorkflow = {
|
|
150
|
+
id: 'data-pipeline',
|
|
151
|
+
name: 'Data Pipeline',
|
|
152
|
+
nodes: [
|
|
153
|
+
{ id: 'fetch', type: 'agent', config: { agentConfig: fetchAgent } },
|
|
154
|
+
{ id: 'process', type: 'transform', config: { transform: 'uppercase' } },
|
|
155
|
+
{ id: 'store', type: 'agent', config: { agentConfig: storeAgent } },
|
|
156
|
+
],
|
|
157
|
+
edges: [
|
|
158
|
+
{ from: 'fetch', to: 'process' },
|
|
159
|
+
{ from: 'process', to: 'store' },
|
|
160
|
+
],
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
await queue.addWorkflowJob(
|
|
164
|
+
workflowConfig,
|
|
165
|
+
{ source: 'api' },
|
|
166
|
+
{
|
|
167
|
+
runId: 'run-789',
|
|
168
|
+
priority: 2,
|
|
169
|
+
}
|
|
170
|
+
);
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
**Swarm Jobs:**
|
|
174
|
+
|
|
175
|
+
```typescript
|
|
176
|
+
const swarmConfig: SerializedSwarm = {
|
|
177
|
+
topology: 'collaborative',
|
|
178
|
+
agents: [researcherConfig, writerConfig, editorConfig],
|
|
179
|
+
coordinator: coordinatorConfig,
|
|
180
|
+
maxRounds: 3,
|
|
181
|
+
consensusThreshold: 0.8,
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
await queue.addSwarmJob(swarmConfig, 'Write an article about AI', {
|
|
185
|
+
priority: 1,
|
|
186
|
+
metadata: { project: 'blog' },
|
|
187
|
+
});
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### Queue Methods
|
|
191
|
+
|
|
192
|
+
```typescript
|
|
193
|
+
const job = await queue.getJob('job-id');
|
|
194
|
+
|
|
195
|
+
const state = await queue.getJobState('job-id');
|
|
196
|
+
// 'waiting' | 'active' | 'completed' | 'failed' | 'delayed' | 'unknown'
|
|
197
|
+
|
|
198
|
+
const metrics = await queue.getMetrics();
|
|
199
|
+
|
|
200
|
+
await queue.pause();
|
|
201
|
+
await queue.resume();
|
|
202
|
+
|
|
203
|
+
await queue.clean(60 * 60 * 1000, 1000, 'completed');
|
|
204
|
+
await queue.clean(24 * 60 * 60 * 1000, 100, 'failed');
|
|
205
|
+
|
|
206
|
+
const bullQueue = queue.getQueue();
|
|
207
|
+
|
|
208
|
+
await queue.close();
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
---
|
|
212
|
+
|
|
213
|
+
## Worker Pool
|
|
214
|
+
|
|
215
|
+
The `WorkerPool` processes jobs with configurable concurrency.
|
|
216
|
+
|
|
217
|
+
### Creating a Worker Pool
|
|
218
|
+
|
|
219
|
+
```typescript
|
|
220
|
+
import { WorkerPool } from '@cogitator-ai/worker';
|
|
221
|
+
|
|
222
|
+
const pool = new WorkerPool(
|
|
223
|
+
{
|
|
224
|
+
redis: { host: 'localhost', port: 6379 },
|
|
225
|
+
workerCount: 2,
|
|
226
|
+
concurrency: 5,
|
|
227
|
+
lockDuration: 30000,
|
|
228
|
+
stalledInterval: 30000,
|
|
229
|
+
},
|
|
230
|
+
{
|
|
231
|
+
onJobStarted: (jobId, type) => {
|
|
232
|
+
console.log(`Job ${jobId} (${type}) started`);
|
|
233
|
+
},
|
|
234
|
+
onJobCompleted: (jobId, result) => {
|
|
235
|
+
console.log(`Job ${jobId} completed:`, result);
|
|
236
|
+
},
|
|
237
|
+
onJobFailed: (jobId, error) => {
|
|
238
|
+
console.error(`Job ${jobId} failed:`, error);
|
|
239
|
+
},
|
|
240
|
+
onWorkerError: (error) => {
|
|
241
|
+
console.error('Worker error:', error);
|
|
242
|
+
},
|
|
243
|
+
}
|
|
244
|
+
);
|
|
245
|
+
|
|
246
|
+
await pool.start();
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
### Worker Configuration
|
|
250
|
+
|
|
251
|
+
```typescript
|
|
252
|
+
interface WorkerConfig extends QueueConfig {
|
|
253
|
+
workerCount?: number; // Default: 1
|
|
254
|
+
concurrency?: number; // Default: 5
|
|
255
|
+
lockDuration?: number; // Default: 30000ms
|
|
256
|
+
stalledInterval?: number; // Default: 30000ms
|
|
257
|
+
}
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
| Option | Default | Description |
|
|
261
|
+
| ----------------- | ------- | ------------------------------------------ |
|
|
262
|
+
| `workerCount` | 1 | Number of worker instances |
|
|
263
|
+
| `concurrency` | 5 | Concurrent jobs per worker |
|
|
264
|
+
| `lockDuration` | 30000 | Lock timeout before job considered stalled |
|
|
265
|
+
| `stalledInterval` | 30000 | Interval to check for stalled jobs |
|
|
266
|
+
|
|
267
|
+
### Worker Events
|
|
268
|
+
|
|
269
|
+
```typescript
|
|
270
|
+
interface WorkerPoolEvents {
|
|
271
|
+
onJobStarted?: (jobId: string, type: 'agent' | 'workflow' | 'swarm') => void;
|
|
272
|
+
onJobCompleted?: (jobId: string, result: JobResult) => void;
|
|
273
|
+
onJobFailed?: (jobId: string, error: Error) => void;
|
|
274
|
+
onWorkerError?: (error: Error) => void;
|
|
275
|
+
}
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
### Pool Methods
|
|
279
|
+
|
|
280
|
+
```typescript
|
|
281
|
+
await pool.start();
|
|
282
|
+
|
|
283
|
+
pool.isPoolRunning();
|
|
284
|
+
|
|
285
|
+
pool.getWorkerCount();
|
|
286
|
+
|
|
287
|
+
const metrics = await pool.getMetrics(await queue.getMetrics());
|
|
288
|
+
|
|
289
|
+
// Graceful shutdown (waits up to 30s for active jobs)
|
|
290
|
+
await pool.stop(30000);
|
|
291
|
+
|
|
292
|
+
// Force shutdown
|
|
293
|
+
await pool.forceStop();
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
---
|
|
297
|
+
|
|
298
|
+
## Job Processors
|
|
299
|
+
|
|
300
|
+
Built-in processors handle each job type.
|
|
301
|
+
|
|
302
|
+
### Using Processors Directly
|
|
303
|
+
|
|
304
|
+
```typescript
|
|
305
|
+
import { processAgentJob, processWorkflowJob, processSwarmJob } from '@cogitator-ai/worker';
|
|
306
|
+
|
|
307
|
+
const agentResult = await processAgentJob({
|
|
308
|
+
type: 'agent',
|
|
309
|
+
jobId: 'job-1',
|
|
310
|
+
agentConfig: myAgentConfig,
|
|
311
|
+
input: 'Hello!',
|
|
312
|
+
threadId: 'thread-1',
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
const workflowResult = await processWorkflowJob({
|
|
316
|
+
type: 'workflow',
|
|
317
|
+
jobId: 'job-2',
|
|
318
|
+
workflowConfig: myWorkflowConfig,
|
|
319
|
+
input: { data: [] },
|
|
320
|
+
runId: 'run-1',
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
const swarmResult = await processSwarmJob({
|
|
324
|
+
type: 'swarm',
|
|
325
|
+
jobId: 'job-3',
|
|
326
|
+
swarmConfig: mySwarmConfig,
|
|
327
|
+
input: 'Solve this problem',
|
|
328
|
+
});
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
---
|
|
332
|
+
|
|
333
|
+
## Job Results
|
|
334
|
+
|
|
335
|
+
Each job type returns a specific result structure.
|
|
336
|
+
|
|
337
|
+
### Agent Job Result
|
|
338
|
+
|
|
339
|
+
```typescript
|
|
340
|
+
interface AgentJobResult {
|
|
341
|
+
type: 'agent';
|
|
342
|
+
output: string;
|
|
343
|
+
toolCalls: {
|
|
344
|
+
name: string;
|
|
345
|
+
input: unknown;
|
|
346
|
+
output: unknown;
|
|
347
|
+
}[];
|
|
348
|
+
tokenUsage?: {
|
|
349
|
+
prompt: number;
|
|
350
|
+
completion: number;
|
|
351
|
+
total: number;
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
### Workflow Job Result
|
|
357
|
+
|
|
358
|
+
```typescript
|
|
359
|
+
interface WorkflowJobResult {
|
|
360
|
+
type: 'workflow';
|
|
361
|
+
output: Record<string, unknown>;
|
|
362
|
+
nodeResults: Record<string, unknown>;
|
|
363
|
+
duration: number;
|
|
364
|
+
}
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
### Swarm Job Result
|
|
368
|
+
|
|
369
|
+
```typescript
|
|
370
|
+
interface SwarmJobResult {
|
|
371
|
+
type: 'swarm';
|
|
372
|
+
output: string;
|
|
373
|
+
rounds: number;
|
|
374
|
+
agentOutputs: {
|
|
375
|
+
agent: string;
|
|
376
|
+
output: string;
|
|
377
|
+
}[];
|
|
378
|
+
}
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
---
|
|
382
|
+
|
|
383
|
+
## Prometheus Metrics
|
|
384
|
+
|
|
385
|
+
Built-in metrics for monitoring and Kubernetes HPA.
|
|
386
|
+
|
|
387
|
+
### Exposing Metrics
|
|
388
|
+
|
|
389
|
+
```typescript
|
|
390
|
+
import {
|
|
391
|
+
JobQueue,
|
|
392
|
+
WorkerPool,
|
|
393
|
+
MetricsCollector,
|
|
394
|
+
formatPrometheusMetrics,
|
|
395
|
+
} from '@cogitator-ai/worker';
|
|
396
|
+
import express from 'express';
|
|
397
|
+
|
|
398
|
+
const queue = new JobQueue({ redis: { host: 'localhost', port: 6379 } });
|
|
399
|
+
const pool = new WorkerPool({ redis: { host: 'localhost', port: 6379 } });
|
|
77
400
|
const metrics = new MetricsCollector();
|
|
78
401
|
|
|
79
|
-
|
|
402
|
+
const app = express();
|
|
403
|
+
|
|
80
404
|
app.get('/metrics', async (req, res) => {
|
|
81
405
|
const queueMetrics = await queue.getMetrics();
|
|
82
|
-
|
|
406
|
+
const fullMetrics = await pool.getMetrics(queueMetrics);
|
|
407
|
+
res.type('text/plain').send(metrics.format(fullMetrics));
|
|
83
408
|
});
|
|
409
|
+
|
|
410
|
+
app.listen(9090);
|
|
84
411
|
```
|
|
85
412
|
|
|
86
413
|
### Available Metrics
|
|
87
414
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
415
|
+
| Metric | Type | Description |
|
|
416
|
+
| --------------------------------- | --------- | ------------------------------ |
|
|
417
|
+
| `cogitator_queue_depth` | gauge | Total waiting + delayed jobs |
|
|
418
|
+
| `cogitator_queue_waiting` | gauge | Jobs waiting to be processed |
|
|
419
|
+
| `cogitator_queue_active` | gauge | Jobs currently being processed |
|
|
420
|
+
| `cogitator_queue_completed_total` | counter | Total completed jobs |
|
|
421
|
+
| `cogitator_queue_failed_total` | counter | Total failed jobs |
|
|
422
|
+
| `cogitator_queue_delayed` | gauge | Scheduled/delayed jobs |
|
|
423
|
+
| `cogitator_workers_total` | gauge | Active workers |
|
|
424
|
+
| `cogitator_job_duration_seconds` | histogram | Job processing time |
|
|
425
|
+
| `cogitator_jobs_by_type_total` | counter | Jobs by type |
|
|
426
|
+
|
|
427
|
+
### Duration Histogram
|
|
428
|
+
|
|
429
|
+
```typescript
|
|
430
|
+
import { DurationHistogram } from '@cogitator-ai/worker';
|
|
431
|
+
|
|
432
|
+
const histogram = new DurationHistogram('my_duration_seconds', 'Custom duration tracking');
|
|
433
|
+
|
|
434
|
+
histogram.observe(0.5);
|
|
435
|
+
histogram.observe(1.2);
|
|
436
|
+
histogram.observe(0.8);
|
|
437
|
+
|
|
438
|
+
console.log(histogram.format({ queue: 'main' }));
|
|
439
|
+
|
|
440
|
+
histogram.reset();
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
### Metrics Collector
|
|
444
|
+
|
|
445
|
+
```typescript
|
|
446
|
+
import { MetricsCollector } from '@cogitator-ai/worker';
|
|
447
|
+
|
|
448
|
+
const collector = new MetricsCollector();
|
|
449
|
+
|
|
450
|
+
collector.recordJob('agent', 1500);
|
|
451
|
+
collector.recordJob('workflow', 3200);
|
|
452
|
+
|
|
453
|
+
const output = collector.format(queueMetrics, { queue: 'main' });
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
### Kubernetes HPA Example
|
|
457
|
+
|
|
458
|
+
```yaml
|
|
459
|
+
apiVersion: autoscaling/v2
|
|
460
|
+
kind: HorizontalPodAutoscaler
|
|
461
|
+
metadata:
|
|
462
|
+
name: cogitator-workers
|
|
463
|
+
spec:
|
|
464
|
+
scaleTargetRef:
|
|
465
|
+
apiVersion: apps/v1
|
|
466
|
+
kind: Deployment
|
|
467
|
+
name: cogitator-workers
|
|
468
|
+
minReplicas: 1
|
|
469
|
+
maxReplicas: 10
|
|
470
|
+
metrics:
|
|
471
|
+
- type: External
|
|
472
|
+
external:
|
|
473
|
+
metric:
|
|
474
|
+
name: cogitator_queue_depth
|
|
475
|
+
target:
|
|
476
|
+
type: AverageValue
|
|
477
|
+
averageValue: 10
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
---
|
|
95
481
|
|
|
96
482
|
## Redis Configuration
|
|
97
483
|
|
|
484
|
+
### Single Node
|
|
485
|
+
|
|
98
486
|
```typescript
|
|
99
|
-
// Single node
|
|
100
487
|
const queue = new JobQueue({
|
|
101
|
-
redis: {
|
|
488
|
+
redis: {
|
|
489
|
+
host: 'localhost',
|
|
490
|
+
port: 6379,
|
|
491
|
+
password: 'secret',
|
|
492
|
+
},
|
|
102
493
|
});
|
|
494
|
+
```
|
|
103
495
|
|
|
104
|
-
|
|
496
|
+
### Redis Cluster
|
|
497
|
+
|
|
498
|
+
```typescript
|
|
105
499
|
const queue = new JobQueue({
|
|
106
500
|
redis: {
|
|
107
501
|
cluster: {
|
|
108
502
|
nodes: [
|
|
109
503
|
{ host: 'redis-1', port: 6379 },
|
|
110
504
|
{ host: 'redis-2', port: 6379 },
|
|
505
|
+
{ host: 'redis-3', port: 6379 },
|
|
111
506
|
],
|
|
112
507
|
},
|
|
113
508
|
password: 'secret',
|
|
@@ -115,9 +510,218 @@ const queue = new JobQueue({
|
|
|
115
510
|
});
|
|
116
511
|
```
|
|
117
512
|
|
|
118
|
-
|
|
513
|
+
---
|
|
514
|
+
|
|
515
|
+
## Serialized Types
|
|
516
|
+
|
|
517
|
+
Jobs use serialized configurations that can be stored in Redis.
|
|
518
|
+
|
|
519
|
+
### SerializedAgent
|
|
520
|
+
|
|
521
|
+
```typescript
|
|
522
|
+
interface SerializedAgent {
|
|
523
|
+
name: string;
|
|
524
|
+
instructions: string;
|
|
525
|
+
model: string;
|
|
526
|
+
provider: 'ollama' | 'openai' | 'anthropic';
|
|
527
|
+
temperature?: number;
|
|
528
|
+
maxTokens?: number;
|
|
529
|
+
tools: ToolSchema[];
|
|
530
|
+
}
|
|
531
|
+
```
|
|
532
|
+
|
|
533
|
+
### SerializedWorkflow
|
|
534
|
+
|
|
535
|
+
```typescript
|
|
536
|
+
interface SerializedWorkflow {
|
|
537
|
+
id: string;
|
|
538
|
+
name: string;
|
|
539
|
+
nodes: SerializedWorkflowNode[];
|
|
540
|
+
edges: SerializedWorkflowEdge[];
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
interface SerializedWorkflowNode {
|
|
544
|
+
id: string;
|
|
545
|
+
type: 'agent' | 'transform' | 'condition' | 'parallel';
|
|
546
|
+
config: Record<string, unknown>;
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
interface SerializedWorkflowEdge {
|
|
550
|
+
from: string;
|
|
551
|
+
to: string;
|
|
552
|
+
condition?: string;
|
|
553
|
+
}
|
|
554
|
+
```
|
|
555
|
+
|
|
556
|
+
### SerializedSwarm
|
|
557
|
+
|
|
558
|
+
```typescript
|
|
559
|
+
interface SerializedSwarm {
|
|
560
|
+
topology: 'sequential' | 'hierarchical' | 'collaborative' | 'debate' | 'voting';
|
|
561
|
+
agents: SerializedAgent[];
|
|
562
|
+
coordinator?: SerializedAgent;
|
|
563
|
+
maxRounds?: number;
|
|
564
|
+
consensusThreshold?: number;
|
|
565
|
+
}
|
|
566
|
+
```
|
|
567
|
+
|
|
568
|
+
---
|
|
569
|
+
|
|
570
|
+
## Examples
|
|
571
|
+
|
|
572
|
+
### Complete Producer/Consumer
|
|
573
|
+
|
|
574
|
+
**Producer (producer.ts):**
|
|
575
|
+
|
|
576
|
+
```typescript
|
|
577
|
+
import { JobQueue } from '@cogitator-ai/worker';
|
|
578
|
+
|
|
579
|
+
const queue = new JobQueue({
|
|
580
|
+
redis: { host: 'localhost', port: 6379 },
|
|
581
|
+
});
|
|
582
|
+
|
|
583
|
+
async function main() {
|
|
584
|
+
const agentConfig = {
|
|
585
|
+
name: 'Summarizer',
|
|
586
|
+
instructions: 'Summarize the given text concisely.',
|
|
587
|
+
model: 'openai/gpt-4',
|
|
588
|
+
provider: 'openai' as const,
|
|
589
|
+
tools: [],
|
|
590
|
+
};
|
|
591
|
+
|
|
592
|
+
const texts = [
|
|
593
|
+
'Long article about technology...',
|
|
594
|
+
'Research paper on climate change...',
|
|
595
|
+
'News story about economics...',
|
|
596
|
+
];
|
|
597
|
+
|
|
598
|
+
for (const text of texts) {
|
|
599
|
+
const job = await queue.addAgentJob(agentConfig, text, {
|
|
600
|
+
priority: 1,
|
|
601
|
+
});
|
|
602
|
+
console.log(`Queued job: ${job.id}`);
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
await queue.close();
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
main();
|
|
609
|
+
```
|
|
610
|
+
|
|
611
|
+
**Consumer (consumer.ts):**
|
|
612
|
+
|
|
613
|
+
```typescript
|
|
614
|
+
import { WorkerPool } from '@cogitator-ai/worker';
|
|
615
|
+
|
|
616
|
+
const pool = new WorkerPool(
|
|
617
|
+
{
|
|
618
|
+
redis: { host: 'localhost', port: 6379 },
|
|
619
|
+
concurrency: 5,
|
|
620
|
+
},
|
|
621
|
+
{
|
|
622
|
+
onJobStarted: (id, type) => console.log(`Starting ${type} job: ${id}`),
|
|
623
|
+
onJobCompleted: (id, result) => console.log(`Completed: ${id}`, result),
|
|
624
|
+
onJobFailed: (id, error) => console.error(`Failed: ${id}`, error),
|
|
625
|
+
}
|
|
626
|
+
);
|
|
627
|
+
|
|
628
|
+
async function main() {
|
|
629
|
+
await pool.start();
|
|
630
|
+
console.log('Worker pool started');
|
|
631
|
+
|
|
632
|
+
process.on('SIGTERM', async () => {
|
|
633
|
+
console.log('Shutting down...');
|
|
634
|
+
await pool.stop(30000);
|
|
635
|
+
process.exit(0);
|
|
636
|
+
});
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
main();
|
|
640
|
+
```
|
|
641
|
+
|
|
642
|
+
### Job Status Monitoring
|
|
643
|
+
|
|
644
|
+
```typescript
|
|
645
|
+
import { JobQueue } from '@cogitator-ai/worker';
|
|
646
|
+
|
|
647
|
+
const queue = new JobQueue({
|
|
648
|
+
redis: { host: 'localhost', port: 6379 },
|
|
649
|
+
});
|
|
650
|
+
|
|
651
|
+
async function monitorJob(jobId: string) {
|
|
652
|
+
let lastState = '';
|
|
653
|
+
|
|
654
|
+
while (true) {
|
|
655
|
+
const state = await queue.getJobState(jobId);
|
|
656
|
+
|
|
657
|
+
if (state !== lastState) {
|
|
658
|
+
console.log(`Job ${jobId}: ${state}`);
|
|
659
|
+
lastState = state;
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
if (state === 'completed' || state === 'failed') {
|
|
663
|
+
const job = await queue.getJob(jobId);
|
|
664
|
+
if (job) {
|
|
665
|
+
console.log('Result:', await job.returnvalue);
|
|
666
|
+
}
|
|
667
|
+
break;
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
await new Promise((r) => setTimeout(r, 1000));
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
```
|
|
674
|
+
|
|
675
|
+
### Priority Processing
|
|
676
|
+
|
|
677
|
+
```typescript
|
|
678
|
+
await queue.addAgentJob(config, 'Low priority', { priority: 10 });
|
|
679
|
+
await queue.addAgentJob(config, 'Medium priority', { priority: 5 });
|
|
680
|
+
await queue.addAgentJob(config, 'High priority', { priority: 1 });
|
|
681
|
+
await queue.addAgentJob(config, 'Critical', { priority: 0 });
|
|
682
|
+
```
|
|
683
|
+
|
|
684
|
+
### Delayed Jobs
|
|
685
|
+
|
|
686
|
+
```typescript
|
|
687
|
+
await queue.addAgentJob(config, 'Run in 5 seconds', { delay: 5000 });
|
|
688
|
+
await queue.addAgentJob(config, 'Run in 1 minute', { delay: 60000 });
|
|
689
|
+
await queue.addAgentJob(config, 'Run in 1 hour', { delay: 3600000 });
|
|
690
|
+
```
|
|
691
|
+
|
|
692
|
+
---
|
|
693
|
+
|
|
694
|
+
## Type Reference
|
|
695
|
+
|
|
696
|
+
```typescript
|
|
697
|
+
import type {
|
|
698
|
+
// Serialized configs
|
|
699
|
+
SerializedAgent,
|
|
700
|
+
SerializedWorkflow,
|
|
701
|
+
SerializedWorkflowNode,
|
|
702
|
+
SerializedWorkflowEdge,
|
|
703
|
+
SerializedSwarm,
|
|
704
|
+
|
|
705
|
+
// Job payloads
|
|
706
|
+
JobPayload,
|
|
707
|
+
AgentJobPayload,
|
|
708
|
+
WorkflowJobPayload,
|
|
709
|
+
SwarmJobPayload,
|
|
710
|
+
|
|
711
|
+
// Job results
|
|
712
|
+
JobResult,
|
|
713
|
+
AgentJobResult,
|
|
714
|
+
WorkflowJobResult,
|
|
715
|
+
SwarmJobResult,
|
|
716
|
+
|
|
717
|
+
// Configuration
|
|
718
|
+
QueueConfig,
|
|
719
|
+
WorkerConfig,
|
|
720
|
+
QueueMetrics,
|
|
721
|
+
} from '@cogitator-ai/worker';
|
|
722
|
+
```
|
|
119
723
|
|
|
120
|
-
|
|
724
|
+
---
|
|
121
725
|
|
|
122
726
|
## License
|
|
123
727
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cogitator-ai/worker",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "Distributed job queue for Cogitator agent execution",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -18,11 +18,11 @@
|
|
|
18
18
|
"bullmq": "^5.34.8",
|
|
19
19
|
"nanoid": "^5.0.9",
|
|
20
20
|
"zod": "^3.22.4",
|
|
21
|
-
"@cogitator-ai/
|
|
22
|
-
"@cogitator-ai/swarms": "0.3.
|
|
23
|
-
"@cogitator-ai/
|
|
24
|
-
"@cogitator-ai/core": "0.
|
|
25
|
-
"@cogitator-ai/redis": "0.2.
|
|
21
|
+
"@cogitator-ai/types": "0.4.0",
|
|
22
|
+
"@cogitator-ai/swarms": "0.3.1",
|
|
23
|
+
"@cogitator-ai/workflows": "0.2.1",
|
|
24
|
+
"@cogitator-ai/core": "0.3.0",
|
|
25
|
+
"@cogitator-ai/redis": "0.2.1"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
28
|
"typescript": "^5.3.0",
|