ai-workflows 2.1.1 → 2.3.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.
Files changed (211) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +17 -1
  3. package/README.md +305 -184
  4. package/dist/barrier.d.ts +159 -0
  5. package/dist/barrier.d.ts.map +1 -0
  6. package/dist/barrier.js +377 -0
  7. package/dist/barrier.js.map +1 -0
  8. package/dist/cascade-context.d.ts +149 -0
  9. package/dist/cascade-context.d.ts.map +1 -0
  10. package/dist/cascade-context.js +324 -0
  11. package/dist/cascade-context.js.map +1 -0
  12. package/dist/cascade-executor.d.ts +196 -0
  13. package/dist/cascade-executor.d.ts.map +1 -0
  14. package/dist/cascade-executor.js +384 -0
  15. package/dist/cascade-executor.js.map +1 -0
  16. package/dist/context.d.ts.map +1 -1
  17. package/dist/context.js +27 -8
  18. package/dist/context.js.map +1 -1
  19. package/dist/cron-parser.d.ts +65 -0
  20. package/dist/cron-parser.d.ts.map +1 -0
  21. package/dist/cron-parser.js +294 -0
  22. package/dist/cron-parser.js.map +1 -0
  23. package/dist/cron-scheduler.d.ts +117 -0
  24. package/dist/cron-scheduler.d.ts.map +1 -0
  25. package/dist/cron-scheduler.js +176 -0
  26. package/dist/cron-scheduler.js.map +1 -0
  27. package/dist/database-context.d.ts +184 -0
  28. package/dist/database-context.d.ts.map +1 -0
  29. package/dist/database-context.js +428 -0
  30. package/dist/database-context.js.map +1 -0
  31. package/dist/dependency-graph.d.ts +157 -0
  32. package/dist/dependency-graph.d.ts.map +1 -0
  33. package/dist/dependency-graph.js +382 -0
  34. package/dist/dependency-graph.js.map +1 -0
  35. package/dist/digital-objects-adapter.d.ts +159 -0
  36. package/dist/digital-objects-adapter.d.ts.map +1 -0
  37. package/dist/digital-objects-adapter.js +229 -0
  38. package/dist/digital-objects-adapter.js.map +1 -0
  39. package/dist/durable-execution-cloudflare.d.ts +427 -0
  40. package/dist/durable-execution-cloudflare.d.ts.map +1 -0
  41. package/dist/durable-execution-cloudflare.js +510 -0
  42. package/dist/durable-execution-cloudflare.js.map +1 -0
  43. package/dist/durable-execution.d.ts +482 -0
  44. package/dist/durable-execution.d.ts.map +1 -0
  45. package/dist/durable-execution.js +594 -0
  46. package/dist/durable-execution.js.map +1 -0
  47. package/dist/durable-workflow.d.ts +176 -0
  48. package/dist/durable-workflow.d.ts.map +1 -0
  49. package/dist/durable-workflow.js +552 -0
  50. package/dist/durable-workflow.js.map +1 -0
  51. package/dist/every.d.ts +31 -2
  52. package/dist/every.d.ts.map +1 -1
  53. package/dist/every.js +63 -32
  54. package/dist/every.js.map +1 -1
  55. package/dist/graph/index.d.ts +8 -0
  56. package/dist/graph/index.d.ts.map +1 -0
  57. package/dist/graph/index.js +8 -0
  58. package/dist/graph/index.js.map +1 -0
  59. package/dist/graph/topological-sort.d.ts +121 -0
  60. package/dist/graph/topological-sort.d.ts.map +1 -0
  61. package/dist/graph/topological-sort.js +292 -0
  62. package/dist/graph/topological-sort.js.map +1 -0
  63. package/dist/index.d.ts +10 -1
  64. package/dist/index.d.ts.map +1 -1
  65. package/dist/index.js +25 -0
  66. package/dist/index.js.map +1 -1
  67. package/dist/logger.d.ts +101 -0
  68. package/dist/logger.d.ts.map +1 -0
  69. package/dist/logger.js +115 -0
  70. package/dist/logger.js.map +1 -0
  71. package/dist/on.d.ts +35 -10
  72. package/dist/on.d.ts.map +1 -1
  73. package/dist/on.js +53 -19
  74. package/dist/on.js.map +1 -1
  75. package/dist/runtime.d.ts +169 -0
  76. package/dist/runtime.d.ts.map +1 -0
  77. package/dist/runtime.js +275 -0
  78. package/dist/runtime.js.map +1 -0
  79. package/dist/send.d.ts.map +1 -1
  80. package/dist/send.js +4 -3
  81. package/dist/send.js.map +1 -1
  82. package/dist/telemetry.d.ts +150 -0
  83. package/dist/telemetry.d.ts.map +1 -0
  84. package/dist/telemetry.js +388 -0
  85. package/dist/telemetry.js.map +1 -0
  86. package/dist/timer-registry.d.ts +77 -0
  87. package/dist/timer-registry.d.ts.map +1 -0
  88. package/dist/timer-registry.js +154 -0
  89. package/dist/timer-registry.js.map +1 -0
  90. package/dist/types.d.ts +105 -6
  91. package/dist/types.d.ts.map +1 -1
  92. package/dist/types.js +17 -1
  93. package/dist/types.js.map +1 -1
  94. package/dist/worker/durable-step.d.ts +481 -0
  95. package/dist/worker/durable-step.d.ts.map +1 -0
  96. package/dist/worker/durable-step.js +606 -0
  97. package/dist/worker/durable-step.js.map +1 -0
  98. package/dist/worker/index.d.ts +106 -0
  99. package/dist/worker/index.d.ts.map +1 -0
  100. package/dist/worker/index.js +124 -0
  101. package/dist/worker/index.js.map +1 -0
  102. package/dist/worker/state-adapter.d.ts +230 -0
  103. package/dist/worker/state-adapter.d.ts.map +1 -0
  104. package/dist/worker/state-adapter.js +409 -0
  105. package/dist/worker/state-adapter.js.map +1 -0
  106. package/dist/worker/topological-executor.d.ts +282 -0
  107. package/dist/worker/topological-executor.d.ts.map +1 -0
  108. package/dist/worker/topological-executor.js +396 -0
  109. package/dist/worker/topological-executor.js.map +1 -0
  110. package/dist/worker/workflow-builder.d.ts +286 -0
  111. package/dist/worker/workflow-builder.d.ts.map +1 -0
  112. package/dist/worker/workflow-builder.js +565 -0
  113. package/dist/worker/workflow-builder.js.map +1 -0
  114. package/dist/worker.d.ts +800 -0
  115. package/dist/worker.d.ts.map +1 -0
  116. package/dist/worker.js +2428 -0
  117. package/dist/worker.js.map +1 -0
  118. package/dist/workflow-builder.d.ts +287 -0
  119. package/dist/workflow-builder.d.ts.map +1 -0
  120. package/dist/workflow-builder.js +762 -0
  121. package/dist/workflow-builder.js.map +1 -0
  122. package/dist/workflow.d.ts +14 -30
  123. package/dist/workflow.d.ts.map +1 -1
  124. package/dist/workflow.js +136 -292
  125. package/dist/workflow.js.map +1 -1
  126. package/examples/01-ecommerce-order-pipeline.ts +358 -0
  127. package/examples/02-content-moderation-cascade.ts +454 -0
  128. package/examples/03-scheduled-reporting-dependencies.ts +479 -0
  129. package/examples/04-database-persistence.ts +518 -0
  130. package/examples/README.md +173 -0
  131. package/package.json +21 -4
  132. package/src/__tests__/digital-objects-adapter.test.ts +274 -0
  133. package/src/__tests__/durable-workflow.test.ts +297 -0
  134. package/src/barrier.ts +507 -0
  135. package/src/cascade-context.ts +495 -0
  136. package/src/cascade-executor.ts +588 -0
  137. package/src/context.ts +51 -17
  138. package/src/cron-parser.ts +347 -0
  139. package/src/cron-scheduler.ts +239 -0
  140. package/src/database-context.ts +658 -0
  141. package/src/dependency-graph.ts +518 -0
  142. package/src/digital-objects-adapter.ts +351 -0
  143. package/src/durable-execution-cloudflare.ts +855 -0
  144. package/src/durable-execution.ts +1042 -0
  145. package/src/durable-workflow.ts +717 -0
  146. package/src/every.ts +104 -35
  147. package/src/graph/index.ts +19 -0
  148. package/src/graph/topological-sort.ts +412 -0
  149. package/src/index.ts +147 -0
  150. package/src/logger.ts +148 -0
  151. package/src/on.ts +81 -26
  152. package/src/runtime.ts +436 -0
  153. package/src/send.ts +4 -5
  154. package/src/telemetry.ts +577 -0
  155. package/src/timer-registry.ts +179 -0
  156. package/src/types.ts +146 -10
  157. package/src/worker/durable-step.ts +976 -0
  158. package/src/worker/index.ts +216 -0
  159. package/src/worker/state-adapter.ts +589 -0
  160. package/src/worker/topological-executor.ts +625 -0
  161. package/src/worker/workflow-builder.ts +871 -0
  162. package/src/worker.ts +2906 -0
  163. package/src/workflow-builder.ts +1068 -0
  164. package/src/workflow.ts +199 -355
  165. package/test/barrier-join.test.ts +442 -0
  166. package/test/barrier-unhandled-rejections.test.ts +359 -0
  167. package/test/cascade-context.test.ts +390 -0
  168. package/test/cascade-executor.test.ts +852 -0
  169. package/test/cron-parser.test.ts +314 -0
  170. package/test/cron-scheduler.test.ts +291 -0
  171. package/test/database-context.test.ts +770 -0
  172. package/test/db-provider-adapter.test.ts +862 -0
  173. package/test/dependency-graph.test.ts +512 -0
  174. package/test/durable-execution-cloudflare.test.ts +606 -0
  175. package/test/durable-execution-in-process.test.ts +286 -0
  176. package/test/durable-execution.test.ts +247 -0
  177. package/test/e2e/workflow-scenarios.e2e.test.ts +1039 -0
  178. package/test/graph/topological-sort.test.ts +586 -0
  179. package/test/integration.test.ts +442 -0
  180. package/test/rpc-surface.test.ts +946 -0
  181. package/test/runtime.test.ts +262 -0
  182. package/test/schedule-timer-cleanup.test.ts +353 -0
  183. package/test/send-race-conditions.test.ts +400 -0
  184. package/test/type-safety-every.test.ts +303 -0
  185. package/test/worker/durable-cascade.test.ts +1117 -0
  186. package/test/worker/durable-step.test.ts +723 -0
  187. package/test/worker/topological-executor.test.ts +1240 -0
  188. package/test/worker/workflow-builder.test.ts +1067 -0
  189. package/test/worker.test.ts +608 -0
  190. package/test/workflow-builder.test.ts +1670 -0
  191. package/test/workflow-cron.test.ts +256 -0
  192. package/test/workflow-state-adapter.test.ts +923 -0
  193. package/test/workflow.test.ts +25 -22
  194. package/tsconfig.json +3 -1
  195. package/vitest.config.ts +38 -1
  196. package/vitest.workers.config.ts +44 -0
  197. package/wrangler.jsonc +22 -0
  198. package/.turbo/turbo-test.log +0 -7
  199. package/src/context.js +0 -83
  200. package/src/every.js +0 -267
  201. package/src/index.js +0 -71
  202. package/src/on.js +0 -79
  203. package/src/send.js +0 -111
  204. package/src/types.js +0 -4
  205. package/src/workflow.js +0 -455
  206. package/test/context.test.js +0 -116
  207. package/test/every.test.js +0 -282
  208. package/test/on.test.js +0 -80
  209. package/test/send.test.js +0 -89
  210. package/test/workflow.test.js +0 -224
  211. package/vitest.config.js +0 -7
@@ -0,0 +1,454 @@
1
+ /**
2
+ * Example: AI Content Moderation with Human Escalation
3
+ *
4
+ * This example demonstrates the CascadeExecutor pattern for content moderation.
5
+ * Content is processed through escalating tiers:
6
+ *
7
+ * 1. Code (rules) - Fast keyword/pattern matching
8
+ * 2. Generative AI - LLM-based analysis for nuanced content
9
+ * 3. Agentic AI - Multi-step reasoning with tools
10
+ * 4. Human - Expert review for edge cases
11
+ *
12
+ * Key concepts demonstrated:
13
+ * - CascadeExecutor for tiered escalation
14
+ * - Per-tier timeouts and retry configuration
15
+ * - Skip conditions for tier bypassing
16
+ * - 5W+H audit trail for compliance
17
+ * - Integration with workflow events
18
+ *
19
+ * @example
20
+ * ```bash
21
+ * npx tsx examples/02-content-moderation-cascade.ts
22
+ * ```
23
+ */
24
+
25
+ import {
26
+ Workflow,
27
+ CascadeExecutor,
28
+ type TierContext,
29
+ type WorkflowContext,
30
+ TIER_ORDER,
31
+ } from '../dist/index.js'
32
+
33
+ // ============================================================================
34
+ // Type Definitions
35
+ // ============================================================================
36
+
37
+ interface ContentItem {
38
+ id: string
39
+ type: 'text' | 'image' | 'video'
40
+ content: string
41
+ metadata: {
42
+ userId: string
43
+ platform: string
44
+ timestamp: number
45
+ }
46
+ }
47
+
48
+ interface ModerationResult {
49
+ action: 'approve' | 'reject' | 'flag'
50
+ confidence: number
51
+ reason: string
52
+ categories?: string[]
53
+ requiresReview?: boolean
54
+ }
55
+
56
+ interface HumanReviewTask {
57
+ contentId: string
58
+ content: string
59
+ aiAnalysis: string
60
+ priority: 'low' | 'medium' | 'high'
61
+ assignedTo?: string
62
+ }
63
+
64
+ // ============================================================================
65
+ // Mock Services
66
+ // ============================================================================
67
+
68
+ // Blocked keywords for rule-based tier
69
+ const BLOCKED_KEYWORDS = ['spam', 'scam', 'hack', 'illegal', 'violence']
70
+ const SUSPICIOUS_PATTERNS = [
71
+ /\b(buy|sell)\s+followers\b/i,
72
+ /\b(free|win)\s+\$?\d+/i,
73
+ /click\s+here\s+now/i,
74
+ ]
75
+
76
+ // Mock AI service
77
+ const aiService = {
78
+ async analyzeContent(content: string): Promise<{
79
+ isSafe: boolean
80
+ confidence: number
81
+ categories: string[]
82
+ explanation: string
83
+ }> {
84
+ // Simulate AI analysis with some latency
85
+ await new Promise((resolve) => setTimeout(resolve, 50))
86
+
87
+ // Mock logic based on content length and keywords
88
+ const hasIssues = content.toLowerCase().includes('suspicious') || content.length > 500
89
+ const confidence = hasIssues ? 0.65 : 0.95
90
+
91
+ return {
92
+ isSafe: !hasIssues,
93
+ confidence,
94
+ categories: hasIssues ? ['potentially_harmful'] : [],
95
+ explanation: hasIssues
96
+ ? 'Content requires further analysis due to suspicious patterns'
97
+ : 'Content appears safe based on AI analysis',
98
+ }
99
+ },
100
+ }
101
+
102
+ // Mock agentic AI with tool access
103
+ const agenticService = {
104
+ async deepAnalysis(
105
+ content: string,
106
+ context: TierContext
107
+ ): Promise<{
108
+ isSafe: boolean
109
+ confidence: number
110
+ reasoning: string[]
111
+ }> {
112
+ // Simulate multi-step reasoning
113
+ await new Promise((resolve) => setTimeout(resolve, 100))
114
+
115
+ const reasoning = [
116
+ 'Step 1: Analyzed semantic meaning of content',
117
+ 'Step 2: Checked against known harmful patterns',
118
+ 'Step 3: Verified user history and context',
119
+ 'Step 4: Applied platform-specific policies',
120
+ ]
121
+
122
+ const isSafe = !content.toLowerCase().includes('escalate')
123
+ const confidence = isSafe ? 0.92 : 0.45
124
+
125
+ return { isSafe, confidence, reasoning }
126
+ },
127
+ }
128
+
129
+ // Mock human review queue
130
+ const humanReviewQueue: HumanReviewTask[] = []
131
+
132
+ // ============================================================================
133
+ // Cascade Executor Configuration
134
+ // ============================================================================
135
+
136
+ function createModerationCascade() {
137
+ const events: Array<{ timestamp: number; event: string; data: unknown }> = []
138
+
139
+ const cascade = new CascadeExecutor<ModerationResult>({
140
+ cascadeName: 'content-moderation',
141
+ actor: 'moderation-system',
142
+
143
+ tiers: {
144
+ // Tier 1: Rule-based (fastest, deterministic)
145
+ code: {
146
+ name: 'rule-based-filter',
147
+ execute: async (input: unknown): Promise<ModerationResult> => {
148
+ const content = (input as ContentItem).content.toLowerCase()
149
+
150
+ // Check blocked keywords
151
+ for (const keyword of BLOCKED_KEYWORDS) {
152
+ if (content.includes(keyword)) {
153
+ return {
154
+ action: 'reject',
155
+ confidence: 1.0,
156
+ reason: `Contains blocked keyword: ${keyword}`,
157
+ categories: ['blocked_content'],
158
+ }
159
+ }
160
+ }
161
+
162
+ // Check suspicious patterns
163
+ for (const pattern of SUSPICIOUS_PATTERNS) {
164
+ if (pattern.test(content)) {
165
+ return {
166
+ action: 'reject',
167
+ confidence: 0.95,
168
+ reason: 'Matches suspicious pattern',
169
+ categories: ['spam_pattern'],
170
+ }
171
+ }
172
+ }
173
+
174
+ // Quick approve obviously safe content
175
+ if (content.length < 50 && /^[a-z\s.,!?]+$/.test(content)) {
176
+ return {
177
+ action: 'approve',
178
+ confidence: 0.99,
179
+ reason: 'Simple safe content',
180
+ }
181
+ }
182
+
183
+ // Escalate to AI for more complex content
184
+ throw new Error('Content requires AI analysis')
185
+ },
186
+ },
187
+
188
+ // Tier 2: Generative AI (nuanced analysis)
189
+ generative: {
190
+ name: 'ai-content-analysis',
191
+ execute: async (input: unknown): Promise<ModerationResult> => {
192
+ const contentItem = input as ContentItem
193
+ const analysis = await aiService.analyzeContent(contentItem.content)
194
+
195
+ // High confidence safe - approve
196
+ if (analysis.isSafe && analysis.confidence > 0.9) {
197
+ return {
198
+ action: 'approve',
199
+ confidence: analysis.confidence,
200
+ reason: analysis.explanation,
201
+ categories: analysis.categories,
202
+ }
203
+ }
204
+
205
+ // High confidence unsafe - reject
206
+ if (!analysis.isSafe && analysis.confidence > 0.9) {
207
+ return {
208
+ action: 'reject',
209
+ confidence: analysis.confidence,
210
+ reason: analysis.explanation,
211
+ categories: analysis.categories,
212
+ }
213
+ }
214
+
215
+ // Low confidence - escalate for deeper analysis
216
+ throw new Error(`Confidence too low (${analysis.confidence}) - needs deeper analysis`)
217
+ },
218
+ },
219
+
220
+ // Tier 3: Agentic AI (multi-step reasoning)
221
+ agentic: {
222
+ name: 'agentic-deep-analysis',
223
+ execute: async (input: unknown, context: TierContext): Promise<ModerationResult> => {
224
+ const contentItem = input as ContentItem
225
+ const analysis = await agenticService.deepAnalysis(contentItem.content, context)
226
+
227
+ console.log(' [Agentic] Reasoning steps:', analysis.reasoning)
228
+
229
+ // High confidence from agent
230
+ if (analysis.confidence > 0.85) {
231
+ return {
232
+ action: analysis.isSafe ? 'approve' : 'reject',
233
+ confidence: analysis.confidence,
234
+ reason: analysis.reasoning.join(' -> '),
235
+ }
236
+ }
237
+
238
+ // Still uncertain - needs human
239
+ throw new Error('Agent uncertain - requires human review')
240
+ },
241
+ },
242
+
243
+ // Tier 4: Human review (final decision)
244
+ human: {
245
+ name: 'human-review',
246
+ execute: async (input: unknown): Promise<ModerationResult> => {
247
+ const contentItem = input as ContentItem
248
+
249
+ // Create review task
250
+ const task: HumanReviewTask = {
251
+ contentId: contentItem.id,
252
+ content: contentItem.content,
253
+ aiAnalysis: 'AI was unable to reach high confidence decision',
254
+ priority: 'high',
255
+ }
256
+
257
+ humanReviewQueue.push(task)
258
+ console.log(` [Human] Created review task for content ${contentItem.id}`)
259
+
260
+ // For demo, simulate immediate human decision
261
+ return {
262
+ action: 'flag',
263
+ confidence: 1.0,
264
+ reason: 'Flagged for human review - decision pending',
265
+ requiresReview: true,
266
+ }
267
+ },
268
+ },
269
+ },
270
+
271
+ // Timeouts per tier
272
+ timeouts: {
273
+ code: 100, // 100ms for rules
274
+ generative: 5000, // 5s for AI
275
+ agentic: 30000, // 30s for agent
276
+ human: 3600000, // 1 hour for human
277
+ },
278
+
279
+ // Retry configuration
280
+ retryConfig: {
281
+ generative: { maxRetries: 2, baseDelay: 100, multiplier: 2 },
282
+ agentic: { maxRetries: 1, baseDelay: 500 },
283
+ },
284
+
285
+ // Skip conditions
286
+ skipConditions: {
287
+ // Skip agentic for very short content
288
+ agentic: (input) => (input as ContentItem).content.length < 20,
289
+ },
290
+
291
+ // Event callback for audit trail
292
+ onEvent: (event) => {
293
+ events.push({
294
+ timestamp: event.when,
295
+ event: event.what,
296
+ data: {
297
+ status: event.how.status,
298
+ duration: event.how.duration,
299
+ ...(event.why && { reason: event.why }),
300
+ },
301
+ })
302
+ },
303
+ })
304
+
305
+ return { cascade, events, humanReviewQueue }
306
+ }
307
+
308
+ // ============================================================================
309
+ // Workflow Integration
310
+ // ============================================================================
311
+
312
+ async function runModerationWorkflow() {
313
+ const { cascade, events, humanReviewQueue } = createModerationCascade()
314
+
315
+ const workflow = Workflow(($) => {
316
+ $.on.Content.submitted(async (content: ContentItem, $: WorkflowContext) => {
317
+ $.log(`Processing content ${content.id}`)
318
+
319
+ try {
320
+ const result = await cascade.execute(content)
321
+
322
+ $.log(`Moderation complete: ${result.tier} tier -> ${result.value.action}`)
323
+
324
+ // Emit result event
325
+ $.send('Content.moderated', {
326
+ contentId: content.id,
327
+ result: result.value,
328
+ resolvedBy: result.tier,
329
+ metrics: result.metrics,
330
+ })
331
+
332
+ // Handle based on result
333
+ if (result.value.action === 'approve') {
334
+ $.send('Content.published', { contentId: content.id })
335
+ } else if (result.value.action === 'reject') {
336
+ $.send('Content.rejected', {
337
+ contentId: content.id,
338
+ reason: result.value.reason,
339
+ })
340
+ }
341
+ } catch (error) {
342
+ $.log(`Moderation failed: ${error}`)
343
+ $.send('Content.moderationFailed', {
344
+ contentId: content.id,
345
+ error: error instanceof Error ? error.message : String(error),
346
+ })
347
+ }
348
+ })
349
+
350
+ $.on.Content.published(async (data: { contentId: string }, $: WorkflowContext) => {
351
+ $.log(`Content ${data.contentId} published successfully`)
352
+ })
353
+
354
+ $.on.Content.rejected(
355
+ async (data: { contentId: string; reason: string }, $: WorkflowContext) => {
356
+ $.log(`Content ${data.contentId} rejected: ${data.reason}`)
357
+ }
358
+ )
359
+ })
360
+
361
+ await workflow.start()
362
+ return { workflow, cascade, events, humanReviewQueue }
363
+ }
364
+
365
+ // ============================================================================
366
+ // Demo Execution
367
+ // ============================================================================
368
+
369
+ async function runDemo() {
370
+ console.log('='.repeat(60))
371
+ console.log('AI Content Moderation with Human Escalation Demo')
372
+ console.log('='.repeat(60))
373
+ console.log()
374
+
375
+ const { workflow, events } = await runModerationWorkflow()
376
+
377
+ // Test cases demonstrating different tiers
378
+ const testContent: ContentItem[] = [
379
+ // Case 1: Blocked keyword - handled by code tier
380
+ {
381
+ id: 'content_001',
382
+ type: 'text',
383
+ content: 'Check out this amazing spam offer!',
384
+ metadata: { userId: 'user_1', platform: 'web', timestamp: Date.now() },
385
+ },
386
+
387
+ // Case 2: Simple safe content - handled by code tier
388
+ {
389
+ id: 'content_002',
390
+ type: 'text',
391
+ content: 'Hello, how are you today?',
392
+ metadata: { userId: 'user_2', platform: 'mobile', timestamp: Date.now() },
393
+ },
394
+
395
+ // Case 3: Complex content - needs AI analysis
396
+ {
397
+ id: 'content_003',
398
+ type: 'text',
399
+ content:
400
+ 'This is a longer piece of content that discusses various topics in a nuanced way. ' +
401
+ 'It requires deeper analysis to determine if it meets community guidelines.',
402
+ metadata: { userId: 'user_3', platform: 'web', timestamp: Date.now() },
403
+ },
404
+
405
+ // Case 4: Suspicious content - may need agent
406
+ {
407
+ id: 'content_004',
408
+ type: 'text',
409
+ content:
410
+ 'This content has suspicious elements that the AI flagged but cannot ' +
411
+ 'determine with high confidence. It requires multi-step reasoning.',
412
+ metadata: { userId: 'user_4', platform: 'web', timestamp: Date.now() },
413
+ },
414
+
415
+ // Case 5: Needs escalation to human
416
+ {
417
+ id: 'content_005',
418
+ type: 'text',
419
+ content:
420
+ 'This complex content contains patterns that need to escalate ' +
421
+ 'all the way to human review for a final decision.',
422
+ metadata: { userId: 'user_5', platform: 'web', timestamp: Date.now() },
423
+ },
424
+ ]
425
+
426
+ // Process each content item
427
+ for (const content of testContent) {
428
+ console.log('-'.repeat(60))
429
+ console.log(`Processing: ${content.id}`)
430
+ console.log(`Content: "${content.content.substring(0, 50)}..."`)
431
+ console.log()
432
+
433
+ await workflow.send('Content.submitted', content)
434
+
435
+ // Small delay between items
436
+ await new Promise((resolve) => setTimeout(resolve, 200))
437
+ }
438
+
439
+ // Display audit trail
440
+ console.log()
441
+ console.log('='.repeat(60))
442
+ console.log('Audit Trail (5W+H Events):')
443
+ console.log('='.repeat(60))
444
+ for (const event of events.slice(-10)) {
445
+ console.log(` ${new Date(event.timestamp).toISOString()} | ${event.event}`)
446
+ console.log(` Data: ${JSON.stringify(event.data)}`)
447
+ }
448
+
449
+ // Clean up
450
+ await workflow.stop()
451
+ }
452
+
453
+ // Run if executed directly
454
+ runDemo().catch(console.error)