New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@breadboard-ai/build

Package Overview
Dependencies
Maintainers
0
Versions
26
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@breadboard-ai/build - npm Package Compare versions

Comparing version

to
0.9.0

dist/internal/common/brand.d.ts

32

CHANGELOG.md
# Changelog
## 0.9.0
### Minor Changes
- cc5f4b6: Changes to the signature of the board function. Introduces new inputNode and outputNode functions which are used for polymorphic boards.
- a940b87: The kit function now takes components as an object instead of an array.
- 7de241c: Remove `BoardRunner`.
### Patch Changes
- 374ea85: Internal refactoring (branding)
- f93ec06: Reflect when an input is optional by making its type parameter possibly undefined.
- 398bf4f: Behaviors added with the annotate function are now additive instead of clobbery.
- Updated dependencies [49b3612]
- Updated dependencies [e0dccfe]
- Updated dependencies [6404cb3]
- Updated dependencies [9ad0524]
- Updated dependencies [a4301e6]
- Updated dependencies [7fdd660]
- Updated dependencies [b201e07]
- Updated dependencies [15b5659]
- Updated dependencies [0296c89]
- Updated dependencies [a34bb69]
- Updated dependencies [534d67e]
- Updated dependencies [c397d53]
- Updated dependencies [7de241c]
- Updated dependencies [a424c92]
- Updated dependencies [c2cd40d]
- Updated dependencies [262cefd]
- Updated dependencies [79d709c]
- @google-labs/breadboard@0.25.0
## 0.8.1

@@ -4,0 +36,0 @@

2

dist/index.d.ts

@@ -6,3 +6,3 @@ /**

*/
export { board } from "./internal/board/board.js";
export { board, inputNode, outputNode } from "./internal/board/board.js";
export { constant } from "./internal/board/constant.js";

@@ -9,0 +9,0 @@ export { converge } from "./internal/board/converge.js";

@@ -6,3 +6,3 @@ /**

*/
export { board } from "./internal/board/board.js";
export { board, inputNode, outputNode } from "./internal/board/board.js";
export { constant } from "./internal/board/constant.js";

@@ -9,0 +9,0 @@ export { converge } from "./internal/board/converge.js";

@@ -7,10 +7,13 @@ /**

import type { NodeDescriberResult } from "@google-labs/breadboard";
import type { GraphMetadata } from "@google-labs/breadboard-schema/graph.js";
import type { GraphMetadata, NodeMetadata } from "@google-labs/breadboard-schema/graph.js";
import type { JSONSchema4 } from "json-schema";
import type { Value } from "../../index.js";
import { InputPort, OutputPort, type OutputPortReference, type ValuesOrOutputPorts } from "../common/port.js";
import type { SerializableInputPort, SerializableOutputPort, SerializableOutputPortReference } from "../common/serializable.js";
import type { SerializableBoard, SerializableInputPort, SerializableOutputPort, SerializableOutputPortReference } from "../common/serializable.js";
import { type JsonSerializable } from "../type-system/type.js";
import { type GenericSpecialInput, type Input, type InputWithDefault } from "./input.js";
import { type Output } from "./output.js";
import type { Loopback } from "./loopback.js";
import type { Convergence } from "./converge.js";
import type { AutoOptional, Expand, FlattenUnion, RemoveReadonly } from "../common/type-util.js";
/**

@@ -38,9 +41,6 @@ * Define a new Breadboard board.

*/
export declare function board<IPORTS extends BoardInputShape, OPORTS extends BoardOutputShape>({ inputs, outputs, id, title, description, version, metadata, }: BoardParameters<IPORTS, OPORTS>): BoardDefinition<FlattenMultiInputs<IPORTS>, FlattenMultiOutputs<OPORTS>>;
export declare function board<const T extends BoardInit>({ inputs, outputs, id, title, description, version, metadata, }: T): BoardDefinition<Expand<AutoOptional<RemoveReadonly<SimplifyBoardInitInputs<T["inputs"]>>>>, Expand<AutoOptional<RemoveReadonly<SimplifyBoardInitOutputs<T["outputs"]>>>>>;
export type FlattenMultiInputs<I extends BoardInputShape> = I extends Array<BoardInputPortsWithUndefined> ? {
[K in keyof I[number] as K extends "$id" | "$metadata" ? never : K]-?: I[number][K] extends Input<infer T> | undefined ? undefined extends I[number][K] ? Input<T | undefined> : Input<T> : never;
[K in keyof I[number] as K extends "$id" | "$metadata" ? never : K]-?: I[number][K] extends Input<infer T> | InputWithDefault<infer T> | undefined ? undefined extends I[number][K] ? Input<T | undefined> : Input<T> : never;
} : I;
type FlattenMultiOutputs<O extends BoardOutputShape> = O extends Array<BoardOutputPortsWithUndefined> ? {
[K in keyof O[number] as K extends "$id" | "$metadata" ? never : K]-?: O[number][K] extends OutputPort<infer T> | undefined ? undefined extends O[number][K] ? OutputPort<T | undefined> : OutputPort<T> : O[number][K] extends OutputPortReference<infer T> | undefined ? undefined extends O[number][K] ? OutputPortReference<T | undefined> : OutputPortReference<T> : never;
} : O;
export interface BoardParameters<IPORTS extends BoardInputShape, OPORTS extends BoardOutputShape> {

@@ -81,3 +81,3 @@ inputs: IPORTS;

};
export type BoardDefinition<IPORTS extends BoardInputPorts, OPORTS extends BoardOutputPorts> = BoardInstantiateFunction<IPORTS, OPORTS> & {
export type OldBoardDefinition<IPORTS extends BoardInputPorts, OPORTS extends BoardOutputPorts> = OldBoardInstantiateFunction<IPORTS, OPORTS> & {
readonly id?: string;

@@ -94,5 +94,5 @@ readonly inputs: IPORTS;

};
export type GenericBoardDefinition = BoardDefinition<any, any>;
type BoardInstantiateFunction<IPORTS extends BoardInputPorts, OPORTS extends BoardOutputPorts> = (values: ValuesOrOutputPorts<ExtractPortTypes<IPORTS>>) => BoardInstance<IPORTS, OPORTS>;
export declare class BoardInstance<IPORTS extends BoardInputPorts, OPORTS extends BoardOutputPorts> {
export type GenericBoardDefinition = OldBoardDefinition<any, any>;
type OldBoardInstantiateFunction<IPORTS extends BoardInputPorts, OPORTS extends BoardOutputPorts> = (values: ValuesOrOutputPorts<ExtractPortTypes<IPORTS>>) => OldBoardInstance<IPORTS, OPORTS>;
export declare class OldBoardInstance<IPORTS extends BoardInputPorts, OPORTS extends BoardOutputPorts> {
#private;

@@ -102,8 +102,8 @@ readonly inputs: IPORTS;

readonly values: ValuesOrOutputPorts<ExtractPortTypes<IPORTS>>;
readonly definition: BoardDefinition<IPORTS, OPORTS>;
constructor(inputs: IPORTS, outputs: OPORTS, values: ValuesOrOutputPorts<ExtractPortTypes<IPORTS>>, definition: BoardDefinition<IPORTS, OPORTS>);
readonly definition: OldBoardDefinition<IPORTS, OPORTS>;
constructor(inputs: IPORTS, outputs: OPORTS, values: ValuesOrOutputPorts<ExtractPortTypes<IPORTS>>, definition: OldBoardDefinition<IPORTS, OPORTS>);
}
export declare function isBoardInstance(value: unknown): value is BoardInstance<BoardInputPorts, BoardOutputPorts>;
export declare function isBoardInstance(value: unknown): value is OldBoardInstance<BoardInputPorts, BoardOutputPorts>;
export type BoardOutput = (OutputPortReference<JsonSerializable> | Output<JsonSerializable> | Input<JsonSerializable> | InputWithDefault<JsonSerializable>) & {
innerBoard: BoardInstance<BoardInputPorts, BoardOutputPorts>;
innerBoard: OldBoardInstance<BoardInputPorts, BoardOutputPorts>;
innerPortName: string;

@@ -126,2 +126,66 @@ };

export declare function unroll(value: Input<JsonSerializable> | InputWithDefault<JsonSerializable> | Output<JsonSerializable> | OutputPort<JsonSerializable> | OutputPortReference<JsonSerializable> | SerializableOutputPort): Input<JsonSerializable> | InputWithDefault<JsonSerializable> | OutputPort<JsonSerializable> | SerializableOutputPort;
export interface BoardInit {
inputs: InputNode | InputNode[] | AnonymousInputNodeShorthand;
outputs: OutputNode | OutputNode[] | AnonymousOutputNodeShorthand;
id?: string;
title?: string;
description?: string;
version?: string;
metadata?: GraphMetadata;
}
type AnonymousInputNodeShorthand = Record<string, GenericSpecialInput>;
type AnonymousOutputNodeShorthand = Record<string, Value | Output | undefined>;
export type BoardDefinition<I extends Record<string, JsonSerializable | undefined> = any, O extends Record<string, JsonSerializable | undefined> = any> = BoardInstantiateFunction<I, O> & SerializableBoard & {
describe: () => Promise<NodeDescriberResult>;
};
export type BoardInstantiateFunction<I extends Record<string, JsonSerializable | undefined>, O extends Record<string, JsonSerializable | undefined>> = (inputs: {
[K in keyof I]: Value<I[K]>;
}) => BoardInstance<I, O>;
export interface BoardInstance<I extends Record<string, JsonSerializable | undefined>, O extends Record<string, JsonSerializable | undefined>> {
outputs: Expand<WrapInValues<FilterSerializable<FlattenUnion<O>>>>;
}
type FilterSerializable<T extends Record<string, unknown>> = {
[K in keyof T]: T[K] extends JsonSerializable | undefined ? T[K] : never;
};
type WrapInValues<T extends Record<string, JsonSerializable | undefined>> = {
[K in keyof T]: Value<T[K]>;
};
/**
* Board inputs can either be an object (one input node) or an array of objects
* (multiple input nodes). This function returns a union of types in the array
* case.
*/
type SimplifyBoardInitInputs<T extends BoardInit["inputs"]> = T extends InputNode<infer X> ? X : T extends InputNode[] ? SimplifyBoardInitInputs<T[number]> : T extends AnonymousInputNodeShorthand ? ExtractInputTypes<T> : never;
/**
*
*/
export type SimplifyBoardInitOutputs<T extends BoardInit["outputs"]> = T extends OutputNode<infer X> ? X : T extends Array<OutputNode> ? SimplifyBoardInitOutputs<T[number]> : T extends AnonymousOutputNodeShorthand ? ExtractOutputTypes<T> : never;
/**
* Pulls out the type parameter for each `Input`, taking care to add `undefined`
* in the case of `InputWithDefault`. This is because when there is a default,
* then it is optional from the caller's perspective.
*/
type ExtractInputTypes<T extends Record<string, GenericSpecialInput>> = {
[K in keyof T]: T[K] extends Input<infer X> ? X : T[K] extends InputWithDefault<infer X> ? X | undefined : never;
};
/**
* Pulls out the type parameter for each `Input`, taking care to add `undefined`
* in the case of `InputWithDefault`. This is because when there is a default,
* then it is optional from the caller's perspective.
*/
type ExtractOutputTypes<T extends Record<string, Value | Output | undefined>> = {
[K in keyof T]: T[K] extends Input<infer X> ? X : T[K] extends InputWithDefault<infer X> ? X | undefined : T[K] extends Output<infer X> ? X : T[K] extends OutputPort<infer X> ? X : T[K] extends OutputPortReference<infer X> ? X : T[K] extends Loopback<infer X> ? X : T[K] extends Convergence<infer X> ? X : T[K] extends Value<infer X> ? X : never;
};
export declare function inputNode<T extends Record<string, GenericSpecialInput>>(inputs: T, metadata?: NodeMetadata & {
id?: string;
}): InputNode<ExtractInputTypes<T>>;
export interface InputNode<T extends Record<string, JsonSerializable | undefined> = Record<string, JsonSerializable | undefined>> {
isInputNode: true;
}
export declare function outputNode<T extends Record<string, Value | Output | undefined>>(outputs: T, metadata?: NodeMetadata & {
id?: string;
}): OutputNode<Expand<ExtractOutputTypes<T>>>;
export interface OutputNode<T extends Record<string, JsonSerializable | undefined> = Record<string, JsonSerializable | undefined>> {
isOutputNode: true;
}
export {};

@@ -11,4 +11,5 @@ /**

import { isSpecialOutput } from "./output.js";
/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable @typescript-eslint/no-unused-vars */
// TODO(aomarks) Support primary ports in boards.
// TODO(aomarks) Support adding descriptions to board ports.
/**

@@ -97,3 +98,3 @@ * Define a new Breadboard board.

instantiate(values) {
return new BoardInstance(this.#inputs, this.#outputs, values, this.definition);
return new OldBoardInstance(this.#inputs, this.#outputs, values, this.definition);
}

@@ -131,3 +132,3 @@ async describe() {

}
export class BoardInstance {
export class OldBoardInstance {
inputs;

@@ -242,2 +243,26 @@ outputs;

}
export function inputNode(inputs, metadata) {
const result = { ...inputs };
if (metadata) {
if (metadata.id) {
result.$id = metadata.id;
metadata = { ...metadata };
delete metadata["id"];
}
result.$metadata = metadata;
}
return result;
}
export function outputNode(outputs, metadata) {
const result = { ...outputs };
if (metadata) {
if (metadata.id) {
result.$id = metadata.id;
metadata = { ...metadata };
delete metadata["id"];
}
result.$metadata = metadata;
}
return result;
}
//# sourceMappingURL=board.js.map

@@ -6,2 +6,3 @@ /**

*/
import { brand } from "../common/brand.js";
import { type OutputPortReference } from "../common/port.js";

@@ -21,2 +22,3 @@ import type { JsonSerializable } from "../type-system/type.js";

interface Constant {
readonly [brand]: "Constant";
[ConstantVersionOf]: OutputPortReference<JsonSerializable> | Input<JsonSerializable> | InputWithDefault<JsonSerializable>;

@@ -23,0 +25,0 @@ }

@@ -6,2 +6,3 @@ /**

*/
import { brand, isBranded } from "../common/brand.js";
import {} from "../common/port.js";

@@ -23,2 +24,3 @@ // TODO(aomarks) Possible other names: `sticky`, `persistent`, `retained`.

return {
[brand]: "Constant",
...output,

@@ -30,6 +32,4 @@ [ConstantVersionOf]: output,

export function isConstant(value) {
return (typeof value === "object" &&
value !== null &&
value[ConstantVersionOf] !== undefined);
return isBranded(value, "Constant");
}
//# sourceMappingURL=constant.js.map

@@ -6,2 +6,3 @@ /**

*/
import { brand } from "../common/brand.js";
import type { OutputPortReference } from "../common/port.js";

@@ -15,7 +16,7 @@ import type { BroadenBasicType } from "../common/type-util.js";

type ExtractType<T extends Convergable<JsonSerializable>> = T extends Convergable<infer X> ? X extends string | number | boolean ? BroadenBasicType<X> : X : never;
export interface Convergence<T extends JsonSerializable> {
__isConvergence: true;
export interface Convergence<T extends JsonSerializable = JsonSerializable> {
readonly [brand]: "Convergence";
ports: Array<Convergable<T>>;
}
export declare function isConvergence(value: unknown): value is Convergence<JsonSerializable>;
export declare function isConvergence(value: unknown): value is Convergence;
export {};

@@ -6,5 +6,6 @@ /**

*/
import { brand, isBranded } from "../common/brand.js";
export function converge(first, second, ...rest) {
return {
__isConvergence: true,
[brand]: "Convergence",
ports: [first, second, ...rest],

@@ -14,6 +15,4 @@ };

export function isConvergence(value) {
return (typeof value === "object" &&
value !== null &&
value.__isConvergence === true);
return isBranded(value, "Convergence");
}
//# sourceMappingURL=converge.js.map

@@ -8,2 +8,3 @@ /**

import type { BreadboardType, ConvertBreadboardType, JsonSerializable } from "../type-system/type.js";
type Optionalize<T extends Record<string, unknown>, X extends JsonSerializable | undefined> = T["optional"] extends true ? X | undefined : X;
export declare function input(): Input<string>;

@@ -16,3 +17,3 @@ export declare function input<T extends Record<string, unknown>>(params: T & {

type: Defined;
} & CheckParams<T>): Input<T["type"] extends BreadboardType ? ConvertBreadboardType<T["type"]> : JsonSerializable>;
} & CheckParams<T>): Input<Optionalize<T, T["type"] extends BreadboardType ? ConvertBreadboardType<T["type"]> : JsonSerializable>>;
export declare function input<T extends Record<string, unknown>>(params: T & LooseParams & {

@@ -29,6 +30,16 @@ default: Defined;

examples?: undefined;
optional?: undefined;
}): Input<string>;
export declare function input(params: {
$id?: string;
description?: string;
title?: string;
type?: undefined;
default?: undefined;
examples?: undefined;
optional: true;
}): Input<string | undefined>;
export declare function input<T extends Record<string, unknown>>(params: T & {
examples: Defined;
} & CheckParams<T>): Input<T["examples"] extends string[] | number[] | boolean[] ? BroadenBasicType<T["examples"][number]> : JsonSerializable>;
} & CheckParams<T>): Input<Optionalize<T, T["examples"] extends string[] | number[] | boolean[] ? BroadenBasicType<T["examples"][number]> : JsonSerializable>>;
interface LooseParams {

@@ -63,3 +74,3 @@ $id?: string;

}
export type GenericSpecialInput = Input<JsonSerializable> | InputWithDefault<JsonSerializable>;
export type GenericSpecialInput = Input<JsonSerializable | undefined> | InputWithDefault<JsonSerializable>;
type CheckParams<T extends LooseParams> = (T["type"] extends Defined ? {

@@ -66,0 +77,0 @@ $id?: string;

@@ -6,2 +6,3 @@ /**

*/
import { brand } from "../common/brand.js";
import type { OutputPortReference } from "../common/port.js";

@@ -23,5 +24,5 @@ import type { BreadboardType, ConvertBreadboardType, JsonSerializable } from "../type-system/type.js";

*/
declare class Loopback<T extends JsonSerializable> {
declare class Loopback<T extends JsonSerializable = JsonSerializable> {
#private;
readonly __BreadboardEntity__ = "Loopback";
readonly [brand] = "Loopback";
readonly type: BreadboardType;

@@ -42,2 +43,2 @@ constructor(type: BreadboardType);

*/
export declare function isLoopback(value: unknown): value is Loopback<JsonSerializable>;
export declare function isLoopback(value: unknown): value is Loopback;

@@ -6,2 +6,3 @@ /**

*/
import { brand, isBranded } from "../common/brand.js";
/**

@@ -20,3 +21,2 @@ * Create a new Breadboard loopback.

}
const LOOPBACK_ENTITY_NAME = "Loopback";
/**

@@ -31,3 +31,3 @@ * Loopbacks can be used in place of real output ports for situations where it

class Loopback {
__BreadboardEntity__ = LOOPBACK_ENTITY_NAME;
[brand] = "Loopback";
type;

@@ -59,10 +59,4 @@ #value;

export function isLoopback(value) {
return isBreadboardEntity(value, LOOPBACK_ENTITY_NAME);
return isBranded(value, "Loopback");
}
// TODO(aomarks) Use this pattern elsewhere.
function isBreadboardEntity(value, type) {
return (typeof value === "object" &&
value !== null &&
value.__BreadboardEntity__ === type);
}
//# sourceMappingURL=loopback.js.map

@@ -6,2 +6,3 @@ /**

*/
import { brand, isBranded } from "../common/brand.js";
import {} from "../common/port.js";

@@ -18,2 +19,3 @@ /**

return {
[brand]: "Optional",
...output,

@@ -25,6 +27,4 @@ [OptionalVersionOf]: output,

export function isOptional(value) {
return (typeof value === "object" &&
value !== null &&
value[OptionalVersionOf] !== undefined);
return isBranded(value, "Optional");
}
//# sourceMappingURL=optional.js.map

@@ -6,6 +6,6 @@ /**

*/
import type { OutputPortReference } from "../common/port.js";
import { brand } from "../common/brand.js";
import type { Value } from "../common/value.js";
import type { JsonSerializable } from "../type-system/type.js";
import type { Input, InputWithDefault } from "./input.js";
export declare function output<T extends JsonSerializable>(port: Output<T> | OutputPortReference<T> | Input<T> | InputWithDefault<T>, { id, title, description, }?: {
export declare function output<T extends JsonSerializable | undefined>(port: Value<T>, { id, title, description, }?: {
id?: string;

@@ -15,9 +15,9 @@ title?: string;

}): Output<T>;
export interface Output<T extends JsonSerializable | undefined> {
readonly __SpecialOutputBrand: true;
export interface Output<T extends JsonSerializable | undefined = JsonSerializable | undefined> {
readonly [brand]: "Output";
readonly id?: string;
readonly title?: string;
readonly description?: string;
readonly port: Output<T> | OutputPortReference<T> | Input<T> | InputWithDefault<T>;
readonly port: Value<T>;
}
export declare function isSpecialOutput(value: unknown): value is Output<JsonSerializable>;
export declare function isSpecialOutput(value: unknown): value is Output;

@@ -6,5 +6,6 @@ /**

*/
import { brand, isBranded } from "../common/brand.js";
export function output(port, { id, title, description, } = {}) {
return {
__SpecialOutputBrand: true,
[brand]: "Output",
id,

@@ -17,6 +18,4 @@ title,

export function isSpecialOutput(value) {
return (typeof value === "object" &&
value !== null &&
"__SpecialOutputBrand" in value);
return isBranded(value, "Output");
}
//# sourceMappingURL=output.js.map

@@ -8,6 +8,6 @@ /**

import {} from "../type-system/type.js";
import { BoardInstance, describeInput, describeOutput, isBoard, isBoardInstance, isBoardOutput, isSerializableOutputPortReference, } from "./board.js";
import { OldBoardInstance, describeInput, describeOutput, isBoard, isBoardInstance, isBoardOutput, isSerializableOutputPortReference, } from "./board.js";
import { ConstantVersionOf, isConstant } from "./constant.js";
import { isConvergence } from "./converge.js";
import { isSpecialInput } from "./input.js";
import { isSpecialInput, } from "./input.js";
import { isLoopback } from "./loopback.js";

@@ -14,0 +14,0 @@ import { OptionalVersionOf, isOptional } from "./optional.js";

@@ -19,2 +19,3 @@ /**

outputsForSerialization: Record<string, SerializableOutputPortReference | Output<JsonSerializable> | Input<JsonSerializable> | InputWithDefault<JsonSerializable>> | Array<Record<string, SerializableOutputPortReference | Output<JsonSerializable> | Input<JsonSerializable> | InputWithDefault<JsonSerializable>>>;
id?: string;
title?: string;

@@ -21,0 +22,0 @@ description?: string;

@@ -50,2 +50,21 @@ /**

export type IsNever<T> = [T] extends [never] ? true : false;
/**
* Remove all readonly modifiers on an object.
*/
export type RemoveReadonly<T> = {
-readonly [K in keyof T]: T[K];
};
/**
* For each property in an object, if its value can be `undefined`, mark that
* property as optional.
*/
export type AutoOptional<T> = T extends unknown ? {
[K in keyof T as undefined extends T[K] ? K : never]?: T[K];
} & {
[K in keyof T as undefined extends T[K] ? never : K]: T[K];
} : never;
export type FlattenUnion<T> = {
[K in keyof UnionToIntersection<T>]: K extends keyof T ? T[K] : UnionToIntersection<T>[K] | undefined;
};
export type UnionToIntersection<U> = (U extends unknown ? (k: U) => void : never) extends (k: infer I) => void ? I : never;
export {};

@@ -10,3 +10,3 @@ /**

import { type BreadboardType, type JsonSerializable } from "../type-system/type.js";
import { type OutputPortReference } from "./port.js";
import { OutputPort, type OutputPortReference } from "./port.js";
/**

@@ -23,3 +23,3 @@ * A value, or something that can stand-in for a value when wiring together

*/
export type Value<T extends JsonSerializable> = T | OutputPortReference<T> | Input<T> | InputWithDefault<T> | Loopback<T> | Convergence<T>;
export type Value<T extends JsonSerializable | undefined = JsonSerializable | undefined> = T | OutputPort<T> | OutputPortReference<T> | Input<T> | InputWithDefault<T> | Loopback<Exclude<T, /* TODO(aomarks) Questionable */ undefined>> | Convergence<Exclude<T, /* TODO(aomarks) Questionable */ undefined>>;
/**

@@ -26,0 +26,0 @@ * Given a Breadboard {@link Value}, determine its JSON Schema type.

@@ -11,3 +11,3 @@ /**

import {} from "../type-system/type.js";
import { isOutputPortReference, OutputPortGetter, } from "./port.js";
import { isOutputPortReference, OutputPort, OutputPortGetter, } from "./port.js";
/**

@@ -14,0 +14,0 @@ * Given a Breadboard {@link Value}, determine its JSON Schema type.

@@ -18,3 +18,3 @@ /**

import type { Convergence } from "../board/converge.js";
import type { BoardDefinition } from "../board/board.js";
import type { SerializableBoard } from "../common/serializable.js";
export interface Definition<SI extends {

@@ -32,9 +32,3 @@ [K: string]: JsonSerializable;

}
export type GenericDiscreteComponent = Definition<{
[K: string]: JsonSerializable;
}, {
[K: string]: JsonSerializable;
}, JsonSerializable | undefined, JsonSerializable | undefined, string, boolean, string | false, string | false, {
[K: string]: InputMetadata;
}>;
export type GenericDiscreteComponent = Definition<any, any, any, any, any, any, any, any, any>;
export declare function isDiscreteComponent(value: object): value is GenericDiscreteComponent;

@@ -73,6 +67,5 @@ export declare class DefinitionImpl<SI extends {

} & {
[K in keyof Omit<SI, OI | "$id" | "$metadata">]: IM[K extends keyof IM ? K : never]["board"] extends true ? // eslint-disable-next-line @typescript-eslint/no-explicit-any
InstantiateArg<SI[K]> | BoardDefinition<any, any> : InstantiateArg<SI[K]>;
[K in keyof Omit<SI, OI | "$id" | "$metadata">]: IM[K extends keyof IM ? K : never]["board"] extends true ? InstantiateArg<SI[K]> | SerializableBoard : InstantiateArg<SI[K]>;
} & {
[K in OI]?: InstantiateArg<SI[K]> | OutputPortReference<SI[K] | undefined> | undefined;
[K in OI]?: InstantiateArg<SI[K] | undefined> | OutputPortReference<SI[K] | undefined> | undefined;
} & {

@@ -93,3 +86,3 @@ [K in keyof Omit<A, keyof SI | "$id" | "$metadata">]: DI extends JsonSerializable ? InstantiateArg<DI> : never;

}> : SO;
type InstantiateArg<T extends JsonSerializable> = T | OutputPortReference<T> | Input<T> | InputWithDefault<T> | Loopback<T> | Convergence<T>;
type InstantiateArg<T extends JsonSerializable | undefined> = T | OutputPortReference<T> | Input<T> | InputWithDefault<T> | Loopback<Exclude<T, /* TODO(aomarks) questionable */ undefined>> | Convergence<Exclude<T, /* TODO(aomarks) questionable */ undefined>>;
export {};

@@ -14,2 +14,3 @@ /**

import { normalizeBreadboardError } from "../common/error.js";
/* eslint-enable @typescript-eslint/no-explicit-any */
export function isDiscreteComponent(value) {

@@ -16,0 +17,0 @@ return ("breadboardType" in value && value.breadboardType === "DiscreteComponent");

@@ -7,6 +7,7 @@ /**

import type { Kit, KitConstructor } from "@google-labs/breadboard";
import type { GenericBoardDefinition } from "./board/board.js";
import type { BoardDefinition } from "./board/board.js";
import { type GenericDiscreteComponent } from "./define/definition.js";
import type { KitTag } from "@google-labs/breadboard-schema/graph.js";
export interface KitOptions {
type ComponentManifest = Record<string, GenericDiscreteComponent | BoardDefinition>;
export interface KitOptions<T extends ComponentManifest> {
title: string;

@@ -17,4 +18,5 @@ description: string;

tags?: KitTag[];
components: Array<GenericDiscreteComponent | GenericBoardDefinition>;
components: T;
}
export declare function kit(options: KitOptions): KitConstructor<Kit>;
export declare function kit<T extends ComponentManifest>(options: KitOptions<T>): KitConstructor<Kit> & T;
export {};

@@ -9,3 +9,7 @@ /**

export function kit(options) {
const handlers = Object.fromEntries(options.components.map((component) => {
const componentsWithIds = Object.fromEntries(Object.entries(options.components).map(([id, component]) => [
id,
{ ...component, id },
]));
const handlers = Object.fromEntries(Object.values(componentsWithIds).map((component) => {
if (isDiscreteComponent(component)) {

@@ -22,2 +26,3 @@ return [component.id, component];

// TODO(aomarks) Should this just be the invoke() method on Board?
// eslint-disable-next-line @typescript-eslint/no-explicit-any
makeBoardComponentHandler(component),

@@ -29,3 +34,3 @@ ];

// certain fields on both the static and instance sides.
return class GeneratedBreadboardKit {
const result = class GeneratedBreadboardKit {
static handlers = handlers;

@@ -40,2 +45,3 @@ static url = options.url;

};
return Object.assign(result, componentsWithIds);
}

@@ -42,0 +48,0 @@ function makeBoardComponentHandler(board) {

@@ -11,6 +11,10 @@ /**

export function annotate(value, annotations) {
const original = toJSONSchema(value);
const behavior = [
...new Set([...(original.behavior ?? []), ...annotations.behavior]),
];
return {
jsonSchema: {
...annotations,
...toJSONSchema(value),
...original,
behavior,
},

@@ -17,0 +21,0 @@ };

{
"name": "@breadboard-ai/build",
"version": "0.8.1",
"version": "0.9.0",
"description": "JavaScript library for building boards and defining new node types for the Breadboard AI prototyping library",

@@ -118,3 +118,3 @@ "license": "Apache-2.0",

"dependencies": {
"@google-labs/breadboard": "^0.24.0",
"@google-labs/breadboard": "^0.25.0",
"@types/json-schema": "^7.0.15"

@@ -126,4 +126,4 @@ },

"typescript": "^5.5.4",
"wireit": "^0.14.5"
"wireit": "^0.14.8"
}
}

@@ -5,5 +5,12 @@ # Breadboard Build

A JavaScript library for defining new node types for the Breadboard AI
prototyping library.
The Breadboard Build API allows you to design and compose boards with
[TypeScript](https://www.typescriptlang.org/).
It is an alternative to the Visual Editor, designed for users who prefer a
code-first approach to working with Breadboard.
Boards that you create with the Build API can be serialized to BGL (Breadboard
Graph Language), which can then be executed directly, or imported into the
Visual Editor.
## Install

@@ -15,397 +22,46 @@

## Defining new node types
## Documentation
Use the `defineNodeType` function to define a new Breadboard node type.
Please refer to the [Build
API](https://breadboard-ai.github.io/breadboard/docs/build/) section of the
Breadboard Documentation site for full documentation.
### Example
## Example
```ts
import { defineNodeType } from "@breadboard-ai/build";
import { board, input, output } from "@breadboard-ai/build";
import { prompt } from "@google-labs/template-kit";
import { geminiText } from "@google-labs/gemini-kit";
export const reverseString = defineNodeType({
name: "example",
inputs: {
forwards: {
type: "string",
description: "The string to reverse",
},
},
outputs: {
backwards: {
type: "string",
description: "The reversed string",
primary: true,
},
},
invoke: ({ forwards }) => {
return {
backwards: forwards.split("").reverse().join(""),
};
},
const topic = input({
description: "What should the poem be about?",
examples: ["Coffee in the morning", "The mind of a cat"],
});
```
### `inputs` and `outputs`
const stanzas = input({
type: "number",
description: "How many stanzas should the poem have?",
default: 4,
});
The `inputs` and `outputs` properties specify the input and output ports of the
node, as a map from port name to a port configuration. Port configurations have
the following fields:
const poemPrompt = prompt`
Write a poem about ${topic} with ${stanzas} stanzas.`;
- `type`: (Required) A [Breadboard Type
Expression](#breadboard-type-expressions) (see below). All values sent or
received on this port must conform to this type.
- `description`: (Recommended) A brief description of the port, which will be
displayed in the Breadboard visual editor and in other places where
introspection/debugging is performed.
- `title`: (Optional) A concise title for this input. Defaults to the name of
the port.
- `default`: (Optional) A default value for this input.
- `format`: (Optional) Additional information about the format of the value.
Primarily used to determine how strings are displayed in the Breadboard Visual
Editor. Valid values:
- `multiline`: A string that is likely to contain multiple lines.
- `javascript`: A string that is JavaScript code.
- `primary`: (Optional) Enables a syntactic sugar feature for an output port to
make wiring nodes more concise. When a node has a `primary` output port, then
it becomes possible to use the node itself in API positions where an output
port is expected, with the node's `primary` port being automatically selected
as the default. There can only be one `primary `output port for a node type.
### `invoke`
The `invoke` function specifies the computation that the node will perform at
runtime. It is passed an object which contains values for all of its input
ports, and is expected to return an object with values for all of its output
ports, or a promise thereof if async work is required.
## Polymorphic node types
Usually, a Breadboard node type has a fixed set of input and output ports, as was
the case for the `reverseString` example above. We call these node types
_monomorphic_, because they have one shape.
However, sometimes it is necessary for a node's input and output ports to change
during the course of execution. We call these nodes _polymorphic_, because they
have multiple shapes.
### Polymorphic example
The following is an example of a polymorphic node type. It performs configurable
substitution of values into a string containing placeholders. It has one fixed
input (`template`), multiple _dynamic_ inputs, and one fixed output.
```ts
import { defineNodeType } from "@breadboard-ai/build";
export const templater = defineNodeType({
name: "example",
inputs: {
template: {
type: "string",
description: "A template with {{placeholders}}.",
},
"*": {
type: "string",
description: "Values to fill into template's {{placeholders}}.",
},
},
outputs: {
result: {
type: "string",
description: "The template with {{placeholders}} substituted.",
},
},
describe: ({ template }) => ({
inputs: extractPlaceholders(template ?? ""),
}),
invoke: ({ template }, placeholders) => ({
result: substituteTemplatePlaceholders(template, placeholders),
}),
const poemWriter = geminiText({
text: poemPrompt,
model: "gemini-1.5-flash-latest",
});
```
### Dynamic (`*`) `inputs` and `outputs`
The special `*` port name is used to signify that this node can dynamically
create input ports at runtime, and what types those ports will have.
### polymorphic `invoke`
The `invoke` function for polymorphic nodes is very similar to [invoke for
monomorphic nodes](#invoke), except that an additional second parameter is
passed to the function which contains the input values for the dynamic values.
### `reflective`
Setting `reflective: true` on the `*` output configuration tells Breadboard that
all dynamically created input ports will have a corresponding output port.
### `describe`
The `describe` function allows you to tell Breadboard which input and output
ports are valid and open at runtime based on some particular set of input
values.
A `describe` function will be passed a set of values (in the same way as
`invoke`), and should return an object containing either or both of `inputs` and
`outputs`, which can either be an array of strings or an object. When an array
of strings, the strings are the names of the ports to open. When an object, the
keys are the names of the ports to open, and the values are an object matching
`{description: string}`.
For example, in `templater` above, the `describe` function parses the static
`template` input and opens a port for each of the template's placeholders.
In most situations a `describe` function is not required, because Breadboard can
use the port configuration and instantiation values to determine the ports
automatically. See the following table to check whether you should provide a
`describe` function, and if so whether it should return `inputs`, `outputs`, or
both. (Note that _Dynamic_ means there is a special `*` port configuration, and
_Static_ means there is not.)
| Inputs | Outputs | Describe Inputs | Describe Outputs |
| ------- | ---------- | --------------- | ---------------- |
| Static | Static | N/A | N/A |
| Dynamic | Static | Optional | N/A |
| Static | Dynamic | N/A | **Required** |
| Dynamic | Dynamic | Optional | **Required** |
| Dynamic | Reflective | Optional | N/A |
### `unsafeOutput`
When a node has dynamic outputs, but is not `reflective`, it is not possible at
compile time for Breadboard to know what the valid output ports of a node are.
In this case, use the `unsafeOutput` method to get an output port with a given
name. Note that there is no guarantee this port will exist at runtime, so a
runtime error could occur.
(Note that the following example is highly contrived. It is better to find a
way to use fully static or reflective nodes whenever possible to avoid the use
of `unsafeOutput`).
```ts
import { defineNodeType, array } from "@breadboard-ai/build";
const weirdStringLength = defineNodeType({
name: "weirdStringLength",
inputs: {
strings: { type: array("string") },
},
outputs: {
"*": { type: "number" },
},
describe: ({ strings }) => ({
outputs: strings,
}),
invoke: ({ strings }) =>
Object.fromEntries(strings.map((name) => [name, name.length])),
const poem = output(poemWriter.outputs.text, {
title: "Poem",
description: "The poem that Gemini generated.",
});
const lengths = weirdStringLength({ strings: ["foo", "bar"] });
// All 3 of these variables will have type OutputPort<number> and can be wired
// up to other nodes and boards as normal, but only `foo` and `bar` will
// *actually* be valid at runtime.
const foo = lengths.unsafeOutput("foo");
const bar = lengths.unsafeOutput("bar");
const baz = lengths.unsafeOutput("baz"); // Oops!
```
## Adding nodes to Kits
Nodes created with `@breadboard-ai/build` can be directly integrated into Kits
created with `@google-labs/breadboard`. In addition, the
`NodeFactoryFromDefinition` type utility automatically provides a type that can
be used to generate the kit's signature.
```ts
import { reverseString } from "./reverse-string.js";
import { templater } from "./templater.js";
import { KitBuilder } from "@google-labs/breadboard/kits";
import { addKit } from "@google-labs/breadboard";
import type { NodeFactoryFromDefinition } from "@breadboard-ai/build";
const ExampleKit = new KitBuilder({
title: "Example Kit",
description: "An example kit",
version: "0.1.0",
url: "npm:@breadboard-ai/example-kit",
}).build({ reverseString, templater });
export default ExampleKit;
export const exampleKit = addKit(ExampleKit) as {
reverseString: NodeFactoryFromDefinition<typeof reverseString>;
templater: NodeFactoryFromDefinition<typeof templater>;
};
```
## Building boards
In Breadboard, nodes defined by `defineNodeType`, (and coming soon, other nested
boards) can be composed into an executable program called a _board_. Boards are
created using the `board` function.
### Example
```ts
import { board, input } from "@breadboard-ai/build";
import { reverseString, prompt } from "../build-example-kit.js";
const word = input({ description: "The word to reverse" });
const reversed = reverseString({ forwards: word });
const result = prompt`The word "${word}" is "${reversed}" in reverse`;
export default board({
title: "Example of @breadboard-ai/build",
description: "A simple example of using the @breadboard-ai/build API",
version: "1.0.0",
inputs: { word },
outputs: { result },
id: "poem-writer",
title: "Poem Writer",
description: "Write a poem with Gemini.",
inputs: { topic, stanzas },
outputs: { poem },
});
```
### Inputs
The special `input` function is how you declare a value that the user of your
board will provide. You can use an `input` anywhere a value of that type is
accepted.
Inputs are typed as `string` by default. To set a different type, use the `type`
property. See [Breadboard type expressions](#breadboard-type-expressions) for
information about what kinds of types can be configured here.
```ts
import { input, array } from "@breadboard-ai/build";
const operands = input({
description: "The numbers to sum",
type: array("number"),
});
```
Note that when you use an `input` anywhere in your board, you need to also
provide that `input` to the `board` function. If you use an `input` without
providing it to `board`, an error will be raised during serialization. (This is
required so that TypeScript understands the input/output signature of the board,
which allows it to qprovide compile-time type-safety for when boards are nested
into other boards (coming soon).)
### Outputs
Board outputs are configured by directly passing the output ports that you wish
to expose (or nodes that have a [primary](#inputs-and-outputs) output port) to
the `outputs` property.
### Metadata
The optional `title`, `description`, and `version` fields are currently only
used by systems such as the Breadboard Visual Editor, for the purposes of
finding and indexing boards.
### Cycles & Loopbacks
Occasionally it is desirable to create a board with _cycles_. However,
instantiating a node normally requires immediately providing a value for all
inputs. This is a problem because when building a cycle, there will always be an
input which needs to be connected to an output which has not yet been
initialized, and so cannot be referenced.
For such situations involving cycles, the `loopback` function is used to create
an object whose value will be provided at some later time, namely with the
missing link in the cycle.
<!-- TODO(aomarks) Provide a more realistic example here. -->
```ts
import { loopback } from "@breadboard-ai/build";
const bPlaceholder = loopback({ type: "number" });
const a = someNode({ value: bPlaceholder });
const b = someNode({ value: a.outputs.result });
bPlaceholder.resolve(b.outputs.result);
```
### Serialization
Use the `serialize` function to convert a `board` result to BGL (Breadboard
Graph Language, a portable JSON format), which allows it to be executed by the
Breadboard runner:
```ts
import { board, serialize } from "@breadboard-ai/build";
const myBoard = board(...);
const bgl = serialize(myBoard);
console.log(JSON.stringify(bgl, null, 2));
```
## Breadboard type expressions
Breadboard type expressions are effectively a common subset of JSON schema and
the TypeScript type system. By using a Breadboard type expression when declaring
your ports, those types will be natively understood by both the Breadboard
runtime (which uses JSON Schema), and when using this node type in the
TypeScript API.
### Basic types
- `"string"`
- `"number"`
- `"boolean"`
- `"null"`
- `"unknown"`
### Utility types
- `array(<type>)`: A function which generates a JSON Schema `array` and its
corresponding TypeScript `Array<...>` type.
- `object({ prop1: <type1>, prop2: <type2>, ... }, [<additional>])`: A function
which generates a JSON Schema `object` and its corresponding TypeScript
`{...}` type. If the optional second argument is set, then the object will
also allow additional properties of the given type.
- `anyOf(<type1>, <type2>, ...)`: A function which generates a JSON Schema
`anyOf` and its corresponding TypeScript union (`type1 | type2`).
- `enumeration(<type1>, <type2>, ...)`: A function which generates a JSON Schema
`enum` and its corresponding TypeScript union (`type1 | type2`).
### Unsafe type escape hatch
The `unsafeType` function can be used as a last resort escape hatch when the
above provided types are not sufficient. It allows you to directly specify JSON
schema and a TypeScript type:
```ts
import { unsafeType } from "@breadboard-ai/build";
const myCrazyType = unsafeType<{ foo: string }>({
type: "object",
properties: {
foo: {
type: "string",
},
},
required: ["foo"],
});
```
## Known issues
1. The `context` object is not yet passed to `invoke`, so certain low-level
operations are not yet possible.
2. There is no way to specify a description for a board's output (probably an
`output` function, similar to `input`, is the solution there).
3. You cannot yet embed boards into other boards (this will work by
instantiating a board object just like a regular node, but during
serialization an `invoke` node will be created in its place.)

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

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