@kiberon-labs/behave-graph-flow 1.0.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (314) hide show
  1. package/.fallowrc.json +16 -0
  2. package/.storybook/main.ts +32 -0
  3. package/.storybook/preview.ts +16 -0
  4. package/.storybook/styles.css +10 -0
  5. package/.storybook/vscode.css +814 -0
  6. package/.turbo/turbo-build.log +7 -0
  7. package/LICENSE +6 -0
  8. package/README.md +2 -2
  9. package/data/Polynomial.json +510 -0
  10. package/data/sequence.json +337 -0
  11. package/data/trigger-event.json +241 -0
  12. package/data/variable-change.json +210 -0
  13. package/dist/entry.css +4 -0
  14. package/dist/index.css +39 -0
  15. package/dist/index.css.map +1 -0
  16. package/dist/index.d.ts +2282 -0
  17. package/dist/index.d.ts.map +1 -0
  18. package/dist/index.js +14873 -0
  19. package/dist/index.js.map +1 -0
  20. package/docs/notifications.md +246 -0
  21. package/docs/protocol.md +679 -0
  22. package/docs/specifics.md +191 -0
  23. package/package.json +85 -21
  24. package/postcss.config.ts +3 -4
  25. package/src/annotations/index.ts +32 -0
  26. package/src/components/FloatingToolbar/index.module.css +45 -0
  27. package/src/components/FloatingToolbar/index.tsx +256 -0
  28. package/src/components/Flow.tsx +276 -75
  29. package/src/components/contextMenus/NodePicker.module.css +274 -0
  30. package/src/components/contextMenus/NodePicker.tsx +481 -0
  31. package/src/components/contextMenus/edge.tsx +108 -0
  32. package/src/components/contextMenus/node.tsx +155 -0
  33. package/src/components/contextMenus/selection.tsx +77 -0
  34. package/src/components/controls/any/index.tsx +8 -0
  35. package/src/components/controls/boolean/index.tsx +13 -0
  36. package/src/components/controls/colorPicker/InputPopover.module.css +100 -0
  37. package/src/components/controls/colorPicker/InputPopover.tsx +31 -0
  38. package/src/components/controls/colorPicker/index.module.css +18 -0
  39. package/src/components/controls/colorPicker/index.tsx +61 -0
  40. package/src/components/controls/number/index.tsx +35 -0
  41. package/src/components/controls/string/index.tsx +16 -0
  42. package/src/components/edges/index.tsx +469 -0
  43. package/src/components/edges/offsetBezier.ts +134 -0
  44. package/src/components/hotKeys.tsx +20 -0
  45. package/src/components/layoutController/index.module.css +10 -0
  46. package/src/components/layoutController/index.tsx +117 -0
  47. package/src/components/layoutController/utils.ts +205 -0
  48. package/src/components/menubar/defaults.tsx +480 -0
  49. package/src/components/menubar/index.tsx +49 -0
  50. package/src/components/menubar/menuItem.module.css +16 -0
  51. package/src/components/menubar/menuItem.tsx +32 -0
  52. package/src/components/nodes/behave/Node.module.css +23 -0
  53. package/src/components/nodes/behave/Node.tsx +176 -0
  54. package/src/components/nodes/behave/NodeContainer.module.css +87 -0
  55. package/src/components/nodes/behave/NodeContainer.tsx +46 -0
  56. package/src/components/nodes/behave/index.tsx +14 -0
  57. package/src/components/nodes/comment/FormatToolbar.tsx +118 -0
  58. package/src/components/nodes/comment/comment.tsx +103 -0
  59. package/src/components/nodes/comment/styles.module.css +150 -0
  60. package/src/components/nodes/group/index.tsx +109 -0
  61. package/src/components/nodes/wrapper/index.tsx +73 -0
  62. package/src/components/nodes/wrapper/styles.module.css +113 -0
  63. package/src/components/notifications/NotificationProvider.tsx +81 -0
  64. package/src/components/notifications/index.ts +2 -0
  65. package/src/components/notifications/utils.ts +71 -0
  66. package/src/components/panels/alignment/index.module.css +20 -0
  67. package/src/components/panels/alignment/index.tsx +244 -0
  68. package/src/components/panels/base/index.tsx +5 -0
  69. package/src/components/panels/base/styles.module.css +12 -0
  70. package/src/components/panels/conversation/index.module.css +151 -0
  71. package/src/components/panels/conversation/index.tsx +162 -0
  72. package/src/components/panels/events/CustomEventsEditor.tsx +384 -0
  73. package/src/components/panels/events/EditEventPanel.tsx +315 -0
  74. package/src/components/panels/events/ManageEventsPanel.tsx +98 -0
  75. package/src/components/panels/events/index.tsx +23 -0
  76. package/src/components/panels/events/styles.module.css +236 -0
  77. package/src/components/panels/history/index.tsx +92 -0
  78. package/src/components/panels/history/styles.module.css +106 -0
  79. package/src/components/panels/keymaps/index.module.css +78 -0
  80. package/src/components/panels/keymaps/index.tsx +167 -0
  81. package/src/components/panels/layers/index.tsx +240 -0
  82. package/src/components/panels/layers/styles.module.css +110 -0
  83. package/src/components/panels/legend/index.module.css +6 -0
  84. package/src/components/panels/legend/index.tsx +76 -0
  85. package/src/components/panels/logs/index.module.css +212 -0
  86. package/src/components/panels/logs/index.tsx +288 -0
  87. package/src/components/panels/nodeInputs/InputControl.tsx +63 -0
  88. package/src/components/panels/nodeInputs/InputsGroup.tsx +64 -0
  89. package/src/components/panels/nodeInputs/MultipleNodesView.tsx +37 -0
  90. package/src/components/panels/nodeInputs/NodeSettings.tsx +92 -0
  91. package/src/components/panels/nodeInputs/NodeTitleEditor.tsx +125 -0
  92. package/src/components/panels/nodeInputs/OutputsGroup.tsx +65 -0
  93. package/src/components/panels/nodeInputs/SocketGenerators.tsx +32 -0
  94. package/src/components/panels/nodeInputs/index.module.css +284 -0
  95. package/src/components/panels/nodeInputs/index.tsx +339 -0
  96. package/src/components/panels/nodeInputs/useNodeHandlers.ts +76 -0
  97. package/src/components/panels/nodeInputs/useNodeInputsData.ts +173 -0
  98. package/src/components/panels/nodePicker/index.tsx +115 -0
  99. package/src/components/panels/panel/index.module.css +66 -0
  100. package/src/components/panels/panel/index.tsx +88 -0
  101. package/src/components/panels/search/index.module.css +66 -0
  102. package/src/components/panels/search/index.tsx +215 -0
  103. package/src/components/panels/systemSettings/index.tsx +206 -0
  104. package/src/components/panels/systemSettings/styles.module.css +11 -0
  105. package/src/components/panels/traces/GridLines.tsx +38 -0
  106. package/src/components/panels/traces/TimeGrid.tsx +48 -0
  107. package/src/components/panels/traces/TraceLane.tsx +62 -0
  108. package/src/components/panels/traces/TraceTooltip.tsx +22 -0
  109. package/src/components/panels/traces/TracesHeader.tsx +56 -0
  110. package/src/components/panels/traces/index.module.css +166 -0
  111. package/src/components/panels/traces/index.tsx +294 -0
  112. package/src/components/panels/traces/types.ts +48 -0
  113. package/src/components/panels/traces/useDerivedSpans.ts +212 -0
  114. package/src/components/panels/traces/utils.ts +25 -0
  115. package/src/components/panels/variables/CreateVariableScreen.tsx +162 -0
  116. package/src/components/panels/variables/ManageVariablesScreen.tsx +144 -0
  117. package/src/components/panels/variables/index.tsx +125 -0
  118. package/src/components/panels/variables/styles.module.css +236 -0
  119. package/src/components/primitives/icon.module.css +45 -0
  120. package/src/components/primitives/icon.tsx +38 -0
  121. package/src/components/sockets/input/index.tsx +76 -0
  122. package/src/components/sockets/input/styles.module.css +27 -0
  123. package/src/components/sockets/output/index.tsx +61 -0
  124. package/src/components/sockets/output/styles.module.css +27 -0
  125. package/src/css/prosemirror.css +57 -0
  126. package/src/css/rc-dock.css +112 -0
  127. package/src/css/rc-menu.css +100 -0
  128. package/src/css/vars.css +14 -0
  129. package/src/css/vscode.css +13 -0
  130. package/src/entry.css +4 -0
  131. package/src/generators/CustomEventOnTriggeredGenerator.tsx +85 -0
  132. package/src/generators/SequenceGenerator.tsx +104 -0
  133. package/src/generators/SwitchOnIntegerGenerator.tsx +256 -0
  134. package/src/generators/SwitchOnStringGenerator.tsx +263 -0
  135. package/src/generators/registerDefaultGenerators.ts +34 -0
  136. package/src/hooks/useBehaveGraphFlow.ts +17 -16
  137. package/src/hooks/useDetachNodes.ts +39 -0
  138. package/src/hooks/useFlowHandlers.ts +115 -29
  139. package/src/hooks/useWasdPan.ts +188 -0
  140. package/src/index.css +146 -0
  141. package/src/index.ts +36 -18
  142. package/src/layout/dagre.tsx +119 -0
  143. package/src/layout/elk.ts +200 -0
  144. package/src/plugin/alignment/index.ts +81 -0
  145. package/src/plugin/docs/index.tsx +299 -0
  146. package/src/plugin/docs/panel/index.tsx +200 -0
  147. package/src/plugin/docs/panel/styles.module.css +174 -0
  148. package/src/plugin/graphrunner/actions.ts +253 -0
  149. package/src/plugin/graphrunner/buttons.tsx +87 -0
  150. package/src/plugin/graphrunner/client.ts +704 -0
  151. package/src/plugin/graphrunner/index.tsx +255 -0
  152. package/src/plugin/graphrunner/panel.tsx +386 -0
  153. package/src/plugin/graphrunner/runner.ts +358 -0
  154. package/src/plugin/graphrunner/session.ts +243 -0
  155. package/src/plugin/graphrunner/store.ts +206 -0
  156. package/src/plugin/graphrunner/styles.module.css +211 -0
  157. package/src/plugin/graphrunner/transport.ts +224 -0
  158. package/src/plugin/graphrunner/types.ts +672 -0
  159. package/src/plugin/graphrunner-local/execution-utils.ts +457 -0
  160. package/src/plugin/graphrunner-local/index.tsx +166 -0
  161. package/src/plugin/graphrunner-local/panel.tsx +231 -0
  162. package/src/plugin/graphrunner-local/store.ts +41 -0
  163. package/src/plugin/graphrunner-local/styles.module.css +101 -0
  164. package/src/plugin/graphrunner-local/transport.ts +1372 -0
  165. package/src/plugin/graphrunner-local/types.ts +10 -0
  166. package/src/plugin/graphrunner-webworker/graph-executor.worker.ts +633 -0
  167. package/src/plugin/graphrunner-webworker/index.tsx +146 -0
  168. package/src/plugin/graphrunner-webworker/panel.tsx +173 -0
  169. package/src/plugin/graphrunner-webworker/store.ts +89 -0
  170. package/src/plugin/graphrunner-webworker/types.ts +17 -0
  171. package/src/plugin/graphrunner-webworker/worker-transport.ts +123 -0
  172. package/src/plugin/realtime/realtimeRunner.ts +570 -0
  173. package/src/specifics/CustomEventOnTriggeredSpecific.tsx +92 -0
  174. package/src/specifics/CustomEventTriggerSpecific.tsx +141 -0
  175. package/src/specifics/VariableGetSpecific.tsx +110 -0
  176. package/src/specifics/VariableSetSpecific.tsx +110 -0
  177. package/src/specifics/registerDefaultSpecifics.ts +5 -0
  178. package/src/store/actions.tsx +698 -0
  179. package/src/store/chat.ts +73 -0
  180. package/src/store/controls.tsx +62 -0
  181. package/src/store/documentation.tsx +69 -0
  182. package/src/store/events.tsx +116 -0
  183. package/src/store/flow.tsx +245 -0
  184. package/src/store/graphRunnerClient.ts +110 -0
  185. package/src/store/hotKeys.tsx +323 -0
  186. package/src/store/layers.ts +259 -0
  187. package/src/store/legend.tsx +76 -0
  188. package/src/store/logs.ts +28 -0
  189. package/src/store/menubar.ts +41 -0
  190. package/src/store/refs.ts +84 -0
  191. package/src/store/registry.ts +43 -0
  192. package/src/store/selection.ts +22 -0
  193. package/src/store/settings.ts +99 -0
  194. package/src/store/socketGenerator.tsx +54 -0
  195. package/src/store/specific.tsx +75 -0
  196. package/src/store/specs.tsx +35 -0
  197. package/src/store/tabs.ts +278 -0
  198. package/src/store/toolbar.tsx +45 -0
  199. package/src/store/traces.ts +240 -0
  200. package/src/store/variables.ts +37 -0
  201. package/src/system/graph.ts +134 -0
  202. package/src/system/index.ts +3 -0
  203. package/src/system/notifications.ts +98 -0
  204. package/src/system/plugin.ts +27 -0
  205. package/src/system/provider.tsx +22 -0
  206. package/src/system/pubsub.ts +323 -0
  207. package/src/system/system.ts +223 -0
  208. package/src/system/tabLoader.tsx +265 -0
  209. package/src/system/undoRedo.ts +103 -0
  210. package/src/transformers/Uigraph.ts +60 -0
  211. package/src/transformers/behaveToFlow.ts +16 -4
  212. package/src/transformers/flowToBehave.ts +32 -12
  213. package/src/types/NodeMetadata.ts +27 -0
  214. package/src/types/graph.ts +49 -0
  215. package/src/types/nodes.ts +45 -0
  216. package/src/types.ts +16 -0
  217. package/src/util/colors.ts +1 -29
  218. package/src/util/downloadJson.ts +18 -0
  219. package/src/util/extractNodeMetadata.ts +16 -0
  220. package/src/util/getPickerFilters.ts +1 -1
  221. package/src/util/isBehaveNode.ts +6 -0
  222. package/src/util/isValidConnection.ts +28 -15
  223. package/src/util/mergeSockets.ts +29 -0
  224. package/src/util/serializeVariables.ts +66 -0
  225. package/src/util/sockets.ts +43 -0
  226. package/stories/apex/layoutController/example-graph.worker.ts +39 -0
  227. package/stories/apex/layoutController/index.stories.tsx +48 -0
  228. package/stories/apex/layoutController/webworker.stories.tsx +103 -0
  229. package/stories/apex/menubar/menubar.stories.tsx +19 -0
  230. package/stories/components/colorpicker/index.stories.tsx +20 -0
  231. package/stories/components/contextMenus/edge.stories.tsx +32 -0
  232. package/stories/components/contextMenus/node.stories.tsx +26 -0
  233. package/stories/components/contextMenus/nodePicker.stories.tsx +115 -0
  234. package/stories/components/controls/any/index.stories.tsx +19 -0
  235. package/stories/components/controls/boolean/index.stories.tsx +19 -0
  236. package/stories/components/controls/colorPicker/index.stories.tsx +49 -0
  237. package/stories/components/controls/number/index.stories.tsx +19 -0
  238. package/stories/components/controls/string/index.stories.tsx +19 -0
  239. package/stories/components/nodes/behaveNode.stories.tsx +108 -0
  240. package/stories/components/nodes/comment.stories.tsx +106 -0
  241. package/stories/components/panels/alignment.stories.tsx +24 -0
  242. package/stories/components/panels/events.stories.tsx +38 -0
  243. package/stories/components/panels/graphRunner.stories.tsx +317 -0
  244. package/stories/components/panels/history.stories.tsx +37 -0
  245. package/stories/components/panels/keymaps.stories.tsx +21 -0
  246. package/stories/components/panels/legend.stories.tsx +37 -0
  247. package/stories/components/panels/logs.stories.tsx +24 -0
  248. package/stories/components/panels/nodeInputs.stories.tsx +21 -0
  249. package/stories/components/panels/nodePicker.stories.tsx +37 -0
  250. package/stories/components/panels/panel.stories.tsx +39 -0
  251. package/stories/components/panels/search.stories.tsx +24 -0
  252. package/stories/components/panels/systemSettings.stories.tsx +26 -0
  253. package/stories/components/panels/traces.stories.tsx +225 -0
  254. package/stories/components/panels/variables.stories.tsx +24 -0
  255. package/stories/defaults/defaultStoryProvider.tsx +167 -0
  256. package/stories/defaults/systemGenerator.ts +38 -0
  257. package/tests/components/edges/offsetBezier.test.ts +51 -0
  258. package/tests/components/layoutController/utils.test.ts +68 -0
  259. package/tests/components/panels/traces/utils.test.ts +52 -0
  260. package/tests/flowToBehave.test.ts +26 -4
  261. package/tests/notifications.test.ts +87 -0
  262. package/tests/saveLoad.test.ts +372 -0
  263. package/tests/util/calculateNewEdge.test.ts +98 -0
  264. package/tests/util/getSocketsByNodeTypeAndHandleType.test.ts +31 -0
  265. package/tests/util/hasPositionMetaData.test.ts +33 -0
  266. package/tests/util/isBehaveNode.test.ts +22 -0
  267. package/tests/util/isHandleConnected.test.ts +37 -0
  268. package/tests/util/mergeSockets.test.ts +43 -0
  269. package/tests/visual/README.md +64 -0
  270. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-alignment-chromium-win32.png +0 -0
  271. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-conversation-chromium-win32.png +0 -0
  272. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-events-chromium-win32.png +0 -0
  273. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-history-chromium-win32.png +0 -0
  274. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-keymaps-chromium-win32.png +0 -0
  275. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-layers-chromium-win32.png +0 -0
  276. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-legend-chromium-win32.png +0 -0
  277. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-logs-chromium-win32.png +0 -0
  278. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-nodeInputs-chromium-win32.png +0 -0
  279. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-nodePicker-chromium-win32.png +0 -0
  280. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-panel-chromium-win32.png +0 -0
  281. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-search-chromium-win32.png +0 -0
  282. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-systemSettings-chromium-win32.png +0 -0
  283. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-traces-chromium-win32.png +0 -0
  284. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-variables-chromium-win32.png +0 -0
  285. package/tests/visual/panels.visual.test.tsx +76 -0
  286. package/tsconfig.base.json +39 -0
  287. package/tsconfig.json +18 -59
  288. package/tsconfig.prod.json +23 -0
  289. package/tsdown.config.ts +15 -3
  290. package/typedoc.json +7 -7
  291. package/vite.config.js +7 -0
  292. package/vitest.config.ts +5 -2
  293. package/vitest.visual.config.ts +48 -0
  294. package/src/components/AutoSizeInput.tsx +0 -65
  295. package/src/components/Controls.tsx +0 -87
  296. package/src/components/InputSocket.tsx +0 -142
  297. package/src/components/Node.tsx +0 -68
  298. package/src/components/NodeContainer.tsx +0 -46
  299. package/src/components/NodePicker.tsx +0 -77
  300. package/src/components/OutputSocket.tsx +0 -58
  301. package/src/components/modals/ClearModal.tsx +0 -40
  302. package/src/components/modals/HelpModal.tsx +0 -36
  303. package/src/components/modals/LoadModal.tsx +0 -96
  304. package/src/components/modals/Modal.tsx +0 -64
  305. package/src/components/modals/SaveModal.tsx +0 -60
  306. package/src/hooks/useCustomNodeTypes.tsx +0 -31
  307. package/src/hooks/useGraphRunner.ts +0 -104
  308. package/src/hooks/useMergeMap.ts +0 -14
  309. package/src/hooks/useNodeSpecJson.ts +0 -20
  310. package/src/hooks/useQueriableDefinitions.ts +0 -22
  311. package/src/styles.css +0 -8
  312. package/tailwind.config.ts +0 -19
  313. package/tests/tsconfig.json +0 -10
  314. /package/src/{types.d.ts → types-declarations.d.ts} +0 -0
@@ -0,0 +1,358 @@
1
+ import type { System } from '../../system/system';
2
+ import type { StoreApi } from 'zustand';
3
+ import type { GraphRunnerClientStore } from './store';
4
+ import { GraphRunnerClient } from './client';
5
+ import { buildUIGraphJSON } from '../../transformers/Uigraph';
6
+ import { setupClientEventListeners } from './actions';
7
+
8
+ declare module '@/system/system' {
9
+ interface System {
10
+ runner: GraphRunner;
11
+ }
12
+ }
13
+
14
+ export class GraphRunner {
15
+ private system: System;
16
+ public readonly store: StoreApi<GraphRunnerClientStore>;
17
+
18
+ constructor(system: System, store: StoreApi<GraphRunnerClientStore>) {
19
+ this.system = system;
20
+ this.store = store;
21
+ }
22
+
23
+ /**
24
+ * Connect to the graph runner server
25
+ */
26
+ async connect(): Promise<void> {
27
+ const {
28
+ client,
29
+ connectionConfig,
30
+ setClient,
31
+ setConnectionState,
32
+ setConnectionInfo,
33
+ setError,
34
+ clearServerMetadata,
35
+ addMessageActivity
36
+ } = this.store.getState();
37
+
38
+ try {
39
+ setError(null);
40
+ setConnectionState('connecting');
41
+
42
+ const theClient =
43
+ client ??
44
+ new GraphRunnerClient({
45
+ url: connectionConfig.url,
46
+ auth: connectionConfig.auth,
47
+ autoReconnect: connectionConfig.autoReconnect,
48
+ onMessageActivity: (direction, message) => {
49
+ addMessageActivity(direction, message);
50
+ }
51
+ });
52
+
53
+ setClient(theClient);
54
+
55
+ await theClient.connect();
56
+
57
+ // Setup persistent event listeners for trace, logs, and run completion
58
+ setupClientEventListeners(theClient, this.system, this.store);
59
+
60
+ setConnectionState('connected');
61
+ setConnectionInfo({
62
+ serverId: theClient.getServerId(),
63
+ userId: theClient.getUserId(),
64
+ sessionId: null,
65
+ authenticated: theClient.isAuthenticated(),
66
+ capabilities: null
67
+ });
68
+
69
+ // Create session
70
+ const sessionId = await theClient.createSession();
71
+ setConnectionInfo({ sessionId });
72
+
73
+ // Get capabilities
74
+ const capabilities = await theClient.getCapabilities();
75
+ setConnectionInfo({ capabilities });
76
+
77
+ // Fetch metadata if supported
78
+ if (capabilities.runtimeMetadata) {
79
+ await this.refreshMetadata();
80
+ }
81
+
82
+ // Notify successful connection
83
+ this.system.notifications.success(
84
+ `Connected to ${theClient.getServerId() || 'graph runner server'}`
85
+ );
86
+ } catch (error) {
87
+ setConnectionState('disconnected');
88
+ const errorMessage =
89
+ error instanceof Error ? error.message : String(error);
90
+ setError(errorMessage);
91
+ setClient(null);
92
+ clearServerMetadata();
93
+
94
+ // Notify connection error
95
+ this.system.notifications.error(`Failed to connect: ${errorMessage}`);
96
+ }
97
+ }
98
+
99
+ /**
100
+ * Disconnect from the graph runner server
101
+ */
102
+ async disconnect(): Promise<void> {
103
+ const {
104
+ client,
105
+ setClient,
106
+ setConnectionState,
107
+ setConnectionInfo,
108
+ clearServerMetadata
109
+ } = this.store.getState();
110
+
111
+ console.log('Disconnecting from graph runner server...');
112
+ if (client) {
113
+ try {
114
+ await client.closeSession();
115
+ client.disconnect();
116
+ } catch (error) {
117
+ console.error('Error disconnecting:', error);
118
+ }
119
+ }
120
+
121
+ setClient(null);
122
+ setConnectionState('disconnected');
123
+ setConnectionInfo({
124
+ serverId: null,
125
+ userId: null,
126
+ sessionId: null,
127
+ authenticated: false,
128
+ capabilities: null
129
+ });
130
+ clearServerMetadata();
131
+ }
132
+
133
+ /**
134
+ * Refresh server metadata (variables, events, node types)
135
+ */
136
+ async refreshMetadata(): Promise<void> {
137
+ const {
138
+ client,
139
+ setServerVariables,
140
+ setServerEvents,
141
+ setNodeTypes,
142
+ setError
143
+ } = this.store.getState();
144
+ if (!client) {
145
+ return;
146
+ }
147
+
148
+ try {
149
+ const capabilities = client.getCachedCapabilities();
150
+ if (!capabilities?.runtimeMetadata) {
151
+ return;
152
+ }
153
+
154
+ const [variables, events, nodeTypes] = await Promise.all([
155
+ client.getServerVariables(),
156
+ client.getServerEvents(),
157
+ client.getNodeTypes()
158
+ ]);
159
+
160
+ setServerVariables(variables);
161
+ setServerEvents(events);
162
+ setNodeTypes(nodeTypes);
163
+
164
+ setError(null);
165
+ } catch (error) {
166
+ setError(error instanceof Error ? error.message : String(error));
167
+ }
168
+ }
169
+
170
+ /**
171
+ * Run a graph remotely
172
+ */
173
+ async runRemotely(
174
+ graphId: string,
175
+ options?: { graph?: unknown; inputs?: unknown }
176
+ ): Promise<void> {
177
+ const {
178
+ client,
179
+ setCurrentRunId,
180
+ setCurrentGraphId,
181
+ setIsExecuting,
182
+ setIsPaused,
183
+ isExecuting,
184
+ enableTracing
185
+ } = this.store.getState();
186
+
187
+ if (!client) {
188
+ this.system.notifications.error('No graph runner connection');
189
+ throw new Error('No graph runner connection');
190
+ }
191
+ //already running
192
+ if (isExecuting) {
193
+ return;
194
+ }
195
+
196
+ try {
197
+ const runId = await client.runGraph(graphId, {
198
+ ...options,
199
+ trace: enableTracing
200
+ });
201
+
202
+ setCurrentRunId(runId);
203
+ setCurrentGraphId(graphId);
204
+ setIsExecuting(true);
205
+ setIsPaused(false);
206
+
207
+ this.system.notifications.info(`Graph execution started: ${graphId}`);
208
+ } catch (error) {
209
+ const errorMessage =
210
+ error instanceof Error ? error.message : String(error);
211
+ setIsPaused(false);
212
+ this.system.notifications.error(`Failed to run graph: ${errorMessage}`);
213
+ setIsExecuting(false);
214
+ setCurrentRunId(null);
215
+ setCurrentGraphId(null);
216
+ throw error;
217
+ }
218
+ }
219
+
220
+ /**
221
+ * Stop the current graph execution
222
+ */
223
+ async stop(): Promise<void> {
224
+ const {
225
+ client,
226
+ currentRunId,
227
+ setIsExecuting,
228
+ setCurrentRunId,
229
+ setCurrentGraphId,
230
+ setIsPaused
231
+ } = this.store.getState();
232
+
233
+ if (!client || !currentRunId) {
234
+ return;
235
+ }
236
+
237
+ try {
238
+ await client.stopGraph(currentRunId);
239
+ this.system.notifications.info('Stopping graph execution');
240
+ setIsExecuting(false);
241
+ setCurrentRunId(null);
242
+ setCurrentGraphId(null);
243
+ setIsPaused(false);
244
+ } catch (error) {
245
+ const errorMessage =
246
+ error instanceof Error ? error.message : String(error);
247
+ this.system.notifications.error(`Failed to stop graph: ${errorMessage}`);
248
+ }
249
+ }
250
+
251
+ /**
252
+ * Play the current graph
253
+ */
254
+ async play(): Promise<void> {
255
+ const { clearLogsOnRun, clearTracesOnRun } = this.store.getState();
256
+
257
+ // Clear logs if enabled
258
+ if (clearLogsOnRun) {
259
+ this.system.logsStore.getState().clear();
260
+ }
261
+
262
+ // Clear traces if enabled
263
+ if (clearTracesOnRun) {
264
+ this.system.traceStore.getState().clear();
265
+ }
266
+
267
+ const graphId = 'current';
268
+ const uiGraphData = buildUIGraphJSON(this.system);
269
+ const graphData = uiGraphData.flow;
270
+
271
+ try {
272
+ await this.runRemotely(graphId, { graph: graphData });
273
+ } catch {
274
+ // Error already handled in runRemotely
275
+ }
276
+ }
277
+
278
+ /**
279
+ * Pause the current graph execution
280
+ */
281
+ async pause(): Promise<void> {
282
+ const { client, currentRunId, setIsPaused } = this.store.getState();
283
+
284
+ if (!client || !currentRunId) {
285
+ return;
286
+ }
287
+
288
+ try {
289
+ // Check if the client's transport is LocalTransport with pause support
290
+ const transport = (client as any).transport;
291
+ if (transport && typeof transport.pauseExecution === 'function') {
292
+ transport.pauseExecution(currentRunId);
293
+ setIsPaused(true);
294
+ this.system.notifications.info('Execution paused');
295
+ } else {
296
+ // Fallback to stop for remote transports
297
+ await this.stop();
298
+ }
299
+ } catch (error) {
300
+ const errorMessage =
301
+ error instanceof Error ? error.message : String(error);
302
+ this.system.notifications.error(`Failed to pause graph: ${errorMessage}`);
303
+ }
304
+ }
305
+
306
+ /**
307
+ * Resume paused execution
308
+ */
309
+ async resume(): Promise<void> {
310
+ const { client, currentRunId, setIsPaused } = this.store.getState();
311
+
312
+ if (!client || !currentRunId) {
313
+ return;
314
+ }
315
+
316
+ try {
317
+ const transport = (client as any).transport;
318
+ if (transport && typeof transport.resumeExecution === 'function') {
319
+ setIsPaused(false);
320
+ this.system.notifications.info('Resuming execution');
321
+ await transport.resumeExecution(currentRunId);
322
+ }
323
+ } catch (error) {
324
+ const errorMessage =
325
+ error instanceof Error ? error.message : String(error);
326
+ this.system.notifications.error(
327
+ `Failed to resume graph: ${errorMessage}`
328
+ );
329
+ }
330
+ }
331
+
332
+ /**
333
+ * Execute one step forward
334
+ */
335
+ async step(): Promise<void> {
336
+ const { client, currentRunId, setIsPaused } = this.store.getState();
337
+
338
+ if (!client || !currentRunId) {
339
+ return;
340
+ }
341
+
342
+ try {
343
+ const transport = (client as any).transport;
344
+ if (transport && typeof transport.stepExecution === 'function') {
345
+ setIsPaused(true); // Ensure we stay paused after stepping
346
+ await transport.stepExecution(currentRunId);
347
+ } else {
348
+ this.system.notifications.info(
349
+ 'Step execution not supported for this transport'
350
+ );
351
+ }
352
+ } catch (error) {
353
+ const errorMessage =
354
+ error instanceof Error ? error.message : String(error);
355
+ this.system.notifications.error(`Failed to step graph: ${errorMessage}`);
356
+ }
357
+ }
358
+ }
@@ -0,0 +1,243 @@
1
+ /**
2
+ * Session management for local graph runner
3
+ * Allows customization of execution context and configuration per session
4
+ */
5
+
6
+ import type { IRegistry } from '@kiberon-labs/behave-graph';
7
+ import type {
8
+ GraphRunnerCapabilities,
9
+ EventFilter
10
+ } from '../graphrunner/types.js';
11
+
12
+ /**
13
+ * Session configuration for graph execution
14
+ */
15
+ export interface SessionConfig {
16
+ /** Custom metadata attached to the session */
17
+ metadata?: Record<string, unknown>;
18
+ /** Default execution options for all runs in this session */
19
+ defaultExecutionOptions?: {
20
+ autoEnd?: boolean;
21
+ trace?: boolean;
22
+ eventFilter?: EventFilter;
23
+ maxExecutionTimeMs?: number;
24
+ };
25
+ /** Session-level execution settings */
26
+ executionSettings?: {
27
+ /** Delay between execution steps in milliseconds */
28
+ stepDelay?: number;
29
+ /** Execution speed multiplier (0.1 to 2.0) */
30
+ executionSpeed?: number;
31
+ /** Interval between tick events in milliseconds */
32
+ tickInterval?: number;
33
+ /** Maximum number of concurrent runs allowed */
34
+ maxConcurrentRuns?: number;
35
+ };
36
+ /** Custom hook for handling tick timing/delays */
37
+ tickStrategy?: () => Promise<void>;
38
+ /** Custom registry overrides for this session */
39
+ registryOverrides?: Partial<IRegistry>;
40
+ /** Session lifecycle hooks */
41
+ hooks?: SessionHooks;
42
+ /** Session-specific capabilities override */
43
+ capabilities?: Partial<GraphRunnerCapabilities>;
44
+ }
45
+
46
+ /**
47
+ * Lifecycle hooks for session events
48
+ */
49
+ export interface SessionHooks {
50
+ /** Called when the session is created */
51
+ onSessionCreated?: (session: Session) => void | Promise<void>;
52
+ /** Called when a run starts in this session */
53
+ onRunStarted?: (
54
+ session: Session,
55
+ runId: string,
56
+ graphId: string
57
+ ) => void | Promise<void>;
58
+ /** Called when a run completes in this session */
59
+ onRunCompleted?: (
60
+ session: Session,
61
+ runId: string,
62
+ graphId: string,
63
+ result: unknown
64
+ ) => void | Promise<void>;
65
+ /** Called when a run fails in this session */
66
+ onRunError?: (
67
+ session: Session,
68
+ runId: string,
69
+ graphId: string,
70
+ error: Error
71
+ ) => void | Promise<void>;
72
+ /** Called when the session is closed */
73
+ onSessionClosed?: (session: Session) => void | Promise<void>;
74
+ }
75
+
76
+ /**
77
+ * Session state
78
+ */
79
+ export interface Session {
80
+ /** Unique session identifier */
81
+ readonly sessionId: string;
82
+ /** Session expiration timestamp */
83
+ readonly expiresAt: number;
84
+ /** Session creation timestamp */
85
+ readonly createdAt: number;
86
+ /** Session configuration */
87
+ readonly config: SessionConfig;
88
+ /** Active run IDs in this session */
89
+ readonly activeRuns: Set<string>;
90
+ /** Custom session state (user-definable) */
91
+ state: Record<string, unknown>;
92
+ /** Session metadata */
93
+ metadata: Record<string, unknown>;
94
+ }
95
+
96
+ /**
97
+ * Factory for creating sessions with custom configuration
98
+ */
99
+ export interface SessionFactory {
100
+ /**
101
+ * Create a new session with optional configuration
102
+ */
103
+ createSession(sessionId: string, config?: SessionConfig): Session;
104
+ }
105
+
106
+ /**
107
+ * Default session factory implementation
108
+ */
109
+ export class DefaultSessionFactory implements SessionFactory {
110
+ private defaultConfig?: SessionConfig;
111
+
112
+ constructor(defaultConfig?: SessionConfig) {
113
+ this.defaultConfig = defaultConfig;
114
+ }
115
+
116
+ createSession(sessionId: string, config?: SessionConfig): Session {
117
+ const mergedConfig: SessionConfig = {
118
+ ...this.defaultConfig,
119
+ ...config,
120
+ metadata: {
121
+ ...this.defaultConfig?.metadata,
122
+ ...config?.metadata
123
+ },
124
+ defaultExecutionOptions: {
125
+ ...this.defaultConfig?.defaultExecutionOptions,
126
+ ...config?.defaultExecutionOptions
127
+ },
128
+ executionSettings: {
129
+ ...this.defaultConfig?.executionSettings,
130
+ ...config?.executionSettings
131
+ },
132
+ hooks: {
133
+ ...this.defaultConfig?.hooks,
134
+ ...config?.hooks
135
+ }
136
+ };
137
+
138
+ const session: Session = {
139
+ sessionId,
140
+ expiresAt: Date.now() + 24 * 60 * 60 * 1000, // 24 hours default
141
+ createdAt: Date.now(),
142
+ config: mergedConfig,
143
+ activeRuns: new Set(),
144
+ state: {},
145
+ metadata: mergedConfig.metadata ?? {}
146
+ };
147
+
148
+ // Call creation hook
149
+ if (mergedConfig.hooks?.onSessionCreated) {
150
+ void mergedConfig.hooks.onSessionCreated(session);
151
+ }
152
+
153
+ return session;
154
+ }
155
+ }
156
+
157
+ /**
158
+ * Session manager to track and manage multiple sessions
159
+ */
160
+ export class SessionManager {
161
+ private sessions = new Map<string, Session>();
162
+ private sessionFactory: SessionFactory;
163
+
164
+ constructor(sessionFactory?: SessionFactory) {
165
+ this.sessionFactory = sessionFactory ?? new DefaultSessionFactory();
166
+ }
167
+
168
+ /**
169
+ * Create a new session
170
+ */
171
+ createSession(sessionId: string, config?: SessionConfig): Session {
172
+ const session = this.sessionFactory.createSession(sessionId, config);
173
+ this.sessions.set(sessionId, session);
174
+ return session;
175
+ }
176
+
177
+ /**
178
+ * Get an existing session
179
+ */
180
+ getSession(sessionId: string): Session | undefined {
181
+ return this.sessions.get(sessionId);
182
+ }
183
+
184
+ /**
185
+ * Check if a session exists
186
+ */
187
+ hasSession(sessionId: string): boolean {
188
+ return this.sessions.has(sessionId);
189
+ }
190
+
191
+ /**
192
+ * Close and remove a session
193
+ */
194
+ async closeSession(sessionId: string): Promise<void> {
195
+ const session = this.sessions.get(sessionId);
196
+ if (session) {
197
+ // Call close hook
198
+ if (session.config.hooks?.onSessionClosed) {
199
+ await session.config.hooks.onSessionClosed(session);
200
+ }
201
+ this.sessions.delete(sessionId);
202
+ }
203
+ }
204
+
205
+ /**
206
+ * Add a run to a session
207
+ */
208
+ addRunToSession(sessionId: string, runId: string): void {
209
+ const session = this.sessions.get(sessionId);
210
+ if (session) {
211
+ session.activeRuns.add(runId);
212
+ }
213
+ }
214
+
215
+ /**
216
+ * Remove a run from a session
217
+ */
218
+ removeRunFromSession(sessionId: string, runId: string): void {
219
+ const session = this.sessions.get(sessionId);
220
+ if (session) {
221
+ session.activeRuns.delete(runId);
222
+ }
223
+ }
224
+
225
+ /**
226
+ * Get all active sessions
227
+ */
228
+ getActiveSessions(): Session[] {
229
+ return Array.from(this.sessions.values());
230
+ }
231
+
232
+ /**
233
+ * Clean up expired sessions
234
+ */
235
+ cleanupExpiredSessions(): void {
236
+ const now = Date.now();
237
+ for (const [sessionId, session] of this.sessions.entries()) {
238
+ if (session.expiresAt < now) {
239
+ void this.closeSession(sessionId);
240
+ }
241
+ }
242
+ }
243
+ }