@mastra/inngest 0.11.10 → 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,49 +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
- }: {
975
- workflowId: string;
976
- runId: string;
977
- step: Step<string, any, any>;
978
- stepResults: Record<string, StepResult<any, any, any, any>>;
979
- executionContext: ExecutionContext;
980
- resume?: {
981
- steps: string[];
982
- resumePayload: any;
983
- };
984
- prevOutput: any;
985
- emitter: Emitter;
986
- abortController: AbortController;
987
- runtimeContext: RuntimeContext;
988
- writableStream?: WritableStream<ChunkType>;
989
- }): Promise<StepResult<any, any, any, any>> {
990
- return super.executeStep({
991
- workflowId,
992
- runId,
993
- step,
994
- stepResults,
995
- executionContext,
996
- resume,
997
- prevOutput,
998
- emitter,
999
- abortController,
1000
- runtimeContext,
1001
- writableStream,
1002
- });
1003
- }
1004
-
1005
973
  // async executeSleep({ id, duration }: { id: string; duration: number }): Promise<void> {
1006
974
  // await this.inngestStep.sleep(id, duration);
1007
975
  // }
@@ -1016,6 +984,7 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
1016
984
  abortController,
1017
985
  runtimeContext,
1018
986
  writableStream,
987
+ tracingContext,
1019
988
  }: {
1020
989
  workflowId: string;
1021
990
  runId: string;
@@ -1040,9 +1009,19 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
1040
1009
  abortController: AbortController;
1041
1010
  runtimeContext: RuntimeContext;
1042
1011
  writableStream?: WritableStream<ChunkType>;
1012
+ tracingContext?: TracingContext;
1043
1013
  }): Promise<void> {
1044
1014
  let { duration, fn } = entry;
1045
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
+
1046
1025
  if (fn) {
1047
1026
  const stepCallId = randomUUID();
1048
1027
  duration = await this.inngestStep.run(`workflow.${workflowId}.sleep.${entry.id}`, async () => {
@@ -1053,6 +1032,9 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
1053
1032
  runtimeContext,
1054
1033
  inputData: prevOutput,
1055
1034
  runCount: -1,
1035
+ tracingContext: {
1036
+ currentSpan: sleepSpan,
1037
+ },
1056
1038
  getInitData: () => stepResults?.input as any,
1057
1039
  getStepResult: (step: any) => {
1058
1040
  if (!step?.id) {
@@ -1087,9 +1069,22 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
1087
1069
  ),
1088
1070
  });
1089
1071
  });
1072
+
1073
+ // Update sleep span with dynamic duration
1074
+ sleepSpan?.update({
1075
+ attributes: {
1076
+ durationMs: duration,
1077
+ },
1078
+ });
1090
1079
  }
1091
1080
 
1092
- 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
+ }
1093
1088
  }
1094
1089
 
1095
1090
  async executeSleepUntil({
@@ -1102,6 +1097,7 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
1102
1097
  abortController,
1103
1098
  runtimeContext,
1104
1099
  writableStream,
1100
+ tracingContext,
1105
1101
  }: {
1106
1102
  workflowId: string;
1107
1103
  runId: string;
@@ -1126,9 +1122,20 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
1126
1122
  abortController: AbortController;
1127
1123
  runtimeContext: RuntimeContext;
1128
1124
  writableStream?: WritableStream<ChunkType>;
1125
+ tracingContext?: TracingContext;
1129
1126
  }): Promise<void> {
1130
1127
  let { date, fn } = entry;
1131
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
+
1132
1139
  if (fn) {
1133
1140
  date = await this.inngestStep.run(`workflow.${workflowId}.sleepUntil.${entry.id}`, async () => {
1134
1141
  const stepCallId = randomUUID();
@@ -1139,6 +1146,9 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
1139
1146
  runtimeContext,
1140
1147
  inputData: prevOutput,
1141
1148
  runCount: -1,
1149
+ tracingContext: {
1150
+ currentSpan: sleepUntilSpan,
1151
+ },
1142
1152
  getInitData: () => stepResults?.input as any,
1143
1153
  getStepResult: (step: any) => {
1144
1154
  if (!step?.id) {
@@ -1173,13 +1183,28 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
1173
1183
  ),
1174
1184
  });
1175
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
+ });
1176
1194
  }
1177
1195
 
1178
1196
  if (!(date instanceof Date)) {
1197
+ sleepUntilSpan?.end();
1179
1198
  return;
1180
1199
  }
1181
1200
 
1182
- 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
+ }
1183
1208
  }
1184
1209
 
1185
1210
  async executeWaitForEvent({ event, timeout }: { event: string; timeout?: number }): Promise<any> {
@@ -1205,6 +1230,7 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
1205
1230
  abortController,
1206
1231
  runtimeContext,
1207
1232
  writableStream,
1233
+ tracingContext,
1208
1234
  }: {
1209
1235
  step: Step<string, any, any>;
1210
1236
  stepResults: Record<string, StepResult<any, any, any, any>>;
@@ -1219,7 +1245,17 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
1219
1245
  abortController: AbortController;
1220
1246
  runtimeContext: RuntimeContext;
1221
1247
  writableStream?: WritableStream<ChunkType>;
1248
+ tracingContext?: TracingContext;
1222
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
+
1223
1259
  const startedAt = await this.inngestStep.run(
1224
1260
  `workflow.${executionContext.workflowId}.run.${executionContext.runId}.step.${step.id}.running_ev`,
1225
1261
  async () => {
@@ -1453,7 +1489,18 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
1453
1489
  }
1454
1490
 
1455
1491
  const stepRes = await this.inngestStep.run(`workflow.${executionContext.workflowId}.step.${step.id}`, async () => {
1456
- 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
+ };
1457
1504
  let suspended: { payload: any } | undefined;
1458
1505
  let bailed: { payload: any } | undefined;
1459
1506
 
@@ -1465,6 +1512,9 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
1465
1512
  writableStream,
1466
1513
  inputData: prevOutput,
1467
1514
  resumeData: resume?.steps[0] === step.id ? resume?.resumePayload : undefined,
1515
+ tracingContext: {
1516
+ currentSpan: stepAISpan,
1517
+ },
1468
1518
  getInitData: () => stepResults?.input as any,
1469
1519
  getStepResult: (step: any) => {
1470
1520
  const result = stepResults[step.id];
@@ -1532,7 +1582,9 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
1532
1582
 
1533
1583
  if (execResults.status === 'failed') {
1534
1584
  if (executionContext.retryConfig.attempts > 0 && this.inngestAttempts < executionContext.retryConfig.attempts) {
1535
- throw execResults.error;
1585
+ const error = new Error(execResults.error);
1586
+ stepAISpan?.error({ error });
1587
+ throw error;
1536
1588
  }
1537
1589
  }
1538
1590
 
@@ -1579,6 +1631,8 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
1579
1631
  });
1580
1632
  }
1581
1633
 
1634
+ stepAISpan?.end({ output: execResults });
1635
+
1582
1636
  return { result: execResults, executionContext, stepResults };
1583
1637
  });
1584
1638
 
@@ -1623,6 +1677,7 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
1623
1677
  context: stepResults as any,
1624
1678
  activePaths: [],
1625
1679
  suspendedPaths: executionContext.suspendedPaths,
1680
+ waitingPaths: {},
1626
1681
  serializedStepGraph,
1627
1682
  status: workflowStatus,
1628
1683
  result,
@@ -1649,6 +1704,7 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
1649
1704
  abortController,
1650
1705
  runtimeContext,
1651
1706
  writableStream,
1707
+ tracingContext,
1652
1708
  }: {
1653
1709
  workflowId: string;
1654
1710
  runId: string;
@@ -1672,12 +1728,31 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
1672
1728
  abortController: AbortController;
1673
1729
  runtimeContext: RuntimeContext;
1674
1730
  writableStream?: WritableStream<ChunkType>;
1731
+ tracingContext?: TracingContext;
1675
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
+
1676
1742
  let execResults: any;
1677
1743
  const truthyIndexes = (
1678
1744
  await Promise.all(
1679
1745
  entry.conditions.map((cond, index) =>
1680
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
+
1681
1756
  try {
1682
1757
  const result = await cond({
1683
1758
  runId,
@@ -1686,6 +1761,9 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
1686
1761
  runtimeContext,
1687
1762
  runCount: -1,
1688
1763
  inputData: prevOutput,
1764
+ tracingContext: {
1765
+ currentSpan: evalSpan,
1766
+ },
1689
1767
  getInitData: () => stepResults?.input as any,
1690
1768
  getStepResult: (step: any) => {
1691
1769
  if (!step?.id) {
@@ -1721,9 +1799,23 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
1721
1799
  writableStream,
1722
1800
  ),
1723
1801
  });
1802
+
1803
+ evalSpan?.end({
1804
+ output: result,
1805
+ attributes: {
1806
+ result: !!result,
1807
+ },
1808
+ });
1809
+
1724
1810
  return result ? index : null;
1725
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
1726
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
+
1727
1819
  return null;
1728
1820
  }
1729
1821
  }),
@@ -1732,16 +1824,25 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
1732
1824
  ).filter((index: any): index is number => index !== null);
1733
1825
 
1734
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
+
1735
1836
  const results: { result: StepResult<any, any, any, any> }[] = await Promise.all(
1736
1837
  stepsToRun.map((step, index) =>
1737
1838
  this.executeEntry({
1738
1839
  workflowId,
1739
1840
  runId,
1740
1841
  entry: step,
1842
+ serializedStepGraph,
1741
1843
  prevStep,
1742
1844
  stepResults,
1743
1845
  resume,
1744
- serializedStepGraph,
1745
1846
  executionContext: {
1746
1847
  workflowId,
1747
1848
  runId,
@@ -1754,6 +1855,9 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
1754
1855
  abortController,
1755
1856
  runtimeContext,
1756
1857
  writableStream,
1858
+ tracingContext: {
1859
+ currentSpan: conditionalSpan,
1860
+ },
1757
1861
  }),
1758
1862
  ),
1759
1863
  );
@@ -1779,6 +1883,16 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
1779
1883
  };
1780
1884
  }
1781
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
+
1782
1896
  return execResults;
1783
1897
  }
1784
1898
  }