@bian-womp/spark-graph 0.3.49 → 0.3.51

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.
Files changed (173) hide show
  1. package/lib/cjs/index.cjs +129 -108
  2. package/lib/cjs/index.cjs.map +1 -1
  3. package/lib/cjs/src/core/types.d.ts +1 -0
  4. package/lib/cjs/src/core/types.d.ts.map +1 -1
  5. package/lib/cjs/src/runtime/GraphRuntime.d.ts +7 -2
  6. package/lib/cjs/src/runtime/GraphRuntime.d.ts.map +1 -1
  7. package/lib/cjs/src/runtime/LocalEngine.d.ts.map +1 -1
  8. package/lib/cjs/src/runtime/components/EdgePropagator.d.ts.map +1 -1
  9. package/lib/cjs/src/runtime/components/NodeExecutor.d.ts +8 -4
  10. package/lib/cjs/src/runtime/components/NodeExecutor.d.ts.map +1 -1
  11. package/lib/cjs/src/runtime/components/interfaces.d.ts +5 -1
  12. package/lib/cjs/src/runtime/components/interfaces.d.ts.map +1 -1
  13. package/lib/cjs/src/runtime/components/types.d.ts +1 -0
  14. package/lib/cjs/src/runtime/components/types.d.ts.map +1 -1
  15. package/lib/esm/index.js +129 -108
  16. package/lib/esm/index.js.map +1 -1
  17. package/lib/esm/src/core/types.d.ts +1 -0
  18. package/lib/esm/src/core/types.d.ts.map +1 -1
  19. package/lib/esm/src/runtime/GraphRuntime.d.ts +7 -2
  20. package/lib/esm/src/runtime/GraphRuntime.d.ts.map +1 -1
  21. package/lib/esm/src/runtime/LocalEngine.d.ts.map +1 -1
  22. package/lib/esm/src/runtime/components/EdgePropagator.d.ts.map +1 -1
  23. package/lib/esm/src/runtime/components/NodeExecutor.d.ts +8 -4
  24. package/lib/esm/src/runtime/components/NodeExecutor.d.ts.map +1 -1
  25. package/lib/esm/src/runtime/components/interfaces.d.ts +5 -1
  26. package/lib/esm/src/runtime/components/interfaces.d.ts.map +1 -1
  27. package/lib/esm/src/runtime/components/types.d.ts +1 -0
  28. package/lib/esm/src/runtime/components/types.d.ts.map +1 -1
  29. package/package.json +2 -2
  30. package/lib/src/builder/GraphBuilder.d.ts +0 -43
  31. package/lib/src/builder/GraphBuilder.d.ts.map +0 -1
  32. package/lib/src/builder/GraphBuilder.js +0 -284
  33. package/lib/src/builder/GraphBuilder.js.map +0 -1
  34. package/lib/src/builder/Registry.d.ts +0 -93
  35. package/lib/src/builder/Registry.d.ts.map +0 -1
  36. package/lib/src/builder/Registry.js +0 -393
  37. package/lib/src/builder/Registry.js.map +0 -1
  38. package/lib/src/core/categories.d.ts +0 -22
  39. package/lib/src/core/categories.d.ts.map +0 -1
  40. package/lib/src/core/categories.js +0 -2
  41. package/lib/src/core/categories.js.map +0 -1
  42. package/lib/src/core/order.d.ts +0 -7
  43. package/lib/src/core/order.d.ts.map +0 -1
  44. package/lib/src/core/order.js +0 -66
  45. package/lib/src/core/order.js.map +0 -1
  46. package/lib/src/core/type-utils.d.ts +0 -29
  47. package/lib/src/core/type-utils.d.ts.map +0 -1
  48. package/lib/src/core/type-utils.js +0 -97
  49. package/lib/src/core/type-utils.js.map +0 -1
  50. package/lib/src/core/types.d.ts +0 -92
  51. package/lib/src/core/types.d.ts.map +0 -1
  52. package/lib/src/core/types.js +0 -2
  53. package/lib/src/core/types.js.map +0 -1
  54. package/lib/src/examples/arrays.d.ts +0 -5
  55. package/lib/src/examples/arrays.d.ts.map +0 -1
  56. package/lib/src/examples/arrays.js +0 -49
  57. package/lib/src/examples/arrays.js.map +0 -1
  58. package/lib/src/examples/async.d.ts +0 -5
  59. package/lib/src/examples/async.d.ts.map +0 -1
  60. package/lib/src/examples/async.js +0 -91
  61. package/lib/src/examples/async.js.map +0 -1
  62. package/lib/src/examples/progress.d.ts +0 -5
  63. package/lib/src/examples/progress.d.ts.map +0 -1
  64. package/lib/src/examples/progress.js +0 -51
  65. package/lib/src/examples/progress.js.map +0 -1
  66. package/lib/src/examples/run.d.ts +0 -2
  67. package/lib/src/examples/run.d.ts.map +0 -1
  68. package/lib/src/examples/run.js +0 -32
  69. package/lib/src/examples/run.js.map +0 -1
  70. package/lib/src/examples/runMode.d.ts +0 -2
  71. package/lib/src/examples/runMode.d.ts.map +0 -1
  72. package/lib/src/examples/runMode.js +0 -223
  73. package/lib/src/examples/runMode.js.map +0 -1
  74. package/lib/src/examples/shared.d.ts +0 -5
  75. package/lib/src/examples/shared.d.ts.map +0 -1
  76. package/lib/src/examples/shared.js +0 -49
  77. package/lib/src/examples/shared.js.map +0 -1
  78. package/lib/src/examples/simple.d.ts +0 -5
  79. package/lib/src/examples/simple.d.ts.map +0 -1
  80. package/lib/src/examples/simple.js +0 -79
  81. package/lib/src/examples/simple.js.map +0 -1
  82. package/lib/src/examples/snapshot.d.ts +0 -4
  83. package/lib/src/examples/snapshot.d.ts.map +0 -1
  84. package/lib/src/examples/snapshot.js +0 -58
  85. package/lib/src/examples/snapshot.js.map +0 -1
  86. package/lib/src/examples/validation.d.ts +0 -5
  87. package/lib/src/examples/validation.d.ts.map +0 -1
  88. package/lib/src/examples/validation.js +0 -105
  89. package/lib/src/examples/validation.js.map +0 -1
  90. package/lib/src/index.d.ts +0 -27
  91. package/lib/src/index.d.ts.map +0 -1
  92. package/lib/src/index.js +0 -19
  93. package/lib/src/index.js.map +0 -1
  94. package/lib/src/misc/base.d.ts +0 -51
  95. package/lib/src/misc/base.d.ts.map +0 -1
  96. package/lib/src/misc/base.js +0 -1122
  97. package/lib/src/misc/base.js.map +0 -1
  98. package/lib/src/misc/utils/json.d.ts +0 -22
  99. package/lib/src/misc/utils/json.d.ts.map +0 -1
  100. package/lib/src/misc/utils/json.js +0 -239
  101. package/lib/src/misc/utils/json.js.map +0 -1
  102. package/lib/src/misc/utils/merge.d.ts +0 -51
  103. package/lib/src/misc/utils/merge.d.ts.map +0 -1
  104. package/lib/src/misc/utils/merge.js +0 -600
  105. package/lib/src/misc/utils/merge.js.map +0 -1
  106. package/lib/src/plugins/composite.d.ts +0 -22
  107. package/lib/src/plugins/composite.d.ts.map +0 -1
  108. package/lib/src/plugins/composite.js +0 -59
  109. package/lib/src/plugins/composite.js.map +0 -1
  110. package/lib/src/plugins/compute.d.ts +0 -5
  111. package/lib/src/plugins/compute.d.ts.map +0 -1
  112. package/lib/src/plugins/compute.js +0 -39
  113. package/lib/src/plugins/compute.js.map +0 -1
  114. package/lib/src/runtime/Engine.d.ts +0 -28
  115. package/lib/src/runtime/Engine.d.ts.map +0 -1
  116. package/lib/src/runtime/Engine.js +0 -2
  117. package/lib/src/runtime/Engine.js.map +0 -1
  118. package/lib/src/runtime/GraphLifecycleApi.d.ts +0 -46
  119. package/lib/src/runtime/GraphLifecycleApi.d.ts.map +0 -1
  120. package/lib/src/runtime/GraphLifecycleApi.js +0 -2
  121. package/lib/src/runtime/GraphLifecycleApi.js.map +0 -1
  122. package/lib/src/runtime/GraphRuntime.d.ts +0 -94
  123. package/lib/src/runtime/GraphRuntime.d.ts.map +0 -1
  124. package/lib/src/runtime/GraphRuntime.js +0 -729
  125. package/lib/src/runtime/GraphRuntime.js.map +0 -1
  126. package/lib/src/runtime/LocalEngine.d.ts +0 -45
  127. package/lib/src/runtime/LocalEngine.d.ts.map +0 -1
  128. package/lib/src/runtime/LocalEngine.js +0 -89
  129. package/lib/src/runtime/LocalEngine.js.map +0 -1
  130. package/lib/src/runtime/components/EdgePropagator.d.ts +0 -101
  131. package/lib/src/runtime/components/EdgePropagator.d.ts.map +0 -1
  132. package/lib/src/runtime/components/EdgePropagator.js +0 -372
  133. package/lib/src/runtime/components/EdgePropagator.js.map +0 -1
  134. package/lib/src/runtime/components/EventEmitter.d.ts +0 -12
  135. package/lib/src/runtime/components/EventEmitter.d.ts.map +0 -1
  136. package/lib/src/runtime/components/EventEmitter.js +0 -33
  137. package/lib/src/runtime/components/EventEmitter.js.map +0 -1
  138. package/lib/src/runtime/components/Graph.d.ts +0 -211
  139. package/lib/src/runtime/components/Graph.d.ts.map +0 -1
  140. package/lib/src/runtime/components/Graph.js +0 -468
  141. package/lib/src/runtime/components/Graph.js.map +0 -1
  142. package/lib/src/runtime/components/HandleResolver.d.ts +0 -36
  143. package/lib/src/runtime/components/HandleResolver.d.ts.map +0 -1
  144. package/lib/src/runtime/components/HandleResolver.js +0 -231
  145. package/lib/src/runtime/components/HandleResolver.js.map +0 -1
  146. package/lib/src/runtime/components/NodeExecutor.d.ts +0 -110
  147. package/lib/src/runtime/components/NodeExecutor.d.ts.map +0 -1
  148. package/lib/src/runtime/components/NodeExecutor.js +0 -659
  149. package/lib/src/runtime/components/NodeExecutor.js.map +0 -1
  150. package/lib/src/runtime/components/RunContextManager.d.ts +0 -86
  151. package/lib/src/runtime/components/RunContextManager.d.ts.map +0 -1
  152. package/lib/src/runtime/components/RunContextManager.js +0 -302
  153. package/lib/src/runtime/components/RunContextManager.js.map +0 -1
  154. package/lib/src/runtime/components/RuntimeValidatorManager.d.ts +0 -31
  155. package/lib/src/runtime/components/RuntimeValidatorManager.d.ts.map +0 -1
  156. package/lib/src/runtime/components/RuntimeValidatorManager.js +0 -55
  157. package/lib/src/runtime/components/RuntimeValidatorManager.js.map +0 -1
  158. package/lib/src/runtime/components/graph-utils.d.ts +0 -33
  159. package/lib/src/runtime/components/graph-utils.d.ts.map +0 -1
  160. package/lib/src/runtime/components/graph-utils.js +0 -292
  161. package/lib/src/runtime/components/graph-utils.js.map +0 -1
  162. package/lib/src/runtime/components/interfaces.d.ts +0 -54
  163. package/lib/src/runtime/components/interfaces.d.ts.map +0 -1
  164. package/lib/src/runtime/components/interfaces.js +0 -2
  165. package/lib/src/runtime/components/interfaces.js.map +0 -1
  166. package/lib/src/runtime/components/types.d.ts +0 -55
  167. package/lib/src/runtime/components/types.d.ts.map +0 -1
  168. package/lib/src/runtime/components/types.js +0 -2
  169. package/lib/src/runtime/components/types.js.map +0 -1
  170. package/lib/src/runtime/utils.d.ts +0 -67
  171. package/lib/src/runtime/utils.d.ts.map +0 -1
  172. package/lib/src/runtime/utils.js +0 -137
  173. package/lib/src/runtime/utils.js.map +0 -1
package/lib/esm/index.js CHANGED
@@ -2152,7 +2152,7 @@ class EdgePropagator {
2152
2152
  // Set input value (respecting skipPropagateValues)
2153
2153
  const shouldSetValue = this.shouldSetInputValue(effectiveRunContexts);
2154
2154
  if (shouldSetValue && valueChanged) {
2155
- this.setTargetInput(edge, dstNode, processedValue);
2155
+ this.setTargetInput(edge, processedValue);
2156
2156
  }
2157
2157
  else if (shouldSetValue && !valueChanged) {
2158
2158
  // Even if value didn't change, update timestamp if we're forcing execution
@@ -2211,7 +2211,7 @@ class EdgePropagator {
2211
2211
  /**
2212
2212
  * Set target input value and emit event
2213
2213
  */
2214
- setTargetInput(edge, dstNode, value) {
2214
+ setTargetInput(edge, value) {
2215
2215
  this.graph.updateNodeInput(edge.target.nodeId, edge.target.handle, value);
2216
2216
  this.handleResolver.scheduleRecomputeHandles(edge.target.nodeId);
2217
2217
  }
@@ -2222,7 +2222,10 @@ class EdgePropagator {
2222
2222
  // Determine if we should propagate
2223
2223
  const shouldPropagate = this.shouldPropagateExecution(effectiveRunContexts);
2224
2224
  if (shouldPropagate && this.graph.allInboundHaveValue(targetNodeId)) {
2225
- this.nodeExecutor.execute(targetNodeId, effectiveRunContexts);
2225
+ this.nodeExecutor.execute(targetNodeId, {
2226
+ runContextIds: effectiveRunContexts,
2227
+ reason: "executeDownstream",
2228
+ });
2226
2229
  }
2227
2230
  }
2228
2231
  /**
@@ -2352,7 +2355,7 @@ class NodeExecutor {
2352
2355
  /**
2353
2356
  * Create an execution context for a node
2354
2357
  */
2355
- createExecutionContext(nodeId, node, inputs, runId, abortSignal, runContextIds, options) {
2358
+ createExecutionContext(nodeId, inputs, runId, abortSignal, runContextIds, options) {
2356
2359
  const emitHandler = options?.emitHandler ??
2357
2360
  ((handle, value) => {
2358
2361
  this.edgePropagator.propagate(nodeId, handle, value, runContextIds);
@@ -2364,8 +2367,9 @@ class NodeExecutor {
2364
2367
  });
2365
2368
  });
2366
2369
  // Create log function that respects node's logLevel using LevelLogger
2367
- const nodeLogLevel = node.logLevel ?? "info";
2368
- const logger = new LevelLogger(nodeLogLevel, `[node:${runId || nodeId}:${node.typeId}]`);
2370
+ const node = this.graph.getNode(nodeId);
2371
+ const nodeLogLevel = node?.logLevel ?? "info";
2372
+ const logger = new LevelLogger(nodeLogLevel, `[node:${runId || nodeId}:${node?.typeId ?? ""}]`);
2369
2373
  const log = (level, message, context) => {
2370
2374
  switch (level) {
2371
2375
  case "debug":
@@ -2384,7 +2388,7 @@ class NodeExecutor {
2384
2388
  };
2385
2389
  return {
2386
2390
  nodeId,
2387
- state: node.state,
2391
+ state: node?.state,
2388
2392
  setState: (next) => this.graph.updateNodeState(nodeId, next),
2389
2393
  emit: emitHandler,
2390
2394
  invalidateDownstream: () => {
@@ -2399,7 +2403,10 @@ class NodeExecutor {
2399
2403
  this.runContextManager.createRunContext(nodeId, opts),
2400
2404
  ]);
2401
2405
  }
2402
- this.execute(nodeId, runContextIdsToUse);
2406
+ this.execute(nodeId, {
2407
+ runContextIds: runContextIdsToUse,
2408
+ reason: opts?.reason ?? "executeFromContext",
2409
+ });
2403
2410
  }
2404
2411
  },
2405
2412
  getInput: (handle) => inputs[handle],
@@ -2411,7 +2418,7 @@ class NodeExecutor {
2411
2418
  this.eventEmitter.emit("stats", {
2412
2419
  kind: "node-custom-data",
2413
2420
  nodeId,
2414
- typeId: node.typeId,
2421
+ typeId: node?.typeId ?? "",
2415
2422
  runId,
2416
2423
  data,
2417
2424
  });
@@ -2422,13 +2429,14 @@ class NodeExecutor {
2422
2429
  /**
2423
2430
  * Internal method for executing inputs changed (also used by GraphRuntime)
2424
2431
  */
2425
- execute(nodeId, runContextIds, canSkipHandleResolution) {
2432
+ execute(nodeId, opts) {
2433
+ let { runContextIds, canSkipHandleResolution, reason = "" } = opts ?? {};
2426
2434
  const node = this.graph.getNode(nodeId);
2427
2435
  if (!node)
2428
2436
  return;
2429
2437
  const runMode = this.runtime.getRunMode();
2430
2438
  if (!runMode) {
2431
- console.trace("NodeExecutor.execute: no runMode, skipping execution");
2439
+ console.trace(`NodeExecutor.execute[${nodeId}:${reason}]: no runMode, skipping execution`);
2432
2440
  return;
2433
2441
  }
2434
2442
  // In manual mode, require runContextIds unless autoRun policy is set
@@ -2440,12 +2448,12 @@ class NodeExecutor {
2440
2448
  ]);
2441
2449
  }
2442
2450
  else {
2443
- console.trace("NodeExecutor.execute: no runContextIds provided in manual mode, skipping execution");
2451
+ console.trace(`NodeExecutor.execute[${nodeId}:${reason}]: no runContextIds provided in manual mode, skipping execution`);
2444
2452
  return;
2445
2453
  }
2446
2454
  }
2447
2455
  if (runMode === "auto" && runContextIds && runContextIds.size > 0) {
2448
- console.trace("NodeExecutor.execute: runContextIds provided in auto mode, ignoring");
2456
+ console.trace(`NodeExecutor.execute[${nodeId}:${reason}]: runContextIds provided in auto mode, ignoring`);
2449
2457
  runContextIds = undefined;
2450
2458
  }
2451
2459
  // Early validation for auto-mode paused state
@@ -2488,7 +2496,11 @@ class NodeExecutor {
2488
2496
  // Re-check node still exists and conditions
2489
2497
  const nodeAfter = this.graph.getNode(nodeId);
2490
2498
  if (nodeAfter) {
2491
- this.execute(nodeId, runContextIds, true);
2499
+ this.execute(nodeId, {
2500
+ runContextIds,
2501
+ canSkipHandleResolution: true,
2502
+ reason: opts?.reason,
2503
+ });
2492
2504
  }
2493
2505
  if (runContextIds && runContextIds.size > 0) {
2494
2506
  for (const id of runContextIds) {
@@ -2500,19 +2512,22 @@ class NodeExecutor {
2500
2512
  }
2501
2513
  // Handle debouncing
2502
2514
  const now = Date.now();
2503
- if (this.shouldDebounce(node, now)) {
2504
- this.handleDebouncedSchedule(node, nodeId, now, runContextIds);
2515
+ if (this.shouldDebounce(nodeId, now)) {
2516
+ this.handleDebouncedSchedule(nodeId, now, runContextIds, reason);
2505
2517
  return;
2506
2518
  }
2507
2519
  // Prepare execution plan
2508
- const executionPlan = this.prepareExecutionPlan(node, nodeId, runContextIds, now);
2520
+ const executionPlan = this.prepareExecutionPlan(nodeId, runContextIds, now, reason);
2509
2521
  // Route to appropriate concurrency handler
2510
- this.routeToConcurrencyHandler(node, nodeId, executionPlan);
2522
+ this.routeToConcurrencyHandler(nodeId, executionPlan);
2511
2523
  }
2512
2524
  /**
2513
2525
  * Check if execution should be debounced
2514
2526
  */
2515
- shouldDebounce(node, now) {
2527
+ shouldDebounce(nodeId, now) {
2528
+ const node = this.graph.getNode(nodeId);
2529
+ if (!node)
2530
+ return false;
2516
2531
  const policy = node.policy ?? {};
2517
2532
  const lastScheduledAt = node.lastScheduledAt;
2518
2533
  return !!(policy.debounceMs &&
@@ -2522,80 +2537,78 @@ class NodeExecutor {
2522
2537
  /**
2523
2538
  * Handle debounced scheduling by replacing the latest queued item
2524
2539
  */
2525
- handleDebouncedSchedule(node, nodeId, now, runContextIds) {
2540
+ handleDebouncedSchedule(nodeId, now, runContextIds, reason) {
2541
+ const node = this.graph.getNode(nodeId);
2542
+ if (!node)
2543
+ return;
2526
2544
  // Decrement pendingQueued for any existing queued items before replacing
2527
2545
  if (node.queue.length > 0) {
2528
2546
  this.decrementQueuedForPlans(node.queue, nodeId);
2529
2547
  }
2530
- const effectiveInputs = this.getEffectiveInputs(nodeId);
2531
- const runSeq = this.graph.incrementNodeRunSeq(nodeId);
2532
- const runId = `${nodeId}:${runSeq}:${now}`;
2533
- const policySnapshot = node.policy ? { ...node.policy } : undefined;
2534
- const plan = {
2535
- runId,
2536
- effectiveInputs,
2537
- runContextIdsForRun: runContextIds,
2538
- timestamp: now,
2539
- policy: policySnapshot,
2540
- };
2541
- this.graph.replaceNodeQueue(nodeId, [plan]);
2548
+ const executionPlan = this.prepareExecutionPlan(nodeId, runContextIds, now, reason);
2549
+ this.graph.replaceNodeQueue(nodeId, [executionPlan]);
2542
2550
  }
2543
2551
  /**
2544
2552
  * Prepare execution plan with all necessary information
2545
2553
  */
2546
- prepareExecutionPlan(node, nodeId, runContextIds, now) {
2554
+ prepareExecutionPlan(nodeId, runContextIds, now, reason) {
2555
+ const node = this.graph.getNode(nodeId);
2547
2556
  this.graph.setNodeLastScheduledAt(nodeId, now);
2548
2557
  const runSeq = this.graph.incrementNodeRunSeq(nodeId);
2549
2558
  const runId = `${nodeId}:${runSeq}:${now}`;
2550
2559
  this.graph.setNodeLatestRunId(nodeId, runId);
2551
2560
  const effectiveInputs = this.getEffectiveInputs(nodeId);
2552
2561
  // Take a shallow snapshot of the current policy for this run
2553
- const policySnapshot = node.policy ? { ...node.policy } : undefined;
2562
+ const policySnapshot = node?.policy ? { ...node.policy } : undefined;
2554
2563
  return {
2555
2564
  runId,
2556
2565
  effectiveInputs,
2557
2566
  runContextIdsForRun: runContextIds,
2558
2567
  timestamp: now,
2559
2568
  policy: policySnapshot,
2569
+ reason,
2560
2570
  };
2561
2571
  }
2562
2572
  /**
2563
2573
  * Route execution to appropriate concurrency handler
2564
2574
  */
2565
- routeToConcurrencyHandler(node, nodeId, plan) {
2575
+ routeToConcurrencyHandler(nodeId, plan) {
2566
2576
  const mode = plan.policy?.asyncConcurrency ?? "switch";
2567
2577
  switch (mode) {
2568
2578
  case "drop":
2569
- this.handleDropMode(node, nodeId, plan);
2579
+ this.handleDropMode(nodeId, plan);
2570
2580
  break;
2571
2581
  case "queue":
2572
- this.handleQueueMode(node, nodeId, plan);
2582
+ this.handleQueueMode(nodeId, plan);
2573
2583
  break;
2574
2584
  case "switch":
2575
2585
  case "merge":
2576
2586
  default:
2577
- this.startRun(node, nodeId, plan);
2587
+ this.startRun(nodeId, plan);
2578
2588
  break;
2579
2589
  }
2580
2590
  }
2581
2591
  /**
2582
2592
  * Handle drop mode - drop execution if node is already running, otherwise start run
2583
2593
  */
2584
- handleDropMode(node, nodeId, plan) {
2594
+ handleDropMode(nodeId, plan) {
2595
+ const node = this.graph.getNode(nodeId);
2596
+ if (!node)
2597
+ return;
2585
2598
  // Drop if node is already running
2586
2599
  if (node.activeControllers.size > 0) {
2587
2600
  return; // Don't increment pendingCount if we're dropping this run
2588
2601
  }
2589
2602
  // Start run if node is not running
2590
- this.startRun(node, nodeId, plan);
2603
+ this.startRun(nodeId, plan);
2591
2604
  }
2592
2605
  /**
2593
2606
  * Handle queue mode - add to queue and process sequentially
2594
2607
  */
2595
- handleQueueMode(node, nodeId, plan) {
2608
+ handleQueueMode(nodeId, plan) {
2596
2609
  const maxQ = plan.policy?.maxQueue ?? 8;
2597
- const currentNode = this.graph.getNode(nodeId);
2598
- if (!currentNode)
2610
+ const node = this.graph.getNode(nodeId);
2611
+ if (!node)
2599
2612
  return;
2600
2613
  // Keep the originating run-context alive while work is queued by
2601
2614
  // incrementing queued counters for the plan's run-contexts.
@@ -2605,18 +2618,18 @@ class NodeExecutor {
2605
2618
  }
2606
2619
  }
2607
2620
  this.graph.addToNodeQueue(nodeId, plan);
2608
- if (currentNode.queue.length > maxQ) {
2621
+ if (node.queue.length > maxQ) {
2609
2622
  const dropped = this.graph.shiftNodeQueue(nodeId);
2610
2623
  if (dropped) {
2611
2624
  this.decrementQueuedForPlans(dropped, nodeId);
2612
2625
  }
2613
2626
  }
2614
- this.processQueue(node, nodeId);
2627
+ this.processQueue(nodeId);
2615
2628
  }
2616
2629
  /**
2617
2630
  * Process queued executions sequentially
2618
2631
  */
2619
- processQueue(node, nodeId) {
2632
+ processQueue(nodeId) {
2620
2633
  const processNext = () => {
2621
2634
  const node = this.graph.getNode(nodeId);
2622
2635
  if (!node)
@@ -2629,7 +2642,7 @@ class NodeExecutor {
2629
2642
  this.graph.setNodeLatestRunId(nodeId, next.runId);
2630
2643
  // Start the run first (which increments pendingNodes), then decrement
2631
2644
  // pendingQueued to ensure the run context stays alive.
2632
- this.startRun(node, nodeId, next, () => {
2645
+ this.startRun(nodeId, next, () => {
2633
2646
  setTimeout(processNext, 0);
2634
2647
  });
2635
2648
  this.decrementQueuedForPlans(next, nodeId);
@@ -2639,19 +2652,19 @@ class NodeExecutor {
2639
2652
  /**
2640
2653
  * Start a node execution run
2641
2654
  */
2642
- startRun(node, nodeId, plan, onDone) {
2655
+ startRun(nodeId, plan, onDone) {
2643
2656
  // Track run-contexts
2644
2657
  this.trackRunContextStart(nodeId, plan.runContextIdsForRun);
2645
2658
  // Setup execution controller
2646
- const controller = this.createExecutionController(nodeId, node, plan.runId);
2659
+ const controller = this.createExecutionController(nodeId, plan.runId);
2647
2660
  // Handle concurrency mode
2648
- this.applyConcurrencyMode(nodeId, node, controller, plan);
2661
+ this.applyConcurrencyMode(nodeId, controller, plan);
2649
2662
  // Setup timeout if needed
2650
- const timeoutId = this.setupTimeout(node, controller, plan);
2663
+ const timeoutId = this.setupTimeout(controller, plan);
2651
2664
  // Create execution context
2652
- const execCtx = this.createExecutionContext(nodeId, node, plan.effectiveInputs, plan.runId, controller.signal, plan.runContextIdsForRun, this.createEmitAndProgressHandlers(node, nodeId, plan));
2665
+ const execCtx = this.createExecutionContext(nodeId, plan.effectiveInputs, plan.runId, controller.signal, plan.runContextIdsForRun, this.createEmitAndProgressHandlers(nodeId, plan));
2653
2666
  // Execute
2654
- this.executeNode(node, nodeId, execCtx, plan, controller, timeoutId, onDone);
2667
+ this.executeNode(nodeId, execCtx, plan, controller, timeoutId, onDone);
2655
2668
  }
2656
2669
  /**
2657
2670
  * Track run-context start for pending nodes
@@ -2680,12 +2693,13 @@ class NodeExecutor {
2680
2693
  /**
2681
2694
  * Create execution controller and update node stats
2682
2695
  */
2683
- createExecutionController(nodeId, node, runId) {
2696
+ createExecutionController(nodeId, runId) {
2684
2697
  const controller = new AbortController();
2685
2698
  const now = Date.now();
2699
+ const node = this.graph.getNode(nodeId);
2686
2700
  this.graph.updateNodeStats(nodeId, {
2687
- runs: node.stats.runs + 1,
2688
- active: node.stats.active + 1,
2701
+ runs: (node?.stats.runs ?? 0) + 1,
2702
+ active: (node?.stats.active ?? 0) + 1,
2689
2703
  lastStartAt: now,
2690
2704
  progress: 0,
2691
2705
  });
@@ -2695,7 +2709,7 @@ class NodeExecutor {
2695
2709
  /**
2696
2710
  * Apply concurrency mode (switch mode aborts other controllers)
2697
2711
  */
2698
- applyConcurrencyMode(nodeId, node, controller, plan) {
2712
+ applyConcurrencyMode(nodeId, controller, plan) {
2699
2713
  const mode = plan.policy?.asyncConcurrency ?? "switch";
2700
2714
  if (mode === "switch") {
2701
2715
  const controllers = this.graph.getNodeControllers(nodeId);
@@ -2708,7 +2722,7 @@ class NodeExecutor {
2708
2722
  /**
2709
2723
  * Setup timeout for execution if configured
2710
2724
  */
2711
- setupTimeout(node, controller, plan) {
2725
+ setupTimeout(controller, plan) {
2712
2726
  const policy = plan.policy ?? {};
2713
2727
  if (policy.timeoutMs && policy.timeoutMs > 0) {
2714
2728
  return setTimeout(() => controller.abort("timeout"), policy.timeoutMs);
@@ -2718,7 +2732,7 @@ class NodeExecutor {
2718
2732
  /**
2719
2733
  * Create emit and progress handlers for execution context
2720
2734
  */
2721
- createEmitAndProgressHandlers(node, nodeId, plan) {
2735
+ createEmitAndProgressHandlers(nodeId, plan) {
2722
2736
  const policy = plan.policy ?? {};
2723
2737
  return {
2724
2738
  emitHandler: (handle, value) => {
@@ -2753,7 +2767,10 @@ class NodeExecutor {
2753
2767
  /**
2754
2768
  * Execute the node with retry logic and cleanup
2755
2769
  */
2756
- executeNode(node, nodeId, ctx, plan, controller, timeoutId, onDone) {
2770
+ executeNode(nodeId, ctx, plan, controller, timeoutId, onDone) {
2771
+ const node = this.graph.getNode(nodeId);
2772
+ if (!node)
2773
+ return;
2757
2774
  // Fire node-start event
2758
2775
  this.eventEmitter.emit("stats", {
2759
2776
  kind: "node-start",
@@ -2761,7 +2778,11 @@ class NodeExecutor {
2761
2778
  typeId: node.typeId,
2762
2779
  runId: plan.runId,
2763
2780
  });
2764
- ctx.log("debug", "node-start");
2781
+ ctx.log("debug", "node-start", {
2782
+ inputs: node.inputs,
2783
+ effectiveInputs: plan.effectiveInputs,
2784
+ reason: plan.reason,
2785
+ });
2765
2786
  const exec = async (attempt) => {
2766
2787
  let hadError = false;
2767
2788
  try {
@@ -2799,7 +2820,7 @@ class NodeExecutor {
2799
2820
  });
2800
2821
  }
2801
2822
  finally {
2802
- this.cleanupExecution(node, nodeId, ctx, plan, controller, timeoutId, hadError, onDone);
2823
+ this.cleanupExecution(nodeId, ctx, plan, controller, timeoutId, hadError, onDone);
2803
2824
  }
2804
2825
  };
2805
2826
  exec(0);
@@ -2807,7 +2828,7 @@ class NodeExecutor {
2807
2828
  /**
2808
2829
  * Cleanup after execution completes
2809
2830
  */
2810
- cleanupExecution(node, nodeId, ctx, plan, controller, timeoutId, hadError, onDone) {
2831
+ cleanupExecution(nodeId, ctx, plan, controller, timeoutId, hadError, onDone) {
2811
2832
  // Decrement pendingNodes count for all relevant run-contexts
2812
2833
  if (plan.runContextIdsForRun && plan.runContextIdsForRun.size > 0) {
2813
2834
  for (const id of plan.runContextIdsForRun) {
@@ -2821,19 +2842,19 @@ class NodeExecutor {
2821
2842
  if (timeoutId)
2822
2843
  clearTimeout(timeoutId);
2823
2844
  this.graph.removeNodeController(nodeId, controller);
2824
- const currentNode = this.graph.getNode(nodeId);
2825
- if (!currentNode)
2845
+ const node = this.graph.getNode(nodeId);
2846
+ if (!node)
2826
2847
  return;
2827
2848
  const controllers = this.graph.getNodeControllers(nodeId);
2828
2849
  const lastEndAt = Date.now();
2829
- const lastDurationMs = currentNode.stats.lastStartAt && lastEndAt
2830
- ? lastEndAt - currentNode.stats.lastStartAt
2850
+ const lastDurationMs = node.stats.lastStartAt && lastEndAt
2851
+ ? lastEndAt - node.stats.lastStartAt
2831
2852
  : undefined;
2832
2853
  this.graph.updateNodeStats(nodeId, {
2833
2854
  active: Math.max(0, controllers.size),
2834
2855
  lastEndAt,
2835
2856
  lastDurationMs,
2836
- lastError: hadError ? currentNode.stats.lastError : undefined,
2857
+ lastError: hadError ? node.stats.lastError : undefined,
2837
2858
  });
2838
2859
  // Track successful completion time (for detecting stale inputs)
2839
2860
  const isCancelled = controller.signal.aborted &&
@@ -2845,27 +2866,22 @@ class NodeExecutor {
2845
2866
  }
2846
2867
  // Only emit node-done if not cancelled (cancellation events emitted separately)
2847
2868
  if (!isCancelled) {
2848
- if (currentNode) {
2869
+ if (node) {
2849
2870
  this.eventEmitter.emit("stats", {
2850
2871
  kind: "node-done",
2851
2872
  nodeId,
2852
- typeId: currentNode.typeId,
2873
+ typeId: node.typeId,
2853
2874
  runId: plan.runId,
2854
- durationMs: currentNode.stats.lastDurationMs,
2875
+ durationMs: node.stats.lastDurationMs,
2855
2876
  });
2856
2877
  }
2857
2878
  }
2858
- if (currentNode) {
2879
+ if (node) {
2859
2880
  ctx.log("debug", "node-done", {
2860
- formatJson: true,
2861
- durationMs: currentNode.stats.lastDurationMs,
2881
+ durationMs: node.stats.lastDurationMs,
2882
+ outputs: node.outputs,
2862
2883
  hadError,
2863
- inputs: currentNode.inputs
2864
- ? structuredClone(currentNode.inputs)
2865
- : undefined,
2866
- outputs: currentNode.outputs
2867
- ? structuredClone(currentNode.outputs)
2868
- : undefined,
2884
+ reason: plan.reason,
2869
2885
  });
2870
2886
  }
2871
2887
  if (onDone)
@@ -2874,14 +2890,13 @@ class NodeExecutor {
2874
2890
  /**
2875
2891
  * Cancel all active runs for a node
2876
2892
  */
2877
- cancelNodeActiveRuns(node, reason) {
2878
- const nodeId = node.nodeId;
2893
+ cancelNodeActiveRuns(nodeId, reason) {
2894
+ const node = this.graph.getNode(nodeId);
2895
+ if (!node)
2896
+ return;
2879
2897
  const controllers = this.graph.getNodeControllers(nodeId);
2880
2898
  for (const controller of controllers) {
2881
- const currentNode = this.graph.getNode(nodeId);
2882
- if (!currentNode)
2883
- continue;
2884
- const runId = currentNode.controllerRunIds.get(controller);
2899
+ const runId = node.controllerRunIds.get(controller);
2885
2900
  if (runId) {
2886
2901
  // Track cancelled runIds for snapshot and user-cancelled operations
2887
2902
  // (to drop emits from cancelled runs)
@@ -2891,8 +2906,8 @@ class NodeExecutor {
2891
2906
  // Emit cancellation event
2892
2907
  this.eventEmitter.emit("stats", {
2893
2908
  kind: "node-done",
2894
- nodeId: currentNode.nodeId,
2895
- typeId: currentNode.typeId,
2909
+ nodeId: nodeId,
2910
+ typeId: node.typeId,
2896
2911
  runId,
2897
2912
  cancelled: true,
2898
2913
  });
@@ -2940,10 +2955,7 @@ class NodeExecutor {
2940
2955
  }
2941
2956
  // Cancel runs for all affected nodes
2942
2957
  for (const nodeId of toCancel) {
2943
- const node = this.graph.getNode(nodeId);
2944
- if (!node)
2945
- continue;
2946
- this.cancelNodeActiveRuns(node, reason);
2958
+ this.cancelNodeActiveRuns(nodeId, reason);
2947
2959
  const runSeq = this.graph.incrementNodeRunSeq(nodeId);
2948
2960
  const now = Date.now();
2949
2961
  const suffix = reason === "snapshot" ? "snapshot" : "cancelled";
@@ -3183,7 +3195,7 @@ class GraphRuntime {
3183
3195
  // However, if autoRun policy is set, nodes run automatically even in manual mode.
3184
3196
  if (anyChanged) {
3185
3197
  this.handleResolver.scheduleRecomputeHandles(nodeId);
3186
- this.executeNodeAutoRun(nodeId);
3198
+ this.executeNodeAutoRun(nodeId, { reason: "setInputs" });
3187
3199
  }
3188
3200
  }
3189
3201
  getOutput(nodeId, output) {
@@ -3194,7 +3206,7 @@ class GraphRuntime {
3194
3206
  this.graph.forEachNode((node) => {
3195
3207
  const effectiveInputs = this.nodeExecutor.getEffectiveInputs(node.nodeId);
3196
3208
  const ctrl = new AbortController();
3197
- const execCtx = this.nodeExecutor.createExecutionContext(node.nodeId, node, effectiveInputs, `${node.nodeId}:init`, ctrl.signal);
3209
+ const execCtx = this.nodeExecutor.createExecutionContext(node.nodeId, effectiveInputs, `${node.nodeId}:init`, ctrl.signal);
3198
3210
  if (node.lifecycle?.prepare) {
3199
3211
  execCtx.log("debug", "prepare-start");
3200
3212
  node.lifecycle.prepare(node.params ?? {}, execCtx);
@@ -3205,7 +3217,7 @@ class GraphRuntime {
3205
3217
  if (this.runMode === "auto" && invalidate) {
3206
3218
  for (const nodeId of this.graph.getNodeIds()) {
3207
3219
  if (this.graph.allInboundHaveValue(nodeId))
3208
- this.execute(nodeId);
3220
+ this.execute(nodeId, { reason: "launch" });
3209
3221
  }
3210
3222
  }
3211
3223
  if (startPaused) {
@@ -3220,7 +3232,7 @@ class GraphRuntime {
3220
3232
  if (this.isInvalidateEvent(event)) {
3221
3233
  // Check if node has all inbound inputs (required for execution)
3222
3234
  if (this.graph.allInboundHaveValue(nodeId)) {
3223
- this.execute(nodeId);
3235
+ this.execute(nodeId, { reason: "triggerExternal" });
3224
3236
  }
3225
3237
  return;
3226
3238
  }
@@ -3344,17 +3356,20 @@ class GraphRuntime {
3344
3356
  setTimeout(check, 10);
3345
3357
  });
3346
3358
  }
3347
- async runFromHereContext(startNodeId, options) {
3359
+ async runFromHereContext(startNodeId, opts) {
3348
3360
  const node = this.graph.getNode(startNodeId);
3349
3361
  if (!node)
3350
3362
  return;
3351
3363
  return new Promise((resolve) => {
3352
3364
  const id = this.runContextManager.createRunContext(startNodeId, {
3353
3365
  resolve,
3354
- ...options,
3366
+ ...opts,
3355
3367
  });
3356
3368
  this.graph.addNodeRunContextId(startNodeId, id);
3357
- this.execute(startNodeId, new Set([id]));
3369
+ this.execute(startNodeId, {
3370
+ runContextIds: new Set([id]),
3371
+ reason: opts?.reason ?? "runFromHereContext",
3372
+ });
3358
3373
  });
3359
3374
  }
3360
3375
  setRunMode(runMode) {
@@ -3401,7 +3416,7 @@ class GraphRuntime {
3401
3416
  }
3402
3417
  }
3403
3418
  }
3404
- executeNodeAutoRun(nodeId) {
3419
+ executeNodeAutoRun(nodeId, opts) {
3405
3420
  const node = this.graph.getNode(nodeId);
3406
3421
  const shouldAutoRun = this.runMode === "auto" || node?.policy?.autoRun === true;
3407
3422
  let runContextIdsToUse = undefined;
@@ -3411,7 +3426,10 @@ class GraphRuntime {
3411
3426
  ]);
3412
3427
  }
3413
3428
  if (shouldAutoRun && this.graph.allInboundHaveValue(nodeId)) {
3414
- this.execute(nodeId, runContextIdsToUse);
3429
+ this.execute(nodeId, {
3430
+ runContextIds: runContextIdsToUse,
3431
+ reason: opts?.reason ?? "executeNodeAutoRun",
3432
+ });
3415
3433
  }
3416
3434
  }
3417
3435
  copyOutputs(fromNodeId, toNodeId, options) {
@@ -3420,7 +3438,7 @@ class GraphRuntime {
3420
3438
  return;
3421
3439
  this.hydrate({ outputs: { [toNodeId]: { ...fromNode.outputs } } }, { invalidate: !options?.dry });
3422
3440
  this.handleResolver.scheduleRecomputeHandles(toNodeId);
3423
- this.executeNodeAutoRun(toNodeId);
3441
+ this.executeNodeAutoRun(toNodeId, { reason: "copyOutputs" });
3424
3442
  }
3425
3443
  hydrate(payload, opts) {
3426
3444
  const releasePause = this.requestPause();
@@ -3478,7 +3496,7 @@ class GraphRuntime {
3478
3496
  const node = this.graph.getNode(nodeId);
3479
3497
  if (!node)
3480
3498
  continue;
3481
- this.nodeExecutor.cancelNodeActiveRuns(node, "node-deleted");
3499
+ this.nodeExecutor.cancelNodeActiveRuns(nodeId, "node-deleted");
3482
3500
  this.runContextManager.cancelNodeInRunContexts(nodeId, true);
3483
3501
  node.runtime.onDeactivated?.();
3484
3502
  node.runtime.dispose?.();
@@ -3539,7 +3557,7 @@ class GraphRuntime {
3539
3557
  this.graph.setNode(n.nodeId, newNode);
3540
3558
  const effectiveInputs = this.nodeExecutor.getEffectiveInputs(newNode.nodeId);
3541
3559
  const ctrl = new AbortController();
3542
- const execCtx = this.nodeExecutor.createExecutionContext(newNode.nodeId, newNode, effectiveInputs, `${newNode.nodeId}:init`, ctrl.signal);
3560
+ const execCtx = this.nodeExecutor.createExecutionContext(newNode.nodeId, effectiveInputs, `${newNode.nodeId}:init`, ctrl.signal);
3543
3561
  if (newNode.lifecycle?.prepare) {
3544
3562
  execCtx.log("debug", "prepare-start");
3545
3563
  newNode.lifecycle.prepare(newNode.params ?? {}, execCtx);
@@ -3650,7 +3668,7 @@ class GraphRuntime {
3650
3668
  this.edgePropagator.clearArrayBuckets(nodeId);
3651
3669
  // Trigger handle resolution when inputs are removed
3652
3670
  this.handleResolver.scheduleRecomputeHandles(nodeId);
3653
- this.executeNodeAutoRun(nodeId);
3671
+ this.executeNodeAutoRun(nodeId, { reason: "graphUpdate" });
3654
3672
  }
3655
3673
  }
3656
3674
  // Propagate changes on edges added
@@ -3720,8 +3738,8 @@ class GraphRuntime {
3720
3738
  });
3721
3739
  this.graph.clear();
3722
3740
  }
3723
- execute(nodeId, runContextIds, canSkipHandleResolution) {
3724
- this.nodeExecutor.execute(nodeId, runContextIds, canSkipHandleResolution);
3741
+ execute(nodeId, opts) {
3742
+ this.nodeExecutor.execute(nodeId, opts);
3725
3743
  }
3726
3744
  propagate(srcNodeId, srcHandle, value, runContextIds) {
3727
3745
  this.edgePropagator.propagate(srcNodeId, srcHandle, value, runContextIds);
@@ -4084,6 +4102,7 @@ class LocalEngine {
4084
4102
  await this.graphRuntime.runFromHereContext(nodeId, {
4085
4103
  skipPropagateValues: options?.skipPropagateValues ?? false,
4086
4104
  propagate: false, // Don't schedule downstream nodes
4105
+ reason: "computeNode",
4087
4106
  });
4088
4107
  }
4089
4108
  /**
@@ -4092,7 +4111,9 @@ class LocalEngine {
4092
4111
  * Uses run-context system for dynamic graph updates.
4093
4112
  */
4094
4113
  async runFromHere(nodeId) {
4095
- await this.graphRuntime.runFromHereContext(nodeId);
4114
+ await this.graphRuntime.runFromHereContext(nodeId, {
4115
+ reason: "runFromHere",
4116
+ });
4096
4117
  }
4097
4118
  setRunMode(runMode) {
4098
4119
  this.graphRuntime.setRunMode(runMode);