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