@ghchinoy/litflow 0.2.8 → 0.3.0

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 (158) hide show
  1. package/CHANGELOG.md +5 -0
  2. package/dist/breadboard/data/common.d.ts +35 -0
  3. package/dist/breadboard/engine/loader/capability.d.ts +21 -0
  4. package/dist/breadboard/engine/loader/loader.d.ts +29 -0
  5. package/dist/breadboard/engine/loader/resolve-graph-urls.d.ts +16 -0
  6. package/dist/breadboard/engine/runtime/bubble.d.ts +23 -0
  7. package/dist/breadboard/engine/runtime/graph-based-node-handler.d.ts +16 -0
  8. package/dist/breadboard/engine/runtime/handler.d.ts +27 -0
  9. package/dist/breadboard/engine/runtime/harness/events.d.ts +145 -0
  10. package/dist/breadboard/engine/runtime/harness/local.d.ts +10 -0
  11. package/dist/breadboard/engine/runtime/harness/plan-runner.d.ts +25 -0
  12. package/dist/breadboard/engine/runtime/run/invoke-graph.d.ts +12 -0
  13. package/dist/breadboard/engine/runtime/run/node-invoker.d.ts +12 -0
  14. package/dist/breadboard/engine/runtime/run/run-graph.d.ts +12 -0
  15. package/dist/breadboard/engine/runtime/run.d.ts +29 -0
  16. package/dist/breadboard/engine/runtime/sandbox/capabilities-manager.d.ts +15 -0
  17. package/dist/breadboard/engine/runtime/sandbox/file-system-handler-factory.d.ts +15 -0
  18. package/dist/breadboard/engine/runtime/sandbox/invoke-describer.d.ts +10 -0
  19. package/dist/breadboard/engine/runtime/static/create-plan.d.ts +14 -0
  20. package/dist/breadboard/engine/runtime/static/orchestrator.d.ts +72 -0
  21. package/dist/breadboard/engine/runtime/traversal/index.d.ts +20 -0
  22. package/dist/breadboard/engine/runtime/traversal/iterator.d.ts +12 -0
  23. package/dist/breadboard/engine/runtime/traversal/machine.d.ts +14 -0
  24. package/dist/breadboard/engine/runtime/traversal/representation.d.ts +27 -0
  25. package/dist/breadboard/engine/runtime/traversal/result.d.ts +24 -0
  26. package/dist/breadboard/engine/runtime/traversal/state.d.ts +34 -0
  27. package/dist/breadboard/lit-flow-runner.d.ts +13 -0
  28. package/dist/breadboard/lit-flow-runner.test.d.ts +1 -0
  29. package/dist/breadboard/runner.d.ts +13 -0
  30. package/dist/index.d.ts +2 -0
  31. package/dist/lit-chiclet.d.ts +9 -0
  32. package/dist/lit-schema-node.d.ts +13 -0
  33. package/dist/lit-schema-node.test.d.ts +1 -0
  34. package/dist/litflow.js +708 -442
  35. package/dist/litflow.js.map +1 -1
  36. package/package.json +15 -3
  37. package/src/breadboard/data/common.ts +450 -0
  38. package/src/breadboard/data/file-system.ts +54 -0
  39. package/src/breadboard/data/inline-all-content.ts +126 -0
  40. package/src/breadboard/data/recent-boards.ts +118 -0
  41. package/src/breadboard/data/save-outputs-as-file.ts +104 -0
  42. package/src/breadboard/engine/add-run-module.ts +168 -0
  43. package/src/breadboard/engine/editor/blank.ts +65 -0
  44. package/src/breadboard/engine/editor/edge.ts +27 -0
  45. package/src/breadboard/engine/editor/events.ts +64 -0
  46. package/src/breadboard/engine/editor/graph.ts +383 -0
  47. package/src/breadboard/engine/editor/history.ts +98 -0
  48. package/src/breadboard/engine/editor/index.ts +8 -0
  49. package/src/breadboard/engine/editor/operations/add-asset.ts +45 -0
  50. package/src/breadboard/engine/editor/operations/add-edge.ts +142 -0
  51. package/src/breadboard/engine/editor/operations/add-graph.ts +47 -0
  52. package/src/breadboard/engine/editor/operations/add-module.ts +64 -0
  53. package/src/breadboard/engine/editor/operations/add-node.ts +86 -0
  54. package/src/breadboard/engine/editor/operations/change-asset-metadata.ts +70 -0
  55. package/src/breadboard/engine/editor/operations/change-configuration.ts +82 -0
  56. package/src/breadboard/engine/editor/operations/change-edge-metadata.ts +58 -0
  57. package/src/breadboard/engine/editor/operations/change-edge.ts +111 -0
  58. package/src/breadboard/engine/editor/operations/change-graph-metadata.ts +52 -0
  59. package/src/breadboard/engine/editor/operations/change-metadata.ts +92 -0
  60. package/src/breadboard/engine/editor/operations/change-module.ts +64 -0
  61. package/src/breadboard/engine/editor/operations/error.ts +21 -0
  62. package/src/breadboard/engine/editor/operations/remove-asset.ts +48 -0
  63. package/src/breadboard/engine/editor/operations/remove-edge.ts +89 -0
  64. package/src/breadboard/engine/editor/operations/remove-graph.ts +49 -0
  65. package/src/breadboard/engine/editor/operations/remove-integration.ts +54 -0
  66. package/src/breadboard/engine/editor/operations/remove-module.ts +69 -0
  67. package/src/breadboard/engine/editor/operations/remove-node.ts +86 -0
  68. package/src/breadboard/engine/editor/operations/replace-graph.ts +52 -0
  69. package/src/breadboard/engine/editor/operations/toggle-export.ts +72 -0
  70. package/src/breadboard/engine/editor/operations/upsert-integration.ts +43 -0
  71. package/src/breadboard/engine/editor/selection.ts +58 -0
  72. package/src/breadboard/engine/editor/transforms/configure-sidewire.ts +73 -0
  73. package/src/breadboard/engine/editor/transforms/isolate-selection.ts +54 -0
  74. package/src/breadboard/engine/editor/transforms/merge-graph.ts +58 -0
  75. package/src/breadboard/engine/editor/transforms/move-to-graph.ts +102 -0
  76. package/src/breadboard/engine/editor/transforms/move-to-new-graph.ts +72 -0
  77. package/src/breadboard/engine/editor/transforms/sidewire-to-new-graph.ts +82 -0
  78. package/src/breadboard/engine/file-system/blob-transform.ts +44 -0
  79. package/src/breadboard/engine/file-system/composed-peristent-backend.ts +140 -0
  80. package/src/breadboard/engine/file-system/ephemeral-blob-store.ts +46 -0
  81. package/src/breadboard/engine/file-system/in-memory-blob-store.ts +87 -0
  82. package/src/breadboard/engine/file-system/index.ts +723 -0
  83. package/src/breadboard/engine/file-system/partial-persistent-backend.ts +109 -0
  84. package/src/breadboard/engine/file-system/path.ts +125 -0
  85. package/src/breadboard/engine/file-system/persistent-file.ts +66 -0
  86. package/src/breadboard/engine/file-system/readable-stream-file.ts +61 -0
  87. package/src/breadboard/engine/file-system/stub-file-system.ts +47 -0
  88. package/src/breadboard/engine/file-system/utils.ts +40 -0
  89. package/src/breadboard/engine/inspector/graph/bubbled-node.ts +162 -0
  90. package/src/breadboard/engine/inspector/graph/describe-cache.ts +78 -0
  91. package/src/breadboard/engine/inspector/graph/describe-type-cache.ts +48 -0
  92. package/src/breadboard/engine/inspector/graph/edge-cache.ts +118 -0
  93. package/src/breadboard/engine/inspector/graph/edge.ts +133 -0
  94. package/src/breadboard/engine/inspector/graph/event.ts +35 -0
  95. package/src/breadboard/engine/inspector/graph/exports-describer.ts +45 -0
  96. package/src/breadboard/engine/inspector/graph/graph-cache.ts +54 -0
  97. package/src/breadboard/engine/inspector/graph/graph-describer-manager.ts +338 -0
  98. package/src/breadboard/engine/inspector/graph/graph-descriptor-handle.ts +73 -0
  99. package/src/breadboard/engine/inspector/graph/graph-node-type.ts +111 -0
  100. package/src/breadboard/engine/inspector/graph/graph-queries.ts +256 -0
  101. package/src/breadboard/engine/inspector/graph/graph.ts +163 -0
  102. package/src/breadboard/engine/inspector/graph/inspectable-asset.ts +36 -0
  103. package/src/breadboard/engine/inspector/graph/kits.ts +208 -0
  104. package/src/breadboard/engine/inspector/graph/module.ts +69 -0
  105. package/src/breadboard/engine/inspector/graph/mutable-graph.ts +150 -0
  106. package/src/breadboard/engine/inspector/graph/node-cache.ts +123 -0
  107. package/src/breadboard/engine/inspector/graph/node-describer-manager.ts +279 -0
  108. package/src/breadboard/engine/inspector/graph/node-type-describer-manager.ts +122 -0
  109. package/src/breadboard/engine/inspector/graph/node.ts +149 -0
  110. package/src/breadboard/engine/inspector/graph/port-cache.ts +80 -0
  111. package/src/breadboard/engine/inspector/graph/ports.ts +292 -0
  112. package/src/breadboard/engine/inspector/graph/schemas.ts +131 -0
  113. package/src/breadboard/engine/inspector/graph/virtual-node.ts +184 -0
  114. package/src/breadboard/engine/inspector/graph-store.ts +629 -0
  115. package/src/breadboard/engine/inspector/index.ts +13 -0
  116. package/src/breadboard/engine/inspector/utils.ts +20 -0
  117. package/src/breadboard/engine/loader/capability.ts +184 -0
  118. package/src/breadboard/engine/loader/index.ts +14 -0
  119. package/src/breadboard/engine/loader/loader.ts +244 -0
  120. package/src/breadboard/engine/loader/resolve-graph-urls.ts +111 -0
  121. package/src/breadboard/engine/runtime/bubble.ts +269 -0
  122. package/src/breadboard/engine/runtime/graph-based-node-handler.ts +174 -0
  123. package/src/breadboard/engine/runtime/handler.ts +166 -0
  124. package/src/breadboard/engine/runtime/harness/diagnostics.ts +22 -0
  125. package/src/breadboard/engine/runtime/harness/events.ts +217 -0
  126. package/src/breadboard/engine/runtime/harness/index.ts +14 -0
  127. package/src/breadboard/engine/runtime/harness/local.ts +48 -0
  128. package/src/breadboard/engine/runtime/harness/plan-runner.ts +759 -0
  129. package/src/breadboard/engine/runtime/index.ts +8 -0
  130. package/src/breadboard/engine/runtime/legacy.ts +28 -0
  131. package/src/breadboard/engine/runtime/run/invoke-graph.ts +79 -0
  132. package/src/breadboard/engine/runtime/run/node-invoker.ts +137 -0
  133. package/src/breadboard/engine/runtime/run/run-graph.ts +186 -0
  134. package/src/breadboard/engine/runtime/run.ts +111 -0
  135. package/src/breadboard/engine/runtime/sandbox/capabilities-manager.ts +253 -0
  136. package/src/breadboard/engine/runtime/sandbox/file-system-handler-factory.ts +53 -0
  137. package/src/breadboard/engine/runtime/sandbox/invoke-describer.ts +125 -0
  138. package/src/breadboard/engine/runtime/static/condense.ts +155 -0
  139. package/src/breadboard/engine/runtime/static/create-plan.ts +134 -0
  140. package/src/breadboard/engine/runtime/static/nodes-to-subgraph.ts +168 -0
  141. package/src/breadboard/engine/runtime/static/orchestrator.ts +664 -0
  142. package/src/breadboard/engine/runtime/static/types.ts +77 -0
  143. package/src/breadboard/engine/runtime/traversal/index.ts +58 -0
  144. package/src/breadboard/engine/runtime/traversal/iterator.ts +124 -0
  145. package/src/breadboard/engine/runtime/traversal/machine.ts +58 -0
  146. package/src/breadboard/engine/runtime/traversal/representation.ts +115 -0
  147. package/src/breadboard/engine/runtime/traversal/result.ts +72 -0
  148. package/src/breadboard/engine/runtime/traversal/state.ts +115 -0
  149. package/src/breadboard/engine/telemetry.ts +121 -0
  150. package/src/breadboard/engine/types.ts +32 -0
  151. package/src/breadboard/lit-flow-runner.test.ts +44 -0
  152. package/src/breadboard/lit-flow-runner.ts +98 -0
  153. package/src/breadboard/runner.ts +80 -0
  154. package/src/index.ts +2 -0
  155. package/src/lit-chiclet.ts +69 -0
  156. package/src/lit-flow.ts +17 -7
  157. package/src/lit-schema-node.test.ts +65 -0
  158. package/src/lit-schema-node.ts +194 -0
@@ -0,0 +1,77 @@
1
+ // @ts-nocheck
2
+ /**
3
+ * @license
4
+ * Copyright 2025 Google LLC
5
+ * SPDX-License-Identifier: Apache-2.0
6
+ */
7
+
8
+ import { NodeIdentifier, Outcome } from "@breadboard-ai/types";
9
+
10
+ /**
11
+ * Very WIP, sketching out reactive Model + Controller
12
+ * that replaces the current HarnessRunner
13
+ */
14
+ export type OrchestrationController = {
15
+ /**
16
+ * Run the graph from start to finish or the next breakpoint.
17
+ * Always restarts, resetting current state.
18
+ * Promise resolves when the run completes.
19
+ */
20
+ run(): Promise<Outcome<void>>;
21
+ /**
22
+ * Run all incomplete stages to finish or the next breakpoint.
23
+ * Promise resolves when the run completes.
24
+ */
25
+ continue(): Promise<Outcome<void>>;
26
+ /**
27
+ * Invoke the next "ready" node in the orchestration.
28
+ * Promise resolves when the node invocation completes.
29
+ * If the node reports failure, this is not an error that affects outcome.
30
+ */
31
+ stepThroughNode(): Promise<Outcome<void>>;
32
+ /**
33
+ * Step through the next incomplete stage in the orchestration.
34
+ * Promise resolves when the stage completes.
35
+ */
36
+ stepThroughStage(): Promise<Outcome<void>>;
37
+ /**
38
+ * Provides a way to manage breakpoints.
39
+ */
40
+ breakpoints: BreakpointsController;
41
+ };
42
+
43
+ export type BreakpointsController = {
44
+ /**
45
+ * All current breakpoints.
46
+ */
47
+ readonly breakpoints: ReadonlyMap<NodeIdentifier, Breakpoint>;
48
+ /**
49
+ * Creates a breakpoint. Can be called multiple times on the same node.
50
+ * @param node - the node at which to set the breakpoint
51
+ */
52
+ create(node: NodeIdentifier): void;
53
+ /**
54
+ * Removes a breakpoint. Can be called multiple times on the same node.
55
+ * @param node - the node at which to remove the breakpoint
56
+ */
57
+ delete(node: NodeIdentifier): void;
58
+ /**
59
+ * Clears all breakpoints.
60
+ */
61
+ clear(): void;
62
+ };
63
+
64
+ export type Breakpoint = {
65
+ /**
66
+ * The node at which the breakpoint is set.
67
+ */
68
+ readonly id: NodeIdentifier;
69
+ /**
70
+ * Disables the breakpoint.
71
+ */
72
+ disable(): void;
73
+ /**
74
+ * Enables the breakpoint.
75
+ */
76
+ enable(): void;
77
+ };
@@ -0,0 +1,58 @@
1
+ // @ts-nocheck
2
+ /**
3
+ * @license
4
+ * Copyright 2023 Google LLC
5
+ * SPDX-License-Identifier: Apache-2.0
6
+ */
7
+
8
+ import {
9
+ Edge,
10
+ InputValues,
11
+ NodeDescriptor,
12
+ NodeIdentifier,
13
+ } from "@breadboard-ai/types";
14
+
15
+ const requiredInputsFromEdges = (edges: Edge[]): string[] => {
16
+ return [
17
+ ...new Set(
18
+ edges
19
+ .filter((edge: Edge) => !!edge.in && !edge.optional)
20
+ .map((edge: Edge) => edge.in || "")
21
+ ),
22
+ ];
23
+ };
24
+
25
+ /**
26
+ * This class holds important parts of the graph traversal algorithm.
27
+ */
28
+ export class Traversal {
29
+ /**
30
+ * Computes the missing inputs for a node. A missing input is an input that is
31
+ * required by the node, but is not (yet) available in the current state.
32
+ * @param heads All the edges that point to the node.
33
+ * @param inputs The input values that will be passed to the node
34
+ * @param current The node that is being visited.
35
+ * @returns Array of missing input names.
36
+ */
37
+ static computeMissingInputs(
38
+ heads: Edge[],
39
+ inputs: InputValues,
40
+ current: NodeDescriptor,
41
+ start?: NodeIdentifier
42
+ ): string[] {
43
+ const isStartNode = current.id === start;
44
+ const requiredInputs: string[] = isStartNode
45
+ ? []
46
+ : requiredInputsFromEdges(heads);
47
+ const inputsWithConfiguration = new Set();
48
+ Object.keys(inputs).forEach((key) => inputsWithConfiguration.add(key));
49
+ if (current.configuration) {
50
+ Object.keys(current.configuration).forEach((key) =>
51
+ inputsWithConfiguration.add(key)
52
+ );
53
+ }
54
+ return requiredInputs.filter(
55
+ (input) => !inputsWithConfiguration.has(input)
56
+ );
57
+ }
58
+ }
@@ -0,0 +1,124 @@
1
+ // @ts-nocheck
2
+ /**
3
+ * @license
4
+ * Copyright 2023 Google LLC
5
+ * SPDX-License-Identifier: Apache-2.0
6
+ */
7
+
8
+ import type {
9
+ Edge,
10
+ ErrorCapability,
11
+ GraphRepresentation,
12
+ TraversalResult,
13
+ } from "@breadboard-ai/types";
14
+ import { Traversal } from "./index.js";
15
+ import { MachineResult } from "./result.js";
16
+
17
+ export class TraversalMachineIterator
18
+ implements AsyncIterator<TraversalResult>
19
+ {
20
+ graph: GraphRepresentation;
21
+ #current: TraversalResult;
22
+
23
+ constructor(graph: GraphRepresentation, result: TraversalResult) {
24
+ this.graph = graph;
25
+ this.#current = result;
26
+ }
27
+
28
+ async next(): Promise<IteratorResult<TraversalResult>> {
29
+ // If there are no missing inputs, let's consume the outputs
30
+ if (!this.#current.skip) {
31
+ const { inputs, descriptor } = this.#current;
32
+ let { outputs, newOpportunities } = this.#current;
33
+
34
+ // Mark inputs as used, i.e. shift inputs queues.
35
+ this.#current.state.useInputs(descriptor.id, this.#current.inputs);
36
+
37
+ if (outputs && outputs.$error) {
38
+ const $error = (
39
+ typeof outputs.$error === "string"
40
+ ? { error: new Error(outputs.$error) }
41
+ : outputs.$error
42
+ ) as ErrorCapability;
43
+ outputs.$error = {
44
+ descriptor,
45
+ ...($error as object),
46
+ ...("metadata" in outputs ? { metadata: outputs.metadata } : {}),
47
+ inputs: { ...inputs, ...$error.inputs },
48
+ };
49
+ newOpportunities = newOpportunities.filter(
50
+ (edge) => edge.out === "$error"
51
+ );
52
+ }
53
+
54
+ outputs ??= {};
55
+
56
+ // Process outputs.
57
+ this.#current.opportunities.push(...newOpportunities);
58
+ this.#current.state.wireOutputs(newOpportunities, outputs);
59
+
60
+ if (outputs.$error) {
61
+ if (newOpportunities.length === 0) {
62
+ // If the node threw an exception and it wasn't routed via $error,
63
+ // throw it again. This will cause the traversal to stop.
64
+ throw new Error(
65
+ "Uncaught exception in node handler. Catch by wiring up the $error output.",
66
+ {
67
+ cause: outputs.$error,
68
+ }
69
+ );
70
+ } else {
71
+ console.warn(
72
+ "Error in node handler, passing to the wired $error output.",
73
+ outputs.$error,
74
+ newOpportunities
75
+ );
76
+ }
77
+ }
78
+ }
79
+
80
+ // If there are no more opportunities and none are pending, we're done.
81
+ if (this.#current.opportunities.length === 0)
82
+ return { done: true, value: null };
83
+
84
+ // Now, we're ready to start the next iteration.
85
+
86
+ // Otherwise, let's pop the next opportunity from the queue.
87
+ const opportunity = this.#current.opportunities.shift() as Edge;
88
+
89
+ const { heads, nodes, tails } = this.graph;
90
+
91
+ const toNode = opportunity.to;
92
+ const currentDescriptor = nodes.get(toNode);
93
+ if (!currentDescriptor) throw new Error(`No node found for id "${toNode}"`);
94
+
95
+ const incomingEdges = heads.get(toNode) || [];
96
+ const inputs = this.#current.state.getAvailableInputs(toNode);
97
+
98
+ const missingInputs = Traversal.computeMissingInputs(
99
+ incomingEdges,
100
+ inputs,
101
+ currentDescriptor,
102
+ this.graph.start
103
+ );
104
+
105
+ const newOpportunities = tails.get(toNode) || [];
106
+ // Pour configuration values into inputs. These are effectively like
107
+ // constants.
108
+ const inputsWithConfiguration = {
109
+ ...currentDescriptor.configuration,
110
+ ...inputs,
111
+ };
112
+
113
+ this.#current = new MachineResult(
114
+ currentDescriptor,
115
+ inputsWithConfiguration,
116
+ missingInputs,
117
+ opportunity,
118
+ this.#current.opportunities,
119
+ newOpportunities,
120
+ this.#current.state
121
+ );
122
+ return { done: false, value: this.#current };
123
+ }
124
+ }
@@ -0,0 +1,58 @@
1
+ // @ts-nocheck
2
+ /**
3
+ * @license
4
+ * Copyright 2023 Google LLC
5
+ * SPDX-License-Identifier: Apache-2.0
6
+ */
7
+
8
+ import type {
9
+ GraphDescriptor,
10
+ TraversalResult,
11
+ NodeIdentifier,
12
+ GraphRepresentation,
13
+ } from "@breadboard-ai/types";
14
+ import { TraversalMachineIterator } from "./iterator.js";
15
+ import { MachineResult } from "./result.js";
16
+ import { MachineEdgeState } from "./state.js";
17
+ import { GraphRepresentationImpl } from "./representation.js";
18
+
19
+ export class TraversalMachine implements AsyncIterable<TraversalResult> {
20
+ graph: GraphRepresentation;
21
+ previousResult?: TraversalResult;
22
+
23
+ constructor(
24
+ descriptor: GraphDescriptor,
25
+ result?: TraversalResult,
26
+ start?: NodeIdentifier
27
+ ) {
28
+ this.graph = new GraphRepresentationImpl(descriptor, start);
29
+ this.previousResult = result;
30
+ }
31
+
32
+ [Symbol.asyncIterator](): AsyncIterator<TraversalResult> {
33
+ return this.start();
34
+ }
35
+
36
+ start(): TraversalMachineIterator {
37
+ if (this.previousResult)
38
+ return new TraversalMachineIterator(this.graph, this.previousResult);
39
+
40
+ const { entries } = this.graph;
41
+ if (entries.length === 0) throw new Error("No entry node found in graph.");
42
+ // Create fake edges to represent entry points.
43
+ const opportunities = entries.map((entry) => ({
44
+ from: "$entry",
45
+ to: entry,
46
+ }));
47
+ const entryResult = new MachineResult(
48
+ { id: "$empty", type: "$empty" },
49
+ {},
50
+ [],
51
+ { from: "$entry", to: entries[0] },
52
+ opportunities,
53
+ [],
54
+ new MachineEdgeState()
55
+ );
56
+ return new TraversalMachineIterator(this.graph, entryResult);
57
+ }
58
+ }
@@ -0,0 +1,115 @@
1
+ // @ts-nocheck
2
+ /**
3
+ * @license
4
+ * Copyright 2023 Google LLC
5
+ * SPDX-License-Identifier: Apache-2.0
6
+ */
7
+
8
+ import {
9
+ Edge,
10
+ GraphDescriptor,
11
+ GraphRepresentation,
12
+ NodeDescriptor,
13
+ NodeIdentifier,
14
+ } from "@breadboard-ai/types";
15
+
16
+ export class GraphRepresentationImpl implements GraphRepresentation {
17
+ start?: NodeIdentifier;
18
+ /**
19
+ * Tails: a map of all outgoing edges, keyed by node id.
20
+ */
21
+ tails: Map<NodeIdentifier, Edge[]> = new Map();
22
+
23
+ /**
24
+ * Heads: a map of all incoming edges, keyed by node id.
25
+ */
26
+ heads: Map<NodeIdentifier, Edge[]> = new Map();
27
+
28
+ /**
29
+ * Nodes: a map of all nodes, keyed by node id.
30
+ */
31
+ nodes: Map<NodeIdentifier, NodeDescriptor> = new Map();
32
+
33
+ /**
34
+ * Entries: a list of all nodes that have no incoming edges.
35
+ */
36
+ entries: NodeIdentifier[] = [];
37
+
38
+ #notInHeads(id: NodeIdentifier) {
39
+ return !this.heads.has(id) || this.heads.get(id)?.length === 0;
40
+ }
41
+
42
+ #notInTails(id: NodeIdentifier) {
43
+ return !this.tails.has(id) || this.tails.get(id)?.length === 0;
44
+ }
45
+
46
+ #findEntries(): NodeIdentifier[] {
47
+ const entries = Array.from(this.nodes.keys()).filter((node) =>
48
+ this.#notInHeads(node)
49
+ );
50
+ // If entries is empty, return empty array
51
+ if (entries.length === 0) return [];
52
+
53
+ // Now, let's separate out all standalone steps and see if maybe we only
54
+ // have standalone nodes.
55
+ const standalone: NodeIdentifier[] = [];
56
+ const connected: NodeIdentifier[] = [];
57
+ let onlyStandalone = true;
58
+ entries.forEach((node) => {
59
+ if (this.#notInTails(node)) {
60
+ standalone.push(node);
61
+ } else {
62
+ onlyStandalone = false;
63
+ connected.push(node);
64
+ }
65
+ });
66
+
67
+ // If there are no standalone nodes, return all entries as usual.
68
+ if (standalone.length === 0) return entries;
69
+
70
+ // First, let's see if we can find the starting one
71
+ const start = standalone.find(
72
+ (node) => this.nodes.get(node)!.metadata?.start
73
+ );
74
+ // If there's a standalone start node, let's return.
75
+ if (start) return [start];
76
+
77
+ if (onlyStandalone) {
78
+ // This is the situation when we have a bunch of random nodes in graph
79
+ // and they are not connected, and there's no designated start node.
80
+
81
+ // Just return the first standalone node.
82
+ return [standalone.at(0)!];
83
+ } else {
84
+ // If there are both standalone and connected nodes, we just ignore
85
+ // all standalone nodes.
86
+ return connected;
87
+ }
88
+ }
89
+
90
+ constructor(descriptor: GraphDescriptor, start?: NodeIdentifier) {
91
+ if (start) {
92
+ this.start = start;
93
+ }
94
+ this.tails = descriptor.edges.reduce((acc, edge) => {
95
+ const from = edge.from;
96
+ // eslint-disable-next-line @typescript-eslint/no-unused-expressions
97
+ acc.has(from) ? acc.get(from)?.push(edge) : acc.set(from, [edge]);
98
+ return acc;
99
+ }, new Map());
100
+
101
+ this.heads = descriptor.edges.reduce((acc, edge) => {
102
+ const to = edge.to;
103
+ // eslint-disable-next-line @typescript-eslint/no-unused-expressions
104
+ acc.has(to) ? acc.get(to)?.push(edge) : acc.set(to, [edge]);
105
+ return acc;
106
+ }, new Map());
107
+
108
+ this.nodes = descriptor.nodes.reduce((acc, node) => {
109
+ acc.set(node.id, node);
110
+ return acc;
111
+ }, new Map());
112
+
113
+ this.entries = this.#findEntries();
114
+ }
115
+ }
@@ -0,0 +1,72 @@
1
+ // @ts-nocheck
2
+ /**
3
+ * @license
4
+ * Copyright 2023 Google LLC
5
+ * SPDX-License-Identifier: Apache-2.0
6
+ */
7
+
8
+ import type {
9
+ Edge,
10
+ QueuedNodeValuesState,
11
+ InputValues,
12
+ NodeDescriptor,
13
+ OutputValues,
14
+ TraversalResult,
15
+ } from "@breadboard-ai/types";
16
+ import { MachineEdgeState } from "./state.js";
17
+
18
+ export class MachineResult implements TraversalResult {
19
+ descriptor: NodeDescriptor;
20
+ inputs: InputValues;
21
+ missingInputs: string[];
22
+ current: Edge;
23
+ opportunities: Edge[];
24
+ newOpportunities: Edge[];
25
+ state: QueuedNodeValuesState;
26
+ outputs?: OutputValues;
27
+ partialOutputs?: OutputValues;
28
+
29
+ constructor(
30
+ descriptor: NodeDescriptor,
31
+ inputs: InputValues,
32
+ missingInputs: string[],
33
+ currentOpportunity: Edge,
34
+ opportunities: Edge[],
35
+ newOpportunities: Edge[],
36
+ state: QueuedNodeValuesState,
37
+ partialOutputs?: OutputValues
38
+ ) {
39
+ this.descriptor = descriptor;
40
+ this.inputs = inputs;
41
+ this.missingInputs = missingInputs;
42
+ this.current = currentOpportunity;
43
+ this.opportunities = opportunities;
44
+ this.newOpportunities = newOpportunities;
45
+ this.state = state;
46
+ this.partialOutputs = partialOutputs;
47
+ }
48
+
49
+ /**
50
+ * `true` if the machine decided that the node should be skipped, rather than
51
+ * visited.
52
+ */
53
+ get skip(): boolean {
54
+ return this.missingInputs.length > 0;
55
+ }
56
+
57
+ static fromObject(o: TraversalResult): MachineResult {
58
+ const edgeState = new MachineEdgeState();
59
+ edgeState.constants = o.state.constants;
60
+ edgeState.state = o.state.state;
61
+ return new MachineResult(
62
+ o.descriptor,
63
+ o.inputs,
64
+ o.missingInputs,
65
+ o.current,
66
+ o.opportunities,
67
+ o.newOpportunities,
68
+ edgeState,
69
+ o.partialOutputs
70
+ );
71
+ }
72
+ }
@@ -0,0 +1,115 @@
1
+ // @ts-nocheck
2
+ /**
3
+ * @license
4
+ * Copyright 2023 Google LLC
5
+ * SPDX-License-Identifier: Apache-2.0
6
+ */
7
+
8
+ import type {
9
+ Edge,
10
+ QueuedNodeValuesState,
11
+ NodeIdentifier,
12
+ InputValues,
13
+ OutputValues,
14
+ NodeValue,
15
+ NodeValuesQueuesMap,
16
+ } from "@breadboard-ai/types";
17
+
18
+ export class MachineEdgeState implements QueuedNodeValuesState {
19
+ state: NodeValuesQueuesMap = new Map();
20
+ constants: NodeValuesQueuesMap = new Map();
21
+
22
+ #queueOutput(
23
+ map: NodeValuesQueuesMap,
24
+ node: NodeIdentifier,
25
+ key: string,
26
+ value: NodeValue
27
+ ) {
28
+ let queuesMap = map.get(node);
29
+ if (!queuesMap) {
30
+ queuesMap = new Map();
31
+ map.set(node, queuesMap);
32
+ }
33
+ let queue = queuesMap.get(key);
34
+ if (!queue) {
35
+ queue = [];
36
+ queuesMap.set(key, queue);
37
+ }
38
+ queue.push(value);
39
+ }
40
+
41
+ /**
42
+ * Processes outputs by wiring them to the destinations according
43
+ * to the supplied edges. Assumes that the outputs were generated by
44
+ * the from node.
45
+ *
46
+ * @param opportunites {Edge[]} Edges to process
47
+ * @param outputs {OutputValues} Outputs to wire
48
+ */
49
+ wireOutputs(opportunites: Edge[], outputs: OutputValues): void {
50
+ // Verify that all edges are from the same node.
51
+ if (
52
+ opportunites.filter(
53
+ (opportunity) => opportunity.from != opportunites[0].from
54
+ ).length !== 0
55
+ )
56
+ throw new Error("All opportunities must be from the same node");
57
+
58
+ opportunites.forEach((opportunity) => {
59
+ const to = opportunity.to;
60
+ const out = opportunity.out;
61
+ const queuesMap = opportunity.constant ? this.constants : this.state;
62
+ if (!out) return;
63
+ if (out === "*") {
64
+ for (const key in outputs) {
65
+ const output = outputs[key];
66
+ if (output != null && output != undefined)
67
+ this.#queueOutput(queuesMap, to, key, output);
68
+ }
69
+ } else if (opportunity.in) {
70
+ const output = outputs[out];
71
+ // TODO: Check and document why we don't allow that
72
+ if (output != null && output != undefined)
73
+ this.#queueOutput(queuesMap, to, opportunity.in, output);
74
+ }
75
+ });
76
+ }
77
+
78
+ /**
79
+ * Returns the available inputs for a given node.
80
+ *
81
+ * @param nodeId {NodeIdentifier} The node to get the inputs for.
82
+ * @returns {InputValues} The available inputs.
83
+ */
84
+ getAvailableInputs(nodeId: NodeIdentifier): InputValues {
85
+ const result: InputValues = {};
86
+
87
+ for (const queuesMap of [
88
+ this.constants.get(nodeId), // Constants are overwritten by state.
89
+ this.state.get(nodeId),
90
+ ]) {
91
+ if (!queuesMap) continue;
92
+ for (const [key, queue] of queuesMap.entries()) {
93
+ if (queue.length === 0) continue;
94
+ result[key] = queue[0];
95
+ }
96
+ }
97
+ return result;
98
+ }
99
+
100
+ /**
101
+ * Shifts inputs from the queues. Leaves constants as is.
102
+ *
103
+ * @param nodeId {NodeIdentifier} The node to shift the inputs for.
104
+ * @param inputs {InputValues} The inputs that are used.
105
+ */
106
+ useInputs(nodeId: NodeIdentifier, inputs: InputValues): void {
107
+ const queuesMap = this.state.get(nodeId);
108
+ if (!queuesMap) return;
109
+ for (const key in inputs) {
110
+ const queue = queuesMap.get(key);
111
+ if (!queue) continue;
112
+ queue.shift();
113
+ }
114
+ }
115
+ }