@google-labs/breadboard
Advanced tools
Comparing version 0.0.2 to 0.1.0
@@ -7,3 +7,3 @@ /** | ||
import type { Edge, NodeDescriptor, InputValues, GraphDescriptor, OutputValues, NodeHandler } from "@google-labs/graph-runner"; | ||
import { type Breadboard, type BreadboardSlotSpec, type BreadbordRunResult, type Kit, type KitConstructor, type OptionalIdConfiguration, type BreadboardValidator } from "./types.js"; | ||
import { type Breadboard, type BreadboardSlotSpec, type BreadbordRunResult, type Kit, type KitConstructor, type OptionalIdConfiguration, type BreadboardValidator, BreadboardNode, ReflectNodeOutputs, IncludeNodeInputs, SlotNodeInputs } from "./types.js"; | ||
import { Node } from "./node.js"; | ||
@@ -62,4 +62,5 @@ /** | ||
* events to it. See [Chapter 7: Probes](https://github.com/google/labs-prototypes/tree/main/seeds/breadboard/docs/tutorial#chapter-7-probes) of the Breadboard tutorial for more information. | ||
* @param slots - an optional map of slotted graphs. See [Chapter 6: Boards with slots](https://github.com/google/labs-prototypes/tree/main/seeds/breadboard/docs/tutorial#chapter-6-boards-with-slots) of the Breadboard tutorial for more information. | ||
*/ | ||
run(probe?: EventTarget): AsyncGenerator<BreadbordRunResult>; | ||
run(probe?: EventTarget, slots?: BreadboardSlotSpec): AsyncGenerator<BreadbordRunResult>; | ||
/** | ||
@@ -75,5 +76,6 @@ * A simplified version of `run` that runs the board until the board provides | ||
* events to it. See [Chapter 7: Probes](https://github.com/google/labs-prototypes/tree/main/seeds/breadboard/docs/tutorial#chapter-7-probes) of the Breadboard tutorial for more information. | ||
* @param slots - an optional map of slotted graphs. See [Chapter 6: Boards with slots](https://github.com/google/labs-prototypes/tree/main/seeds/breadboard/docs/tutorial#chapter-6-boards-with-slots) of the Breadboard tutorial for more information. | ||
* @returns - outputs provided by the board. | ||
*/ | ||
runOnce(inputs: InputValues, probe?: EventTarget): Promise<OutputValues>; | ||
runOnce(inputs: InputValues, probe?: EventTarget, slots?: BreadboardSlotSpec): Promise<OutputValues>; | ||
/** | ||
@@ -102,3 +104,3 @@ * Add validator to the board. | ||
*/ | ||
passthrough(config?: OptionalIdConfiguration): Node; | ||
passthrough<In = InputValues, Out = OutputValues>(config?: OptionalIdConfiguration): BreadboardNode<In, Out>; | ||
/** | ||
@@ -115,3 +117,3 @@ * Places an `input` node on the board. | ||
*/ | ||
input(message?: string, config?: OptionalIdConfiguration): Node; | ||
input<In = InputValues, Out = OutputValues>(message?: string, config?: OptionalIdConfiguration): Node<In, Out>; | ||
/** | ||
@@ -127,3 +129,3 @@ * Places an `output` node on the board. | ||
*/ | ||
output(config?: OptionalIdConfiguration): Node; | ||
output<In = InputValues, Out = OutputValues>(config?: OptionalIdConfiguration): BreadboardNode<In, Out>; | ||
/** | ||
@@ -144,3 +146,3 @@ * Places an `include` node on the board. | ||
*/ | ||
include($ref: string, config?: OptionalIdConfiguration): Node; | ||
include<In = InputValues, Out = OutputValues>($ref: string, config?: OptionalIdConfiguration): BreadboardNode<IncludeNodeInputs & In, Out>; | ||
/** | ||
@@ -158,3 +160,3 @@ * Places a `reflect` node on the board. | ||
*/ | ||
reflect(config?: OptionalIdConfiguration): Node; | ||
reflect(config?: OptionalIdConfiguration): BreadboardNode<never, ReflectNodeOutputs>; | ||
/** | ||
@@ -176,3 +178,3 @@ * Places a `slot` node on the board. | ||
*/ | ||
slot(slot: string, config?: OptionalIdConfiguration): Node; | ||
slot<In = InputValues, Out = OutputValues>(slot: string, config?: OptionalIdConfiguration): BreadboardNode<SlotNodeInputs & In, Out>; | ||
/** | ||
@@ -207,3 +209,3 @@ * This method is a work in progress. Once finished, it will allow | ||
*/ | ||
node(handler: NodeHandler, config?: OptionalIdConfiguration): Node; | ||
node<In = InputValues, Out = OutputValues>(handler: NodeHandler, config?: OptionalIdConfiguration): BreadboardNode<In, Out>; | ||
addEdge(edge: Edge): void; | ||
@@ -210,0 +212,0 @@ addNode(node: NodeDescriptor): void; |
@@ -10,3 +10,2 @@ /** | ||
import { InputStageResult, OutputStageResult } from "./run.js"; | ||
import { readFile } from "fs/promises"; | ||
import { KitLoader } from "./kit.js"; | ||
@@ -26,4 +25,8 @@ import { IdVendor } from "./id.js"; | ||
export const loadGraph = async (path, ref) => { | ||
if (path) | ||
if (path && typeof process === "undefined") | ||
throw new Error("Unable to use `path` when not running in node"); | ||
if (path) { | ||
const { readFile } = await import("node:fs/promises"); | ||
return JSON.parse(await readFile(path, "utf-8")); | ||
} | ||
if (!ref) | ||
@@ -95,5 +98,6 @@ throw new Error("To include, we need a path or a $ref"); | ||
* events to it. See [Chapter 7: Probes](https://github.com/google/labs-prototypes/tree/main/seeds/breadboard/docs/tutorial#chapter-7-probes) of the Breadboard tutorial for more information. | ||
* @param slots - an optional map of slotted graphs. See [Chapter 6: Boards with slots](https://github.com/google/labs-prototypes/tree/main/seeds/breadboard/docs/tutorial#chapter-6-boards-with-slots) of the Breadboard tutorial for more information. | ||
*/ | ||
async *run(probe) { | ||
const core = new Core(this, this.#slots, probe); | ||
async *run(probe, slots) { | ||
const core = new Core(this, { ...this.#slots, ...slots }, this.#validators, probe); | ||
const kits = [core, ...this.kits]; | ||
@@ -112,3 +116,3 @@ const handlers = kits.reduce((handlers, kit) => { | ||
if (descriptor.type === "input") { | ||
const inputStage = new InputStageResult(inputs); | ||
const inputStage = new InputStageResult(descriptor, inputs); | ||
yield inputStage; | ||
@@ -125,5 +129,9 @@ result.outputs = inputStage.inputs; | ||
probe?.dispatchEvent(new ProbeEvent("output", { descriptor, inputs })); | ||
yield new OutputStageResult(inputs); | ||
yield new OutputStageResult(descriptor, inputs); | ||
continue; | ||
} | ||
// The include and slot handlers require a reference to themselves to | ||
// create subgraph validators at the right location in the graph. | ||
if (["include", "slot"].includes(descriptor.type)) | ||
inputs["parent"] = descriptor; | ||
const handler = handlers[descriptor.type]; | ||
@@ -152,7 +160,8 @@ if (!handler) | ||
* events to it. See [Chapter 7: Probes](https://github.com/google/labs-prototypes/tree/main/seeds/breadboard/docs/tutorial#chapter-7-probes) of the Breadboard tutorial for more information. | ||
* @param slots - an optional map of slotted graphs. See [Chapter 6: Boards with slots](https://github.com/google/labs-prototypes/tree/main/seeds/breadboard/docs/tutorial#chapter-6-boards-with-slots) of the Breadboard tutorial for more information. | ||
* @returns - outputs provided by the board. | ||
*/ | ||
async runOnce(inputs, probe) { | ||
async runOnce(inputs, probe, slots) { | ||
let outputs = {}; | ||
for await (const result of this.run(probe)) { | ||
for await (const result of this.run(probe, slots)) { | ||
if (result.seeksInputs) { | ||
@@ -350,4 +359,6 @@ result.inputs = inputs; | ||
addKit(ctr) { | ||
const kit = new ctr((...args) => { | ||
return new Node(this, ...args); | ||
const kit = new ctr({ | ||
create: (...args) => { | ||
return new Node(this, ...args); | ||
}, | ||
}); | ||
@@ -354,0 +365,0 @@ this.kits.push(kit); |
@@ -7,7 +7,7 @@ /** | ||
import type { GraphDescriptor, InputValues, NodeHandlers, OutputValues } from "@google-labs/graph-runner"; | ||
import type { BreadboardSlotSpec } from "./types.js"; | ||
import type { BreadboardSlotSpec, BreadboardValidator } from "./types.js"; | ||
export declare class Core { | ||
#private; | ||
handlers: NodeHandlers; | ||
constructor(graph: GraphDescriptor, slots: BreadboardSlotSpec, probe?: EventTarget); | ||
constructor(graph: GraphDescriptor, slots: BreadboardSlotSpec, validators: BreadboardValidator[], probe?: EventTarget); | ||
include(inputs: InputValues): Promise<OutputValues>; | ||
@@ -14,0 +14,0 @@ reflect(_inputs: InputValues): Promise<OutputValues>; |
@@ -7,2 +7,3 @@ /** | ||
import { Board } from "./board.js"; | ||
import { NestedProbe } from "./nested-probe.js"; | ||
const CORE_HANDLERS = ["include", "reflect", "slot", "passthrough"]; | ||
@@ -12,36 +13,12 @@ const deepCopy = (graph) => { | ||
}; | ||
class NestedProbe extends EventTarget { | ||
#probe; | ||
#transform; | ||
constructor(probe, transform) { | ||
super(); | ||
this.#probe = probe; | ||
this.#transform = transform; | ||
} | ||
dispatchEvent(event) { | ||
return this.#probe.dispatchEvent(this.#transform(event)); | ||
} | ||
static create(probe, source) { | ||
if (!probe) | ||
return undefined; | ||
return new NestedProbe(probe, (e) => { | ||
const probeEvent = e; | ||
return new CustomEvent(probeEvent.type, { | ||
detail: { | ||
...probeEvent.detail, | ||
nesting: (probeEvent.detail.nesting || 0) + 1, | ||
sources: [...(probeEvent.detail.sources || []), source], | ||
}, | ||
}); | ||
}); | ||
} | ||
} | ||
export class Core { | ||
#graph; | ||
#slots; | ||
#validators; | ||
#probe; | ||
handlers; | ||
constructor(graph, slots, probe) { | ||
constructor(graph, slots, validators, probe) { | ||
this.#graph = graph; | ||
this.#slots = slots; | ||
this.#validators = validators; | ||
this.#probe = probe; | ||
@@ -55,6 +32,8 @@ this.handlers = CORE_HANDLERS.reduce((handlers, type) => { | ||
async include(inputs) { | ||
const { path, $ref, slotted, ...args } = inputs; | ||
const { path, $ref, slotted, parent, ...args } = inputs; | ||
// TODO: Please fix the $ref/path mess. | ||
const source = path || $ref || ""; | ||
const board = await Board.load(source, slotted); | ||
for (const validator of this.#validators) | ||
board.addValidator(validator.getSubgraphValidator(parent, Object.keys(args))); | ||
return await board.runOnce(args, NestedProbe.create(this.#probe, source)); | ||
@@ -67,3 +46,3 @@ } | ||
async slot(inputs) { | ||
const { slot, ...args } = inputs; | ||
const { slot, parent, ...args } = inputs; | ||
if (!slot) | ||
@@ -75,2 +54,4 @@ throw new Error("To use a slot, we need to specify its name"); | ||
const slottedBreadboard = await Board.fromGraphDescriptor(graph); | ||
for (const validator of this.#validators) | ||
slottedBreadboard.addValidator(validator.getSubgraphValidator(parent)); | ||
return await slottedBreadboard.runOnce(args, NestedProbe.create(this.#probe, slot)); | ||
@@ -77,0 +58,0 @@ } |
@@ -9,3 +9,3 @@ /** | ||
export { LogProbe } from "./log.js"; | ||
export type { ProbeEvent, Kit, NodeFactory, BreadboardValidator, BreadboardValidatorMetadata, BreadboardNode, OptionalIdConfiguration, } from "./types.js"; | ||
export type { ProbeEvent, Kit, NodeFactory, BreadboardValidator, BreadboardValidatorMetadata, BreadboardSlotSpec, BreadboardNode, OptionalIdConfiguration, } from "./types.js"; | ||
//# sourceMappingURL=index.d.ts.map |
@@ -26,3 +26,3 @@ /** | ||
const spec = urlToNpmSpec(url); | ||
const { default: module } = await import(spec); | ||
const { default: module } = await import(/* @vite-ignore */ spec); | ||
// TODO: Check to see if this import is actually a Kit class. | ||
@@ -29,0 +29,0 @@ return module; |
@@ -31,11 +31,8 @@ /** | ||
export declare const parseSpec: (spec: string) => ParsedSpec; | ||
export declare class Node implements BreadboardNode { | ||
export declare class Node<Inputs, Outputs> implements BreadboardNode<Inputs, Outputs> { | ||
#private; | ||
id: string; | ||
type: NodeTypeIdentifier; | ||
configuration?: NodeConfiguration; | ||
constructor(breadboard: Breadboard, type: NodeTypeIdentifier, configuration?: NodeConfiguration, id?: string); | ||
wire(spec: string, to: BreadboardNode): BreadboardNode; | ||
wire<ToInputs, ToOutputs>(spec: string, to: BreadboardNode<ToInputs, ToOutputs>): BreadboardNode<Inputs, Outputs>; | ||
} | ||
export {}; | ||
//# sourceMappingURL=node.d.ts.map |
@@ -66,19 +66,20 @@ /** | ||
export class Node { | ||
id; | ||
type; | ||
configuration; | ||
#descriptor; | ||
#breadboard; | ||
constructor(breadboard, type, configuration, id) { | ||
this.#breadboard = breadboard; | ||
this.id = id ?? nodeIdVendor.vendId(breadboard, type); | ||
this.#descriptor = { | ||
id: id ?? nodeIdVendor.vendId(breadboard, type), | ||
type, | ||
}; | ||
if (configuration && hasValues(configuration)) | ||
this.configuration = configuration; | ||
this.type = type; | ||
this.#breadboard.addNode(this); | ||
this.#descriptor.configuration = configuration; | ||
this.#breadboard.addNode(this.#descriptor); | ||
} | ||
wire(spec, to) { | ||
const { ltr, edge } = parseSpec(spec); | ||
const toNode = to; | ||
const result = { | ||
from: ltr ? this.id : to.id, | ||
to: ltr ? to.id : this.id, | ||
from: ltr ? this.#descriptor.id : toNode.#descriptor.id, | ||
to: ltr ? toNode.#descriptor.id : this.#descriptor.id, | ||
...edge, | ||
@@ -85,0 +86,0 @@ }; |
@@ -6,8 +6,9 @@ /** | ||
*/ | ||
import type { InputValues, OutputValues } from "@google-labs/graph-runner"; | ||
import type { InputValues, NodeDescriptor, OutputValues } from "@google-labs/graph-runner"; | ||
import type { BreadbordRunResult } from "./types.js"; | ||
export declare class InputStageResult implements BreadbordRunResult { | ||
#private; | ||
node: NodeDescriptor; | ||
seeksInputs: boolean; | ||
constructor(args: InputValues); | ||
constructor(node: NodeDescriptor, args: InputValues); | ||
get inputArguments(): InputValues; | ||
@@ -20,4 +21,5 @@ set inputs(inputs: InputValues); | ||
#private; | ||
node: NodeDescriptor; | ||
seeksInputs: boolean; | ||
constructor(outputs: OutputValues); | ||
constructor(node: NodeDescriptor, outputs: OutputValues); | ||
get inputArguments(): InputValues; | ||
@@ -24,0 +26,0 @@ set inputs(inputs: InputValues); |
@@ -7,6 +7,8 @@ /** | ||
export class InputStageResult { | ||
node; | ||
seeksInputs = true; | ||
#args = {}; | ||
#inputs = {}; | ||
constructor(args) { | ||
constructor(node, args) { | ||
this.node = node; | ||
this.#args = args; | ||
@@ -28,5 +30,7 @@ } | ||
export class OutputStageResult { | ||
node; | ||
seeksInputs = false; | ||
#outputs = {}; | ||
constructor(outputs) { | ||
constructor(node, outputs) { | ||
this.node = node; | ||
this.#outputs = outputs; | ||
@@ -33,0 +37,0 @@ } |
@@ -13,2 +13,8 @@ /** | ||
/** | ||
* The current node that is being visited. This property can be used to get | ||
* information about the current node, such as its id, type, and | ||
* configuration. | ||
*/ | ||
node: NodeDescriptor; | ||
/** | ||
* Returns `true` if the board is waiting for | ||
@@ -38,3 +44,5 @@ * input values. Returns `false` if the board is providing outputs. | ||
} | ||
export type NodeFactory = (type: NodeTypeIdentifier, configuration?: NodeConfiguration, id?: string) => BreadboardNode; | ||
export interface NodeFactory { | ||
create<Inputs, Outputs>(type: NodeTypeIdentifier, configuration?: NodeConfiguration, id?: string): BreadboardNode<Inputs, Outputs>; | ||
} | ||
export interface KitConstructor<T extends Kit> { | ||
@@ -68,2 +76,12 @@ new (nodeFactory: NodeFactory): T; | ||
getValidatorMetadata(node: NodeDescriptor): BreadboardValidatorMetadata; | ||
/** | ||
* Generate a validator for a subgraph, replacing a given node. Call | ||
* .addGraph() on the returned validator to add and validate the subgraph. | ||
* | ||
* @param node The node to replace. | ||
* @param actualInputs Actual inputs to the node (as opposed to assuming all | ||
* inputs with * or that optional ones are present) | ||
* @returns A validator for the subgraph. | ||
*/ | ||
getSubgraphValidator(node: NodeDescriptor, actualInputs?: string[]): BreadboardValidator; | ||
} | ||
@@ -111,3 +129,13 @@ /** | ||
} | ||
export interface BreadboardNode extends NodeDescriptor { | ||
type Common<To, From> = { | ||
[P in keyof (From | To) as From[P] extends To[P] ? P : never]?: To[P] | undefined; | ||
}; | ||
type LongOutSpec<From, To> = `${string & keyof From}->${string & keyof To}` | `${string & keyof From}->${string & keyof To}.` | `${string & keyof From}->${string & keyof To}?`; | ||
type LongInSpec<From, To> = `${string & keyof From}<-${string & keyof To}` | `${string & keyof From}<-${string & keyof To}.` | `${string & keyof From}<-${string & keyof To}?`; | ||
type ShortOutSpec<From, To> = `${string & keyof Common<From, To>}` | `${string & keyof Common<From, To>}->` | `${string & keyof Common<From, To>}->.` | `${string & keyof Common<From, To>}->?`; | ||
type ShortInSpec<From, To> = `<-${string & keyof Common<From, To>}` | `<-${string & keyof Common<From, To>}.` | `<-${string & keyof Common<From, To>}?`; | ||
export type WireOutSpec<From, To> = LongOutSpec<From, To> | ShortOutSpec<From, To>; | ||
export type WireInSpec<From, To> = LongInSpec<From, To> | ShortInSpec<From, To>; | ||
export type WireSpec<FromIn, FromOut, ToIn, ToOut> = WireOutSpec<FromOut, ToIn> | WireInSpec<ToOut, FromIn>; | ||
export interface BreadboardNode<Inputs, Outputs> { | ||
/** | ||
@@ -122,3 +150,3 @@ * Wires the current node to another node. | ||
*/ | ||
wire(spec: string, to: BreadboardNode): BreadboardNode; | ||
wire<ToInputs, ToOutputs>(spec: string, to: BreadboardNode<ToInputs, ToOutputs>): BreadboardNode<Inputs, Outputs>; | ||
} | ||
@@ -134,2 +162,17 @@ /** | ||
} & NodeConfiguration; | ||
export type ReflectNodeOutputs = OutputValues & { | ||
graph: GraphDescriptor; | ||
}; | ||
export type IncludeNodeInputs = InputValues & { | ||
path?: string; | ||
$ref?: string; | ||
slotted?: BreadboardSlotSpec; | ||
parent: NodeDescriptor; | ||
args: InputValues; | ||
}; | ||
export type SlotNodeInputs = { | ||
slot: string; | ||
parent: NodeDescriptor; | ||
}; | ||
export {}; | ||
//# sourceMappingURL=types.d.ts.map |
{ | ||
"name": "@google-labs/breadboard", | ||
"version": "0.0.2", | ||
"version": "0.1.0", | ||
"description": "A library for rapid generative AI application prototyping", | ||
@@ -43,3 +43,3 @@ "main": "./dist/src/index.js", | ||
"@google-labs/tsconfig": "*", | ||
"@types/node": "^18.16.3", | ||
"@types/node": "^18.17.4", | ||
"@typescript-eslint/eslint-plugin": "^5.56.0", | ||
@@ -51,3 +51,3 @@ "@typescript-eslint/parser": "^5.56.0", | ||
"dependencies": { | ||
"@google-labs/graph-runner": "^0.0.1" | ||
"@google-labs/graph-runner": "^0.0.2" | ||
}, | ||
@@ -54,0 +54,0 @@ "engines": { |
@@ -43,3 +43,3 @@ # Breadboard | ||
Placing things on the board is exceedingly simple. Here's a line that places an `input` and an `output` node on the board: | ||
Placing things on the board is simple. This example places an `input` and an `output` node on the board: | ||
@@ -51,3 +51,3 @@ ```js | ||
Wiring things is also pretty easy: | ||
Wiring things is also simple: | ||
@@ -58,3 +58,3 @@ ```js | ||
The statement above wires the `say` property of the `input` node to the `hear` property the `output` node". | ||
The statement above wires the `say` property of the `input` node to the `hear` property of the `output` node. | ||
@@ -79,3 +79,3 @@ The `wire` method is chainable, so you can wire multiple wires at once. Wiring can also happen in both directions, allowing for more expressivity and flexibility. | ||
You can run boards using `runOnce` and `run` methods. The `runOnce` is the simplest. It just takes inputs and produces a set of outputs: | ||
You can run boards using `runOnce` and `run` methods. The `runOnce` is the simplest; it takes inputs and produces a set of outputs: | ||
@@ -89,3 +89,3 @@ ```js | ||
When run like that, the output of the sample board above will look something like this: | ||
When run, the output of the sample board above will look something like this: | ||
@@ -113,3 +113,3 @@ ```sh | ||
You can include them into your own boards, kind of like JS modules, and then treat them as nodes in your graph: | ||
You can include them into your own boards, similar to JS modules, and then treat them as nodes in your graph: | ||
@@ -148,3 +148,3 @@ ```js | ||
- [Breadboard Tutorial](https://github.com/google/labs-prototypes/blob/main/seeds/breadboard/docs/tutorial/README.md) -- this one is great if learning step-by-step, from easy to more complex is your style. | ||
- [Breadboard Tutorial](https://github.com/google/labs-prototypes/blob/main/seeds/breadboard/docs/tutorial/README.md) -- learn how to use breadboard step-by-step, from easy to more complex. | ||
- [Node Types Reference](https://github.com/google/labs-prototypes/blob/main/seeds/breadboard/docs/nodes.md) - learn about the nodes that come built-in with Breadboard. | ||
@@ -151,0 +151,0 @@ - [Wiring spec](https://github.com/google/labs-prototypes/blob/main/seeds/breadboard/docs/wires.md) -- all the different ways to wire nodes. |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
83653
42
1282
0
+ Added@google-labs/graph-runner@0.0.2(transitive)
- Removed@google-labs/graph-runner@0.0.1(transitive)