@bian-womp/spark-workbench 0.2.35 → 0.2.36

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/lib/cjs/index.cjs CHANGED
@@ -339,7 +339,6 @@ class AbstractGraphRunner {
339
339
  if (this.engine) {
340
340
  throw new Error("Engine already running. Stop the current engine first.");
341
341
  }
342
- this.currentDef = def;
343
342
  }
344
343
  setInput(nodeId, handle, value) {
345
344
  if (!this.stagedInputs[nodeId])
@@ -396,7 +395,6 @@ class AbstractGraphRunner {
396
395
  this.engine = undefined;
397
396
  this.runtime?.dispose();
398
397
  this.runtime = undefined;
399
- this.currentDef = undefined;
400
398
  if (this.runningKind) {
401
399
  this.runningKind = undefined;
402
400
  this.emit("status", { running: false, engine: undefined });
@@ -431,14 +429,12 @@ class LocalGraphRunner extends AbstractGraphRunner {
431
429
  this.emit("transport", { state: "local" });
432
430
  }
433
431
  build(def) {
434
- this.currentDef = def;
435
432
  const builder = new sparkGraph.GraphBuilder(this.registry);
436
433
  this.runtime = builder.build(def);
437
434
  // Signal UI that freshly built graph should be considered invalidated
438
435
  this.emit("invalidate", { reason: "graph-built" });
439
436
  }
440
437
  update(def) {
441
- this.currentDef = def;
442
438
  if (!this.runtime)
443
439
  return;
444
440
  // Prevent mid-run churn while wiring changes are applied
@@ -503,11 +499,11 @@ class LocalGraphRunner extends AbstractGraphRunner {
503
499
  if (eng instanceof sparkGraph.BatchedEngine)
504
500
  eng.flush();
505
501
  }
506
- getOutputs() {
502
+ getOutputs(def) {
507
503
  const out = {};
508
- if (!this.runtime || !this.currentDef)
504
+ if (!this.runtime)
509
505
  return out;
510
- for (const n of this.currentDef.nodes) {
506
+ for (const n of def.nodes) {
511
507
  const desc = this.registry.nodes.get(n.typeId);
512
508
  const handles = Object.keys(desc?.outputs ?? {});
513
509
  for (const h of handles) {
@@ -521,17 +517,15 @@ class LocalGraphRunner extends AbstractGraphRunner {
521
517
  }
522
518
  return out;
523
519
  }
524
- getInputs() {
520
+ getInputs(def) {
525
521
  const out = {};
526
- if (!this.currentDef)
527
- return out;
528
- for (const n of this.currentDef.nodes) {
522
+ for (const n of def.nodes) {
529
523
  const staged = this.stagedInputs[n.nodeId] ?? {};
530
524
  const runtimeInputs = this.runtime
531
525
  ? this.runtime.getNodeData?.(n.nodeId)?.inputs ?? {}
532
526
  : {};
533
527
  // Build inbound handle set for this node from current def
534
- const inbound = new Set(this.currentDef.edges
528
+ const inbound = new Set(def.edges
535
529
  .filter((e) => e.target.nodeId === n.nodeId)
536
530
  .map((e) => e.target.handle));
537
531
  // Merge staged only for non-inbound handles so UI reflects runtime values for wired inputs
@@ -545,11 +539,9 @@ class LocalGraphRunner extends AbstractGraphRunner {
545
539
  }
546
540
  return out;
547
541
  }
548
- getInputDefaults() {
542
+ getInputDefaults(def) {
549
543
  const out = {};
550
- if (!this.currentDef)
551
- return out;
552
- for (const n of this.currentDef.nodes) {
544
+ for (const n of def.nodes) {
553
545
  const dynDefaults = n.resolvedHandles?.inputDefaults ?? {};
554
546
  if (Object.keys(dynDefaults).length > 0) {
555
547
  out[n.nodeId] = dynDefaults;
@@ -559,8 +551,24 @@ class LocalGraphRunner extends AbstractGraphRunner {
559
551
  }
560
552
  async snapshotFull() {
561
553
  const def = undefined; // UI will supply def/positions on download for local
562
- const inputs = this.getInputs();
563
- const outputs = this.getOutputs();
554
+ const inputs = this.getInputs(this.runtime
555
+ ? {
556
+ nodes: Array.from(this.runtime.getNodeIds()).map((id) => ({
557
+ nodeId: id,
558
+ typeId: "",
559
+ })),
560
+ edges: [],
561
+ }
562
+ : { nodes: [], edges: [] });
563
+ const outputs = this.getOutputs(this.runtime
564
+ ? {
565
+ nodes: Array.from(this.runtime.getNodeIds()).map((id) => ({
566
+ nodeId: id,
567
+ typeId: "",
568
+ })),
569
+ edges: [],
570
+ }
571
+ : { nodes: [], edges: [] });
564
572
  const environment = this.getEnvironment() || {};
565
573
  return { def, environment, inputs, outputs };
566
574
  }
@@ -637,8 +645,8 @@ class RemoteGraphRunner extends AbstractGraphRunner {
637
645
  this.emit("registry", this.registry);
638
646
  // Trigger update so validation/UI refreshes using last known graph
639
647
  try {
640
- if (this.currentDef)
641
- this.update(this.currentDef);
648
+ if (this.lastDef)
649
+ this.update(this.lastDef);
642
650
  }
643
651
  catch {
644
652
  console.error("Failed to update graph definition after registry changed");
@@ -656,12 +664,12 @@ class RemoteGraphRunner extends AbstractGraphRunner {
656
664
  console.warn("Unsupported operation for remote runner");
657
665
  }
658
666
  update(def) {
659
- this.currentDef = def;
660
667
  // Remote: forward update; ignore errors (fire-and-forget)
661
668
  this.ensureRemoteRunner().then(async (runner) => {
662
669
  try {
663
670
  await runner.update(def);
664
671
  this.emit("invalidate", { reason: "graph-updated" });
672
+ this.lastDef = def;
665
673
  }
666
674
  catch { }
667
675
  });
@@ -673,6 +681,7 @@ class RemoteGraphRunner extends AbstractGraphRunner {
673
681
  await runner.build(def);
674
682
  // Signal UI after remote build as well
675
683
  this.emit("invalidate", { reason: "graph-built" });
684
+ this.lastDef = def;
676
685
  // Hydrate current remote inputs/outputs (including defaults) into cache
677
686
  try {
678
687
  const snap = await runner.snapshot();
@@ -808,12 +817,12 @@ class RemoteGraphRunner extends AbstractGraphRunner {
808
817
  // For now, we expose an async helper on RemoteRunner. Keep sync signature per interface.
809
818
  return undefined;
810
819
  }
811
- getOutputs() {
820
+ getOutputs(def) {
812
821
  const out = {};
813
822
  const cache = this.valueCache;
814
- if (!cache || !this.currentDef)
823
+ if (!cache)
815
824
  return out;
816
- for (const n of this.currentDef.nodes) {
825
+ for (const n of def.nodes) {
817
826
  const resolved = n.resolvedHandles?.outputs;
818
827
  const desc = this.registry.nodes.get(n.typeId);
819
828
  const handles = Object.keys(resolved ?? desc?.outputs ?? {});
@@ -829,19 +838,17 @@ class RemoteGraphRunner extends AbstractGraphRunner {
829
838
  }
830
839
  return out;
831
840
  }
832
- getInputs() {
841
+ getInputs(def) {
833
842
  const out = {};
834
843
  const cache = this.valueCache;
835
- if (!this.currentDef)
836
- return out;
837
- for (const n of this.currentDef.nodes) {
844
+ for (const n of def.nodes) {
838
845
  const staged = this.stagedInputs[n.nodeId] ?? {};
839
846
  const resolved = n.resolvedHandles?.inputs;
840
847
  const desc = this.registry.nodes.get(n.typeId);
841
848
  const handles = Object.keys(resolved ?? desc?.inputs ?? {});
842
849
  const cur = {};
843
850
  // Build inbound handle set for this node to honor wiring precedence
844
- const inbound = new Set(this.currentDef.edges
851
+ const inbound = new Set(def.edges
845
852
  .filter((e) => e.target.nodeId === n.nodeId)
846
853
  .map((e) => e.target.handle));
847
854
  for (const h of handles) {
@@ -860,11 +867,9 @@ class RemoteGraphRunner extends AbstractGraphRunner {
860
867
  }
861
868
  return out;
862
869
  }
863
- getInputDefaults() {
870
+ getInputDefaults(def) {
864
871
  const out = {};
865
- if (!this.currentDef)
866
- return out;
867
- for (const n of this.currentDef.nodes) {
872
+ for (const n of def.nodes) {
868
873
  const dynDefaults = n.resolvedHandles?.inputDefaults ?? {};
869
874
  if (Object.keys(dynDefaults).length > 0) {
870
875
  out[n.nodeId] = dynDefaults;
@@ -1789,9 +1794,9 @@ function WorkbenchProvider({ wb, runner, registry, setRegistry, overrides, uiVer
1789
1794
  const valuesTick = versionTick + graphTick + graphUiTick;
1790
1795
  // Def and IO values
1791
1796
  const def = wb.export();
1792
- const inputsMap = React.useMemo(() => runner.getInputs(), [runner, valuesTick]);
1793
- const inputDefaultsMap = React.useMemo(() => runner.getInputDefaults(), [runner, valuesTick]);
1794
- const outputsMap = React.useMemo(() => runner.getOutputs(), [runner, valuesTick]);
1797
+ const inputsMap = React.useMemo(() => runner.getInputs(def), [runner, def, valuesTick]);
1798
+ const inputDefaultsMap = React.useMemo(() => runner.getInputDefaults(def), [runner, def, valuesTick]);
1799
+ const outputsMap = React.useMemo(() => runner.getOutputs(def), [runner, def, valuesTick]);
1795
1800
  const outputTypesMap = React.useMemo(() => {
1796
1801
  const out = {};
1797
1802
  // Local: runtimeTypeId is not stored; derive from typed wrapper in outputsMap
@@ -2191,13 +2196,14 @@ function WorkbenchProvider({ wb, runner, registry, setRegistry, overrides, uiVer
2191
2196
  offRunnerTransport();
2192
2197
  };
2193
2198
  }, [runner, wb]);
2194
- // Keep runner.currentDef in sync with the workbench graph at all times.
2195
- // When an engine/runtime exists, this also pushes incremental wiring changes into it.
2199
+ // Push incremental updates into running engine without full reload
2196
2200
  React.useEffect(() => {
2197
- try {
2198
- runner.update(def);
2201
+ if (runner.isRunning()) {
2202
+ try {
2203
+ runner.update(def);
2204
+ }
2205
+ catch { }
2199
2206
  }
2200
- catch { }
2201
2207
  }, [runner, def, graphTick]);
2202
2208
  const validationByNode = React.useMemo(() => {
2203
2209
  const inputs = {};
@@ -3465,7 +3471,7 @@ function WorkbenchStudioCanvas({ setRegistry, autoScroll, onAutoScrollChange, ex
3465
3471
  const off1 = wb.on("graphChanged", () => {
3466
3472
  try {
3467
3473
  const cur = wb.export();
3468
- const inputs = runner.getInputs();
3474
+ const inputs = runner.getInputs(cur);
3469
3475
  onChange({ def: cur, inputs });
3470
3476
  }
3471
3477
  catch { }
@@ -3473,7 +3479,7 @@ function WorkbenchStudioCanvas({ setRegistry, autoScroll, onAutoScrollChange, ex
3473
3479
  const off2 = runner.on("value", () => {
3474
3480
  try {
3475
3481
  const cur = wb.export();
3476
- const inputs = runner.getInputs();
3482
+ const inputs = runner.getInputs(cur);
3477
3483
  onChange({ def: cur, inputs });
3478
3484
  }
3479
3485
  catch { }
@@ -3519,7 +3525,7 @@ function WorkbenchStudioCanvas({ setRegistry, autoScroll, onAutoScrollChange, ex
3519
3525
  const downloadGraph = React.useCallback(() => {
3520
3526
  try {
3521
3527
  const def = wb.export();
3522
- const inputs = runner.getInputs();
3528
+ const inputs = runner.getInputs(def);
3523
3529
  const payload = { def, inputs };
3524
3530
  const pretty = JSON.stringify(payload, null, 2);
3525
3531
  const blob = new Blob([pretty], { type: "application/json" });