@datatechsolutions/ui 2.11.1 → 2.11.3

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.
Files changed (99) hide show
  1. package/dist/astrlabe/contracts.d.mts +293 -0
  2. package/dist/astrlabe/contracts.d.ts +293 -0
  3. package/dist/astrlabe/contracts.js +5 -0
  4. package/dist/astrlabe/contracts.js.map +1 -0
  5. package/dist/astrlabe/contracts.mjs +4 -0
  6. package/dist/astrlabe/contracts.mjs.map +1 -0
  7. package/dist/astrlabe/graph-node.d.mts +28 -0
  8. package/dist/astrlabe/graph-node.d.ts +28 -0
  9. package/dist/astrlabe/graph-node.js +26 -0
  10. package/dist/astrlabe/graph-node.js.map +1 -0
  11. package/dist/astrlabe/graph-node.mjs +5 -0
  12. package/dist/astrlabe/graph-node.mjs.map +1 -0
  13. package/dist/astrlabe/index.d.mts +707 -0
  14. package/dist/astrlabe/index.d.ts +707 -0
  15. package/dist/astrlabe/index.js +3247 -0
  16. package/dist/astrlabe/index.js.map +1 -0
  17. package/dist/astrlabe/index.mjs +2956 -0
  18. package/dist/astrlabe/index.mjs.map +1 -0
  19. package/dist/astrlabe/utils.d.mts +71 -0
  20. package/dist/astrlabe/utils.d.ts +71 -0
  21. package/dist/astrlabe/utils.js +30 -0
  22. package/dist/astrlabe/utils.js.map +1 -0
  23. package/dist/astrlabe/utils.mjs +5 -0
  24. package/dist/astrlabe/utils.mjs.map +1 -0
  25. package/dist/astrlabe/workflow-canvas.d.mts +5 -0
  26. package/dist/astrlabe/workflow-canvas.d.ts +5 -0
  27. package/dist/astrlabe/workflow-canvas.js +19 -0
  28. package/dist/astrlabe/workflow-canvas.js.map +1 -0
  29. package/dist/astrlabe/workflow-canvas.mjs +10 -0
  30. package/dist/astrlabe/workflow-canvas.mjs.map +1 -0
  31. package/dist/astrlabe/workflow-preview-canvas.d.mts +10 -0
  32. package/dist/astrlabe/workflow-preview-canvas.d.ts +10 -0
  33. package/dist/astrlabe/workflow-preview-canvas.js +28 -0
  34. package/dist/astrlabe/workflow-preview-canvas.js.map +1 -0
  35. package/dist/astrlabe/workflow-preview-canvas.mjs +26 -0
  36. package/dist/astrlabe/workflow-preview-canvas.mjs.map +1 -0
  37. package/dist/chunk-3GE3MBUZ.js +279 -0
  38. package/dist/chunk-3GE3MBUZ.js.map +1 -0
  39. package/dist/chunk-55H6WZQP.js +5 -0
  40. package/dist/chunk-55H6WZQP.js.map +1 -0
  41. package/dist/chunk-7VJ7CMMT.mjs +96 -0
  42. package/dist/chunk-7VJ7CMMT.mjs.map +1 -0
  43. package/dist/chunk-BLNXRUC4.mjs +276 -0
  44. package/dist/chunk-BLNXRUC4.mjs.map +1 -0
  45. package/dist/chunk-D2JF6C3E.mjs +46 -0
  46. package/dist/chunk-D2JF6C3E.mjs.map +1 -0
  47. package/dist/chunk-JB6RNAD2.mjs +4 -0
  48. package/dist/chunk-JB6RNAD2.mjs.map +1 -0
  49. package/dist/chunk-LJSJMBLO.mjs +7177 -0
  50. package/dist/chunk-LJSJMBLO.mjs.map +1 -0
  51. package/dist/chunk-OZNTQROP.mjs +39 -0
  52. package/dist/chunk-OZNTQROP.mjs.map +1 -0
  53. package/dist/chunk-P4YYEM4B.js +44 -0
  54. package/dist/chunk-P4YYEM4B.js.map +1 -0
  55. package/dist/chunk-PBKTXX4Y.js +20756 -0
  56. package/dist/chunk-PBKTXX4Y.js.map +1 -0
  57. package/dist/chunk-PWBWP5FJ.js +197 -0
  58. package/dist/chunk-PWBWP5FJ.js.map +1 -0
  59. package/dist/chunk-QWG2FMUN.mjs +60 -0
  60. package/dist/chunk-QWG2FMUN.mjs.map +1 -0
  61. package/dist/chunk-S7KHTUHA.js +65 -0
  62. package/dist/chunk-S7KHTUHA.js.map +1 -0
  63. package/dist/chunk-TLPPVL3W.mjs +189 -0
  64. package/dist/chunk-TLPPVL3W.mjs.map +1 -0
  65. package/dist/chunk-UZ3CMNUJ.js +49 -0
  66. package/dist/chunk-UZ3CMNUJ.js.map +1 -0
  67. package/dist/chunk-XAQME7DD.js +7238 -0
  68. package/dist/chunk-XAQME7DD.js.map +1 -0
  69. package/dist/chunk-XO7IYJSF.mjs +20022 -0
  70. package/dist/chunk-XO7IYJSF.mjs.map +1 -0
  71. package/dist/chunk-YXN2K77G.js +102 -0
  72. package/dist/chunk-YXN2K77G.js.map +1 -0
  73. package/dist/dynamic-island-confirm-Cbxh-sta.d.mts +52 -0
  74. package/dist/dynamic-island-confirm-Cbxh-sta.d.ts +52 -0
  75. package/dist/index.d.mts +4771 -0
  76. package/dist/index.d.ts +4771 -0
  77. package/dist/index.js +2892 -0
  78. package/dist/index.js.map +1 -0
  79. package/dist/index.mjs +7 -0
  80. package/dist/index.mjs.map +1 -0
  81. package/dist/lib/i18n-context.d.mts +36 -0
  82. package/dist/lib/i18n-context.d.ts +36 -0
  83. package/dist/lib/i18n-context.js +29 -0
  84. package/dist/lib/i18n-context.js.map +1 -0
  85. package/dist/lib/i18n-context.mjs +4 -0
  86. package/dist/lib/i18n-context.mjs.map +1 -0
  87. package/dist/lib/router-context.d.mts +35 -0
  88. package/dist/lib/router-context.d.ts +35 -0
  89. package/dist/lib/router-context.js +25 -0
  90. package/dist/lib/router-context.js.map +1 -0
  91. package/dist/lib/router-context.mjs +4 -0
  92. package/dist/lib/router-context.mjs.map +1 -0
  93. package/dist/use-haptic-RDQNJYBE.js +17 -0
  94. package/dist/use-haptic-RDQNJYBE.js.map +1 -0
  95. package/dist/use-haptic-TCMOLPGA.mjs +4 -0
  96. package/dist/use-haptic-TCMOLPGA.mjs.map +1 -0
  97. package/dist/workflow-canvas-CJwGehdk.d.mts +241 -0
  98. package/dist/workflow-canvas-DSm0iyof.d.ts +241 -0
  99. package/package.json +2 -1
@@ -0,0 +1,71 @@
1
+ import { WorkflowNodeType, LogicNodeConfig, WorkflowGraph } from './contracts.mjs';
2
+ import { Node, Edge } from '@xyflow/react';
3
+
4
+ /**
5
+ * Layout Engine
6
+ * =============
7
+ * Auto-layout for workflow graphs using @dagrejs/dagre.
8
+ * Pure utility — no React dependencies.
9
+ */
10
+
11
+ /** Layout direction: free means no auto-layout is applied. */
12
+ type LayoutDirection = 'free' | 'LR' | 'TB';
13
+ /**
14
+ * Apply dagre layout to the given nodes and edges.
15
+ * Returns a new array of nodes with updated positions.
16
+ * Group child nodes (parentId set) and note nodes are excluded from layout.
17
+ */
18
+ declare function applyDagreLayout(nodes: Node[], edges: Edge[], direction: Exclude<LayoutDirection, 'free'>): Node[];
19
+
20
+ /**
21
+ * Logic Node Default Configs
22
+ * ==========================
23
+ * Factory function to create default configs for each logic node type.
24
+ */
25
+
26
+ declare function createDefaultLogicNodeConfig(nodeType: WorkflowNodeType): LogicNodeConfig | null;
27
+
28
+ /**
29
+ * Workflow Validator
30
+ * =================
31
+ * Validates the workflow graph before publishing.
32
+ * Ensures the graph forms a valid DAG with proper node connections.
33
+ */
34
+
35
+ type ValidationResult = {
36
+ valid: boolean;
37
+ errors: string[];
38
+ };
39
+ /**
40
+ * Validate a workflow graph for publishing.
41
+ * Checks:
42
+ * - At least one agent node exists
43
+ * - All edges have valid source/target nodes
44
+ * - No orphan nodes (every node has at least one connection, except note nodes)
45
+ * - Tool nodes connect to agent nodes only
46
+ * - Agent chain forms a valid DAG (no cycles)
47
+ * - Rule nodes have incoming edges from agents
48
+ * - Logic node constraints (start/end uniqueness, config validation)
49
+ * - New node type validations (answer, question_classifier, parameter_extractor, etc.)
50
+ */
51
+ declare function validateWorkflowGraph(graph: WorkflowGraph): ValidationResult;
52
+ /**
53
+ * Topologically sort agent nodes from the graph edges.
54
+ * Returns agent entityIds in execution order.
55
+ * Logic nodes are skipped — only agent entityIds are returned.
56
+ */
57
+ declare function topologicalSortAgents(graph: WorkflowGraph): string[];
58
+
59
+ /**
60
+ * Agent ELO Tier
61
+ * ==============
62
+ * Derives difficulty tier from agent ELO rating.
63
+ * Used in node palette, agent flow node, and agent modal.
64
+ */
65
+ type AgentTier = {
66
+ key: 'beginner' | 'intermediate' | 'advanced' | 'expert';
67
+ pillColor: string;
68
+ };
69
+ declare function getAgentTier(elo: number | undefined): AgentTier;
70
+
71
+ export { type AgentTier, type LayoutDirection, applyDagreLayout, createDefaultLogicNodeConfig, getAgentTier, topologicalSortAgents, validateWorkflowGraph };
@@ -0,0 +1,71 @@
1
+ import { WorkflowNodeType, LogicNodeConfig, WorkflowGraph } from './contracts.js';
2
+ import { Node, Edge } from '@xyflow/react';
3
+
4
+ /**
5
+ * Layout Engine
6
+ * =============
7
+ * Auto-layout for workflow graphs using @dagrejs/dagre.
8
+ * Pure utility — no React dependencies.
9
+ */
10
+
11
+ /** Layout direction: free means no auto-layout is applied. */
12
+ type LayoutDirection = 'free' | 'LR' | 'TB';
13
+ /**
14
+ * Apply dagre layout to the given nodes and edges.
15
+ * Returns a new array of nodes with updated positions.
16
+ * Group child nodes (parentId set) and note nodes are excluded from layout.
17
+ */
18
+ declare function applyDagreLayout(nodes: Node[], edges: Edge[], direction: Exclude<LayoutDirection, 'free'>): Node[];
19
+
20
+ /**
21
+ * Logic Node Default Configs
22
+ * ==========================
23
+ * Factory function to create default configs for each logic node type.
24
+ */
25
+
26
+ declare function createDefaultLogicNodeConfig(nodeType: WorkflowNodeType): LogicNodeConfig | null;
27
+
28
+ /**
29
+ * Workflow Validator
30
+ * =================
31
+ * Validates the workflow graph before publishing.
32
+ * Ensures the graph forms a valid DAG with proper node connections.
33
+ */
34
+
35
+ type ValidationResult = {
36
+ valid: boolean;
37
+ errors: string[];
38
+ };
39
+ /**
40
+ * Validate a workflow graph for publishing.
41
+ * Checks:
42
+ * - At least one agent node exists
43
+ * - All edges have valid source/target nodes
44
+ * - No orphan nodes (every node has at least one connection, except note nodes)
45
+ * - Tool nodes connect to agent nodes only
46
+ * - Agent chain forms a valid DAG (no cycles)
47
+ * - Rule nodes have incoming edges from agents
48
+ * - Logic node constraints (start/end uniqueness, config validation)
49
+ * - New node type validations (answer, question_classifier, parameter_extractor, etc.)
50
+ */
51
+ declare function validateWorkflowGraph(graph: WorkflowGraph): ValidationResult;
52
+ /**
53
+ * Topologically sort agent nodes from the graph edges.
54
+ * Returns agent entityIds in execution order.
55
+ * Logic nodes are skipped — only agent entityIds are returned.
56
+ */
57
+ declare function topologicalSortAgents(graph: WorkflowGraph): string[];
58
+
59
+ /**
60
+ * Agent ELO Tier
61
+ * ==============
62
+ * Derives difficulty tier from agent ELO rating.
63
+ * Used in node palette, agent flow node, and agent modal.
64
+ */
65
+ type AgentTier = {
66
+ key: 'beginner' | 'intermediate' | 'advanced' | 'expert';
67
+ pillColor: string;
68
+ };
69
+ declare function getAgentTier(elo: number | undefined): AgentTier;
70
+
71
+ export { type AgentTier, type LayoutDirection, applyDagreLayout, createDefaultLogicNodeConfig, getAgentTier, topologicalSortAgents, validateWorkflowGraph };
@@ -0,0 +1,30 @@
1
+ "use client";
2
+ 'use strict';
3
+
4
+ var chunk3GE3MBUZ_js = require('../chunk-3GE3MBUZ.js');
5
+ var chunkPWBWP5FJ_js = require('../chunk-PWBWP5FJ.js');
6
+
7
+
8
+
9
+ Object.defineProperty(exports, "topologicalSortAgents", {
10
+ enumerable: true,
11
+ get: function () { return chunk3GE3MBUZ_js.topologicalSortAgents; }
12
+ });
13
+ Object.defineProperty(exports, "validateWorkflowGraph", {
14
+ enumerable: true,
15
+ get: function () { return chunk3GE3MBUZ_js.validateWorkflowGraph; }
16
+ });
17
+ Object.defineProperty(exports, "applyDagreLayout", {
18
+ enumerable: true,
19
+ get: function () { return chunkPWBWP5FJ_js.applyDagreLayout; }
20
+ });
21
+ Object.defineProperty(exports, "createDefaultLogicNodeConfig", {
22
+ enumerable: true,
23
+ get: function () { return chunkPWBWP5FJ_js.createDefaultLogicNodeConfig; }
24
+ });
25
+ Object.defineProperty(exports, "getAgentTier", {
26
+ enumerable: true,
27
+ get: function () { return chunkPWBWP5FJ_js.getAgentTier; }
28
+ });
29
+ //# sourceMappingURL=utils.js.map
30
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"utils.js"}
@@ -0,0 +1,5 @@
1
+ "use client";
2
+ export { topologicalSortAgents, validateWorkflowGraph } from '../chunk-BLNXRUC4.mjs';
3
+ export { applyDagreLayout, createDefaultLogicNodeConfig, getAgentTier } from '../chunk-TLPPVL3W.mjs';
4
+ //# sourceMappingURL=utils.mjs.map
5
+ //# sourceMappingURL=utils.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"utils.mjs"}
@@ -0,0 +1,5 @@
1
+ import 'react/jsx-runtime';
2
+ import 'react';
3
+ export { i as Workspace, h as WorkspaceProps } from '../workflow-canvas-CJwGehdk.mjs';
4
+ import '@xyflow/react';
5
+ import './contracts.mjs';
@@ -0,0 +1,5 @@
1
+ import 'react/jsx-runtime';
2
+ import 'react';
3
+ export { i as Workspace, h as WorkspaceProps } from '../workflow-canvas-DSm0iyof.js';
4
+ import '@xyflow/react';
5
+ import './contracts.js';
@@ -0,0 +1,19 @@
1
+ "use client";
2
+ 'use strict';
3
+
4
+ var chunkXAQME7DD_js = require('../chunk-XAQME7DD.js');
5
+ require('../chunk-PBKTXX4Y.js');
6
+ require('../chunk-S7KHTUHA.js');
7
+ require('../chunk-UZ3CMNUJ.js');
8
+ require('../chunk-P4YYEM4B.js');
9
+ require('../chunk-PWBWP5FJ.js');
10
+ require('../chunk-YXN2K77G.js');
11
+
12
+
13
+
14
+ Object.defineProperty(exports, "Workspace", {
15
+ enumerable: true,
16
+ get: function () { return chunkXAQME7DD_js.Workspace; }
17
+ });
18
+ //# sourceMappingURL=workflow-canvas.js.map
19
+ //# sourceMappingURL=workflow-canvas.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"workflow-canvas.js"}
@@ -0,0 +1,10 @@
1
+ "use client";
2
+ export { Workspace } from '../chunk-LJSJMBLO.mjs';
3
+ import '../chunk-XO7IYJSF.mjs';
4
+ import '../chunk-QWG2FMUN.mjs';
5
+ import '../chunk-D2JF6C3E.mjs';
6
+ import '../chunk-OZNTQROP.mjs';
7
+ import '../chunk-TLPPVL3W.mjs';
8
+ import '../chunk-7VJ7CMMT.mjs';
9
+ //# sourceMappingURL=workflow-canvas.mjs.map
10
+ //# sourceMappingURL=workflow-canvas.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"workflow-canvas.mjs"}
@@ -0,0 +1,10 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { WorkflowGraph } from './contracts.mjs';
3
+
4
+ type WorkflowPreviewCanvasProps = {
5
+ graph: WorkflowGraph;
6
+ className?: string;
7
+ };
8
+ declare function WorkflowPreviewCanvas({ graph, className }: WorkflowPreviewCanvasProps): react_jsx_runtime.JSX.Element;
9
+
10
+ export { WorkflowPreviewCanvas, type WorkflowPreviewCanvasProps };
@@ -0,0 +1,10 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { WorkflowGraph } from './contracts.js';
3
+
4
+ type WorkflowPreviewCanvasProps = {
5
+ graph: WorkflowGraph;
6
+ className?: string;
7
+ };
8
+ declare function WorkflowPreviewCanvas({ graph, className }: WorkflowPreviewCanvasProps): react_jsx_runtime.JSX.Element;
9
+
10
+ export { WorkflowPreviewCanvas, type WorkflowPreviewCanvasProps };
@@ -0,0 +1,28 @@
1
+ "use client";
2
+ 'use strict';
3
+
4
+ var jsxRuntime = require('react/jsx-runtime');
5
+
6
+ // src/astrlabe/workflow-preview-canvas.tsx
7
+ function WorkflowPreviewCanvas({ graph, className }) {
8
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className, style: { overflow: "auto", padding: 12 }, children: /* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "grid", gap: 10 }, children: graph.nodes.map((node) => /* @__PURE__ */ jsxRuntime.jsxs(
9
+ "div",
10
+ {
11
+ style: {
12
+ border: "1px solid #cbd5e1",
13
+ borderRadius: 10,
14
+ padding: "10px 12px",
15
+ background: "#fff"
16
+ },
17
+ children: [
18
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: 12, color: "#64748b", textTransform: "uppercase" }, children: node.type }),
19
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: 14, fontWeight: 600 }, children: node.data?.label || node.id })
20
+ ]
21
+ },
22
+ node.id
23
+ )) }) });
24
+ }
25
+
26
+ exports.WorkflowPreviewCanvas = WorkflowPreviewCanvas;
27
+ //# sourceMappingURL=workflow-preview-canvas.js.map
28
+ //# sourceMappingURL=workflow-preview-canvas.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/astrlabe/workflow-preview-canvas.tsx"],"names":["jsx","jsxs"],"mappings":";;;;;AAOO,SAAS,qBAAA,CAAsB,EAAE,KAAA,EAAO,SAAA,EAAU,EAA+B;AACtF,EAAA,uBACEA,cAAA,CAAC,SAAI,SAAA,EAAsB,KAAA,EAAO,EAAE,QAAA,EAAU,MAAA,EAAQ,OAAA,EAAS,EAAA,EAAG,EAChE,QAAA,kBAAAA,cAAA,CAAC,SAAI,KAAA,EAAO,EAAE,OAAA,EAAS,MAAA,EAAQ,GAAA,EAAK,EAAA,IACjC,QAAA,EAAA,KAAA,CAAM,KAAA,CAAM,GAAA,CAAI,CAAC,IAAA,qBAChBC,eAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MAEC,KAAA,EAAO;AAAA,QACL,MAAA,EAAQ,mBAAA;AAAA,QACR,YAAA,EAAc,EAAA;AAAA,QACd,OAAA,EAAS,WAAA;AAAA,QACT,UAAA,EAAY;AAAA,OACd;AAAA,MAEA,QAAA,EAAA;AAAA,wBAAAD,cAAA,CAAC,KAAA,EAAA,EAAI,KAAA,EAAO,EAAE,QAAA,EAAU,EAAA,EAAI,KAAA,EAAO,SAAA,EAAW,aAAA,EAAe,WAAA,EAAY,EAAI,QAAA,EAAA,IAAA,CAAK,IAAA,EAAK,CAAA;AAAA,wBACvFA,cAAA,CAAC,KAAA,EAAA,EAAI,KAAA,EAAO,EAAE,QAAA,EAAU,EAAA,EAAI,UAAA,EAAY,GAAA,EAAI,EAAI,QAAA,EAAA,IAAA,CAAK,IAAA,EAAM,KAAA,IAAS,KAAK,EAAA,EAAG;AAAA;AAAA,KAAA;AAAA,IATvE,IAAA,CAAK;AAAA,GAWb,GACH,CAAA,EACF,CAAA;AAEJ","file":"workflow-preview-canvas.js","sourcesContent":["import type { WorkflowGraph } from './contracts'\n\nexport type WorkflowPreviewCanvasProps = {\n graph: WorkflowGraph\n className?: string\n}\n\nexport function WorkflowPreviewCanvas({ graph, className }: WorkflowPreviewCanvasProps) {\n return (\n <div className={className} style={{ overflow: 'auto', padding: 12 }}>\n <div style={{ display: 'grid', gap: 10 }}>\n {graph.nodes.map((node) => (\n <div\n key={node.id}\n style={{\n border: '1px solid #cbd5e1',\n borderRadius: 10,\n padding: '10px 12px',\n background: '#fff',\n }}\n >\n <div style={{ fontSize: 12, color: '#64748b', textTransform: 'uppercase' }}>{node.type}</div>\n <div style={{ fontSize: 14, fontWeight: 600 }}>{node.data?.label || node.id}</div>\n </div>\n ))}\n </div>\n </div>\n )\n}\n"]}
@@ -0,0 +1,26 @@
1
+ "use client";
2
+ import { jsx, jsxs } from 'react/jsx-runtime';
3
+
4
+ // src/astrlabe/workflow-preview-canvas.tsx
5
+ function WorkflowPreviewCanvas({ graph, className }) {
6
+ return /* @__PURE__ */ jsx("div", { className, style: { overflow: "auto", padding: 12 }, children: /* @__PURE__ */ jsx("div", { style: { display: "grid", gap: 10 }, children: graph.nodes.map((node) => /* @__PURE__ */ jsxs(
7
+ "div",
8
+ {
9
+ style: {
10
+ border: "1px solid #cbd5e1",
11
+ borderRadius: 10,
12
+ padding: "10px 12px",
13
+ background: "#fff"
14
+ },
15
+ children: [
16
+ /* @__PURE__ */ jsx("div", { style: { fontSize: 12, color: "#64748b", textTransform: "uppercase" }, children: node.type }),
17
+ /* @__PURE__ */ jsx("div", { style: { fontSize: 14, fontWeight: 600 }, children: node.data?.label || node.id })
18
+ ]
19
+ },
20
+ node.id
21
+ )) }) });
22
+ }
23
+
24
+ export { WorkflowPreviewCanvas };
25
+ //# sourceMappingURL=workflow-preview-canvas.mjs.map
26
+ //# sourceMappingURL=workflow-preview-canvas.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/astrlabe/workflow-preview-canvas.tsx"],"names":[],"mappings":";;;AAOO,SAAS,qBAAA,CAAsB,EAAE,KAAA,EAAO,SAAA,EAAU,EAA+B;AACtF,EAAA,uBACE,GAAA,CAAC,SAAI,SAAA,EAAsB,KAAA,EAAO,EAAE,QAAA,EAAU,MAAA,EAAQ,OAAA,EAAS,EAAA,EAAG,EAChE,QAAA,kBAAA,GAAA,CAAC,SAAI,KAAA,EAAO,EAAE,OAAA,EAAS,MAAA,EAAQ,GAAA,EAAK,EAAA,IACjC,QAAA,EAAA,KAAA,CAAM,KAAA,CAAM,GAAA,CAAI,CAAC,IAAA,qBAChB,IAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MAEC,KAAA,EAAO;AAAA,QACL,MAAA,EAAQ,mBAAA;AAAA,QACR,YAAA,EAAc,EAAA;AAAA,QACd,OAAA,EAAS,WAAA;AAAA,QACT,UAAA,EAAY;AAAA,OACd;AAAA,MAEA,QAAA,EAAA;AAAA,wBAAA,GAAA,CAAC,KAAA,EAAA,EAAI,KAAA,EAAO,EAAE,QAAA,EAAU,EAAA,EAAI,KAAA,EAAO,SAAA,EAAW,aAAA,EAAe,WAAA,EAAY,EAAI,QAAA,EAAA,IAAA,CAAK,IAAA,EAAK,CAAA;AAAA,wBACvF,GAAA,CAAC,KAAA,EAAA,EAAI,KAAA,EAAO,EAAE,QAAA,EAAU,EAAA,EAAI,UAAA,EAAY,GAAA,EAAI,EAAI,QAAA,EAAA,IAAA,CAAK,IAAA,EAAM,KAAA,IAAS,KAAK,EAAA,EAAG;AAAA;AAAA,KAAA;AAAA,IATvE,IAAA,CAAK;AAAA,GAWb,GACH,CAAA,EACF,CAAA;AAEJ","file":"workflow-preview-canvas.mjs","sourcesContent":["import type { WorkflowGraph } from './contracts'\n\nexport type WorkflowPreviewCanvasProps = {\n graph: WorkflowGraph\n className?: string\n}\n\nexport function WorkflowPreviewCanvas({ graph, className }: WorkflowPreviewCanvasProps) {\n return (\n <div className={className} style={{ overflow: 'auto', padding: 12 }}>\n <div style={{ display: 'grid', gap: 10 }}>\n {graph.nodes.map((node) => (\n <div\n key={node.id}\n style={{\n border: '1px solid #cbd5e1',\n borderRadius: 10,\n padding: '10px 12px',\n background: '#fff',\n }}\n >\n <div style={{ fontSize: 12, color: '#64748b', textTransform: 'uppercase' }}>{node.type}</div>\n <div style={{ fontSize: 14, fontWeight: 600 }}>{node.data?.label || node.id}</div>\n </div>\n ))}\n </div>\n </div>\n )\n}\n"]}
@@ -0,0 +1,279 @@
1
+ "use client";
2
+ 'use strict';
3
+
4
+ // src/astrlabe/utils/workflow-validator.ts
5
+ function validateWorkflowGraph(graph) {
6
+ const errors = [];
7
+ const nodeMap = /* @__PURE__ */ new Map();
8
+ for (const node of graph.nodes) {
9
+ nodeMap.set(node.id, node);
10
+ }
11
+ const agentNodes = graph.nodes.filter((node) => node.type === "agent");
12
+ if (agentNodes.length === 0) {
13
+ errors.push("At least one agent node is required");
14
+ }
15
+ for (const edge of graph.edges) {
16
+ if (!nodeMap.has(edge.source)) {
17
+ errors.push(`Edge "${edge.id}" references non-existent source node "${edge.source}"`);
18
+ }
19
+ if (!nodeMap.has(edge.target)) {
20
+ errors.push(`Edge "${edge.id}" references non-existent target node "${edge.target}"`);
21
+ }
22
+ }
23
+ const connectedNodeIds = /* @__PURE__ */ new Set();
24
+ for (const edge of graph.edges) {
25
+ connectedNodeIds.add(edge.source);
26
+ connectedNodeIds.add(edge.target);
27
+ }
28
+ for (const node of graph.nodes) {
29
+ if (node.type === "note") continue;
30
+ if (!connectedNodeIds.has(node.id)) {
31
+ errors.push(`Node "${node.data.label}" (${node.type}) is not connected to any other node`);
32
+ }
33
+ }
34
+ for (const edge of graph.edges) {
35
+ const sourceNode = nodeMap.get(edge.source);
36
+ const targetNode = nodeMap.get(edge.target);
37
+ if (!sourceNode || !targetNode) continue;
38
+ if (sourceNode.type === "tool" && targetNode.type !== "agent") {
39
+ errors.push(`Tool "${sourceNode.data.label}" can only connect to agent nodes, not ${targetNode.type} nodes`);
40
+ }
41
+ }
42
+ const ruleNodes = graph.nodes.filter((node) => node.type === "rule");
43
+ for (const ruleNode of ruleNodes) {
44
+ const incomingEdges = graph.edges.filter((edge) => edge.target === ruleNode.id);
45
+ const hasAgentSource = incomingEdges.some((edge) => {
46
+ const sourceNode = nodeMap.get(edge.source);
47
+ return sourceNode?.type === "agent";
48
+ });
49
+ if (incomingEdges.length === 0 || !hasAgentSource) {
50
+ errors.push(`Rule "${ruleNode.data.label}" must have an incoming connection from an agent`);
51
+ }
52
+ }
53
+ if (agentNodes.length > 1) {
54
+ const cycleError = detectCycle(agentNodes, graph.edges, nodeMap);
55
+ if (cycleError) {
56
+ errors.push(cycleError);
57
+ }
58
+ }
59
+ const startNodes = graph.nodes.filter((node) => node.type === "start");
60
+ if (startNodes.length > 1) {
61
+ errors.push("Only one Start node is allowed");
62
+ }
63
+ const endNodes = graph.nodes.filter((node) => node.type === "end");
64
+ if (endNodes.length > 1) {
65
+ errors.push("Only one End node is allowed");
66
+ }
67
+ for (const startNode of startNodes) {
68
+ const incomingEdges = graph.edges.filter((edge) => edge.target === startNode.id);
69
+ if (incomingEdges.length > 0) {
70
+ errors.push("Start node cannot have incoming connections");
71
+ }
72
+ }
73
+ for (const endNode of endNodes) {
74
+ const outgoingEdges = graph.edges.filter((edge) => edge.source === endNode.id);
75
+ if (outgoingEdges.length > 0) {
76
+ errors.push("End node cannot have outgoing connections");
77
+ }
78
+ }
79
+ const ifElseNodes = graph.nodes.filter((node) => node.type === "if_else");
80
+ for (const ifElseNode of ifElseNodes) {
81
+ const config = ifElseNode.data.config;
82
+ if (!config || config.conditions.length === 0) {
83
+ errors.push("IF/ELSE node must have at least one condition");
84
+ }
85
+ }
86
+ const codeNodes = graph.nodes.filter((node) => node.type === "code");
87
+ for (const codeNode of codeNodes) {
88
+ const config = codeNode.data.config;
89
+ if (!config || !config.code.trim()) {
90
+ errors.push("Code node must have code content");
91
+ }
92
+ }
93
+ const httpNodes = graph.nodes.filter((node) => node.type === "http_request");
94
+ for (const httpNode of httpNodes) {
95
+ const config = httpNode.data.config;
96
+ if (!config || !config.url.trim()) {
97
+ errors.push("HTTP Request node must have a URL");
98
+ }
99
+ }
100
+ const templateNodes = graph.nodes.filter((node) => node.type === "template_transform");
101
+ for (const templateNode of templateNodes) {
102
+ const config = templateNode.data.config;
103
+ if (!config || !config.template.trim()) {
104
+ errors.push("Template node must have template content");
105
+ }
106
+ }
107
+ const knowledgeBaseNodes = graph.nodes.filter((node) => node.type === "knowledge_base");
108
+ for (const knowledgeBaseNode of knowledgeBaseNodes) {
109
+ const config = knowledgeBaseNode.data.config;
110
+ if (!config || !config.sourceId.trim()) {
111
+ errors.push("Knowledge Base node must have a source configured");
112
+ }
113
+ }
114
+ const iterationNodes = graph.nodes.filter((node) => node.type === "iteration");
115
+ for (const iterationNode of iterationNodes) {
116
+ const outgoingEdges = graph.edges.filter((edge) => edge.source === iterationNode.id);
117
+ if (outgoingEdges.length === 0) {
118
+ errors.push("Iteration node must have at least one outgoing connection");
119
+ }
120
+ }
121
+ const answerNodes = graph.nodes.filter((node) => node.type === "answer");
122
+ for (const answerNode of answerNodes) {
123
+ const config = answerNode.data.config;
124
+ if (!config || !config.outputTemplate.trim()) {
125
+ errors.push("Answer node must have a non-empty output template");
126
+ }
127
+ }
128
+ const questionClassifierNodes = graph.nodes.filter((node) => node.type === "question_classifier");
129
+ for (const questionClassifierNode of questionClassifierNodes) {
130
+ const config = questionClassifierNode.data.config;
131
+ if (!config || config.categories.length < 2) {
132
+ errors.push("Question Classifier node must have at least 2 categories");
133
+ } else {
134
+ const emptyCategories = config.categories.filter((category) => !category.name.trim());
135
+ if (emptyCategories.length > 0) {
136
+ errors.push("Question Classifier node has categories with empty names");
137
+ }
138
+ }
139
+ }
140
+ const parameterExtractorNodes = graph.nodes.filter((node) => node.type === "parameter_extractor");
141
+ for (const parameterExtractorNode of parameterExtractorNodes) {
142
+ const config = parameterExtractorNode.data.config;
143
+ if (!config || config.parameters.length === 0) {
144
+ errors.push("Parameter Extractor node must have at least 1 parameter");
145
+ } else {
146
+ const emptyParameters = config.parameters.filter((parameter) => !parameter.name.trim());
147
+ if (emptyParameters.length > 0) {
148
+ errors.push("Parameter Extractor node has parameters with empty names");
149
+ }
150
+ }
151
+ }
152
+ const variableAssignerNodes = graph.nodes.filter((node) => node.type === "variable_assigner");
153
+ for (const variableAssignerNode of variableAssignerNodes) {
154
+ const config = variableAssignerNode.data.config;
155
+ if (!config || config.assignments.length === 0) {
156
+ errors.push("Variable Assigner node must have at least 1 assignment");
157
+ }
158
+ }
159
+ const variableAggregatorNodes = graph.nodes.filter((node) => node.type === "variable_aggregator");
160
+ for (const variableAggregatorNode of variableAggregatorNodes) {
161
+ const config = variableAggregatorNode.data.config;
162
+ if (!config || config.inputVariables.length === 0) {
163
+ errors.push("Variable Aggregator node must have at least 1 input variable");
164
+ }
165
+ if (!config || !config.outputVariable.trim()) {
166
+ errors.push("Variable Aggregator node must have a non-empty output variable");
167
+ }
168
+ }
169
+ const documentExtractorNodes = graph.nodes.filter((node) => node.type === "document_extractor");
170
+ for (const documentExtractorNode of documentExtractorNodes) {
171
+ const config = documentExtractorNode.data.config;
172
+ if (!config || !config.outputVariable.trim()) {
173
+ errors.push("Document Extractor node must have a non-empty output variable");
174
+ }
175
+ }
176
+ const listOperatorNodes = graph.nodes.filter((node) => node.type === "list_operator");
177
+ for (const listOperatorNode of listOperatorNodes) {
178
+ const config = listOperatorNode.data.config;
179
+ if (!config || !config.inputVariable.trim()) {
180
+ errors.push("List Operator node must have a non-empty input variable");
181
+ }
182
+ if (!config || !config.outputVariable.trim()) {
183
+ errors.push("List Operator node must have a non-empty output variable");
184
+ }
185
+ }
186
+ const iterationStartNodes = graph.nodes.filter((node) => node.type === "iteration_start");
187
+ for (const iterationStartNode of iterationStartNodes) {
188
+ const incomingEdges = graph.edges.filter((edge) => edge.target === iterationStartNode.id);
189
+ const hasIterationSource = incomingEdges.some((edge) => {
190
+ const sourceNode = nodeMap.get(edge.source);
191
+ return sourceNode?.type === "iteration";
192
+ });
193
+ if (incomingEdges.length === 0 || !hasIterationSource) {
194
+ errors.push("Iteration Start node must have an incoming connection from an Iteration node");
195
+ }
196
+ }
197
+ return {
198
+ valid: errors.length === 0,
199
+ errors
200
+ };
201
+ }
202
+ function detectCycle(agentNodes, edges, nodeMap) {
203
+ const agentIds = new Set(agentNodes.map((node) => node.id));
204
+ const adjacencyList = /* @__PURE__ */ new Map();
205
+ for (const agentId of agentIds) {
206
+ adjacencyList.set(agentId, []);
207
+ }
208
+ for (const edge of edges) {
209
+ const sourceNode = nodeMap.get(edge.source);
210
+ const targetNode = nodeMap.get(edge.target);
211
+ if (sourceNode?.type === "agent" && targetNode?.type === "agent" && agentIds.has(edge.source) && agentIds.has(edge.target)) {
212
+ adjacencyList.get(edge.source).push(edge.target);
213
+ }
214
+ }
215
+ const visited = /* @__PURE__ */ new Set();
216
+ const inStack = /* @__PURE__ */ new Set();
217
+ function hasCycleDfs(nodeId) {
218
+ visited.add(nodeId);
219
+ inStack.add(nodeId);
220
+ const neighbors = adjacencyList.get(nodeId) ?? [];
221
+ for (const neighbor of neighbors) {
222
+ if (!visited.has(neighbor)) {
223
+ if (hasCycleDfs(neighbor)) return true;
224
+ } else if (inStack.has(neighbor)) {
225
+ return true;
226
+ }
227
+ }
228
+ inStack.delete(nodeId);
229
+ return false;
230
+ }
231
+ for (const agentId of agentIds) {
232
+ if (!visited.has(agentId)) {
233
+ if (hasCycleDfs(agentId)) {
234
+ return "Cycle detected in agent pipeline \u2014 agents must form a directed acyclic graph (DAG)";
235
+ }
236
+ }
237
+ }
238
+ return null;
239
+ }
240
+ function topologicalSortAgents(graph) {
241
+ const agentNodes = graph.nodes.filter((node) => node.type === "agent");
242
+ const agentIdSet = new Set(agentNodes.map((node) => node.id));
243
+ const inDegree = /* @__PURE__ */ new Map();
244
+ const adjacencyList = /* @__PURE__ */ new Map();
245
+ for (const node of agentNodes) {
246
+ inDegree.set(node.id, 0);
247
+ adjacencyList.set(node.id, []);
248
+ }
249
+ for (const edge of graph.edges) {
250
+ if (agentIdSet.has(edge.source) && agentIdSet.has(edge.target)) {
251
+ adjacencyList.get(edge.source).push(edge.target);
252
+ inDegree.set(edge.target, (inDegree.get(edge.target) ?? 0) + 1);
253
+ }
254
+ }
255
+ const queue = [];
256
+ for (const [nodeId, degree] of inDegree) {
257
+ if (degree === 0) queue.push(nodeId);
258
+ }
259
+ const sorted = [];
260
+ while (queue.length > 0) {
261
+ const current = queue.shift();
262
+ sorted.push(current);
263
+ for (const neighbor of adjacencyList.get(current) ?? []) {
264
+ const newDegree = (inDegree.get(neighbor) ?? 1) - 1;
265
+ inDegree.set(neighbor, newDegree);
266
+ if (newDegree === 0) queue.push(neighbor);
267
+ }
268
+ }
269
+ const nodeIdToEntityId = /* @__PURE__ */ new Map();
270
+ for (const node of agentNodes) {
271
+ nodeIdToEntityId.set(node.id, node.data.entityId);
272
+ }
273
+ return sorted.map((nodeId) => nodeIdToEntityId.get(nodeId) ?? nodeId);
274
+ }
275
+
276
+ exports.topologicalSortAgents = topologicalSortAgents;
277
+ exports.validateWorkflowGraph = validateWorkflowGraph;
278
+ //# sourceMappingURL=chunk-3GE3MBUZ.js.map
279
+ //# sourceMappingURL=chunk-3GE3MBUZ.js.map