@positronic/core 0.0.1 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/CLAUDE.md +141 -0
  2. package/dist/src/adapters/types.js +1 -16
  3. package/dist/src/clients/types.js +4 -1
  4. package/dist/src/dsl/brain-runner.js +487 -0
  5. package/dist/src/dsl/brain-runner.test.js +733 -0
  6. package/dist/src/dsl/brain.js +1128 -0
  7. package/dist/src/dsl/brain.test.js +4225 -0
  8. package/dist/src/dsl/constants.js +6 -6
  9. package/dist/src/dsl/json-patch.js +37 -9
  10. package/dist/src/index.js +11 -10
  11. package/dist/src/resources/resources.js +371 -0
  12. package/dist/src/test-utils.js +474 -0
  13. package/dist/src/testing.js +3 -0
  14. package/dist/types/adapters/types.d.ts +3 -8
  15. package/dist/types/adapters/types.d.ts.map +1 -1
  16. package/dist/types/clients/types.d.ts +46 -6
  17. package/dist/types/clients/types.d.ts.map +1 -1
  18. package/dist/types/dsl/brain-runner.d.ts +24 -0
  19. package/dist/types/dsl/brain-runner.d.ts.map +1 -0
  20. package/dist/types/dsl/brain.d.ts +136 -0
  21. package/dist/types/dsl/brain.d.ts.map +1 -0
  22. package/dist/types/dsl/constants.d.ts +5 -5
  23. package/dist/types/dsl/constants.d.ts.map +1 -1
  24. package/dist/types/dsl/json-patch.d.ts +2 -1
  25. package/dist/types/dsl/json-patch.d.ts.map +1 -1
  26. package/dist/types/index.d.ts +13 -11
  27. package/dist/types/index.d.ts.map +1 -1
  28. package/dist/types/resources/resource-loader.d.ts +6 -0
  29. package/dist/types/resources/resource-loader.d.ts.map +1 -0
  30. package/dist/types/resources/resources.d.ts +23 -0
  31. package/dist/types/resources/resources.d.ts.map +1 -0
  32. package/dist/types/test-utils.d.ts +94 -0
  33. package/dist/types/test-utils.d.ts.map +1 -0
  34. package/dist/types/testing.d.ts +2 -0
  35. package/dist/types/testing.d.ts.map +1 -0
  36. package/docs/core-testing-guide.md +289 -0
  37. package/package.json +26 -7
  38. package/src/adapters/types.ts +3 -22
  39. package/src/clients/types.ts +50 -10
  40. package/src/dsl/brain-runner.test.ts +384 -0
  41. package/src/dsl/brain-runner.ts +111 -0
  42. package/src/dsl/brain.test.ts +1981 -0
  43. package/src/dsl/brain.ts +740 -0
  44. package/src/dsl/constants.ts +6 -6
  45. package/src/dsl/json-patch.ts +24 -9
  46. package/src/dsl/types.ts +1 -1
  47. package/src/index.ts +30 -16
  48. package/src/resources/resource-loader.ts +8 -0
  49. package/src/resources/resources.ts +267 -0
  50. package/src/test-utils.ts +254 -0
  51. package/test/resources.test.ts +248 -0
  52. package/tsconfig.json +2 -2
  53. package/.swcrc +0 -31
  54. package/dist/src/dsl/extensions.js +0 -19
  55. package/dist/src/dsl/workflow-runner.js +0 -93
  56. package/dist/src/dsl/workflow.js +0 -308
  57. package/dist/src/file-stores/local-file-store.js +0 -12
  58. package/dist/src/utils/temp-files.js +0 -27
  59. package/dist/types/dsl/extensions.d.ts +0 -18
  60. package/dist/types/dsl/extensions.d.ts.map +0 -1
  61. package/dist/types/dsl/workflow-runner.d.ts +0 -28
  62. package/dist/types/dsl/workflow-runner.d.ts.map +0 -1
  63. package/dist/types/dsl/workflow.d.ts +0 -118
  64. package/dist/types/dsl/workflow.d.ts.map +0 -1
  65. package/dist/types/file-stores/local-file-store.d.ts +0 -7
  66. package/dist/types/file-stores/local-file-store.d.ts.map +0 -1
  67. package/dist/types/file-stores/types.d.ts +0 -4
  68. package/dist/types/file-stores/types.d.ts.map +0 -1
  69. package/dist/types/utils/temp-files.d.ts +0 -12
  70. package/dist/types/utils/temp-files.d.ts.map +0 -1
  71. package/src/dsl/extensions.ts +0 -58
  72. package/src/dsl/workflow-runner.test.ts +0 -203
  73. package/src/dsl/workflow-runner.ts +0 -146
  74. package/src/dsl/workflow.test.ts +0 -1435
  75. package/src/dsl/workflow.ts +0 -554
  76. package/src/file-stores/local-file-store.ts +0 -11
  77. package/src/file-stores/types.ts +0 -3
  78. package/src/utils/temp-files.ts +0 -46
  79. /package/dist/src/{file-stores/types.js → resources/resource-loader.js} +0 -0
@@ -0,0 +1,4225 @@
1
+ function _array_like_to_array(arr, len) {
2
+ if (len == null || len > arr.length) len = arr.length;
3
+ for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
4
+ return arr2;
5
+ }
6
+ function _array_without_holes(arr) {
7
+ if (Array.isArray(arr)) return _array_like_to_array(arr);
8
+ }
9
+ function _async_iterator(iterable) {
10
+ var method, async, sync, retry = 2;
11
+ for("undefined" != typeof Symbol && (async = Symbol.asyncIterator, sync = Symbol.iterator); retry--;){
12
+ if (async && null != (method = iterable[async])) return method.call(iterable);
13
+ if (sync && null != (method = iterable[sync])) return new AsyncFromSyncIterator(method.call(iterable));
14
+ async = "@@asyncIterator", sync = "@@iterator";
15
+ }
16
+ throw new TypeError("Object is not async iterable");
17
+ }
18
+ function AsyncFromSyncIterator(s) {
19
+ function AsyncFromSyncIteratorContinuation(r) {
20
+ if (Object(r) !== r) return Promise.reject(new TypeError(r + " is not an object."));
21
+ var done = r.done;
22
+ return Promise.resolve(r.value).then(function(value) {
23
+ return {
24
+ value: value,
25
+ done: done
26
+ };
27
+ });
28
+ }
29
+ return AsyncFromSyncIterator = function(s) {
30
+ this.s = s, this.n = s.next;
31
+ }, AsyncFromSyncIterator.prototype = {
32
+ s: null,
33
+ n: null,
34
+ next: function() {
35
+ return AsyncFromSyncIteratorContinuation(this.n.apply(this.s, arguments));
36
+ },
37
+ return: function(value) {
38
+ var ret = this.s.return;
39
+ return void 0 === ret ? Promise.resolve({
40
+ value: value,
41
+ done: !0
42
+ }) : AsyncFromSyncIteratorContinuation(ret.apply(this.s, arguments));
43
+ },
44
+ throw: function(value) {
45
+ var thr = this.s.return;
46
+ return void 0 === thr ? Promise.reject(value) : AsyncFromSyncIteratorContinuation(thr.apply(this.s, arguments));
47
+ }
48
+ }, new AsyncFromSyncIterator(s);
49
+ }
50
+ function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
51
+ try {
52
+ var info = gen[key](arg);
53
+ var value = info.value;
54
+ } catch (error) {
55
+ reject(error);
56
+ return;
57
+ }
58
+ if (info.done) {
59
+ resolve(value);
60
+ } else {
61
+ Promise.resolve(value).then(_next, _throw);
62
+ }
63
+ }
64
+ function _async_to_generator(fn) {
65
+ return function() {
66
+ var self = this, args = arguments;
67
+ return new Promise(function(resolve, reject) {
68
+ var gen = fn.apply(self, args);
69
+ function _next(value) {
70
+ asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);
71
+ }
72
+ function _throw(err) {
73
+ asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err);
74
+ }
75
+ _next(undefined);
76
+ });
77
+ };
78
+ }
79
+ function _define_property(obj, key, value) {
80
+ if (key in obj) {
81
+ Object.defineProperty(obj, key, {
82
+ value: value,
83
+ enumerable: true,
84
+ configurable: true,
85
+ writable: true
86
+ });
87
+ } else {
88
+ obj[key] = value;
89
+ }
90
+ return obj;
91
+ }
92
+ function _iterable_to_array(iter) {
93
+ if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
94
+ }
95
+ function _non_iterable_spread() {
96
+ throw new TypeError("Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
97
+ }
98
+ function _object_spread(target) {
99
+ for(var i = 1; i < arguments.length; i++){
100
+ var source = arguments[i] != null ? arguments[i] : {};
101
+ var ownKeys = Object.keys(source);
102
+ if (typeof Object.getOwnPropertySymbols === "function") {
103
+ ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function(sym) {
104
+ return Object.getOwnPropertyDescriptor(source, sym).enumerable;
105
+ }));
106
+ }
107
+ ownKeys.forEach(function(key) {
108
+ _define_property(target, key, source[key]);
109
+ });
110
+ }
111
+ return target;
112
+ }
113
+ function ownKeys(object, enumerableOnly) {
114
+ var keys = Object.keys(object);
115
+ if (Object.getOwnPropertySymbols) {
116
+ var symbols = Object.getOwnPropertySymbols(object);
117
+ if (enumerableOnly) {
118
+ symbols = symbols.filter(function(sym) {
119
+ return Object.getOwnPropertyDescriptor(object, sym).enumerable;
120
+ });
121
+ }
122
+ keys.push.apply(keys, symbols);
123
+ }
124
+ return keys;
125
+ }
126
+ function _object_spread_props(target, source) {
127
+ source = source != null ? source : {};
128
+ if (Object.getOwnPropertyDescriptors) {
129
+ Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
130
+ } else {
131
+ ownKeys(Object(source)).forEach(function(key) {
132
+ Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
133
+ });
134
+ }
135
+ return target;
136
+ }
137
+ function _to_consumable_array(arr) {
138
+ return _array_without_holes(arr) || _iterable_to_array(arr) || _unsupported_iterable_to_array(arr) || _non_iterable_spread();
139
+ }
140
+ function _unsupported_iterable_to_array(o, minLen) {
141
+ if (!o) return;
142
+ if (typeof o === "string") return _array_like_to_array(o, minLen);
143
+ var n = Object.prototype.toString.call(o).slice(8, -1);
144
+ if (n === "Object" && o.constructor) n = o.constructor.name;
145
+ if (n === "Map" || n === "Set") return Array.from(n);
146
+ if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array(o, minLen);
147
+ }
148
+ function _ts_generator(thisArg, body) {
149
+ var f, y, t, _ = {
150
+ label: 0,
151
+ sent: function() {
152
+ if (t[0] & 1) throw t[1];
153
+ return t[1];
154
+ },
155
+ trys: [],
156
+ ops: []
157
+ }, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
158
+ return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() {
159
+ return this;
160
+ }), g;
161
+ function verb(n) {
162
+ return function(v) {
163
+ return step([
164
+ n,
165
+ v
166
+ ]);
167
+ };
168
+ }
169
+ function step(op) {
170
+ if (f) throw new TypeError("Generator is already executing.");
171
+ while(g && (g = 0, op[0] && (_ = 0)), _)try {
172
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
173
+ if (y = 0, t) op = [
174
+ op[0] & 2,
175
+ t.value
176
+ ];
177
+ switch(op[0]){
178
+ case 0:
179
+ case 1:
180
+ t = op;
181
+ break;
182
+ case 4:
183
+ _.label++;
184
+ return {
185
+ value: op[1],
186
+ done: false
187
+ };
188
+ case 5:
189
+ _.label++;
190
+ y = op[1];
191
+ op = [
192
+ 0
193
+ ];
194
+ continue;
195
+ case 7:
196
+ op = _.ops.pop();
197
+ _.trys.pop();
198
+ continue;
199
+ default:
200
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) {
201
+ _ = 0;
202
+ continue;
203
+ }
204
+ if (op[0] === 3 && (!t || op[1] > t[0] && op[1] < t[3])) {
205
+ _.label = op[1];
206
+ break;
207
+ }
208
+ if (op[0] === 6 && _.label < t[1]) {
209
+ _.label = t[1];
210
+ t = op;
211
+ break;
212
+ }
213
+ if (t && _.label < t[2]) {
214
+ _.label = t[2];
215
+ _.ops.push(op);
216
+ break;
217
+ }
218
+ if (t[2]) _.ops.pop();
219
+ _.trys.pop();
220
+ continue;
221
+ }
222
+ op = body.call(thisArg, _);
223
+ } catch (e) {
224
+ op = [
225
+ 6,
226
+ e
227
+ ];
228
+ y = 0;
229
+ } finally{
230
+ f = t = 0;
231
+ }
232
+ if (op[0] & 5) throw op[1];
233
+ return {
234
+ value: op[0] ? op[1] : void 0,
235
+ done: true
236
+ };
237
+ }
238
+ }
239
+ import { BRAIN_EVENTS, STATUS } from './constants.js';
240
+ import { applyPatches } from './json-patch.js';
241
+ import { brain } from './brain.js';
242
+ import { z } from 'zod';
243
+ import { jest } from '@jest/globals';
244
+ import { createResources } from '../resources/resources.js';
245
+ // Helper function to get the next value from an AsyncIterator
246
+ var nextStep = function(brainRun) {
247
+ return _async_to_generator(function() {
248
+ var result;
249
+ return _ts_generator(this, function(_state) {
250
+ switch(_state.label){
251
+ case 0:
252
+ return [
253
+ 4,
254
+ brainRun.next()
255
+ ];
256
+ case 1:
257
+ result = _state.sent();
258
+ if (result.done) throw new Error('Iterator is done');
259
+ return [
260
+ 2,
261
+ result.value
262
+ ];
263
+ }
264
+ });
265
+ })();
266
+ };
267
+ // Mock services for testing
268
+ var testLogger = {
269
+ log: jest.fn()
270
+ };
271
+ // Mock ObjectGenerator for testing
272
+ var mockGenerateObject = jest.fn();
273
+ var mockClient = {
274
+ generateObject: mockGenerateObject
275
+ };
276
+ // Mock Resources for testing
277
+ var mockResourceLoad = jest.fn(function(resourceName, type) {
278
+ return _async_to_generator(function() {
279
+ return _ts_generator(this, function(_state) {
280
+ if (type === 'binary') return [
281
+ 2,
282
+ Buffer.from("mock ".concat(resourceName, " binary content"))
283
+ ];
284
+ return [
285
+ 2,
286
+ "mock ".concat(resourceName, " text content")
287
+ ];
288
+ });
289
+ })();
290
+ });
291
+ var mockResourceLoader = {
292
+ load: mockResourceLoad
293
+ };
294
+ var testManifest = {
295
+ myFile: {
296
+ type: 'text',
297
+ key: 'myFile',
298
+ path: '/test/myFile.txt'
299
+ },
300
+ myBinaryFile: {
301
+ type: 'binary',
302
+ key: 'myBinaryFile',
303
+ path: '/test/myBinaryFile.bin'
304
+ },
305
+ nested: {
306
+ anotherFile: {
307
+ type: 'text',
308
+ key: 'anotherFile',
309
+ path: '/test/anotherFile.txt'
310
+ }
311
+ }
312
+ };
313
+ var mockResources = createResources(mockResourceLoader, testManifest);
314
+ describe('brain creation', function() {
315
+ beforeEach(function() {
316
+ mockGenerateObject.mockClear();
317
+ mockResourceLoad.mockClear();
318
+ });
319
+ it('should create a brain with steps and run through them', function() {
320
+ return _async_to_generator(function() {
321
+ var testBrain, brainRun, startResult, firstStepStartResult, firstStepStatusRunning, firstStepResult, secondStepStartResult, secondStepStatusRunning, secondStepResult, stepStatusResult, completeResult;
322
+ return _ts_generator(this, function(_state) {
323
+ switch(_state.label){
324
+ case 0:
325
+ testBrain = brain('test brain').step('First step', function() {
326
+ return {
327
+ count: 1
328
+ };
329
+ }).step('Second step', function(param) {
330
+ var state = param.state;
331
+ return _object_spread_props(_object_spread({}, state), {
332
+ doubled: state.count * 2
333
+ });
334
+ });
335
+ brainRun = testBrain.run({
336
+ client: mockClient
337
+ });
338
+ return [
339
+ 4,
340
+ brainRun.next()
341
+ ];
342
+ case 1:
343
+ startResult = _state.sent();
344
+ expect(startResult.value).toEqual(expect.objectContaining({
345
+ type: BRAIN_EVENTS.START,
346
+ status: STATUS.RUNNING,
347
+ brainTitle: 'test brain',
348
+ brainDescription: undefined
349
+ }));
350
+ // Skip initial step status event
351
+ return [
352
+ 4,
353
+ nextStep(brainRun)
354
+ ];
355
+ case 2:
356
+ _state.sent();
357
+ return [
358
+ 4,
359
+ nextStep(brainRun)
360
+ ];
361
+ case 3:
362
+ firstStepStartResult = _state.sent();
363
+ expect(firstStepStartResult).toEqual(expect.objectContaining({
364
+ type: BRAIN_EVENTS.STEP_START,
365
+ status: STATUS.RUNNING,
366
+ stepTitle: 'First step',
367
+ stepId: expect.any(String)
368
+ }));
369
+ return [
370
+ 4,
371
+ nextStep(brainRun)
372
+ ];
373
+ case 4:
374
+ firstStepStatusRunning = _state.sent();
375
+ expect(firstStepStatusRunning).toEqual(expect.objectContaining({
376
+ type: BRAIN_EVENTS.STEP_STATUS,
377
+ steps: expect.any(Array)
378
+ }));
379
+ if (firstStepStatusRunning.type === BRAIN_EVENTS.STEP_STATUS) {
380
+ expect(firstStepStatusRunning.steps[0].status).toBe(STATUS.RUNNING);
381
+ }
382
+ return [
383
+ 4,
384
+ nextStep(brainRun)
385
+ ];
386
+ case 5:
387
+ firstStepResult = _state.sent();
388
+ expect(firstStepResult).toEqual(expect.objectContaining({
389
+ type: BRAIN_EVENTS.STEP_COMPLETE,
390
+ status: STATUS.RUNNING,
391
+ stepTitle: 'First step',
392
+ stepId: expect.any(String),
393
+ patch: [
394
+ {
395
+ op: 'add',
396
+ path: '/count',
397
+ value: 1
398
+ }
399
+ ]
400
+ }));
401
+ // Step Status Event
402
+ return [
403
+ 4,
404
+ nextStep(brainRun)
405
+ ];
406
+ case 6:
407
+ _state.sent();
408
+ return [
409
+ 4,
410
+ nextStep(brainRun)
411
+ ];
412
+ case 7:
413
+ secondStepStartResult = _state.sent();
414
+ expect(secondStepStartResult).toEqual(expect.objectContaining({
415
+ type: BRAIN_EVENTS.STEP_START,
416
+ status: STATUS.RUNNING,
417
+ stepTitle: 'Second step',
418
+ stepId: expect.any(String)
419
+ }));
420
+ return [
421
+ 4,
422
+ nextStep(brainRun)
423
+ ];
424
+ case 8:
425
+ secondStepStatusRunning = _state.sent();
426
+ expect(secondStepStatusRunning).toEqual(expect.objectContaining({
427
+ type: BRAIN_EVENTS.STEP_STATUS,
428
+ steps: expect.any(Array)
429
+ }));
430
+ if (secondStepStatusRunning.type === BRAIN_EVENTS.STEP_STATUS) {
431
+ expect(secondStepStatusRunning.steps[1].status).toBe(STATUS.RUNNING);
432
+ }
433
+ return [
434
+ 4,
435
+ nextStep(brainRun)
436
+ ];
437
+ case 9:
438
+ secondStepResult = _state.sent();
439
+ expect(secondStepResult).toEqual(expect.objectContaining({
440
+ type: BRAIN_EVENTS.STEP_COMPLETE,
441
+ stepTitle: 'Second step',
442
+ stepId: expect.any(String),
443
+ patch: [
444
+ {
445
+ op: 'add',
446
+ path: '/doubled',
447
+ value: 2
448
+ }
449
+ ]
450
+ }));
451
+ return [
452
+ 4,
453
+ nextStep(brainRun)
454
+ ];
455
+ case 10:
456
+ stepStatusResult = _state.sent();
457
+ expect(stepStatusResult).toEqual(expect.objectContaining({
458
+ type: BRAIN_EVENTS.STEP_STATUS,
459
+ steps: [
460
+ expect.objectContaining({
461
+ title: 'First step',
462
+ status: STATUS.COMPLETE,
463
+ id: expect.any(String)
464
+ }),
465
+ expect.objectContaining({
466
+ title: 'Second step',
467
+ status: STATUS.COMPLETE,
468
+ id: expect.any(String)
469
+ })
470
+ ]
471
+ }));
472
+ return [
473
+ 4,
474
+ nextStep(brainRun)
475
+ ];
476
+ case 11:
477
+ completeResult = _state.sent();
478
+ expect(completeResult).toEqual(expect.objectContaining({
479
+ type: BRAIN_EVENTS.COMPLETE,
480
+ status: STATUS.COMPLETE,
481
+ brainTitle: 'test brain',
482
+ brainDescription: undefined
483
+ }));
484
+ return [
485
+ 2
486
+ ];
487
+ }
488
+ });
489
+ })();
490
+ });
491
+ it('should create a brain with a name and description when passed an object', function() {
492
+ return _async_to_generator(function() {
493
+ var testBrain, brainRun, startResult;
494
+ return _ts_generator(this, function(_state) {
495
+ switch(_state.label){
496
+ case 0:
497
+ testBrain = brain({
498
+ title: 'my named brain',
499
+ description: 'some description'
500
+ });
501
+ brainRun = testBrain.run({
502
+ client: mockClient
503
+ });
504
+ return [
505
+ 4,
506
+ brainRun.next()
507
+ ];
508
+ case 1:
509
+ startResult = _state.sent();
510
+ expect(startResult.value).toEqual(expect.objectContaining({
511
+ type: BRAIN_EVENTS.START,
512
+ status: STATUS.RUNNING,
513
+ brainTitle: 'my named brain',
514
+ brainDescription: 'some description',
515
+ options: {}
516
+ }));
517
+ return [
518
+ 2
519
+ ];
520
+ }
521
+ });
522
+ })();
523
+ });
524
+ it('should create a brain with just a name when passed a string', function() {
525
+ return _async_to_generator(function() {
526
+ var testBrain, brainRun, startResult;
527
+ return _ts_generator(this, function(_state) {
528
+ switch(_state.label){
529
+ case 0:
530
+ testBrain = brain('simple brain');
531
+ brainRun = testBrain.run({
532
+ client: mockClient
533
+ });
534
+ return [
535
+ 4,
536
+ brainRun.next()
537
+ ];
538
+ case 1:
539
+ startResult = _state.sent();
540
+ expect(startResult.value).toEqual(expect.objectContaining({
541
+ type: BRAIN_EVENTS.START,
542
+ status: STATUS.RUNNING,
543
+ brainTitle: 'simple brain',
544
+ brainDescription: undefined,
545
+ options: {}
546
+ }));
547
+ return [
548
+ 2
549
+ ];
550
+ }
551
+ });
552
+ })();
553
+ });
554
+ it('should allow overriding client per step', function() {
555
+ return _async_to_generator(function() {
556
+ var overrideClient, testBrain, events, finalState, _iteratorAbruptCompletion, _didIteratorError, _iteratorError, _iterator, _step, _value, event, err;
557
+ return _ts_generator(this, function(_state) {
558
+ switch(_state.label){
559
+ case 0:
560
+ overrideClient = {
561
+ generateObject: jest.fn().mockResolvedValue({
562
+ override: true
563
+ })
564
+ };
565
+ // Make sure that for the default prompt the default client returns a known value.
566
+ mockClient.generateObject.mockResolvedValueOnce({
567
+ override: false
568
+ });
569
+ testBrain = brain('Client Override Test').prompt('Use default client', {
570
+ template: function() {
571
+ return 'prompt1';
572
+ },
573
+ outputSchema: {
574
+ schema: z.object({
575
+ override: z.boolean()
576
+ }),
577
+ name: 'overrideResponse'
578
+ }
579
+ }).prompt('Use override client', {
580
+ template: function() {
581
+ return 'prompt2';
582
+ },
583
+ outputSchema: {
584
+ schema: z.object({
585
+ override: z.boolean()
586
+ }),
587
+ name: 'overrideResponse'
588
+ },
589
+ client: overrideClient
590
+ });
591
+ // Run the brain and capture all events
592
+ events = [];
593
+ finalState = {};
594
+ _iteratorAbruptCompletion = false, _didIteratorError = false;
595
+ _state.label = 1;
596
+ case 1:
597
+ _state.trys.push([
598
+ 1,
599
+ 6,
600
+ 7,
601
+ 12
602
+ ]);
603
+ _iterator = _async_iterator(testBrain.run({
604
+ client: mockClient
605
+ }));
606
+ _state.label = 2;
607
+ case 2:
608
+ return [
609
+ 4,
610
+ _iterator.next()
611
+ ];
612
+ case 3:
613
+ if (!(_iteratorAbruptCompletion = !(_step = _state.sent()).done)) return [
614
+ 3,
615
+ 5
616
+ ];
617
+ _value = _step.value;
618
+ event = _value;
619
+ events.push(event);
620
+ if (event.type === BRAIN_EVENTS.STEP_COMPLETE) {
621
+ finalState = applyPatches(finalState, [
622
+ event.patch
623
+ ]);
624
+ }
625
+ _state.label = 4;
626
+ case 4:
627
+ _iteratorAbruptCompletion = false;
628
+ return [
629
+ 3,
630
+ 2
631
+ ];
632
+ case 5:
633
+ return [
634
+ 3,
635
+ 12
636
+ ];
637
+ case 6:
638
+ err = _state.sent();
639
+ _didIteratorError = true;
640
+ _iteratorError = err;
641
+ return [
642
+ 3,
643
+ 12
644
+ ];
645
+ case 7:
646
+ _state.trys.push([
647
+ 7,
648
+ ,
649
+ 10,
650
+ 11
651
+ ]);
652
+ if (!(_iteratorAbruptCompletion && _iterator.return != null)) return [
653
+ 3,
654
+ 9
655
+ ];
656
+ return [
657
+ 4,
658
+ _iterator.return()
659
+ ];
660
+ case 8:
661
+ _state.sent();
662
+ _state.label = 9;
663
+ case 9:
664
+ return [
665
+ 3,
666
+ 11
667
+ ];
668
+ case 10:
669
+ if (_didIteratorError) {
670
+ throw _iteratorError;
671
+ }
672
+ return [
673
+ 7
674
+ ];
675
+ case 11:
676
+ return [
677
+ 7
678
+ ];
679
+ case 12:
680
+ // Final state should include both responses
681
+ expect(finalState).toEqual({
682
+ overrideResponse: {
683
+ override: true
684
+ }
685
+ });
686
+ // Verify that each client was used correctly based on the supplied prompt configuration.
687
+ expect(mockClient.generateObject).toHaveBeenCalledWith({
688
+ schema: expect.any(z.ZodObject),
689
+ schemaName: 'overrideResponse',
690
+ prompt: 'prompt1'
691
+ });
692
+ expect(overrideClient.generateObject).toHaveBeenCalledWith({
693
+ schema: expect.any(z.ZodObject),
694
+ schemaName: 'overrideResponse',
695
+ prompt: 'prompt2'
696
+ });
697
+ return [
698
+ 2
699
+ ];
700
+ }
701
+ });
702
+ // Verify that the state was updated correctly with values from both clients.
703
+ })();
704
+ });
705
+ it('should use the provided brainRunId for the initial run if supplied', function() {
706
+ return _async_to_generator(function() {
707
+ var testBrain, providedId, brainRun, startResult;
708
+ return _ts_generator(this, function(_state) {
709
+ switch(_state.label){
710
+ case 0:
711
+ testBrain = brain('Brain with Provided ID');
712
+ providedId = 'my-custom-run-id-123';
713
+ brainRun = testBrain.run({
714
+ client: mockClient,
715
+ brainRunId: providedId
716
+ });
717
+ return [
718
+ 4,
719
+ brainRun.next()
720
+ ];
721
+ case 1:
722
+ startResult = _state.sent();
723
+ expect(startResult.value).toEqual(expect.objectContaining({
724
+ type: BRAIN_EVENTS.START,
725
+ status: STATUS.RUNNING,
726
+ brainTitle: 'Brain with Provided ID',
727
+ brainRunId: providedId
728
+ }));
729
+ return [
730
+ 2
731
+ ];
732
+ }
733
+ });
734
+ })();
735
+ });
736
+ describe('Resource Availability in Steps', function() {
737
+ it('should make resources available in a simple step action', function() {
738
+ return _async_to_generator(function() {
739
+ var loadedText, testBrain, run, _iteratorAbruptCompletion, _didIteratorError, _iteratorError, _iterator, _step, _value, _, err;
740
+ return _ts_generator(this, function(_state) {
741
+ switch(_state.label){
742
+ case 0:
743
+ testBrain = brain('Resource Step Test').step('Load My File', function(param) {
744
+ var resources = param.resources;
745
+ return _async_to_generator(function() {
746
+ return _ts_generator(this, function(_state) {
747
+ switch(_state.label){
748
+ case 0:
749
+ return [
750
+ 4,
751
+ resources.myFile.loadText()
752
+ ];
753
+ case 1:
754
+ loadedText = _state.sent();
755
+ return [
756
+ 2,
757
+ {
758
+ loadedText: loadedText
759
+ }
760
+ ];
761
+ }
762
+ });
763
+ })();
764
+ });
765
+ run = testBrain.run({
766
+ client: mockClient,
767
+ resources: mockResources
768
+ });
769
+ _iteratorAbruptCompletion = false, _didIteratorError = false;
770
+ _state.label = 1;
771
+ case 1:
772
+ _state.trys.push([
773
+ 1,
774
+ 6,
775
+ 7,
776
+ 12
777
+ ]);
778
+ _iterator = _async_iterator(run);
779
+ _state.label = 2;
780
+ case 2:
781
+ return [
782
+ 4,
783
+ _iterator.next()
784
+ ];
785
+ case 3:
786
+ if (!(_iteratorAbruptCompletion = !(_step = _state.sent()).done)) return [
787
+ 3,
788
+ 5
789
+ ];
790
+ _value = _step.value;
791
+ _ = _value;
792
+ _state.label = 4;
793
+ case 4:
794
+ _iteratorAbruptCompletion = false;
795
+ return [
796
+ 3,
797
+ 2
798
+ ];
799
+ case 5:
800
+ return [
801
+ 3,
802
+ 12
803
+ ];
804
+ case 6:
805
+ err = _state.sent();
806
+ _didIteratorError = true;
807
+ _iteratorError = err;
808
+ return [
809
+ 3,
810
+ 12
811
+ ];
812
+ case 7:
813
+ _state.trys.push([
814
+ 7,
815
+ ,
816
+ 10,
817
+ 11
818
+ ]);
819
+ if (!(_iteratorAbruptCompletion && _iterator.return != null)) return [
820
+ 3,
821
+ 9
822
+ ];
823
+ return [
824
+ 4,
825
+ _iterator.return()
826
+ ];
827
+ case 8:
828
+ _state.sent();
829
+ _state.label = 9;
830
+ case 9:
831
+ return [
832
+ 3,
833
+ 11
834
+ ];
835
+ case 10:
836
+ if (_didIteratorError) {
837
+ throw _iteratorError;
838
+ }
839
+ return [
840
+ 7
841
+ ];
842
+ case 11:
843
+ return [
844
+ 7
845
+ ];
846
+ case 12:
847
+ expect(mockResourceLoad).toHaveBeenCalledWith('myFile', 'text');
848
+ expect(loadedText).toBe('mock myFile text content');
849
+ return [
850
+ 2
851
+ ];
852
+ }
853
+ });
854
+ })();
855
+ });
856
+ it('should make resources available in a prompt action and reducer', function() {
857
+ return _async_to_generator(function() {
858
+ var promptTemplateString, reduceContent, testBrain, run, finalState, allPatches, initialStateForReconstruction, _iteratorAbruptCompletion, _didIteratorError, _iteratorError, _iterator, _step, _value, event, err;
859
+ return _ts_generator(this, function(_state) {
860
+ switch(_state.label){
861
+ case 0:
862
+ mockGenerateObject.mockResolvedValue({
863
+ summary: 'Generated summary'
864
+ });
865
+ testBrain = brain('Resource Prompt Test').step('Load File For Prompt', function(param) {
866
+ var resources = param.resources;
867
+ return _async_to_generator(function() {
868
+ var fileContent;
869
+ return _ts_generator(this, function(_state) {
870
+ switch(_state.label){
871
+ case 0:
872
+ return [
873
+ 4,
874
+ resources.myFile.loadText()
875
+ ];
876
+ case 1:
877
+ fileContent = _state.sent();
878
+ return [
879
+ 2,
880
+ {
881
+ fileContentForPrompt: fileContent
882
+ }
883
+ ];
884
+ }
885
+ });
886
+ })();
887
+ }).prompt('Summarize File', {
888
+ template: function(state) {
889
+ return 'Summarize: ' + state.fileContentForPrompt;
890
+ },
891
+ outputSchema: {
892
+ schema: z.object({
893
+ summary: z.string()
894
+ }),
895
+ name: 'promptResult'
896
+ }
897
+ }, function(param) {
898
+ var state = param.state, response = param.response, resources = param.resources;
899
+ return _async_to_generator(function() {
900
+ return _ts_generator(this, function(_state) {
901
+ switch(_state.label){
902
+ case 0:
903
+ return [
904
+ 4,
905
+ resources.nested.anotherFile.loadText()
906
+ ];
907
+ case 1:
908
+ reduceContent = _state.sent();
909
+ return [
910
+ 2,
911
+ _object_spread_props(_object_spread({}, state), {
912
+ reducedResult: response.summary + ' based on ' + reduceContent
913
+ })
914
+ ];
915
+ }
916
+ });
917
+ })();
918
+ });
919
+ run = testBrain.run({
920
+ client: mockClient,
921
+ resources: mockResources,
922
+ options: {
923
+ myOption: 'test'
924
+ }
925
+ });
926
+ finalState = {};
927
+ allPatches = [];
928
+ initialStateForReconstruction = {};
929
+ _iteratorAbruptCompletion = false, _didIteratorError = false;
930
+ _state.label = 1;
931
+ case 1:
932
+ _state.trys.push([
933
+ 1,
934
+ 6,
935
+ 7,
936
+ 12
937
+ ]);
938
+ _iterator = _async_iterator(run);
939
+ _state.label = 2;
940
+ case 2:
941
+ return [
942
+ 4,
943
+ _iterator.next()
944
+ ];
945
+ case 3:
946
+ if (!(_iteratorAbruptCompletion = !(_step = _state.sent()).done)) return [
947
+ 3,
948
+ 5
949
+ ];
950
+ _value = _step.value;
951
+ event = _value;
952
+ if (event.type === BRAIN_EVENTS.STEP_COMPLETE && event.patch) {
953
+ allPatches.push(event.patch);
954
+ }
955
+ _state.label = 4;
956
+ case 4:
957
+ _iteratorAbruptCompletion = false;
958
+ return [
959
+ 3,
960
+ 2
961
+ ];
962
+ case 5:
963
+ return [
964
+ 3,
965
+ 12
966
+ ];
967
+ case 6:
968
+ err = _state.sent();
969
+ _didIteratorError = true;
970
+ _iteratorError = err;
971
+ return [
972
+ 3,
973
+ 12
974
+ ];
975
+ case 7:
976
+ _state.trys.push([
977
+ 7,
978
+ ,
979
+ 10,
980
+ 11
981
+ ]);
982
+ if (!(_iteratorAbruptCompletion && _iterator.return != null)) return [
983
+ 3,
984
+ 9
985
+ ];
986
+ return [
987
+ 4,
988
+ _iterator.return()
989
+ ];
990
+ case 8:
991
+ _state.sent();
992
+ _state.label = 9;
993
+ case 9:
994
+ return [
995
+ 3,
996
+ 11
997
+ ];
998
+ case 10:
999
+ if (_didIteratorError) {
1000
+ throw _iteratorError;
1001
+ }
1002
+ return [
1003
+ 7
1004
+ ];
1005
+ case 11:
1006
+ return [
1007
+ 7
1008
+ ];
1009
+ case 12:
1010
+ finalState = applyPatches(initialStateForReconstruction, allPatches);
1011
+ expect(mockResourceLoad).toHaveBeenCalledWith('myFile', 'text');
1012
+ expect(mockResourceLoad).toHaveBeenCalledWith('anotherFile', 'text');
1013
+ expect(reduceContent).toBe('mock anotherFile text content');
1014
+ expect(finalState.reducedResult).toBe('Generated summary based on mock anotherFile text content');
1015
+ return [
1016
+ 2
1017
+ ];
1018
+ }
1019
+ });
1020
+ })();
1021
+ });
1022
+ it('should pass resources to prompt template function', function() {
1023
+ return _async_to_generator(function() {
1024
+ var testBrain, run, finalState, _iteratorAbruptCompletion, _didIteratorError, _iteratorError, _iterator, _step, _value, event, err;
1025
+ return _ts_generator(this, function(_state) {
1026
+ switch(_state.label){
1027
+ case 0:
1028
+ testBrain = brain('Resource Prompt Template Test').prompt('Generate Summary', {
1029
+ template: function(state, resources) {
1030
+ return _async_to_generator(function() {
1031
+ var templateContent;
1032
+ return _ts_generator(this, function(_state) {
1033
+ switch(_state.label){
1034
+ case 0:
1035
+ return [
1036
+ 4,
1037
+ resources.myFile.loadText()
1038
+ ];
1039
+ case 1:
1040
+ templateContent = _state.sent();
1041
+ return [
1042
+ 2,
1043
+ "Generate a summary for: ".concat(templateContent)
1044
+ ];
1045
+ }
1046
+ });
1047
+ })();
1048
+ },
1049
+ outputSchema: {
1050
+ schema: z.object({
1051
+ summary: z.string()
1052
+ }),
1053
+ name: 'promptResult'
1054
+ }
1055
+ });
1056
+ mockGenerateObject.mockResolvedValue({
1057
+ summary: 'Test summary'
1058
+ });
1059
+ run = testBrain.run({
1060
+ client: mockClient,
1061
+ resources: mockResources
1062
+ });
1063
+ finalState = {};
1064
+ _iteratorAbruptCompletion = false, _didIteratorError = false;
1065
+ _state.label = 1;
1066
+ case 1:
1067
+ _state.trys.push([
1068
+ 1,
1069
+ 6,
1070
+ 7,
1071
+ 12
1072
+ ]);
1073
+ _iterator = _async_iterator(run);
1074
+ _state.label = 2;
1075
+ case 2:
1076
+ return [
1077
+ 4,
1078
+ _iterator.next()
1079
+ ];
1080
+ case 3:
1081
+ if (!(_iteratorAbruptCompletion = !(_step = _state.sent()).done)) return [
1082
+ 3,
1083
+ 5
1084
+ ];
1085
+ _value = _step.value;
1086
+ event = _value;
1087
+ if (event.type === BRAIN_EVENTS.STEP_COMPLETE) {
1088
+ finalState = applyPatches(finalState, [
1089
+ event.patch
1090
+ ]);
1091
+ }
1092
+ _state.label = 4;
1093
+ case 4:
1094
+ _iteratorAbruptCompletion = false;
1095
+ return [
1096
+ 3,
1097
+ 2
1098
+ ];
1099
+ case 5:
1100
+ return [
1101
+ 3,
1102
+ 12
1103
+ ];
1104
+ case 6:
1105
+ err = _state.sent();
1106
+ _didIteratorError = true;
1107
+ _iteratorError = err;
1108
+ return [
1109
+ 3,
1110
+ 12
1111
+ ];
1112
+ case 7:
1113
+ _state.trys.push([
1114
+ 7,
1115
+ ,
1116
+ 10,
1117
+ 11
1118
+ ]);
1119
+ if (!(_iteratorAbruptCompletion && _iterator.return != null)) return [
1120
+ 3,
1121
+ 9
1122
+ ];
1123
+ return [
1124
+ 4,
1125
+ _iterator.return()
1126
+ ];
1127
+ case 8:
1128
+ _state.sent();
1129
+ _state.label = 9;
1130
+ case 9:
1131
+ return [
1132
+ 3,
1133
+ 11
1134
+ ];
1135
+ case 10:
1136
+ if (_didIteratorError) {
1137
+ throw _iteratorError;
1138
+ }
1139
+ return [
1140
+ 7
1141
+ ];
1142
+ case 11:
1143
+ return [
1144
+ 7
1145
+ ];
1146
+ case 12:
1147
+ // Verify resource was loaded in template
1148
+ expect(mockResourceLoad).toHaveBeenCalledWith('myFile', 'text');
1149
+ // Verify the generated prompt included the resource content
1150
+ expect(mockGenerateObject).toHaveBeenCalledWith(expect.objectContaining({
1151
+ prompt: 'Generate a summary for: mock myFile text content'
1152
+ }));
1153
+ // Verify final state
1154
+ expect(finalState).toEqual({
1155
+ promptResult: {
1156
+ summary: 'Test summary'
1157
+ }
1158
+ });
1159
+ return [
1160
+ 2
1161
+ ];
1162
+ }
1163
+ });
1164
+ })();
1165
+ });
1166
+ it('templates can use state', function() {
1167
+ return _async_to_generator(function() {
1168
+ var testBrain, run, finalState, _iteratorAbruptCompletion, _didIteratorError, _iteratorError, _iterator, _step, _value, event, err;
1169
+ return _ts_generator(this, function(_state) {
1170
+ switch(_state.label){
1171
+ case 0:
1172
+ testBrain = brain('State Template Test').step('Set Data', function() {
1173
+ return {
1174
+ existingData: 'legacy data'
1175
+ };
1176
+ }).prompt('Analyze Data', {
1177
+ template: function(state) {
1178
+ return "Analyze this: ".concat(state.existingData);
1179
+ },
1180
+ outputSchema: {
1181
+ schema: z.object({
1182
+ analysis: z.string()
1183
+ }),
1184
+ name: 'promptResult'
1185
+ }
1186
+ });
1187
+ mockGenerateObject.mockResolvedValue({
1188
+ analysis: 'Analysis result'
1189
+ });
1190
+ run = testBrain.run({
1191
+ client: mockClient,
1192
+ resources: mockResources
1193
+ });
1194
+ finalState = {};
1195
+ _iteratorAbruptCompletion = false, _didIteratorError = false;
1196
+ _state.label = 1;
1197
+ case 1:
1198
+ _state.trys.push([
1199
+ 1,
1200
+ 6,
1201
+ 7,
1202
+ 12
1203
+ ]);
1204
+ _iterator = _async_iterator(run);
1205
+ _state.label = 2;
1206
+ case 2:
1207
+ return [
1208
+ 4,
1209
+ _iterator.next()
1210
+ ];
1211
+ case 3:
1212
+ if (!(_iteratorAbruptCompletion = !(_step = _state.sent()).done)) return [
1213
+ 3,
1214
+ 5
1215
+ ];
1216
+ _value = _step.value;
1217
+ event = _value;
1218
+ if (event.type === BRAIN_EVENTS.STEP_COMPLETE) {
1219
+ finalState = applyPatches(finalState, [
1220
+ event.patch
1221
+ ]);
1222
+ }
1223
+ _state.label = 4;
1224
+ case 4:
1225
+ _iteratorAbruptCompletion = false;
1226
+ return [
1227
+ 3,
1228
+ 2
1229
+ ];
1230
+ case 5:
1231
+ return [
1232
+ 3,
1233
+ 12
1234
+ ];
1235
+ case 6:
1236
+ err = _state.sent();
1237
+ _didIteratorError = true;
1238
+ _iteratorError = err;
1239
+ return [
1240
+ 3,
1241
+ 12
1242
+ ];
1243
+ case 7:
1244
+ _state.trys.push([
1245
+ 7,
1246
+ ,
1247
+ 10,
1248
+ 11
1249
+ ]);
1250
+ if (!(_iteratorAbruptCompletion && _iterator.return != null)) return [
1251
+ 3,
1252
+ 9
1253
+ ];
1254
+ return [
1255
+ 4,
1256
+ _iterator.return()
1257
+ ];
1258
+ case 8:
1259
+ _state.sent();
1260
+ _state.label = 9;
1261
+ case 9:
1262
+ return [
1263
+ 3,
1264
+ 11
1265
+ ];
1266
+ case 10:
1267
+ if (_didIteratorError) {
1268
+ throw _iteratorError;
1269
+ }
1270
+ return [
1271
+ 7
1272
+ ];
1273
+ case 11:
1274
+ return [
1275
+ 7
1276
+ ];
1277
+ case 12:
1278
+ // Verify the prompt was generated correctly
1279
+ expect(mockGenerateObject).toHaveBeenCalledWith(expect.objectContaining({
1280
+ prompt: 'Analyze this: legacy data'
1281
+ }));
1282
+ // Verify final state
1283
+ expect(finalState).toEqual({
1284
+ existingData: 'legacy data',
1285
+ promptResult: {
1286
+ analysis: 'Analysis result'
1287
+ }
1288
+ });
1289
+ // Verify no resources were loaded (since template didn't use them)
1290
+ expect(mockResourceLoad).not.toHaveBeenCalled();
1291
+ return [
1292
+ 2
1293
+ ];
1294
+ }
1295
+ });
1296
+ })();
1297
+ });
1298
+ it('should make resources available in a nested brain step', function() {
1299
+ return _async_to_generator(function() {
1300
+ var nestedLoadedText, innerBrain, outerBrain, run, _iteratorAbruptCompletion, _didIteratorError, _iteratorError, _iterator, _step, _value, _, err;
1301
+ return _ts_generator(this, function(_state) {
1302
+ switch(_state.label){
1303
+ case 0:
1304
+ innerBrain = brain('Inner Resource Brain').step('Inner Load Step', function(param) {
1305
+ var resources = param.resources;
1306
+ return _async_to_generator(function() {
1307
+ return _ts_generator(this, function(_state) {
1308
+ switch(_state.label){
1309
+ case 0:
1310
+ return [
1311
+ 4,
1312
+ resources.myBinaryFile.loadBinary().then(function(b) {
1313
+ return b.toString();
1314
+ })
1315
+ ];
1316
+ case 1:
1317
+ nestedLoadedText = _state.sent();
1318
+ return [
1319
+ 2,
1320
+ {
1321
+ nestedLoadedText: nestedLoadedText
1322
+ }
1323
+ ];
1324
+ }
1325
+ });
1326
+ })();
1327
+ });
1328
+ outerBrain = brain('Outer Resource Brain').brain('Run Inner', innerBrain, function(param) {
1329
+ var state = param.state, brainState = param.brainState;
1330
+ return _object_spread({}, state, brainState);
1331
+ });
1332
+ run = outerBrain.run({
1333
+ client: mockClient,
1334
+ resources: mockResources
1335
+ });
1336
+ _iteratorAbruptCompletion = false, _didIteratorError = false;
1337
+ _state.label = 1;
1338
+ case 1:
1339
+ _state.trys.push([
1340
+ 1,
1341
+ 6,
1342
+ 7,
1343
+ 12
1344
+ ]);
1345
+ _iterator = _async_iterator(run);
1346
+ _state.label = 2;
1347
+ case 2:
1348
+ return [
1349
+ 4,
1350
+ _iterator.next()
1351
+ ];
1352
+ case 3:
1353
+ if (!(_iteratorAbruptCompletion = !(_step = _state.sent()).done)) return [
1354
+ 3,
1355
+ 5
1356
+ ];
1357
+ _value = _step.value;
1358
+ _ = _value;
1359
+ _state.label = 4;
1360
+ case 4:
1361
+ _iteratorAbruptCompletion = false;
1362
+ return [
1363
+ 3,
1364
+ 2
1365
+ ];
1366
+ case 5:
1367
+ return [
1368
+ 3,
1369
+ 12
1370
+ ];
1371
+ case 6:
1372
+ err = _state.sent();
1373
+ _didIteratorError = true;
1374
+ _iteratorError = err;
1375
+ return [
1376
+ 3,
1377
+ 12
1378
+ ];
1379
+ case 7:
1380
+ _state.trys.push([
1381
+ 7,
1382
+ ,
1383
+ 10,
1384
+ 11
1385
+ ]);
1386
+ if (!(_iteratorAbruptCompletion && _iterator.return != null)) return [
1387
+ 3,
1388
+ 9
1389
+ ];
1390
+ return [
1391
+ 4,
1392
+ _iterator.return()
1393
+ ];
1394
+ case 8:
1395
+ _state.sent();
1396
+ _state.label = 9;
1397
+ case 9:
1398
+ return [
1399
+ 3,
1400
+ 11
1401
+ ];
1402
+ case 10:
1403
+ if (_didIteratorError) {
1404
+ throw _iteratorError;
1405
+ }
1406
+ return [
1407
+ 7
1408
+ ];
1409
+ case 11:
1410
+ return [
1411
+ 7
1412
+ ];
1413
+ case 12:
1414
+ expect(mockResourceLoad).toHaveBeenCalledWith('myBinaryFile', 'binary');
1415
+ expect(nestedLoadedText).toBe('mock myBinaryFile binary content');
1416
+ return [
1417
+ 2
1418
+ ];
1419
+ }
1420
+ });
1421
+ })();
1422
+ });
1423
+ });
1424
+ });
1425
+ describe('error handling', function() {
1426
+ it('should handle errors in actions and maintain correct status', function() {
1427
+ return _async_to_generator(function() {
1428
+ var _errorEvent_error, errorBrain, errorEvent, finalStepStatusEvent, _iteratorAbruptCompletion, _didIteratorError, _iteratorError, _iterator, _step, _value, event, err, error;
1429
+ return _ts_generator(this, function(_state) {
1430
+ switch(_state.label){
1431
+ case 0:
1432
+ errorBrain = brain('Error Brain')// Step 1: Normal step
1433
+ .step('First step', function() {
1434
+ return {
1435
+ value: 1
1436
+ };
1437
+ })// Step 2: Error step
1438
+ .step('Error step', function() {
1439
+ if (true) {
1440
+ throw new Error('Test error');
1441
+ }
1442
+ return {
1443
+ value: 1
1444
+ };
1445
+ })// Step 3: Should never execute
1446
+ .step('Never reached', function(param) {
1447
+ var state = param.state;
1448
+ return {
1449
+ value: state.value + 1
1450
+ };
1451
+ });
1452
+ _state.label = 1;
1453
+ case 1:
1454
+ _state.trys.push([
1455
+ 1,
1456
+ 14,
1457
+ ,
1458
+ 15
1459
+ ]);
1460
+ _iteratorAbruptCompletion = false, _didIteratorError = false;
1461
+ _state.label = 2;
1462
+ case 2:
1463
+ _state.trys.push([
1464
+ 2,
1465
+ 7,
1466
+ 8,
1467
+ 13
1468
+ ]);
1469
+ _iterator = _async_iterator(errorBrain.run({
1470
+ client: mockClient
1471
+ }));
1472
+ _state.label = 3;
1473
+ case 3:
1474
+ return [
1475
+ 4,
1476
+ _iterator.next()
1477
+ ];
1478
+ case 4:
1479
+ if (!(_iteratorAbruptCompletion = !(_step = _state.sent()).done)) return [
1480
+ 3,
1481
+ 6
1482
+ ];
1483
+ _value = _step.value;
1484
+ event = _value;
1485
+ if (event.type === BRAIN_EVENTS.ERROR) {
1486
+ errorEvent = event;
1487
+ }
1488
+ if (event.type === BRAIN_EVENTS.STEP_STATUS) {
1489
+ finalStepStatusEvent = event;
1490
+ }
1491
+ _state.label = 5;
1492
+ case 5:
1493
+ _iteratorAbruptCompletion = false;
1494
+ return [
1495
+ 3,
1496
+ 3
1497
+ ];
1498
+ case 6:
1499
+ return [
1500
+ 3,
1501
+ 13
1502
+ ];
1503
+ case 7:
1504
+ err = _state.sent();
1505
+ _didIteratorError = true;
1506
+ _iteratorError = err;
1507
+ return [
1508
+ 3,
1509
+ 13
1510
+ ];
1511
+ case 8:
1512
+ _state.trys.push([
1513
+ 8,
1514
+ ,
1515
+ 11,
1516
+ 12
1517
+ ]);
1518
+ if (!(_iteratorAbruptCompletion && _iterator.return != null)) return [
1519
+ 3,
1520
+ 10
1521
+ ];
1522
+ return [
1523
+ 4,
1524
+ _iterator.return()
1525
+ ];
1526
+ case 9:
1527
+ _state.sent();
1528
+ _state.label = 10;
1529
+ case 10:
1530
+ return [
1531
+ 3,
1532
+ 12
1533
+ ];
1534
+ case 11:
1535
+ if (_didIteratorError) {
1536
+ throw _iteratorError;
1537
+ }
1538
+ return [
1539
+ 7
1540
+ ];
1541
+ case 12:
1542
+ return [
1543
+ 7
1544
+ ];
1545
+ case 13:
1546
+ return [
1547
+ 3,
1548
+ 15
1549
+ ];
1550
+ case 14:
1551
+ error = _state.sent();
1552
+ return [
1553
+ 3,
1554
+ 15
1555
+ ];
1556
+ case 15:
1557
+ // Verify final state
1558
+ expect(errorEvent === null || errorEvent === void 0 ? void 0 : errorEvent.status).toBe(STATUS.ERROR);
1559
+ expect(errorEvent === null || errorEvent === void 0 ? void 0 : (_errorEvent_error = errorEvent.error) === null || _errorEvent_error === void 0 ? void 0 : _errorEvent_error.message).toBe('Test error');
1560
+ // Verify steps status
1561
+ if (!(finalStepStatusEvent === null || finalStepStatusEvent === void 0 ? void 0 : finalStepStatusEvent.steps)) {
1562
+ throw new Error('Steps not found');
1563
+ }
1564
+ expect(finalStepStatusEvent.steps[0].status).toBe(STATUS.COMPLETE);
1565
+ expect(finalStepStatusEvent.steps[1].status).toBe(STATUS.ERROR);
1566
+ expect(finalStepStatusEvent.steps[2].status).toBe(STATUS.PENDING);
1567
+ // Verify error event structure
1568
+ expect(errorEvent).toEqual(expect.objectContaining({
1569
+ type: BRAIN_EVENTS.ERROR,
1570
+ status: STATUS.ERROR,
1571
+ brainTitle: 'Error Brain',
1572
+ error: expect.objectContaining({
1573
+ name: expect.any(String),
1574
+ message: expect.any(String)
1575
+ })
1576
+ }));
1577
+ return [
1578
+ 2
1579
+ ];
1580
+ }
1581
+ });
1582
+ })();
1583
+ });
1584
+ it('should handle errors in nested brains and propagate them up', function() {
1585
+ return _async_to_generator(function() {
1586
+ var innerBrain, outerBrain, events, error, mainBrainId, _iteratorAbruptCompletion, _didIteratorError, _iteratorError, _iterator, _step, _value, event, err, e, innerErrorEvent, outerErrorEvent;
1587
+ return _ts_generator(this, function(_state) {
1588
+ switch(_state.label){
1589
+ case 0:
1590
+ // Create an inner brain that will throw an error
1591
+ innerBrain = brain('Failing Inner Brain').step('Throw error', function() {
1592
+ throw new Error('Inner brain error');
1593
+ });
1594
+ // Create outer brain that uses the failing inner brain
1595
+ outerBrain = brain('Outer Brain').step('First step', function() {
1596
+ return {
1597
+ step: 'first'
1598
+ };
1599
+ }).brain('Run inner brain', innerBrain, function(param) {
1600
+ var state = param.state, brainState = param.brainState;
1601
+ return _object_spread_props(_object_spread({}, state), {
1602
+ step: 'second',
1603
+ innerResult: brainState.value
1604
+ });
1605
+ }, function() {
1606
+ return {
1607
+ value: 5
1608
+ };
1609
+ });
1610
+ events = [];
1611
+ _state.label = 1;
1612
+ case 1:
1613
+ _state.trys.push([
1614
+ 1,
1615
+ 14,
1616
+ ,
1617
+ 15
1618
+ ]);
1619
+ _iteratorAbruptCompletion = false, _didIteratorError = false;
1620
+ _state.label = 2;
1621
+ case 2:
1622
+ _state.trys.push([
1623
+ 2,
1624
+ 7,
1625
+ 8,
1626
+ 13
1627
+ ]);
1628
+ _iterator = _async_iterator(outerBrain.run({
1629
+ client: mockClient
1630
+ }));
1631
+ _state.label = 3;
1632
+ case 3:
1633
+ return [
1634
+ 4,
1635
+ _iterator.next()
1636
+ ];
1637
+ case 4:
1638
+ if (!(_iteratorAbruptCompletion = !(_step = _state.sent()).done)) return [
1639
+ 3,
1640
+ 6
1641
+ ];
1642
+ _value = _step.value;
1643
+ event = _value;
1644
+ events.push(event);
1645
+ if (event.type === BRAIN_EVENTS.START && !mainBrainId) {
1646
+ mainBrainId = event.brainRunId;
1647
+ }
1648
+ _state.label = 5;
1649
+ case 5:
1650
+ _iteratorAbruptCompletion = false;
1651
+ return [
1652
+ 3,
1653
+ 3
1654
+ ];
1655
+ case 6:
1656
+ return [
1657
+ 3,
1658
+ 13
1659
+ ];
1660
+ case 7:
1661
+ err = _state.sent();
1662
+ _didIteratorError = true;
1663
+ _iteratorError = err;
1664
+ return [
1665
+ 3,
1666
+ 13
1667
+ ];
1668
+ case 8:
1669
+ _state.trys.push([
1670
+ 8,
1671
+ ,
1672
+ 11,
1673
+ 12
1674
+ ]);
1675
+ if (!(_iteratorAbruptCompletion && _iterator.return != null)) return [
1676
+ 3,
1677
+ 10
1678
+ ];
1679
+ return [
1680
+ 4,
1681
+ _iterator.return()
1682
+ ];
1683
+ case 9:
1684
+ _state.sent();
1685
+ _state.label = 10;
1686
+ case 10:
1687
+ return [
1688
+ 3,
1689
+ 12
1690
+ ];
1691
+ case 11:
1692
+ if (_didIteratorError) {
1693
+ throw _iteratorError;
1694
+ }
1695
+ return [
1696
+ 7
1697
+ ];
1698
+ case 12:
1699
+ return [
1700
+ 7
1701
+ ];
1702
+ case 13:
1703
+ return [
1704
+ 3,
1705
+ 15
1706
+ ];
1707
+ case 14:
1708
+ e = _state.sent();
1709
+ error = e;
1710
+ return [
1711
+ 3,
1712
+ 15
1713
+ ];
1714
+ case 15:
1715
+ // Verify error was thrown
1716
+ expect(error === null || error === void 0 ? void 0 : error.message).toBe('Inner brain error');
1717
+ // Verify event sequence including error
1718
+ expect(events).toEqual([
1719
+ expect.objectContaining({
1720
+ type: BRAIN_EVENTS.START,
1721
+ brainTitle: 'Outer Brain',
1722
+ status: STATUS.RUNNING,
1723
+ brainRunId: mainBrainId
1724
+ }),
1725
+ expect.objectContaining({
1726
+ type: BRAIN_EVENTS.STEP_STATUS,
1727
+ steps: expect.any(Array)
1728
+ }),
1729
+ expect.objectContaining({
1730
+ type: BRAIN_EVENTS.STEP_START,
1731
+ status: STATUS.RUNNING,
1732
+ stepTitle: 'First step'
1733
+ }),
1734
+ expect.objectContaining({
1735
+ type: BRAIN_EVENTS.STEP_STATUS,
1736
+ steps: expect.any(Array)
1737
+ }),
1738
+ expect.objectContaining({
1739
+ type: BRAIN_EVENTS.STEP_COMPLETE,
1740
+ status: STATUS.RUNNING,
1741
+ stepTitle: 'First step'
1742
+ }),
1743
+ expect.objectContaining({
1744
+ type: BRAIN_EVENTS.STEP_STATUS,
1745
+ steps: expect.any(Array)
1746
+ }),
1747
+ expect.objectContaining({
1748
+ type: BRAIN_EVENTS.STEP_START,
1749
+ status: STATUS.RUNNING,
1750
+ stepTitle: 'Run inner brain'
1751
+ }),
1752
+ expect.objectContaining({
1753
+ type: BRAIN_EVENTS.STEP_STATUS,
1754
+ steps: expect.any(Array)
1755
+ }),
1756
+ expect.objectContaining({
1757
+ type: BRAIN_EVENTS.START,
1758
+ brainTitle: 'Failing Inner Brain',
1759
+ status: STATUS.RUNNING
1760
+ }),
1761
+ expect.objectContaining({
1762
+ type: BRAIN_EVENTS.STEP_STATUS,
1763
+ steps: expect.any(Array)
1764
+ }),
1765
+ expect.objectContaining({
1766
+ type: BRAIN_EVENTS.STEP_START,
1767
+ status: STATUS.RUNNING,
1768
+ stepTitle: 'Throw error'
1769
+ }),
1770
+ expect.objectContaining({
1771
+ type: BRAIN_EVENTS.STEP_STATUS,
1772
+ steps: expect.any(Array)
1773
+ }),
1774
+ expect.objectContaining({
1775
+ type: BRAIN_EVENTS.ERROR,
1776
+ brainTitle: 'Failing Inner Brain',
1777
+ status: STATUS.ERROR,
1778
+ error: expect.objectContaining({
1779
+ name: expect.any(String),
1780
+ message: expect.any(String)
1781
+ })
1782
+ }),
1783
+ expect.objectContaining({
1784
+ type: BRAIN_EVENTS.STEP_STATUS,
1785
+ steps: expect.arrayContaining([
1786
+ expect.objectContaining({
1787
+ title: 'Throw error',
1788
+ status: STATUS.ERROR
1789
+ })
1790
+ ])
1791
+ }),
1792
+ expect.objectContaining({
1793
+ type: BRAIN_EVENTS.ERROR,
1794
+ brainTitle: 'Outer Brain',
1795
+ status: STATUS.ERROR,
1796
+ error: expect.objectContaining({
1797
+ name: expect.any(String),
1798
+ message: expect.any(String)
1799
+ })
1800
+ }),
1801
+ expect.objectContaining({
1802
+ type: BRAIN_EVENTS.STEP_STATUS,
1803
+ steps: expect.arrayContaining([
1804
+ expect.objectContaining({
1805
+ title: 'Run inner brain',
1806
+ status: STATUS.ERROR
1807
+ })
1808
+ ])
1809
+ })
1810
+ ]);
1811
+ // Find inner and outer error events by brainRunId
1812
+ innerErrorEvent = events.find(function(e) {
1813
+ return e.type === BRAIN_EVENTS.ERROR && e.brainRunId !== mainBrainId;
1814
+ });
1815
+ outerErrorEvent = events.find(function(e) {
1816
+ return e.type === BRAIN_EVENTS.ERROR && e.brainRunId === mainBrainId;
1817
+ });
1818
+ expect(innerErrorEvent.error).toEqual(expect.objectContaining({
1819
+ message: 'Inner brain error'
1820
+ }));
1821
+ expect(outerErrorEvent.error).toEqual(expect.objectContaining({
1822
+ message: 'Inner brain error'
1823
+ }));
1824
+ return [
1825
+ 2
1826
+ ];
1827
+ }
1828
+ });
1829
+ })();
1830
+ });
1831
+ });
1832
+ describe('step creation', function() {
1833
+ it('should create a step that updates state', function() {
1834
+ return _async_to_generator(function() {
1835
+ var testBrain, events, finalState, _iteratorAbruptCompletion, _didIteratorError, _iteratorError, _iterator, _step, _value, event, err;
1836
+ return _ts_generator(this, function(_state) {
1837
+ switch(_state.label){
1838
+ case 0:
1839
+ testBrain = brain('Simple Brain').step('Simple step', function(param) {
1840
+ var state = param.state;
1841
+ return _object_spread_props(_object_spread({}, state), {
1842
+ count: 1,
1843
+ message: 'Count is now 1'
1844
+ });
1845
+ });
1846
+ events = [];
1847
+ finalState = {};
1848
+ _iteratorAbruptCompletion = false, _didIteratorError = false;
1849
+ _state.label = 1;
1850
+ case 1:
1851
+ _state.trys.push([
1852
+ 1,
1853
+ 6,
1854
+ 7,
1855
+ 12
1856
+ ]);
1857
+ _iterator = _async_iterator(testBrain.run({
1858
+ client: mockClient
1859
+ }));
1860
+ _state.label = 2;
1861
+ case 2:
1862
+ return [
1863
+ 4,
1864
+ _iterator.next()
1865
+ ];
1866
+ case 3:
1867
+ if (!(_iteratorAbruptCompletion = !(_step = _state.sent()).done)) return [
1868
+ 3,
1869
+ 5
1870
+ ];
1871
+ _value = _step.value;
1872
+ event = _value;
1873
+ events.push(event);
1874
+ if (event.type === BRAIN_EVENTS.STEP_COMPLETE) {
1875
+ finalState = applyPatches(finalState, event.patch);
1876
+ }
1877
+ _state.label = 4;
1878
+ case 4:
1879
+ _iteratorAbruptCompletion = false;
1880
+ return [
1881
+ 3,
1882
+ 2
1883
+ ];
1884
+ case 5:
1885
+ return [
1886
+ 3,
1887
+ 12
1888
+ ];
1889
+ case 6:
1890
+ err = _state.sent();
1891
+ _didIteratorError = true;
1892
+ _iteratorError = err;
1893
+ return [
1894
+ 3,
1895
+ 12
1896
+ ];
1897
+ case 7:
1898
+ _state.trys.push([
1899
+ 7,
1900
+ ,
1901
+ 10,
1902
+ 11
1903
+ ]);
1904
+ if (!(_iteratorAbruptCompletion && _iterator.return != null)) return [
1905
+ 3,
1906
+ 9
1907
+ ];
1908
+ return [
1909
+ 4,
1910
+ _iterator.return()
1911
+ ];
1912
+ case 8:
1913
+ _state.sent();
1914
+ _state.label = 9;
1915
+ case 9:
1916
+ return [
1917
+ 3,
1918
+ 11
1919
+ ];
1920
+ case 10:
1921
+ if (_didIteratorError) {
1922
+ throw _iteratorError;
1923
+ }
1924
+ return [
1925
+ 7
1926
+ ];
1927
+ case 11:
1928
+ return [
1929
+ 7
1930
+ ];
1931
+ case 12:
1932
+ // Skip checking events[0] (brain:start)
1933
+ // Skip checking events[1] (step:status)
1934
+ // Verify the step start event
1935
+ expect(events[2]).toEqual(expect.objectContaining({
1936
+ type: BRAIN_EVENTS.STEP_START,
1937
+ status: STATUS.RUNNING,
1938
+ stepTitle: 'Simple step',
1939
+ stepId: expect.any(String),
1940
+ options: {}
1941
+ }));
1942
+ // Verify the step status event (running)
1943
+ expect(events[3]).toEqual(expect.objectContaining({
1944
+ type: BRAIN_EVENTS.STEP_STATUS,
1945
+ steps: expect.any(Array),
1946
+ options: {}
1947
+ }));
1948
+ if (events[3].type === BRAIN_EVENTS.STEP_STATUS) {
1949
+ expect(events[3].steps[0].status).toBe(STATUS.RUNNING);
1950
+ }
1951
+ // Verify the step complete event
1952
+ expect(events[4]).toEqual(expect.objectContaining({
1953
+ type: BRAIN_EVENTS.STEP_COMPLETE,
1954
+ status: STATUS.RUNNING,
1955
+ stepTitle: 'Simple step',
1956
+ stepId: expect.any(String),
1957
+ patch: [
1958
+ {
1959
+ op: 'add',
1960
+ path: '/count',
1961
+ value: 1
1962
+ },
1963
+ {
1964
+ op: 'add',
1965
+ path: '/message',
1966
+ value: 'Count is now 1'
1967
+ }
1968
+ ],
1969
+ options: {}
1970
+ }));
1971
+ expect(events[5]).toEqual(expect.objectContaining({
1972
+ type: BRAIN_EVENTS.STEP_STATUS,
1973
+ steps: [
1974
+ expect.objectContaining({
1975
+ title: 'Simple step',
1976
+ status: STATUS.COMPLETE,
1977
+ id: expect.any(String)
1978
+ })
1979
+ ],
1980
+ options: {}
1981
+ }));
1982
+ // Verify the brain complete event
1983
+ expect(events[6]).toEqual(expect.objectContaining({
1984
+ type: BRAIN_EVENTS.COMPLETE,
1985
+ status: STATUS.COMPLETE,
1986
+ brainTitle: 'Simple Brain',
1987
+ options: {}
1988
+ }));
1989
+ // Verify the final state
1990
+ expect(finalState).toEqual({
1991
+ count: 1,
1992
+ message: 'Count is now 1'
1993
+ });
1994
+ return [
1995
+ 2
1996
+ ];
1997
+ }
1998
+ });
1999
+ })();
2000
+ });
2001
+ it('should maintain immutable results between steps', function() {
2002
+ return _async_to_generator(function() {
2003
+ var testBrain, finalState, patches, _iteratorAbruptCompletion, _didIteratorError, _iteratorError, _iterator, _step, _value, event, _patches, err;
2004
+ return _ts_generator(this, function(_state) {
2005
+ switch(_state.label){
2006
+ case 0:
2007
+ testBrain = brain('Immutable Steps Brain').step('First step', function() {
2008
+ return {
2009
+ value: 1
2010
+ };
2011
+ }).step('Second step', function(param) {
2012
+ var state = param.state;
2013
+ // Attempt to modify previous step's state
2014
+ state.value = 99;
2015
+ return {
2016
+ value: 2
2017
+ };
2018
+ });
2019
+ finalState = {};
2020
+ patches = [];
2021
+ _iteratorAbruptCompletion = false, _didIteratorError = false;
2022
+ _state.label = 1;
2023
+ case 1:
2024
+ _state.trys.push([
2025
+ 1,
2026
+ 6,
2027
+ 7,
2028
+ 12
2029
+ ]);
2030
+ _iterator = _async_iterator(testBrain.run({
2031
+ client: mockClient
2032
+ }));
2033
+ _state.label = 2;
2034
+ case 2:
2035
+ return [
2036
+ 4,
2037
+ _iterator.next()
2038
+ ];
2039
+ case 3:
2040
+ if (!(_iteratorAbruptCompletion = !(_step = _state.sent()).done)) return [
2041
+ 3,
2042
+ 5
2043
+ ];
2044
+ _value = _step.value;
2045
+ event = _value;
2046
+ if (event.type === BRAIN_EVENTS.STEP_COMPLETE) {
2047
+ ;
2048
+ (_patches = patches).push.apply(_patches, _to_consumable_array(event.patch));
2049
+ }
2050
+ _state.label = 4;
2051
+ case 4:
2052
+ _iteratorAbruptCompletion = false;
2053
+ return [
2054
+ 3,
2055
+ 2
2056
+ ];
2057
+ case 5:
2058
+ return [
2059
+ 3,
2060
+ 12
2061
+ ];
2062
+ case 6:
2063
+ err = _state.sent();
2064
+ _didIteratorError = true;
2065
+ _iteratorError = err;
2066
+ return [
2067
+ 3,
2068
+ 12
2069
+ ];
2070
+ case 7:
2071
+ _state.trys.push([
2072
+ 7,
2073
+ ,
2074
+ 10,
2075
+ 11
2076
+ ]);
2077
+ if (!(_iteratorAbruptCompletion && _iterator.return != null)) return [
2078
+ 3,
2079
+ 9
2080
+ ];
2081
+ return [
2082
+ 4,
2083
+ _iterator.return()
2084
+ ];
2085
+ case 8:
2086
+ _state.sent();
2087
+ _state.label = 9;
2088
+ case 9:
2089
+ return [
2090
+ 3,
2091
+ 11
2092
+ ];
2093
+ case 10:
2094
+ if (_didIteratorError) {
2095
+ throw _iteratorError;
2096
+ }
2097
+ return [
2098
+ 7
2099
+ ];
2100
+ case 11:
2101
+ return [
2102
+ 7
2103
+ ];
2104
+ case 12:
2105
+ // Apply all patches to the initial state
2106
+ finalState = applyPatches(finalState, patches);
2107
+ // Verify the final state
2108
+ expect(finalState).toEqual({
2109
+ value: 2
2110
+ });
2111
+ return [
2112
+ 2
2113
+ ];
2114
+ }
2115
+ });
2116
+ })();
2117
+ });
2118
+ });
2119
+ describe('brain resumption', function() {
2120
+ var mockClient = {
2121
+ generateObject: jest.fn()
2122
+ };
2123
+ it('should resume brain from the correct step when given initialCompletedSteps', function() {
2124
+ return _async_to_generator(function() {
2125
+ var executedSteps, threeStepBrain, initialCompletedSteps, initialState, firstStepState, allStepsInfo, _iteratorAbruptCompletion, _didIteratorError, _iteratorError, _loop, _iterator, _step, _ret, err, resumedState, _iteratorAbruptCompletion1, _didIteratorError1, _iteratorError1, _iterator1, _step1, _value, event, err1;
2126
+ return _ts_generator(this, function(_state) {
2127
+ switch(_state.label){
2128
+ case 0:
2129
+ executedSteps = [];
2130
+ threeStepBrain = brain('Three Step Brain').step('Step 1', function(param) {
2131
+ var state = param.state;
2132
+ executedSteps.push('Step 1');
2133
+ return _object_spread_props(_object_spread({}, state), {
2134
+ value: 2
2135
+ });
2136
+ }).step('Step 2', function(param) {
2137
+ var state = param.state;
2138
+ executedSteps.push('Step 2');
2139
+ return _object_spread_props(_object_spread({}, state), {
2140
+ value: state.value + 10
2141
+ });
2142
+ }).step('Step 3', function(param) {
2143
+ var state = param.state;
2144
+ executedSteps.push('Step 3');
2145
+ return _object_spread_props(_object_spread({}, state), {
2146
+ value: state.value * 3
2147
+ });
2148
+ });
2149
+ // First run to get the first step completed with initial state
2150
+ initialCompletedSteps = []; // Use the correct type
2151
+ initialState = {
2152
+ initialValue: true
2153
+ };
2154
+ firstStepState = initialState;
2155
+ allStepsInfo = []; // Explicit type annotation needed
2156
+ _iteratorAbruptCompletion = false, _didIteratorError = false;
2157
+ _state.label = 1;
2158
+ case 1:
2159
+ _state.trys.push([
2160
+ 1,
2161
+ 6,
2162
+ 7,
2163
+ 12
2164
+ ]);
2165
+ _loop = function() {
2166
+ var _value = _step.value;
2167
+ var event = _value;
2168
+ // Capture the full step list from the first status event
2169
+ if (event.type === BRAIN_EVENTS.STEP_STATUS) {
2170
+ allStepsInfo = event.steps; // Direct assignment, type is SerializedStepStatus[]
2171
+ }
2172
+ if (event.type === BRAIN_EVENTS.STEP_COMPLETE && event.stepTitle === 'Step 1') {
2173
+ firstStepState = applyPatches(firstStepState, [
2174
+ event.patch
2175
+ ]);
2176
+ // Construct initialCompletedSteps with the full data for completed steps
2177
+ initialCompletedSteps = allStepsInfo.map(function(stepInfo, index) {
2178
+ if (index === 0) {
2179
+ // If it's Step 1
2180
+ return _object_spread_props(_object_spread({}, stepInfo), {
2181
+ status: STATUS.COMPLETE,
2182
+ patch: event.patch
2183
+ });
2184
+ } else {
2185
+ return _object_spread_props(_object_spread({}, stepInfo), {
2186
+ status: STATUS.PENDING,
2187
+ patch: undefined
2188
+ });
2189
+ }
2190
+ });
2191
+ return "break" // Stop after first step
2192
+ ;
2193
+ }
2194
+ };
2195
+ _iterator = _async_iterator(threeStepBrain.run({
2196
+ client: mockClient,
2197
+ initialState: initialState
2198
+ }));
2199
+ _state.label = 2;
2200
+ case 2:
2201
+ return [
2202
+ 4,
2203
+ _iterator.next()
2204
+ ];
2205
+ case 3:
2206
+ if (!(_iteratorAbruptCompletion = !(_step = _state.sent()).done)) return [
2207
+ 3,
2208
+ 5
2209
+ ];
2210
+ _ret = _loop();
2211
+ if (_ret === "break") return [
2212
+ 3,
2213
+ 5
2214
+ ];
2215
+ _state.label = 4;
2216
+ case 4:
2217
+ _iteratorAbruptCompletion = false;
2218
+ return [
2219
+ 3,
2220
+ 2
2221
+ ];
2222
+ case 5:
2223
+ return [
2224
+ 3,
2225
+ 12
2226
+ ];
2227
+ case 6:
2228
+ err = _state.sent();
2229
+ _didIteratorError = true;
2230
+ _iteratorError = err;
2231
+ return [
2232
+ 3,
2233
+ 12
2234
+ ];
2235
+ case 7:
2236
+ _state.trys.push([
2237
+ 7,
2238
+ ,
2239
+ 10,
2240
+ 11
2241
+ ]);
2242
+ if (!(_iteratorAbruptCompletion && _iterator.return != null)) return [
2243
+ 3,
2244
+ 9
2245
+ ];
2246
+ return [
2247
+ 4,
2248
+ _iterator.return()
2249
+ ];
2250
+ case 8:
2251
+ _state.sent();
2252
+ _state.label = 9;
2253
+ case 9:
2254
+ return [
2255
+ 3,
2256
+ 11
2257
+ ];
2258
+ case 10:
2259
+ if (_didIteratorError) {
2260
+ throw _iteratorError;
2261
+ }
2262
+ return [
2263
+ 7
2264
+ ];
2265
+ case 11:
2266
+ return [
2267
+ 7
2268
+ ];
2269
+ case 12:
2270
+ // Clear executed steps array
2271
+ executedSteps.length = 0;
2272
+ if (!initialCompletedSteps) throw new Error('Expected initialCompletedSteps');
2273
+ _iteratorAbruptCompletion1 = false, _didIteratorError1 = false;
2274
+ _state.label = 13;
2275
+ case 13:
2276
+ _state.trys.push([
2277
+ 13,
2278
+ 18,
2279
+ 19,
2280
+ 24
2281
+ ]);
2282
+ _iterator1 = _async_iterator(threeStepBrain.run({
2283
+ client: mockClient,
2284
+ initialState: initialState,
2285
+ initialCompletedSteps: initialCompletedSteps,
2286
+ brainRunId: 'test-run-id'
2287
+ }));
2288
+ _state.label = 14;
2289
+ case 14:
2290
+ return [
2291
+ 4,
2292
+ _iterator1.next()
2293
+ ];
2294
+ case 15:
2295
+ if (!(_iteratorAbruptCompletion1 = !(_step1 = _state.sent()).done)) return [
2296
+ 3,
2297
+ 17
2298
+ ];
2299
+ _value = _step1.value;
2300
+ event = _value;
2301
+ if (event.type === BRAIN_EVENTS.RESTART) {
2302
+ resumedState = event.initialState;
2303
+ } else if (event.type === BRAIN_EVENTS.STEP_COMPLETE) {
2304
+ resumedState = applyPatches(resumedState, [
2305
+ event.patch
2306
+ ]);
2307
+ }
2308
+ _state.label = 16;
2309
+ case 16:
2310
+ _iteratorAbruptCompletion1 = false;
2311
+ return [
2312
+ 3,
2313
+ 14
2314
+ ];
2315
+ case 17:
2316
+ return [
2317
+ 3,
2318
+ 24
2319
+ ];
2320
+ case 18:
2321
+ err1 = _state.sent();
2322
+ _didIteratorError1 = true;
2323
+ _iteratorError1 = err1;
2324
+ return [
2325
+ 3,
2326
+ 24
2327
+ ];
2328
+ case 19:
2329
+ _state.trys.push([
2330
+ 19,
2331
+ ,
2332
+ 22,
2333
+ 23
2334
+ ]);
2335
+ if (!(_iteratorAbruptCompletion1 && _iterator1.return != null)) return [
2336
+ 3,
2337
+ 21
2338
+ ];
2339
+ return [
2340
+ 4,
2341
+ _iterator1.return()
2342
+ ];
2343
+ case 20:
2344
+ _state.sent();
2345
+ _state.label = 21;
2346
+ case 21:
2347
+ return [
2348
+ 3,
2349
+ 23
2350
+ ];
2351
+ case 22:
2352
+ if (_didIteratorError1) {
2353
+ throw _iteratorError1;
2354
+ }
2355
+ return [
2356
+ 7
2357
+ ];
2358
+ case 23:
2359
+ return [
2360
+ 7
2361
+ ];
2362
+ case 24:
2363
+ // Verify only steps 2 and 3 were executed
2364
+ expect(executedSteps).toEqual([
2365
+ 'Step 2',
2366
+ 'Step 3'
2367
+ ]);
2368
+ expect(executedSteps).not.toContain('Step 1');
2369
+ // Verify the final state after all steps complete
2370
+ expect(resumedState).toEqual({
2371
+ value: 36,
2372
+ initialValue: true
2373
+ });
2374
+ return [
2375
+ 2
2376
+ ];
2377
+ }
2378
+ });
2379
+ })();
2380
+ });
2381
+ });
2382
+ describe('nested brains', function() {
2383
+ it('should execute nested brains and yield all inner brain events', function() {
2384
+ return _async_to_generator(function() {
2385
+ var innerBrain, outerBrain, events, _iteratorAbruptCompletion, _didIteratorError, _iteratorError, _iterator, _step, _value, event, err, innerState, outerState, _iteratorNormalCompletion, _didIteratorError1, _iteratorError1, _iterator1, _step1, event1;
2386
+ return _ts_generator(this, function(_state) {
2387
+ switch(_state.label){
2388
+ case 0:
2389
+ // Create an inner brain that will be nested
2390
+ innerBrain = brain('Inner Brain').step('Double value', function(param) {
2391
+ var state = param.state;
2392
+ return {
2393
+ inner: true,
2394
+ value: state.value * 2
2395
+ };
2396
+ });
2397
+ // Create outer brain that uses the inner brain
2398
+ outerBrain = brain('Outer Brain').step('Set prefix', function() {
2399
+ return {
2400
+ prefix: 'test-'
2401
+ };
2402
+ }).brain('Run inner brain', innerBrain, function(param) {
2403
+ var state = param.state, brainState = param.brainState;
2404
+ return _object_spread_props(_object_spread({}, state), {
2405
+ innerResult: brainState.value
2406
+ });
2407
+ }, function() {
2408
+ return {
2409
+ value: 5
2410
+ };
2411
+ });
2412
+ events = [];
2413
+ _iteratorAbruptCompletion = false, _didIteratorError = false;
2414
+ _state.label = 1;
2415
+ case 1:
2416
+ _state.trys.push([
2417
+ 1,
2418
+ 6,
2419
+ 7,
2420
+ 12
2421
+ ]);
2422
+ _iterator = _async_iterator(outerBrain.run({
2423
+ client: mockClient
2424
+ }));
2425
+ _state.label = 2;
2426
+ case 2:
2427
+ return [
2428
+ 4,
2429
+ _iterator.next()
2430
+ ];
2431
+ case 3:
2432
+ if (!(_iteratorAbruptCompletion = !(_step = _state.sent()).done)) return [
2433
+ 3,
2434
+ 5
2435
+ ];
2436
+ _value = _step.value;
2437
+ event = _value;
2438
+ events.push(event);
2439
+ _state.label = 4;
2440
+ case 4:
2441
+ _iteratorAbruptCompletion = false;
2442
+ return [
2443
+ 3,
2444
+ 2
2445
+ ];
2446
+ case 5:
2447
+ return [
2448
+ 3,
2449
+ 12
2450
+ ];
2451
+ case 6:
2452
+ err = _state.sent();
2453
+ _didIteratorError = true;
2454
+ _iteratorError = err;
2455
+ return [
2456
+ 3,
2457
+ 12
2458
+ ];
2459
+ case 7:
2460
+ _state.trys.push([
2461
+ 7,
2462
+ ,
2463
+ 10,
2464
+ 11
2465
+ ]);
2466
+ if (!(_iteratorAbruptCompletion && _iterator.return != null)) return [
2467
+ 3,
2468
+ 9
2469
+ ];
2470
+ return [
2471
+ 4,
2472
+ _iterator.return()
2473
+ ];
2474
+ case 8:
2475
+ _state.sent();
2476
+ _state.label = 9;
2477
+ case 9:
2478
+ return [
2479
+ 3,
2480
+ 11
2481
+ ];
2482
+ case 10:
2483
+ if (_didIteratorError) {
2484
+ throw _iteratorError;
2485
+ }
2486
+ return [
2487
+ 7
2488
+ ];
2489
+ case 11:
2490
+ return [
2491
+ 7
2492
+ ];
2493
+ case 12:
2494
+ // Verify all events are yielded in correct order
2495
+ expect(events.map(function(e) {
2496
+ return {
2497
+ type: e.type,
2498
+ brainTitle: 'brainTitle' in e ? e.brainTitle : undefined,
2499
+ status: 'status' in e ? e.status : undefined,
2500
+ stepTitle: 'stepTitle' in e ? e.stepTitle : undefined
2501
+ };
2502
+ })).toEqual([
2503
+ // Outer brain start
2504
+ {
2505
+ type: BRAIN_EVENTS.START,
2506
+ brainTitle: 'Outer Brain',
2507
+ status: STATUS.RUNNING,
2508
+ stepTitle: undefined
2509
+ },
2510
+ // Initial step status for outer brain
2511
+ {
2512
+ type: BRAIN_EVENTS.STEP_STATUS,
2513
+ brainTitle: undefined,
2514
+ status: undefined,
2515
+ stepTitle: undefined
2516
+ },
2517
+ // First step of outer brain
2518
+ {
2519
+ type: BRAIN_EVENTS.STEP_START,
2520
+ brainTitle: undefined,
2521
+ status: STATUS.RUNNING,
2522
+ stepTitle: 'Set prefix'
2523
+ },
2524
+ // First step status (running)
2525
+ {
2526
+ type: BRAIN_EVENTS.STEP_STATUS,
2527
+ brainTitle: undefined,
2528
+ status: undefined,
2529
+ stepTitle: undefined
2530
+ },
2531
+ {
2532
+ type: BRAIN_EVENTS.STEP_COMPLETE,
2533
+ brainTitle: undefined,
2534
+ status: STATUS.RUNNING,
2535
+ stepTitle: 'Set prefix'
2536
+ },
2537
+ {
2538
+ type: BRAIN_EVENTS.STEP_STATUS,
2539
+ brainTitle: undefined,
2540
+ status: undefined,
2541
+ stepTitle: undefined
2542
+ },
2543
+ {
2544
+ type: BRAIN_EVENTS.STEP_START,
2545
+ brainTitle: undefined,
2546
+ status: STATUS.RUNNING,
2547
+ stepTitle: 'Run inner brain'
2548
+ },
2549
+ // Step status for inner brain (running)
2550
+ {
2551
+ type: BRAIN_EVENTS.STEP_STATUS,
2552
+ brainTitle: undefined,
2553
+ status: undefined,
2554
+ stepTitle: undefined
2555
+ },
2556
+ // Inner brain start
2557
+ {
2558
+ type: BRAIN_EVENTS.START,
2559
+ brainTitle: 'Inner Brain',
2560
+ status: STATUS.RUNNING,
2561
+ stepTitle: undefined
2562
+ },
2563
+ // Initial step status for inner brain
2564
+ {
2565
+ type: BRAIN_EVENTS.STEP_STATUS,
2566
+ brainTitle: undefined,
2567
+ status: undefined,
2568
+ stepTitle: undefined
2569
+ },
2570
+ // Inner brain step
2571
+ {
2572
+ type: BRAIN_EVENTS.STEP_START,
2573
+ brainTitle: undefined,
2574
+ status: STATUS.RUNNING,
2575
+ stepTitle: 'Double value'
2576
+ },
2577
+ // Inner brain step status (running)
2578
+ {
2579
+ type: BRAIN_EVENTS.STEP_STATUS,
2580
+ brainTitle: undefined,
2581
+ status: undefined,
2582
+ stepTitle: undefined
2583
+ },
2584
+ {
2585
+ type: BRAIN_EVENTS.STEP_COMPLETE,
2586
+ brainTitle: undefined,
2587
+ status: STATUS.RUNNING,
2588
+ stepTitle: 'Double value'
2589
+ },
2590
+ {
2591
+ type: BRAIN_EVENTS.STEP_STATUS,
2592
+ brainTitle: undefined,
2593
+ status: undefined,
2594
+ stepTitle: undefined
2595
+ },
2596
+ {
2597
+ type: BRAIN_EVENTS.COMPLETE,
2598
+ brainTitle: 'Inner Brain',
2599
+ status: STATUS.COMPLETE,
2600
+ stepTitle: undefined
2601
+ },
2602
+ // Outer brain nested step completion
2603
+ {
2604
+ type: BRAIN_EVENTS.STEP_COMPLETE,
2605
+ brainTitle: undefined,
2606
+ status: STATUS.RUNNING,
2607
+ stepTitle: 'Run inner brain'
2608
+ },
2609
+ {
2610
+ type: BRAIN_EVENTS.STEP_STATUS,
2611
+ brainTitle: undefined,
2612
+ status: undefined,
2613
+ stepTitle: undefined
2614
+ },
2615
+ // Outer brain completion
2616
+ {
2617
+ type: BRAIN_EVENTS.COMPLETE,
2618
+ brainTitle: 'Outer Brain',
2619
+ status: STATUS.COMPLETE,
2620
+ stepTitle: undefined
2621
+ }
2622
+ ]);
2623
+ // Verify states are passed correctly
2624
+ innerState = {
2625
+ value: 5
2626
+ }; // Match the initial state from the brain
2627
+ outerState = {};
2628
+ _iteratorNormalCompletion = true, _didIteratorError1 = false, _iteratorError1 = undefined;
2629
+ try {
2630
+ for(_iterator1 = events[Symbol.iterator](); !(_iteratorNormalCompletion = (_step1 = _iterator1.next()).done); _iteratorNormalCompletion = true){
2631
+ event1 = _step1.value;
2632
+ if (event1.type === BRAIN_EVENTS.STEP_COMPLETE) {
2633
+ if (event1.stepTitle === 'Double value') {
2634
+ innerState = applyPatches(innerState, [
2635
+ event1.patch
2636
+ ]);
2637
+ } else {
2638
+ outerState = applyPatches(outerState, [
2639
+ event1.patch
2640
+ ]);
2641
+ }
2642
+ }
2643
+ }
2644
+ } catch (err) {
2645
+ _didIteratorError1 = true;
2646
+ _iteratorError1 = err;
2647
+ } finally{
2648
+ try {
2649
+ if (!_iteratorNormalCompletion && _iterator1.return != null) {
2650
+ _iterator1.return();
2651
+ }
2652
+ } finally{
2653
+ if (_didIteratorError1) {
2654
+ throw _iteratorError1;
2655
+ }
2656
+ }
2657
+ }
2658
+ // Verify final states
2659
+ expect(innerState).toEqual({
2660
+ inner: true,
2661
+ value: 10
2662
+ });
2663
+ expect(outerState).toEqual({
2664
+ prefix: 'test-',
2665
+ innerResult: 10
2666
+ });
2667
+ return [
2668
+ 2
2669
+ ];
2670
+ }
2671
+ });
2672
+ })();
2673
+ });
2674
+ it('should handle errors in nested brains and propagate them up', function() {
2675
+ return _async_to_generator(function() {
2676
+ var innerBrain, outerBrain, events, error, mainBrainId, _iteratorAbruptCompletion, _didIteratorError, _iteratorError, _iterator, _step, _value, event, err, e, innerErrorEvent, outerErrorEvent;
2677
+ return _ts_generator(this, function(_state) {
2678
+ switch(_state.label){
2679
+ case 0:
2680
+ // Create an inner brain that will throw an error
2681
+ innerBrain = brain('Failing Inner Brain').step('Throw error', function() {
2682
+ throw new Error('Inner brain error');
2683
+ });
2684
+ // Create outer brain that uses the failing inner brain
2685
+ outerBrain = brain('Outer Brain').step('First step', function() {
2686
+ return {
2687
+ step: 'first'
2688
+ };
2689
+ }).brain('Run inner brain', innerBrain, function(param) {
2690
+ var state = param.state, brainState = param.brainState;
2691
+ return _object_spread_props(_object_spread({}, state), {
2692
+ step: 'second',
2693
+ innerResult: brainState.value
2694
+ });
2695
+ }, function() {
2696
+ return {
2697
+ value: 5
2698
+ };
2699
+ });
2700
+ events = [];
2701
+ _state.label = 1;
2702
+ case 1:
2703
+ _state.trys.push([
2704
+ 1,
2705
+ 14,
2706
+ ,
2707
+ 15
2708
+ ]);
2709
+ _iteratorAbruptCompletion = false, _didIteratorError = false;
2710
+ _state.label = 2;
2711
+ case 2:
2712
+ _state.trys.push([
2713
+ 2,
2714
+ 7,
2715
+ 8,
2716
+ 13
2717
+ ]);
2718
+ _iterator = _async_iterator(outerBrain.run({
2719
+ client: mockClient
2720
+ }));
2721
+ _state.label = 3;
2722
+ case 3:
2723
+ return [
2724
+ 4,
2725
+ _iterator.next()
2726
+ ];
2727
+ case 4:
2728
+ if (!(_iteratorAbruptCompletion = !(_step = _state.sent()).done)) return [
2729
+ 3,
2730
+ 6
2731
+ ];
2732
+ _value = _step.value;
2733
+ event = _value;
2734
+ events.push(event);
2735
+ if (event.type === BRAIN_EVENTS.START && !mainBrainId) {
2736
+ mainBrainId = event.brainRunId;
2737
+ }
2738
+ _state.label = 5;
2739
+ case 5:
2740
+ _iteratorAbruptCompletion = false;
2741
+ return [
2742
+ 3,
2743
+ 3
2744
+ ];
2745
+ case 6:
2746
+ return [
2747
+ 3,
2748
+ 13
2749
+ ];
2750
+ case 7:
2751
+ err = _state.sent();
2752
+ _didIteratorError = true;
2753
+ _iteratorError = err;
2754
+ return [
2755
+ 3,
2756
+ 13
2757
+ ];
2758
+ case 8:
2759
+ _state.trys.push([
2760
+ 8,
2761
+ ,
2762
+ 11,
2763
+ 12
2764
+ ]);
2765
+ if (!(_iteratorAbruptCompletion && _iterator.return != null)) return [
2766
+ 3,
2767
+ 10
2768
+ ];
2769
+ return [
2770
+ 4,
2771
+ _iterator.return()
2772
+ ];
2773
+ case 9:
2774
+ _state.sent();
2775
+ _state.label = 10;
2776
+ case 10:
2777
+ return [
2778
+ 3,
2779
+ 12
2780
+ ];
2781
+ case 11:
2782
+ if (_didIteratorError) {
2783
+ throw _iteratorError;
2784
+ }
2785
+ return [
2786
+ 7
2787
+ ];
2788
+ case 12:
2789
+ return [
2790
+ 7
2791
+ ];
2792
+ case 13:
2793
+ return [
2794
+ 3,
2795
+ 15
2796
+ ];
2797
+ case 14:
2798
+ e = _state.sent();
2799
+ error = e;
2800
+ return [
2801
+ 3,
2802
+ 15
2803
+ ];
2804
+ case 15:
2805
+ // Verify error was thrown
2806
+ expect(error === null || error === void 0 ? void 0 : error.message).toBe('Inner brain error');
2807
+ // Verify event sequence including error
2808
+ expect(events).toEqual([
2809
+ expect.objectContaining({
2810
+ type: BRAIN_EVENTS.START,
2811
+ brainTitle: 'Outer Brain',
2812
+ status: STATUS.RUNNING,
2813
+ brainRunId: mainBrainId
2814
+ }),
2815
+ expect.objectContaining({
2816
+ type: BRAIN_EVENTS.STEP_STATUS,
2817
+ steps: expect.any(Array)
2818
+ }),
2819
+ expect.objectContaining({
2820
+ type: BRAIN_EVENTS.STEP_START,
2821
+ status: STATUS.RUNNING,
2822
+ stepTitle: 'First step'
2823
+ }),
2824
+ expect.objectContaining({
2825
+ type: BRAIN_EVENTS.STEP_STATUS,
2826
+ steps: expect.any(Array)
2827
+ }),
2828
+ expect.objectContaining({
2829
+ type: BRAIN_EVENTS.STEP_COMPLETE,
2830
+ status: STATUS.RUNNING,
2831
+ stepTitle: 'First step'
2832
+ }),
2833
+ expect.objectContaining({
2834
+ type: BRAIN_EVENTS.STEP_STATUS,
2835
+ steps: expect.any(Array)
2836
+ }),
2837
+ expect.objectContaining({
2838
+ type: BRAIN_EVENTS.STEP_START,
2839
+ status: STATUS.RUNNING,
2840
+ stepTitle: 'Run inner brain'
2841
+ }),
2842
+ expect.objectContaining({
2843
+ type: BRAIN_EVENTS.STEP_STATUS,
2844
+ steps: expect.any(Array)
2845
+ }),
2846
+ expect.objectContaining({
2847
+ type: BRAIN_EVENTS.START,
2848
+ brainTitle: 'Failing Inner Brain',
2849
+ status: STATUS.RUNNING
2850
+ }),
2851
+ expect.objectContaining({
2852
+ type: BRAIN_EVENTS.STEP_STATUS,
2853
+ steps: expect.any(Array)
2854
+ }),
2855
+ expect.objectContaining({
2856
+ type: BRAIN_EVENTS.STEP_START,
2857
+ status: STATUS.RUNNING,
2858
+ stepTitle: 'Throw error'
2859
+ }),
2860
+ expect.objectContaining({
2861
+ type: BRAIN_EVENTS.STEP_STATUS,
2862
+ steps: expect.any(Array)
2863
+ }),
2864
+ expect.objectContaining({
2865
+ type: BRAIN_EVENTS.ERROR,
2866
+ brainTitle: 'Failing Inner Brain',
2867
+ status: STATUS.ERROR,
2868
+ error: expect.objectContaining({
2869
+ name: expect.any(String),
2870
+ message: expect.any(String)
2871
+ })
2872
+ }),
2873
+ expect.objectContaining({
2874
+ type: BRAIN_EVENTS.STEP_STATUS,
2875
+ steps: expect.arrayContaining([
2876
+ expect.objectContaining({
2877
+ title: 'Throw error',
2878
+ status: STATUS.ERROR
2879
+ })
2880
+ ])
2881
+ }),
2882
+ expect.objectContaining({
2883
+ type: BRAIN_EVENTS.ERROR,
2884
+ brainTitle: 'Outer Brain',
2885
+ status: STATUS.ERROR,
2886
+ error: expect.objectContaining({
2887
+ name: expect.any(String),
2888
+ message: expect.any(String)
2889
+ })
2890
+ }),
2891
+ expect.objectContaining({
2892
+ type: BRAIN_EVENTS.STEP_STATUS,
2893
+ steps: expect.arrayContaining([
2894
+ expect.objectContaining({
2895
+ title: 'Run inner brain',
2896
+ status: STATUS.ERROR
2897
+ })
2898
+ ])
2899
+ })
2900
+ ]);
2901
+ // Find inner and outer error events by brainRunId
2902
+ innerErrorEvent = events.find(function(e) {
2903
+ return e.type === BRAIN_EVENTS.ERROR && e.brainRunId !== mainBrainId;
2904
+ });
2905
+ outerErrorEvent = events.find(function(e) {
2906
+ return e.type === BRAIN_EVENTS.ERROR && e.brainRunId === mainBrainId;
2907
+ });
2908
+ expect(innerErrorEvent.error).toEqual(expect.objectContaining({
2909
+ message: 'Inner brain error'
2910
+ }));
2911
+ expect(outerErrorEvent.error).toEqual(expect.objectContaining({
2912
+ message: 'Inner brain error'
2913
+ }));
2914
+ return [
2915
+ 2
2916
+ ];
2917
+ }
2918
+ });
2919
+ })();
2920
+ });
2921
+ it('should include patches in step status events for inner brain steps', function() {
2922
+ return _async_to_generator(function() {
2923
+ var innerBrain, outerBrain, finalStepStatus, _iteratorAbruptCompletion, _didIteratorError, _iteratorError, _iterator, _step, _value, event, err;
2924
+ return _ts_generator(this, function(_state) {
2925
+ switch(_state.label){
2926
+ case 0:
2927
+ // Create an inner brain that modifies state
2928
+ innerBrain = brain('Inner Brain').step('Double value', function(param) {
2929
+ var state = param.state;
2930
+ return _object_spread_props(_object_spread({}, state), {
2931
+ value: state.value * 2
2932
+ });
2933
+ });
2934
+ // Create outer brain that uses the inner brain
2935
+ outerBrain = brain('Outer Brain').step('Set initial', function() {
2936
+ return {
2937
+ value: 5
2938
+ };
2939
+ }).brain('Run inner brain', innerBrain, function(param) {
2940
+ var state = param.state, brainState = param.brainState;
2941
+ return _object_spread_props(_object_spread({}, state), {
2942
+ result: brainState.value
2943
+ });
2944
+ }, function(state) {
2945
+ return {
2946
+ value: state.value
2947
+ };
2948
+ });
2949
+ _iteratorAbruptCompletion = false, _didIteratorError = false;
2950
+ _state.label = 1;
2951
+ case 1:
2952
+ _state.trys.push([
2953
+ 1,
2954
+ 6,
2955
+ 7,
2956
+ 12
2957
+ ]);
2958
+ _iterator = _async_iterator(outerBrain.run({
2959
+ client: mockClient
2960
+ }));
2961
+ _state.label = 2;
2962
+ case 2:
2963
+ return [
2964
+ 4,
2965
+ _iterator.next()
2966
+ ];
2967
+ case 3:
2968
+ if (!(_iteratorAbruptCompletion = !(_step = _state.sent()).done)) return [
2969
+ 3,
2970
+ 5
2971
+ ];
2972
+ _value = _step.value;
2973
+ event = _value;
2974
+ if (event.type === BRAIN_EVENTS.STEP_STATUS) {
2975
+ finalStepStatus = event;
2976
+ }
2977
+ _state.label = 4;
2978
+ case 4:
2979
+ _iteratorAbruptCompletion = false;
2980
+ return [
2981
+ 3,
2982
+ 2
2983
+ ];
2984
+ case 5:
2985
+ return [
2986
+ 3,
2987
+ 12
2988
+ ];
2989
+ case 6:
2990
+ err = _state.sent();
2991
+ _didIteratorError = true;
2992
+ _iteratorError = err;
2993
+ return [
2994
+ 3,
2995
+ 12
2996
+ ];
2997
+ case 7:
2998
+ _state.trys.push([
2999
+ 7,
3000
+ ,
3001
+ 10,
3002
+ 11
3003
+ ]);
3004
+ if (!(_iteratorAbruptCompletion && _iterator.return != null)) return [
3005
+ 3,
3006
+ 9
3007
+ ];
3008
+ return [
3009
+ 4,
3010
+ _iterator.return()
3011
+ ];
3012
+ case 8:
3013
+ _state.sent();
3014
+ _state.label = 9;
3015
+ case 9:
3016
+ return [
3017
+ 3,
3018
+ 11
3019
+ ];
3020
+ case 10:
3021
+ if (_didIteratorError) {
3022
+ throw _iteratorError;
3023
+ }
3024
+ return [
3025
+ 7
3026
+ ];
3027
+ case 11:
3028
+ return [
3029
+ 7
3030
+ ];
3031
+ case 12:
3032
+ // Verify step status contains patches for all steps including the inner brain step
3033
+ expect(finalStepStatus === null || finalStepStatus === void 0 ? void 0 : finalStepStatus.steps).toEqual([
3034
+ expect.objectContaining({
3035
+ title: 'Set initial',
3036
+ status: STATUS.COMPLETE
3037
+ }),
3038
+ expect.objectContaining({
3039
+ title: 'Run inner brain',
3040
+ status: STATUS.COMPLETE
3041
+ })
3042
+ ]);
3043
+ return [
3044
+ 2
3045
+ ];
3046
+ }
3047
+ });
3048
+ })();
3049
+ });
3050
+ });
3051
+ describe('brain options', function() {
3052
+ it('should pass options through to brain events', function() {
3053
+ return _async_to_generator(function() {
3054
+ var testBrain, brainOptions, finalEvent, finalStepStatus, _iteratorAbruptCompletion, _didIteratorError, _iteratorError, _iterator, _step, _value, event, err;
3055
+ return _ts_generator(this, function(_state) {
3056
+ switch(_state.label){
3057
+ case 0:
3058
+ testBrain = brain('Options Brain').step('Simple step', function(param) {
3059
+ var state = param.state, options = param.options;
3060
+ return {
3061
+ value: 1,
3062
+ passedOption: options.testOption
3063
+ };
3064
+ });
3065
+ brainOptions = {
3066
+ testOption: 'test-value'
3067
+ };
3068
+ _iteratorAbruptCompletion = false, _didIteratorError = false;
3069
+ _state.label = 1;
3070
+ case 1:
3071
+ _state.trys.push([
3072
+ 1,
3073
+ 6,
3074
+ 7,
3075
+ 12
3076
+ ]);
3077
+ _iterator = _async_iterator(testBrain.run({
3078
+ client: mockClient,
3079
+ options: brainOptions
3080
+ }));
3081
+ _state.label = 2;
3082
+ case 2:
3083
+ return [
3084
+ 4,
3085
+ _iterator.next()
3086
+ ];
3087
+ case 3:
3088
+ if (!(_iteratorAbruptCompletion = !(_step = _state.sent()).done)) return [
3089
+ 3,
3090
+ 5
3091
+ ];
3092
+ _value = _step.value;
3093
+ event = _value;
3094
+ if (event.type === BRAIN_EVENTS.STEP_STATUS) {
3095
+ finalStepStatus = event;
3096
+ } else {
3097
+ finalEvent = event;
3098
+ }
3099
+ _state.label = 4;
3100
+ case 4:
3101
+ _iteratorAbruptCompletion = false;
3102
+ return [
3103
+ 3,
3104
+ 2
3105
+ ];
3106
+ case 5:
3107
+ return [
3108
+ 3,
3109
+ 12
3110
+ ];
3111
+ case 6:
3112
+ err = _state.sent();
3113
+ _didIteratorError = true;
3114
+ _iteratorError = err;
3115
+ return [
3116
+ 3,
3117
+ 12
3118
+ ];
3119
+ case 7:
3120
+ _state.trys.push([
3121
+ 7,
3122
+ ,
3123
+ 10,
3124
+ 11
3125
+ ]);
3126
+ if (!(_iteratorAbruptCompletion && _iterator.return != null)) return [
3127
+ 3,
3128
+ 9
3129
+ ];
3130
+ return [
3131
+ 4,
3132
+ _iterator.return()
3133
+ ];
3134
+ case 8:
3135
+ _state.sent();
3136
+ _state.label = 9;
3137
+ case 9:
3138
+ return [
3139
+ 3,
3140
+ 11
3141
+ ];
3142
+ case 10:
3143
+ if (_didIteratorError) {
3144
+ throw _iteratorError;
3145
+ }
3146
+ return [
3147
+ 7
3148
+ ];
3149
+ case 11:
3150
+ return [
3151
+ 7
3152
+ ];
3153
+ case 12:
3154
+ expect(finalEvent).toEqual(expect.objectContaining({
3155
+ type: BRAIN_EVENTS.COMPLETE,
3156
+ status: STATUS.COMPLETE,
3157
+ brainTitle: 'Options Brain',
3158
+ brainDescription: undefined,
3159
+ options: brainOptions
3160
+ }));
3161
+ expect(finalStepStatus).toEqual(expect.objectContaining({
3162
+ type: BRAIN_EVENTS.STEP_STATUS,
3163
+ steps: [
3164
+ expect.objectContaining({
3165
+ title: 'Simple step',
3166
+ status: STATUS.COMPLETE
3167
+ })
3168
+ ],
3169
+ options: brainOptions
3170
+ }));
3171
+ return [
3172
+ 2
3173
+ ];
3174
+ }
3175
+ });
3176
+ })();
3177
+ });
3178
+ it('should provide empty object as default options', function() {
3179
+ return _async_to_generator(function() {
3180
+ var testBrain, brainRun, stepStartResult, stepStatusRunning, stepResult;
3181
+ return _ts_generator(this, function(_state) {
3182
+ switch(_state.label){
3183
+ case 0:
3184
+ testBrain = brain('Default Options Brain').step('Simple step', function(param) {
3185
+ var options = param.options;
3186
+ return {
3187
+ hasOptions: Object.keys(options).length === 0
3188
+ };
3189
+ });
3190
+ brainRun = testBrain.run({
3191
+ client: mockClient
3192
+ });
3193
+ // Skip start event
3194
+ return [
3195
+ 4,
3196
+ brainRun.next()
3197
+ ];
3198
+ case 1:
3199
+ _state.sent();
3200
+ // Skip initial step status event
3201
+ return [
3202
+ 4,
3203
+ brainRun.next()
3204
+ ];
3205
+ case 2:
3206
+ _state.sent();
3207
+ return [
3208
+ 4,
3209
+ brainRun.next()
3210
+ ];
3211
+ case 3:
3212
+ stepStartResult = _state.sent();
3213
+ expect(stepStartResult.value).toEqual(expect.objectContaining({
3214
+ options: {},
3215
+ type: BRAIN_EVENTS.STEP_START
3216
+ }));
3217
+ return [
3218
+ 4,
3219
+ brainRun.next()
3220
+ ];
3221
+ case 4:
3222
+ stepStatusRunning = _state.sent();
3223
+ expect(stepStatusRunning.value).toEqual(expect.objectContaining({
3224
+ type: BRAIN_EVENTS.STEP_STATUS,
3225
+ steps: expect.any(Array)
3226
+ }));
3227
+ if (stepStatusRunning.value.type === BRAIN_EVENTS.STEP_STATUS) {
3228
+ expect(stepStatusRunning.value.steps[0].status).toBe(STATUS.RUNNING);
3229
+ }
3230
+ return [
3231
+ 4,
3232
+ brainRun.next()
3233
+ ];
3234
+ case 5:
3235
+ stepResult = _state.sent();
3236
+ expect(stepResult.value).toEqual(expect.objectContaining({
3237
+ type: BRAIN_EVENTS.STEP_COMPLETE,
3238
+ stepTitle: 'Simple step',
3239
+ options: {}
3240
+ }));
3241
+ return [
3242
+ 2
3243
+ ];
3244
+ }
3245
+ });
3246
+ })();
3247
+ });
3248
+ });
3249
+ describe('services support', function() {
3250
+ it('should allow adding custom services to brains', function() {
3251
+ return _async_to_generator(function() {
3252
+ var testBrain, finalState, _iteratorAbruptCompletion, _didIteratorError, _iteratorError, _iterator, _step, _value, event, err;
3253
+ return _ts_generator(this, function(_state) {
3254
+ switch(_state.label){
3255
+ case 0:
3256
+ // Create a brain with services
3257
+ testBrain = brain('Services Test').withServices({
3258
+ logger: testLogger
3259
+ }).step('Use service', function(param) {
3260
+ var state = param.state, logger = param.logger;
3261
+ logger.log('Test service called');
3262
+ return {
3263
+ serviceUsed: true
3264
+ };
3265
+ });
3266
+ // Run the brain and collect events
3267
+ finalState = {};
3268
+ _iteratorAbruptCompletion = false, _didIteratorError = false;
3269
+ _state.label = 1;
3270
+ case 1:
3271
+ _state.trys.push([
3272
+ 1,
3273
+ 6,
3274
+ 7,
3275
+ 12
3276
+ ]);
3277
+ _iterator = _async_iterator(testBrain.run({
3278
+ client: mockClient
3279
+ }));
3280
+ _state.label = 2;
3281
+ case 2:
3282
+ return [
3283
+ 4,
3284
+ _iterator.next()
3285
+ ];
3286
+ case 3:
3287
+ if (!(_iteratorAbruptCompletion = !(_step = _state.sent()).done)) return [
3288
+ 3,
3289
+ 5
3290
+ ];
3291
+ _value = _step.value;
3292
+ event = _value;
3293
+ if (event.type === BRAIN_EVENTS.STEP_COMPLETE) {
3294
+ finalState = applyPatches(finalState, [
3295
+ event.patch
3296
+ ]);
3297
+ }
3298
+ _state.label = 4;
3299
+ case 4:
3300
+ _iteratorAbruptCompletion = false;
3301
+ return [
3302
+ 3,
3303
+ 2
3304
+ ];
3305
+ case 5:
3306
+ return [
3307
+ 3,
3308
+ 12
3309
+ ];
3310
+ case 6:
3311
+ err = _state.sent();
3312
+ _didIteratorError = true;
3313
+ _iteratorError = err;
3314
+ return [
3315
+ 3,
3316
+ 12
3317
+ ];
3318
+ case 7:
3319
+ _state.trys.push([
3320
+ 7,
3321
+ ,
3322
+ 10,
3323
+ 11
3324
+ ]);
3325
+ if (!(_iteratorAbruptCompletion && _iterator.return != null)) return [
3326
+ 3,
3327
+ 9
3328
+ ];
3329
+ return [
3330
+ 4,
3331
+ _iterator.return()
3332
+ ];
3333
+ case 8:
3334
+ _state.sent();
3335
+ _state.label = 9;
3336
+ case 9:
3337
+ return [
3338
+ 3,
3339
+ 11
3340
+ ];
3341
+ case 10:
3342
+ if (_didIteratorError) {
3343
+ throw _iteratorError;
3344
+ }
3345
+ return [
3346
+ 7
3347
+ ];
3348
+ case 11:
3349
+ return [
3350
+ 7
3351
+ ];
3352
+ case 12:
3353
+ // Verify the service was called
3354
+ expect(testLogger.log).toHaveBeenCalledWith('Test service called');
3355
+ // Verify the state was updated
3356
+ expect(finalState).toEqual({
3357
+ serviceUsed: true
3358
+ });
3359
+ return [
3360
+ 2
3361
+ ];
3362
+ }
3363
+ });
3364
+ })();
3365
+ });
3366
+ });
3367
+ describe('type inference', function() {
3368
+ it('should correctly infer complex brain state types', function() {
3369
+ return _async_to_generator(function() {
3370
+ var innerBrain, complexBrain, _typeAssert, events, finalStepStatus, finalState, mainBrainId, _iteratorAbruptCompletion, _didIteratorError, _iteratorError, _iterator, _step, _value, event, err, innerStartEvent, lastStep;
3371
+ return _ts_generator(this, function(_state) {
3372
+ switch(_state.label){
3373
+ case 0:
3374
+ // Create an inner brain that uses the shared options type
3375
+ innerBrain = brain('Inner Type Test').step('Process features', function(param) {
3376
+ var options = param.options;
3377
+ return {
3378
+ processedValue: options.features.includes('fast') ? 100 : 42,
3379
+ featureCount: options.features.length
3380
+ };
3381
+ });
3382
+ // Create a complex brain using multiple features
3383
+ complexBrain = brain('Complex Type Test').step('First step', function(param) {
3384
+ var options = param.options;
3385
+ return {
3386
+ initialFeatures: options.features,
3387
+ value: 42
3388
+ };
3389
+ }).brain('Nested brain', innerBrain, function(param) {
3390
+ var state = param.state, brainState = param.brainState;
3391
+ return _object_spread_props(_object_spread({}, state), {
3392
+ processedValue: brainState.processedValue,
3393
+ totalFeatures: brainState.featureCount
3394
+ });
3395
+ }, function() {
3396
+ return {
3397
+ processedValue: 0,
3398
+ featureCount: 0
3399
+ };
3400
+ }).step('Final step', function(param) {
3401
+ var state = param.state;
3402
+ return _object_spread_props(_object_spread({}, state), {
3403
+ completed: true
3404
+ });
3405
+ });
3406
+ _typeAssert = true;
3407
+ // Collect all events
3408
+ events = [];
3409
+ finalState = {};
3410
+ _iteratorAbruptCompletion = false, _didIteratorError = false;
3411
+ _state.label = 1;
3412
+ case 1:
3413
+ _state.trys.push([
3414
+ 1,
3415
+ 6,
3416
+ 7,
3417
+ 12
3418
+ ]);
3419
+ _iterator = _async_iterator(complexBrain.run({
3420
+ client: mockClient,
3421
+ options: {
3422
+ features: [
3423
+ 'fast',
3424
+ 'secure'
3425
+ ]
3426
+ }
3427
+ }));
3428
+ _state.label = 2;
3429
+ case 2:
3430
+ return [
3431
+ 4,
3432
+ _iterator.next()
3433
+ ];
3434
+ case 3:
3435
+ if (!(_iteratorAbruptCompletion = !(_step = _state.sent()).done)) return [
3436
+ 3,
3437
+ 5
3438
+ ];
3439
+ _value = _step.value;
3440
+ event = _value;
3441
+ events.push(event);
3442
+ // Capture the main brain's ID from its start event
3443
+ if (event.type === BRAIN_EVENTS.START && !mainBrainId) {
3444
+ mainBrainId = event.brainRunId;
3445
+ }
3446
+ if (event.type === BRAIN_EVENTS.STEP_STATUS) {
3447
+ finalStepStatus = event;
3448
+ } else if (event.type === BRAIN_EVENTS.STEP_COMPLETE && event.brainRunId === mainBrainId // Only process events from main brain
3449
+ ) {
3450
+ finalState = applyPatches(finalState, [
3451
+ event.patch
3452
+ ]);
3453
+ }
3454
+ _state.label = 4;
3455
+ case 4:
3456
+ _iteratorAbruptCompletion = false;
3457
+ return [
3458
+ 3,
3459
+ 2
3460
+ ];
3461
+ case 5:
3462
+ return [
3463
+ 3,
3464
+ 12
3465
+ ];
3466
+ case 6:
3467
+ err = _state.sent();
3468
+ _didIteratorError = true;
3469
+ _iteratorError = err;
3470
+ return [
3471
+ 3,
3472
+ 12
3473
+ ];
3474
+ case 7:
3475
+ _state.trys.push([
3476
+ 7,
3477
+ ,
3478
+ 10,
3479
+ 11
3480
+ ]);
3481
+ if (!(_iteratorAbruptCompletion && _iterator.return != null)) return [
3482
+ 3,
3483
+ 9
3484
+ ];
3485
+ return [
3486
+ 4,
3487
+ _iterator.return()
3488
+ ];
3489
+ case 8:
3490
+ _state.sent();
3491
+ _state.label = 9;
3492
+ case 9:
3493
+ return [
3494
+ 3,
3495
+ 11
3496
+ ];
3497
+ case 10:
3498
+ if (_didIteratorError) {
3499
+ throw _iteratorError;
3500
+ }
3501
+ return [
3502
+ 7
3503
+ ];
3504
+ case 11:
3505
+ return [
3506
+ 7
3507
+ ];
3508
+ case 12:
3509
+ // Verify brain start event
3510
+ expect(events[0]).toEqual(expect.objectContaining({
3511
+ type: BRAIN_EVENTS.START,
3512
+ status: STATUS.RUNNING,
3513
+ brainTitle: 'Complex Type Test',
3514
+ brainDescription: undefined,
3515
+ options: {
3516
+ features: [
3517
+ 'fast',
3518
+ 'secure'
3519
+ ]
3520
+ },
3521
+ brainRunId: mainBrainId
3522
+ }));
3523
+ // Verify inner brain events are included
3524
+ innerStartEvent = events.find(function(e) {
3525
+ return e.type === BRAIN_EVENTS.START && 'brainRunId' in e && e.brainRunId !== mainBrainId;
3526
+ });
3527
+ expect(innerStartEvent).toEqual(expect.objectContaining({
3528
+ type: BRAIN_EVENTS.START,
3529
+ status: STATUS.RUNNING,
3530
+ brainTitle: 'Inner Type Test',
3531
+ options: {
3532
+ features: [
3533
+ 'fast',
3534
+ 'secure'
3535
+ ]
3536
+ }
3537
+ }));
3538
+ // Verify the final step status
3539
+ if (!finalStepStatus) throw new Error('Expected final step status event');
3540
+ lastStep = finalStepStatus.steps[finalStepStatus.steps.length - 1];
3541
+ expect(lastStep.status).toBe(STATUS.COMPLETE);
3542
+ expect(lastStep.title).toBe('Final step');
3543
+ expect(finalState).toEqual({
3544
+ initialFeatures: [
3545
+ 'fast',
3546
+ 'secure'
3547
+ ],
3548
+ value: 42,
3549
+ processedValue: 100,
3550
+ totalFeatures: 2,
3551
+ completed: true
3552
+ });
3553
+ return [
3554
+ 2
3555
+ ];
3556
+ }
3557
+ });
3558
+ })();
3559
+ });
3560
+ it('should correctly infer brain reducer state types', function() {
3561
+ return _async_to_generator(function() {
3562
+ var innerBrain, outerBrain, finalState, mainBrainId, _iteratorAbruptCompletion, _didIteratorError, _iteratorError, _iterator, _step, _value, event, err;
3563
+ return _ts_generator(this, function(_state) {
3564
+ switch(_state.label){
3565
+ case 0:
3566
+ // Create an inner brain with a specific state shape
3567
+ innerBrain = brain('Inner State Test').step('Inner step', function() {
3568
+ return {
3569
+ innerValue: 42,
3570
+ metadata: {
3571
+ processed: true
3572
+ }
3573
+ };
3574
+ });
3575
+ // Create outer brain to test reducer type inference
3576
+ outerBrain = brain('Outer State Test').step('First step', function() {
3577
+ return {
3578
+ outerValue: 100,
3579
+ status: 'ready'
3580
+ };
3581
+ }).brain('Nested brain', innerBrain, function(param) {
3582
+ var state = param.state, brainState = param.brainState;
3583
+ var _outerAssert = true;
3584
+ var _innerAssert = true;
3585
+ return _object_spread_props(_object_spread({}, state), {
3586
+ innerResult: brainState.innerValue,
3587
+ processed: brainState.metadata.processed
3588
+ });
3589
+ }, function() {
3590
+ return {};
3591
+ });
3592
+ // Run the brain to verify runtime behavior
3593
+ finalState = {};
3594
+ _iteratorAbruptCompletion = false, _didIteratorError = false;
3595
+ _state.label = 1;
3596
+ case 1:
3597
+ _state.trys.push([
3598
+ 1,
3599
+ 6,
3600
+ 7,
3601
+ 12
3602
+ ]);
3603
+ _iterator = _async_iterator(outerBrain.run({
3604
+ client: mockClient
3605
+ }));
3606
+ _state.label = 2;
3607
+ case 2:
3608
+ return [
3609
+ 4,
3610
+ _iterator.next()
3611
+ ];
3612
+ case 3:
3613
+ if (!(_iteratorAbruptCompletion = !(_step = _state.sent()).done)) return [
3614
+ 3,
3615
+ 5
3616
+ ];
3617
+ _value = _step.value;
3618
+ event = _value;
3619
+ if (event.type === BRAIN_EVENTS.START && !mainBrainId) {
3620
+ mainBrainId = event.brainRunId;
3621
+ }
3622
+ if (event.type === BRAIN_EVENTS.STEP_COMPLETE && event.brainRunId === mainBrainId) {
3623
+ finalState = applyPatches(finalState, [
3624
+ event.patch
3625
+ ]);
3626
+ }
3627
+ _state.label = 4;
3628
+ case 4:
3629
+ _iteratorAbruptCompletion = false;
3630
+ return [
3631
+ 3,
3632
+ 2
3633
+ ];
3634
+ case 5:
3635
+ return [
3636
+ 3,
3637
+ 12
3638
+ ];
3639
+ case 6:
3640
+ err = _state.sent();
3641
+ _didIteratorError = true;
3642
+ _iteratorError = err;
3643
+ return [
3644
+ 3,
3645
+ 12
3646
+ ];
3647
+ case 7:
3648
+ _state.trys.push([
3649
+ 7,
3650
+ ,
3651
+ 10,
3652
+ 11
3653
+ ]);
3654
+ if (!(_iteratorAbruptCompletion && _iterator.return != null)) return [
3655
+ 3,
3656
+ 9
3657
+ ];
3658
+ return [
3659
+ 4,
3660
+ _iterator.return()
3661
+ ];
3662
+ case 8:
3663
+ _state.sent();
3664
+ _state.label = 9;
3665
+ case 9:
3666
+ return [
3667
+ 3,
3668
+ 11
3669
+ ];
3670
+ case 10:
3671
+ if (_didIteratorError) {
3672
+ throw _iteratorError;
3673
+ }
3674
+ return [
3675
+ 7
3676
+ ];
3677
+ case 11:
3678
+ return [
3679
+ 7
3680
+ ];
3681
+ case 12:
3682
+ expect(finalState).toEqual({
3683
+ outerValue: 100,
3684
+ status: 'ready',
3685
+ innerResult: 42,
3686
+ processed: true
3687
+ });
3688
+ return [
3689
+ 2
3690
+ ];
3691
+ }
3692
+ });
3693
+ })();
3694
+ });
3695
+ it('should correctly infer step action state types', function() {
3696
+ return _async_to_generator(function() {
3697
+ var testBrain, finalState, mainBrainId, _iteratorAbruptCompletion, _didIteratorError, _iteratorError, _iterator, _step, _value, event, err;
3698
+ return _ts_generator(this, function(_state) {
3699
+ switch(_state.label){
3700
+ case 0:
3701
+ testBrain = brain('Action State Test').step('First step', function() {
3702
+ return {
3703
+ count: 1,
3704
+ metadata: {
3705
+ created: new Date().toISOString()
3706
+ }
3707
+ };
3708
+ }).step('Second step', function(param) {
3709
+ var state = param.state;
3710
+ var _stateAssert = true;
3711
+ return _object_spread_props(_object_spread({}, state), {
3712
+ count: state.count + 1,
3713
+ metadata: _object_spread_props(_object_spread({}, state.metadata), {
3714
+ updated: new Date().toISOString()
3715
+ })
3716
+ });
3717
+ });
3718
+ // Run the brain to verify runtime behavior
3719
+ finalState = {};
3720
+ _iteratorAbruptCompletion = false, _didIteratorError = false;
3721
+ _state.label = 1;
3722
+ case 1:
3723
+ _state.trys.push([
3724
+ 1,
3725
+ 6,
3726
+ 7,
3727
+ 12
3728
+ ]);
3729
+ _iterator = _async_iterator(testBrain.run({
3730
+ client: mockClient
3731
+ }));
3732
+ _state.label = 2;
3733
+ case 2:
3734
+ return [
3735
+ 4,
3736
+ _iterator.next()
3737
+ ];
3738
+ case 3:
3739
+ if (!(_iteratorAbruptCompletion = !(_step = _state.sent()).done)) return [
3740
+ 3,
3741
+ 5
3742
+ ];
3743
+ _value = _step.value;
3744
+ event = _value;
3745
+ if (event.type === BRAIN_EVENTS.START && !mainBrainId) {
3746
+ mainBrainId = event.brainRunId;
3747
+ }
3748
+ if (event.type === BRAIN_EVENTS.STEP_COMPLETE && event.brainRunId === mainBrainId) {
3749
+ finalState = applyPatches(finalState, [
3750
+ event.patch
3751
+ ]);
3752
+ }
3753
+ _state.label = 4;
3754
+ case 4:
3755
+ _iteratorAbruptCompletion = false;
3756
+ return [
3757
+ 3,
3758
+ 2
3759
+ ];
3760
+ case 5:
3761
+ return [
3762
+ 3,
3763
+ 12
3764
+ ];
3765
+ case 6:
3766
+ err = _state.sent();
3767
+ _didIteratorError = true;
3768
+ _iteratorError = err;
3769
+ return [
3770
+ 3,
3771
+ 12
3772
+ ];
3773
+ case 7:
3774
+ _state.trys.push([
3775
+ 7,
3776
+ ,
3777
+ 10,
3778
+ 11
3779
+ ]);
3780
+ if (!(_iteratorAbruptCompletion && _iterator.return != null)) return [
3781
+ 3,
3782
+ 9
3783
+ ];
3784
+ return [
3785
+ 4,
3786
+ _iterator.return()
3787
+ ];
3788
+ case 8:
3789
+ _state.sent();
3790
+ _state.label = 9;
3791
+ case 9:
3792
+ return [
3793
+ 3,
3794
+ 11
3795
+ ];
3796
+ case 10:
3797
+ if (_didIteratorError) {
3798
+ throw _iteratorError;
3799
+ }
3800
+ return [
3801
+ 7
3802
+ ];
3803
+ case 11:
3804
+ return [
3805
+ 7
3806
+ ];
3807
+ case 12:
3808
+ expect(finalState).toMatchObject({
3809
+ count: 2,
3810
+ metadata: {
3811
+ created: expect.any(String),
3812
+ updated: expect.any(String)
3813
+ }
3814
+ });
3815
+ return [
3816
+ 2
3817
+ ];
3818
+ }
3819
+ });
3820
+ })();
3821
+ });
3822
+ it('should correctly infer prompt response types in subsequent steps', function() {
3823
+ return _async_to_generator(function() {
3824
+ var testBrain, finalState, _iteratorAbruptCompletion, _didIteratorError, _iteratorError, _iterator, _step, _value, event, err;
3825
+ return _ts_generator(this, function(_state) {
3826
+ switch(_state.label){
3827
+ case 0:
3828
+ testBrain = brain('Prompt Type Test').prompt('Get user info', {
3829
+ template: function() {
3830
+ return "What is the user's info?";
3831
+ },
3832
+ outputSchema: {
3833
+ schema: z.object({
3834
+ name: z.string(),
3835
+ age: z.number()
3836
+ }),
3837
+ name: 'userInfo'
3838
+ }
3839
+ }).step('Use response', function(param) {
3840
+ var state = param.state;
3841
+ var _stateAssert = true;
3842
+ return _object_spread_props(_object_spread({}, state), {
3843
+ greeting: "Hello ".concat(state.userInfo.name, ", you are ").concat(state.userInfo.age, " years old")
3844
+ });
3845
+ });
3846
+ // Mock the client response
3847
+ mockClient.generateObject.mockResolvedValueOnce({
3848
+ name: 'Test User',
3849
+ age: 30
3850
+ });
3851
+ // Run brain and collect final state
3852
+ finalState = {};
3853
+ _iteratorAbruptCompletion = false, _didIteratorError = false;
3854
+ _state.label = 1;
3855
+ case 1:
3856
+ _state.trys.push([
3857
+ 1,
3858
+ 6,
3859
+ 7,
3860
+ 12
3861
+ ]);
3862
+ _iterator = _async_iterator(testBrain.run({
3863
+ client: mockClient
3864
+ }));
3865
+ _state.label = 2;
3866
+ case 2:
3867
+ return [
3868
+ 4,
3869
+ _iterator.next()
3870
+ ];
3871
+ case 3:
3872
+ if (!(_iteratorAbruptCompletion = !(_step = _state.sent()).done)) return [
3873
+ 3,
3874
+ 5
3875
+ ];
3876
+ _value = _step.value;
3877
+ event = _value;
3878
+ if (event.type === BRAIN_EVENTS.STEP_COMPLETE) {
3879
+ finalState = applyPatches(finalState, [
3880
+ event.patch
3881
+ ]);
3882
+ }
3883
+ _state.label = 4;
3884
+ case 4:
3885
+ _iteratorAbruptCompletion = false;
3886
+ return [
3887
+ 3,
3888
+ 2
3889
+ ];
3890
+ case 5:
3891
+ return [
3892
+ 3,
3893
+ 12
3894
+ ];
3895
+ case 6:
3896
+ err = _state.sent();
3897
+ _didIteratorError = true;
3898
+ _iteratorError = err;
3899
+ return [
3900
+ 3,
3901
+ 12
3902
+ ];
3903
+ case 7:
3904
+ _state.trys.push([
3905
+ 7,
3906
+ ,
3907
+ 10,
3908
+ 11
3909
+ ]);
3910
+ if (!(_iteratorAbruptCompletion && _iterator.return != null)) return [
3911
+ 3,
3912
+ 9
3913
+ ];
3914
+ return [
3915
+ 4,
3916
+ _iterator.return()
3917
+ ];
3918
+ case 8:
3919
+ _state.sent();
3920
+ _state.label = 9;
3921
+ case 9:
3922
+ return [
3923
+ 3,
3924
+ 11
3925
+ ];
3926
+ case 10:
3927
+ if (_didIteratorError) {
3928
+ throw _iteratorError;
3929
+ }
3930
+ return [
3931
+ 7
3932
+ ];
3933
+ case 11:
3934
+ return [
3935
+ 7
3936
+ ];
3937
+ case 12:
3938
+ // Verify the brain executed correctly
3939
+ expect(finalState).toEqual({
3940
+ userInfo: {
3941
+ name: 'Test User',
3942
+ age: 30
3943
+ },
3944
+ greeting: 'Hello Test User, you are 30 years old'
3945
+ });
3946
+ return [
3947
+ 2
3948
+ ];
3949
+ }
3950
+ });
3951
+ })();
3952
+ });
3953
+ it('should correctly handle prompt reduce function', function() {
3954
+ return _async_to_generator(function() {
3955
+ var testBrain, finalState, _iteratorAbruptCompletion, _didIteratorError, _iteratorError, _iterator, _step, _value, event, err, _typeAssert;
3956
+ return _ts_generator(this, function(_state) {
3957
+ switch(_state.label){
3958
+ case 0:
3959
+ testBrain = brain('Prompt Reduce Test').prompt('Get numbers', {
3960
+ template: function() {
3961
+ return 'Give me some numbers';
3962
+ },
3963
+ outputSchema: {
3964
+ schema: z.object({
3965
+ numbers: z.array(z.number())
3966
+ }),
3967
+ name: 'numbersResponse'
3968
+ }
3969
+ }, function(param) {
3970
+ var state = param.state, response = param.response, options = param.options;
3971
+ return _object_spread_props(_object_spread({}, state), {
3972
+ numbersResponse: response,
3973
+ sum: response.numbers.reduce(function(a, b) {
3974
+ return a + b;
3975
+ }, 0),
3976
+ count: response.numbers.length
3977
+ });
3978
+ });
3979
+ // Mock the client response
3980
+ mockClient.generateObject.mockResolvedValueOnce({
3981
+ numbers: [
3982
+ 1,
3983
+ 2,
3984
+ 3,
3985
+ 4,
3986
+ 5
3987
+ ]
3988
+ });
3989
+ // Run brain and collect final state
3990
+ finalState = {};
3991
+ _iteratorAbruptCompletion = false, _didIteratorError = false;
3992
+ _state.label = 1;
3993
+ case 1:
3994
+ _state.trys.push([
3995
+ 1,
3996
+ 6,
3997
+ 7,
3998
+ 12
3999
+ ]);
4000
+ _iterator = _async_iterator(testBrain.run({
4001
+ client: mockClient
4002
+ }));
4003
+ _state.label = 2;
4004
+ case 2:
4005
+ return [
4006
+ 4,
4007
+ _iterator.next()
4008
+ ];
4009
+ case 3:
4010
+ if (!(_iteratorAbruptCompletion = !(_step = _state.sent()).done)) return [
4011
+ 3,
4012
+ 5
4013
+ ];
4014
+ _value = _step.value;
4015
+ event = _value;
4016
+ if (event.type === BRAIN_EVENTS.STEP_COMPLETE) {
4017
+ finalState = applyPatches(finalState, [
4018
+ event.patch
4019
+ ]);
4020
+ }
4021
+ _state.label = 4;
4022
+ case 4:
4023
+ _iteratorAbruptCompletion = false;
4024
+ return [
4025
+ 3,
4026
+ 2
4027
+ ];
4028
+ case 5:
4029
+ return [
4030
+ 3,
4031
+ 12
4032
+ ];
4033
+ case 6:
4034
+ err = _state.sent();
4035
+ _didIteratorError = true;
4036
+ _iteratorError = err;
4037
+ return [
4038
+ 3,
4039
+ 12
4040
+ ];
4041
+ case 7:
4042
+ _state.trys.push([
4043
+ 7,
4044
+ ,
4045
+ 10,
4046
+ 11
4047
+ ]);
4048
+ if (!(_iteratorAbruptCompletion && _iterator.return != null)) return [
4049
+ 3,
4050
+ 9
4051
+ ];
4052
+ return [
4053
+ 4,
4054
+ _iterator.return()
4055
+ ];
4056
+ case 8:
4057
+ _state.sent();
4058
+ _state.label = 9;
4059
+ case 9:
4060
+ return [
4061
+ 3,
4062
+ 11
4063
+ ];
4064
+ case 10:
4065
+ if (_didIteratorError) {
4066
+ throw _iteratorError;
4067
+ }
4068
+ return [
4069
+ 7
4070
+ ];
4071
+ case 11:
4072
+ return [
4073
+ 7
4074
+ ];
4075
+ case 12:
4076
+ // Verify the brain executed correctly with reduced state
4077
+ expect(finalState).toEqual({
4078
+ numbersResponse: {
4079
+ numbers: [
4080
+ 1,
4081
+ 2,
4082
+ 3,
4083
+ 4,
4084
+ 5
4085
+ ]
4086
+ },
4087
+ sum: 15,
4088
+ count: 5
4089
+ });
4090
+ _typeAssert = true;
4091
+ return [
4092
+ 2
4093
+ ];
4094
+ }
4095
+ });
4096
+ })();
4097
+ });
4098
+ });
4099
+ describe('brain structure', function() {
4100
+ it('should expose brain structure with steps', function() {
4101
+ var testBrain = brain({
4102
+ title: 'Test Brain',
4103
+ description: 'A test brain description'
4104
+ }).step('First step', function(param) {
4105
+ var state = param.state;
4106
+ return _object_spread_props(_object_spread({}, state), {
4107
+ step1: true
4108
+ });
4109
+ }).step('Second step', function(param) {
4110
+ var state = param.state;
4111
+ return _object_spread_props(_object_spread({}, state), {
4112
+ step2: true
4113
+ });
4114
+ }).step('Third step', function(param) {
4115
+ var state = param.state;
4116
+ return _object_spread_props(_object_spread({}, state), {
4117
+ step3: true
4118
+ });
4119
+ });
4120
+ var structure = testBrain.structure;
4121
+ expect(structure).toEqual({
4122
+ title: 'Test Brain',
4123
+ description: 'A test brain description',
4124
+ steps: [
4125
+ {
4126
+ type: 'step',
4127
+ title: 'First step'
4128
+ },
4129
+ {
4130
+ type: 'step',
4131
+ title: 'Second step'
4132
+ },
4133
+ {
4134
+ type: 'step',
4135
+ title: 'Third step'
4136
+ }
4137
+ ]
4138
+ });
4139
+ });
4140
+ it('should expose nested brain structure recursively', function() {
4141
+ var innerBrain = brain({
4142
+ title: 'Inner Brain',
4143
+ description: 'An inner brain'
4144
+ }).step('Inner step 1', function(param) {
4145
+ var state = param.state;
4146
+ return _object_spread_props(_object_spread({}, state), {
4147
+ inner1: true
4148
+ });
4149
+ }).step('Inner step 2', function(param) {
4150
+ var state = param.state;
4151
+ return _object_spread_props(_object_spread({}, state), {
4152
+ inner2: true
4153
+ });
4154
+ });
4155
+ var outerBrain = brain({
4156
+ title: 'Outer Brain',
4157
+ description: 'An outer brain'
4158
+ }).step('Outer step 1', function(param) {
4159
+ var state = param.state;
4160
+ return _object_spread_props(_object_spread({}, state), {
4161
+ outer1: true
4162
+ });
4163
+ }).brain('Run inner brain', innerBrain, function(param) {
4164
+ var brainState = param.brainState;
4165
+ return {
4166
+ result: brainState
4167
+ };
4168
+ }).step('Outer step 2', function(param) {
4169
+ var state = param.state;
4170
+ return _object_spread_props(_object_spread({}, state), {
4171
+ outer2: true
4172
+ });
4173
+ });
4174
+ var structure = outerBrain.structure;
4175
+ expect(structure).toEqual({
4176
+ title: 'Outer Brain',
4177
+ description: 'An outer brain',
4178
+ steps: [
4179
+ {
4180
+ type: 'step',
4181
+ title: 'Outer step 1'
4182
+ },
4183
+ {
4184
+ type: 'brain',
4185
+ title: 'Run inner brain',
4186
+ innerBrain: {
4187
+ title: 'Inner Brain',
4188
+ description: 'An inner brain',
4189
+ steps: [
4190
+ {
4191
+ type: 'step',
4192
+ title: 'Inner step 1'
4193
+ },
4194
+ {
4195
+ type: 'step',
4196
+ title: 'Inner step 2'
4197
+ }
4198
+ ]
4199
+ }
4200
+ },
4201
+ {
4202
+ type: 'step',
4203
+ title: 'Outer step 2'
4204
+ }
4205
+ ]
4206
+ });
4207
+ });
4208
+ it('should handle brain without description', function() {
4209
+ var testBrain = brain('No Description Brain').step('Only step', function(param) {
4210
+ var state = param.state;
4211
+ return state;
4212
+ });
4213
+ var structure = testBrain.structure;
4214
+ expect(structure).toEqual({
4215
+ title: 'No Description Brain',
4216
+ description: undefined,
4217
+ steps: [
4218
+ {
4219
+ type: 'step',
4220
+ title: 'Only step'
4221
+ }
4222
+ ]
4223
+ });
4224
+ });
4225
+ });