@ghchinoy/litflow 0.2.7 → 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.
- package/CHANGELOG.md +59 -0
- package/dist/breadboard/data/common.d.ts +35 -0
- package/dist/breadboard/engine/loader/capability.d.ts +21 -0
- package/dist/breadboard/engine/loader/loader.d.ts +29 -0
- package/dist/breadboard/engine/loader/resolve-graph-urls.d.ts +16 -0
- package/dist/breadboard/engine/runtime/bubble.d.ts +23 -0
- package/dist/breadboard/engine/runtime/graph-based-node-handler.d.ts +16 -0
- package/dist/breadboard/engine/runtime/handler.d.ts +27 -0
- package/dist/breadboard/engine/runtime/harness/events.d.ts +145 -0
- package/dist/breadboard/engine/runtime/harness/local.d.ts +10 -0
- package/dist/breadboard/engine/runtime/harness/plan-runner.d.ts +25 -0
- package/dist/breadboard/engine/runtime/run/invoke-graph.d.ts +12 -0
- package/dist/breadboard/engine/runtime/run/node-invoker.d.ts +12 -0
- package/dist/breadboard/engine/runtime/run/run-graph.d.ts +12 -0
- package/dist/breadboard/engine/runtime/run.d.ts +29 -0
- package/dist/breadboard/engine/runtime/sandbox/capabilities-manager.d.ts +15 -0
- package/dist/breadboard/engine/runtime/sandbox/file-system-handler-factory.d.ts +15 -0
- package/dist/breadboard/engine/runtime/sandbox/invoke-describer.d.ts +10 -0
- package/dist/breadboard/engine/runtime/static/create-plan.d.ts +14 -0
- package/dist/breadboard/engine/runtime/static/orchestrator.d.ts +72 -0
- package/dist/breadboard/engine/runtime/traversal/index.d.ts +20 -0
- package/dist/breadboard/engine/runtime/traversal/iterator.d.ts +12 -0
- package/dist/breadboard/engine/runtime/traversal/machine.d.ts +14 -0
- package/dist/breadboard/engine/runtime/traversal/representation.d.ts +27 -0
- package/dist/breadboard/engine/runtime/traversal/result.d.ts +24 -0
- package/dist/breadboard/engine/runtime/traversal/state.d.ts +34 -0
- package/dist/breadboard/lit-flow-runner.d.ts +13 -0
- package/dist/breadboard/lit-flow-runner.test.d.ts +1 -0
- package/dist/breadboard/runner.d.ts +13 -0
- package/dist/index.d.ts +2 -0
- package/dist/lit-chiclet.d.ts +9 -0
- package/dist/lit-schema-node.d.ts +13 -0
- package/dist/lit-schema-node.test.d.ts +1 -0
- package/dist/litflow.js +708 -442
- package/dist/litflow.js.map +1 -1
- package/package.json +18 -4
- package/src/breadboard/data/common.ts +450 -0
- package/src/breadboard/data/file-system.ts +54 -0
- package/src/breadboard/data/inline-all-content.ts +126 -0
- package/src/breadboard/data/recent-boards.ts +118 -0
- package/src/breadboard/data/save-outputs-as-file.ts +104 -0
- package/src/breadboard/engine/add-run-module.ts +168 -0
- package/src/breadboard/engine/editor/blank.ts +65 -0
- package/src/breadboard/engine/editor/edge.ts +27 -0
- package/src/breadboard/engine/editor/events.ts +64 -0
- package/src/breadboard/engine/editor/graph.ts +383 -0
- package/src/breadboard/engine/editor/history.ts +98 -0
- package/src/breadboard/engine/editor/index.ts +8 -0
- package/src/breadboard/engine/editor/operations/add-asset.ts +45 -0
- package/src/breadboard/engine/editor/operations/add-edge.ts +142 -0
- package/src/breadboard/engine/editor/operations/add-graph.ts +47 -0
- package/src/breadboard/engine/editor/operations/add-module.ts +64 -0
- package/src/breadboard/engine/editor/operations/add-node.ts +86 -0
- package/src/breadboard/engine/editor/operations/change-asset-metadata.ts +70 -0
- package/src/breadboard/engine/editor/operations/change-configuration.ts +82 -0
- package/src/breadboard/engine/editor/operations/change-edge-metadata.ts +58 -0
- package/src/breadboard/engine/editor/operations/change-edge.ts +111 -0
- package/src/breadboard/engine/editor/operations/change-graph-metadata.ts +52 -0
- package/src/breadboard/engine/editor/operations/change-metadata.ts +92 -0
- package/src/breadboard/engine/editor/operations/change-module.ts +64 -0
- package/src/breadboard/engine/editor/operations/error.ts +21 -0
- package/src/breadboard/engine/editor/operations/remove-asset.ts +48 -0
- package/src/breadboard/engine/editor/operations/remove-edge.ts +89 -0
- package/src/breadboard/engine/editor/operations/remove-graph.ts +49 -0
- package/src/breadboard/engine/editor/operations/remove-integration.ts +54 -0
- package/src/breadboard/engine/editor/operations/remove-module.ts +69 -0
- package/src/breadboard/engine/editor/operations/remove-node.ts +86 -0
- package/src/breadboard/engine/editor/operations/replace-graph.ts +52 -0
- package/src/breadboard/engine/editor/operations/toggle-export.ts +72 -0
- package/src/breadboard/engine/editor/operations/upsert-integration.ts +43 -0
- package/src/breadboard/engine/editor/selection.ts +58 -0
- package/src/breadboard/engine/editor/transforms/configure-sidewire.ts +73 -0
- package/src/breadboard/engine/editor/transforms/isolate-selection.ts +54 -0
- package/src/breadboard/engine/editor/transforms/merge-graph.ts +58 -0
- package/src/breadboard/engine/editor/transforms/move-to-graph.ts +102 -0
- package/src/breadboard/engine/editor/transforms/move-to-new-graph.ts +72 -0
- package/src/breadboard/engine/editor/transforms/sidewire-to-new-graph.ts +82 -0
- package/src/breadboard/engine/file-system/blob-transform.ts +44 -0
- package/src/breadboard/engine/file-system/composed-peristent-backend.ts +140 -0
- package/src/breadboard/engine/file-system/ephemeral-blob-store.ts +46 -0
- package/src/breadboard/engine/file-system/in-memory-blob-store.ts +87 -0
- package/src/breadboard/engine/file-system/index.ts +723 -0
- package/src/breadboard/engine/file-system/partial-persistent-backend.ts +109 -0
- package/src/breadboard/engine/file-system/path.ts +125 -0
- package/src/breadboard/engine/file-system/persistent-file.ts +66 -0
- package/src/breadboard/engine/file-system/readable-stream-file.ts +61 -0
- package/src/breadboard/engine/file-system/stub-file-system.ts +47 -0
- package/src/breadboard/engine/file-system/utils.ts +40 -0
- package/src/breadboard/engine/inspector/graph/bubbled-node.ts +162 -0
- package/src/breadboard/engine/inspector/graph/describe-cache.ts +78 -0
- package/src/breadboard/engine/inspector/graph/describe-type-cache.ts +48 -0
- package/src/breadboard/engine/inspector/graph/edge-cache.ts +118 -0
- package/src/breadboard/engine/inspector/graph/edge.ts +133 -0
- package/src/breadboard/engine/inspector/graph/event.ts +35 -0
- package/src/breadboard/engine/inspector/graph/exports-describer.ts +45 -0
- package/src/breadboard/engine/inspector/graph/graph-cache.ts +54 -0
- package/src/breadboard/engine/inspector/graph/graph-describer-manager.ts +338 -0
- package/src/breadboard/engine/inspector/graph/graph-descriptor-handle.ts +73 -0
- package/src/breadboard/engine/inspector/graph/graph-node-type.ts +111 -0
- package/src/breadboard/engine/inspector/graph/graph-queries.ts +256 -0
- package/src/breadboard/engine/inspector/graph/graph.ts +163 -0
- package/src/breadboard/engine/inspector/graph/inspectable-asset.ts +36 -0
- package/src/breadboard/engine/inspector/graph/kits.ts +208 -0
- package/src/breadboard/engine/inspector/graph/module.ts +69 -0
- package/src/breadboard/engine/inspector/graph/mutable-graph.ts +150 -0
- package/src/breadboard/engine/inspector/graph/node-cache.ts +123 -0
- package/src/breadboard/engine/inspector/graph/node-describer-manager.ts +279 -0
- package/src/breadboard/engine/inspector/graph/node-type-describer-manager.ts +122 -0
- package/src/breadboard/engine/inspector/graph/node.ts +149 -0
- package/src/breadboard/engine/inspector/graph/port-cache.ts +80 -0
- package/src/breadboard/engine/inspector/graph/ports.ts +292 -0
- package/src/breadboard/engine/inspector/graph/schemas.ts +131 -0
- package/src/breadboard/engine/inspector/graph/virtual-node.ts +184 -0
- package/src/breadboard/engine/inspector/graph-store.ts +629 -0
- package/src/breadboard/engine/inspector/index.ts +13 -0
- package/src/breadboard/engine/inspector/utils.ts +20 -0
- package/src/breadboard/engine/loader/capability.ts +184 -0
- package/src/breadboard/engine/loader/index.ts +14 -0
- package/src/breadboard/engine/loader/loader.ts +244 -0
- package/src/breadboard/engine/loader/resolve-graph-urls.ts +111 -0
- package/src/breadboard/engine/runtime/bubble.ts +269 -0
- package/src/breadboard/engine/runtime/graph-based-node-handler.ts +174 -0
- package/src/breadboard/engine/runtime/handler.ts +166 -0
- package/src/breadboard/engine/runtime/harness/diagnostics.ts +22 -0
- package/src/breadboard/engine/runtime/harness/events.ts +217 -0
- package/src/breadboard/engine/runtime/harness/index.ts +14 -0
- package/src/breadboard/engine/runtime/harness/local.ts +48 -0
- package/src/breadboard/engine/runtime/harness/plan-runner.ts +759 -0
- package/src/breadboard/engine/runtime/index.ts +8 -0
- package/src/breadboard/engine/runtime/legacy.ts +28 -0
- package/src/breadboard/engine/runtime/run/invoke-graph.ts +79 -0
- package/src/breadboard/engine/runtime/run/node-invoker.ts +137 -0
- package/src/breadboard/engine/runtime/run/run-graph.ts +186 -0
- package/src/breadboard/engine/runtime/run.ts +111 -0
- package/src/breadboard/engine/runtime/sandbox/capabilities-manager.ts +253 -0
- package/src/breadboard/engine/runtime/sandbox/file-system-handler-factory.ts +53 -0
- package/src/breadboard/engine/runtime/sandbox/invoke-describer.ts +125 -0
- package/src/breadboard/engine/runtime/static/condense.ts +155 -0
- package/src/breadboard/engine/runtime/static/create-plan.ts +134 -0
- package/src/breadboard/engine/runtime/static/nodes-to-subgraph.ts +168 -0
- package/src/breadboard/engine/runtime/static/orchestrator.ts +664 -0
- package/src/breadboard/engine/runtime/static/types.ts +77 -0
- package/src/breadboard/engine/runtime/traversal/index.ts +58 -0
- package/src/breadboard/engine/runtime/traversal/iterator.ts +124 -0
- package/src/breadboard/engine/runtime/traversal/machine.ts +58 -0
- package/src/breadboard/engine/runtime/traversal/representation.ts +115 -0
- package/src/breadboard/engine/runtime/traversal/result.ts +72 -0
- package/src/breadboard/engine/runtime/traversal/state.ts +115 -0
- package/src/breadboard/engine/telemetry.ts +121 -0
- package/src/breadboard/engine/types.ts +32 -0
- package/src/breadboard/lit-flow-runner.test.ts +44 -0
- package/src/breadboard/lit-flow-runner.ts +98 -0
- package/src/breadboard/runner.ts +80 -0
- package/src/index.ts +2 -0
- package/src/lit-chiclet.ts +69 -0
- package/src/lit-flow.ts +17 -7
- package/src/lit-schema-node.test.ts +65 -0
- package/src/lit-schema-node.ts +194 -0
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
/**
|
|
3
|
+
* @license
|
|
4
|
+
* Copyright 2023 Google LLC
|
|
5
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type {
|
|
9
|
+
GraphInlineMetadata,
|
|
10
|
+
InputValues,
|
|
11
|
+
NodeDescriptor,
|
|
12
|
+
NodeHandlerContext,
|
|
13
|
+
NodeValue,
|
|
14
|
+
OutputValues,
|
|
15
|
+
RunArguments,
|
|
16
|
+
Schema,
|
|
17
|
+
TraversalResult,
|
|
18
|
+
} from "@breadboard-ai/types";
|
|
19
|
+
import { InputStageResult, OutputStageResult, RunResult } from "./run.js";
|
|
20
|
+
|
|
21
|
+
export const createErrorMessage = (
|
|
22
|
+
inputName: string | string[],
|
|
23
|
+
metadata: GraphInlineMetadata = {},
|
|
24
|
+
required: boolean
|
|
25
|
+
): string => {
|
|
26
|
+
const boardTitle = metadata.title ?? metadata?.url;
|
|
27
|
+
const inputNames = typeof inputName === "string" ? [inputName] : inputName;
|
|
28
|
+
const requiredText = required ? "required " : "";
|
|
29
|
+
return `Missing ${requiredText}input ${inputNames.map((name) => `"${name}"`).join(", ")}${
|
|
30
|
+
boardTitle ? ` for board "${boardTitle}".` : "."
|
|
31
|
+
}`;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export const bubbleUpInputsIfNeeded = async (
|
|
35
|
+
metadata: GraphInlineMetadata,
|
|
36
|
+
context: NodeHandlerContext,
|
|
37
|
+
descriptor: NodeDescriptor,
|
|
38
|
+
result: TraversalResult,
|
|
39
|
+
path: number[]
|
|
40
|
+
): Promise<void> => {
|
|
41
|
+
// If we have no way to bubble up inputs, we just return and not
|
|
42
|
+
// enforce required inputs.
|
|
43
|
+
if (!context.requestInput) return;
|
|
44
|
+
|
|
45
|
+
const outputs = result.outputs ?? {};
|
|
46
|
+
const reader = new InputSchemaReader(outputs, result.inputs, path);
|
|
47
|
+
result.outputs = await reader.read(
|
|
48
|
+
createBubbleHandler(metadata, context, descriptor)
|
|
49
|
+
);
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export const createBubbleHandler = (
|
|
53
|
+
metadata: GraphInlineMetadata,
|
|
54
|
+
context: NodeHandlerContext,
|
|
55
|
+
descriptor: NodeDescriptor
|
|
56
|
+
) => {
|
|
57
|
+
return (async (propertiesSchema, path) => {
|
|
58
|
+
const entries = Object.entries(propertiesSchema.properties || {});
|
|
59
|
+
const defaultOutputs: OutputValues = {};
|
|
60
|
+
const propertiesToRequest: [string, Schema][] = [];
|
|
61
|
+
// Pre-process the entries and prepare to request input.
|
|
62
|
+
for (const [name, schema] of entries) {
|
|
63
|
+
const required = propertiesSchema.required?.includes(name) ?? false;
|
|
64
|
+
|
|
65
|
+
if (required) {
|
|
66
|
+
throw new Error(createErrorMessage(name, metadata, required));
|
|
67
|
+
}
|
|
68
|
+
if (schema.default !== undefined) {
|
|
69
|
+
if ("type" in schema && schema.type !== "string") {
|
|
70
|
+
defaultOutputs[name] = JSON.parse(schema.default);
|
|
71
|
+
} else {
|
|
72
|
+
defaultOutputs[name] = schema.default;
|
|
73
|
+
}
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
propertiesToRequest.push([name, schema]);
|
|
77
|
+
}
|
|
78
|
+
// Exit early if we already have all properties.
|
|
79
|
+
if (propertiesToRequest.length === 0) {
|
|
80
|
+
return defaultOutputs;
|
|
81
|
+
}
|
|
82
|
+
// Request properties that did not have default values.
|
|
83
|
+
const inputRequestSchema: Schema = {
|
|
84
|
+
properties: Object.fromEntries(propertiesToRequest),
|
|
85
|
+
};
|
|
86
|
+
const outputs = await context.requestInput?.(
|
|
87
|
+
inputRequestSchema,
|
|
88
|
+
descriptor,
|
|
89
|
+
path
|
|
90
|
+
);
|
|
91
|
+
// If the run was aborted, let's bail
|
|
92
|
+
if (context?.signal?.aborted) {
|
|
93
|
+
throw context.signal.throwIfAborted();
|
|
94
|
+
}
|
|
95
|
+
// Finally, let's make sure we have all values and if not, throw an error.
|
|
96
|
+
if (!outputs || Object.keys(outputs).length === 0) {
|
|
97
|
+
throw new Error(
|
|
98
|
+
createErrorMessage(
|
|
99
|
+
propertiesToRequest.map(([name]) => name),
|
|
100
|
+
metadata,
|
|
101
|
+
false
|
|
102
|
+
)
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
return { ...defaultOutputs, ...outputs };
|
|
106
|
+
}) satisfies InputSchemaHandler;
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
export type InputSchemaHandler = (
|
|
110
|
+
schema: Schema,
|
|
111
|
+
path: number[]
|
|
112
|
+
) => Promise<OutputValues>;
|
|
113
|
+
|
|
114
|
+
export class InputSchemaReader {
|
|
115
|
+
#currentOutputs: OutputValues;
|
|
116
|
+
#inputs: InputValues;
|
|
117
|
+
#path: number[];
|
|
118
|
+
|
|
119
|
+
constructor(
|
|
120
|
+
currentOutputs: OutputValues,
|
|
121
|
+
inputs: InputValues,
|
|
122
|
+
path: number[]
|
|
123
|
+
) {
|
|
124
|
+
this.#currentOutputs = currentOutputs;
|
|
125
|
+
this.#inputs = inputs;
|
|
126
|
+
this.#path = path;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
async read(handler: InputSchemaHandler): Promise<OutputValues> {
|
|
130
|
+
if (!("schema" in this.#inputs)) return this.#currentOutputs;
|
|
131
|
+
|
|
132
|
+
const schema = this.#inputs.schema as Schema;
|
|
133
|
+
|
|
134
|
+
if (!schema.properties) return this.#currentOutputs;
|
|
135
|
+
|
|
136
|
+
const unfulfilled = structuredClone(schema);
|
|
137
|
+
for (const name of Object.keys(schema.properties)) {
|
|
138
|
+
if (name in this.#currentOutputs) {
|
|
139
|
+
delete unfulfilled.properties?.[name];
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const willAsk = Object.keys(unfulfilled.properties || {}).length > 0;
|
|
144
|
+
|
|
145
|
+
const newOutputs = willAsk ? await handler(unfulfilled, this.#path) : {};
|
|
146
|
+
|
|
147
|
+
return { ...this.#currentOutputs, ...newOutputs };
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export class RequestedInputsManager {
|
|
152
|
+
#context: NodeHandlerContext;
|
|
153
|
+
#cache: Map<string, NodeValue> = new Map();
|
|
154
|
+
|
|
155
|
+
constructor(args: RunArguments) {
|
|
156
|
+
const { inputs, ...context } = args;
|
|
157
|
+
this.#context = context;
|
|
158
|
+
this.#cache = new Map(inputs ? Object.entries(inputs) : []);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
createHandler(
|
|
162
|
+
next: (result: RunResult) => Promise<void>,
|
|
163
|
+
result: TraversalResult
|
|
164
|
+
): NodeHandlerContext["requestInput"] {
|
|
165
|
+
return async (schema: Schema, node: NodeDescriptor, path: number[]) => {
|
|
166
|
+
// Retrieve all cached values
|
|
167
|
+
const propertiesToRequest = Object.entries(schema.properties || {});
|
|
168
|
+
const cachedValues: OutputValues = {};
|
|
169
|
+
const uncachedProperties = propertiesToRequest.filter(([name]) => {
|
|
170
|
+
const cachedValue = this.#cache.get(name);
|
|
171
|
+
if (cachedValue !== undefined) {
|
|
172
|
+
cachedValues[name] = cachedValue;
|
|
173
|
+
return false;
|
|
174
|
+
}
|
|
175
|
+
return true;
|
|
176
|
+
});
|
|
177
|
+
// Early return when all properties are cached
|
|
178
|
+
if (uncachedProperties.length === 0) return cachedValues;
|
|
179
|
+
|
|
180
|
+
const configuration = node.configuration?.schema
|
|
181
|
+
? {
|
|
182
|
+
configuration: { schema: node.configuration.schema },
|
|
183
|
+
}
|
|
184
|
+
: {};
|
|
185
|
+
const descriptor = { id: node.id, type: node.type, ...configuration };
|
|
186
|
+
const requestInputResult = {
|
|
187
|
+
...result,
|
|
188
|
+
descriptor,
|
|
189
|
+
inputs: {
|
|
190
|
+
schema: {
|
|
191
|
+
type: "object",
|
|
192
|
+
properties: Object.fromEntries(uncachedProperties),
|
|
193
|
+
} satisfies Schema,
|
|
194
|
+
},
|
|
195
|
+
};
|
|
196
|
+
await next(new InputStageResult(requestInputResult, -1, path));
|
|
197
|
+
const outputs = requestInputResult.outputs;
|
|
198
|
+
const requestedProperties = schema.properties || {};
|
|
199
|
+
const remainingProperties = outputs
|
|
200
|
+
? Object.fromEntries(
|
|
201
|
+
Object.entries(requestedProperties).filter(([name]) => {
|
|
202
|
+
return !(name in outputs);
|
|
203
|
+
})
|
|
204
|
+
)
|
|
205
|
+
: requestedProperties;
|
|
206
|
+
if (Object.keys(remainingProperties).length === 0) {
|
|
207
|
+
return outputs;
|
|
208
|
+
}
|
|
209
|
+
// Bubble up: request outer context to request input
|
|
210
|
+
const bubbledOutputs: OutputValues =
|
|
211
|
+
(await this.#context.requestInput?.(
|
|
212
|
+
{ properties: remainingProperties },
|
|
213
|
+
descriptor,
|
|
214
|
+
path
|
|
215
|
+
)) || {};
|
|
216
|
+
// Cache all non-transient properties.
|
|
217
|
+
for (const [name, propertySchema] of uncachedProperties) {
|
|
218
|
+
if (!isTransient(propertySchema)) {
|
|
219
|
+
const value = bubbledOutputs[name];
|
|
220
|
+
if (value) {
|
|
221
|
+
this.#cache.set(name, bubbledOutputs[name]);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
return { ...outputs, ...bubbledOutputs };
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
function isTransient(schema: Schema): boolean {
|
|
231
|
+
return schema.behavior?.includes("transient") ?? false;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
export const bubbleUpOutputsIfNeeded = async (
|
|
235
|
+
outputs: OutputValues,
|
|
236
|
+
descriptor: NodeDescriptor,
|
|
237
|
+
context: NodeHandlerContext,
|
|
238
|
+
path: number[]
|
|
239
|
+
): Promise<boolean> => {
|
|
240
|
+
if (!context.provideOutput) return false;
|
|
241
|
+
const schema = descriptor.configuration?.schema as Schema;
|
|
242
|
+
const shouldBubble = schema?.behavior?.includes("bubble");
|
|
243
|
+
if (!shouldBubble) return false;
|
|
244
|
+
|
|
245
|
+
await context.provideOutput(outputs, descriptor, path);
|
|
246
|
+
return true;
|
|
247
|
+
};
|
|
248
|
+
|
|
249
|
+
export const createOutputProvider = (
|
|
250
|
+
next: (result: RunResult) => Promise<void>,
|
|
251
|
+
result: TraversalResult,
|
|
252
|
+
context: NodeHandlerContext
|
|
253
|
+
) => {
|
|
254
|
+
if (context.provideOutput) {
|
|
255
|
+
return context.provideOutput;
|
|
256
|
+
}
|
|
257
|
+
return async (
|
|
258
|
+
outputs: OutputValues,
|
|
259
|
+
descriptor: NodeDescriptor,
|
|
260
|
+
path: number[]
|
|
261
|
+
) => {
|
|
262
|
+
const provideOutputResult = {
|
|
263
|
+
...result,
|
|
264
|
+
descriptor,
|
|
265
|
+
inputs: outputs,
|
|
266
|
+
};
|
|
267
|
+
await next(new OutputStageResult(provideOutputResult, -1, path));
|
|
268
|
+
};
|
|
269
|
+
};
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
/**
|
|
3
|
+
* @license
|
|
4
|
+
* Copyright 2024 Google LLC
|
|
5
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
GraphToRun,
|
|
10
|
+
InputValues,
|
|
11
|
+
MutableGraph,
|
|
12
|
+
NodeDescriberContext,
|
|
13
|
+
NodeDescriberResult,
|
|
14
|
+
NodeHandlerContext,
|
|
15
|
+
NodeHandlerMetadata,
|
|
16
|
+
NodeHandlerObject,
|
|
17
|
+
NodeTypeIdentifier,
|
|
18
|
+
Schema,
|
|
19
|
+
} from "@breadboard-ai/types";
|
|
20
|
+
import { emptyDescriberResult, filterEmptyValues } from "@breadboard-ai/utils";
|
|
21
|
+
import { invokeGraph } from "./run/invoke-graph.js";
|
|
22
|
+
import { CapabilitiesManagerImpl } from "./sandbox/capabilities-manager.js";
|
|
23
|
+
import { invokeDescriber } from "./sandbox/invoke-describer.js";
|
|
24
|
+
|
|
25
|
+
export {
|
|
26
|
+
describerResultToNodeHandlerMetadata,
|
|
27
|
+
GraphBasedNodeHandler,
|
|
28
|
+
toNodeHandlerMetadata,
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
class GraphBasedNodeHandler implements NodeHandlerObject {
|
|
32
|
+
#graph: GraphToRun;
|
|
33
|
+
#type: NodeTypeIdentifier;
|
|
34
|
+
|
|
35
|
+
constructor(graph: GraphToRun, type: NodeTypeIdentifier) {
|
|
36
|
+
this.#graph = graph;
|
|
37
|
+
this.#type = type;
|
|
38
|
+
this.invoke = this.invoke.bind(this);
|
|
39
|
+
this.describe = this.describe.bind(this);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async invoke(inputs: InputValues, context: NodeHandlerContext) {
|
|
43
|
+
const base = context.board?.url && new URL(context.board?.url);
|
|
44
|
+
const invocationContext = base
|
|
45
|
+
? {
|
|
46
|
+
...context,
|
|
47
|
+
base,
|
|
48
|
+
}
|
|
49
|
+
: { ...context };
|
|
50
|
+
|
|
51
|
+
return await invokeGraph(this.#graph, inputs, invocationContext);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async describe(
|
|
55
|
+
inputs?: InputValues,
|
|
56
|
+
inputSchema?: Schema,
|
|
57
|
+
outputSchema?: Schema,
|
|
58
|
+
context?: NodeDescriberContext
|
|
59
|
+
) {
|
|
60
|
+
if (!context) {
|
|
61
|
+
return { inputSchema: {}, outputSchema: {} };
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const graphStore = context?.graphStore;
|
|
65
|
+
if (!graphStore) {
|
|
66
|
+
return emptyDescriberResult();
|
|
67
|
+
}
|
|
68
|
+
const url = this.#graph.graph.url;
|
|
69
|
+
let mutable: MutableGraph;
|
|
70
|
+
if (url) {
|
|
71
|
+
// In the most common case, just use the URL of the graph.
|
|
72
|
+
const adding = graphStore.addByURL(url, [], context);
|
|
73
|
+
mutable = adding.mutable;
|
|
74
|
+
} else {
|
|
75
|
+
const adding = graphStore.addByDescriptor(this.#graph.graph);
|
|
76
|
+
if (!adding.success) {
|
|
77
|
+
return emptyDescriberResult();
|
|
78
|
+
}
|
|
79
|
+
mutable = graphStore.get(adding.result)!;
|
|
80
|
+
}
|
|
81
|
+
mutable = await graphStore.getLatest(mutable);
|
|
82
|
+
if (this.#graph.moduleId) {
|
|
83
|
+
const moduleId = this.#graph.moduleId;
|
|
84
|
+
const graph = this.#graph.graph;
|
|
85
|
+
const sandbox = context.graphStore?.sandbox;
|
|
86
|
+
if (!sandbox) {
|
|
87
|
+
console.warn("Sandbox was not supplied to describe node type");
|
|
88
|
+
return emptyDescriberResult();
|
|
89
|
+
}
|
|
90
|
+
const result = await invokeDescriber(
|
|
91
|
+
context,
|
|
92
|
+
moduleId,
|
|
93
|
+
mutable,
|
|
94
|
+
graph,
|
|
95
|
+
inputs || {},
|
|
96
|
+
inputSchema,
|
|
97
|
+
outputSchema,
|
|
98
|
+
new CapabilitiesManagerImpl(context),
|
|
99
|
+
context.asType || false
|
|
100
|
+
);
|
|
101
|
+
if (!result) {
|
|
102
|
+
return emptyDescriberResult();
|
|
103
|
+
}
|
|
104
|
+
return result;
|
|
105
|
+
} else {
|
|
106
|
+
const inspectableGraph = graphStore.inspect(
|
|
107
|
+
mutable.id,
|
|
108
|
+
this.#graph.subGraphId || ""
|
|
109
|
+
);
|
|
110
|
+
if (!inspectableGraph) {
|
|
111
|
+
return emptyDescriberResult();
|
|
112
|
+
}
|
|
113
|
+
const result = await inspectableGraph.describe(inputs, context);
|
|
114
|
+
return result;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
get metadata() {
|
|
119
|
+
return toNodeHandlerMetadata(this.#graph, this.#type, false);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function describerResultToNodeHandlerMetadata(
|
|
124
|
+
result: NodeDescriberResult,
|
|
125
|
+
updating: boolean
|
|
126
|
+
): NodeHandlerMetadata {
|
|
127
|
+
return filterEmptyValues({
|
|
128
|
+
title: result.title,
|
|
129
|
+
description: result.description,
|
|
130
|
+
url: result.url,
|
|
131
|
+
icon: result.metadata?.icon,
|
|
132
|
+
help: result.metadata?.help,
|
|
133
|
+
updating,
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function toNodeHandlerMetadata(
|
|
138
|
+
graphToRun: GraphToRun,
|
|
139
|
+
url: NodeTypeIdentifier,
|
|
140
|
+
updating: boolean
|
|
141
|
+
): NodeHandlerMetadata | undefined {
|
|
142
|
+
const graph = graphToRun.graph;
|
|
143
|
+
if (graphToRun.moduleId) {
|
|
144
|
+
const module = graph.modules?.[graphToRun.moduleId];
|
|
145
|
+
if (!module) return undefined;
|
|
146
|
+
const {
|
|
147
|
+
title = graphToRun.moduleId,
|
|
148
|
+
description,
|
|
149
|
+
icon,
|
|
150
|
+
help,
|
|
151
|
+
} = module.metadata || {};
|
|
152
|
+
return filterEmptyValues({ title, description, url, icon, help, updating });
|
|
153
|
+
} else if (graphToRun.subGraphId) {
|
|
154
|
+
const descriptor = graph.graphs?.[graphToRun.subGraphId];
|
|
155
|
+
if (!descriptor) return undefined;
|
|
156
|
+
return filterEmptyValues({
|
|
157
|
+
title: descriptor.title,
|
|
158
|
+
description: descriptor.description,
|
|
159
|
+
url,
|
|
160
|
+
icon: descriptor.metadata?.icon,
|
|
161
|
+
help: descriptor.metadata?.help,
|
|
162
|
+
updating,
|
|
163
|
+
});
|
|
164
|
+
} else {
|
|
165
|
+
return filterEmptyValues({
|
|
166
|
+
title: graph.title,
|
|
167
|
+
description: graph.description,
|
|
168
|
+
url: graph.url,
|
|
169
|
+
icon: graph.metadata?.icon,
|
|
170
|
+
help: graph.metadata?.help,
|
|
171
|
+
updating,
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
/**
|
|
3
|
+
* @license
|
|
4
|
+
* Copyright 2023 Google LLC
|
|
5
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type {
|
|
9
|
+
InputValues,
|
|
10
|
+
Kit,
|
|
11
|
+
MutableGraph,
|
|
12
|
+
NodeHandler,
|
|
13
|
+
NodeHandlerContext,
|
|
14
|
+
NodeHandlerFunction,
|
|
15
|
+
NodeHandlerObject,
|
|
16
|
+
NodeHandlers,
|
|
17
|
+
NodeTypeIdentifier,
|
|
18
|
+
OutputValues,
|
|
19
|
+
} from "@breadboard-ai/types";
|
|
20
|
+
import { graphUrlLike } from "@breadboard-ai/utils";
|
|
21
|
+
import { GraphBasedNodeHandler } from "./graph-based-node-handler.js";
|
|
22
|
+
import { getGraphUrl } from "../loader/loader.js";
|
|
23
|
+
|
|
24
|
+
// TODO: Deduplicate.
|
|
25
|
+
function contextFromMutableGraph(mutable: MutableGraph): NodeHandlerContext {
|
|
26
|
+
const store = mutable.store;
|
|
27
|
+
return {
|
|
28
|
+
kits: [...store.kits],
|
|
29
|
+
loader: store.loader,
|
|
30
|
+
sandbox: store.sandbox,
|
|
31
|
+
graphStore: store,
|
|
32
|
+
outerGraph: mutable.graph,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const getHandlerFunction = (handler: NodeHandler): NodeHandlerFunction => {
|
|
37
|
+
if ("invoke" in handler && handler.invoke) return handler.invoke;
|
|
38
|
+
if (handler instanceof Function) return handler;
|
|
39
|
+
throw new Error("Invalid handler");
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export const callHandler = async (
|
|
43
|
+
handler: NodeHandler,
|
|
44
|
+
inputs: InputValues,
|
|
45
|
+
context: NodeHandlerContext
|
|
46
|
+
): Promise<OutputValues | void> => {
|
|
47
|
+
// if (handler instanceof Function) return handler(inputs, context);
|
|
48
|
+
// if (handler.invoke) return handler.invoke(inputs, context);
|
|
49
|
+
const handlerFunction = getHandlerFunction(handler);
|
|
50
|
+
return new Promise((resolve) => {
|
|
51
|
+
handlerFunction(inputs, context)
|
|
52
|
+
.then(resolve)
|
|
53
|
+
.catch((error) => {
|
|
54
|
+
resolve({ $error: { error } });
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
export const handlersFromKits = (kits: Kit[]): NodeHandlers => {
|
|
60
|
+
return kits.reduce((handlers, kit) => {
|
|
61
|
+
// If multiple kits have the same handler, the kit earlier in the list
|
|
62
|
+
// gets precedence, including upstream kits getting precedence over kits
|
|
63
|
+
// defined in the graph.
|
|
64
|
+
//
|
|
65
|
+
// TODO: This means kits are fallback, consider non-fallback as well.
|
|
66
|
+
return { ...kit.handlers, ...handlers };
|
|
67
|
+
}, {} as NodeHandlers);
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* The single entry point for getting a handler for a node type.
|
|
72
|
+
* The handler can be one of the two types:
|
|
73
|
+
* - A graph-based handler, where the `type` is actually a
|
|
74
|
+
* URL-like string that points to a graph.
|
|
75
|
+
* - A kit-based handler, where the `type` is a string that
|
|
76
|
+
* corresponds to a node type in a kit.
|
|
77
|
+
*
|
|
78
|
+
* The function throws an error if no handler is found for the
|
|
79
|
+
* given node type.
|
|
80
|
+
*
|
|
81
|
+
* @param type -- The node type to get a handler for.
|
|
82
|
+
* @param context -- The context in which the handler is
|
|
83
|
+
* being requested.
|
|
84
|
+
* @returns -- The handler for the node type.
|
|
85
|
+
*/
|
|
86
|
+
export async function getHandler(
|
|
87
|
+
type: NodeTypeIdentifier,
|
|
88
|
+
context: NodeHandlerContext
|
|
89
|
+
): Promise<NodeHandler> {
|
|
90
|
+
if (graphUrlLike(type)) {
|
|
91
|
+
const graphHandler = await getGraphHandler(type, context);
|
|
92
|
+
if (graphHandler) {
|
|
93
|
+
return graphHandler;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
const handlers = handlersFromKits(context.kits ?? []);
|
|
97
|
+
const kitHandler = handlers[type];
|
|
98
|
+
if (kitHandler) {
|
|
99
|
+
return kitHandler;
|
|
100
|
+
}
|
|
101
|
+
throw new Error(`No handler for node type "${type}"`);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export async function getGraphHandlerFromMutableGraph(
|
|
105
|
+
type: NodeTypeIdentifier,
|
|
106
|
+
mutable: MutableGraph
|
|
107
|
+
): Promise<NodeHandlerObject | undefined> {
|
|
108
|
+
const nodeTypeUrl = graphUrlLike(type)
|
|
109
|
+
? getGraphUrl(type, contextFromMutableGraph(mutable))
|
|
110
|
+
: undefined;
|
|
111
|
+
if (!nodeTypeUrl) {
|
|
112
|
+
return undefined;
|
|
113
|
+
}
|
|
114
|
+
const store = mutable.store;
|
|
115
|
+
const result = store.addByURL(type, [], {
|
|
116
|
+
outerGraph: mutable.graph,
|
|
117
|
+
});
|
|
118
|
+
const latest = await store.getLatest(result.mutable);
|
|
119
|
+
return new GraphBasedNodeHandler(
|
|
120
|
+
{
|
|
121
|
+
graph: latest.graph,
|
|
122
|
+
subGraphId: result.graphId,
|
|
123
|
+
moduleId: result.moduleId,
|
|
124
|
+
},
|
|
125
|
+
type
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export async function getGraphHandler(
|
|
130
|
+
type: NodeTypeIdentifier,
|
|
131
|
+
context: NodeHandlerContext,
|
|
132
|
+
allow3PModules = false
|
|
133
|
+
): Promise<NodeHandlerObject | undefined> {
|
|
134
|
+
if (is3pModule(type) && !allow3PModules) {
|
|
135
|
+
return undefined;
|
|
136
|
+
}
|
|
137
|
+
const nodeTypeUrl = graphUrlLike(type)
|
|
138
|
+
? getGraphUrl(type, context)
|
|
139
|
+
: undefined;
|
|
140
|
+
if (!nodeTypeUrl) {
|
|
141
|
+
return undefined;
|
|
142
|
+
}
|
|
143
|
+
const { graphStore } = context;
|
|
144
|
+
if (!graphStore) {
|
|
145
|
+
throw new Error(
|
|
146
|
+
`Cannot load graph for type "${type}" without a graph store.`
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
const loadResult = await graphStore.load(type, context);
|
|
151
|
+
if (!loadResult.success) {
|
|
152
|
+
throw new Error(
|
|
153
|
+
`Loading graph for type "${type}" failed: ${loadResult.error}`
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
return new GraphBasedNodeHandler(loadResult, type);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* This is a somewhat hacky module invocation filter.
|
|
161
|
+
* TODO: Instead of hard-coding the type, plumb the invocationFilter from
|
|
162
|
+
* the configuration here.
|
|
163
|
+
*/
|
|
164
|
+
function is3pModule(type: NodeTypeIdentifier) {
|
|
165
|
+
return !type.startsWith("embed://");
|
|
166
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
/**
|
|
3
|
+
* @license
|
|
4
|
+
* Copyright 2023 Google LLC
|
|
5
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { Probe, ProbeMessage } from "@breadboard-ai/types";
|
|
9
|
+
|
|
10
|
+
export type DiagnosticsCallback = (message: ProbeMessage) => Promise<void>;
|
|
11
|
+
|
|
12
|
+
export class Diagnostics implements Probe {
|
|
13
|
+
#callback: DiagnosticsCallback;
|
|
14
|
+
|
|
15
|
+
constructor(callback: DiagnosticsCallback) {
|
|
16
|
+
this.#callback = callback;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
async report(message: ProbeMessage): Promise<void> {
|
|
20
|
+
return this.#callback(message);
|
|
21
|
+
}
|
|
22
|
+
}
|