@datatechsolutions/ui 2.11.0 → 2.11.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/dist/astrlabe/contracts.js +5 -0
  2. package/dist/astrlabe/contracts.js.map +1 -0
  3. package/dist/astrlabe/contracts.mjs +4 -0
  4. package/dist/astrlabe/contracts.mjs.map +1 -0
  5. package/dist/astrlabe/graph-node.js +26 -0
  6. package/dist/astrlabe/graph-node.js.map +1 -0
  7. package/dist/astrlabe/graph-node.mjs +5 -0
  8. package/dist/astrlabe/graph-node.mjs.map +1 -0
  9. package/dist/astrlabe/index.js +3247 -0
  10. package/dist/astrlabe/index.js.map +1 -0
  11. package/dist/astrlabe/index.mjs +2956 -0
  12. package/dist/astrlabe/index.mjs.map +1 -0
  13. package/dist/astrlabe/utils.js +30 -0
  14. package/dist/astrlabe/utils.js.map +1 -0
  15. package/dist/astrlabe/utils.mjs +5 -0
  16. package/dist/astrlabe/utils.mjs.map +1 -0
  17. package/dist/astrlabe/workflow-canvas.js +19 -0
  18. package/dist/astrlabe/workflow-canvas.js.map +1 -0
  19. package/dist/astrlabe/workflow-canvas.mjs +10 -0
  20. package/dist/astrlabe/workflow-canvas.mjs.map +1 -0
  21. package/dist/astrlabe/workflow-preview-canvas.js +28 -0
  22. package/dist/astrlabe/workflow-preview-canvas.js.map +1 -0
  23. package/dist/astrlabe/workflow-preview-canvas.mjs +26 -0
  24. package/dist/astrlabe/workflow-preview-canvas.mjs.map +1 -0
  25. package/dist/chunk-3GE3MBUZ.js +279 -0
  26. package/dist/chunk-3GE3MBUZ.js.map +1 -0
  27. package/dist/chunk-4TZNBT5V.js +7228 -0
  28. package/dist/chunk-4TZNBT5V.js.map +1 -0
  29. package/dist/chunk-55H6WZQP.js +5 -0
  30. package/dist/chunk-55H6WZQP.js.map +1 -0
  31. package/dist/chunk-7VJ7CMMT.mjs +96 -0
  32. package/dist/chunk-7VJ7CMMT.mjs.map +1 -0
  33. package/dist/chunk-AM2TTPYM.mjs +189 -0
  34. package/dist/chunk-AM2TTPYM.mjs.map +1 -0
  35. package/dist/chunk-BLNXRUC4.mjs +276 -0
  36. package/dist/chunk-BLNXRUC4.mjs.map +1 -0
  37. package/dist/chunk-D2JF6C3E.mjs +46 -0
  38. package/dist/chunk-D2JF6C3E.mjs.map +1 -0
  39. package/dist/chunk-DFR6CMJH.js +197 -0
  40. package/dist/chunk-DFR6CMJH.js.map +1 -0
  41. package/dist/chunk-JB6RNAD2.mjs +4 -0
  42. package/dist/chunk-JB6RNAD2.mjs.map +1 -0
  43. package/dist/chunk-NMXHJMGI.js +20756 -0
  44. package/dist/chunk-NMXHJMGI.js.map +1 -0
  45. package/dist/chunk-OZNTQROP.mjs +39 -0
  46. package/dist/chunk-OZNTQROP.mjs.map +1 -0
  47. package/dist/chunk-P4YYEM4B.js +44 -0
  48. package/dist/chunk-P4YYEM4B.js.map +1 -0
  49. package/dist/chunk-QWG2FMUN.mjs +60 -0
  50. package/dist/chunk-QWG2FMUN.mjs.map +1 -0
  51. package/dist/chunk-S7KHTUHA.js +65 -0
  52. package/dist/chunk-S7KHTUHA.js.map +1 -0
  53. package/dist/chunk-UZ3CMNUJ.js +49 -0
  54. package/dist/chunk-UZ3CMNUJ.js.map +1 -0
  55. package/dist/chunk-VB45EBH5.mjs +20022 -0
  56. package/dist/chunk-VB45EBH5.mjs.map +1 -0
  57. package/dist/chunk-YXN2K77G.js +102 -0
  58. package/dist/chunk-YXN2K77G.js.map +1 -0
  59. package/dist/chunk-ZEYHIEHE.mjs +7167 -0
  60. package/dist/chunk-ZEYHIEHE.mjs.map +1 -0
  61. package/dist/index.js +2892 -0
  62. package/dist/index.js.map +1 -0
  63. package/dist/index.mjs +7 -0
  64. package/dist/index.mjs.map +1 -0
  65. package/dist/lib/i18n-context.js +29 -0
  66. package/dist/lib/i18n-context.js.map +1 -0
  67. package/dist/lib/i18n-context.mjs +4 -0
  68. package/dist/lib/i18n-context.mjs.map +1 -0
  69. package/dist/lib/router-context.js +25 -0
  70. package/dist/lib/router-context.js.map +1 -0
  71. package/dist/lib/router-context.mjs +4 -0
  72. package/dist/lib/router-context.mjs.map +1 -0
  73. package/dist/use-haptic-RDQNJYBE.js +17 -0
  74. package/dist/use-haptic-RDQNJYBE.js.map +1 -0
  75. package/dist/use-haptic-TCMOLPGA.mjs +4 -0
  76. package/dist/use-haptic-TCMOLPGA.mjs.map +1 -0
  77. package/package.json +2 -2
@@ -0,0 +1,5 @@
1
+ "use client";
2
+ 'use strict';
3
+
4
+ //# sourceMappingURL=chunk-55H6WZQP.js.map
5
+ //# sourceMappingURL=chunk-55H6WZQP.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"chunk-55H6WZQP.js"}
@@ -0,0 +1,96 @@
1
+ "use client";
2
+ import { createContext, useContext } from 'react';
3
+ import { jsx } from 'react/jsx-runtime';
4
+
5
+ // src/lib/i18n-context.tsx
6
+ var I18nContext = createContext(null);
7
+ function I18nProvider({ children, value }) {
8
+ return /* @__PURE__ */ jsx(I18nContext.Provider, { value, children });
9
+ }
10
+ function useTranslations(namespace) {
11
+ const context = useContext(I18nContext);
12
+ if (!context) {
13
+ const fallback = ((key, params) => {
14
+ let result = namespace ? `${namespace}.${key}` : key;
15
+ if (params) {
16
+ for (const [paramKey, paramValue] of Object.entries(params)) {
17
+ result = result.replace(`{${paramKey}}`, String(paramValue));
18
+ }
19
+ }
20
+ return result;
21
+ });
22
+ fallback.raw = (key) => key;
23
+ return fallback;
24
+ }
25
+ const translateFn = context.translate(namespace);
26
+ if (!translateFn.raw) {
27
+ translateFn.raw = (key) => {
28
+ const messages = context.messages;
29
+ if (!messages) return void 0;
30
+ const fullKey = namespace ? `${namespace}.${key}` : key;
31
+ return getNestedValue(messages, fullKey);
32
+ };
33
+ }
34
+ return translateFn;
35
+ }
36
+ function getNestedValue(object, path) {
37
+ const parts = path.split(".");
38
+ let current = object;
39
+ for (const part of parts) {
40
+ if (current === null || current === void 0 || typeof current !== "object") return void 0;
41
+ current = current[part];
42
+ }
43
+ return current;
44
+ }
45
+ function useLocale() {
46
+ const context = useContext(I18nContext);
47
+ return context?.locale ?? "en";
48
+ }
49
+ function useFormatter() {
50
+ const locale = useLocale();
51
+ return {
52
+ dateTime: (date, options) => new Intl.DateTimeFormat(locale, options).format(date),
53
+ relativeTime: (date) => {
54
+ const now = Date.now();
55
+ const diffMs = date.getTime() - now;
56
+ const diffSeconds = Math.round(diffMs / 1e3);
57
+ const diffMinutes = Math.round(diffMs / 6e4);
58
+ const diffHours = Math.round(diffMs / 36e5);
59
+ const diffDays = Math.round(diffMs / 864e5);
60
+ const rtf = new Intl.RelativeTimeFormat(locale, { numeric: "auto" });
61
+ if (Math.abs(diffSeconds) < 60) return rtf.format(diffSeconds, "second");
62
+ if (Math.abs(diffMinutes) < 60) return rtf.format(diffMinutes, "minute");
63
+ if (Math.abs(diffHours) < 24) return rtf.format(diffHours, "hour");
64
+ return rtf.format(diffDays, "day");
65
+ },
66
+ number: (value, options) => new Intl.NumberFormat(locale, options).format(value)
67
+ };
68
+ }
69
+ function createI18nFromMessages(locale, messages) {
70
+ return {
71
+ locale,
72
+ messages,
73
+ translate: (namespace) => {
74
+ const fn = ((key, params) => {
75
+ const fullKey = namespace ? `${namespace}.${key}` : key;
76
+ const raw = getNestedValue(messages, fullKey);
77
+ let result = typeof raw === "string" ? raw : key;
78
+ if (params) {
79
+ for (const [paramKey, paramValue] of Object.entries(params)) {
80
+ result = result.replace(new RegExp(`\\{${paramKey}\\}`, "g"), String(paramValue));
81
+ }
82
+ }
83
+ return result;
84
+ });
85
+ fn.raw = (key) => {
86
+ const fullKey = namespace ? `${namespace}.${key}` : key;
87
+ return getNestedValue(messages, fullKey);
88
+ };
89
+ return fn;
90
+ }
91
+ };
92
+ }
93
+
94
+ export { I18nProvider, createI18nFromMessages, useFormatter, useLocale, useTranslations };
95
+ //# sourceMappingURL=chunk-7VJ7CMMT.mjs.map
96
+ //# sourceMappingURL=chunk-7VJ7CMMT.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lib/i18n-context.tsx"],"names":[],"mappings":"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","file":"chunk-7VJ7CMMT.mjs","sourcesContent":["import { createContext, useContext, type ReactNode } from 'react'\n\ntype TranslateFn = ((key: string, params?: Record<string, unknown>) => string) & {\n /** Return the raw (unparsed) value at a given key — useful for arrays/objects in messages */\n raw: (key: string) => unknown\n}\n\nexport interface I18nContextValue {\n translate: (namespace?: string) => TranslateFn\n locale: string\n messages?: Record<string, unknown>\n}\n\nconst I18nContext = createContext<I18nContextValue | null>(null)\n\nexport type I18nProviderProps = {\n children: ReactNode\n value: I18nContextValue\n}\n\nexport function I18nProvider({ children, value }: I18nProviderProps) {\n return <I18nContext.Provider value={value}>{children}</I18nContext.Provider>\n}\n\nexport function useTranslations(namespace?: string): TranslateFn {\n const context = useContext(I18nContext)\n if (!context) {\n const fallback = ((key: string, params?: Record<string, unknown>) => {\n let result = namespace ? `${namespace}.${key}` : key\n if (params) {\n for (const [paramKey, paramValue] of Object.entries(params)) {\n result = result.replace(`{${paramKey}}`, String(paramValue))\n }\n }\n return result\n }) as TranslateFn\n fallback.raw = (key: string) => key\n return fallback\n }\n const translateFn = context.translate(namespace) as TranslateFn\n if (!translateFn.raw) {\n translateFn.raw = (key: string) => {\n const messages = context.messages\n if (!messages) return undefined\n const fullKey = namespace ? `${namespace}.${key}` : key\n return getNestedValue(messages, fullKey)\n }\n }\n return translateFn\n}\n\nfunction getNestedValue(object: Record<string, unknown>, path: string): unknown {\n const parts = path.split('.')\n let current: unknown = object\n for (const part of parts) {\n if (current === null || current === undefined || typeof current !== 'object') return undefined\n current = (current as Record<string, unknown>)[part]\n }\n return current\n}\n\nexport function useLocale(): string {\n const context = useContext(I18nContext)\n return context?.locale ?? 'en'\n}\n\nexport type I18nFormatter = {\n dateTime: (date: Date, options?: Intl.DateTimeFormatOptions) => string\n relativeTime: (date: Date, options?: Intl.RelativeTimeFormatOptions) => string\n number: (value: number, options?: Intl.NumberFormatOptions) => string\n}\n\nexport function useFormatter(): I18nFormatter {\n const locale = useLocale()\n return {\n dateTime: (date: Date, options?: Intl.DateTimeFormatOptions) =>\n new Intl.DateTimeFormat(locale, options).format(date),\n relativeTime: (date: Date) => {\n const now = Date.now()\n const diffMs = date.getTime() - now\n const diffSeconds = Math.round(diffMs / 1000)\n const diffMinutes = Math.round(diffMs / 60000)\n const diffHours = Math.round(diffMs / 3600000)\n const diffDays = Math.round(diffMs / 86400000)\n const rtf = new Intl.RelativeTimeFormat(locale, { numeric: 'auto' })\n if (Math.abs(diffSeconds) < 60) return rtf.format(diffSeconds, 'second')\n if (Math.abs(diffMinutes) < 60) return rtf.format(diffMinutes, 'minute')\n if (Math.abs(diffHours) < 24) return rtf.format(diffHours, 'hour')\n return rtf.format(diffDays, 'day')\n },\n number: (value: number, options?: Intl.NumberFormatOptions) =>\n new Intl.NumberFormat(locale, options).format(value),\n }\n}\n\n/**\n * Create an I18nContextValue from a flat messages object and locale.\n * Messages should be a nested object where keys are namespaces\n * and values are objects of translation key → ICU message string.\n *\n * This performs simple string interpolation with {param} placeholders.\n * For full ICU MessageFormat (plurals, select, etc.), use intl-messageformat.\n */\nexport function createI18nFromMessages(\n locale: string,\n messages: Record<string, unknown>,\n): I18nContextValue {\n return {\n locale,\n messages,\n translate: (namespace?: string) => {\n const fn = ((key: string, params?: Record<string, unknown>) => {\n const fullKey = namespace ? `${namespace}.${key}` : key\n const raw = getNestedValue(messages, fullKey)\n let result = typeof raw === 'string' ? raw : key\n if (params) {\n for (const [paramKey, paramValue] of Object.entries(params)) {\n result = result.replace(new RegExp(`\\\\{${paramKey}\\\\}`, 'g'), String(paramValue))\n }\n }\n return result\n }) as TranslateFn\n fn.raw = (key: string) => {\n const fullKey = namespace ? `${namespace}.${key}` : key\n return getNestedValue(messages, fullKey)\n }\n return fn\n },\n }\n}\n"]}
@@ -0,0 +1,189 @@
1
+ "use client";
2
+ import Dagre from '@dagrejs/dagre';
3
+
4
+ // src/astrlabe/utils/logic-node-defaults.ts
5
+ function createDefaultLogicNodeConfig(nodeType) {
6
+ switch (nodeType) {
7
+ case "start":
8
+ return { type: "start", inputVariables: [] };
9
+ case "end":
10
+ return { type: "end", outputVariables: [] };
11
+ case "if_else":
12
+ return {
13
+ type: "if_else",
14
+ conditions: [{ variable: "", operator: "equals", value: "" }],
15
+ logicalOperator: "and"
16
+ };
17
+ case "code":
18
+ return { type: "code", language: "javascript", code: "" };
19
+ case "http_request":
20
+ return {
21
+ type: "http_request",
22
+ method: "GET",
23
+ url: "",
24
+ headers: {},
25
+ body: "",
26
+ timeoutMs: 1e4
27
+ };
28
+ case "template_transform":
29
+ return { type: "template_transform", template: "", outputVariable: "" };
30
+ case "iteration":
31
+ return { type: "iteration", iteratorVariable: "", maxIterations: 100 };
32
+ case "knowledge_base":
33
+ return { type: "knowledge_base", sourceId: "", topK: 5, similarityThreshold: 0.7 };
34
+ case "answer":
35
+ return { type: "answer", outputTemplate: "", outputVariables: [] };
36
+ case "question_classifier":
37
+ return {
38
+ type: "question_classifier",
39
+ modelId: "",
40
+ instructions: "",
41
+ categories: [
42
+ { id: crypto.randomUUID(), name: "", description: "" },
43
+ { id: crypto.randomUUID(), name: "", description: "" }
44
+ ]
45
+ };
46
+ case "parameter_extractor":
47
+ return {
48
+ type: "parameter_extractor",
49
+ modelId: "",
50
+ parameters: [{ name: "", type: "string", description: "", required: true }]
51
+ };
52
+ case "variable_assigner":
53
+ return {
54
+ type: "variable_assigner",
55
+ assignments: [{ target: "", source: "" }]
56
+ };
57
+ case "variable_aggregator":
58
+ return {
59
+ type: "variable_aggregator",
60
+ inputVariables: [],
61
+ outputVariable: "",
62
+ aggregationMode: "array"
63
+ };
64
+ case "document_extractor":
65
+ return {
66
+ type: "document_extractor",
67
+ extractionMode: "text",
68
+ outputVariable: ""
69
+ };
70
+ case "list_operator":
71
+ return {
72
+ type: "list_operator",
73
+ operation: "filter",
74
+ inputVariable: "",
75
+ outputVariable: "",
76
+ condition: ""
77
+ };
78
+ case "iteration_start":
79
+ return {
80
+ type: "iteration_start",
81
+ iteratorVariable: "",
82
+ itemVariable: "item",
83
+ indexVariable: "index"
84
+ };
85
+ case "note":
86
+ return {
87
+ type: "note",
88
+ text: "",
89
+ color: "yellow",
90
+ width: 200,
91
+ height: 150
92
+ };
93
+ case "group":
94
+ return {
95
+ type: "group",
96
+ label: "Group",
97
+ color: "slate",
98
+ isExpanded: true,
99
+ width: 400,
100
+ height: 300,
101
+ collapsedWidth: 260,
102
+ collapsedHeight: 60
103
+ };
104
+ case "datasource":
105
+ return {
106
+ type: "datasource",
107
+ datasourceId: "",
108
+ dialect: "",
109
+ table: "",
110
+ selectedColumns: [],
111
+ filterVariables: {},
112
+ outputVariable: "datasourceResult",
113
+ limit: 100
114
+ };
115
+ default:
116
+ return null;
117
+ }
118
+ }
119
+ var DEFAULT_NODE_WIDTH = 260;
120
+ var DEFAULT_NODE_HEIGHT = 70;
121
+ function getNodeSize(node) {
122
+ const measured = node.measured;
123
+ return {
124
+ width: measured?.width ?? DEFAULT_NODE_WIDTH,
125
+ height: measured?.height ?? DEFAULT_NODE_HEIGHT
126
+ };
127
+ }
128
+ function applyDagreLayout(nodes, edges, direction) {
129
+ const nodeSpacingHorizontal = 80;
130
+ const nodeSpacingVertical = 50;
131
+ const layoutNodes = nodes.filter(
132
+ (node) => !node.parentId && node.type !== "note"
133
+ );
134
+ const dagreGraph = new Dagre.graphlib.Graph({ directed: true });
135
+ dagreGraph.setDefaultEdgeLabel(() => ({}));
136
+ const isHorizontal = direction === "LR";
137
+ dagreGraph.setGraph({
138
+ rankdir: direction,
139
+ nodesep: isHorizontal ? nodeSpacingVertical : nodeSpacingHorizontal,
140
+ ranksep: isHorizontal ? nodeSpacingHorizontal : nodeSpacingVertical,
141
+ marginx: 40,
142
+ marginy: 40
143
+ });
144
+ const layoutNodeIds = new Set(layoutNodes.map((node) => node.id));
145
+ for (const node of layoutNodes) {
146
+ const { width, height } = getNodeSize(node);
147
+ dagreGraph.setNode(node.id, { width, height });
148
+ }
149
+ for (const edge of edges) {
150
+ if (layoutNodeIds.has(edge.source) && layoutNodeIds.has(edge.target)) {
151
+ dagreGraph.setEdge(edge.source, edge.target);
152
+ }
153
+ }
154
+ Dagre.layout(dagreGraph);
155
+ const positionMap = /* @__PURE__ */ new Map();
156
+ for (const node of layoutNodes) {
157
+ const dagreNode = dagreGraph.node(node.id);
158
+ if (!dagreNode) continue;
159
+ const { width, height } = getNodeSize(node);
160
+ positionMap.set(node.id, {
161
+ x: dagreNode.x - width / 2,
162
+ y: dagreNode.y - height / 2
163
+ });
164
+ }
165
+ return nodes.map((node) => {
166
+ const newPosition = positionMap.get(node.id);
167
+ if (!newPosition) return node;
168
+ return { ...node, position: newPosition };
169
+ });
170
+ }
171
+
172
+ // src/astrlabe/utils/agent-tier.ts
173
+ var TIERS = [
174
+ { maxElo: 1200, tier: { key: "beginner", pillColor: "bg-cyan-100 text-cyan-700 dark:bg-cyan-900/30 dark:text-cyan-400" } },
175
+ { maxElo: 1600, tier: { key: "intermediate", pillColor: "bg-pink-100 text-pink-700 dark:bg-pink-900/30 dark:text-pink-400" } },
176
+ { maxElo: 2e3, tier: { key: "advanced", pillColor: "bg-amber-100 text-amber-700 dark:bg-amber-900/30 dark:text-amber-400" } },
177
+ { maxElo: Infinity, tier: { key: "expert", pillColor: "bg-emerald-100 text-emerald-700 dark:bg-emerald-900/30 dark:text-emerald-400" } }
178
+ ];
179
+ function getAgentTier(elo) {
180
+ const eloValue = elo ?? 0;
181
+ for (const { maxElo, tier } of TIERS) {
182
+ if (eloValue < maxElo) return tier;
183
+ }
184
+ return TIERS[TIERS.length - 1].tier;
185
+ }
186
+
187
+ export { applyDagreLayout, createDefaultLogicNodeConfig, getAgentTier };
188
+ //# sourceMappingURL=chunk-AM2TTPYM.mjs.map
189
+ //# sourceMappingURL=chunk-AM2TTPYM.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/astrlabe/utils/logic-node-defaults.ts","../src/astrlabe/utils/layout-engine.ts","../src/astrlabe/utils/agent-tier.ts"],"names":[],"mappings":"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","file":"chunk-AM2TTPYM.mjs","sourcesContent":["/**\n * Logic Node Default Configs\n * ==========================\n * Factory function to create default configs for each logic node type.\n */\n\nimport type { WorkflowNodeType, LogicNodeConfig } from '../contracts'\n\nexport function createDefaultLogicNodeConfig(nodeType: WorkflowNodeType): LogicNodeConfig | null {\n switch (nodeType) {\n case 'start':\n return { type: 'start', inputVariables: [] }\n case 'end':\n return { type: 'end', outputVariables: [] }\n case 'if_else':\n return {\n type: 'if_else',\n conditions: [{ variable: '', operator: 'equals', value: '' }],\n logicalOperator: 'and',\n }\n case 'code':\n return { type: 'code', language: 'javascript', code: '' }\n case 'http_request':\n return {\n type: 'http_request',\n method: 'GET',\n url: '',\n headers: {},\n body: '',\n timeoutMs: 10000,\n }\n case 'template_transform':\n return { type: 'template_transform', template: '', outputVariable: '' }\n case 'iteration':\n return { type: 'iteration', iteratorVariable: '', maxIterations: 100 }\n case 'knowledge_base':\n return { type: 'knowledge_base', sourceId: '', topK: 5, similarityThreshold: 0.7 }\n case 'answer':\n return { type: 'answer', outputTemplate: '', outputVariables: [] }\n case 'question_classifier':\n return {\n type: 'question_classifier',\n modelId: '',\n instructions: '',\n categories: [\n { id: crypto.randomUUID(), name: '', description: '' },\n { id: crypto.randomUUID(), name: '', description: '' },\n ],\n }\n case 'parameter_extractor':\n return {\n type: 'parameter_extractor',\n modelId: '',\n parameters: [{ name: '', type: 'string', description: '', required: true }],\n }\n case 'variable_assigner':\n return {\n type: 'variable_assigner',\n assignments: [{ target: '', source: '' }],\n }\n case 'variable_aggregator':\n return {\n type: 'variable_aggregator',\n inputVariables: [],\n outputVariable: '',\n aggregationMode: 'array',\n }\n case 'document_extractor':\n return {\n type: 'document_extractor',\n extractionMode: 'text',\n outputVariable: '',\n }\n case 'list_operator':\n return {\n type: 'list_operator',\n operation: 'filter',\n inputVariable: '',\n outputVariable: '',\n condition: '',\n }\n case 'iteration_start':\n return {\n type: 'iteration_start',\n iteratorVariable: '',\n itemVariable: 'item',\n indexVariable: 'index',\n }\n case 'note':\n return {\n type: 'note',\n text: '',\n color: 'yellow',\n width: 200,\n height: 150,\n }\n case 'group':\n return {\n type: 'group',\n label: 'Group',\n color: 'slate',\n isExpanded: true,\n width: 400,\n height: 300,\n collapsedWidth: 260,\n collapsedHeight: 60,\n }\n case 'datasource':\n return {\n type: 'datasource',\n datasourceId: '',\n dialect: '',\n table: '',\n selectedColumns: [],\n filterVariables: {},\n outputVariable: 'datasourceResult',\n limit: 100,\n }\n default:\n return null\n }\n}\n","/**\n * Layout Engine\n * =============\n * Auto-layout for workflow graphs using @dagrejs/dagre.\n * Pure utility — no React dependencies.\n */\n\nimport Dagre from '@dagrejs/dagre'\nimport type { Node, Edge } from '@xyflow/react'\n\n/** Layout direction: free means no auto-layout is applied. */\nexport type LayoutDirection = 'free' | 'LR' | 'TB'\n\nconst DEFAULT_NODE_WIDTH = 260\nconst DEFAULT_NODE_HEIGHT = 70\n\nfunction getNodeSize(node: Node): { width: number; height: number } {\n const measured = node.measured as { width?: number; height?: number } | undefined\n return {\n width: measured?.width ?? DEFAULT_NODE_WIDTH,\n height: measured?.height ?? DEFAULT_NODE_HEIGHT,\n }\n}\n\n/**\n * Apply dagre layout to the given nodes and edges.\n * Returns a new array of nodes with updated positions.\n * Group child nodes (parentId set) and note nodes are excluded from layout.\n */\nexport function applyDagreLayout(\n nodes: Node[],\n edges: Edge[],\n direction: Exclude<LayoutDirection, 'free'>,\n): Node[] {\n const nodeSpacingHorizontal = 80\n const nodeSpacingVertical = 50\n\n // Separate layoutable nodes from excluded ones\n const layoutNodes = nodes.filter(\n (node) => !node.parentId && node.type !== 'note',\n )\n\n // Build dagre graph\n const dagreGraph = new Dagre.graphlib.Graph({ directed: true })\n dagreGraph.setDefaultEdgeLabel(() => ({}))\n\n const isHorizontal = direction === 'LR'\n dagreGraph.setGraph({\n rankdir: direction,\n nodesep: isHorizontal ? nodeSpacingVertical : nodeSpacingHorizontal,\n ranksep: isHorizontal ? nodeSpacingHorizontal : nodeSpacingVertical,\n marginx: 40,\n marginy: 40,\n })\n\n const layoutNodeIds = new Set(layoutNodes.map((node) => node.id))\n\n for (const node of layoutNodes) {\n const { width, height } = getNodeSize(node)\n dagreGraph.setNode(node.id, { width, height })\n }\n\n for (const edge of edges) {\n if (layoutNodeIds.has(edge.source) && layoutNodeIds.has(edge.target)) {\n dagreGraph.setEdge(edge.source, edge.target)\n }\n }\n\n Dagre.layout(dagreGraph)\n\n // Build position map — dagre returns center coords, React Flow uses top-left\n const positionMap = new Map<string, { x: number; y: number }>()\n for (const node of layoutNodes) {\n const dagreNode = dagreGraph.node(node.id)\n if (!dagreNode) continue\n const { width, height } = getNodeSize(node)\n positionMap.set(node.id, {\n x: dagreNode.x - width / 2,\n y: dagreNode.y - height / 2,\n })\n }\n\n // Return all nodes with updated positions for layout-participating nodes\n return nodes.map((node) => {\n const newPosition = positionMap.get(node.id)\n if (!newPosition) return node\n return { ...node, position: newPosition }\n })\n}\n","/**\n * Agent ELO Tier\n * ==============\n * Derives difficulty tier from agent ELO rating.\n * Used in node palette, agent flow node, and agent drawer.\n */\n\nexport type AgentTier = {\n key: 'beginner' | 'intermediate' | 'advanced' | 'expert'\n pillColor: string\n}\n\nconst TIERS: Array<{ maxElo: number; tier: AgentTier }> = [\n { maxElo: 1200, tier: { key: 'beginner', pillColor: 'bg-cyan-100 text-cyan-700 dark:bg-cyan-900/30 dark:text-cyan-400' } },\n { maxElo: 1600, tier: { key: 'intermediate', pillColor: 'bg-pink-100 text-pink-700 dark:bg-pink-900/30 dark:text-pink-400' } },\n { maxElo: 2000, tier: { key: 'advanced', pillColor: 'bg-amber-100 text-amber-700 dark:bg-amber-900/30 dark:text-amber-400' } },\n { maxElo: Infinity, tier: { key: 'expert', pillColor: 'bg-emerald-100 text-emerald-700 dark:bg-emerald-900/30 dark:text-emerald-400' } },\n]\n\nexport function getAgentTier(elo: number | undefined): AgentTier {\n const eloValue = elo ?? 0\n for (const { maxElo, tier } of TIERS) {\n if (eloValue < maxElo) return tier\n }\n return TIERS[TIERS.length - 1].tier\n}\n"]}
@@ -0,0 +1,276 @@
1
+ "use client";
2
+ // src/astrlabe/utils/workflow-validator.ts
3
+ function validateWorkflowGraph(graph) {
4
+ const errors = [];
5
+ const nodeMap = /* @__PURE__ */ new Map();
6
+ for (const node of graph.nodes) {
7
+ nodeMap.set(node.id, node);
8
+ }
9
+ const agentNodes = graph.nodes.filter((node) => node.type === "agent");
10
+ if (agentNodes.length === 0) {
11
+ errors.push("At least one agent node is required");
12
+ }
13
+ for (const edge of graph.edges) {
14
+ if (!nodeMap.has(edge.source)) {
15
+ errors.push(`Edge "${edge.id}" references non-existent source node "${edge.source}"`);
16
+ }
17
+ if (!nodeMap.has(edge.target)) {
18
+ errors.push(`Edge "${edge.id}" references non-existent target node "${edge.target}"`);
19
+ }
20
+ }
21
+ const connectedNodeIds = /* @__PURE__ */ new Set();
22
+ for (const edge of graph.edges) {
23
+ connectedNodeIds.add(edge.source);
24
+ connectedNodeIds.add(edge.target);
25
+ }
26
+ for (const node of graph.nodes) {
27
+ if (node.type === "note") continue;
28
+ if (!connectedNodeIds.has(node.id)) {
29
+ errors.push(`Node "${node.data.label}" (${node.type}) is not connected to any other node`);
30
+ }
31
+ }
32
+ for (const edge of graph.edges) {
33
+ const sourceNode = nodeMap.get(edge.source);
34
+ const targetNode = nodeMap.get(edge.target);
35
+ if (!sourceNode || !targetNode) continue;
36
+ if (sourceNode.type === "tool" && targetNode.type !== "agent") {
37
+ errors.push(`Tool "${sourceNode.data.label}" can only connect to agent nodes, not ${targetNode.type} nodes`);
38
+ }
39
+ }
40
+ const ruleNodes = graph.nodes.filter((node) => node.type === "rule");
41
+ for (const ruleNode of ruleNodes) {
42
+ const incomingEdges = graph.edges.filter((edge) => edge.target === ruleNode.id);
43
+ const hasAgentSource = incomingEdges.some((edge) => {
44
+ const sourceNode = nodeMap.get(edge.source);
45
+ return sourceNode?.type === "agent";
46
+ });
47
+ if (incomingEdges.length === 0 || !hasAgentSource) {
48
+ errors.push(`Rule "${ruleNode.data.label}" must have an incoming connection from an agent`);
49
+ }
50
+ }
51
+ if (agentNodes.length > 1) {
52
+ const cycleError = detectCycle(agentNodes, graph.edges, nodeMap);
53
+ if (cycleError) {
54
+ errors.push(cycleError);
55
+ }
56
+ }
57
+ const startNodes = graph.nodes.filter((node) => node.type === "start");
58
+ if (startNodes.length > 1) {
59
+ errors.push("Only one Start node is allowed");
60
+ }
61
+ const endNodes = graph.nodes.filter((node) => node.type === "end");
62
+ if (endNodes.length > 1) {
63
+ errors.push("Only one End node is allowed");
64
+ }
65
+ for (const startNode of startNodes) {
66
+ const incomingEdges = graph.edges.filter((edge) => edge.target === startNode.id);
67
+ if (incomingEdges.length > 0) {
68
+ errors.push("Start node cannot have incoming connections");
69
+ }
70
+ }
71
+ for (const endNode of endNodes) {
72
+ const outgoingEdges = graph.edges.filter((edge) => edge.source === endNode.id);
73
+ if (outgoingEdges.length > 0) {
74
+ errors.push("End node cannot have outgoing connections");
75
+ }
76
+ }
77
+ const ifElseNodes = graph.nodes.filter((node) => node.type === "if_else");
78
+ for (const ifElseNode of ifElseNodes) {
79
+ const config = ifElseNode.data.config;
80
+ if (!config || config.conditions.length === 0) {
81
+ errors.push("IF/ELSE node must have at least one condition");
82
+ }
83
+ }
84
+ const codeNodes = graph.nodes.filter((node) => node.type === "code");
85
+ for (const codeNode of codeNodes) {
86
+ const config = codeNode.data.config;
87
+ if (!config || !config.code.trim()) {
88
+ errors.push("Code node must have code content");
89
+ }
90
+ }
91
+ const httpNodes = graph.nodes.filter((node) => node.type === "http_request");
92
+ for (const httpNode of httpNodes) {
93
+ const config = httpNode.data.config;
94
+ if (!config || !config.url.trim()) {
95
+ errors.push("HTTP Request node must have a URL");
96
+ }
97
+ }
98
+ const templateNodes = graph.nodes.filter((node) => node.type === "template_transform");
99
+ for (const templateNode of templateNodes) {
100
+ const config = templateNode.data.config;
101
+ if (!config || !config.template.trim()) {
102
+ errors.push("Template node must have template content");
103
+ }
104
+ }
105
+ const knowledgeBaseNodes = graph.nodes.filter((node) => node.type === "knowledge_base");
106
+ for (const knowledgeBaseNode of knowledgeBaseNodes) {
107
+ const config = knowledgeBaseNode.data.config;
108
+ if (!config || !config.sourceId.trim()) {
109
+ errors.push("Knowledge Base node must have a source configured");
110
+ }
111
+ }
112
+ const iterationNodes = graph.nodes.filter((node) => node.type === "iteration");
113
+ for (const iterationNode of iterationNodes) {
114
+ const outgoingEdges = graph.edges.filter((edge) => edge.source === iterationNode.id);
115
+ if (outgoingEdges.length === 0) {
116
+ errors.push("Iteration node must have at least one outgoing connection");
117
+ }
118
+ }
119
+ const answerNodes = graph.nodes.filter((node) => node.type === "answer");
120
+ for (const answerNode of answerNodes) {
121
+ const config = answerNode.data.config;
122
+ if (!config || !config.outputTemplate.trim()) {
123
+ errors.push("Answer node must have a non-empty output template");
124
+ }
125
+ }
126
+ const questionClassifierNodes = graph.nodes.filter((node) => node.type === "question_classifier");
127
+ for (const questionClassifierNode of questionClassifierNodes) {
128
+ const config = questionClassifierNode.data.config;
129
+ if (!config || config.categories.length < 2) {
130
+ errors.push("Question Classifier node must have at least 2 categories");
131
+ } else {
132
+ const emptyCategories = config.categories.filter((category) => !category.name.trim());
133
+ if (emptyCategories.length > 0) {
134
+ errors.push("Question Classifier node has categories with empty names");
135
+ }
136
+ }
137
+ }
138
+ const parameterExtractorNodes = graph.nodes.filter((node) => node.type === "parameter_extractor");
139
+ for (const parameterExtractorNode of parameterExtractorNodes) {
140
+ const config = parameterExtractorNode.data.config;
141
+ if (!config || config.parameters.length === 0) {
142
+ errors.push("Parameter Extractor node must have at least 1 parameter");
143
+ } else {
144
+ const emptyParameters = config.parameters.filter((parameter) => !parameter.name.trim());
145
+ if (emptyParameters.length > 0) {
146
+ errors.push("Parameter Extractor node has parameters with empty names");
147
+ }
148
+ }
149
+ }
150
+ const variableAssignerNodes = graph.nodes.filter((node) => node.type === "variable_assigner");
151
+ for (const variableAssignerNode of variableAssignerNodes) {
152
+ const config = variableAssignerNode.data.config;
153
+ if (!config || config.assignments.length === 0) {
154
+ errors.push("Variable Assigner node must have at least 1 assignment");
155
+ }
156
+ }
157
+ const variableAggregatorNodes = graph.nodes.filter((node) => node.type === "variable_aggregator");
158
+ for (const variableAggregatorNode of variableAggregatorNodes) {
159
+ const config = variableAggregatorNode.data.config;
160
+ if (!config || config.inputVariables.length === 0) {
161
+ errors.push("Variable Aggregator node must have at least 1 input variable");
162
+ }
163
+ if (!config || !config.outputVariable.trim()) {
164
+ errors.push("Variable Aggregator node must have a non-empty output variable");
165
+ }
166
+ }
167
+ const documentExtractorNodes = graph.nodes.filter((node) => node.type === "document_extractor");
168
+ for (const documentExtractorNode of documentExtractorNodes) {
169
+ const config = documentExtractorNode.data.config;
170
+ if (!config || !config.outputVariable.trim()) {
171
+ errors.push("Document Extractor node must have a non-empty output variable");
172
+ }
173
+ }
174
+ const listOperatorNodes = graph.nodes.filter((node) => node.type === "list_operator");
175
+ for (const listOperatorNode of listOperatorNodes) {
176
+ const config = listOperatorNode.data.config;
177
+ if (!config || !config.inputVariable.trim()) {
178
+ errors.push("List Operator node must have a non-empty input variable");
179
+ }
180
+ if (!config || !config.outputVariable.trim()) {
181
+ errors.push("List Operator node must have a non-empty output variable");
182
+ }
183
+ }
184
+ const iterationStartNodes = graph.nodes.filter((node) => node.type === "iteration_start");
185
+ for (const iterationStartNode of iterationStartNodes) {
186
+ const incomingEdges = graph.edges.filter((edge) => edge.target === iterationStartNode.id);
187
+ const hasIterationSource = incomingEdges.some((edge) => {
188
+ const sourceNode = nodeMap.get(edge.source);
189
+ return sourceNode?.type === "iteration";
190
+ });
191
+ if (incomingEdges.length === 0 || !hasIterationSource) {
192
+ errors.push("Iteration Start node must have an incoming connection from an Iteration node");
193
+ }
194
+ }
195
+ return {
196
+ valid: errors.length === 0,
197
+ errors
198
+ };
199
+ }
200
+ function detectCycle(agentNodes, edges, nodeMap) {
201
+ const agentIds = new Set(agentNodes.map((node) => node.id));
202
+ const adjacencyList = /* @__PURE__ */ new Map();
203
+ for (const agentId of agentIds) {
204
+ adjacencyList.set(agentId, []);
205
+ }
206
+ for (const edge of edges) {
207
+ const sourceNode = nodeMap.get(edge.source);
208
+ const targetNode = nodeMap.get(edge.target);
209
+ if (sourceNode?.type === "agent" && targetNode?.type === "agent" && agentIds.has(edge.source) && agentIds.has(edge.target)) {
210
+ adjacencyList.get(edge.source).push(edge.target);
211
+ }
212
+ }
213
+ const visited = /* @__PURE__ */ new Set();
214
+ const inStack = /* @__PURE__ */ new Set();
215
+ function hasCycleDfs(nodeId) {
216
+ visited.add(nodeId);
217
+ inStack.add(nodeId);
218
+ const neighbors = adjacencyList.get(nodeId) ?? [];
219
+ for (const neighbor of neighbors) {
220
+ if (!visited.has(neighbor)) {
221
+ if (hasCycleDfs(neighbor)) return true;
222
+ } else if (inStack.has(neighbor)) {
223
+ return true;
224
+ }
225
+ }
226
+ inStack.delete(nodeId);
227
+ return false;
228
+ }
229
+ for (const agentId of agentIds) {
230
+ if (!visited.has(agentId)) {
231
+ if (hasCycleDfs(agentId)) {
232
+ return "Cycle detected in agent pipeline \u2014 agents must form a directed acyclic graph (DAG)";
233
+ }
234
+ }
235
+ }
236
+ return null;
237
+ }
238
+ function topologicalSortAgents(graph) {
239
+ const agentNodes = graph.nodes.filter((node) => node.type === "agent");
240
+ const agentIdSet = new Set(agentNodes.map((node) => node.id));
241
+ const inDegree = /* @__PURE__ */ new Map();
242
+ const adjacencyList = /* @__PURE__ */ new Map();
243
+ for (const node of agentNodes) {
244
+ inDegree.set(node.id, 0);
245
+ adjacencyList.set(node.id, []);
246
+ }
247
+ for (const edge of graph.edges) {
248
+ if (agentIdSet.has(edge.source) && agentIdSet.has(edge.target)) {
249
+ adjacencyList.get(edge.source).push(edge.target);
250
+ inDegree.set(edge.target, (inDegree.get(edge.target) ?? 0) + 1);
251
+ }
252
+ }
253
+ const queue = [];
254
+ for (const [nodeId, degree] of inDegree) {
255
+ if (degree === 0) queue.push(nodeId);
256
+ }
257
+ const sorted = [];
258
+ while (queue.length > 0) {
259
+ const current = queue.shift();
260
+ sorted.push(current);
261
+ for (const neighbor of adjacencyList.get(current) ?? []) {
262
+ const newDegree = (inDegree.get(neighbor) ?? 1) - 1;
263
+ inDegree.set(neighbor, newDegree);
264
+ if (newDegree === 0) queue.push(neighbor);
265
+ }
266
+ }
267
+ const nodeIdToEntityId = /* @__PURE__ */ new Map();
268
+ for (const node of agentNodes) {
269
+ nodeIdToEntityId.set(node.id, node.data.entityId);
270
+ }
271
+ return sorted.map((nodeId) => nodeIdToEntityId.get(nodeId) ?? nodeId);
272
+ }
273
+
274
+ export { topologicalSortAgents, validateWorkflowGraph };
275
+ //# sourceMappingURL=chunk-BLNXRUC4.mjs.map
276
+ //# sourceMappingURL=chunk-BLNXRUC4.mjs.map