lea-GEO / scripts /verify-dify-dsl.py
hsmm's picture
Initial commit for HF Space
35bdde1
import argparse
import sys
from typing import Any
import yaml
def fail(msg: str) -> None:
print(f"ERROR: {msg}", file=sys.stderr)
raise SystemExit(1)
def expect_type(value: Any, t: type, label: str) -> None:
if not isinstance(value, t):
fail(f"{label} must be {t.__name__}, got {type(value).__name__}")
def main() -> int:
ap = argparse.ArgumentParser()
ap.add_argument("--path", required=True)
args = ap.parse_args()
with open(args.path, "r", encoding="utf-8") as f:
doc = yaml.safe_load(f)
expect_type(doc, dict, "root")
if doc.get("kind") != "app":
fail("root.kind must be 'app'")
version = doc.get("version")
if not isinstance(version, (str, int, float)):
fail("root.version must be a scalar")
app = doc.get("app")
expect_type(app, dict, "root.app")
if app.get("mode") != "workflow":
fail("app.mode must be 'workflow'")
if not app.get("name"):
fail("app.name is required")
workflow = doc.get("workflow")
expect_type(workflow, dict, "root.workflow")
graph = workflow.get("graph")
expect_type(graph, dict, "workflow.graph")
nodes = graph.get("nodes")
edges = graph.get("edges")
expect_type(nodes, list, "workflow.graph.nodes")
expect_type(edges, list, "workflow.graph.edges")
if not nodes:
fail("workflow.graph.nodes must be non-empty")
node_ids: set[str] = set()
node_types: set[str] = set()
for i, n in enumerate(nodes):
expect_type(n, dict, f"node[{i}]")
nid = n.get("id")
if not isinstance(nid, str) or not nid:
fail(f"node[{i}].id must be non-empty string")
if nid in node_ids:
fail(f"duplicate node id: {nid}")
node_ids.add(nid)
data = n.get("data") or {}
if isinstance(data, dict):
ntype = data.get("type")
if isinstance(ntype, str):
node_types.add(ntype)
# Minimal sanity: ensure a workflow has start/end nodes.
if "start" not in node_types:
fail("no start node found (node.data.type == 'start')")
if "end" not in node_types:
fail("no end node found (node.data.type == 'end')")
for i, e in enumerate(edges):
expect_type(e, dict, f"edge[{i}]")
src = e.get("source")
tgt = e.get("target")
if src not in node_ids:
fail(f"edge[{i}].source references unknown node: {src}")
if tgt not in node_ids:
fail(f"edge[{i}].target references unknown node: {tgt}")
print(f"OK: {args.path} looks like a Dify app DSL (kind=app, mode=workflow, nodes={len(nodes)}, edges={len(edges)}).")
return 0
if __name__ == "__main__":
raise SystemExit(main())