@mastra/inngest 0.0.0-redis-cloud-transporter-20250508203756 → 0.0.0-support-d1-client-20250701191943
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 +440 -2
- package/dist/_tsup-dts-rollup.d.cts +136 -65
- package/dist/_tsup-dts-rollup.d.ts +136 -65
- package/dist/index.cjs +484 -59
- package/dist/index.d.cts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +481 -57
- package/package.json +21 -17
- package/src/index.test.ts +4983 -3348
- package/src/index.ts +730 -103
package/src/index.ts
CHANGED
|
@@ -1,34 +1,49 @@
|
|
|
1
1
|
import { randomUUID } from 'crypto';
|
|
2
|
+
import type { ReadableStream } from 'node:stream/web';
|
|
2
3
|
import { subscribe } from '@inngest/realtime';
|
|
3
|
-
import type { Mastra, WorkflowRun } from '@mastra/core';
|
|
4
|
+
import type { Agent, Mastra, ToolExecutionContext, WorkflowRun, WorkflowRuns } from '@mastra/core';
|
|
4
5
|
import { RuntimeContext } from '@mastra/core/di';
|
|
5
|
-
import {
|
|
6
|
+
import { Tool } from '@mastra/core/tools';
|
|
7
|
+
import { Workflow, Run, DefaultExecutionEngine } from '@mastra/core/workflows';
|
|
6
8
|
import type {
|
|
7
9
|
ExecuteFunction,
|
|
8
10
|
ExecutionContext,
|
|
9
11
|
ExecutionEngine,
|
|
10
12
|
ExecutionGraph,
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
NewWorkflowConfig,
|
|
13
|
+
Step,
|
|
14
|
+
WorkflowConfig,
|
|
14
15
|
StepFlowEntry,
|
|
15
16
|
StepResult,
|
|
16
17
|
WorkflowResult,
|
|
17
|
-
|
|
18
|
+
SerializedStepFlowEntry,
|
|
19
|
+
StepFailure,
|
|
20
|
+
Emitter,
|
|
21
|
+
WatchEvent,
|
|
22
|
+
StreamEvent,
|
|
23
|
+
} from '@mastra/core/workflows';
|
|
24
|
+
import { EMITTER_SYMBOL } from '@mastra/core/workflows/_constants';
|
|
18
25
|
import type { Span } from '@opentelemetry/api';
|
|
19
26
|
import type { Inngest, BaseContext } from 'inngest';
|
|
20
27
|
import { serve as inngestServe } from 'inngest/hono';
|
|
21
|
-
import
|
|
28
|
+
import { z } from 'zod';
|
|
29
|
+
|
|
30
|
+
export type InngestEngineType = {
|
|
31
|
+
step: any;
|
|
32
|
+
};
|
|
22
33
|
|
|
23
34
|
export function serve({ mastra, inngest }: { mastra: Mastra; inngest: Inngest }): ReturnType<typeof inngestServe> {
|
|
24
|
-
const wfs = mastra.
|
|
25
|
-
const functions =
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
35
|
+
const wfs = mastra.getWorkflows();
|
|
36
|
+
const functions = Array.from(
|
|
37
|
+
new Set(
|
|
38
|
+
Object.values(wfs).flatMap(wf => {
|
|
39
|
+
if (wf instanceof InngestWorkflow) {
|
|
40
|
+
wf.__registerMastra(mastra);
|
|
41
|
+
return wf.getFunctions();
|
|
42
|
+
}
|
|
43
|
+
return [];
|
|
44
|
+
}),
|
|
45
|
+
),
|
|
46
|
+
);
|
|
32
47
|
return inngestServe({
|
|
33
48
|
client: inngest,
|
|
34
49
|
functions,
|
|
@@ -36,11 +51,13 @@ export function serve({ mastra, inngest }: { mastra: Mastra; inngest: Inngest })
|
|
|
36
51
|
}
|
|
37
52
|
|
|
38
53
|
export class InngestRun<
|
|
39
|
-
|
|
54
|
+
TEngineType = InngestEngineType,
|
|
55
|
+
TSteps extends Step<string, any, any>[] = Step<string, any, any>[],
|
|
40
56
|
TInput extends z.ZodType<any> = z.ZodType<any>,
|
|
41
57
|
TOutput extends z.ZodType<any> = z.ZodType<any>,
|
|
42
|
-
> extends Run<TSteps, TInput, TOutput> {
|
|
58
|
+
> extends Run<TEngineType, TSteps, TInput, TOutput> {
|
|
43
59
|
private inngest: Inngest;
|
|
60
|
+
serializedStepGraph: SerializedStepFlowEntry[];
|
|
44
61
|
#mastra: Mastra;
|
|
45
62
|
|
|
46
63
|
constructor(
|
|
@@ -49,6 +66,7 @@ export class InngestRun<
|
|
|
49
66
|
runId: string;
|
|
50
67
|
executionEngine: ExecutionEngine;
|
|
51
68
|
executionGraph: ExecutionGraph;
|
|
69
|
+
serializedStepGraph: SerializedStepFlowEntry[];
|
|
52
70
|
mastra?: Mastra;
|
|
53
71
|
retryConfig?: {
|
|
54
72
|
attempts?: number;
|
|
@@ -60,11 +78,12 @@ export class InngestRun<
|
|
|
60
78
|
) {
|
|
61
79
|
super(params);
|
|
62
80
|
this.inngest = inngest;
|
|
81
|
+
this.serializedStepGraph = params.serializedStepGraph;
|
|
63
82
|
this.#mastra = params.mastra!;
|
|
64
83
|
}
|
|
65
84
|
|
|
66
85
|
async getRuns(eventId: string) {
|
|
67
|
-
const response = await fetch(`${this.inngest.apiBaseUrl}/v1/events/${eventId}/runs`, {
|
|
86
|
+
const response = await fetch(`${this.inngest.apiBaseUrl ?? 'https://api.inngest.com'}/v1/events/${eventId}/runs`, {
|
|
68
87
|
headers: {
|
|
69
88
|
Authorization: `Bearer ${process.env.INNGEST_SIGNING_KEY}`,
|
|
70
89
|
},
|
|
@@ -75,16 +94,54 @@ export class InngestRun<
|
|
|
75
94
|
|
|
76
95
|
async getRunOutput(eventId: string) {
|
|
77
96
|
let runs = await this.getRuns(eventId);
|
|
78
|
-
|
|
97
|
+
|
|
98
|
+
while (runs?.[0]?.status !== 'Completed' || runs?.[0]?.event_id !== eventId) {
|
|
79
99
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
80
100
|
runs = await this.getRuns(eventId);
|
|
81
|
-
if (runs?.[0]?.status === 'Failed'
|
|
101
|
+
if (runs?.[0]?.status === 'Failed') {
|
|
82
102
|
throw new Error(`Function run ${runs?.[0]?.status}`);
|
|
103
|
+
} else if (runs?.[0]?.status === 'Cancelled') {
|
|
104
|
+
const snapshot = await this.#mastra?.storage?.loadWorkflowSnapshot({
|
|
105
|
+
workflowName: this.workflowId,
|
|
106
|
+
runId: this.runId,
|
|
107
|
+
});
|
|
108
|
+
return { output: { result: { steps: snapshot?.context, status: 'canceled' } } };
|
|
83
109
|
}
|
|
84
110
|
}
|
|
85
111
|
return runs?.[0];
|
|
86
112
|
}
|
|
87
113
|
|
|
114
|
+
async sendEvent(event: string, data: any) {
|
|
115
|
+
await this.inngest.send({
|
|
116
|
+
name: `user-event-${event}`,
|
|
117
|
+
data,
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
async cancel() {
|
|
122
|
+
await this.inngest.send({
|
|
123
|
+
name: `cancel.workflow.${this.workflowId}`,
|
|
124
|
+
data: {
|
|
125
|
+
runId: this.runId,
|
|
126
|
+
},
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
const snapshot = await this.#mastra?.storage?.loadWorkflowSnapshot({
|
|
130
|
+
workflowName: this.workflowId,
|
|
131
|
+
runId: this.runId,
|
|
132
|
+
});
|
|
133
|
+
if (snapshot) {
|
|
134
|
+
await this.#mastra?.storage?.persistWorkflowSnapshot({
|
|
135
|
+
workflowName: this.workflowId,
|
|
136
|
+
runId: this.runId,
|
|
137
|
+
snapshot: {
|
|
138
|
+
...snapshot,
|
|
139
|
+
status: 'canceled' as any,
|
|
140
|
+
},
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
88
145
|
async start({
|
|
89
146
|
inputData,
|
|
90
147
|
}: {
|
|
@@ -96,11 +153,13 @@ export class InngestRun<
|
|
|
96
153
|
runId: this.runId,
|
|
97
154
|
snapshot: {
|
|
98
155
|
runId: this.runId,
|
|
156
|
+
serializedStepGraph: this.serializedStepGraph,
|
|
99
157
|
value: {},
|
|
100
158
|
context: {} as any,
|
|
101
159
|
activePaths: [],
|
|
102
160
|
suspendedPaths: {},
|
|
103
161
|
timestamp: Date.now(),
|
|
162
|
+
status: 'running',
|
|
104
163
|
},
|
|
105
164
|
});
|
|
106
165
|
|
|
@@ -122,7 +181,9 @@ export class InngestRun<
|
|
|
122
181
|
result.error = new Error(result.error);
|
|
123
182
|
}
|
|
124
183
|
|
|
125
|
-
|
|
184
|
+
if (result.status !== 'suspended') {
|
|
185
|
+
this.cleanup?.();
|
|
186
|
+
}
|
|
126
187
|
return result;
|
|
127
188
|
}
|
|
128
189
|
|
|
@@ -134,6 +195,27 @@ export class InngestRun<
|
|
|
134
195
|
| string
|
|
135
196
|
| string[];
|
|
136
197
|
runtimeContext?: RuntimeContext;
|
|
198
|
+
}): Promise<WorkflowResult<TOutput, TSteps>> {
|
|
199
|
+
const p = this._resume(params).then(result => {
|
|
200
|
+
if (result.status !== 'suspended') {
|
|
201
|
+
this.closeStreamAction?.().catch(() => {});
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
return result;
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
this.executionResults = p;
|
|
208
|
+
return p;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
async _resume<TResumeSchema extends z.ZodType<any>>(params: {
|
|
212
|
+
resumeData?: z.infer<TResumeSchema>;
|
|
213
|
+
step:
|
|
214
|
+
| Step<string, any, any, TResumeSchema, any>
|
|
215
|
+
| [...Step<string, any, any, any, any>[], Step<string, any, any, TResumeSchema, any>]
|
|
216
|
+
| string
|
|
217
|
+
| string[];
|
|
218
|
+
runtimeContext?: RuntimeContext;
|
|
137
219
|
}): Promise<WorkflowResult<TOutput, TSteps>> {
|
|
138
220
|
const steps: string[] = (Array.isArray(params.step) ? params.step : [params.step]).map(step =>
|
|
139
221
|
typeof step === 'string' ? step : step?.id,
|
|
@@ -171,43 +253,88 @@ export class InngestRun<
|
|
|
171
253
|
return result;
|
|
172
254
|
}
|
|
173
255
|
|
|
174
|
-
watch(cb: (event:
|
|
256
|
+
watch(cb: (event: WatchEvent) => void, type: 'watch' | 'watch-v2' = 'watch'): () => void {
|
|
257
|
+
let active = true;
|
|
175
258
|
const streamPromise = subscribe(
|
|
176
259
|
{
|
|
177
260
|
channel: `workflow:${this.workflowId}:${this.runId}`,
|
|
178
|
-
topics: [
|
|
261
|
+
topics: [type],
|
|
179
262
|
app: this.inngest,
|
|
180
263
|
},
|
|
181
264
|
(message: any) => {
|
|
182
|
-
|
|
265
|
+
if (active) {
|
|
266
|
+
cb(message.data);
|
|
267
|
+
}
|
|
183
268
|
},
|
|
184
269
|
);
|
|
185
270
|
|
|
186
271
|
return () => {
|
|
272
|
+
active = false;
|
|
187
273
|
streamPromise
|
|
188
|
-
.then((stream:
|
|
189
|
-
stream.cancel();
|
|
274
|
+
.then(async (stream: Awaited<typeof streamPromise>) => {
|
|
275
|
+
return stream.cancel();
|
|
190
276
|
})
|
|
191
277
|
.catch(err => {
|
|
192
278
|
console.error(err);
|
|
193
279
|
});
|
|
194
280
|
};
|
|
195
281
|
}
|
|
282
|
+
|
|
283
|
+
stream({ inputData, runtimeContext }: { inputData?: z.infer<TInput>; runtimeContext?: RuntimeContext } = {}): {
|
|
284
|
+
stream: ReadableStream<StreamEvent>;
|
|
285
|
+
getWorkflowState: () => Promise<WorkflowResult<TOutput, TSteps>>;
|
|
286
|
+
} {
|
|
287
|
+
const { readable, writable } = new TransformStream<StreamEvent, StreamEvent>();
|
|
288
|
+
|
|
289
|
+
const writer = writable.getWriter();
|
|
290
|
+
const unwatch = this.watch(async event => {
|
|
291
|
+
try {
|
|
292
|
+
// watch-v2 events are data stream events, so we need to cast them to the correct type
|
|
293
|
+
await writer.write(event as any);
|
|
294
|
+
} catch {}
|
|
295
|
+
}, 'watch-v2');
|
|
296
|
+
|
|
297
|
+
this.closeStreamAction = async () => {
|
|
298
|
+
unwatch();
|
|
299
|
+
|
|
300
|
+
try {
|
|
301
|
+
await writer.close();
|
|
302
|
+
} catch (err) {
|
|
303
|
+
console.error('Error closing stream:', err);
|
|
304
|
+
} finally {
|
|
305
|
+
writer.releaseLock();
|
|
306
|
+
}
|
|
307
|
+
};
|
|
308
|
+
|
|
309
|
+
this.executionResults = this.start({ inputData, runtimeContext }).then(result => {
|
|
310
|
+
if (result.status !== 'suspended') {
|
|
311
|
+
this.closeStreamAction?.().catch(() => {});
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
return result;
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
return {
|
|
318
|
+
stream: readable as ReadableStream<StreamEvent>,
|
|
319
|
+
getWorkflowState: () => this.executionResults!,
|
|
320
|
+
};
|
|
321
|
+
}
|
|
196
322
|
}
|
|
197
323
|
|
|
198
324
|
export class InngestWorkflow<
|
|
199
|
-
|
|
325
|
+
TEngineType = InngestEngineType,
|
|
326
|
+
TSteps extends Step<string, any, any>[] = Step<string, any, any>[],
|
|
200
327
|
TWorkflowId extends string = string,
|
|
201
328
|
TInput extends z.ZodType<any> = z.ZodType<any>,
|
|
202
329
|
TOutput extends z.ZodType<any> = z.ZodType<any>,
|
|
203
330
|
TPrevSchema extends z.ZodType<any> = TInput,
|
|
204
|
-
> extends
|
|
331
|
+
> extends Workflow<TEngineType, TSteps, TWorkflowId, TInput, TOutput, TPrevSchema> {
|
|
205
332
|
#mastra: Mastra;
|
|
206
333
|
public inngest: Inngest;
|
|
207
334
|
|
|
208
335
|
private function: ReturnType<Inngest['createFunction']> | undefined;
|
|
209
336
|
|
|
210
|
-
constructor(params:
|
|
337
|
+
constructor(params: WorkflowConfig<TWorkflowId, TInput, TOutput, TSteps>, inngest: Inngest) {
|
|
211
338
|
super(params);
|
|
212
339
|
this.#mastra = params.mastra!;
|
|
213
340
|
this.inngest = inngest;
|
|
@@ -226,16 +353,19 @@ export class InngestWorkflow<
|
|
|
226
353
|
return { runs: [], total: 0 };
|
|
227
354
|
}
|
|
228
355
|
|
|
229
|
-
return storage.getWorkflowRuns({ workflowName: this.id, ...(args ?? {}) });
|
|
356
|
+
return storage.getWorkflowRuns({ workflowName: this.id, ...(args ?? {}) }) as unknown as WorkflowRuns;
|
|
230
357
|
}
|
|
231
358
|
|
|
232
359
|
async getWorkflowRunById(runId: string): Promise<WorkflowRun | null> {
|
|
233
360
|
const storage = this.#mastra?.getStorage();
|
|
234
361
|
if (!storage) {
|
|
235
362
|
this.logger.debug('Cannot get workflow runs. Mastra engine is not initialized');
|
|
236
|
-
|
|
363
|
+
//returning in memory run if no storage is initialized
|
|
364
|
+
return this.runs.get(runId)
|
|
365
|
+
? ({ ...this.runs.get(runId), workflowName: this.id } as unknown as WorkflowRun)
|
|
366
|
+
: null;
|
|
237
367
|
}
|
|
238
|
-
const run = await storage.getWorkflowRunById({ runId, workflowName: this.id });
|
|
368
|
+
const run = (await storage.getWorkflowRunById({ runId, workflowName: this.id })) as unknown as WorkflowRun;
|
|
239
369
|
|
|
240
370
|
return (
|
|
241
371
|
run ??
|
|
@@ -243,6 +373,32 @@ export class InngestWorkflow<
|
|
|
243
373
|
);
|
|
244
374
|
}
|
|
245
375
|
|
|
376
|
+
async getWorkflowRunExecutionResult(runId: string): Promise<WatchEvent['payload']['workflowState'] | null> {
|
|
377
|
+
const storage = this.#mastra?.getStorage();
|
|
378
|
+
if (!storage) {
|
|
379
|
+
this.logger.debug('Cannot get workflow run execution result. Mastra storage is not initialized');
|
|
380
|
+
return null;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
const run = await storage.getWorkflowRunById({ runId, workflowName: this.id });
|
|
384
|
+
|
|
385
|
+
if (!run?.snapshot) {
|
|
386
|
+
return null;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
if (typeof run.snapshot === 'string') {
|
|
390
|
+
return null;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
return {
|
|
394
|
+
status: run.snapshot.status,
|
|
395
|
+
result: run.snapshot.result,
|
|
396
|
+
error: run.snapshot.error,
|
|
397
|
+
payload: run.snapshot.context?.input,
|
|
398
|
+
steps: run.snapshot.context as any,
|
|
399
|
+
};
|
|
400
|
+
}
|
|
401
|
+
|
|
246
402
|
__registerMastra(mastra: Mastra) {
|
|
247
403
|
this.#mastra = mastra;
|
|
248
404
|
this.executionEngine.__registerMastra(mastra);
|
|
@@ -266,11 +422,11 @@ export class InngestWorkflow<
|
|
|
266
422
|
}
|
|
267
423
|
}
|
|
268
424
|
|
|
269
|
-
createRun(options?: { runId?: string }): Run<TSteps, TInput, TOutput> {
|
|
425
|
+
createRun(options?: { runId?: string }): Run<TEngineType, TSteps, TInput, TOutput> {
|
|
270
426
|
const runIdToUse = options?.runId || randomUUID();
|
|
271
427
|
|
|
272
428
|
// Return a new Run instance with object parameters
|
|
273
|
-
const run: Run<TSteps, TInput, TOutput> =
|
|
429
|
+
const run: Run<TEngineType, TSteps, TInput, TOutput> =
|
|
274
430
|
this.runs.get(runIdToUse) ??
|
|
275
431
|
new InngestRun(
|
|
276
432
|
{
|
|
@@ -278,6 +434,7 @@ export class InngestWorkflow<
|
|
|
278
434
|
runId: runIdToUse,
|
|
279
435
|
executionEngine: this.executionEngine,
|
|
280
436
|
executionGraph: this.executionGraph,
|
|
437
|
+
serializedStepGraph: this.serializedStepGraph,
|
|
281
438
|
mastra: this.#mastra,
|
|
282
439
|
retryConfig: this.retryConfig,
|
|
283
440
|
cleanup: () => this.runs.delete(runIdToUse),
|
|
@@ -289,13 +446,64 @@ export class InngestWorkflow<
|
|
|
289
446
|
return run;
|
|
290
447
|
}
|
|
291
448
|
|
|
449
|
+
async createRunAsync(options?: { runId?: string }): Promise<Run<TEngineType, TSteps, TInput, TOutput>> {
|
|
450
|
+
const runIdToUse = options?.runId || randomUUID();
|
|
451
|
+
|
|
452
|
+
// Return a new Run instance with object parameters
|
|
453
|
+
const run: Run<TEngineType, TSteps, TInput, TOutput> =
|
|
454
|
+
this.runs.get(runIdToUse) ??
|
|
455
|
+
new InngestRun(
|
|
456
|
+
{
|
|
457
|
+
workflowId: this.id,
|
|
458
|
+
runId: runIdToUse,
|
|
459
|
+
executionEngine: this.executionEngine,
|
|
460
|
+
executionGraph: this.executionGraph,
|
|
461
|
+
serializedStepGraph: this.serializedStepGraph,
|
|
462
|
+
mastra: this.#mastra,
|
|
463
|
+
retryConfig: this.retryConfig,
|
|
464
|
+
cleanup: () => this.runs.delete(runIdToUse),
|
|
465
|
+
},
|
|
466
|
+
this.inngest,
|
|
467
|
+
);
|
|
468
|
+
|
|
469
|
+
this.runs.set(runIdToUse, run);
|
|
470
|
+
|
|
471
|
+
const workflowSnapshotInStorage = await this.getWorkflowRunExecutionResult(runIdToUse);
|
|
472
|
+
|
|
473
|
+
if (!workflowSnapshotInStorage) {
|
|
474
|
+
await this.mastra?.getStorage()?.persistWorkflowSnapshot({
|
|
475
|
+
workflowName: this.id,
|
|
476
|
+
runId: runIdToUse,
|
|
477
|
+
snapshot: {
|
|
478
|
+
runId: runIdToUse,
|
|
479
|
+
status: 'pending',
|
|
480
|
+
value: {},
|
|
481
|
+
context: {},
|
|
482
|
+
activePaths: [],
|
|
483
|
+
serializedStepGraph: this.serializedStepGraph,
|
|
484
|
+
suspendedPaths: {},
|
|
485
|
+
result: undefined,
|
|
486
|
+
error: undefined,
|
|
487
|
+
// @ts-ignore
|
|
488
|
+
timestamp: Date.now(),
|
|
489
|
+
},
|
|
490
|
+
});
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
return run;
|
|
494
|
+
}
|
|
495
|
+
|
|
292
496
|
getFunction() {
|
|
293
497
|
if (this.function) {
|
|
294
498
|
return this.function;
|
|
295
499
|
}
|
|
296
500
|
this.function = this.inngest.createFunction(
|
|
297
|
-
|
|
298
|
-
|
|
501
|
+
{
|
|
502
|
+
id: `workflow.${this.id}`,
|
|
503
|
+
// @ts-ignore
|
|
504
|
+
retries: this.retryConfig?.attempts ?? 0,
|
|
505
|
+
cancelOn: [{ event: `cancel.workflow.${this.id}` }],
|
|
506
|
+
},
|
|
299
507
|
{ event: `workflow.${this.id}` },
|
|
300
508
|
async ({ event, step, attempt, publish }) => {
|
|
301
509
|
let { inputData, runId, resume } = event.data;
|
|
@@ -315,13 +523,22 @@ export class InngestWorkflow<
|
|
|
315
523
|
try {
|
|
316
524
|
await publish({
|
|
317
525
|
channel: `workflow:${this.id}:${runId}`,
|
|
318
|
-
topic:
|
|
526
|
+
topic: event,
|
|
319
527
|
data,
|
|
320
528
|
});
|
|
321
529
|
} catch (err: any) {
|
|
322
530
|
this.logger.error('Error emitting event: ' + (err?.stack ?? err?.message ?? err));
|
|
323
531
|
}
|
|
324
532
|
},
|
|
533
|
+
on: (_event: string, _callback: (data: any) => void) => {
|
|
534
|
+
// no-op
|
|
535
|
+
},
|
|
536
|
+
off: (_event: string, _callback: (data: any) => void) => {
|
|
537
|
+
// no-op
|
|
538
|
+
},
|
|
539
|
+
once: (_event: string, _callback: (data: any) => void) => {
|
|
540
|
+
// no-op
|
|
541
|
+
},
|
|
325
542
|
};
|
|
326
543
|
|
|
327
544
|
const engine = new InngestExecutionEngine(this.#mastra, step, attempt);
|
|
@@ -329,11 +546,13 @@ export class InngestWorkflow<
|
|
|
329
546
|
workflowId: this.id,
|
|
330
547
|
runId,
|
|
331
548
|
graph: this.executionGraph,
|
|
549
|
+
serializedStepGraph: this.serializedStepGraph,
|
|
332
550
|
input: inputData,
|
|
333
551
|
emitter,
|
|
334
552
|
retryConfig: this.retryConfig,
|
|
335
553
|
runtimeContext: new RuntimeContext(), // TODO
|
|
336
554
|
resume,
|
|
555
|
+
abortController: new AbortController(),
|
|
337
556
|
});
|
|
338
557
|
|
|
339
558
|
return { result, runId };
|
|
@@ -362,29 +581,197 @@ export class InngestWorkflow<
|
|
|
362
581
|
}
|
|
363
582
|
}
|
|
364
583
|
|
|
365
|
-
function
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
584
|
+
function isAgent(params: any): params is Agent<any, any, any> {
|
|
585
|
+
return params?.component === 'AGENT';
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
function isTool(params: any): params is Tool<any, any, any> {
|
|
589
|
+
return params instanceof Tool;
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
export function createStep<
|
|
593
|
+
TStepId extends string,
|
|
594
|
+
TStepInput extends z.ZodType<any>,
|
|
595
|
+
TStepOutput extends z.ZodType<any>,
|
|
596
|
+
TResumeSchema extends z.ZodType<any>,
|
|
597
|
+
TSuspendSchema extends z.ZodType<any>,
|
|
598
|
+
>(params: {
|
|
599
|
+
id: TStepId;
|
|
600
|
+
description?: string;
|
|
601
|
+
inputSchema: TStepInput;
|
|
602
|
+
outputSchema: TStepOutput;
|
|
603
|
+
resumeSchema?: TResumeSchema;
|
|
604
|
+
suspendSchema?: TSuspendSchema;
|
|
605
|
+
execute: ExecuteFunction<
|
|
606
|
+
z.infer<TStepInput>,
|
|
607
|
+
z.infer<TStepOutput>,
|
|
608
|
+
z.infer<TResumeSchema>,
|
|
609
|
+
z.infer<TSuspendSchema>,
|
|
610
|
+
InngestEngineType
|
|
611
|
+
>;
|
|
612
|
+
}): Step<TStepId, TStepInput, TStepOutput, TResumeSchema, TSuspendSchema, InngestEngineType>;
|
|
613
|
+
|
|
614
|
+
export function createStep<
|
|
615
|
+
TStepId extends string,
|
|
616
|
+
TStepInput extends z.ZodObject<{ prompt: z.ZodString }>,
|
|
617
|
+
TStepOutput extends z.ZodObject<{ text: z.ZodString }>,
|
|
618
|
+
TResumeSchema extends z.ZodType<any>,
|
|
619
|
+
TSuspendSchema extends z.ZodType<any>,
|
|
370
620
|
>(
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
): InngestWorkflow<TSteps, TWorkflowId, TInput, TOutput> {
|
|
374
|
-
const wf = new InngestWorkflow(
|
|
375
|
-
{
|
|
376
|
-
id: opts.id,
|
|
377
|
-
inputSchema: workflow.inputSchema,
|
|
378
|
-
outputSchema: workflow.outputSchema,
|
|
379
|
-
steps: workflow.stepDefs,
|
|
380
|
-
mastra: workflow.mastra,
|
|
381
|
-
},
|
|
382
|
-
workflow.inngest,
|
|
383
|
-
);
|
|
621
|
+
agent: Agent<TStepId, any, any>,
|
|
622
|
+
): Step<TStepId, TStepInput, TStepOutput, TResumeSchema, TSuspendSchema, InngestEngineType>;
|
|
384
623
|
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
624
|
+
export function createStep<
|
|
625
|
+
TSchemaIn extends z.ZodType<any>,
|
|
626
|
+
TSchemaOut extends z.ZodType<any>,
|
|
627
|
+
TContext extends ToolExecutionContext<TSchemaIn>,
|
|
628
|
+
>(
|
|
629
|
+
tool: Tool<TSchemaIn, TSchemaOut, TContext> & {
|
|
630
|
+
inputSchema: TSchemaIn;
|
|
631
|
+
outputSchema: TSchemaOut;
|
|
632
|
+
execute: (context: TContext) => Promise<any>;
|
|
633
|
+
},
|
|
634
|
+
): Step<string, TSchemaIn, TSchemaOut, z.ZodType<any>, z.ZodType<any>, InngestEngineType>;
|
|
635
|
+
export function createStep<
|
|
636
|
+
TStepId extends string,
|
|
637
|
+
TStepInput extends z.ZodType<any>,
|
|
638
|
+
TStepOutput extends z.ZodType<any>,
|
|
639
|
+
TResumeSchema extends z.ZodType<any>,
|
|
640
|
+
TSuspendSchema extends z.ZodType<any>,
|
|
641
|
+
>(
|
|
642
|
+
params:
|
|
643
|
+
| {
|
|
644
|
+
id: TStepId;
|
|
645
|
+
description?: string;
|
|
646
|
+
inputSchema: TStepInput;
|
|
647
|
+
outputSchema: TStepOutput;
|
|
648
|
+
resumeSchema?: TResumeSchema;
|
|
649
|
+
suspendSchema?: TSuspendSchema;
|
|
650
|
+
execute: ExecuteFunction<
|
|
651
|
+
z.infer<TStepInput>,
|
|
652
|
+
z.infer<TStepOutput>,
|
|
653
|
+
z.infer<TResumeSchema>,
|
|
654
|
+
z.infer<TSuspendSchema>,
|
|
655
|
+
InngestEngineType
|
|
656
|
+
>;
|
|
657
|
+
}
|
|
658
|
+
| Agent<any, any, any>
|
|
659
|
+
| (Tool<TStepInput, TStepOutput, any> & {
|
|
660
|
+
inputSchema: TStepInput;
|
|
661
|
+
outputSchema: TStepOutput;
|
|
662
|
+
execute: (context: ToolExecutionContext<TStepInput>) => Promise<any>;
|
|
663
|
+
}),
|
|
664
|
+
): Step<TStepId, TStepInput, TStepOutput, TResumeSchema, TSuspendSchema, InngestEngineType> {
|
|
665
|
+
if (isAgent(params)) {
|
|
666
|
+
return {
|
|
667
|
+
id: params.name,
|
|
668
|
+
// @ts-ignore
|
|
669
|
+
inputSchema: z.object({
|
|
670
|
+
prompt: z.string(),
|
|
671
|
+
// resourceId: z.string().optional(),
|
|
672
|
+
// threadId: z.string().optional(),
|
|
673
|
+
}),
|
|
674
|
+
// @ts-ignore
|
|
675
|
+
outputSchema: z.object({
|
|
676
|
+
text: z.string(),
|
|
677
|
+
}),
|
|
678
|
+
execute: async ({ inputData, [EMITTER_SYMBOL]: emitter, runtimeContext, abortSignal, abort }) => {
|
|
679
|
+
let streamPromise = {} as {
|
|
680
|
+
promise: Promise<string>;
|
|
681
|
+
resolve: (value: string) => void;
|
|
682
|
+
reject: (reason?: any) => void;
|
|
683
|
+
};
|
|
684
|
+
|
|
685
|
+
streamPromise.promise = new Promise((resolve, reject) => {
|
|
686
|
+
streamPromise.resolve = resolve;
|
|
687
|
+
streamPromise.reject = reject;
|
|
688
|
+
});
|
|
689
|
+
const toolData = {
|
|
690
|
+
name: params.name,
|
|
691
|
+
args: inputData,
|
|
692
|
+
};
|
|
693
|
+
await emitter.emit('watch-v2', {
|
|
694
|
+
type: 'tool-call-streaming-start',
|
|
695
|
+
...toolData,
|
|
696
|
+
});
|
|
697
|
+
const { fullStream } = await params.stream(inputData.prompt, {
|
|
698
|
+
// resourceId: inputData.resourceId,
|
|
699
|
+
// threadId: inputData.threadId,
|
|
700
|
+
runtimeContext,
|
|
701
|
+
onFinish: result => {
|
|
702
|
+
streamPromise.resolve(result.text);
|
|
703
|
+
},
|
|
704
|
+
abortSignal,
|
|
705
|
+
});
|
|
706
|
+
|
|
707
|
+
if (abortSignal.aborted) {
|
|
708
|
+
return abort();
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
for await (const chunk of fullStream) {
|
|
712
|
+
switch (chunk.type) {
|
|
713
|
+
case 'text-delta':
|
|
714
|
+
await emitter.emit('watch-v2', {
|
|
715
|
+
type: 'tool-call-delta',
|
|
716
|
+
...toolData,
|
|
717
|
+
argsTextDelta: chunk.textDelta,
|
|
718
|
+
});
|
|
719
|
+
break;
|
|
720
|
+
|
|
721
|
+
case 'step-start':
|
|
722
|
+
case 'step-finish':
|
|
723
|
+
case 'finish':
|
|
724
|
+
break;
|
|
725
|
+
|
|
726
|
+
case 'tool-call':
|
|
727
|
+
case 'tool-result':
|
|
728
|
+
case 'tool-call-streaming-start':
|
|
729
|
+
case 'tool-call-delta':
|
|
730
|
+
case 'source':
|
|
731
|
+
case 'file':
|
|
732
|
+
default:
|
|
733
|
+
await emitter.emit('watch-v2', chunk);
|
|
734
|
+
break;
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
return {
|
|
739
|
+
text: await streamPromise.promise,
|
|
740
|
+
};
|
|
741
|
+
},
|
|
742
|
+
};
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
if (isTool(params)) {
|
|
746
|
+
if (!params.inputSchema || !params.outputSchema) {
|
|
747
|
+
throw new Error('Tool must have input and output schemas defined');
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
return {
|
|
751
|
+
// TODO: tool probably should have strong id type
|
|
752
|
+
// @ts-ignore
|
|
753
|
+
id: params.id,
|
|
754
|
+
inputSchema: params.inputSchema,
|
|
755
|
+
outputSchema: params.outputSchema,
|
|
756
|
+
execute: async ({ inputData, mastra, runtimeContext }) => {
|
|
757
|
+
return params.execute({
|
|
758
|
+
context: inputData,
|
|
759
|
+
mastra,
|
|
760
|
+
runtimeContext,
|
|
761
|
+
});
|
|
762
|
+
},
|
|
763
|
+
};
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
return {
|
|
767
|
+
id: params.id,
|
|
768
|
+
description: params.description,
|
|
769
|
+
inputSchema: params.inputSchema,
|
|
770
|
+
outputSchema: params.outputSchema,
|
|
771
|
+
resumeSchema: params.resumeSchema,
|
|
772
|
+
suspendSchema: params.suspendSchema,
|
|
773
|
+
execute: params.execute,
|
|
774
|
+
};
|
|
388
775
|
}
|
|
389
776
|
|
|
390
777
|
export function init(inngest: Inngest) {
|
|
@@ -393,13 +780,59 @@ export function init(inngest: Inngest) {
|
|
|
393
780
|
TWorkflowId extends string = string,
|
|
394
781
|
TInput extends z.ZodType<any> = z.ZodType<any>,
|
|
395
782
|
TOutput extends z.ZodType<any> = z.ZodType<any>,
|
|
396
|
-
TSteps extends Step<string, any, any
|
|
397
|
-
|
|
398
|
-
|
|
783
|
+
TSteps extends Step<string, any, any, any, any, InngestEngineType>[] = Step<
|
|
784
|
+
string,
|
|
785
|
+
any,
|
|
786
|
+
any,
|
|
787
|
+
any,
|
|
788
|
+
any,
|
|
789
|
+
InngestEngineType
|
|
790
|
+
>[],
|
|
791
|
+
>(params: WorkflowConfig<TWorkflowId, TInput, TOutput, TSteps>) {
|
|
792
|
+
return new InngestWorkflow<InngestEngineType, TSteps, TWorkflowId, TInput, TOutput, TInput>(params, inngest);
|
|
399
793
|
},
|
|
400
794
|
createStep,
|
|
401
|
-
cloneStep
|
|
402
|
-
|
|
795
|
+
cloneStep<TStepId extends string>(
|
|
796
|
+
step: Step<string, any, any, any, any, InngestEngineType>,
|
|
797
|
+
opts: { id: TStepId },
|
|
798
|
+
): Step<TStepId, any, any, any, any, InngestEngineType> {
|
|
799
|
+
return {
|
|
800
|
+
id: opts.id,
|
|
801
|
+
description: step.description,
|
|
802
|
+
inputSchema: step.inputSchema,
|
|
803
|
+
outputSchema: step.outputSchema,
|
|
804
|
+
execute: step.execute,
|
|
805
|
+
};
|
|
806
|
+
},
|
|
807
|
+
cloneWorkflow<
|
|
808
|
+
TWorkflowId extends string = string,
|
|
809
|
+
TInput extends z.ZodType<any> = z.ZodType<any>,
|
|
810
|
+
TOutput extends z.ZodType<any> = z.ZodType<any>,
|
|
811
|
+
TSteps extends Step<string, any, any, any, any, InngestEngineType>[] = Step<
|
|
812
|
+
string,
|
|
813
|
+
any,
|
|
814
|
+
any,
|
|
815
|
+
any,
|
|
816
|
+
any,
|
|
817
|
+
InngestEngineType
|
|
818
|
+
>[],
|
|
819
|
+
TPrevSchema extends z.ZodType<any> = TInput,
|
|
820
|
+
>(
|
|
821
|
+
workflow: Workflow<InngestEngineType, TSteps, string, TInput, TOutput, TPrevSchema>,
|
|
822
|
+
opts: { id: TWorkflowId },
|
|
823
|
+
): Workflow<InngestEngineType, TSteps, TWorkflowId, TInput, TOutput, TPrevSchema> {
|
|
824
|
+
const wf: Workflow<InngestEngineType, TSteps, TWorkflowId, TInput, TOutput, TPrevSchema> = new Workflow({
|
|
825
|
+
id: opts.id,
|
|
826
|
+
inputSchema: workflow.inputSchema,
|
|
827
|
+
outputSchema: workflow.outputSchema,
|
|
828
|
+
steps: workflow.stepDefs,
|
|
829
|
+
mastra: workflow.mastra,
|
|
830
|
+
});
|
|
831
|
+
|
|
832
|
+
wf.setStepFlow(workflow.stepGraph);
|
|
833
|
+
wf.commit();
|
|
834
|
+
return wf;
|
|
835
|
+
},
|
|
403
836
|
};
|
|
404
837
|
}
|
|
405
838
|
|
|
@@ -413,11 +846,47 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
|
|
|
413
846
|
this.inngestAttempts = inngestAttempts;
|
|
414
847
|
}
|
|
415
848
|
|
|
849
|
+
async execute<TInput, TOutput>(params: {
|
|
850
|
+
workflowId: string;
|
|
851
|
+
runId: string;
|
|
852
|
+
graph: ExecutionGraph;
|
|
853
|
+
serializedStepGraph: SerializedStepFlowEntry[];
|
|
854
|
+
input?: TInput;
|
|
855
|
+
resume?: {
|
|
856
|
+
// TODO: add execute path
|
|
857
|
+
steps: string[];
|
|
858
|
+
stepResults: Record<string, StepResult<any, any, any, any>>;
|
|
859
|
+
resumePayload: any;
|
|
860
|
+
resumePath: number[];
|
|
861
|
+
};
|
|
862
|
+
emitter: Emitter;
|
|
863
|
+
retryConfig?: {
|
|
864
|
+
attempts?: number;
|
|
865
|
+
delay?: number;
|
|
866
|
+
};
|
|
867
|
+
runtimeContext: RuntimeContext;
|
|
868
|
+
abortController: AbortController;
|
|
869
|
+
}): Promise<TOutput> {
|
|
870
|
+
await params.emitter.emit('watch-v2', {
|
|
871
|
+
type: 'start',
|
|
872
|
+
payload: { runId: params.runId },
|
|
873
|
+
});
|
|
874
|
+
|
|
875
|
+
const result = await super.execute<TInput, TOutput>(params);
|
|
876
|
+
|
|
877
|
+
await params.emitter.emit('watch-v2', {
|
|
878
|
+
type: 'finish',
|
|
879
|
+
payload: { runId: params.runId },
|
|
880
|
+
});
|
|
881
|
+
|
|
882
|
+
return result;
|
|
883
|
+
}
|
|
884
|
+
|
|
416
885
|
protected async fmtReturnValue<TOutput>(
|
|
417
886
|
executionSpan: Span | undefined,
|
|
418
|
-
emitter:
|
|
419
|
-
stepResults: Record<string, StepResult<any>>,
|
|
420
|
-
lastOutput: StepResult<any>,
|
|
887
|
+
emitter: Emitter,
|
|
888
|
+
stepResults: Record<string, StepResult<any, any, any, any>>,
|
|
889
|
+
lastOutput: StepResult<any, any, any, any>,
|
|
421
890
|
error?: Error | string,
|
|
422
891
|
): Promise<TOutput> {
|
|
423
892
|
const base: any = {
|
|
@@ -496,21 +965,23 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
|
|
|
496
965
|
resume,
|
|
497
966
|
prevOutput,
|
|
498
967
|
emitter,
|
|
968
|
+
abortController,
|
|
499
969
|
runtimeContext,
|
|
500
970
|
}: {
|
|
501
971
|
workflowId: string;
|
|
502
972
|
runId: string;
|
|
503
973
|
step: Step<string, any, any>;
|
|
504
|
-
stepResults: Record<string, StepResult<any>>;
|
|
974
|
+
stepResults: Record<string, StepResult<any, any, any, any>>;
|
|
505
975
|
executionContext: ExecutionContext;
|
|
506
976
|
resume?: {
|
|
507
977
|
steps: string[];
|
|
508
978
|
resumePayload: any;
|
|
509
979
|
};
|
|
510
980
|
prevOutput: any;
|
|
511
|
-
emitter:
|
|
981
|
+
emitter: Emitter;
|
|
982
|
+
abortController: AbortController;
|
|
512
983
|
runtimeContext: RuntimeContext;
|
|
513
|
-
}): Promise<StepResult<any>> {
|
|
984
|
+
}): Promise<StepResult<any, any, any, any>> {
|
|
514
985
|
return super.executeStep({
|
|
515
986
|
workflowId,
|
|
516
987
|
runId,
|
|
@@ -520,10 +991,28 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
|
|
|
520
991
|
resume,
|
|
521
992
|
prevOutput,
|
|
522
993
|
emitter,
|
|
994
|
+
abortController,
|
|
523
995
|
runtimeContext,
|
|
524
996
|
});
|
|
525
997
|
}
|
|
526
998
|
|
|
999
|
+
async executeSleep({ id, duration }: { id: string; duration: number }): Promise<void> {
|
|
1000
|
+
await this.inngestStep.sleep(id, duration);
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
async executeWaitForEvent({ event, timeout }: { event: string; timeout?: number }): Promise<any> {
|
|
1004
|
+
const eventData = await this.inngestStep.waitForEvent(`user-event-${event}`, {
|
|
1005
|
+
event: `user-event-${event}`,
|
|
1006
|
+
timeout: timeout ?? 5e3,
|
|
1007
|
+
});
|
|
1008
|
+
|
|
1009
|
+
if (eventData === null) {
|
|
1010
|
+
throw 'Timeout waiting for event';
|
|
1011
|
+
}
|
|
1012
|
+
|
|
1013
|
+
return eventData?.data;
|
|
1014
|
+
}
|
|
1015
|
+
|
|
527
1016
|
async executeStep({
|
|
528
1017
|
step,
|
|
529
1018
|
stepResults,
|
|
@@ -531,29 +1020,26 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
|
|
|
531
1020
|
resume,
|
|
532
1021
|
prevOutput,
|
|
533
1022
|
emitter,
|
|
1023
|
+
abortController,
|
|
534
1024
|
runtimeContext,
|
|
535
1025
|
}: {
|
|
536
1026
|
step: Step<string, any, any>;
|
|
537
|
-
stepResults: Record<string, StepResult<any>>;
|
|
538
|
-
executionContext:
|
|
539
|
-
workflowId: string;
|
|
540
|
-
runId: string;
|
|
541
|
-
executionPath: number[];
|
|
542
|
-
suspendedPaths: Record<string, number[]>;
|
|
543
|
-
retryConfig: { attempts: number; delay: number };
|
|
544
|
-
};
|
|
1027
|
+
stepResults: Record<string, StepResult<any, any, any, any>>;
|
|
1028
|
+
executionContext: ExecutionContext;
|
|
545
1029
|
resume?: {
|
|
546
1030
|
steps: string[];
|
|
547
1031
|
resumePayload: any;
|
|
548
1032
|
runId?: string;
|
|
549
1033
|
};
|
|
550
1034
|
prevOutput: any;
|
|
551
|
-
emitter:
|
|
1035
|
+
emitter: Emitter;
|
|
1036
|
+
abortController: AbortController;
|
|
552
1037
|
runtimeContext: RuntimeContext;
|
|
553
|
-
}): Promise<StepResult<any>> {
|
|
554
|
-
await this.inngestStep.run(
|
|
1038
|
+
}): Promise<StepResult<any, any, any, any>> {
|
|
1039
|
+
const startedAt = await this.inngestStep.run(
|
|
555
1040
|
`workflow.${executionContext.workflowId}.run.${executionContext.runId}.step.${step.id}.running_ev`,
|
|
556
1041
|
async () => {
|
|
1042
|
+
const startedAt = Date.now();
|
|
557
1043
|
await emitter.emit('watch', {
|
|
558
1044
|
type: 'watch',
|
|
559
1045
|
payload: {
|
|
@@ -575,6 +1061,16 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
|
|
|
575
1061
|
},
|
|
576
1062
|
eventTimestamp: Date.now(),
|
|
577
1063
|
});
|
|
1064
|
+
|
|
1065
|
+
await emitter.emit('watch-v2', {
|
|
1066
|
+
type: 'step-start',
|
|
1067
|
+
payload: {
|
|
1068
|
+
id: step.id,
|
|
1069
|
+
status: 'running',
|
|
1070
|
+
},
|
|
1071
|
+
});
|
|
1072
|
+
|
|
1073
|
+
return startedAt;
|
|
578
1074
|
},
|
|
579
1075
|
);
|
|
580
1076
|
|
|
@@ -641,10 +1137,20 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
|
|
|
641
1137
|
eventTimestamp: Date.now(),
|
|
642
1138
|
});
|
|
643
1139
|
|
|
1140
|
+
await emitter.emit('watch-v2', {
|
|
1141
|
+
type: 'step-result',
|
|
1142
|
+
payload: {
|
|
1143
|
+
id: step.id,
|
|
1144
|
+
status: 'failed',
|
|
1145
|
+
error: result?.error,
|
|
1146
|
+
payload: prevOutput,
|
|
1147
|
+
},
|
|
1148
|
+
});
|
|
1149
|
+
|
|
644
1150
|
return { executionContext, result: { status: 'failed', error: result?.error } };
|
|
645
1151
|
} else if (result.status === 'suspended') {
|
|
646
1152
|
const suspendedSteps = Object.entries(result.steps).filter(([_stepName, stepResult]) => {
|
|
647
|
-
const stepRes: StepResult<any> = stepResult as StepResult<any>;
|
|
1153
|
+
const stepRes: StepResult<any, any, any, any> = stepResult as StepResult<any, any, any, any>;
|
|
648
1154
|
return stepRes?.status === 'suspended';
|
|
649
1155
|
});
|
|
650
1156
|
|
|
@@ -671,6 +1177,14 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
|
|
|
671
1177
|
eventTimestamp: Date.now(),
|
|
672
1178
|
});
|
|
673
1179
|
|
|
1180
|
+
await emitter.emit('watch-v2', {
|
|
1181
|
+
type: 'step-suspended',
|
|
1182
|
+
payload: {
|
|
1183
|
+
id: step.id,
|
|
1184
|
+
status: 'suspended',
|
|
1185
|
+
},
|
|
1186
|
+
});
|
|
1187
|
+
|
|
674
1188
|
return {
|
|
675
1189
|
executionContext,
|
|
676
1190
|
result: {
|
|
@@ -727,19 +1241,39 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
|
|
|
727
1241
|
eventTimestamp: Date.now(),
|
|
728
1242
|
});
|
|
729
1243
|
|
|
1244
|
+
await emitter.emit('watch-v2', {
|
|
1245
|
+
type: 'step-result',
|
|
1246
|
+
payload: {
|
|
1247
|
+
id: step.id,
|
|
1248
|
+
status: 'success',
|
|
1249
|
+
output: result?.result,
|
|
1250
|
+
},
|
|
1251
|
+
});
|
|
1252
|
+
|
|
1253
|
+
await emitter.emit('watch-v2', {
|
|
1254
|
+
type: 'step-finish',
|
|
1255
|
+
payload: {
|
|
1256
|
+
id: step.id,
|
|
1257
|
+
metadata: {},
|
|
1258
|
+
},
|
|
1259
|
+
});
|
|
1260
|
+
|
|
730
1261
|
return { executionContext, result: { status: 'success', output: result?.result } };
|
|
731
1262
|
},
|
|
732
1263
|
);
|
|
733
1264
|
|
|
734
1265
|
Object.assign(executionContext, res.executionContext);
|
|
735
|
-
return res.result as StepResult<any>;
|
|
1266
|
+
return res.result as StepResult<any, any, any, any>;
|
|
736
1267
|
}
|
|
737
1268
|
|
|
738
1269
|
const stepRes = await this.inngestStep.run(`workflow.${executionContext.workflowId}.step.${step.id}`, async () => {
|
|
739
1270
|
let execResults: any;
|
|
740
1271
|
let suspended: { payload: any } | undefined;
|
|
1272
|
+
let bailed: { payload: any } | undefined;
|
|
1273
|
+
|
|
741
1274
|
try {
|
|
742
1275
|
const result = await step.execute({
|
|
1276
|
+
runId: executionContext.runId,
|
|
743
1277
|
mastra: this.mastra!,
|
|
744
1278
|
runtimeContext,
|
|
745
1279
|
inputData: prevOutput,
|
|
@@ -757,22 +1291,56 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
|
|
|
757
1291
|
executionContext.suspendedPaths[step.id] = executionContext.executionPath;
|
|
758
1292
|
suspended = { payload: suspendPayload };
|
|
759
1293
|
},
|
|
1294
|
+
bail: (result: any) => {
|
|
1295
|
+
bailed = { payload: result };
|
|
1296
|
+
},
|
|
760
1297
|
resume: {
|
|
761
1298
|
steps: resume?.steps?.slice(1) || [],
|
|
762
1299
|
resumePayload: resume?.resumePayload,
|
|
763
1300
|
// @ts-ignore
|
|
764
1301
|
runId: stepResults[step.id]?.payload?.__workflow_meta?.runId,
|
|
765
1302
|
},
|
|
766
|
-
emitter,
|
|
1303
|
+
[EMITTER_SYMBOL]: emitter,
|
|
1304
|
+
engine: {
|
|
1305
|
+
step: this.inngestStep,
|
|
1306
|
+
},
|
|
1307
|
+
abortSignal: abortController.signal,
|
|
767
1308
|
});
|
|
768
|
-
|
|
769
|
-
|
|
1309
|
+
const endedAt = Date.now();
|
|
1310
|
+
|
|
1311
|
+
execResults = {
|
|
1312
|
+
status: 'success',
|
|
1313
|
+
output: result,
|
|
1314
|
+
startedAt,
|
|
1315
|
+
endedAt,
|
|
1316
|
+
payload: prevOutput,
|
|
1317
|
+
resumedAt: resume?.steps[0] === step.id ? startedAt : undefined,
|
|
1318
|
+
resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : undefined,
|
|
1319
|
+
};
|
|
770
1320
|
} catch (e) {
|
|
771
|
-
execResults = {
|
|
1321
|
+
execResults = {
|
|
1322
|
+
status: 'failed',
|
|
1323
|
+
payload: prevOutput,
|
|
1324
|
+
error: e instanceof Error ? e.message : String(e),
|
|
1325
|
+
endedAt: Date.now(),
|
|
1326
|
+
startedAt,
|
|
1327
|
+
resumedAt: resume?.steps[0] === step.id ? startedAt : undefined,
|
|
1328
|
+
resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : undefined,
|
|
1329
|
+
};
|
|
772
1330
|
}
|
|
773
1331
|
|
|
774
1332
|
if (suspended) {
|
|
775
|
-
execResults = {
|
|
1333
|
+
execResults = {
|
|
1334
|
+
status: 'suspended',
|
|
1335
|
+
suspendedPayload: suspended.payload,
|
|
1336
|
+
payload: prevOutput,
|
|
1337
|
+
suspendedAt: Date.now(),
|
|
1338
|
+
startedAt,
|
|
1339
|
+
resumedAt: resume?.steps[0] === step.id ? startedAt : undefined,
|
|
1340
|
+
resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : undefined,
|
|
1341
|
+
};
|
|
1342
|
+
} else if (bailed) {
|
|
1343
|
+
execResults = { status: 'bailed', output: bailed.payload, payload: prevOutput, endedAt: Date.now(), startedAt };
|
|
776
1344
|
}
|
|
777
1345
|
|
|
778
1346
|
if (execResults.status === 'failed') {
|
|
@@ -786,12 +1354,11 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
|
|
|
786
1354
|
payload: {
|
|
787
1355
|
currentStep: {
|
|
788
1356
|
id: step.id,
|
|
789
|
-
|
|
790
|
-
output: execResults.output,
|
|
1357
|
+
...execResults,
|
|
791
1358
|
},
|
|
792
1359
|
workflowState: {
|
|
793
1360
|
status: 'running',
|
|
794
|
-
steps: stepResults,
|
|
1361
|
+
steps: { ...stepResults, [step.id]: execResults },
|
|
795
1362
|
result: null,
|
|
796
1363
|
error: null,
|
|
797
1364
|
},
|
|
@@ -799,6 +1366,32 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
|
|
|
799
1366
|
eventTimestamp: Date.now(),
|
|
800
1367
|
});
|
|
801
1368
|
|
|
1369
|
+
if (execResults.status === 'suspended') {
|
|
1370
|
+
await emitter.emit('watch-v2', {
|
|
1371
|
+
type: 'step-suspended',
|
|
1372
|
+
payload: {
|
|
1373
|
+
id: step.id,
|
|
1374
|
+
...execResults,
|
|
1375
|
+
},
|
|
1376
|
+
});
|
|
1377
|
+
} else {
|
|
1378
|
+
await emitter.emit('watch-v2', {
|
|
1379
|
+
type: 'step-result',
|
|
1380
|
+
payload: {
|
|
1381
|
+
id: step.id,
|
|
1382
|
+
...execResults,
|
|
1383
|
+
},
|
|
1384
|
+
});
|
|
1385
|
+
|
|
1386
|
+
await emitter.emit('watch-v2', {
|
|
1387
|
+
type: 'step-finish',
|
|
1388
|
+
payload: {
|
|
1389
|
+
id: step.id,
|
|
1390
|
+
metadata: {},
|
|
1391
|
+
},
|
|
1392
|
+
});
|
|
1393
|
+
}
|
|
1394
|
+
|
|
802
1395
|
return { result: execResults, executionContext, stepResults };
|
|
803
1396
|
});
|
|
804
1397
|
|
|
@@ -816,11 +1409,19 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
|
|
|
816
1409
|
runId,
|
|
817
1410
|
stepResults,
|
|
818
1411
|
executionContext,
|
|
1412
|
+
serializedStepGraph,
|
|
1413
|
+
workflowStatus,
|
|
1414
|
+
result,
|
|
1415
|
+
error,
|
|
819
1416
|
}: {
|
|
820
1417
|
workflowId: string;
|
|
821
1418
|
runId: string;
|
|
822
|
-
stepResults: Record<string, StepResult<any>>;
|
|
1419
|
+
stepResults: Record<string, StepResult<any, any, any, any>>;
|
|
1420
|
+
serializedStepGraph: SerializedStepFlowEntry[];
|
|
823
1421
|
executionContext: ExecutionContext;
|
|
1422
|
+
workflowStatus: 'success' | 'failed' | 'suspended' | 'running';
|
|
1423
|
+
result?: Record<string, any>;
|
|
1424
|
+
error?: string | Error;
|
|
824
1425
|
}) {
|
|
825
1426
|
await this.inngestStep.run(
|
|
826
1427
|
`workflow.${workflowId}.run.${runId}.path.${JSON.stringify(executionContext.executionPath)}.stepUpdate`,
|
|
@@ -834,6 +1435,10 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
|
|
|
834
1435
|
context: stepResults as any,
|
|
835
1436
|
activePaths: [],
|
|
836
1437
|
suspendedPaths: executionContext.suspendedPaths,
|
|
1438
|
+
serializedStepGraph,
|
|
1439
|
+
status: workflowStatus,
|
|
1440
|
+
result,
|
|
1441
|
+
error,
|
|
837
1442
|
// @ts-ignore
|
|
838
1443
|
timestamp: Date.now(),
|
|
839
1444
|
},
|
|
@@ -849,27 +1454,35 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
|
|
|
849
1454
|
prevOutput,
|
|
850
1455
|
prevStep,
|
|
851
1456
|
stepResults,
|
|
1457
|
+
serializedStepGraph,
|
|
852
1458
|
resume,
|
|
853
1459
|
executionContext,
|
|
854
1460
|
emitter,
|
|
1461
|
+
abortController,
|
|
855
1462
|
runtimeContext,
|
|
856
1463
|
}: {
|
|
857
1464
|
workflowId: string;
|
|
858
1465
|
runId: string;
|
|
859
|
-
entry: {
|
|
1466
|
+
entry: {
|
|
1467
|
+
type: 'conditional';
|
|
1468
|
+
steps: StepFlowEntry[];
|
|
1469
|
+
conditions: ExecuteFunction<any, any, any, any, InngestEngineType>[];
|
|
1470
|
+
};
|
|
860
1471
|
prevStep: StepFlowEntry;
|
|
1472
|
+
serializedStepGraph: SerializedStepFlowEntry[];
|
|
861
1473
|
prevOutput: any;
|
|
862
|
-
stepResults: Record<string, StepResult<any>>;
|
|
1474
|
+
stepResults: Record<string, StepResult<any, any, any, any>>;
|
|
863
1475
|
resume?: {
|
|
864
1476
|
steps: string[];
|
|
865
|
-
stepResults: Record<string, StepResult<any>>;
|
|
1477
|
+
stepResults: Record<string, StepResult<any, any, any, any>>;
|
|
866
1478
|
resumePayload: any;
|
|
867
1479
|
resumePath: number[];
|
|
868
1480
|
};
|
|
869
1481
|
executionContext: ExecutionContext;
|
|
870
|
-
emitter:
|
|
1482
|
+
emitter: Emitter;
|
|
1483
|
+
abortController: AbortController;
|
|
871
1484
|
runtimeContext: RuntimeContext;
|
|
872
|
-
}): Promise<StepResult<any>> {
|
|
1485
|
+
}): Promise<StepResult<any, any, any, any>> {
|
|
873
1486
|
let execResults: any;
|
|
874
1487
|
const truthyIndexes = (
|
|
875
1488
|
await Promise.all(
|
|
@@ -877,8 +1490,10 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
|
|
|
877
1490
|
this.inngestStep.run(`workflow.${workflowId}.conditional.${index}`, async () => {
|
|
878
1491
|
try {
|
|
879
1492
|
const result = await cond({
|
|
1493
|
+
runId,
|
|
880
1494
|
mastra: this.mastra!,
|
|
881
1495
|
runtimeContext,
|
|
1496
|
+
runCount: -1,
|
|
882
1497
|
inputData: prevOutput,
|
|
883
1498
|
getInitData: () => stepResults?.input as any,
|
|
884
1499
|
getStepResult: (step: any) => {
|
|
@@ -896,7 +1511,15 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
|
|
|
896
1511
|
|
|
897
1512
|
// TODO: this function shouldn't have suspend probably?
|
|
898
1513
|
suspend: async (_suspendPayload: any) => {},
|
|
899
|
-
|
|
1514
|
+
bail: () => {},
|
|
1515
|
+
abort: () => {
|
|
1516
|
+
abortController.abort();
|
|
1517
|
+
},
|
|
1518
|
+
[EMITTER_SYMBOL]: emitter,
|
|
1519
|
+
engine: {
|
|
1520
|
+
step: this.inngestStep,
|
|
1521
|
+
},
|
|
1522
|
+
abortSignal: abortController.signal,
|
|
900
1523
|
});
|
|
901
1524
|
return result ? index : null;
|
|
902
1525
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
@@ -909,7 +1532,7 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
|
|
|
909
1532
|
).filter((index: any): index is number => index !== null);
|
|
910
1533
|
|
|
911
1534
|
const stepsToRun = entry.steps.filter((_, index) => truthyIndexes.includes(index));
|
|
912
|
-
const results: StepResult<any>[] = await Promise.all(
|
|
1535
|
+
const results: { result: StepResult<any, any, any, any> }[] = await Promise.all(
|
|
913
1536
|
stepsToRun.map((step, index) =>
|
|
914
1537
|
this.executeEntry({
|
|
915
1538
|
workflowId,
|
|
@@ -918,6 +1541,7 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
|
|
|
918
1541
|
prevStep,
|
|
919
1542
|
stepResults,
|
|
920
1543
|
resume,
|
|
1544
|
+
serializedStepGraph,
|
|
921
1545
|
executionContext: {
|
|
922
1546
|
workflowId,
|
|
923
1547
|
runId,
|
|
@@ -927,21 +1551,24 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
|
|
|
927
1551
|
executionSpan: executionContext.executionSpan,
|
|
928
1552
|
},
|
|
929
1553
|
emitter,
|
|
1554
|
+
abortController,
|
|
930
1555
|
runtimeContext,
|
|
931
1556
|
}),
|
|
932
1557
|
),
|
|
933
1558
|
);
|
|
934
|
-
const hasFailed = results.find(result => result.status === 'failed')
|
|
935
|
-
|
|
1559
|
+
const hasFailed = results.find(result => result.result.status === 'failed') as {
|
|
1560
|
+
result: StepFailure<any, any, any>;
|
|
1561
|
+
};
|
|
1562
|
+
const hasSuspended = results.find(result => result.result.status === 'suspended');
|
|
936
1563
|
if (hasFailed) {
|
|
937
|
-
execResults = { status: 'failed', error: hasFailed.error };
|
|
1564
|
+
execResults = { status: 'failed', error: hasFailed.result.error };
|
|
938
1565
|
} else if (hasSuspended) {
|
|
939
|
-
execResults = { status: 'suspended', payload: hasSuspended.
|
|
1566
|
+
execResults = { status: 'suspended', payload: hasSuspended.result.suspendPayload };
|
|
940
1567
|
} else {
|
|
941
1568
|
execResults = {
|
|
942
1569
|
status: 'success',
|
|
943
1570
|
output: results.reduce((acc: Record<string, any>, result, index) => {
|
|
944
|
-
if (result.status === 'success') {
|
|
1571
|
+
if (result.result.status === 'success') {
|
|
945
1572
|
// @ts-ignore
|
|
946
1573
|
acc[stepsToRun[index]!.step.id] = result.output;
|
|
947
1574
|
}
|