@zibby/agent-workflow 0.4.39 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/node.js CHANGED
@@ -1,9 +1,9 @@
1
- var nt=Object.defineProperty;var N=(r,t)=>()=>(r&&(t=r(r=0)),t);var at=(r,t)=>{for(var e in t)nt(r,e,{get:t[e],enumerable:!0})};var D,lt,A,p,W=N(()=>{D=()=>{},lt={debug:D,info:D,warn:(...r)=>console.warn("[workflow]",...r),error:(...r)=>console.error("[workflow]",...r)},A={impl:lt},p={debug:(...r)=>A.impl.debug?.(...r),info:(...r)=>A.impl.info?.(...r),warn:(...r)=>A.impl.warn?.(...r),error:(...r)=>A.impl.error?.(...r)}});var z=N(()=>{});function V(r){return pt.get(r)||null}var P,C,pt,kt,q=N(()=>{P=Symbol.for("@zibby/agent-workflow.skills"),C=Symbol.for("@zibby/agent-workflow.skills.sources");globalThis[P]||(globalThis[P]=new Map);globalThis[C]||(globalThis[C]=new Map);pt=globalThis[P],kt=globalThis[C]});var tt={};at(tt,{getAgentStrategy:()=>Q,invokeAgent:()=>ht,listStrategies:()=>ft,registerStrategy:()=>dt,resolveInvocationModel:()=>X});function dt(r){if(!r||typeof r.getName!="function"||typeof r.invoke!="function")throw new Error("strategy must implement getName() and invoke() (AgentStrategy shape)");let t=y.findIndex(e=>e.getName()===r.getName());t>=0?y[t]=r:y.push(r)}function ft(){return y.map(r=>r.getName())}function X({config:r={},options:t={},strategyName:e,envModel:o}={}){let n=r.models||{},s=t.nodeName&&n[t.nodeName]||null,a=n.default||null,S=r.agent?.[e]?.model||null,u=(typeof o=="string"?o.trim():"")||null;return s||a||S||t.model||u||null}function Q(r={}){let{state:t={},preferredAgent:e=null}=r,o=e||t.agentType||process.env.AGENT_TYPE;if(!o){let s=y.map(a=>a.getName()).join(", ")||"none registered";throw new Error(`No agent specified. Set agentType in state or AGENT_TYPE env var. Available: ${s}`)}p.debug(`[workflow] agent selection: requested=${o}`);let n=y.find(s=>s.getName()===o);if(!n){let s=y.map(a=>a.getName()).join(", ")||"none registered";throw new Error(`Unknown agent '${o}'. Available: ${s}`)}if(!n.canHandle(r))throw new Error(`Agent '${o}' is not available in this environment. Check credentials/environment.`);return p.debug(`[workflow] using agent: ${n.getName()}`),n}async function ht(r,t={},e={}){let o=t.state&&typeof t.state.getAll=="function"?t.state.getAll():t.state||{},n={...t,state:o},s=Q(n),a=o.config||e.config||{},S=X({config:a,options:e,strategyName:s.name,envModel:process.env.MODEL}),u={...e,model:S,workspace:o.workspace||e.workspace,schema:e.schema||t.schema,images:e.images||t.images||[],skills:e.skills||t.skills||[],plugins:e.plugins||t.plugins||[],config:a},h=r,b=u.skills||[];if(b.length>0&&!e.skipPromptFragments){let g=b.map(E=>{let l=V(E)?.promptFragment;return typeof l=="function"?l():l}).filter(Boolean);g.length>0&&(h+=`
1
+ var nt=Object.defineProperty;var N=(r,t,e)=>()=>{if(e)throw e[0];try{return r&&(t=r(r=0)),t}catch(o){throw e=[o],o}};var at=(r,t)=>{for(var e in t)nt(r,e,{get:t[e],enumerable:!0})};var D,lt,T,p,v=N(()=>{D=()=>{},lt={debug:D,info:D,warn:(...r)=>console.warn("[workflow]",...r),error:(...r)=>console.error("[workflow]",...r)},T={impl:lt},p={debug:(...r)=>T.impl.debug?.(...r),info:(...r)=>T.impl.info?.(...r),warn:(...r)=>T.impl.warn?.(...r),error:(...r)=>T.impl.error?.(...r)}});var z=N(()=>{});function V(r){return pt.get(r)||null}var P,M,pt,Ot,q=N(()=>{P=Symbol.for("@zibby/agent-workflow.skills"),M=Symbol.for("@zibby/agent-workflow.skills.sources");globalThis[P]||(globalThis[P]=new Map);globalThis[M]||(globalThis[M]=new Map);pt=globalThis[P],Ot=globalThis[M]});var tt={};at(tt,{getAgentStrategy:()=>Q,invokeAgent:()=>ht,listStrategies:()=>ft,registerStrategy:()=>dt,resolveInvocationModel:()=>X});function dt(r){if(!r||typeof r.getName!="function"||typeof r.invoke!="function")throw new Error("strategy must implement getName() and invoke() (AgentStrategy shape)");let t=y.findIndex(e=>e.getName()===r.getName());t>=0?y[t]=r:y.push(r)}function ft(){return y.map(r=>r.getName())}function X({config:r={},options:t={},strategyName:e,envModel:o}={}){let n=r.models||{},s=t.nodeName&&n[t.nodeName]||null,a=n.default||null,_=r.agent?.[e]?.model||null,u=(typeof o=="string"?o.trim():"")||null;return s||a||_||t.model||u||null}function Q(r={}){let{state:t={},preferredAgent:e=null}=r,o=e||t.agentType||process.env.AGENT_TYPE;if(!o){let s=y.map(a=>a.getName()).join(", ")||"none registered";throw new Error(`No agent specified. Set agentType in state or AGENT_TYPE env var. Available: ${s}`)}p.debug(`[workflow] agent selection: requested=${o}`);let n=y.find(s=>s.getName()===o);if(!n){let s=y.map(a=>a.getName()).join(", ")||"none registered";throw new Error(`Unknown agent '${o}'. Available: ${s}`)}if(!n.canHandle(r))throw new Error(`Agent '${o}' is not available in this environment. Check credentials/environment.`);return p.debug(`[workflow] using agent: ${n.getName()}`),n}async function ht(r,t={},e={}){let o=t.state&&typeof t.state.getAll=="function"?t.state.getAll():t.state||{},n={...t,state:o},s=Q(n),a=o.config||e.config||{},_=X({config:a,options:e,strategyName:s.name,envModel:process.env.MODEL}),u={...e,model:_,workspace:o.workspace||e.workspace,schema:e.schema||t.schema,images:e.images||t.images||[],skills:e.skills||t.skills||[],extraMcpServers:e.extraMcpServers||o.extraMcpServers||t.extraMcpServers||[],plugins:e.plugins||t.plugins||[],config:a},h=r,b=u.skills||[];if(b.length>0&&!e.skipPromptFragments){let g=b.map(E=>{let l=V(E)?.promptFragment;return typeof l=="function"?l():l}).filter(Boolean);g.length>0&&(h+=`
2
2
 
3
3
  ${g.join(`
4
4
 
5
- `)}`)}let i=o._currentNodeConfig?.stores;if(Array.isArray(i)&&i.length>0&&typeof i[0]=="object"){let g=i.length<=8,E=i.map(l=>{let I=l?.id??l?.storeId??"",O=(l?.name??"").toString().trim()||I,w=l?.type?` \xB7 ${l.type}`:"",f=(l?.description||"").toString().replace(/\s+/g," ").trim(),_=`- ${O} \xB7 ${f||"(no description)"}${w} (id: ${I})`;if(g&&l?.schema&&typeof l.schema=="object"){let c=l.schema.properties&&typeof l.schema.properties=="object"?Object.keys(l.schema.properties):Object.keys(l.schema);c.length&&(_+=`
6
- fields: ${c.join(", ")}`)}return _});h+=`
5
+ `)}`)}let i=o._currentNodeConfig?.stores;if(Array.isArray(i)&&i.length>0&&typeof i[0]=="object"){let g=i.length<=8,E=i.map(l=>{let I=l?.id??l?.storeId??"",k=(l?.name??"").toString().trim()||I,S=l?.type?` \xB7 ${l.type}`:"",f=(l?.description||"").toString().replace(/\s+/g," ").trim(),w=`- ${k} \xB7 ${f||"(no description)"}${S} (id: ${I})`;if(g&&l?.schema&&typeof l.schema=="object"){let c=l.schema.properties&&typeof l.schema.properties=="object"?Object.keys(l.schema.properties):Object.keys(l.schema);c.length&&(w+=`
6
+ fields: ${c.join(", ")}`)}return w});h+=`
7
7
 
8
8
  AVAILABLE STORES (pick a store by its description and pass its NAME to the store tool):
9
9
  ${E.join(`
@@ -14,9 +14,9 @@ PRIORITY OVERRIDE \u2014 THE FOLLOWING INSTRUCTIONS TAKE PRECEDENCE OVER ALL PRE
14
14
  \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
15
15
 
16
16
  ${m}
17
- `),p.debug(`[workflow] prompt length: ${h.length} chars`),s.invoke(h,u)}var M,y,et=N(()=>{z();W();q();M=Symbol.for("@zibby/agent-workflow.strategies");globalThis[M]||(globalThis[M]=[]);y=globalThis[M]});import $ from"handlebars";var T=class{constructor(t){this.schema=t}parse(t){let e=t.match(/```json\s*([\s\S]*?)\s*```/);if(e)return this.validate(JSON.parse(e[1]));let o=[t.match(/\{[\s\S]*?\}/),t.match(/\{[\s\S]*\}/)].filter(Boolean).map(n=>n[0]);for(let n of o)try{return this.validate(JSON.parse(n))}catch(s){if(!(s instanceof SyntaxError))throw s}return this.validate({result:t.trim()})}validate(t){let e=[];for(let[o,n]of Object.entries(this.schema)){if(n.required&&!(o in t)&&e.push(`Missing required field: ${o}`),o in t&&n.type){let s=typeof t[o];s!==n.type&&e.push(`Field '${o}' expected ${n.type}, got ${s}`)}if(n.validate&&o in t){let s=n.validate(t[o]);s&&e.push(`Field '${o}': ${s}`)}}if(e.length>0)throw new Error(`Output validation failed:
17
+ `),p.debug(`[workflow] prompt length: ${h.length} chars`),s.invoke(h,u)}var C,y,et=N(()=>{z();v();q();C=Symbol.for("@zibby/agent-workflow.strategies");globalThis[C]||(globalThis[C]=[]);y=globalThis[C]});import $ from"handlebars";var W=class{constructor(t){this.schema=t}parse(t){let e=t.match(/```json\s*([\s\S]*?)\s*```/);if(e)return this.validate(JSON.parse(e[1]));let o=[t.match(/\{[\s\S]*?\}/),t.match(/\{[\s\S]*\}/)].filter(Boolean).map(n=>n[0]);for(let n of o)try{return this.validate(JSON.parse(n))}catch(s){if(!(s instanceof SyntaxError))throw s}return this.validate({result:t.trim()})}validate(t){let e=[];for(let[o,n]of Object.entries(this.schema)){if(n.required&&!(o in t)&&e.push(`Missing required field: ${o}`),o in t&&n.type){let s=typeof t[o];s!==n.type&&e.push(`Field '${o}' expected ${n.type}, got ${s}`)}if(n.validate&&o in t){let s=n.validate(t[o]);s&&e.push(`Field '${o}': ${s}`)}}if(e.length>0)throw new Error(`Output validation failed:
18
18
  ${e.join(`
19
- `)}`);return t}};W();import{writeFileSync as F,readFileSync as rt,existsSync as ot,mkdirSync as mt}from"node:fs";import{join as j,dirname as gt}from"node:path";import d from"chalk";var ct="__WORKFLOW_GRAPH_LOG__",k=d.gray("\u2502"),ut=d.gray("\u250C"),G=d.gray("\u2514"),v=d.green("\u25C6"),H=d.hex("#c084fc")("\u25C6"),J=d.hex("#2dd4bf")("\u25C6"),x=d.red("\u25C6"),U=`${k} `,B=2;function K(r){return r<1e3?`${r}ms`:`${(r/1e3).toFixed(1)}s`}function Y(r,t){return(e,o,n)=>{if(typeof e!="string")return r(e,o,n);let s=process.stdout.columns||120,a="";for(let S=0;S<e.length;S++){let u=e[S];t.lineStart&&(a+=U,t.col=B,t.lineStart=!1),u===`
19
+ `)}`);return t}};v();import{writeFileSync as F,readFileSync as rt,existsSync as ot,mkdirSync as mt}from"node:fs";import{join as j,dirname as gt}from"node:path";import d from"chalk";var ct="__WORKFLOW_GRAPH_LOG__",O=d.gray("\u2502"),ut=d.gray("\u250C"),G=d.gray("\u2514"),x=d.green("\u25C6"),H=d.hex("#c084fc")("\u25C6"),J=d.hex("#2dd4bf")("\u25C6"),A=d.red("\u25C6"),U=`${O} `,B=2;function K(r){return r<1e3?`${r}ms`:`${(r/1e3).toFixed(1)}s`}function Y(r,t){return(e,o,n)=>{if(typeof e!="string")return r(e,o,n);let s=process.stdout.columns||120,a="";for(let _=0;_<e.length;_++){let u=e[_];t.lineStart&&(a+=U,t.col=B,t.lineStart=!1),u===`
20
20
  `?(a+=u,t.lineStart=!0,t.col=0,t.inEsc=!1):u==="\x1B"?(t.inEsc=!0,a+=u):t.inEsc?(a+=u,(u>="A"&&u<="Z"||u>="a"&&u<="z")&&(t.inEsc=!1)):(t.col++,a+=u,t.col>=s&&(a+=`
21
21
  ${U}`,t.col=B))}return r(a,o,n)}}var R=class{constructor(){this._currentNode=null,this._origStdoutWrite=null,this._origStderrWrite=null,this._emitWorkflowGraphMarkers=String(process.env.ZIBBY_EMIT_GRAPH_MARKERS||"").trim()==="1"||String(process.env.ZIBBY_WORKFLOW_GRAPH_LOG_MARKERS||"").trim()==="1"}get isInsideNode(){return this._currentNode!==null}_startIntercepting(){this._origStdoutWrite=process.stdout.write.bind(process.stdout),this._origStderrWrite=process.stderr.write.bind(process.stderr);let t={lineStart:!0,col:0,inEsc:!1},e={lineStart:!0,col:0,inEsc:!1};this._outState=t,this._errState=e,process.stdout.write=Y(this._origStdoutWrite,t),process.stderr.write=Y(this._origStderrWrite,e)}_stopIntercepting(){this._origStdoutWrite&&(this._outState&&!this._outState.lineStart&&this._origStdoutWrite(`
22
22
  `),process.stdout.write=this._origStdoutWrite),this._origStderrWrite&&(this._errState&&!this._errState.lineStart&&this._origStderrWrite(`
@@ -25,10 +25,10 @@ ${U}`,t.col=B))}return r(a,o,n)}}var R=class{constructor(){this._currentNode=nul
25
25
  `;this._origStdoutWrite?this._origStdoutWrite(e):process.stdout.write(e)}_writeDot(t,e){this._origStdoutWrite?(this._outState&&!this._outState.lineStart&&(this._origStdoutWrite(`
26
26
  `),this._outState.lineStart=!0,this._outState.col=0),this._origStdoutWrite(`${t} ${e}
27
27
  `)):process.stdout.write.bind(process.stdout)(`${t} ${e}
28
- `)}step(t){this._origStdoutWrite?this._writeDot(v,t):process.stdout.write.bind(process.stdout)(`${k} ${v} ${t}
29
- `)}stepInfo(t){this.step(t)}stepTool(t){this._origStdoutWrite?this._writeDot(H,t):process.stdout.write.bind(process.stdout)(`${k} ${H} ${t}
30
- `)}stepMemory(t){let e=d.hex("#2dd4bf")(t);this._origStdoutWrite?this._writeDot(J,e):process.stdout.write.bind(process.stdout)(`${k} ${J} ${e}
31
- `)}stepFail(t){this._origStdoutWrite?this._writeDot(x,d.red(t)):process.stdout.write.bind(process.stdout)(`${k} ${x} ${d.red(t)}
32
- `)}nodeStart(t){this._currentNode=t,this._emitGraphLogMarker({phase:"node_begin",node:t}),this._rawWrite(`${ut} ${t}`),this._startIntercepting()}nodeComplete(t,e={}){this._stopIntercepting();let{duration:o,details:n}=e;if(n)for(let a of n)this._rawWrite(`${v} ${a}`);let s=o?d.dim(` ${K(o)}`):"";this._rawWrite(`${G} ${d.green("done")}${s}`),this._emitGraphLogMarker({phase:"node_end",node:t}),this._rawWrite("")}nodeFailed(t,e,o={}){this._stopIntercepting();let{duration:n}=o,s=n?d.dim(` ${K(n)}`):"";this._rawWrite(`${x} ${d.red(e)}`),this._rawWrite(`${G} ${d.red("failed")}${s}`),this._emitGraphLogMarker({phase:"node_end",node:t}),this._rawWrite("")}route(t,e){this._rawWrite(d.dim(` ${t} \u2192 ${e}`)),this._rawWrite("")}graphComplete(){}},Z=new R;var L=".session-info.json";var Et=Object.freeze(["codebase-memory","code-scan","artifact"]);$.helpers.inc||$.registerHelper("inc",r=>Number(r)+1);$.helpers.json||$.registerHelper("json",r=>JSON.stringify(r,null,2));$.helpers.eq||$.registerHelper("eq",(r,t)=>r===t);var it=class{constructor(t){if(this.config=t,this.name=t.name,this.prompt=t.prompt,this.outputSchema=t.outputSchema,!this.outputSchema&&!t._isCustomCode&&!t._isRouter)throw new Error(`Node '${this.name}' must define outputSchema (Zod schema). This defines the contract for what the node returns to state.`);this.isZodSchema=this.outputSchema&&typeof this.outputSchema._def<"u",this.parser=t.outputSchema&&!this.isZodSchema?new T(t.outputSchema):null,this.retries=t.retries||0,this.onComplete=t.onComplete,this.customExecute=t.execute}async execute(t,e){if(this.config._isRouter)return p.debug(`[workflow] node '${this.name}': router passthrough (routing happens on its conditional edges)`),{success:!0,output:{},raw:null};let o=()=>e&&typeof e.getAll=="function"?e.getAll():t,n=i=>e&&typeof e.get=="function"?e.get(i):t?.[i];if(typeof this.customExecute=="function"){p.debug(`[workflow] node '${this.name}': custom execute (skipping LLM)`);try{let i=await this.customExecute(t);return typeof i=="object"&&i!==null&&i.success===!1?{success:!1,error:i.error||"Node execution failed",raw:i.raw||null}:this.isZodSchema?(p.debug(`[workflow] node '${this.name}': validating output schema`),{success:!0,output:this.outputSchema.parse(i),raw:null}):{success:!0,output:i,raw:null}}catch(i){return p.error(`[workflow] node '${this.name}' failed: ${i.message}`),i.name==="ZodError"&&p.error(`Schema errors: ${JSON.stringify(i.issues||i.errors,null,2)}`),{success:!1,error:i.message,raw:null}}}let s;typeof this.prompt=="function"?s=this.prompt(o()):typeof this.prompt=="string"&&this.prompt.includes("{{")?(this._compiledPrompt||(this._compiledPrompt=$.compile(this.prompt,{noEscape:!0})),s=this._compiledPrompt(o())):s=this.prompt;let a=n("_skillHints");a&&(s=`${a}
28
+ `)}step(t){this._origStdoutWrite?this._writeDot(x,t):process.stdout.write.bind(process.stdout)(`${O} ${x} ${t}
29
+ `)}stepInfo(t){this.step(t)}stepTool(t){this._origStdoutWrite?this._writeDot(H,t):process.stdout.write.bind(process.stdout)(`${O} ${H} ${t}
30
+ `)}stepMemory(t){let e=d.hex("#2dd4bf")(t);this._origStdoutWrite?this._writeDot(J,e):process.stdout.write.bind(process.stdout)(`${O} ${J} ${e}
31
+ `)}stepFail(t){this._origStdoutWrite?this._writeDot(A,d.red(t)):process.stdout.write.bind(process.stdout)(`${O} ${A} ${d.red(t)}
32
+ `)}nodeStart(t){this._currentNode=t,this._emitGraphLogMarker({phase:"node_begin",node:t}),this._rawWrite(`${ut} ${t}`),this._startIntercepting()}nodeComplete(t,e={}){this._stopIntercepting();let{duration:o,details:n}=e;if(n)for(let a of n)this._rawWrite(`${x} ${a}`);let s=o?d.dim(` ${K(o)}`):"";this._rawWrite(`${G} ${d.green("done")}${s}`),this._emitGraphLogMarker({phase:"node_end",node:t}),this._rawWrite("")}nodeFailed(t,e,o={}){this._stopIntercepting();let{duration:n}=o,s=n?d.dim(` ${K(n)}`):"";this._rawWrite(`${A} ${d.red(e)}`),this._rawWrite(`${G} ${d.red("failed")}${s}`),this._emitGraphLogMarker({phase:"node_end",node:t}),this._rawWrite("")}route(t,e){this._rawWrite(d.dim(` ${t} \u2192 ${e}`)),this._rawWrite("")}graphComplete(){}},Z=new R;var L=".session-info.json";var Et=Object.freeze(["codebase-memory","code-scan","artifact"]);$.helpers.inc||$.registerHelper("inc",r=>Number(r)+1);$.helpers.json||$.registerHelper("json",r=>JSON.stringify(r,null,2));$.helpers.eq||$.registerHelper("eq",(r,t)=>r===t);var it=class{constructor(t){if(this.config=t,this.name=t.name,this.prompt=t.prompt,this.outputSchema=t.outputSchema,!this.outputSchema&&!t._isCustomCode&&!t._isRouter)throw new Error(`Node '${this.name}' must define outputSchema (Zod schema). This defines the contract for what the node returns to state.`);this.isZodSchema=this.outputSchema&&typeof this.outputSchema._def<"u",this.parser=t.outputSchema&&!this.isZodSchema?new W(t.outputSchema):null,this.retries=t.retries||0,this.onComplete=t.onComplete,this.customExecute=t.execute}async execute(t,e){if(this.config._isRouter)return p.debug(`[workflow] node '${this.name}': router passthrough (routing happens on its conditional edges)`),{success:!0,output:{},raw:null};let o=()=>e&&typeof e.getAll=="function"?e.getAll():t,n=i=>e&&typeof e.get=="function"?e.get(i):t?.[i];if(typeof this.customExecute=="function"){p.debug(`[workflow] node '${this.name}': custom execute (skipping LLM)`);try{let i=await this.customExecute(t);return typeof i=="object"&&i!==null&&i.success===!1?{success:!1,error:i.error||"Node execution failed",raw:i.raw||null}:this.isZodSchema?(p.debug(`[workflow] node '${this.name}': validating output schema`),{success:!0,output:this.outputSchema.parse(i),raw:null}):{success:!0,output:i,raw:null}}catch(i){return p.error(`[workflow] node '${this.name}' failed: ${i.message}`),i.name==="ZodError"&&p.error(`Schema errors: ${JSON.stringify(i.issues||i.errors,null,2)}`),{success:!1,error:i.message,raw:null}}}let s;typeof this.prompt=="function"?s=this.prompt(o()):typeof this.prompt=="string"&&this.prompt.includes("{{")?(this._compiledPrompt||(this._compiledPrompt=$.compile(this.prompt,{noEscape:!0})),s=this._compiledPrompt(o())):s=this.prompt;let a=n("_skillHints");a&&(s=`${a}
33
33
 
34
- ${s}`);let S=o(),u=S.cwd||process.cwd(),h=S.sessionPath;try{if(h){let i=j(h,L);if(ot(i)){let g=JSON.parse(rt(i,"utf-8"));g.currentNode=this.name,F(i,JSON.stringify(g,null,2),"utf-8")}let m=j(h,"..",L);if(ot(m))try{let g=JSON.parse(rt(m,"utf-8"));g.currentNode=this.name,F(m,JSON.stringify(g,null,2),"utf-8")}catch{}}}catch(i){p.debug(`[workflow] could not update session info: ${i.message}`)}let b=null;for(let i=0;i<=this.retries;i++)try{p.debug(`[workflow] node '${this.name}' attempt ${i}`);let m=o().config||{},g=m.agents||{},E=this.config.agent??g[this.name]??null,l={state:o()};E&&(l.preferredAgent=E);let I={workspace:u,schema:this.isZodSchema?this.outputSchema:null,skills:this.config.skills||[],plugins:this.config.plugins||[],sessionPath:h,config:m,nodeName:this.name,timeout:this.config?.timeout||3e5},O=t?._coreInvokeAgent;O||(O=(await Promise.resolve().then(()=>(et(),tt))).invokeAgent);let w=await O(s,l,I),f,_;if(typeof w=="string"?(f=w,_=null):w.structured?(f=w.raw||JSON.stringify(w.structured,null,2),_=w.structured):(f=w.raw||JSON.stringify(w,null,2),_=w.extracted||null),h)try{let c=j(h,this.name,"raw_stream_output.txt");mt(gt(c),{recursive:!0}),F(c,typeof f=="string"?f:JSON.stringify(f),"utf-8")}catch(c){p.debug(`[workflow] could not save raw output: ${c.message}`)}if(this.isZodSchema&&_){p.info(`[workflow] node '${this.name}': output validated: ${JSON.stringify(_,null,2)}`);let c=_;if(typeof this.onComplete=="function")try{c=await this.onComplete(o(),_)}catch(st){p.warn(`[workflow] onComplete hook failed: ${st.message}`)}return{success:!0,output:c,raw:f}}if(typeof this.onComplete=="function")try{return{success:!0,output:await this.onComplete(o(),{raw:f}),raw:f}}catch(c){throw new Error(`onComplete failed: ${c.message}`,{cause:c})}if(this.parser){let c=this.parser.parse(f);return p.info(`[workflow] node '${this.name}': parsed output: ${JSON.stringify(c,null,2)}`),Z.step("Output parsed"),{success:!0,output:c,raw:f}}return{success:!0,output:f,raw:f}}catch(m){b=m,i<this.retries&&p.info(`[workflow] node '${this.name}' failed, retrying (${i+1}/${this.retries})\u2026`)}return{success:!1,error:b.message,raw:null}}};export{it as Node};
34
+ ${s}`);let _=o(),u=_.cwd||process.cwd(),h=_.sessionPath;try{if(h){let i=j(h,L);if(ot(i)){let g=JSON.parse(rt(i,"utf-8"));g.currentNode=this.name,F(i,JSON.stringify(g,null,2),"utf-8")}let m=j(h,"..",L);if(ot(m))try{let g=JSON.parse(rt(m,"utf-8"));g.currentNode=this.name,F(m,JSON.stringify(g,null,2),"utf-8")}catch{}}}catch(i){p.debug(`[workflow] could not update session info: ${i.message}`)}let b=null;for(let i=0;i<=this.retries;i++)try{p.debug(`[workflow] node '${this.name}' attempt ${i}`);let m=o().config||{},g=m.agents||{},E=this.config.agent??g[this.name]??null,l={state:o()};E&&(l.preferredAgent=E);let I={workspace:u,schema:this.isZodSchema?this.outputSchema:null,skills:this.config.skills||[],plugins:this.config.plugins||[],sessionPath:h,config:m,nodeName:this.name,timeout:this.config?.timeout||3e5},k=t?._coreInvokeAgent;k||(k=(await Promise.resolve().then(()=>(et(),tt))).invokeAgent);let S=await k(s,l,I),f,w;if(typeof S=="string"?(f=S,w=null):S.structured?(f=S.raw||JSON.stringify(S.structured,null,2),w=S.structured):(f=S.raw||JSON.stringify(S,null,2),w=S.extracted||null),h)try{let c=j(h,this.name,"raw_stream_output.txt");mt(gt(c),{recursive:!0}),F(c,typeof f=="string"?f:JSON.stringify(f),"utf-8")}catch(c){p.debug(`[workflow] could not save raw output: ${c.message}`)}if(this.isZodSchema&&w){p.info(`[workflow] node '${this.name}': output validated: ${JSON.stringify(w,null,2)}`);let c=w;if(typeof this.onComplete=="function")try{c=await this.onComplete(o(),w)}catch(st){p.warn(`[workflow] onComplete hook failed: ${st.message}`)}return{success:!0,output:c,raw:f}}if(typeof this.onComplete=="function")try{return{success:!0,output:await this.onComplete(o(),{raw:f}),raw:f}}catch(c){throw new Error(`onComplete failed: ${c.message}`,{cause:c})}if(this.parser){let c=this.parser.parse(f);return p.info(`[workflow] node '${this.name}': parsed output: ${JSON.stringify(c,null,2)}`),Z.step("Output parsed"),{success:!0,output:c,raw:f}}return{success:!0,output:f,raw:f}}catch(m){b=m,i<this.retries&&p.info(`[workflow] node '${this.name}' failed, retrying (${i+1}/${this.retries})\u2026`)}return{success:!1,error:b.message,raw:null}}};export{it as Node};
@@ -2,34 +2,10 @@
2
2
  * Structured output parsing with schema validation.
3
3
  * Similar to LangChain's StructuredOutputParser.
4
4
  */
5
- export class OutputParser {
5
+ export declare class OutputParser {
6
+ schema?: any;
6
7
  constructor(schema: any);
7
- schema: any;
8
8
  parse(text: any): any;
9
9
  validate(data: any): any;
10
10
  }
11
- export namespace SchemaTypes {
12
- export function string(required?: boolean): {
13
- type: string;
14
- required: boolean;
15
- };
16
- export function number(required?: boolean): {
17
- type: string;
18
- required: boolean;
19
- };
20
- export function boolean(required?: boolean): {
21
- type: string;
22
- required: boolean;
23
- };
24
- export function array(required?: boolean): {
25
- type: string;
26
- required: boolean;
27
- validate: (v: any) => string;
28
- };
29
- export function _enum(values: any, required?: boolean): {
30
- type: string;
31
- required: boolean;
32
- validate: (v: any) => string;
33
- };
34
- export { _enum as enum };
35
- }
11
+ export declare const SchemaTypes: any;
@@ -1,3 +1,3 @@
1
- var a=class{constructor(e){this.schema=e}parse(e){let r=e.match(/```json\s*([\s\S]*?)\s*```/);if(r)return this.validate(JSON.parse(r[1]));let i=[e.match(/\{[\s\S]*?\}/),e.match(/\{[\s\S]*\}/)].filter(Boolean).map(n=>n[0]);for(let n of i)try{return this.validate(JSON.parse(n))}catch(s){if(!(s instanceof SyntaxError))throw s}return this.validate({result:e.trim()})}validate(e){let r=[];for(let[i,n]of Object.entries(this.schema)){if(n.required&&!(i in e)&&r.push(`Missing required field: ${i}`),i in e&&n.type){let s=typeof e[i];s!==n.type&&r.push(`Field '${i}' expected ${n.type}, got ${s}`)}if(n.validate&&i in e){let s=n.validate(e[i]);s&&r.push(`Field '${i}': ${s}`)}}if(r.length>0)throw new Error(`Output validation failed:
1
+ var s=class{constructor(e){this.schema=e}parse(e){let r=e.match(/```json\s*([\s\S]*?)\s*```/);if(r)return this.validate(JSON.parse(r[1]));let i=[e.match(/\{[\s\S]*?\}/),e.match(/\{[\s\S]*\}/)].filter(Boolean).map(n=>n[0]);for(let n of i)try{return this.validate(JSON.parse(n))}catch(a){if(!(a instanceof SyntaxError))throw a}return this.validate({result:e.trim()})}validate(e){let r=[];for(let[i,n]of Object.entries(this.schema)){if(n.required&&!(i in e)&&r.push(`Missing required field: ${i}`),i in e&&n.type){let a=typeof e[i];a!==n.type&&r.push(`Field '${i}' expected ${n.type}, got ${a}`)}if(n.validate&&i in e){let a=n.validate(e[i]);a&&r.push(`Field '${i}': ${a}`)}}if(r.length>0)throw new Error(`Output validation failed:
2
2
  ${r.join(`
3
- `)}`);return e}},o={string:(t=!0)=>({type:"string",required:t}),number:(t=!0)=>({type:"number",required:t}),boolean:(t=!0)=>({type:"boolean",required:t}),array:(t=!0)=>({type:"object",required:t,validate:e=>Array.isArray(e)?null:"must be an array"}),enum:(t,e=!0)=>({type:"string",required:e,validate:r=>t.includes(r)?null:`must be one of: ${t.join(", ")}`})};export{a as OutputParser,o as SchemaTypes};
3
+ `)}`);return e}},o={string:(t=!0)=>({type:"string",required:t}),number:(t=!0)=>({type:"number",required:t}),boolean:(t=!0)=>({type:"boolean",required:t}),array:(t=!0)=>({type:"object",required:t,validate:e=>Array.isArray(e)?null:"must be an array"}),enum:(t,e=!0)=>({type:"string",required:e,validate:r=>t.includes(r)?null:`must be one of: ${t.join(", ")}`})};export{s as OutputParser,o as SchemaTypes};
@@ -19,25 +19,11 @@
19
19
  * across sources. First-party / intentional only.
20
20
  * @throws if a DIFFERENT source tries to overwrite an already-registered id (collision).
21
21
  */
22
- export function registerSkill(skill: {
23
- id: string;
24
- serverName: string;
25
- allowedTools: string[];
26
- resolve?: Function;
27
- envKeys?: string[];
28
- description?: string;
29
- tools?: any[];
30
- cursorKey?: string;
31
- promptFragment?: Function;
32
- middleware?: Function;
33
- }, opts?: {
34
- source?: string;
35
- override?: boolean;
36
- }): void;
22
+ export declare function registerSkill(skill: any, opts?: any): void;
37
23
  /** @returns {object|null} */
38
- export function getSkill(id: any): object | null;
24
+ export declare function getSkill(id: any): any;
39
25
  /** @returns {boolean} */
40
- export function hasSkill(id: any): boolean;
26
+ export declare function hasSkill(id: any): any;
41
27
  /**
42
28
  * The provenance (package name) that registered an id, or `null` for a
43
29
  * first-party (untagged) registration / an unknown id. Lets the runtime decide
@@ -45,10 +31,10 @@ export function hasSkill(id: any): boolean;
45
31
  * ambient tenant tokens / the egress JWT (Phase-3 secret-scoping prereq).
46
32
  * @returns {string|null}
47
33
  */
48
- export function getSkillSource(id: any): string | null;
34
+ export declare function getSkillSource(id: any): any;
49
35
  /** @returns {Map<string, object>} shallow copy */
50
- export function getAllSkills(): Map<string, object>;
36
+ export declare function getAllSkills(): Map<unknown, unknown>;
51
37
  /** @returns {string[]} */
52
- export function listSkillIds(): string[];
38
+ export declare function listSkillIds(): unknown[];
53
39
  /** Remove all registered skills. Primarily for test teardown. */
54
- export function clearSkills(): void;
40
+ export declare function clearSkills(): void;
package/dist/state.d.ts CHANGED
@@ -1,7 +1,11 @@
1
- export class WorkflowState {
2
- constructor(initialState?: {});
3
- _state: any;
4
- _history: any[];
1
+ /**
2
+ * Immutable-snapshot state container for workflow graph execution.
3
+ * Similar in spirit to LangGraph's state annotation.
4
+ */
5
+ export declare class WorkflowState {
6
+ _history?: any;
7
+ _state?: any;
8
+ constructor(initialState?: any);
5
9
  get(key: any): any;
6
10
  set(key: any, value: any): void;
7
11
  update(updates: any): void;
package/dist/state.js CHANGED
@@ -1 +1 @@
1
- var a=new Set(["__proto__","constructor","prototype"]);function i(r){if(a.has(r))throw new Error(`Invalid state key: "${r}"`)}var h=class{constructor(t={}){this._state=Object.create(null),Object.assign(this._state,{messages:[],errors:[],artifacts:{},metadata:{},...t}),this._history=[]}get(t){return this._state[t]}set(t,s){i(t),this._history.push({...this._state}),this._state[t]=s}update(t){let s=Object.getOwnPropertyNames(t);for(let e of s)i(e);this._history.push({...this._state});for(let e of s)this._state[e]=t[e]}append(t,s){i(t),this._history.push({...this._state}),Array.isArray(this._state[t])||(this._state[t]=[]),this._state[t].push(s)}getAll(){return{...this._state}}rollback(){this._history.length>0&&(this._state=this._history.pop())}};export{h as WorkflowState};
1
+ var h=new Set(["__proto__","constructor","prototype"]);function a(r){if(h.has(r))throw new Error(`Invalid state key: "${r}"`)}var i=class{constructor(t={}){this._state=Object.create(null),Object.assign(this._state,{messages:[],errors:[],artifacts:{},metadata:{},...t}),this._history=[]}get(t){return this._state[t]}set(t,s){a(t),this._history.push({...this._state}),this._state[t]=s}update(t){let s=Object.getOwnPropertyNames(t);for(let e of s)a(e);this._history.push({...this._state});for(let e of s)this._state[e]=t[e]}append(t,s){a(t),this._history.push({...this._state}),Array.isArray(this._state[t])||(this._state[t]=[]),this._state[t].push(s)}getAll(){return{...this._state}}rollback(){this._history.length>0&&(this._state=this._history.pop())}};export{i as WorkflowState};
package/dist/stores.d.ts CHANGED
@@ -1,13 +1,3 @@
1
- /**
2
- * Validate an array of store declarations.
3
- *
4
- * @param {Array<{name?: string, description?: string}>} stores
5
- * @returns {string[]} errors — empty when valid.
6
- */
7
- export function validateStoreDefs(stores: Array<{
8
- name?: string;
9
- description?: string;
10
- }>): string[];
11
1
  /**
12
2
  * Stores v2 — declaration helpers.
13
3
  *
@@ -27,4 +17,11 @@ export function validateStoreDefs(stores: Array<{
27
17
  * an empty array means the declarations are valid.
28
18
  */
29
19
  /** Store `name` must form a valid env-key suffix. */
30
- export const STORE_NAME_REGEX: RegExp;
20
+ export declare const STORE_NAME_REGEX: RegExp;
21
+ /**
22
+ * Validate an array of store declarations.
23
+ *
24
+ * @param {Array<{name?: string, description?: string}>} stores
25
+ * @returns {string[]} errors — empty when valid.
26
+ */
27
+ export declare function validateStoreDefs(stores: any): any[];
@@ -1,3 +1,16 @@
1
+ /**
2
+ * Strategy Registry
3
+ *
4
+ * Register agent strategies at startup; the framework selects and invokes them at runtime.
5
+ * No built-in strategies are bundled — register your own via registerStrategy().
6
+ *
7
+ * @example
8
+ * import { registerStrategy, invokeAgent } from '@zibby/workflow';
9
+ * import { MyClaudeStrategy } from './my-claude-strategy.js';
10
+ *
11
+ * registerStrategy(new MyClaudeStrategy());
12
+ * const result = await invokeAgent('Do the thing', { state: { agentType: 'claude' } }, {});
13
+ */
1
14
  /**
2
15
  * Register an agent strategy. Re-registering by name replaces the existing entry.
3
16
  *
@@ -9,9 +22,9 @@
9
22
  *
10
23
  * @param {AgentStrategy} strategy
11
24
  */
12
- export function registerStrategy(strategy: AgentStrategy): void;
25
+ export declare function registerStrategy(strategy: any): void;
13
26
  /** @returns {string[]} names of all registered strategies */
14
- export function listStrategies(): string[];
27
+ export declare function listStrategies(): any;
15
28
  /**
16
29
  * Resolve the best strategy for the given context.
17
30
  * Agent is selected by: context.preferredAgent > state.agentType > AGENT_TYPE env.
@@ -26,11 +39,8 @@ export function listStrategies(): string[];
26
39
  * chain resolving to null and the strategy silently substituting its vendor
27
40
  * default underneath us.
28
41
  */
29
- export function resolveInvocationModel({ config, options, strategyName, envModel }?: {
30
- config?: {};
31
- options?: {};
32
- }): any;
33
- export function getAgentStrategy(context?: {}): any;
42
+ export declare function resolveInvocationModel({ config, options, strategyName, envModel }?: any): any;
43
+ export declare function getAgentStrategy(context?: any): any;
34
44
  /**
35
45
  * Invoke an agent with automatic strategy selection.
36
46
  * @param {string} prompt
@@ -38,8 +48,4 @@ export function getAgentStrategy(context?: {}): any;
38
48
  * @param {object} [options]
39
49
  * @returns {Promise<string | { raw: string, structured: object }>}
40
50
  */
41
- export function invokeAgent(prompt: string, context?: object, options?: object): Promise<string | {
42
- raw: string;
43
- structured: object;
44
- }>;
45
- import { AgentStrategy } from './agents/base.js';
51
+ export declare function invokeAgent(prompt: any, context?: any, options?: any): Promise<any>;
@@ -1,17 +1,17 @@
1
- var v=()=>{},_={debug:v,info:v,warn:(...e)=>console.warn("[workflow]",...e),error:(...e)=>console.error("[workflow]",...e)},m={impl:_};var d={debug:(...e)=>m.impl.debug?.(...e),info:(...e)=>m.impl.info?.(...e),warn:(...e)=>m.impl.warn?.(...e),error:(...e)=>m.impl.error?.(...e)};var w=Symbol.for("@zibby/agent-workflow.skills"),b=Symbol.for("@zibby/agent-workflow.skills.sources");globalThis[w]||(globalThis[w]=new Map);globalThis[b]||(globalThis[b]=new Map);var x=globalThis[w],P=globalThis[b];function A(e){return x.get(e)||null}var y=Symbol.for("@zibby/agent-workflow.strategies");globalThis[y]||(globalThis[y]=[]);var a=globalThis[y];function D(e){if(!e||typeof e.getName!="function"||typeof e.invoke!="function")throw new Error("strategy must implement getName() and invoke() (AgentStrategy shape)");let t=a.findIndex(r=>r.getName()===e.getName());t>=0?a[t]=e:a.push(e)}function H(){return a.map(e=>e.getName())}function R({config:e={},options:t={},strategyName:r,envModel:o}={}){let s=e.models||{},i=t.nodeName&&s[t.nodeName]||null,l=s.default||null,u=e.agent?.[r]?.model||null,p=(typeof o=="string"?o.trim():"")||null;return i||l||u||t.model||p||null}function j(e={}){let{state:t={},preferredAgent:r=null}=e,o=r||t.agentType||process.env.AGENT_TYPE;if(!o){let i=a.map(l=>l.getName()).join(", ")||"none registered";throw new Error(`No agent specified. Set agentType in state or AGENT_TYPE env var. Available: ${i}`)}d.debug(`[workflow] agent selection: requested=${o}`);let s=a.find(i=>i.getName()===o);if(!s){let i=a.map(l=>l.getName()).join(", ")||"none registered";throw new Error(`Unknown agent '${o}'. Available: ${i}`)}if(!s.canHandle(e))throw new Error(`Agent '${o}' is not available in this environment. Check credentials/environment.`);return d.debug(`[workflow] using agent: ${s.getName()}`),s}async function K(e,t={},r={}){let o=t.state&&typeof t.state.getAll=="function"?t.state.getAll():t.state||{},s={...t,state:o},i=j(s),l=o.config||r.config||{},u=R({config:l,options:r,strategyName:i.name,envModel:process.env.MODEL}),p={...r,model:u,workspace:o.workspace||r.workspace,schema:r.schema||t.schema,images:r.images||t.images||[],skills:r.skills||t.skills||[],plugins:r.plugins||t.plugins||[],config:l},c=e,k=p.skills||[];if(k.length>0&&!r.skipPromptFragments){let f=k.map(h=>{let n=A(h)?.promptFragment;return typeof n=="function"?n():n}).filter(Boolean);f.length>0&&(c+=`
1
+ var T=()=>{},O={debug:T,info:T,warn:(...e)=>console.warn("[workflow]",...e),error:(...e)=>console.error("[workflow]",...e)},f={impl:O};var d={debug:(...e)=>f.impl.debug?.(...e),info:(...e)=>f.impl.info?.(...e),warn:(...e)=>f.impl.warn?.(...e),error:(...e)=>f.impl.error?.(...e)};var h=Symbol.for("@zibby/agent-workflow.skills"),w=Symbol.for("@zibby/agent-workflow.skills.sources");globalThis[h]||(globalThis[h]=new Map);globalThis[w]||(globalThis[w]=new Map);var _=globalThis[h],P=globalThis[w];function A(e){return _.get(e)||null}var b=Symbol.for("@zibby/agent-workflow.strategies");globalThis[b]||(globalThis[b]=[]);var l=globalThis[b];function D(e){if(!e||typeof e.getName!="function"||typeof e.invoke!="function")throw new Error("strategy must implement getName() and invoke() (AgentStrategy shape)");let t=l.findIndex(n=>n.getName()===e.getName());t>=0?l[t]=e:l.push(e)}function H(){return l.map(e=>e.getName())}function M({config:e={},options:t={},strategyName:n,envModel:o}={}){let s=e.models||{},i=t.nodeName&&s[t.nodeName]||null,a=s.default||null,u=e.agent?.[n]?.model||null,p=(typeof o=="string"?o.trim():"")||null;return i||a||u||t.model||p||null}function R(e={}){let{state:t={},preferredAgent:n=null}=e,o=n||t.agentType||process.env.AGENT_TYPE;if(!o){let i=l.map(a=>a.getName()).join(", ")||"none registered";throw new Error(`No agent specified. Set agentType in state or AGENT_TYPE env var. Available: ${i}`)}d.debug(`[workflow] agent selection: requested=${o}`);let s=l.find(i=>i.getName()===o);if(!s){let i=l.map(a=>a.getName()).join(", ")||"none registered";throw new Error(`Unknown agent '${o}'. Available: ${i}`)}if(!s.canHandle(e))throw new Error(`Agent '${o}' is not available in this environment. Check credentials/environment.`);return d.debug(`[workflow] using agent: ${s.getName()}`),s}async function K(e,t={},n={}){let o=t.state&&typeof t.state.getAll=="function"?t.state.getAll():t.state||{},s={...t,state:o},i=R(s),a=o.config||n.config||{},u=M({config:a,options:n,strategyName:i.name,envModel:process.env.MODEL}),p={...n,model:u,workspace:o.workspace||n.workspace,schema:n.schema||t.schema,images:n.images||t.images||[],skills:n.skills||t.skills||[],extraMcpServers:n.extraMcpServers||o.extraMcpServers||t.extraMcpServers||[],plugins:n.plugins||t.plugins||[],config:a},c=e,k=p.skills||[];if(k.length>0&&!n.skipPromptFragments){let m=k.map(y=>{let r=A(y)?.promptFragment;return typeof r=="function"?r():r}).filter(Boolean);m.length>0&&(c+=`
2
2
 
3
- ${f.join(`
3
+ ${m.join(`
4
4
 
5
- `)}`)}let g=o._currentNodeConfig?.stores;if(Array.isArray(g)&&g.length>0&&typeof g[0]=="object"){let f=g.length<=8,h=g.map(n=>{let S=n?.id??n?.storeId??"",$=(n?.name??"").toString().trim()||S,I=n?.type?` \xB7 ${n.type}`:"",O=(n?.description||"").toString().replace(/\s+/g," ").trim(),N=`- ${$} \xB7 ${O||"(no description)"}${I} (id: ${S})`;if(f&&n?.schema&&typeof n.schema=="object"){let T=n.schema.properties&&typeof n.schema.properties=="object"?Object.keys(n.schema.properties):Object.keys(n.schema);T.length&&(N+=`
6
- fields: ${T.join(", ")}`)}return N});c+=`
5
+ `)}`)}let g=o._currentNodeConfig?.stores;if(Array.isArray(g)&&g.length>0&&typeof g[0]=="object"){let m=g.length<=8,y=g.map(r=>{let E=r?.id??r?.storeId??"",$=(r?.name??"").toString().trim()||E,x=r?.type?` \xB7 ${r.type}`:"",I=(r?.description||"").toString().replace(/\s+/g," ").trim(),v=`- ${$} \xB7 ${I||"(no description)"}${x} (id: ${E})`;if(m&&r?.schema&&typeof r.schema=="object"){let N=r.schema.properties&&typeof r.schema.properties=="object"?Object.keys(r.schema.properties):Object.keys(r.schema);N.length&&(v+=`
6
+ fields: ${N.join(", ")}`)}return v});c+=`
7
7
 
8
8
  AVAILABLE STORES (pick a store by its description and pass its NAME to the store tool):
9
- ${h.join(`
10
- `)}`}let E=o._currentNodeConfig?.extraPromptInstructions?.trim();return E&&(c+=`
9
+ ${y.join(`
10
+ `)}`}let S=o._currentNodeConfig?.extraPromptInstructions?.trim();return S&&(c+=`
11
11
 
12
12
  \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
13
13
  PRIORITY OVERRIDE \u2014 THE FOLLOWING INSTRUCTIONS TAKE PRECEDENCE OVER ALL PREVIOUS CONTENT
14
14
  \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
15
15
 
16
- ${E}
17
- `),d.debug(`[workflow] prompt length: ${c.length} chars`),i.invoke(c,p)}export{j as getAgentStrategy,K as invokeAgent,H as listStrategies,D as registerStrategy,R as resolveInvocationModel};
16
+ ${S}
17
+ `),d.debug(`[workflow] prompt length: ${c.length} chars`),i.invoke(c,p)}export{R as getAgentStrategy,K as invokeAgent,H as listStrategies,D as registerStrategy,M as resolveInvocationModel};
@@ -1,3 +1,38 @@
1
+ /**
2
+ * Sub-graph executor — runs another workflow as a child from inside a
3
+ * running parent workflow.
4
+ *
5
+ * Triggered when a node config has `{ workflow: 'name-of-other-workflow' }`.
6
+ *
7
+ * Two dispatch paths:
8
+ *
9
+ * 1. **In-process** (preferred for sync, fast — added Phase 2). Loads
10
+ * the child's bundle into the same Node.js process as the parent
11
+ * and runs it via a fresh `child.run()` invocation. Saves the
12
+ * 3-10s Fargate cold start. Gated on:
13
+ * - `ZIBBY_INPROCESS_SUBGRAPH=1` env (set per task at default-on),
14
+ * - `options.async !== true` (async sub-graphs need a separate
15
+ * process to actually run in parallel),
16
+ * - The runtime can fetch the child's bundle and its runtimeTag
17
+ * matches the parent's. Mismatch → automatic fallback to (2).
18
+ *
19
+ * 2. **HTTP / ECS RunTask** (the original path). Parent POSTs to the
20
+ * public trigger endpoint, backend spawns a fresh Fargate task,
21
+ * parent polls until the child reaches a terminal status. Still
22
+ * the only option for async dispatches and the safety net for
23
+ * every in-process failure mode.
24
+ *
25
+ * Auth/URL plumbing comes from env vars already set on every Fargate
26
+ * task by workflow-executor.js:
27
+ * - PROGRESS_API_URL → "https://api-prod.zibby.app/executions"
28
+ * - PROJECT_API_TOKEN → bearer token scoped to this project
29
+ * - PROJECT_ID → the project this workflow runs under
30
+ * - EXECUTION_ID → parent's executionId (becomes child.parentExecutionId)
31
+ *
32
+ * Local dev: when these env vars are missing, dispatch throws a clear
33
+ * error. In-process is never attempted without PROJECT_API_TOKEN — we
34
+ * keep the "no cloud creds = no sub-graphs" invariant from v1.
35
+ */
1
36
  /**
2
37
  * Dispatch `workflowName` as a child of the currently-running execution.
3
38
  *
@@ -33,11 +68,4 @@
33
68
  * - Sub-graph reached a non-success terminal status (failed/canceled/timeout)
34
69
  * - Sync timeout exceeded
35
70
  */
36
- export function dispatchSubgraph(workflowName: string, options?: {
37
- input?: object;
38
- async?: boolean;
39
- conversationId?: string;
40
- timeoutMs?: number;
41
- pollIntervalMs?: number;
42
- output?: string | ((finalState: object) => any);
43
- }): Promise<any>;
71
+ export declare function dispatchSubgraph(workflowName: any, options?: any): Promise<any>;
@@ -1 +1 @@
1
- var D=()=>{},Z={debug:D,info:D,warn:(...e)=>console.warn("[workflow]",...e),error:(...e)=>console.error("[workflow]",...e)},R={impl:Z};var h={debug:(...e)=>R.impl.debug?.(...e),info:(...e)=>R.impl.info?.(...e),warn:(...e)=>R.impl.warn?.(...e),error:(...e)=>R.impl.error?.(...e)};import{mkdirSync as W,existsSync as x,statSync as N,readdirSync as X,rmSync as ee}from"node:fs";import{spawn as z}from"node:child_process";import{join as v}from"node:path";import{pathToFileURL as te}from"node:url";import{AsyncLocalStorage as re}from"node:async_hooks";import{AsyncLocalStorage as K}from"node:async_hooks";var U=new K;function A(){let e=U.getStore();return e||Object.freeze({executionId:process.env.EXECUTION_ID||null,parentExecutionId:process.env.PARENT_EXECUTION_ID||null,depth:0,conversationId:process.env.ZIBBY_CONVERSATION_ID||null,dispatchMode:process.env.DISPATCH_MODE||null})}function j(e,t){let n=U.getStore()||A(),r=Object.freeze({executionId:e.executionId,parentExecutionId:e.parentExecutionId??n.executionId??null,depth:(n.depth||0)+(e.executionId!==n.executionId?1:0),conversationId:e.conversationId!==void 0?e.conversationId:n.conversationId??null,dispatchMode:e.dispatchMode??null});return U.run(r,t)}var k=new Map,M=new Map,L=new Map;function H(e,t,n={}){if(!e||typeof e!="string")throw new Error("subgraph-registry.register: name required");if(typeof t!="function")throw new Error("subgraph-registry.register: factory must be a function");k.set(e,t),M.set(e,"ready"),L.set(e,{...n,cachedAt:Date.now()})}function G(e,t){M.set(e,"failed"),L.set(e,{error:t?.message||String(t),failedAt:Date.now()}),k.delete(e)}function J(e){return M.get(e)==="ready"?k.get(e):null}var P=process.env.ZIBBY_SUBGRAPH_CACHE_DIR||"/tmp/zibby/subgraphs";function ne(){return`node${(process.versions?.node||"").split(".")[0]||"unknown"}-${process.platform}-${process.arch}`}var g=class extends Error{constructor(t,n){super(`in-process sub-graph fallback: ${t}${n?` (${n})`:""}`),this.fallback=!0,this.reason=t,this.detail=n||null,this.name="SubgraphFallback"}},F=new re,q=Promise.resolve();async function oe(e,t){let n=e&&typeof e=="object"&&!Array.isArray(e)?Object.entries(e).filter(([s,i])=>typeof s=="string"&&s&&typeof i=="string"):[];if(n.length===0)return t();let r=F.getStore()===!0,a=null;if(!r){let s=q;q=new Promise(i=>{a=i}),await s}let o=new Map;try{for(let[s,i]of n)o.set(s,Object.prototype.hasOwnProperty.call(process.env,s)?process.env[s]:void 0),process.env[s]=i;return h.debug(`[in-process subgraph] scoped ${n.length} child env var(s)${r?" (nested)":""}`),await F.run(!0,t)}finally{for(let[s,i]of o)i===void 0?delete process.env[s]:process.env[s]=i;a&&a()}}function se(){let e=(process.env.SUBGRAPH_INTERNAL_URL||"").replace(/\/$/,""),t=(process.env.PROGRESS_API_URL||"").replace(/\/executions\/?$/,""),n=e||t,r=process.env.PROJECT_ID,a=process.env.PROJECT_API_TOKEN;if(!n||!r||!a)throw new g("env","SUBGRAPH_INTERNAL_URL/PROGRESS_API_URL/PROJECT_ID/PROJECT_API_TOKEN missing");return{apiBase:n,projectId:r,authToken:a}}async function ae({apiBase:e,authToken:t,body:n}){let r;try{r=await fetch(`${e}/internal/subgraph/begin`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${t}`},body:JSON.stringify(n)})}catch(o){throw new g("network",`begin fetch failed: ${o.message}`)}let a=null;try{a=await r.json()}catch{}if(!r.ok){if(r.status===404){let o=new Error(`Sub-graph child '${n.childWorkflowType}' not found in project`);throw o.code="SUBGRAPH_NOT_FOUND",o.status=404,o}if(r.status===429){let o=a?.quotaInfo||{},s=new Error(`Sub-graph blocked by quota (${o.used??"?"}/${o.limit??"?"} on ${o.planId||"plan"})`);throw s.code="SUBGRAPH_QUOTA_EXCEEDED",s.status=429,s.quotaInfo=o,s}if(r.status===400&&a?.validationErrors){let o=new Error(`Sub-graph rejected input: ${a?.error||a?.message||"validation failed"}`);throw o.code="SUBGRAPH_INVALID_INPUT",o.status=400,o.validationErrors=a.validationErrors,o.missing=a.missing,o}throw new g("begin-status",`begin returned ${r.status}`)}return a?.data||a}async function _({apiBase:e,authToken:t,payload:n}){try{let r=await fetch(`${e}/internal/subgraph/finalize`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${t}`},body:JSON.stringify(n)});r.ok||h.warn(`[in-process subgraph] finalize returned ${r.status} for ${n.childExecutionId}`)}catch(r){h.warn(`[in-process subgraph] finalize failed: ${r.message}`)}}async function ie(e,t){let n=v(t,".ready"),r=v(t,"graph.mjs");if(x(n)&&x(r))return;W(t,{recursive:!0});let a=v(t,".lock"),o=!1;try{let{openSync:s,closeSync:i}=await import("node:fs"),y=s(a,"wx");i(y),o=!0}catch(s){if(s.code!=="EEXIST")throw s}if(!o){let s=Date.now()+3e4;for(;Date.now()<s;){if(x(n)&&x(r))return;await new Promise(i=>setTimeout(i,100))}throw new g("bundle-extract-timeout","sibling extract did not complete within 30s")}try{await new Promise((y,b)=>{let l=z("curl",["-fsSL",e],{stdio:["ignore","pipe","inherit"]}),S=z("tar",["-xzf","-","-C",t],{stdio:["pipe","inherit","inherit"]});l.stdout.pipe(S.stdin);let p,E,w=()=>{if(p!==void 0&&E!==void 0){if(p!==0)return b(new Error(`curl exited ${p}`));if(E!==0)return b(new Error(`tar exited ${E}`));y()}};l.on("close",$=>{p=$,w()}),S.on("close",$=>{E=$,w()}),l.on("error",b),S.on("error",b)});let{writeFileSync:s,unlinkSync:i}=await import("node:fs");s(n,"");try{i(a)}catch{}}catch(s){try{let{unlinkSync:i}=await import("node:fs");i(a)}catch{}throw new g("bundle-extract-failed",s.message)}}async function ce(e){let t=v(e,"graph.mjs");if(!x(t))throw new g("entry-missing",`graph.mjs missing under ${e}`);let n;try{n=await import(te(t).href)}catch(a){throw new g("import-failed",`${a?.code||a?.name||"unknown"}: ${a.message}`)}let r=n.default||Object.values(n).find(a=>typeof a=="function"&&a.prototype?.buildGraph);if(!r)throw new g("entry-class-missing","no buildGraph() class export found");return r}async function Y(e,t={}){if(!e||typeof e!="string")throw new Error("runInProcessSubgraph: workflowName (string) is required");let n=A(),r;try{r=se()}catch(c){throw c}h.debug(`[in-process subgraph] begin '${e}' parent=${n.executionId||"<root>"}`);let a=await ae({apiBase:r.apiBase,authToken:r.authToken,body:{parentExecutionId:n.executionId,childWorkflowType:e,input:t.input||{},...t.conversationId?{conversationId:t.conversationId}:{}}}),{childExecutionId:o,runtimeTag:s,bundlePresignedUrl:i,sourcesPresignedUrl:y,workflowVersion:b,workflowUuid:l,bundleReady:S,nodeConfigs:p}=a,E=ne();if(s&&s!==E)throw await _({apiBase:r.apiBase,authToken:r.authToken,payload:{childExecutionId:o,status:"canceled",error:{message:`runtimeTag mismatch: parent=${E} child=${s}`,code:"RUNTIME_MISMATCH"}}}),new g("runtime-mismatch",`${E} vs ${s}`);if(!S||!i)throw await _({apiBase:r.apiBase,authToken:r.authToken,payload:{childExecutionId:o,status:"canceled",error:{message:"bundle not ready for in-process; falling back to HTTP",code:"NO_BUNDLE"}}}),new g("no-bundle","workflow bundle not built yet");let w=J(e);if(!w){let c=v(P,`${l}@${b||"0"}`);try{await ie(i,c);try{de()}catch{}}catch(d){throw d.fallback&&await _({apiBase:r.apiBase,authToken:r.authToken,payload:{childExecutionId:o,status:"failed",error:{message:d.message,code:d.reason}}}),d}try{w=await ce(c),H(e,w,{workflowUuid:l,version:b,runtimeTag:s,cacheDir:c})}catch(d){throw G(e,d),await _({apiBase:r.apiBase,authToken:r.authToken,payload:{childExecutionId:o,status:"failed",error:{message:d.message,code:d.reason||"IMPORT_FAILED"}}}),d.fallback?d:new g("import-failed",d.message)}}let $=Date.now(),C=a.env&&typeof a.env=="object"&&!Array.isArray(a.env)?a.env:null,m=p&&typeof p=="object"&&!Array.isArray(p)&&Object.keys(p).length>0,B={...t.input||{},...m?{nodeConfigs:p}:{}},I,u;try{I=await oe(C,async()=>{let d=await(typeof w=="function"&&w.prototype?.buildGraph?new w:w).buildGraph();return j({executionId:o,parentExecutionId:n.executionId,conversationId:t.conversationId!==void 0?t.conversationId:n.conversationId,dispatchMode:"inprocess"},()=>d.run(t.parentAgent,B,{signal:t.signal}))}),u=I&&typeof I=="object"&&"state"in I?I.state:I}catch(c){throw await _({apiBase:r.apiBase,authToken:r.authToken,payload:{childExecutionId:o,status:"failed",error:{message:c.message,code:c.code||"CHILD_THREW",stack:c.stack},durationMs:Date.now()-$}}),c}if(I&&typeof I=="object"&&I.stoppedExternally){await _({apiBase:r.apiBase,authToken:r.authToken,payload:{childExecutionId:o,status:"canceled",finalState:u,durationMs:Date.now()-$}});let c=new Error(`Sub-graph '${e}' canceled by parent abort`);throw c.code="SUBGRAPH_CANCELED",c.subgraphJobId=o,c}return await _({apiBase:r.apiBase,authToken:r.authToken,payload:{childExecutionId:o,status:"completed",finalState:u,durationMs:Date.now()-$}}),{finalState:u,executionId:o}}function ue(e){let t=0,n=[e];for(;n.length;){let r=n.pop(),a;try{a=N(r)}catch{continue}if(a.isDirectory()){let o;try{o=X(r)}catch{continue}for(let s of o)n.push(v(r,s))}else t+=a.size}return t}function de({cap:e=Number(process.env.ZIBBY_SUBGRAPH_CACHE_CAP_BYTES||2*1024*1024*1024)}={}){try{if(!x(P))return{evicted:0,freedBytes:0};let t=X(P),n=[],r=0;for(let i of t){let y=v(P,i),b;try{b=N(y)}catch{continue}let l=b.isDirectory()?ue(y):b.size;r+=l,n.push({name:i,full:y,size:l,mtimeMs:b.mtimeMs})}if(r<=e)return{evicted:0,freedBytes:0,totalBytes:r};n.sort((i,y)=>i.mtimeMs-y.mtimeMs);let a=Math.floor(e*.7),o=0,s=0;for(let i of n){if(r-o<=a)break;if(!x(v(i.full,".lock")))try{ee(i.full,{recursive:!0,force:!0}),o+=i.size,s+=1}catch(y){h.debug(`[sub-graph cache] evict skip ${i.name}: ${y.message}`)}}return s>0&&h.info(`[sub-graph cache] evicted ${s} entr(y/ies), freed ${(o/1024/1024).toFixed(1)}MB`),{evicted:s,freedBytes:o,totalBytes:r-o}}catch(t){return h.debug(`[sub-graph cache] evict failed: ${t.message}`),{evicted:0,freedBytes:0}}}var pe=2e3,le=600*1e3,he=new Set(["completed","failed","canceled","timeout"]);function fe(){let e=process.env.PROGRESS_API_URL;if(!e)throw new Error("Sub-graph dispatch requires PROGRESS_API_URL env var (set automatically on cloud runs). Sub-graphs are not supported in local in-process runs yet \u2014 deploy the parent and child to cloud.");return e.replace(/\/executions\/?$/,"")}function ge(){let e=process.env.PROJECT_ID;if(!e)throw new Error("Sub-graph dispatch requires PROJECT_ID env var.");return e}function ye(){let e=process.env.PROJECT_API_TOKEN;if(!e)throw new Error("Sub-graph dispatch requires PROJECT_API_TOKEN env var.");return e}function be(){return process.env.EXECUTION_ID||null}function V(e,t){return t==null?e:typeof t=="function"?t(e):typeof t=="string"?t.split(".").reduce((n,r)=>n==null?n:n[r],e):e}async function Ce(e,t={}){if(!e||typeof e!="string")throw new Error("dispatchSubgraph: workflowName (string) is required");let n=A(),r=Number(process.env.ZIBBY_SUBGRAPH_MAX_DEPTH||10);if((n.depth||0)>=r)throw new Error(`dispatchSubgraph('${e}'): sub-graph depth ${n.depth} reached cap of ${r}. Restructure the graph or raise ZIBBY_SUBGRAPH_MAX_DEPTH.`);if(process.env.ZIBBY_INPROCESS_SUBGRAPH!=="0"&&!t.async)try{h.debug(`[sub-graph] trying in-process for '${e}'`);let{finalState:u}=await Y(e,{input:t.input,conversationId:t.conversationId,signal:t.signal,parentAgent:t.parentAgent}),c=V(u,t.output);return h.info(`[sub-graph] '${e}' completed in-process`),c}catch(u){if(u instanceof g||u?.fallback)h.info(`[sub-graph] in-process fallback for '${e}': ${u.reason||"unknown"} \u2014 using HTTP`);else throw u}let a=fe(),o=ge(),s=ye(),i=be(),y=`${a}/projects/${encodeURIComponent(o)}/workflows/${encodeURIComponent(e)}/trigger`,b={input:t.input||{},...i?{parentExecutionId:i}:{},...t.conversationId?{conversationId:t.conversationId}:{}};h.info(`[sub-graph] dispatching '${e}' (${t.async?"async":"sync"}) from parent ${i||"<none>"}`);let l=await fetch(y,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${s}`},body:JSON.stringify(b)});if(!l.ok){let u=null,c="";try{u=await l.json(),c=u?.error||u?.message||JSON.stringify(u)}catch{c=await l.text().catch(()=>"")}if(l.status===429){let f=u?.quotaInfo||{},T=new Error(`Sub-graph '${e}' blocked by execution quota (${f.used??"?"}/${f.limit??"?"} on plan ${f.planId||"unknown"}). Sub-workflow runs count toward the same monthly cap as user-triggered runs.`);throw T.code="SUBGRAPH_QUOTA_EXCEEDED",T.status=429,T.subgraph=e,T.quotaInfo=f,T}if(l.status===400){let f=new Error(`Sub-graph '${e}' rejected input: ${c}`);throw f.code="SUBGRAPH_INVALID_INPUT",f.status=400,f.subgraph=e,f.validationErrors=u?.validationErrors||null,f.missing=u?.missing||null,f}let d=new Error(`Sub-graph '${e}' trigger rejected (${l.status}): ${c}`);throw d.code="SUBGRAPH_TRIGGER_FAILED",d.status=l.status,d.subgraph=e,d}let S=await l.json(),p=S?.data?.jobId||S?.jobId;if(!p)throw new Error(`Sub-graph '${e}' trigger returned no jobId: ${JSON.stringify(S).slice(0,200)}`);if(t.async)return h.info(`[sub-graph] async dispatch of '${e}' \u2192 jobId=${p} (not waiting)`),{jobId:p,status:"accepted",workflow:e};let E=Number.isFinite(t.timeoutMs)?t.timeoutMs:le,w=Number.isFinite(t.pollIntervalMs)?t.pollIntervalMs:pe,$=`${a}/executions/${encodeURIComponent(p)}`,C=Date.now()+E,m="accepted",B=0;for(;Date.now()<C;){await new Promise(f=>setTimeout(f,w)),B+=1;let u=await fetch($,{headers:{Authorization:`Bearer ${s}`}});if(!u.ok){if(u.status>=500){h.warn(`[sub-graph] status poll for ${p} returned ${u.status}, will retry`);continue}throw new Error(`Sub-graph status poll failed for ${p}: ${u.status}`)}let c=await u.json(),d=c?.data||c?.execution||c;if(m=d?.status||m,he.has(m)){if(m!=="completed"){let O=new Error(`Sub-graph '${e}' (${p}) ended in status '${m}'`);throw O.subgraphJobId=p,O.subgraphStatus=m,O}let f=d?.finalState||d?.state||{},T=V(f,t.output);return h.info(`[sub-graph] '${e}' (${p}) completed after ${B} polls`),T}}let I=new Error(`Sub-graph '${e}' (${p}) timed out after ${Math.round(E/1e3)}s (last status: ${m})`);throw I.subgraphJobId=p,I.subgraphStatus=m,I}export{Ce as dispatchSubgraph};
1
+ var D=()=>{},Z={debug:D,info:D,warn:(...e)=>console.warn("[workflow]",...e),error:(...e)=>console.error("[workflow]",...e)},R={impl:Z};var h={debug:(...e)=>R.impl.debug?.(...e),info:(...e)=>R.impl.info?.(...e),warn:(...e)=>R.impl.warn?.(...e),error:(...e)=>R.impl.error?.(...e)};import{mkdirSync as W,existsSync as x,statSync as N,readdirSync as X,rmSync as ee}from"node:fs";import{spawn as z}from"node:child_process";import{join as v}from"node:path";import{pathToFileURL as te}from"node:url";import{AsyncLocalStorage as ne}from"node:async_hooks";import{AsyncLocalStorage as K}from"node:async_hooks";var k=new K;function A(){let e=k.getStore();return e||Object.freeze({executionId:process.env.EXECUTION_ID||null,parentExecutionId:process.env.PARENT_EXECUTION_ID||null,depth:0,conversationId:process.env.ZIBBY_CONVERSATION_ID||null,dispatchMode:process.env.DISPATCH_MODE||null})}function j(e,t){let r=k.getStore()||A(),n=Object.freeze({executionId:e.executionId,parentExecutionId:e.parentExecutionId??r.executionId??null,depth:(r.depth||0)+(e.executionId!==r.executionId?1:0),conversationId:e.conversationId!==void 0?e.conversationId:r.conversationId??null,dispatchMode:e.dispatchMode??null});return k.run(n,t)}var U=new Map,M=new Map,L=new Map;function H(e,t,r={}){if(!e||typeof e!="string")throw new Error("subgraph-registry.register: name required");if(typeof t!="function")throw new Error("subgraph-registry.register: factory must be a function");U.set(e,t),M.set(e,"ready"),L.set(e,{...r,cachedAt:Date.now()})}function G(e,t){M.set(e,"failed"),L.set(e,{error:t?.message||String(t),failedAt:Date.now()}),U.delete(e)}function J(e){return M.get(e)==="ready"?U.get(e):null}var P=process.env.ZIBBY_SUBGRAPH_CACHE_DIR||"/tmp/zibby/subgraphs";function re(){return`node${(process.versions?.node||"").split(".")[0]||"unknown"}-${process.platform}-${process.arch}`}var g=class extends Error{constructor(t,r){super(`in-process sub-graph fallback: ${t}${r?` (${r})`:""}`),this.fallback=!0,this.reason=t,this.detail=r||null,this.name="SubgraphFallback"}},F=new ne,q=Promise.resolve();async function oe(e,t){let r=e&&typeof e=="object"&&!Array.isArray(e)?Object.entries(e).filter(([s,i])=>typeof s=="string"&&s&&typeof i=="string"):[];if(r.length===0)return t();let n=F.getStore()===!0,a=null;if(!n){let s=q;q=new Promise(i=>{a=i}),await s}let o=new Map;try{for(let[s,i]of r)o.set(s,Object.prototype.hasOwnProperty.call(process.env,s)?process.env[s]:void 0),process.env[s]=i;return h.debug(`[in-process subgraph] scoped ${r.length} child env var(s)${n?" (nested)":""}`),await F.run(!0,t)}finally{for(let[s,i]of o)i===void 0?delete process.env[s]:process.env[s]=i;a&&a()}}function se(){let e=(process.env.SUBGRAPH_INTERNAL_URL||"").replace(/\/$/,""),t=(process.env.PROGRESS_API_URL||"").replace(/\/executions\/?$/,""),r=e||t,n=process.env.PROJECT_ID,a=process.env.PROJECT_API_TOKEN;if(!r||!n||!a)throw new g("env","SUBGRAPH_INTERNAL_URL/PROGRESS_API_URL/PROJECT_ID/PROJECT_API_TOKEN missing");return{apiBase:r,projectId:n,authToken:a}}async function ae({apiBase:e,authToken:t,body:r}){let n;try{n=await fetch(`${e}/internal/subgraph/begin`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${t}`},body:JSON.stringify(r)})}catch(o){throw new g("network",`begin fetch failed: ${o.message}`)}let a=null;try{a=await n.json()}catch{}if(!n.ok){if(n.status===404){let o=new Error(`Sub-graph child '${r.childWorkflowType}' not found in project`);throw o.code="SUBGRAPH_NOT_FOUND",o.status=404,o}if(n.status===429){let o=a?.quotaInfo||{},s=new Error(`Sub-graph blocked by quota (${o.used??"?"}/${o.limit??"?"} on ${o.planId||"plan"})`);throw s.code="SUBGRAPH_QUOTA_EXCEEDED",s.status=429,s.quotaInfo=o,s}if(n.status===400&&a?.validationErrors){let o=new Error(`Sub-graph rejected input: ${a?.error||a?.message||"validation failed"}`);throw o.code="SUBGRAPH_INVALID_INPUT",o.status=400,o.validationErrors=a.validationErrors,o.missing=a.missing,o}throw new g("begin-status",`begin returned ${n.status}`)}return a?.data||a}async function _({apiBase:e,authToken:t,payload:r}){try{let n=await fetch(`${e}/internal/subgraph/finalize`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${t}`},body:JSON.stringify(r)});n.ok||h.warn(`[in-process subgraph] finalize returned ${n.status} for ${r.childExecutionId}`)}catch(n){h.warn(`[in-process subgraph] finalize failed: ${n.message}`)}}async function ie(e,t){let r=v(t,".ready"),n=v(t,"graph.mjs");if(x(r)&&x(n))return;W(t,{recursive:!0});let a=v(t,".lock"),o=!1;try{let{openSync:s,closeSync:i}=await import("node:fs"),y=s(a,"wx");i(y),o=!0}catch(s){if(s.code!=="EEXIST")throw s}if(!o){let s=Date.now()+3e4;for(;Date.now()<s;){if(x(r)&&x(n))return;await new Promise(i=>setTimeout(i,100))}throw new g("bundle-extract-timeout","sibling extract did not complete within 30s")}try{await new Promise((y,b)=>{let l=z("curl",["-fsSL",e],{stdio:["ignore","pipe","inherit"]}),S=z("tar",["-xzf","-","-C",t],{stdio:["pipe","inherit","inherit"]});l.stdout.pipe(S.stdin);let p,E,w=()=>{if(p!==void 0&&E!==void 0){if(p!==0)return b(new Error(`curl exited ${p}`));if(E!==0)return b(new Error(`tar exited ${E}`));y()}};l.on("close",$=>{p=$,w()}),S.on("close",$=>{E=$,w()}),l.on("error",b),S.on("error",b)});let{writeFileSync:s,unlinkSync:i}=await import("node:fs");s(r,"");try{i(a)}catch{}}catch(s){try{let{unlinkSync:i}=await import("node:fs");i(a)}catch{}throw new g("bundle-extract-failed",s.message)}}async function ce(e){let t=v(e,"graph.mjs");if(!x(t))throw new g("entry-missing",`graph.mjs missing under ${e}`);let r;try{r=await import(te(t).href)}catch(a){throw new g("import-failed",`${a?.code||a?.name||"unknown"}: ${a.message}`)}let n=r.default||Object.values(r).find(a=>typeof a=="function"&&a.prototype?.buildGraph);if(!n)throw new g("entry-class-missing","no buildGraph() class export found");return n}async function Y(e,t={}){if(!e||typeof e!="string")throw new Error("runInProcessSubgraph: workflowName (string) is required");let r=A(),n;try{n=se()}catch(c){throw c}h.debug(`[in-process subgraph] begin '${e}' parent=${r.executionId||"<root>"}`);let a=await ae({apiBase:n.apiBase,authToken:n.authToken,body:{parentExecutionId:r.executionId,childWorkflowType:e,input:t.input||{},...t.conversationId?{conversationId:t.conversationId}:{}}}),{childExecutionId:o,runtimeTag:s,bundlePresignedUrl:i,sourcesPresignedUrl:y,workflowVersion:b,workflowUuid:l,bundleReady:S,nodeConfigs:p}=a,E=re();if(s&&s!==E)throw await _({apiBase:n.apiBase,authToken:n.authToken,payload:{childExecutionId:o,status:"canceled",error:{message:`runtimeTag mismatch: parent=${E} child=${s}`,code:"RUNTIME_MISMATCH"}}}),new g("runtime-mismatch",`${E} vs ${s}`);if(!S||!i)throw await _({apiBase:n.apiBase,authToken:n.authToken,payload:{childExecutionId:o,status:"canceled",error:{message:"bundle not ready for in-process; falling back to HTTP",code:"NO_BUNDLE"}}}),new g("no-bundle","workflow bundle not built yet");let w=J(e);if(!w){let c=v(P,`${l}@${b||"0"}`);try{await ie(i,c);try{de()}catch{}}catch(d){throw d.fallback&&await _({apiBase:n.apiBase,authToken:n.authToken,payload:{childExecutionId:o,status:"failed",error:{message:d.message,code:d.reason}}}),d}try{w=await ce(c),H(e,w,{workflowUuid:l,version:b,runtimeTag:s,cacheDir:c})}catch(d){throw G(e,d),await _({apiBase:n.apiBase,authToken:n.authToken,payload:{childExecutionId:o,status:"failed",error:{message:d.message,code:d.reason||"IMPORT_FAILED"}}}),d.fallback?d:new g("import-failed",d.message)}}let $=Date.now(),C=a.env&&typeof a.env=="object"&&!Array.isArray(a.env)?a.env:null,m=p&&typeof p=="object"&&!Array.isArray(p)&&Object.keys(p).length>0,B={...t.input||{},...m?{nodeConfigs:p}:{}},I,u;try{I=await oe(C,async()=>{let d=await(typeof w=="function"&&w.prototype?.buildGraph?new w:w).buildGraph();return j({executionId:o,parentExecutionId:r.executionId,conversationId:t.conversationId!==void 0?t.conversationId:r.conversationId,dispatchMode:"inprocess"},()=>d.run(t.parentAgent,B,{signal:t.signal}))}),u=I&&typeof I=="object"&&"state"in I?I.state:I}catch(c){throw await _({apiBase:n.apiBase,authToken:n.authToken,payload:{childExecutionId:o,status:"failed",error:{message:c.message,code:c.code||"CHILD_THREW",stack:c.stack},durationMs:Date.now()-$}}),c}if(I&&typeof I=="object"&&I.stoppedExternally){await _({apiBase:n.apiBase,authToken:n.authToken,payload:{childExecutionId:o,status:"canceled",finalState:u,durationMs:Date.now()-$}});let c=new Error(`Sub-graph '${e}' canceled by parent abort`);throw c.code="SUBGRAPH_CANCELED",c.subgraphJobId=o,c}return await _({apiBase:n.apiBase,authToken:n.authToken,payload:{childExecutionId:o,status:"completed",finalState:u,durationMs:Date.now()-$}}),{finalState:u,executionId:o}}function ue(e){let t=0,r=[e];for(;r.length;){let n=r.pop(),a;try{a=N(n)}catch{continue}if(a.isDirectory()){let o;try{o=X(n)}catch{continue}for(let s of o)r.push(v(n,s))}else t+=a.size}return t}function de({cap:e=Number(process.env.ZIBBY_SUBGRAPH_CACHE_CAP_BYTES||2*1024*1024*1024)}={}){try{if(!x(P))return{evicted:0,freedBytes:0};let t=X(P),r=[],n=0;for(let i of t){let y=v(P,i),b;try{b=N(y)}catch{continue}let l=b.isDirectory()?ue(y):b.size;n+=l,r.push({name:i,full:y,size:l,mtimeMs:b.mtimeMs})}if(n<=e)return{evicted:0,freedBytes:0,totalBytes:n};r.sort((i,y)=>i.mtimeMs-y.mtimeMs);let a=Math.floor(e*.7),o=0,s=0;for(let i of r){if(n-o<=a)break;if(!x(v(i.full,".lock")))try{ee(i.full,{recursive:!0,force:!0}),o+=i.size,s+=1}catch(y){h.debug(`[sub-graph cache] evict skip ${i.name}: ${y.message}`)}}return s>0&&h.info(`[sub-graph cache] evicted ${s} entr(y/ies), freed ${(o/1024/1024).toFixed(1)}MB`),{evicted:s,freedBytes:o,totalBytes:n-o}}catch(t){return h.debug(`[sub-graph cache] evict failed: ${t.message}`),{evicted:0,freedBytes:0}}}var pe=2e3,le=600*1e3,he=new Set(["completed","failed","canceled","timeout"]);function fe(){let e=process.env.PROGRESS_API_URL;if(!e)throw new Error("Sub-graph dispatch requires PROGRESS_API_URL env var (set automatically on cloud runs). Sub-graphs are not supported in local in-process runs yet \u2014 deploy the parent and child to cloud.");return e.replace(/\/executions\/?$/,"")}function ge(){let e=process.env.PROJECT_ID;if(!e)throw new Error("Sub-graph dispatch requires PROJECT_ID env var.");return e}function ye(){let e=process.env.PROJECT_API_TOKEN;if(!e)throw new Error("Sub-graph dispatch requires PROJECT_API_TOKEN env var.");return e}function be(){return process.env.EXECUTION_ID||null}function V(e,t){return t==null?e:typeof t=="function"?t(e):typeof t=="string"?t.split(".").reduce((r,n)=>r==null?r:r[n],e):e}async function Ce(e,t={}){if(!e||typeof e!="string")throw new Error("dispatchSubgraph: workflowName (string) is required");let r=A(),n=Number(process.env.ZIBBY_SUBGRAPH_MAX_DEPTH||10);if((r.depth||0)>=n)throw new Error(`dispatchSubgraph('${e}'): sub-graph depth ${r.depth} reached cap of ${n}. Restructure the graph or raise ZIBBY_SUBGRAPH_MAX_DEPTH.`);if(process.env.ZIBBY_INPROCESS_SUBGRAPH!=="0"&&!t.async)try{h.debug(`[sub-graph] trying in-process for '${e}'`);let{finalState:u}=await Y(e,{input:t.input,conversationId:t.conversationId,signal:t.signal,parentAgent:t.parentAgent}),c=V(u,t.output);return h.info(`[sub-graph] '${e}' completed in-process`),c}catch(u){if(u instanceof g||u?.fallback)h.info(`[sub-graph] in-process fallback for '${e}': ${u.reason||"unknown"} \u2014 using HTTP`);else throw u}let a=fe(),o=ge(),s=ye(),i=be(),y=`${a}/projects/${encodeURIComponent(o)}/workflows/${encodeURIComponent(e)}/trigger`,b={input:t.input||{},...i?{parentExecutionId:i}:{},...t.conversationId?{conversationId:t.conversationId}:{}};h.info(`[sub-graph] dispatching '${e}' (${t.async?"async":"sync"}) from parent ${i||"<none>"}`);let l=await fetch(y,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${s}`},body:JSON.stringify(b)});if(!l.ok){let u=null,c="";try{u=await l.json(),c=u?.error||u?.message||JSON.stringify(u)}catch{c=await l.text().catch(()=>"")}if(l.status===429){let f=u?.quotaInfo||{},T=new Error(`Sub-graph '${e}' blocked by execution quota (${f.used??"?"}/${f.limit??"?"} on plan ${f.planId||"unknown"}). Sub-workflow runs count toward the same monthly cap as user-triggered runs.`);throw T.code="SUBGRAPH_QUOTA_EXCEEDED",T.status=429,T.subgraph=e,T.quotaInfo=f,T}if(l.status===400){let f=new Error(`Sub-graph '${e}' rejected input: ${c}`);throw f.code="SUBGRAPH_INVALID_INPUT",f.status=400,f.subgraph=e,f.validationErrors=u?.validationErrors||null,f.missing=u?.missing||null,f}let d=new Error(`Sub-graph '${e}' trigger rejected (${l.status}): ${c}`);throw d.code="SUBGRAPH_TRIGGER_FAILED",d.status=l.status,d.subgraph=e,d}let S=await l.json(),p=S?.data?.jobId||S?.jobId;if(!p)throw new Error(`Sub-graph '${e}' trigger returned no jobId: ${JSON.stringify(S).slice(0,200)}`);if(t.async)return h.info(`[sub-graph] async dispatch of '${e}' \u2192 jobId=${p} (not waiting)`),{jobId:p,status:"accepted",workflow:e};let E=Number.isFinite(t.timeoutMs)?t.timeoutMs:le,w=Number.isFinite(t.pollIntervalMs)?t.pollIntervalMs:pe,$=`${a}/executions/${encodeURIComponent(p)}`,C=Date.now()+E,m="accepted",B=0;for(;Date.now()<C;){await new Promise(f=>setTimeout(f,w)),B+=1;let u=await fetch($,{headers:{Authorization:`Bearer ${s}`}});if(!u.ok){if(u.status>=500){h.warn(`[sub-graph] status poll for ${p} returned ${u.status}, will retry`);continue}throw new Error(`Sub-graph status poll failed for ${p}: ${u.status}`)}let c=await u.json(),d=c?.data||c?.execution||c;if(m=d?.status||m,he.has(m)){if(m!=="completed"){let O=new Error(`Sub-graph '${e}' (${p}) ended in status '${m}'`);throw O.subgraphJobId=p,O.subgraphStatus=m,O}let f=d?.finalState||d?.state||{},T=V(f,t.output);return h.info(`[sub-graph] '${e}' (${p}) completed after ${B} polls`),T}}let I=new Error(`Sub-graph '${e}' (${p}) timed out after ${Math.round(E/1e3)}s (last status: ${m})`);throw I.subgraphJobId=p,I.subgraphStatus=m,I}export{Ce as dispatchSubgraph};
@@ -1,3 +1,31 @@
1
+ /**
2
+ * Process-local registry of sub-graph factories that the current
3
+ * Fargate task can run **in-process**.
4
+ *
5
+ * Populated two ways:
6
+ *
7
+ * 1. **Eager (Phase 1+)**: at container start, if the parent workflow
8
+ * declares `subgraphRefs: ['child-a', 'child-b']` on its workflow
9
+ * row (computed by the backend's static analyzer), the CLI's
10
+ * `run-workflow` entrypoint kicks off a background fetch that
11
+ * `register()`s each child as soon as its sources land on tmpfs.
12
+ * Non-blocking — the parent's first node can run while children
13
+ * are still loading.
14
+ *
15
+ * 2. **Lazy (Phase 2+)**: when the parent hits a `{ workflow: X }`
16
+ * node and the registry has no entry for X (or `subgraphRefs`
17
+ * missed the reference because X was computed at runtime), the
18
+ * in-process executor fetches X's bundle on demand, imports it,
19
+ * and `register()`s the factory before invoking it.
20
+ *
21
+ * The registry is **synchronous** so `dispatchSubgraph` can decide
22
+ * "in-process or HTTP" at a sync decision point. Async fetch lives in
23
+ * `in-process-subgraph.js`; this module is just the bookkeeping.
24
+ *
25
+ * Module-level state. Each Fargate task is a fresh Node process, so
26
+ * cross-task leakage is impossible — only within-task siblings share
27
+ * the cache, which is by design (one fetch per child per task).
28
+ */
1
29
  /**
2
30
  * Synchronously check whether `name` is in-process executable.
3
31
  *
@@ -5,7 +33,7 @@
5
33
  * that as "not ready, fall back to HTTP this time" rather than waiting
6
34
  * (waiting defeats the purpose: HTTP dispatch is the same latency).
7
35
  */
8
- export function has(name: any): boolean;
36
+ export declare function has(name: any): boolean;
9
37
  /**
10
38
  * Register a child workflow as available in-process. Idempotent — a
11
39
  * second call with the same name replaces the factory (intentional: a
@@ -18,10 +46,7 @@ export function has(name: any): boolean;
18
46
  * sub-graph invocation gets its own graph so state is not shared.
19
47
  * @param {object} [meta] — bookkeeping written for diagnostics
20
48
  */
21
- export function register(name: string, factory: () => Promise<{
22
- graph: any;
23
- AgentClass: any;
24
- }>, meta?: object): void;
49
+ export declare function register(name: any, factory: any, meta?: any): void;
25
50
  /**
26
51
  * Mark a child as currently being fetched. Lets concurrent first-call
27
52
  * dispatches for the same name observe "in flight" and either wait or
@@ -29,20 +54,16 @@ export function register(name: string, factory: () => Promise<{
29
54
  * has the same latency budget as the HTTP path; defer to a future PR
30
55
  * if we want to dedupe waiters.
31
56
  */
32
- export function markLoading(name: any): void;
33
- export function markFailed(name: any, err: any): void;
57
+ export declare function markLoading(name: any): void;
58
+ export declare function markFailed(name: any, err: any): void;
34
59
  /**
35
60
  * Get the factory for `name`, or null if not ready. Returns the factory
36
61
  * itself; callers invoke it to materialize a fresh graph.
37
62
  */
38
- export function get(name: any): any;
39
- export function getState(name: any): any;
40
- export function getMeta(name: any): any;
63
+ export declare function get(name: any): any;
64
+ export declare function getState(name: any): any;
65
+ export declare function getMeta(name: any): any;
41
66
  /** Diagnostics: snapshot the current registry state. */
42
- export function list(): {
43
- name: any;
44
- state: any;
45
- meta: any;
46
- }[];
67
+ export declare function list(): any[];
47
68
  /** Reset — only for tests. Don't call in production. */
48
- export function _reset(): void;
69
+ export declare function _reset(): void;
@@ -1,29 +1,41 @@
1
+ /**
2
+ * Timeline UI — progressive CLI output with vertical-line connectors.
3
+ *
4
+ * When inside a node, ALL console output is automatically prefixed with │
5
+ * and soft-wrapped at terminal width so the pipe stays visible on every
6
+ * visual line, even when text wraps.
7
+ *
8
+ * Milestone dots (◆) sit ON the line, replacing │ at that point.
9
+ *
10
+ * ── Public protocol contract ──────────────────────────────────────────────
11
+ * `timeline.nodeStart` / `nodeComplete` / `nodeFailed` emit machine-readable
12
+ * lines on stdout prefixed with WORKFLOW_GRAPH_LOG_MARKER_PREFIX. External
13
+ * consumers parse these lines to track node lifecycle:
14
+ * - `studio/src/utils/studioRunStreamLog.js` (Studio's run progress UI)
15
+ * - `packages/skills/src/test-runner.js` (test runner's per-node tracking)
16
+ *
17
+ * If you change the marker prefix or payload shape, you must update both
18
+ * consumers in the same change. Markers are emitted only when a host opts
19
+ * in via ZIBBY_EMIT_GRAPH_MARKERS=1 (or the legacy alias
20
+ * ZIBBY_WORKFLOW_GRAPH_LOG_MARKERS=1), to keep regular CLI output clean.
21
+ */
1
22
  /**
2
23
  * Prefix for machine-readable stdout lines that bound graph-node execution.
3
24
  * Plain text (no styling) so external tools can split logs by node.
4
25
  * Line format: `${WORKFLOW_GRAPH_LOG_MARKER_PREFIX}${JSON.stringify(payload)}\n`
5
26
  * Payload: `{ phase: 'node_begin'|'node_end', node: string }`
6
27
  */
7
- export const WORKFLOW_GRAPH_LOG_MARKER_PREFIX: "__WORKFLOW_GRAPH_LOG__";
8
- export const timeline: Timeline;
9
- export default timeline;
10
- export class Timeline {
11
- _currentNode: any;
12
- _origStdoutWrite: any;
13
- _origStderrWrite: any;
14
- _emitWorkflowGraphMarkers: boolean;
28
+ export declare const WORKFLOW_GRAPH_LOG_MARKER_PREFIX = "__WORKFLOW_GRAPH_LOG__";
29
+ declare class Timeline {
30
+ _currentNode?: any;
31
+ _emitWorkflowGraphMarkers?: any;
32
+ _errState?: any;
33
+ _origStderrWrite?: any;
34
+ _origStdoutWrite?: any;
35
+ _outState?: any;
36
+ constructor();
15
37
  get isInsideNode(): boolean;
16
38
  _startIntercepting(): void;
17
- _outState: {
18
- lineStart: boolean;
19
- col: number;
20
- inEsc: boolean;
21
- };
22
- _errState: {
23
- lineStart: boolean;
24
- col: number;
25
- inEsc: boolean;
26
- };
27
39
  _stopIntercepting(): void;
28
40
  _rawWrite(msg: any): void;
29
41
  /** Emit a single-line graph log marker (never chalk). */
@@ -43,8 +55,11 @@ export class Timeline {
43
55
  stepMemory(message: any): void;
44
56
  stepFail(message: any): void;
45
57
  nodeStart(name: any): void;
46
- nodeComplete(name: any, opts?: {}): void;
47
- nodeFailed(name: any, error: any, opts?: {}): void;
58
+ nodeComplete(name: any, opts?: any): void;
59
+ nodeFailed(name: any, error: any, opts?: any): void;
48
60
  route(from: any, to: any): void;
49
61
  graphComplete(): void;
50
62
  }
63
+ export declare const timeline: Timeline;
64
+ export { Timeline };
65
+ export default timeline;