@zibby/agent-workflow 0.1.4 → 0.2.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/README.md +5 -1
- package/dist/code-generator.js +10 -10
- package/dist/constants.d.ts +14 -1
- package/dist/constants.js +1 -1
- package/dist/graph-compiler.js +21 -21
- package/dist/graph.d.ts +49 -8
- package/dist/graph.js +24 -24
- package/dist/index.d.ts +2 -2
- package/dist/index.js +29 -29
- package/dist/node-registry.js +5 -5
- package/dist/node.js +11 -11
- package/dist/output-parser.js +3 -3
- package/dist/skill-registry.js +1 -1
- package/dist/strategy-registry.js +5 -5
- package/dist/timeline.js +5 -5
- package/dist/tool-resolver.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -5,7 +5,9 @@
|
|
|
5
5
|
[](https://www.npmjs.com/package/@zibby/agent-workflow)
|
|
6
6
|
[](./LICENSE)
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
📖 **Full docs:** [docs.zibby.app](https://docs.zibby.app) · [Get Started](https://docs.zibby.app/get-started/install) · [Concepts](https://docs.zibby.app/concepts/graph) · [CLI Reference](https://docs.zibby.app/cli-reference) · [Cloud](https://docs.zibby.app/cloud/triggering)
|
|
9
|
+
|
|
10
|
+
> **The cloud pipeline for Claude Code, Cursor, Codex, and Gemini.** Compose them into structured workflows with Zod-validated handoff between nodes. Vendor-neutral, JavaScript-first, runs locally or in our cloud.
|
|
9
11
|
|
|
10
12
|
```
|
|
11
13
|
┌──────────┐ ┌──────────┐ ┌──────────┐
|
|
@@ -27,6 +29,8 @@ graph
|
|
|
27
29
|
.addNode('verify', { prompt, outputSchema: Result, agent: 'codex' });
|
|
28
30
|
```
|
|
29
31
|
|
|
32
|
+
Each agent reads its own credential env var (`ANTHROPIC_API_KEY`, `CURSOR_API_KEY`, `OPENAI_API_KEY`). In **Zibby Cloud** you can set those per-workflow — different keys per pipeline, no global state — see [Per-workflow env vars](https://docs.zibby.app/cloud/env-vars). Per-node `model` overrides come from `.zibby.config.mjs` (`models: { node_id: 'claude-opus-4.6' }`), which the CLI ships to cloud as part of the deploy bundle.
|
|
33
|
+
|
|
30
34
|
---
|
|
31
35
|
|
|
32
36
|
## ⚡ Try it in 60 seconds
|
package/dist/code-generator.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
var
|
|
1
|
+
var D=Object.defineProperty;var T=(e,o)=>()=>(e&&(o=e(e=0)),o);var L=(e,o)=>{for(var n in o)D(e,n,{get:o[n],enumerable:!0})};function v(e){return M.get(e)||null}var $,M,S=T(()=>{$=Symbol.for("@zibby/agent-workflow.skills");globalThis[$]||(globalThis[$]=new Map);M=globalThis[$]});var _,F,N,k,x=T(()=>{_=()=>{},F={debug:_,info:_,warn:(...e)=>console.warn("[workflow]",...e),error:(...e)=>console.error("[workflow]",...e)},N={impl:F},k={debug:(...e)=>N.impl.debug?.(...e),info:(...e)=>N.impl.info?.(...e),warn:(...e)=>N.impl.warn?.(...e),error:(...e)=>N.impl.error?.(...e)}});var A=T(()=>{});var I={};L(I,{getAgentStrategy:()=>C,invokeAgent:()=>B,listStrategies:()=>z,registerStrategy:()=>G});function G(e){if(!e||typeof e.getName!="function"||typeof e.invoke!="function")throw new Error("strategy must implement getName() and invoke() (AgentStrategy shape)");let o=m.findIndex(n=>n.getName()===e.getName());o>=0?m[o]=e:m.push(e)}function z(){return m.map(e=>e.getName())}function C(e={}){let{state:o={},preferredAgent:n=null}=e,r=n||o.agentType||process.env.AGENT_TYPE;if(!r){let s=m.map(t=>t.getName()).join(", ")||"none registered";throw new Error(`No agent specified. Set agentType in state or AGENT_TYPE env var. Available: ${s}`)}k.debug(`[workflow] agent selection: requested=${r}`);let i=m.find(s=>s.getName()===r);if(!i){let s=m.map(t=>t.getName()).join(", ")||"none registered";throw new Error(`Unknown agent '${r}'. Available: ${s}`)}if(!i.canHandle(e))throw new Error(`Agent '${r}' is not available in this environment. Check credentials/environment.`);return k.debug(`[workflow] using agent: ${i.getName()}`),i}async function B(e,o={},n={}){let r=C(o),i=o.state?.config||n.config||{},s=i.models||{},t=n.nodeName&&s[n.nodeName]||null,a=s.default||null,c=i.agent?.[r.name]?.model||null,l=t||a||c||n.model||null,p={...n,model:l,workspace:o.state?.workspace||n.workspace,schema:n.schema||o.schema,images:n.images||o.images||[],skills:n.skills||o.skills||[],config:i},u=e,g=p.skills||[];if(g.length>0&&!n.skipPromptFragments){let d=g.map(y=>{let f=v(y)?.promptFragment;return typeof f=="function"?f():f}).filter(Boolean);d.length>0&&(u+=`
|
|
2
2
|
|
|
3
3
|
${d.join(`
|
|
4
4
|
|
|
5
|
-
`)}`)}let h=o.state?._currentNodeConfig?.extraPromptInstructions?.trim();return h&&(
|
|
5
|
+
`)}`)}let h=o.state?._currentNodeConfig?.extraPromptInstructions?.trim();return h&&(u+=`
|
|
6
6
|
|
|
7
7
|
\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
|
|
8
8
|
PRIORITY OVERRIDE \u2014 THE FOLLOWING INSTRUCTIONS TAKE PRECEDENCE OVER ALL PREVIOUS CONTENT
|
|
9
9
|
\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
|
|
10
10
|
|
|
11
11
|
${h}
|
|
12
|
-
`),k.debug(`[workflow] prompt length: ${
|
|
12
|
+
`),k.debug(`[workflow] prompt length: ${u.length} chars`),r.invoke(u,p)}var E,m,j=T(()=>{A();x();S();E=Symbol.for("@zibby/agent-workflow.strategies");globalThis[E]||(globalThis[E]=[]);m=globalThis[E]});S();x();var b={};var O=new Map;function U(e,o){O.set(e,o)}function P(e){let o=O.get(e);return o?o.factory&&typeof o.create=="function"?o.create.toString():typeof o.execute=="function"?o.execute.toString():typeof o=="function"?o.toString():null:null}U("ai_agent",{name:"ai_agent",factory:!0,create:(e,o={})=>({name:e,_isCustomCode:!0,execute:async n=>{let r=n?._coreInvokeAgent;r||(r=(await Promise.resolve().then(()=>(j(),I))).invokeAgent);let i=o.extraPromptInstructions||"Execute the task based on the current state.",s=V(i,n),t=await r(s,{cwd:n.workspace||process.cwd(),model:n.model,tools:o.resolvedTools||null});return{success:!0,output:{raw:t,nodeId:e},raw:typeof t=="string"?t:t.raw}}})});function V(e,o){let n=/@([\w.]+)/g,r=new Set,i;for(;(i=n.exec(e))!==null;)r.add(i[1]);if(r.size===0)return e;let s=[],t=new Set;for(let a of r){let c=a.split(".")[0];if(t.has(c))continue;let l=a.split(".").reduce((g,h)=>g?.[h],o);if(l===void 0)continue;let p=typeof l=="string"?l:l?.raw??JSON.stringify(l,null,2),u=a.replace(/_/g," ").replace(/\b\w/g,g=>g.toUpperCase());s.push(`## ${u}
|
|
13
13
|
${p}`),a.includes(".")||t.add(c)}return s.length===0?e:`${e}
|
|
14
14
|
|
|
15
15
|
---
|
|
@@ -17,13 +17,13 @@ ${p}`),a.includes(".")||t.add(c)}return s.length===0?e:`${e}
|
|
|
17
17
|
|
|
18
18
|
${s.join(`
|
|
19
19
|
|
|
20
|
-
`)}`}function
|
|
21
|
-
`)}function
|
|
20
|
+
`)}`}function ge(e,o={}){let{nodes:n,edges:r,nodeConfigs:i={}}=e,s=new Set,t=[],a=new Map;for(let f of n){let w=f.data?.nodeType||f.type;a.set(f.id,w),w==="decision"?s.add(f.id):t.push({id:f.id,nodeType:w,label:f.data?.label||f.id})}let c=t.some(f=>{let w=i[f.id]||{};return!w.customCode&&!w.executeCode}),{toolsPerNode:l,toolIdsByVar:p}=q(t,i),{simpleEdges:u,conditionalEdges:g}=Q(r,s),h=X(t,r,s),d=[],y=o.workflowType||"workflow";return d.push(Y(o)),d.push(H(y,{usesRegisteredNodes:c})),d.push(W(p)),d.push(J(y)),d.push(K(t,i)),d.push(Z(t,h,u,g,l,y)),d.filter(Boolean).join(`
|
|
21
|
+
`)}function me(e){let o={};for(let[n,r]of Object.entries(e)){let{tools:i,...s}=r;Object.keys(s).length>0&&(o[n]=s)}return o}function Y(e){let o=e.workflowType||"workflow";return["// Generated workflow",`// ${e.projectId?`Project: ${e.projectId} | `:""}Type: ${o} | Version: ${e.version??0}`,`// Downloaded: ${new Date().toISOString()}`,""].join(`
|
|
22
22
|
`)}function H(e,{usesRegisteredNodes:o=!0}={}){let n=["import { WorkflowGraph, invokeAgent, getResolvedToolDefinitions } from '@zibby/agent-workflow';"];return o&&n.push("// import './register-nodes.js'; // register custom node types here"),n.push("import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'node:fs';","import { join, dirname } from 'node:path';","import { fileURLToPath } from 'node:url';",""),n.join(`
|
|
23
23
|
`)}function W(e){if(e.size===0)return"";let o=["// \u2500\u2500 Tool Bindings \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"];for(let[n,r]of e)o.push(`const ${n} = getResolvedToolDefinitions(${JSON.stringify(r)}); // ${r.join(", ")}`);return o.push(""),o.join(`
|
|
24
|
-
`)}function
|
|
25
|
-
`)}function
|
|
26
|
-
`)}function
|
|
27
|
-
`).map((p,
|
|
24
|
+
`)}function J(e){return["// \u2500\u2500 Node Configs \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500","const __filename = fileURLToPath(import.meta.url);","const __dirname = dirname(__filename);",`const configPath = join(__dirname, 'workflow-${e}.config.json');`,"const nodeConfigs = existsSync(configPath) ? JSON.parse(readFileSync(configPath, 'utf-8')) : {};",""].join(`
|
|
25
|
+
`)}function K(e,o){let n=["// \u2500\u2500 Node Implementations \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500",""];for(let r of e){let i=R(r.id),s=o[r.id]?.customCode;if(s)n.push(`// @custom \u2014 modified from default "${r.nodeType}" template`),n.push(`const ${i}_execute = ${s};`);else{let t=P(r.nodeType);t?(n.push(`// Default "${r.nodeType}" implementation`),n.push(`const ${i}_execute = ${t};`)):(n.push(`// No template for "${r.nodeType}" \u2014 passthrough`),n.push(`const ${i}_execute = async (state) => ({ success: true, output: {}, raw: null });`))}n.push("")}return n.join(`
|
|
26
|
+
`)}function Z(e,o,n,r,i,s){let t=["// \u2500\u2500 Graph Builder \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"];t.push("export function buildGraph(options = {}) {"),t.push(" const graph = new WorkflowGraph(options);",""),t.push(" // Nodes");for(let c of e){let l=R(c.id);t.push(` graph.addNode('${c.id}', { name: '${c.id}', execute: ${l}_execute });`),t.push(` graph.setNodeType('${c.id}', '${c.nodeType}');`)}t.push("",` graph.setEntryPoint('${o}');`,""),(n.length>0||r.length>0)&&t.push(" // Edges");for(let c of n)t.push(` graph.addEdge('${c.source}', '${c.target}');`);for(let c of r){let l=c.code.split(`
|
|
27
|
+
`).map((p,u)=>u===0?p:` ${p}`).join(`
|
|
28
28
|
`);t.push(` graph.addConditionalEdges('${c.source}', ${l});`)}let a=[];for(let c of e){let l=i.get(c.id);l&&a.push(` '${c.id}': ${l},`)}return a.length>0&&t.push(""," graph.resolvedToolsMap = {",...a," };"),t.push(""," return graph;","}",""),t.push("export { nodeConfigs };",""),t.join(`
|
|
29
|
-
`)}function
|
|
29
|
+
`)}function q(e,o){let n=new Map,r=new Map;for(let i of e){let s=o[i.id]?.tools,t;if(Array.isArray(s)&&s.length>0)t=[...s].sort();else{let a=b[i.nodeType];a?.length>0&&(t=[...a].sort())}if(t){let a=`${t.map(c=>c.replace(/[^a-zA-Z0-9]/g,"")).join("And")}Tools`;n.set(i.id,a),r.has(a)||r.set(a,t)}}return{toolsPerNode:n,toolIdsByVar:r}}function Q(e,o){let n=[],r=[],i=new Map,s=new Set;for(let t of e)i.has(t.source)||i.set(t.source,[]),i.get(t.source).push(t);for(let t of e)if(!o.has(t.source))if(o.has(t.target)){if(s.has(t.target))continue;s.add(t.target);let c=(i.get(t.target)||[]).find(l=>l.data?.conditionalCode||l.conditionalCode);c&&r.push({source:t.source,code:c.data?.conditionalCode||c.conditionalCode})}else n.push({source:t.source,target:t.target});return{simpleEdges:n,conditionalEdges:r}}function X(e,o,n){let r=new Set;for(let s of o)n.has(s.target)||r.add(s.target);let i=e.find(s=>!r.has(s.id));return i?i.id:e[0]?.id}function R(e){return e.replace(/[^a-zA-Z0-9]/g,"_")}export{me as generateNodeConfigsJson,ge as generateWorkflowCode};
|
package/dist/constants.d.ts
CHANGED
|
@@ -4,7 +4,20 @@
|
|
|
4
4
|
export const DEFAULT_OUTPUT_BASE: ".zibby/output";
|
|
5
5
|
export const SESSIONS_DIR: "sessions";
|
|
6
6
|
export const SESSION_INFO_FILE: ".session-info.json";
|
|
7
|
-
/**
|
|
7
|
+
/**
|
|
8
|
+
* Written by any consumer (CLI Ctrl+C handler, IDE plugin, desktop app) to
|
|
9
|
+
* request that an in-flight workflow stop at the next abort-checkpoint.
|
|
10
|
+
* WorkflowGraph polls for this file between nodes and exits cleanly.
|
|
11
|
+
*
|
|
12
|
+
* The engine accepts BOTH this generic name and the legacy Studio-specific
|
|
13
|
+
* name during the AbortSignal-migration BC window. New consumers should
|
|
14
|
+
* use STOP_REQUEST_FILE.
|
|
15
|
+
*/
|
|
16
|
+
export const STOP_REQUEST_FILE: ".zibby-stop";
|
|
17
|
+
/**
|
|
18
|
+
* @deprecated Use STOP_REQUEST_FILE. Will be removed in v2 once the
|
|
19
|
+
* AbortSignal contract is universally adopted across consumers.
|
|
20
|
+
*/
|
|
8
21
|
export const STUDIO_STOP_REQUEST_FILE: ".zibby-studio-stop";
|
|
9
22
|
export const RESULT_FILE: "result.json";
|
|
10
23
|
export const RAW_OUTPUT_FILE: "raw_stream_output.txt";
|
package/dist/constants.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var o=".zibby/output",t="sessions",s=".session-info.json",_=".zibby-studio-stop",I="result.json",r="raw_stream_output.txt",
|
|
1
|
+
var o=".zibby/output",t="sessions",s=".session-info.json",_=".zibby-stop",E=".zibby-studio-stop",I="result.json",r="raw_stream_output.txt",e="events.json",S={BROWSER:"browser",JIRA:"jira",GITHUB:"github",SLACK:"slack",MEMORY:"memory",CHAT_MEMORY:"chat-memory",RUNNER:"runner",SKILL_INSTALLER:"skill-installer",CORE_TOOLS:"core-tools",WORKFLOW_BUILDER:"workflow-builder"},L=["CI_JOB_ID","GITHUB_RUN_ID","CIRCLE_WORKFLOW_ID","BUILD_ID"];export{L as CI_ENV_VARS,o as DEFAULT_OUTPUT_BASE,e as EVENTS_FILE,r as RAW_OUTPUT_FILE,I as RESULT_FILE,t as SESSIONS_DIR,s as SESSION_INFO_FILE,S as SKILLS,_ as STOP_REQUEST_FILE,E as STUDIO_STOP_REQUEST_FILE};
|
package/dist/graph-compiler.js
CHANGED
|
@@ -1,45 +1,45 @@
|
|
|
1
|
-
var
|
|
1
|
+
var ut=Object.defineProperty;var le=(o=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(o,{get:(e,t)=>(typeof require<"u"?require:e)[t]}):o)(function(o){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+o+'" is not supported')});var q=(o,e)=>()=>(o&&(e=o(o=0)),e);var Oe=(o,e)=>{for(var t in e)ut(o,t,{get:e[t],enumerable:!0})};var ke,ft,ee,w,U=q(()=>{ke=()=>{},ft={debug:ke,info:ke,warn:(...o)=>console.warn("[workflow]",...o),error:(...o)=>console.error("[workflow]",...o)},ee={impl:ft},w={debug:(...o)=>ee.impl.debug?.(...o),info:(...o)=>ee.impl.info?.(...o),warn:(...o)=>ee.impl.warn?.(...o),error:(...o)=>ee.impl.error?.(...o)}});var Ze=q(()=>{});var je={};Oe(je,{clearSkills:()=>yt,getAllSkills:()=>wt,getSkill:()=>H,hasSkill:()=>St,listSkillIds:()=>_t,registerSkill:()=>gt});function gt(o){if(!o||typeof o.id!="string")throw new Error("Skill definition must include a string id");F.set(o.id,Object.freeze({...o}))}function H(o){return F.get(o)||null}function St(o){return F.has(o)}function wt(){return new Map(F)}function _t(){return Array.from(F.keys())}function yt(){F.clear()}var he,F,oe=q(()=>{he=Symbol.for("@zibby/agent-workflow.skills");globalThis[he]||(globalThis[he]=new Map);F=globalThis[he]});var K={};Oe(K,{getAgentStrategy:()=>Ue,invokeAgent:()=>Nt,listStrategies:()=>It,registerStrategy:()=>Et});function Et(o){if(!o||typeof o.getName!="function"||typeof o.invoke!="function")throw new Error("strategy must implement getName() and invoke() (AgentStrategy shape)");let e=W.findIndex(t=>t.getName()===o.getName());e>=0?W[e]=o:W.push(o)}function It(){return W.map(o=>o.getName())}function Ue(o={}){let{state:e={},preferredAgent:t=null}=o,r=t||e.agentType||process.env.AGENT_TYPE;if(!r){let i=W.map(a=>a.getName()).join(", ")||"none registered";throw new Error(`No agent specified. Set agentType in state or AGENT_TYPE env var. Available: ${i}`)}w.debug(`[workflow] agent selection: requested=${r}`);let s=W.find(i=>i.getName()===r);if(!s){let i=W.map(a=>a.getName()).join(", ")||"none registered";throw new Error(`Unknown agent '${r}'. Available: ${i}`)}if(!s.canHandle(o))throw new Error(`Agent '${r}' is not available in this environment. Check credentials/environment.`);return w.debug(`[workflow] using agent: ${s.getName()}`),s}async function Nt(o,e={},t={}){let r=Ue(e),s=e.state?.config||t.config||{},i=s.models||{},a=t.nodeName&&i[t.nodeName]||null,n=i.default||null,c=s.agent?.[r.name]?.model||null,d=a||n||c||t.model||null,h={...t,model:d,workspace:e.state?.workspace||t.workspace,schema:t.schema||e.schema,images:t.images||e.images||[],skills:t.skills||e.skills||[],config:s},u=o,l=h.skills||[];if(l.length>0&&!t.skipPromptFragments){let _=l.map(S=>{let $=H(S)?.promptFragment;return typeof $=="function"?$():$}).filter(Boolean);_.length>0&&(u+=`
|
|
2
2
|
|
|
3
|
-
${
|
|
3
|
+
${_.join(`
|
|
4
4
|
|
|
5
|
-
`)}`)}let
|
|
5
|
+
`)}`)}let m=e.state?._currentNodeConfig?.extraPromptInstructions?.trim();return m&&(u+=`
|
|
6
6
|
|
|
7
7
|
\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
|
|
8
8
|
PRIORITY OVERRIDE \u2014 THE FOLLOWING INSTRUCTIONS TAKE PRECEDENCE OVER ALL PREVIOUS CONTENT
|
|
9
9
|
\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
|
|
10
10
|
|
|
11
|
-
${
|
|
12
|
-
`),w.debug(`[workflow] prompt length: ${
|
|
11
|
+
${m}
|
|
12
|
+
`),w.debug(`[workflow] prompt length: ${u.length} chars`),r.invoke(u,h)}var me,W,z=q(()=>{Ze();U();oe();me=Symbol.for("@zibby/agent-workflow.strategies");globalThis[me]||(globalThis[me]=[]);W=globalThis[me]});var pt=new Set(["__proto__","constructor","prototype"]);function de(o){if(pt.has(o))throw new Error(`Invalid state key: "${o}"`)}var Q=class{constructor(e={}){this._state=Object.create(null),Object.assign(this._state,{messages:[],errors:[],artifacts:{},metadata:{},...e}),this._history=[]}get(e){return this._state[e]}set(e,t){de(e),this._history.push({...this._state}),this._state[e]=t}update(e){let t=Object.getOwnPropertyNames(e);for(let r of t)de(r);this._history.push({...this._state});for(let r of t)this._state[r]=e[r]}append(e,t){de(e),this._history.push({...this._state}),Array.isArray(this._state[e])||(this._state[e]=[]),this._state[e].push(t)}getAll(){return{...this._state}}rollback(){this._history.length>0&&(this._state=this._history.pop())}};var X=class{constructor(e){this.schema=e}parse(e){let t=e.match(/```json\s*([\s\S]*?)\s*```/);if(t)return this.validate(JSON.parse(t[1]));let r=[e.match(/\{[\s\S]*?\}/),e.match(/\{[\s\S]*\}/)].filter(Boolean).map(s=>s[0]);for(let s of r)try{return this.validate(JSON.parse(s))}catch(i){if(!(i instanceof SyntaxError))throw i}return this.validate({result:e.trim()})}validate(e){let t=[];for(let[r,s]of Object.entries(this.schema)){if(s.required&&!(r in e)&&t.push(`Missing required field: ${r}`),r in e&&s.type){let i=typeof e[r];i!==s.type&&t.push(`Field '${r}' expected ${s.type}, got ${i}`)}if(s.validate&&r in e){let i=s.validate(e[r]);i&&t.push(`Field '${r}': ${i}`)}}if(t.length>0)throw new Error(`Output validation failed:
|
|
13
13
|
${t.join(`
|
|
14
|
-
`)}`);return e}};
|
|
15
|
-
`?(a+=c,e.lineStart=!0,e.col=0,e.inEsc=!1):c==="\x1B"?(e.inEsc=!0,a+=c):e.inEsc?(a+=c,(c>="A"&&c<="Z"||c>="a"&&c<="z")&&(e.inEsc=!1)):(e.col++,a+=c,e.col>=
|
|
16
|
-
${
|
|
14
|
+
`)}`);return e}};U();import{writeFileSync as ge,readFileSync as Ge,existsSync as He,mkdirSync as vt}from"node:fs";import{join as Se,dirname as $t}from"node:path";import I from"chalk";var ht="__WORKFLOW_GRAPH_LOG__",G=I.gray("\u2502"),mt=I.gray("\u250C"),xe=I.gray("\u2514"),ue=I.green("\u25C6"),Ce=I.hex("#c084fc")("\u25C6"),Pe=I.hex("#2dd4bf")("\u25C6"),pe=I.red("\u25C6"),Re=`${G} `,Be=2;function We(o){return o<1e3?`${o}ms`:`${(o/1e3).toFixed(1)}s`}function Me(o,e){return(t,r,s)=>{if(typeof t!="string")return o(t,r,s);let i=process.stdout.columns||120,a="";for(let n=0;n<t.length;n++){let c=t[n];e.lineStart&&(a+=Re,e.col=Be,e.lineStart=!1),c===`
|
|
15
|
+
`?(a+=c,e.lineStart=!0,e.col=0,e.inEsc=!1):c==="\x1B"?(e.inEsc=!0,a+=c):e.inEsc?(a+=c,(c>="A"&&c<="Z"||c>="a"&&c<="z")&&(e.inEsc=!1)):(e.col++,a+=c,e.col>=i&&(a+=`
|
|
16
|
+
${Re}`,e.col=Be))}return o(a,r,s)}}var fe=class{constructor(){this._currentNode=null,this._origStdoutWrite=null,this._origStderrWrite=null;let e=String(process.env.ZIBBY_EMIT_GRAPH_MARKERS||"").trim()==="1"||String(process.env.ZIBBY_WORKFLOW_GRAPH_LOG_MARKERS||"").trim()==="1",t=!e&&String(process.env.ZIBBY_RUN_SOURCE||"").trim().toLowerCase()==="studio";t&&process.env.ZIBBY_NO_DEPRECATION_WARNINGS!=="1"&&console.warn("[zibby/agent-workflow] `ZIBBY_RUN_SOURCE=studio` env var is deprecated for graph-marker emission. Set `ZIBBY_EMIT_GRAPH_MARKERS=1` instead. The Studio-specific value will be ignored in v2. Suppress with ZIBBY_NO_DEPRECATION_WARNINGS=1."),this._emitWorkflowGraphMarkers=e||t}get isInsideNode(){return this._currentNode!==null}_startIntercepting(){this._origStdoutWrite=process.stdout.write.bind(process.stdout),this._origStderrWrite=process.stderr.write.bind(process.stderr);let e={lineStart:!0,col:0,inEsc:!1},t={lineStart:!0,col:0,inEsc:!1};this._outState=e,this._errState=t,process.stdout.write=Me(this._origStdoutWrite,e),process.stderr.write=Me(this._origStderrWrite,t)}_stopIntercepting(){this._origStdoutWrite&&(this._outState&&!this._outState.lineStart&&this._origStdoutWrite(`
|
|
17
17
|
`),process.stdout.write=this._origStdoutWrite),this._origStderrWrite&&(this._errState&&!this._errState.lineStart&&this._origStderrWrite(`
|
|
18
18
|
`),process.stderr.write=this._origStderrWrite),this._origStdoutWrite=null,this._origStderrWrite=null}_rawWrite(e){(this._origStdoutWrite||process.stdout.write.bind(process.stdout))(`${e}
|
|
19
|
-
`)}_emitGraphLogMarker(e){if(!this._emitWorkflowGraphMarkers)return;let t=`${
|
|
19
|
+
`)}_emitGraphLogMarker(e){if(!this._emitWorkflowGraphMarkers)return;let t=`${ht}${JSON.stringify(e)}
|
|
20
20
|
`;this._origStdoutWrite?this._origStdoutWrite(t):process.stdout.write(t)}_writeDot(e,t){this._origStdoutWrite?(this._outState&&!this._outState.lineStart&&(this._origStdoutWrite(`
|
|
21
21
|
`),this._outState.lineStart=!0,this._outState.col=0),this._origStdoutWrite(`${e} ${t}
|
|
22
22
|
`)):process.stdout.write.bind(process.stdout)(`${e} ${t}
|
|
23
|
-
`)}step(e){this._origStdoutWrite?this._writeDot(
|
|
24
|
-
`)}stepInfo(e){this.step(e)}stepTool(e){this._origStdoutWrite?this._writeDot(
|
|
25
|
-
`)}stepMemory(e){let t=
|
|
26
|
-
`)}stepFail(e){this._origStdoutWrite?this._writeDot(
|
|
27
|
-
`)}nodeStart(e){this._currentNode=e,this._emitGraphLogMarker({phase:"node_begin",node:e}),this._rawWrite(`${
|
|
23
|
+
`)}step(e){this._origStdoutWrite?this._writeDot(ue,e):process.stdout.write.bind(process.stdout)(`${G} ${ue} ${e}
|
|
24
|
+
`)}stepInfo(e){this.step(e)}stepTool(e){this._origStdoutWrite?this._writeDot(Ce,e):process.stdout.write.bind(process.stdout)(`${G} ${Ce} ${e}
|
|
25
|
+
`)}stepMemory(e){let t=I.hex("#2dd4bf")(e);this._origStdoutWrite?this._writeDot(Pe,t):process.stdout.write.bind(process.stdout)(`${G} ${Pe} ${t}
|
|
26
|
+
`)}stepFail(e){this._origStdoutWrite?this._writeDot(pe,I.red(e)):process.stdout.write.bind(process.stdout)(`${G} ${pe} ${I.red(e)}
|
|
27
|
+
`)}nodeStart(e){this._currentNode=e,this._emitGraphLogMarker({phase:"node_begin",node:e}),this._rawWrite(`${mt} ${e}`),this._startIntercepting()}nodeComplete(e,t={}){this._stopIntercepting();let{duration:r,details:s}=t;if(s)for(let a of s)this._rawWrite(`${ue} ${a}`);let i=r?I.dim(` ${We(r)}`):"";this._rawWrite(`${xe} ${I.green("done")}${i}`),this._emitGraphLogMarker({phase:"node_end",node:e}),this._rawWrite("")}nodeFailed(e,t,r={}){this._stopIntercepting();let{duration:s}=r,i=s?I.dim(` ${We(s)}`):"";this._rawWrite(`${pe} ${I.red(t)}`),this._rawWrite(`${xe} ${I.red("failed")}${i}`),this._emitGraphLogMarker({phase:"node_end",node:e}),this._rawWrite("")}route(e,t){this._rawWrite(I.dim(` ${e} \u2192 ${t}`)),this._rawWrite("")}graphComplete(){this._rawWrite(I.green.bold("\u2713 Workflow completed"))}},N=new fe;var te=".zibby/output",De="sessions",L=".session-info.json",Le=".zibby-stop",Fe=".zibby-studio-stop";var Ye=["CI_JOB_ID","GITHUB_RUN_ID","CIRCLE_WORKFLOW_ID","BUILD_ID"];var Y=class{constructor(e){if(this.config=e,this.name=e.name,this.prompt=e.prompt,this.outputSchema=e.outputSchema,!this.outputSchema&&!e._isCustomCode)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=e.outputSchema&&!this.isZodSchema?new X(e.outputSchema):null,this.retries=e.retries||0,this.onComplete=e.onComplete,this.customExecute=e.execute}async execute(e,t){let r=()=>t&&typeof t.getAll=="function"?t.getAll():e,s=u=>t&&typeof t.get=="function"?t.get(u):e?.[u];if(typeof this.customExecute=="function"){w.debug(`[workflow] node '${this.name}': custom execute (skipping LLM)`);try{let u=await this.customExecute(e);return typeof u=="object"&&u!==null&&u.success===!1?{success:!1,error:u.error||"Node execution failed",raw:u.raw||null}:this.isZodSchema?(w.debug(`[workflow] node '${this.name}': validating output schema`),{success:!0,output:this.outputSchema.parse(u),raw:null}):{success:!0,output:u,raw:null}}catch(u){return w.error(`[workflow] node '${this.name}' failed: ${u.message}`),u.name==="ZodError"&&w.error(`Schema errors: ${JSON.stringify(u.issues||u.errors,null,2)}`),{success:!1,error:u.message,raw:null}}}let i=typeof this.prompt=="function"?this.prompt(r()):this.prompt,a=s("_skillHints");a&&(i=`${a}
|
|
28
28
|
|
|
29
|
-
${
|
|
29
|
+
${i}`);let n=r(),c=n.cwd||process.cwd(),d=n.sessionPath;try{if(d){let u=Se(d,L);if(He(u)){let m=JSON.parse(Ge(u,"utf-8"));m.currentNode=this.name,ge(u,JSON.stringify(m,null,2),"utf-8")}let l=Se(d,"..",L);if(He(l))try{let m=JSON.parse(Ge(l,"utf-8"));m.currentNode=this.name,ge(l,JSON.stringify(m,null,2),"utf-8")}catch{}}}catch(u){w.debug(`[workflow] could not update session info: ${u.message}`)}let h=null;for(let u=0;u<=this.retries;u++)try{w.debug(`[workflow] node '${this.name}' attempt ${u}`);let l=r().config||{},m=l.agents||{},_=this.config.agent??m[this.name]??null,S={state:r()};_&&(S.preferredAgent=_);let $={workspace:c,schema:this.isZodSchema?this.outputSchema:null,skills:this.config.skills||[],sessionPath:d,config:l,nodeName:this.name,timeout:this.config?.timeout||3e5},f=e?._coreInvokeAgent;f||(f=(await Promise.resolve().then(()=>(z(),K))).invokeAgent);let v=await f(i,S,$),y,A;if(typeof v=="string"?(y=v,A=null):v.structured?(y=v.raw||JSON.stringify(v.structured,null,2),A=v.structured):(y=v.raw||JSON.stringify(v,null,2),A=v.extracted||null),d)try{let p=Se(d,this.name,"raw_stream_output.txt");vt($t(p),{recursive:!0}),ge(p,typeof y=="string"?y:JSON.stringify(y),"utf-8")}catch(p){w.debug(`[workflow] could not save raw output: ${p.message}`)}if(this.isZodSchema&&A){w.info(`[workflow] node '${this.name}': output validated: ${JSON.stringify(A,null,2)}`);let p=A;if(typeof this.onComplete=="function")try{p=await this.onComplete(r(),A)}catch(R){w.warn(`[workflow] onComplete hook failed: ${R.message}`)}return{success:!0,output:p,raw:y}}if(typeof this.onComplete=="function")try{return{success:!0,output:await this.onComplete(r(),{raw:y}),raw:y}}catch(p){throw new Error(`onComplete failed: ${p.message}`,{cause:p})}if(this.parser){let p=this.parser.parse(y);return w.info(`[workflow] node '${this.name}': parsed output: ${JSON.stringify(p,null,2)}`),N.step("Output parsed"),{success:!0,output:p,raw:y}}return{success:!0,output:y,raw:y}}catch(l){h=l,u<this.retries&&w.info(`[workflow] node '${this.name}' failed, retrying (${u+1}/${this.retries})\u2026`)}return{success:!1,error:h.message,raw:null}}},re=class extends Y{constructor(e){super({...e,_isCustomCode:!0}),this.condition=e.condition}async execute(e,t){let r=t&&typeof t.getAll=="function"?t.getAll():e;return{success:!0,output:{nextNode:this.condition(r)},raw:null}}};import{existsSync as Ke,readFileSync as bt}from"node:fs";import{join as we,dirname as ze}from"node:path";var se=class{static async loadContext(e,t,r={}){let s={},i=r.filenames||["CONTEXT.md","AGENTS.md"];if(e){let n=ze(we(t,e));for(let c of i){let d=await this.findAndMergeContextFiles(c,n,t);if(d){let h=c.replace(/\.[^.]+$/,"").toLowerCase();s[h]=d}}}let a=r.discovery||{};for(let[n,c]of Object.entries(a))try{let d=we(t,c);Ke(d)&&(s[n]=await this.loadFile(d))}catch(d){console.warn(`[workflow] could not load context '${n}' from '${c}': ${d.message}`)}return s}static async findAndMergeContextFiles(e,t,r){let s=[],i=t;for(;i.startsWith(r);){let a=we(i,e);if(Ke(a))try{s.unshift(await this.loadFile(a))}catch(c){console.warn(`[workflow] could not load ${e} from ${a}: ${c.message}`)}let n=ze(i);if(n===i)break;i=n}return s.length===0?null:s.every(a=>typeof a=="string")?s.join(`
|
|
30
30
|
|
|
31
31
|
---
|
|
32
32
|
|
|
33
|
-
`):
|
|
33
|
+
`):s.every(a=>typeof a=="object")?Object.assign({},...s):s[s.length-1]}static async loadFile(e){let t=bt(e,"utf-8");if(e.endsWith(".json"))return JSON.parse(t);if(e.endsWith(".js")||e.endsWith(".mjs")){let{pathToFileURL:r}=await import("url"),s=await import(r(e).href);return s.default||s}return t}};import{mkdirSync as Xe,existsSync as ne,writeFileSync as Je,unlinkSync as Ve}from"node:fs";import{join as P,resolve as et}from"node:path";import{config as Tt}from"dotenv";import{zodToJsonSchema as qe}from"zod-to-json-schema";import At from"handlebars";var Qe=new Set;function ie(o,e){Qe.has(o)||(Qe.add(o),process.env.ZIBBY_NO_DEPRECATION_WARNINGS!=="1"&&console.warn(`[zibby/agent-workflow] ${e}`))}function Ot({traceFrom:o,sessionId:e,sessionPath:t,idSource:r,mkdirFresh:s}){if(!(process.env.ZIBBY_SESSION_LOG==="1"||process.env.ZIBBY_SESSION_LOG==="true"))return;let a=typeof process.ppid=="number"?process.ppid:"n/a",n=`[zibby:session] from=${o} pid=${process.pid} ppid=${a} sessionId=${e} source=${r} mkdir=${s?"yes":"no"} path=${t}`;if(console.log(n),process.env.ZIBBY_TRACE_SESSION==="1"||process.env.ZIBBY_TRACE_SESSION==="true"){let h=(new Error("session trace").stack||"").split(`
|
|
34
34
|
`).slice(2,14).join(`
|
|
35
35
|
`);console.log(`[zibby:session] stack (${o}):
|
|
36
|
-
${
|
|
37
|
-
\u{1F6D1}
|
|
38
|
-
${
|
|
36
|
+
${h}`)}}function kt(){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"?!0:process.env.ZIBBY_RUN_SOURCE==="studio"?(ie("legacy-zibby-run-source","`ZIBBY_RUN_SOURCE=studio` env var is deprecated. Set `ZIBBY_TRUST_SESSION_ENV=1` (and `ZIBBY_PIN_SESSION_PATH=1` / `ZIBBY_EMIT_GRAPH_MARKERS=1` if you need those gates) instead. The Studio-specific value will be ignored in v2. Suppress with ZIBBY_NO_DEPRECATION_WARNINGS=1."),!0):!1}function xt(){let o=process.env.ZIBBY_PIN_SESSION_PATH==="1"||process.env.ZIBBY_PIN_SESSION_PATH==="true",e=!o&&process.env.ZIBBY_RUN_SOURCE==="studio";if(e&&ie("legacy-zibby-run-source","`ZIBBY_RUN_SOURCE=studio` env var is deprecated. Set `ZIBBY_PIN_SESSION_PATH=1` (and `ZIBBY_TRUST_SESSION_ENV=1` / `ZIBBY_EMIT_GRAPH_MARKERS=1` if you need those gates) instead. The Studio-specific value will be ignored in v2. Suppress with ZIBBY_NO_DEPRECATION_WARNINGS=1."),!o&&!e)return;let t=process.env.ZIBBY_SESSION_PATH;if(!(t==null||String(t).trim()===""))try{return et(String(t).trim())}catch{return String(t).trim()}}var Ct=xt;function Pt(){kt()||(delete process.env.ZIBBY_SESSION_PATH,delete process.env.ZIBBY_SESSION_ID)}function Rt({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 Bt(o={}){let e=Ye.map(i=>process.env[i]).find(Boolean),t=Math.random().toString(36).slice(2,6),r=e||`${Date.now()}_${t}`,s=o.paths?.sessionPrefix;return s?`${s}_${r}`:r}function Wt({cwd:o=process.cwd(),config:e={},initialState:t={},traceFrom:r="resolveWorkflowSession"}={}){let s=t.sessionPath,i=t.sessionTimestamp,a="initialState.sessionPath";if(!s&&process.env.ZIBBY_SESSION_PATH)try{let d=et(String(process.env.ZIBBY_SESSION_PATH));d&&(s=d,a="ZIBBY_SESSION_PATH")}catch{}let n;if(s)n=String(s).split(/[/\\]/).filter(Boolean).pop(),i==null&&(i=Date.now());else{let d=process.env.ZIBBY_SESSION_ID&&String(process.env.ZIBBY_SESSION_ID).trim();if(d)n=d,a="ZIBBY_SESSION_ID";else{let u=e.sessionId!=null?String(e.sessionId).trim():"";u&&u!=="last"?(n=u,a="config.sessionId"):(n=Bt(e),a="generated")}i=i??Date.now();let h=e.paths?.output||te;s=P(o,h,De,n)}let c=!ne(s);return c&&Xe(s,{recursive:!0}),(c||a!=="initialState.sessionPath")&&Ot({traceFrom:r,sessionId:n,sessionPath:s,idSource:a,mkdirFresh:c}),Rt({sessionPath:s,sessionId:n}),{sessionPath:s,sessionId:n,sessionTimestamp:i}}var ae=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.nodePrompts=new Map,this.nodeOptions=new Map,this._invokeAgent=e.invokeAgent||null,this._compiledPrompts=new Map}setStateSchema(e){return this.stateSchema=e,this}getStateSchema(){return this.stateSchema}addNode(e,t,r={}){let s=t instanceof Y?t:new Y(t);return s.name=e,this.nodes.set(e,s),r.prompt&&this.nodePrompts.set(e,r.prompt),Object.keys(r).length>0&&this.nodeOptions.set(e,r),this}addConditionalNode(e,t){return this.nodes.set(e,new re({...t,name:e})),this}addEdge(e,t){return this.edges.set(e,t),this}setNodeType(e,t){return this.nodeTypeMap.set(e,t),this}addConditionalEdges(e,t,{labels:r}={}){return this.edges.set(e,{conditional:!0,routes:t,labels:r}),typeof t=="function"&&this.conditionalCodeMap.set(e,t.toString()),this}setEntryPoint(e){return this.entryPoint=e,this}use(e){return typeof e=="function"&&this.middleware.push(e),this}_composeMiddleware(e,t,r,s,i){let a=r;for(let n=e.length-1;n>=0;n--){let c=e[n],d=a;a=()=>c(t,d,s,i)}return a()}serialize(){let e=[],t={};for(let[i,a]of this.nodes){let n=this.nodeTypeMap.get(i)||i;e.push({id:i,type:n,data:{nodeType:n,label:i}});let c={};a._isCustomCode&&typeof a.execute=="function"&&(c.customCode=a.execute.toString());let d=this.nodePrompts.get(i);if(d&&(c.prompt=d),typeof a.customExecute=="function"&&(c.executeCode=a.customExecute.toString()),a.outputSchema)try{if(typeof a.outputSchema._def<"u"){let u=qe(a.outputSchema,{target:"openApi3"});c.outputSchema={jsonSchema:u,variables:this._flattenJsonSchemaToVariables(u)}}else c.outputSchema={schema:a.outputSchema}}catch(u){console.warn(`[workflow] failed to convert schema for ${i}:`,u.message)}let h=(this.resolvedToolsMap||{})[i];h?.toolIds&&(c.tools=h.toolIds),Object.keys(c).length>0&&(t[i]=c)}let r=[];for(let[i,a]of this.edges)if(typeof a=="string")r.push({source:i,target:a});else if(a.conditional){let n=this.conditionalCodeMap.get(i)||a.routes.toString(),c=this._inferConditionalTargets(a.routes),d=a.labels||{};for(let h of c){let u={source:i,target:h,data:{conditionalCode:n}};d[h]&&(u.label=d[h]),r.push(u)}}let s=null;if(this.stateSchema)try{s=qe(this.stateSchema,{target:"openApi3"})}catch{s=this.stateSchema}return{nodes:e,edges:r,nodeConfigs:t,stateSchema:s}}_inferConditionalTargets(e){let t=e.toString(),r=new Set,s=/return\s+['"]([^'"]+)['"]/g,i;for(;(i=s.exec(t))!==null;)r.add(i[1]);return[...r]}_flattenJsonSchemaToVariables(e,t=""){let r=e;if(e.$ref&&e.definitions){let s=e.$ref.replace("#/definitions/","");r=e.definitions[s]||e}return this._flattenSchema(r,t)}_flattenSchema(e,t=""){if(!e||typeof e!="object")return[];let r=[],s=e.properties||{},i=e.required||[];for(let[a,n]of Object.entries(s)){let c=t?`${t}.${a}`:a;r.push({path:c,type:n.type||"unknown",label:n.description||this._formatLabel(a),optional:!i.includes(a)}),n.type==="object"&&n.properties&&r.push(...this._flattenSchema(n,c)),n.type==="array"&&n.items?.type==="object"&&n.items.properties&&r.push(...this._flattenSchema(n.items,`${c}[]`))}return r}_formatLabel(e){return e.replace(/([A-Z])/g," $1").replace(/^./,t=>t.toUpperCase()).trim()}_summarizeNodeOutput(e,t){if(!t||typeof t!="object")return[];let r=[];t.success!==void 0&&r.push(`Result: ${t.success?"passed":"failed"}`);for(let[s,i]of Object.entries(t))if(!(s==="success"||s==="raw"||s==="nextNode")){if(typeof i=="string"&&i.length<=80)r.push(`${s}: ${i}`);else if(Array.isArray(i)){let a=i.length,n=i.filter(d=>d?.passed===!0).length,c=i.some(d=>d?.passed!==void 0);r.push(c?`${s}: ${n}/${a} passed${a-n?`, ${a-n} failed`:""}`:`${s}: ${a} items`)}if(r.length>=4)break}return r}async run(e,t={},r={}){if(!this.entryPoint)throw new Error("No entry point set for graph");let s=new AbortController;r.signal&&(r.signal.aborted?s.abort():r.signal.addEventListener("abort",()=>s.abort(),{once:!0}));let i=r.strategyAbortTimeoutMs??t.config?.strategyAbortTimeoutMs??5e3,a=t.cwd||process.cwd();Tt({path:P(a,".env")});let n=t.config||{};if(!n||Object.keys(n).length===0)try{let g=P(a,".zibby.config.js");ne(g)&&(n=(await import(g)).default||{})}catch{}process.env.EXECUTION_ID&&!n.agent?.strictMode&&(n.agent={...n.agent,strictMode:!0});let c=t.agentType;if(!c){let g=n?.agent;g?.provider?c=g.provider:g?.gemini?c="gemini":g?.claude?c="claude":g?.cursor?c="cursor":g?.codex?c="codex":c=process.env.AGENT_TYPE||"cursor"}let d=t.contextConfig||e?.config?.contextConfig||e?.config?.context||n?.context||{};if(this.stateSchema){let g=this.stateSchema.safeParse(t);if(!g.success){let T=g.error.issues.map(O=>`${O.path.join(".")}: ${O.message}`);throw console.error("\u274C Initial state validation failed:"),T.forEach(O=>console.error(` - ${O}`)),new Error(`State validation failed: ${T.join(", ")}`)}N.step("State validated against schema")}let h=Ct(),u=t.sessionPath||h;u||Pt();let{sessionPath:l,sessionTimestamp:m,sessionId:_}=Wt({cwd:a,config:n,traceFrom:"WorkflowGraph.run",initialState:{sessionPath:u,sessionTimestamp:t.sessionTimestamp}});N.step(`Session ${_}`);let S=await se.loadContext(t.specPath||"",a,d);Object.keys(S).length>0&&N.step(`Context loaded: ${Object.keys(S).join(", ")}`);let $=t.outputPath;!$&&t.specPath&&(e?.calculateOutputPath?$=e.calculateOutputPath(t.specPath):console.warn(`\u26A0\uFE0F outputPath not resolved (specPath=${t.specPath})`));let f=new Q({...t,config:n,agentType:c,outputPath:$,sessionPath:l,sessionTimestamp:m,context:S,resolvedTools:this.resolvedToolsMap||{},_signal:s.signal}),v=new Map;try{await import("@zibby/skills")}catch{}let{getSkill:y}=await Promise.resolve().then(()=>(oe(),je)),A=new Set;for(let[,g]of this.nodes)for(let T of g.config?.skills||[])A.add(T);for(let g of A){let T=y(g);if(typeof T?.middleware=="function")try{let O=await T.middleware();typeof O=="function"&&v.set(g,O)}catch{}}let p=this.entryPoint,R=[],Ee=n?.recursionLimit??100,nt=0;try{for(;p&&p!=="END";){if(++nt>Ee)throw new Error(`Workflow exceeded recursion limit (${Ee}) \u2014 likely a cyclic conditional route. Set config.recursionLimit if you need a higher cap.`);let T=P(l,Le),O=P(l,Fe);if(ne(T)){try{Ve(T)}catch{}s.abort()}if(ne(O)){try{Ve(O)}catch{}s.abort(),ie("legacy-stop-file","Detected legacy `.zibby-studio-stop` file. Consumers should migrate to either `.zibby-stop` (renamed) or pass an AbortSignal to graph.run. The legacy filename will be removed in v2. Suppress with ZIBBY_NO_DEPRECATION_WARNINGS=1.")}if(s.signal.aborted)return console.warn(`
|
|
37
|
+
\u{1F6D1} External stop requested \u2014 ending workflow.`),N.step("Workflow stopped externally"),{success:!0,state:f.getAll(),executionLog:R,stoppedExternally:!0,stoppedByStudio:!0};let Z=this.nodes.get(p);if(!Z)throw new Error(`Node '${p}' not found in graph`);let Ie=JSON.stringify({sessionPath:l,sessionTimestamp:m,currentNode:p,createdAt:new Date().toISOString(),config:f.get("config")}),it=P(l,L);Je(it,Ie,"utf-8");let Ne=f.get("config")?.paths?.output||te,at=P(a,Ne,L);Xe(P(a,Ne),{recursive:!0});try{Je(at,Ie,"utf-8")}catch{}let ve=t.onPipelineProgress;if(typeof ve=="function")try{ve({cwd:a,sessionPath:l,sessionId:_,outputBase:f.get("config")?.paths?.output||te,currentNode:p})}catch{}let ct=(this.resolvedToolsMap||{})[p]||null;f.set("_currentNodeTools",ct);let lt=f.get("nodeConfigs")||{};f.set("_currentNodeConfig",lt[p]||{}),N.nodeStart(p);let $e=Date.now(),J=this.nodePrompts.get(p);if(!this._invokeAgent){let k=await Promise.resolve().then(()=>(z(),K));this._invokeAgent=k.invokeAgent}let dt=this._invokeAgent,be=async(k,x,E={})=>{let b=dt(k,x,{...E,signal:s.signal});return b.catch(()=>{}),s.signal.aborted?b:Promise.race([b,new Promise((M,D)=>{let B=()=>{setTimeout(()=>{let j=new Error(`Strategy ignored AbortSignal \u2014 engine deadman fired after ${i}ms`);j.name="AbortError",D(j)},i)};s.signal.addEventListener("abort",B,{once:!0})})])},Te={state:f,invokeAgent:async(k={},x={})=>{let E=x.prompt||"";if(J){let b=this._compiledPrompts.get(p);b||(b=At.compile(J,{noEscape:!0}),this._compiledPrompts.set(p,b));try{E=b(k)}catch(M){throw console.error(`\u274C Template rendering failed for node '${p}':`,M.message),new Error(`Template rendering failed: ${M.message}`,{cause:M})}}else if(!E)throw new Error(`No prompt template configured for node '${p}' and no prompt provided in options`);return be(E,{state:f.getAll(),images:x.images||[]},{model:x.model||f.get("model"),workspace:f.get("workspace"),schema:x.schema,...x,signal:s.signal})},_coreInvokeAgent:be,agent:e,nodeId:p,promptTemplate:J,getPromptTemplate:()=>J,...f.getAll()};try{let k=(Z.config?.skills||[]).map(B=>v.get(B)).filter(Boolean),x=[...this.middleware,...k],E;x.length>0?E=await this._composeMiddleware(x,p,async()=>Z.execute(Te,f),f.getAll(),f):E=await Z.execute(Te,f);let b=Date.now()-$e;if(R.push({node:p,success:E.success,duration:b,timestamp:new Date().toISOString()}),!E.success){if(String(E.error||"").includes("Stopped from Zibby Studio"))return ie("legacy-error-string",'Strategy returned the legacy `Stopped from Zibby Studio` error string. Strategies should reject with `Error.name === "AbortError"` instead. The string-match fallback will be removed in v2. Suppress with ZIBBY_NO_DEPRECATION_WARNINGS=1.'),N.step("Workflow stopped externally"),f.set("stoppedExternally",!0),f.set("stoppedByStudio",!0),{success:!0,state:f.getAll(),executionLog:R,stoppedExternally:!0,stoppedByStudio:!0};if(s.signal.aborted)return N.step("Workflow stopped externally"),{success:!0,state:f.getAll(),executionLog:R,stoppedExternally:!0,stoppedByStudio:!0};f.append("errors",{node:p,error:E.error});let j=Z.config?.retries||0,Ae=`${p}_retries`,V=f.getAll()[Ae]||0;if(V<j){N.stepInfo(`Retrying (attempt ${V+1}/${j})`),f.update({[Ae]:V+1,[`${p}_raw`]:E.raw});continue}throw N.nodeFailed(p,E.error,{duration:b}),new Error(`Node '${p}' failed after ${V} attempts: ${E.error}`)}f.update({[p]:E.output});let M=this._summarizeNodeOutput(p,E.output);N.nodeComplete(p,{duration:b,details:M});let D=this.edges.get(p);if(!D)p="END";else if(D.conditional){let B=D.routes(f.getAll());N.route(p,B),p=B}else p=D}catch(k){throw N.isInsideNode&&N.nodeFailed(p,k.message,{duration:Date.now()-$e}),f.set("failed",!0),f.set("failedAt",p),k}}N.graphComplete();let g={success:!0,state:f.getAll(),executionLog:R};return e&&typeof e.onComplete=="function"&&await e.onComplete(g),g}finally{if(e&&typeof e.cleanup=="function")try{await e.cleanup()}catch(g){console.warn(`[workflow] agent.cleanup() failed: ${g.message}`)}}}};var _e=new Map;function Mt(o,e){_e.set(o,e)}function tt(o){return _e.get(o)}function ye(o){return _e.has(o)}Mt("ai_agent",{name:"ai_agent",factory:!0,create:(o,e={})=>({name:o,_isCustomCode:!0,execute:async t=>{let r=t?._coreInvokeAgent;r||(r=(await Promise.resolve().then(()=>(z(),K))).invokeAgent);let s=e.extraPromptInstructions||"Execute the task based on the current state.",i=Dt(s,t),a=await r(i,{cwd:t.workspace||process.cwd(),model:t.model,tools:e.resolvedTools||null});return{success:!0,output:{raw:a,nodeId:o},raw:typeof a=="string"?a:a.raw}}})});function Dt(o,e){let t=/@([\w.]+)/g,r=new Set,s;for(;(s=t.exec(o))!==null;)r.add(s[1]);if(r.size===0)return o;let i=[],a=new Set;for(let n of r){let c=n.split(".")[0];if(a.has(c))continue;let d=n.split(".").reduce((l,m)=>l?.[m],e);if(d===void 0)continue;let h=typeof d=="string"?d:d?.raw??JSON.stringify(d,null,2),u=n.replace(/_/g," ").replace(/\b\w/g,l=>l.toUpperCase());i.push(`## ${u}
|
|
38
|
+
${h}`),n.includes(".")||a.add(c)}return i.length===0?o:`${o}
|
|
39
39
|
|
|
40
40
|
---
|
|
41
41
|
# Referenced Context
|
|
42
42
|
|
|
43
|
-
${
|
|
43
|
+
${i.join(`
|
|
44
44
|
|
|
45
|
-
`)}`}
|
|
45
|
+
`)}`}oe();U();var Lt={};function rt(o,e){if(Array.isArray(e))return ot(e);let t=Lt[o];return!t||t.length===0?null:ot(t)}function ot(o){if(!Array.isArray(o)||o.length===0)return null;let e=[],t={},r=[];for(let s of o){let i=H(s);if(!i){w.warn(`[workflow] unknown skill "${s}" \u2014 skipping`);continue}r.push(s);for(let a of i.tools||[])e.push({name:a.name,description:a.description,input_schema:a.input_schema||{type:"object",properties:{}}});if(!t[i.serverName])if(typeof i.resolve=="function"){let a=i.resolve();a&&(t[i.serverName]={...a,toolPrefix:s})}else{let a={};for(let n of i.envKeys||[]){let c=process.env[n];c&&(a[n]=c)}t[i.serverName]={command:i.command,args:[...i.args||[]],env:a,toolPrefix:s}}}return r.length===0?null:{toolIds:r,claudeTools:e,mcpServers:t}}U();function xo(o,e={}){let{nodes:t,edges:r,nodeConfigs:s={}}=o;if(!Array.isArray(t)||t.length===0)throw new C("Graph must have at least one node");if(!Array.isArray(r))throw new C("Graph edges must be an array");let i=new ae(e);e.stateSchema&&i.setStateSchema(e.stateSchema);let a=new Set,n=new Map,c={};for(let l of t){let m=ce(l);n.set(l.id,{...l,resolvedType:m}),m==="decision"&&a.add(l.id)}for(let[l,m]of n){if(a.has(l))continue;let _=m.resolvedType,S=s[l]||{},$=rt(_,S.tools);$&&(c[l]=$);let f={};S.prompt&&(f.prompt=S.prompt);let v=ye(_);if(w.debug(`[workflow] compiler: node "${l}" type="${_}" registered=${v}`),S.customCode&&!v)i.addNode(l,st(l,S.customCode,S),f),i.setNodeType(l,_);else if(v){let y=tt(_);y.factory?i.addNode(l,y.create(l,{...S,resolvedTools:$}),f):i.addNode(l,y,f),i.setNodeType(l,_)}else if(S.executeCode)i.addNode(l,st(l,S.executeCode,S),f),i.setNodeType(l,_);else throw new C(`Unknown node type "${_}" for node "${l}". Did you forget to register it?`)}i.resolvedToolsMap=c;let d=new Set;for(let l of r)a.has(l.target)||d.add(l.target);let h=t.find(l=>!a.has(l.id)&&!d.has(l.id));if(!h)throw new C("Could not determine entry point: no node without incoming edges found");i.setEntryPoint(h.id);let u=Ft(r,"source");for(let l of r)if(!a.has(l.source))if(a.has(l.target)){let m=l.target,_=u.get(m)||[];if(_.length===0)throw new C(`Decision node "${m}" has no outgoing edges`);let S=Yt(m,_,a);i.addConditionalEdges(l.source,S)}else i.addEdge(l.source,l.target);return i}function Co(o){let e=[];if(!o||typeof o!="object")return{valid:!1,errors:["Config must be a non-null object"]};if((!Array.isArray(o.nodes)||o.nodes.length===0)&&e.push("Graph must have at least one node"),Array.isArray(o.edges)||e.push("Graph edges must be an array"),e.length>0)return{valid:!1,errors:e};let t=o.nodeConfigs||{};for(let n of o.nodes){let c=ce(n);if(c==="decision"||ye(c))continue;let d=t[n.id]||{};d.customCode||d.executeCode||e.push(`Unknown node type "${c}" for node "${n.id}". Register it or provide customCode/executeCode.`)}let r=new Set(o.nodes.map(n=>n.id));for(let n of o.edges)r.has(n.source)||e.push(`Edge references unknown source node "${n.source}"`),r.has(n.target)||e.push(`Edge references unknown target node "${n.target}"`);let s=new Set(o.nodes.filter(n=>ce(n)==="decision").map(n=>n.id)),i=new Set;for(let n of o.edges)s.has(n.target)||i.add(n.target);let a=o.nodes.filter(n=>!s.has(n.id)&&!i.has(n.id));a.length===0?e.push("No entry point found (every node has incoming edges)"):a.length>1&&e.push(`Multiple entry points found: ${a.map(n=>n.id).join(", ")}`);for(let n of s){let c=o.edges.filter(h=>h.source===n);c.length===0&&e.push(`Decision node "${n}" has no outgoing edges`),c.some(h=>h.data?.conditionalCode||h.conditionalCode)||e.push(`Decision node "${n}" outgoing edges have no conditionalCode`)}return{valid:e.length===0,errors:e}}function Po(o){return!o||!Array.isArray(o.nodes)?[]:o.nodes.filter(e=>ce(e)!=="decision").map(e=>e.id)}function ce(o){let e=o.data?.nodeType||o.data?.type||o.type;return e==="workflowNode"||e==="custom"||e==="default"?o.id:e}function Ft(o,e){let t=new Map;for(let r of o){let s=r[e];t.has(s)||t.set(s,[]),t.get(s).push(r)}return t}function Yt(o,e,t){let r=e.find(n=>n.data?.conditionalCode||n.conditionalCode);if(!r)throw new C(`Decision node "${o}" has no conditionalCode on its outgoing edges`);let s=r.data?.conditionalCode||r.conditionalCode,i=new Set(e.map(n=>n.target).filter(n=>!t.has(n))),a;try{let c=new Function(`return (${s})`)();a=d=>{let h=c(d);return i.has(h)||w.warn(`[workflow] conditional route from "${o}" returned "${h}" which is not in valid targets: ${[...i].join(", ")}`),h}}catch(n){throw new C(`Failed to compile conditionalCode for "${o}": ${n.message}`)}return a}function st(o,e,t={}){let r;try{r=new Function("invokeAgent","require","console",`return (${e})`)}catch(a){throw new C(`Failed to compile customCode for node "${o}": ${a.message}`)}let s=r(async(...a)=>{let{invokeAgent:n}=await Promise.resolve().then(()=>(z(),K));return n(...a)},typeof le<"u"?le:void 0,console),i=null;return t.outputSchema&&(i=t.outputSchema.jsonSchema||t.outputSchema),{name:o,_isCustomCode:!0,outputSchema:i,execute:async a=>{try{let n=await s(a);return typeof n=="object"&&"success"in n?n:{success:!0,output:n,raw:null}}catch(n){return{success:!1,error:n.message,raw:null}}}}}var C=class extends Error{constructor(e){super(e),this.name="CompilationError"}};export{C as CompilationError,xo as compileGraph,Po as extractSteps,Co as validateGraphConfig};
|
package/dist/graph.d.ts
CHANGED
|
@@ -1,15 +1,23 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
2
|
+
* Returns true when the host process has spawned this workflow with
|
|
3
|
+
* ZIBBY_SESSION_* env vars that should be preserved (not cleared by
|
|
4
|
+
* `clearInheritedSessionEnvForFreshRun`). True when ANY of:
|
|
5
|
+
* - `ZIBBY_TRUST_SESSION_ENV=1` (canonical, consumer-agnostic)
|
|
6
|
+
* - `ZIBBY_KEEP_SESSION_ENV=1` (legacy CLI-side opt-in)
|
|
7
|
+
* - `ZIBBY_RUN_SOURCE=studio` (legacy Studio-specific; deprecated)
|
|
4
8
|
*/
|
|
5
9
|
export function shouldTrustInheritedSessionEnv(): boolean;
|
|
6
10
|
/**
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
+
* If the host has pinned a specific session folder via env (e.g. a desktop
|
|
12
|
+
* app spawning the CLI with ZIBBY_SESSION_PATH already set), return its
|
|
13
|
+
* resolved absolute path. Returns undefined when the host hasn't pinned one.
|
|
14
|
+
*
|
|
15
|
+
* Gated on `ZIBBY_PIN_SESSION_PATH=1` (canonical) OR the legacy
|
|
16
|
+
* `ZIBBY_RUN_SOURCE=studio` (deprecated) so an unrelated process that
|
|
17
|
+
* happens to have ZIBBY_SESSION_PATH in its environment doesn't accidentally
|
|
18
|
+
* land in someone else's session folder.
|
|
11
19
|
*/
|
|
12
|
-
export function
|
|
20
|
+
export function readPinnedSessionPathFromEnv(): any;
|
|
13
21
|
/** Drop stale shell exports so graph + children do not write to an old session folder. */
|
|
14
22
|
export function clearInheritedSessionEnvForFreshRun(): void;
|
|
15
23
|
/**
|
|
@@ -39,6 +47,17 @@ export function resolveWorkflowSession({ cwd, config, initialState, traceFrom, }
|
|
|
39
47
|
sessionId: any;
|
|
40
48
|
sessionTimestamp: any;
|
|
41
49
|
};
|
|
50
|
+
/**
|
|
51
|
+
* If the host has pinned a specific session folder via env (e.g. a desktop
|
|
52
|
+
* app spawning the CLI with ZIBBY_SESSION_PATH already set), return its
|
|
53
|
+
* resolved absolute path. Returns undefined when the host hasn't pinned one.
|
|
54
|
+
*
|
|
55
|
+
* Gated on `ZIBBY_PIN_SESSION_PATH=1` (canonical) OR the legacy
|
|
56
|
+
* `ZIBBY_RUN_SOURCE=studio` (deprecated) so an unrelated process that
|
|
57
|
+
* happens to have ZIBBY_SESSION_PATH in its environment doesn't accidentally
|
|
58
|
+
* land in someone else's session folder.
|
|
59
|
+
*/
|
|
60
|
+
export function readStudioPinnedSessionPathFromEnv(): any;
|
|
42
61
|
export class WorkflowGraph {
|
|
43
62
|
constructor(options?: {});
|
|
44
63
|
nodes: Map<any, any>;
|
|
@@ -51,6 +70,7 @@ export class WorkflowGraph {
|
|
|
51
70
|
nodePrompts: Map<any, any>;
|
|
52
71
|
nodeOptions: Map<any, any>;
|
|
53
72
|
_invokeAgent: any;
|
|
73
|
+
_compiledPrompts: Map<any, any>;
|
|
54
74
|
setStateSchema(schema: any): this;
|
|
55
75
|
getStateSchema(): any;
|
|
56
76
|
addNode(name: any, nodeOrConfig: any, options?: {}): this;
|
|
@@ -88,7 +108,28 @@ export class WorkflowGraph {
|
|
|
88
108
|
_flattenSchema(schema: any, prefix?: string): any;
|
|
89
109
|
_formatLabel(str: any): any;
|
|
90
110
|
_summarizeNodeOutput(nodeName: any, output: any): string[];
|
|
91
|
-
|
|
111
|
+
/**
|
|
112
|
+
* Execute the graph.
|
|
113
|
+
*
|
|
114
|
+
* @param {object} agent User-supplied agent shell (calculateOutputPath, onComplete, cleanup hooks).
|
|
115
|
+
* @param {object} [initialState] Initial state values (cwd, input, config, sessionPath, etc.).
|
|
116
|
+
* @param {object} [options] Run-level options.
|
|
117
|
+
* @param {AbortSignal} [options.signal] External abort signal. When aborted, the engine stops at the next
|
|
118
|
+
* abort-checkpoint, returns `{ stoppedExternally: true }`, and runs cleanup.
|
|
119
|
+
* The legacy stop-file watcher (`.zibby-stop` / `.zibby-studio-stop`) feeds
|
|
120
|
+
* the same internal abort, so all stop paths converge to one return shape.
|
|
121
|
+
* @param {number} [options.strategyAbortTimeoutMs=5000]
|
|
122
|
+
* Engine deadman timer. After abort fires, if a strategy.invoke() call
|
|
123
|
+
* hasn't settled within this many ms, the engine throws AbortError on
|
|
124
|
+
* behalf of graph.run, runs cleanup, and abandons the strategy promise.
|
|
125
|
+
* Protects against strategies (especially third-party) that ignore
|
|
126
|
+
* AbortSignal entirely. Set higher if you have legitimately long-running
|
|
127
|
+
* cleanup paths inside a strategy's abort handler.
|
|
128
|
+
*/
|
|
129
|
+
run(agent: object, initialState?: object, options?: {
|
|
130
|
+
signal?: AbortSignal;
|
|
131
|
+
strategyAbortTimeoutMs?: number;
|
|
132
|
+
}): Promise<{
|
|
92
133
|
success: boolean;
|
|
93
134
|
state: any;
|
|
94
135
|
executionLog: {
|