ai-workflows 2.1.1 → 2.1.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.
Files changed (78) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/.turbo/turbo-test.log +165 -3
  3. package/CHANGELOG.md +10 -1
  4. package/LICENSE +21 -0
  5. package/README.md +303 -184
  6. package/dist/barrier.d.ts +153 -0
  7. package/dist/barrier.d.ts.map +1 -0
  8. package/dist/barrier.js +339 -0
  9. package/dist/barrier.js.map +1 -0
  10. package/dist/cascade-context.d.ts +149 -0
  11. package/dist/cascade-context.d.ts.map +1 -0
  12. package/dist/cascade-context.js +324 -0
  13. package/dist/cascade-context.js.map +1 -0
  14. package/dist/cascade-executor.d.ts +196 -0
  15. package/dist/cascade-executor.d.ts.map +1 -0
  16. package/dist/cascade-executor.js +384 -0
  17. package/dist/cascade-executor.js.map +1 -0
  18. package/dist/context.d.ts.map +1 -1
  19. package/dist/context.js +4 -1
  20. package/dist/context.js.map +1 -1
  21. package/dist/dependency-graph.d.ts +157 -0
  22. package/dist/dependency-graph.d.ts.map +1 -0
  23. package/dist/dependency-graph.js +382 -0
  24. package/dist/dependency-graph.js.map +1 -0
  25. package/dist/every.d.ts +31 -2
  26. package/dist/every.d.ts.map +1 -1
  27. package/dist/every.js +63 -32
  28. package/dist/every.js.map +1 -1
  29. package/dist/graph/index.d.ts +8 -0
  30. package/dist/graph/index.d.ts.map +1 -0
  31. package/dist/graph/index.js +8 -0
  32. package/dist/graph/index.js.map +1 -0
  33. package/dist/graph/topological-sort.d.ts +121 -0
  34. package/dist/graph/topological-sort.d.ts.map +1 -0
  35. package/dist/graph/topological-sort.js +292 -0
  36. package/dist/graph/topological-sort.js.map +1 -0
  37. package/dist/index.d.ts +6 -1
  38. package/dist/index.d.ts.map +1 -1
  39. package/dist/index.js +10 -0
  40. package/dist/index.js.map +1 -1
  41. package/dist/on.d.ts +35 -10
  42. package/dist/on.d.ts.map +1 -1
  43. package/dist/on.js +52 -18
  44. package/dist/on.js.map +1 -1
  45. package/dist/timer-registry.d.ts +52 -0
  46. package/dist/timer-registry.d.ts.map +1 -0
  47. package/dist/timer-registry.js +120 -0
  48. package/dist/timer-registry.js.map +1 -0
  49. package/dist/types.d.ts +88 -0
  50. package/dist/types.d.ts.map +1 -1
  51. package/dist/types.js +17 -1
  52. package/dist/types.js.map +1 -1
  53. package/dist/workflow.d.ts.map +1 -1
  54. package/dist/workflow.js +15 -11
  55. package/dist/workflow.js.map +1 -1
  56. package/package.json +11 -11
  57. package/src/barrier.ts +466 -0
  58. package/src/cascade-context.ts +488 -0
  59. package/src/cascade-executor.ts +587 -0
  60. package/src/context.ts +12 -7
  61. package/src/dependency-graph.ts +518 -0
  62. package/src/every.ts +104 -35
  63. package/src/graph/index.ts +19 -0
  64. package/src/graph/topological-sort.ts +414 -0
  65. package/src/index.ts +78 -0
  66. package/src/on.ts +81 -25
  67. package/src/timer-registry.ts +145 -0
  68. package/src/types.ts +121 -0
  69. package/src/workflow.ts +23 -16
  70. package/test/barrier-join.test.ts +434 -0
  71. package/test/barrier-unhandled-rejections.test.ts +359 -0
  72. package/test/cascade-context.test.ts +390 -0
  73. package/test/cascade-executor.test.ts +859 -0
  74. package/test/dependency-graph.test.ts +512 -0
  75. package/test/graph/topological-sort.test.ts +586 -0
  76. package/test/schedule-timer-cleanup.test.ts +344 -0
  77. package/test/send-race-conditions.test.ts +410 -0
  78. package/test/type-safety-every.test.ts +303 -0
package/README.md CHANGED
@@ -1,13 +1,14 @@
1
1
  # ai-workflows
2
2
 
3
- Event-driven workflows with the `$` context. Handle events, schedule tasks, and orchestrate processes.
3
+ **Event-driven AI workflows shouldn't require a PhD in distributed systems.**
4
+
5
+ You have business logic that needs to react to events, run on schedules, and coordinate parallel tasks. Traditional workflow engines make you wade through XML configs, learn proprietary DSLs, and debug mysterious state machines. You just want to write `$.on.Order.placed(handler)` and have it work.
4
6
 
5
7
  ```typescript
6
8
  import { Workflow } from 'ai-workflows'
7
9
 
8
10
  const workflow = Workflow($ => {
9
11
  $.on.Customer.created(async (customer, $) => {
10
- $.log('New customer:', customer.name)
11
12
  await $.send('Email.welcome', { to: customer.email })
12
13
  })
13
14
 
@@ -17,214 +18,351 @@ const workflow = Workflow($ => {
17
18
  })
18
19
 
19
20
  await workflow.start()
20
- await workflow.send('Customer.created', { name: 'John', email: 'john@example.com' })
21
21
  ```
22
22
 
23
+ That's it. No YAML. No state machine diagrams. Just JavaScript.
24
+
23
25
  ## Installation
24
26
 
25
27
  ```bash
26
- pnpm add ai-workflows
28
+ npm install ai-workflows
27
29
  ```
28
30
 
29
- ## The `$` Context
31
+ ## Quick Start
32
+
33
+ ### Event Handlers
30
34
 
31
- Everything flows through `$`. It's your workflow's connection to events, schedules, state, and the outside world.
35
+ React to events with the `$.on` pattern. Events follow `Noun.verb` naming:
32
36
 
33
37
  ```typescript
34
38
  Workflow($ => {
35
- // Event handlers
36
- $.on.Order.completed(async (order, $) => {
37
- await $.send('Invoice.generate', { orderId: order.id })
38
- $.log('Order completed', order)
39
+ $.on.Order.placed(async (order, $) => {
40
+ $.log('Processing order', order.id)
41
+ await $.send('Inventory.reserve', { items: order.items })
42
+ await $.send('Payment.charge', { amount: order.total })
39
43
  })
40
44
 
41
- // Scheduled tasks
42
- $.every.hour(async ($) => {
43
- $.log('Hourly health check')
45
+ $.on.Payment.completed(async (payment, $) => {
46
+ await $.send('Order.fulfill', { orderId: payment.orderId })
47
+ })
48
+
49
+ $.on.Payment.failed(async (payment, $) => {
50
+ await $.send('Customer.notify', {
51
+ message: 'Payment failed',
52
+ orderId: payment.orderId
53
+ })
44
54
  })
45
55
  })
46
56
  ```
47
57
 
48
- ## Event Handling
58
+ ### Scheduled Tasks
49
59
 
50
- Events follow the `Noun.verb` pattern:
60
+ Natural scheduling with `$.every`:
51
61
 
52
62
  ```typescript
53
- $.on.Customer.created(handler) // Customer created
54
- $.on.Order.shipped(handler) // Order shipped
55
- $.on.Payment.failed(handler) // Payment failed
56
- $.on.Ticket.resolved(handler) // Ticket resolved
63
+ Workflow($ => {
64
+ // Simple intervals
65
+ $.every.hour(async ($) => {
66
+ $.log('Hourly health check')
67
+ })
68
+
69
+ // Day + time combinations
70
+ $.every.Monday.at9am(async ($) => {
71
+ const report = await $.do('Analytics.weeklyReport', {})
72
+ await $.send('Slack.post', { channel: '#metrics', report })
73
+ })
74
+
75
+ $.every.weekday.at8am(async ($) => {
76
+ $.log('Good morning! Time to standup.')
77
+ })
78
+
79
+ // Precise intervals
80
+ $.every.minutes(30)(async ($) => {
81
+ await $.send('Cache.refresh', {})
82
+ })
83
+ })
57
84
  ```
58
85
 
59
- ### Sending Events
86
+ **Available schedules:**
87
+
88
+ | Intervals | Days | Times |
89
+ |-----------|------|-------|
90
+ | `$.every.second` | `$.every.Monday` | `.at6am` `.at7am` `.at8am` |
91
+ | `$.every.minute` | `$.every.Tuesday` | `.at9am` `.at10am` `.at11am` |
92
+ | `$.every.hour` | `$.every.Wednesday` | `.at12pm` `.atnoon` |
93
+ | `$.every.day` | `$.every.Thursday` | `.at1pm` `.at2pm` `.at3pm` |
94
+ | `$.every.week` | `$.every.Friday` | `.at4pm` `.at5pm` `.at6pm` |
95
+ | `$.every.month` | `$.every.Saturday` | `.at7pm` `.at8pm` `.at9pm` |
96
+ | `$.every.minutes(n)` | `$.every.Sunday` | `.atmidnight` |
97
+ | `$.every.hours(n)` | `$.every.weekday` | |
98
+ | | `$.every.weekend` | |
99
+
100
+ ## The Cascade Pattern
101
+
102
+ Not every problem can be solved with code. Some need AI. Some need human judgment. The cascade executor tries each tier in sequence, escalating only when needed:
103
+
104
+ ```
105
+ Code -> Generative AI -> Agentic AI -> Human
106
+ ```
60
107
 
61
108
  ```typescript
62
- // Fire and forget
63
- await $.send('Email.welcome', { to: 'user@example.com' })
109
+ import { CascadeExecutor } from 'ai-workflows'
110
+
111
+ const processRefund = new CascadeExecutor({
112
+ cascadeName: 'refund-processor',
113
+
114
+ tiers: {
115
+ // Tier 1: Deterministic rules (fastest, cheapest)
116
+ code: {
117
+ name: 'rule-based-refund',
118
+ execute: async (request) => {
119
+ if (request.amount < 50 && request.reason === 'defective') {
120
+ return { approved: true, method: 'original-payment' }
121
+ }
122
+ throw new Error('Rules inconclusive')
123
+ }
124
+ },
125
+
126
+ // Tier 2: AI analysis for complex cases
127
+ generative: {
128
+ name: 'ai-refund-analysis',
129
+ execute: async (request, ctx) => {
130
+ const analysis = await analyzeRefundRequest(request)
131
+ if (analysis.confidence > 0.9) {
132
+ return { approved: analysis.shouldApprove, reason: analysis.explanation }
133
+ }
134
+ throw new Error('Confidence too low')
135
+ }
136
+ },
137
+
138
+ // Tier 3: Agent with tool access
139
+ agentic: {
140
+ name: 'refund-agent',
141
+ execute: async (request, ctx) => {
142
+ return await refundAgent.process(request)
143
+ }
144
+ },
145
+
146
+ // Tier 4: Human review for edge cases
147
+ human: {
148
+ name: 'human-review',
149
+ execute: async (request) => {
150
+ return await createHumanTask({
151
+ type: 'refund-review',
152
+ data: request,
153
+ assignTo: 'support-team'
154
+ })
155
+ }
156
+ }
157
+ },
64
158
 
65
- // Execute and wait for result (durable)
66
- const result = await $.do('Order.process', orderData)
159
+ // Default timeouts per tier
160
+ useDefaultTimeouts: true, // code: 5s, generative: 30s, agentic: 5m, human: 24h
161
+ })
67
162
 
68
- // Execute without durability
69
- const result = await $.try('Order.validate', orderData)
163
+ const result = await processRefund.execute(refundRequest)
164
+ console.log(`Resolved by ${result.tier} tier in ${result.metrics.totalDuration}ms`)
70
165
  ```
71
166
 
72
- ## Scheduling
167
+ ### Cascade Features
168
+
169
+ - **Automatic escalation** - Failed tiers escalate to the next level
170
+ - **Tier timeouts** - Each tier has configurable time limits
171
+ - **Retry support** - Configure retries with exponential backoff per tier
172
+ - **Skip conditions** - Skip tiers based on input characteristics
173
+ - **5W+H audit trail** - Full event log: who, what, when, where, why, how
73
174
 
74
- Natural language scheduling with `$.every`:
175
+ ## Dependency Graphs
176
+
177
+ For complex workflows with interdependent steps, use the dependency graph to ensure correct execution order:
75
178
 
76
179
  ```typescript
77
- // Simple intervals
78
- $.every.second(handler)
79
- $.every.minute(handler)
80
- $.every.hour(handler)
81
- $.every.day(handler)
82
- $.every.week(handler)
83
-
84
- // Days of the week
85
- $.every.Monday(handler)
86
- $.every.Friday(handler)
87
- $.every.weekday(handler)
88
- $.every.weekend(handler)
89
-
90
- // Day + time combinations
91
- $.every.Monday.at9am(handler)
92
- $.every.Friday.at5pm(handler)
93
- $.every.weekday.at8am(handler)
94
-
95
- // Intervals with values
96
- $.every.minutes(30)(handler)
97
- $.every.hours(4)(handler)
98
-
99
- // Natural language (requires AI converter)
100
- $.every('first Monday of the month at 9am', handler)
101
- $.every('every 15 minutes during business hours', handler)
180
+ import { DependencyGraph, getExecutionLevels } from 'ai-workflows'
181
+
182
+ const graph = new DependencyGraph()
183
+
184
+ // Steps with no dependencies run first (level 0)
185
+ graph.addNode('fetch-user')
186
+ graph.addNode('fetch-products')
187
+
188
+ // Dependent steps run after their dependencies complete
189
+ graph.addNode('validate-cart', { dependsOn: ['fetch-user', 'fetch-products'] })
190
+ graph.addNode('calculate-shipping', { dependsOn: 'fetch-products' })
191
+ graph.addNode('apply-discounts', { dependsOn: 'validate-cart' })
192
+ graph.addNode('process-payment', { dependsOn: ['apply-discounts', 'calculate-shipping'] })
193
+
194
+ // Automatic cycle detection
195
+ try {
196
+ graph.addNode('bad-step', { dependsOn: 'process-payment' })
197
+ graph.addEdge('bad-step', 'fetch-user') // Would create a cycle!
198
+ } catch (e) {
199
+ console.log('Caught circular dependency:', e.cyclePath)
200
+ }
102
201
  ```
103
202
 
104
- ### Available Times
203
+ ### Topological Sort
204
+
205
+ Execute steps in dependency order:
105
206
 
106
207
  ```typescript
107
- .at6am .at7am .at8am .at9am .at10am .at11am
108
- .at12pm .atnoon .at1pm .at2pm .at3pm .at4pm
109
- .at5pm .at6pm .at7pm .at8pm .at9pm .atmidnight
208
+ import { topologicalSort, getExecutionLevels } from 'ai-workflows'
209
+
210
+ const steps = [
211
+ { id: 'A', dependencies: [] },
212
+ { id: 'B', dependencies: ['A'] },
213
+ { id: 'C', dependencies: ['A'] },
214
+ { id: 'D', dependencies: ['B', 'C'] },
215
+ ]
216
+
217
+ // Linear execution order
218
+ const { order } = topologicalSort(steps)
219
+ // => ['A', 'B', 'C', 'D']
220
+
221
+ // Parallel execution groups
222
+ const levels = getExecutionLevels(steps)
223
+ // => [
224
+ // { level: 0, nodes: ['A'] }, // Run first
225
+ // { level: 1, nodes: ['B', 'C'] }, // Run in parallel
226
+ // { level: 2, nodes: ['D'] } // Run after B and C complete
227
+ // ]
110
228
  ```
111
229
 
112
- ## Standalone API
230
+ ## Barriers and Joins
113
231
 
114
- Use `on`, `every`, and `send` for global registration:
232
+ Coordinate parallel operations with barrier semantics:
115
233
 
116
234
  ```typescript
117
- import { on, every, send } from 'ai-workflows'
118
-
119
- on.Customer.created(async (customer, $) => {
120
- await $.send('Email.welcome', { to: customer.email })
235
+ import { waitForAll, waitForAny, Barrier, withConcurrencyLimit } from 'ai-workflows'
236
+
237
+ // Wait for all parallel tasks
238
+ const results = await waitForAll([
239
+ fetchUserData(userId),
240
+ fetchOrderHistory(userId),
241
+ fetchRecommendations(userId),
242
+ ], { timeout: 5000 })
243
+
244
+ // Wait for N of M (e.g., 2 of 3 replicas)
245
+ const { completed, pending } = await waitForAny(2, [
246
+ writeToReplica1(data),
247
+ writeToReplica2(data),
248
+ writeToReplica3(data),
249
+ ])
250
+
251
+ // Manual barrier for complex coordination
252
+ const barrier = new Barrier(3, {
253
+ timeout: 10000,
254
+ onProgress: ({ arrived, expected, percentage }) => {
255
+ console.log(`${arrived}/${expected} (${percentage}%)`)
256
+ }
121
257
  })
122
258
 
123
- every.hour(async ($) => {
124
- $.log('Hourly task')
125
- })
259
+ // In parallel handlers...
260
+ barrier.arrive(resultFromWorker1)
261
+ barrier.arrive(resultFromWorker2)
262
+ barrier.arrive(resultFromWorker3)
126
263
 
127
- await send('Customer.created', { name: 'John' })
264
+ // Wait for all to arrive
265
+ const allResults = await barrier.wait()
128
266
  ```
129
267
 
130
- ## Real-World Examples
268
+ ### Concurrency Control
131
269
 
132
- ### Order Processing
270
+ Limit parallel executions to prevent overwhelming downstream services:
133
271
 
134
272
  ```typescript
135
- const workflow = Workflow($ => {
136
- $.on.Order.placed(async (order, $) => {
137
- $.log('Processing order', order.id)
273
+ const urls = [/* 100 URLs */]
274
+
275
+ // Process 5 at a time
276
+ const results = await withConcurrencyLimit(
277
+ urls.map(url => () => fetch(url)),
278
+ 5, // max concurrent
279
+ { collectErrors: true } // don't fail fast
280
+ )
281
+ ```
138
282
 
139
- // Validate inventory
140
- const valid = await $.do('Inventory.check', order.items)
141
- if (!valid) {
142
- await $.send('Order.cancelled', { orderId: order.id, reason: 'Out of stock' })
143
- return
144
- }
283
+ ## Standalone API
145
284
 
146
- // Process payment
147
- const payment = await $.do('Payment.charge', {
148
- amount: order.total,
149
- customer: order.customerId,
150
- })
285
+ Use `on`, `every`, and `send` for global registration outside of a workflow:
151
286
 
152
- // Fulfill order
153
- await $.send('Fulfillment.ship', { orderId: order.id })
154
- })
287
+ ```typescript
288
+ import { on, every, send } from 'ai-workflows'
155
289
 
156
- $.on.Order.shipped(async (data, $) => {
157
- await $.send('Email.tracking', { orderId: data.orderId })
158
- })
290
+ // Register handlers
291
+ on.Customer.created(async (customer, $) => {
292
+ await $.send('Email.welcome', { to: customer.email })
159
293
  })
160
- ```
161
294
 
162
- ### Customer Lifecycle
295
+ every.hour(async ($) => {
296
+ $.log('Background task running')
297
+ })
163
298
 
164
- ```typescript
165
- Workflow($ => {
166
- $.on.Customer.signedUp(async (customer, $) => {
167
- await $.send('Email.welcome', { to: customer.email })
168
- await $.send('Slack.notify', { message: `New signup: ${customer.name}` })
169
- })
299
+ // Emit events from anywhere
300
+ await send('Customer.created', { name: 'Alice', email: 'alice@example.com' })
301
+ ```
170
302
 
171
- $.on.Customer.upgraded(async (customer, $) => {
172
- await $.send('Email.upgradeConfirmation', { to: customer.email })
173
- await $.send('Analytics.track', { event: 'upgrade', plan: customer.plan })
174
- })
303
+ ## Configuration
175
304
 
176
- // Check for inactive users daily
177
- $.every.day.at9am(async ($) => {
178
- const inactive = await $.do('Customer.findInactive', { days: 30 })
179
- for (const customer of inactive) {
180
- await $.send('Email.reengagement', { to: customer.email })
181
- }
182
- })
183
- })
184
- ```
305
+ ### Custom Cron Converter
185
306
 
186
- ### Scheduled Reports
307
+ Enable natural language scheduling with an AI-powered cron converter:
187
308
 
188
309
  ```typescript
189
- Workflow($ => {
190
- $.every.Monday.at9am(async ($) => {
191
- const report = await $.do('Analytics.weeklyReport', {})
192
- await $.send('Email.report', {
193
- to: 'team@company.com',
194
- report,
195
- })
196
- })
310
+ import { setCronConverter } from 'ai-workflows'
197
311
 
198
- $.every.month(async ($) => {
199
- const metrics = await $.do('Metrics.monthly', {})
200
- await $.send('Dashboard.update', { metrics })
201
- })
312
+ setCronConverter(async (description) => {
313
+ // Use your AI service to convert natural language to cron
314
+ const response = await ai.complete(`Convert to cron: "${description}"`)
315
+ return response.cron
202
316
  })
317
+
318
+ // Now you can use natural language
319
+ $.every('first Monday of the month at 9am', handler)
320
+ $.every('every 15 minutes during business hours', handler)
203
321
  ```
204
322
 
205
- ## Workflow Instance
323
+ ### Cascade Timeouts
206
324
 
207
- The `Workflow()` function returns an instance with:
325
+ Configure per-tier and total timeouts:
208
326
 
209
327
  ```typescript
210
- const workflow = Workflow($ => { /* ... */ })
328
+ const executor = new CascadeExecutor({
329
+ tiers: { /* ... */ },
330
+
331
+ // Custom timeouts per tier (milliseconds)
332
+ timeouts: {
333
+ code: 2000, // 2 seconds
334
+ generative: 15000, // 15 seconds
335
+ agentic: 60000, // 1 minute
336
+ human: 3600000, // 1 hour
337
+ },
338
+
339
+ // Or use defaults
340
+ useDefaultTimeouts: true, // code: 5s, generative: 30s, agentic: 5m, human: 24h
341
+
342
+ // Total cascade timeout
343
+ totalTimeout: 300000, // 5 minutes max for entire cascade
344
+ })
345
+ ```
211
346
 
212
- // Access the workflow
213
- workflow.definition // Event and schedule registrations
214
- workflow.state // Current state and history
215
- workflow.$ // The $ context
347
+ ### Retry Configuration
216
348
 
217
- // Control the workflow
218
- await workflow.start() // Begin processing schedules
219
- await workflow.stop() // Stop all schedules
349
+ Add retries with exponential backoff:
220
350
 
221
- // Send events
222
- await workflow.send('Customer.created', { name: 'John' })
351
+ ```typescript
352
+ const executor = new CascadeExecutor({
353
+ tiers: { /* ... */ },
354
+
355
+ retryConfig: {
356
+ code: { maxRetries: 2, baseDelay: 100 },
357
+ generative: { maxRetries: 3, baseDelay: 1000, multiplier: 2 },
358
+ agentic: { maxRetries: 1, baseDelay: 5000 },
359
+ }
360
+ })
223
361
  ```
224
362
 
225
363
  ## Testing
226
364
 
227
- Create isolated test contexts:
365
+ Create isolated contexts for testing:
228
366
 
229
367
  ```typescript
230
368
  import { createTestContext } from 'ai-workflows'
@@ -232,75 +370,56 @@ import { createTestContext } from 'ai-workflows'
232
370
  const $ = createTestContext()
233
371
 
234
372
  // Call your handler
235
- await yourHandler({ name: 'test' }, $)
373
+ await orderHandler({ id: '123', total: 99.99 }, $)
236
374
 
237
- // Check what was emitted
375
+ // Assert on emitted events
238
376
  expect($.emittedEvents).toContainEqual({
239
- event: 'Email.welcome',
240
- data: { to: 'test@example.com' },
377
+ event: 'Payment.charge',
378
+ data: { amount: 99.99 },
241
379
  })
242
380
  ```
243
381
 
244
382
  ## API Reference
245
383
 
246
- ### Workflow Functions
384
+ ### Core Workflow
247
385
 
248
386
  | Export | Description |
249
387
  |--------|-------------|
250
388
  | `Workflow($)` | Create a workflow with $ context |
251
- | `on` | Standalone event registration |
252
- | `every` | Standalone schedule registration |
253
- | `send` | Emit events globally |
389
+ | `on` | Standalone event registration proxy |
390
+ | `every` | Standalone schedule registration proxy |
391
+ | `send(event, data)` | Emit events globally |
254
392
  | `createTestContext()` | Create isolated $ for testing |
255
393
 
256
- ### Context Methods
394
+ ### Cascade Executor
257
395
 
258
- | Method | Description |
396
+ | Export | Description |
259
397
  |--------|-------------|
260
- | `$.on.Noun.verb(handler)` | Register event handler |
261
- | `$.every.*` | Register scheduled handler |
262
- | `$.send(event, data)` | Emit event (fire and forget) |
263
- | `$.do(event, data)` | Execute handler (durable) |
264
- | `$.try(event, data)` | Execute handler (non-durable) |
265
- | `$.log(message, data?)` | Log with history |
266
- | `$.state` | Access workflow state |
398
+ | `CascadeExecutor` | Tiered execution: code -> AI -> agent -> human |
399
+ | `TIER_ORDER` | `['code', 'generative', 'agentic', 'human']` |
400
+ | `DEFAULT_TIER_TIMEOUTS` | Default timeout per tier |
267
401
 
268
- ### Schedule Helpers
402
+ ### Dependency Graph
269
403
 
270
404
  | Export | Description |
271
405
  |--------|-------------|
272
- | `toCron(description)` | Convert to cron expression |
273
- | `setCronConverter(fn)` | Set AI cron converter |
274
- | `intervalToMs(interval)` | Get interval in milliseconds |
275
- | `formatInterval(interval)` | Format for display |
406
+ | `DependencyGraph` | DAG for workflow step dependencies |
407
+ | `topologicalSort(nodes)` | Sort nodes in dependency order |
408
+ | `getExecutionLevels(nodes)` | Group nodes for parallel execution |
409
+ | `CircularDependencyError` | Thrown when cycle detected |
276
410
 
277
- ## Types
411
+ ### Barriers
278
412
 
279
- ```typescript
280
- interface WorkflowContext {
281
- on: OnProxy
282
- every: EveryProxy
283
- send<T>(event: string, data: T): Promise<void>
284
- do<T, R>(event: string, data: T): Promise<R>
285
- try<T, R>(event: string, data: T): Promise<R>
286
- log(message: string, data?: unknown): void
287
- state: Record<string, unknown>
288
- db?: DatabaseContext
289
- }
290
-
291
- interface WorkflowInstance {
292
- definition: WorkflowDefinition
293
- state: WorkflowState
294
- $: WorkflowContext
295
- send<T>(event: string, data: T): Promise<void>
296
- start(): Promise<void>
297
- stop(): Promise<void>
298
- }
299
- ```
413
+ | Export | Description |
414
+ |--------|-------------|
415
+ | `Barrier` | Manual synchronization point |
416
+ | `waitForAll(promises)` | Wait for all with timeout support |
417
+ | `waitForAny(n, promises)` | Wait for N of M to complete |
418
+ | `withConcurrencyLimit(tasks, n)` | Limit parallel executions |
300
419
 
301
420
  ## Related Packages
302
421
 
303
- - [`ai-functions`](../ai-functions) AI-powered functions
304
- - [`ai-database`](../ai-database) Durable event storage
305
- - [`human-in-the-loop`](../human-in-the-loop) Human workflow steps
306
- - [`digital-tasks`](../digital-tasks) Task management
422
+ - [`ai-functions`](../ai-functions) - AI-powered functions with type safety
423
+ - [`ai-database`](../ai-database) - Durable event storage
424
+ - [`human-in-the-loop`](../human-in-the-loop) - Human workflow steps
425
+ - [`digital-workers`](../digital-workers) - Autonomous AI agents