digital-workers 2.1.3 → 2.4.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 (183) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +17 -0
  3. package/README.md +2 -0
  4. package/dist/actions.d.ts.map +1 -1
  5. package/dist/actions.js +33 -21
  6. package/dist/actions.js.map +1 -1
  7. package/dist/agent-comms.d.ts.map +1 -1
  8. package/dist/agent-comms.js +36 -25
  9. package/dist/agent-comms.js.map +1 -1
  10. package/dist/approve.d.ts +40 -8
  11. package/dist/approve.d.ts.map +1 -1
  12. package/dist/approve.js +86 -20
  13. package/dist/approve.js.map +1 -1
  14. package/dist/ask.d.ts +38 -7
  15. package/dist/ask.d.ts.map +1 -1
  16. package/dist/ask.js +85 -25
  17. package/dist/ask.js.map +1 -1
  18. package/dist/browse.d.ts +223 -0
  19. package/dist/browse.d.ts.map +1 -0
  20. package/dist/browse.js +392 -0
  21. package/dist/browse.js.map +1 -0
  22. package/dist/capability-tiers.js +3 -3
  23. package/dist/capability-tiers.js.map +1 -1
  24. package/dist/cascade-context.d.ts +28 -28
  25. package/dist/client.d.ts +162 -0
  26. package/dist/client.d.ts.map +1 -0
  27. package/dist/client.js +64 -0
  28. package/dist/client.js.map +1 -0
  29. package/dist/decide.d.ts +42 -6
  30. package/dist/decide.d.ts.map +1 -1
  31. package/dist/decide.js +54 -11
  32. package/dist/decide.js.map +1 -1
  33. package/dist/do.d.ts +36 -7
  34. package/dist/do.d.ts.map +1 -1
  35. package/dist/do.js +82 -39
  36. package/dist/do.js.map +1 -1
  37. package/dist/error-escalation.d.ts.map +1 -1
  38. package/dist/error-escalation.js +38 -38
  39. package/dist/error-escalation.js.map +1 -1
  40. package/dist/generate.d.ts +48 -7
  41. package/dist/generate.d.ts.map +1 -1
  42. package/dist/generate.js +49 -8
  43. package/dist/generate.js.map +1 -1
  44. package/dist/goals.d.ts +10 -9
  45. package/dist/goals.d.ts.map +1 -1
  46. package/dist/goals.js +30 -24
  47. package/dist/goals.js.map +1 -1
  48. package/dist/image.d.ts +189 -0
  49. package/dist/image.d.ts.map +1 -0
  50. package/dist/image.js +528 -0
  51. package/dist/image.js.map +1 -0
  52. package/dist/index.d.ts +49 -2
  53. package/dist/index.d.ts.map +1 -1
  54. package/dist/index.js +58 -2
  55. package/dist/index.js.map +1 -1
  56. package/dist/is.d.ts +45 -10
  57. package/dist/is.d.ts.map +1 -1
  58. package/dist/is.js +56 -21
  59. package/dist/is.js.map +1 -1
  60. package/dist/kpis.d.ts +24 -15
  61. package/dist/kpis.d.ts.map +1 -1
  62. package/dist/kpis.js +16 -14
  63. package/dist/kpis.js.map +1 -1
  64. package/dist/load-balancing.d.ts.map +1 -1
  65. package/dist/load-balancing.js +124 -38
  66. package/dist/load-balancing.js.map +1 -1
  67. package/dist/logger.d.ts +76 -0
  68. package/dist/logger.d.ts.map +1 -0
  69. package/dist/logger.js +39 -0
  70. package/dist/logger.js.map +1 -0
  71. package/dist/notify.d.ts +38 -9
  72. package/dist/notify.d.ts.map +1 -1
  73. package/dist/notify.js +72 -17
  74. package/dist/notify.js.map +1 -1
  75. package/dist/role.d.ts +5 -4
  76. package/dist/role.d.ts.map +1 -1
  77. package/dist/role.js +13 -10
  78. package/dist/role.js.map +1 -1
  79. package/dist/runtime.d.ts +310 -0
  80. package/dist/runtime.d.ts.map +1 -0
  81. package/dist/runtime.js +510 -0
  82. package/dist/runtime.js.map +1 -0
  83. package/dist/team.d.ts +11 -6
  84. package/dist/team.d.ts.map +1 -1
  85. package/dist/team.js +22 -15
  86. package/dist/team.js.map +1 -1
  87. package/dist/transports/email.d.ts +318 -0
  88. package/dist/transports/email.d.ts.map +1 -0
  89. package/dist/transports/email.js +779 -0
  90. package/dist/transports/email.js.map +1 -0
  91. package/dist/transports/slack.d.ts +515 -0
  92. package/dist/transports/slack.d.ts.map +1 -0
  93. package/dist/transports/slack.js +844 -0
  94. package/dist/transports/slack.js.map +1 -0
  95. package/dist/transports.d.ts.map +1 -1
  96. package/dist/transports.js +44 -25
  97. package/dist/transports.js.map +1 -1
  98. package/dist/types.d.ts +141 -19
  99. package/dist/types.d.ts.map +1 -1
  100. package/dist/types.js +5 -0
  101. package/dist/types.js.map +1 -1
  102. package/dist/utils/id.d.ts +19 -0
  103. package/dist/utils/id.d.ts.map +1 -0
  104. package/dist/utils/id.js +21 -0
  105. package/dist/utils/id.js.map +1 -0
  106. package/dist/video.d.ts +203 -0
  107. package/dist/video.d.ts.map +1 -0
  108. package/dist/video.js +528 -0
  109. package/dist/video.js.map +1 -0
  110. package/dist/worker.d.ts +343 -0
  111. package/dist/worker.d.ts.map +1 -0
  112. package/dist/worker.js +698 -0
  113. package/dist/worker.js.map +1 -0
  114. package/package.json +32 -14
  115. package/src/actions.ts +39 -30
  116. package/src/agent-comms.ts +54 -92
  117. package/src/approve.ts +91 -20
  118. package/src/ask.ts +99 -25
  119. package/src/browse.ts +627 -0
  120. package/src/capability-tiers.ts +5 -5
  121. package/src/client.ts +221 -0
  122. package/src/decide.ts +81 -35
  123. package/src/do.ts +98 -52
  124. package/src/error-escalation.ts +55 -67
  125. package/src/generate.ts +52 -18
  126. package/src/goals.ts +36 -27
  127. package/src/image.ts +816 -0
  128. package/src/index.ts +187 -2
  129. package/src/is.ts +59 -25
  130. package/src/kpis.ts +41 -36
  131. package/src/load-balancing.ts +132 -46
  132. package/src/logger.ts +93 -0
  133. package/src/notify.ts +78 -17
  134. package/src/role.ts +30 -20
  135. package/src/runtime.ts +796 -0
  136. package/src/team.ts +24 -19
  137. package/src/transports/email.ts +1160 -0
  138. package/src/transports/slack.ts +1320 -0
  139. package/src/transports.ts +58 -43
  140. package/src/types.ts +174 -46
  141. package/src/utils/id.ts +21 -0
  142. package/src/video.ts +906 -0
  143. package/src/worker.ts +1007 -0
  144. package/test/approve.test.ts +305 -0
  145. package/test/ask.test.ts +274 -0
  146. package/test/browse.test.ts +361 -0
  147. package/test/decide.test.ts +252 -0
  148. package/test/do.test.ts +144 -0
  149. package/test/error-logging.test.ts +357 -0
  150. package/test/generate.test.ts +319 -0
  151. package/test/image.test.ts +398 -0
  152. package/test/is.test.ts +287 -0
  153. package/test/load-balancing-safety.test.ts +404 -0
  154. package/test/notify.test.ts +434 -0
  155. package/test/primitives.test.ts +320 -0
  156. package/test/runtime-integration.test.ts +892 -0
  157. package/test/transports/crypto.test.ts +230 -0
  158. package/test/transports/email.test.ts +866 -0
  159. package/test/transports/id-generation.test.ts +91 -0
  160. package/test/transports/slack.test.ts +760 -0
  161. package/test/type-safety.test.ts +834 -0
  162. package/test/types.test.ts +60 -2
  163. package/test/video.test.ts +530 -0
  164. package/test/worker.test.ts +1433 -0
  165. package/tsconfig.json +4 -1
  166. package/vitest.config.ts +42 -0
  167. package/wrangler.jsonc +36 -0
  168. package/LICENSE +0 -21
  169. package/src/actions.js +0 -436
  170. package/src/approve.js +0 -234
  171. package/src/ask.js +0 -226
  172. package/src/decide.js +0 -244
  173. package/src/do.js +0 -227
  174. package/src/generate.js +0 -298
  175. package/src/goals.js +0 -205
  176. package/src/index.js +0 -68
  177. package/src/is.js +0 -317
  178. package/src/kpis.js +0 -270
  179. package/src/notify.js +0 -219
  180. package/src/role.js +0 -110
  181. package/src/team.js +0 -130
  182. package/src/transports.js +0 -357
  183. package/src/types.js +0 -71
@@ -0,0 +1,319 @@
1
+ /**
2
+ * Tests for generate() - Content generation primitive
3
+ *
4
+ * The generate() function provides content generation with rich metadata
5
+ * about the generation process. Unlike ai-functions.generate() which is a
6
+ * lower-level type-dispatch function, this function returns GenerateResult
7
+ * with content, metadata (model, tokens, duration), and content type info.
8
+ *
9
+ * These tests use real AI calls via the Cloudflare AI Gateway.
10
+ * Tests are skipped if AI_GATEWAY_URL is not configured.
11
+ */
12
+
13
+ import { describe, it, expect } from 'vitest'
14
+ import { generate } from '../src/index.js'
15
+
16
+ // Skip tests if no gateway configured
17
+ const hasGateway = !!process.env.AI_GATEWAY_URL || !!process.env.ANTHROPIC_API_KEY
18
+
19
+ describe('generate() - Content Generation Primitive', () => {
20
+ describe('Unit Tests (no AI)', () => {
21
+ it('should be exported from index', () => {
22
+ expect(generate).toBeDefined()
23
+ expect(typeof generate).toBe('function')
24
+ })
25
+
26
+ it('should have variations method', () => {
27
+ expect(generate.variations).toBeDefined()
28
+ expect(typeof generate.variations).toBe('function')
29
+ })
30
+
31
+ it('should have withTone method', () => {
32
+ expect(generate.withTone).toBeDefined()
33
+ expect(typeof generate.withTone).toBe('function')
34
+ })
35
+
36
+ it('should have forAudience method', () => {
37
+ expect(generate.forAudience).toBeDefined()
38
+ expect(typeof generate.forAudience).toBe('function')
39
+ })
40
+
41
+ it('should have withLength method', () => {
42
+ expect(generate.withLength).toBeDefined()
43
+ expect(typeof generate.withLength).toBe('function')
44
+ })
45
+
46
+ it('should have refine method', () => {
47
+ expect(generate.refine).toBeDefined()
48
+ expect(typeof generate.refine).toBe('function')
49
+ })
50
+ })
51
+
52
+ describe.skipIf(!hasGateway)('Integration Tests (with AI) - Text Generation', () => {
53
+ it('should generate text content', async () => {
54
+ const result = await generate('Write a haiku about coding')
55
+
56
+ expect(result).toBeDefined()
57
+ expect(result.content).toBeDefined()
58
+ expect(typeof result.content).toBe('string')
59
+ expect(result.type).toBe('text')
60
+ expect(result.metadata).toBeDefined()
61
+ })
62
+
63
+ it('should include metadata with duration', async () => {
64
+ const result = await generate('Say hello in one word')
65
+
66
+ expect(result.metadata).toBeDefined()
67
+ expect(result.metadata?.duration).toBeDefined()
68
+ expect(typeof result.metadata?.duration).toBe('number')
69
+ expect(result.metadata?.duration).toBeGreaterThan(0)
70
+ })
71
+
72
+ it('should include model in metadata', async () => {
73
+ const result = await generate('Generate a greeting', {
74
+ model: 'sonnet',
75
+ })
76
+
77
+ expect(result.metadata?.model).toBeDefined()
78
+ })
79
+
80
+ it('should respect instructions', async () => {
81
+ const result = await generate('Write a product description', {
82
+ type: 'text',
83
+ instructions: 'Keep it under 20 words. Be enthusiastic.',
84
+ })
85
+
86
+ expect(result.content).toBeDefined()
87
+ expect(result.type).toBe('text')
88
+ })
89
+ })
90
+
91
+ describe.skipIf(!hasGateway)('Integration Tests (with AI) - Structured Generation', () => {
92
+ it('should generate structured content with schema', async () => {
93
+ const result = await generate<{ name: string; description: string }>('Create a product', {
94
+ type: 'structured',
95
+ schema: {
96
+ name: 'Product name',
97
+ description: 'Short product description',
98
+ },
99
+ })
100
+
101
+ expect(result).toBeDefined()
102
+ expect(result.content).toBeDefined()
103
+ expect(result.type).toBe('structured')
104
+ expect(typeof result.content).toBe('object')
105
+ expect((result.content as { name: string }).name).toBeDefined()
106
+ expect((result.content as { description: string }).description).toBeDefined()
107
+ })
108
+
109
+ it('should generate complex structured content', async () => {
110
+ const result = await generate<{
111
+ title: string
112
+ sections: string[]
113
+ author: { name: string; expertise: string }
114
+ }>('Create a technical article outline', {
115
+ type: 'structured',
116
+ schema: {
117
+ title: 'Article title',
118
+ sections: ['List of section headings'],
119
+ author: {
120
+ name: 'Author name',
121
+ expertise: 'Area of expertise',
122
+ },
123
+ },
124
+ })
125
+
126
+ expect(result.content).toBeDefined()
127
+ expect((result.content as { title: string }).title).toBeDefined()
128
+ expect(Array.isArray((result.content as { sections: string[] }).sections)).toBe(true)
129
+ expect((result.content as { author: { name: string } }).author.name).toBeDefined()
130
+ })
131
+
132
+ it('should throw error for structured without schema', async () => {
133
+ await expect(generate('Generate something', { type: 'structured' })).rejects.toThrow(
134
+ 'Schema is required'
135
+ )
136
+ })
137
+ })
138
+
139
+ describe.skipIf(!hasGateway)('Integration Tests (with AI) - Code Generation', () => {
140
+ it('should generate code', async () => {
141
+ const result = await generate('Write a function to add two numbers', {
142
+ type: 'code',
143
+ })
144
+
145
+ expect(result).toBeDefined()
146
+ expect(result.content).toBeDefined()
147
+ expect(result.type).toBe('code')
148
+ expect(result.metadata?.language).toBeDefined()
149
+ })
150
+
151
+ it('should include explanation for code', async () => {
152
+ const result = await generate('Write a TypeScript function to reverse a string', {
153
+ type: 'code',
154
+ instructions: 'Use modern ES6+ syntax',
155
+ })
156
+
157
+ expect(result.metadata?.explanation).toBeDefined()
158
+ expect(typeof result.metadata?.explanation).toBe('string')
159
+ })
160
+ })
161
+
162
+ describe.skipIf(!hasGateway)('Integration Tests (with AI) - Variations', () => {
163
+ it('should generate multiple variations', async () => {
164
+ const variations = await generate.variations('Write a catchy tagline for a coffee shop', 3, {
165
+ type: 'text',
166
+ })
167
+
168
+ expect(variations).toBeDefined()
169
+ expect(Array.isArray(variations)).toBe(true)
170
+ expect(variations.length).toBe(3)
171
+
172
+ variations.forEach((v) => {
173
+ expect(v.content).toBeDefined()
174
+ expect(v.type).toBe('text')
175
+ })
176
+ })
177
+
178
+ it('should generate unique variations', async () => {
179
+ const variations = await generate.variations('Generate a random color name', 2)
180
+
181
+ expect(variations.length).toBe(2)
182
+ // Variations should be defined (may or may not be unique)
183
+ variations.forEach((v) => {
184
+ expect(v.content).toBeDefined()
185
+ })
186
+ })
187
+ })
188
+
189
+ describe.skipIf(!hasGateway)('Integration Tests (with AI) - Tone', () => {
190
+ it('should generate with professional tone', async () => {
191
+ const result = await generate.withTone(
192
+ 'Write an email declining a meeting invitation',
193
+ 'professional'
194
+ )
195
+
196
+ expect(result.content).toBeDefined()
197
+ expect(typeof result.content).toBe('string')
198
+ })
199
+
200
+ it('should generate with friendly tone', async () => {
201
+ const result = await generate.withTone('Write a thank you message', 'friendly')
202
+
203
+ expect(result.content).toBeDefined()
204
+ })
205
+
206
+ it('should generate with formal tone', async () => {
207
+ const result = await generate.withTone('Write a business letter introduction', 'formal')
208
+
209
+ expect(result.content).toBeDefined()
210
+ })
211
+
212
+ it('should support all tone options', async () => {
213
+ const tones = [
214
+ 'professional',
215
+ 'casual',
216
+ 'friendly',
217
+ 'formal',
218
+ 'humorous',
219
+ 'empathetic',
220
+ ] as const
221
+
222
+ for (const tone of tones.slice(0, 2)) {
223
+ // Test just a couple to save time
224
+ const result = await generate.withTone('Write a greeting', tone)
225
+ expect(result.content).toBeDefined()
226
+ }
227
+ })
228
+ })
229
+
230
+ describe.skipIf(!hasGateway)('Integration Tests (with AI) - Audience', () => {
231
+ it('should generate for technical audience', async () => {
232
+ const result = await generate.forAudience('Explain how HTTP works', 'software engineers')
233
+
234
+ expect(result.content).toBeDefined()
235
+ expect(typeof result.content).toBe('string')
236
+ })
237
+
238
+ it('should generate for non-technical audience', async () => {
239
+ const result = await generate.forAudience(
240
+ 'Explain how HTTP works',
241
+ 'non-technical business stakeholders'
242
+ )
243
+
244
+ expect(result.content).toBeDefined()
245
+ })
246
+ })
247
+
248
+ describe.skipIf(!hasGateway)('Integration Tests (with AI) - Length', () => {
249
+ it('should generate brief content', async () => {
250
+ const result = await generate.withLength('Describe a sunset', 'brief')
251
+
252
+ expect(result.content).toBeDefined()
253
+ // Brief should be short
254
+ expect((result.content as string).length).toBeLessThan(200)
255
+ })
256
+
257
+ it('should generate short content', async () => {
258
+ const result = await generate.withLength('Describe a forest', 'short')
259
+
260
+ expect(result.content).toBeDefined()
261
+ })
262
+
263
+ it('should generate medium content', async () => {
264
+ const result = await generate.withLength('Describe a city', 'medium')
265
+
266
+ expect(result.content).toBeDefined()
267
+ })
268
+
269
+ it('should support all length options', async () => {
270
+ const lengths = ['brief', 'short', 'medium', 'long', 'detailed'] as const
271
+
272
+ // Just test brief to save time
273
+ const result = await generate.withLength('Write about trees', 'brief')
274
+ expect(result.content).toBeDefined()
275
+ })
276
+ })
277
+
278
+ describe.skipIf(!hasGateway)('Integration Tests (with AI) - Refinement', () => {
279
+ it('should refine content iteratively', async () => {
280
+ const result = await generate.refine('Write a product tagline', [
281
+ 'Make it more memorable',
282
+ 'Add urgency',
283
+ ])
284
+
285
+ expect(result).toBeDefined()
286
+ expect(result.content).toBeDefined()
287
+ // Refined content should exist
288
+ })
289
+
290
+ it('should apply multiple refinements', async () => {
291
+ const result = await generate.refine('Write a headline', [
292
+ 'Make it shorter',
293
+ 'Add a call to action',
294
+ ])
295
+
296
+ expect(result.content).toBeDefined()
297
+ })
298
+ })
299
+
300
+ describe('Error Handling', () => {
301
+ it('should throw for unsupported content type', async () => {
302
+ await expect(generate('Generate an image', { type: 'image' })).rejects.toThrow(
303
+ 'not yet implemented'
304
+ )
305
+ })
306
+
307
+ it('should throw for video type', async () => {
308
+ await expect(generate('Generate a video', { type: 'video' })).rejects.toThrow(
309
+ 'not yet implemented'
310
+ )
311
+ })
312
+
313
+ it('should throw for audio type', async () => {
314
+ await expect(generate('Generate audio', { type: 'audio' })).rejects.toThrow(
315
+ 'not yet implemented'
316
+ )
317
+ })
318
+ })
319
+ })