ai-workflows 1.0.0 → 2.0.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/.turbo/turbo-build.log +5 -0
- package/.turbo/turbo-test.log +104 -0
- package/README.md +285 -24
- package/dist/context.d.ts +26 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +84 -0
- package/dist/context.js.map +1 -0
- package/dist/every.d.ts +67 -0
- package/dist/every.d.ts.map +1 -0
- package/dist/every.js +268 -0
- package/dist/every.js.map +1 -0
- package/dist/index.d.ts +66 -5
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +70 -7
- package/dist/index.js.map +1 -0
- package/dist/on.d.ts +49 -0
- package/dist/on.d.ts.map +1 -0
- package/dist/on.js +80 -0
- package/dist/on.js.map +1 -0
- package/dist/send.d.ts +59 -0
- package/dist/send.d.ts.map +1 -0
- package/dist/send.js +112 -0
- package/dist/send.js.map +1 -0
- package/dist/types.d.ts +229 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/dist/workflow.d.ts +79 -0
- package/dist/workflow.d.ts.map +1 -0
- package/dist/workflow.js +456 -0
- package/dist/workflow.js.map +1 -0
- package/package.json +24 -65
- package/src/context.ts +108 -0
- package/src/every.ts +299 -0
- package/src/index.ts +106 -0
- package/src/on.ts +100 -0
- package/src/send.ts +131 -0
- package/src/types.ts +244 -0
- package/src/workflow.ts +569 -0
- package/test/context.test.ts +151 -0
- package/test/every.test.ts +361 -0
- package/test/on.test.ts +100 -0
- package/test/send.test.ts +118 -0
- package/test/workflow.test.ts +288 -0
- package/tsconfig.json +9 -0
- package/vitest.config.ts +8 -0
- package/LICENSE +0 -21
- package/dist/index.test.d.ts +0 -1
- package/dist/index.test.js +0 -9
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
|
|
2
|
+
> ai-workflows@0.0.1 test /Users/nathanclevenger/projects/mdx.org.ai/primitives/packages/ai-workflows
|
|
3
|
+
> vitest
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
DEV v2.1.9 /Users/nathanclevenger/projects/mdx.org.ai/primitives/packages/ai-workflows
|
|
7
|
+
|
|
8
|
+
✓ test/every.test.ts (39 tests) 7ms
|
|
9
|
+
✓ test/on.test.ts (8 tests) 4ms
|
|
10
|
+
✓ test/context.test.ts (11 tests) 5ms
|
|
11
|
+
stdout | test/workflow.test.ts > Workflow - unified $ API > Workflow() > should deliver events to registered handlers
|
|
12
|
+
[workflow] Starting with 1 event handlers and 0 schedules
|
|
13
|
+
|
|
14
|
+
stdout | test/workflow.test.ts > Workflow - unified $ API > Workflow() > should allow chained event sending from handlers
|
|
15
|
+
[workflow] Starting with 2 event handlers and 0 schedules
|
|
16
|
+
|
|
17
|
+
stdout | test/workflow.test.ts > Workflow - unified $ API > Workflow() > should track events in state history
|
|
18
|
+
[workflow] Starting with 1 event handlers and 0 schedules
|
|
19
|
+
|
|
20
|
+
✓ test/send.test.ts (9 tests) 20ms
|
|
21
|
+
stderr | test/send.test.ts > send - event emission > send > should continue with other handlers if one throws
|
|
22
|
+
Error in handler for Customer.created: Error: Handler 1 failed
|
|
23
|
+
at /Users/nathanclevenger/projects/mdx.org.ai/primitives/packages/ai-workflows/test/send.test.ts:104:50
|
|
24
|
+
at file:///Users/nathanclevenger/projects/mdx.org.ai/node_modules/.pnpm/@vitest+runner@2.1.9/node_modules/@vitest/runner/dist/index.js:146:14
|
|
25
|
+
at file:///Users/nathanclevenger/projects/mdx.org.ai/node_modules/.pnpm/@vitest+runner@2.1.9/node_modules/@vitest/runner/dist/index.js:533:11
|
|
26
|
+
at runWithTimeout (file:///Users/nathanclevenger/projects/mdx.org.ai/node_modules/.pnpm/@vitest+runner@2.1.9/node_modules/@vitest/runner/dist/index.js:39:7)
|
|
27
|
+
at runTest (file:///Users/nathanclevenger/projects/mdx.org.ai/node_modules/.pnpm/@vitest+runner@2.1.9/node_modules/@vitest/runner/dist/index.js:1056:17)
|
|
28
|
+
at runSuite (file:///Users/nathanclevenger/projects/mdx.org.ai/node_modules/.pnpm/@vitest+runner@2.1.9/node_modules/@vitest/runner/dist/index.js:1205:15)
|
|
29
|
+
at runSuite (file:///Users/nathanclevenger/projects/mdx.org.ai/node_modules/.pnpm/@vitest+runner@2.1.9/node_modules/@vitest/runner/dist/index.js:1205:15)
|
|
30
|
+
at runSuite (file:///Users/nathanclevenger/projects/mdx.org.ai/node_modules/.pnpm/@vitest+runner@2.1.9/node_modules/@vitest/runner/dist/index.js:1205:15)
|
|
31
|
+
at runFiles (file:///Users/nathanclevenger/projects/mdx.org.ai/node_modules/.pnpm/@vitest+runner@2.1.9/node_modules/@vitest/runner/dist/index.js:1262:5)
|
|
32
|
+
at startTests (file:///Users/nathanclevenger/projects/mdx.org.ai/node_modules/.pnpm/@vitest+runner@2.1.9/node_modules/@vitest/runner/dist/index.js:1271:3)
|
|
33
|
+
|
|
34
|
+
stdout | test/workflow.test.ts > Workflow - unified $ API > Workflow() > should trigger schedule handlers
|
|
35
|
+
[workflow] Starting with 0 event handlers and 1 schedules
|
|
36
|
+
|
|
37
|
+
stdout | test/workflow.test.ts > Workflow - unified $ API > Workflow() > should trigger schedule handlers
|
|
38
|
+
[workflow] Stopping
|
|
39
|
+
|
|
40
|
+
stdout | test/workflow.test.ts > Workflow - unified $ API > Workflow() > should stop schedule handlers on stop
|
|
41
|
+
[workflow] Starting with 0 event handlers and 1 schedules
|
|
42
|
+
[workflow] Stopping
|
|
43
|
+
|
|
44
|
+
stdout | test/workflow.test.ts > Workflow - unified $ API > Workflow() > should support $.set and $.get for context data
|
|
45
|
+
[workflow] Starting with 2 event handlers and 0 schedules
|
|
46
|
+
|
|
47
|
+
✓ test/workflow.test.ts (20 tests) 23ms
|
|
48
|
+
|
|
49
|
+
Test Files 5 passed (5)
|
|
50
|
+
Tests 87 passed (87)
|
|
51
|
+
Start at 14:14:37
|
|
52
|
+
Duration 512ms (transform 163ms, setup 0ms, collect 335ms, tests 58ms, environment 0ms, prepare 404ms)
|
|
53
|
+
|
|
54
|
+
PASS Waiting for file changes...
|
|
55
|
+
press h to show help, press q to quit
|
|
56
|
+
c[3J RERUN src/context.ts
|
|
57
|
+
|
|
58
|
+
✓ test/context.test.ts (11 tests) 5ms
|
|
59
|
+
stdout | test/workflow.test.ts > Workflow - unified $ API > Workflow() > should deliver events to registered handlers
|
|
60
|
+
[workflow] Starting with 1 event handlers and 0 schedules
|
|
61
|
+
|
|
62
|
+
stdout | test/workflow.test.ts > Workflow - unified $ API > Workflow() > should allow chained event sending from handlers
|
|
63
|
+
[workflow] Starting with 2 event handlers and 0 schedules
|
|
64
|
+
|
|
65
|
+
stdout | test/workflow.test.ts > Workflow - unified $ API > Workflow() > should track events in state history
|
|
66
|
+
[workflow] Starting with 1 event handlers and 0 schedules
|
|
67
|
+
|
|
68
|
+
stdout | test/workflow.test.ts > Workflow - unified $ API > Workflow() > should trigger schedule handlers
|
|
69
|
+
[workflow] Starting with 0 event handlers and 1 schedules
|
|
70
|
+
|
|
71
|
+
stdout | test/workflow.test.ts > Workflow - unified $ API > Workflow() > should trigger schedule handlers
|
|
72
|
+
[workflow] Stopping
|
|
73
|
+
|
|
74
|
+
stdout | test/workflow.test.ts > Workflow - unified $ API > Workflow() > should stop schedule handlers on stop
|
|
75
|
+
[workflow] Starting with 0 event handlers and 1 schedules
|
|
76
|
+
[workflow] Stopping
|
|
77
|
+
|
|
78
|
+
stdout | test/workflow.test.ts > Workflow - unified $ API > Workflow() > should support $.set and $.get for context data
|
|
79
|
+
[workflow] Starting with 2 event handlers and 0 schedules
|
|
80
|
+
|
|
81
|
+
✓ test/send.test.ts (9 tests) 17ms
|
|
82
|
+
✓ test/workflow.test.ts (20 tests) 11ms
|
|
83
|
+
stderr | test/send.test.ts > send - event emission > send > should continue with other handlers if one throws
|
|
84
|
+
Error in handler for Customer.created: Error: Handler 1 failed
|
|
85
|
+
at /Users/nathanclevenger/projects/mdx.org.ai/primitives/packages/ai-workflows/test/send.test.ts:104:50
|
|
86
|
+
at file:///Users/nathanclevenger/projects/mdx.org.ai/node_modules/.pnpm/@vitest+runner@2.1.9/node_modules/@vitest/runner/dist/index.js:146:14
|
|
87
|
+
at file:///Users/nathanclevenger/projects/mdx.org.ai/node_modules/.pnpm/@vitest+runner@2.1.9/node_modules/@vitest/runner/dist/index.js:533:11
|
|
88
|
+
at runWithTimeout (file:///Users/nathanclevenger/projects/mdx.org.ai/node_modules/.pnpm/@vitest+runner@2.1.9/node_modules/@vitest/runner/dist/index.js:39:7)
|
|
89
|
+
at runTest (file:///Users/nathanclevenger/projects/mdx.org.ai/node_modules/.pnpm/@vitest+runner@2.1.9/node_modules/@vitest/runner/dist/index.js:1056:17)
|
|
90
|
+
at runSuite (file:///Users/nathanclevenger/projects/mdx.org.ai/node_modules/.pnpm/@vitest+runner@2.1.9/node_modules/@vitest/runner/dist/index.js:1205:15)
|
|
91
|
+
at runSuite (file:///Users/nathanclevenger/projects/mdx.org.ai/node_modules/.pnpm/@vitest+runner@2.1.9/node_modules/@vitest/runner/dist/index.js:1205:15)
|
|
92
|
+
at runSuite (file:///Users/nathanclevenger/projects/mdx.org.ai/node_modules/.pnpm/@vitest+runner@2.1.9/node_modules/@vitest/runner/dist/index.js:1205:15)
|
|
93
|
+
at runFiles (file:///Users/nathanclevenger/projects/mdx.org.ai/node_modules/.pnpm/@vitest+runner@2.1.9/node_modules/@vitest/runner/dist/index.js:1262:5)
|
|
94
|
+
at startTests (file:///Users/nathanclevenger/projects/mdx.org.ai/node_modules/.pnpm/@vitest+runner@2.1.9/node_modules/@vitest/runner/dist/index.js:1271:3)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
Test Files 3 passed (3)
|
|
98
|
+
Tests 40 passed (40)
|
|
99
|
+
Start at 01:20:37
|
|
100
|
+
Duration 78ms
|
|
101
|
+
|
|
102
|
+
PASS Waiting for file changes...
|
|
103
|
+
press h to show help, press q to quit
|
|
104
|
+
ELIFECYCLE Test failed. See above for more details.
|
package/README.md
CHANGED
|
@@ -1,45 +1,306 @@
|
|
|
1
|
-
[](https://badge.fury.io/js/ai-workflows)
|
|
2
|
-
[](https://opensource.org/licenses/MIT)
|
|
3
|
-
|
|
4
1
|
# ai-workflows
|
|
5
2
|
|
|
6
|
-
|
|
3
|
+
Event-driven workflows with the `$` context. Handle events, schedule tasks, and orchestrate processes.
|
|
7
4
|
|
|
8
|
-
|
|
5
|
+
```typescript
|
|
6
|
+
import { Workflow } from 'ai-workflows'
|
|
9
7
|
|
|
10
|
-
|
|
8
|
+
const workflow = Workflow($ => {
|
|
9
|
+
$.on.Customer.created(async (customer, $) => {
|
|
10
|
+
$.log('New customer:', customer.name)
|
|
11
|
+
await $.send('Email.welcome', { to: customer.email })
|
|
12
|
+
})
|
|
11
13
|
|
|
12
|
-
|
|
14
|
+
$.every.Monday.at9am(async ($) => {
|
|
15
|
+
$.log('Weekly standup reminder')
|
|
16
|
+
})
|
|
17
|
+
})
|
|
13
18
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
- 📝 **Workflow Definitions** - Design workflows by composing AI functions and events
|
|
18
|
-
- 💪 **Durable Execution** - Reliable workflow execution with state persistence
|
|
19
|
+
await workflow.start()
|
|
20
|
+
await workflow.send('Customer.created', { name: 'John', email: 'john@example.com' })
|
|
21
|
+
```
|
|
19
22
|
|
|
20
23
|
## Installation
|
|
21
24
|
|
|
22
25
|
```bash
|
|
23
|
-
|
|
26
|
+
pnpm add ai-workflows
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## The `$` Context
|
|
30
|
+
|
|
31
|
+
Everything flows through `$`. It's your workflow's connection to events, schedules, state, and the outside world.
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
Workflow($ => {
|
|
35
|
+
// Event handlers
|
|
36
|
+
$.on.Order.completed(async (order, $) => {
|
|
37
|
+
await $.send('Invoice.generate', { orderId: order.id })
|
|
38
|
+
$.log('Order completed', order)
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
// Scheduled tasks
|
|
42
|
+
$.every.hour(async ($) => {
|
|
43
|
+
$.log('Hourly health check')
|
|
44
|
+
})
|
|
45
|
+
})
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Event Handling
|
|
49
|
+
|
|
50
|
+
Events follow the `Noun.verb` pattern:
|
|
51
|
+
|
|
52
|
+
```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
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Sending Events
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
// Fire and forget
|
|
63
|
+
await $.send('Email.welcome', { to: 'user@example.com' })
|
|
64
|
+
|
|
65
|
+
// Execute and wait for result (durable)
|
|
66
|
+
const result = await $.do('Order.process', orderData)
|
|
67
|
+
|
|
68
|
+
// Execute without durability
|
|
69
|
+
const result = await $.try('Order.validate', orderData)
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Scheduling
|
|
73
|
+
|
|
74
|
+
Natural language scheduling with `$.every`:
|
|
75
|
+
|
|
76
|
+
```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)
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Available Times
|
|
105
|
+
|
|
106
|
+
```typescript
|
|
107
|
+
.at6am .at7am .at8am .at9am .at10am .at11am
|
|
108
|
+
.at12pm .atnoon .at1pm .at2pm .at3pm .at4pm
|
|
109
|
+
.at5pm .at6pm .at7pm .at8pm .at9pm .atmidnight
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## Standalone API
|
|
113
|
+
|
|
114
|
+
Use `on`, `every`, and `send` for global registration:
|
|
115
|
+
|
|
116
|
+
```typescript
|
|
117
|
+
import { on, every, send } from 'ai-workflows'
|
|
118
|
+
|
|
119
|
+
on.Customer.created(async (customer, $) => {
|
|
120
|
+
await $.send('Email.welcome', { to: customer.email })
|
|
121
|
+
})
|
|
122
|
+
|
|
123
|
+
every.hour(async ($) => {
|
|
124
|
+
$.log('Hourly task')
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
await send('Customer.created', { name: 'John' })
|
|
24
128
|
```
|
|
25
129
|
|
|
26
|
-
##
|
|
130
|
+
## Real-World Examples
|
|
27
131
|
|
|
28
|
-
###
|
|
132
|
+
### Order Processing
|
|
29
133
|
|
|
30
|
-
```
|
|
31
|
-
|
|
134
|
+
```typescript
|
|
135
|
+
const workflow = Workflow($ => {
|
|
136
|
+
$.on.Order.placed(async (order, $) => {
|
|
137
|
+
$.log('Processing order', order.id)
|
|
32
138
|
|
|
33
|
-
|
|
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
|
+
}
|
|
34
145
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
146
|
+
// Process payment
|
|
147
|
+
const payment = await $.do('Payment.charge', {
|
|
148
|
+
amount: order.total,
|
|
149
|
+
customer: order.customerId,
|
|
150
|
+
})
|
|
151
|
+
|
|
152
|
+
// Fulfill order
|
|
153
|
+
await $.send('Fulfillment.ship', { orderId: order.id })
|
|
154
|
+
})
|
|
155
|
+
|
|
156
|
+
$.on.Order.shipped(async (data, $) => {
|
|
157
|
+
await $.send('Email.tracking', { orderId: data.orderId })
|
|
158
|
+
})
|
|
159
|
+
})
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### Customer Lifecycle
|
|
163
|
+
|
|
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
|
+
})
|
|
170
|
+
|
|
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
|
+
})
|
|
175
|
+
|
|
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
|
+
```
|
|
185
|
+
|
|
186
|
+
### Scheduled Reports
|
|
187
|
+
|
|
188
|
+
```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
|
+
})
|
|
197
|
+
|
|
198
|
+
$.every.month(async ($) => {
|
|
199
|
+
const metrics = await $.do('Metrics.monthly', {})
|
|
200
|
+
await $.send('Dashboard.update', { metrics })
|
|
201
|
+
})
|
|
202
|
+
})
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
## Workflow Instance
|
|
206
|
+
|
|
207
|
+
The `Workflow()` function returns an instance with:
|
|
208
|
+
|
|
209
|
+
```typescript
|
|
210
|
+
const workflow = Workflow($ => { /* ... */ })
|
|
211
|
+
|
|
212
|
+
// Access the workflow
|
|
213
|
+
workflow.definition // Event and schedule registrations
|
|
214
|
+
workflow.state // Current state and history
|
|
215
|
+
workflow.$ // The $ context
|
|
216
|
+
|
|
217
|
+
// Control the workflow
|
|
218
|
+
await workflow.start() // Begin processing schedules
|
|
219
|
+
await workflow.stop() // Stop all schedules
|
|
220
|
+
|
|
221
|
+
// Send events
|
|
222
|
+
await workflow.send('Customer.created', { name: 'John' })
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
## Testing
|
|
226
|
+
|
|
227
|
+
Create isolated test contexts:
|
|
228
|
+
|
|
229
|
+
```typescript
|
|
230
|
+
import { createTestContext } from 'ai-workflows'
|
|
231
|
+
|
|
232
|
+
const $ = createTestContext()
|
|
233
|
+
|
|
234
|
+
// Call your handler
|
|
235
|
+
await yourHandler({ name: 'test' }, $)
|
|
236
|
+
|
|
237
|
+
// Check what was emitted
|
|
238
|
+
expect($.emittedEvents).toContainEqual({
|
|
239
|
+
event: 'Email.welcome',
|
|
240
|
+
data: { to: 'test@example.com' },
|
|
38
241
|
})
|
|
242
|
+
```
|
|
39
243
|
|
|
40
|
-
|
|
244
|
+
## API Reference
|
|
41
245
|
|
|
42
|
-
|
|
246
|
+
### Workflow Functions
|
|
43
247
|
|
|
44
|
-
|
|
248
|
+
| Export | Description |
|
|
249
|
+
|--------|-------------|
|
|
250
|
+
| `Workflow($)` | Create a workflow with $ context |
|
|
251
|
+
| `on` | Standalone event registration |
|
|
252
|
+
| `every` | Standalone schedule registration |
|
|
253
|
+
| `send` | Emit events globally |
|
|
254
|
+
| `createTestContext()` | Create isolated $ for testing |
|
|
255
|
+
|
|
256
|
+
### Context Methods
|
|
257
|
+
|
|
258
|
+
| Method | Description |
|
|
259
|
+
|--------|-------------|
|
|
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 |
|
|
267
|
+
|
|
268
|
+
### Schedule Helpers
|
|
269
|
+
|
|
270
|
+
| Export | Description |
|
|
271
|
+
|--------|-------------|
|
|
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 |
|
|
276
|
+
|
|
277
|
+
## Types
|
|
278
|
+
|
|
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
|
+
}
|
|
45
299
|
```
|
|
300
|
+
|
|
301
|
+
## Related Packages
|
|
302
|
+
|
|
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
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workflow context implementation
|
|
3
|
+
*/
|
|
4
|
+
import type { WorkflowContext } from './types.js';
|
|
5
|
+
/**
|
|
6
|
+
* Event bus interface (imported from send.ts to avoid circular dependency)
|
|
7
|
+
*/
|
|
8
|
+
interface EventBusLike {
|
|
9
|
+
emit(event: string, data: unknown): Promise<void>;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Create a workflow context
|
|
13
|
+
*/
|
|
14
|
+
export declare function createWorkflowContext(eventBus: EventBusLike): WorkflowContext;
|
|
15
|
+
/**
|
|
16
|
+
* Create an isolated workflow context (not connected to event bus)
|
|
17
|
+
* Useful for testing or standalone execution
|
|
18
|
+
*/
|
|
19
|
+
export declare function createIsolatedContext(): WorkflowContext & {
|
|
20
|
+
getEmittedEvents: () => Array<{
|
|
21
|
+
event: string;
|
|
22
|
+
data: unknown;
|
|
23
|
+
}>;
|
|
24
|
+
};
|
|
25
|
+
export {};
|
|
26
|
+
//# sourceMappingURL=context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,eAAe,EAA4D,MAAM,YAAY,CAAA;AAE3G;;GAEG;AACH,UAAU,YAAY;IACpB,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CAClD;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,YAAY,GAAG,eAAe,CAwE7E;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,IAAI,eAAe,GAAG;IAAE,gBAAgB,EAAE,MAAM,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,OAAO,CAAA;KAAE,CAAC,CAAA;CAAE,CAa7H"}
|
package/dist/context.js
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workflow context implementation
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Create a workflow context
|
|
6
|
+
*/
|
|
7
|
+
export function createWorkflowContext(eventBus) {
|
|
8
|
+
const workflowState = {
|
|
9
|
+
context: {},
|
|
10
|
+
history: [],
|
|
11
|
+
};
|
|
12
|
+
const addHistory = (entry) => {
|
|
13
|
+
workflowState.history.push({
|
|
14
|
+
...entry,
|
|
15
|
+
timestamp: Date.now(),
|
|
16
|
+
});
|
|
17
|
+
};
|
|
18
|
+
// Create no-op proxies for on/every (these are used in send context, not workflow setup)
|
|
19
|
+
const noOpOnProxy = new Proxy({}, {
|
|
20
|
+
get() {
|
|
21
|
+
return new Proxy({}, {
|
|
22
|
+
get() {
|
|
23
|
+
return () => { };
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
const noOpEveryProxy = new Proxy(function () { }, {
|
|
29
|
+
get() {
|
|
30
|
+
return () => () => { };
|
|
31
|
+
},
|
|
32
|
+
apply() { }
|
|
33
|
+
});
|
|
34
|
+
return {
|
|
35
|
+
async send(event, data) {
|
|
36
|
+
addHistory({ type: 'event', name: event, data });
|
|
37
|
+
await eventBus.emit(event, data);
|
|
38
|
+
},
|
|
39
|
+
async do(_event, _data) {
|
|
40
|
+
throw new Error('$.do not available in this context');
|
|
41
|
+
},
|
|
42
|
+
async try(_event, _data) {
|
|
43
|
+
throw new Error('$.try not available in this context');
|
|
44
|
+
},
|
|
45
|
+
on: noOpOnProxy,
|
|
46
|
+
every: noOpEveryProxy,
|
|
47
|
+
state: workflowState.context,
|
|
48
|
+
getState() {
|
|
49
|
+
// Return a deep copy to prevent mutation
|
|
50
|
+
return {
|
|
51
|
+
current: workflowState.current,
|
|
52
|
+
context: { ...workflowState.context },
|
|
53
|
+
history: [...workflowState.history],
|
|
54
|
+
};
|
|
55
|
+
},
|
|
56
|
+
set(key, value) {
|
|
57
|
+
workflowState.context[key] = value;
|
|
58
|
+
},
|
|
59
|
+
get(key) {
|
|
60
|
+
return workflowState.context[key];
|
|
61
|
+
},
|
|
62
|
+
log(message, data) {
|
|
63
|
+
addHistory({ type: 'action', name: 'log', data: { message, data } });
|
|
64
|
+
console.log(`[workflow] ${message}`, data ?? '');
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Create an isolated workflow context (not connected to event bus)
|
|
70
|
+
* Useful for testing or standalone execution
|
|
71
|
+
*/
|
|
72
|
+
export function createIsolatedContext() {
|
|
73
|
+
const emittedEvents = [];
|
|
74
|
+
const ctx = createWorkflowContext({
|
|
75
|
+
async emit(event, data) {
|
|
76
|
+
emittedEvents.push({ event, data });
|
|
77
|
+
},
|
|
78
|
+
});
|
|
79
|
+
return {
|
|
80
|
+
...ctx,
|
|
81
|
+
getEmittedEvents: () => [...emittedEvents],
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.js","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"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"}
|
package/dist/every.d.ts
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Schedule registration using natural language
|
|
3
|
+
*
|
|
4
|
+
* Usage:
|
|
5
|
+
* every.hour($ => { ... })
|
|
6
|
+
* every.Thursday.at8am($ => { ... })
|
|
7
|
+
* every.weekday.at9am($ => { ... })
|
|
8
|
+
* every('hour during business hours', $ => { ... })
|
|
9
|
+
* every('first Monday of the month at 9am', $ => { ... })
|
|
10
|
+
*/
|
|
11
|
+
import type { ScheduleHandler, ScheduleRegistration, ScheduleInterval } from './types.js';
|
|
12
|
+
/**
|
|
13
|
+
* Get all registered schedule handlers
|
|
14
|
+
*/
|
|
15
|
+
export declare function getScheduleHandlers(): ScheduleRegistration[];
|
|
16
|
+
/**
|
|
17
|
+
* Clear all registered schedule handlers
|
|
18
|
+
*/
|
|
19
|
+
export declare function clearScheduleHandlers(): void;
|
|
20
|
+
/**
|
|
21
|
+
* Register a schedule handler directly
|
|
22
|
+
*/
|
|
23
|
+
export declare function registerScheduleHandler(interval: ScheduleInterval, handler: ScheduleHandler): void;
|
|
24
|
+
/**
|
|
25
|
+
* Set the AI cron converter function
|
|
26
|
+
*/
|
|
27
|
+
export declare function setCronConverter(converter: (description: string) => Promise<string>): void;
|
|
28
|
+
/**
|
|
29
|
+
* Convert natural language to cron expression
|
|
30
|
+
*/
|
|
31
|
+
export declare function toCron(description: string): Promise<string>;
|
|
32
|
+
/**
|
|
33
|
+
* The `every` function/object for registering scheduled handlers
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```ts
|
|
37
|
+
* import { every } from 'ai-workflows'
|
|
38
|
+
*
|
|
39
|
+
* // Simple intervals
|
|
40
|
+
* every.hour($ => $.log('Hourly task'))
|
|
41
|
+
* every.day($ => $.log('Daily task'))
|
|
42
|
+
*
|
|
43
|
+
* // Day + time combinations
|
|
44
|
+
* every.Monday.at9am($ => $.log('Monday morning standup'))
|
|
45
|
+
* every.weekday.at8am($ => $.log('Workday start'))
|
|
46
|
+
* every.Friday.at5pm($ => $.log('End of week report'))
|
|
47
|
+
*
|
|
48
|
+
* // Plural intervals with values
|
|
49
|
+
* every.minutes(30)($ => $.log('Every 30 minutes'))
|
|
50
|
+
* every.hours(4)($ => $.log('Every 4 hours'))
|
|
51
|
+
*
|
|
52
|
+
* // Natural language (requires AI converter)
|
|
53
|
+
* every('hour during business hours', $ => { ... })
|
|
54
|
+
* every('first Monday of the month at 9am', $ => { ... })
|
|
55
|
+
* every('every 15 minutes between 9am and 5pm on weekdays', $ => { ... })
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
58
|
+
export declare const every: any;
|
|
59
|
+
/**
|
|
60
|
+
* Convert interval to milliseconds (for simulation/testing)
|
|
61
|
+
*/
|
|
62
|
+
export declare function intervalToMs(interval: ScheduleInterval): number;
|
|
63
|
+
/**
|
|
64
|
+
* Format interval for display
|
|
65
|
+
*/
|
|
66
|
+
export declare function formatInterval(interval: ScheduleInterval): string;
|
|
67
|
+
//# sourceMappingURL=every.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"every.d.ts","sourceRoot":"","sources":["../src/every.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAOzF;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,oBAAoB,EAAE,CAE5D;AAED;;GAEG;AACH,wBAAgB,qBAAqB,IAAI,IAAI,CAE5C;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,gBAAgB,EAC1B,OAAO,EAAE,eAAe,GACvB,IAAI,CAMN;AA6ED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,GAAG,IAAI,CAE1F;AAED;;GAEG;AACH,wBAAsB,MAAM,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAmBjE;AAgED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,eAAO,MAAM,KAAK,KAAqB,CAAA;AAEvC;;GAEG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,gBAAgB,GAAG,MAAM,CAiB/D;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,gBAAgB,GAAG,MAAM,CA+BjE"}
|