@mastra/inngest 0.11.11-alpha.0 → 0.12.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/index.ts CHANGED
@@ -1,8 +1,13 @@
1
1
  import { randomUUID } from 'crypto';
2
2
  import type { ReadableStream } from 'node:stream/web';
3
3
  import { subscribe } from '@inngest/realtime';
4
- import type { Agent, Mastra, ToolExecutionContext, WorkflowRun, WorkflowRuns } from '@mastra/core';
4
+ import type { Agent } from '@mastra/core/agent';
5
+ import { AISpanType, wrapMastra } from '@mastra/core/ai-tracing';
6
+ import type { TracingContext, AnyAISpan } from '@mastra/core/ai-tracing';
5
7
  import { RuntimeContext } from '@mastra/core/di';
8
+ import type { Mastra } from '@mastra/core/mastra';
9
+ import type { WorkflowRun, WorkflowRuns } from '@mastra/core/storage';
10
+ import type { ToolExecutionContext } from '@mastra/core/tools';
6
11
  import { Tool, ToolStream } from '@mastra/core/tools';
7
12
  import { Workflow, Run, DefaultExecutionEngine } from '@mastra/core/workflows';
8
13
  import type {
@@ -160,6 +165,7 @@ export class InngestRun<
160
165
  context: {} as any,
161
166
  activePaths: [],
162
167
  suspendedPaths: {},
168
+ waitingPaths: {},
163
169
  timestamp: Date.now(),
164
170
  status: 'running',
165
171
  },
@@ -483,6 +489,7 @@ export class InngestWorkflow<
483
489
  value: {},
484
490
  context: {},
485
491
  activePaths: [],
492
+ waitingPaths: {},
486
493
  serializedStepGraph: this.serializedStepGraph,
487
494
  suspendedPaths: {},
488
495
  result: undefined,
@@ -556,6 +563,7 @@ export class InngestWorkflow<
556
563
  runtimeContext: new RuntimeContext(), // TODO
557
564
  resume,
558
565
  abortController: new AbortController(),
566
+ currentSpan: undefined, // TODO: Pass actual parent AI span from workflow execution context
559
567
  });
560
568
 
561
569
  return { result, runId };
@@ -678,7 +686,7 @@ export function createStep<
678
686
  outputSchema: z.object({
679
687
  text: z.string(),
680
688
  }),
681
- execute: async ({ inputData, [EMITTER_SYMBOL]: emitter, runtimeContext, abortSignal, abort }) => {
689
+ execute: async ({ inputData, [EMITTER_SYMBOL]: emitter, runtimeContext, abortSignal, abort, tracingContext }) => {
682
690
  let streamPromise = {} as {
683
691
  promise: Promise<string>;
684
692
  resolve: (value: string) => void;
@@ -701,6 +709,7 @@ export function createStep<
701
709
  // resourceId: inputData.resourceId,
702
710
  // threadId: inputData.threadId,
703
711
  runtimeContext,
712
+ tracingContext,
704
713
  onFinish: result => {
705
714
  streamPromise.resolve(result.text);
706
715
  },
@@ -756,11 +765,12 @@ export function createStep<
756
765
  id: params.id,
757
766
  inputSchema: params.inputSchema,
758
767
  outputSchema: params.outputSchema,
759
- execute: async ({ inputData, mastra, runtimeContext }) => {
768
+ execute: async ({ inputData, mastra, runtimeContext, tracingContext }) => {
760
769
  return params.execute({
761
770
  context: inputData,
762
- mastra,
771
+ mastra: wrapMastra(mastra, tracingContext),
763
772
  runtimeContext,
773
+ tracingContext,
764
774
  });
765
775
  },
766
776
  };
@@ -869,6 +879,7 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
869
879
  };
870
880
  runtimeContext: RuntimeContext;
871
881
  abortController: AbortController;
882
+ currentSpan?: AnyAISpan;
872
883
  }): Promise<TOutput> {
873
884
  await params.emitter.emit('watch-v2', {
874
885
  type: 'start',
@@ -959,52 +970,6 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
959
970
  return base as TOutput;
960
971
  }
961
972
 
962
- async superExecuteStep({
963
- workflowId,
964
- runId,
965
- step,
966
- stepResults,
967
- executionContext,
968
- resume,
969
- prevOutput,
970
- emitter,
971
- abortController,
972
- runtimeContext,
973
- writableStream,
974
- serializedStepGraph,
975
- }: {
976
- workflowId: string;
977
- runId: string;
978
- step: Step<string, any, any>;
979
- stepResults: Record<string, StepResult<any, any, any, any>>;
980
- executionContext: ExecutionContext;
981
- resume?: {
982
- steps: string[];
983
- resumePayload: any;
984
- };
985
- prevOutput: any;
986
- emitter: Emitter;
987
- abortController: AbortController;
988
- runtimeContext: RuntimeContext;
989
- writableStream?: WritableStream<ChunkType>;
990
- serializedStepGraph: SerializedStepFlowEntry[];
991
- }): Promise<StepResult<any, any, any, any>> {
992
- return super.executeStep({
993
- workflowId,
994
- runId,
995
- step,
996
- stepResults,
997
- executionContext,
998
- resume,
999
- prevOutput,
1000
- emitter,
1001
- abortController,
1002
- runtimeContext,
1003
- writableStream,
1004
- serializedStepGraph,
1005
- });
1006
- }
1007
-
1008
973
  // async executeSleep({ id, duration }: { id: string; duration: number }): Promise<void> {
1009
974
  // await this.inngestStep.sleep(id, duration);
1010
975
  // }
@@ -1019,6 +984,7 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
1019
984
  abortController,
1020
985
  runtimeContext,
1021
986
  writableStream,
987
+ tracingContext,
1022
988
  }: {
1023
989
  workflowId: string;
1024
990
  runId: string;
@@ -1043,9 +1009,19 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
1043
1009
  abortController: AbortController;
1044
1010
  runtimeContext: RuntimeContext;
1045
1011
  writableStream?: WritableStream<ChunkType>;
1012
+ tracingContext?: TracingContext;
1046
1013
  }): Promise<void> {
1047
1014
  let { duration, fn } = entry;
1048
1015
 
1016
+ const sleepSpan = tracingContext?.currentSpan?.createChildSpan({
1017
+ type: AISpanType.WORKFLOW_SLEEP,
1018
+ name: `sleep: ${duration ? `${duration}ms` : 'dynamic'}`,
1019
+ attributes: {
1020
+ durationMs: duration,
1021
+ sleepType: fn ? 'dynamic' : 'fixed',
1022
+ },
1023
+ });
1024
+
1049
1025
  if (fn) {
1050
1026
  const stepCallId = randomUUID();
1051
1027
  duration = await this.inngestStep.run(`workflow.${workflowId}.sleep.${entry.id}`, async () => {
@@ -1056,6 +1032,9 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
1056
1032
  runtimeContext,
1057
1033
  inputData: prevOutput,
1058
1034
  runCount: -1,
1035
+ tracingContext: {
1036
+ currentSpan: sleepSpan,
1037
+ },
1059
1038
  getInitData: () => stepResults?.input as any,
1060
1039
  getStepResult: (step: any) => {
1061
1040
  if (!step?.id) {
@@ -1090,9 +1069,22 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
1090
1069
  ),
1091
1070
  });
1092
1071
  });
1072
+
1073
+ // Update sleep span with dynamic duration
1074
+ sleepSpan?.update({
1075
+ attributes: {
1076
+ durationMs: duration,
1077
+ },
1078
+ });
1093
1079
  }
1094
1080
 
1095
- await this.inngestStep.sleep(entry.id, !duration || duration < 0 ? 0 : duration);
1081
+ try {
1082
+ await this.inngestStep.sleep(entry.id, !duration || duration < 0 ? 0 : duration);
1083
+ sleepSpan?.end();
1084
+ } catch (e) {
1085
+ sleepSpan?.error({ error: e as Error });
1086
+ throw e;
1087
+ }
1096
1088
  }
1097
1089
 
1098
1090
  async executeSleepUntil({
@@ -1105,6 +1097,7 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
1105
1097
  abortController,
1106
1098
  runtimeContext,
1107
1099
  writableStream,
1100
+ tracingContext,
1108
1101
  }: {
1109
1102
  workflowId: string;
1110
1103
  runId: string;
@@ -1129,9 +1122,20 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
1129
1122
  abortController: AbortController;
1130
1123
  runtimeContext: RuntimeContext;
1131
1124
  writableStream?: WritableStream<ChunkType>;
1125
+ tracingContext?: TracingContext;
1132
1126
  }): Promise<void> {
1133
1127
  let { date, fn } = entry;
1134
1128
 
1129
+ const sleepUntilSpan = tracingContext?.currentSpan?.createChildSpan({
1130
+ type: AISpanType.WORKFLOW_SLEEP,
1131
+ name: `sleepUntil: ${date ? date.toISOString() : 'dynamic'}`,
1132
+ attributes: {
1133
+ untilDate: date,
1134
+ durationMs: date ? Math.max(0, date.getTime() - Date.now()) : undefined,
1135
+ sleepType: fn ? 'dynamic' : 'fixed',
1136
+ },
1137
+ });
1138
+
1135
1139
  if (fn) {
1136
1140
  date = await this.inngestStep.run(`workflow.${workflowId}.sleepUntil.${entry.id}`, async () => {
1137
1141
  const stepCallId = randomUUID();
@@ -1142,6 +1146,9 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
1142
1146
  runtimeContext,
1143
1147
  inputData: prevOutput,
1144
1148
  runCount: -1,
1149
+ tracingContext: {
1150
+ currentSpan: sleepUntilSpan,
1151
+ },
1145
1152
  getInitData: () => stepResults?.input as any,
1146
1153
  getStepResult: (step: any) => {
1147
1154
  if (!step?.id) {
@@ -1176,13 +1183,28 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
1176
1183
  ),
1177
1184
  });
1178
1185
  });
1186
+
1187
+ // Update sleep until span with dynamic duration
1188
+ const time = !date ? 0 : date.getTime() - Date.now();
1189
+ sleepUntilSpan?.update({
1190
+ attributes: {
1191
+ durationMs: Math.max(0, time),
1192
+ },
1193
+ });
1179
1194
  }
1180
1195
 
1181
1196
  if (!(date instanceof Date)) {
1197
+ sleepUntilSpan?.end();
1182
1198
  return;
1183
1199
  }
1184
1200
 
1185
- await this.inngestStep.sleepUntil(entry.id, date);
1201
+ try {
1202
+ await this.inngestStep.sleepUntil(entry.id, date);
1203
+ sleepUntilSpan?.end();
1204
+ } catch (e) {
1205
+ sleepUntilSpan?.error({ error: e as Error });
1206
+ throw e;
1207
+ }
1186
1208
  }
1187
1209
 
1188
1210
  async executeWaitForEvent({ event, timeout }: { event: string; timeout?: number }): Promise<any> {
@@ -1208,6 +1230,7 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
1208
1230
  abortController,
1209
1231
  runtimeContext,
1210
1232
  writableStream,
1233
+ tracingContext,
1211
1234
  }: {
1212
1235
  step: Step<string, any, any>;
1213
1236
  stepResults: Record<string, StepResult<any, any, any, any>>;
@@ -1222,7 +1245,17 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
1222
1245
  abortController: AbortController;
1223
1246
  runtimeContext: RuntimeContext;
1224
1247
  writableStream?: WritableStream<ChunkType>;
1248
+ tracingContext?: TracingContext;
1225
1249
  }): Promise<StepResult<any, any, any, any>> {
1250
+ const stepAISpan = tracingContext?.currentSpan?.createChildSpan({
1251
+ name: `workflow step: '${step.id}'`,
1252
+ type: AISpanType.WORKFLOW_STEP,
1253
+ input: prevOutput,
1254
+ attributes: {
1255
+ stepId: step.id,
1256
+ },
1257
+ });
1258
+
1226
1259
  const startedAt = await this.inngestStep.run(
1227
1260
  `workflow.${executionContext.workflowId}.run.${executionContext.runId}.step.${step.id}.running_ev`,
1228
1261
  async () => {
@@ -1456,7 +1489,18 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
1456
1489
  }
1457
1490
 
1458
1491
  const stepRes = await this.inngestStep.run(`workflow.${executionContext.workflowId}.step.${step.id}`, async () => {
1459
- let execResults: any;
1492
+ let execResults: {
1493
+ status: 'success' | 'failed' | 'suspended' | 'bailed';
1494
+ output?: any;
1495
+ startedAt: number;
1496
+ endedAt?: number;
1497
+ payload: any;
1498
+ error?: string;
1499
+ resumedAt?: number;
1500
+ resumePayload?: any;
1501
+ suspendedPayload?: any;
1502
+ suspendedAt?: number;
1503
+ };
1460
1504
  let suspended: { payload: any } | undefined;
1461
1505
  let bailed: { payload: any } | undefined;
1462
1506
 
@@ -1468,6 +1512,9 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
1468
1512
  writableStream,
1469
1513
  inputData: prevOutput,
1470
1514
  resumeData: resume?.steps[0] === step.id ? resume?.resumePayload : undefined,
1515
+ tracingContext: {
1516
+ currentSpan: stepAISpan,
1517
+ },
1471
1518
  getInitData: () => stepResults?.input as any,
1472
1519
  getStepResult: (step: any) => {
1473
1520
  const result = stepResults[step.id];
@@ -1535,7 +1582,9 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
1535
1582
 
1536
1583
  if (execResults.status === 'failed') {
1537
1584
  if (executionContext.retryConfig.attempts > 0 && this.inngestAttempts < executionContext.retryConfig.attempts) {
1538
- throw execResults.error;
1585
+ const error = new Error(execResults.error);
1586
+ stepAISpan?.error({ error });
1587
+ throw error;
1539
1588
  }
1540
1589
  }
1541
1590
 
@@ -1582,6 +1631,8 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
1582
1631
  });
1583
1632
  }
1584
1633
 
1634
+ stepAISpan?.end({ output: execResults });
1635
+
1585
1636
  return { result: execResults, executionContext, stepResults };
1586
1637
  });
1587
1638
 
@@ -1626,6 +1677,7 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
1626
1677
  context: stepResults as any,
1627
1678
  activePaths: [],
1628
1679
  suspendedPaths: executionContext.suspendedPaths,
1680
+ waitingPaths: {},
1629
1681
  serializedStepGraph,
1630
1682
  status: workflowStatus,
1631
1683
  result,
@@ -1652,6 +1704,7 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
1652
1704
  abortController,
1653
1705
  runtimeContext,
1654
1706
  writableStream,
1707
+ tracingContext,
1655
1708
  }: {
1656
1709
  workflowId: string;
1657
1710
  runId: string;
@@ -1675,12 +1728,31 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
1675
1728
  abortController: AbortController;
1676
1729
  runtimeContext: RuntimeContext;
1677
1730
  writableStream?: WritableStream<ChunkType>;
1731
+ tracingContext?: TracingContext;
1678
1732
  }): Promise<StepResult<any, any, any, any>> {
1733
+ const conditionalSpan = tracingContext?.currentSpan?.createChildSpan({
1734
+ type: AISpanType.WORKFLOW_CONDITIONAL,
1735
+ name: `conditional: ${entry.conditions.length} conditions`,
1736
+ input: prevOutput,
1737
+ attributes: {
1738
+ conditionCount: entry.conditions.length,
1739
+ },
1740
+ });
1741
+
1679
1742
  let execResults: any;
1680
1743
  const truthyIndexes = (
1681
1744
  await Promise.all(
1682
1745
  entry.conditions.map((cond, index) =>
1683
1746
  this.inngestStep.run(`workflow.${workflowId}.conditional.${index}`, async () => {
1747
+ const evalSpan = conditionalSpan?.createChildSpan({
1748
+ type: AISpanType.WORKFLOW_CONDITIONAL_EVAL,
1749
+ name: `condition ${index}`,
1750
+ input: prevOutput,
1751
+ attributes: {
1752
+ conditionIndex: index,
1753
+ },
1754
+ });
1755
+
1684
1756
  try {
1685
1757
  const result = await cond({
1686
1758
  runId,
@@ -1689,6 +1761,9 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
1689
1761
  runtimeContext,
1690
1762
  runCount: -1,
1691
1763
  inputData: prevOutput,
1764
+ tracingContext: {
1765
+ currentSpan: evalSpan,
1766
+ },
1692
1767
  getInitData: () => stepResults?.input as any,
1693
1768
  getStepResult: (step: any) => {
1694
1769
  if (!step?.id) {
@@ -1724,9 +1799,23 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
1724
1799
  writableStream,
1725
1800
  ),
1726
1801
  });
1802
+
1803
+ evalSpan?.end({
1804
+ output: result,
1805
+ attributes: {
1806
+ result: !!result,
1807
+ },
1808
+ });
1809
+
1727
1810
  return result ? index : null;
1728
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
1729
1811
  } catch (e: unknown) {
1812
+ evalSpan?.error({
1813
+ error: e instanceof Error ? e : new Error(String(e)),
1814
+ attributes: {
1815
+ result: false,
1816
+ },
1817
+ });
1818
+
1730
1819
  return null;
1731
1820
  }
1732
1821
  }),
@@ -1735,6 +1824,15 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
1735
1824
  ).filter((index: any): index is number => index !== null);
1736
1825
 
1737
1826
  const stepsToRun = entry.steps.filter((_, index) => truthyIndexes.includes(index));
1827
+
1828
+ // Update conditional span with evaluation results
1829
+ conditionalSpan?.update({
1830
+ attributes: {
1831
+ truthyIndexes,
1832
+ selectedSteps: stepsToRun.map(s => (s.type === 'step' ? s.step.id : `control-${s.type}`)),
1833
+ },
1834
+ });
1835
+
1738
1836
  const results: { result: StepResult<any, any, any, any> }[] = await Promise.all(
1739
1837
  stepsToRun.map((step, index) =>
1740
1838
  this.executeEntry({
@@ -1757,6 +1855,9 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
1757
1855
  abortController,
1758
1856
  runtimeContext,
1759
1857
  writableStream,
1858
+ tracingContext: {
1859
+ currentSpan: conditionalSpan,
1860
+ },
1760
1861
  }),
1761
1862
  ),
1762
1863
  );
@@ -1782,6 +1883,16 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
1782
1883
  };
1783
1884
  }
1784
1885
 
1886
+ if (execResults.status === 'failed') {
1887
+ conditionalSpan?.error({
1888
+ error: new Error(execResults.error),
1889
+ });
1890
+ } else {
1891
+ conditionalSpan?.end({
1892
+ output: execResults.output || execResults,
1893
+ });
1894
+ }
1895
+
1785
1896
  return execResults;
1786
1897
  }
1787
1898
  }