@kortyx/runtime 0.10.3 → 0.11.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/dist/index.js CHANGED
@@ -26,6 +26,7 @@ __export(index_exports, {
26
26
  createFrameworkAdapterFromEnv: () => createFrameworkAdapterFromEnv,
27
27
  createInMemoryFrameworkAdapter: () => createInMemoryFrameworkAdapter,
28
28
  createInMemoryPendingRequestStore: () => createInMemoryPendingRequestStore,
29
+ createInMemorySessionCheckpointStore: () => createInMemorySessionCheckpointStore,
29
30
  createInMemoryWorkflowRegistry: () => createInMemoryWorkflowRegistry,
30
31
  createRedisFrameworkAdapter: () => createRedisFrameworkAdapter,
31
32
  getCheckpointer: () => getCheckpointer,
@@ -112,7 +113,6 @@ function createInMemoryCheckpointSaver(options) {
112
113
  );
113
114
  }
114
115
  const ns = nsKey(threadId, checkpointNs);
115
- const prevId = latest.get(ns);
116
116
  const prepared = (0, import_langgraph_checkpoint.copyCheckpoint)(checkpoint);
117
117
  const entry = {
118
118
  checkpoint: prepared,
@@ -123,9 +123,6 @@ function createInMemoryCheckpointSaver(options) {
123
123
  const id = checkpoint.id;
124
124
  checkpoints.set(chkKey(threadId, checkpointNs, id), entry);
125
125
  latest.set(ns, id);
126
- if (prevId && prevId !== id) {
127
- checkpoints.delete(chkKey(threadId, checkpointNs, prevId));
128
- }
129
126
  return {
130
127
  configurable: {
131
128
  thread_id: threadId,
@@ -159,6 +156,15 @@ function createInMemoryCheckpointSaver(options) {
159
156
  for (const k of Array.from(checkpoints.keys())) {
160
157
  if (k.startsWith(`${threadId}`)) checkpoints.delete(k);
161
158
  }
159
+ },
160
+ async deleteCheckpointWrites(threadId, checkpointNs, checkpointId) {
161
+ const stored = checkpoints.get(
162
+ chkKey(threadId, checkpointNs, checkpointId)
163
+ );
164
+ stored?.writes.clear();
165
+ },
166
+ async getLatestCheckpointId(threadId, checkpointNs = "") {
167
+ return latest.get(nsKey(threadId, checkpointNs));
162
168
  }
163
169
  };
164
170
  return saver;
@@ -335,7 +341,6 @@ function createRedisCheckpointSaver(options) {
335
341
  'Failed to put checkpoint: missing "thread_id" in config.configurable.'
336
342
  );
337
343
  }
338
- const prevId = await store.get(latestKey(threadId, checkpointNs));
339
344
  const prepared = (0, import_langgraph_checkpoint2.copyCheckpoint)(checkpoint);
340
345
  const [[, chkBytes], [, metaBytes]] = await Promise.all([
341
346
  serde.dumpsTyped(prepared),
@@ -350,10 +355,6 @@ function createRedisCheckpointSaver(options) {
350
355
  };
351
356
  await store.set(key, JSON.stringify(stored), ttlMs);
352
357
  await store.set(latestKey(threadId, checkpointNs), checkpointId, ttlMs);
353
- if (prevId && prevId !== checkpointId) {
354
- await store.del(checkpointKey(threadId, checkpointNs, prevId));
355
- await store.del(writesKey(threadId, checkpointNs, prevId));
356
- }
357
358
  return {
358
359
  configurable: {
359
360
  thread_id: threadId,
@@ -402,6 +403,12 @@ function createRedisCheckpointSaver(options) {
402
403
  const wrKeys = await store.scanKeys(`${prefix}wr:${threadId}:`);
403
404
  const latestKeys = await store.scanKeys(`${prefix}latest:${threadId}:`);
404
405
  await store.delRaw([...chkKeys, ...wrKeys, ...latestKeys]);
406
+ },
407
+ async deleteCheckpointWrites(threadId, checkpointNs, checkpointId) {
408
+ await store.del(writesKey(threadId, checkpointNs, checkpointId));
409
+ },
410
+ async getLatestCheckpointId(threadId, checkpointNs = "") {
411
+ return await store.get(latestKey(threadId, checkpointNs)) ?? void 0;
405
412
  }
406
413
  };
407
414
  return saver;
@@ -498,7 +505,7 @@ function createRedisClient(options) {
498
505
  const payload = encodeCommand(cmd, args);
499
506
  return new Promise((resolve2, reject) => {
500
507
  inflight.push({ resolve: resolve2, reject });
501
- socket.write(payload);
508
+ socket?.write(payload);
502
509
  });
503
510
  };
504
511
  const ensureConnected = async () => {
@@ -521,12 +528,12 @@ function createRedisClient(options) {
521
528
  });
522
529
  s.on("error", (err) => {
523
530
  ready = false;
524
- while (inflight.length) inflight.shift().reject(err);
531
+ while (inflight.length) inflight.shift()?.reject(err);
525
532
  });
526
533
  s.on("close", () => {
527
534
  ready = false;
528
535
  while (inflight.length)
529
- inflight.shift().reject(new Error("Redis socket closed"));
536
+ inflight.shift()?.reject(new Error("Redis socket closed"));
530
537
  });
531
538
  await new Promise((resolve2, reject) => {
532
539
  const timer = setTimeout(
@@ -670,6 +677,346 @@ function createRedisFrameworkStore(options) {
670
677
  };
671
678
  }
672
679
 
680
+ // src/framework/redis/session-checkpoint-store.ts
681
+ var import_node_crypto = require("crypto");
682
+ var DEFAULT_MAX_CHECKPOINTS_PER_SESSION = 50;
683
+ var clone = (value) => value === void 0 ? value : JSON.parse(JSON.stringify(value));
684
+ var uniqueStrings = (values) => Array.from(
685
+ new Set(
686
+ Array.from(values).filter(
687
+ (value) => typeof value === "string" && value.length > 0
688
+ )
689
+ )
690
+ );
691
+ var createId = (prefix) => {
692
+ return `${prefix}-${(0, import_node_crypto.randomUUID)()}`;
693
+ };
694
+ var createResumeToken = () => (0, import_node_crypto.randomUUID)();
695
+ var toSummary = (record) => ({
696
+ id: record.id,
697
+ sessionId: record.sessionId,
698
+ turnIndex: record.turnIndex,
699
+ createdAt: record.createdAt,
700
+ nodes: [...record.nodes],
701
+ workflow: record.workflow,
702
+ ...record.label ? { label: record.label } : {},
703
+ ...record.parentCheckpointId ? { parentCheckpointId: record.parentCheckpointId } : {},
704
+ ...record.parentSessionId ? { parentSessionId: record.parentSessionId } : {},
705
+ ...record.forkedFrom ? { forkedFrom: record.forkedFrom } : {},
706
+ ...record.workflowVersion ? { workflowVersion: record.workflowVersion } : {},
707
+ ...record.buildId ? { buildId: record.buildId } : {}
708
+ });
709
+ function createRedisSessionCheckpointStore(options) {
710
+ const store = options.store;
711
+ const ttlMs = options.ttlMs;
712
+ const prefix = options.prefix ?? "kortyx:session-cp:";
713
+ const maxCheckpointsPerSession = options.maxCheckpointsPerSession ?? DEFAULT_MAX_CHECKPOINTS_PER_SESSION;
714
+ const byIdKey = (id) => `${prefix}by-id:${id}`;
715
+ const sessionRecordKey = (sessionId, id) => `${prefix}session:${sessionId}:${id}`;
716
+ const sessionPrefix = (sessionId) => `${prefix}session:${sessionId}:`;
717
+ const headKey = (sessionId) => `${prefix}head:${sessionId}`;
718
+ const saveRecord = async (record) => {
719
+ const serialized = JSON.stringify(record);
720
+ await Promise.all([
721
+ store.set(byIdKey(record.id), serialized, ttlMs),
722
+ store.set(
723
+ sessionRecordKey(record.sessionId, record.id),
724
+ serialized,
725
+ ttlMs
726
+ ),
727
+ store.set(headKey(record.sessionId), record.id, ttlMs)
728
+ ]);
729
+ };
730
+ const deleteRecord = async (record) => {
731
+ await Promise.all([
732
+ store.del(byIdKey(record.id)),
733
+ store.del(sessionRecordKey(record.sessionId, record.id))
734
+ ]);
735
+ };
736
+ const getRecord = async (id) => {
737
+ const raw = await store.get(byIdKey(id));
738
+ return raw ? JSON.parse(raw) : null;
739
+ };
740
+ const sortedRecords = async (sessionId) => {
741
+ const keys = await store.scanKeys(sessionPrefix(sessionId));
742
+ const records = await Promise.all(
743
+ keys.map(async (rawKey) => {
744
+ const logicalKey = rawKey.includes(sessionPrefix(sessionId)) ? rawKey.slice(rawKey.indexOf(sessionPrefix(sessionId))) : rawKey;
745
+ const raw = await store.get(logicalKey);
746
+ return raw ? JSON.parse(raw) : null;
747
+ })
748
+ );
749
+ return records.filter((record) => Boolean(record)).sort((a, b) => a.turnIndex - b.turnIndex || a.createdAt - b.createdAt);
750
+ };
751
+ const prune = async (sessionId) => {
752
+ const records = await sortedRecords(sessionId);
753
+ const overflow = Math.max(0, records.length - maxCheckpointsPerSession);
754
+ await Promise.all(records.slice(0, overflow).map(deleteRecord));
755
+ };
756
+ const getHead = async (sessionId) => {
757
+ const headId = await store.get(headKey(sessionId));
758
+ if (!headId) return null;
759
+ const record = await getRecord(headId);
760
+ return record ? clone(record) : null;
761
+ };
762
+ return {
763
+ async list(sessionId) {
764
+ return (await sortedRecords(sessionId)).map(toSummary);
765
+ },
766
+ async get(id) {
767
+ const record = await getRecord(id);
768
+ return record ? clone(record) : null;
769
+ },
770
+ getHead,
771
+ async append(args) {
772
+ const previousHead = await getHead(args.sessionId);
773
+ const pendingRequests = args.pendingRequests ?? [];
774
+ const record = {
775
+ id: createId("cp"),
776
+ sessionId: args.sessionId,
777
+ runId: args.runId,
778
+ ...args.graphCheckpointId ? { graphCheckpointId: args.graphCheckpointId } : {},
779
+ turnIndex: previousHead ? previousHead.turnIndex + 1 : 0,
780
+ createdAt: Date.now(),
781
+ workflow: args.workflow,
782
+ state: clone(args.state),
783
+ nodes: uniqueStrings(args.nodes ?? []),
784
+ effects: {
785
+ structuredStreamIds: uniqueStrings(args.structuredStreamIds ?? []),
786
+ interruptTokens: uniqueStrings(
787
+ pendingRequests.map((request) => request.token)
788
+ )
789
+ },
790
+ activePendingRequests: clone(pendingRequests),
791
+ ...previousHead ? { parentCheckpointId: previousHead.id } : {},
792
+ ...args.label ? { label: args.label } : {},
793
+ ...args.workflowVersion ? { workflowVersion: args.workflowVersion } : {},
794
+ ...args.buildId ? { buildId: args.buildId } : {}
795
+ };
796
+ await saveRecord(record);
797
+ await prune(args.sessionId);
798
+ return clone(record);
799
+ },
800
+ async rollbackTo(id) {
801
+ const target = await getRecord(id);
802
+ if (!target) throw new Error(`Checkpoint "${id}" not found.`);
803
+ const records = await sortedRecords(target.sessionId);
804
+ const trailing = records.filter(
805
+ (record) => record.turnIndex > target.turnIndex
806
+ );
807
+ const invalidatedStructuredStreamIds = uniqueStrings(
808
+ trailing.flatMap((record) => record.effects.structuredStreamIds)
809
+ );
810
+ const invalidatedInterruptTokens = uniqueStrings(
811
+ trailing.flatMap((record) => [
812
+ ...record.effects.interruptTokens,
813
+ ...record.activePendingRequests.map((request) => request.token)
814
+ ])
815
+ );
816
+ await Promise.all(trailing.map(deleteRecord));
817
+ await store.set(headKey(target.sessionId), target.id, ttlMs);
818
+ return {
819
+ sessionId: target.sessionId,
820
+ head: target.id,
821
+ invalidatedStructuredStreamIds,
822
+ invalidatedInterruptTokens,
823
+ activePendingRequests: clone(target.activePendingRequests)
824
+ };
825
+ },
826
+ async fork(id, options2) {
827
+ const source = await getRecord(id);
828
+ if (!source) throw new Error(`Checkpoint "${id}" not found.`);
829
+ const sessionId = options2?.newSessionId || createId("session");
830
+ const { parentCheckpointId: _parentCheckpointId, ...sourceRecord } = clone(source);
831
+ const forked = {
832
+ ...sourceRecord,
833
+ id: createId("cp"),
834
+ sessionId,
835
+ parentSessionId: source.sessionId,
836
+ forkedFrom: source.id,
837
+ activePendingRequests: clone(source.activePendingRequests).map(
838
+ (request) => ({
839
+ ...request,
840
+ token: createResumeToken(),
841
+ requestId: createId("human"),
842
+ sessionId
843
+ })
844
+ )
845
+ };
846
+ await saveRecord(forked);
847
+ return {
848
+ sessionId,
849
+ parentSessionId: source.sessionId,
850
+ forkedFrom: source.id,
851
+ checkpoint: clone(forked)
852
+ };
853
+ }
854
+ };
855
+ }
856
+
857
+ // src/framework/session-checkpoints.ts
858
+ var import_node_crypto2 = require("crypto");
859
+ var DEFAULT_MAX_CHECKPOINTS_PER_SESSION2 = 50;
860
+ var createCheckpointId = () => `cp-${(0, import_node_crypto2.randomUUID)()}`;
861
+ var createSessionId = () => `session-${(0, import_node_crypto2.randomUUID)()}`;
862
+ var createResumeToken2 = () => (0, import_node_crypto2.randomUUID)();
863
+ var createRequestId = () => `human-${(0, import_node_crypto2.randomUUID)()}`;
864
+ var clone2 = (value) => value === void 0 ? value : JSON.parse(JSON.stringify(value));
865
+ var toSummary2 = (record) => ({
866
+ id: record.id,
867
+ sessionId: record.sessionId,
868
+ turnIndex: record.turnIndex,
869
+ createdAt: record.createdAt,
870
+ nodes: [...record.nodes],
871
+ workflow: record.workflow,
872
+ ...record.label ? { label: record.label } : {},
873
+ ...record.parentCheckpointId ? { parentCheckpointId: record.parentCheckpointId } : {},
874
+ ...record.parentSessionId ? { parentSessionId: record.parentSessionId } : {},
875
+ ...record.forkedFrom ? { forkedFrom: record.forkedFrom } : {},
876
+ ...record.workflowVersion ? { workflowVersion: record.workflowVersion } : {},
877
+ ...record.buildId ? { buildId: record.buildId } : {}
878
+ });
879
+ var uniqueStrings2 = (values) => Array.from(
880
+ new Set(
881
+ Array.from(values).filter(
882
+ (value) => typeof value === "string" && value.length > 0
883
+ )
884
+ )
885
+ );
886
+ function createInMemorySessionCheckpointStore(options) {
887
+ const maxCheckpointsPerSession = options?.maxCheckpointsPerSession ?? DEFAULT_MAX_CHECKPOINTS_PER_SESSION2;
888
+ const byId = /* @__PURE__ */ new Map();
889
+ const bySession = /* @__PURE__ */ new Map();
890
+ const headBySession = /* @__PURE__ */ new Map();
891
+ const sortedRecords = (sessionId) => (bySession.get(sessionId) ?? []).map((id) => byId.get(id)).filter((record) => Boolean(record)).sort((a, b) => a.turnIndex - b.turnIndex || a.createdAt - b.createdAt);
892
+ const saveRecord = (record) => {
893
+ byId.set(record.id, clone2(record));
894
+ const ids = bySession.get(record.sessionId) ?? [];
895
+ if (!ids.includes(record.id)) ids.push(record.id);
896
+ bySession.set(record.sessionId, ids);
897
+ headBySession.set(record.sessionId, record.id);
898
+ };
899
+ const deleteRecord = (record) => {
900
+ byId.delete(record.id);
901
+ bySession.set(
902
+ record.sessionId,
903
+ /* v8 ignore next -- deleteRecord only receives records that came from this session index. */
904
+ (bySession.get(record.sessionId) ?? []).filter((id) => id !== record.id)
905
+ );
906
+ };
907
+ const prune = (sessionId) => {
908
+ const records = sortedRecords(sessionId);
909
+ const overflow = Math.max(0, records.length - maxCheckpointsPerSession);
910
+ for (const record of records.slice(0, overflow)) {
911
+ deleteRecord(record);
912
+ }
913
+ };
914
+ const getHead = async (sessionId) => {
915
+ const headId = headBySession.get(sessionId);
916
+ if (!headId) return null;
917
+ const record = byId.get(headId);
918
+ return record ? clone2(record) : null;
919
+ };
920
+ return {
921
+ async list(sessionId) {
922
+ return sortedRecords(sessionId).map(toSummary2);
923
+ },
924
+ async get(id) {
925
+ const record = byId.get(id);
926
+ return record ? clone2(record) : null;
927
+ },
928
+ getHead,
929
+ async append(args) {
930
+ const previousHead = await getHead(args.sessionId);
931
+ const turnIndex = previousHead ? previousHead.turnIndex + 1 : 0;
932
+ const pendingRequests = args.pendingRequests ?? [];
933
+ const record = {
934
+ id: createCheckpointId(),
935
+ sessionId: args.sessionId,
936
+ runId: args.runId,
937
+ ...args.graphCheckpointId ? { graphCheckpointId: args.graphCheckpointId } : {},
938
+ turnIndex,
939
+ createdAt: Date.now(),
940
+ workflow: args.workflow,
941
+ state: clone2(args.state),
942
+ nodes: uniqueStrings2(args.nodes ?? []),
943
+ effects: {
944
+ structuredStreamIds: uniqueStrings2(args.structuredStreamIds ?? []),
945
+ interruptTokens: uniqueStrings2(
946
+ pendingRequests.map((request) => request.token)
947
+ )
948
+ },
949
+ activePendingRequests: clone2(pendingRequests),
950
+ ...previousHead ? { parentCheckpointId: previousHead.id } : {},
951
+ ...args.label ? { label: args.label } : {},
952
+ ...args.workflowVersion ? { workflowVersion: args.workflowVersion } : {},
953
+ ...args.buildId ? { buildId: args.buildId } : {}
954
+ };
955
+ saveRecord(record);
956
+ prune(args.sessionId);
957
+ return clone2(record);
958
+ },
959
+ async rollbackTo(id) {
960
+ const target = byId.get(id);
961
+ if (!target) {
962
+ throw new Error(`Checkpoint "${id}" not found.`);
963
+ }
964
+ const records = sortedRecords(target.sessionId);
965
+ const trailing = records.filter(
966
+ (record) => record.turnIndex > target.turnIndex
967
+ );
968
+ const invalidatedStructuredStreamIds = uniqueStrings2(
969
+ trailing.flatMap((record) => record.effects.structuredStreamIds)
970
+ );
971
+ const invalidatedInterruptTokens = uniqueStrings2(
972
+ trailing.flatMap((record) => [
973
+ ...record.effects.interruptTokens,
974
+ ...record.activePendingRequests.map((request) => request.token)
975
+ ])
976
+ );
977
+ for (const record of trailing) deleteRecord(record);
978
+ headBySession.set(target.sessionId, target.id);
979
+ return {
980
+ sessionId: target.sessionId,
981
+ head: target.id,
982
+ invalidatedStructuredStreamIds,
983
+ invalidatedInterruptTokens,
984
+ activePendingRequests: clone2(target.activePendingRequests)
985
+ };
986
+ },
987
+ async fork(id, options2) {
988
+ const source = byId.get(id);
989
+ if (!source) {
990
+ throw new Error(`Checkpoint "${id}" not found.`);
991
+ }
992
+ const sessionId = options2?.newSessionId || createSessionId();
993
+ const { parentCheckpointId: _parentCheckpointId, ...sourceRecord } = clone2(source);
994
+ const forked = {
995
+ ...sourceRecord,
996
+ id: createCheckpointId(),
997
+ sessionId,
998
+ parentSessionId: source.sessionId,
999
+ forkedFrom: source.id,
1000
+ activePendingRequests: clone2(source.activePendingRequests).map(
1001
+ (request) => ({
1002
+ ...request,
1003
+ token: createResumeToken2(),
1004
+ requestId: createRequestId(),
1005
+ sessionId
1006
+ })
1007
+ )
1008
+ };
1009
+ saveRecord(forked);
1010
+ return {
1011
+ sessionId,
1012
+ parentSessionId: source.sessionId,
1013
+ forkedFrom: source.id,
1014
+ checkpoint: clone2(forked)
1015
+ };
1016
+ }
1017
+ };
1018
+ }
1019
+
673
1020
  // src/framework/adapter.ts
674
1021
  function createInMemoryFrameworkAdapter(options) {
675
1022
  const ttlMs = options?.ttlMs ?? 15 * 60 * 1e3;
@@ -678,6 +1025,9 @@ function createInMemoryFrameworkAdapter(options) {
678
1025
  kind: "in-memory",
679
1026
  ttlMs,
680
1027
  pendingRequests: createInMemoryPendingRequestStore(),
1028
+ sessionCheckpoints: createInMemorySessionCheckpointStore({
1029
+ ...options?.maxSessionCheckpoints !== void 0 ? { maxCheckpointsPerSession: options.maxSessionCheckpoints } : {}
1030
+ }),
681
1031
  checkpointer,
682
1032
  cleanupRun: async (runId) => {
683
1033
  try {
@@ -701,6 +1051,12 @@ function createRedisFrameworkAdapter(options) {
701
1051
  store,
702
1052
  prefix: "kortyx:pending:"
703
1053
  }),
1054
+ sessionCheckpoints: createRedisSessionCheckpointStore({
1055
+ store,
1056
+ ttlMs,
1057
+ prefix: "kortyx:session-cp:",
1058
+ ...options.maxSessionCheckpoints !== void 0 ? { maxCheckpointsPerSession: options.maxSessionCheckpoints } : {}
1059
+ }),
704
1060
  checkpointer: createRedisCheckpointSaver({
705
1061
  store,
706
1062
  ttlMs,
@@ -798,7 +1154,7 @@ function pickNodeExport(mod, exportName) {
798
1154
  const fnExports = Object.entries(mod).filter(
799
1155
  ([, v]) => typeof v === "function"
800
1156
  );
801
- if (fnExports.length === 1) return fnExports[0][1];
1157
+ if (fnExports.length === 1) return fnExports[0]?.[1];
802
1158
  const names = fnExports.map(([k]) => k).sort();
803
1159
  throw new Error(
804
1160
  `Node module must export a default function or exactly one named function (found: ${names.join(", ") || "none"}).`
@@ -852,6 +1208,7 @@ async function createExecutionGraph(workflow, config) {
852
1208
  }
853
1209
  const isRecord = (value) => Boolean(value) && typeof value === "object" && !Array.isArray(value);
854
1210
  const traceAdapter = () => runtimeConfig.telemetry?.trace ?? runtimeConfig.reasonTrace;
1211
+ const telemetryCorrelation = () => runtimeConfig.telemetry?.correlation;
855
1212
  const configContext = () => isRecord(runtimeConfig.context) ? runtimeConfig.context : void 0;
856
1213
  const toRecordInput = (value) => {
857
1214
  if (isRecord(value)) return value;
@@ -975,7 +1332,13 @@ async function createExecutionGraph(workflow, config) {
975
1332
  const spanArgs = {
976
1333
  name: "kortyx.node",
977
1334
  attributes: {
1335
+ ...typeof telemetryCorrelation()?.runId === "string" ? { runId: telemetryCorrelation()?.runId } : {},
1336
+ ...typeof telemetryCorrelation()?.sessionId === "string" ? { sessionId: telemetryCorrelation()?.sessionId } : {},
978
1337
  workflowId: workflowName,
1338
+ ...typeof telemetryCorrelation()?.workflowRevisionId === "string" ? {
1339
+ workflowRevisionId: telemetryCorrelation()?.workflowRevisionId
1340
+ } : {},
1341
+ ...typeof telemetryCorrelation()?.topologyHash === "string" ? { topologyHash: telemetryCorrelation()?.topologyHash } : {},
979
1342
  nodeId,
980
1343
  attempt,
981
1344
  ...typeof context?.userId === "string" ? { userId: context.userId } : {},
@@ -1032,6 +1395,8 @@ async function createExecutionGraph(workflow, config) {
1032
1395
  }
1033
1396
  if (res.transitionTo) {
1034
1397
  emitRuntimeEvent("transition", {
1398
+ node: nodeId,
1399
+ workflow: workflowName,
1035
1400
  transitionTo: res.transitionTo,
1036
1401
  payload: res.data ?? {}
1037
1402
  });
@@ -1141,18 +1506,18 @@ async function createExecutionGraph(workflow, config) {
1141
1506
  }
1142
1507
 
1143
1508
  // src/interrupt/tokens.ts
1144
- var import_node_crypto = require("crypto");
1509
+ var import_node_crypto3 = require("crypto");
1145
1510
  function makeResumeToken() {
1146
- return (0, import_node_crypto.randomUUID)();
1511
+ return (0, import_node_crypto3.randomUUID)();
1147
1512
  }
1148
1513
  function makeRequestId(prefix = "req") {
1149
- return `${prefix}-${(0, import_node_crypto.randomUUID)()}`;
1514
+ return `${prefix}-${(0, import_node_crypto3.randomUUID)()}`;
1150
1515
  }
1151
1516
 
1152
1517
  // src/registry/file-registry.ts
1153
- var import_core = require("@kortyx/core");
1154
1518
  var import_promises = require("fs/promises");
1155
- var import_path = require("path");
1519
+ var import_node_path2 = require("path");
1520
+ var import_core = require("@kortyx/core");
1156
1521
  var DEFAULT_EXTENSIONS = [
1157
1522
  ".workflow.ts",
1158
1523
  ".workflow.mts",
@@ -1181,7 +1546,7 @@ function createFileWorkflowRegistry(options) {
1181
1546
  const workflows = {};
1182
1547
  for (const file of workflowFiles) {
1183
1548
  try {
1184
- const modulePath = (0, import_path.join)(workflowsDir, file);
1549
+ const modulePath = (0, import_node_path2.join)(workflowsDir, file);
1185
1550
  if (isDeclarativeWorkflowFile(file)) {
1186
1551
  const raw = await (0, import_promises.readFile)(modulePath, "utf8");
1187
1552
  const workflow = (0, import_core.loadWorkflow)(raw);
@@ -1301,6 +1666,7 @@ async function buildInitialGraphState({
1301
1666
  createFrameworkAdapterFromEnv,
1302
1667
  createInMemoryFrameworkAdapter,
1303
1668
  createInMemoryPendingRequestStore,
1669
+ createInMemorySessionCheckpointStore,
1304
1670
  createInMemoryWorkflowRegistry,
1305
1671
  createRedisFrameworkAdapter,
1306
1672
  getCheckpointer,