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

@google-labs/breadboard

Package Overview
Dependencies
Maintainers
0
Versions
46
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@google-labs/breadboard - npm Package Compare versions

Comparing version 0.21.0 to 0.22.0

16

dist/harness.min.js

@@ -61,3 +61,3 @@ /**

* SPDX-License-Identifier: Apache-2.0
*/class C{#S;#E;constructor(t){this.#S=structuredClone(t)||[]}onGraphStart(){this.#S.push({graph:0,node:0})}onNodeStart(t){this.#S[this.#S.length-1].node++,this.#E=t}onNodeEnd(){}onGraphEnd(){}async state(){const t=structuredClone(this.#S);return this.#E&&(t[t.length-1].state=await c("nodestart",this.#E)),t}}var q="https://raw.githubusercontent.com/breadboard-ai/breadboard/@google-labs/breadboard-schema@1.5.0/packages/schema/breadboard.schema.json";class A{name="DefaultGraphProvider";#P=Promise.resolve();ready(){return this.#P}isSupported(){return!0}extendedCapabilities(){return{modify:!1,connect:!1,disconnect:!1,refresh:!1,watch:!1}}canProvide(t){return("http:"===t.protocol||"https:"===t.protocol||"file:"===t.protocol&&""===t.hostname)&&{load:!0,save:!1,delete:!1}}async load(t){if("file:"===t.protocol){return(async t=>{if(void 0===globalThis.process)throw new Error("Unable to use `path` when not running in node");let e;if("function"==typeof require){const{readFile:t}=require("node:fs/promises");e=t}else{const{readFile:t}=await import("node:fs/promises");e=t}return JSON.parse(await e(t,"utf-8"))})(decodeURIComponent(t.pathname))}return"http:"===t.protocol||"https:"===t.protocol?(async t=>{const e=await fetch(t);return await e.json()})(t.href):null}async save(t,e){throw new Error("Save not implemented for DefaultGraphProvider")}async delete(t){throw new Error("Delete not implemented for DefaultGraphProvider")}async connect(t){throw new Error("Connect not implemented for DefaultGraphProvider")}async disconnect(t){throw new Error("Disconnect not implemented for DefaultGraphProvider")}async refresh(t){throw new Error("Refresh not implemented for DefaultGraphProvider")}async createBlank(t){throw new Error("Create Blank not implemented for DefaultGraphProvider")}async create(t,e){throw new Error("Create not implemented for DefaultGraphProvider")}async createURL(t,e){throw new Error("createURL not implemented for DefaultGraphProvider")}parseURL(t){throw new Error("parseURL not implemented for DefaultGraphProvider")}async restore(){throw new Error("restore is not implemented for DefaultGraphProvider")}items(){throw new Error("items is not implemented for DefaultGraphProvider")}startingURL(){return null}watch(){throw new Error("watch is not implemented for DefaultGraphProvider")}}
*/class C{#S;#E;constructor(t){this.#S=structuredClone(t)||[]}onGraphStart(){this.#S.push({graph:0,node:0})}onNodeStart(t){this.#S[this.#S.length-1].node++,this.#E=t}onNodeEnd(){}onGraphEnd(){}async state(){const t=structuredClone(this.#S);return this.#E&&(t[t.length-1].state=await c("nodestart",this.#E)),t}}var q="https://raw.githubusercontent.com/breadboard-ai/breadboard/@google-labs/breadboard-schema@1.5.1/packages/schema/breadboard.schema.json";class A{name="DefaultGraphProvider";#P=Promise.resolve();ready(){return this.#P}isSupported(){return!0}extendedCapabilities(){return{modify:!1,connect:!1,disconnect:!1,refresh:!1,watch:!1}}canProvide(t){return("http:"===t.protocol||"https:"===t.protocol||"file:"===t.protocol&&""===t.hostname)&&{load:!0,save:!1,delete:!1}}async load(t){if("file:"===t.protocol){return(async t=>{if(void 0===globalThis.process)throw new Error("Unable to use `path` when not running in node");let e;if("function"==typeof require){const{readFile:t}=require("node:fs/promises");e=t}else{const{readFile:t}=await import("node:fs/promises");e=t}return JSON.parse(await e(t,"utf-8"))})(decodeURIComponent(t.pathname))}return"http:"===t.protocol||"https:"===t.protocol?(async t=>{const e=await fetch(t);return await e.json()})(t.href):null}async save(t,e){throw new Error("Save not implemented for DefaultGraphProvider")}async delete(t){throw new Error("Delete not implemented for DefaultGraphProvider")}async connect(t){throw new Error("Connect not implemented for DefaultGraphProvider")}async disconnect(t){throw new Error("Disconnect not implemented for DefaultGraphProvider")}async refresh(t){throw new Error("Refresh not implemented for DefaultGraphProvider")}async createBlank(t){throw new Error("Create Blank not implemented for DefaultGraphProvider")}async create(t,e){throw new Error("Create not implemented for DefaultGraphProvider")}async createURL(t,e){throw new Error("createURL not implemented for DefaultGraphProvider")}parseURL(t){throw new Error("parseURL not implemented for DefaultGraphProvider")}async restore(){throw new Error("restore is not implemented for DefaultGraphProvider")}items(){throw new Error("items is not implemented for DefaultGraphProvider")}startingURL(){return null}watch(){throw new Error("watch is not implemented for DefaultGraphProvider")}}
/**

@@ -216,3 +216,3 @@ * @license

*/
var ae,ce,ue;ne("input",ie),ne("output",ie),function(t){t.Ordinary="ordinary",t.Constant="constant",t.Control="control",t.Star="star"}(ae||(ae={})),function(t){t.Indeterminate="indeterminate",t.Connected="connected",t.Ready="ready",t.Missing="missing",t.Dangling="dangling"}(ce||(ce={})),function(t){t[t.In=0]="In",t[t.Out=1]="Out"}(ue||(ue={}));
var ae,ce;ne("input",ie),ne("output",ie),function(t){t.Ordinary="ordinary",t.Constant="constant",t.Control="control",t.Star="star"}(ae||(ae={})),function(t){t.Indeterminate="indeterminate",t.Connected="connected",t.Ready="ready",t.Missing="missing",t.Dangling="dangling"}(ce||(ce={}));
/**

@@ -223,2 +223,14 @@ * @license

*/
new Set(["string","number","integer","object","array","boolean","null"]);
/**
* @license
* Copyright 2024 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
var ue;!function(t){t[t.In=0]="In",t[t.Out=1]="Out"}(ue||(ue={}));
/**
* @license
* Copyright 2024 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
class de{#ft=1;#wt=new Map;async store(t){const e=URL.createObjectURL(t);let r=this.#wt.get(this.#ft);r||(r=[],this.#wt.set(this.#ft,r)),r.push(e);return{storedData:{handle:e,mimeType:t.type}}}async retrieve(t){const e=await this.retrieveAsBlob(t);return{inlineData:{mimeType:t.storedData.mimeType,data:await qt(e)}}}async retrieveAsBlob(t){if(!Ct(t))throw new Error("Invalid stored data");const{handle:e}=t.storedData,r=await fetch(e);return await r.blob()}async retrieveAsURL(t){if(!Ct(t))throw new Error("Invalid stored data");const{handle:e}=t.storedData;return e}startGroup(){this.#ft}endGroup(){return this.#ft++}async serializeGroup(t){const e=this.#wt.get(t);return e?Promise.all(e.map((async t=>fetch(t).then((async e=>{const r=await e.blob(),s=r.type,n=await qt(r);return{handle:t,inlineData:{mimeType:s,data:n}}}))))):null}releaseGroup(t){const e=this.#wt.get(t);if(e)for(const t of e)URL.revokeObjectURL(t)}}

@@ -225,0 +237,0 @@ /**

61

dist/kits.min.js

@@ -27,3 +27,3 @@ /**

* SPDX-License-Identifier: Apache-2.0
*/class u{graph;#e;#r;constructor(t,e,r=!0){this.graph=t,this.#e=e,this.#r=r}static#s(t,e){const{promiseId:r,outputs:s,newOpportunities:n}=e;t.pendingOutputs.delete(r);const i=s.$error?n.filter((t=>"$error"===t.out)):n;if(t.opportunities.push(...i),t.state.wireOutputs(i,s),s.$error){if(0===i.length)throw new Error("Uncaught exception in node handler. Catch by wiring up the $error output.",{cause:s.$error});globalThis.console.warn("Error in node handler, passing to the wired $error output.",s.$error,i)}}static async processAllPendingNodes(t){return(await Promise.all(t.pendingOutputs.values())).forEach((e=>{u.#s(t,e)})),t}async next(){if(!this.#e.skip){const{inputs:t,outputsPromise:e,newOpportunities:r,descriptor:s}=this.#e;this.#e.state.useInputs(s.id,this.#e.inputs);const n=Symbol(),i=new Promise((i=>{(e||Promise.resolve({})).then((e=>{if(e&&e.$error){const r=e.$error;e.$error={descriptor:s,...r,inputs:{...t,...r.inputs}}}e??={},i({promiseId:n,outputs:e,newOpportunities:r})})).catch((e=>{i({promiseId:n,outputs:{$error:{kind:"error",error:e,inputs:t,descriptor:s}},newOpportunities:r.filter((t=>"$error"===t.out))})}))}));this.#e.pendingOutputs.set(n,i)}for(;(0===this.#e.opportunities.length||this.#r)&&this.#e.pendingOutputs.size>0;)u.#s(this.#e,await Promise.race(this.#e.pendingOutputs.values()));if(0===this.#e.opportunities.length)return{done:!0,value:null};const t=this.#e.opportunities.shift(),{heads:e,nodes:r,tails:s}=this.graph,n=t.to,o=r.get(n);if(!o)throw new Error(`No node found for id "${n}"`);const c=e.get(n)||[],h=this.#e.state.getAvailableInputs(n),p=i.computeMissingInputs(c,h,o),d=s.get(n)||[],l={...o.configuration,...h};return this.#e=new a(o,l,p,this.#e.opportunities,d,this.#e.state,this.#e.pendingOutputs),{done:!1,value:this.#e}}}
*/class u{graph;#e;#r;constructor(t,e,r=!0){this.graph=t,this.#e=e,this.#r=r}static#s(t,e){const{promiseId:r,outputs:s,newOpportunities:n}=e;t.pendingOutputs.delete(r);const i=s.$error?n.filter((t=>"$error"===t.out)):n;if(t.opportunities.push(...i),t.state.wireOutputs(i,s),s.$error){if(0===i.length)throw new Error("Uncaught exception in node handler. Catch by wiring up the $error output.",{cause:s.$error});globalThis.console.warn("Error in node handler, passing to the wired $error output.",s.$error,i)}}static async processAllPendingNodes(t){return(await Promise.all(t.pendingOutputs.values())).forEach((e=>{u.#s(t,e)})),t}async next(){if(!this.#e.skip){const{inputs:t,outputsPromise:e,newOpportunities:r,descriptor:s}=this.#e;this.#e.state.useInputs(s.id,this.#e.inputs);const n=Symbol(),i=new Promise((i=>{(e||Promise.resolve({})).then((e=>{if(e&&e.$error){const r=e.$error;e.$error={descriptor:s,...r,inputs:{...t,...r.inputs}}}e??={},i({promiseId:n,outputs:e,newOpportunities:r})})).catch((e=>{i({promiseId:n,outputs:{$error:{kind:"error",error:e,inputs:t,descriptor:s}},newOpportunities:r.filter((t=>"$error"===t.out))})}))}));this.#e.pendingOutputs.set(n,i)}for(;(0===this.#e.opportunities.length||this.#r)&&this.#e.pendingOutputs.size>0;)u.#s(this.#e,await Promise.race(this.#e.pendingOutputs.values()));if(0===this.#e.opportunities.length)return{done:!0,value:null};const t=this.#e.opportunities.shift(),{heads:e,nodes:r,tails:s}=this.graph,n=t.to,o=r.get(n);if(!o)throw new Error(`No node found for id "${n}"`);const p=e.get(n)||[],c=this.#e.state.getAvailableInputs(n),h=i.computeMissingInputs(p,c,o),d=s.get(n)||[],l={...o.configuration,...c};return this.#e=new a(o,l,h,this.#e.opportunities,d,this.#e.state,this.#e.pendingOutputs),{done:!1,value:this.#e}}}
/**

@@ -33,3 +33,3 @@ * @license

* SPDX-License-Identifier: Apache-2.0
*/class c{tails=new Map;heads=new Map;nodes=new Map;entries=[];#n(t){return!this.heads.has(t)||0===this.heads.get(t)?.length}constructor(t){this.tails=t.edges.reduce(((t,e)=>{const r=e.from;return t.has(r)?t.get(r)?.push(e):t.set(r,[e]),t}),new Map),this.heads=t.edges.reduce(((t,e)=>{const r=e.to;return t.has(r)?t.get(r)?.push(e):t.set(r,[e]),t}),new Map),this.nodes=t.nodes.reduce(((t,e)=>(t.set(e.id,e),t)),new Map),this.entries=Array.from(this.nodes.keys()).filter((t=>this.#n(t)))}}
*/class p{tails=new Map;heads=new Map;nodes=new Map;entries=[];#n(t){return!this.heads.has(t)||0===this.heads.get(t)?.length}constructor(t){this.tails=t.edges.reduce(((t,e)=>{const r=e.from;return t.has(r)?t.get(r)?.push(e):t.set(r,[e]),t}),new Map),this.heads=t.edges.reduce(((t,e)=>{const r=e.to;return t.has(r)?t.get(r)?.push(e):t.set(r,[e]),t}),new Map),this.nodes=t.nodes.reduce(((t,e)=>(t.set(e.id,e),t)),new Map),this.entries=Array.from(this.nodes.keys()).filter((t=>this.#n(t)))}}
/**

@@ -39,3 +39,3 @@ * @license

* SPDX-License-Identifier: Apache-2.0
*/class h{graph;previousResult;constructor(t,e){this.graph=new c(t),this.previousResult=e}[Symbol.asyncIterator](){return this.start()}start(){if(this.previousResult)return new u(this.graph,this.previousResult);const{entries:t}=this.graph;if(0===t.length)throw new Error("No entry node found in graph.");const e=t.map((t=>({from:"$entry",to:t}))),r=new a({id:"$empty",type:"$empty"},{},[],e,[],new o,new Map);return new u(this.graph,r)}static async prepareToSave(t){return await u.processAllPendingNodes(t)}}
*/class c{graph;previousResult;constructor(t,e){this.graph=new p(t),this.previousResult=e}[Symbol.asyncIterator](){return this.start()}start(){if(this.previousResult)return new u(this.graph,this.previousResult);const{entries:t}=this.graph;if(0===t.length)throw new Error("No entry node found in graph.");const e=t.map((t=>({from:"$entry",to:t}))),r=new a({id:"$empty",type:"$empty"},{},[],e,[],new o,new Map);return new u(this.graph,r)}static async prepareToSave(t){return await u.processAllPendingNodes(t)}}
/**

@@ -45,3 +45,3 @@ * @license

* SPDX-License-Identifier: Apache-2.0
*/const p=(t,e)=>e instanceof Map?{$type:"Map",value:Array.from(e.entries())}:e,d=(t,e)=>{const{$type:r}=e||{};return"Map"==r&&e.value?new Map(e.value):e},l=async(t,e)=>{const r=await h.prepareToSave(e);return JSON.stringify({state:r,type:t},p)},f=()=>globalThis.performance.now()
*/const h=(t,e)=>e instanceof Map?{$type:"Map",value:Array.from(e.entries())}:e,d=(t,e)=>{const{$type:r}=e||{};return"Map"==r&&e.value?new Map(e.value):e},l=async(t,e)=>{const r=await c.prepareToSave(e);return JSON.stringify({state:r,type:t},h)},f=()=>globalThis.performance.now()
/**

@@ -51,3 +51,3 @@ * @license

* SPDX-License-Identifier: Apache-2.0
*/;class g{#i;#o;#a;#u;#c;constructor(t,e,r,s,n){this.#o=t,this.#i=e,this.#a=r,this.#u=s,this.#c=n}get invocationId(){return this.#u}get path(){return this.#c}get type(){return this.#i}get node(){return this.#o.descriptor}get inputArguments(){return this.#o.inputs}set inputs(t){this.#o.outputsPromise=Promise.resolve(t)}get outputs(){const{schema:t,...e}=this.#o.inputs;return e}get state(){return this.#o}async save(){return l(this.#i,this.#o)}get runState(){return this.#a}get timestamp(){return f()}isAtExitNode(){return 0===this.#o.newOpportunities.length&&0===this.#o.opportunities.length&&0===this.#o.pendingOutputs.size}static load(t){const{state:e,type:r}=(t=>{const{state:e,type:r}=JSON.parse(t,d);return{state:a.fromObject(e),type:r}})(t);return new g(e,r,void 0,0,[])}}class m extends g{constructor(t,e,r,s){super(t,"input",e,r,s)}get outputs(){throw new Error('Outputs are not available in the "input" stage')}}class y extends g{constructor(t,e,r){super(t,"output",void 0,e,r)}get inputArguments(){throw new Error('Input arguments are not available in the "output" stage')}set inputs(t){throw new Error('Setting inputs is not available in the "output" stage')}}
*/;class m{#i;#o;#a;#u;#p;constructor(t,e,r,s,n){this.#o=t,this.#i=e,this.#a=r,this.#u=s,this.#p=n}get invocationId(){return this.#u}get path(){return this.#p}get type(){return this.#i}get node(){return this.#o.descriptor}get inputArguments(){return this.#o.inputs}set inputs(t){this.#o.outputsPromise=Promise.resolve(t)}get outputs(){const{schema:t,...e}=this.#o.inputs;return e}get state(){return this.#o}async save(){return l(this.#i,this.#o)}get runState(){return this.#a}get timestamp(){return f()}isAtExitNode(){return 0===this.#o.newOpportunities.length&&0===this.#o.opportunities.length&&0===this.#o.pendingOutputs.size}static load(t){const{state:e,type:r}=(t=>{const{state:e,type:r}=JSON.parse(t,d);return{state:a.fromObject(e),type:r}})(t);return new m(e,r,void 0,0,[])}}class g extends m{constructor(t,e,r,s){super(t,"input",e,r,s)}get outputs(){throw new Error('Outputs are not available in the "input" stage')}}class y extends m{constructor(t,e,r){super(t,"output",void 0,e,r)}get inputArguments(){throw new Error('Input arguments are not available in the "output" stage')}set inputs(t){throw new Error('Setting inputs is not available in the "output" stage')}}
/**

@@ -57,3 +57,3 @@ * @license

* SPDX-License-Identifier: Apache-2.0
*/const w=t=>t&&t.replace(/-/g,""),b=(t,e="")=>{if(!t)return"";const r=t.id,s=`${e?`${w(e)}_`:""}${w(r)}`,n=t.type,i=`"${n} <br> id='${r}'"`;switch(n){case"include":return`${s}[[${i}]]:::include`;case"slot":return`${s}((${i})):::slot`;case"passthrough":return`${s}((${i})):::passthrough`;case"input":return`${s}[/${i}/]:::input`;case"secrets":return`${s}(${i}):::secrets`;case"output":return`${s}{{${i}}}:::output`;default:return`${s}[${i}]`}};class v{nodeMap;edges;nodes;idPrefix;subgraphs;constructor(t,e=""){const{edges:r,nodes:s}=t;this.nodeMap=new Map(s.map((t=>[t.id,t]))),this.edges=r,this.nodes=s,this.idPrefix=e,this.subgraphs=t.graphs||{}}handleSlotted(t,e){const r=e?`${w(e)}_`:"";if("include"!==t.type)return"";const s=t.configuration?.slotted;if(!s)return"";return Object.entries(s).map((([e,s])=>this.describeSubgraph(s,e,"slotted",t,`${r}${t.id}`))).join("\n")}handleLambda(t,e){const r=e?`${w(e)}_`:"",s=t.configuration?.board;if(!s)return"";const n=s;if("board"!==n.kind)return"";const i=n.board;return this.describeSubgraph(i,t.id,"lamdba",t,`${r}${t.id}`)}describeSubgraphs(t,e=""){const r=this.nodeMap.get(t.from);if(!r)return"";const s=this.handleLambda(r,e);return`${this.handleSlotted(r,e)}${s}`}describeSubgraph(t,e,r,s,n){const i=new v(t,n).describeGraph(),o=this.idPrefix?`${w(this.idPrefix)}_`:"",a=r&&s?`sg_${w(e)}:::slotted -- "${r}->${r}" --o ${o}${w(s.id)}\n`:"";return`\nsubgraph sg_${w(e)} [${e}]\n${i}\nend\n${a}`}describeGraph(t=!1){return[...this.edges.map((e=>{const r=((t,e,r="")=>{const s=t.from,n=b(e.get(s),r),i=t.to,o=b(e.get(i),r),a=t.in,u=t.out,c=t.optional,h=t.constant;return"*"===u?`${n} -- all --\x3e ${o}`:u&&a?c?`${n} -. "${u}->${a}" .-> ${o}`:h?`${n} -- "${u}->${a}" --o ${o}`:`${n} -- "${u}->${a}" --\x3e ${o}`:`${n} --\x3e ${o}`})(e,this.nodeMap,this.idPrefix);return`${r}${t?"":this.describeSubgraphs(e,this.idPrefix)}`})),...t?"":Object.entries(this.subgraphs).map((([t,e])=>this.describeSubgraph(e,t,void 0,void 0,`${t}${this.idPrefix}`)))].join("\n")}}const $=(t,e={},r)=>{const s=e.title??e?.url;return`Missing ${r?"required ":""}input "${t}"${s?` for board "${s}".`:"."}`},P=async(t,e,r,s,n)=>{if(!e.requestInput)return;const i=await s.outputsPromise??{},o=new S(i,s.inputs,n);s.outputsPromise=o.read(k(t,e,r))},k=(t,e,r)=>async(s,n,i,o)=>{if(i)throw new Error($(s,t,i));if(void 0!==n.default)return"type"in n&&"string"!==n.type?JSON.parse(n.default):n.default;const a=await(e.requestInput?.(s,n,r,o));if(void 0===a)throw new Error($(s,t,i));return a};
*/const w=t=>t&&t.replace(/-/g,""),b=(t,e="")=>{if(!t)return"";const r=t.id,s=`${e?`${w(e)}_`:""}${w(r)}`,n=t.type,i=`"${n} <br> id='${r}'"`;switch(n){case"include":return`${s}[[${i}]]:::include`;case"slot":return`${s}((${i})):::slot`;case"passthrough":return`${s}((${i})):::passthrough`;case"input":return`${s}[/${i}/]:::input`;case"secrets":return`${s}(${i}):::secrets`;case"output":return`${s}{{${i}}}:::output`;default:return`${s}[${i}]`}};class v{nodeMap;edges;nodes;idPrefix;subgraphs;constructor(t,e=""){const{edges:r,nodes:s}=t;this.nodeMap=new Map(s.map((t=>[t.id,t]))),this.edges=r,this.nodes=s,this.idPrefix=e,this.subgraphs=t.graphs||{}}handleSlotted(t,e){const r=e?`${w(e)}_`:"";if("include"!==t.type)return"";const s=t.configuration?.slotted;if(!s)return"";return Object.entries(s).map((([e,s])=>this.describeSubgraph(s,e,"slotted",t,`${r}${t.id}`))).join("\n")}handleLambda(t,e){const r=e?`${w(e)}_`:"",s=t.configuration?.board;if(!s)return"";const n=s;if("board"!==n.kind)return"";const i=n.board;return this.describeSubgraph(i,t.id,"lamdba",t,`${r}${t.id}`)}describeSubgraphs(t,e=""){const r=this.nodeMap.get(t.from);if(!r)return"";const s=this.handleLambda(r,e);return`${this.handleSlotted(r,e)}${s}`}describeSubgraph(t,e,r,s,n){const i=new v(t,n).describeGraph(),o=this.idPrefix?`${w(this.idPrefix)}_`:"",a=r&&s?`sg_${w(e)}:::slotted -- "${r}->${r}" --o ${o}${w(s.id)}\n`:"";return`\nsubgraph sg_${w(e)} [${e}]\n${i}\nend\n${a}`}describeGraph(t=!1){return[...this.edges.map((e=>{const r=((t,e,r="")=>{const s=t.from,n=b(e.get(s),r),i=t.to,o=b(e.get(i),r),a=t.in,u=t.out,p=t.optional,c=t.constant;return"*"===u?`${n} -- all --\x3e ${o}`:u&&a?p?`${n} -. "${u}->${a}" .-> ${o}`:c?`${n} -- "${u}->${a}" --o ${o}`:`${n} -- "${u}->${a}" --\x3e ${o}`:`${n} --\x3e ${o}`})(e,this.nodeMap,this.idPrefix);return`${r}${t?"":this.describeSubgraphs(e,this.idPrefix)}`})),...t?"":Object.entries(this.subgraphs).map((([t,e])=>this.describeSubgraph(e,t,void 0,void 0,`${t}${this.idPrefix}`)))].join("\n")}}const P=(t,e={},r)=>{const s=e.title??e?.url;return`Missing ${r?"required ":""}input "${t}"${s?` for board "${s}".`:"."}`},$=async(t,e,r,s,n)=>{if(!e.requestInput)return;const i=await s.outputsPromise??{},o=new k(i,s.inputs,n);s.outputsPromise=o.read(S(t,e,r))},S=(t,e,r)=>async(s,n,i,o)=>{if(i)throw new Error(P(s,t,i));if(void 0!==n.default)return"type"in n&&"string"!==n.type?JSON.parse(n.default):n.default;const a=await(e.requestInput?.(s,n,r,o));if(void 0===a)throw new Error(P(s,t,i));return a};
/**

@@ -63,3 +63,3 @@ * @license

* SPDX-License-Identifier: Apache-2.0
*/class S{#h;#p;#c;constructor(t,e,r){this.#h=t,this.#p=e,this.#c=r}async read(t){if(!("schema"in this.#p))return this.#h;const e=this.#p.schema;if(!e.properties)return this.#h;const r=Object.entries(e.properties),s={};for(const[n,i]of r){if(n in this.#h){s[n]=this.#h[n];continue}const r=e.required?.includes(n)??!1,o=await t(n,i,r,this.#c);s[n]=o}return{...this.#h,...s}}}class E{#d;#l=new Map;constructor(t){const{inputs:e,...r}=t;this.#d=r,this.#l=new Map(e?Object.entries(e):[])}createHandler(t,e){return async(r,s,n,i)=>{const o=this.#l.get(r);if(void 0!==o)return o;const a={id:n.id,type:n.type},u={...e,descriptor:a,inputs:{schema:{type:"object",properties:{[r]:s}}}};await t(new m(u,void 0,-1,i));const c=await u.outputsPromise;let h=c&&c[r];return void 0===h&&(h=await(this.#d.requestInput?.(r,s,a,i))),O(s)||this.#l.set(r,h),h}}}const O=t=>t.behavior?.includes("transient")??!1,x=async(t,e,r,s)=>{if(!r.provideOutput)return!1;const n=e.configuration?.schema,i=n?.behavior?.includes("bubble");return!!i&&(await r.provideOutput(t,e,s),!0)},I=(t,e,r)=>r.provideOutput?r.provideOutput:async(r,s,n)=>{const i={...e,descriptor:s,inputs:r};await t(new y(i,-1,n))},j=()=>{};class N{#f=[];#g=j;#m;#y;abort=j;constructor(){this.#w()}#w(){this.#m=new Promise(((t,e)=>{this.#g=t,this.abort=e}))}#b(t){this.#f.push(t),1==this.#f.length&&(this.#g(),this.#w())}async write(t){return new Promise((e=>{this.#b({value:t,receipt:e})}))}async read(){this.#y&&this.#y(),0===this.#f.length&&await this.#m;const t=this.#f.shift();if(!t)throw new Error("asyncGen queue should never be empty.");return this.#y=t.receipt,t.value?{done:!1,value:t.value}:{done:!0,value:void 0}}close(){this.#b({value:void 0,receipt:j})}}class M{#v;#$=!0;#f=new N;constructor(t){this.#v=t}async#P(t){return this.#f.write(t)}async next(){return this.#$&&(this.#$=!1,this.#v(this.#P.bind(this)).then((()=>{this.#f.close()})).catch((t=>{this.#f.abort(t)}))),this.#f.read()}}
*/class k{#c;#h;#p;constructor(t,e,r){this.#c=t,this.#h=e,this.#p=r}async read(t){if(!("schema"in this.#h))return this.#c;const e=this.#h.schema;if(!e.properties)return this.#c;const r=Object.entries(e.properties),s={};for(const[n,i]of r){if(n in this.#c){s[n]=this.#c[n];continue}const r=e.required?.includes(n)??!1,o=await t(n,i,r,this.#p);s[n]=o}return{...this.#c,...s}}}class O{#d;#l=new Map;constructor(t){const{inputs:e,...r}=t;this.#d=r,this.#l=new Map(e?Object.entries(e):[])}createHandler(t,e){return async(r,s,n,i)=>{const o=this.#l.get(r);if(void 0!==o)return o;const a={id:n.id,type:n.type},u={...e,descriptor:a,inputs:{schema:{type:"object",properties:{[r]:s}}}};await t(new g(u,void 0,-1,i));const p=await u.outputsPromise;let c=p&&p[r];return void 0===c&&(c=await(this.#d.requestInput?.(r,s,a,i))),E(s)||this.#l.set(r,c),c}}}const E=t=>t.behavior?.includes("transient")??!1,A=async(t,e,r,s)=>{if(!r.provideOutput)return!1;const n=e.configuration?.schema,i=n?.behavior?.includes("bubble");return!!i&&(await r.provideOutput(t,e,s),!0)},x=(t,e,r)=>r.provideOutput?r.provideOutput:async(r,s,n)=>{const i={...e,descriptor:s,inputs:r};await t(new y(i,-1,n))},I=()=>{};class j{#f=[];#m=I;#g;#y;abort=I;constructor(){this.#w()}#w(){this.#g=new Promise(((t,e)=>{this.#m=t,this.abort=e}))}#b(t){this.#f.push(t),1==this.#f.length&&(this.#m(),this.#w())}async write(t){return new Promise((e=>{this.#b({value:t,receipt:e})}))}async read(){this.#y&&this.#y(),0===this.#f.length&&await this.#g;const t=this.#f.shift();if(!t)throw new Error("asyncGen queue should never be empty.");return this.#y=t.receipt,t.value?{done:!1,value:t.value}:{done:!0,value:void 0}}close(){this.#b({value:void 0,receipt:I})}}class N{#v;#P=!0;#f=new j;constructor(t){this.#v=t}async#$(t){return this.#f.write(t)}async next(){return this.#P&&(this.#P=!1,this.#v(this.#$.bind(this)).then((()=>{this.#f.close()})).catch((t=>{this.#f.abort(t)}))),this.#f.read()}}
/**

@@ -70,3 +70,3 @@ * @license

*/
class C{#k;#S;constructor(t){this.#k=structuredClone(t)||[]}onGraphStart(){this.#k.push({graph:0,node:0})}onNodeStart(t){this.#k[this.#k.length-1].node++,this.#S=t}onNodeEnd(){}onGraphEnd(){}async state(){const t=structuredClone(this.#k);return this.#S&&(t[t.length-1].state=await l("nodestart",this.#S)),t}}var q="https://raw.githubusercontent.com/breadboard-ai/breadboard/@google-labs/breadboard-schema@1.5.0/packages/schema/breadboard.schema.json";
class C{#S;#k;constructor(t){this.#S=structuredClone(t)||[]}onGraphStart(){this.#S.push({graph:0,node:0})}onNodeStart(t){this.#S[this.#S.length-1].node++,this.#k=t}onNodeEnd(){}onGraphEnd(){}async state(){const t=structuredClone(this.#S);return this.#k&&(t[t.length-1].state=await l("nodestart",this.#k)),t}}var B="https://raw.githubusercontent.com/breadboard-ai/breadboard/@google-labs/breadboard-schema@1.5.1/packages/schema/breadboard.schema.json";
/**

@@ -77,3 +77,3 @@ * @license

*/
const A=async t=>{const e=await fetch(t);return await e.json()};class R{name="DefaultGraphProvider";#E=Promise.resolve();ready(){return this.#E}isSupported(){return!0}extendedCapabilities(){return{modify:!1,connect:!1,disconnect:!1,refresh:!1,watch:!1}}canProvide(t){return("http:"===t.protocol||"https:"===t.protocol||"file:"===t.protocol&&""===t.hostname)&&{load:!0,save:!1,delete:!1}}async load(t){if("file:"===t.protocol){return(async t=>{if(void 0===globalThis.process)throw new Error("Unable to use `path` when not running in node");let e;if("function"==typeof require){const{readFile:t}=require("node:fs/promises");e=t}else{const{readFile:t}=await import("node:fs/promises");e=t}return JSON.parse(await e(t,"utf-8"))})(decodeURIComponent(t.pathname))}return"http:"===t.protocol||"https:"===t.protocol?A(t.href):null}async save(t,e){throw new Error("Save not implemented for DefaultGraphProvider")}async delete(t){throw new Error("Delete not implemented for DefaultGraphProvider")}async connect(t){throw new Error("Connect not implemented for DefaultGraphProvider")}async disconnect(t){throw new Error("Disconnect not implemented for DefaultGraphProvider")}async refresh(t){throw new Error("Refresh not implemented for DefaultGraphProvider")}async createBlank(t){throw new Error("Create Blank not implemented for DefaultGraphProvider")}async create(t,e){throw new Error("Create not implemented for DefaultGraphProvider")}async createURL(t,e){throw new Error("createURL not implemented for DefaultGraphProvider")}parseURL(t){throw new Error("parseURL not implemented for DefaultGraphProvider")}async restore(){throw new Error("restore is not implemented for DefaultGraphProvider")}items(){throw new Error("items is not implemented for DefaultGraphProvider")}startingURL(){return null}watch(){throw new Error("watch is not implemented for DefaultGraphProvider")}}
const q=async t=>{const e=await fetch(t);return await e.json()};class M{name="DefaultGraphProvider";#O=Promise.resolve();ready(){return this.#O}isSupported(){return!0}extendedCapabilities(){return{modify:!1,connect:!1,disconnect:!1,refresh:!1,watch:!1}}canProvide(t){return("http:"===t.protocol||"https:"===t.protocol||"file:"===t.protocol&&""===t.hostname)&&{load:!0,save:!1,delete:!1}}async load(t){if("file:"===t.protocol){return(async t=>{if(void 0===globalThis.process)throw new Error("Unable to use `path` when not running in node");let e;if("function"==typeof require){const{readFile:t}=require("node:fs/promises");e=t}else{const{readFile:t}=await import("node:fs/promises");e=t}return JSON.parse(await e(t,"utf-8"))})(decodeURIComponent(t.pathname))}return"http:"===t.protocol||"https:"===t.protocol?q(t.href):null}async save(t,e){throw new Error("Save not implemented for DefaultGraphProvider")}async delete(t){throw new Error("Delete not implemented for DefaultGraphProvider")}async connect(t){throw new Error("Connect not implemented for DefaultGraphProvider")}async disconnect(t){throw new Error("Disconnect not implemented for DefaultGraphProvider")}async refresh(t){throw new Error("Refresh not implemented for DefaultGraphProvider")}async createBlank(t){throw new Error("Create Blank not implemented for DefaultGraphProvider")}async create(t,e){throw new Error("Create not implemented for DefaultGraphProvider")}async createURL(t,e){throw new Error("createURL not implemented for DefaultGraphProvider")}parseURL(t){throw new Error("parseURL not implemented for DefaultGraphProvider")}async restore(){throw new Error("restore is not implemented for DefaultGraphProvider")}items(){throw new Error("items is not implemented for DefaultGraphProvider")}startingURL(){return null}watch(){throw new Error("watch is not implemented for DefaultGraphProvider")}}
/**

@@ -83,3 +83,3 @@ * @license

* SPDX-License-Identifier: Apache-2.0
*/const T=new URL("sentinel://sentinel/sentinel"),D=t=>{const e=new URL(t.href);return e.hash="",e},G=t=>{if(t.outerGraph?.url)return new URL(t.outerGraph.url);const e=t.board?.url;return e?new URL(e):t.base?t.base:T};class U{#O;constructor(t){this.#O=[...t,new R]}async#x(t){for(const e of this.#O){const r=e.canProvide(t);if(!1!==r&&r.load){const r=await e.load(t);if(null!==r)return r.nodes?.map((t=>{"superWorker"===t.type&&(console.warn("superWorker encountered, converting to specialist"),t.type="specialist")})),r.url=t.href,r}}return console.warn(`Unable to load graph from "${t.href}"`),null}async#I(t){const e=await this.#x(t);return e||null}#j(t,e,r){if(!r)return console.warn(`No subgraphs to load "#${e}" from`),null;const s=r[e];return s?(t&&(s.url=t.href),s):(console.warn(`No subgraph found for hash: #${e}`),null)}async load(t,e){const r=e.outerGraph;if(t.startsWith("#")&&r&&!r.url){const e=this.#j(null,t.substring(1),r.graphs);return e||console.warn(`Unable to load graph from "${t}"`),e}const s=G(e),n=new URL(t,s);if(!n.hash)return await this.#I(n);if(r){const t=r.url?new URL(r.url):T;if(i=t,D(n).href===D(i).href){const t=n.hash.substring(1);return this.#j(n,t,r.graphs)}}var i;const o=await this.#I(D(n));return o?this.#j(n,n.hash.substring(1),o.graphs):null}}
*/const R=new URL("sentinel://sentinel/sentinel"),L=t=>{const e=new URL(t.href);return e.hash="",e},D=t=>{if(t.outerGraph?.url)return new URL(t.outerGraph.url);const e=t.board?.url;return e?new URL(e):t.base?t.base:R};class U{#E;constructor(t){this.#E=[...t,new M]}async#A(t){for(const e of this.#E){const r=e.canProvide(t);if(!1!==r&&r.load){const r=await e.load(t);if(null!==r)return r.nodes?.map((t=>{"superWorker"===t.type&&(console.warn("superWorker encountered, converting to specialist"),t.type="specialist")})),r.url=t.href,r}}return console.warn(`Unable to load graph from "${t.href}"`),null}async#x(t){const e=await this.#A(t);return e||null}#I(t,e,r){if(!r)return console.warn(`No subgraphs to load "#${e}" from`),null;const s=r[e];return s?(t&&(s.url=t.href),s):(console.warn(`No subgraph found for hash: #${e}`),null)}async load(t,e){const r=e.outerGraph;if(t.startsWith("#")&&r&&!r.url){const e=this.#I(null,t.substring(1),r.graphs);return e||console.warn(`Unable to load graph from "${t}"`),e}const s=D(e),n=new URL(t,s);if(!n.hash)return await this.#x(n);if(r){const t=r.url?new URL(r.url):R;if(i=t,L(n).href===L(i).href){const t=n.hash.substring(1);return this.#I(n,t,r.graphs)}}var i;const o=await this.#x(L(n));return o?this.#I(n,n.hash.substring(1),o.graphs):null}}
/**

@@ -89,3 +89,3 @@ * @license

* SPDX-License-Identifier: Apache-2.0
*/const F=t=>new U(t??[]),L=t=>!!t&&"board"===t.kind,z=t=>!!t.path,B=(t,e)=>{const r=t.path;return{kind:"board",url:new URL(r,e).href}},_=async(t,e,r)=>{const s=await t;return V(s,e,r),Promise.resolve(s)},V=(t,e,r)=>{for(const s in t){const n=t[s];if(L(n)&&z(n)){const i=r?new URL(r):G(e);t[s]=B(n,i)}}return t};
*/const G=t=>new U(t??[]),F=t=>!!t&&"board"===t.kind,T=t=>!!t.path,z=(t,e)=>{const r=t.path;return{kind:"board",url:new URL(r,e).href}},_=async(t,e,r)=>{const s=await t;return V(s,e,r),Promise.resolve(s)},V=(t,e,r)=>{for(const s in t){const n=t[s];if(F(n)&&T(n)){const i=r?new URL(r):D(e);t[s]=z(n,i)}}return t};
/**

@@ -101,3 +101,3 @@ * @license

*/
class W{url;title;description;$schema;version;edges=[];nodes=[];kits=[];graphs;args;#N={};#M=[];constructor({url:t,title:e,description:r,version:s,$schema:n}={$schema:q}){Object.assign(this,{$schema:n??q,url:t,title:e,description:r,version:s})}async*run(t={},e){const{inputs:r,...n}=t,i=n.base||T;var o;yield*(o=async r=>{const{probe:o}=n,a=await W.handlersFromBoard(this,n.kits),u={...this.#N,...n.slots};this.#M.forEach((t=>t.addGraph(this)));const c=new h(this,e?.state),p=new E(t),d=n.invocationPath||[],l=new C(n.state);await(o?.report?.({type:"graphstart",data:{graph:this,path:d,timestamp:f()}}));let g=0;l.onGraphStart();const w=()=>[...d,g];for await(const t of c){n?.signal?.throwIfAborted(),g++;const{inputs:e,descriptor:c,missingInputs:h}=t;if(t.skip){await(o?.report?.({type:"skip",data:{node:c,inputs:e,missingInputs:h,path:w(),timestamp:f()}}));continue}let d;if(l.onNodeStart(t),await(o?.report?.({type:"nodestart",data:{node:c,inputs:e,path:w(),timestamp:f()},state:await l.state()})),"input"===c.type)await r(new m(t,await l.state(),g,w())),await P(this,n,c,t,w()),d=t.outputsPromise?_(t.outputsPromise,n,this.url):void 0;else if("output"===c.type)await x(e,c,n,w())||await r(new y(t,g,w())),d=t.outputsPromise;else{const o=a[c.type];if(!o)throw new Error(`No handler for node type "${c.type}"`);const h={...n,descriptor:c,board:this,outerGraph:this,base:i,slots:u,kits:[...n.kits||[],...this.kits],requestInput:p.createHandler(r,t),provideOutput:I(r,t,n),invocationPath:w(),state:await l.state()};d=s(o,V(e,n,this.url),h)}l.onNodeEnd(),await(o?.report?.({type:"nodeend",data:{node:c,inputs:e,outputs:await d,validatorMetadata:this.#M.map((t=>t.getValidatorMetadata(c))),path:w(),timestamp:f()}})),t.outputsPromise=d}l.onGraphEnd(),await(o?.report?.({type:"graphend",data:{path:d,timestamp:f()}}))},{[Symbol.asyncIterator]:()=>new M(o)})}get validators(){return this.#M}async runOnce(t,e={}){const r={...t,...this.args},{probe:s}=e;if(e.board&&e.descriptor)for(const t of e.board.validators)this.addValidator(t.getSubgraphValidator(e.descriptor,Object.keys(r)));try{let t={};const n=e.invocationPath||[];for await(const i of this.run(e))if("input"===i.type)i.inputs=r;else if("output"===i.type){t=i.outputs,await(s?.report?.({type:"nodeend",data:{node:i.node,inputs:i.inputs,outputs:t,path:[...n,i.invocationId],timestamp:f()}})),await(s?.report?.({type:"graphend",data:{path:n,timestamp:f()}}));break}return t}catch(t){if(t.cause)return{$error:t.cause};throw t}}addValidator(t){this.#M.push(t)}mermaid(t="TD",e=!1,r=!1){return((t,e="TD",r=!1,s=!1)=>{const n=new v(t).describeGraph(s);return r?((t,e)=>`graph ${e};\n${t}`)(n,e):((t,e)=>`%%{init: 'themeVariables': { 'fontFamily': 'Fira Code, monospace' }}%%\ngraph ${e};\n${t}\nclassDef default stroke:#ffab40,fill:#fff2ccff,color:#000\nclassDef input stroke:#3c78d8,fill:#c9daf8ff,color:#000\nclassDef output stroke:#38761d,fill:#b6d7a8ff,color:#000\nclassDef passthrough stroke:#a64d79,fill:#ead1dcff,color:#000\nclassDef slot stroke:#a64d79,fill:#ead1dcff,color:#000\nclassDef config stroke:#a64d79,fill:#ead1dcff,color:#000\nclassDef secrets stroke:#db4437,fill:#f4cccc,color:#000\nclassDef slotted stroke:#a64d79`)(n,e)})(this,t,e,r)}static async fromGraphDescriptor(t){const e=new W(t);return e.edges=t.edges,e.nodes=t.nodes,e.graphs=t.graphs,e.args=t.args,e}static async load(t,e){const{base:r,slotted:s,outerGraph:n}=e||{},i=F(e.graphProviders),o=await i.load(t,{base:r,outerGraph:n});if(!o)throw new Error(`Unable to load graph from "${t}"`);const a=await W.fromGraphDescriptor(o);return a.#N=s||{},a}static async fromBreadboardCapability(t,e,r){if(!L(t))throw new Error(`Expected a "board" Capability, but got "${JSON.stringify(t)}`);if((t=>{const e=t.board;return!!e&&!!e.edges&&!!e.nodes})(t)){const e=t.board,r=e;return r.runOnce?r:await W.fromGraphDescriptor(e)}if((t=>!!t.url)(t)){if(!e||!r)throw new Error('The "board" Capability is a URL, but no loader and/or context was supplied.');const s=await e.load(t.url,r);if(!s)throw new Error(`Unable to load "board" Capability with the URL of ${t.url}.`);return W.fromGraphDescriptor(s)}if(z(t))throw new Error('Integrity error: somehow, the unresolved path "board" Capability snuck through the processing of inputs');throw new Error('Unsupported type of "board" Capability. Perhaps the supplied board isn\'t actually a GraphDescriptor?')}static async handlersFromBoard(t,e=[]){const r=[new H,...e,...t.kits];return n(r)}}class H{handlers;constructor(){this.handlers={lambda:{describe:async t=>({inputSchema:(new e).setAdditionalProperties(!0).addInputs(t).addProperty("board",{title:"board",description:"The board to run.",type:"object"}).build(),outputSchema:(new e).addProperty("board",{title:"board",description:"The now-runnable board.",type:"object"}).build()}),invoke:async t=>{const{board:e,...r}=t;if(!e||"board"!==e.kind||!e.board)throw new Error('Lambda node requires a BoardCapability as "board" input');const s={...await W.fromBreadboardCapability(e),args:r};return{board:{...e,board:s}}}}}}}
class W{url;title;description;$schema;version;edges=[];nodes=[];kits=[];graphs;args;#j={};#N=[];constructor({url:t,title:e,description:r,version:s,$schema:n}={$schema:B}){Object.assign(this,{$schema:n??B,url:t,title:e,description:r,version:s})}async*run(t={},e){const{inputs:r,...n}=t,i=n.base||R;var o;yield*(o=async r=>{const{probe:o}=n,a=await W.handlersFromBoard(this,n.kits),u={...this.#j,...n.slots};this.#N.forEach((t=>t.addGraph(this)));const p=new c(this,e?.state),h=new O(t),d=n.invocationPath||[],l=new C(n.state);await(o?.report?.({type:"graphstart",data:{graph:this,path:d,timestamp:f()}}));let m=0;l.onGraphStart();const w=()=>[...d,m];for await(const t of p){n?.signal?.throwIfAborted(),m++;const{inputs:e,descriptor:p,missingInputs:c}=t;if(t.skip){await(o?.report?.({type:"skip",data:{node:p,inputs:e,missingInputs:c,path:w(),timestamp:f()}}));continue}let d;if(l.onNodeStart(t),await(o?.report?.({type:"nodestart",data:{node:p,inputs:e,path:w(),timestamp:f()},state:await l.state()})),"input"===p.type)await r(new g(t,await l.state(),m,w())),await $(this,n,p,t,w()),d=t.outputsPromise?_(t.outputsPromise,n,this.url):void 0;else if("output"===p.type)await A(e,p,n,w())||await r(new y(t,m,w())),d=t.outputsPromise;else{const o=a[p.type];if(!o)throw new Error(`No handler for node type "${p.type}"`);const c={...n,descriptor:p,board:this,outerGraph:this,base:i,slots:u,kits:[...n.kits||[],...this.kits],requestInput:h.createHandler(r,t),provideOutput:x(r,t,n),invocationPath:w(),state:await l.state()};d=s(o,V(e,n,this.url),c)}l.onNodeEnd(),await(o?.report?.({type:"nodeend",data:{node:p,inputs:e,outputs:await d,validatorMetadata:this.#N.map((t=>t.getValidatorMetadata(p))),path:w(),timestamp:f()}})),t.outputsPromise=d}l.onGraphEnd(),await(o?.report?.({type:"graphend",data:{path:d,timestamp:f()}}))},{[Symbol.asyncIterator]:()=>new N(o)})}get validators(){return this.#N}async runOnce(t,e={}){const r={...t,...this.args},{probe:s}=e;if(e.board&&e.descriptor)for(const t of e.board.validators)this.addValidator(t.getSubgraphValidator(e.descriptor,Object.keys(r)));try{let t={};const n=e.invocationPath||[];for await(const i of this.run(e))if("input"===i.type)i.inputs=r;else if("output"===i.type){t=i.outputs,await(s?.report?.({type:"nodeend",data:{node:i.node,inputs:i.inputs,outputs:t,path:[...n,i.invocationId],timestamp:f()}})),await(s?.report?.({type:"graphend",data:{path:n,timestamp:f()}}));break}return t}catch(t){if(t.cause)return{$error:t.cause};throw t}}addValidator(t){this.#N.push(t)}mermaid(t="TD",e=!1,r=!1){return((t,e="TD",r=!1,s=!1)=>{const n=new v(t).describeGraph(s);return r?((t,e)=>`graph ${e};\n${t}`)(n,e):((t,e)=>`%%{init: 'themeVariables': { 'fontFamily': 'Fira Code, monospace' }}%%\ngraph ${e};\n${t}\nclassDef default stroke:#ffab40,fill:#fff2ccff,color:#000\nclassDef input stroke:#3c78d8,fill:#c9daf8ff,color:#000\nclassDef output stroke:#38761d,fill:#b6d7a8ff,color:#000\nclassDef passthrough stroke:#a64d79,fill:#ead1dcff,color:#000\nclassDef slot stroke:#a64d79,fill:#ead1dcff,color:#000\nclassDef config stroke:#a64d79,fill:#ead1dcff,color:#000\nclassDef secrets stroke:#db4437,fill:#f4cccc,color:#000\nclassDef slotted stroke:#a64d79`)(n,e)})(this,t,e,r)}static async fromGraphDescriptor(t){const e=new W(t);return e.edges=t.edges,e.nodes=t.nodes,e.graphs=t.graphs,e.args=t.args,e}static async load(t,e){const{base:r,slotted:s,outerGraph:n}=e||{},i=G(e.graphProviders),o=await i.load(t,{base:r,outerGraph:n});if(!o)throw new Error(`Unable to load graph from "${t}"`);const a=await W.fromGraphDescriptor(o);return a.#j=s||{},a}static async fromBreadboardCapability(t,e,r){if(!F(t))throw new Error(`Expected a "board" Capability, but got "${JSON.stringify(t)}`);if((t=>{const e=t.board;return!!e&&!!e.edges&&!!e.nodes})(t)){const e=t.board,r=e;return r.runOnce?r:await W.fromGraphDescriptor(e)}if((t=>!!t.url)(t)){if(!e||!r)throw new Error('The "board" Capability is a URL, but no loader and/or context was supplied.');const s=await e.load(t.url,r);if(!s)throw new Error(`Unable to load "board" Capability with the URL of ${t.url}.`);return W.fromGraphDescriptor(s)}if(T(t))throw new Error('Integrity error: somehow, the unresolved path "board" Capability snuck through the processing of inputs');throw new Error('Unsupported type of "board" Capability. Perhaps the supplied board isn\'t actually a GraphDescriptor?')}static async handlersFromBoard(t,e=[]){const r=[new H,...e,...t.kits];return n(r)}}class H{handlers;constructor(){this.handlers={lambda:{describe:async t=>({inputSchema:(new e).setAdditionalProperties(!0).addInputs(t).addProperty("board",{title:"board",description:"The board to run.",type:"object"}).build(),outputSchema:(new e).addProperty("board",{title:"board",description:"The now-runnable board.",type:"object"}).build()}),invoke:async t=>{const{board:e,...r}=t;if(!e||"board"!==e.kind||!e.board)throw new Error('Lambda node requires a BoardCapability as "board" input');const s={...await W.fromBreadboardCapability(e),args:r};return{board:{...e,board:s}}}}}}}
/**

@@ -123,3 +123,3 @@ * @license

* SPDX-License-Identifier: Apache-2.0
*/;class J extends K{id;type;outgoing=[];incoming=[];configuration={};metadata;#q;#A;constructor(t,e,r={}){super(),this.#A=e,"string"==typeof t?this.type=t:(this.type="fn",this.#q=t);const{$id:s,$metadata:n,...i}=r;this.id=s??Q.vendId(e,this.type),n&&(this.metadata=n),this.configuration=i}addIncomingEdge(t,e,r,s,n){if(t.#A!==this.#A)throw new Error("Can't connect nodes from different scopes");const i={to:this,from:t,out:e,in:r,schema:n};s&&(i.constant=!0),this.incoming.push(i),t.outgoing.push(i)}#R(t){const e=this.#q??t.getHandler(this.type);return e&&"describe"in e&&e.describe?e.describe:void 0}async invoke(t,e){const r=e??this.#A,s=this.#q??r.getHandler(this.type);let n;const i=s&&"invoke"in s&&s.invoke?s.invoke:"function"==typeof s?s:void 0;if(i)n=await i(t,this);else{if(!s||"function"==typeof s||!s.graph)throw new Error(`Can't find handler for ${this.id}`);{const e=s.graph.getPinnedNodes();if(1!==e.length)throw new Error("Expected exactly one graph");n=await r.invokeOneRound(t,e[0])}}return n}async describe(t=this.#A,e,r,s){const n=this.#R(t);return n?await n(e,r,s):void 0}async serialize(t){return this.#A.serialize(t,this)}async serializeNode(){const t={id:this.id,type:this.type,configuration:this.configuration};return this.metadata&&(t.metadata=this.metadata),[t]}}
*/;class J extends K{id;type;outgoing=[];incoming=[];configuration={};metadata;#B;#q;constructor(t,e,r={}){super(),this.#q=e,"string"==typeof t?this.type=t:(this.type="fn",this.#B=t);const{$id:s,$metadata:n,...i}=r;this.id=s??Q.vendId(e,this.type),n&&(this.metadata=n),this.configuration=i}addIncomingEdge(t,e,r,s,n){if(t.#q!==this.#q)throw new Error("Can't connect nodes from different scopes");const i={to:this,from:t,out:e,in:r,schema:n};s&&(i.constant=!0),this.incoming.push(i),t.outgoing.push(i)}#M(t){const e=this.#B??t.getHandler(this.type);return e&&"describe"in e&&e.describe?e.describe:void 0}async invoke(t,e){const r=e??this.#q,s=this.#B??r.getHandler(this.type);let n;const i=s&&"invoke"in s&&s.invoke?s.invoke:"function"==typeof s?s:void 0;if(i)n=await i(t,this);else{if(!s||"function"==typeof s||!s.graph)throw new Error(`Can't find handler for ${this.id}`);{const e=s.graph.getPinnedNodes();if(1!==e.length)throw new Error("Expected exactly one graph");n=await r.invokeOneRound(t,e[0])}}return n}async describe(t=this.#q,e,r,s){const n=this.#M(t);return n?await n(e,r,s):void 0}async serialize(t){return this.#q.serialize(t,this)}async serializeNode(){const t={id:this.id,type:this.type,configuration:this.configuration};return this.metadata&&(t.metadata=this.metadata),[t]}}
/**

@@ -134,3 +134,3 @@ * @license

* SPDX-License-Identifier: Apache-2.0
*/class Y{parentLexicalScope;parentDynamicScope;#T={};#D=[];#G=[];constructor(t={}){this.parentLexicalScope=t.lexicalScope,this.parentDynamicScope=t.dynamicScope}addHandlers(t){Object.entries(t).forEach((([t,e])=>this.#T[t]=e))}getHandler(t){return this.#T[t]||this.parentDynamicScope?.getHandler(t)||this.parentLexicalScope?.getHandler(t)}pin(t){this.#D.push(t)}compactPins(){const t=new Set,e=[];for(const r of this.#D){if(t.has(r))continue;e.push(r);this.#U(r).forEach((e=>t.add(e)))}this.#D=e}getPinnedNodes(){return this.#D}addCallbacks(t){this.#G.push(t)}#F(){return[...this.#G,...this.parentDynamicScope?this.parentDynamicScope.#F():[]]}async invoke(t,e=new X){try{!1!==t&&(t?t instanceof Array?t:[t]:this.#D).flatMap((t=>this.#U(t).filter((t=>!1===e?.missingInputs(t))))).forEach((t=>e?.queueUp(t)));const r=this.#F();for(;!e.done();){for(const t of r)if(await(t.stop?.(this,e)))return;const t=e.next(),s=e.shiftInputs(t);let n;for(const e of r)n??=await(e.before?.(this,t,s));const i=n??await t.invoke(s,this).catch((t=>({$error:{type:"error",error:t}}))),o=e.processResult(t,i);for(const e of r)await(e.after?.(this,t,s,i,o));if(o.unused.includes("$error"))throw i.$error.error}}finally{for(const t of this.#G)await(t.done?.())}}invokeOneRound(t={},e=void 0,r){let s;"$state"in t&&(r=t.$state,delete t.$state);const n=new Promise((t=>{s=t})),i=new Y({dynamicScope:this});let o;i.addHandlers({input:async()=>t,output:async t=>(s?.(await t),s=void 0,t)});const a=new Map;let u;i.addCallbacks({stop:(t,e)=>(s||(u=e),!s),after:(t,e,r,s,n)=>{o=e;for(const{node:t,missing:e}of n.nodes)e?a.set(t.id,e.join(", ")):a.delete(t.id)},done:()=>{s?.({$error:{type:"error",error:new Error(`Output node never reached. Last node was ${o?.id}.\n\nThese nodes had inputs missing:\n${Array.from(a,(([t,e])=>` ${t}: ${e}`)).join("\n")}`)}})}});const c=i.invoke(void 0!==e?e:this.#D,r);return Promise.all([n,c]).then((([t])=>({...t,...u?{$state:u}:{}})))}async serialize(t,e){const r=(e?[e]:this.#D).flatMap((t=>this.#U(t))),s={},n=await Promise.all(r.map((async t=>{const[e,r]=await t.serializeNode();if(r&&(s[e.id]=r),("input"===e.type||"output"===e.type)&&!e.configuration?.schema){const r=await this.#L(t);Object.entries(r.properties??{}).length>0&&(e.configuration={...e.configuration,schema:r})}return e}))),i=r.flatMap((t=>t.outgoing.map((t=>({from:t.from.id,to:t.to.id,out:t.out,in:t.in,...t.constant?{constant:!0}:{}})))));return{...t,edges:i,nodes:n,graphs:s}}#U(t){const e=new Set,r=[t];for(;r.length;){const t=r.shift();e.has(t)||(e.add(t),t.incoming.forEach((t=>r.push(t.from))),t.outgoing.forEach((t=>r.push(t.to))))}return[...e]}async#z(t){const e=Object.fromEntries(t.incoming.filter((t=>""!==t.out&&"*"!==t.out)).map((t=>[t.out,t.schema??{}]))),r=Object.fromEntries(t.outgoing.filter((t=>""!==t.out&&"*"!==t.out)).map((t=>[t.out,t.schema??{}])));return await t.describe(this,t.configuration,{properties:e},{properties:r})}async#L(t){const e={},r=new Set;let s;if("input"===t.type){const n=new Set;for(const s of t.outgoing)"*"!==s.out&&""!==s.out&&(n.add(s.to),r.add(s.out),s.schema&&(e[s.out]=s.schema));for(const r of n){const s=await this.#z(r),n=s?.inputSchema?.properties;if(n)for(const s of r.incoming)s.from===t&&n[s.in]&&(e[s.out]={...n[s.in],...e[s.out]})}s=(t=>Object.entries(t).map((([t,e])=>{const r=e;if(!r.$optional)return t;delete r.$optional})).filter(Boolean))(e)}else{if("output"!==t.type)throw new Error("Can't yet derive schema for non-input/output nodes");{const s=new Set;for(const n of t.incoming)"*"!==n.out&&""!==n.out&&(s.add(n.from),r.add(n.in),n.schema&&(e[n.in]=n.schema));for(const r of s){const s=await this.#z(r),n=s?.outputSchema?.properties;if(n)for(const s of r.outgoing)s.to===t&&n[s.out]&&(e[s.in]={...n[s.out],...e[s.in]})}}}for(const t of r)e[t]?(e[t].type||="string",e[t].title||=t):e[t]={type:"string",title:t};const n={type:"object",properties:e};return s&&(n.required=s),n}}
*/class Y{parentLexicalScope;parentDynamicScope;#R={};#L=[];#D=[];constructor(t={}){this.parentLexicalScope=t.lexicalScope,this.parentDynamicScope=t.dynamicScope}addHandlers(t){Object.entries(t).forEach((([t,e])=>this.#R[t]=e))}getHandler(t){return this.#R[t]||this.parentDynamicScope?.getHandler(t)||this.parentLexicalScope?.getHandler(t)}pin(t){this.#L.push(t)}compactPins(){const t=new Set,e=[];for(const r of this.#L){if(t.has(r))continue;e.push(r);this.#U(r).forEach((e=>t.add(e)))}this.#L=e}getPinnedNodes(){return this.#L}addCallbacks(t){this.#D.push(t)}#G(){return[...this.#D,...this.parentDynamicScope?this.parentDynamicScope.#G():[]]}async invoke(t,e=new X){try{!1!==t&&(t?t instanceof Array?t:[t]:this.#L).flatMap((t=>this.#U(t).filter((t=>!1===e?.missingInputs(t))))).forEach((t=>e?.queueUp(t)));const r=this.#G();for(;!e.done();){for(const t of r)if(await(t.stop?.(this,e)))return;const t=e.next(),s=e.shiftInputs(t);let n;for(const e of r)n??=await(e.before?.(this,t,s));const i=n??await t.invoke(s,this).catch((t=>({$error:{type:"error",error:t}}))),o=e.processResult(t,i);for(const e of r)await(e.after?.(this,t,s,i,o));if(o.unused.includes("$error"))throw i.$error.error}}finally{for(const t of this.#D)await(t.done?.())}}invokeOneRound(t={},e=void 0,r){let s;"$state"in t&&(r=t.$state,delete t.$state);const n=new Promise((t=>{s=t})),i=new Y({dynamicScope:this});let o;i.addHandlers({input:async()=>t,output:async t=>(s?.(await t),s=void 0,t)});const a=new Map;let u;i.addCallbacks({stop:(t,e)=>(s||(u=e),!s),after:(t,e,r,s,n)=>{o=e;for(const{node:t,missing:e}of n.nodes)e?a.set(t.id,e.join(", ")):a.delete(t.id)},done:()=>{s?.({$error:{type:"error",error:new Error(`Output node never reached. Last node was ${o?.id}.\n\nThese nodes had inputs missing:\n${Array.from(a,(([t,e])=>` ${t}: ${e}`)).join("\n")}`)}})}});const p=i.invoke(void 0!==e?e:this.#L,r);return Promise.all([n,p]).then((([t])=>({...t,...u?{$state:u}:{}})))}async serialize(t,e){const r=(e?[e]:this.#L).flatMap((t=>this.#U(t))),s={},n=await Promise.all(r.map((async t=>{const[e,r]=await t.serializeNode();if(r&&(s[e.id]=r),("input"===e.type||"output"===e.type)&&!e.configuration?.schema){const r=await this.#F(t);Object.entries(r.properties??{}).length>0&&(e.configuration={...e.configuration,schema:r})}return e}))),i=r.flatMap((t=>t.outgoing.map((t=>({from:t.from.id,to:t.to.id,out:t.out,in:t.in,...t.constant?{constant:!0}:{}})))));return{...t,edges:i,nodes:n,graphs:s}}#U(t){const e=new Set,r=[t];for(;r.length;){const t=r.shift();e.has(t)||(e.add(t),t.incoming.forEach((t=>r.push(t.from))),t.outgoing.forEach((t=>r.push(t.to))))}return[...e]}async#T(t){const e=Object.fromEntries(t.incoming.filter((t=>""!==t.out&&"*"!==t.out)).map((t=>[t.out,t.schema??{}]))),r=Object.fromEntries(t.outgoing.filter((t=>""!==t.out&&"*"!==t.out)).map((t=>[t.out,t.schema??{}])));return await t.describe(this,t.configuration,{properties:e},{properties:r})}async#F(t){const e={},r=new Set;let s;if("input"===t.type){const n=new Set;for(const s of t.outgoing)"*"!==s.out&&""!==s.out&&(n.add(s.to),r.add(s.out),s.schema&&(e[s.out]=s.schema));for(const r of n){const s=await this.#T(r),n=s?.inputSchema?.properties;if(n)for(const s of r.incoming)s.from===t&&n[s.in]&&(e[s.out]={...n[s.in],...e[s.out]})}s=(t=>Object.entries(t).map((([t,e])=>{const r=e;if(!r.$optional)return t;delete r.$optional})).filter(Boolean))(e)}else{if("output"!==t.type)throw new Error("Can't yet derive schema for non-input/output nodes");{const s=new Set;for(const n of t.incoming)"*"!==n.out&&""!==n.out&&(s.add(n.from),r.add(n.in),n.schema&&(e[n.in]=n.schema));for(const r of s){const s=await this.#T(r),n=s?.outputSchema?.properties;if(n)for(const s of r.outgoing)s.to===t&&n[s.out]&&(e[s.in]={...n[s.out],...e[s.in]})}}}for(const t of r)e[t]?(e[t].type||="string",e[t].title||=t):e[t]={type:"string",title:t};const n={type:"object",properties:e};return s&&(n.required=s),n}}
/**

@@ -140,3 +140,3 @@ * @license

* SPDX-License-Identifier: Apache-2.0
*/class Z extends Y{#B;#_=[];parentLambdaNode;constructor(t={}){super(t),this.#B=t.serialize??!1,this.parentLambdaNode=t.parentLambda}async serialize(t,e){return super.serialize(t,e&&"function"==typeof e.unProxy?e.unProxy():e)}serializing(){return this.#B}asScopeFor(t){return(...e)=>{const r=rt(this);try{return t(...e)}finally{rt(r)}}}addClosureEdge(t){this.#_.push(t)}getClosureEdges(){return this.#_}}let tt;function et(){return tt||(tt=new Z),tt}function rt(t){const e=et();return tt=t,e}
*/class Z extends Y{#z;#_=[];parentLambdaNode;constructor(t={}){super(t),this.#z=t.serialize??!1,this.parentLambdaNode=t.parentLambda}async serialize(t,e){return super.serialize(t,e&&"function"==typeof e.unProxy?e.unProxy():e)}serializing(){return this.#z}asScopeFor(t){return(...e)=>{const r=rt(this);try{return t(...e)}finally{rt(r)}}}addClosureEdge(t){this.#_.push(t)}getClosureEdges(){return this.#_}}let tt;function et(){return tt||(tt=new Z),tt}function rt(t){const e=et();return tt=t,e}
/**

@@ -151,3 +151,3 @@ * @license

* SPDX-License-Identifier: Apache-2.0
*/const nt=Symbol("IsValue");function it(t){return("object"==typeof t||"function"==typeof t)&&void 0!==t[nt]}const ot=t=>{if("array"===t.type){t.items??={};const r=(e=t.items,Array.isArray(e)?t.items[0]:t.items);return r.type??="object",r}var e;return t};class at extends st{#V;#A;#W;#H;#K;constructor(t,e,r,s=!1,n={}){super(),this.#V=t,this.#A=e,this.#W="string"==typeof r?{[r]:r}:r,this[nt]=this,this.#H=s,this.#K=n}then(t,e){if(1!==Object.keys(this.#W).length)throw Error("Can't `await` for multiple values");return this.#V.then((e=>e&&t&&this.#A.asScopeFor(t)(e[Object.keys(this.#W)[0]])),e&&this.#A.asScopeFor(e))}asNodeInput(){return[this.#V.unProxy(),this.#W,this.#H,this.#K]}to(t,e){const r=ct(t)?t.unProxy():new ut(t,this.#A,e);return r.addInputsFromNode(this.#V,this.#W,this.#H,this.#K),r.asProxy()}in(t){let e=Object.fromEntries(Object.entries(this.#W).map((([t,e])=>[e,t])));it(t)?(e=t.#Q(e),this.#V.addInputsFromNode(t.#V,e,t.#H,t.#K)):ct(t)?this.#V.addInputsFromNode(t.unProxy(),e):this.#V.addInputsAsValues(t)}as(t){let e;if("string"==typeof t){if(1!==Object.keys(this.#W).length)throw new Error("Can't rename multiple values with a single string");e={[Object.keys(this.#W)[0]]:t}}else e=this.#Q(t);return new at(this.#V,this.#A,e,this.#H,this.#K)}memoize(){return new at(this.#V,this.#A,this.#W,!0,this.#K)}invoke(t){return new ut("invoke",this.#A,{...t,$board:this}).asProxy()}isUnknown(){return delete this.#K.type,this}isString(){return this.#K.type="string",this}isNumber(){return this.#K.type="number",this}isBoolean(){return this.#K.type="boolean",this}isArray(){return this.#K.type="array",this}isObject(){return this.#K.type="object",this}title(t){return this.#K.title=t,this}description(t){return this.#K.description=t,this}format(t){return ot(this.#K).format=t,this}examples(...t){return this.#K.examples=t,this}default(t){return this.#K.default=t,this}optional(){return this.#K.$optional=!0,this}behavior(...t){const e=ot(this.#K);return e.behavior??=[],e.behavior.push(...t),this}#Q(t){const e={...this.#W};return Object.entries(t).forEach((([t,r])=>{this.#W[r]?(e[t]=this.#W[r],delete this.#W[r]):e[t]=r})),e}}
*/const nt=Symbol("IsValue");function it(t){return("object"==typeof t||"function"==typeof t)&&void 0!==t[nt]}const ot=t=>{if("array"===t.type){t.items??={};const r=(e=t.items,Array.isArray(e)?t.items[0]:t.items);return r.type??="object",r}var e;return t};class at extends st{#V;#q;#W;#H;#K;constructor(t,e,r,s=!1,n={}){super(),this.#V=t,this.#q=e,this.#W="string"==typeof r?{[r]:r}:r,this[nt]=this,this.#H=s,this.#K=n}then(t,e){if(1!==Object.keys(this.#W).length)throw Error("Can't `await` for multiple values");return this.#V.then((e=>e&&t&&this.#q.asScopeFor(t)(e[Object.keys(this.#W)[0]])),e&&this.#q.asScopeFor(e))}asNodeInput(){return[this.#V.unProxy(),this.#W,this.#H,this.#K]}to(t,e){const r=pt(t)?t.unProxy():new ut(t,this.#q,e);return r.addInputsFromNode(this.#V,this.#W,this.#H,this.#K),r.asProxy()}in(t){let e=Object.fromEntries(Object.entries(this.#W).map((([t,e])=>[e,t])));it(t)?(e=t.#Q(e),this.#V.addInputsFromNode(t.#V,e,t.#H,t.#K)):pt(t)?this.#V.addInputsFromNode(t.unProxy(),e):this.#V.addInputsAsValues(t)}as(t){let e;if("string"==typeof t){if(1!==Object.keys(this.#W).length)throw new Error("Can't rename multiple values with a single string");e={[Object.keys(this.#W)[0]]:t}}else e=this.#Q(t);return new at(this.#V,this.#q,e,this.#H,this.#K)}memoize(){return new at(this.#V,this.#q,this.#W,!0,this.#K)}invoke(t){return new ut("invoke",this.#q,{...t,$board:this}).asProxy()}isUnknown(){return delete this.#K.type,this}isString(){return this.#K.type="string",this}isNumber(){return this.#K.type="number",this}isBoolean(){return this.#K.type="boolean",this}isArray(){return this.#K.type="array",this}isObject(){return this.#K.type="object",this}title(t){return this.#K.title=t,this}description(t){return this.#K.description=t,this}format(t){return ot(this.#K).format=t,this}examples(...t){return this.#K.examples=t,this}default(t){return this.#K.default=t,this}optional(){return this.#K.$optional=!0,this}behavior(...t){const e=ot(this.#K);return e.behavior??=[],e.behavior.push(...t),this}#Q(t){const e={...this.#W};return Object.entries(t).forEach((([t,r])=>{this.#W[r]?(e[t]=this.#W[r],delete this.#W[r]):e[t]=r})),e}}
/**

@@ -157,3 +157,3 @@ * @license

* SPDX-License-Identifier: Apache-2.0
*/class ut extends J{#J;#X;#Y;#A;#q;constructor(t,e,r={}){const s=!ct(r)&&!(r instanceof K)&&!pt(r)&&!it(r)&&r.$id;if(super(t,e,s?{$id:s}:{}),this.#A=e,"string"!=typeof t&&(this.#q=t),ct(r))this.addInputsFromNode(r.unProxy());else if(r instanceof K)this.addInputsFromNode(r);else if(pt(r))this.addInputsAsValues({$board:r.getBoardCapabilityAsValue()});else if(it(r))this.addInputsFromNode(...r.asNodeInput());else{void 0!==r.$id&&delete r.$id;const t=r.$metadata;void 0!==t&&(this.metadata=t,delete r.$metadata),this.addInputsAsValues(r)}this[this.#Z()]=this,this.#J=new Promise(((t,e)=>{this.#X=t,this.#Y=e}))}addInputsAsValues(t){const e={},r=[];Object.entries(t).forEach((([t,s])=>{pt(s)&&(s=s.getBoardCapabilityAsValue()),it(s)?r.push(s.as(t).asNodeInput()):s instanceof K||ct(s)?r.push([ct(s)?s.unProxy():s,{[t]:t},!1,void 0]):e[t]=s})),this.configuration={...this.configuration,...e},r.forEach((t=>this.unProxy().addInputsFromNode(...t)))}addInputsFromNode(t,e={"*":""},r,s){const n=Object.entries(e);0===n.length?this.addIncomingEdge(t,"","",r):n.forEach((([e,n])=>{e.startsWith("*-")&&(e="*",n=""),this.unProxy().addIncomingEdge(ct(t)?t.unProxy():t,e,n,r,s)}))}addIncomingEdge(t,e,r,s,n){const i=t.#A;if(i!==this.#A){for(let t=this.#A;t!==i;t=t.parentLexicalScope)if(!t)throw new Error("Only wires from parent scopes allowed");if("*"===e||""===e)throw new Error("Can't use * or empty wires from parent scopes");this.#A.addClosureEdge({scope:i,from:t,to:this,out:e,in:r})}else super.addIncomingEdge(t,e,r,s,n)}async invoke(t,e){const r=new Z({dynamicScope:e,lexicalScope:this.#A});return r.asScopeFor((async()=>{try{const e=this.#q??r.getHandler(this.type);let s;const n=e&&"invoke"in e&&e.invoke?e.invoke:"function"==typeof e?e:void 0;if(n)s=await n(t,this);else{if(!e||"function"==typeof e||!e.graph)throw new Error(`Can't find handler for ${this.id}`);{const n=e.graph.getPinnedNodes();if(1!==n.length)throw new Error("Expected exactly one graph");s=await r.invokeOneRound(t,n[0])}}for(const[t,e]of Object.entries(s))e instanceof ut?s[t]=(await e)[t]:it(e)?s[t]=await e:pt(e)&&(s[t]=await e.getBoardCapabilityAsValue());return this.#X&&(this.#X(s),this.#X=this.#Y=void 0),s}catch(t){throw this.#Y&&(this.#Y(t),this.#X=this.#Y=void 0),t}}))()}async serializeNode(){for(const[t,e]of Object.entries(this.configuration))e instanceof Promise&&(this.configuration[t]=await e);if("fn"!==this.type)return super.serializeNode();const t=new Z({lexicalScope:this.#A,serialize:!0}),e=this.#q??t.getHandler(this.type);if(e&&"function"!=typeof e&&e.graph){const r={id:this.id,type:"invoke",configuration:{...this.configuration,path:"#"+this.id}},s=e.graph.getPinnedNodes();if(1!==s.length)throw new Error("Expected exactly one graph");return[r,await t.serialize({},s[0])]}{const t=e&&"invoke"in e&&e.invoke?e.invoke:"function"==typeof e?e:void 0;if(!t)throw new Error(`Handler for ${this.type} in ${this.id} not found`);const r=this.id.replace(/-/g,"_"),[s,n]=((t,e)=>{let r=e.toString();const s=/(?:async\s+)?function\s+(\w+)\s*\(([^)]*)\)\s*\{/;if(/(?:async\s*)?(\w+|\([^)]*\))\s*=>\s*/.test(r))r=`const ${t} = ${r};`;else{const e=s.exec(r);if(null===e)throw new Error("Unexpected serialization: "+r);t=e[1]||t}return[r,t]})(r,t);return[{id:this.id,type:"runJavascript",configuration:{...this.configuration,code:s,name:n,raw:!0},metadata:this.metadata}]}}asProxy(){return new Proxy(this,{get(t,e,r){if("string"==typeof e){const r=new at(t,t.#A,e);let s=t[e];return s=s&&"function"==typeof s?s.bind(t):(t=>r.invoke(t)).bind(r),new Proxy(s,{get(t,e,s){const n=Reflect.get(r,e,r);return"function"==typeof n?n.bind(r):n},ownKeys:t=>Reflect.ownKeys(r).filter((t=>"string"==typeof t))})}return Reflect.get(t,e,r)},ownKeys:t=>[t.#Z()]})}unProxy(){return this}then(t,e){if(this.#A.serializing())throw new Error(`Can't \`await\` on ${this.id} in board declaration. Did you mean to use \`code\` instead of \`board\`?`);try{return this.#A.invoke(this).catch((t=>{if(e)return Promise.reject(t).catch(this.#A.asScopeFor(e));throw t})),this.#J.then(t&&this.#A.asScopeFor(t),e&&this.#A.asScopeFor(e))}catch(t){if(e)return Promise.reject(t).catch(this.#A.asScopeFor(e));throw t}}to(t,e){const r=ct(t)?t.unProxy():new ut(t,this.#A,e);return r.addInputsFromNode(this,{"*":""}),r.asProxy()}in(t){return t instanceof J?this.addInputsFromNode(t):it(t)?this.addInputsFromNode(...t.asNodeInput()):this.addInputsAsValues(t),this.asProxy()}as(t){return new at(this,this.#A,t)}keys(){return[this.#Z()]}#Z(){return"*-"+this.id}}function ct(t){return"function"==typeof t.unProxy}
*/class ut extends J{#J;#X;#Y;#q;#B;constructor(t,e,r={}){const s=!pt(r)&&!(r instanceof K)&&!ht(r)&&!it(r)&&r.$id;if(super(t,e,s?{$id:s}:{}),this.#q=e,"string"!=typeof t&&(this.#B=t),pt(r))this.addInputsFromNode(r.unProxy());else if(r instanceof K)this.addInputsFromNode(r);else if(ht(r))this.addInputsAsValues({$board:r.getBoardCapabilityAsValue()});else if(it(r))this.addInputsFromNode(...r.asNodeInput());else{void 0!==r.$id&&delete r.$id;const t=r.$metadata;void 0!==t&&(this.metadata=t,delete r.$metadata),this.addInputsAsValues(r)}this[this.#Z()]=this,this.#J=new Promise(((t,e)=>{this.#X=t,this.#Y=e}))}addInputsAsValues(t){const e={},r=[];Object.entries(t).forEach((([t,s])=>{ht(s)&&(s=s.getBoardCapabilityAsValue()),it(s)?r.push(s.as(t).asNodeInput()):s instanceof K||pt(s)?r.push([pt(s)?s.unProxy():s,{[t]:t},!1,void 0]):e[t]=s})),this.configuration={...this.configuration,...e},r.forEach((t=>this.unProxy().addInputsFromNode(...t)))}addInputsFromNode(t,e={"*":""},r,s){const n=Object.entries(e);0===n.length?this.addIncomingEdge(t,"","",r):n.forEach((([e,n])=>{e.startsWith("*-")&&(e="*",n=""),this.unProxy().addIncomingEdge(pt(t)?t.unProxy():t,e,n,r,s)}))}addIncomingEdge(t,e,r,s,n){const i=t.#q;if(i!==this.#q){for(let t=this.#q;t!==i;t=t.parentLexicalScope)if(!t)throw new Error("Only wires from parent scopes allowed");if("*"===e||""===e)throw new Error("Can't use * or empty wires from parent scopes");this.#q.addClosureEdge({scope:i,from:t,to:this,out:e,in:r})}else super.addIncomingEdge(t,e,r,s,n)}async invoke(t,e){const r=new Z({dynamicScope:e,lexicalScope:this.#q});return r.asScopeFor((async()=>{try{const e=this.#B??r.getHandler(this.type);let s;const n=e&&"invoke"in e&&e.invoke?e.invoke:"function"==typeof e?e:void 0;if(n)s=await n(t,this);else{if(!e||"function"==typeof e||!e.graph)throw new Error(`Can't find handler for ${this.id}`);{const n=e.graph.getPinnedNodes();if(1!==n.length)throw new Error("Expected exactly one graph");s=await r.invokeOneRound(t,n[0])}}for(const[t,e]of Object.entries(s))e instanceof ut?s[t]=(await e)[t]:it(e)?s[t]=await e:ht(e)&&(s[t]=await e.getBoardCapabilityAsValue());return this.#X&&(this.#X(s),this.#X=this.#Y=void 0),s}catch(t){throw this.#Y&&(this.#Y(t),this.#X=this.#Y=void 0),t}}))()}async serializeNode(){for(const[t,e]of Object.entries(this.configuration))e instanceof Promise&&(this.configuration[t]=await e);if("fn"!==this.type)return super.serializeNode();const t=new Z({lexicalScope:this.#q,serialize:!0}),e=this.#B??t.getHandler(this.type);if(e&&"function"!=typeof e&&e.graph){const r={id:this.id,type:"invoke",configuration:{...this.configuration,path:"#"+this.id}},s=e.graph.getPinnedNodes();if(1!==s.length)throw new Error("Expected exactly one graph");return[r,await t.serialize({},s[0])]}{const t=e&&"invoke"in e&&e.invoke?e.invoke:"function"==typeof e?e:void 0;if(!t)throw new Error(`Handler for ${this.type} in ${this.id} not found`);const r=this.id.replace(/-/g,"_"),[s,n]=((t,e)=>{let r=e.toString();const s=/(?:async\s+)?function\s+(\w+)\s*\(([^)]*)\)\s*\{/;if(/(?:async\s*)?(\w+|\([^)]*\))\s*=>\s*/.test(r))r=`const ${t} = ${r};`;else{const e=s.exec(r);if(null===e)throw new Error("Unexpected serialization: "+r);t=e[1]||t}return[r,t]})(r,t);return[{id:this.id,type:"runJavascript",configuration:{...this.configuration,code:s,name:n,raw:!0},metadata:this.metadata}]}}asProxy(){return new Proxy(this,{get(t,e,r){if("string"==typeof e){const r=new at(t,t.#q,e);let s=t[e];return s=s&&"function"==typeof s?s.bind(t):(t=>r.invoke(t)).bind(r),new Proxy(s,{get(t,e,s){const n=Reflect.get(r,e,r);return"function"==typeof n?n.bind(r):n},ownKeys:t=>Reflect.ownKeys(r).filter((t=>"string"==typeof t))})}return Reflect.get(t,e,r)},ownKeys:t=>[t.#Z()]})}unProxy(){return this}then(t,e){if(this.#q.serializing())throw new Error(`Can't \`await\` on ${this.id} in board declaration. Did you mean to use \`code\` instead of \`board\`?`);try{return this.#q.invoke(this).catch((t=>{if(e)return Promise.reject(t).catch(this.#q.asScopeFor(e));throw t})),this.#J.then(t&&this.#q.asScopeFor(t),e&&this.#q.asScopeFor(e))}catch(t){if(e)return Promise.reject(t).catch(this.#q.asScopeFor(e));throw t}}to(t,e){const r=pt(t)?t.unProxy():new ut(t,this.#q,e);return r.addInputsFromNode(this,{"*":""}),r.asProxy()}in(t){return t instanceof J?this.addInputsFromNode(t):it(t)?this.addInputsFromNode(...t.asNodeInput()):this.addInputsAsValues(t),this.asProxy()}as(t){return new at(this,this.#q,t)}keys(){return[this.#Z()]}#Z(){return"*-"+this.id}}function pt(t){return"function"==typeof t.unProxy}
/**

@@ -163,3 +163,3 @@ * @license

* SPDX-License-Identifier: Apache-2.0
*/function ht(t,e){return t&&function(t,e){et().addHandlers({[t]:e})}
*/function ct(t,e){return t&&function(t,e){et().addHandlers({[t]:e})}
/**

@@ -169,3 +169,3 @@ * @license

* SPDX-License-Identifier: Apache-2.0
*/(t,e),r=>new ut(t??e,et(),r).asProxy()}function pt(t){return"function"==typeof t&&"function"==typeof t.getBoardCapabilityAsValue}
*/(t,e),r=>new ut(t??e,et(),r).asProxy()}function ht(t){return"function"==typeof t&&"function"==typeof t.getBoardCapabilityAsValue}
/**

@@ -181,3 +181,3 @@ * @license

*/
var lt,ft;ht("input",dt),ht("output",dt),function(t){t.Ordinary="ordinary",t.Constant="constant",t.Control="control",t.Star="star"}(lt||(lt={})),function(t){t.Indeterminate="indeterminate",t.Connected="connected",t.Ready="ready",t.Missing="missing",t.Dangling="dangling"}(ft||(ft={}));class gt{#tt;#et;constructor(t,e){this.#tt=t,this.#et=e}get from(){const t=this.#tt.get(this.#et.from);return console.assert(t,"From node not found when getting from."),t}get out(){return this.#et.out}get to(){const t=this.#tt.get(this.#et.to);return console.assert(t,"To node not found when getting to."),t}get in(){return"*"===this.#et.out?"*":this.#et.in}get type(){return"*"===this.#et.out?lt.Star:""===this.#et.out?lt.Control:this.#et.constant?lt.Constant:lt.Ordinary}async validate(){const[t,e]=await Promise.all([await this.from.ports(),await this.to.ports()]),r=t.outputs.ports.find((t=>t.name===this.out)),s=e.inputs.ports.find((t=>t.name===this.in));return void 0===r||void 0===s?{status:"unknown"}:r.type.canConnect(s.type)?{status:"valid"}:{status:"invalid",errors:[{message:`The schema of "${this.in}" is not compatible with "${this.out}"`}]}}}class mt{#tt;#C=new Map;constructor(t){this.#tt=t}populate(t){return this.#C=new Map(t.edges.map((t=>[t,new gt(this.#tt,t)])))}get(t){return this.#C.get(t)}getOrCreate(t){let e=this.get(t);return e||(e=new gt(this.#tt,t),this.add(t),e)}add(t){console.assert(!this.#C.has(t),"Edge already exists when adding."),this.#C.set(t,new gt(this.#tt,t))}remove(t){console.assert(this.#C.has(t),"Edge not found when removing."),this.#C.delete(t)}has(t){return this.#C.has(t)}hasByValue(t){t=(t=>"*"===t.out?{...t,in:"*"}:t)(t);return!!this.edges().find((e=>e.from.descriptor.id===t.from&&e.to.descriptor.id===t.to&&e.out===t.out&&e.in===t.in))}edges(){return Array.from(this.#C.values())}}
var lt,ft;ct("input",dt),ct("output",dt),function(t){t.Ordinary="ordinary",t.Constant="constant",t.Control="control",t.Star="star"}(lt||(lt={})),function(t){t.Indeterminate="indeterminate",t.Connected="connected",t.Ready="ready",t.Missing="missing",t.Dangling="dangling"}(ft||(ft={}));class mt{#tt;#et;constructor(t,e){this.#tt=t,this.#et=e}get from(){const t=this.#tt.get(this.#et.from);return console.assert(t,"From node not found when getting from."),t}get out(){return this.#et.out}get to(){const t=this.#tt.get(this.#et.to);return console.assert(t,"To node not found when getting to."),t}get in(){return"*"===this.#et.out?"*":this.#et.in}get type(){return"*"===this.#et.out?lt.Star:""===this.#et.out?lt.Control:this.#et.constant?lt.Constant:lt.Ordinary}async outPort(){return(await this.from.ports()).outputs.ports.find((t=>t.name===this.out))}async inPort(){return(await this.to.ports()).inputs.ports.find((t=>t.name===this.in))}async validate(){const[t,e]=await Promise.all([this.outPort(),this.inPort()]);if(void 0===t||void 0===e)return{status:"unknown"};const r=t.type.analyzeCanConnect(e.type);return r.canConnect?{status:"valid"}:{status:"invalid",errors:r.details}}}class gt{#tt;#C=new Map;constructor(t){this.#tt=t}populate(t){return this.#C=new Map(t.edges.map((t=>[t,new mt(this.#tt,t)])))}get(t){return this.#C.get(t)}getOrCreate(t){let e=this.get(t);return e||(e=new mt(this.#tt,t),this.add(t),e)}add(t){console.assert(!this.#C.has(t),"Edge already exists when adding."),this.#C.set(t,new mt(this.#tt,t))}remove(t){console.assert(this.#C.has(t),"Edge not found when removing."),this.#C.delete(t)}has(t){return this.#C.has(t)}hasByValue(t){t=(t=>"*"===t.out?{...t,in:"*"}:t)(t);return!!this.edges().find((e=>e.from.descriptor.id===t.from&&e.to.descriptor.id===t.to&&e.out===t.out&&e.in===t.in))}edges(){return Array.from(this.#C.values())}}
/**

@@ -187,3 +187,3 @@ * @license

* SPDX-License-Identifier: Apache-2.0
*/var yt;!function(t){t[t.In=0]="In",t[t.Out=1]="Out"}(yt||(yt={}));const wt={type:"object",behavior:["json-schema","ports-spec","config"]},bt={type:"string"},vt=t=>{const e=t.type;return e===lt.Star||e===lt.Control},$t=(t,e,r=!1)=>e?e.reduce(((e,s)=>{if(!r&&vt(s))return e;const n=t===yt.In?s.in:s.out;return e[n]||(e[n]=bt),e}),{}):{},Pt=(t,r,s=!1)=>r?(new e).addProperties($t(t,r,s)).setAdditionalProperties(!0).build():{},kt=t=>{const s=t.inputs?.schema||{type:"object"},n=(new e).addProperty("schema",wt).build();let i=!1;const o=t.outgoing?.filter((t=>{const e=vt(t);return e&&(i=!0),!e})),a=r([Pt(yt.Out,o,!0),s]);return t.asType&&(i||(a.additionalProperties=!1)),{inputSchema:n,outputSchema:a}},St=t=>{const s=t.inputs?.schema||{type:"object"},n=(new e).setAdditionalProperties(!1).build(),i=(new e).addProperty("schema",wt),o=r([i.addProperties($t(yt.In,t.incoming,!0)).setAdditionalProperties(!0).build(),s]);if(t.asType){!!t.incoming?.find((t=>"*"===t.out))||(o.additionalProperties=!1)}return{inputSchema:o,outputSchema:n}},Et=(t,e)=>t.properties?.[e]?.title||e,Ot=(t,e,r,s)=>t?e?ft.Connected:s?ft.Indeterminate:ft.Dangling:r?s?ft.Indeterminate:ft.Missing:ft.Ready,xt=(t,e,r,s,n,i)=>{let o=!1;const a=e.map((e=>"*"===e.out?(o=!0,"*"):t===yt.In?e.in:e.out)),u=!1===r.additionalProperties,c=Object.keys(r.properties||{});s&&c.push("$error");const h=c.includes("*"),p=r.required||[],d=Object.keys(i||{}),l=[...new Set([...a,...c,...d,"*",""])];return l.sort(),l.map((s=>{const l="*"===s||""===s,f=d.includes(s),g=a.includes(s),m=c.includes(s)||l,y=p.includes(s),w=r.properties?.[s]||bt;return w.behavior?.includes("deprecated")&&!g?null:{name:s,title:Et(r,s),configured:f,value:i?.[s],star:l,get edges(){return g?e.filter((e=>!("*"!==e.out||!l)||(t===yt.In?e.in===s:e.out===s))):[]},status:Ot(g||f,!u||m||h,n&&y,o),schema:w,type:new It(w)}})).filter(Boolean)};class It{schema;constructor(t){this.schema=t}hasBehavior(t){return!!this.schema.behavior?.includes(t)}#rt(t){return t.delete("deprecated"),t.delete("transient"),t.delete("config"),t}#st(t,e){return[...t].every((t=>e.has(t)))}#nt(t,e){return new Set([...t].filter((t=>!e.has(t))))}#it(t,e){const r=t?.type||"unknown",s=e?.type||"unknown";return"unknown"===s||r===s&&void 0}canConnect(t){let e=this.schema,r=t.schema;const s=this.#it(e,r);if(s)return!0;if(!1===s)return!1;"array"===this.schema.type&&(e=Array.isArray(e.items)?e.items[0]:e.items,r=Array.isArray(r.items)?r.items[0]:r.items,this.#it(e,r));const n=this.#rt(new Set(e?.behavior)),i=this.#rt(new Set(r?.behavior));if(n.size!==i.size)return!1;if(!this.#st(n,i))return!1;const o=new Set(e?.format?.split(",")||[]),a=new Set(r?.format?.split(",")||[]);if(0===a.size)return!0;if(0===o.size)return!1;return!this.#nt(o,a).size}}const jt=t=>{const e=Object.keys(t.properties||{}),r=t.required||[];return e.sort(),e.map((e=>{const s=t.properties?.[e]||bt;return{name:e,title:Et(t,e),configured:!1,star:!1,edges:[],value:null,status:Ot(!1,!0,r.includes(e),!1),schema:s,type:new It(s)}}))},Nt=t=>Object.entries(t).sort().map((([t,e])=>new Mt(t,e)));
*/const yt=Symbol(),wt=Symbol(),bt=[function(t,e,r){if(void 0!==t.anyOf){for(let s=0;s<t.anyOf.length;s++){const n=t.anyOf[s],i=kt(t,n);if(void 0===e.anyOf){const t=[],o={...r,details:t};r.pathA.push("anyOf",s);const a=$t(i,e,o).isSubSchema;if(r.pathA.pop(),r.pathA.pop(),!a)return r.details.push(...Ot(t,s,n)),wt}else{let t=!1;for(const r of e.anyOf)if($t(i,kt(e,r)).isSubSchema){t=!0;break}if(!t)return r.details.push({pathA:[...r.pathA,"anyOf",s],pathB:[...r.pathB,"anyOf"]}),wt}}return yt}if(void 0!==e.anyOf){for(const r of e.anyOf)if($t(t,kt(e,r)).isSubSchema)return yt;return r.details.push({pathA:[...r.pathA],pathB:[...r.pathB,"anyOf"]}),wt}return!0},function(t,e,r){if(t.type===e.type)return!0;const s=St(t),n=St(e);s.has("integer")&&n.has("number")&&(s.delete("integer"),s.add("number"));if(!At(s,n))return r.details.push({pathA:[...r.pathA,"type"],pathB:[...r.pathB,"type"]}),!1;return!0},function(t,e,r){if(void 0===e.enum)return!0;if(void 0===t.enum||0===t.enum.length&&e.enum.length>0||!At(Et(t.enum),Et(e.enum)))return r.details.push({pathA:[...r.pathA,"enum"],pathB:[...r.pathB,"enum"]}),!1;return!0},function(t,e,r){if(void 0===e.minLength&&void 0===e.maxLength)return!0;let s=!0;const n=t.minLength??0,i=e.minLength??0;n<i&&(s=!1,r.details.push({pathA:[...r.pathA,"minLength"],pathB:[...r.pathB,"minLength"]}));const o=t.maxLength??Number.MAX_VALUE,a=e.maxLength??Number.MAX_VALUE;o>a&&(s=!1,r.details.push({pathA:[...r.pathA,"maxLength"],pathB:[...r.pathB,"maxLength"]}));return s},function(t,e,r){if(void 0===e.pattern)return!0;if(t.pattern!==e.pattern)return r.details.push({pathA:[...r.pathA,"pattern"],pathB:[...r.pathB,"pattern"]}),!1;return!0},function(t,e,r){if(void 0===e.format)return!0;if(t.format!==e.format)return r.details.push({pathA:[...r.pathA,"format"],pathB:[...r.pathB,"format"]}),!1;return!0},function(t,e,r){if(void 0===e.minimum&&void 0===e.maximum)return!0;const s=t.minimum??0,n=e.minimum??0;if(s<n)return r.details.push({pathA:[...r.pathA,"minimum"],pathB:[...r.pathB,"minimum"]}),!1;const i=t.maximum??Number.MAX_VALUE,o=e.maximum??Number.MAX_VALUE;if(i>o)return r.details.push({pathA:[...r.pathA,"maximum"],pathB:[...r.pathB,"maximum"]}),!1;return!0},function(t,e,r){if(void 0===e.items)return!0;if(Array.isArray(t.items)||Array.isArray(e.items))return!0;r.pathA.push("items"),r.pathB.push("items");const s=$t(t.items??Pt,e.items,r).isSubSchema;return r.pathA.pop(),r.pathB.pop(),s},function(t,e,r){if(void 0===t.properties)return!0;for(const[s,n]of Object.entries(t.properties)){const t=e.properties?.[s];if(void 0!==t){r.pathA.push("properties",s),r.pathB.push("properties",s);const{isSubSchema:e}=$t(n,t,r);if(r.pathA.pop(),r.pathB.pop(),!e)return!1}else{if(!0===e.additionalProperties||void 0===e.additionalProperties)continue;if(!1===e.additionalProperties)return r.details.push({pathA:[...r.pathA,"properties",s],pathB:[...r.pathB,"additionalProperties"]}),!1;{r.pathA.push("properties",s),r.pathB.push("additionalProperties");const{isSubSchema:t}=$t(n,e.additionalProperties,r);if(r.pathA.pop(),r.pathB.pop(),!t)return!1}}}return!0},function(t,e,r){const s=e.additionalProperties??!0;if(!0===s)return!0;const n=t.additionalProperties??!0;if(!1===n)return!0;if(!1===s)return r.details.push({pathA:[...r.pathA,"additionalProperties"],pathB:[...r.pathB,"additionalProperties"]}),!1;r.pathA.push("additionalProperties"),r.pathB.push("additionalProperties");const i=$t(!0===n?{}:n,s,r).isSubSchema;return r.pathA.pop(),r.pathB.pop(),i},function(t,e,r){if("boolean"==typeof t.required||"boolean"==typeof e.required)return!0;if(void 0===e.required||0===e.required.length)return!0;const s=new Set(t.required??[]);let n=!0;for(let t=0;t<e.required.length;t++){const i=e.required[t];s.has(i)||(n=!1,r.details.push({pathA:[...r.pathA,"required"],pathB:[...r.pathB,"required",t]}))}return n}],vt=new Set(["string","number","integer","object","array","boolean","null"]),Pt={type:[...vt]};function $t(t,e,r={pathA:[],pathB:[],details:[]}){let s=!1;for(const n of bt){const i=n(t,e,r);if(!0===i);else if(!1===i)s=!0;else{if(i===yt)break;if(i===wt){s=!0;break}}}return s?{isSubSchema:!1,details:r.details}:{isSubSchema:!0}}function St(t){return void 0===t.type?vt:Et(t.type)}function kt(t,e){return 1===Object.keys(t).length?e:{...t,anyOf:void 0,...e}}function Ot(t,e,r){return t.map((t=>{const{pathA:s,pathB:n}=t;return"anyOf"===s[0]&&s[1]===e&&void 0===r[s[2]]?{pathA:s.slice(2),pathB:n}:t}))}function Et(t){return new Set(void 0===t?[]:Array.isArray(t)?t:[t])}function At(t,e){if(t.size>e.size)return!1;for(const r of t)if(!e.has(r))return!1;return!0}
/**

@@ -193,3 +193,3 @@ * @license

* SPDX-License-Identifier: Apache-2.0
*/class Mt{#i;#q;constructor(t,e){this.#i=t,this.#q=e}metadata(){return"metadata"in this.#q&&this.#q.metadata||{}}type(){return this.#i}async ports(){if("function"==typeof this.#q||!this.#q.describe)return qt();try{const t=await this.#q.describe();return{inputs:{fixed:!1===t.inputSchema.additionalProperties,ports:jt(t.inputSchema)},outputs:{fixed:!1===t.outputSchema.additionalProperties,ports:jt(t.outputSchema)}}}catch(t){return console.warn(`Error describing node type ${this.#i}:`,t),qt()}}}class Ct extends Mt{constructor(t,e,r){super(t,{invoke:async()=>{},describe:async()=>e({}),metadata:r})}}const qt=()=>({inputs:{ports:[],fixed:!1},outputs:{ports:[],fixed:!1}})
*/var xt;!function(t){t[t.In=0]="In",t[t.Out=1]="Out"}(xt||(xt={}));const It={type:"object",behavior:["json-schema","ports-spec","config"]},jt={type:"string"},Nt=t=>{const e=t.type;return e===lt.Star||e===lt.Control},Ct=(t,e,r=!1)=>e?e.reduce(((e,s)=>{if(!r&&Nt(s))return e;const n=t===xt.In?s.in:s.out;return e[n]||(e[n]=jt),e}),{}):{},Bt=(t,r,s=!1)=>r?(new e).addProperties(Ct(t,r,s)).setAdditionalProperties(!0).build():{},qt=t=>{const s=t.inputs?.schema||{type:"object"},n=(new e).addProperty("schema",It).build();let i=!1;const o=t.outgoing?.filter((t=>{const e=Nt(t);return e&&(i=!0),!e})),a=r([Bt(xt.Out,o,!0),s]);return t.asType&&(i||(a.additionalProperties=!1)),{inputSchema:n,outputSchema:a}},Mt=t=>{const s=t.inputs?.schema||{type:"object"},n=(new e).setAdditionalProperties(!1).build(),i=(new e).addProperty("schema",It),o=r([i.addProperties(Ct(xt.In,t.incoming,!0)).setAdditionalProperties(!0).build(),s]);if(t.asType){!!t.incoming?.find((t=>"*"===t.out))||(o.additionalProperties=!1)}return{inputSchema:o,outputSchema:n}},Rt=(t,e)=>t.properties?.[e]?.title||e,Lt=(t,e,r,s)=>t?e?ft.Connected:s?ft.Indeterminate:ft.Dangling:r?s?ft.Indeterminate:ft.Missing:ft.Ready,Dt={deprecated:!1,transient:!1,config:!1,bubble:!0,board:!0,stream:!0,error:!0,"llm-content":!0,"json-schema":!0,"ports-spec":!0,image:!0,code:!0},Ut=(t,e,r,s,n,i)=>{let o=!1;const a=e.map((e=>"*"===e.out?(o=!0,"*"):t===xt.In?e.in:e.out)),u=!1===r.additionalProperties,p=Object.keys(r.properties||{});s&&p.push("$error");const c=p.includes("*"),h=r.required||[],d=Object.keys(i||{}),l=[...new Set([...a,...p,...d,"*",""])];return l.sort(),l.map((s=>{const l="*"===s||""===s,f=d.includes(s),m=a.includes(s),g=p.includes(s)||l,y=h.includes(s),w=r.properties?.[s]||jt;return w.behavior?.includes("deprecated")&&!m?null:{name:s,title:Rt(r,s),configured:f,value:i?.[s],star:l,get edges(){return m?e.filter((e=>!("*"!==e.out||!l)||(t===xt.In?e.in===s:e.out===s))):[]},status:Lt(m||f,!u||g||c,n&&y,o),schema:w,type:new Gt(w),kind:t===xt.In?"input":"output"}})).filter(Boolean)};class Gt{schema;constructor(t){this.schema=t}hasBehavior(t){return!!this.schema.behavior?.includes(t)}canConnect(t){return this.analyzeCanConnect(t).canConnect}analyzeCanConnect(t){const e=$t(this.schema,t.schema);if(!e.isSubSchema)return{canConnect:!1,details:e.details.map((t=>({message:"Incompatible schema",detail:{outputPath:t.pathA,inputPath:t.pathB}})))};const r=new Set(this.schema.behavior);for(const e of t.schema.behavior??[])if(Dt[e]&&!r.has(e))return{canConnect:!1,details:[{message:"Incompatible behaviors",detail:{outputPath:["behavior"],inputPath:["behavior"]}}]};return{canConnect:!0}}}const Ft=(t,e)=>{const r=Object.keys(t.properties||{}),s=t.required||[];return r.sort(),r.map((r=>{const n=t.properties?.[r]||jt;return{name:r,title:Rt(t,r),configured:!1,star:!1,edges:[],value:null,status:Lt(!1,!0,s.includes(r),!1),schema:n,type:new Gt(n),kind:e}}))},Tt=t=>Object.entries(t).sort().map((([t,e])=>new zt(t,e)));
/**

@@ -199,3 +199,3 @@ * @license

* SPDX-License-Identifier: Apache-2.0
*/;class At{descriptor;#ot;constructor(t,e){this.descriptor=t,this.#ot=e}title(){return this.descriptor.metadata?.title||this.descriptor.id}description(){return this.descriptor.metadata?.description||this.title()}incoming(){return this.#ot.incomingForNode(this.descriptor.id)}outgoing(){return this.#ot.outgoingForNode(this.descriptor.id)}isEntry(){return 0===this.incoming().length}isExit(){return 0===this.outgoing().length}type(){const t=this.#ot.typeForNode(this.descriptor.id);if(!t)throw new Error(`Possible integrity error: node ${this.descriptor.id} does not have a type`);return t}configuration(){return this.descriptor.configuration||{}}metadata(){return this.descriptor.metadata||{}}#at(t,e){return{...e,...t}}async#ut(t){return this.#ot.describeType(this.descriptor.type,{inputs:this.#at(t.inputs,this.configuration()),incoming:t.incoming,outgoing:t.outgoing})}async describe(t){return this.#ut({inputs:t,incoming:this.incoming(),outgoing:this.outgoing()})}async ports(t,e){const r=this.incoming(),s=this.outgoing(),n=await this.#ut({inputs:t,incoming:r,outgoing:s}),i={fixed:!1===n.inputSchema.additionalProperties,ports:xt(yt.In,r,n.inputSchema,!1,!0,this.#at(t,this.configuration()))},o="input"!==this.descriptor.type&&"output"!==this.descriptor.type;return{inputs:i,outputs:{fixed:!1===n.outputSchema.additionalProperties,ports:xt(yt.Out,s,n.outputSchema,o,!1,e)}}}}class Rt{#ot;#C;#ct;constructor(t){this.#ot=t}populate(t){t.nodes.forEach((t=>this.#ht(t)))}#ht(t){this.#ct??=new Map,this.#C??=new Map;const e=new At(t,this.#ot),r=t.type;let s=this.#ct.get(r);return s||(s=[],this.#ct.set(r,s)),s.push(e),this.#C.set(t.id,e),e}#pt(){return this.#C||(this.populate(this.#ot.raw()),this.#C??=new Map),this.#C}byType(t){return this.#pt(),this.#ct?.get(t)||[]}get(t){return this.#pt().get(t)}add(t){this.#C&&(console.assert(!this.#C.has(t.id),"Node already exists in cache."),this.#ht(t))}remove(t){if(!this.#C)return;const e=this.#C.get(t);console.assert(e,"Node does not exist in cache.");const r=e.descriptor.type,s=this.#ct?.get(r);if(s){const t=s.indexOf(e);s.splice(t,1)}this.#C.delete(t)}nodes(){return Array.from(this.#pt().values())}}
*/class zt{#i;#B;constructor(t,e){this.#i=t,this.#B=e}metadata(){return"metadata"in this.#B&&this.#B.metadata||{}}type(){return this.#i}async ports(){if("function"==typeof this.#B||!this.#B.describe)return Vt();try{const t=await this.#B.describe();return{inputs:{fixed:!1===t.inputSchema.additionalProperties,ports:Ft(t.inputSchema,"input")},outputs:{fixed:!1===t.outputSchema.additionalProperties,ports:Ft(t.outputSchema,"output")}}}catch(t){return console.warn(`Error describing node type ${this.#i}:`,t),Vt()}}}class _t extends zt{constructor(t,e,r){super(t,{invoke:async()=>{},describe:async()=>e({}),metadata:r})}}const Vt=()=>({inputs:{ports:[],fixed:!1},outputs:{ports:[],fixed:!1}})
/**

@@ -205,3 +205,3 @@ * @license

* SPDX-License-Identifier: Apache-2.0
*/var Tt;class Dt{#dt;#lt;#ft;#gt;#ot;#l;#mt=null;constructor(t,e){this.#ot=t,this.#dt=(t=>{t=t||"";try{return new URL(t)}catch{return}})(t.url),this.#gt=e||{};const r=new Rt(this),s=new mt(r);s.populate(t),this.#l={edges:s,nodes:r}}raw(){return this.#ot}metadata(){return this.#ot.metadata}nodesByType(t){return this.#l.nodes.byType(t)}async describeType(t,e={}){if("input"===t)return kt(e);if("output"===t)return St(e);const{kits:r}=this.#gt,s=n(r||[])[t],i={inputSchema:Pt(yt.In,e?.incoming),outputSchema:Pt(yt.Out,e?.outgoing)};if(!s||!("describe"in s)||!s.describe)return i;const o=this.#gt.loader||F(),a={outerGraph:this.#ot,loader:o};this.#dt&&(a.base=this.#dt);try{return s.describe(e?.inputs||void 0,i.inputSchema,i.outputSchema,a)}catch(e){return console.warn(`Error describing node type ${t}`,e),i}}nodeById(t){return this.#l.nodes.get(t)}nodes(){return this.#l.nodes.nodes()}edges(){return this.#l.edges.edges()}hasEdge(t){return this.#l.edges.hasByValue(t)}kits(){return this.#lt??=(t=this.#gt.kits||[],[{descriptor:{title:"Built-in Kit",description:"A kit containing built-in Breadboard nodes",url:""},nodeTypes:[new Ct("input",kt,{title:"Input",description:"The input node. Use it to request inputs for your board.",help:{url:"https://breadboard-ai.github.io/breadboard/docs/reference/kits/built-in/#the-input-node"}}),new Ct("output",St,{title:"Output",description:"The output node. Use it to provide outputs from your board.",help:{url:"https://breadboard-ai.github.io/breadboard/docs/reference/kits/built-in/#the-output-node"}})]},...t.map((t=>({descriptor:{title:t.title,description:t.description,url:t.url},nodeTypes:Nt(t.handlers)})))]);var t}typeForNode(t){const e=this.nodeById(t);if(e)return this.typeById(e.descriptor.type)}typeById(t){const e=this.kits();return this.#ft??=new Map(e.flatMap((t=>t.nodeTypes.map((t=>[t.type(),t]))))),this.#ft.get(t)}incomingForNode(t){return this.#ot.edges.filter((e=>e.to===t)).map((t=>this.#l.edges.getOrCreate(t)))}outgoingForNode(t){return this.#ot.edges.filter((e=>e.from===t)).map((t=>this.#l.edges.getOrCreate(t)))}entries(){return this.#l.nodes.nodes().filter((t=>t.isEntry()))}async describe(){const t=(await Promise.all(this.nodesByType("input").filter((t=>t.isEntry())).map((t=>kt({inputs:t.configuration(),incoming:t.incoming(),outgoing:t.outgoing(),asType:!0}))))).map((t=>t.outputSchema)),e=(await Promise.all(this.nodesByType("output").filter((t=>t.isExit())).map((t=>St({inputs:t.configuration(),incoming:t.incoming(),outgoing:t.outgoing(),asType:!0}))))).map((t=>t.inputSchema.behavior?.includes("bubble")?null:t.inputSchema)).filter(Boolean);return{inputSchema:r(t,((t,e)=>{!1!==e.additionalProperties?t.additionalProperties=!0:"additionalProperties"in t||(t.additionalProperties=!1)})),outputSchema:((t,e)=>{const r=Object.entries(t.properties||{});if(0==r.length)return t;const s=r.findIndex((([t])=>t===e));return-1==s?t:(r.splice(s,1),{...t,properties:Object.fromEntries(r)})})(r(e),"schema")}}get nodeStore(){return this.#l.nodes}get edgeStore(){return this.#l.edges}updateGraph(t){this.#ot=t}resetGraph(t){this.#ot=t;const e=new Rt(this),r=new mt(e);r.populate(t),this.#l={edges:r,nodes:e},this.#mt=null}#yt(){const t=this.#ot.graphs;return t?Object.fromEntries(Object.entries(t).map((([t,e])=>[t,new Tt(e,this.#gt)]))):{}}graphs(){return this.#mt??=this.#yt()}}Tt=Dt;
*/;class Wt{descriptor;#rt;constructor(t,e){this.descriptor=t,this.#rt=e}title(){return this.descriptor.metadata?.title||this.descriptor.id}description(){return this.descriptor.metadata?.description||this.title()}incoming(){return this.#rt.incomingForNode(this.descriptor.id)}outgoing(){return this.#rt.outgoingForNode(this.descriptor.id)}isEntry(){return 0===this.incoming().length}isExit(){return 0===this.outgoing().length}type(){const t=this.#rt.typeForNode(this.descriptor.id);if(!t)throw new Error(`Possible integrity error: node ${this.descriptor.id} does not have a type`);return t}configuration(){return this.descriptor.configuration||{}}metadata(){return this.descriptor.metadata||{}}#st(t,e){return{...e,...t}}async#nt(t){return this.#rt.describeType(this.descriptor.type,{inputs:this.#st(t.inputs,this.configuration()),incoming:t.incoming,outgoing:t.outgoing})}async describe(t){return this.#nt({inputs:t,incoming:this.incoming(),outgoing:this.outgoing()})}async ports(t,e){const r=this.incoming(),s=this.outgoing(),n=await this.#nt({inputs:t,incoming:r,outgoing:s}),i={fixed:!1===n.inputSchema.additionalProperties,ports:Ut(xt.In,r,n.inputSchema,!1,!0,this.#st(t,this.configuration()))},o="input"!==this.descriptor.type&&"output"!==this.descriptor.type;return{inputs:i,outputs:{fixed:!1===n.outputSchema.additionalProperties,ports:Ut(xt.Out,s,n.outputSchema,o,!1,e)}}}}class Ht{#rt;#C;#it;constructor(t){this.#rt=t}populate(t){t.nodes.forEach((t=>this.#ot(t)))}#ot(t){this.#it??=new Map,this.#C??=new Map;const e=new Wt(t,this.#rt),r=t.type;let s=this.#it.get(r);return s||(s=[],this.#it.set(r,s)),s.push(e),this.#C.set(t.id,e),e}#at(){return this.#C||(this.populate(this.#rt.raw()),this.#C??=new Map),this.#C}byType(t){return this.#at(),this.#it?.get(t)||[]}get(t){return this.#at().get(t)}add(t){this.#C&&(console.assert(!this.#C.has(t.id),"Node already exists in cache."),this.#ot(t))}remove(t){if(!this.#C)return;const e=this.#C.get(t);console.assert(e,"Node does not exist in cache.");const r=e.descriptor.type,s=this.#it?.get(r);if(s){const t=s.indexOf(e);s.splice(t,1)}this.#C.delete(t)}nodes(){return Array.from(this.#at().values())}}
/**

@@ -211,4 +211,9 @@ * @license

* SPDX-License-Identifier: Apache-2.0
*/var Kt;class Qt{#ut;#pt;#ct;#ht;#rt;#l;#dt=null;constructor(t,e){this.#rt=t,this.#ut=(t=>{t=t||"";try{return new URL(t)}catch{return}})(t.url),this.#ht=e||{};const r=new Ht(this),s=new gt(r);s.populate(t),this.#l={edges:s,nodes:r}}raw(){return this.#rt}metadata(){return this.#rt.metadata}nodesByType(t){return this.#l.nodes.byType(t)}async describeType(t,e={}){if("input"===t)return qt(e);if("output"===t)return Mt(e);const{kits:r}=this.#ht,s=n(r||[])[t],i={inputSchema:Bt(xt.In,e?.incoming),outputSchema:Bt(xt.Out,e?.outgoing)};if(!s||!("describe"in s)||!s.describe)return i;const o=this.#ht.loader||G(),a={outerGraph:this.#rt,loader:o,wires:{incoming:Object.fromEntries((e?.incoming??[]).map((t=>[t.in,{outputPort:{describe:async()=>(await t.outPort()).type.schema}}]))),outgoing:Object.fromEntries((e?.outgoing??[]).map((t=>[t.out,{inputPort:{describe:async()=>(await t.inPort()).type.schema}}])))}};this.#ut&&(a.base=this.#ut);try{return s.describe(e?.inputs||void 0,i.inputSchema,i.outputSchema,a)}catch(e){return console.warn(`Error describing node type ${t}`,e),i}}nodeById(t){return this.#l.nodes.get(t)}nodes(){return this.#l.nodes.nodes()}edges(){return this.#l.edges.edges()}hasEdge(t){return this.#l.edges.hasByValue(t)}kits(){return this.#pt??=(t=this.#ht.kits||[],[{descriptor:{title:"Built-in Kit",description:"A kit containing built-in Breadboard nodes",url:""},nodeTypes:[new _t("input",qt,{title:"Input",description:"The input node. Use it to request inputs for your board.",help:{url:"https://breadboard-ai.github.io/breadboard/docs/reference/kits/built-in/#the-input-node"}}),new _t("output",Mt,{title:"Output",description:"The output node. Use it to provide outputs from your board.",help:{url:"https://breadboard-ai.github.io/breadboard/docs/reference/kits/built-in/#the-output-node"}})]},...t.map((t=>({descriptor:{title:t.title,description:t.description,url:t.url},nodeTypes:Tt(t.handlers)})))]);var t}typeForNode(t){const e=this.nodeById(t);if(e)return this.typeById(e.descriptor.type)}typeById(t){const e=this.kits();return this.#ct??=new Map(e.flatMap((t=>t.nodeTypes.map((t=>[t.type(),t]))))),this.#ct.get(t)}incomingForNode(t){return this.#rt.edges.filter((e=>e.to===t)).map((t=>this.#l.edges.getOrCreate(t)))}outgoingForNode(t){return this.#rt.edges.filter((e=>e.from===t)).map((t=>this.#l.edges.getOrCreate(t)))}entries(){return this.#l.nodes.nodes().filter((t=>t.isEntry()))}async describe(){const t=(await Promise.all(this.nodesByType("input").filter((t=>t.isEntry())).map((t=>qt({inputs:t.configuration(),incoming:t.incoming(),outgoing:t.outgoing(),asType:!0}))))).map((t=>t.outputSchema)),e=(await Promise.all(this.nodesByType("output").filter((t=>t.isExit())).map((t=>Mt({inputs:t.configuration(),incoming:t.incoming(),outgoing:t.outgoing(),asType:!0}))))).map((t=>t.inputSchema.behavior?.includes("bubble")?null:t.inputSchema)).filter(Boolean);return{inputSchema:r(t,((t,e)=>{!1!==e.additionalProperties?t.additionalProperties=!0:"additionalProperties"in t||(t.additionalProperties=!1)})),outputSchema:((t,e)=>{const r=Object.entries(t.properties||{});if(0==r.length)return t;const s=r.findIndex((([t])=>t===e));return-1==s?t:(r.splice(s,1),{...t,properties:Object.fromEntries(r)})})(r(e),"schema")}}get nodeStore(){return this.#l.nodes}get edgeStore(){return this.#l.edges}updateGraph(t){this.#rt=t}resetGraph(t){this.#rt=t;const e=new Ht(this),r=new gt(e);r.populate(t),this.#l={edges:r,nodes:e},this.#dt=null}#lt(){const t=this.#rt.graphs;return t?Object.fromEntries(Object.entries(t).map((([t,e])=>[t,new Kt(e,this.#ht)]))):{}}graphs(){return this.#dt??=this.#lt()}}Kt=Qt;
/**
* @license
* Copyright 2024 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
const Gt=(t,e)=>((t,e)=>new Dt(t,e))(t,e);
const Jt=(t,e)=>((t,e)=>new Qt(t,e))(t,e);
/**

@@ -218,3 +223,3 @@ * @license

* SPDX-License-Identifier: Apache-2.0
*/class Ut{graph;handlers;runner;constructor(t){this.graph=t}populateDescriptor(t){const{title:e,description:r,version:s}=this.graph;return{title:e,description:r,version:s,...t}}async#wt(t,e=[]){const r=await W.fromGraphDescriptor(this.graph);r.url=t,this.handlers=e?.reduce(((t,e)=>({...t,...e.handlers})),{}),this.runner=r}handlerForNode(t){if(!this.graph)throw new Error("Builder was not yet initialized.");const{nodes:e}=this.graph,r=e.find((e=>e.id===t));if(!r)throw new Error(`Node ${t} not found in graph.`);return{metadata:r.configuration?.$metadata,describe:async()=>{const e={inputSchema:{type:"object"},outputSchema:{type:"object"}};if(null!=this.graph.graphs&&t in this.graph.graphs){const r=this.graph.graphs[t];return null==r?e:await Gt(r).describe()}if("invoke"===r.type){const{$board:t}=r.configuration;if(t)return await Gt(t).describe()}return e},invoke:async(t,e)=>{const i=r.configuration;i&&(t={...i,...t});const o={...this.handlers,...n(e?.kits||[])},a=o?.[r.type];if(!a)throw new Error(`No handler found for node "${r.type}".`);const u=this.runner,c=u.url?new URL(u.url):new URL(import.meta.url);return s(a,t,{...e,outerGraph:u,base:c,kits:[...e.kits||[],...u.kits]})}}}static async create(t,e,r){const s=new Ut(t);return await s.#wt(e,r),s}}
*/class Xt{graph;handlers;runner;constructor(t){this.graph=t}populateDescriptor(t){const{title:e,description:r,version:s}=this.graph;return{title:e,description:r,version:s,...t}}async#ft(t,e=[]){const r=await W.fromGraphDescriptor(this.graph);r.url=t,this.handlers=e?.reduce(((t,e)=>({...t,...e.handlers})),{}),this.runner=r}handlerForNode(t){if(!this.graph)throw new Error("Builder was not yet initialized.");const{nodes:e}=this.graph,r=e.find((e=>e.id===t));if(!r)throw new Error(`Node ${t} not found in graph.`);return{metadata:r.configuration?.$metadata,describe:async()=>{const e={inputSchema:{type:"object"},outputSchema:{type:"object"}};if(null!=this.graph.graphs&&t in this.graph.graphs){const r=this.graph.graphs[t];return null==r?e:await Jt(r).describe()}if("invoke"===r.type){const{$board:t}=r.configuration;if(t)return await Jt(t).describe()}return e},invoke:async(t,e)=>{const i=r.configuration;i&&(t={...i,...t});const o={...this.handlers,...n(e?.kits||[])},a=o?.[r.type];if(!a)throw new Error(`No handler found for node "${r.type}".`);const u=this.runner,p=u.url?new URL(u.url):new URL(import.meta.url);return s(a,t,{...e,outerGraph:u,base:p,kits:[...e.kits||[],...u.kits]})}}}static async create(t,e,r){const s=new Xt(t);return await s.#ft(e,r),s}}
/**

@@ -224,3 +229,3 @@ * @license

* SPDX-License-Identifier: Apache-2.0
*/class Ft{url;title;description;version;namespacePrefix;constructor({title:t,description:e,version:r,url:s,namespacePrefix:n=""}){this.url=s,this.title=t,this.description=e,this.version=r,this.namespacePrefix=n}#bt(t){return Object.keys(t).reduce(((e,r)=>(e[`${this.namespacePrefix}${r}`]=t[r],e)),{})}build(t){if(!this.url)throw new Error("Builder was not yet initialized.");const e=this.url,r=this.namespacePrefix,{title:s,description:n,version:i}=this,o=this.#bt(t),a=Object.keys(t);return class{title=s;description=n;version=i;url=e;get handlers(){return o}constructor(t){const e=new Proxy(this,{get:(s,n)=>"handlers"===n||"url"===n||"title"===n?s[n]:a.includes(n)?(s={})=>{const i=t.getConfigWithLambda(s),{$id:o,...a}=i;return t.create(e,`${r}${n}`,{...a},o)}:void 0});return e}}}static wrap(t,e){const r=Object.entries(e).reduce(((t,e)=>{const[r,s]=e;return t[r]={invoke:async t=>{let e=[];s&&s.length>0&&(e=s.toString().match(/\((.+?)\)/)?.[1].split(",")??[],s.length>1&&0===e.length&&"___args"in t&&Array.isArray(t.___args)&&(e=["___args"]));for(const r of e)if(r.trim()in t==!1)throw new Error(`Missing input: ${r.trim()}. Valid inputs are: ${Object.keys(t).join(", ")}`);const r=e.filter((t=>0==t.startsWith("___"))).map((e=>t[e.trim()])),n=e[e.length-1];null!=n&&n.startsWith("___")&&r.push(...t[n]);const i=await s(...r);return"object"!=typeof i||Array.isArray(i)?{result:i}:{...i}}},t}),{});return new Ft(t).build(r)}}
*/class Yt{url;title;description;version;namespacePrefix;constructor({title:t,description:e,version:r,url:s,namespacePrefix:n=""}){this.url=s,this.title=t,this.description=e,this.version=r,this.namespacePrefix=n}#mt(t){return Object.keys(t).reduce(((e,r)=>(e[`${this.namespacePrefix}${r}`]=t[r],e)),{})}build(t){if(!this.url)throw new Error("Builder was not yet initialized.");const e=this.url,r=this.namespacePrefix,{title:s,description:n,version:i}=this,o=this.#mt(t),a=Object.keys(t);return class{title=s;description=n;version=i;url=e;get handlers(){return o}constructor(t){const e=new Proxy(this,{get:(s,n)=>"handlers"===n||"url"===n||"title"===n?s[n]:a.includes(n)?(s={})=>{const i=t.getConfigWithLambda(s),{$id:o,...a}=i;return t.create(e,`${r}${n}`,{...a},o)}:void 0});return e}}}static wrap(t,e){const r=Object.entries(e).reduce(((t,e)=>{const[r,s]=e;return t[r]={invoke:async t=>{let e=[];s&&s.length>0&&(e=s.toString().match(/\((.+?)\)/)?.[1].split(",")??[],s.length>1&&0===e.length&&"___args"in t&&Array.isArray(t.___args)&&(e=["___args"]));for(const r of e)if(r.trim()in t==!1)throw new Error(`Missing input: ${r.trim()}. Valid inputs are: ${Object.keys(t).join(", ")}`);const r=e.filter((t=>0==t.startsWith("___"))).map((e=>t[e.trim()])),n=e[e.length-1];null!=n&&n.startsWith("___")&&r.push(...t[n]);const i=await s(...r);return"object"!=typeof i||Array.isArray(i)?{result:i}:{...i}}},t}),{});return new Yt(t).build(r)}}
/**

@@ -230,3 +235,3 @@ * @license

* SPDX-License-Identifier: Apache-2.0
*/class Lt{#vt;#i;#ot;metadata;constructor(t,e,r){this.#vt=t,this.#i=e,this.#ot=((t,e,r)=>{if(r.edges&&r.nodes){const s=new URL(t);return s.searchParams.set("graph",e),{...r,url:s.href}}throw new Error("Invalid graph descriptor")})(t,e,r),this.describe=this.describe.bind(this),this.invoke=this.invoke.bind(this);const{title:s,description:n,metadata:i}=this.#ot;this.metadata={title:s,description:n},i?.deprecated&&(this.metadata.deprecated=i.deprecated),i?.icon&&(this.metadata.icon=i.icon)}async describe(){return await Gt(this.#ot).describe()}async invoke(t,e){const r=await W.fromGraphDescriptor(this.#ot);return await r.runOnce(t,e)}}const zt=t=>{const{title:e,description:r,version:s,url:n}=t;return{title:e,description:r,version:s,url:n,handlers:(i=new URL(n),o=t.nodes,Object.fromEntries(Object.entries(o).map((([t,e])=>[t,new Lt(i,t,e)]))))};var i,o},Bt=async t=>{if("https:"===t.protocol||"http:"===t.protocol){if(!t.pathname.endsWith(".kit.json")){const e=await import(t.href);if(null==e.default)throw new Error(`Module ${t} does not have a default export.`);const r=Object.getOwnPropertyNames(e.default.prototype);if(0==r.includes("constructor")||0==r.includes("handlers"))throw new Error(`Module default export '${t}' does not look like a Kit (either no constructor or no handler).`);return new(0,e.default)({create:()=>{throw Error("Node instantiation can't (yet) happen during runtime")}})}{const e=await A(t);if((t=>{if("object"!=typeof t||null===t)return!1;const e=t;return"string"==typeof e.title&&"string"==typeof e.description&&"string"==typeof e.version&&"string"==typeof e.url&&"object"==typeof e.nodes})(e))return zt(e)}}else if("file:"===t.protocol)throw new Error("File protocol is not yet supported");throw new Error(`Unable to load kit from "${t}"`)};export{Ut as GraphToKitAdapter,Ft as KitBuilder,e as SchemaBuilder,zt as fromManifest,Bt as load};
*/class Zt{#gt;#i;#rt;metadata;constructor(t,e,r){this.#gt=t,this.#i=e,this.#rt=((t,e,r)=>{if(r.edges&&r.nodes){const s=new URL(t);return s.searchParams.set("graph",e),{...r,url:s.href}}throw new Error("Invalid graph descriptor")})(t,e,r),this.describe=this.describe.bind(this),this.invoke=this.invoke.bind(this);const{title:s,description:n,metadata:i}=this.#rt;this.metadata={title:s,description:n},i?.deprecated&&(this.metadata.deprecated=i.deprecated),i?.icon&&(this.metadata.icon=i.icon)}async describe(){return await Jt(this.#rt).describe()}async invoke(t,e){const r=await W.fromGraphDescriptor(this.#rt);return await r.runOnce(t,e)}}const te=t=>{const{title:e,description:r,version:s,url:n}=t;return{title:e,description:r,version:s,url:n,handlers:(i=new URL(n),o=t.nodes,Object.fromEntries(Object.entries(o).map((([t,e])=>[t,new Zt(i,t,e)]))))};var i,o},ee=async t=>{if("https:"===t.protocol||"http:"===t.protocol){if(!t.pathname.endsWith(".kit.json")){const e=await import(t.href);if(null==e.default)throw new Error(`Module ${t} does not have a default export.`);const r=Object.getOwnPropertyNames(e.default.prototype);if(0==r.includes("constructor")||0==r.includes("handlers"))throw new Error(`Module default export '${t}' does not look like a Kit (either no constructor or no handler).`);return new(0,e.default)({create:()=>{throw Error("Node instantiation can't (yet) happen during runtime")}})}{const e=await q(t);if((t=>{if("object"!=typeof t||null===t)return!1;const e=t;return"string"==typeof e.title&&"string"==typeof e.description&&"string"==typeof e.version&&"string"==typeof e.url&&"object"==typeof e.nodes})(e))return te(e)}}else if("file:"===t.protocol)throw new Error("File protocol is not yet supported");throw new Error(`Unable to load kit from "${t}"`)};export{Xt as GraphToKitAdapter,Yt as KitBuilder,e as SchemaBuilder,te as fromManifest,ee as load};
//# sourceMappingURL=kits.min.js.map

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

import { Edge as EdgeDescriptor, GraphDescriptor } from "../types.js";
import { InspectableEdge, InspectableEdgeType, InspectableNodeCache, ValidateResult } from "./types.js";
import { InspectableEdge, InspectableEdgeType, InspectableNodeCache, InspectablePort, ValidateResult } from "./types.js";
/**

@@ -34,2 +34,4 @@ * This helper is necessary because both "*" and "" are valid representations

get type(): InspectableEdgeType;
outPort(): Promise<InspectablePort>;
inPort(): Promise<InspectablePort>;
validate(): Promise<ValidateResult>;

@@ -36,0 +38,0 @@ }

@@ -73,20 +73,23 @@ /**

}
async outPort() {
const ports = await this.from.ports();
return ports.outputs.ports.find((port) => port.name === this.out);
}
async inPort() {
const ports = await this.to.ports();
return ports.inputs.ports.find((port) => port.name === this.in);
}
async validate() {
const [fromPorts, toPorts] = await Promise.all([
await this.from.ports(),
await this.to.ports(),
const [outPort, inPort] = await Promise.all([
this.outPort(),
this.inPort(),
]);
const outPort = fromPorts.outputs.ports.find((port) => port.name === this.out);
const inPort = toPorts.inputs.ports.find((port) => port.name === this.in);
if (outPort === undefined || inPort === undefined) {
return { status: "unknown" };
}
if (!outPort.type.canConnect(inPort.type)) {
const canConnectAnalysis = outPort.type.analyzeCanConnect(inPort.type);
if (!canConnectAnalysis.canConnect) {
return {
status: "invalid",
errors: [
{
message: `The schema of "${this.in}" is not compatible with "${this.out}"`,
},
],
errors: canConnectAnalysis.details,
};

@@ -93,0 +96,0 @@ }

@@ -74,2 +74,20 @@ /**

loader,
wires: {
incoming: Object.fromEntries((options?.incoming ?? []).map((edge) => [
edge.in,
{
outputPort: {
describe: async () => (await edge.outPort()).type.schema,
},
},
])),
outgoing: Object.fromEntries((options?.outgoing ?? []).map((edge) => [
edge.out,
{
inputPort: {
describe: async () => (await edge.inPort()).type.schema,
},
},
])),
},
};

@@ -76,0 +94,0 @@ if (this.#url) {

@@ -76,7 +76,7 @@ /**

fixed: described.inputSchema.additionalProperties === false,
ports: collectPortsForType(described.inputSchema),
ports: collectPortsForType(described.inputSchema, "input"),
},
outputs: {
fixed: described.outputSchema.additionalProperties === false,
ports: collectPortsForType(described.outputSchema),
ports: collectPortsForType(described.outputSchema, "output"),
},

@@ -83,0 +83,0 @@ };

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

*/
import { BehaviorSchema, NodeConfiguration, Schema } from "../types.js";
import { EdgeType } from "./schemas.js";
import { InspectableEdge, InspectablePort, InspectablePortType, PortStatus } from "./types.js";
import { BehaviorSchema, NodeConfiguration, Schema } from "../types.js";
import { CanConnectAnalysis, InspectableEdge, InspectablePort, InspectablePortType, PortStatus } from "./types.js";
export declare const computePortStatus: (wired: boolean, expected: boolean, required: boolean, wiredContainsStar: boolean) => PortStatus;
export declare const collectPorts: (type: EdgeType, edges: InspectableEdge[], schema: Schema, addErrorPort: boolean, allowRequired: boolean, values?: NodeConfiguration) => InspectablePort[];
export declare class PortType implements InspectablePortType {
#private;
schema: Schema;

@@ -18,4 +17,5 @@ constructor(schema: Schema);

canConnect(to: InspectablePortType): boolean;
analyzeCanConnect(to: InspectablePortType): CanConnectAnalysis;
}
export declare const collectPortsForType: (schema: Schema) => InspectablePort[];
export declare const collectPortsForType: (schema: Schema, kind: "input" | "output") => InspectablePort[];
//# sourceMappingURL=ports.d.ts.map

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

*/
import { analyzeIsJsonSubSchema } from "@google-labs/breadboard-schema/subschema.js";
import { DEFAULT_SCHEMA, EdgeType } from "./schemas.js";

@@ -23,2 +24,22 @@ import { PortStatus, } from "./types.js";

};
/**
* A mapping from each Breadboard behavior to whether or not that behavior
* matters for type-checking.
*/
const BEHAVIOR_AFFECTS_TYPE_CHECKING = {
deprecated: false,
transient: false,
config: false,
// TODO(aomarks) Not sure about many of these. Some affect the data type, some
// only affect formatting?
bubble: true,
board: true,
stream: true,
error: true,
"llm-content": true,
"json-schema": true,
"ports-spec": true,
image: true,
code: true,
};
export const collectPorts = (type, edges, schema, addErrorPort, allowRequired, values) => {

@@ -82,2 +103,3 @@ let wiredContainsStar = false;

type: new PortType(portSchema),
kind: type === EdgeType.In ? "input" : "output",
};

@@ -95,64 +117,40 @@ })

}
#onlyTypeRelated(behavior) {
behavior.delete("deprecated");
behavior.delete("transient");
behavior.delete("config");
return behavior;
canConnect(to) {
return this.analyzeCanConnect(to).canConnect;
}
#subset(a, b) {
return [...a].every((item) => b.has(item));
}
#difference(a, b) {
return new Set([...a].filter((item) => !b.has(item)));
}
#matchTypes(from, to) {
const type = from?.type || "unknown";
const toType = to?.type || "unknown";
// Allow connecting to the incoming port of unknown type.
if (toType === "unknown")
return true;
// Otherwise, match types exactly.
if (type !== toType)
return false;
return undefined;
}
canConnect(to) {
let schema = this.schema;
let toSchema = to.schema;
const match = this.#matchTypes(schema, toSchema);
if (match)
return true;
if (match === false)
return false;
// Now, check for arrays.
if (this.schema.type === "array") {
schema = Array.isArray(schema.items) ? schema.items[0] : schema.items;
toSchema = Array.isArray(toSchema.items)
? toSchema.items[0]
: toSchema.items;
this.#matchTypes(schema, toSchema);
analyzeCanConnect(to) {
// Check standard JSON Schema subset rules.
const subSchemaAnalysis = analyzeIsJsonSubSchema(this.schema, to.schema);
if (!subSchemaAnalysis.isSubSchema) {
return {
canConnect: false,
details: subSchemaAnalysis.details.map((detail) => ({
message: "Incompatible schema",
detail: {
outputPath: detail.pathA,
inputPath: detail.pathB,
},
})),
};
}
// Match behaviors.
const behavior = this.#onlyTypeRelated(new Set(schema?.behavior));
const toBehavior = this.#onlyTypeRelated(new Set(toSchema?.behavior));
if (behavior.size !== toBehavior.size)
return false;
if (!this.#subset(behavior, toBehavior))
return false;
// Match formats.
const formats = new Set(schema?.format?.split(",") || []);
const toFormats = new Set(toSchema?.format?.split(",") || []);
// When "to" can accept any format, no need to check for specifics.
if (toFormats.size === 0)
return true;
// When "from" provides any format, we already know we can't handle that.
if (formats.size === 0)
return false;
const formatDiff = this.#difference(formats, toFormats);
if (formatDiff.size)
return false;
return true;
// Check Breadboard-specific behaviors.
const fromBehaviors = new Set(this.schema.behavior);
for (const toBehavior of to.schema.behavior ?? []) {
if (BEHAVIOR_AFFECTS_TYPE_CHECKING[toBehavior] &&
!fromBehaviors.has(toBehavior)) {
return {
canConnect: false,
details: [
{
message: "Incompatible behaviors",
detail: { outputPath: ["behavior"], inputPath: ["behavior"] },
},
],
};
}
}
return { canConnect: true };
}
}
export const collectPortsForType = (schema) => {
export const collectPortsForType = (schema, kind) => {
const portNames = Object.keys(schema.properties || {});

@@ -173,2 +171,3 @@ const requiredPortNames = schema.required || [];

type: new PortType(portSchema),
kind,
};

@@ -175,0 +174,0 @@ });

@@ -140,2 +140,10 @@ /**

/**
* Get an inspectable output port.
*/
outPort(): Promise<InspectablePort>;
/**
* Get the inspectable input port.
*/
inPort(): Promise<InspectablePort>;
/**
* Check if the input and output schemas are compatible (meaning that the

@@ -158,2 +166,6 @@ * output port type is a subtype of the input port type).

message: string;
detail?: {
outputPath: Array<string | number>;
inputPath: Array<string | number>;
};
}

@@ -348,2 +360,6 @@ export type InspectableSubgraphs = Record<GraphIdentifier, InspectableGraph>;

type: InspectablePortType;
/**
* Is this an input or output port?
*/
kind: "input" | "output";
};

@@ -366,3 +382,18 @@ export type InspectablePortType = {

canConnect(to: InspectablePortType): boolean;
analyzeCanConnect(to: InspectablePortType): CanConnectAnalysis;
};
export type CanConnectAnalysis = {
canConnect: true;
details?: never;
} | {
canConnect: false;
details: CanConnectAnalysisDetail[];
};
export interface CanConnectAnalysisDetail {
message: string;
detail?: {
outputPath: Array<string | number>;
inputPath: Array<string | number>;
};
}
/**

@@ -369,0 +400,0 @@ * Represents one side (input or output) of ports of a node.

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

loader?: GraphLoader;
/**
* Information about the wires currently connected to this node.
*/
wires: NodeDescriberWires;
};
export type NodeDescriberWires = {
incoming: Record<string, {
outputPort: NodeDescriberPort;
}>;
outgoing: Record<string, {
inputPort: NodeDescriberPort;
}>;
};
export type NodeDescriberPort = {
describe(): Promise<Schema>;
};
/**

@@ -192,0 +207,0 @@ * Asks to describe a node. Can be called in multiple ways:

@@ -6,3 +6,3 @@ {

},
"version": "0.21.0",
"version": "0.22.0",
"description": "A library for rapid generative AI application prototyping",

@@ -150,3 +150,4 @@ "main": "./dist/src/index.js",

"rollup": "^4.18.0",
"typescript": "^5.5.2"
"rollup-plugin-dts": "^6.1.1",
"typescript": "^5.5.3"
},

@@ -157,4 +158,5 @@ "engines": {

"dependencies": {
"@google-labs/breadboard-schema": "^1.5.0"
"@google-labs/breadboard-schema": "^1.5.1",
"json-schema": "^0.4.0"
}
}

@@ -1,697 +0,3 @@

# Breadboard
# Breadboard Core Library
![Milestone](https://img.shields.io/badge/milestone-M4-red) ![Stability](https://img.shields.io/badge/stability-wip-green) [![Discord](https://img.shields.io/discord/1138546999872999556?logo=discord)](https://discord.gg/breadboard)
A library for prototyping generative AI applications.
> [!NOTE]
> Breadboard supports authoring in JavaScript/TypeScript, Python, and with Breadboard Visual Editor.
This library was inspired by the hardware maker community and their boundless creativity. They make amazing things with off-the-shelf parts and a [breadboard](https://learn.sparkfun.com/tutorials/how-to-use-a-breadboard/all), just wiring things together and trying this and that until it works.
Breadboard is an attempt to bring the same spirit of creativity and simplicity to the creation of generative AI applications.
This library's design emphasizes two key properties:
1. **Ease and flexibility of wiring**. Make wiring prototypes easy and fun.
2. **Modularity and composability**. Easily share, remix, reuse, and compose prototypes.
## Table of Contents
- [Table of Contents](#table-of-contents)
- [Installation](#installation)
- [Useful packages (optional)](#useful-packages-optional)
- [Usage](#usage)
- [Making your first board](#making-your-first-board)
- [Wiring directions](#wiring-directions)
- [Creating `code` nodes](#creating-code-nodes)
- [Kits](#kits)
- [Using kits](#using-kits)
- [Creating custom kits](#creating-custom-kits)
- [Serializing boards](#serializing-boards)
- [Serialization](#serialization)
- [Deserialization](#deserialization)
- [Running boards](#running-boards)
- [Using a board within a board](#using-a-board-within-a-board)
- [Breadboard Board Schema](#breadboard-board-schema)
- [Breadboard Web](#breadboard-web)
- [1. Running Breadboard Web Locally](#1-running-breadboard-web-locally)
- [2. Using Breadboard Web hosted by Google](#2-using-breadboard-web-hosted-by-google)
- [Using Breadboard Web](#using-breadboard-web)
- [Concepts](#concepts)
- [Additional Info](#additional-info)
## Installation
Breadboard requires [Node.js](https://nodejs.org/) version 20.14.0 or higher. Before installing, [download and install Node.js](https://nodejs.org/en/download/).
- Check what version of Node.js you're running with `node -v`.
- In your workspace, make sure to create a `package.json` first with the [`npm init` command](https://docs.npmjs.com/creating-a-package-json-file).
To install Breadboard with [npm](https://www.npmjs.com/), run:
```shell
npm install @google-labs/breadboard
```
If you want to use [TypeScript](https://www.typescriptlang.org/), you will need to [install the package](https://www.npmjs.com/package/typescript).
- You can use npm to download TypeScript into your project using `npm install typescript --save-dev`.
- You can then initialize the TypeScript project and create a `tsconfig.json` file using `npx tsc --init`.
> **For Windows Users**: For compatability, [Dev Containers](https://code.visualstudio.com/docs/devcontainers/containers) are recommended for ease of use.
### Useful packages (optional)
| Name | Description | Install |
| ----------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------- |
| [Breadboard Core Kit](https://www.npmjs.com/package/@google-labs/core-kit) | Breadboard kit for foundational board operations like `map` and `invoke`. This contains operations that enable composition and reuse of boards | `npm install @google-labs/core-kit` |
| [Breadboard CLI](https://github.com/breadboard-ai/breadboard/tree/main/packages/breadboard-cli) | Command-line tool for generating, running, and debugging boards. This lets you run and build breadboards directly from the command-line. | `npm install @google-labs/breadboard-cli` |
You can find many other helpful [Breadboard packages](https://github.com/breadboard-ai/breadboard/blob/main/README.md#packages) available.
## Usage
### Making your first board
```typescript
import { board } from "@google-labs/breadboard";
const echo = board<{ say: string }>(({ say }, { output }) => {
return output({ hear: say });
});
console.log(await echo({ say: "Hello Breadboard!" })); // { hear: 'Hello Breadboard!' }
```
This simple example demonstrates a board with an input port named `say` that gets passed to an output port named `output`. When running the board, `"Hello Breadboard!"` is passed to `say` which then passes it to the output as a property called `hear`.
```typescript
const echo = board<{
say: string; // Input string to be echoed
}>(
(
{
say, // Input port for string
},
{
output, // Output port for result
}
) => {
return output({ hear: say }); // Echo the input string as 'hear' property
}
);
```
Similarly, this can be achieved through chaining the nodes.
```typescript
const echo = board<{ say: string }>(({ say }, { output }) => {
return say.as("hear").to(output());
});
```
In this example, `say` is renamed to `hear` using `.as(...)`, which is then sent to the output using `.to(...)`.
Alternatively, we can use `base` to create input and output nodes.
```typescript
import { base, board } from "@google-labs/breadboard";
const echo = board(() => {
const input = base.input();
const output = base.output();
input.say.as("hear").to(output);
return output;
});
console.log(await echo({ say: "Hello Breadboard!" })); // { hear: 'Hello Breadboard!' }
```
### Wiring direction
Attributes can be passed between nodes by wiring them together.
Using `to`, attributes can be wired from left-to-right.
```typescript
board<{ message: string }>(({ message }, { output }) => {
return message.as("response").to(output());
});
```
Alternatively, `in` can be used to pass attributes from right-to-left.
```typescript
board<{ message: string }>(({ message }, { output }) => {
return output().in(message.as("response"));
});
```
### Creating `code` nodes
The `code` function helps us create a new type of node, of type `code`. The result of calling `code` is a special function -- let's call it a "node factory". A node factory can be used to create many instances of the node.
```typescript
import { base, board, code } from "@google-labs/breadboard";
const calculator = board(() => {
const input = base.input();
const output = base.output();
const calculate = code(({ x, y }) => {
if (typeof x !== "number" || typeof y !== "number") return {};
const sum = x + y;
const diff = x - y;
const prod = x * y;
const quo = x / y;
return { results: { sum, diff, prod, quo } };
})();
input.to(calculate);
calculate.results.to(output);
return output;
});
console.log(await calculator({ x: 1, y: 2 })); // { results: { sum: 3, diff: -1, prod: 2, quo: 0.5 } }
```
In this example, the `code` node takes two properties, `x` and `y`, checks that they are numbers before performing arithmetic operations, and then returns each of the calculations as properties of `results`. If either input is not of the `number` type, then an empty object is returned.
These nodes can be created inside or outside the board. They can also be used when creating custom kits.
> [!NOTE]
> The `code` uses nodes from the [Core Kit](https://www.npmjs.com/package/@google-labs/core-kit). If a board using `code` is serialized, then a runtime instance of the Core Kit must be passed into the board.
### Kits
Kits are collections of ready-made node factory functions for all types of nodes.
#### Using kits
Kits are an easy way to add functionality to your board without writing it yourself. You can think of them as purpose-built third-party libraries you'd add to your web application.
For example, there's a [template kit](https://github.com/breadboard-ai/breadboard/tree/main/packages/template-kit), which contains node types that help with templating: `promptTemplate` and `urlTemplate`. The npm package, which contains the kit, must be installed before they can be imported.
```typescript
import { addKit, board } from "@google-labs/breadboard";
import TemplateKit from "@google-labs/template-kit";
const templateKit = addKit(TemplateKit);
const myBoard = board<{ template: string; name: string }>(
({ template, name }, { output }) => {
const promptTemplate = templateKit.promptTemplate({
template: template,
name: name,
});
return output({ prompt: promptTemplate.prompt });
}
);
console.log(
await myBoard({ template: "Hi, my name is {{name}}!", name: "Bob" })
); // { prompt: 'Hi, my name is Bob!' }
```
Here, `addKit` creates an instance of the Template Kit, which is used to create a `promptTemplate` node within the board. We pass in `template`, which has a placeholder expecting a property called `name` to be supplied, along with the `name` itself. The `promptTemplate` node populates the placeholder in our template with the corresponding inputted value. The value of `prompt`, and a key with the same name, gets passed as an object to the output.
There's a variety of pre-made kits readily available: you can find [a non-exhaustive list of kits here](https://github.com/breadboard-ai/breadboard/blob/main/README.md#packages).
#### Creating custom kits
Custom kits can be created using the `KitBuilder`.
```typescript
const stringManipulationKit = new KitBuilder({
url: ".",
}).build({
joiner: async (inputs) => ({
result: Object.values(inputs).join(" "),
}),
splitter: async (inputs) => ({
result: Object.entries(inputs).map(([key, value]) => ({
[key]: value?.toString().split(""),
})),
}),
});
```
This kit has two different nodes: `joiner`, which joins together all the values from the `inputs` object into a single string separated by spaces, and `splitter`, which also takes `inputs` as an argument and converts each value into a character array that is paired with their respective keys.
The `code` node can also be used when creating custom kits: let's move the logic for `joiner` into a `code` node and use it when building the kit.
```typescript
const joiner = code((inputs) => {
const output = Object.values(inputs).join(" ");
return { output };
});
const stringManipulationKit = new KitBuilder({
url: ".",
}).build({
joiner: async (inputs) => ({
result: await joiner(inputs),
}),
splitter: async (inputs) => ({
result: Object.entries(inputs).map(([key, value]) => ({
[key]: value?.toString().split(""),
})),
}),
});
```
> **Important**: All kits used in a board must be passed in, as runtime kits, when running a board that has been serialized/deserialized.
### Serializing boards
Boards can be serialized into Breadboard Graph Language (BGL). BGL is the common format that Breadboard uses to represent boards. BGL is useful to have a unified language, so you can have boards that call into other boards.
#### Serialization
```typescript
export default await board(({ say }, { output }) => {
return output({ hear: say });
}).serialize({
url: ".",
title: "Echo board",
description: "Say something to the board and it'll echo back!",
version: "0.0.1",
});
```
The `serialize` function is called on the result of the board invocation, which is serialized as [JavaScript Object Notation (JSON)](https://www.json.org/json-en.html).
```json
{
"url": ".",
"title": "Echo board",
"description": "Say something to the board and it'll echo back!",
"version": "0.0.1",
"edges": [
...
],
"nodes": [
...
],
"graphs": {}
}
```
The `serialize` function also takes a single argument: a metadata object that describes the board.
| Name | Type | Description |
| ------------- | -------- | ------------------------------------------------------------------------- |
| `description` | `string` | The description of the graph. |
| `title` | `string` | The title of the graph. |
| `url` | `string` | The URL pointing to the location of the graph. |
| `version` | `string` | Version of the graph. [semver](https://semver.org/) format is encouraged. |
#### Deserialization
To get a runnable board instance, we can pass our serialized board into the `BoardRunner` with `fromGraphDescriptor`.
```typescript
import { BoardRunner } from "@google-labs/breadboard";
import Serialized from "./board/board.js";
const runner = await BoardRunner.fromGraphDescriptor(Serialized);
console.log(await runner.runOnce({ say: "Hello World!" })); // { hear: 'Hello World!' }
```
> **Important**: Any kits used by the board will need to be passed in when running a board that's been serialized.
>
> The `code` node requires the `invoke` node from the `core-kit`.
When running a serialized board that uses kits or `code`, all the kits it uses must be passed in as runtime kits. The `code` function uses nodes from the [Core Kit](https://www.npmjs.com/package/@google-labs/core-kit), which also needs to be passed in.
Each of the kits must be wrapped with `asRuntimeKit` and passed in together in an array.
```typescript
import {
addKit,
asRuntimeKit,
board,
BoardRunner,
code,
} from "@google-labs/breadboard";
import Core from "@google-labs/core-kit";
import TemplateKit from "@google-labs/template-kit";
const templateKit = addKit(TemplateKit);
const helloWorld = await board(({ name }, { output }) => {
const template = code(() => {
return { greeting: "Hello {{name}}!" };
})();
return output({
response: templateKit.promptTemplate({ template: template.greeting, name })
.text,
}); // Output `response` object containing `text` property from `promptTemplate`
}).serialize();
const runner = await BoardRunner.fromGraphDescriptor(helloWorld);
const result = await runner.runOnce(
{ name: "World" },
{ kits: [asRuntimeKit(Core), asRuntimeKit(TemplateKit)] } // Array of `asRuntimeKit` wrapped kits
);
console.log(result); // { response: 'Hello World!' }
```
This board simply takes a `name` property and inserts the value into a template using the `promptTemplate` node from the `TemplateKit`, which returns the value of `text` as `response` in the object returned to the output.
### Running boards
Boards are programs that can be executed by Breadboard runtimes, and they can have multiple input and output nodes which can be visited more than once. In most real-world scenarios, boards will need to run continuously, sometimes stopping to receive inputs or provide outputs, but a simple board might just run once and return a single output.
For the following examples, we will use a simple board that just takes a property called `say` from the input object and passes it, as a property called `hear`, to the output node.
```typescript
import { base, board } from "@google-labs/breadboard";
export default board(({ say }) => {
return say.as("hear").to(base.output());
});
```
`board` instances can be invoked, which initiates a single run (equivalent to the `BoardRunner` using `runOnce(...)`).
```typescript
import myBoard from "./board/board.js";
console.log(await myBoard({ say: "Hello Breadboard!" })); // { hear: 'Hello Breadboard!' }
```
Whereas `BoardRunner` can create runnable boards from serialized graphs: it can run boards continuously or initiate a single run. `BoardRunner` has two ways of running a board:
- `runOnce(...)`: A simplified version of `run` that runs the board until the board provides an output, and returns that output.
```typescript
console.log(await runner.runOnce({ say: "Hello Breadboard!" })); // { hear: 'Hello Breadboard!' }
```
- `run(...)`: Runs the board continuously. This method is an [async generator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AsyncGenerator) that yields the results of each stage of the run.
```typescript
for await (const stop of runner.run()) {
if (stop.type === "input") {
stop.inputs = { say: "Hello Breadboard!" };
} else if (stop.type === "output") {
console.log(stop.outputs); // { hear: 'Hello Breadboard!' }
}
}
```
So far, our board only has outputs that are visited once, and we could simply invoke the `board` or use `runOnce` to run it entirely. Let's change our board to return from two different outputs instead of one.
```typescript
import { base, board } from "@google-labs/breadboard";
export default board(({ say }) => {
say.as("firstHear").to(base.output({ $id: "outputOne" }));
return say.as("secondHear").to(base.output({ $id: "outputTwo" }));
});
```
This board takes the `say` property and passes it to the two different output nodes, which can be identified as `outputOne` and `outputTwo` using the `$id` property, as properties named `firstHear` and `secondHear` respectively. For better clarity, we will change the runner outputs to be logged to the console separately, using the IDs we added to the output nodes against the ID of the currently iterated node in the runner.
```typescript
else if (stop.type === "output") {
if (stop.node.id === "outputOne") {
console.log("outputOne", stop.outputs); // outputOne { firstHear: 'Hello Breadboard!' }
} else if (stop.node.id === "outputTwo") {
console.log("outputTwo", stop.outputs); // outputTwo { secondHear: 'Hello Breadboard!' }
}
}
```
If we were to use `runOnce`, or invoke the board, then we would only receive one output before the board stops running.
### Using a board within a board
Using the [Breadboard Core Kit](https://www.npmjs.com/package/@google-labs/core-kit), boards can be invoked with `core` by passing its graph to the `invoke` function. **Important:** `invoke` runs as `runOnce`, so only the first output of an invoked board will be returned.
```typescript
import { asRuntimeKit, board, BoardRunner } from "@google-labs/breadboard";
import { core, Core } from "@google-labs/core-kit";
import JoinerBoard from "./board/index.js";
const myBoard = await board((inputs, { output }) => {
const invokedBoard = core.invoke({ graph: JoinerBoard });
inputs.to(invokedBoard);
return { response: output(invokedBoard) };
}).serialize();
const runner = await BoardRunner.fromGraphDescriptor(myBoard);
const result = await runner.runOnce(
{ greeting: "Hello", subject: "World" },
{ kits: [asRuntimeKit(Core)] }
);
console.log(result); // { joined: 'Hello World' }
```
This example imports the `JoinerBoard` which is then invoked within `myBoard`. The result is passed to the output node and can be executed using `BoardRunner`.
```typescript
import { board, code } from "@google-labs/breadboard";
export default await board((inputs, { output }) => {
const message = inputs.to(
code((values) => {
const joined = Object.values(values).join(" ");
return { joined };
})()
);
return { response: output(message) };
}).serialize({
title: "Simple Joiner Board",
description: "Joins object values and separates with a space.",
});
```
## Breadboard Board Schema
Schemas are used to attach metadata to a board. This metadata provides useful information that can assist in a board's usage. Schemas can be used to define, describe, and provide default values for a board's inputs. In the next section, we will see schemas in action when running a board on Breadboard Web.
The following is an example of a board which concatenates two strings together and has a schema.
```typescript
import { base, board, code } from "@google-labs/breadboard";
const concatStrings = code<{ greeting: string; subject: string }>((inputs) => {
const { greeting, subject } = inputs;
const concat = greeting.concat(subject);
return { concat };
});
// Metadata for an input
const greetingSchema = {
type: "string",
title: "My Greeting",
default: "Hello",
description: "The greeting",
};
const subjectSchema = {
type: "string",
title: "Subject",
default: "World",
description: "The subject we are greeting",
};
export default await board(() => {
// Attach schema properties to base input
const inputs = base.input({
$id: "String concatenation Inputs",
schema: {
title: "Inputs for string concatenation",
properties: {
greeting: greetingSchema,
subject: subjectSchema,
},
// Used to indicate on Breadboard Web if an input is optional
required: ["greeting", "subject"],
},
});
const result = concatStrings({
greeting: inputs.greeting.isString(),
subject: inputs.subject.isString(),
});
const output = base.output({ $id: "main" });
result.to(output);
return { output };
}).serialize({
title: "String Concatenation",
description: "Board which concatenates two strings together",
});
```
The schema has two inputs, `greeting` and `subject`, both of type string. Inputs can be assigned a `default` value, which will be used if a user does not provide one. `Description` is the text that will appear in the input field on the Breadboard Web UI. `Title` is the text that will be labeled above the input field. `$id` will be the node's name as seen on the Breadboard Web.
The properties can then be accessed similarly to object properties. For example, `inputs.greeting` will access the `greeting` property of the input, which in our example is the greeting string. Inputs can then be provided as inputs to code nodes.
We can also add metadata to input nodes without using the `base` input.
```typescript
export default await board<{ greeting: string; subject: string }>(
({ greeting, subject }, { output }) => {
const greetNode = greeting
.title("My Greeting")
.default("Hello")
.description("The greeting")
.isString();
const subjectNode = subject
.title("Subject")
.default("World")
.description("The subject we are greeting")
.isString();
const result = concatStrings({
greeting: greetNode,
subject: subjectNode,
});
return result.to(output({ $id: "main" }));
}
);
```
## Breadboard Web
Breadboard Web is a package that enables running Breadboard applications in a web browser.
There are two ways to run a board using Breadboard Web:
### 1. Running Breadboard Web Locally
You can run a local instance of Breadboard Web from the [`./packages/breadboard-web`](https://github.com/breadboard-ai/breadboard/tree/main/packages/breadboard-web) directory in the Breadboard monorepo. New TypeScript boards can be added to the `src/boards` directory, and they will be automatically built and picked up by Breadboard Web.
In this example, we will use the board in the Breadboard Schema Section.
```typescript
import { base, board, code } from "@google-labs/breadboard";
const concatStrings = code<{ greeting: string; subject: string }>((inputs) => {
const { greeting, subject } = inputs;
const concat = greeting.concat(subject);
return { concat };
});
const greetingSchema = {
type: "string",
title: "My Greeting",
default: "Hello",
description: "The greeting",
};
const subjectSchema = {
type: "string",
title: "Subject",
default: "World",
description: "The subject we are greeting",
};
export default await board(() => {
const inputs = base.input({
$id: "String concatenation Inputs",
schema: {
title: "Inputs for string concatenation",
properties: {
greeting: greetingSchema,
subject: subjectSchema,
},
},
type: "string",
});
const result = concatStrings({
greeting: inputs.greeting as unknown as string,
subject: inputs.subject as unknown as string,
});
const output = base.output({ $id: "main" });
result.to(output);
return { output };
}).serialize({
title: "String Concatenation",
description: "Board which concatenates two strings together",
});
```
You can then run `npm run dev` in the `boards` directory. This deploys an instance of Breadboard Web accessible athttp://localhost:5173/. Breadboard Web will automatically pick up this graph and allow the board to be selectable in the UI menu.
Running Breadboard Web locally also features hot reloading, which is handy if you are constantly changing your board. Save the file, and it will automatically rebuild and deploy Breadboard Web.
### 2. Using Breadboard Web hosted by Google
We have already demonstrated how to serialize a board into a graph representation. We can store this graph representation as a JSON file.
```typescript
const serialized = await board(() => {
// board code
return { output };
}).serialize({
title: "Serialize Example",
description: "Serialize Example",
});
// save as JSON file
fs.writeFileSync(
path.join(".", "board.json"),
JSON.stringify(serialized, null, "\t")
);
```
The graph representation can then be stored as a file on the internet. This works well with GitHub Gists or repositories. The URL of the file can then be provided as the board in the request parameter and loaded into Breadboard Web (https://breadboard-ai.web.app/?board={raw_github_link_to_file}).
There are several boards available to use on Breadboard Web; below is a board that performs JSON validation.
```
https://breadboard-ai.web.app/?board=%2Fgraphs%2Fjson-validator.json
```
It is also possible to load a remote URL directly into Breadboard Web, for example from a Git repo or a Gist.
```
https://breadboard-ai.web.app/?board=https://raw.githubusercontent.com/breadboard-ai/breadboard/main/packages/breadboard-web/public/graphs/json-validator.json
```
Local instances of Breadboard Web can also load boards via a JSON file and the board request parameter. Option 2 is great if you want to showcase your boards to other people!
### Using Breadboard Web
Now that we have described how to run a board on Breadboard Web, let's discuss how to use it.
When viewing the board on Breadboard Web, we can see all the nodes it comprises.
Clicking `run` on the UI will prompt the user to provide inputs to the board. One of the great features of Breadboard Web is its interactivity. By clicking on the input node, we can see more information about these inputs. As we can see, we have provided information about what the inputs are for. This is metadata attached to the board by using a board schema. This is also where schema defaults come in handy. We can use these defaults if the user does not want to provide their own, as well as providing guidance on what kind of inputs are accepted.
After the board has finished executing, we can see its output. And just like that, we were able to quickly load a board and run it in a web environment.
## Concepts
| Concept | Description |
| ------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Board | A board is a kind of executable program, expressed declaratively as a graph. |
| Nodes | A node is a step in a board that performs some action. This might be calling an external API or executing some local computation. Nodes are similar to functions in traditional programs. |
| Ports | A port is a named input or output of a node. Nodes can have any number of ports. Ports can be source ports (data flows out) or destination ports (data flows in). Source ports are analogous to the parameters of a function. Destination ports are analogous to the results returned by a function. |
| Edges | An edge is a connection between two ports through which data flows. Edges can be constant or optional. **Constants**: Edges can be optional, which means that the execution of a node will not wait for data to be present before proceeding with execution. **Optional**: Edges can be constant, which means the most recent object that flowed through the edge will remain available indefinitely, instead of being destructively consumed. |
| Kits | A kit is a library that provides graphs. |
| Breadboard Graph Language (BGL) | Breadboard Graph Language (BGL) is a graph serialization format described by [this JSON schema](https://github.com/breadboard-ai/breadboard/blob/main/packages/schema/breadboard.schema.json). |
| Runtimes | A runtime is a system that executes boards. Current runtimes include Node and Web. |
| Frontends | A frontend is a system that generates boards. Current frontends include the `@google-labs/breadboard` API for Node, a Python library (coming soon!), and the Breadboard Visual Playground. Boards can also be written by hand directly as JSON, but using a frontend is typically easier. **Note that frontends are never coupled to a specific runtime.** Boards generated by the Node API can be executed by any runtime. |
## Additional Info
To learn more about Breadboard, go to [Breadboard docs site](https://breadboard-ai.github.io/breadboard/).

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

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

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc