@mastra/inngest 0.10.5 → 0.10.6-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +7 -7
- package/CHANGELOG.md +10 -0
- package/dist/_tsup-dts-rollup.d.cts +45 -15
- package/dist/_tsup-dts-rollup.d.ts +45 -15
- package/dist/index.cjs +182 -18
- package/dist/index.js +182 -18
- package/package.json +4 -4
- package/src/index.test.ts +1316 -78
- package/src/index.ts +250 -25
package/src/index.test.ts
CHANGED
|
@@ -5,10 +5,12 @@ import { openai } from '@ai-sdk/openai';
|
|
|
5
5
|
import { serve } from '@hono/node-server';
|
|
6
6
|
import { realtimeMiddleware } from '@inngest/realtime';
|
|
7
7
|
import { createTool, Mastra, Telemetry } from '@mastra/core';
|
|
8
|
+
import type { StreamEvent } from '@mastra/core';
|
|
8
9
|
import { Agent } from '@mastra/core/agent';
|
|
9
10
|
import { RuntimeContext } from '@mastra/core/runtime-context';
|
|
10
11
|
import { createHonoServer } from '@mastra/deployer/server';
|
|
11
12
|
import { DefaultStorage } from '@mastra/libsql';
|
|
13
|
+
import { MockLanguageModelV1, simulateReadableStream } from 'ai/test';
|
|
12
14
|
import { $ } from 'execa';
|
|
13
15
|
import getPort from 'get-port';
|
|
14
16
|
import { Inngest } from 'inngest';
|
|
@@ -33,13 +35,15 @@ describe('MastraInngestWorkflow', () => {
|
|
|
33
35
|
ctx.inngestPort = inngestPort;
|
|
34
36
|
ctx.handlerPort = handlerPort;
|
|
35
37
|
ctx.containerName = containerName;
|
|
38
|
+
|
|
39
|
+
vi.restoreAllMocks();
|
|
36
40
|
});
|
|
37
41
|
|
|
38
42
|
afterEach<LocalTestContext>(async ctx => {
|
|
39
43
|
await $`docker stop ${ctx.containerName}`;
|
|
40
44
|
});
|
|
41
45
|
|
|
42
|
-
describe('Basic Workflow Execution', () => {
|
|
46
|
+
describe.sequential('Basic Workflow Execution', () => {
|
|
43
47
|
it('should execute a single step workflow successfully', async ctx => {
|
|
44
48
|
const inngest = new Inngest({
|
|
45
49
|
id: 'mastra',
|
|
@@ -95,7 +99,7 @@ describe('MastraInngestWorkflow', () => {
|
|
|
95
99
|
const result = await run.start({ inputData: {} });
|
|
96
100
|
|
|
97
101
|
expect(execute).toHaveBeenCalled();
|
|
98
|
-
expect(result.steps['step1']).
|
|
102
|
+
expect(result.steps['step1']).toMatchObject({
|
|
99
103
|
status: 'success',
|
|
100
104
|
output: { result: 'success' },
|
|
101
105
|
});
|
|
@@ -171,7 +175,7 @@ describe('MastraInngestWorkflow', () => {
|
|
|
171
175
|
|
|
172
176
|
expect(step1Action).toHaveBeenCalled();
|
|
173
177
|
expect(step2Action).toHaveBeenCalled();
|
|
174
|
-
expect(result.steps).
|
|
178
|
+
expect(result.steps).toMatchObject({
|
|
175
179
|
input: {},
|
|
176
180
|
step1: { status: 'success', output: { value: 'step1' } },
|
|
177
181
|
step2: { status: 'success', output: { value: 'step2' } },
|
|
@@ -250,8 +254,8 @@ describe('MastraInngestWorkflow', () => {
|
|
|
250
254
|
const run = workflow.createRun();
|
|
251
255
|
const result = await run.start({ inputData: {} });
|
|
252
256
|
|
|
253
|
-
expect(executionOrder).
|
|
254
|
-
expect(result.steps).
|
|
257
|
+
expect(executionOrder).toMatchObject(['step1', 'step2']);
|
|
258
|
+
expect(result.steps).toMatchObject({
|
|
255
259
|
input: {},
|
|
256
260
|
step1: { status: 'success', output: { value: 'step1' } },
|
|
257
261
|
step2: { status: 'success', output: { value: 'step2' } },
|
|
@@ -327,7 +331,7 @@ describe('MastraInngestWorkflow', () => {
|
|
|
327
331
|
const endTime = Date.now();
|
|
328
332
|
|
|
329
333
|
expect(execute).toHaveBeenCalled();
|
|
330
|
-
expect(result.steps['step1']).
|
|
334
|
+
expect(result.steps['step1']).toMatchObject({
|
|
331
335
|
status: 'success',
|
|
332
336
|
output: { result: 'success' },
|
|
333
337
|
// payload: {},
|
|
@@ -335,7 +339,7 @@ describe('MastraInngestWorkflow', () => {
|
|
|
335
339
|
// endedAt: expect.any(Number),
|
|
336
340
|
});
|
|
337
341
|
|
|
338
|
-
expect(result.steps['step2']).
|
|
342
|
+
expect(result.steps['step2']).toMatchObject({
|
|
339
343
|
status: 'success',
|
|
340
344
|
output: { result: 'slept successfully: success' },
|
|
341
345
|
// payload: { result: 'success' },
|
|
@@ -419,7 +423,7 @@ describe('MastraInngestWorkflow', () => {
|
|
|
419
423
|
const endTime = Date.now();
|
|
420
424
|
|
|
421
425
|
expect(execute).toHaveBeenCalled();
|
|
422
|
-
expect(result.steps['step1']).
|
|
426
|
+
expect(result.steps['step1']).toMatchObject({
|
|
423
427
|
status: 'success',
|
|
424
428
|
output: { result: 'success' },
|
|
425
429
|
// payload: {},
|
|
@@ -427,7 +431,7 @@ describe('MastraInngestWorkflow', () => {
|
|
|
427
431
|
// endedAt: expect.any(Number),
|
|
428
432
|
});
|
|
429
433
|
|
|
430
|
-
expect(result.steps['step2']).
|
|
434
|
+
expect(result.steps['step2']).toMatchObject({
|
|
431
435
|
status: 'success',
|
|
432
436
|
output: { result: 'slept successfully: success' },
|
|
433
437
|
// payload: { result: 'success' },
|
|
@@ -439,6 +443,190 @@ describe('MastraInngestWorkflow', () => {
|
|
|
439
443
|
|
|
440
444
|
srv.close();
|
|
441
445
|
});
|
|
446
|
+
|
|
447
|
+
it('should execute a a waitForEvent step', async ctx => {
|
|
448
|
+
const inngest = new Inngest({
|
|
449
|
+
id: 'mastra',
|
|
450
|
+
baseUrl: `http://localhost:${(ctx as any).inngestPort}`,
|
|
451
|
+
});
|
|
452
|
+
|
|
453
|
+
const { createWorkflow, createStep } = init(inngest);
|
|
454
|
+
|
|
455
|
+
const execute = vi.fn<any>().mockResolvedValue({ result: 'success' });
|
|
456
|
+
const step1 = createStep({
|
|
457
|
+
id: 'step1',
|
|
458
|
+
execute,
|
|
459
|
+
inputSchema: z.object({}),
|
|
460
|
+
outputSchema: z.object({ result: z.string() }),
|
|
461
|
+
});
|
|
462
|
+
const step2 = createStep({
|
|
463
|
+
id: 'step2',
|
|
464
|
+
execute: async ({ inputData, resumeData }) => {
|
|
465
|
+
return { result: inputData.result, resumed: resumeData };
|
|
466
|
+
},
|
|
467
|
+
inputSchema: z.object({ result: z.string() }),
|
|
468
|
+
outputSchema: z.object({ result: z.string(), resumed: z.any() }),
|
|
469
|
+
resumeSchema: z.any(),
|
|
470
|
+
});
|
|
471
|
+
|
|
472
|
+
const workflow = createWorkflow({
|
|
473
|
+
id: 'test-workflow',
|
|
474
|
+
inputSchema: z.object({}),
|
|
475
|
+
outputSchema: z.object({
|
|
476
|
+
result: z.string(),
|
|
477
|
+
resumed: z.any(),
|
|
478
|
+
}),
|
|
479
|
+
steps: [step1],
|
|
480
|
+
});
|
|
481
|
+
|
|
482
|
+
workflow.then(step1).waitForEvent('hello-event', step2).commit();
|
|
483
|
+
|
|
484
|
+
const mastra = new Mastra({
|
|
485
|
+
storage: new DefaultStorage({
|
|
486
|
+
url: ':memory:',
|
|
487
|
+
}),
|
|
488
|
+
workflows: {
|
|
489
|
+
'test-workflow': workflow,
|
|
490
|
+
},
|
|
491
|
+
server: {
|
|
492
|
+
apiRoutes: [
|
|
493
|
+
{
|
|
494
|
+
path: '/inngest/api',
|
|
495
|
+
method: 'ALL',
|
|
496
|
+
createHandler: async ({ mastra }) => inngestServe({ mastra, inngest }),
|
|
497
|
+
},
|
|
498
|
+
],
|
|
499
|
+
},
|
|
500
|
+
});
|
|
501
|
+
|
|
502
|
+
const app = await createHonoServer(mastra);
|
|
503
|
+
|
|
504
|
+
const srv = serve({
|
|
505
|
+
fetch: app.fetch,
|
|
506
|
+
port: (ctx as any).handlerPort,
|
|
507
|
+
});
|
|
508
|
+
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
509
|
+
|
|
510
|
+
const run = workflow.createRun();
|
|
511
|
+
const startTime = Date.now();
|
|
512
|
+
setTimeout(() => {
|
|
513
|
+
run.sendEvent('hello-event', { data: 'hello' });
|
|
514
|
+
}, 1000);
|
|
515
|
+
const result = await run.start({ inputData: {} });
|
|
516
|
+
const endTime = Date.now();
|
|
517
|
+
|
|
518
|
+
expect(execute).toHaveBeenCalled();
|
|
519
|
+
expect(result.steps['step1']).toMatchObject({
|
|
520
|
+
status: 'success',
|
|
521
|
+
output: { result: 'success' },
|
|
522
|
+
// payload: {},
|
|
523
|
+
// startedAt: expect.any(Number),
|
|
524
|
+
// endedAt: expect.any(Number),
|
|
525
|
+
});
|
|
526
|
+
|
|
527
|
+
expect(result.steps['step2']).toMatchObject({
|
|
528
|
+
status: 'success',
|
|
529
|
+
output: { result: 'success', resumed: { data: 'hello' } },
|
|
530
|
+
payload: { result: 'success' },
|
|
531
|
+
// resumePayload: { data: 'hello' },
|
|
532
|
+
startedAt: expect.any(Number),
|
|
533
|
+
endedAt: expect.any(Number),
|
|
534
|
+
});
|
|
535
|
+
|
|
536
|
+
expect(endTime - startTime).toBeGreaterThan(1000);
|
|
537
|
+
|
|
538
|
+
srv.close();
|
|
539
|
+
});
|
|
540
|
+
|
|
541
|
+
it('should execute a a waitForEvent step after timeout', async ctx => {
|
|
542
|
+
const inngest = new Inngest({
|
|
543
|
+
id: 'mastra',
|
|
544
|
+
baseUrl: `http://localhost:${(ctx as any).inngestPort}`,
|
|
545
|
+
});
|
|
546
|
+
|
|
547
|
+
const { createWorkflow, createStep } = init(inngest);
|
|
548
|
+
|
|
549
|
+
const execute = vi.fn<any>().mockResolvedValue({ result: 'success' });
|
|
550
|
+
const step1 = createStep({
|
|
551
|
+
id: 'step1',
|
|
552
|
+
execute,
|
|
553
|
+
inputSchema: z.object({}),
|
|
554
|
+
outputSchema: z.object({ result: z.string() }),
|
|
555
|
+
});
|
|
556
|
+
const step2 = createStep({
|
|
557
|
+
id: 'step2',
|
|
558
|
+
execute: async ({ inputData, resumeData }) => {
|
|
559
|
+
return { result: inputData.result, resumed: resumeData };
|
|
560
|
+
},
|
|
561
|
+
inputSchema: z.object({ result: z.string() }),
|
|
562
|
+
outputSchema: z.object({ result: z.string(), resumed: z.any() }),
|
|
563
|
+
resumeSchema: z.any(),
|
|
564
|
+
});
|
|
565
|
+
|
|
566
|
+
const workflow = createWorkflow({
|
|
567
|
+
id: 'test-workflow',
|
|
568
|
+
inputSchema: z.object({}),
|
|
569
|
+
outputSchema: z.object({
|
|
570
|
+
result: z.string(),
|
|
571
|
+
resumed: z.any(),
|
|
572
|
+
}),
|
|
573
|
+
steps: [step1],
|
|
574
|
+
});
|
|
575
|
+
|
|
576
|
+
workflow.then(step1).waitForEvent('hello-event', step2, { timeout: 1000 }).commit();
|
|
577
|
+
|
|
578
|
+
const mastra = new Mastra({
|
|
579
|
+
storage: new DefaultStorage({
|
|
580
|
+
url: ':memory:',
|
|
581
|
+
}),
|
|
582
|
+
workflows: {
|
|
583
|
+
'test-workflow': workflow,
|
|
584
|
+
},
|
|
585
|
+
server: {
|
|
586
|
+
apiRoutes: [
|
|
587
|
+
{
|
|
588
|
+
path: '/inngest/api',
|
|
589
|
+
method: 'ALL',
|
|
590
|
+
createHandler: async ({ mastra }) => inngestServe({ mastra, inngest }),
|
|
591
|
+
},
|
|
592
|
+
],
|
|
593
|
+
},
|
|
594
|
+
});
|
|
595
|
+
|
|
596
|
+
const app = await createHonoServer(mastra);
|
|
597
|
+
|
|
598
|
+
const srv = serve({
|
|
599
|
+
fetch: app.fetch,
|
|
600
|
+
port: (ctx as any).handlerPort,
|
|
601
|
+
});
|
|
602
|
+
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
603
|
+
|
|
604
|
+
const run = workflow.createRun();
|
|
605
|
+
const startTime = Date.now();
|
|
606
|
+
const result = await run.start({ inputData: {} });
|
|
607
|
+
const endTime = Date.now();
|
|
608
|
+
|
|
609
|
+
expect(execute).toHaveBeenCalled();
|
|
610
|
+
expect(result.steps['step1']).toMatchObject({
|
|
611
|
+
status: 'success',
|
|
612
|
+
output: { result: 'success' },
|
|
613
|
+
// payload: {},
|
|
614
|
+
// startedAt: expect.any(Number),
|
|
615
|
+
// endedAt: expect.any(Number),
|
|
616
|
+
});
|
|
617
|
+
|
|
618
|
+
expect(result.steps['step2']).toMatchObject({
|
|
619
|
+
status: 'failed',
|
|
620
|
+
error: expect.any(String),
|
|
621
|
+
payload: { result: 'success' },
|
|
622
|
+
startedAt: expect.any(Number),
|
|
623
|
+
endedAt: expect.any(Number),
|
|
624
|
+
});
|
|
625
|
+
|
|
626
|
+
expect(endTime - startTime).toBeGreaterThan(1000);
|
|
627
|
+
|
|
628
|
+
srv.close();
|
|
629
|
+
});
|
|
442
630
|
});
|
|
443
631
|
|
|
444
632
|
describe('Variable Resolution', () => {
|
|
@@ -501,8 +689,8 @@ describe('MastraInngestWorkflow', () => {
|
|
|
501
689
|
const run = workflow.createRun();
|
|
502
690
|
const result = await run.start({ inputData: { inputData: 'test-input' } });
|
|
503
691
|
|
|
504
|
-
expect(result.steps.step1).
|
|
505
|
-
expect(result.steps.step2).
|
|
692
|
+
expect(result.steps.step1).toMatchObject({ status: 'success', output: { result: 'success' } });
|
|
693
|
+
expect(result.steps.step2).toMatchObject({ status: 'success', output: { result: 'success' } });
|
|
506
694
|
|
|
507
695
|
srv.close();
|
|
508
696
|
});
|
|
@@ -517,14 +705,14 @@ describe('MastraInngestWorkflow', () => {
|
|
|
517
705
|
|
|
518
706
|
const step1Action = vi.fn().mockImplementation(async ({ inputData }) => {
|
|
519
707
|
// Test accessing trigger data with correct type
|
|
520
|
-
expect(inputData).
|
|
708
|
+
expect(inputData).toMatchObject({ inputValue: 'test-input' });
|
|
521
709
|
return { value: 'step1-result' };
|
|
522
710
|
});
|
|
523
711
|
|
|
524
712
|
const step2Action = vi.fn().mockImplementation(async ({ getStepResult }) => {
|
|
525
713
|
// Test accessing previous step result with type
|
|
526
714
|
const step1Result = getStepResult(step1);
|
|
527
|
-
expect(step1Result).
|
|
715
|
+
expect(step1Result).toMatchObject({ value: 'step1-result' });
|
|
528
716
|
|
|
529
717
|
const failedStep = getStepResult(nonExecutedStep);
|
|
530
718
|
expect(failedStep).toBe(null);
|
|
@@ -590,7 +778,7 @@ describe('MastraInngestWorkflow', () => {
|
|
|
590
778
|
|
|
591
779
|
expect(step1Action).toHaveBeenCalled();
|
|
592
780
|
expect(step2Action).toHaveBeenCalled();
|
|
593
|
-
expect(result.steps).
|
|
781
|
+
expect(result.steps).toMatchObject({
|
|
594
782
|
input: { inputValue: 'test-input' },
|
|
595
783
|
step1: { status: 'success', output: { value: 'step1-result' } },
|
|
596
784
|
step2: { status: 'success', output: { value: 'step2-result' } },
|
|
@@ -736,7 +924,7 @@ describe('MastraInngestWorkflow', () => {
|
|
|
736
924
|
}),
|
|
737
925
|
);
|
|
738
926
|
|
|
739
|
-
expect(result.steps.step2).
|
|
927
|
+
expect(result.steps.step2).toMatchObject({ status: 'success', output: { result: { cool: 'test-input' } } });
|
|
740
928
|
|
|
741
929
|
srv.close();
|
|
742
930
|
});
|
|
@@ -919,7 +1107,7 @@ describe('MastraInngestWorkflow', () => {
|
|
|
919
1107
|
expect(step1Action).toHaveBeenCalled();
|
|
920
1108
|
expect(step2Action).toHaveBeenCalled();
|
|
921
1109
|
expect(step3Action).not.toHaveBeenCalled();
|
|
922
|
-
expect(result.steps).
|
|
1110
|
+
expect(result.steps).toMatchObject({
|
|
923
1111
|
input: { status: 'success' },
|
|
924
1112
|
step1: { status: 'success', output: { status: 'success' } },
|
|
925
1113
|
step2: { status: 'success', output: { result: 'step2' } },
|
|
@@ -1000,7 +1188,7 @@ describe('MastraInngestWorkflow', () => {
|
|
|
1000
1188
|
|
|
1001
1189
|
expect(step1Action).toHaveBeenCalled();
|
|
1002
1190
|
expect(step2Action).not.toHaveBeenCalled();
|
|
1003
|
-
expect(result?.steps).
|
|
1191
|
+
expect(result?.steps).toMatchObject({
|
|
1004
1192
|
input: {},
|
|
1005
1193
|
step1: { status: 'failed', error: 'Failed' },
|
|
1006
1194
|
});
|
|
@@ -1181,13 +1369,12 @@ describe('MastraInngestWorkflow', () => {
|
|
|
1181
1369
|
srv.close();
|
|
1182
1370
|
|
|
1183
1371
|
expect(step2Action).toHaveBeenCalled();
|
|
1184
|
-
expect(result.steps.step1).
|
|
1372
|
+
expect(result.steps.step1).toMatchObject({
|
|
1185
1373
|
status: 'success',
|
|
1186
1374
|
output: { count: 5 },
|
|
1187
1375
|
});
|
|
1188
|
-
expect(result.steps.step2).
|
|
1376
|
+
expect(result.steps.step2).toMatchObject({
|
|
1189
1377
|
status: 'success',
|
|
1190
|
-
output: undefined,
|
|
1191
1378
|
});
|
|
1192
1379
|
});
|
|
1193
1380
|
});
|
|
@@ -1556,7 +1743,7 @@ describe('MastraInngestWorkflow', () => {
|
|
|
1556
1743
|
|
|
1557
1744
|
expect(step2Action).toHaveBeenCalled();
|
|
1558
1745
|
expect(step3Action).not.toHaveBeenCalled();
|
|
1559
|
-
expect(result.steps.step2).
|
|
1746
|
+
expect(result.steps.step2).toMatchObject({ status: 'success', output: { result: 'step2' } });
|
|
1560
1747
|
|
|
1561
1748
|
srv.close();
|
|
1562
1749
|
});
|
|
@@ -1659,9 +1846,9 @@ describe('MastraInngestWorkflow', () => {
|
|
|
1659
1846
|
expect(increment).toHaveBeenCalledTimes(12);
|
|
1660
1847
|
expect(final).toHaveBeenCalledTimes(1);
|
|
1661
1848
|
// @ts-ignore
|
|
1662
|
-
expect(result.result).
|
|
1849
|
+
expect(result.result).toMatchObject({ finalValue: 12 });
|
|
1663
1850
|
// @ts-ignore
|
|
1664
|
-
expect(result.steps.increment.output).
|
|
1851
|
+
expect(result.steps.increment.output).toMatchObject({ value: 12 });
|
|
1665
1852
|
|
|
1666
1853
|
srv.close();
|
|
1667
1854
|
});
|
|
@@ -1762,9 +1949,9 @@ describe('MastraInngestWorkflow', () => {
|
|
|
1762
1949
|
expect(increment).toHaveBeenCalledTimes(12);
|
|
1763
1950
|
expect(final).toHaveBeenCalledTimes(1);
|
|
1764
1951
|
// @ts-ignore
|
|
1765
|
-
expect(result.result).
|
|
1952
|
+
expect(result.result).toMatchObject({ finalValue: 12 });
|
|
1766
1953
|
// @ts-ignore
|
|
1767
|
-
expect(result.steps.increment.output).
|
|
1954
|
+
expect(result.steps.increment.output).toMatchObject({ value: 12 });
|
|
1768
1955
|
|
|
1769
1956
|
srv.close();
|
|
1770
1957
|
});
|
|
@@ -1853,7 +2040,7 @@ describe('MastraInngestWorkflow', () => {
|
|
|
1853
2040
|
expect(duration).toBeGreaterThan(1e3 * 3);
|
|
1854
2041
|
|
|
1855
2042
|
expect(map).toHaveBeenCalledTimes(3);
|
|
1856
|
-
expect(result.steps).
|
|
2043
|
+
expect(result.steps).toMatchObject({
|
|
1857
2044
|
input: [{ value: 1 }, { value: 22 }, { value: 333 }],
|
|
1858
2045
|
map: { status: 'success', output: [{ value: 12 }, { value: 33 }, { value: 344 }] },
|
|
1859
2046
|
final: { status: 'success', output: { finalValue: 1 + 11 + (22 + 11) + (333 + 11) } },
|
|
@@ -2005,9 +2192,9 @@ describe('MastraInngestWorkflow', () => {
|
|
|
2005
2192
|
expect(other).toHaveBeenCalledTimes(0);
|
|
2006
2193
|
expect(final).toHaveBeenCalledTimes(1);
|
|
2007
2194
|
// @ts-ignore
|
|
2008
|
-
expect(result.steps.finalIf.output).
|
|
2195
|
+
expect(result.steps.finalIf.output).toMatchObject({ finalValue: 2 });
|
|
2009
2196
|
// @ts-ignore
|
|
2010
|
-
expect(result.steps.start.output).
|
|
2197
|
+
expect(result.steps.start.output).toMatchObject({ newValue: 2 });
|
|
2011
2198
|
|
|
2012
2199
|
srv.close();
|
|
2013
2200
|
});
|
|
@@ -2154,9 +2341,9 @@ describe('MastraInngestWorkflow', () => {
|
|
|
2154
2341
|
expect(other).toHaveBeenCalledTimes(1);
|
|
2155
2342
|
expect(final).toHaveBeenCalledTimes(1);
|
|
2156
2343
|
// @ts-ignore
|
|
2157
|
-
expect(result.steps['else-branch'].output).
|
|
2344
|
+
expect(result.steps['else-branch'].output).toMatchObject({ finalValue: 26 + 6 + 1 });
|
|
2158
2345
|
// @ts-ignore
|
|
2159
|
-
expect(result.steps.start.output).
|
|
2346
|
+
expect(result.steps.start.output).toMatchObject({ newValue: 7 });
|
|
2160
2347
|
|
|
2161
2348
|
srv.close();
|
|
2162
2349
|
});
|
|
@@ -2322,8 +2509,8 @@ describe('MastraInngestWorkflow', () => {
|
|
|
2322
2509
|
const run = workflow.createRun();
|
|
2323
2510
|
const result = await run.start({ inputData: {} });
|
|
2324
2511
|
|
|
2325
|
-
expect(result.steps['nested-a']).
|
|
2326
|
-
expect(result.steps['nested-b']).
|
|
2512
|
+
expect(result.steps['nested-a']).toMatchObject({ status: 'success', output: { result: 'success3' } });
|
|
2513
|
+
expect(result.steps['nested-b']).toMatchObject({ status: 'success', output: { result: 'success5' } });
|
|
2327
2514
|
|
|
2328
2515
|
srv.close();
|
|
2329
2516
|
});
|
|
@@ -2388,8 +2575,8 @@ describe('MastraInngestWorkflow', () => {
|
|
|
2388
2575
|
const run = workflow.createRun();
|
|
2389
2576
|
const result = await run.start({ inputData: {} });
|
|
2390
2577
|
|
|
2391
|
-
expect(result.steps.step1).
|
|
2392
|
-
expect(result.steps.step2).
|
|
2578
|
+
expect(result.steps.step1).toMatchObject({ status: 'success', output: { result: 'success' } });
|
|
2579
|
+
expect(result.steps.step2).toMatchObject({ status: 'failed', error: 'Step failed' });
|
|
2393
2580
|
expect(step1.execute).toHaveBeenCalledTimes(1);
|
|
2394
2581
|
expect(step2.execute).toHaveBeenCalledTimes(1); // 0 retries + 1 initial call
|
|
2395
2582
|
|
|
@@ -2445,8 +2632,8 @@ describe('MastraInngestWorkflow', () => {
|
|
|
2445
2632
|
const run = workflow.createRun();
|
|
2446
2633
|
const result = await run.start({ inputData: {} });
|
|
2447
2634
|
|
|
2448
|
-
expect(result.steps.step1).
|
|
2449
|
-
expect(result.steps.step2).
|
|
2635
|
+
expect(result.steps.step1).toMatchObject({ status: 'success', output: { result: 'success' } });
|
|
2636
|
+
expect(result.steps.step2).toMatchObject({ status: 'failed', error: 'Step failed' });
|
|
2450
2637
|
expect(step1.execute).toHaveBeenCalledTimes(1);
|
|
2451
2638
|
expect(step2.execute).toHaveBeenCalledTimes(6); // 5 retries + 1 initial call
|
|
2452
2639
|
});
|
|
@@ -2523,8 +2710,8 @@ describe('MastraInngestWorkflow', () => {
|
|
|
2523
2710
|
|
|
2524
2711
|
expect(step1Action).toHaveBeenCalled();
|
|
2525
2712
|
expect(toolAction).toHaveBeenCalled();
|
|
2526
|
-
expect(result.steps.step1).
|
|
2527
|
-
expect(result.steps['random-tool']).
|
|
2713
|
+
expect(result.steps.step1).toMatchObject({ status: 'success', output: { name: 'step1' } });
|
|
2714
|
+
expect(result.steps['random-tool']).toMatchObject({ status: 'success', output: { name: 'step1' } });
|
|
2528
2715
|
}, 10000);
|
|
2529
2716
|
});
|
|
2530
2717
|
|
|
@@ -2703,11 +2890,11 @@ describe('MastraInngestWorkflow', () => {
|
|
|
2703
2890
|
});
|
|
2704
2891
|
|
|
2705
2892
|
// Verify execution completed successfully
|
|
2706
|
-
expect(executionResult.steps.step1).
|
|
2893
|
+
expect(executionResult.steps.step1).toMatchObject({
|
|
2707
2894
|
status: 'success',
|
|
2708
2895
|
output: { result: 'success1' },
|
|
2709
2896
|
});
|
|
2710
|
-
expect(executionResult.steps.step2).
|
|
2897
|
+
expect(executionResult.steps.step2).toMatchObject({
|
|
2711
2898
|
status: 'success',
|
|
2712
2899
|
output: { result: 'success2' },
|
|
2713
2900
|
});
|
|
@@ -2976,7 +3163,7 @@ describe('MastraInngestWorkflow', () => {
|
|
|
2976
3163
|
throw new Error('Resume failed to return a result');
|
|
2977
3164
|
}
|
|
2978
3165
|
|
|
2979
|
-
expect(resumeResult.steps).
|
|
3166
|
+
expect(resumeResult.steps).toMatchObject({
|
|
2980
3167
|
input: { input: 'test' },
|
|
2981
3168
|
getUserInput: { status: 'success', output: { userInput: 'test input' } },
|
|
2982
3169
|
promptAgent: { status: 'success', output: { modelOutput: 'test output' } },
|
|
@@ -3139,7 +3326,7 @@ describe('MastraInngestWorkflow', () => {
|
|
|
3139
3326
|
throw new Error('Resume failed to return a result');
|
|
3140
3327
|
}
|
|
3141
3328
|
|
|
3142
|
-
expect(result.steps).
|
|
3329
|
+
expect(result.steps).toMatchObject({
|
|
3143
3330
|
input: { input: 'test' },
|
|
3144
3331
|
getUserInput: { status: 'success', output: { userInput: 'test input' } },
|
|
3145
3332
|
promptAgent: { status: 'success', output: { modelOutput: 'test output' } },
|
|
@@ -3499,8 +3686,8 @@ describe('MastraInngestWorkflow', () => {
|
|
|
3499
3686
|
expect(promptAgentAction).toHaveBeenCalledTimes(1);
|
|
3500
3687
|
// expect(initialResult.activePaths.size).toBe(1);
|
|
3501
3688
|
// expect(initialResult.activePaths.get('promptAgent')?.status).toBe('suspended');
|
|
3502
|
-
// expect(initialResult.activePaths.get('promptAgent')?.suspendPayload).
|
|
3503
|
-
expect(initialResult.steps).
|
|
3689
|
+
// expect(initialResult.activePaths.get('promptAgent')?.suspendPayload).toMatchObject({ testPayload: 'hello' });
|
|
3690
|
+
expect(initialResult.steps).toMatchObject({
|
|
3504
3691
|
input: { input: 'test' },
|
|
3505
3692
|
getUserInput: { status: 'success', output: { userInput: 'test input' } },
|
|
3506
3693
|
promptAgent: { status: 'suspended', payload: { testPayload: 'hello' } },
|
|
@@ -3520,7 +3707,7 @@ describe('MastraInngestWorkflow', () => {
|
|
|
3520
3707
|
|
|
3521
3708
|
// expect(firstResumeResult.activePaths.size).toBe(1);
|
|
3522
3709
|
// expect(firstResumeResult.activePaths.get('improveResponse')?.status).toBe('suspended');
|
|
3523
|
-
expect(firstResumeResult.steps).
|
|
3710
|
+
expect(firstResumeResult.steps).toMatchObject({
|
|
3524
3711
|
input: { input: 'test' },
|
|
3525
3712
|
getUserInput: { status: 'success', output: { userInput: 'test input' } },
|
|
3526
3713
|
promptAgent: { status: 'success', output: { modelOutput: 'test output' } },
|
|
@@ -3547,7 +3734,7 @@ describe('MastraInngestWorkflow', () => {
|
|
|
3547
3734
|
|
|
3548
3735
|
expect(promptAgentAction).toHaveBeenCalledTimes(2);
|
|
3549
3736
|
|
|
3550
|
-
expect(secondResumeResult.steps).
|
|
3737
|
+
expect(secondResumeResult.steps).toMatchObject({
|
|
3551
3738
|
input: { input: 'test' },
|
|
3552
3739
|
getUserInput: { status: 'success', output: { userInput: 'test input' } },
|
|
3553
3740
|
promptAgent: { status: 'success', output: { modelOutput: 'test output' } },
|
|
@@ -3632,6 +3819,7 @@ describe('MastraInngestWorkflow', () => {
|
|
|
3632
3819
|
const inngest = new Inngest({
|
|
3633
3820
|
id: 'mastra',
|
|
3634
3821
|
baseUrl: `http://localhost:${(ctx as any).inngestPort}`,
|
|
3822
|
+
middleware: [realtimeMiddleware()],
|
|
3635
3823
|
});
|
|
3636
3824
|
|
|
3637
3825
|
const { createWorkflow, createStep } = init(inngest);
|
|
@@ -3724,23 +3912,24 @@ describe('MastraInngestWorkflow', () => {
|
|
|
3724
3912
|
inputData: { prompt1: 'Capital of France, just the name', prompt2: 'Capital of UK, just the name' },
|
|
3725
3913
|
});
|
|
3726
3914
|
|
|
3727
|
-
|
|
3915
|
+
srv.close();
|
|
3916
|
+
|
|
3917
|
+
expect(result.steps['test-agent-1']).toMatchObject({
|
|
3728
3918
|
status: 'success',
|
|
3729
3919
|
output: { text: 'Paris' },
|
|
3730
3920
|
});
|
|
3731
3921
|
|
|
3732
|
-
expect(result.steps['test-agent-2']).
|
|
3922
|
+
expect(result.steps['test-agent-2']).toMatchObject({
|
|
3733
3923
|
status: 'success',
|
|
3734
3924
|
output: { text: 'London' },
|
|
3735
3925
|
});
|
|
3736
|
-
|
|
3737
|
-
srv.close();
|
|
3738
3926
|
});
|
|
3739
3927
|
|
|
3740
3928
|
it('should be able to use an agent in parallel', async ctx => {
|
|
3741
3929
|
const inngest = new Inngest({
|
|
3742
3930
|
id: 'mastra',
|
|
3743
3931
|
baseUrl: `http://localhost:${(ctx as any).inngestPort}`,
|
|
3932
|
+
middleware: [realtimeMiddleware()],
|
|
3744
3933
|
});
|
|
3745
3934
|
|
|
3746
3935
|
const { createWorkflow, createStep } = init(inngest);
|
|
@@ -3861,17 +4050,17 @@ describe('MastraInngestWorkflow', () => {
|
|
|
3861
4050
|
});
|
|
3862
4051
|
|
|
3863
4052
|
expect(execute).toHaveBeenCalledTimes(1);
|
|
3864
|
-
expect(result.steps['finalStep']).
|
|
4053
|
+
expect(result.steps['finalStep']).toMatchObject({
|
|
3865
4054
|
status: 'success',
|
|
3866
4055
|
output: { result: 'success' },
|
|
3867
4056
|
});
|
|
3868
4057
|
|
|
3869
|
-
expect(result.steps['nested-workflow']).
|
|
4058
|
+
expect(result.steps['nested-workflow']).toMatchObject({
|
|
3870
4059
|
status: 'success',
|
|
3871
4060
|
output: { text: 'Paris' },
|
|
3872
4061
|
});
|
|
3873
4062
|
|
|
3874
|
-
expect(result.steps['nested-workflow-2']).
|
|
4063
|
+
expect(result.steps['nested-workflow-2']).toMatchObject({
|
|
3875
4064
|
status: 'success',
|
|
3876
4065
|
output: { text: 'London' },
|
|
3877
4066
|
});
|
|
@@ -4008,16 +4197,16 @@ describe('MastraInngestWorkflow', () => {
|
|
|
4008
4197
|
expect(final).toHaveBeenCalledTimes(2);
|
|
4009
4198
|
expect(last).toHaveBeenCalledTimes(1);
|
|
4010
4199
|
// @ts-ignore
|
|
4011
|
-
expect(result.steps['nested-workflow-a'].output).
|
|
4200
|
+
expect(result.steps['nested-workflow-a'].output).toMatchObject({
|
|
4012
4201
|
finalValue: 26 + 1,
|
|
4013
4202
|
});
|
|
4014
4203
|
|
|
4015
4204
|
// @ts-ignore
|
|
4016
|
-
expect(result.steps['nested-workflow-b'].output).
|
|
4205
|
+
expect(result.steps['nested-workflow-b'].output).toMatchObject({
|
|
4017
4206
|
finalValue: 1,
|
|
4018
4207
|
});
|
|
4019
4208
|
|
|
4020
|
-
expect(result.steps['last-step']).
|
|
4209
|
+
expect(result.steps['last-step']).toMatchObject({
|
|
4021
4210
|
output: { success: true },
|
|
4022
4211
|
status: 'success',
|
|
4023
4212
|
});
|
|
@@ -4160,16 +4349,16 @@ describe('MastraInngestWorkflow', () => {
|
|
|
4160
4349
|
expect(final).toHaveBeenCalledTimes(2);
|
|
4161
4350
|
expect(last).toHaveBeenCalledTimes(1);
|
|
4162
4351
|
// @ts-ignore
|
|
4163
|
-
expect(result.steps['nested-workflow-a'].output).
|
|
4352
|
+
expect(result.steps['nested-workflow-a'].output).toMatchObject({
|
|
4164
4353
|
finalValue: 26 + 1,
|
|
4165
4354
|
});
|
|
4166
4355
|
|
|
4167
4356
|
// @ts-ignore
|
|
4168
|
-
expect(result.steps['nested-workflow-b'].output).
|
|
4357
|
+
expect(result.steps['nested-workflow-b'].output).toMatchObject({
|
|
4169
4358
|
finalValue: 1,
|
|
4170
4359
|
});
|
|
4171
4360
|
|
|
4172
|
-
expect(result.steps['last-step']).
|
|
4361
|
+
expect(result.steps['last-step']).toMatchObject({
|
|
4173
4362
|
output: { success: true },
|
|
4174
4363
|
status: 'success',
|
|
4175
4364
|
});
|
|
@@ -4320,16 +4509,16 @@ describe('MastraInngestWorkflow', () => {
|
|
|
4320
4509
|
expect(first).toHaveBeenCalledTimes(1);
|
|
4321
4510
|
expect(last).toHaveBeenCalledTimes(1);
|
|
4322
4511
|
// @ts-ignore
|
|
4323
|
-
expect(result.steps['nested-workflow-a'].output).
|
|
4512
|
+
expect(result.steps['nested-workflow-a'].output).toMatchObject({
|
|
4324
4513
|
finalValue: 26 + 1,
|
|
4325
4514
|
});
|
|
4326
4515
|
|
|
4327
|
-
expect(result.steps['first-step']).
|
|
4516
|
+
expect(result.steps['first-step']).toMatchObject({
|
|
4328
4517
|
output: { success: true },
|
|
4329
4518
|
status: 'success',
|
|
4330
4519
|
});
|
|
4331
4520
|
|
|
4332
|
-
expect(result.steps['last-step']).
|
|
4521
|
+
expect(result.steps['last-step']).toMatchObject({
|
|
4333
4522
|
output: { success: true },
|
|
4334
4523
|
status: 'success',
|
|
4335
4524
|
});
|
|
@@ -4480,16 +4669,16 @@ describe('MastraInngestWorkflow', () => {
|
|
|
4480
4669
|
expect(last).toHaveBeenCalledTimes(1);
|
|
4481
4670
|
|
|
4482
4671
|
// @ts-ignore
|
|
4483
|
-
expect(result.steps['nested-workflow-b'].output).
|
|
4672
|
+
expect(result.steps['nested-workflow-b'].output).toMatchObject({
|
|
4484
4673
|
finalValue: 1,
|
|
4485
4674
|
});
|
|
4486
4675
|
|
|
4487
|
-
expect(result.steps['first-step']).
|
|
4676
|
+
expect(result.steps['first-step']).toMatchObject({
|
|
4488
4677
|
output: { success: true },
|
|
4489
4678
|
status: 'success',
|
|
4490
4679
|
});
|
|
4491
4680
|
|
|
4492
|
-
expect(result.steps['last-step']).
|
|
4681
|
+
expect(result.steps['last-step']).toMatchObject({
|
|
4493
4682
|
output: { success: true },
|
|
4494
4683
|
status: 'success',
|
|
4495
4684
|
});
|
|
@@ -4677,16 +4866,16 @@ describe('MastraInngestWorkflow', () => {
|
|
|
4677
4866
|
// expect(last).toHaveBeenCalledTimes(1);
|
|
4678
4867
|
|
|
4679
4868
|
// @ts-ignore
|
|
4680
|
-
expect(result.steps['nested-workflow-b'].output).
|
|
4869
|
+
expect(result.steps['nested-workflow-b'].output).toMatchObject({
|
|
4681
4870
|
finalValue: 1,
|
|
4682
4871
|
});
|
|
4683
4872
|
|
|
4684
|
-
expect(result.steps['first-step']).
|
|
4873
|
+
expect(result.steps['first-step']).toMatchObject({
|
|
4685
4874
|
output: { success: true },
|
|
4686
4875
|
status: 'success',
|
|
4687
4876
|
});
|
|
4688
4877
|
|
|
4689
|
-
expect(result.steps['last-step']).
|
|
4878
|
+
expect(result.steps['last-step']).toMatchObject({
|
|
4690
4879
|
output: { success: true },
|
|
4691
4880
|
status: 'success',
|
|
4692
4881
|
});
|
|
@@ -4832,12 +5021,12 @@ describe('MastraInngestWorkflow', () => {
|
|
|
4832
5021
|
});
|
|
4833
5022
|
|
|
4834
5023
|
// @ts-ignore
|
|
4835
|
-
expect(result.steps['last-step']).
|
|
5024
|
+
expect(result.steps['last-step']).toMatchObject(undefined);
|
|
4836
5025
|
|
|
4837
5026
|
const resumedResults = await run.resume({ step: [wfA, otherStep], resumeData: { newValue: 0 } });
|
|
4838
5027
|
|
|
4839
5028
|
// @ts-ignore
|
|
4840
|
-
expect(resumedResults.steps['nested-workflow-a'].output).
|
|
5029
|
+
expect(resumedResults.steps['nested-workflow-a'].output).toMatchObject({
|
|
4841
5030
|
finalValue: 26 + 1,
|
|
4842
5031
|
});
|
|
4843
5032
|
|
|
@@ -4988,7 +5177,7 @@ describe('MastraInngestWorkflow', () => {
|
|
|
4988
5177
|
},
|
|
4989
5178
|
});
|
|
4990
5179
|
|
|
4991
|
-
expect(result.steps['last-step']).
|
|
5180
|
+
expect(result.steps['last-step']).toMatchObject({
|
|
4992
5181
|
status: 'success',
|
|
4993
5182
|
output: { success: true },
|
|
4994
5183
|
});
|
|
@@ -5165,18 +5354,23 @@ describe('MastraInngestWorkflow', () => {
|
|
|
5165
5354
|
});
|
|
5166
5355
|
|
|
5167
5356
|
// @ts-ignore
|
|
5168
|
-
expect(result.steps['last-step']).
|
|
5357
|
+
expect(result.steps['last-step']).toMatchObject(undefined);
|
|
5169
5358
|
|
|
5170
5359
|
if (result.status !== 'suspended') {
|
|
5171
5360
|
expect.fail('Workflow should be suspended');
|
|
5172
5361
|
}
|
|
5173
|
-
expect(result.suspended[0]).
|
|
5362
|
+
expect(result.suspended[0]).toMatchObject([
|
|
5363
|
+
'nested-workflow-c',
|
|
5364
|
+
'nested-workflow-b',
|
|
5365
|
+
'nested-workflow-a',
|
|
5366
|
+
'other',
|
|
5367
|
+
]);
|
|
5174
5368
|
const resumedResults = await run.resume({ step: result.suspended[0], resumeData: { newValue: 0 } });
|
|
5175
5369
|
|
|
5176
5370
|
srv.close();
|
|
5177
5371
|
|
|
5178
5372
|
// @ts-ignore
|
|
5179
|
-
expect(resumedResults.steps['nested-workflow-c'].output).
|
|
5373
|
+
expect(resumedResults.steps['nested-workflow-c'].output).toMatchObject({
|
|
5180
5374
|
finalValue: 26 + 1,
|
|
5181
5375
|
});
|
|
5182
5376
|
|
|
@@ -5318,16 +5512,16 @@ describe('MastraInngestWorkflow', () => {
|
|
|
5318
5512
|
expect(final).toHaveBeenCalledTimes(2);
|
|
5319
5513
|
expect(last).toHaveBeenCalledTimes(1);
|
|
5320
5514
|
// @ts-ignore
|
|
5321
|
-
expect(result.steps['nested-workflow-a-clone'].output).
|
|
5515
|
+
expect(result.steps['nested-workflow-a-clone'].output).toMatchObject({
|
|
5322
5516
|
finalValue: 26 + 1,
|
|
5323
5517
|
});
|
|
5324
5518
|
|
|
5325
5519
|
// @ts-ignore
|
|
5326
|
-
expect(result.steps['nested-workflow-b'].output).
|
|
5520
|
+
expect(result.steps['nested-workflow-b'].output).toMatchObject({
|
|
5327
5521
|
finalValue: 1,
|
|
5328
5522
|
});
|
|
5329
5523
|
|
|
5330
|
-
expect(result.steps['last-step']).
|
|
5524
|
+
expect(result.steps['last-step']).toMatchObject({
|
|
5331
5525
|
output: { success: true },
|
|
5332
5526
|
status: 'success',
|
|
5333
5527
|
});
|
|
@@ -5517,5 +5711,1049 @@ describe('MastraInngestWorkflow', () => {
|
|
|
5517
5711
|
});
|
|
5518
5712
|
});
|
|
5519
5713
|
|
|
5520
|
-
describe('Access to inngest step primitives', () => {
|
|
5714
|
+
describe('Access to inngest step primitives', () => {
|
|
5715
|
+
it('should inject inngest step primitives into steps during run', async ctx => {
|
|
5716
|
+
const inngest = new Inngest({
|
|
5717
|
+
id: 'mastra',
|
|
5718
|
+
baseUrl: `http://localhost:${(ctx as any).inngestPort}`,
|
|
5719
|
+
});
|
|
5720
|
+
|
|
5721
|
+
const { createWorkflow, createStep } = init(inngest);
|
|
5722
|
+
|
|
5723
|
+
const step = createStep({
|
|
5724
|
+
id: 'step1',
|
|
5725
|
+
execute: async ({ engine }) => {
|
|
5726
|
+
return {
|
|
5727
|
+
hasEngine: !!engine.step,
|
|
5728
|
+
};
|
|
5729
|
+
},
|
|
5730
|
+
inputSchema: z.object({}),
|
|
5731
|
+
outputSchema: z.object({}),
|
|
5732
|
+
});
|
|
5733
|
+
const workflow = createWorkflow({
|
|
5734
|
+
id: 'test-workflow',
|
|
5735
|
+
inputSchema: z.object({}),
|
|
5736
|
+
outputSchema: z.object({
|
|
5737
|
+
hasEngine: z.boolean(),
|
|
5738
|
+
}),
|
|
5739
|
+
});
|
|
5740
|
+
workflow.then(step).commit();
|
|
5741
|
+
|
|
5742
|
+
const mastra = new Mastra({
|
|
5743
|
+
storage: new DefaultStorage({
|
|
5744
|
+
url: ':memory:',
|
|
5745
|
+
}),
|
|
5746
|
+
workflows: {
|
|
5747
|
+
'test-workflow': workflow,
|
|
5748
|
+
},
|
|
5749
|
+
server: {
|
|
5750
|
+
apiRoutes: [
|
|
5751
|
+
{
|
|
5752
|
+
path: '/inngest/api',
|
|
5753
|
+
method: 'ALL',
|
|
5754
|
+
createHandler: async ({ mastra }) => inngestServe({ mastra, inngest }),
|
|
5755
|
+
},
|
|
5756
|
+
],
|
|
5757
|
+
},
|
|
5758
|
+
});
|
|
5759
|
+
|
|
5760
|
+
const app = await createHonoServer(mastra);
|
|
5761
|
+
|
|
5762
|
+
const srv = serve({
|
|
5763
|
+
fetch: app.fetch,
|
|
5764
|
+
port: (ctx as any).handlerPort,
|
|
5765
|
+
});
|
|
5766
|
+
|
|
5767
|
+
const run = workflow.createRun();
|
|
5768
|
+
const result = await run.start({});
|
|
5769
|
+
|
|
5770
|
+
srv.close();
|
|
5771
|
+
|
|
5772
|
+
// @ts-ignore
|
|
5773
|
+
expect(result?.steps.step1.output.hasEngine).toBe(true);
|
|
5774
|
+
});
|
|
5775
|
+
});
|
|
5776
|
+
|
|
5777
|
+
describe('Streaming', () => {
|
|
5778
|
+
it('should generate a stream', async ctx => {
|
|
5779
|
+
const inngest = new Inngest({
|
|
5780
|
+
id: 'mastra',
|
|
5781
|
+
baseUrl: `http://localhost:${(ctx as any).inngestPort}`,
|
|
5782
|
+
middleware: [realtimeMiddleware()],
|
|
5783
|
+
});
|
|
5784
|
+
|
|
5785
|
+
const { createWorkflow, createStep } = init(inngest);
|
|
5786
|
+
|
|
5787
|
+
const step1Action = vi.fn<any>().mockResolvedValue({ result: 'success1' });
|
|
5788
|
+
const step2Action = vi.fn<any>().mockResolvedValue({ result: 'success2' });
|
|
5789
|
+
|
|
5790
|
+
const step1 = createStep({
|
|
5791
|
+
id: 'step1',
|
|
5792
|
+
execute: step1Action,
|
|
5793
|
+
inputSchema: z.object({}),
|
|
5794
|
+
outputSchema: z.object({ value: z.string() }),
|
|
5795
|
+
});
|
|
5796
|
+
const step2 = createStep({
|
|
5797
|
+
id: 'step2',
|
|
5798
|
+
execute: step2Action,
|
|
5799
|
+
inputSchema: z.object({ value: z.string() }),
|
|
5800
|
+
outputSchema: z.object({}),
|
|
5801
|
+
});
|
|
5802
|
+
|
|
5803
|
+
const workflow = createWorkflow({
|
|
5804
|
+
id: 'test-workflow',
|
|
5805
|
+
inputSchema: z.object({}),
|
|
5806
|
+
outputSchema: z.object({}),
|
|
5807
|
+
steps: [step1, step2],
|
|
5808
|
+
});
|
|
5809
|
+
workflow.then(step1).then(step2).commit();
|
|
5810
|
+
|
|
5811
|
+
const mastra = new Mastra({
|
|
5812
|
+
storage: new DefaultStorage({
|
|
5813
|
+
url: ':memory:',
|
|
5814
|
+
}),
|
|
5815
|
+
workflows: {
|
|
5816
|
+
'test-workflow': workflow,
|
|
5817
|
+
},
|
|
5818
|
+
server: {
|
|
5819
|
+
apiRoutes: [
|
|
5820
|
+
{
|
|
5821
|
+
path: '/inngest/api',
|
|
5822
|
+
method: 'ALL',
|
|
5823
|
+
createHandler: async ({ mastra }) => inngestServe({ mastra, inngest }),
|
|
5824
|
+
},
|
|
5825
|
+
],
|
|
5826
|
+
},
|
|
5827
|
+
});
|
|
5828
|
+
|
|
5829
|
+
const app = await createHonoServer(mastra);
|
|
5830
|
+
|
|
5831
|
+
const srv = serve({
|
|
5832
|
+
fetch: app.fetch,
|
|
5833
|
+
port: (ctx as any).handlerPort,
|
|
5834
|
+
});
|
|
5835
|
+
|
|
5836
|
+
const runId = 'test-run-id';
|
|
5837
|
+
let watchData: StreamEvent[] = [];
|
|
5838
|
+
const run = workflow.createRun({
|
|
5839
|
+
runId,
|
|
5840
|
+
});
|
|
5841
|
+
|
|
5842
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
5843
|
+
|
|
5844
|
+
const { stream, getWorkflowState } = run.stream({ inputData: {} });
|
|
5845
|
+
|
|
5846
|
+
// Start watching the workflow
|
|
5847
|
+
const collectedStreamData: StreamEvent[] = [];
|
|
5848
|
+
for await (const data of stream) {
|
|
5849
|
+
collectedStreamData.push(JSON.parse(JSON.stringify(data)));
|
|
5850
|
+
}
|
|
5851
|
+
watchData = collectedStreamData;
|
|
5852
|
+
|
|
5853
|
+
const executionResult = await getWorkflowState();
|
|
5854
|
+
|
|
5855
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
5856
|
+
|
|
5857
|
+
srv.close();
|
|
5858
|
+
|
|
5859
|
+
expect(watchData.length).toBe(8);
|
|
5860
|
+
expect(watchData).toMatchInlineSnapshot(`
|
|
5861
|
+
[
|
|
5862
|
+
{
|
|
5863
|
+
"payload": {
|
|
5864
|
+
"runId": "test-run-id",
|
|
5865
|
+
},
|
|
5866
|
+
"type": "start",
|
|
5867
|
+
},
|
|
5868
|
+
{
|
|
5869
|
+
"payload": {
|
|
5870
|
+
"id": "step1",
|
|
5871
|
+
},
|
|
5872
|
+
"type": "step-start",
|
|
5873
|
+
},
|
|
5874
|
+
{
|
|
5875
|
+
"payload": {
|
|
5876
|
+
"id": "step1",
|
|
5877
|
+
"output": {
|
|
5878
|
+
"result": "success1",
|
|
5879
|
+
},
|
|
5880
|
+
"status": "success",
|
|
5881
|
+
},
|
|
5882
|
+
"type": "step-result",
|
|
5883
|
+
},
|
|
5884
|
+
{
|
|
5885
|
+
"payload": {
|
|
5886
|
+
"id": "step1",
|
|
5887
|
+
"metadata": {},
|
|
5888
|
+
},
|
|
5889
|
+
"type": "step-finish",
|
|
5890
|
+
},
|
|
5891
|
+
{
|
|
5892
|
+
"payload": {
|
|
5893
|
+
"id": "step2",
|
|
5894
|
+
},
|
|
5895
|
+
"type": "step-start",
|
|
5896
|
+
},
|
|
5897
|
+
{
|
|
5898
|
+
"payload": {
|
|
5899
|
+
"id": "step2",
|
|
5900
|
+
"output": {
|
|
5901
|
+
"result": "success2",
|
|
5902
|
+
},
|
|
5903
|
+
"status": "success",
|
|
5904
|
+
},
|
|
5905
|
+
"type": "step-result",
|
|
5906
|
+
},
|
|
5907
|
+
{
|
|
5908
|
+
"payload": {
|
|
5909
|
+
"id": "step2",
|
|
5910
|
+
"metadata": {},
|
|
5911
|
+
},
|
|
5912
|
+
"type": "step-finish",
|
|
5913
|
+
},
|
|
5914
|
+
{
|
|
5915
|
+
"payload": {
|
|
5916
|
+
"runId": "test-run-id",
|
|
5917
|
+
},
|
|
5918
|
+
"type": "finish",
|
|
5919
|
+
},
|
|
5920
|
+
]
|
|
5921
|
+
`);
|
|
5922
|
+
// Verify execution completed successfully
|
|
5923
|
+
expect(executionResult.steps.step1).toMatchObject({
|
|
5924
|
+
status: 'success',
|
|
5925
|
+
output: { result: 'success1' },
|
|
5926
|
+
payload: {},
|
|
5927
|
+
startedAt: expect.any(Number),
|
|
5928
|
+
endedAt: expect.any(Number),
|
|
5929
|
+
});
|
|
5930
|
+
expect(executionResult.steps.step2).toMatchObject({
|
|
5931
|
+
status: 'success',
|
|
5932
|
+
output: { result: 'success2' },
|
|
5933
|
+
payload: {
|
|
5934
|
+
result: 'success1',
|
|
5935
|
+
},
|
|
5936
|
+
startedAt: expect.any(Number),
|
|
5937
|
+
endedAt: expect.any(Number),
|
|
5938
|
+
});
|
|
5939
|
+
});
|
|
5940
|
+
|
|
5941
|
+
it('should handle basic sleep waiting flow', async ctx => {
|
|
5942
|
+
const inngest = new Inngest({
|
|
5943
|
+
id: 'mastra',
|
|
5944
|
+
baseUrl: `http://localhost:${(ctx as any).inngestPort}`,
|
|
5945
|
+
middleware: [realtimeMiddleware()],
|
|
5946
|
+
});
|
|
5947
|
+
|
|
5948
|
+
const { createWorkflow, createStep } = init(inngest);
|
|
5949
|
+
|
|
5950
|
+
const step1Action = vi.fn<any>().mockResolvedValue({ result: 'success1' });
|
|
5951
|
+
const step2Action = vi.fn<any>().mockResolvedValue({ result: 'success2' });
|
|
5952
|
+
|
|
5953
|
+
const step1 = createStep({
|
|
5954
|
+
id: 'step1',
|
|
5955
|
+
execute: step1Action,
|
|
5956
|
+
inputSchema: z.object({}),
|
|
5957
|
+
outputSchema: z.object({ value: z.string() }),
|
|
5958
|
+
});
|
|
5959
|
+
const step2 = createStep({
|
|
5960
|
+
id: 'step2',
|
|
5961
|
+
execute: step2Action,
|
|
5962
|
+
inputSchema: z.object({ value: z.string() }),
|
|
5963
|
+
outputSchema: z.object({}),
|
|
5964
|
+
});
|
|
5965
|
+
|
|
5966
|
+
const workflow = createWorkflow({
|
|
5967
|
+
id: 'test-workflow',
|
|
5968
|
+
inputSchema: z.object({}),
|
|
5969
|
+
outputSchema: z.object({}),
|
|
5970
|
+
steps: [step1, step2],
|
|
5971
|
+
});
|
|
5972
|
+
workflow.then(step1).sleep(1000).then(step2).commit();
|
|
5973
|
+
|
|
5974
|
+
const mastra = new Mastra({
|
|
5975
|
+
storage: new DefaultStorage({
|
|
5976
|
+
url: ':memory:',
|
|
5977
|
+
}),
|
|
5978
|
+
workflows: {
|
|
5979
|
+
'test-workflow': workflow,
|
|
5980
|
+
},
|
|
5981
|
+
server: {
|
|
5982
|
+
apiRoutes: [
|
|
5983
|
+
{
|
|
5984
|
+
path: '/inngest/api',
|
|
5985
|
+
method: 'ALL',
|
|
5986
|
+
createHandler: async ({ mastra }) => inngestServe({ mastra, inngest }),
|
|
5987
|
+
},
|
|
5988
|
+
],
|
|
5989
|
+
},
|
|
5990
|
+
});
|
|
5991
|
+
|
|
5992
|
+
const app = await createHonoServer(mastra);
|
|
5993
|
+
|
|
5994
|
+
const srv = serve({
|
|
5995
|
+
fetch: app.fetch,
|
|
5996
|
+
port: (ctx as any).handlerPort,
|
|
5997
|
+
});
|
|
5998
|
+
|
|
5999
|
+
const runId = 'test-run-id';
|
|
6000
|
+
let watchData: StreamEvent[] = [];
|
|
6001
|
+
const run = workflow.createRun({
|
|
6002
|
+
runId,
|
|
6003
|
+
});
|
|
6004
|
+
|
|
6005
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
6006
|
+
|
|
6007
|
+
const { stream, getWorkflowState } = run.stream({ inputData: {} });
|
|
6008
|
+
|
|
6009
|
+
// Start watching the workflow
|
|
6010
|
+
const collectedStreamData: StreamEvent[] = [];
|
|
6011
|
+
for await (const data of stream) {
|
|
6012
|
+
collectedStreamData.push(JSON.parse(JSON.stringify(data)));
|
|
6013
|
+
}
|
|
6014
|
+
watchData = collectedStreamData;
|
|
6015
|
+
|
|
6016
|
+
const executionResult = await getWorkflowState();
|
|
6017
|
+
|
|
6018
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
6019
|
+
|
|
6020
|
+
srv.close();
|
|
6021
|
+
|
|
6022
|
+
expect(watchData.length).toBe(9);
|
|
6023
|
+
expect(watchData).toMatchObject([
|
|
6024
|
+
{
|
|
6025
|
+
payload: {
|
|
6026
|
+
runId: 'test-run-id',
|
|
6027
|
+
},
|
|
6028
|
+
type: 'start',
|
|
6029
|
+
},
|
|
6030
|
+
{
|
|
6031
|
+
payload: {
|
|
6032
|
+
id: 'step1',
|
|
6033
|
+
},
|
|
6034
|
+
type: 'step-start',
|
|
6035
|
+
},
|
|
6036
|
+
{
|
|
6037
|
+
payload: {
|
|
6038
|
+
id: 'step1',
|
|
6039
|
+
output: {
|
|
6040
|
+
result: 'success1',
|
|
6041
|
+
},
|
|
6042
|
+
status: 'success',
|
|
6043
|
+
},
|
|
6044
|
+
type: 'step-result',
|
|
6045
|
+
},
|
|
6046
|
+
{
|
|
6047
|
+
payload: {
|
|
6048
|
+
id: 'step1',
|
|
6049
|
+
metadata: {},
|
|
6050
|
+
},
|
|
6051
|
+
type: 'step-finish',
|
|
6052
|
+
},
|
|
6053
|
+
{
|
|
6054
|
+
payload: {},
|
|
6055
|
+
type: 'step-waiting',
|
|
6056
|
+
},
|
|
6057
|
+
{
|
|
6058
|
+
payload: {
|
|
6059
|
+
id: 'step2',
|
|
6060
|
+
},
|
|
6061
|
+
type: 'step-start',
|
|
6062
|
+
},
|
|
6063
|
+
{
|
|
6064
|
+
payload: {
|
|
6065
|
+
id: 'step2',
|
|
6066
|
+
output: {
|
|
6067
|
+
result: 'success2',
|
|
6068
|
+
},
|
|
6069
|
+
status: 'success',
|
|
6070
|
+
},
|
|
6071
|
+
type: 'step-result',
|
|
6072
|
+
},
|
|
6073
|
+
{
|
|
6074
|
+
payload: {
|
|
6075
|
+
id: 'step2',
|
|
6076
|
+
metadata: {},
|
|
6077
|
+
},
|
|
6078
|
+
type: 'step-finish',
|
|
6079
|
+
},
|
|
6080
|
+
{
|
|
6081
|
+
payload: {
|
|
6082
|
+
runId: 'test-run-id',
|
|
6083
|
+
},
|
|
6084
|
+
type: 'finish',
|
|
6085
|
+
},
|
|
6086
|
+
]);
|
|
6087
|
+
// Verify execution completed successfully
|
|
6088
|
+
expect(executionResult.steps.step1).toMatchObject({
|
|
6089
|
+
status: 'success',
|
|
6090
|
+
output: { result: 'success1' },
|
|
6091
|
+
payload: {},
|
|
6092
|
+
startedAt: expect.any(Number),
|
|
6093
|
+
endedAt: expect.any(Number),
|
|
6094
|
+
});
|
|
6095
|
+
expect(executionResult.steps.step2).toMatchObject({
|
|
6096
|
+
status: 'success',
|
|
6097
|
+
output: { result: 'success2' },
|
|
6098
|
+
payload: {
|
|
6099
|
+
result: 'success1',
|
|
6100
|
+
},
|
|
6101
|
+
startedAt: expect.any(Number),
|
|
6102
|
+
endedAt: expect.any(Number),
|
|
6103
|
+
});
|
|
6104
|
+
});
|
|
6105
|
+
|
|
6106
|
+
it('should handle waitForEvent waiting flow', async ctx => {
|
|
6107
|
+
const inngest = new Inngest({
|
|
6108
|
+
id: 'mastra',
|
|
6109
|
+
baseUrl: `http://localhost:${(ctx as any).inngestPort}`,
|
|
6110
|
+
middleware: [realtimeMiddleware()],
|
|
6111
|
+
});
|
|
6112
|
+
|
|
6113
|
+
const { createWorkflow, createStep } = init(inngest);
|
|
6114
|
+
|
|
6115
|
+
const step1Action = vi.fn<any>().mockResolvedValue({ result: 'success1' });
|
|
6116
|
+
const step2Action = vi.fn<any>().mockResolvedValue({ result: 'success2' });
|
|
6117
|
+
|
|
6118
|
+
const step1 = createStep({
|
|
6119
|
+
id: 'step1',
|
|
6120
|
+
execute: step1Action,
|
|
6121
|
+
inputSchema: z.object({}),
|
|
6122
|
+
outputSchema: z.object({ value: z.string() }),
|
|
6123
|
+
});
|
|
6124
|
+
const step2 = createStep({
|
|
6125
|
+
id: 'step2',
|
|
6126
|
+
execute: step2Action,
|
|
6127
|
+
inputSchema: z.object({ value: z.string() }),
|
|
6128
|
+
outputSchema: z.object({}),
|
|
6129
|
+
});
|
|
6130
|
+
|
|
6131
|
+
const workflow = createWorkflow({
|
|
6132
|
+
id: 'test-workflow',
|
|
6133
|
+
inputSchema: z.object({}),
|
|
6134
|
+
outputSchema: z.object({}),
|
|
6135
|
+
steps: [step1, step2],
|
|
6136
|
+
});
|
|
6137
|
+
workflow.then(step1).waitForEvent('user-event-test', step2).commit();
|
|
6138
|
+
|
|
6139
|
+
const mastra = new Mastra({
|
|
6140
|
+
storage: new DefaultStorage({
|
|
6141
|
+
url: ':memory:',
|
|
6142
|
+
}),
|
|
6143
|
+
workflows: {
|
|
6144
|
+
'test-workflow': workflow,
|
|
6145
|
+
},
|
|
6146
|
+
server: {
|
|
6147
|
+
apiRoutes: [
|
|
6148
|
+
{
|
|
6149
|
+
path: '/inngest/api',
|
|
6150
|
+
method: 'ALL',
|
|
6151
|
+
createHandler: async ({ mastra }) => inngestServe({ mastra, inngest }),
|
|
6152
|
+
},
|
|
6153
|
+
],
|
|
6154
|
+
},
|
|
6155
|
+
});
|
|
6156
|
+
|
|
6157
|
+
const app = await createHonoServer(mastra);
|
|
6158
|
+
|
|
6159
|
+
const srv = serve({
|
|
6160
|
+
fetch: app.fetch,
|
|
6161
|
+
port: (ctx as any).handlerPort,
|
|
6162
|
+
});
|
|
6163
|
+
|
|
6164
|
+
const runId = 'test-run-id';
|
|
6165
|
+
let watchData: StreamEvent[] = [];
|
|
6166
|
+
const run = workflow.createRun({
|
|
6167
|
+
runId,
|
|
6168
|
+
});
|
|
6169
|
+
|
|
6170
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
6171
|
+
|
|
6172
|
+
const { stream, getWorkflowState } = run.stream({ inputData: {} });
|
|
6173
|
+
|
|
6174
|
+
setTimeout(() => {
|
|
6175
|
+
run.sendEvent('user-event-test', {
|
|
6176
|
+
value: 'eventdata',
|
|
6177
|
+
});
|
|
6178
|
+
}, 3000);
|
|
6179
|
+
|
|
6180
|
+
// Start watching the workflow
|
|
6181
|
+
const collectedStreamData: StreamEvent[] = [];
|
|
6182
|
+
for await (const data of stream) {
|
|
6183
|
+
collectedStreamData.push(JSON.parse(JSON.stringify(data)));
|
|
6184
|
+
}
|
|
6185
|
+
watchData = collectedStreamData;
|
|
6186
|
+
console.dir({ watchData }, { depth: null });
|
|
6187
|
+
|
|
6188
|
+
const executionResult = await getWorkflowState();
|
|
6189
|
+
|
|
6190
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
6191
|
+
|
|
6192
|
+
srv.close();
|
|
6193
|
+
|
|
6194
|
+
expect(watchData.length).toBe(9);
|
|
6195
|
+
expect(watchData).toMatchObject([
|
|
6196
|
+
{
|
|
6197
|
+
payload: {
|
|
6198
|
+
runId: 'test-run-id',
|
|
6199
|
+
},
|
|
6200
|
+
type: 'start',
|
|
6201
|
+
},
|
|
6202
|
+
{
|
|
6203
|
+
payload: {
|
|
6204
|
+
id: 'step1',
|
|
6205
|
+
},
|
|
6206
|
+
type: 'step-start',
|
|
6207
|
+
},
|
|
6208
|
+
{
|
|
6209
|
+
payload: {
|
|
6210
|
+
id: 'step1',
|
|
6211
|
+
output: {
|
|
6212
|
+
result: 'success1',
|
|
6213
|
+
},
|
|
6214
|
+
status: 'success',
|
|
6215
|
+
},
|
|
6216
|
+
type: 'step-result',
|
|
6217
|
+
},
|
|
6218
|
+
{
|
|
6219
|
+
payload: {
|
|
6220
|
+
id: 'step1',
|
|
6221
|
+
metadata: {},
|
|
6222
|
+
},
|
|
6223
|
+
type: 'step-finish',
|
|
6224
|
+
},
|
|
6225
|
+
{
|
|
6226
|
+
payload: {
|
|
6227
|
+
id: 'step2',
|
|
6228
|
+
},
|
|
6229
|
+
type: 'step-waiting',
|
|
6230
|
+
},
|
|
6231
|
+
{
|
|
6232
|
+
payload: {
|
|
6233
|
+
id: 'step2',
|
|
6234
|
+
},
|
|
6235
|
+
type: 'step-start',
|
|
6236
|
+
},
|
|
6237
|
+
{
|
|
6238
|
+
payload: {
|
|
6239
|
+
id: 'step2',
|
|
6240
|
+
output: {
|
|
6241
|
+
result: 'success2',
|
|
6242
|
+
},
|
|
6243
|
+
status: 'success',
|
|
6244
|
+
},
|
|
6245
|
+
type: 'step-result',
|
|
6246
|
+
},
|
|
6247
|
+
{
|
|
6248
|
+
payload: {
|
|
6249
|
+
id: 'step2',
|
|
6250
|
+
metadata: {},
|
|
6251
|
+
},
|
|
6252
|
+
type: 'step-finish',
|
|
6253
|
+
},
|
|
6254
|
+
{
|
|
6255
|
+
payload: {
|
|
6256
|
+
runId: 'test-run-id',
|
|
6257
|
+
},
|
|
6258
|
+
type: 'finish',
|
|
6259
|
+
},
|
|
6260
|
+
]);
|
|
6261
|
+
// Verify execution completed successfully
|
|
6262
|
+
expect(executionResult.steps.step1).toMatchObject({
|
|
6263
|
+
status: 'success',
|
|
6264
|
+
output: { result: 'success1' },
|
|
6265
|
+
payload: {},
|
|
6266
|
+
startedAt: expect.any(Number),
|
|
6267
|
+
endedAt: expect.any(Number),
|
|
6268
|
+
});
|
|
6269
|
+
expect(executionResult.steps.step2).toMatchObject({
|
|
6270
|
+
status: 'success',
|
|
6271
|
+
output: { result: 'success2' },
|
|
6272
|
+
payload: {
|
|
6273
|
+
result: 'success1',
|
|
6274
|
+
},
|
|
6275
|
+
resumePayload: {
|
|
6276
|
+
value: 'eventdata',
|
|
6277
|
+
},
|
|
6278
|
+
startedAt: expect.any(Number),
|
|
6279
|
+
resumedAt: expect.any(Number),
|
|
6280
|
+
endedAt: expect.any(Number),
|
|
6281
|
+
});
|
|
6282
|
+
});
|
|
6283
|
+
|
|
6284
|
+
it('should handle basic suspend and resume flow', async ctx => {
|
|
6285
|
+
const inngest = new Inngest({
|
|
6286
|
+
id: 'mastra',
|
|
6287
|
+
baseUrl: `http://localhost:${(ctx as any).inngestPort}`,
|
|
6288
|
+
middleware: [realtimeMiddleware()],
|
|
6289
|
+
});
|
|
6290
|
+
|
|
6291
|
+
const { createWorkflow, createStep } = init(inngest);
|
|
6292
|
+
|
|
6293
|
+
const getUserInputAction = vi.fn().mockResolvedValue({ userInput: 'test input' });
|
|
6294
|
+
const promptAgentAction = vi
|
|
6295
|
+
.fn()
|
|
6296
|
+
.mockImplementationOnce(async ({ suspend }) => {
|
|
6297
|
+
console.log('suspend');
|
|
6298
|
+
await suspend();
|
|
6299
|
+
return undefined;
|
|
6300
|
+
})
|
|
6301
|
+
.mockImplementationOnce(() => ({ modelOutput: 'test output' }));
|
|
6302
|
+
const evaluateToneAction = vi.fn().mockResolvedValue({
|
|
6303
|
+
toneScore: { score: 0.8 },
|
|
6304
|
+
completenessScore: { score: 0.7 },
|
|
6305
|
+
});
|
|
6306
|
+
const improveResponseAction = vi.fn().mockResolvedValue({ improvedOutput: 'improved output' });
|
|
6307
|
+
const evaluateImprovedAction = vi.fn().mockResolvedValue({
|
|
6308
|
+
toneScore: { score: 0.9 },
|
|
6309
|
+
completenessScore: { score: 0.8 },
|
|
6310
|
+
});
|
|
6311
|
+
|
|
6312
|
+
const getUserInput = createStep({
|
|
6313
|
+
id: 'getUserInput',
|
|
6314
|
+
execute: getUserInputAction,
|
|
6315
|
+
inputSchema: z.object({ input: z.string() }),
|
|
6316
|
+
outputSchema: z.object({ userInput: z.string() }),
|
|
6317
|
+
});
|
|
6318
|
+
const promptAgent = createStep({
|
|
6319
|
+
id: 'promptAgent',
|
|
6320
|
+
execute: promptAgentAction,
|
|
6321
|
+
inputSchema: z.object({ userInput: z.string() }),
|
|
6322
|
+
outputSchema: z.object({ modelOutput: z.string() }),
|
|
6323
|
+
});
|
|
6324
|
+
const evaluateTone = createStep({
|
|
6325
|
+
id: 'evaluateToneConsistency',
|
|
6326
|
+
execute: evaluateToneAction,
|
|
6327
|
+
inputSchema: z.object({ modelOutput: z.string() }),
|
|
6328
|
+
outputSchema: z.object({
|
|
6329
|
+
toneScore: z.any(),
|
|
6330
|
+
completenessScore: z.any(),
|
|
6331
|
+
}),
|
|
6332
|
+
});
|
|
6333
|
+
const improveResponse = createStep({
|
|
6334
|
+
id: 'improveResponse',
|
|
6335
|
+
execute: improveResponseAction,
|
|
6336
|
+
inputSchema: z.object({ toneScore: z.any(), completenessScore: z.any() }),
|
|
6337
|
+
outputSchema: z.object({ improvedOutput: z.string() }),
|
|
6338
|
+
});
|
|
6339
|
+
const evaluateImproved = createStep({
|
|
6340
|
+
id: 'evaluateImprovedResponse',
|
|
6341
|
+
execute: evaluateImprovedAction,
|
|
6342
|
+
inputSchema: z.object({ improvedOutput: z.string() }),
|
|
6343
|
+
outputSchema: z.object({
|
|
6344
|
+
toneScore: z.any(),
|
|
6345
|
+
completenessScore: z.any(),
|
|
6346
|
+
}),
|
|
6347
|
+
});
|
|
6348
|
+
|
|
6349
|
+
const promptEvalWorkflow = createWorkflow({
|
|
6350
|
+
id: 'test-workflow',
|
|
6351
|
+
inputSchema: z.object({ input: z.string() }),
|
|
6352
|
+
outputSchema: z.object({}),
|
|
6353
|
+
steps: [getUserInput, promptAgent, evaluateTone, improveResponse, evaluateImproved],
|
|
6354
|
+
});
|
|
6355
|
+
|
|
6356
|
+
promptEvalWorkflow
|
|
6357
|
+
.then(getUserInput)
|
|
6358
|
+
.then(promptAgent)
|
|
6359
|
+
.then(evaluateTone)
|
|
6360
|
+
.then(improveResponse)
|
|
6361
|
+
.then(evaluateImproved)
|
|
6362
|
+
.commit();
|
|
6363
|
+
|
|
6364
|
+
const mastra = new Mastra({
|
|
6365
|
+
storage: new DefaultStorage({
|
|
6366
|
+
url: ':memory:',
|
|
6367
|
+
}),
|
|
6368
|
+
workflows: {
|
|
6369
|
+
'test-workflow': promptEvalWorkflow,
|
|
6370
|
+
},
|
|
6371
|
+
server: {
|
|
6372
|
+
apiRoutes: [
|
|
6373
|
+
{
|
|
6374
|
+
path: '/inngest/api',
|
|
6375
|
+
method: 'ALL',
|
|
6376
|
+
createHandler: async ({ mastra }) => inngestServe({ mastra, inngest }),
|
|
6377
|
+
},
|
|
6378
|
+
],
|
|
6379
|
+
},
|
|
6380
|
+
});
|
|
6381
|
+
|
|
6382
|
+
const app = await createHonoServer(mastra);
|
|
6383
|
+
|
|
6384
|
+
const srv = serve({
|
|
6385
|
+
fetch: app.fetch,
|
|
6386
|
+
port: (ctx as any).handlerPort,
|
|
6387
|
+
});
|
|
6388
|
+
|
|
6389
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
6390
|
+
|
|
6391
|
+
const run = promptEvalWorkflow.createRun();
|
|
6392
|
+
|
|
6393
|
+
const { stream, getWorkflowState } = run.stream({ inputData: { input: 'test' } });
|
|
6394
|
+
|
|
6395
|
+
for await (const data of stream) {
|
|
6396
|
+
if (data.type === 'step-suspended') {
|
|
6397
|
+
expect(promptAgentAction).toHaveBeenCalledTimes(1);
|
|
6398
|
+
|
|
6399
|
+
// make it async to show that execution is not blocked
|
|
6400
|
+
setImmediate(() => {
|
|
6401
|
+
const resumeData = { stepId: 'promptAgent', context: { userInput: 'test input for resumption' } };
|
|
6402
|
+
run.resume({ resumeData: resumeData as any, step: promptAgent });
|
|
6403
|
+
});
|
|
6404
|
+
expect(evaluateToneAction).not.toHaveBeenCalledTimes(1);
|
|
6405
|
+
}
|
|
6406
|
+
}
|
|
6407
|
+
|
|
6408
|
+
await new Promise(resolve => setTimeout(resolve, 5000));
|
|
6409
|
+
const resumeResult = await getWorkflowState();
|
|
6410
|
+
|
|
6411
|
+
srv.close();
|
|
6412
|
+
|
|
6413
|
+
expect(evaluateToneAction).toHaveBeenCalledTimes(1);
|
|
6414
|
+
expect(resumeResult.steps).toMatchObject({
|
|
6415
|
+
input: { input: 'test' },
|
|
6416
|
+
getUserInput: {
|
|
6417
|
+
status: 'success',
|
|
6418
|
+
output: { userInput: 'test input' },
|
|
6419
|
+
payload: { input: 'test' },
|
|
6420
|
+
startedAt: expect.any(Number),
|
|
6421
|
+
endedAt: expect.any(Number),
|
|
6422
|
+
},
|
|
6423
|
+
promptAgent: {
|
|
6424
|
+
status: 'success',
|
|
6425
|
+
output: { modelOutput: 'test output' },
|
|
6426
|
+
payload: { userInput: 'test input' },
|
|
6427
|
+
startedAt: expect.any(Number),
|
|
6428
|
+
endedAt: expect.any(Number),
|
|
6429
|
+
resumePayload: { stepId: 'promptAgent', context: { userInput: 'test input for resumption' } },
|
|
6430
|
+
resumedAt: expect.any(Number),
|
|
6431
|
+
// suspendedAt: expect.any(Number),
|
|
6432
|
+
},
|
|
6433
|
+
evaluateToneConsistency: {
|
|
6434
|
+
status: 'success',
|
|
6435
|
+
output: { toneScore: { score: 0.8 }, completenessScore: { score: 0.7 } },
|
|
6436
|
+
payload: { modelOutput: 'test output' },
|
|
6437
|
+
startedAt: expect.any(Number),
|
|
6438
|
+
endedAt: expect.any(Number),
|
|
6439
|
+
},
|
|
6440
|
+
improveResponse: {
|
|
6441
|
+
status: 'success',
|
|
6442
|
+
output: { improvedOutput: 'improved output' },
|
|
6443
|
+
payload: { toneScore: { score: 0.8 }, completenessScore: { score: 0.7 } },
|
|
6444
|
+
startedAt: expect.any(Number),
|
|
6445
|
+
endedAt: expect.any(Number),
|
|
6446
|
+
},
|
|
6447
|
+
evaluateImprovedResponse: {
|
|
6448
|
+
status: 'success',
|
|
6449
|
+
output: { toneScore: { score: 0.9 }, completenessScore: { score: 0.8 } },
|
|
6450
|
+
payload: { improvedOutput: 'improved output' },
|
|
6451
|
+
startedAt: expect.any(Number),
|
|
6452
|
+
endedAt: expect.any(Number),
|
|
6453
|
+
},
|
|
6454
|
+
});
|
|
6455
|
+
});
|
|
6456
|
+
|
|
6457
|
+
it('should be able to use an agent as a step', async ctx => {
|
|
6458
|
+
const inngest = new Inngest({
|
|
6459
|
+
id: 'mastra',
|
|
6460
|
+
baseUrl: `http://localhost:${(ctx as any).inngestPort}`,
|
|
6461
|
+
middleware: [realtimeMiddleware()],
|
|
6462
|
+
});
|
|
6463
|
+
|
|
6464
|
+
const { createWorkflow, createStep } = init(inngest);
|
|
6465
|
+
|
|
6466
|
+
const workflow = createWorkflow({
|
|
6467
|
+
id: 'test-workflow',
|
|
6468
|
+
inputSchema: z.object({
|
|
6469
|
+
prompt1: z.string(),
|
|
6470
|
+
prompt2: z.string(),
|
|
6471
|
+
}),
|
|
6472
|
+
outputSchema: z.object({}),
|
|
6473
|
+
});
|
|
6474
|
+
|
|
6475
|
+
const agent = new Agent({
|
|
6476
|
+
name: 'test-agent-1',
|
|
6477
|
+
instructions: 'test agent instructions"',
|
|
6478
|
+
model: new MockLanguageModelV1({
|
|
6479
|
+
doStream: async () => ({
|
|
6480
|
+
stream: simulateReadableStream({
|
|
6481
|
+
chunks: [
|
|
6482
|
+
{ type: 'text-delta', textDelta: 'Paris' },
|
|
6483
|
+
{
|
|
6484
|
+
type: 'finish',
|
|
6485
|
+
finishReason: 'stop',
|
|
6486
|
+
logprobs: undefined,
|
|
6487
|
+
usage: { completionTokens: 10, promptTokens: 3 },
|
|
6488
|
+
},
|
|
6489
|
+
],
|
|
6490
|
+
}),
|
|
6491
|
+
rawCall: { rawPrompt: null, rawSettings: {} },
|
|
6492
|
+
}),
|
|
6493
|
+
}),
|
|
6494
|
+
});
|
|
6495
|
+
|
|
6496
|
+
const agent2 = new Agent({
|
|
6497
|
+
name: 'test-agent-2',
|
|
6498
|
+
instructions: 'test agent instructions',
|
|
6499
|
+
model: new MockLanguageModelV1({
|
|
6500
|
+
doStream: async () => ({
|
|
6501
|
+
stream: simulateReadableStream({
|
|
6502
|
+
chunks: [
|
|
6503
|
+
{ type: 'text-delta', textDelta: 'London' },
|
|
6504
|
+
{
|
|
6505
|
+
type: 'finish',
|
|
6506
|
+
finishReason: 'stop',
|
|
6507
|
+
logprobs: undefined,
|
|
6508
|
+
usage: { completionTokens: 10, promptTokens: 3 },
|
|
6509
|
+
},
|
|
6510
|
+
],
|
|
6511
|
+
}),
|
|
6512
|
+
rawCall: { rawPrompt: null, rawSettings: {} },
|
|
6513
|
+
}),
|
|
6514
|
+
}),
|
|
6515
|
+
});
|
|
6516
|
+
|
|
6517
|
+
const startStep = createStep({
|
|
6518
|
+
id: 'start',
|
|
6519
|
+
inputSchema: z.object({
|
|
6520
|
+
prompt1: z.string(),
|
|
6521
|
+
prompt2: z.string(),
|
|
6522
|
+
}),
|
|
6523
|
+
outputSchema: z.object({ prompt1: z.string(), prompt2: z.string() }),
|
|
6524
|
+
execute: async ({ inputData }) => {
|
|
6525
|
+
return {
|
|
6526
|
+
prompt1: inputData.prompt1,
|
|
6527
|
+
prompt2: inputData.prompt2,
|
|
6528
|
+
};
|
|
6529
|
+
},
|
|
6530
|
+
});
|
|
6531
|
+
|
|
6532
|
+
const agentStep1 = createStep(agent);
|
|
6533
|
+
const agentStep2 = createStep(agent2);
|
|
6534
|
+
|
|
6535
|
+
workflow
|
|
6536
|
+
.then(startStep)
|
|
6537
|
+
.map({
|
|
6538
|
+
prompt: {
|
|
6539
|
+
step: startStep,
|
|
6540
|
+
path: 'prompt1',
|
|
6541
|
+
},
|
|
6542
|
+
})
|
|
6543
|
+
.then(agentStep1)
|
|
6544
|
+
.map({
|
|
6545
|
+
prompt: {
|
|
6546
|
+
step: startStep,
|
|
6547
|
+
path: 'prompt2',
|
|
6548
|
+
},
|
|
6549
|
+
})
|
|
6550
|
+
.then(agentStep2)
|
|
6551
|
+
.commit();
|
|
6552
|
+
|
|
6553
|
+
const mastra = new Mastra({
|
|
6554
|
+
storage: new DefaultStorage({
|
|
6555
|
+
url: ':memory:',
|
|
6556
|
+
}),
|
|
6557
|
+
workflows: {
|
|
6558
|
+
'test-workflow': workflow,
|
|
6559
|
+
},
|
|
6560
|
+
server: {
|
|
6561
|
+
apiRoutes: [
|
|
6562
|
+
{
|
|
6563
|
+
path: '/inngest/api',
|
|
6564
|
+
method: 'ALL',
|
|
6565
|
+
createHandler: async ({ mastra }) => inngestServe({ mastra, inngest }),
|
|
6566
|
+
},
|
|
6567
|
+
],
|
|
6568
|
+
},
|
|
6569
|
+
});
|
|
6570
|
+
|
|
6571
|
+
const app = await createHonoServer(mastra);
|
|
6572
|
+
|
|
6573
|
+
const srv = serve({
|
|
6574
|
+
fetch: app.fetch,
|
|
6575
|
+
port: (ctx as any).handlerPort,
|
|
6576
|
+
});
|
|
6577
|
+
|
|
6578
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
6579
|
+
|
|
6580
|
+
const run = workflow.createRun({
|
|
6581
|
+
runId: 'test-run-id',
|
|
6582
|
+
});
|
|
6583
|
+
const { stream } = await run.stream({
|
|
6584
|
+
inputData: {
|
|
6585
|
+
prompt1: 'Capital of France, just the name',
|
|
6586
|
+
prompt2: 'Capital of UK, just the name',
|
|
6587
|
+
},
|
|
6588
|
+
});
|
|
6589
|
+
|
|
6590
|
+
const values: StreamEvent[] = [];
|
|
6591
|
+
for await (const value of stream.values()) {
|
|
6592
|
+
values.push(value);
|
|
6593
|
+
}
|
|
6594
|
+
|
|
6595
|
+
srv.close();
|
|
6596
|
+
|
|
6597
|
+
expect(values).toMatchObject([
|
|
6598
|
+
{
|
|
6599
|
+
payload: {
|
|
6600
|
+
runId: 'test-run-id',
|
|
6601
|
+
},
|
|
6602
|
+
type: 'start',
|
|
6603
|
+
},
|
|
6604
|
+
{
|
|
6605
|
+
payload: {
|
|
6606
|
+
id: 'start',
|
|
6607
|
+
},
|
|
6608
|
+
type: 'step-start',
|
|
6609
|
+
},
|
|
6610
|
+
{
|
|
6611
|
+
payload: {
|
|
6612
|
+
id: 'start',
|
|
6613
|
+
output: {
|
|
6614
|
+
prompt1: 'Capital of France, just the name',
|
|
6615
|
+
prompt2: 'Capital of UK, just the name',
|
|
6616
|
+
},
|
|
6617
|
+
status: 'success',
|
|
6618
|
+
},
|
|
6619
|
+
type: 'step-result',
|
|
6620
|
+
},
|
|
6621
|
+
{
|
|
6622
|
+
payload: {
|
|
6623
|
+
id: 'start',
|
|
6624
|
+
metadata: {},
|
|
6625
|
+
},
|
|
6626
|
+
type: 'step-finish',
|
|
6627
|
+
},
|
|
6628
|
+
{
|
|
6629
|
+
payload: {
|
|
6630
|
+
id: expect.any(String),
|
|
6631
|
+
},
|
|
6632
|
+
type: 'step-start',
|
|
6633
|
+
},
|
|
6634
|
+
{
|
|
6635
|
+
payload: {
|
|
6636
|
+
id: expect.any(String),
|
|
6637
|
+
output: {
|
|
6638
|
+
prompt: 'Capital of France, just the name',
|
|
6639
|
+
},
|
|
6640
|
+
status: 'success',
|
|
6641
|
+
},
|
|
6642
|
+
type: 'step-result',
|
|
6643
|
+
},
|
|
6644
|
+
{
|
|
6645
|
+
payload: {
|
|
6646
|
+
id: expect.any(String),
|
|
6647
|
+
metadata: {},
|
|
6648
|
+
},
|
|
6649
|
+
type: 'step-finish',
|
|
6650
|
+
},
|
|
6651
|
+
{
|
|
6652
|
+
payload: {
|
|
6653
|
+
id: 'test-agent-1',
|
|
6654
|
+
},
|
|
6655
|
+
type: 'step-start',
|
|
6656
|
+
},
|
|
6657
|
+
{
|
|
6658
|
+
args: {
|
|
6659
|
+
prompt: 'Capital of France, just the name',
|
|
6660
|
+
},
|
|
6661
|
+
name: 'test-agent-1',
|
|
6662
|
+
type: 'tool-call-streaming-start',
|
|
6663
|
+
},
|
|
6664
|
+
{
|
|
6665
|
+
args: {
|
|
6666
|
+
prompt: 'Capital of France, just the name',
|
|
6667
|
+
},
|
|
6668
|
+
argsTextDelta: 'Paris',
|
|
6669
|
+
name: 'test-agent-1',
|
|
6670
|
+
type: 'tool-call-delta',
|
|
6671
|
+
},
|
|
6672
|
+
{
|
|
6673
|
+
payload: {
|
|
6674
|
+
id: 'test-agent-1',
|
|
6675
|
+
output: {
|
|
6676
|
+
text: 'Paris',
|
|
6677
|
+
},
|
|
6678
|
+
status: 'success',
|
|
6679
|
+
},
|
|
6680
|
+
type: 'step-result',
|
|
6681
|
+
},
|
|
6682
|
+
{
|
|
6683
|
+
payload: {
|
|
6684
|
+
id: expect.any(String),
|
|
6685
|
+
metadata: {},
|
|
6686
|
+
},
|
|
6687
|
+
type: 'step-finish',
|
|
6688
|
+
},
|
|
6689
|
+
{
|
|
6690
|
+
payload: {
|
|
6691
|
+
id: expect.any(String),
|
|
6692
|
+
},
|
|
6693
|
+
type: 'step-start',
|
|
6694
|
+
},
|
|
6695
|
+
{
|
|
6696
|
+
payload: {
|
|
6697
|
+
id: expect.any(String),
|
|
6698
|
+
output: {
|
|
6699
|
+
prompt: 'Capital of UK, just the name',
|
|
6700
|
+
},
|
|
6701
|
+
status: 'success',
|
|
6702
|
+
},
|
|
6703
|
+
type: 'step-result',
|
|
6704
|
+
},
|
|
6705
|
+
{
|
|
6706
|
+
payload: {
|
|
6707
|
+
id: expect.any(String),
|
|
6708
|
+
metadata: {},
|
|
6709
|
+
},
|
|
6710
|
+
type: 'step-finish',
|
|
6711
|
+
},
|
|
6712
|
+
{
|
|
6713
|
+
payload: {
|
|
6714
|
+
id: expect.any(String),
|
|
6715
|
+
},
|
|
6716
|
+
type: 'step-start',
|
|
6717
|
+
},
|
|
6718
|
+
{
|
|
6719
|
+
args: {
|
|
6720
|
+
prompt: 'Capital of UK, just the name',
|
|
6721
|
+
},
|
|
6722
|
+
name: 'test-agent-2',
|
|
6723
|
+
type: 'tool-call-streaming-start',
|
|
6724
|
+
},
|
|
6725
|
+
{
|
|
6726
|
+
args: {
|
|
6727
|
+
prompt: 'Capital of UK, just the name',
|
|
6728
|
+
},
|
|
6729
|
+
argsTextDelta: 'London',
|
|
6730
|
+
name: 'test-agent-2',
|
|
6731
|
+
type: 'tool-call-delta',
|
|
6732
|
+
},
|
|
6733
|
+
{
|
|
6734
|
+
payload: {
|
|
6735
|
+
id: expect.any(String),
|
|
6736
|
+
output: {
|
|
6737
|
+
text: 'London',
|
|
6738
|
+
},
|
|
6739
|
+
status: 'success',
|
|
6740
|
+
},
|
|
6741
|
+
type: 'step-result',
|
|
6742
|
+
},
|
|
6743
|
+
{
|
|
6744
|
+
payload: {
|
|
6745
|
+
id: expect.any(String),
|
|
6746
|
+
metadata: {},
|
|
6747
|
+
},
|
|
6748
|
+
type: 'step-finish',
|
|
6749
|
+
},
|
|
6750
|
+
{
|
|
6751
|
+
payload: {
|
|
6752
|
+
runId: 'test-run-id',
|
|
6753
|
+
},
|
|
6754
|
+
type: 'finish',
|
|
6755
|
+
},
|
|
6756
|
+
]);
|
|
6757
|
+
});
|
|
6758
|
+
});
|
|
5521
6759
|
}, 40e3);
|