@zibby/agent-workflow 2.0.1 → 2.0.2
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/graph-compiler.js +1 -1
- package/dist/graph.js +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
package/dist/graph-compiler.js
CHANGED
|
@@ -39,7 +39,7 @@ ${s}`);let a=o(),u=a.cwd||process.cwd(),d=a.sessionPath;try{if(d){let l=Re(d,K);
|
|
|
39
39
|
`).slice(2,14).join(`
|
|
40
40
|
`);console.log(`[zibby:session] stack (${n}):
|
|
41
41
|
${y}`)}}function Un(){return process.env.ZIBBY_TRUST_SESSION_ENV==="1"||process.env.ZIBBY_TRUST_SESSION_ENV==="true"||process.env.ZIBBY_KEEP_SESSION_ENV==="1"||process.env.ZIBBY_KEEP_SESSION_ENV==="true"}function Wn(){if(!(process.env.ZIBBY_PIN_SESSION_PATH==="1"||process.env.ZIBBY_PIN_SESSION_PATH==="true"))return;let e=process.env.ZIBBY_SESSION_PATH;if(!(e==null||String(e).trim()===""))try{return Ct(String(e).trim())}catch{return String(e).trim()}}function Fn(){Un()||(delete process.env.ZIBBY_SESSION_PATH,delete process.env.ZIBBY_SESSION_ID)}function Gn({sessionPath:n,sessionId:e}){n&&typeof n=="string"&&(process.env.ZIBBY_SESSION_PATH=n),e!=null&&String(e).trim()!==""&&(process.env.ZIBBY_SESSION_ID=String(e).trim())}function Hn(n={}){let e=it.map(s=>process.env[s]).find(Boolean),t=Math.random().toString(36).slice(2,6),o=e||`${Date.now()}_${t}`,r=n.paths?.sessionPrefix;return r?`${r}_${o}`:o}function Jn({cwd:n=process.cwd(),config:e={},initialState:t={},traceFrom:o="resolveWorkflowSession"}={}){let r=t.sessionPath,s=t.sessionTimestamp,i="initialState.sessionPath";if(!r&&process.env.ZIBBY_SESSION_PATH)try{let d=Ct(String(process.env.ZIBBY_SESSION_PATH));d&&(r=d,i="ZIBBY_SESSION_PATH")}catch{}let a;if(r)a=String(r).split(/[/\\]/).filter(Boolean).pop(),s==null&&(s=Date.now());else{let d=process.env.ZIBBY_SESSION_ID&&String(process.env.ZIBBY_SESSION_ID).trim();if(d)a=d,i="ZIBBY_SESSION_ID";else{let l=e.sessionId!=null?String(e.sessionId).trim():"";l&&l!=="last"?(a=l,i="config.sessionId"):(a=Hn(e),i="generated")}s=s??Date.now();let y=e.paths?.output||he;r=Z(n,y,rt,a)}let u=!De(r);return u&&Nt(r,{recursive:!0}),(u||i!=="initialState.sessionPath")&&Ln({traceFrom:o,sessionId:a,sessionPath:r,idSource:i,mkdirFresh:u}),Gn({sessionPath:r,sessionId:a}),{sessionPath:r,sessionId:a,sessionTimestamp:s}}var _e=class{constructor(e={}){this.nodes=new Map,this.edges=new Map,this.entryPoint=null,this.middleware=Array.isArray(e.middleware)?[...e.middleware]:[],e.nodeMiddleware&&this.middleware.push(e.nodeMiddleware),this.nodeTypeMap=new Map,this.conditionalCodeMap=new Map,this.stateSchema=e.stateSchema||null,this.inputSchema=e.inputSchema||null,this.contextSchema=e.contextSchema||null,this.nodePrompts=new Map,this.nodeOptions=new Map,this._invokeAgent=e.invokeAgent||null,this._compiledPrompts=new Map}setInputSchema(e){return this.inputSchema=e,this}setContextSchema(e){return this.contextSchema=e,this}setStateSchema(e){return this.stateSchema=e,this}getInputSchema(){return this.inputSchema}getContextSchema(){return this.contextSchema}getStateSchema(){return this.stateSchema}_runtimeSchema(){if(this.inputSchema&&this.contextSchema)try{if(typeof this.inputSchema.merge=="function")return this.inputSchema.merge(this.contextSchema);if(typeof this.inputSchema.and=="function")return this.inputSchema.and(this.contextSchema)}catch{}return this.inputSchema&&!this.contextSchema?this.inputSchema:this.stateSchema}addNode(e,t,o={}){if(!(t instanceof U)&&t&&typeof t=="object"&&typeof t.workflow=="string"){let i=t,a={name:e,_isCustomCode:!0,dispatchesWorkflow:i.workflow,retries:i.retries,onComplete:i.onComplete,execute:async d=>{let y=d?.state&&typeof d.state.getAll=="function"?d.state.getAll():d,l;return typeof i.input=="function"?l=i.input(y):i.input&&typeof i.input=="object"?l=i.input:l={},At(i.workflow,{input:l,async:i.async===!0,conversationId:typeof i.conversationId=="function"?i.conversationId(y):i.conversationId,output:i.output,timeoutMs:i.timeoutMs,pollIntervalMs:i.pollIntervalMs,signal:y?._signal,parentAgent:d?.agent})}},u=new U(a);return u.name=e,this.nodes.set(e,u),o.prompt&&this.nodePrompts.set(e,o.prompt),Object.keys(o).length>0&&this.nodeOptions.set(e,o),this}let r=!(t instanceof U)&&t&&typeof t=="object"&&typeof t.execute!="function"&&t.prompt==null&&t.outputSchema==null&&t._isCustomCode!==!0,s=t instanceof U?t:new U(r?{...t,_isRouter:!0}:t);return s.name=e,this.nodes.set(e,s),o.prompt?this.nodePrompts.set(e,o.prompt):typeof t?.prompt=="string"&&t.prompt.trim()&&this.nodePrompts.set(e,t.prompt),Object.keys(o).length>0&&this.nodeOptions.set(e,o),this}addEdge(e,t){let o=this.edges.get(e);return o===void 0?this.edges.set(e,t):typeof o=="string"?o!==t&&this.edges.set(e,[o,t]):Array.isArray(o)?o.includes(t)||o.push(t):(console.warn(`[workflow] addEdge('${e}', '${t}') overrides the conditional edges already declared on '${e}'. A node routes EITHER unconditionally (addEdge) OR conditionally (addConditionalEdges) \u2014 not both.`),this.edges.set(e,t)),this}setNodeType(e,t){return this.nodeTypeMap.set(e,t),this}addConditionalEdges(e,t,{labels:o}={}){let r=this.edges.get(e);return r!==void 0&&!r.conditional&&console.warn(`[workflow] addConditionalEdges('${e}', \u2026) overrides the unconditional edge(s) already declared on '${e}' (${Array.isArray(r)?r.join(", "):r}). A node routes EITHER unconditionally OR conditionally \u2014 not both.`),this.edges.set(e,{conditional:!0,routes:t,labels:o}),typeof t=="function"&&this.conditionalCodeMap.set(e,t.toString()),this}setEntryPoint(e){return this.entryPoint=e,this}_simpleTargets(e){let t=this.edges.get(e);return t===void 0?[]:typeof t=="string"?[t]:Array.isArray(t)?t:[]}_analyzeFlow(){let e=new Set,t=new Map,o=s=>{t.set(s,1);for(let i of this._simpleTargets(s)){if(!i||i==="END")continue;let a=t.get(i)||0;a===1?e.add(`${s}->${i}`):a===0&&o(i)}t.set(s,2)};this.entryPoint&&o(this.entryPoint);let r=new Map;for(let[s]of this.edges)for(let i of this._simpleTargets(s))!i||i==="END"||e.has(`${s}->${i}`)||r.set(i,(r.get(i)||0)+1);return{backEdges:e,joinDegree:r}}use(e){return typeof e=="function"&&this.middleware.push(e),this}_composeMiddleware(e,t,o,r,s){let i=o;for(let a=e.length-1;a>=0;a--){let u=e[a],d=i;i=()=>u(t,d,r,s)}return i()}serialize(){let e=[],t={};for(let[l,c]of this.nodes){let g=this.nodeTypeMap.get(l)||(c?.config?._isRouter===!0?"decision":l);e.push({id:l,type:g,data:{nodeType:g,label:l}});let m={};c._isCustomCode&&typeof c.execute=="function"&&(m.customCode=c.execute.toString());let b=typeof c?.config?.description=="string"&&c.config.description.trim()?c.config.description:typeof c?.description=="string"&&c.description.trim()?c.description:null;b&&(m.description=b);let A=this.nodePrompts.get(l);if(A)m.prompt=A;else if(typeof c.prompt=="function")try{let p=c.prompt({});typeof p=="string"&&p.trim()&&(m.prompt=p,m.promptIsCode=!0)}catch{}if(typeof c.customExecute=="function"&&(m.executeCode=c.customExecute.toString()),typeof c?.config?.dispatchesWorkflow=="string"&&c.config.dispatchesWorkflow.trim()&&(m.dispatchesWorkflow=c.config.dispatchesWorkflow.trim()),typeof c?.config?.agent=="string"&&c.config.agent.trim()&&(m.agent=c.config.agent.trim()),c.outputSchema)if(typeof c.outputSchema._def<"u"){let p=null;if(typeof Se?.toJSONSchema=="function")try{p=Se.toJSONSchema(c.outputSchema)}catch{}if(!p)try{p=Pt(c.outputSchema,{target:"openApi3"})}catch{}m.outputSchema=p?{jsonSchema:p,variables:this._flattenJsonSchemaToVariables(p)}:{schema:c.outputSchema}}else m.outputSchema={schema:c.outputSchema};let T=(this.resolvedToolsMap||{})[l];T?.toolIds&&(m.tools=T.toolIds);let f=Array.isArray(c?.config?.skills)?c.config.skills:Array.isArray(c?.skills)?c.skills:null;f&&f.length>0&&(m.skills=[...f]);let h=Array.isArray(c?.config?.plugins)?c.config.plugins:Array.isArray(c?.plugins)?c.plugins:null;h&&h.length>0&&(m.plugins=h.map(p=>p&&typeof p=="object"?{...p}:p));let I=Array.isArray(c?.config?.stores)?c.config.stores:Array.isArray(c?.stores)?c.stores:null;I&&I.length>0&&(m.stores=I.map(p=>p&&typeof p=="object"?{...p}:p)),Object.keys(m).length>0&&(t[l]=m)}let o=[];for(let[l,c]of this.edges)if(typeof c=="string")o.push({source:l,target:c});else if(Array.isArray(c))for(let g of c)o.push({source:l,target:g});else if(c.conditional){let g=this.conditionalCodeMap.get(l)||c.routes.toString(),m=this._inferConditionalTargets(c.routes,c.labels),b=c.labels||{},A=this.nodes.get(l),T=A?.config?._isRouter===!0||this.nodeTypeMap.get(l)==="decision"||!A,f=l;if(!T){let h=`${l}__branch`;e.push({id:h,type:"decision",data:{nodeType:"decision",label:h}}),o.push({source:l,target:h}),f=h}for(let h of m){let I={source:f,target:h,data:{conditionalCode:g}};b[h]&&(I.label=b[h]),o.push(I)}}let r=l=>{if(!l)return null;if(typeof Se?.toJSONSchema=="function")try{return Se.toJSONSchema(l)}catch{}try{return Pt(l,{target:"openApi3"})}catch{return null}};this.entryPoint&&this.nodes.has(this.entryPoint)&&(e.unshift({id:"START",type:"start",data:{nodeType:"start",label:"Start"}}),o.unshift({source:"START",target:this.entryPoint}));let s=0;for(let l of o)if(l.target==="END"){s+=1;let c=`END__${s}`;l.target=c,e.push({id:c,type:"end",data:{nodeType:"end",label:"End"}})}for(let l of this.nodes.keys())if(!this.edges.has(l)){s+=1;let c=`END__${s}`;e.push({id:c,type:"end",data:{nodeType:"end",label:"End"}}),o.push({source:l,target:c})}let i=this._topoOrderNodes(e,o),a=this._runtimeSchema(),u=r(a||this.stateSchema),d=r(this.inputSchema),y=r(this.contextSchema);return{nodes:i,edges:o,nodeConfigs:t,stateSchema:u,inputSchema:d,contextSchema:y}}_topoOrderNodes(e,t){let o=new Map(e.map((l,c)=>[l.id,c])),r=new Map(e.map(l=>[l.id,l])),s=new Map(e.map(l=>[l.id,0])),i=new Map(e.map(l=>[l.id,[]]));for(let l of t)i.has(l.source)&&s.has(l.target)&&(i.get(l.source).push(l.target),s.set(l.target,s.get(l.target)+1));let a=new Set,u=new Set(o.keys()),d=[...u].filter(l=>s.get(l)===0),y=[];for(;y.length<e.length;){let l;if(d.length>0){if(d.sort((c,g)=>o.get(c)-o.get(g)),l=d.shift(),a.has(l))continue}else l=[...u].sort((c,g)=>o.get(c)-o.get(g))[0];a.add(l),u.delete(l),y.push(r.get(l));for(let c of i.get(l)||[])s.set(c,s.get(c)-1),s.get(c)<=0&&!a.has(c)&&d.push(c)}return y}_inferConditionalTargets(e,t){let o=e.toString(),r=new Set,s=/(['"])((?:\\.|(?!\1).)*?)\1|`((?:\\.|[^`$]|\$(?!\{))*?)`/g,i;for(;(i=s.exec(o))!==null;){let d=i[2]!==void 0?i[2]:i[3];d!==void 0&&d!==""&&r.add(d)}let a=new Set(["END","START","__end__","__start__"]);for(let d of this.nodes.keys())a.add(d);if(t&&typeof t=="object")for(let d of Object.keys(t))a.add(d);let u=new Set;for(let d of r)a.has(d)&&u.add(d);if(u.size===0){let d=/return\s+['"]([^'"]+)['"]/g,y;for(;(y=d.exec(o))!==null;)u.add(y[1])}return[...u]}_flattenJsonSchemaToVariables(e,t=""){let o=e;if(e.$ref&&e.definitions){let r=e.$ref.replace("#/definitions/","");o=e.definitions[r]||e}return this._flattenSchema(o,t)}_flattenSchema(e,t=""){if(!e||typeof e!="object")return[];let o=[],r=e.properties||{},s=e.required||[];for(let[i,a]of Object.entries(r)){let u=t?`${t}.${i}`:i;o.push({path:u,type:a.type||"unknown",label:a.description||this._formatLabel(i),optional:!s.includes(i)}),a.type==="object"&&a.properties&&o.push(...this._flattenSchema(a,u)),a.type==="array"&&a.items?.type==="object"&&a.items.properties&&o.push(...this._flattenSchema(a.items,`${u}[]`))}return o}_formatLabel(e){return e.replace(/([A-Z])/g," $1").replace(/^./,t=>t.toUpperCase()).trim()}_summarizeNodeOutput(e,t){if(!t||typeof t!="object")return[];let o=[];t.success!==void 0&&o.push(`Result: ${t.success?"passed":"failed"}`);for(let[r,s]of Object.entries(t))if(!(r==="success"||r==="raw"||r==="nextNode")){if(typeof s=="string"&&s.length<=80)o.push(`${r}: ${s}`);else if(Array.isArray(s)){let i=s.length,a=s.filter(d=>d?.passed===!0).length,u=s.some(d=>d?.passed!==void 0);o.push(u?`${r}: ${a}/${i} passed${i-a?`, ${i-a} failed`:""}`:`${r}: ${i} items`)}if(o.length>=4)break}return o}async run(e,t={},o={}){if(!this.entryPoint)throw new Error("No entry point set for graph");if(e&&typeof e.normalizeInput=="function"&&t&&typeof t=="object"&&!Array.isArray(t))try{t=e.normalizeInput(t)??t}catch(S){let w=new Error(`agent.normalizeInput() rejected the trigger input: ${S?.message||S}`);throw w.cause=S,w.code=S?.code||"NORMALIZE_INPUT_FAILED",w}let r=new AbortController;o.signal&&(o.signal.aborted?r.abort():o.signal.addEventListener("abort",()=>r.abort(),{once:!0}));let s=o.strategyAbortTimeoutMs??t.config?.strategyAbortTimeoutMs??5e3,i=t.cwd||process.cwd();jn({path:Z(i,".env")});let a=t.config||{};if(!a||Object.keys(a).length===0)try{let S=Z(i,".zibby.config.js");De(S)&&(a=(await import(S)).default||{})}catch{}process.env.EXECUTION_ID&&!a.agent?.strictMode&&(a.agent={...a.agent,strictMode:!0});let u=t.agentType;if(!u){let S=a?.agent;S?.provider?u=S.provider:S?.gemini?u="gemini":S?.claude?u="claude":S?.cursor?u="cursor":S?.codex?u="codex":u=process.env.AGENT_TYPE||"claude"}let d=t.contextConfig||e?.config?.contextConfig||e?.config?.context||a?.context||{},y=this._runtimeSchema();if(y){let S=y.safeParse(t);if(!S.success){let w=S.error.issues.map(M=>`${M.path.join(".")}: ${M.message}`);throw console.error("\u274C Initial state validation failed:"),w.forEach(M=>console.error(` - ${M}`)),new Error(`State validation failed: ${w.join(", ")}`)}P.step("State validated against schema")}let l=Wn(),c=t.sessionPath||l;c||Fn();let{sessionPath:g,sessionTimestamp:m,sessionId:b}=Jn({cwd:i,config:a,traceFrom:"WorkflowGraph.run",initialState:{sessionPath:c,sessionTimestamp:t.sessionTimestamp}});P.step(`Session ${b}`);let A=await we.loadContext(t.specPath||"",i,d);Object.keys(A).length>0&&P.step(`Context loaded: ${Object.keys(A).join(", ")}`);let T=t.outputPath;!T&&t.specPath&&(e?.calculateOutputPath?T=e.calculateOutputPath(t.specPath):console.warn(`\u26A0\uFE0F outputPath not resolved (specPath=${t.specPath})`));let f=new de({...t,config:a,agentType:u,outputPath:T,sessionPath:g,sessionTimestamp:m,context:A,resolvedTools:this.resolvedToolsMap||{},_signal:r.signal}),h=new Map;try{await import("@zibby/skills")}catch{}let{getSkill:I}=await Promise.resolve().then(()=>(ge(),ct)),p=a.skills&&typeof a.skills=="object"?a.skills:{},E=Object.values(p).filter(S=>S&&typeof S=="object"&&typeof S.id=="string"),$=S=>{for(let w of E)if(w.id===S)return w;return I(S)},v=new Set;for(let[,S]of this.nodes)for(let w of S.config?.skills||[])v.add(w);for(let S of v){let w=$(S);if(typeof w?.middleware=="function")try{let M=await w.middleware();typeof M=="function"&&h.set(S,M)}catch{}}let{backEdges:Dt,joinDegree:Lt}=this._analyzeFlow(),Ie=new Map,X=[],Ee=(S,w,M)=>{if(!S||S==="END")return;let D=Lt.get(S)||0;if(M&&D>1&&!Dt.has(`${w}->${S}`)){let Q=(Ie.get(S)||0)+1;if(Q<D){Ie.set(S,Q);return}Ie.set(S,0)}X.includes(S)||X.push(S)};this.entryPoint&&X.push(this.entryPoint);let ae=[],Fe=a?.recursionLimit??100,Ut=0;try{for(;X.length>0;){let w=X.pop();if(!w||w==="END")continue;if(++Ut>Fe)throw new Error(`Workflow exceeded recursion limit (${Fe}) \u2014 the cap counts NODE EXECUTIONS, so this is either a cyclic conditional route or a graph whose branches total more nodes than the cap. Set config.recursionLimit if you need a higher cap.`);let M=Z(g,st);if(De(M)){try{Bn(M)}catch{}r.abort()}if(r.signal.aborted)return console.warn(`
|
|
42
|
-
\u{1F6D1} External stop requested \u2014 ending workflow.`),P.step("Workflow stopped externally"),{success:!0,state:f.getAll(),executionLog:ae,stoppedExternally:!0};let D=this.nodes.get(w);if(!D)throw new Error(`Node '${w}' not found in graph`);let Q=JSON.stringify({sessionPath:g,sessionTimestamp:m,currentNode:w,createdAt:new Date().toISOString(),config:f.get("config")}),Wt=Z(g,K);Ot(Wt,Q,"utf-8");let Ge=f.get("config")?.paths?.output||he,Ft=Z(i,Ge,K);Nt(Z(i,Ge),{recursive:!0});try{Ot(Ft,Q,"utf-8")}catch{}let He=t.onPipelineProgress;if(typeof He=="function")try{He({cwd:i,sessionPath:g,sessionId:b,outputBase:f.get("config")?.paths?.output||he,currentNode:w})}catch{}let Gt=(this.resolvedToolsMap||{})[w]||null;f.set("_currentNodeTools",Gt);let Ht=f.get("nodeConfigs")||{};f.set("_currentNodeConfig",Ht[w]||{}),P.nodeStart(w);let Je=Date.now(),ce=this.nodePrompts.get(w);if(!this._invokeAgent){let x=await Promise.resolve().then(()=>(se(),re));this._invokeAgent=x.invokeAgent}let Jt=this._invokeAgent,$e={},zt=D.config?.skills||[];for(let x of zt){let C=$(x);if(typeof C?.invokeAgentOptions=="function")try{let k=C.invokeAgentOptions(f.getAll(),{agentType:f.get("agentType"),nodeName:w});k&&typeof k=="object"&&($e={...$e,...k})}catch(k){console.warn(`[graph] skill '${x}' invokeAgentOptions threw: ${k.message}`)}}let ze=async(x,C,k={})=>{let B=Jt(x,C,{...$e,...k,signal:r.signal});return B.catch(()=>{}),r.signal.aborted?B:Promise.race([B,new Promise((q,L)=>{let R=()=>{setTimeout(()=>{let ee=new Error(`Strategy ignored AbortSignal \u2014 engine deadman fired after ${s}ms`);ee.name="AbortError",L(ee)},s)};r.signal.addEventListener("abort",R,{once:!0})})])},Yt=async(x={},C={})=>{let k=C.prompt||"";if(ce){let B=this._compiledPrompts.get(w);B||(B=Dn.compile(ce,{noEscape:!0}),this._compiledPrompts.set(w,B));try{k=B(x)}catch(q){throw console.error(`\u274C Template rendering failed for node '${w}':`,q.message),new Error(`Template rendering failed: ${q.message}`,{cause:q})}}else if(!k)throw new Error(`No prompt template configured for node '${w}' and no prompt provided in options`);return ze(k,{state:f.getAll(),images:C.images||[]},{model:C.model||f.get("model"),workspace:f.get("workspace"),schema:C.schema,...C,signal:r.signal})},Ye=f.getAll(),Zt=["state","invokeAgent","_coreInvokeAgent","agent","nodeId","promptTemplate","getPromptTemplate"];for(let x of Zt)Object.prototype.hasOwnProperty.call(Ye,x)&&console.warn(`[workflow] node "${w}": state key "${x}" is shadowed by the engine context prop; read it via context.state.get('${x}')`);let Ze={...Ye,state:f,invokeAgent:Yt,_coreInvokeAgent:ze,agent:e,nodeId:w,promptTemplate:ce,getPromptTemplate:()=>ce};try{let x=(D.config?.skills||[]).map(R=>h.get(R)).filter(Boolean),C=[...this.middleware,...x],k;k=await gt(e,r.signal,async()=>C.length>0?this._composeMiddleware(C,w,async()=>D.execute(Ze,f),f.getAll(),f):D.execute(Ze,f));let B=Date.now()-Je;if(ae.push({node:w,success:k.success,duration:B,timestamp:new Date().toISOString()}),!k.success){if(r.signal.aborted)return P.step("Workflow stopped externally"),{success:!0,state:f.getAll(),executionLog:ae,stoppedExternally:!0};f.append("errors",{node:w,error:k.error});let R=D.config?.retries||0,ee=`${w}_retries`,le=f.getAll()[ee]||0;if(le<R){P.stepInfo(`Retrying (attempt ${le+1}/${R})`),f.update({[ee]:le+1,[`${w}_raw`]:k.raw});continue}throw P.nodeFailed(w,k.error,{duration:B}),new Error(`Node '${w}' failed after ${le} attempts: ${k.error}`)}f.update({[w]:k.output});let q=this._summarizeNodeOutput(w,k.output);P.nodeComplete(w,{duration:B,details:q});let L=this.edges.get(w);if(L)if(L.conditional){let R=L.routes(f.getAll());P.route(w,R),Ee(R,w,!1)}else if(Array.isArray(L))for(let R=L.length-1;R>=0;R--)Ee(L[R],w,!0);else Ee(L,w,!0)}catch(x){throw P.isInsideNode&&P.nodeFailed(w,x.message,{duration:Date.now()-Je}),f.set("failed",!0),f.set("failedAt",w),x}}P.graphComplete();let S={success:!0,state:f.getAll(),executionLog:ae};return e&&typeof e.onComplete=="function"&&await e.onComplete(S),S}finally{if(e&&typeof e.cleanup=="function")try{await e.cleanup()}catch(S){console.warn(`[workflow] agent.cleanup() failed: ${S.message}`)}}}};var Le=Symbol.for("@zibby/agent-workflow.nodes");globalThis[Le]||(globalThis[Le]=new Map);var Ue=globalThis[Le];function zn(n,e){Ue.set(n,e)}function Rt(n){return Ue.get(n)}function We(n){return Ue.has(n)}zn("ai_agent",{name:"ai_agent",factory:!0,create:(n,e={})=>({name:n,_isCustomCode:!0,execute:async t=>{let o=t?._coreInvokeAgent;o||(o=(await Promise.resolve().then(()=>(se(),re))).invokeAgent);let r=e.extraPromptInstructions||"Execute the task based on the current state.",s=Yn(r,t),i=await o(s,{cwd:t.workspace||process.cwd(),model:t.model,tools:e.resolvedTools||null});return{success:!0,output:{raw:i,nodeId:n},raw:typeof i=="string"?i:i.raw}}})});function Yn(n,e){let t=/@([\w.]+)/g,o=new Set,r;for(;(r=t.exec(n))!==null;)o.add(r[1]);if(o.size===0)return n;let s=[],i=new Set;for(let a of o){let u=a.split(".")[0];if(i.has(u))continue;let d=a.split(".").reduce((c,g)=>c?.[g],e);if(d===void 0)continue;let y=typeof d=="string"?d:d?.raw??JSON.stringify(d,null,2),l=a.replace(/_/g," ").replace(/\b\w/g,c=>c.toUpperCase());s.push(`## ${l}
|
|
42
|
+
\u{1F6D1} External stop requested \u2014 ending workflow.`),P.step("Workflow stopped externally"),{success:!0,state:f.getAll(),executionLog:ae,stoppedExternally:!0};let D=this.nodes.get(w);if(!D)throw new Error(`Node '${w}' not found in graph`);let Q=JSON.stringify({sessionPath:g,sessionTimestamp:m,currentNode:w,createdAt:new Date().toISOString(),config:f.get("config")}),Wt=Z(g,K);Ot(Wt,Q,"utf-8");let Ge=f.get("config")?.paths?.output||he,Ft=Z(i,Ge,K);Nt(Z(i,Ge),{recursive:!0});try{Ot(Ft,Q,"utf-8")}catch{}let He=t.onPipelineProgress;if(typeof He=="function")try{He({cwd:i,sessionPath:g,sessionId:b,outputBase:f.get("config")?.paths?.output||he,currentNode:w})}catch{}let Gt=(this.resolvedToolsMap||{})[w]||null;f.set("_currentNodeTools",Gt);let Ht=f.get("nodeConfigs")||{};f.set("_currentNodeConfig",Ht[w]||{}),P.nodeStart(w);let Je=Date.now(),ce=this.nodePrompts.get(w);if(!this._invokeAgent){let x=await Promise.resolve().then(()=>(se(),re));this._invokeAgent=x.invokeAgent}let Jt=this._invokeAgent,$e={},zt=D.config?.skills||[];for(let x of zt){let C=$(x);if(typeof C?.invokeAgentOptions=="function")try{let k=C.invokeAgentOptions(f.getAll(),{agentType:f.get("agentType"),nodeName:w});k&&typeof k=="object"&&($e={...$e,...k})}catch(k){console.warn(`[graph] skill '${x}' invokeAgentOptions threw: ${k.message}`)}}let ze=async(x,C,k={})=>{let B=Jt(x,C,{...$e,...k,signal:r.signal});return B.catch(()=>{}),r.signal.aborted?B:Promise.race([B,new Promise((q,L)=>{let R=()=>{setTimeout(()=>{let ee=new Error(`Strategy ignored AbortSignal \u2014 engine deadman fired after ${s}ms`);ee.name="AbortError",L(ee)},s)};r.signal.addEventListener("abort",R,{once:!0})})])},Yt=async(x={},C={})=>{let k=C.prompt||"";if(ce){let B=this._compiledPrompts.get(w);B||(B=Dn.compile(ce,{noEscape:!0}),this._compiledPrompts.set(w,B));try{k=B(x)}catch(q){throw console.error(`\u274C Template rendering failed for node '${w}':`,q.message),new Error(`Template rendering failed: ${q.message}`,{cause:q})}}else if(!k)throw new Error(`No prompt template configured for node '${w}' and no prompt provided in options`);return ze(k,{state:f.getAll(),images:C.images||[]},{model:C.model||f.get("model"),workspace:f.get("workspace"),schema:C.schema,...C,signal:r.signal,nodeName:w})},Ye=f.getAll(),Zt=["state","invokeAgent","_coreInvokeAgent","agent","nodeId","promptTemplate","getPromptTemplate"];for(let x of Zt)Object.prototype.hasOwnProperty.call(Ye,x)&&console.warn(`[workflow] node "${w}": state key "${x}" is shadowed by the engine context prop; read it via context.state.get('${x}')`);let Ze={...Ye,state:f,invokeAgent:Yt,_coreInvokeAgent:ze,agent:e,nodeId:w,promptTemplate:ce,getPromptTemplate:()=>ce};try{let x=(D.config?.skills||[]).map(R=>h.get(R)).filter(Boolean),C=[...this.middleware,...x],k;k=await gt(e,r.signal,async()=>C.length>0?this._composeMiddleware(C,w,async()=>D.execute(Ze,f),f.getAll(),f):D.execute(Ze,f));let B=Date.now()-Je;if(ae.push({node:w,success:k.success,duration:B,timestamp:new Date().toISOString()}),!k.success){if(r.signal.aborted)return P.step("Workflow stopped externally"),{success:!0,state:f.getAll(),executionLog:ae,stoppedExternally:!0};f.append("errors",{node:w,error:k.error});let R=D.config?.retries||0,ee=`${w}_retries`,le=f.getAll()[ee]||0;if(le<R){P.stepInfo(`Retrying (attempt ${le+1}/${R})`),f.update({[ee]:le+1,[`${w}_raw`]:k.raw});continue}throw P.nodeFailed(w,k.error,{duration:B}),new Error(`Node '${w}' failed after ${le} attempts: ${k.error}`)}f.update({[w]:k.output});let q=this._summarizeNodeOutput(w,k.output);P.nodeComplete(w,{duration:B,details:q});let L=this.edges.get(w);if(L)if(L.conditional){let R=L.routes(f.getAll());P.route(w,R),Ee(R,w,!1)}else if(Array.isArray(L))for(let R=L.length-1;R>=0;R--)Ee(L[R],w,!0);else Ee(L,w,!0)}catch(x){throw P.isInsideNode&&P.nodeFailed(w,x.message,{duration:Date.now()-Je}),f.set("failed",!0),f.set("failedAt",w),x}}P.graphComplete();let S={success:!0,state:f.getAll(),executionLog:ae};return e&&typeof e.onComplete=="function"&&await e.onComplete(S),S}finally{if(e&&typeof e.cleanup=="function")try{await e.cleanup()}catch(S){console.warn(`[workflow] agent.cleanup() failed: ${S.message}`)}}}};var Le=Symbol.for("@zibby/agent-workflow.nodes");globalThis[Le]||(globalThis[Le]=new Map);var Ue=globalThis[Le];function zn(n,e){Ue.set(n,e)}function Rt(n){return Ue.get(n)}function We(n){return Ue.has(n)}zn("ai_agent",{name:"ai_agent",factory:!0,create:(n,e={})=>({name:n,_isCustomCode:!0,execute:async t=>{let o=t?._coreInvokeAgent;o||(o=(await Promise.resolve().then(()=>(se(),re))).invokeAgent);let r=e.extraPromptInstructions||"Execute the task based on the current state.",s=Yn(r,t),i=await o(s,{cwd:t.workspace||process.cwd(),model:t.model,tools:e.resolvedTools||null});return{success:!0,output:{raw:i,nodeId:n},raw:typeof i=="string"?i:i.raw}}})});function Yn(n,e){let t=/@([\w.]+)/g,o=new Set,r;for(;(r=t.exec(n))!==null;)o.add(r[1]);if(o.size===0)return n;let s=[],i=new Set;for(let a of o){let u=a.split(".")[0];if(i.has(u))continue;let d=a.split(".").reduce((c,g)=>c?.[g],e);if(d===void 0)continue;let y=typeof d=="string"?d:d?.raw??JSON.stringify(d,null,2),l=a.replace(/_/g," ").replace(/\b\w/g,c=>c.toUpperCase());s.push(`## ${l}
|
|
43
43
|
${y}`),a.includes(".")||i.add(u)}return s.length===0?n:`${n}
|
|
44
44
|
|
|
45
45
|
---
|
package/dist/graph.js
CHANGED
|
@@ -39,4 +39,4 @@ ${o}`);let a=n(),u=a.cwd||process.cwd(),p=a.sessionPath;try{if(p){let c=xe(p,Z);
|
|
|
39
39
|
`).slice(2,14).join(`
|
|
40
40
|
`);console.log(`[zibby:session] stack (${r}):
|
|
41
41
|
${w}`)}}function xn(){return process.env.ZIBBY_TRUST_SESSION_ENV==="1"||process.env.ZIBBY_TRUST_SESSION_ENV==="true"||process.env.ZIBBY_KEEP_SESSION_ENV==="1"||process.env.ZIBBY_KEEP_SESSION_ENV==="true"}function Pn(){if(!(process.env.ZIBBY_PIN_SESSION_PATH==="1"||process.env.ZIBBY_PIN_SESSION_PATH==="true"))return;let e=process.env.ZIBBY_SESSION_PATH;if(!(e==null||String(e).trim()===""))try{return Tt(String(e).trim())}catch{return String(e).trim()}}function Nn(){xn()||(delete process.env.ZIBBY_SESSION_PATH,delete process.env.ZIBBY_SESSION_ID)}function Rn({sessionPath:r,sessionId:e}){r&&typeof r=="string"&&(process.env.ZIBBY_SESSION_PATH=r),e!=null&&String(e).trim()!==""&&(process.env.ZIBBY_SESSION_ID=String(e).trim())}function Bn(r={}){let e=Qe.map(o=>process.env[o]).find(Boolean),t=Math.random().toString(36).slice(2,6),n=e||`${Date.now()}_${t}`,s=r.paths?.sessionPrefix;return s?`${s}_${n}`:n}function Cn({cwd:r=process.cwd(),config:e={},initialState:t={},traceFrom:n="resolveWorkflowSession"}={}){let s=t.sessionPath,o=t.sessionTimestamp,i="initialState.sessionPath";if(!s&&process.env.ZIBBY_SESSION_PATH)try{let p=Tt(String(process.env.ZIBBY_SESSION_PATH));p&&(s=p,i="ZIBBY_SESSION_PATH")}catch{}let a;if(s)a=String(s).split(/[/\\]/).filter(Boolean).pop(),o==null&&(o=Date.now());else{let p=process.env.ZIBBY_SESSION_ID&&String(process.env.ZIBBY_SESSION_ID).trim();if(p)a=p,i="ZIBBY_SESSION_ID";else{let c=e.sessionId!=null?String(e.sessionId).trim():"";c&&c!=="last"?(a=c,i="config.sessionId"):(a=Bn(e),i="generated")}o=o??Date.now();let w=e.paths?.output||ue;s=z(r,w,Ve,a)}let u=!Be(s);return u&&At(s,{recursive:!0}),(u||i!=="initialState.sessionPath")&&On({traceFrom:n,sessionId:a,sessionPath:s,idSource:i,mkdirFresh:u}),Rn({sessionPath:s,sessionId:a}),{sessionPath:s,sessionId:a,sessionTimestamp:o}}var vt=class{constructor(e={}){this.nodes=new Map,this.edges=new Map,this.entryPoint=null,this.middleware=Array.isArray(e.middleware)?[...e.middleware]:[],e.nodeMiddleware&&this.middleware.push(e.nodeMiddleware),this.nodeTypeMap=new Map,this.conditionalCodeMap=new Map,this.stateSchema=e.stateSchema||null,this.inputSchema=e.inputSchema||null,this.contextSchema=e.contextSchema||null,this.nodePrompts=new Map,this.nodeOptions=new Map,this._invokeAgent=e.invokeAgent||null,this._compiledPrompts=new Map}setInputSchema(e){return this.inputSchema=e,this}setContextSchema(e){return this.contextSchema=e,this}setStateSchema(e){return this.stateSchema=e,this}getInputSchema(){return this.inputSchema}getContextSchema(){return this.contextSchema}getStateSchema(){return this.stateSchema}_runtimeSchema(){if(this.inputSchema&&this.contextSchema)try{if(typeof this.inputSchema.merge=="function")return this.inputSchema.merge(this.contextSchema);if(typeof this.inputSchema.and=="function")return this.inputSchema.and(this.contextSchema)}catch{}return this.inputSchema&&!this.contextSchema?this.inputSchema:this.stateSchema}addNode(e,t,n={}){if(!(t instanceof L)&&t&&typeof t=="object"&&typeof t.workflow=="string"){let i=t,a={name:e,_isCustomCode:!0,dispatchesWorkflow:i.workflow,retries:i.retries,onComplete:i.onComplete,execute:async p=>{let w=p?.state&&typeof p.state.getAll=="function"?p.state.getAll():p,c;return typeof i.input=="function"?c=i.input(w):i.input&&typeof i.input=="object"?c=i.input:c={},_t(i.workflow,{input:c,async:i.async===!0,conversationId:typeof i.conversationId=="function"?i.conversationId(w):i.conversationId,output:i.output,timeoutMs:i.timeoutMs,pollIntervalMs:i.pollIntervalMs,signal:w?._signal,parentAgent:p?.agent})}},u=new L(a);return u.name=e,this.nodes.set(e,u),n.prompt&&this.nodePrompts.set(e,n.prompt),Object.keys(n).length>0&&this.nodeOptions.set(e,n),this}let s=!(t instanceof L)&&t&&typeof t=="object"&&typeof t.execute!="function"&&t.prompt==null&&t.outputSchema==null&&t._isCustomCode!==!0,o=t instanceof L?t:new L(s?{...t,_isRouter:!0}:t);return o.name=e,this.nodes.set(e,o),n.prompt?this.nodePrompts.set(e,n.prompt):typeof t?.prompt=="string"&&t.prompt.trim()&&this.nodePrompts.set(e,t.prompt),Object.keys(n).length>0&&this.nodeOptions.set(e,n),this}addEdge(e,t){let n=this.edges.get(e);return n===void 0?this.edges.set(e,t):typeof n=="string"?n!==t&&this.edges.set(e,[n,t]):Array.isArray(n)?n.includes(t)||n.push(t):(console.warn(`[workflow] addEdge('${e}', '${t}') overrides the conditional edges already declared on '${e}'. A node routes EITHER unconditionally (addEdge) OR conditionally (addConditionalEdges) \u2014 not both.`),this.edges.set(e,t)),this}setNodeType(e,t){return this.nodeTypeMap.set(e,t),this}addConditionalEdges(e,t,{labels:n}={}){let s=this.edges.get(e);return s!==void 0&&!s.conditional&&console.warn(`[workflow] addConditionalEdges('${e}', \u2026) overrides the unconditional edge(s) already declared on '${e}' (${Array.isArray(s)?s.join(", "):s}). A node routes EITHER unconditionally OR conditionally \u2014 not both.`),this.edges.set(e,{conditional:!0,routes:t,labels:n}),typeof t=="function"&&this.conditionalCodeMap.set(e,t.toString()),this}setEntryPoint(e){return this.entryPoint=e,this}_simpleTargets(e){let t=this.edges.get(e);return t===void 0?[]:typeof t=="string"?[t]:Array.isArray(t)?t:[]}_analyzeFlow(){let e=new Set,t=new Map,n=o=>{t.set(o,1);for(let i of this._simpleTargets(o)){if(!i||i==="END")continue;let a=t.get(i)||0;a===1?e.add(`${o}->${i}`):a===0&&n(i)}t.set(o,2)};this.entryPoint&&n(this.entryPoint);let s=new Map;for(let[o]of this.edges)for(let i of this._simpleTargets(o))!i||i==="END"||e.has(`${o}->${i}`)||s.set(i,(s.get(i)||0)+1);return{backEdges:e,joinDegree:s}}use(e){return typeof e=="function"&&this.middleware.push(e),this}_composeMiddleware(e,t,n,s,o){let i=n;for(let a=e.length-1;a>=0;a--){let u=e[a],p=i;i=()=>u(t,p,s,o)}return i()}serialize(){let e=[],t={};for(let[c,l]of this.nodes){let m=this.nodeTypeMap.get(c)||(l?.config?._isRouter===!0?"decision":c);e.push({id:c,type:m,data:{nodeType:m,label:c}});let S={};l._isCustomCode&&typeof l.execute=="function"&&(S.customCode=l.execute.toString());let A=typeof l?.config?.description=="string"&&l.config.description.trim()?l.config.description:typeof l?.description=="string"&&l.description.trim()?l.description:null;A&&(S.description=A);let T=this.nodePrompts.get(c);if(T)S.prompt=T;else if(typeof l.prompt=="function")try{let d=l.prompt({});typeof d=="string"&&d.trim()&&(S.prompt=d,S.promptIsCode=!0)}catch{}if(typeof l.customExecute=="function"&&(S.executeCode=l.customExecute.toString()),typeof l?.config?.dispatchesWorkflow=="string"&&l.config.dispatchesWorkflow.trim()&&(S.dispatchesWorkflow=l.config.dispatchesWorkflow.trim()),typeof l?.config?.agent=="string"&&l.config.agent.trim()&&(S.agent=l.config.agent.trim()),l.outputSchema)if(typeof l.outputSchema._def<"u"){let d=null;if(typeof he?.toJSONSchema=="function")try{d=he.toJSONSchema(l.outputSchema)}catch{}if(!d)try{d=$t(l.outputSchema,{target:"openApi3"})}catch{}S.outputSchema=d?{jsonSchema:d,variables:this._flattenJsonSchemaToVariables(d)}:{schema:l.outputSchema}}else S.outputSchema={schema:l.outputSchema};let v=(this.resolvedToolsMap||{})[c];v?.toolIds&&(S.tools=v.toolIds);let f=Array.isArray(l?.config?.skills)?l.config.skills:Array.isArray(l?.skills)?l.skills:null;f&&f.length>0&&(S.skills=[...f]);let h=Array.isArray(l?.config?.plugins)?l.config.plugins:Array.isArray(l?.plugins)?l.plugins:null;h&&h.length>0&&(S.plugins=h.map(d=>d&&typeof d=="object"?{...d}:d));let _=Array.isArray(l?.config?.stores)?l.config.stores:Array.isArray(l?.stores)?l.stores:null;_&&_.length>0&&(S.stores=_.map(d=>d&&typeof d=="object"?{...d}:d)),Object.keys(S).length>0&&(t[c]=S)}let n=[];for(let[c,l]of this.edges)if(typeof l=="string")n.push({source:c,target:l});else if(Array.isArray(l))for(let m of l)n.push({source:c,target:m});else if(l.conditional){let m=this.conditionalCodeMap.get(c)||l.routes.toString(),S=this._inferConditionalTargets(l.routes,l.labels),A=l.labels||{},T=this.nodes.get(c),v=T?.config?._isRouter===!0||this.nodeTypeMap.get(c)==="decision"||!T,f=c;if(!v){let h=`${c}__branch`;e.push({id:h,type:"decision",data:{nodeType:"decision",label:h}}),n.push({source:c,target:h}),f=h}for(let h of S){let _={source:f,target:h,data:{conditionalCode:m}};A[h]&&(_.label=A[h]),n.push(_)}}let s=c=>{if(!c)return null;if(typeof he?.toJSONSchema=="function")try{return he.toJSONSchema(c)}catch{}try{return $t(c,{target:"openApi3"})}catch{return null}};this.entryPoint&&this.nodes.has(this.entryPoint)&&(e.unshift({id:"START",type:"start",data:{nodeType:"start",label:"Start"}}),n.unshift({source:"START",target:this.entryPoint}));let o=0;for(let c of n)if(c.target==="END"){o+=1;let l=`END__${o}`;c.target=l,e.push({id:l,type:"end",data:{nodeType:"end",label:"End"}})}for(let c of this.nodes.keys())if(!this.edges.has(c)){o+=1;let l=`END__${o}`;e.push({id:l,type:"end",data:{nodeType:"end",label:"End"}}),n.push({source:c,target:l})}let i=this._topoOrderNodes(e,n),a=this._runtimeSchema(),u=s(a||this.stateSchema),p=s(this.inputSchema),w=s(this.contextSchema);return{nodes:i,edges:n,nodeConfigs:t,stateSchema:u,inputSchema:p,contextSchema:w}}_topoOrderNodes(e,t){let n=new Map(e.map((c,l)=>[c.id,l])),s=new Map(e.map(c=>[c.id,c])),o=new Map(e.map(c=>[c.id,0])),i=new Map(e.map(c=>[c.id,[]]));for(let c of t)i.has(c.source)&&o.has(c.target)&&(i.get(c.source).push(c.target),o.set(c.target,o.get(c.target)+1));let a=new Set,u=new Set(n.keys()),p=[...u].filter(c=>o.get(c)===0),w=[];for(;w.length<e.length;){let c;if(p.length>0){if(p.sort((l,m)=>n.get(l)-n.get(m)),c=p.shift(),a.has(c))continue}else c=[...u].sort((l,m)=>n.get(l)-n.get(m))[0];a.add(c),u.delete(c),w.push(s.get(c));for(let l of i.get(c)||[])o.set(l,o.get(l)-1),o.get(l)<=0&&!a.has(l)&&p.push(l)}return w}_inferConditionalTargets(e,t){let n=e.toString(),s=new Set,o=/(['"])((?:\\.|(?!\1).)*?)\1|`((?:\\.|[^`$]|\$(?!\{))*?)`/g,i;for(;(i=o.exec(n))!==null;){let p=i[2]!==void 0?i[2]:i[3];p!==void 0&&p!==""&&s.add(p)}let a=new Set(["END","START","__end__","__start__"]);for(let p of this.nodes.keys())a.add(p);if(t&&typeof t=="object")for(let p of Object.keys(t))a.add(p);let u=new Set;for(let p of s)a.has(p)&&u.add(p);if(u.size===0){let p=/return\s+['"]([^'"]+)['"]/g,w;for(;(w=p.exec(n))!==null;)u.add(w[1])}return[...u]}_flattenJsonSchemaToVariables(e,t=""){let n=e;if(e.$ref&&e.definitions){let s=e.$ref.replace("#/definitions/","");n=e.definitions[s]||e}return this._flattenSchema(n,t)}_flattenSchema(e,t=""){if(!e||typeof e!="object")return[];let n=[],s=e.properties||{},o=e.required||[];for(let[i,a]of Object.entries(s)){let u=t?`${t}.${i}`:i;n.push({path:u,type:a.type||"unknown",label:a.description||this._formatLabel(i),optional:!o.includes(i)}),a.type==="object"&&a.properties&&n.push(...this._flattenSchema(a,u)),a.type==="array"&&a.items?.type==="object"&&a.items.properties&&n.push(...this._flattenSchema(a.items,`${u}[]`))}return n}_formatLabel(e){return e.replace(/([A-Z])/g," $1").replace(/^./,t=>t.toUpperCase()).trim()}_summarizeNodeOutput(e,t){if(!t||typeof t!="object")return[];let n=[];t.success!==void 0&&n.push(`Result: ${t.success?"passed":"failed"}`);for(let[s,o]of Object.entries(t))if(!(s==="success"||s==="raw"||s==="nextNode")){if(typeof o=="string"&&o.length<=80)n.push(`${s}: ${o}`);else if(Array.isArray(o)){let i=o.length,a=o.filter(p=>p?.passed===!0).length,u=o.some(p=>p?.passed!==void 0);n.push(u?`${s}: ${a}/${i} passed${i-a?`, ${i-a} failed`:""}`:`${s}: ${i} items`)}if(n.length>=4)break}return n}async run(e,t={},n={}){if(!this.entryPoint)throw new Error("No entry point set for graph");if(e&&typeof e.normalizeInput=="function"&&t&&typeof t=="object"&&!Array.isArray(t))try{t=e.normalizeInput(t)??t}catch(y){let g=new Error(`agent.normalizeInput() rejected the trigger input: ${y?.message||y}`);throw g.cause=y,g.code=y?.code||"NORMALIZE_INPUT_FAILED",g}let s=new AbortController;n.signal&&(n.signal.aborted?s.abort():n.signal.addEventListener("abort",()=>s.abort(),{once:!0}));let o=n.strategyAbortTimeoutMs??t.config?.strategyAbortTimeoutMs??5e3,i=t.cwd||process.cwd();Tn({path:z(i,".env")});let a=t.config||{};if(!a||Object.keys(a).length===0)try{let y=z(i,".zibby.config.js");Be(y)&&(a=(await import(y)).default||{})}catch{}process.env.EXECUTION_ID&&!a.agent?.strictMode&&(a.agent={...a.agent,strictMode:!0});let u=t.agentType;if(!u){let y=a?.agent;y?.provider?u=y.provider:y?.gemini?u="gemini":y?.claude?u="claude":y?.cursor?u="cursor":y?.codex?u="codex":u=process.env.AGENT_TYPE||"claude"}let p=t.contextConfig||e?.config?.contextConfig||e?.config?.context||a?.context||{},w=this._runtimeSchema();if(w){let y=w.safeParse(t);if(!y.success){let g=y.error.issues.map(C=>`${C.path.join(".")}: ${C.message}`);throw console.error("\u274C Initial state validation failed:"),g.forEach(C=>console.error(` - ${C}`)),new Error(`State validation failed: ${g.join(", ")}`)}P.step("State validated against schema")}let c=Pn(),l=t.sessionPath||c;l||Nn();let{sessionPath:m,sessionTimestamp:S,sessionId:A}=Cn({cwd:i,config:a,traceFrom:"WorkflowGraph.run",initialState:{sessionPath:l,sessionTimestamp:t.sessionTimestamp}});P.step(`Session ${A}`);let T=await fe.loadContext(t.specPath||"",i,p);Object.keys(T).length>0&&P.step(`Context loaded: ${Object.keys(T).join(", ")}`);let v=t.outputPath;!v&&t.specPath&&(e?.calculateOutputPath?v=e.calculateOutputPath(t.specPath):console.warn(`\u26A0\uFE0F outputPath not resolved (specPath=${t.specPath})`));let f=new ae({...t,config:a,agentType:u,outputPath:v,sessionPath:m,sessionTimestamp:S,context:T,resolvedTools:this.resolvedToolsMap||{},_signal:s.signal}),h=new Map;try{await import("@zibby/skills")}catch{}let{getSkill:_}=await Promise.resolve().then(()=>(ve(),tt)),d=a.skills&&typeof a.skills=="object"?a.skills:{},b=Object.values(d).filter(y=>y&&typeof y=="object"&&typeof y.id=="string"),I=y=>{for(let g of b)if(g.id===y)return g;return _(y)},E=new Set;for(let[,y]of this.nodes)for(let g of y.config?.skills||[])E.add(g);for(let y of E){let g=I(y);if(typeof g?.middleware=="function")try{let C=await g.middleware();typeof C=="function"&&h.set(y,C)}catch{}}let{backEdges:kt,joinDegree:Ot}=this._analyzeFlow(),ge=new Map,K=[],me=(y,g,C)=>{if(!y||y==="END")return;let j=Ot.get(y)||0;if(C&&j>1&&!kt.has(`${g}->${y}`)){let V=(ge.get(y)||0)+1;if(V<j){ge.set(y,V);return}ge.set(y,0)}K.includes(y)||K.push(y)};this.entryPoint&&K.push(this.entryPoint);let re=[],Ce=a?.recursionLimit??100,xt=0;try{for(;K.length>0;){let g=K.pop();if(!g||g==="END")continue;if(++xt>Ce)throw new Error(`Workflow exceeded recursion limit (${Ce}) \u2014 the cap counts NODE EXECUTIONS, so this is either a cyclic conditional route or a graph whose branches total more nodes than the cap. Set config.recursionLimit if you need a higher cap.`);let C=z(m,Xe);if(Be(C)){try{An(C)}catch{}s.abort()}if(s.signal.aborted)return console.warn(`
|
|
42
|
-
\u{1F6D1} External stop requested \u2014 ending workflow.`),P.step("Workflow stopped externally"),{success:!0,state:f.getAll(),executionLog:re,stoppedExternally:!0};let j=this.nodes.get(g);if(!j)throw new Error(`Node '${g}' not found in graph`);let V=JSON.stringify({sessionPath:m,sessionTimestamp:S,currentNode:g,createdAt:new Date().toISOString(),config:f.get("config")}),Pt=z(m,Z);Et(Pt,V,"utf-8");let Me=f.get("config")?.paths?.output||ue,Nt=z(i,Me,Z);At(z(i,Me),{recursive:!0});try{Et(Nt,V,"utf-8")}catch{}let je=t.onPipelineProgress;if(typeof je=="function")try{je({cwd:i,sessionPath:m,sessionId:A,outputBase:f.get("config")?.paths?.output||ue,currentNode:g})}catch{}let Rt=(this.resolvedToolsMap||{})[g]||null;f.set("_currentNodeTools",Rt);let Bt=f.get("nodeConfigs")||{};f.set("_currentNodeConfig",Bt[g]||{}),P.nodeStart(g);let De=Date.now(),se=this.nodePrompts.get(g);if(!this._invokeAgent){let O=await Promise.resolve().then(()=>(ke(),Te));this._invokeAgent=O.invokeAgent}let Ct=this._invokeAgent,ye={},Mt=j.config?.skills||[];for(let O of Mt){let R=I(O);if(typeof R?.invokeAgentOptions=="function")try{let k=R.invokeAgentOptions(f.getAll(),{agentType:f.get("agentType"),nodeName:g});k&&typeof k=="object"&&(ye={...ye,...k})}catch(k){console.warn(`[graph] skill '${O}' invokeAgentOptions threw: ${k.message}`)}}let Le=async(O,R,k={})=>{let M=Ct(O,R,{...ye,...k,signal:s.signal});return M.catch(()=>{}),s.signal.aborted?M:Promise.race([M,new Promise((Y,D)=>{let B=()=>{setTimeout(()=>{let X=new Error(`Strategy ignored AbortSignal \u2014 engine deadman fired after ${o}ms`);X.name="AbortError",D(X)},o)};s.signal.addEventListener("abort",B,{once:!0})})])},jt=async(O={},R={})=>{let k=R.prompt||"";if(se){let M=this._compiledPrompts.get(g);M||(M=kn.compile(se,{noEscape:!0}),this._compiledPrompts.set(g,M));try{k=M(O)}catch(Y){throw console.error(`\u274C Template rendering failed for node '${g}':`,Y.message),new Error(`Template rendering failed: ${Y.message}`,{cause:Y})}}else if(!k)throw new Error(`No prompt template configured for node '${g}' and no prompt provided in options`);return Le(k,{state:f.getAll(),images:R.images||[]},{model:R.model||f.get("model"),workspace:f.get("workspace"),schema:R.schema,...R,signal:s.signal})},We=f.getAll(),Dt=["state","invokeAgent","_coreInvokeAgent","agent","nodeId","promptTemplate","getPromptTemplate"];for(let O of Dt)Object.prototype.hasOwnProperty.call(We,O)&&console.warn(`[workflow] node "${g}": state key "${O}" is shadowed by the engine context prop; read it via context.state.get('${O}')`);let Ue={...We,state:f,invokeAgent:jt,_coreInvokeAgent:Le,agent:e,nodeId:g,promptTemplate:se,getPromptTemplate:()=>se};try{let O=(j.config?.skills||[]).map(B=>h.get(B)).filter(Boolean),R=[...this.middleware,...O],k;k=await ct(e,s.signal,async()=>R.length>0?this._composeMiddleware(R,g,async()=>j.execute(Ue,f),f.getAll(),f):j.execute(Ue,f));let M=Date.now()-De;if(re.push({node:g,success:k.success,duration:M,timestamp:new Date().toISOString()}),!k.success){if(s.signal.aborted)return P.step("Workflow stopped externally"),{success:!0,state:f.getAll(),executionLog:re,stoppedExternally:!0};f.append("errors",{node:g,error:k.error});let B=j.config?.retries||0,X=`${g}_retries`,oe=f.getAll()[X]||0;if(oe<B){P.stepInfo(`Retrying (attempt ${oe+1}/${B})`),f.update({[X]:oe+1,[`${g}_raw`]:k.raw});continue}throw P.nodeFailed(g,k.error,{duration:M}),new Error(`Node '${g}' failed after ${oe} attempts: ${k.error}`)}f.update({[g]:k.output});let Y=this._summarizeNodeOutput(g,k.output);P.nodeComplete(g,{duration:M,details:Y});let D=this.edges.get(g);if(D)if(D.conditional){let B=D.routes(f.getAll());P.route(g,B),me(B,g,!1)}else if(Array.isArray(D))for(let B=D.length-1;B>=0;B--)me(D[B],g,!0);else me(D,g,!0)}catch(O){throw P.isInsideNode&&P.nodeFailed(g,O.message,{duration:Date.now()-De}),f.set("failed",!0),f.set("failedAt",g),O}}P.graphComplete();let y={success:!0,state:f.getAll(),executionLog:re};return e&&typeof e.onComplete=="function"&&await e.onComplete(y),y}finally{if(e&&typeof e.cleanup=="function")try{await e.cleanup()}catch(y){console.warn(`[workflow] agent.cleanup() failed: ${y.message}`)}}}};export{vt as WorkflowGraph,Nn as clearInheritedSessionEnvForFreshRun,Bn as generateWorkflowSessionId,Pn as readPinnedSessionPathFromEnv,Cn as resolveWorkflowSession,xn as shouldTrustInheritedSessionEnv,Rn as syncProcessEnvToSession};
|
|
42
|
+
\u{1F6D1} External stop requested \u2014 ending workflow.`),P.step("Workflow stopped externally"),{success:!0,state:f.getAll(),executionLog:re,stoppedExternally:!0};let j=this.nodes.get(g);if(!j)throw new Error(`Node '${g}' not found in graph`);let V=JSON.stringify({sessionPath:m,sessionTimestamp:S,currentNode:g,createdAt:new Date().toISOString(),config:f.get("config")}),Pt=z(m,Z);Et(Pt,V,"utf-8");let Me=f.get("config")?.paths?.output||ue,Nt=z(i,Me,Z);At(z(i,Me),{recursive:!0});try{Et(Nt,V,"utf-8")}catch{}let je=t.onPipelineProgress;if(typeof je=="function")try{je({cwd:i,sessionPath:m,sessionId:A,outputBase:f.get("config")?.paths?.output||ue,currentNode:g})}catch{}let Rt=(this.resolvedToolsMap||{})[g]||null;f.set("_currentNodeTools",Rt);let Bt=f.get("nodeConfigs")||{};f.set("_currentNodeConfig",Bt[g]||{}),P.nodeStart(g);let De=Date.now(),se=this.nodePrompts.get(g);if(!this._invokeAgent){let O=await Promise.resolve().then(()=>(ke(),Te));this._invokeAgent=O.invokeAgent}let Ct=this._invokeAgent,ye={},Mt=j.config?.skills||[];for(let O of Mt){let R=I(O);if(typeof R?.invokeAgentOptions=="function")try{let k=R.invokeAgentOptions(f.getAll(),{agentType:f.get("agentType"),nodeName:g});k&&typeof k=="object"&&(ye={...ye,...k})}catch(k){console.warn(`[graph] skill '${O}' invokeAgentOptions threw: ${k.message}`)}}let Le=async(O,R,k={})=>{let M=Ct(O,R,{...ye,...k,signal:s.signal});return M.catch(()=>{}),s.signal.aborted?M:Promise.race([M,new Promise((Y,D)=>{let B=()=>{setTimeout(()=>{let X=new Error(`Strategy ignored AbortSignal \u2014 engine deadman fired after ${o}ms`);X.name="AbortError",D(X)},o)};s.signal.addEventListener("abort",B,{once:!0})})])},jt=async(O={},R={})=>{let k=R.prompt||"";if(se){let M=this._compiledPrompts.get(g);M||(M=kn.compile(se,{noEscape:!0}),this._compiledPrompts.set(g,M));try{k=M(O)}catch(Y){throw console.error(`\u274C Template rendering failed for node '${g}':`,Y.message),new Error(`Template rendering failed: ${Y.message}`,{cause:Y})}}else if(!k)throw new Error(`No prompt template configured for node '${g}' and no prompt provided in options`);return Le(k,{state:f.getAll(),images:R.images||[]},{model:R.model||f.get("model"),workspace:f.get("workspace"),schema:R.schema,...R,signal:s.signal,nodeName:g})},We=f.getAll(),Dt=["state","invokeAgent","_coreInvokeAgent","agent","nodeId","promptTemplate","getPromptTemplate"];for(let O of Dt)Object.prototype.hasOwnProperty.call(We,O)&&console.warn(`[workflow] node "${g}": state key "${O}" is shadowed by the engine context prop; read it via context.state.get('${O}')`);let Ue={...We,state:f,invokeAgent:jt,_coreInvokeAgent:Le,agent:e,nodeId:g,promptTemplate:se,getPromptTemplate:()=>se};try{let O=(j.config?.skills||[]).map(B=>h.get(B)).filter(Boolean),R=[...this.middleware,...O],k;k=await ct(e,s.signal,async()=>R.length>0?this._composeMiddleware(R,g,async()=>j.execute(Ue,f),f.getAll(),f):j.execute(Ue,f));let M=Date.now()-De;if(re.push({node:g,success:k.success,duration:M,timestamp:new Date().toISOString()}),!k.success){if(s.signal.aborted)return P.step("Workflow stopped externally"),{success:!0,state:f.getAll(),executionLog:re,stoppedExternally:!0};f.append("errors",{node:g,error:k.error});let B=j.config?.retries||0,X=`${g}_retries`,oe=f.getAll()[X]||0;if(oe<B){P.stepInfo(`Retrying (attempt ${oe+1}/${B})`),f.update({[X]:oe+1,[`${g}_raw`]:k.raw});continue}throw P.nodeFailed(g,k.error,{duration:M}),new Error(`Node '${g}' failed after ${oe} attempts: ${k.error}`)}f.update({[g]:k.output});let Y=this._summarizeNodeOutput(g,k.output);P.nodeComplete(g,{duration:M,details:Y});let D=this.edges.get(g);if(D)if(D.conditional){let B=D.routes(f.getAll());P.route(g,B),me(B,g,!1)}else if(Array.isArray(D))for(let B=D.length-1;B>=0;B--)me(D[B],g,!0);else me(D,g,!0)}catch(O){throw P.isInsideNode&&P.nodeFailed(g,O.message,{duration:Date.now()-De}),f.set("failed",!0),f.set("failedAt",g),O}}P.graphComplete();let y={success:!0,state:f.getAll(),executionLog:re};return e&&typeof e.onComplete=="function"&&await e.onComplete(y),y}finally{if(e&&typeof e.cleanup=="function")try{await e.cleanup()}catch(y){console.warn(`[workflow] agent.cleanup() failed: ${y.message}`)}}}};export{vt as WorkflowGraph,Nn as clearInheritedSessionEnvForFreshRun,Bn as generateWorkflowSessionId,Pn as readPinnedSessionPathFromEnv,Cn as resolveWorkflowSession,xn as shouldTrustInheritedSessionEnv,Rn as syncProcessEnvToSession};
|
package/dist/index.js
CHANGED
|
@@ -39,7 +39,7 @@ ${i}`);let a=n(),l=a.cwd||process.cwd(),u=a.sessionPath;try{if(u){let d=ze(u,G);
|
|
|
39
39
|
`).slice(2,14).join(`
|
|
40
40
|
`);console.log(`[zibby:session] stack (${o}):
|
|
41
41
|
${m}`)}}function Xt(){return process.env.ZIBBY_TRUST_SESSION_ENV==="1"||process.env.ZIBBY_TRUST_SESSION_ENV==="true"||process.env.ZIBBY_KEEP_SESSION_ENV==="1"||process.env.ZIBBY_KEEP_SESSION_ENV==="true"}function Qt(){if(!(process.env.ZIBBY_PIN_SESSION_PATH==="1"||process.env.ZIBBY_PIN_SESSION_PATH==="true"))return;let e=process.env.ZIBBY_SESSION_PATH;if(!(e==null||String(e).trim()===""))try{return qt(String(e).trim())}catch{return String(e).trim()}}function eo(){Xt()||(delete process.env.ZIBBY_SESSION_PATH,delete process.env.ZIBBY_SESSION_ID)}function to({sessionPath:o,sessionId:e}){o&&typeof o=="string"&&(process.env.ZIBBY_SESSION_PATH=o),e!=null&&String(e).trim()!==""&&(process.env.ZIBBY_SESSION_ID=String(e).trim())}function oo(o={}){let e=Me.map(i=>process.env[i]).find(Boolean),t=Math.random().toString(36).slice(2,6),n=e||`${Date.now()}_${t}`,r=o.paths?.sessionPrefix;return r?`${r}_${n}`:n}function no({cwd:o=process.cwd(),config:e={},initialState:t={},traceFrom:n="resolveWorkflowSession"}={}){let r=t.sessionPath,i=t.sessionTimestamp,s="initialState.sessionPath";if(!r&&process.env.ZIBBY_SESSION_PATH)try{let u=qt(String(process.env.ZIBBY_SESSION_PATH));u&&(r=u,s="ZIBBY_SESSION_PATH")}catch{}let a;if(r)a=String(r).split(/[/\\]/).filter(Boolean).pop(),i==null&&(i=Date.now());else{let u=process.env.ZIBBY_SESSION_ID&&String(process.env.ZIBBY_SESSION_ID).trim();if(u)a=u,s="ZIBBY_SESSION_ID";else{let d=e.sessionId!=null?String(e.sessionId).trim():"";d&&d!=="last"?(a=d,s="config.sessionId"):(a=oo(e),s="generated")}i=i??Date.now();let m=e.paths?.output||ce;r=K(o,m,Ce,a)}let l=!Ve(r);return l&&Vt(r,{recursive:!0}),(l||s!=="initialState.sessionPath")&&nn({traceFrom:n,sessionId:a,sessionPath:r,idSource:s,mkdirFresh:l}),to({sessionPath:r,sessionId:a}),{sessionPath:r,sessionId:a,sessionTimestamp:i}}var ee=class{constructor(e={}){this.nodes=new Map,this.edges=new Map,this.entryPoint=null,this.middleware=Array.isArray(e.middleware)?[...e.middleware]:[],e.nodeMiddleware&&this.middleware.push(e.nodeMiddleware),this.nodeTypeMap=new Map,this.conditionalCodeMap=new Map,this.stateSchema=e.stateSchema||null,this.inputSchema=e.inputSchema||null,this.contextSchema=e.contextSchema||null,this.nodePrompts=new Map,this.nodeOptions=new Map,this._invokeAgent=e.invokeAgent||null,this._compiledPrompts=new Map}setInputSchema(e){return this.inputSchema=e,this}setContextSchema(e){return this.contextSchema=e,this}setStateSchema(e){return this.stateSchema=e,this}getInputSchema(){return this.inputSchema}getContextSchema(){return this.contextSchema}getStateSchema(){return this.stateSchema}_runtimeSchema(){if(this.inputSchema&&this.contextSchema)try{if(typeof this.inputSchema.merge=="function")return this.inputSchema.merge(this.contextSchema);if(typeof this.inputSchema.and=="function")return this.inputSchema.and(this.contextSchema)}catch{}return this.inputSchema&&!this.contextSchema?this.inputSchema:this.stateSchema}addNode(e,t,n={}){if(!(t instanceof F)&&t&&typeof t=="object"&&typeof t.workflow=="string"){let s=t,a={name:e,_isCustomCode:!0,dispatchesWorkflow:s.workflow,retries:s.retries,onComplete:s.onComplete,execute:async u=>{let m=u?.state&&typeof u.state.getAll=="function"?u.state.getAll():u,d;return typeof s.input=="function"?d=s.input(m):s.input&&typeof s.input=="object"?d=s.input:d={},Ze(s.workflow,{input:d,async:s.async===!0,conversationId:typeof s.conversationId=="function"?s.conversationId(m):s.conversationId,output:s.output,timeoutMs:s.timeoutMs,pollIntervalMs:s.pollIntervalMs,signal:m?._signal,parentAgent:u?.agent})}},l=new F(a);return l.name=e,this.nodes.set(e,l),n.prompt&&this.nodePrompts.set(e,n.prompt),Object.keys(n).length>0&&this.nodeOptions.set(e,n),this}let r=!(t instanceof F)&&t&&typeof t=="object"&&typeof t.execute!="function"&&t.prompt==null&&t.outputSchema==null&&t._isCustomCode!==!0,i=t instanceof F?t:new F(r?{...t,_isRouter:!0}:t);return i.name=e,this.nodes.set(e,i),n.prompt?this.nodePrompts.set(e,n.prompt):typeof t?.prompt=="string"&&t.prompt.trim()&&this.nodePrompts.set(e,t.prompt),Object.keys(n).length>0&&this.nodeOptions.set(e,n),this}addEdge(e,t){let n=this.edges.get(e);return n===void 0?this.edges.set(e,t):typeof n=="string"?n!==t&&this.edges.set(e,[n,t]):Array.isArray(n)?n.includes(t)||n.push(t):(console.warn(`[workflow] addEdge('${e}', '${t}') overrides the conditional edges already declared on '${e}'. A node routes EITHER unconditionally (addEdge) OR conditionally (addConditionalEdges) \u2014 not both.`),this.edges.set(e,t)),this}setNodeType(e,t){return this.nodeTypeMap.set(e,t),this}addConditionalEdges(e,t,{labels:n}={}){let r=this.edges.get(e);return r!==void 0&&!r.conditional&&console.warn(`[workflow] addConditionalEdges('${e}', \u2026) overrides the unconditional edge(s) already declared on '${e}' (${Array.isArray(r)?r.join(", "):r}). A node routes EITHER unconditionally OR conditionally \u2014 not both.`),this.edges.set(e,{conditional:!0,routes:t,labels:n}),typeof t=="function"&&this.conditionalCodeMap.set(e,t.toString()),this}setEntryPoint(e){return this.entryPoint=e,this}_simpleTargets(e){let t=this.edges.get(e);return t===void 0?[]:typeof t=="string"?[t]:Array.isArray(t)?t:[]}_analyzeFlow(){let e=new Set,t=new Map,n=i=>{t.set(i,1);for(let s of this._simpleTargets(i)){if(!s||s==="END")continue;let a=t.get(s)||0;a===1?e.add(`${i}->${s}`):a===0&&n(s)}t.set(i,2)};this.entryPoint&&n(this.entryPoint);let r=new Map;for(let[i]of this.edges)for(let s of this._simpleTargets(i))!s||s==="END"||e.has(`${i}->${s}`)||r.set(s,(r.get(s)||0)+1);return{backEdges:e,joinDegree:r}}use(e){return typeof e=="function"&&this.middleware.push(e),this}_composeMiddleware(e,t,n,r,i){let s=n;for(let a=e.length-1;a>=0;a--){let l=e[a],u=s;s=()=>l(t,u,r,i)}return s()}serialize(){let e=[],t={};for(let[d,c]of this.nodes){let y=this.nodeTypeMap.get(d)||(c?.config?._isRouter===!0?"decision":d);e.push({id:d,type:y,data:{nodeType:y,label:d}});let g={};c._isCustomCode&&typeof c.execute=="function"&&(g.customCode=c.execute.toString());let _=typeof c?.config?.description=="string"&&c.config.description.trim()?c.config.description:typeof c?.description=="string"&&c.description.trim()?c.description:null;_&&(g.description=_);let I=this.nodePrompts.get(d);if(I)g.prompt=I;else if(typeof c.prompt=="function")try{let p=c.prompt({});typeof p=="string"&&p.trim()&&(g.prompt=p,g.promptIsCode=!0)}catch{}if(typeof c.customExecute=="function"&&(g.executeCode=c.customExecute.toString()),typeof c?.config?.dispatchesWorkflow=="string"&&c.config.dispatchesWorkflow.trim()&&(g.dispatchesWorkflow=c.config.dispatchesWorkflow.trim()),typeof c?.config?.agent=="string"&&c.config.agent.trim()&&(g.agent=c.config.agent.trim()),c.outputSchema)if(typeof c.outputSchema._def<"u"){let p=null;if(typeof Ee?.toJSONSchema=="function")try{p=Ee.toJSONSchema(c.outputSchema)}catch{}if(!p)try{p=Kt(c.outputSchema,{target:"openApi3"})}catch{}g.outputSchema=p?{jsonSchema:p,variables:this._flattenJsonSchemaToVariables(p)}:{schema:c.outputSchema}}else g.outputSchema={schema:c.outputSchema};let b=(this.resolvedToolsMap||{})[d];b?.toolIds&&(g.tools=b.toolIds);let f=Array.isArray(c?.config?.skills)?c.config.skills:Array.isArray(c?.skills)?c.skills:null;f&&f.length>0&&(g.skills=[...f]);let h=Array.isArray(c?.config?.plugins)?c.config.plugins:Array.isArray(c?.plugins)?c.plugins:null;h&&h.length>0&&(g.plugins=h.map(p=>p&&typeof p=="object"?{...p}:p));let v=Array.isArray(c?.config?.stores)?c.config.stores:Array.isArray(c?.stores)?c.stores:null;v&&v.length>0&&(g.stores=v.map(p=>p&&typeof p=="object"?{...p}:p)),Object.keys(g).length>0&&(t[d]=g)}let n=[];for(let[d,c]of this.edges)if(typeof c=="string")n.push({source:d,target:c});else if(Array.isArray(c))for(let y of c)n.push({source:d,target:y});else if(c.conditional){let y=this.conditionalCodeMap.get(d)||c.routes.toString(),g=this._inferConditionalTargets(c.routes,c.labels),_=c.labels||{},I=this.nodes.get(d),b=I?.config?._isRouter===!0||this.nodeTypeMap.get(d)==="decision"||!I,f=d;if(!b){let h=`${d}__branch`;e.push({id:h,type:"decision",data:{nodeType:"decision",label:h}}),n.push({source:d,target:h}),f=h}for(let h of g){let v={source:f,target:h,data:{conditionalCode:y}};_[h]&&(v.label=_[h]),n.push(v)}}let r=d=>{if(!d)return null;if(typeof Ee?.toJSONSchema=="function")try{return Ee.toJSONSchema(d)}catch{}try{return Kt(d,{target:"openApi3"})}catch{return null}};this.entryPoint&&this.nodes.has(this.entryPoint)&&(e.unshift({id:"START",type:"start",data:{nodeType:"start",label:"Start"}}),n.unshift({source:"START",target:this.entryPoint}));let i=0;for(let d of n)if(d.target==="END"){i+=1;let c=`END__${i}`;d.target=c,e.push({id:c,type:"end",data:{nodeType:"end",label:"End"}})}for(let d of this.nodes.keys())if(!this.edges.has(d)){i+=1;let c=`END__${i}`;e.push({id:c,type:"end",data:{nodeType:"end",label:"End"}}),n.push({source:d,target:c})}let s=this._topoOrderNodes(e,n),a=this._runtimeSchema(),l=r(a||this.stateSchema),u=r(this.inputSchema),m=r(this.contextSchema);return{nodes:s,edges:n,nodeConfigs:t,stateSchema:l,inputSchema:u,contextSchema:m}}_topoOrderNodes(e,t){let n=new Map(e.map((d,c)=>[d.id,c])),r=new Map(e.map(d=>[d.id,d])),i=new Map(e.map(d=>[d.id,0])),s=new Map(e.map(d=>[d.id,[]]));for(let d of t)s.has(d.source)&&i.has(d.target)&&(s.get(d.source).push(d.target),i.set(d.target,i.get(d.target)+1));let a=new Set,l=new Set(n.keys()),u=[...l].filter(d=>i.get(d)===0),m=[];for(;m.length<e.length;){let d;if(u.length>0){if(u.sort((c,y)=>n.get(c)-n.get(y)),d=u.shift(),a.has(d))continue}else d=[...l].sort((c,y)=>n.get(c)-n.get(y))[0];a.add(d),l.delete(d),m.push(r.get(d));for(let c of s.get(d)||[])i.set(c,i.get(c)-1),i.get(c)<=0&&!a.has(c)&&u.push(c)}return m}_inferConditionalTargets(e,t){let n=e.toString(),r=new Set,i=/(['"])((?:\\.|(?!\1).)*?)\1|`((?:\\.|[^`$]|\$(?!\{))*?)`/g,s;for(;(s=i.exec(n))!==null;){let u=s[2]!==void 0?s[2]:s[3];u!==void 0&&u!==""&&r.add(u)}let a=new Set(["END","START","__end__","__start__"]);for(let u of this.nodes.keys())a.add(u);if(t&&typeof t=="object")for(let u of Object.keys(t))a.add(u);let l=new Set;for(let u of r)a.has(u)&&l.add(u);if(l.size===0){let u=/return\s+['"]([^'"]+)['"]/g,m;for(;(m=u.exec(n))!==null;)l.add(m[1])}return[...l]}_flattenJsonSchemaToVariables(e,t=""){let n=e;if(e.$ref&&e.definitions){let r=e.$ref.replace("#/definitions/","");n=e.definitions[r]||e}return this._flattenSchema(n,t)}_flattenSchema(e,t=""){if(!e||typeof e!="object")return[];let n=[],r=e.properties||{},i=e.required||[];for(let[s,a]of Object.entries(r)){let l=t?`${t}.${s}`:s;n.push({path:l,type:a.type||"unknown",label:a.description||this._formatLabel(s),optional:!i.includes(s)}),a.type==="object"&&a.properties&&n.push(...this._flattenSchema(a,l)),a.type==="array"&&a.items?.type==="object"&&a.items.properties&&n.push(...this._flattenSchema(a.items,`${l}[]`))}return n}_formatLabel(e){return e.replace(/([A-Z])/g," $1").replace(/^./,t=>t.toUpperCase()).trim()}_summarizeNodeOutput(e,t){if(!t||typeof t!="object")return[];let n=[];t.success!==void 0&&n.push(`Result: ${t.success?"passed":"failed"}`);for(let[r,i]of Object.entries(t))if(!(r==="success"||r==="raw"||r==="nextNode")){if(typeof i=="string"&&i.length<=80)n.push(`${r}: ${i}`);else if(Array.isArray(i)){let s=i.length,a=i.filter(u=>u?.passed===!0).length,l=i.some(u=>u?.passed!==void 0);n.push(l?`${r}: ${a}/${s} passed${s-a?`, ${s-a} failed`:""}`:`${r}: ${s} items`)}if(n.length>=4)break}return n}async run(e,t={},n={}){if(!this.entryPoint)throw new Error("No entry point set for graph");if(e&&typeof e.normalizeInput=="function"&&t&&typeof t=="object"&&!Array.isArray(t))try{t=e.normalizeInput(t)??t}catch(S){let w=new Error(`agent.normalizeInput() rejected the trigger input: ${S?.message||S}`);throw w.cause=S,w.code=S?.code||"NORMALIZE_INPUT_FAILED",w}let r=new AbortController;n.signal&&(n.signal.aborted?r.abort():n.signal.addEventListener("abort",()=>r.abort(),{once:!0}));let i=n.strategyAbortTimeoutMs??t.config?.strategyAbortTimeoutMs??5e3,s=t.cwd||process.cwd();tn({path:K(s,".env")});let a=t.config||{};if(!a||Object.keys(a).length===0)try{let S=K(s,".zibby.config.js");Ve(S)&&(a=(await import(S)).default||{})}catch{}process.env.EXECUTION_ID&&!a.agent?.strictMode&&(a.agent={...a.agent,strictMode:!0});let l=t.agentType;if(!l){let S=a?.agent;S?.provider?l=S.provider:S?.gemini?l="gemini":S?.claude?l="claude":S?.cursor?l="cursor":S?.codex?l="codex":l=process.env.AGENT_TYPE||"claude"}let u=t.contextConfig||e?.config?.contextConfig||e?.config?.context||a?.context||{},m=this._runtimeSchema();if(m){let S=m.safeParse(t);if(!S.success){let w=S.error.issues.map(M=>`${M.path.join(".")}: ${M.message}`);throw console.error("\u274C Initial state validation failed:"),w.forEach(M=>console.error(` - ${M}`)),new Error(`State validation failed: ${w.join(", ")}`)}N.step("State validated against schema")}let d=Qt(),c=t.sessionPath||d;c||eo();let{sessionPath:y,sessionTimestamp:g,sessionId:_}=no({cwd:s,config:a,traceFrom:"WorkflowGraph.run",initialState:{sessionPath:c,sessionTimestamp:t.sessionTimestamp}});N.step(`Session ${_}`);let I=await fe.loadContext(t.specPath||"",s,u);Object.keys(I).length>0&&N.step(`Context loaded: ${Object.keys(I).join(", ")}`);let b=t.outputPath;!b&&t.specPath&&(e?.calculateOutputPath?b=e.calculateOutputPath(t.specPath):console.warn(`\u26A0\uFE0F outputPath not resolved (specPath=${t.specPath})`));let f=new re({...t,config:a,agentType:l,outputPath:b,sessionPath:y,sessionTimestamp:g,context:I,resolvedTools:this.resolvedToolsMap||{},_signal:r.signal}),h=new Map;try{await import("@zibby/skills")}catch{}let{getSkill:v}=await Promise.resolve().then(()=>(de(),kt)),p=a.skills&&typeof a.skills=="object"?a.skills:{},$=Object.values(p).filter(S=>S&&typeof S=="object"&&typeof S.id=="string"),T=S=>{for(let w of $)if(w.id===S)return w;return v(S)},k=new Set;for(let[,S]of this.nodes)for(let w of S.config?.skills||[])k.add(w);for(let S of k){let w=T(S);if(typeof w?.middleware=="function")try{let M=await w.middleware();typeof M=="function"&&h.set(S,M)}catch{}}let{backEdges:ao,joinDegree:co}=this._analyzeFlow(),Te=new Map,te=[],ke=(S,w,M)=>{if(!S||S==="END")return;let D=co.get(S)||0;if(M&&D>1&&!ao.has(`${w}->${S}`)){let oe=(Te.get(S)||0)+1;if(oe<D){Te.set(S,oe);return}Te.set(S,0)}te.includes(S)||te.push(S)};this.entryPoint&&te.push(this.entryPoint);let ge=[],nt=a?.recursionLimit??100,lo=0;try{for(;te.length>0;){let w=te.pop();if(!w||w==="END")continue;if(++lo>nt)throw new Error(`Workflow exceeded recursion limit (${nt}) \u2014 the cap counts NODE EXECUTIONS, so this is either a cyclic conditional route or a graph whose branches total more nodes than the cap. Set config.recursionLimit if you need a higher cap.`);let M=K(y,Re);if(Ve(M)){try{en(M)}catch{}r.abort()}if(r.signal.aborted)return console.warn(`
|
|
42
|
-
\u{1F6D1} External stop requested \u2014 ending workflow.`),N.step("Workflow stopped externally"),{success:!0,state:f.getAll(),executionLog:ge,stoppedExternally:!0};let D=this.nodes.get(w);if(!D)throw new Error(`Node '${w}' not found in graph`);let oe=JSON.stringify({sessionPath:y,sessionTimestamp:g,currentNode:w,createdAt:new Date().toISOString(),config:f.get("config")}),uo=K(y,G);Zt(uo,oe,"utf-8");let rt=f.get("config")?.paths?.output||ce,po=K(s,rt,G);Vt(K(s,rt),{recursive:!0});try{Zt(po,oe,"utf-8")}catch{}let st=t.onPipelineProgress;if(typeof st=="function")try{st({cwd:s,sessionPath:y,sessionId:_,outputBase:f.get("config")?.paths?.output||ce,currentNode:w})}catch{}let fo=(this.resolvedToolsMap||{})[w]||null;f.set("_currentNodeTools",fo);let ho=f.get("nodeConfigs")||{};f.set("_currentNodeConfig",ho[w]||{}),N.nodeStart(w);let it=Date.now(),me=this.nodePrompts.get(w);if(!this._invokeAgent){let x=await Promise.resolve().then(()=>(X(),ue));this._invokeAgent=x.invokeAgent}let go=this._invokeAgent,Ae={},mo=D.config?.skills||[];for(let x of mo){let C=T(x);if(typeof C?.invokeAgentOptions=="function")try{let A=C.invokeAgentOptions(f.getAll(),{agentType:f.get("agentType"),nodeName:w});A&&typeof A=="object"&&(Ae={...Ae,...A})}catch(A){console.warn(`[graph] skill '${x}' invokeAgentOptions threw: ${A.message}`)}}let at=async(x,C,A={})=>{let j=go(x,C,{...Ae,...A,signal:r.signal});return j.catch(()=>{}),r.signal.aborted?j:Promise.race([j,new Promise((V,L)=>{let R=()=>{setTimeout(()=>{let ne=new Error(`Strategy ignored AbortSignal \u2014 engine deadman fired after ${i}ms`);ne.name="AbortError",L(ne)},i)};r.signal.addEventListener("abort",R,{once:!0})})])},yo=async(x={},C={})=>{let A=C.prompt||"";if(me){let j=this._compiledPrompts.get(w);j||(j=on.compile(me,{noEscape:!0}),this._compiledPrompts.set(w,j));try{A=j(x)}catch(V){throw console.error(`\u274C Template rendering failed for node '${w}':`,V.message),new Error(`Template rendering failed: ${V.message}`,{cause:V})}}else if(!A)throw new Error(`No prompt template configured for node '${w}' and no prompt provided in options`);return at(A,{state:f.getAll(),images:C.images||[]},{model:C.model||f.get("model"),workspace:f.get("workspace"),schema:C.schema,...C,signal:r.signal})},ct=f.getAll(),wo=["state","invokeAgent","_coreInvokeAgent","agent","nodeId","promptTemplate","getPromptTemplate"];for(let x of wo)Object.prototype.hasOwnProperty.call(ct,x)&&console.warn(`[workflow] node "${w}": state key "${x}" is shadowed by the engine context prop; read it via context.state.get('${x}')`);let lt={...ct,state:f,invokeAgent:yo,_coreInvokeAgent:at,agent:e,nodeId:w,promptTemplate:me,getPromptTemplate:()=>me};try{let x=(D.config?.skills||[]).map(R=>h.get(R)).filter(Boolean),C=[...this.middleware,...x],A;A=await Rt(e,r.signal,async()=>C.length>0?this._composeMiddleware(C,w,async()=>D.execute(lt,f),f.getAll(),f):D.execute(lt,f));let j=Date.now()-it;if(ge.push({node:w,success:A.success,duration:j,timestamp:new Date().toISOString()}),!A.success){if(r.signal.aborted)return N.step("Workflow stopped externally"),{success:!0,state:f.getAll(),executionLog:ge,stoppedExternally:!0};f.append("errors",{node:w,error:A.error});let R=D.config?.retries||0,ne=`${w}_retries`,ye=f.getAll()[ne]||0;if(ye<R){N.stepInfo(`Retrying (attempt ${ye+1}/${R})`),f.update({[ne]:ye+1,[`${w}_raw`]:A.raw});continue}throw N.nodeFailed(w,A.error,{duration:j}),new Error(`Node '${w}' failed after ${ye} attempts: ${A.error}`)}f.update({[w]:A.output});let V=this._summarizeNodeOutput(w,A.output);N.nodeComplete(w,{duration:j,details:V});let L=this.edges.get(w);if(L)if(L.conditional){let R=L.routes(f.getAll());N.route(w,R),ke(R,w,!1)}else if(Array.isArray(L))for(let R=L.length-1;R>=0;R--)ke(L[R],w,!0);else ke(L,w,!0)}catch(x){throw N.isInsideNode&&N.nodeFailed(w,x.message,{duration:Date.now()-it}),f.set("failed",!0),f.set("failedAt",w),x}}N.graphComplete();let S={success:!0,state:f.getAll(),executionLog:ge};return e&&typeof e.onComplete=="function"&&await e.onComplete(S),S}finally{if(e&&typeof e.cleanup=="function")try{await e.cleanup()}catch(S){console.warn(`[workflow] agent.cleanup() failed: ${S.message}`)}}}};var qe=Symbol.for("@zibby/agent-workflow.nodes");globalThis[qe]||(globalThis[qe]=new Map);var he=globalThis[qe];function ro(o,e){he.set(o,e)}function Xe(o){return he.get(o)}function Ie(o){return he.has(o)}function rn(){return Array.from(he.keys())}function Qe(o){let e=he.get(o);return e?e.factory&&typeof e.create=="function"?e.create.toString():typeof e.execute=="function"?e.execute.toString():typeof e=="function"?e.toString():null:null}ro("ai_agent",{name:"ai_agent",factory:!0,create:(o,e={})=>({name:o,_isCustomCode:!0,execute:async t=>{let n=t?._coreInvokeAgent;n||(n=(await Promise.resolve().then(()=>(X(),ue))).invokeAgent);let r=e.extraPromptInstructions||"Execute the task based on the current state.",i=sn(r,t),s=await n(i,{cwd:t.workspace||process.cwd(),model:t.model,tools:e.resolvedTools||null});return{success:!0,output:{raw:s,nodeId:o},raw:typeof s=="string"?s:s.raw}}})});function sn(o,e){let t=/@([\w.]+)/g,n=new Set,r;for(;(r=t.exec(o))!==null;)n.add(r[1]);if(n.size===0)return o;let i=[],s=new Set;for(let a of n){let l=a.split(".")[0];if(s.has(l))continue;let u=a.split(".").reduce((c,y)=>c?.[y],e);if(u===void 0)continue;let m=typeof u=="string"?u:u?.raw??JSON.stringify(u,null,2),d=a.replace(/_/g," ").replace(/\b\w/g,c=>c.toUpperCase());i.push(`## ${d}
|
|
42
|
+
\u{1F6D1} External stop requested \u2014 ending workflow.`),N.step("Workflow stopped externally"),{success:!0,state:f.getAll(),executionLog:ge,stoppedExternally:!0};let D=this.nodes.get(w);if(!D)throw new Error(`Node '${w}' not found in graph`);let oe=JSON.stringify({sessionPath:y,sessionTimestamp:g,currentNode:w,createdAt:new Date().toISOString(),config:f.get("config")}),uo=K(y,G);Zt(uo,oe,"utf-8");let rt=f.get("config")?.paths?.output||ce,po=K(s,rt,G);Vt(K(s,rt),{recursive:!0});try{Zt(po,oe,"utf-8")}catch{}let st=t.onPipelineProgress;if(typeof st=="function")try{st({cwd:s,sessionPath:y,sessionId:_,outputBase:f.get("config")?.paths?.output||ce,currentNode:w})}catch{}let fo=(this.resolvedToolsMap||{})[w]||null;f.set("_currentNodeTools",fo);let ho=f.get("nodeConfigs")||{};f.set("_currentNodeConfig",ho[w]||{}),N.nodeStart(w);let it=Date.now(),me=this.nodePrompts.get(w);if(!this._invokeAgent){let x=await Promise.resolve().then(()=>(X(),ue));this._invokeAgent=x.invokeAgent}let go=this._invokeAgent,Ae={},mo=D.config?.skills||[];for(let x of mo){let C=T(x);if(typeof C?.invokeAgentOptions=="function")try{let A=C.invokeAgentOptions(f.getAll(),{agentType:f.get("agentType"),nodeName:w});A&&typeof A=="object"&&(Ae={...Ae,...A})}catch(A){console.warn(`[graph] skill '${x}' invokeAgentOptions threw: ${A.message}`)}}let at=async(x,C,A={})=>{let j=go(x,C,{...Ae,...A,signal:r.signal});return j.catch(()=>{}),r.signal.aborted?j:Promise.race([j,new Promise((V,L)=>{let R=()=>{setTimeout(()=>{let ne=new Error(`Strategy ignored AbortSignal \u2014 engine deadman fired after ${i}ms`);ne.name="AbortError",L(ne)},i)};r.signal.addEventListener("abort",R,{once:!0})})])},yo=async(x={},C={})=>{let A=C.prompt||"";if(me){let j=this._compiledPrompts.get(w);j||(j=on.compile(me,{noEscape:!0}),this._compiledPrompts.set(w,j));try{A=j(x)}catch(V){throw console.error(`\u274C Template rendering failed for node '${w}':`,V.message),new Error(`Template rendering failed: ${V.message}`,{cause:V})}}else if(!A)throw new Error(`No prompt template configured for node '${w}' and no prompt provided in options`);return at(A,{state:f.getAll(),images:C.images||[]},{model:C.model||f.get("model"),workspace:f.get("workspace"),schema:C.schema,...C,signal:r.signal,nodeName:w})},ct=f.getAll(),wo=["state","invokeAgent","_coreInvokeAgent","agent","nodeId","promptTemplate","getPromptTemplate"];for(let x of wo)Object.prototype.hasOwnProperty.call(ct,x)&&console.warn(`[workflow] node "${w}": state key "${x}" is shadowed by the engine context prop; read it via context.state.get('${x}')`);let lt={...ct,state:f,invokeAgent:yo,_coreInvokeAgent:at,agent:e,nodeId:w,promptTemplate:me,getPromptTemplate:()=>me};try{let x=(D.config?.skills||[]).map(R=>h.get(R)).filter(Boolean),C=[...this.middleware,...x],A;A=await Rt(e,r.signal,async()=>C.length>0?this._composeMiddleware(C,w,async()=>D.execute(lt,f),f.getAll(),f):D.execute(lt,f));let j=Date.now()-it;if(ge.push({node:w,success:A.success,duration:j,timestamp:new Date().toISOString()}),!A.success){if(r.signal.aborted)return N.step("Workflow stopped externally"),{success:!0,state:f.getAll(),executionLog:ge,stoppedExternally:!0};f.append("errors",{node:w,error:A.error});let R=D.config?.retries||0,ne=`${w}_retries`,ye=f.getAll()[ne]||0;if(ye<R){N.stepInfo(`Retrying (attempt ${ye+1}/${R})`),f.update({[ne]:ye+1,[`${w}_raw`]:A.raw});continue}throw N.nodeFailed(w,A.error,{duration:j}),new Error(`Node '${w}' failed after ${ye} attempts: ${A.error}`)}f.update({[w]:A.output});let V=this._summarizeNodeOutput(w,A.output);N.nodeComplete(w,{duration:j,details:V});let L=this.edges.get(w);if(L)if(L.conditional){let R=L.routes(f.getAll());N.route(w,R),ke(R,w,!1)}else if(Array.isArray(L))for(let R=L.length-1;R>=0;R--)ke(L[R],w,!0);else ke(L,w,!0)}catch(x){throw N.isInsideNode&&N.nodeFailed(w,x.message,{duration:Date.now()-it}),f.set("failed",!0),f.set("failedAt",w),x}}N.graphComplete();let S={success:!0,state:f.getAll(),executionLog:ge};return e&&typeof e.onComplete=="function"&&await e.onComplete(S),S}finally{if(e&&typeof e.cleanup=="function")try{await e.cleanup()}catch(S){console.warn(`[workflow] agent.cleanup() failed: ${S.message}`)}}}};var qe=Symbol.for("@zibby/agent-workflow.nodes");globalThis[qe]||(globalThis[qe]=new Map);var he=globalThis[qe];function ro(o,e){he.set(o,e)}function Xe(o){return he.get(o)}function Ie(o){return he.has(o)}function rn(){return Array.from(he.keys())}function Qe(o){let e=he.get(o);return e?e.factory&&typeof e.create=="function"?e.create.toString():typeof e.execute=="function"?e.execute.toString():typeof e=="function"?e.toString():null:null}ro("ai_agent",{name:"ai_agent",factory:!0,create:(o,e={})=>({name:o,_isCustomCode:!0,execute:async t=>{let n=t?._coreInvokeAgent;n||(n=(await Promise.resolve().then(()=>(X(),ue))).invokeAgent);let r=e.extraPromptInstructions||"Execute the task based on the current state.",i=sn(r,t),s=await n(i,{cwd:t.workspace||process.cwd(),model:t.model,tools:e.resolvedTools||null});return{success:!0,output:{raw:s,nodeId:o},raw:typeof s=="string"?s:s.raw}}})});function sn(o,e){let t=/@([\w.]+)/g,n=new Set,r;for(;(r=t.exec(o))!==null;)n.add(r[1]);if(n.size===0)return o;let i=[],s=new Set;for(let a of n){let l=a.split(".")[0];if(s.has(l))continue;let u=a.split(".").reduce((c,y)=>c?.[y],e);if(u===void 0)continue;let m=typeof u=="string"?u:u?.raw??JSON.stringify(u,null,2),d=a.replace(/_/g," ").replace(/\b\w/g,c=>c.toUpperCase());i.push(`## ${d}
|
|
43
43
|
${m}`),a.includes(".")||s.add(l)}return i.length===0?o:`${o}
|
|
44
44
|
|
|
45
45
|
---
|