@cogitator-ai/workflows 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.
Files changed (2) hide show
  1. package/README.md +850 -30
  2. package/package.json +3 -3
package/README.md CHANGED
@@ -1,6 +1,9 @@
1
1
  # @cogitator-ai/workflows
2
2
 
3
- DAG-based workflow engine for Cogitator agents. Build complex multi-step workflows with branching, loops, and checkpoints.
3
+ [![npm version](https://img.shields.io/npm/v/@cogitator-ai/workflows.svg)](https://www.npmjs.com/package/@cogitator-ai/workflows)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
+
6
+ DAG-based workflow engine for Cogitator agents. Build complex multi-step workflows with branching, loops, checkpoints, human-in-the-loop, timers, and more.
4
7
 
5
8
  ## Installation
6
9
 
@@ -8,46 +11,176 @@ DAG-based workflow engine for Cogitator agents. Build complex multi-step workflo
8
11
  pnpm add @cogitator-ai/workflows
9
12
  ```
10
13
 
11
- ## Usage
14
+ ## Features
15
+
16
+ - **DAG Builder** — Type-safe workflow construction with nodes, conditionals, loops
17
+ - **Checkpoints** — Save and resume workflow state
18
+ - **Pre-built Nodes** — Agent, tool, and function nodes
19
+ - **Timer System** — Delays, cron schedules, wait-until patterns
20
+ - **Saga Patterns** — Retries, circuit breakers, compensation, DLQ
21
+ - **Subworkflows** — Nested, parallel, fan-out/fan-in patterns
22
+ - **Human-in-the-Loop** — Approvals, choices, inputs, rating
23
+ - **Map-Reduce** — Parallel processing with aggregation
24
+ - **Triggers** — Cron, webhook, and event triggers
25
+ - **Observability** — Tracing and metrics with multiple exporters
12
26
 
13
- ### Basic Workflow
27
+ ## Quick Start
14
28
 
15
29
  ```typescript
16
- import { WorkflowBuilder, WorkflowExecutor } from '@cogitator-ai/workflows';
30
+ import { WorkflowBuilder, WorkflowExecutor, agentNode } from '@cogitator-ai/workflows';
31
+ import { Cogitator, Agent } from '@cogitator-ai/core';
32
+
33
+ const cogitator = new Cogitator({
34
+ /* config */
35
+ });
36
+ const analyst = new Agent({ name: 'analyst', model: 'openai/gpt-4o', instructions: '...' });
37
+
38
+ const workflow = new WorkflowBuilder('data-pipeline')
39
+ .addNode('analyze', agentNode(analyst))
40
+ .addNode('report', async (ctx) => ({ output: `Report: ${ctx.state.analysis}` }))
41
+ .build();
42
+
43
+ const executor = new WorkflowExecutor(cogitator);
44
+ const result = await executor.execute(workflow, { input: 'Analyze this data...' });
45
+ ```
46
+
47
+ ---
17
48
 
18
- const workflow = new WorkflowBuilder<{ count: number }>('counter')
49
+ ## Table of Contents
50
+
51
+ - [Core Concepts](#core-concepts)
52
+ - [Pre-built Nodes](#pre-built-nodes)
53
+ - [Conditional Branching](#conditional-branching)
54
+ - [Loops](#loops)
55
+ - [Checkpoints](#checkpoints)
56
+ - [Timer System](#timer-system)
57
+ - [Saga Patterns](#saga-patterns)
58
+ - [Subworkflows](#subworkflows)
59
+ - [Human-in-the-Loop](#human-in-the-loop)
60
+ - [Map-Reduce Patterns](#map-reduce-patterns)
61
+ - [Triggers](#triggers)
62
+ - [Observability](#observability)
63
+ - [Workflow Management](#workflow-management)
64
+
65
+ ---
66
+
67
+ ## Core Concepts
68
+
69
+ ### WorkflowBuilder
70
+
71
+ ```typescript
72
+ import { WorkflowBuilder } from '@cogitator-ai/workflows';
73
+
74
+ const workflow = new WorkflowBuilder<MyState>('my-workflow')
19
75
  .initialState({ count: 0 })
20
- .addNode('increment', async (ctx) => ({
21
- state: { count: ctx.state.count + 1 },
22
- }))
23
- .addNode('done', async (ctx) => ({
24
- output: `Final count: ${ctx.state.count}`,
76
+ .addNode('step1', async (ctx) => ({
77
+ state: { ...ctx.state, count: ctx.state.count + 1 },
25
78
  }))
79
+ .addNode(
80
+ 'step2',
81
+ async (ctx) => ({
82
+ output: `Count: ${ctx.state.count}`,
83
+ }),
84
+ { after: ['step1'] }
85
+ )
26
86
  .build();
87
+ ```
88
+
89
+ ### WorkflowExecutor
90
+
91
+ ```typescript
92
+ import { WorkflowExecutor } from '@cogitator-ai/workflows';
27
93
 
28
94
  const executor = new WorkflowExecutor(cogitator);
29
- const result = await executor.execute(workflow);
95
+ const result = await executor.execute(workflow, {
96
+ input: 'Start the workflow',
97
+ context: { userId: '123' },
98
+ timeout: 60000,
99
+ });
100
+
101
+ console.log(result.output);
102
+ console.log(result.state);
103
+ console.log(result.events);
104
+ ```
105
+
106
+ ---
107
+
108
+ ## Pre-built Nodes
109
+
110
+ ### agentNode
111
+
112
+ Run an agent as a workflow node:
113
+
114
+ ```typescript
115
+ import { agentNode } from '@cogitator-ai/workflows';
116
+
117
+ const workflow = new WorkflowBuilder('agent-flow')
118
+ .addNode(
119
+ 'research',
120
+ agentNode(researchAgent, {
121
+ promptKey: 'researchPrompt', // State key for input
122
+ outputKey: 'researchResult', // State key for output
123
+ timeout: 30000,
124
+ onToolCall: (call) => console.log('Tool:', call.name),
125
+ })
126
+ )
127
+ .build();
30
128
  ```
31
129
 
32
- ### Conditional Branching
130
+ ### toolNode
131
+
132
+ Execute a tool directly:
133
+
134
+ ```typescript
135
+ import { toolNode } from '@cogitator-ai/workflows';
136
+
137
+ const workflow = new WorkflowBuilder('tool-flow')
138
+ .addNode('calculate', toolNode('calculator', { expression: '2 + 2' }))
139
+ .build();
140
+ ```
141
+
142
+ ### functionNode
143
+
144
+ Custom function as a node:
33
145
 
34
146
  ```typescript
35
- const workflow = new WorkflowBuilder('approval')
147
+ import { functionNode } from '@cogitator-ai/workflows';
148
+
149
+ const workflow = new WorkflowBuilder('func-flow')
150
+ .addNode(
151
+ 'transform',
152
+ functionNode(async (ctx) => {
153
+ const transformed = processData(ctx.state.data);
154
+ return { state: { ...ctx.state, transformed } };
155
+ })
156
+ )
157
+ .build();
158
+ ```
159
+
160
+ ---
161
+
162
+ ## Conditional Branching
163
+
164
+ ```typescript
165
+ const workflow = new WorkflowBuilder('approval-flow')
36
166
  .addNode('review', reviewNode)
37
167
  .addConditional('check', (state) => state.approved, {
38
168
  after: ['review'],
39
169
  })
40
170
  .addNode('approve', approveNode, { after: ['check:true'] })
41
171
  .addNode('reject', rejectNode, { after: ['check:false'] })
172
+ .addNode('notify', notifyNode, { after: ['approve', 'reject'] })
42
173
  .build();
43
174
  ```
44
175
 
45
- ### Loops
176
+ ---
177
+
178
+ ## Loops
46
179
 
47
180
  ```typescript
48
- const workflow = new WorkflowBuilder('retry')
181
+ const workflow = new WorkflowBuilder('retry-flow')
49
182
  .addNode('attempt', attemptNode)
50
- .addLoop('check', {
183
+ .addLoop('retry-check', {
51
184
  condition: (state) => !state.success && state.attempts < 3,
52
185
  back: 'attempt',
53
186
  exit: 'done',
@@ -57,43 +190,730 @@ const workflow = new WorkflowBuilder('retry')
57
190
  .build();
58
191
  ```
59
192
 
60
- ### Checkpoints
193
+ ---
194
+
195
+ ## Checkpoints
61
196
 
62
- Resume workflows from saved state:
197
+ Save and resume workflow execution:
63
198
 
64
199
  ```typescript
65
- import { FileCheckpointStore } from '@cogitator-ai/workflows';
200
+ import { FileCheckpointStore, InMemoryCheckpointStore } from '@cogitator-ai/workflows';
66
201
 
202
+ // File-based persistence
67
203
  const store = new FileCheckpointStore('./checkpoints');
68
204
 
69
- // Save checkpoint
205
+ // Execute with checkpoints
70
206
  await executor.execute(workflow, {
71
207
  checkpointStore: store,
72
- checkpointInterval: 5000,
208
+ checkpointInterval: 5000, // Save every 5 seconds
73
209
  });
74
210
 
75
211
  // Resume from checkpoint
76
212
  const result = await executor.resume(checkpointId, store);
77
213
  ```
78
214
 
79
- ### Pre-built Nodes
215
+ ---
216
+
217
+ ## Timer System
218
+
219
+ ### Delay Nodes
220
+
221
+ ```typescript
222
+ import { delayNode, dynamicDelayNode, cronWaitNode, untilNode } from '@cogitator-ai/workflows';
223
+
224
+ const workflow = new WorkflowBuilder('timer-flow')
225
+ // Fixed delay
226
+ .addNode('wait', delayNode(5000)) // 5 seconds
227
+
228
+ // Dynamic delay based on state
229
+ .addNode(
230
+ 'dynamic-wait',
231
+ dynamicDelayNode((state) => state.retryCount * 1000)
232
+ )
233
+
234
+ // Wait for cron schedule
235
+ .addNode('cron-wait', cronWaitNode('0 9 * * *')) // Wait until 9 AM
236
+
237
+ // Wait until specific date
238
+ .addNode(
239
+ 'until',
240
+ untilNode((state) => state.scheduledTime)
241
+ )
242
+ .build();
243
+ ```
244
+
245
+ ### Duration Parsing
246
+
247
+ ```typescript
248
+ import { parseDuration, formatDuration } from '@cogitator-ai/workflows';
249
+
250
+ const ms = parseDuration('1h30m'); // 5400000
251
+ const str = formatDuration(5400000); // '1h 30m'
252
+ ```
253
+
254
+ ### Cron Utilities
255
+
256
+ ```typescript
257
+ import {
258
+ validateCronExpression,
259
+ getNextCronOccurrence,
260
+ getNextCronOccurrences,
261
+ describeCronExpression,
262
+ CRON_PRESETS,
263
+ } from '@cogitator-ai/workflows';
264
+
265
+ // Validate
266
+ const valid = validateCronExpression('0 9 * * 1-5'); // true
267
+
268
+ // Get next occurrence
269
+ const next = getNextCronOccurrence('0 9 * * *');
270
+
271
+ // Get multiple occurrences
272
+ const nextFive = getNextCronOccurrences('0 9 * * *', 5);
273
+
274
+ // Human-readable description
275
+ const desc = describeCronExpression('0 9 * * 1-5'); // "At 09:00 on weekdays"
276
+
277
+ // Presets
278
+ CRON_PRESETS.EVERY_MINUTE; // '* * * * *'
279
+ CRON_PRESETS.HOURLY; // '0 * * * *'
280
+ CRON_PRESETS.DAILY; // '0 0 * * *'
281
+ CRON_PRESETS.WEEKLY; // '0 0 * * 0'
282
+ CRON_PRESETS.MONTHLY; // '0 0 1 * *'
283
+ ```
284
+
285
+ ### TimerManager
286
+
287
+ Manage recurring timers:
288
+
289
+ ```typescript
290
+ import { createTimerManager, createRecurringScheduler } from '@cogitator-ai/workflows';
291
+
292
+ const manager = createTimerManager({
293
+ maxConcurrent: 10,
294
+ defaultTimeout: 60000,
295
+ });
296
+
297
+ // One-shot timer
298
+ manager.schedule('task-1', 5000, async () => {
299
+ console.log('Executed after 5 seconds');
300
+ });
301
+
302
+ // Recurring timer
303
+ const scheduler = createRecurringScheduler();
304
+ scheduler.schedule('daily-report', '0 9 * * *', async () => {
305
+ await generateDailyReport();
306
+ });
307
+ ```
308
+
309
+ ---
310
+
311
+ ## Saga Patterns
312
+
313
+ ### Retry with Backoff
314
+
315
+ ```typescript
316
+ import { executeWithRetry, withRetry, Retryable } from '@cogitator-ai/workflows';
317
+
318
+ // Function wrapper
319
+ const result = await executeWithRetry(async () => await unreliableOperation(), {
320
+ maxAttempts: 5,
321
+ initialDelay: 1000,
322
+ maxDelay: 30000,
323
+ backoffMultiplier: 2,
324
+ jitter: 0.1,
325
+ shouldRetry: (error) => error.code !== 'FATAL',
326
+ onRetry: (attempt, error, delay) => console.log(`Retry ${attempt} in ${delay}ms`),
327
+ });
328
+
329
+ // Decorator-style
330
+ const retryableFetch = withRetry({ maxAttempts: 3 })(async (url: string) => await fetch(url));
331
+
332
+ // Class decorator
333
+ class ApiClient {
334
+ @Retryable({ maxAttempts: 3, initialDelay: 500 })
335
+ async request(endpoint: string) {
336
+ return fetch(endpoint);
337
+ }
338
+ }
339
+ ```
340
+
341
+ ### Circuit Breaker
342
+
343
+ ```typescript
344
+ import { CircuitBreaker, createCircuitBreaker, WithCircuitBreaker } from '@cogitator-ai/workflows';
345
+
346
+ const breaker = createCircuitBreaker({
347
+ failureThreshold: 5,
348
+ successThreshold: 2,
349
+ timeout: 30000,
350
+ halfOpenMaxAttempts: 3,
351
+ onStateChange: (from, to) => console.log(`Circuit: ${from} -> ${to}`),
352
+ });
353
+
354
+ // Use the breaker
355
+ try {
356
+ const result = await breaker.execute(async () => {
357
+ return await externalService.call();
358
+ });
359
+ } catch (error) {
360
+ if (error instanceof CircuitBreakerOpenError) {
361
+ console.log('Circuit is open, using fallback');
362
+ }
363
+ }
364
+
365
+ // Get stats
366
+ const stats = breaker.getStats();
367
+ console.log(stats.failures, stats.successes, stats.state);
368
+
369
+ // Decorator-style
370
+ class ServiceClient {
371
+ @WithCircuitBreaker({ failureThreshold: 3 })
372
+ async call() {
373
+ return fetch('/api');
374
+ }
375
+ }
376
+ ```
377
+
378
+ ### Compensation (Saga)
379
+
380
+ ```typescript
381
+ import { CompensationManager, compensationBuilder } from '@cogitator-ai/workflows';
382
+
383
+ const saga = compensationBuilder<{ orderId: string }>()
384
+ .step({
385
+ name: 'reserve-inventory',
386
+ execute: async (ctx) => {
387
+ ctx.state.inventoryReserved = await inventory.reserve(ctx.data.orderId);
388
+ },
389
+ compensate: async (ctx) => {
390
+ await inventory.release(ctx.data.orderId);
391
+ },
392
+ })
393
+ .step({
394
+ name: 'charge-payment',
395
+ execute: async (ctx) => {
396
+ ctx.state.paymentId = await payments.charge(ctx.data.orderId);
397
+ },
398
+ compensate: async (ctx) => {
399
+ await payments.refund(ctx.state.paymentId);
400
+ },
401
+ })
402
+ .step({
403
+ name: 'ship-order',
404
+ execute: async (ctx) => {
405
+ await shipping.ship(ctx.data.orderId);
406
+ },
407
+ compensate: async (ctx) => {
408
+ await shipping.cancel(ctx.data.orderId);
409
+ },
410
+ })
411
+ .build();
412
+
413
+ const manager = new CompensationManager();
414
+ const result = await manager.execute(saga, { orderId: 'order-123' });
415
+
416
+ if (!result.success) {
417
+ console.log('Saga failed at:', result.failedStep);
418
+ console.log('Compensated steps:', result.compensatedSteps);
419
+ }
420
+ ```
421
+
422
+ ### Dead Letter Queue (DLQ)
423
+
424
+ ```typescript
425
+ import { createFileDLQ, createInMemoryDLQ } from '@cogitator-ai/workflows';
426
+
427
+ const dlq = createFileDLQ('./dlq');
428
+
429
+ // Add failed item
430
+ await dlq.add({
431
+ id: 'job-123',
432
+ payload: { orderId: 'order-456' },
433
+ error: 'Payment failed',
434
+ source: 'checkout-workflow',
435
+ attemptCount: 3,
436
+ });
437
+
438
+ // Process DLQ
439
+ const items = await dlq.list({ source: 'checkout-workflow' });
440
+ for (const item of items) {
441
+ try {
442
+ await retryJob(item.payload);
443
+ await dlq.remove(item.id);
444
+ } catch {
445
+ await dlq.update(item.id, { attemptCount: item.attemptCount + 1 });
446
+ }
447
+ }
448
+ ```
449
+
450
+ ### Idempotency
451
+
452
+ ```typescript
453
+ import { idempotent, Idempotent, createFileIdempotencyStore } from '@cogitator-ai/workflows';
454
+
455
+ const store = createFileIdempotencyStore('./idempotency');
456
+
457
+ // Function wrapper
458
+ const processOrder = idempotent(store, {
459
+ keyGenerator: (orderId: string) => `order:${orderId}`,
460
+ ttl: 24 * 60 * 60 * 1000, // 24 hours
461
+ })(async (orderId: string) => {
462
+ return await processOrderInternal(orderId);
463
+ });
464
+
465
+ // Safe to call multiple times
466
+ await processOrder('order-123'); // Executes
467
+ await processOrder('order-123'); // Returns cached result
468
+
469
+ // Decorator-style
470
+ class OrderService {
471
+ @Idempotent({ keyGenerator: (id) => `order:${id}`, ttl: 86400000 })
472
+ async process(orderId: string) {
473
+ return processOrderInternal(orderId);
474
+ }
475
+ }
476
+ ```
477
+
478
+ ---
479
+
480
+ ## Subworkflows
481
+
482
+ ### Nested Subworkflows
483
+
484
+ ```typescript
485
+ import { subworkflowNode, executeSubworkflow } from '@cogitator-ai/workflows';
486
+
487
+ const mainWorkflow = new WorkflowBuilder('main')
488
+ .addNode('prepare', prepareNode)
489
+ .addNode(
490
+ 'process',
491
+ subworkflowNode(processingWorkflow, {
492
+ inputMapper: (state) => ({ items: state.items }),
493
+ outputMapper: (result) => ({ processedItems: result.output }),
494
+ maxDepth: 5,
495
+ errorStrategy: 'fail', // 'fail' | 'continue' | 'compensate'
496
+ })
497
+ )
498
+ .addNode('finalize', finalizeNode, { after: ['process'] })
499
+ .build();
500
+ ```
501
+
502
+ ### Parallel Subworkflows
503
+
504
+ ```typescript
505
+ import { parallelSubworkflows, fanOutFanIn, scatterGather } from '@cogitator-ai/workflows';
506
+
507
+ // Fan-out/Fan-in pattern
508
+ const workflow = new WorkflowBuilder('parallel')
509
+ .addNode(
510
+ 'distribute',
511
+ fanOutFanIn(
512
+ [
513
+ { workflow: workflowA, input: { type: 'a' } },
514
+ { workflow: workflowB, input: { type: 'b' } },
515
+ { workflow: workflowC, input: { type: 'c' } },
516
+ ],
517
+ {
518
+ concurrency: 3,
519
+ onProgress: (completed, total) => console.log(`${completed}/${total}`),
520
+ }
521
+ )
522
+ )
523
+ .build();
524
+
525
+ // Scatter-Gather (collect all results)
526
+ const results = await scatterGather(executor, workflows, inputs);
527
+
528
+ // Race (first to complete wins)
529
+ const winner = await raceSubworkflows(executor, [workflow1, workflow2]);
530
+
531
+ // Fallback (try until one succeeds)
532
+ const result = await fallbackSubworkflows(executor, [primary, secondary, tertiary]);
533
+ ```
534
+
535
+ ---
536
+
537
+ ## Human-in-the-Loop
538
+
539
+ ### Approval Node
540
+
541
+ ```typescript
542
+ import { approvalNode, InMemoryApprovalStore, WebhookNotifier } from '@cogitator-ai/workflows';
543
+
544
+ const store = new InMemoryApprovalStore();
545
+ const notifier = new WebhookNotifier('https://slack.webhook.url');
546
+
547
+ const workflow = new WorkflowBuilder('approval-flow')
548
+ .addNode(
549
+ 'request',
550
+ approvalNode({
551
+ message: (state) => `Approve expense: $${state.amount}`,
552
+ approvers: ['manager@company.com'],
553
+ timeout: 24 * 60 * 60 * 1000, // 24 hours
554
+ store,
555
+ notifier,
556
+ })
557
+ )
558
+ .addConditional('check', (state) => state.approved, { after: ['request'] })
559
+ .addNode('process', processNode, { after: ['check:true'] })
560
+ .addNode('reject', rejectNode, { after: ['check:false'] })
561
+ .build();
562
+ ```
563
+
564
+ ### Choice Node
565
+
566
+ ```typescript
567
+ import { choiceNode } from '@cogitator-ai/workflows';
568
+
569
+ const workflow = new WorkflowBuilder('choice-flow')
570
+ .addNode(
571
+ 'select',
572
+ choiceNode({
573
+ message: 'Select processing method:',
574
+ choices: [
575
+ { id: 'fast', label: 'Fast (less accurate)', value: 'fast' },
576
+ { id: 'accurate', label: 'Accurate (slower)', value: 'accurate' },
577
+ ],
578
+ store,
579
+ notifier,
580
+ })
581
+ )
582
+ .build();
583
+ ```
584
+
585
+ ### Input Node
586
+
587
+ ```typescript
588
+ import { inputNode } from '@cogitator-ai/workflows';
589
+
590
+ const workflow = new WorkflowBuilder('input-flow')
591
+ .addNode(
592
+ 'get-details',
593
+ inputNode({
594
+ message: 'Please provide additional details:',
595
+ fields: [
596
+ { name: 'reason', type: 'text', required: true },
597
+ { name: 'priority', type: 'select', options: ['low', 'medium', 'high'] },
598
+ ],
599
+ store,
600
+ notifier,
601
+ })
602
+ )
603
+ .build();
604
+ ```
605
+
606
+ ### Approval Chains
80
607
 
81
608
  ```typescript
82
- import { agentNode, toolNode, functionNode } from '@cogitator-ai/workflows';
609
+ import { managementChain, chainNode } from '@cogitator-ai/workflows';
83
610
 
84
- const workflow = new WorkflowBuilder('pipeline')
85
- .addNode('analyze', agentNode(analyzerAgent))
86
- .addNode('transform', toolNode('json-transform', { mapping: '...' }))
611
+ const workflow = new WorkflowBuilder('chain-approval')
87
612
  .addNode(
88
- 'validate',
89
- functionNode(async (ctx) => ({ valid: true }))
613
+ 'approval',
614
+ managementChain({
615
+ steps: [
616
+ { approver: 'team-lead@co.com', requiredFor: (state) => state.amount > 100 },
617
+ { approver: 'manager@co.com', requiredFor: (state) => state.amount > 1000 },
618
+ { approver: 'director@co.com', requiredFor: (state) => state.amount > 10000 },
619
+ ],
620
+ store,
621
+ notifier,
622
+ })
90
623
  )
91
624
  .build();
92
625
  ```
93
626
 
94
- ## Documentation
627
+ ---
628
+
629
+ ## Map-Reduce Patterns
630
+
631
+ ### Map (Parallel Processing)
632
+
633
+ ```typescript
634
+ import { mapNode, parallelMap, batchedMap } from '@cogitator-ai/workflows';
635
+
636
+ const workflow = new WorkflowBuilder('map-flow')
637
+ .addNode(
638
+ 'process-items',
639
+ mapNode({
640
+ items: (state) => state.items,
641
+ mapper: async (item, index, ctx) => {
642
+ return await processItem(item);
643
+ },
644
+ concurrency: 5,
645
+ onProgress: ({ completed, total }) => console.log(`${completed}/${total}`),
646
+ })
647
+ )
648
+ .build();
649
+
650
+ // Batched processing
651
+ const results = await batchedMap(items, processItem, { batchSize: 10, concurrency: 3 });
652
+ ```
653
+
654
+ ### Reduce (Aggregation)
655
+
656
+ ```typescript
657
+ import { reduceNode, collect, sum, groupBy, stats } from '@cogitator-ai/workflows';
658
+
659
+ const workflow = new WorkflowBuilder('reduce-flow')
660
+ .addNode(
661
+ 'aggregate',
662
+ reduceNode({
663
+ items: (state) => state.results,
664
+ reducer: (acc, item) => acc + item.value,
665
+ initialValue: 0,
666
+ })
667
+ )
668
+ .build();
669
+
670
+ // Built-in aggregators
671
+ const collected = collect(items); // Collect all
672
+ const total = sum(items, (i) => i.value); // Sum values
673
+ const grouped = groupBy(items, (i) => i.category); // Group by key
674
+ const statistics = stats(items, (i) => i.score); // { min, max, avg, sum, count }
675
+ ```
676
+
677
+ ### Map-Reduce
678
+
679
+ ```typescript
680
+ import { mapReduceNode, executeMapReduce } from '@cogitator-ai/workflows';
681
+
682
+ const workflow = new WorkflowBuilder('mapreduce-flow')
683
+ .addNode(
684
+ 'word-count',
685
+ mapReduceNode({
686
+ items: (state) => state.documents,
687
+ mapper: async (doc) => {
688
+ const words = doc.text.split(/\s+/);
689
+ return words.map((w) => ({ word: w, count: 1 }));
690
+ },
691
+ reducer: (results) => {
692
+ return results.flat().reduce((acc, { word, count }) => {
693
+ acc[word] = (acc[word] || 0) + count;
694
+ return acc;
695
+ }, {});
696
+ },
697
+ concurrency: 10,
698
+ })
699
+ )
700
+ .build();
701
+ ```
702
+
703
+ ---
704
+
705
+ ## Triggers
706
+
707
+ ### Cron Trigger
708
+
709
+ ```typescript
710
+ import { createCronTrigger, CronTriggerExecutor } from '@cogitator-ai/workflows';
711
+
712
+ const trigger = createCronTrigger({
713
+ expression: '0 9 * * 1-5', // 9 AM on weekdays
714
+ timezone: 'America/New_York',
715
+ workflow: dailyReportWorkflow,
716
+ executor,
717
+ onTrigger: (time) => console.log('Triggered at:', time),
718
+ });
719
+
720
+ trigger.start();
721
+ // Later: trigger.stop();
722
+ ```
723
+
724
+ ### Webhook Trigger
725
+
726
+ ```typescript
727
+ import { createWebhookTrigger, WebhookTriggerExecutor } from '@cogitator-ai/workflows';
728
+
729
+ const webhook = createWebhookTrigger({
730
+ path: '/webhooks/github',
731
+ workflow: githubEventWorkflow,
732
+ executor,
733
+ auth: {
734
+ type: 'hmac',
735
+ secret: process.env.WEBHOOK_SECRET!,
736
+ header: 'X-Hub-Signature-256',
737
+ },
738
+ rateLimit: {
739
+ maxRequests: 100,
740
+ windowMs: 60000,
741
+ },
742
+ inputMapper: (req) => ({ event: req.body.action, payload: req.body }),
743
+ });
744
+
745
+ // Handle incoming request
746
+ const result = await webhook.handle(request);
747
+ ```
748
+
749
+ ### Trigger Manager
750
+
751
+ ```typescript
752
+ import {
753
+ createTriggerManager,
754
+ cronTrigger,
755
+ webhookTrigger,
756
+ eventTrigger,
757
+ } from '@cogitator-ai/workflows';
758
+
759
+ const manager = createTriggerManager({ executor });
760
+
761
+ manager.register(
762
+ 'daily-report',
763
+ cronTrigger({
764
+ expression: '0 9 * * *',
765
+ workflow: reportWorkflow,
766
+ })
767
+ );
768
+
769
+ manager.register(
770
+ 'github-webhook',
771
+ webhookTrigger({
772
+ path: '/hooks/github',
773
+ workflow: githubWorkflow,
774
+ })
775
+ );
776
+
777
+ manager.register(
778
+ 'order-created',
779
+ eventTrigger({
780
+ event: 'order.created',
781
+ workflow: orderProcessingWorkflow,
782
+ })
783
+ );
784
+
785
+ await manager.startAll();
786
+ ```
787
+
788
+ ---
789
+
790
+ ## Observability
791
+
792
+ ### Tracing
793
+
794
+ ```typescript
795
+ import {
796
+ createTracer,
797
+ OTLPSpanExporter,
798
+ ZipkinSpanExporter,
799
+ CompositeSpanExporter,
800
+ } from '@cogitator-ai/workflows';
801
+
802
+ // OTLP exporter (Jaeger, Tempo, etc.)
803
+ const otlpExporter = new OTLPSpanExporter({
804
+ endpoint: 'http://localhost:4318/v1/traces',
805
+ headers: { 'X-Api-Key': 'secret' },
806
+ });
807
+
808
+ // Zipkin exporter
809
+ const zipkinExporter = new ZipkinSpanExporter({
810
+ endpoint: 'http://localhost:9411/api/v2/spans',
811
+ });
812
+
813
+ // Composite (multiple exporters)
814
+ const exporter = new CompositeSpanExporter([otlpExporter, zipkinExporter]);
815
+
816
+ const tracer = createTracer({
817
+ serviceName: 'my-workflow-service',
818
+ exporter,
819
+ });
820
+
821
+ // Execute with tracing
822
+ await executor.execute(workflow, { tracer });
823
+ ```
824
+
825
+ ### Metrics
826
+
827
+ ```typescript
828
+ import { createMetricsCollector, WorkflowMetricsCollector } from '@cogitator-ai/workflows';
829
+
830
+ const metrics = createMetricsCollector({
831
+ prefix: 'cogitator_workflow',
832
+ labels: { environment: 'production' },
833
+ });
834
+
835
+ // Execute with metrics
836
+ await executor.execute(workflow, { metrics });
837
+
838
+ // Get metrics
839
+ const nodeMetrics = metrics.getNodeMetrics('my-node');
840
+ console.log(nodeMetrics.executionCount);
841
+ console.log(nodeMetrics.averageDuration);
842
+ console.log(nodeMetrics.errorRate);
843
+
844
+ const workflowMetrics = metrics.getWorkflowMetrics('my-workflow');
845
+ console.log(workflowMetrics.completionRate);
846
+ console.log(workflowMetrics.averageCompletionTime);
847
+ ```
848
+
849
+ ---
850
+
851
+ ## Workflow Management
852
+
853
+ ### WorkflowManager
854
+
855
+ ```typescript
856
+ import { createWorkflowManager, createFileRunStore } from '@cogitator-ai/workflows';
857
+
858
+ const runStore = createFileRunStore('./runs');
859
+
860
+ const manager = createWorkflowManager({
861
+ executor,
862
+ runStore,
863
+ concurrency: 10,
864
+ defaultTimeout: 300000,
865
+ });
866
+
867
+ // Schedule a workflow run
868
+ const runId = await manager.schedule(workflow, {
869
+ input: 'Process this',
870
+ priority: 1,
871
+ scheduledAt: new Date(Date.now() + 60000), // 1 minute from now
872
+ tags: ['daily', 'report'],
873
+ });
874
+
875
+ // Get run status
876
+ const run = await manager.getRun(runId);
877
+ console.log(run.status); // 'pending' | 'running' | 'completed' | 'failed' | 'cancelled'
878
+
879
+ // List runs
880
+ const runs = await manager.listRuns({
881
+ status: 'running',
882
+ workflowId: 'daily-report',
883
+ fromDate: new Date('2024-01-01'),
884
+ });
885
+
886
+ // Cancel a run
887
+ await manager.cancel(runId);
888
+
889
+ // Get stats
890
+ const stats = await manager.getStats();
891
+ console.log(stats.pending, stats.running, stats.completed, stats.failed);
892
+ ```
893
+
894
+ ### JobScheduler
895
+
896
+ ```typescript
897
+ import { createJobScheduler, PriorityQueue } from '@cogitator-ai/workflows';
898
+
899
+ const scheduler = createJobScheduler({
900
+ concurrency: 5,
901
+ maxQueueSize: 1000,
902
+ });
903
+
904
+ // Add jobs with priority
905
+ scheduler.enqueue({ id: 'job-1', payload: data1, priority: 1 });
906
+ scheduler.enqueue({ id: 'job-2', payload: data2, priority: 10 }); // Higher priority
907
+
908
+ // Process jobs
909
+ scheduler.process(async (job) => {
910
+ await processJob(job.payload);
911
+ });
912
+
913
+ scheduler.start();
914
+ ```
95
915
 
96
- See the [Cogitator documentation](https://github.com/eL1fe/cogitator) for full API reference.
916
+ ---
97
917
 
98
918
  ## License
99
919
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cogitator-ai/workflows",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "DAG-based workflow engine for Cogitator agents",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -18,8 +18,8 @@
18
18
  "@types/node": "^25.0.0",
19
19
  "cron-parser": "^4.9.0",
20
20
  "nanoid": "^5.0.4",
21
- "@cogitator-ai/core": "0.2.0",
22
- "@cogitator-ai/types": "0.3.1"
21
+ "@cogitator-ai/core": "0.3.0",
22
+ "@cogitator-ai/types": "0.4.0"
23
23
  },
24
24
  "devDependencies": {
25
25
  "typescript": "^5.3.0",