@mastra/inngest 0.0.0-mcp-changeset-20250707162621 → 0.0.0-memory-system-message-error-20250813233316

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/src/index.test.ts CHANGED
@@ -4258,6 +4258,124 @@ describe('MastraInngestWorkflow', () => {
4258
4258
 
4259
4259
  expect(promptAgentAction).toHaveBeenCalledTimes(2);
4260
4260
  });
4261
+
4262
+ it('should handle consecutive nested workflows with suspend/resume', async ctx => {
4263
+ const inngest = new Inngest({
4264
+ id: 'mastra',
4265
+ baseUrl: `http://localhost:${(ctx as any).inngestPort}`,
4266
+ middleware: [realtimeMiddleware()],
4267
+ });
4268
+
4269
+ const { createWorkflow, createStep } = init(inngest);
4270
+
4271
+ const step1 = vi.fn().mockImplementation(async ({ resumeData, suspend }) => {
4272
+ if (!resumeData?.suspect) {
4273
+ return await suspend({ message: 'What is the suspect?' });
4274
+ }
4275
+ return { suspect: resumeData.suspect };
4276
+ });
4277
+ const step1Definition = createStep({
4278
+ id: 'step-1',
4279
+ inputSchema: z.object({ suspect: z.string() }),
4280
+ outputSchema: z.object({ suspect: z.string() }),
4281
+ suspendSchema: z.object({ message: z.string() }),
4282
+ resumeSchema: z.object({ suspect: z.string() }),
4283
+ execute: step1,
4284
+ });
4285
+
4286
+ const step2 = vi.fn().mockImplementation(async ({ resumeData, suspend }) => {
4287
+ if (!resumeData?.suspect) {
4288
+ return await suspend({ message: 'What is the second suspect?' });
4289
+ }
4290
+ return { suspect: resumeData.suspect };
4291
+ });
4292
+ const step2Definition = createStep({
4293
+ id: 'step-2',
4294
+ inputSchema: z.object({ suspect: z.string() }),
4295
+ outputSchema: z.object({ suspect: z.string() }),
4296
+ suspendSchema: z.object({ message: z.string() }),
4297
+ resumeSchema: z.object({ suspect: z.string() }),
4298
+ execute: step2,
4299
+ });
4300
+
4301
+ const subWorkflow1 = createWorkflow({
4302
+ id: 'sub-workflow-1',
4303
+ inputSchema: z.object({ suspect: z.string() }),
4304
+ outputSchema: z.object({ suspect: z.string() }),
4305
+ })
4306
+ .then(step1Definition)
4307
+ .commit();
4308
+
4309
+ const subWorkflow2 = createWorkflow({
4310
+ id: 'sub-workflow-2',
4311
+ inputSchema: z.object({ suspect: z.string() }),
4312
+ outputSchema: z.object({ suspect: z.string() }),
4313
+ })
4314
+ .then(step2Definition)
4315
+ .commit();
4316
+
4317
+ const mainWorkflow = createWorkflow({
4318
+ id: 'main-workflow',
4319
+ inputSchema: z.object({ suspect: z.string() }),
4320
+ outputSchema: z.object({ suspect: z.string() }),
4321
+ })
4322
+ .then(subWorkflow1)
4323
+ .then(subWorkflow2)
4324
+ .commit();
4325
+
4326
+ const mastra = new Mastra({
4327
+ logger: false,
4328
+ storage: new DefaultStorage({
4329
+ url: ':memory:',
4330
+ }),
4331
+ workflows: { mainWorkflow },
4332
+ server: {
4333
+ apiRoutes: [
4334
+ {
4335
+ path: '/inngest/api',
4336
+ method: 'ALL',
4337
+ createHandler: async ({ mastra }) => inngestServe({ mastra, inngest }),
4338
+ },
4339
+ ],
4340
+ },
4341
+ });
4342
+
4343
+ const app = await createHonoServer(mastra);
4344
+
4345
+ const srv = (globServer = serve({
4346
+ fetch: app.fetch,
4347
+ port: (ctx as any).handlerPort,
4348
+ }));
4349
+ await resetInngest();
4350
+
4351
+ const run = await mainWorkflow.createRunAsync();
4352
+
4353
+ const initialResult = await run.start({ inputData: { suspect: 'initial-suspect' } });
4354
+ expect(initialResult.status).toBe('suspended');
4355
+
4356
+ const firstResumeResult = await run.resume({
4357
+ step: ['sub-workflow-1', 'step-1'],
4358
+ resumeData: { suspect: 'first-suspect' },
4359
+ });
4360
+ expect(firstResumeResult.status).toBe('suspended');
4361
+
4362
+ const secondResumeResult = await run.resume({
4363
+ step: ['sub-workflow-2', 'step-2'],
4364
+ resumeData: { suspect: 'second-suspect' },
4365
+ });
4366
+
4367
+ expect(step1).toHaveBeenCalledTimes(2);
4368
+ expect(step2).toHaveBeenCalledTimes(2);
4369
+ expect(secondResumeResult.status).toBe('success');
4370
+ expect(secondResumeResult.steps['sub-workflow-1']).toMatchObject({
4371
+ status: 'success',
4372
+ });
4373
+ expect(secondResumeResult.steps['sub-workflow-2']).toMatchObject({
4374
+ status: 'success',
4375
+ });
4376
+
4377
+ srv.close();
4378
+ });
4261
4379
  });
4262
4380
 
4263
4381
  describe('Accessing Mastra', () => {
@@ -6219,6 +6337,176 @@ describe('MastraInngestWorkflow', () => {
6219
6337
  // @ts-ignore
6220
6338
  expect(result?.steps.step1.output.injectedValue).toBe(testValue + '2');
6221
6339
  });
6340
+
6341
+ it('should have access to runtimeContext from before suspension during workflow resume', async ctx => {
6342
+ const inngest = new Inngest({
6343
+ id: 'mastra',
6344
+ baseUrl: `http://localhost:${(ctx as any).inngestPort}`,
6345
+ });
6346
+
6347
+ const { createWorkflow, createStep } = init(inngest);
6348
+
6349
+ const testValue = 'test-dependency';
6350
+ const resumeStep = createStep({
6351
+ id: 'resume',
6352
+ inputSchema: z.object({ value: z.number() }),
6353
+ outputSchema: z.object({ value: z.number() }),
6354
+ resumeSchema: z.object({ value: z.number() }),
6355
+ suspendSchema: z.object({ message: z.string() }),
6356
+ execute: async ({ inputData, resumeData, suspend }) => {
6357
+ const finalValue = (resumeData?.value ?? 0) + inputData.value;
6358
+
6359
+ if (!resumeData?.value || finalValue < 10) {
6360
+ return await suspend({
6361
+ message: `Please provide additional information. now value is ${inputData.value}`,
6362
+ });
6363
+ }
6364
+
6365
+ return { value: finalValue };
6366
+ },
6367
+ });
6368
+
6369
+ const incrementStep = createStep({
6370
+ id: 'increment',
6371
+ inputSchema: z.object({
6372
+ value: z.number(),
6373
+ }),
6374
+ outputSchema: z.object({
6375
+ value: z.number(),
6376
+ }),
6377
+ execute: async ({ inputData, runtimeContext }) => {
6378
+ runtimeContext.set('testKey', testValue);
6379
+ return {
6380
+ value: inputData.value + 1,
6381
+ };
6382
+ },
6383
+ });
6384
+
6385
+ const incrementWorkflow = createWorkflow({
6386
+ id: 'increment-workflow',
6387
+ inputSchema: z.object({ value: z.number() }),
6388
+ outputSchema: z.object({ value: z.number() }),
6389
+ })
6390
+ .then(incrementStep)
6391
+ .then(resumeStep)
6392
+ .then(
6393
+ createStep({
6394
+ id: 'final',
6395
+ inputSchema: z.object({ value: z.number() }),
6396
+ outputSchema: z.object({ value: z.number() }),
6397
+ execute: async ({ inputData, runtimeContext }) => {
6398
+ const testKey = runtimeContext.get('testKey');
6399
+ expect(testKey).toBe(testValue);
6400
+ return { value: inputData.value };
6401
+ },
6402
+ }),
6403
+ )
6404
+ .commit();
6405
+
6406
+ new Mastra({
6407
+ logger: false,
6408
+ storage: testStorage,
6409
+ workflows: { incrementWorkflow },
6410
+ });
6411
+
6412
+ const run = await incrementWorkflow.createRunAsync();
6413
+ const result = await run.start({ inputData: { value: 0 } });
6414
+ expect(result.status).toBe('suspended');
6415
+
6416
+ const resumeResult = await run.resume({
6417
+ resumeData: { value: 21 },
6418
+ step: ['resume'],
6419
+ });
6420
+
6421
+ expect(resumeResult.status).toBe('success');
6422
+ });
6423
+
6424
+ it('should not show removed runtimeContext values in subsequent steps', async ctx => {
6425
+ const inngest = new Inngest({
6426
+ id: 'mastra',
6427
+ baseUrl: `http://localhost:${(ctx as any).inngestPort}`,
6428
+ });
6429
+
6430
+ const { createWorkflow, createStep } = init(inngest);
6431
+ const testValue = 'test-dependency';
6432
+ const resumeStep = createStep({
6433
+ id: 'resume',
6434
+ inputSchema: z.object({ value: z.number() }),
6435
+ outputSchema: z.object({ value: z.number() }),
6436
+ resumeSchema: z.object({ value: z.number() }),
6437
+ suspendSchema: z.object({ message: z.string() }),
6438
+ execute: async ({ inputData, resumeData, suspend, runtimeContext }) => {
6439
+ const finalValue = (resumeData?.value ?? 0) + inputData.value;
6440
+
6441
+ if (!resumeData?.value || finalValue < 10) {
6442
+ return await suspend({
6443
+ message: `Please provide additional information. now value is ${inputData.value}`,
6444
+ });
6445
+ }
6446
+
6447
+ const testKey = runtimeContext.get('testKey');
6448
+ expect(testKey).toBe(testValue);
6449
+
6450
+ runtimeContext.delete('testKey');
6451
+
6452
+ return { value: finalValue };
6453
+ },
6454
+ });
6455
+
6456
+ const incrementStep = createStep({
6457
+ id: 'increment',
6458
+ inputSchema: z.object({
6459
+ value: z.number(),
6460
+ }),
6461
+ outputSchema: z.object({
6462
+ value: z.number(),
6463
+ }),
6464
+ execute: async ({ inputData, runtimeContext }) => {
6465
+ runtimeContext.set('testKey', testValue);
6466
+ return {
6467
+ value: inputData.value + 1,
6468
+ };
6469
+ },
6470
+ });
6471
+
6472
+ const incrementWorkflow = createWorkflow({
6473
+ id: 'increment-workflow',
6474
+ inputSchema: z.object({ value: z.number() }),
6475
+ outputSchema: z.object({ value: z.number() }),
6476
+ })
6477
+ .then(incrementStep)
6478
+ .then(resumeStep)
6479
+ .then(
6480
+ createStep({
6481
+ id: 'final',
6482
+ inputSchema: z.object({ value: z.number() }),
6483
+ outputSchema: z.object({ value: z.number() }),
6484
+ execute: async ({ inputData, runtimeContext }) => {
6485
+ const testKey = runtimeContext.get('testKey');
6486
+ expect(testKey).toBeUndefined();
6487
+ return { value: inputData.value };
6488
+ },
6489
+ }),
6490
+ )
6491
+ .commit();
6492
+
6493
+ new Mastra({
6494
+ logger: false,
6495
+ storage: testStorage,
6496
+ workflows: { incrementWorkflow },
6497
+ });
6498
+
6499
+ const run = await incrementWorkflow.createRunAsync();
6500
+ const result = await run.start({ inputData: { value: 0 } });
6501
+ expect(result.status).toBe('suspended');
6502
+
6503
+ const resumeResult = await run.resume({
6504
+ resumeData: { value: 21 },
6505
+ step: ['resume'],
6506
+ });
6507
+
6508
+ expect(resumeResult.status).toBe('success');
6509
+ });
6222
6510
  });
6223
6511
 
6224
6512
  describe('Access to inngest step primitives', () => {
package/src/index.ts CHANGED
@@ -3,7 +3,7 @@ import type { ReadableStream } from 'node:stream/web';
3
3
  import { subscribe } from '@inngest/realtime';
4
4
  import type { Agent, Mastra, ToolExecutionContext, WorkflowRun, WorkflowRuns } from '@mastra/core';
5
5
  import { RuntimeContext } from '@mastra/core/di';
6
- import { Tool } from '@mastra/core/tools';
6
+ import { Tool, ToolStream } from '@mastra/core/tools';
7
7
  import { Workflow, Run, DefaultExecutionEngine } from '@mastra/core/workflows';
8
8
  import type {
9
9
  ExecuteFunction,
@@ -20,6 +20,7 @@ import type {
20
20
  Emitter,
21
21
  WatchEvent,
22
22
  StreamEvent,
23
+ ChunkType,
23
24
  } from '@mastra/core/workflows';
24
25
  import { EMITTER_SYMBOL } from '@mastra/core/workflows/_constants';
25
26
  import type { Span } from '@opentelemetry/api';
@@ -231,6 +232,7 @@ export class InngestRun<
231
232
  data: {
232
233
  inputData: params.resumeData,
233
234
  runId: this.runId,
235
+ workflowId: this.workflowId,
234
236
  stepResults: snapshot?.context as any,
235
237
  resume: {
236
238
  steps,
@@ -968,6 +970,7 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
968
970
  emitter,
969
971
  abortController,
970
972
  runtimeContext,
973
+ writableStream,
971
974
  }: {
972
975
  workflowId: string;
973
976
  runId: string;
@@ -982,6 +985,7 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
982
985
  emitter: Emitter;
983
986
  abortController: AbortController;
984
987
  runtimeContext: RuntimeContext;
988
+ writableStream?: WritableStream<ChunkType>;
985
989
  }): Promise<StepResult<any, any, any, any>> {
986
990
  return super.executeStep({
987
991
  workflowId,
@@ -994,6 +998,7 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
994
998
  emitter,
995
999
  abortController,
996
1000
  runtimeContext,
1001
+ writableStream,
997
1002
  });
998
1003
  }
999
1004
 
@@ -1010,6 +1015,7 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
1010
1015
  emitter,
1011
1016
  abortController,
1012
1017
  runtimeContext,
1018
+ writableStream,
1013
1019
  }: {
1014
1020
  workflowId: string;
1015
1021
  runId: string;
@@ -1033,13 +1039,16 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
1033
1039
  emitter: Emitter;
1034
1040
  abortController: AbortController;
1035
1041
  runtimeContext: RuntimeContext;
1042
+ writableStream?: WritableStream<ChunkType>;
1036
1043
  }): Promise<void> {
1037
1044
  let { duration, fn } = entry;
1038
1045
 
1039
1046
  if (fn) {
1047
+ const stepCallId = randomUUID();
1040
1048
  duration = await this.inngestStep.run(`workflow.${workflowId}.sleep.${entry.id}`, async () => {
1041
1049
  return await fn({
1042
1050
  runId,
1051
+ workflowId,
1043
1052
  mastra: this.mastra!,
1044
1053
  runtimeContext,
1045
1054
  inputData: prevOutput,
@@ -1067,6 +1076,15 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
1067
1076
  [EMITTER_SYMBOL]: emitter,
1068
1077
  engine: { step: this.inngestStep },
1069
1078
  abortSignal: abortController?.signal,
1079
+ writer: new ToolStream(
1080
+ {
1081
+ prefix: 'step',
1082
+ callId: stepCallId,
1083
+ name: 'sleep',
1084
+ runId,
1085
+ },
1086
+ writableStream,
1087
+ ),
1070
1088
  });
1071
1089
  });
1072
1090
  }
@@ -1083,6 +1101,7 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
1083
1101
  emitter,
1084
1102
  abortController,
1085
1103
  runtimeContext,
1104
+ writableStream,
1086
1105
  }: {
1087
1106
  workflowId: string;
1088
1107
  runId: string;
@@ -1106,13 +1125,16 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
1106
1125
  emitter: Emitter;
1107
1126
  abortController: AbortController;
1108
1127
  runtimeContext: RuntimeContext;
1128
+ writableStream?: WritableStream<ChunkType>;
1109
1129
  }): Promise<void> {
1110
1130
  let { date, fn } = entry;
1111
1131
 
1112
1132
  if (fn) {
1113
1133
  date = await this.inngestStep.run(`workflow.${workflowId}.sleepUntil.${entry.id}`, async () => {
1134
+ const stepCallId = randomUUID();
1114
1135
  return await fn({
1115
1136
  runId,
1137
+ workflowId,
1116
1138
  mastra: this.mastra!,
1117
1139
  runtimeContext,
1118
1140
  inputData: prevOutput,
@@ -1140,6 +1162,15 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
1140
1162
  [EMITTER_SYMBOL]: emitter,
1141
1163
  engine: { step: this.inngestStep },
1142
1164
  abortSignal: abortController?.signal,
1165
+ writer: new ToolStream(
1166
+ {
1167
+ prefix: 'step',
1168
+ callId: stepCallId,
1169
+ name: 'sleep',
1170
+ runId,
1171
+ },
1172
+ writableStream,
1173
+ ),
1143
1174
  });
1144
1175
  });
1145
1176
  }
@@ -1173,6 +1204,7 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
1173
1204
  emitter,
1174
1205
  abortController,
1175
1206
  runtimeContext,
1207
+ writableStream,
1176
1208
  }: {
1177
1209
  step: Step<string, any, any>;
1178
1210
  stepResults: Record<string, StepResult<any, any, any, any>>;
@@ -1186,6 +1218,7 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
1186
1218
  emitter: Emitter;
1187
1219
  abortController: AbortController;
1188
1220
  runtimeContext: RuntimeContext;
1221
+ writableStream?: WritableStream<ChunkType>;
1189
1222
  }): Promise<StepResult<any, any, any, any>> {
1190
1223
  const startedAt = await this.inngestStep.run(
1191
1224
  `workflow.${executionContext.workflowId}.run.${executionContext.runId}.step.${step.id}.running_ev`,
@@ -1429,6 +1462,7 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
1429
1462
  runId: executionContext.runId,
1430
1463
  mastra: this.mastra!,
1431
1464
  runtimeContext,
1465
+ writableStream,
1432
1466
  inputData: prevOutput,
1433
1467
  resumeData: resume?.steps[0] === step.id ? resume?.resumePayload : undefined,
1434
1468
  getInitData: () => stepResults?.input as any,
@@ -1575,6 +1609,7 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
1575
1609
  workflowStatus: 'success' | 'failed' | 'suspended' | 'running';
1576
1610
  result?: Record<string, any>;
1577
1611
  error?: string | Error;
1612
+ runtimeContext: RuntimeContext;
1578
1613
  }) {
1579
1614
  await this.inngestStep.run(
1580
1615
  `workflow.${workflowId}.run.${runId}.path.${JSON.stringify(executionContext.executionPath)}.stepUpdate`,
@@ -1613,6 +1648,7 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
1613
1648
  emitter,
1614
1649
  abortController,
1615
1650
  runtimeContext,
1651
+ writableStream,
1616
1652
  }: {
1617
1653
  workflowId: string;
1618
1654
  runId: string;
@@ -1635,6 +1671,7 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
1635
1671
  emitter: Emitter;
1636
1672
  abortController: AbortController;
1637
1673
  runtimeContext: RuntimeContext;
1674
+ writableStream?: WritableStream<ChunkType>;
1638
1675
  }): Promise<StepResult<any, any, any, any>> {
1639
1676
  let execResults: any;
1640
1677
  const truthyIndexes = (
@@ -1644,6 +1681,7 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
1644
1681
  try {
1645
1682
  const result = await cond({
1646
1683
  runId,
1684
+ workflowId,
1647
1685
  mastra: this.mastra!,
1648
1686
  runtimeContext,
1649
1687
  runCount: -1,
@@ -1673,6 +1711,15 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
1673
1711
  step: this.inngestStep,
1674
1712
  },
1675
1713
  abortSignal: abortController.signal,
1714
+ writer: new ToolStream(
1715
+ {
1716
+ prefix: 'step',
1717
+ callId: randomUUID(),
1718
+ name: 'conditional',
1719
+ runId,
1720
+ },
1721
+ writableStream,
1722
+ ),
1676
1723
  });
1677
1724
  return result ? index : null;
1678
1725
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
@@ -1706,6 +1753,7 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
1706
1753
  emitter,
1707
1754
  abortController,
1708
1755
  runtimeContext,
1756
+ writableStream,
1709
1757
  }),
1710
1758
  ),
1711
1759
  );
@@ -0,0 +1,9 @@
1
+ {
2
+ "extends": ["./tsconfig.json", "../../tsconfig.build.json"],
3
+ "compilerOptions": {
4
+ "outDir": "./dist",
5
+ "rootDir": "./src"
6
+ },
7
+ "include": ["src/**/*"],
8
+ "exclude": ["node_modules", "**/*.test.ts", "src/**/*.mock.ts"]
9
+ }
package/tsconfig.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "extends": "../../tsconfig.node.json",
3
- "include": ["src/**/*"],
3
+ "include": ["src/**/*", "tsup.config.ts"],
4
4
  "exclude": ["node_modules", "**/*.test.ts"]
5
5
  }
package/tsup.config.ts ADDED
@@ -0,0 +1,17 @@
1
+ import { generateTypes } from '@internal/types-builder';
2
+ import { defineConfig } from 'tsup';
3
+
4
+ export default defineConfig({
5
+ entry: ['src/index.ts'],
6
+ format: ['esm', 'cjs'],
7
+ clean: true,
8
+ dts: false,
9
+ splitting: true,
10
+ treeshake: {
11
+ preset: 'smallest',
12
+ },
13
+ sourcemap: true,
14
+ onSuccess: async () => {
15
+ await generateTypes(process.cwd());
16
+ },
17
+ });