digital-workers 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 (197) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/README.md +136 -180
  3. package/dist/actions.d.ts.map +1 -1
  4. package/dist/actions.js +34 -21
  5. package/dist/actions.js.map +1 -1
  6. package/dist/agent-comms.d.ts +438 -0
  7. package/dist/agent-comms.d.ts.map +1 -0
  8. package/dist/agent-comms.js +677 -0
  9. package/dist/agent-comms.js.map +1 -0
  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.d.ts +230 -0
  23. package/dist/capability-tiers.d.ts.map +1 -0
  24. package/dist/capability-tiers.js +388 -0
  25. package/dist/capability-tiers.js.map +1 -0
  26. package/dist/cascade-context.d.ts +523 -0
  27. package/dist/cascade-context.d.ts.map +1 -0
  28. package/dist/cascade-context.js +494 -0
  29. package/dist/cascade-context.js.map +1 -0
  30. package/dist/client.d.ts +162 -0
  31. package/dist/client.d.ts.map +1 -0
  32. package/dist/client.js +64 -0
  33. package/dist/client.js.map +1 -0
  34. package/dist/decide.d.ts +42 -6
  35. package/dist/decide.d.ts.map +1 -1
  36. package/dist/decide.js +54 -11
  37. package/dist/decide.js.map +1 -1
  38. package/dist/do.d.ts +36 -7
  39. package/dist/do.d.ts.map +1 -1
  40. package/dist/do.js +82 -39
  41. package/dist/do.js.map +1 -1
  42. package/dist/error-escalation.d.ts +416 -0
  43. package/dist/error-escalation.d.ts.map +1 -0
  44. package/dist/error-escalation.js +656 -0
  45. package/dist/error-escalation.js.map +1 -0
  46. package/dist/generate.d.ts +48 -7
  47. package/dist/generate.d.ts.map +1 -1
  48. package/dist/generate.js +49 -8
  49. package/dist/generate.js.map +1 -1
  50. package/dist/goals.d.ts +10 -9
  51. package/dist/goals.d.ts.map +1 -1
  52. package/dist/goals.js +30 -24
  53. package/dist/goals.js.map +1 -1
  54. package/dist/image.d.ts +189 -0
  55. package/dist/image.d.ts.map +1 -0
  56. package/dist/image.js +528 -0
  57. package/dist/image.js.map +1 -0
  58. package/dist/index.d.ts +59 -2
  59. package/dist/index.d.ts.map +1 -1
  60. package/dist/index.js +92 -2
  61. package/dist/index.js.map +1 -1
  62. package/dist/is.d.ts +45 -10
  63. package/dist/is.d.ts.map +1 -1
  64. package/dist/is.js +56 -21
  65. package/dist/is.js.map +1 -1
  66. package/dist/kpis.d.ts +24 -15
  67. package/dist/kpis.d.ts.map +1 -1
  68. package/dist/kpis.js +16 -14
  69. package/dist/kpis.js.map +1 -1
  70. package/dist/load-balancing.d.ts +395 -0
  71. package/dist/load-balancing.d.ts.map +1 -0
  72. package/dist/load-balancing.js +991 -0
  73. package/dist/load-balancing.js.map +1 -0
  74. package/dist/logger.d.ts +76 -0
  75. package/dist/logger.d.ts.map +1 -0
  76. package/dist/logger.js +39 -0
  77. package/dist/logger.js.map +1 -0
  78. package/dist/notify.d.ts +38 -9
  79. package/dist/notify.d.ts.map +1 -1
  80. package/dist/notify.js +72 -17
  81. package/dist/notify.js.map +1 -1
  82. package/dist/role.d.ts +5 -4
  83. package/dist/role.d.ts.map +1 -1
  84. package/dist/role.js +13 -10
  85. package/dist/role.js.map +1 -1
  86. package/dist/runtime.d.ts +310 -0
  87. package/dist/runtime.d.ts.map +1 -0
  88. package/dist/runtime.js +510 -0
  89. package/dist/runtime.js.map +1 -0
  90. package/dist/team.d.ts +11 -6
  91. package/dist/team.d.ts.map +1 -1
  92. package/dist/team.js +22 -15
  93. package/dist/team.js.map +1 -1
  94. package/dist/transports/email.d.ts +318 -0
  95. package/dist/transports/email.d.ts.map +1 -0
  96. package/dist/transports/email.js +779 -0
  97. package/dist/transports/email.js.map +1 -0
  98. package/dist/transports/slack.d.ts +515 -0
  99. package/dist/transports/slack.d.ts.map +1 -0
  100. package/dist/transports/slack.js +844 -0
  101. package/dist/transports/slack.js.map +1 -0
  102. package/dist/transports.d.ts.map +1 -1
  103. package/dist/transports.js +44 -25
  104. package/dist/transports.js.map +1 -1
  105. package/dist/types.d.ts +149 -19
  106. package/dist/types.d.ts.map +1 -1
  107. package/dist/types.js +6 -0
  108. package/dist/types.js.map +1 -1
  109. package/dist/utils/id.d.ts +19 -0
  110. package/dist/utils/id.d.ts.map +1 -0
  111. package/dist/utils/id.js +21 -0
  112. package/dist/utils/id.js.map +1 -0
  113. package/dist/video.d.ts +203 -0
  114. package/dist/video.d.ts.map +1 -0
  115. package/dist/video.js +528 -0
  116. package/dist/video.js.map +1 -0
  117. package/dist/worker.d.ts +343 -0
  118. package/dist/worker.d.ts.map +1 -0
  119. package/dist/worker.js +698 -0
  120. package/dist/worker.js.map +1 -0
  121. package/package.json +24 -5
  122. package/src/actions.ts +48 -38
  123. package/src/agent-comms.ts +1200 -0
  124. package/src/approve.ts +91 -20
  125. package/src/ask.ts +99 -25
  126. package/src/browse.ts +627 -0
  127. package/src/capability-tiers.ts +545 -0
  128. package/src/cascade-context.ts +648 -0
  129. package/src/client.ts +221 -0
  130. package/src/decide.ts +81 -35
  131. package/src/do.ts +98 -52
  132. package/src/error-escalation.ts +1123 -0
  133. package/src/generate.ts +52 -18
  134. package/src/goals.ts +36 -27
  135. package/src/image.ts +816 -0
  136. package/src/index.ts +410 -2
  137. package/src/is.ts +59 -25
  138. package/src/kpis.ts +41 -36
  139. package/src/load-balancing.ts +1467 -0
  140. package/src/logger.ts +93 -0
  141. package/src/notify.ts +78 -17
  142. package/src/role.ts +30 -20
  143. package/src/runtime.ts +796 -0
  144. package/src/team.ts +24 -19
  145. package/src/transports/email.ts +1160 -0
  146. package/src/transports/slack.ts +1320 -0
  147. package/src/transports.ts +58 -43
  148. package/src/types.ts +182 -46
  149. package/src/utils/id.ts +21 -0
  150. package/src/video.ts +906 -0
  151. package/src/worker.ts +1007 -0
  152. package/test/agent-comms.test.ts +1397 -0
  153. package/test/approve.test.ts +305 -0
  154. package/test/ask.test.ts +274 -0
  155. package/test/browse.test.ts +361 -0
  156. package/test/capability-tiers.test.ts +631 -0
  157. package/test/cascade-context.test.ts +692 -0
  158. package/test/decide.test.ts +252 -0
  159. package/test/do.test.ts +144 -0
  160. package/test/error-escalation.test.ts +1205 -0
  161. package/test/error-logging.test.ts +357 -0
  162. package/test/generate.test.ts +319 -0
  163. package/test/image.test.ts +398 -0
  164. package/test/is.test.ts +287 -0
  165. package/test/load-balancing-safety.test.ts +404 -0
  166. package/test/load-balancing-thread-safety.test.ts +464 -0
  167. package/test/load-balancing.test.ts +1145 -0
  168. package/test/notify.test.ts +434 -0
  169. package/test/primitives.test.ts +320 -0
  170. package/test/runtime-integration.test.ts +892 -0
  171. package/test/transports/crypto.test.ts +230 -0
  172. package/test/transports/email.test.ts +866 -0
  173. package/test/transports/id-generation.test.ts +91 -0
  174. package/test/transports/slack.test.ts +760 -0
  175. package/test/type-safety.test.ts +834 -0
  176. package/test/types.test.ts +95 -2
  177. package/test/video.test.ts +530 -0
  178. package/test/worker.test.ts +1433 -0
  179. package/tsconfig.json +4 -1
  180. package/vitest.config.ts +42 -0
  181. package/wrangler.jsonc +36 -0
  182. package/.turbo/turbo-build.log +0 -5
  183. package/src/actions.js +0 -436
  184. package/src/approve.js +0 -234
  185. package/src/ask.js +0 -226
  186. package/src/decide.js +0 -244
  187. package/src/do.js +0 -227
  188. package/src/generate.js +0 -298
  189. package/src/goals.js +0 -205
  190. package/src/index.js +0 -68
  191. package/src/is.js +0 -317
  192. package/src/kpis.js +0 -270
  193. package/src/notify.js +0 -219
  194. package/src/role.js +0 -110
  195. package/src/team.js +0 -130
  196. package/src/transports.js +0 -357
  197. package/src/types.js +0 -71
@@ -0,0 +1,252 @@
1
+ /**
2
+ * Tests for decide() - Decision making primitive
3
+ *
4
+ * The decide() function provides structured decision-making with criteria
5
+ * evaluation, confidence scoring, and optional human approval. Unlike
6
+ * ai-functions.decide() which is an LLM-as-judge comparison, this function
7
+ * provides comprehensive decision analysis.
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 { decide } 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('decide() - Decision Making Primitive', () => {
20
+ describe('Unit Tests (no AI)', () => {
21
+ it('should be exported from index', () => {
22
+ expect(decide).toBeDefined()
23
+ expect(typeof decide).toBe('function')
24
+ })
25
+
26
+ it('should have yesNo method', () => {
27
+ expect(decide.yesNo).toBeDefined()
28
+ expect(typeof decide.yesNo).toBe('function')
29
+ })
30
+
31
+ it('should have prioritize method', () => {
32
+ expect(decide.prioritize).toBeDefined()
33
+ expect(typeof decide.prioritize).toBe('function')
34
+ })
35
+
36
+ it('should have withApproval method', () => {
37
+ expect(decide.withApproval).toBeDefined()
38
+ expect(typeof decide.withApproval).toBe('function')
39
+ })
40
+ })
41
+
42
+ describe.skipIf(!hasGateway)('Integration Tests (with AI) - Basic Decisions', () => {
43
+ it('should make a decision from options', async () => {
44
+ const decision = await decide({
45
+ options: ['Option A', 'Option B', 'Option C'],
46
+ context: 'Choose the best option for a simple test',
47
+ })
48
+
49
+ expect(decision).toBeDefined()
50
+ expect(decision.choice).toBeDefined()
51
+ expect(['Option A', 'Option B', 'Option C']).toContain(decision.choice)
52
+ expect(decision.reasoning).toBeDefined()
53
+ expect(typeof decision.reasoning).toBe('string')
54
+ expect(decision.confidence).toBeDefined()
55
+ expect(typeof decision.confidence).toBe('number')
56
+ expect(decision.confidence).toBeGreaterThanOrEqual(0)
57
+ expect(decision.confidence).toBeLessThanOrEqual(1)
58
+ })
59
+
60
+ it('should include alternatives in decision', async () => {
61
+ const decision = await decide({
62
+ options: ['React', 'Vue', 'Svelte'],
63
+ context: 'Choose a frontend framework for a small project',
64
+ })
65
+
66
+ expect(decision).toBeDefined()
67
+ expect(decision.alternatives).toBeDefined()
68
+ expect(Array.isArray(decision.alternatives)).toBe(true)
69
+ })
70
+
71
+ it('should support criteria evaluation', async () => {
72
+ const decision = await decide({
73
+ options: ['PostgreSQL', 'MongoDB', 'Redis'],
74
+ context: 'Choose a database for an e-commerce application',
75
+ criteria: ['ACID compliance', 'Scalability', 'Ease of use', 'Community support'],
76
+ })
77
+
78
+ expect(decision).toBeDefined()
79
+ expect(decision.choice).toBeDefined()
80
+ expect(decision.reasoning).toBeDefined()
81
+ // Reasoning should mention criteria
82
+ expect(decision.reasoning.length).toBeGreaterThan(10)
83
+ })
84
+
85
+ it('should handle object options', async () => {
86
+ const decision = await decide({
87
+ options: [
88
+ { id: 'plan-a', name: 'Basic Plan', price: 10 },
89
+ { id: 'plan-b', name: 'Pro Plan', price: 25 },
90
+ { id: 'plan-c', name: 'Enterprise Plan', price: 100 },
91
+ ],
92
+ context: 'Choose the best plan for a startup with limited budget',
93
+ })
94
+
95
+ expect(decision).toBeDefined()
96
+ expect(decision.choice).toBeDefined()
97
+ })
98
+
99
+ it('should respect includeReasoning option', async () => {
100
+ const decision = await decide({
101
+ options: ['Yes', 'No'],
102
+ context: 'Should we proceed?',
103
+ includeReasoning: true,
104
+ })
105
+
106
+ expect(decision.reasoning).toBeDefined()
107
+ expect(decision.reasoning.length).toBeGreaterThan(0)
108
+ })
109
+
110
+ it('should handle complex context object', async () => {
111
+ const decision = await decide({
112
+ options: ['Approve', 'Reject', 'Request more info'],
113
+ context: {
114
+ requestType: 'Budget increase',
115
+ amount: 50000,
116
+ department: 'Engineering',
117
+ justification: 'Need to hire additional developer',
118
+ currentBudget: 200000,
119
+ utilizationRate: 0.95,
120
+ },
121
+ })
122
+
123
+ expect(decision).toBeDefined()
124
+ expect(decision.choice).toBeDefined()
125
+ })
126
+ })
127
+
128
+ describe.skipIf(!hasGateway)('Integration Tests (with AI) - Yes/No Decisions', () => {
129
+ it('should make binary decision', async () => {
130
+ const decision = await decide.yesNo(
131
+ 'Should we deploy on Friday?',
132
+ 'The deploy is a minor bug fix with good test coverage'
133
+ )
134
+
135
+ expect(decision).toBeDefined()
136
+ expect(['yes', 'no']).toContain(decision.choice)
137
+ expect(decision.reasoning).toBeDefined()
138
+ expect(decision.confidence).toBeDefined()
139
+ })
140
+
141
+ it('should handle context object in yesNo', async () => {
142
+ const decision = await decide.yesNo('Should we approve this expense?', {
143
+ amount: 500,
144
+ category: 'Software',
145
+ policy: 'Software expenses under $1000 are auto-approved',
146
+ })
147
+
148
+ expect(decision).toBeDefined()
149
+ expect(['yes', 'no']).toContain(decision.choice)
150
+ })
151
+
152
+ it('should provide confidence score for yesNo', async () => {
153
+ const decision = await decide.yesNo('Is this a valid email format: test@example.com?')
154
+
155
+ expect(decision.confidence).toBeGreaterThan(0)
156
+ })
157
+ })
158
+
159
+ describe.skipIf(!hasGateway)('Integration Tests (with AI) - Prioritization', () => {
160
+ it('should prioritize items', async () => {
161
+ const prioritized = await decide.prioritize(
162
+ ['Feature A', 'Bug Fix B', 'Tech Debt C', 'Feature D'],
163
+ 'Sprint planning for a 2-week sprint'
164
+ )
165
+
166
+ expect(prioritized).toBeDefined()
167
+ expect(Array.isArray(prioritized)).toBe(true)
168
+ expect(prioritized.length).toBe(4)
169
+
170
+ prioritized.forEach((item) => {
171
+ expect(item.choice).toBeDefined()
172
+ expect(item.rank).toBeDefined()
173
+ expect(typeof item.rank).toBe('number')
174
+ expect(item.reasoning).toBeDefined()
175
+ expect(item.confidence).toBeDefined()
176
+ })
177
+ })
178
+
179
+ it('should prioritize with criteria', async () => {
180
+ const prioritized = await decide.prioritize(
181
+ ['Task 1', 'Task 2', 'Task 3'],
182
+ 'Project backlog',
183
+ ['User impact', 'Urgency', 'Effort required']
184
+ )
185
+
186
+ expect(prioritized).toBeDefined()
187
+ expect(prioritized.length).toBe(3)
188
+
189
+ // All items should have a rank
190
+ const ranks = prioritized.map((p) => p.rank)
191
+ expect(ranks.every((r) => typeof r === 'number')).toBe(true)
192
+ })
193
+
194
+ it('should prioritize object items', async () => {
195
+ const items = [
196
+ { id: 1, name: 'Critical bug', severity: 'high' },
197
+ { id: 2, name: 'New feature', severity: 'low' },
198
+ { id: 3, name: 'Performance fix', severity: 'medium' },
199
+ ]
200
+
201
+ const prioritized = await decide.prioritize(items, 'Bug triage session')
202
+
203
+ expect(prioritized).toBeDefined()
204
+ expect(prioritized.length).toBe(3)
205
+ })
206
+ })
207
+
208
+ describe.skipIf(!hasGateway)('Integration Tests (with AI) - Decision Quality', () => {
209
+ it('should provide meaningful reasoning', async () => {
210
+ const decision = await decide({
211
+ options: ['AWS', 'GCP', 'Azure'],
212
+ context: 'Choosing a cloud provider for a machine learning startup',
213
+ criteria: ['ML services', 'Pricing', 'Documentation', 'Support'],
214
+ })
215
+
216
+ expect(decision.reasoning).toBeDefined()
217
+ expect(decision.reasoning.length).toBeGreaterThan(50)
218
+ // Reasoning should be substantive
219
+ })
220
+
221
+ it('should score alternatives', async () => {
222
+ const decision = await decide({
223
+ options: ['TypeScript', 'Python', 'Go', 'Rust'],
224
+ context: 'Choosing a language for a CLI tool',
225
+ })
226
+
227
+ if (decision.alternatives && decision.alternatives.length > 0) {
228
+ decision.alternatives.forEach((alt) => {
229
+ expect(alt.option).toBeDefined()
230
+ expect(typeof alt.score).toBe('number')
231
+ })
232
+ }
233
+ })
234
+
235
+ it('should normalize confidence to 0-1 range', async () => {
236
+ const decision = await decide({
237
+ options: ['A', 'B'],
238
+ context: 'Simple choice',
239
+ })
240
+
241
+ expect(decision.confidence).toBeGreaterThanOrEqual(0)
242
+ expect(decision.confidence).toBeLessThanOrEqual(1)
243
+ })
244
+ })
245
+
246
+ describe('Decision with Approval', () => {
247
+ it('should have withApproval method that requires approver', async () => {
248
+ // Just verify the signature - actual approval routing is tested in approve.test.ts
249
+ expect(typeof decide.withApproval).toBe('function')
250
+ })
251
+ })
252
+ })
@@ -0,0 +1,144 @@
1
+ /**
2
+ * Tests for do() - Task execution primitive
3
+ *
4
+ * The do() function routes tasks to appropriate Workers (AI Agents or Humans)
5
+ * based on capability matching. Unlike ai-functions.do() which directly calls
6
+ * the LLM, this function provides worker coordination with retries and timeouts.
7
+ *
8
+ * These tests use real AI calls via the Cloudflare AI Gateway.
9
+ * Tests are skipped if AI_GATEWAY_URL is not configured.
10
+ */
11
+
12
+ import { describe, it, expect } from 'vitest'
13
+ import { do as doTask } from '../src/index.js'
14
+
15
+ // Skip tests if no gateway configured
16
+ const hasGateway = !!process.env.AI_GATEWAY_URL || !!process.env.ANTHROPIC_API_KEY
17
+
18
+ describe('do() - Task Execution Primitive', () => {
19
+ describe('Unit Tests (no AI)', () => {
20
+ it('should be exported from index', () => {
21
+ expect(doTask).toBeDefined()
22
+ expect(typeof doTask).toBe('function')
23
+ })
24
+
25
+ it('should have parallel method', () => {
26
+ expect(doTask.parallel).toBeDefined()
27
+ expect(typeof doTask.parallel).toBe('function')
28
+ })
29
+
30
+ it('should have sequence method', () => {
31
+ expect(doTask.sequence).toBeDefined()
32
+ expect(typeof doTask.sequence).toBe('function')
33
+ })
34
+
35
+ it('should have withDependencies method', () => {
36
+ expect(doTask.withDependencies).toBeDefined()
37
+ expect(typeof doTask.withDependencies).toBe('function')
38
+ })
39
+ })
40
+
41
+ describe.skipIf(!hasGateway)('Integration Tests (with AI)', () => {
42
+ it('should execute a simple task', async () => {
43
+ const result = await doTask('Calculate 2 + 2 and return the result', {
44
+ timeout: 30000,
45
+ })
46
+
47
+ expect(result).toBeDefined()
48
+ expect(typeof result.success).toBe('boolean')
49
+ expect(typeof result.duration).toBe('number')
50
+ expect(result.duration).toBeGreaterThan(0)
51
+ })
52
+
53
+ it('should execute task with context', async () => {
54
+ const result = await doTask('Summarize the provided text', {
55
+ timeout: 30000,
56
+ context: {
57
+ text: 'Hello world. This is a simple test message.',
58
+ },
59
+ })
60
+
61
+ expect(result).toBeDefined()
62
+ expect(result.success).toBeDefined()
63
+ expect(result.duration).toBeGreaterThan(0)
64
+ })
65
+
66
+ it('should return steps array', async () => {
67
+ const result = await doTask('List 3 colors', {
68
+ timeout: 30000,
69
+ })
70
+
71
+ expect(result).toBeDefined()
72
+ expect(Array.isArray(result.steps)).toBe(true)
73
+ })
74
+
75
+ it('should handle task with structured context', async () => {
76
+ const result = await doTask<{ name: string; greeting: string }>(
77
+ 'Generate a greeting for the user',
78
+ {
79
+ timeout: 30000,
80
+ context: {
81
+ user: { name: 'Alice', language: 'English' },
82
+ },
83
+ }
84
+ )
85
+
86
+ expect(result).toBeDefined()
87
+ expect(result.success).toBeDefined()
88
+ })
89
+
90
+ it('should handle timeout option', async () => {
91
+ // Very short timeout to test timeout behavior
92
+ const result = await doTask('Count from 1 to 5', {
93
+ timeout: 1, // 1ms timeout - will likely fail
94
+ })
95
+
96
+ // Either succeeds quickly or fails due to timeout
97
+ expect(result).toBeDefined()
98
+ expect(typeof result.success).toBe('boolean')
99
+ })
100
+
101
+ it('should execute parallel tasks', async () => {
102
+ const results = await doTask.parallel(['What is 1+1?', 'What is 2+2?', 'What is 3+3?'], {
103
+ timeout: 30000,
104
+ })
105
+
106
+ expect(results).toBeDefined()
107
+ expect(Array.isArray(results)).toBe(true)
108
+ expect(results.length).toBe(3)
109
+ results.forEach((result) => {
110
+ expect(result.success).toBeDefined()
111
+ expect(result.duration).toBeDefined()
112
+ })
113
+ })
114
+
115
+ it('should execute sequential tasks', async () => {
116
+ const results = await doTask.sequence(['Say hello', 'Say goodbye'], { timeout: 30000 })
117
+
118
+ expect(results).toBeDefined()
119
+ expect(Array.isArray(results)).toBe(true)
120
+ expect(results.length).toBe(2)
121
+ })
122
+
123
+ it('should handle task with retries option', async () => {
124
+ const result = await doTask('Return the word "success"', {
125
+ maxRetries: 1,
126
+ timeout: 30000,
127
+ })
128
+
129
+ expect(result).toBeDefined()
130
+ expect(result.success).toBeDefined()
131
+ })
132
+
133
+ it('should support background execution option', async () => {
134
+ const result = await doTask('Generate a random number', {
135
+ background: true,
136
+ timeout: 30000,
137
+ })
138
+
139
+ expect(result).toBeDefined()
140
+ // Background tasks still return a result
141
+ expect(result.success).toBeDefined()
142
+ })
143
+ })
144
+ })