@zibby/core 0.1.30 → 0.1.33
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/framework/graph.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import{WorkflowState as ee}from"./state.js";import{Node as L,ConditionalNode as te}from"./node.js";import{ContextLoader as oe}from"./context-loader.js";import{mkdirSync as W,existsSync as b,writeFileSync as z,unlinkSync as se}from"fs";import{join as E,resolve as G}from"path";import{config as ne}from"dotenv";import{zodToJsonSchema as H}from"zod-to-json-schema";import re from"handlebars";import{DEFAULT_OUTPUT_BASE as
|
|
1
|
+
import{WorkflowState as ee}from"./state.js";import{Node as L,ConditionalNode as te}from"./node.js";import{ContextLoader as oe}from"./context-loader.js";import{mkdirSync as W,existsSync as b,writeFileSync as z,unlinkSync as se}from"fs";import{join as E,resolve as G}from"path";import{config as ne}from"dotenv";import{zodToJsonSchema as H}from"zod-to-json-schema";import re from"handlebars";import{DEFAULT_OUTPUT_BASE as x,SESSIONS_DIR as ie,SESSION_INFO_FILE as V,CI_ENV_VARS as ce,STUDIO_STOP_REQUEST_FILE as ae}from"./constants.js";import{timeline as S}from"../utils/timeline.js";function de({traceFrom:f,sessionId:e,sessionPath:t,idSource:s,mkdirFresh:o}){if(process.env.ZIBBY_SESSION_LOG==="0"||process.env.ZIBBY_SESSION_LOG==="false")return;const n=typeof process.ppid=="number"?process.ppid:"n/a",r=`[zibby:session] from=${f} pid=${process.pid} ppid=${n} sessionId=${e} source=${s} mkdir=${o?"yes":"no"} path=${t}`;if(console.log(r),(process.env.ZIBBY_TRACE_SESSION==="1"||process.env.ZIBBY_TRACE_SESSION==="true")&&process.env.ZIBBY_SESSION_LOG!=="0"&&process.env.ZIBBY_SESSION_LOG!=="false"){const i=(new Error("session trace").stack||"").split(`
|
|
2
2
|
`).slice(2,14).join(`
|
|
3
3
|
`);console.log(`[zibby:session] stack (${f}):
|
|
4
|
-
${i}`)}}function le(){return process.env.ZIBBY_RUN_SOURCE==="studio"||process.env.ZIBBY_KEEP_SESSION_ENV==="1"||process.env.ZIBBY_KEEP_SESSION_ENV==="true"}function pe(){if(process.env.ZIBBY_RUN_SOURCE!=="studio")return;const f=process.env.ZIBBY_SESSION_PATH;if(!(f==null||String(f).trim()===""))try{return G(String(f).trim())}catch{return String(f).trim()}}function fe(){le()||(delete process.env.ZIBBY_SESSION_PATH,delete process.env.ZIBBY_SESSION_ID)}function ue({sessionPath:f,sessionId:e}){f&&typeof f=="string"&&(process.env.ZIBBY_SESSION_PATH=f),e!=null&&String(e).trim()!==""&&(process.env.ZIBBY_SESSION_ID=String(e).trim())}function he(f={}){const e=ce.map(n=>process.env[n]).find(Boolean),t=Math.random().toString(36).slice(2,6),s=e||`${Date.now()}_${t}`,o=f.paths?.sessionPrefix;return o?`${o}_${s}`:s}function me({cwd:f=process.cwd(),config:e={},initialState:t={},traceFrom:s="resolveWorkflowSession"}={}){let o=t.sessionPath,n=t.sessionTimestamp,r="initialState.sessionPath";if(!o&&process.env.ZIBBY_SESSION_PATH)try{const i=G(String(process.env.ZIBBY_SESSION_PATH));i&&(o=i,r="ZIBBY_SESSION_PATH")}catch{}let c;if(o)c=String(o).split(/[/\\]/).filter(Boolean).pop(),n==null&&(n=Date.now());else{const i=process.env.ZIBBY_SESSION_ID&&String(process.env.ZIBBY_SESSION_ID).trim();if(i)c=i,r="ZIBBY_SESSION_ID";else{const g=e.sessionId!=null?String(e.sessionId).trim():"";g&&g!=="last"?(c=g,r="config.sessionId"):(c=he(e),r="generated")}n=n??Date.now();const u=e.paths?.output||
|
|
5
|
-
\u{1F6D1} Studio stop requested \u2014 ending workflow.`);try{se(l)}catch{}if(e&&typeof e.cleanup=="function")try{await e.cleanup()}catch{}return S.step("Workflow stopped by Studio"),{success:!0,state:d.getAll(),executionLog:O,stoppedByStudio:!0}}const m=this.nodes.get(a);if(!m)throw new Error(`Node '${a}' not found in graph`);const w=JSON.stringify({sessionPath:i,sessionTimestamp:u,currentNode:a,createdAt:new Date().toISOString(),config:d.get("config")}),q=E(i,V);z(q,w,"utf-8");const D=d.get("config")?.paths?.output||
|
|
4
|
+
${i}`)}}function le(){return process.env.ZIBBY_RUN_SOURCE==="studio"||process.env.ZIBBY_KEEP_SESSION_ENV==="1"||process.env.ZIBBY_KEEP_SESSION_ENV==="true"}function pe(){if(process.env.ZIBBY_RUN_SOURCE!=="studio")return;const f=process.env.ZIBBY_SESSION_PATH;if(!(f==null||String(f).trim()===""))try{return G(String(f).trim())}catch{return String(f).trim()}}function fe(){le()||(delete process.env.ZIBBY_SESSION_PATH,delete process.env.ZIBBY_SESSION_ID)}function ue({sessionPath:f,sessionId:e}){f&&typeof f=="string"&&(process.env.ZIBBY_SESSION_PATH=f),e!=null&&String(e).trim()!==""&&(process.env.ZIBBY_SESSION_ID=String(e).trim())}function he(f={}){const e=ce.map(n=>process.env[n]).find(Boolean),t=Math.random().toString(36).slice(2,6),s=e||`${Date.now()}_${t}`,o=f.paths?.sessionPrefix;return o?`${o}_${s}`:s}function me({cwd:f=process.cwd(),config:e={},initialState:t={},traceFrom:s="resolveWorkflowSession"}={}){let o=t.sessionPath,n=t.sessionTimestamp,r="initialState.sessionPath";if(!o&&process.env.ZIBBY_SESSION_PATH)try{const i=G(String(process.env.ZIBBY_SESSION_PATH));i&&(o=i,r="ZIBBY_SESSION_PATH")}catch{}let c;if(o)c=String(o).split(/[/\\]/).filter(Boolean).pop(),n==null&&(n=Date.now());else{const i=process.env.ZIBBY_SESSION_ID&&String(process.env.ZIBBY_SESSION_ID).trim();if(i)c=i,r="ZIBBY_SESSION_ID";else{const g=e.sessionId!=null?String(e.sessionId).trim():"";g&&g!=="last"?(c=g,r="config.sessionId"):(c=he(e),r="generated")}n=n??Date.now();const u=e.paths?.output||x;o=E(f,u,ie,c)}const p=!b(o);return p&&W(o,{recursive:!0}),de({traceFrom:s,sessionId:c,sessionPath:o,idSource:r,mkdirFresh:p}),ue({sessionPath:o,sessionId:c}),{sessionPath:o,sessionId:c,sessionTimestamp:n}}class Oe{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}setStateSchema(e){return this.stateSchema=e,this}getStateSchema(){return this.stateSchema}addNode(e,t,s={}){const o=t instanceof L?t:new L(t);return o.name=e,this.nodes.set(e,o),s.prompt&&this.nodePrompts.set(e,s.prompt),Object.keys(s).length>0&&this.nodeOptions.set(e,s),this}addConditionalNode(e,t){const s=new te({...t,name:e});return this.nodes.set(e,s),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:s}={}){return this.edges.set(e,{conditional:!0,routes:t,labels:s}),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,s,o,n){let r=s;for(let c=e.length-1;c>=0;c--){const p=e[c],i=r;r=()=>p(t,i,o,n)}return r()}serialize(){const e=[],t={};for(const[n,r]of this.nodes){const c=this.nodeTypeMap.get(n)||n;e.push({id:n,type:c,data:{nodeType:c,label:n}});const p=r._isCustomCode||!1,i={};p&&typeof r.execute=="function"&&(i.customCode=r.execute.toString());const u=this.nodePrompts.get(n);if(u&&(i.prompt=u),typeof r.customExecute=="function"&&(i.executeCode=r.customExecute.toString()),r.outputSchema)try{if(typeof r.outputSchema._def<"u"){const P=H(r.outputSchema,{target:"openApi3"}),d=this._flattenJsonSchemaToVariables(P);i.outputSchema={jsonSchema:P,variables:d}}else i.outputSchema={schema:r.outputSchema}}catch(v){console.warn(`Failed to convert schema for ${n}:`,v.message)}const g=(this.resolvedToolsMap||{})[n];g?.toolIds&&(i.tools=g.toolIds),Object.keys(i).length>0&&(t[n]=i)}const s=[];for(const[n,r]of this.edges)if(typeof r=="string")s.push({source:n,target:r});else if(r.conditional){const c=this.conditionalCodeMap.get(n)||r.routes.toString(),p=this._inferConditionalTargets(r.routes),i=r.labels||{};for(const u of p){const g={source:n,target:u,data:{conditionalCode:c}};i[u]&&(g.label=i[u]),s.push(g)}}let o=null;if(this.stateSchema)try{o=H(this.stateSchema,{target:"openApi3"})}catch{o=this.stateSchema}return{nodes:e,edges:s,nodeConfigs:t,stateSchema:o}}_inferConditionalTargets(e){const t=e.toString(),s=new Set,o=/return\s+['"]([^'"]+)['"]/g;let n;for(;(n=o.exec(t))!==null;)s.add(n[1]);return[...s]}_flattenJsonSchemaToVariables(e,t=""){let s=e;if(e.$ref&&e.definitions){const o=e.$ref.replace("#/definitions/","");s=e.definitions[o]||e}return this._flattenSchema(s,t)}_flattenSchema(e,t=""){if(!e||typeof e!="object")return[];const s=[],o=e.properties||{},n=e.required||[];for(const[r,c]of Object.entries(o)){const p=t?`${t}.${r}`:r,i=!n.includes(r);if(s.push({path:p,type:c.type||"unknown",label:c.description||this._formatLabel(r),optional:i}),c.type==="object"&&c.properties){const u=this._flattenSchema(c,p);s.push(...u)}if(c.type==="array"&&c.items?.type==="object"&&c.items.properties){const u=this._flattenSchema(c.items,`${p}[]`);s.push(...u)}}return s}_formatLabel(e){return e.replace(/([A-Z])/g," $1").replace(/^./,t=>t.toUpperCase()).trim()}_summarizeNodeOutput(e,t){if(!t||typeof t!="object")return[];const s=[];t.success!==void 0&&s.push(`Result: ${t.success?"passed":"failed"}`);for(const[o,n]of Object.entries(t))if(!(o==="success"||o==="raw"||o==="nextNode")){if(typeof n=="string"&&n.length<=80)s.push(`${o}: ${n}`);else if(Array.isArray(n)){const r=n.length,c=n.filter(i=>i?.passed===!0).length;if(n.some(i=>i?.passed!==void 0)){const i=r-c;s.push(`${o}: ${c}/${r} passed${i?`, ${i} failed`:""}`)}else s.push(`${o}: ${r} items`)}if(s.length>=4)break}return s}async run(e,t={}){if(!this.entryPoint)throw new Error("No entry point set for graph");const s=t.cwd||process.cwd();ne({path:E(s,".env")});let o=t.config||{};if(!o||Object.keys(o).length===0)try{const l=E(s,".zibby.config.js");b(l)&&(o=(await import(l)).default||{})}catch{}process.env.EXECUTION_ID&&!o.agent?.strictMode&&(o.agent={...o.agent,strictMode:!0});let n=t.agentType;if(!n){const l=o?.agent;l?.provider?n=l.provider:l?.gemini?n="gemini":l?.claude?n="claude":l?.cursor?n="cursor":l?.codex?n="codex":n=process.env.AGENT_TYPE||"cursor"}const r=t.contextConfig||e?.config?.contextConfig||e?.config?.context||o?.context||{};if(this.stateSchema){const l=this.stateSchema.safeParse(t);if(!l.success){const m=l.error.issues.map(w=>`${w.path.join(".")}: ${w.message}`);throw console.error("\u274C Initial state validation failed:"),m.forEach(w=>console.error(` - ${w}`)),new Error(`State validation failed: ${m.join(", ")}`)}S.step("State validated against schema")}const c=pe(),p=t.sessionPath||c;p||fe();const{sessionPath:i,sessionTimestamp:u,sessionId:g}=me({cwd:s,config:o,traceFrom:"WorkflowGraph.run",initialState:{sessionPath:p,sessionTimestamp:t.sessionTimestamp}});S.step(`Session ${g}`);const v=await oe.loadContext(t.specPath||"",s,r);Object.keys(v).length>0&&S.step(`Context loaded: ${Object.keys(v).join(", ")}`);let P=t.outputPath;!P&&t.specPath&&(e?.calculateOutputPath?P=e.calculateOutputPath(t.specPath):console.warn(`\u26A0\uFE0F outputPath not resolved (specPath=${t.specPath})`));const d=new ee({...t,config:o,agentType:n,outputPath:P,sessionPath:i,sessionTimestamp:u,context:v,resolvedTools:this.resolvedToolsMap||{}}),C=new Map;try{await import("@zibby/skills")}catch{}const{getSkill:J}=await import("./skill-registry.js"),M=new Set;for(const[,l]of this.nodes)for(const m of l.config?.skills||[])M.add(m);for(const l of M){const m=J(l);if(typeof m?.middleware=="function")try{const w=await m.middleware();typeof w=="function"&&C.set(l,w)}catch{}}let a=this.entryPoint;const O=[];for(;a&&a!=="END";){const l=E(i,ae);if(b(l)){console.warn(`
|
|
5
|
+
\u{1F6D1} Studio stop requested \u2014 ending workflow.`);try{se(l)}catch{}if(e&&typeof e.cleanup=="function")try{await e.cleanup()}catch{}return S.step("Workflow stopped by Studio"),{success:!0,state:d.getAll(),executionLog:O,stoppedByStudio:!0}}const m=this.nodes.get(a);if(!m)throw new Error(`Node '${a}' not found in graph`);const w=JSON.stringify({sessionPath:i,sessionTimestamp:u,currentNode:a,createdAt:new Date().toISOString(),config:d.get("config")}),q=E(i,V);z(q,w,"utf-8");const D=d.get("config")?.paths?.output||x,K=E(s,D,V);W(E(s,D),{recursive:!0});try{z(K,w,"utf-8")}catch{}const Y=t.onPipelineProgress;if(typeof Y=="function")try{Y({cwd:s,sessionPath:i,sessionId:g,outputBase:d.get("config")?.paths?.output||x,currentNode:a})}catch{}const Q=(this.resolvedToolsMap||{})[a]||null;d.set("_currentNodeTools",Q);const X=d.get("nodeConfigs")||{};d.set("_currentNodeConfig",X[a]||{}),S.nodeStart(a);const R=Date.now(),T=this.nodePrompts.get(a);if(!this._invokeAgent){const _=await import("./agents/index.js");this._invokeAgent=_.invokeAgent}const j=this._invokeAgent,F={state:d,invokeAgent:async(_={},I={})=>{let h=I.prompt||"";if(T)try{h=re.compile(T,{noEscape:!0})(_)}catch(y){throw console.error(`\u274C Template rendering failed for node '${a}':`,y.message),new Error(`Template rendering failed: ${y.message}`,{cause:y})}else if(!h)throw new Error(`No prompt template configured for node '${a}' and no prompt provided in options`);const B={state:d.getAll(),images:I.images||[]},A={model:I.model||d.get("model"),workspace:d.get("workspace"),schema:I.schema,...I};return j(h,B,A)},_coreInvokeAgent:j,agent:e,nodeId:a,promptTemplate:T,getPromptTemplate:()=>T,...d.getAll()};try{const _=(m.config?.skills||[]).map($=>C.get($)).filter(Boolean),I=[...this.middleware,..._];let h;I.length>0?h=await this._composeMiddleware(I,a,async()=>m.execute(F,d),d.getAll(),d):h=await m.execute(F,d);const B=Date.now()-R;if(O.push({node:a,success:h.success,duration:B,timestamp:new Date().toISOString()}),!h.success){if(String(h.error||"").includes("Stopped from Zibby Studio")){if(S.step("Workflow stopped by Studio"),d.set("stoppedByStudio",!0),e&&typeof e.cleanup=="function")try{await e.cleanup()}catch{}return{success:!0,state:d.getAll(),executionLog:O,stoppedByStudio:!0}}d.append("errors",{node:a,error:h.error});const N=m.config?.retries||0,U=`${a}_retries`,k=d.getAll()[U]||0;if(k<N){S.stepInfo(`Retrying (attempt ${k+1}/${N})`),d.update({[U]:k+1,[`${a}_raw`]:h.raw});continue}throw S.nodeFailed(a,h.error,{duration:B}),new Error(`Node '${a}' failed after ${k} attempts: ${h.error}`)}d.update({[a]:h.output});const A=this._summarizeNodeOutput(a,h.output);S.nodeComplete(a,{duration:B,details:A});const y=this.edges.get(a);if(!y)a="END";else if(y.conditional){const $=d.getAll(),N=y.routes($);S.route(a,N),a=N}else a=y}catch(_){throw S.isInsideNode&&S.nodeFailed(a,_.message,{duration:Date.now()-R}),d.set("failed",!0),d.set("failedAt",a),_}}S.graphComplete();const Z={success:!0,state:d.getAll(),executionLog:O};return e&&typeof e.onComplete=="function"&&await e.onComplete(Z),Z}}export{Oe as WorkflowGraph,fe as clearInheritedSessionEnvForFreshRun,he as generateWorkflowSessionId,pe as readStudioPinnedSessionPathFromEnv,me as resolveWorkflowSession,le as shouldTrustInheritedSessionEnv,ue as syncProcessEnvToSession};
|
package/dist/package.json
CHANGED
package/package.json
CHANGED
|
@@ -16,7 +16,7 @@ import { SKILLS } from '@zibby/core';
|
|
|
16
16
|
|
|
17
17
|
export const CHAT_CONFIG = {
|
|
18
18
|
name: 'zibby_chat',
|
|
19
|
-
skills: [SKILLS.CORE_TOOLS, SKILLS.SKILL_INSTALLER, SKILLS.CHAT_MEMORY],
|
|
19
|
+
skills: [SKILLS.CORE_TOOLS, SKILLS.SKILL_INSTALLER, SKILLS.CHAT_MEMORY, SKILLS.WORKFLOW_BUILDER],
|
|
20
20
|
timeout: 0,
|
|
21
21
|
|
|
22
22
|
systemPrompt: `You are Zibby, a helpful AI assistant. Capabilities come from installed skills.
|
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
{
|
|
2
|
+
"nodes": [
|
|
3
|
+
{
|
|
4
|
+
"id": "preflight",
|
|
5
|
+
"type": "preflight",
|
|
6
|
+
"data": {
|
|
7
|
+
"nodeType": "preflight",
|
|
8
|
+
"label": "preflight"
|
|
9
|
+
}
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"id": "execute_live",
|
|
13
|
+
"type": "execute_live",
|
|
14
|
+
"data": {
|
|
15
|
+
"nodeType": "execute_live",
|
|
16
|
+
"label": "execute_live"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"id": "generate_script",
|
|
21
|
+
"type": "generate_script",
|
|
22
|
+
"data": {
|
|
23
|
+
"nodeType": "generate_script",
|
|
24
|
+
"label": "generate_script"
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
],
|
|
28
|
+
"edges": [
|
|
29
|
+
{
|
|
30
|
+
"source": "preflight",
|
|
31
|
+
"target": "execute_live"
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"source": "generate_script",
|
|
35
|
+
"target": "END"
|
|
36
|
+
}
|
|
37
|
+
],
|
|
38
|
+
"nodeConfigs": {
|
|
39
|
+
"preflight": {
|
|
40
|
+
"outputSchema": {
|
|
41
|
+
"jsonSchema": {
|
|
42
|
+
"type": "object",
|
|
43
|
+
"properties": {
|
|
44
|
+
"title": {
|
|
45
|
+
"type": "string",
|
|
46
|
+
"description": "Concise test title (5-10 words, action-oriented). Prefix with ticket ID if found."
|
|
47
|
+
},
|
|
48
|
+
"assertions": {
|
|
49
|
+
"type": "array",
|
|
50
|
+
"items": {
|
|
51
|
+
"type": "object",
|
|
52
|
+
"properties": {
|
|
53
|
+
"description": {
|
|
54
|
+
"type": "string",
|
|
55
|
+
"description": "What to verify (e.g., \"User is redirected to dashboard\")"
|
|
56
|
+
},
|
|
57
|
+
"expected": {
|
|
58
|
+
"type": "string",
|
|
59
|
+
"description": "What the expected outcome looks like (e.g., \"URL contains /dashboard\")"
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
"required": [
|
|
63
|
+
"description",
|
|
64
|
+
"expected"
|
|
65
|
+
],
|
|
66
|
+
"additionalProperties": false
|
|
67
|
+
},
|
|
68
|
+
"description": "Every expected result from the spec as a verifiable assertion"
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
"required": [
|
|
72
|
+
"title",
|
|
73
|
+
"assertions"
|
|
74
|
+
],
|
|
75
|
+
"additionalProperties": false
|
|
76
|
+
},
|
|
77
|
+
"variables": [
|
|
78
|
+
{
|
|
79
|
+
"path": "title",
|
|
80
|
+
"type": "string",
|
|
81
|
+
"label": "Concise test title (5-10 words, action-oriented). Prefix with ticket ID if found.",
|
|
82
|
+
"optional": false
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
"path": "assertions",
|
|
86
|
+
"type": "array",
|
|
87
|
+
"label": "Every expected result from the spec as a verifiable assertion",
|
|
88
|
+
"optional": false
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
"path": "assertions[].description",
|
|
92
|
+
"type": "string",
|
|
93
|
+
"label": "What to verify (e.g., \"User is redirected to dashboard\")",
|
|
94
|
+
"optional": false
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
"path": "assertions[].expected",
|
|
98
|
+
"type": "string",
|
|
99
|
+
"label": "What the expected outcome looks like (e.g., \"URL contains /dashboard\")",
|
|
100
|
+
"optional": false
|
|
101
|
+
}
|
|
102
|
+
]
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
"execute_live": {
|
|
106
|
+
"outputSchema": {
|
|
107
|
+
"jsonSchema": {
|
|
108
|
+
"type": "object",
|
|
109
|
+
"properties": {
|
|
110
|
+
"success": {
|
|
111
|
+
"type": "boolean",
|
|
112
|
+
"description": "Whether the test execution completed successfully"
|
|
113
|
+
},
|
|
114
|
+
"steps": {
|
|
115
|
+
"type": "array",
|
|
116
|
+
"items": {
|
|
117
|
+
"type": "string"
|
|
118
|
+
},
|
|
119
|
+
"description": "Array of test steps executed"
|
|
120
|
+
},
|
|
121
|
+
"finalUrl": {
|
|
122
|
+
"type": "string",
|
|
123
|
+
"description": "Final URL after test execution"
|
|
124
|
+
},
|
|
125
|
+
"actions": {
|
|
126
|
+
"type": "array",
|
|
127
|
+
"description": "Detailed array of actions performed with descriptions and reasoning"
|
|
128
|
+
},
|
|
129
|
+
"assertions": {
|
|
130
|
+
"type": "array",
|
|
131
|
+
"items": {
|
|
132
|
+
"type": "object",
|
|
133
|
+
"properties": {
|
|
134
|
+
"description": {
|
|
135
|
+
"type": "string",
|
|
136
|
+
"description": "What was verified"
|
|
137
|
+
},
|
|
138
|
+
"passed": {
|
|
139
|
+
"type": "boolean",
|
|
140
|
+
"description": "Whether the assertion passed"
|
|
141
|
+
},
|
|
142
|
+
"verifiedAfterAction": {
|
|
143
|
+
"type": "number",
|
|
144
|
+
"description": "Index of the action after which this was verified (0-based, matches actions array index) - REQUIRED"
|
|
145
|
+
},
|
|
146
|
+
"evidence": {
|
|
147
|
+
"type": "string",
|
|
148
|
+
"description": "Brief evidence of what was observed"
|
|
149
|
+
}
|
|
150
|
+
},
|
|
151
|
+
"required": [
|
|
152
|
+
"description",
|
|
153
|
+
"passed",
|
|
154
|
+
"verifiedAfterAction"
|
|
155
|
+
],
|
|
156
|
+
"additionalProperties": false
|
|
157
|
+
},
|
|
158
|
+
"description": "Array of assertions made during test"
|
|
159
|
+
},
|
|
160
|
+
"waits": {
|
|
161
|
+
"type": "array",
|
|
162
|
+
"description": "Array of waits needed for proper test execution"
|
|
163
|
+
},
|
|
164
|
+
"evidenceScreenshots": {
|
|
165
|
+
"type": "array",
|
|
166
|
+
"items": {
|
|
167
|
+
"type": "object",
|
|
168
|
+
"properties": {
|
|
169
|
+
"filename": {
|
|
170
|
+
"type": "string",
|
|
171
|
+
"description": "Descriptive filename pattern: {step-number}-{action-or-state}.png"
|
|
172
|
+
},
|
|
173
|
+
"description": {
|
|
174
|
+
"type": "string",
|
|
175
|
+
"description": "What the screenshot shows and why it is evidence"
|
|
176
|
+
},
|
|
177
|
+
"verdict": {
|
|
178
|
+
"type": "string",
|
|
179
|
+
"enum": [
|
|
180
|
+
"pass",
|
|
181
|
+
"fail",
|
|
182
|
+
"info"
|
|
183
|
+
],
|
|
184
|
+
"description": "Test verdict: pass/fail for validation points, info for checkpoints"
|
|
185
|
+
}
|
|
186
|
+
},
|
|
187
|
+
"required": [
|
|
188
|
+
"filename",
|
|
189
|
+
"description",
|
|
190
|
+
"verdict"
|
|
191
|
+
],
|
|
192
|
+
"additionalProperties": false
|
|
193
|
+
},
|
|
194
|
+
"description": "Array of screenshots taken at key validation points throughout the test"
|
|
195
|
+
},
|
|
196
|
+
"browserClosed": {
|
|
197
|
+
"type": "boolean",
|
|
198
|
+
"description": "Whether the browser was properly closed (should always be true)"
|
|
199
|
+
},
|
|
200
|
+
"notes": {
|
|
201
|
+
"type": "string",
|
|
202
|
+
"description": "Additional notes or observations. REQUIRED when success=false to explain why test failed or could not execute"
|
|
203
|
+
}
|
|
204
|
+
},
|
|
205
|
+
"required": [
|
|
206
|
+
"success",
|
|
207
|
+
"steps",
|
|
208
|
+
"browserClosed"
|
|
209
|
+
],
|
|
210
|
+
"additionalProperties": false
|
|
211
|
+
},
|
|
212
|
+
"variables": [
|
|
213
|
+
{
|
|
214
|
+
"path": "success",
|
|
215
|
+
"type": "boolean",
|
|
216
|
+
"label": "Whether the test execution completed successfully",
|
|
217
|
+
"optional": false
|
|
218
|
+
},
|
|
219
|
+
{
|
|
220
|
+
"path": "steps",
|
|
221
|
+
"type": "array",
|
|
222
|
+
"label": "Array of test steps executed",
|
|
223
|
+
"optional": false
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
"path": "finalUrl",
|
|
227
|
+
"type": "string",
|
|
228
|
+
"label": "Final URL after test execution",
|
|
229
|
+
"optional": true
|
|
230
|
+
},
|
|
231
|
+
{
|
|
232
|
+
"path": "actions",
|
|
233
|
+
"type": "array",
|
|
234
|
+
"label": "Detailed array of actions performed with descriptions and reasoning",
|
|
235
|
+
"optional": true
|
|
236
|
+
},
|
|
237
|
+
{
|
|
238
|
+
"path": "assertions",
|
|
239
|
+
"type": "array",
|
|
240
|
+
"label": "Array of assertions made during test",
|
|
241
|
+
"optional": true
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
"path": "assertions[].description",
|
|
245
|
+
"type": "string",
|
|
246
|
+
"label": "What was verified",
|
|
247
|
+
"optional": false
|
|
248
|
+
},
|
|
249
|
+
{
|
|
250
|
+
"path": "assertions[].passed",
|
|
251
|
+
"type": "boolean",
|
|
252
|
+
"label": "Whether the assertion passed",
|
|
253
|
+
"optional": false
|
|
254
|
+
},
|
|
255
|
+
{
|
|
256
|
+
"path": "assertions[].verifiedAfterAction",
|
|
257
|
+
"type": "number",
|
|
258
|
+
"label": "Index of the action after which this was verified (0-based, matches actions array index) - REQUIRED",
|
|
259
|
+
"optional": false
|
|
260
|
+
},
|
|
261
|
+
{
|
|
262
|
+
"path": "assertions[].evidence",
|
|
263
|
+
"type": "string",
|
|
264
|
+
"label": "Brief evidence of what was observed",
|
|
265
|
+
"optional": true
|
|
266
|
+
},
|
|
267
|
+
{
|
|
268
|
+
"path": "waits",
|
|
269
|
+
"type": "array",
|
|
270
|
+
"label": "Array of waits needed for proper test execution",
|
|
271
|
+
"optional": true
|
|
272
|
+
},
|
|
273
|
+
{
|
|
274
|
+
"path": "evidenceScreenshots",
|
|
275
|
+
"type": "array",
|
|
276
|
+
"label": "Array of screenshots taken at key validation points throughout the test",
|
|
277
|
+
"optional": true
|
|
278
|
+
},
|
|
279
|
+
{
|
|
280
|
+
"path": "evidenceScreenshots[].filename",
|
|
281
|
+
"type": "string",
|
|
282
|
+
"label": "Descriptive filename pattern: {step-number}-{action-or-state}.png",
|
|
283
|
+
"optional": false
|
|
284
|
+
},
|
|
285
|
+
{
|
|
286
|
+
"path": "evidenceScreenshots[].description",
|
|
287
|
+
"type": "string",
|
|
288
|
+
"label": "What the screenshot shows and why it is evidence",
|
|
289
|
+
"optional": false
|
|
290
|
+
},
|
|
291
|
+
{
|
|
292
|
+
"path": "evidenceScreenshots[].verdict",
|
|
293
|
+
"type": "string",
|
|
294
|
+
"label": "Test verdict: pass/fail for validation points, info for checkpoints",
|
|
295
|
+
"optional": false
|
|
296
|
+
},
|
|
297
|
+
{
|
|
298
|
+
"path": "browserClosed",
|
|
299
|
+
"type": "boolean",
|
|
300
|
+
"label": "Whether the browser was properly closed (should always be true)",
|
|
301
|
+
"optional": false
|
|
302
|
+
},
|
|
303
|
+
{
|
|
304
|
+
"path": "notes",
|
|
305
|
+
"type": "string",
|
|
306
|
+
"label": "Additional notes or observations. REQUIRED when success=false to explain why test failed or could not execute",
|
|
307
|
+
"optional": true
|
|
308
|
+
}
|
|
309
|
+
]
|
|
310
|
+
}
|
|
311
|
+
},
|
|
312
|
+
"generate_script": {
|
|
313
|
+
"outputSchema": {
|
|
314
|
+
"jsonSchema": {
|
|
315
|
+
"type": "object",
|
|
316
|
+
"properties": {
|
|
317
|
+
"success": {
|
|
318
|
+
"type": "boolean"
|
|
319
|
+
},
|
|
320
|
+
"scriptPath": {
|
|
321
|
+
"type": "string"
|
|
322
|
+
},
|
|
323
|
+
"method": {
|
|
324
|
+
"type": "string"
|
|
325
|
+
}
|
|
326
|
+
},
|
|
327
|
+
"required": [
|
|
328
|
+
"success",
|
|
329
|
+
"scriptPath",
|
|
330
|
+
"method"
|
|
331
|
+
],
|
|
332
|
+
"additionalProperties": false
|
|
333
|
+
},
|
|
334
|
+
"variables": [
|
|
335
|
+
{
|
|
336
|
+
"path": "success",
|
|
337
|
+
"type": "boolean",
|
|
338
|
+
"label": "Success",
|
|
339
|
+
"optional": false
|
|
340
|
+
},
|
|
341
|
+
{
|
|
342
|
+
"path": "scriptPath",
|
|
343
|
+
"type": "string",
|
|
344
|
+
"label": "Script Path",
|
|
345
|
+
"optional": false
|
|
346
|
+
},
|
|
347
|
+
{
|
|
348
|
+
"path": "method",
|
|
349
|
+
"type": "string",
|
|
350
|
+
"label": "Method",
|
|
351
|
+
"optional": false
|
|
352
|
+
}
|
|
353
|
+
]
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
},
|
|
357
|
+
"stateSchema": null
|
|
358
|
+
}
|