@mastra/inngest 0.0.0-vnext-20251104230439 → 0.0.0-vnext-20251119160359
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/CHANGELOG.md +236 -3
- package/dist/index.cjs +293 -73
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +56 -25
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +295 -75
- package/dist/index.js.map +1 -1
- package/package.json +18 -13
package/dist/index.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { randomUUID } from 'crypto';
|
|
2
|
-
import { ReadableStream } from 'stream/web';
|
|
2
|
+
import { ReadableStream, WritableStream } from 'stream/web';
|
|
3
3
|
import { subscribe } from '@inngest/realtime';
|
|
4
4
|
import { RequestContext } from '@mastra/core/di';
|
|
5
|
-
import {
|
|
5
|
+
import { SpanType } from '@mastra/core/observability';
|
|
6
6
|
import { ChunkFrom, WorkflowRunOutput } from '@mastra/core/stream';
|
|
7
7
|
import { ToolStream, Tool } from '@mastra/core/tools';
|
|
8
|
-
import { Run, Workflow, DefaultExecutionEngine, createDeprecationProxy, getStepResult, runCountDeprecationMessage, validateStepInput } from '@mastra/core/workflows';
|
|
8
|
+
import { Run, createTimeTravelExecutionParams, Workflow, DefaultExecutionEngine, createDeprecationProxy, getStepResult, runCountDeprecationMessage, validateStepInput, validateStepResumeData } from '@mastra/core/workflows';
|
|
9
9
|
import { EMITTER_SYMBOL, STREAM_FORMAT_SYMBOL } from '@mastra/core/workflows/_constants';
|
|
10
10
|
import { NonRetriableError, RetryAfterError } from 'inngest';
|
|
11
11
|
import { serve as serve$1 } from 'inngest/hono';
|
|
@@ -80,12 +80,6 @@ var InngestRun = class extends Run {
|
|
|
80
80
|
}
|
|
81
81
|
return runs?.[0];
|
|
82
82
|
}
|
|
83
|
-
async sendEvent(event, data) {
|
|
84
|
-
await this.inngest.send({
|
|
85
|
-
name: `user-event-${event}`,
|
|
86
|
-
data
|
|
87
|
-
});
|
|
88
|
-
}
|
|
89
83
|
async cancel() {
|
|
90
84
|
const storage = this.#mastra?.getStorage();
|
|
91
85
|
await this.inngest.send({
|
|
@@ -105,7 +99,8 @@ var InngestRun = class extends Run {
|
|
|
105
99
|
resourceId: this.resourceId,
|
|
106
100
|
snapshot: {
|
|
107
101
|
...snapshot,
|
|
108
|
-
status: "canceled"
|
|
102
|
+
status: "canceled",
|
|
103
|
+
value: snapshot.value
|
|
109
104
|
}
|
|
110
105
|
});
|
|
111
106
|
}
|
|
@@ -127,14 +122,15 @@ var InngestRun = class extends Run {
|
|
|
127
122
|
snapshot: {
|
|
128
123
|
runId: this.runId,
|
|
129
124
|
serializedStepGraph: this.serializedStepGraph,
|
|
125
|
+
status: "running",
|
|
130
126
|
value: {},
|
|
131
127
|
context: {},
|
|
132
128
|
activePaths: [],
|
|
133
129
|
suspendedPaths: {},
|
|
130
|
+
activeStepsPath: {},
|
|
134
131
|
resumeLabels: {},
|
|
135
132
|
waitingPaths: {},
|
|
136
|
-
timestamp: Date.now()
|
|
137
|
-
status: "running"
|
|
133
|
+
timestamp: Date.now()
|
|
138
134
|
}
|
|
139
135
|
});
|
|
140
136
|
const inputDataToUse = await this._validateInput(inputData);
|
|
@@ -178,9 +174,14 @@ var InngestRun = class extends Run {
|
|
|
178
174
|
}
|
|
179
175
|
async _resume(params) {
|
|
180
176
|
const storage = this.#mastra?.getStorage();
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
177
|
+
let steps = [];
|
|
178
|
+
if (typeof params.step === "string") {
|
|
179
|
+
steps = params.step.split(".");
|
|
180
|
+
} else {
|
|
181
|
+
steps = (Array.isArray(params.step) ? params.step : [params.step]).map(
|
|
182
|
+
(step) => typeof step === "string" ? step : step?.id
|
|
183
|
+
);
|
|
184
|
+
}
|
|
184
185
|
const snapshot = await storage?.loadWorkflowSnapshot({
|
|
185
186
|
workflowName: this.workflowId,
|
|
186
187
|
runId: this.runId
|
|
@@ -199,9 +200,99 @@ var InngestRun = class extends Run {
|
|
|
199
200
|
steps,
|
|
200
201
|
stepResults: snapshot?.context,
|
|
201
202
|
resumePayload: resumeDataToUse,
|
|
202
|
-
|
|
203
|
-
|
|
203
|
+
resumePath: steps?.[0] ? snapshot?.suspendedPaths?.[steps?.[0]] : void 0
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
});
|
|
207
|
+
const eventId = eventOutput.ids[0];
|
|
208
|
+
if (!eventId) {
|
|
209
|
+
throw new Error("Event ID is not set");
|
|
210
|
+
}
|
|
211
|
+
const runOutput = await this.getRunOutput(eventId);
|
|
212
|
+
const result = runOutput?.output?.result;
|
|
213
|
+
if (result.status === "failed") {
|
|
214
|
+
result.error = new Error(result.error);
|
|
215
|
+
}
|
|
216
|
+
return result;
|
|
217
|
+
}
|
|
218
|
+
async timeTravel(params) {
|
|
219
|
+
const p = this._timeTravel(params).then((result) => {
|
|
220
|
+
if (result.status !== "suspended") {
|
|
221
|
+
this.closeStreamAction?.().catch(() => {
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
return result;
|
|
225
|
+
});
|
|
226
|
+
this.executionResults = p;
|
|
227
|
+
return p;
|
|
228
|
+
}
|
|
229
|
+
async _timeTravel(params) {
|
|
230
|
+
if (!params.step || Array.isArray(params.step) && params.step?.length === 0) {
|
|
231
|
+
throw new Error("Step is required and must be a valid step or array of steps");
|
|
232
|
+
}
|
|
233
|
+
let steps = [];
|
|
234
|
+
if (typeof params.step === "string") {
|
|
235
|
+
steps = params.step.split(".");
|
|
236
|
+
} else {
|
|
237
|
+
steps = (Array.isArray(params.step) ? params.step : [params.step]).map(
|
|
238
|
+
(step) => typeof step === "string" ? step : step?.id
|
|
239
|
+
);
|
|
240
|
+
}
|
|
241
|
+
if (steps.length === 0) {
|
|
242
|
+
throw new Error("No steps provided to timeTravel");
|
|
243
|
+
}
|
|
244
|
+
const storage = this.#mastra?.getStorage();
|
|
245
|
+
const snapshot = await storage?.loadWorkflowSnapshot({
|
|
246
|
+
workflowName: this.workflowId,
|
|
247
|
+
runId: this.runId
|
|
248
|
+
});
|
|
249
|
+
if (!snapshot) {
|
|
250
|
+
await storage?.persistWorkflowSnapshot({
|
|
251
|
+
workflowName: this.workflowId,
|
|
252
|
+
runId: this.runId,
|
|
253
|
+
resourceId: this.resourceId,
|
|
254
|
+
snapshot: {
|
|
255
|
+
runId: this.runId,
|
|
256
|
+
serializedStepGraph: this.serializedStepGraph,
|
|
257
|
+
status: "pending",
|
|
258
|
+
value: {},
|
|
259
|
+
context: {},
|
|
260
|
+
activePaths: [],
|
|
261
|
+
suspendedPaths: {},
|
|
262
|
+
activeStepsPath: {},
|
|
263
|
+
resumeLabels: {},
|
|
264
|
+
waitingPaths: {},
|
|
265
|
+
timestamp: Date.now()
|
|
204
266
|
}
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
if (snapshot?.status === "running") {
|
|
270
|
+
throw new Error("This workflow run is still running, cannot time travel");
|
|
271
|
+
}
|
|
272
|
+
let inputDataToUse = params.inputData;
|
|
273
|
+
if (inputDataToUse && steps.length === 1) {
|
|
274
|
+
inputDataToUse = await this._validateTimetravelInputData(params.inputData, this.workflowSteps[steps[0]]);
|
|
275
|
+
}
|
|
276
|
+
const timeTravelData = createTimeTravelExecutionParams({
|
|
277
|
+
steps,
|
|
278
|
+
inputData: inputDataToUse,
|
|
279
|
+
resumeData: params.resumeData,
|
|
280
|
+
context: params.context,
|
|
281
|
+
nestedStepsContext: params.nestedStepsContext,
|
|
282
|
+
snapshot: snapshot ?? { context: {} },
|
|
283
|
+
graph: this.executionGraph,
|
|
284
|
+
initialState: params.initialState
|
|
285
|
+
});
|
|
286
|
+
const eventOutput = await this.inngest.send({
|
|
287
|
+
name: `workflow.${this.workflowId}`,
|
|
288
|
+
data: {
|
|
289
|
+
initialState: timeTravelData.state,
|
|
290
|
+
runId: this.runId,
|
|
291
|
+
workflowId: this.workflowId,
|
|
292
|
+
stepResults: timeTravelData.stepResults,
|
|
293
|
+
timeTravel: timeTravelData,
|
|
294
|
+
tracingOptions: params.tracingOptions,
|
|
295
|
+
outputOptions: params.outputOptions
|
|
205
296
|
}
|
|
206
297
|
});
|
|
207
298
|
const eventId = eventOutput.ids[0];
|
|
@@ -364,6 +455,75 @@ var InngestRun = class extends Run {
|
|
|
364
455
|
streamVNext(args = {}) {
|
|
365
456
|
return this.stream(args);
|
|
366
457
|
}
|
|
458
|
+
timeTravelStream({
|
|
459
|
+
inputData,
|
|
460
|
+
resumeData,
|
|
461
|
+
initialState,
|
|
462
|
+
step,
|
|
463
|
+
context,
|
|
464
|
+
nestedStepsContext,
|
|
465
|
+
requestContext,
|
|
466
|
+
tracingOptions,
|
|
467
|
+
outputOptions
|
|
468
|
+
}) {
|
|
469
|
+
this.closeStreamAction = async () => {
|
|
470
|
+
};
|
|
471
|
+
const self = this;
|
|
472
|
+
const stream = new ReadableStream({
|
|
473
|
+
async start(controller) {
|
|
474
|
+
const unwatch = self.watch(async ({ type, from = ChunkFrom.WORKFLOW, payload }) => {
|
|
475
|
+
controller.enqueue({
|
|
476
|
+
type,
|
|
477
|
+
runId: self.runId,
|
|
478
|
+
from,
|
|
479
|
+
payload: {
|
|
480
|
+
stepName: payload?.id,
|
|
481
|
+
...payload
|
|
482
|
+
}
|
|
483
|
+
});
|
|
484
|
+
});
|
|
485
|
+
self.closeStreamAction = async () => {
|
|
486
|
+
unwatch();
|
|
487
|
+
try {
|
|
488
|
+
await controller.close();
|
|
489
|
+
} catch (err) {
|
|
490
|
+
console.error("Error closing stream:", err);
|
|
491
|
+
}
|
|
492
|
+
};
|
|
493
|
+
const executionResultsPromise = self._timeTravel({
|
|
494
|
+
inputData,
|
|
495
|
+
step,
|
|
496
|
+
context,
|
|
497
|
+
nestedStepsContext,
|
|
498
|
+
resumeData,
|
|
499
|
+
initialState,
|
|
500
|
+
requestContext,
|
|
501
|
+
tracingOptions,
|
|
502
|
+
outputOptions
|
|
503
|
+
});
|
|
504
|
+
self.executionResults = executionResultsPromise;
|
|
505
|
+
let executionResults;
|
|
506
|
+
try {
|
|
507
|
+
executionResults = await executionResultsPromise;
|
|
508
|
+
self.closeStreamAction?.().catch(() => {
|
|
509
|
+
});
|
|
510
|
+
if (self.streamOutput) {
|
|
511
|
+
self.streamOutput.updateResults(executionResults);
|
|
512
|
+
}
|
|
513
|
+
} catch (err) {
|
|
514
|
+
self.streamOutput?.rejectResults(err);
|
|
515
|
+
self.closeStreamAction?.().catch(() => {
|
|
516
|
+
});
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
});
|
|
520
|
+
this.streamOutput = new WorkflowRunOutput({
|
|
521
|
+
runId: this.runId,
|
|
522
|
+
workflowId: this.workflowId,
|
|
523
|
+
stream
|
|
524
|
+
});
|
|
525
|
+
return this.streamOutput;
|
|
526
|
+
}
|
|
367
527
|
};
|
|
368
528
|
var InngestWorkflow = class _InngestWorkflow extends Workflow {
|
|
369
529
|
#mastra;
|
|
@@ -373,6 +533,7 @@ var InngestWorkflow = class _InngestWorkflow extends Workflow {
|
|
|
373
533
|
constructor(params, inngest) {
|
|
374
534
|
const { concurrency, rateLimit, throttle, debounce, priority, ...workflowParams } = params;
|
|
375
535
|
super(workflowParams);
|
|
536
|
+
this.engineType = "inngest";
|
|
376
537
|
const flowControlEntries = Object.entries({ concurrency, rateLimit, throttle, debounce, priority }).filter(
|
|
377
538
|
([_, value]) => value !== void 0
|
|
378
539
|
);
|
|
@@ -428,7 +589,9 @@ var InngestWorkflow = class _InngestWorkflow extends Workflow {
|
|
|
428
589
|
mastra: this.#mastra,
|
|
429
590
|
retryConfig: this.retryConfig,
|
|
430
591
|
cleanup: () => this.runs.delete(runIdToUse),
|
|
431
|
-
workflowSteps: this.steps
|
|
592
|
+
workflowSteps: this.steps,
|
|
593
|
+
workflowEngineType: this.engineType,
|
|
594
|
+
validateInputs: this.options.validateInputs
|
|
432
595
|
},
|
|
433
596
|
this.inngest
|
|
434
597
|
);
|
|
@@ -449,13 +612,13 @@ var InngestWorkflow = class _InngestWorkflow extends Workflow {
|
|
|
449
612
|
value: {},
|
|
450
613
|
context: {},
|
|
451
614
|
activePaths: [],
|
|
615
|
+
activeStepsPath: {},
|
|
452
616
|
waitingPaths: {},
|
|
453
617
|
serializedStepGraph: this.serializedStepGraph,
|
|
454
618
|
suspendedPaths: {},
|
|
455
619
|
resumeLabels: {},
|
|
456
620
|
result: void 0,
|
|
457
621
|
error: void 0,
|
|
458
|
-
// @ts-ignore
|
|
459
622
|
timestamp: Date.now()
|
|
460
623
|
}
|
|
461
624
|
});
|
|
@@ -469,15 +632,14 @@ var InngestWorkflow = class _InngestWorkflow extends Workflow {
|
|
|
469
632
|
this.function = this.inngest.createFunction(
|
|
470
633
|
{
|
|
471
634
|
id: `workflow.${this.id}`,
|
|
472
|
-
|
|
473
|
-
retries: this.retryConfig?.attempts ?? 0,
|
|
635
|
+
retries: Math.min(this.retryConfig?.attempts ?? 0, 20),
|
|
474
636
|
cancelOn: [{ event: `cancel.workflow.${this.id}` }],
|
|
475
637
|
// Spread flow control configuration
|
|
476
638
|
...this.flowControlConfig
|
|
477
639
|
},
|
|
478
640
|
{ event: `workflow.${this.id}` },
|
|
479
641
|
async ({ event, step, attempt, publish }) => {
|
|
480
|
-
let { inputData, initialState, runId, resourceId, resume, outputOptions, format } = event.data;
|
|
642
|
+
let { inputData, initialState, runId, resourceId, resume, outputOptions, format, timeTravel } = event.data;
|
|
481
643
|
if (!runId) {
|
|
482
644
|
runId = await step.run(`workflow.${this.id}.runIdGen`, async () => {
|
|
483
645
|
return randomUUID();
|
|
@@ -519,9 +681,10 @@ var InngestWorkflow = class _InngestWorkflow extends Workflow {
|
|
|
519
681
|
requestContext: new RequestContext(),
|
|
520
682
|
// TODO
|
|
521
683
|
resume,
|
|
684
|
+
timeTravel,
|
|
522
685
|
format,
|
|
523
686
|
abortController: new AbortController(),
|
|
524
|
-
// currentSpan: undefined, // TODO: Pass actual parent
|
|
687
|
+
// currentSpan: undefined, // TODO: Pass actual parent Span from workflow execution context
|
|
525
688
|
outputOptions,
|
|
526
689
|
writableStream: new WritableStream({
|
|
527
690
|
write(chunk) {
|
|
@@ -571,13 +734,11 @@ function createStep(params, agentOptions) {
|
|
|
571
734
|
return {
|
|
572
735
|
id: params.name,
|
|
573
736
|
description: params.getDescription(),
|
|
574
|
-
// @ts-ignore
|
|
575
737
|
inputSchema: z.object({
|
|
576
738
|
prompt: z.string()
|
|
577
739
|
// resourceId: z.string().optional(),
|
|
578
740
|
// threadId: z.string().optional(),
|
|
579
741
|
}),
|
|
580
|
-
// @ts-ignore
|
|
581
742
|
outputSchema: z.object({
|
|
582
743
|
text: z.string()
|
|
583
744
|
}),
|
|
@@ -667,20 +828,36 @@ function createStep(params, agentOptions) {
|
|
|
667
828
|
}
|
|
668
829
|
return {
|
|
669
830
|
// TODO: tool probably should have strong id type
|
|
670
|
-
// @ts-ignore
|
|
671
831
|
id: params.id,
|
|
672
832
|
description: params.description,
|
|
673
833
|
inputSchema: params.inputSchema,
|
|
674
834
|
outputSchema: params.outputSchema,
|
|
675
|
-
execute: async ({
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
835
|
+
execute: async ({
|
|
836
|
+
inputData,
|
|
837
|
+
mastra,
|
|
838
|
+
requestContext,
|
|
839
|
+
tracingContext,
|
|
840
|
+
suspend,
|
|
841
|
+
resumeData,
|
|
842
|
+
runId,
|
|
843
|
+
workflowId,
|
|
844
|
+
state,
|
|
845
|
+
setState
|
|
846
|
+
}) => {
|
|
847
|
+
const toolContext = {
|
|
848
|
+
mastra,
|
|
679
849
|
requestContext,
|
|
680
850
|
tracingContext,
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
851
|
+
resumeData,
|
|
852
|
+
workflow: {
|
|
853
|
+
runId,
|
|
854
|
+
suspend,
|
|
855
|
+
workflowId,
|
|
856
|
+
state,
|
|
857
|
+
setState
|
|
858
|
+
}
|
|
859
|
+
};
|
|
860
|
+
return params.execute(inputData, toolContext);
|
|
684
861
|
},
|
|
685
862
|
component: "TOOL"
|
|
686
863
|
};
|
|
@@ -714,6 +891,8 @@ function init(inngest) {
|
|
|
714
891
|
suspendSchema: step.suspendSchema,
|
|
715
892
|
stateSchema: step.stateSchema,
|
|
716
893
|
execute: step.execute,
|
|
894
|
+
retries: step.retries,
|
|
895
|
+
scorers: step.scorers,
|
|
717
896
|
component: step.component
|
|
718
897
|
};
|
|
719
898
|
},
|
|
@@ -778,7 +957,7 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
|
|
|
778
957
|
}) {
|
|
779
958
|
let { duration, fn } = entry;
|
|
780
959
|
const sleepSpan = tracingContext?.currentSpan?.createChildSpan({
|
|
781
|
-
type:
|
|
960
|
+
type: SpanType.WORKFLOW_SLEEP,
|
|
782
961
|
name: `sleep: ${duration ? `${duration}ms` : "dynamic"}`,
|
|
783
962
|
attributes: {
|
|
784
963
|
durationMs: duration,
|
|
@@ -866,7 +1045,7 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
|
|
|
866
1045
|
}) {
|
|
867
1046
|
let { date, fn } = entry;
|
|
868
1047
|
const sleepUntilSpan = tracingContext?.currentSpan?.createChildSpan({
|
|
869
|
-
type:
|
|
1048
|
+
type: SpanType.WORKFLOW_SLEEP,
|
|
870
1049
|
name: `sleepUntil: ${date ? date.toISOString() : "dynamic"}`,
|
|
871
1050
|
attributes: {
|
|
872
1051
|
untilDate: date,
|
|
@@ -948,21 +1127,12 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
|
|
|
948
1127
|
throw e;
|
|
949
1128
|
}
|
|
950
1129
|
}
|
|
951
|
-
async executeWaitForEvent({ event, timeout }) {
|
|
952
|
-
const eventData = await this.inngestStep.waitForEvent(`user-event-${event}`, {
|
|
953
|
-
event: `user-event-${event}`,
|
|
954
|
-
timeout: timeout ?? 5e3
|
|
955
|
-
});
|
|
956
|
-
if (eventData === null) {
|
|
957
|
-
throw "Timeout waiting for event";
|
|
958
|
-
}
|
|
959
|
-
return eventData?.data;
|
|
960
|
-
}
|
|
961
1130
|
async executeStep({
|
|
962
1131
|
step,
|
|
963
1132
|
stepResults,
|
|
964
1133
|
executionContext,
|
|
965
1134
|
resume,
|
|
1135
|
+
timeTravel,
|
|
966
1136
|
prevOutput,
|
|
967
1137
|
emitter,
|
|
968
1138
|
abortController,
|
|
@@ -971,9 +1141,9 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
|
|
|
971
1141
|
writableStream,
|
|
972
1142
|
disableScorers
|
|
973
1143
|
}) {
|
|
974
|
-
const
|
|
1144
|
+
const stepSpan = tracingContext?.currentSpan?.createChildSpan({
|
|
975
1145
|
name: `workflow step: '${step.id}'`,
|
|
976
|
-
type:
|
|
1146
|
+
type: SpanType.WORKFLOW_STEP,
|
|
977
1147
|
input: prevOutput,
|
|
978
1148
|
attributes: {
|
|
979
1149
|
stepId: step.id
|
|
@@ -983,7 +1153,7 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
|
|
|
983
1153
|
const { inputData, validationError } = await validateStepInput({
|
|
984
1154
|
prevOutput,
|
|
985
1155
|
step,
|
|
986
|
-
validateInputs: this.options?.validateInputs ??
|
|
1156
|
+
validateInputs: this.options?.validateInputs ?? true
|
|
987
1157
|
});
|
|
988
1158
|
const startedAt = await this.inngestStep.run(
|
|
989
1159
|
`workflow.${executionContext.workflowId}.run.${executionContext.runId}.step.${step.id}.running_ev`,
|
|
@@ -1005,9 +1175,10 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
|
|
|
1005
1175
|
const isResume = !!resume?.steps?.length;
|
|
1006
1176
|
let result;
|
|
1007
1177
|
let runId;
|
|
1178
|
+
const isTimeTravel = !!(timeTravel && timeTravel.steps?.length > 1 && timeTravel.steps[0] === step.id);
|
|
1008
1179
|
try {
|
|
1009
1180
|
if (isResume) {
|
|
1010
|
-
runId = stepResults[resume?.steps?.[0]]?.suspendPayload?.__workflow_meta?.runId ?? randomUUID();
|
|
1181
|
+
runId = stepResults[resume?.steps?.[0] ?? ""]?.suspendPayload?.__workflow_meta?.runId ?? randomUUID();
|
|
1011
1182
|
const snapshot = await this.mastra?.getStorage()?.loadWorkflowSnapshot({
|
|
1012
1183
|
workflowName: step.id,
|
|
1013
1184
|
runId
|
|
@@ -1023,8 +1194,7 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
|
|
|
1023
1194
|
steps: resume.steps.slice(1),
|
|
1024
1195
|
stepResults: snapshot?.context,
|
|
1025
1196
|
resumePayload: resume.resumePayload,
|
|
1026
|
-
|
|
1027
|
-
resumePath: snapshot?.suspendedPaths?.[resume.steps?.[1]]
|
|
1197
|
+
resumePath: resume.steps?.[1] ? snapshot?.suspendedPaths?.[resume.steps?.[1]] : void 0
|
|
1028
1198
|
},
|
|
1029
1199
|
outputOptions: { includeState: true }
|
|
1030
1200
|
}
|
|
@@ -1032,6 +1202,32 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
|
|
|
1032
1202
|
result = invokeResp.result;
|
|
1033
1203
|
runId = invokeResp.runId;
|
|
1034
1204
|
executionContext.state = invokeResp.result.state;
|
|
1205
|
+
} else if (isTimeTravel) {
|
|
1206
|
+
const snapshot = await this.mastra?.getStorage()?.loadWorkflowSnapshot({
|
|
1207
|
+
workflowName: step.id,
|
|
1208
|
+
runId: executionContext.runId
|
|
1209
|
+
}) ?? { context: {} };
|
|
1210
|
+
const timeTravelParams = createTimeTravelExecutionParams({
|
|
1211
|
+
steps: timeTravel.steps.slice(1),
|
|
1212
|
+
inputData: timeTravel.inputData,
|
|
1213
|
+
resumeData: timeTravel.resumeData,
|
|
1214
|
+
context: timeTravel.nestedStepResults?.[step.id] ?? {},
|
|
1215
|
+
nestedStepsContext: timeTravel.nestedStepResults ?? {},
|
|
1216
|
+
snapshot,
|
|
1217
|
+
graph: step.buildExecutionGraph()
|
|
1218
|
+
});
|
|
1219
|
+
const invokeResp = await this.inngestStep.invoke(`workflow.${executionContext.workflowId}.step.${step.id}`, {
|
|
1220
|
+
function: step.getFunction(),
|
|
1221
|
+
data: {
|
|
1222
|
+
timeTravel: timeTravelParams,
|
|
1223
|
+
initialState: executionContext.state ?? {},
|
|
1224
|
+
runId: executionContext.runId,
|
|
1225
|
+
outputOptions: { includeState: true }
|
|
1226
|
+
}
|
|
1227
|
+
});
|
|
1228
|
+
result = invokeResp.result;
|
|
1229
|
+
runId = invokeResp.runId;
|
|
1230
|
+
executionContext.state = invokeResp.result.state;
|
|
1035
1231
|
} else {
|
|
1036
1232
|
const invokeResp = await this.inngestStep.invoke(`workflow.${executionContext.workflowId}.step.${step.id}`, {
|
|
1037
1233
|
function: step.getFunction(),
|
|
@@ -1144,14 +1340,32 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
|
|
|
1144
1340
|
let execResults;
|
|
1145
1341
|
let suspended;
|
|
1146
1342
|
let bailed;
|
|
1343
|
+
const { resumeData: timeTravelResumeData, validationError: timeTravelResumeValidationError } = await validateStepResumeData({
|
|
1344
|
+
resumeData: timeTravel?.stepResults[step.id]?.status === "suspended" ? timeTravel?.resumeData : void 0,
|
|
1345
|
+
step
|
|
1346
|
+
});
|
|
1347
|
+
let resumeDataToUse;
|
|
1348
|
+
if (timeTravelResumeData && !timeTravelResumeValidationError) {
|
|
1349
|
+
resumeDataToUse = timeTravelResumeData;
|
|
1350
|
+
} else if (timeTravelResumeData && timeTravelResumeValidationError) {
|
|
1351
|
+
this.logger.warn("Time travel resume data validation failed", {
|
|
1352
|
+
stepId: step.id,
|
|
1353
|
+
error: timeTravelResumeValidationError.message
|
|
1354
|
+
});
|
|
1355
|
+
} else if (resume?.steps[0] === step.id) {
|
|
1356
|
+
resumeDataToUse = resume?.resumePayload;
|
|
1357
|
+
}
|
|
1147
1358
|
try {
|
|
1148
1359
|
if (validationError) {
|
|
1149
1360
|
throw validationError;
|
|
1150
1361
|
}
|
|
1362
|
+
const retryCount = this.getOrGenerateRetryCount(step.id);
|
|
1151
1363
|
const result = await step.execute({
|
|
1152
1364
|
runId: executionContext.runId,
|
|
1365
|
+
workflowId: executionContext.workflowId,
|
|
1153
1366
|
mastra: this.mastra,
|
|
1154
1367
|
requestContext,
|
|
1368
|
+
retryCount,
|
|
1155
1369
|
writer: new ToolStream(
|
|
1156
1370
|
{
|
|
1157
1371
|
prefix: "workflow-step",
|
|
@@ -1166,9 +1380,9 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
|
|
|
1166
1380
|
executionContext.state = state;
|
|
1167
1381
|
},
|
|
1168
1382
|
inputData,
|
|
1169
|
-
resumeData:
|
|
1383
|
+
resumeData: resumeDataToUse,
|
|
1170
1384
|
tracingContext: {
|
|
1171
|
-
currentSpan:
|
|
1385
|
+
currentSpan: stepSpan
|
|
1172
1386
|
},
|
|
1173
1387
|
getInitData: () => stepResults?.input,
|
|
1174
1388
|
getStepResult: getStepResult.bind(this, stepResults),
|
|
@@ -1188,11 +1402,8 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
|
|
|
1188
1402
|
bail: (result2) => {
|
|
1189
1403
|
bailed = { payload: result2 };
|
|
1190
1404
|
},
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
resumePayload: resume?.resumePayload,
|
|
1194
|
-
// @ts-ignore
|
|
1195
|
-
runId: stepResults[step.id]?.suspendPayload?.__workflow_meta?.runId
|
|
1405
|
+
abort: () => {
|
|
1406
|
+
abortController?.abort();
|
|
1196
1407
|
},
|
|
1197
1408
|
[EMITTER_SYMBOL]: emitter,
|
|
1198
1409
|
[STREAM_FORMAT_SYMBOL]: executionContext.format,
|
|
@@ -1208,8 +1419,8 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
|
|
|
1208
1419
|
startedAt,
|
|
1209
1420
|
endedAt,
|
|
1210
1421
|
payload: inputData,
|
|
1211
|
-
resumedAt:
|
|
1212
|
-
resumePayload:
|
|
1422
|
+
resumedAt: resumeDataToUse ? startedAt : void 0,
|
|
1423
|
+
resumePayload: resumeDataToUse
|
|
1213
1424
|
};
|
|
1214
1425
|
} catch (e) {
|
|
1215
1426
|
const stepFailure = {
|
|
@@ -1218,12 +1429,12 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
|
|
|
1218
1429
|
error: e instanceof Error ? e.message : String(e),
|
|
1219
1430
|
endedAt: Date.now(),
|
|
1220
1431
|
startedAt,
|
|
1221
|
-
resumedAt:
|
|
1222
|
-
resumePayload:
|
|
1432
|
+
resumedAt: resumeDataToUse ? startedAt : void 0,
|
|
1433
|
+
resumePayload: resumeDataToUse
|
|
1223
1434
|
};
|
|
1224
1435
|
execResults = stepFailure;
|
|
1225
1436
|
const fallbackErrorMessage = `Step ${step.id} failed`;
|
|
1226
|
-
|
|
1437
|
+
stepSpan?.error({ error: new Error(execResults.error ?? fallbackErrorMessage) });
|
|
1227
1438
|
throw new RetryAfterError(execResults.error ?? fallbackErrorMessage, executionContext.retryConfig.delay, {
|
|
1228
1439
|
cause: execResults
|
|
1229
1440
|
});
|
|
@@ -1232,11 +1443,12 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
|
|
|
1232
1443
|
execResults = {
|
|
1233
1444
|
status: "suspended",
|
|
1234
1445
|
suspendPayload: suspended.payload,
|
|
1446
|
+
...execResults.output ? { suspendOutput: execResults.output } : {},
|
|
1235
1447
|
payload: inputData,
|
|
1236
1448
|
suspendedAt: Date.now(),
|
|
1237
1449
|
startedAt,
|
|
1238
|
-
resumedAt:
|
|
1239
|
-
resumePayload:
|
|
1450
|
+
resumedAt: resumeDataToUse ? startedAt : void 0,
|
|
1451
|
+
resumePayload: resumeDataToUse
|
|
1240
1452
|
};
|
|
1241
1453
|
} else if (bailed) {
|
|
1242
1454
|
execResults = {
|
|
@@ -1271,7 +1483,7 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
|
|
|
1271
1483
|
}
|
|
1272
1484
|
});
|
|
1273
1485
|
}
|
|
1274
|
-
|
|
1486
|
+
stepSpan?.end({ output: execResults });
|
|
1275
1487
|
return { result: execResults, executionContext, stepResults };
|
|
1276
1488
|
});
|
|
1277
1489
|
} catch (e) {
|
|
@@ -1303,13 +1515,12 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
|
|
|
1303
1515
|
stepId: step.id,
|
|
1304
1516
|
requestContext,
|
|
1305
1517
|
disableScorers,
|
|
1306
|
-
tracingContext: { currentSpan:
|
|
1518
|
+
tracingContext: { currentSpan: stepSpan }
|
|
1307
1519
|
});
|
|
1308
1520
|
}
|
|
1309
1521
|
});
|
|
1310
1522
|
}
|
|
1311
1523
|
Object.assign(executionContext.suspendedPaths, stepRes.executionContext.suspendedPaths);
|
|
1312
|
-
Object.assign(stepResults, stepRes.stepResults);
|
|
1313
1524
|
executionContext.state = stepRes.executionContext.state;
|
|
1314
1525
|
return stepRes.result;
|
|
1315
1526
|
}
|
|
@@ -1337,17 +1548,17 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
|
|
|
1337
1548
|
resourceId,
|
|
1338
1549
|
snapshot: {
|
|
1339
1550
|
runId,
|
|
1551
|
+
status: workflowStatus,
|
|
1340
1552
|
value: executionContext.state,
|
|
1341
1553
|
context: stepResults,
|
|
1342
|
-
activePaths:
|
|
1554
|
+
activePaths: executionContext.executionPath,
|
|
1555
|
+
activeStepsPath: executionContext.activeStepsPath,
|
|
1343
1556
|
suspendedPaths: executionContext.suspendedPaths,
|
|
1344
1557
|
resumeLabels: executionContext.resumeLabels,
|
|
1345
1558
|
waitingPaths: {},
|
|
1346
1559
|
serializedStepGraph,
|
|
1347
|
-
status: workflowStatus,
|
|
1348
1560
|
result,
|
|
1349
1561
|
error,
|
|
1350
|
-
// @ts-ignore
|
|
1351
1562
|
timestamp: Date.now()
|
|
1352
1563
|
}
|
|
1353
1564
|
});
|
|
@@ -1360,6 +1571,7 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
|
|
|
1360
1571
|
entry,
|
|
1361
1572
|
prevOutput,
|
|
1362
1573
|
stepResults,
|
|
1574
|
+
timeTravel,
|
|
1363
1575
|
resume,
|
|
1364
1576
|
executionContext,
|
|
1365
1577
|
emitter,
|
|
@@ -1370,7 +1582,7 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
|
|
|
1370
1582
|
tracingContext
|
|
1371
1583
|
}) {
|
|
1372
1584
|
const conditionalSpan = tracingContext?.currentSpan?.createChildSpan({
|
|
1373
|
-
type:
|
|
1585
|
+
type: SpanType.WORKFLOW_CONDITIONAL,
|
|
1374
1586
|
name: `conditional: '${entry.conditions.length} conditions'`,
|
|
1375
1587
|
input: prevOutput,
|
|
1376
1588
|
attributes: {
|
|
@@ -1383,7 +1595,7 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
|
|
|
1383
1595
|
entry.conditions.map(
|
|
1384
1596
|
(cond, index) => this.inngestStep.run(`workflow.${workflowId}.conditional.${index}`, async () => {
|
|
1385
1597
|
const evalSpan = conditionalSpan?.createChildSpan({
|
|
1386
|
-
type:
|
|
1598
|
+
type: SpanType.WORKFLOW_CONDITIONAL_EVAL,
|
|
1387
1599
|
name: `condition: '${index}'`,
|
|
1388
1600
|
input: prevOutput,
|
|
1389
1601
|
attributes: {
|
|
@@ -1478,10 +1690,12 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
|
|
|
1478
1690
|
prevOutput,
|
|
1479
1691
|
stepResults,
|
|
1480
1692
|
resume,
|
|
1693
|
+
timeTravel,
|
|
1481
1694
|
executionContext: {
|
|
1482
1695
|
workflowId,
|
|
1483
1696
|
runId,
|
|
1484
1697
|
executionPath: [...executionContext.executionPath, index],
|
|
1698
|
+
activeStepsPath: executionContext.activeStepsPath,
|
|
1485
1699
|
suspendedPaths: executionContext.suspendedPaths,
|
|
1486
1700
|
resumeLabels: executionContext.resumeLabels,
|
|
1487
1701
|
retryConfig: executionContext.retryConfig,
|
|
@@ -1505,13 +1719,19 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
|
|
|
1505
1719
|
if (hasFailed) {
|
|
1506
1720
|
execResults = { status: "failed", error: hasFailed.error };
|
|
1507
1721
|
} else if (hasSuspended) {
|
|
1508
|
-
execResults = {
|
|
1722
|
+
execResults = {
|
|
1723
|
+
status: "suspended",
|
|
1724
|
+
suspendPayload: hasSuspended.suspendPayload,
|
|
1725
|
+
...hasSuspended.suspendOutput ? { suspendOutput: hasSuspended.suspendOutput } : {}
|
|
1726
|
+
};
|
|
1509
1727
|
} else {
|
|
1510
1728
|
execResults = {
|
|
1511
1729
|
status: "success",
|
|
1512
1730
|
output: results.reduce((acc, result, index) => {
|
|
1513
1731
|
if (result.status === "success") {
|
|
1514
|
-
|
|
1732
|
+
if ("step" in stepsToRun[index]) {
|
|
1733
|
+
acc[stepsToRun[index].step.id] = result.output;
|
|
1734
|
+
}
|
|
1515
1735
|
}
|
|
1516
1736
|
return acc;
|
|
1517
1737
|
}, {})
|