@kiberon-labs/behave-graph-flow 1.0.0 → 3.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 (378) hide show
  1. package/.fallowrc.json +16 -0
  2. package/.storybook/main.ts +32 -0
  3. package/.storybook/manager.ts +6 -0
  4. package/.storybook/preview.ts +64 -0
  5. package/.storybook/styles.css +16 -0
  6. package/.turbo/turbo-build.log +7 -0
  7. package/CHANGELOG.md +368 -0
  8. package/LICENSE +6 -0
  9. package/README.md +2 -2
  10. package/data/Polynomial.json +510 -0
  11. package/data/sequence.json +337 -0
  12. package/data/trigger-event.json +241 -0
  13. package/data/variable-change.json +210 -0
  14. package/dist/AnyControlImpl-Ds-CShIB.js +20 -0
  15. package/dist/AnyControlImpl-Ds-CShIB.js.map +1 -0
  16. package/dist/DocumentationBrowserPanelImpl-deZNzFX8.js +166 -0
  17. package/dist/DocumentationBrowserPanelImpl-deZNzFX8.js.map +1 -0
  18. package/dist/entry.css +4 -0
  19. package/dist/index.css +42 -0
  20. package/dist/index.css.map +1 -0
  21. package/dist/index.d.ts +3597 -0
  22. package/dist/index.d.ts.map +1 -0
  23. package/dist/index.js +18009 -0
  24. package/dist/index.js.map +1 -0
  25. package/dist/noteImpl-KkrrWgJd.js +242 -0
  26. package/dist/noteImpl-KkrrWgJd.js.map +1 -0
  27. package/dist/styles.module-CvmpDkZj.css +3 -0
  28. package/dist/styles.module-CvmpDkZj.css.map +1 -0
  29. package/dist/styles.module-DZxg8aW9.js +271 -0
  30. package/dist/styles.module-DZxg8aW9.js.map +1 -0
  31. package/dist/useChangeNodeData-ChQGK7AI.js +23 -0
  32. package/dist/useChangeNodeData-ChQGK7AI.js.map +1 -0
  33. package/docs/notifications.md +246 -0
  34. package/docs/protocol.md +702 -0
  35. package/docs/specifics.md +191 -0
  36. package/package.json +82 -22
  37. package/postcss.config.ts +3 -4
  38. package/src/annotations/index.ts +32 -0
  39. package/src/components/FloatingToolbar/index.module.css +37 -0
  40. package/src/components/FloatingToolbar/index.tsx +256 -0
  41. package/src/components/Flow.tsx +287 -75
  42. package/src/components/contextMenus/DynamicContextMenu.tsx +85 -0
  43. package/src/components/contextMenus/NodePicker.module.css +274 -0
  44. package/src/components/contextMenus/NodePicker.tsx +481 -0
  45. package/src/components/contextMenus/edge.tsx +22 -0
  46. package/src/components/contextMenus/node.tsx +15 -0
  47. package/src/components/contextMenus/selection.tsx +11 -0
  48. package/src/components/controls/any/AnyControlImpl.tsx +14 -0
  49. package/src/components/controls/any/index.tsx +19 -0
  50. package/src/components/controls/boolean/index.tsx +13 -0
  51. package/src/components/controls/colorPicker/InputPopover.module.css +100 -0
  52. package/src/components/controls/colorPicker/InputPopover.tsx +31 -0
  53. package/src/components/controls/colorPicker/index.module.css +18 -0
  54. package/src/components/controls/colorPicker/index.tsx +61 -0
  55. package/src/components/controls/number/index.tsx +35 -0
  56. package/src/components/controls/string/index.tsx +16 -0
  57. package/src/components/edges/index.tsx +475 -0
  58. package/src/components/edges/offsetBezier.ts +134 -0
  59. package/src/components/hotKeys.tsx +20 -0
  60. package/src/components/layoutController/index.module.css +13 -0
  61. package/src/components/layoutController/index.tsx +140 -0
  62. package/src/components/layoutController/utils.ts +248 -0
  63. package/src/components/menubar/defaults.tsx +516 -0
  64. package/src/components/menubar/index.tsx +49 -0
  65. package/src/components/menubar/menuItem.module.css +31 -0
  66. package/src/components/menubar/menuItem.tsx +65 -0
  67. package/src/components/nodes/behave/Node.module.css +23 -0
  68. package/src/components/nodes/behave/Node.tsx +176 -0
  69. package/src/components/nodes/behave/NodeContainer.module.css +88 -0
  70. package/src/components/nodes/behave/NodeContainer.tsx +46 -0
  71. package/src/components/nodes/behave/index.tsx +14 -0
  72. package/src/components/nodes/group/index.tsx +109 -0
  73. package/src/components/nodes/wrapper/index.tsx +73 -0
  74. package/src/components/nodes/wrapper/styles.module.css +87 -0
  75. package/src/components/notifications/NotificationProvider.tsx +81 -0
  76. package/src/components/notifications/index.ts +2 -0
  77. package/src/components/notifications/utils.ts +71 -0
  78. package/src/components/panels/alignment/index.module.css +10 -0
  79. package/src/components/panels/alignment/index.tsx +244 -0
  80. package/src/components/panels/base/index.tsx +5 -0
  81. package/src/components/panels/base/styles.module.css +12 -0
  82. package/src/components/panels/common/PanelHeader.module.css +24 -0
  83. package/src/components/panels/common/PanelHeader.tsx +22 -0
  84. package/src/components/panels/common/SectionTitle.module.css +13 -0
  85. package/src/components/panels/common/SectionTitle.tsx +10 -0
  86. package/src/components/panels/events/EditEventPanel.tsx +324 -0
  87. package/src/components/panels/events/ManageEventsPanel.tsx +101 -0
  88. package/src/components/panels/events/index.tsx +23 -0
  89. package/src/components/panels/events/styles.module.css +178 -0
  90. package/src/components/panels/graphProperties/index.tsx +125 -0
  91. package/src/components/panels/history/index.tsx +92 -0
  92. package/src/components/panels/history/styles.module.css +97 -0
  93. package/src/components/panels/keymaps/index.module.css +68 -0
  94. package/src/components/panels/keymaps/index.tsx +166 -0
  95. package/src/components/panels/layers/index.tsx +245 -0
  96. package/src/components/panels/layers/styles.module.css +107 -0
  97. package/src/components/panels/legend/index.module.css +6 -0
  98. package/src/components/panels/legend/index.tsx +76 -0
  99. package/src/components/panels/logs/index.module.css +218 -0
  100. package/src/components/panels/logs/index.tsx +288 -0
  101. package/src/components/panels/nodeInputs/InputControl.tsx +63 -0
  102. package/src/components/panels/nodeInputs/InputsGroup.tsx +65 -0
  103. package/src/components/panels/nodeInputs/MultipleNodesView.tsx +37 -0
  104. package/src/components/panels/nodeInputs/NodeSettings.tsx +92 -0
  105. package/src/components/panels/nodeInputs/NodeTitleEditor.tsx +125 -0
  106. package/src/components/panels/nodeInputs/OutputsGroup.tsx +55 -0
  107. package/src/components/panels/nodeInputs/SocketGenerators.tsx +32 -0
  108. package/src/components/panels/nodeInputs/index.module.css +308 -0
  109. package/src/components/panels/nodeInputs/index.tsx +349 -0
  110. package/src/components/panels/nodeInputs/useNodeHandlers.ts +76 -0
  111. package/src/components/panels/nodeInputs/useNodeInputsData.ts +153 -0
  112. package/src/components/panels/nodePicker/index.tsx +115 -0
  113. package/src/components/panels/panel/index.module.css +66 -0
  114. package/src/components/panels/panel/index.tsx +88 -0
  115. package/src/components/panels/search/index.module.css +16 -0
  116. package/src/components/panels/search/index.tsx +215 -0
  117. package/src/components/panels/systemSettings/ConversionsSettings.tsx +203 -0
  118. package/src/components/panels/systemSettings/index.tsx +251 -0
  119. package/src/components/panels/systemSettings/styles.module.css +138 -0
  120. package/src/components/panels/traces/GridLines.tsx +38 -0
  121. package/src/components/panels/traces/TimeGrid.tsx +48 -0
  122. package/src/components/panels/traces/TraceLane.tsx +62 -0
  123. package/src/components/panels/traces/TraceTooltip.tsx +22 -0
  124. package/src/components/panels/traces/TracesHeader.tsx +56 -0
  125. package/src/components/panels/traces/index.module.css +159 -0
  126. package/src/components/panels/traces/index.tsx +298 -0
  127. package/src/components/panels/traces/types.ts +48 -0
  128. package/src/components/panels/traces/useDerivedSpans.ts +307 -0
  129. package/src/components/panels/traces/utils.ts +33 -0
  130. package/src/components/panels/variables/CreateVariableScreen.tsx +162 -0
  131. package/src/components/panels/variables/ManageVariablesScreen.tsx +147 -0
  132. package/src/components/panels/variables/index.tsx +125 -0
  133. package/src/components/panels/variables/styles.module.css +149 -0
  134. package/src/components/primitives/icon.module.css +45 -0
  135. package/src/components/primitives/icon.tsx +38 -0
  136. package/src/components/sockets/input/index.tsx +83 -0
  137. package/src/components/sockets/input/styles.module.css +26 -0
  138. package/src/components/sockets/output/index.tsx +68 -0
  139. package/src/components/sockets/output/styles.module.css +22 -0
  140. package/src/css/notes.css +135 -0
  141. package/src/css/prosemirror.css +57 -0
  142. package/src/css/rc-dock.css +212 -0
  143. package/src/css/rc-menu.css +101 -0
  144. package/src/css/themes/kiberon.css +127 -0
  145. package/src/css/vars.css +198 -0
  146. package/src/css/vscode-elements.css +124 -0
  147. package/src/entry.css +4 -0
  148. package/src/generators/CallSubgraphGenerator.tsx +136 -0
  149. package/src/generators/CustomEventOnTriggeredGenerator.tsx +85 -0
  150. package/src/generators/GraphBoundaryGenerator.module.css +32 -0
  151. package/src/generators/GraphBoundaryGenerator.tsx +193 -0
  152. package/src/generators/SequenceGenerator.tsx +104 -0
  153. package/src/generators/SwitchOnIntegerGenerator.tsx +256 -0
  154. package/src/generators/SwitchOnStringGenerator.tsx +263 -0
  155. package/src/generators/callSubgraphSync.ts +126 -0
  156. package/src/generators/registerDefaultGenerators.ts +55 -0
  157. package/src/generators/registerDefaults.ts +26 -0
  158. package/src/hooks/useBehaveGraphFlow.ts +17 -16
  159. package/src/hooks/useFlowHandlers.ts +154 -30
  160. package/src/hooks/useWasdPan.ts +210 -0
  161. package/src/index.css +134 -0
  162. package/src/index.ts +53 -18
  163. package/src/manifest/contributionRegistry.ts +93 -0
  164. package/src/manifest/index.ts +4 -0
  165. package/src/manifest/loadManifest.ts +82 -0
  166. package/src/manifest/manifestPlugin.ts +29 -0
  167. package/src/manifest/passthroughValueType.ts +40 -0
  168. package/src/plugin/alignment/index.ts +91 -0
  169. package/src/plugin/autosave/controller.ts +366 -0
  170. package/src/plugin/autosave/index.tsx +114 -0
  171. package/src/plugin/autosave/panel/BackupPanel.tsx +141 -0
  172. package/src/plugin/autosave/panel/index.tsx +1 -0
  173. package/src/plugin/autosave/panel/styles.module.css +56 -0
  174. package/src/plugin/autosave/settings.ts +65 -0
  175. package/src/plugin/autosave/storage.ts +147 -0
  176. package/src/plugin/docs/index.tsx +297 -0
  177. package/src/plugin/docs/panel/DocumentationBrowserPanelImpl.tsx +200 -0
  178. package/src/plugin/docs/panel/index.tsx +21 -0
  179. package/src/plugin/docs/panel/styles.module.css +174 -0
  180. package/src/plugin/graphrunner/actions.ts +326 -0
  181. package/src/plugin/graphrunner/buttons.tsx +95 -0
  182. package/src/plugin/graphrunner/client.ts +707 -0
  183. package/src/plugin/graphrunner/index.tsx +184 -0
  184. package/src/plugin/graphrunner/panel.tsx +386 -0
  185. package/src/plugin/graphrunner/runController.ts +283 -0
  186. package/src/plugin/graphrunner/runner.ts +187 -0
  187. package/src/plugin/graphrunner/session.ts +243 -0
  188. package/src/plugin/graphrunner/store.ts +196 -0
  189. package/src/plugin/graphrunner/styles.module.css +171 -0
  190. package/src/plugin/graphrunner/transport.ts +250 -0
  191. package/src/plugin/graphrunner/types.ts +693 -0
  192. package/src/plugin/graphrunner-local/execution-utils.ts +637 -0
  193. package/src/plugin/graphrunner-local/index.tsx +172 -0
  194. package/src/plugin/graphrunner-local/panel.tsx +187 -0
  195. package/src/plugin/graphrunner-local/store.ts +41 -0
  196. package/src/plugin/graphrunner-local/styles.module.css +82 -0
  197. package/src/plugin/graphrunner-local/transport.ts +1339 -0
  198. package/src/plugin/graphrunner-local/types.ts +10 -0
  199. package/src/plugin/graphrunner-webworker/graph-executor.worker.ts +635 -0
  200. package/src/plugin/graphrunner-webworker/index.tsx +140 -0
  201. package/src/plugin/graphrunner-webworker/panel.tsx +173 -0
  202. package/src/plugin/graphrunner-webworker/store.ts +98 -0
  203. package/src/plugin/graphrunner-webworker/worker-transport.ts +123 -0
  204. package/src/plugin/kitchen-sink/index.ts +38 -0
  205. package/src/plugin/layout/dagre.ts +131 -0
  206. package/src/plugin/layout/elk.ts +216 -0
  207. package/src/plugin/layout/index.ts +80 -0
  208. package/src/plugin/notes/FormatToolbar.tsx +200 -0
  209. package/src/plugin/notes/index.tsx +191 -0
  210. package/src/plugin/notes/nodeActions.ts +100 -0
  211. package/src/plugin/notes/note.tsx +20 -0
  212. package/src/plugin/notes/noteImpl.tsx +89 -0
  213. package/src/plugin/realtime/realtimeRunner.ts +624 -0
  214. package/src/specifics/CustomEventOnTriggeredSpecific.tsx +92 -0
  215. package/src/specifics/CustomEventTriggerSpecific.tsx +141 -0
  216. package/src/specifics/VariableGetSpecific.tsx +110 -0
  217. package/src/specifics/VariableSetSpecific.tsx +110 -0
  218. package/src/store/actions.tsx +698 -0
  219. package/src/store/commands.ts +278 -0
  220. package/src/store/contextMenu.ts +192 -0
  221. package/src/store/controls.tsx +62 -0
  222. package/src/store/conversions.ts +47 -0
  223. package/src/store/documentation.tsx +69 -0
  224. package/src/store/events.tsx +116 -0
  225. package/src/store/flow.tsx +230 -0
  226. package/src/store/graphMeta.ts +39 -0
  227. package/src/store/hotKeys.tsx +364 -0
  228. package/src/store/layers.ts +259 -0
  229. package/src/store/legend.tsx +76 -0
  230. package/src/store/logs.ts +28 -0
  231. package/src/store/menubar.ts +41 -0
  232. package/src/store/refs.ts +84 -0
  233. package/src/store/registry.ts +51 -0
  234. package/src/store/selection.ts +22 -0
  235. package/src/store/settings.ts +99 -0
  236. package/src/store/settingsSchema.ts +210 -0
  237. package/src/store/socketGenerator.tsx +54 -0
  238. package/src/store/specific.tsx +75 -0
  239. package/src/store/specs.tsx +35 -0
  240. package/src/store/tabs.ts +282 -0
  241. package/src/store/toolbar.tsx +45 -0
  242. package/src/store/traces.ts +240 -0
  243. package/src/store/variables.ts +37 -0
  244. package/src/system/graph.ts +131 -0
  245. package/src/system/graphSession.ts +172 -0
  246. package/src/system/index.ts +6 -0
  247. package/src/system/notifications.ts +111 -0
  248. package/src/system/persistence.ts +82 -0
  249. package/src/system/plugin.ts +55 -0
  250. package/src/system/provider.tsx +86 -0
  251. package/src/system/pubsub.ts +323 -0
  252. package/src/system/system.ts +653 -0
  253. package/src/system/tabLoader.tsx +303 -0
  254. package/src/system/undoRedo.ts +103 -0
  255. package/src/transformers/Uigraph.ts +61 -0
  256. package/src/transformers/behaveToFlow.ts +16 -4
  257. package/src/transformers/contract.ts +87 -0
  258. package/src/transformers/flowToBehave.ts +40 -12
  259. package/src/types/NodeMetadata.ts +27 -0
  260. package/src/types/graph.ts +49 -0
  261. package/src/types/nodes.ts +50 -0
  262. package/src/types.ts +18 -0
  263. package/src/util/autoConvert.ts +200 -0
  264. package/src/util/colors.ts +1 -29
  265. package/src/util/downloadJson.ts +18 -0
  266. package/src/util/extractNodeMetadata.ts +16 -0
  267. package/src/util/getPickerFilters.ts +1 -1
  268. package/src/util/isBehaveNode.ts +6 -0
  269. package/src/util/isValidConnection.ts +51 -17
  270. package/src/util/mergeSockets.ts +29 -0
  271. package/src/util/serializeVariables.ts +66 -0
  272. package/src/util/sockets.ts +43 -0
  273. package/stories/apex/layoutController/example-graph.worker.ts +39 -0
  274. package/stories/apex/layoutController/index.stories.tsx +48 -0
  275. package/stories/apex/layoutController/webworker.stories.tsx +103 -0
  276. package/stories/apex/menubar/menubar.stories.tsx +19 -0
  277. package/stories/components/colorpicker/index.stories.tsx +20 -0
  278. package/stories/components/contextMenus/edge.stories.tsx +32 -0
  279. package/stories/components/contextMenus/node.stories.tsx +26 -0
  280. package/stories/components/contextMenus/nodePicker.stories.tsx +115 -0
  281. package/stories/components/controls/any/index.stories.tsx +19 -0
  282. package/stories/components/controls/boolean/index.stories.tsx +19 -0
  283. package/stories/components/controls/colorPicker/index.stories.tsx +49 -0
  284. package/stories/components/controls/number/index.stories.tsx +19 -0
  285. package/stories/components/controls/string/index.stories.tsx +19 -0
  286. package/stories/components/nodes/behaveNode.stories.tsx +108 -0
  287. package/stories/components/panels/alignment.stories.tsx +24 -0
  288. package/stories/components/panels/events.stories.tsx +38 -0
  289. package/stories/components/panels/graphRunner.stories.tsx +317 -0
  290. package/stories/components/panels/history.stories.tsx +37 -0
  291. package/stories/components/panels/keymaps.stories.tsx +21 -0
  292. package/stories/components/panels/legend.stories.tsx +37 -0
  293. package/stories/components/panels/logs.stories.tsx +24 -0
  294. package/stories/components/panels/nodeInputs.stories.tsx +21 -0
  295. package/stories/components/panels/nodePicker.stories.tsx +37 -0
  296. package/stories/components/panels/panel.stories.tsx +39 -0
  297. package/stories/components/panels/search.stories.tsx +24 -0
  298. package/stories/components/panels/systemSettings.stories.tsx +26 -0
  299. package/stories/components/panels/traces.stories.tsx +225 -0
  300. package/stories/components/panels/variables.stories.tsx +24 -0
  301. package/stories/defaults/defaultStoryProvider.tsx +170 -0
  302. package/stories/defaults/systemGenerator.ts +43 -0
  303. package/stories/plugins/notes.stories.tsx +100 -0
  304. package/tests/autoConvert.test.ts +329 -0
  305. package/tests/autosavePlugin.test.ts +204 -0
  306. package/tests/callSubgraphSync.test.ts +148 -0
  307. package/tests/commandRegistry.test.ts +137 -0
  308. package/tests/components/edges/offsetBezier.test.ts +51 -0
  309. package/tests/components/layoutController/utils.test.ts +68 -0
  310. package/tests/components/panels/traces/utils.test.ts +52 -0
  311. package/tests/contract.test.ts +51 -0
  312. package/tests/contractSerialize.test.ts +62 -0
  313. package/tests/deriveSpans.test.ts +71 -0
  314. package/tests/flowToBehave.test.ts +27 -4
  315. package/tests/hotkeys.test.ts +79 -0
  316. package/tests/keepAliveLifecycle.test.ts +167 -0
  317. package/tests/loadManifest.test.ts +113 -0
  318. package/tests/noteMarkdown.test.ts +65 -0
  319. package/tests/notesPlugin.test.ts +162 -0
  320. package/tests/notifications.test.ts +87 -0
  321. package/tests/persistence.test.ts +51 -0
  322. package/tests/saveLoad.test.ts +373 -0
  323. package/tests/settings.test.ts +178 -0
  324. package/tests/traceStore.test.ts +46 -0
  325. package/tests/util/calculateNewEdge.test.ts +98 -0
  326. package/tests/util/getSocketsByNodeTypeAndHandleType.test.ts +31 -0
  327. package/tests/util/hasPositionMetaData.test.ts +33 -0
  328. package/tests/util/isBehaveNode.test.ts +22 -0
  329. package/tests/util/isHandleConnected.test.ts +37 -0
  330. package/tests/util/mergeSockets.test.ts +43 -0
  331. package/tests/visual/README.md +64 -0
  332. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-alignment-chromium-win32.png +0 -0
  333. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-conversation-chromium-win32.png +0 -0
  334. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-events-chromium-win32.png +0 -0
  335. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-history-chromium-win32.png +0 -0
  336. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-keymaps-chromium-win32.png +0 -0
  337. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-layers-chromium-win32.png +0 -0
  338. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-legend-chromium-win32.png +0 -0
  339. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-localGraphRunner-chromium-win32.png +0 -0
  340. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-logs-chromium-win32.png +0 -0
  341. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-nodeInputs-chromium-win32.png +0 -0
  342. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-nodePicker-chromium-win32.png +0 -0
  343. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-panel-chromium-win32.png +0 -0
  344. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-search-chromium-win32.png +0 -0
  345. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-systemSettings-chromium-win32.png +0 -0
  346. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-traces-chromium-win32.png +0 -0
  347. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-variables-chromium-win32.png +0 -0
  348. package/tests/visual/panels.visual.test.tsx +76 -0
  349. package/tests/wasdPan.test.ts +71 -0
  350. package/tsconfig.base.json +39 -0
  351. package/tsconfig.json +18 -59
  352. package/tsconfig.prod.json +23 -0
  353. package/tsdown.config.ts +15 -3
  354. package/typedoc.json +7 -7
  355. package/vite.config.js +7 -0
  356. package/vitest.config.ts +5 -2
  357. package/vitest.visual.config.ts +55 -0
  358. package/src/components/AutoSizeInput.tsx +0 -65
  359. package/src/components/Controls.tsx +0 -87
  360. package/src/components/InputSocket.tsx +0 -142
  361. package/src/components/Node.tsx +0 -68
  362. package/src/components/NodeContainer.tsx +0 -46
  363. package/src/components/NodePicker.tsx +0 -77
  364. package/src/components/OutputSocket.tsx +0 -58
  365. package/src/components/modals/ClearModal.tsx +0 -40
  366. package/src/components/modals/HelpModal.tsx +0 -36
  367. package/src/components/modals/LoadModal.tsx +0 -96
  368. package/src/components/modals/Modal.tsx +0 -64
  369. package/src/components/modals/SaveModal.tsx +0 -60
  370. package/src/hooks/useCustomNodeTypes.tsx +0 -31
  371. package/src/hooks/useGraphRunner.ts +0 -104
  372. package/src/hooks/useMergeMap.ts +0 -14
  373. package/src/hooks/useNodeSpecJson.ts +0 -20
  374. package/src/hooks/useQueriableDefinitions.ts +0 -22
  375. package/src/styles.css +0 -8
  376. package/tailwind.config.ts +0 -19
  377. package/tests/tsconfig.json +0 -10
  378. /package/src/{types.d.ts → types-declarations.d.ts} +0 -0
@@ -0,0 +1,303 @@
1
+ import { Flow } from '@/components/Flow';
2
+ import type { TabBase, TabData } from 'rc-dock';
3
+ import { ErrorBoundary } from 'react-error-boundary';
4
+ import type { System } from './system';
5
+ import { Settings } from '@/components/panels/systemSettings';
6
+ import { LogsPanel } from '@/components/panels/logs';
7
+ import { VariablesPanel } from '@/components/panels/variables';
8
+ import { NodeInputsPanel } from '@/components/panels/nodeInputs';
9
+ import { AlignmentPanel } from '@/components/panels/alignment';
10
+ import { SearchPanel } from '@/components/panels/search';
11
+ import { KeymapsPanel } from '@/components/panels/keymaps';
12
+ import { EventsPanel } from '@/components/panels/events';
13
+ import { TracesPanel } from '@/components/panels/traces';
14
+ import { LegendPanel } from '@/components/panels/legend';
15
+ import { HistoryPanel } from '@/components/panels/history';
16
+ import { HotKeys } from '@/components/hotKeys';
17
+ import { NodePickerPanel } from '@/components/panels/nodePicker';
18
+ import { PanelPanel } from '@/components/panels/panel';
19
+ import { LayersPanel } from '@/components/panels/layers';
20
+ import { GraphPropertiesPanel } from '@/components/panels/graphProperties';
21
+ import { GraphProvider } from './provider';
22
+ import { useStore } from 'zustand';
23
+ import type { GraphSession } from './graphSession';
24
+ import {
25
+ DEFAULT_GRAPH_ID,
26
+ isGraphTabId,
27
+ sessionIdFromTabId,
28
+ tabIdForSession
29
+ } from '@/components/layoutController/utils';
30
+
31
+ /** Live graph tab title , re-renders when the graph is renamed. */
32
+ const GraphTabTitle = ({ session }: { session: GraphSession }) => {
33
+ const name = useStore(session.metaStore, (s) => s.name);
34
+ return <>{name}</>;
35
+ };
36
+
37
+ export class TabLoader {
38
+ public readonly tabs: Record<string, () => TabData> = {};
39
+ private readonly system: System;
40
+
41
+ constructor(system: System) {
42
+ this.system = system;
43
+
44
+ // The default graph tab. Other graphs are loaded dynamically by id
45
+ // (see `loadGraphTab`).
46
+ this.register(DEFAULT_GRAPH_ID, () => this.buildGraphTab(DEFAULT_GRAPH_ID));
47
+
48
+ this.register('system:settings', () => {
49
+ return {
50
+ id: 'system:settings',
51
+ closable: true,
52
+ group: 'default',
53
+ title: 'System Settings',
54
+ content: () => (
55
+ <ErrorBoundary fallback={'whoops'}>
56
+ <Settings />
57
+ </ErrorBoundary>
58
+ )
59
+ };
60
+ });
61
+
62
+ this.register('distribution', () => {
63
+ return {
64
+ id: 'distribution',
65
+ closable: true,
66
+ group: 'default',
67
+ title: 'Distribution + Alignment',
68
+ content: () => (
69
+ <ErrorBoundary fallback={'whoops'}>
70
+ <AlignmentPanel />
71
+ </ErrorBoundary>
72
+ )
73
+ };
74
+ });
75
+
76
+ this.register('variables', () => {
77
+ return {
78
+ id: 'variables',
79
+ closable: true,
80
+ title: 'Variables',
81
+ group: 'default',
82
+ content: () => (
83
+ <ErrorBoundary fallback={'whoops'}>
84
+ <VariablesPanel />
85
+ </ErrorBoundary>
86
+ )
87
+ };
88
+ });
89
+
90
+ this.register('logs', () => {
91
+ return {
92
+ id: 'logs',
93
+ closable: true,
94
+ title: 'Logs',
95
+ group: 'default',
96
+ content: () => (
97
+ <ErrorBoundary fallback={'whoops'}>
98
+ <LogsPanel />
99
+ </ErrorBoundary>
100
+ )
101
+ };
102
+ });
103
+
104
+ this.register('graphProperties', () => {
105
+ return {
106
+ id: 'graphProperties',
107
+ closable: true,
108
+ title: 'Graph Properties',
109
+ group: 'default',
110
+ content: () => (
111
+ <ErrorBoundary fallback={'whoops'}>
112
+ <GraphPropertiesPanel />
113
+ </ErrorBoundary>
114
+ )
115
+ };
116
+ });
117
+ this.register('find', () => {
118
+ return {
119
+ id: 'find',
120
+ closable: true,
121
+ title: 'Find',
122
+ group: 'default',
123
+ content: () => (
124
+ <ErrorBoundary fallback={'whoops'}>
125
+ <SearchPanel />
126
+ </ErrorBoundary>
127
+ )
128
+ };
129
+ });
130
+
131
+ this.register('nodeInputs', () => {
132
+ return {
133
+ id: 'nodeInputs',
134
+ closable: true,
135
+ title: 'Node Inputs',
136
+ group: 'default',
137
+ content: () => (
138
+ <ErrorBoundary fallback={'whoops'}>
139
+ <NodeInputsPanel />
140
+ </ErrorBoundary>
141
+ )
142
+ };
143
+ });
144
+
145
+ this.register('keymaps', () => {
146
+ return {
147
+ id: 'keymaps',
148
+ closable: true,
149
+ title: 'Keyboard Shortcuts',
150
+ group: 'default',
151
+ content: () => (
152
+ <ErrorBoundary fallback={'whoops'}>
153
+ <KeymapsPanel />
154
+ </ErrorBoundary>
155
+ )
156
+ };
157
+ });
158
+
159
+ this.register('events', () => {
160
+ return {
161
+ id: 'events',
162
+ closable: true,
163
+ title: 'Events',
164
+ group: 'default',
165
+ content: () => (
166
+ <ErrorBoundary fallback={'whoops'}>
167
+ <EventsPanel />
168
+ </ErrorBoundary>
169
+ )
170
+ };
171
+ });
172
+
173
+ this.register('traces', () => {
174
+ return {
175
+ id: 'traces',
176
+ closable: true,
177
+ title: 'Traces',
178
+ group: 'default',
179
+ content: () => (
180
+ <ErrorBoundary fallback={'whoops'}>
181
+ <TracesPanel />
182
+ </ErrorBoundary>
183
+ )
184
+ };
185
+ });
186
+
187
+ this.register('legend', () => {
188
+ return {
189
+ id: 'legend',
190
+ closable: true,
191
+ title: 'Legend',
192
+ group: 'default',
193
+ content: () => (
194
+ <ErrorBoundary fallback={'whoops'}>
195
+ <LegendPanel />
196
+ </ErrorBoundary>
197
+ )
198
+ };
199
+ });
200
+
201
+ this.register('history', () => {
202
+ return {
203
+ id: 'history',
204
+ closable: true,
205
+ title: 'History',
206
+ group: 'default',
207
+ content: () => (
208
+ <ErrorBoundary fallback={'whoops'}>
209
+ <HistoryPanel />
210
+ </ErrorBoundary>
211
+ )
212
+ };
213
+ });
214
+
215
+ this.register('layers', () => {
216
+ return {
217
+ id: 'layers',
218
+ closable: true,
219
+ title: 'Layers',
220
+ group: 'default',
221
+ content: () => (
222
+ <ErrorBoundary fallback={'whoops'}>
223
+ <LayersPanel />
224
+ </ErrorBoundary>
225
+ )
226
+ };
227
+ });
228
+
229
+ this.register('nodepicker', () => {
230
+ return {
231
+ id: 'nodepicker',
232
+ closable: true,
233
+ cached: true,
234
+ title: 'Add Node',
235
+ group: 'headless',
236
+ content: () => (
237
+ <ErrorBoundary fallback={'whoops'}>
238
+ <NodePickerPanel />
239
+ </ErrorBoundary>
240
+ )
241
+ };
242
+ });
243
+
244
+ this.register('panels', () => {
245
+ return {
246
+ id: 'panels',
247
+ closable: true,
248
+ title: 'Panels',
249
+ group: 'default',
250
+ content: () => (
251
+ <ErrorBoundary fallback={'whoops'}>
252
+ <PanelPanel />
253
+ </ErrorBoundary>
254
+ )
255
+ };
256
+ });
257
+
258
+ // The 'conversation' tab is provided by the AI nodes package's editor
259
+ // plugin (`@kiberon-labs/behave-graph-nodes-ai/ui`), which owns the chat
260
+ // store and panel.
261
+ }
262
+
263
+ load(tab: TabBase): TabData | undefined {
264
+ if (!tab.id) {
265
+ return;
266
+ }
267
+ // Dynamic per-graph tabs (`graph:<sessionId>`) are not in the registry.
268
+ if (isGraphTabId(tab.id) && tab.id !== DEFAULT_GRAPH_ID) {
269
+ return this.buildGraphTab(tab.id);
270
+ }
271
+ return this.tabs[tab.id]?.();
272
+ }
273
+
274
+ register(id: string, loader: () => TabData) {
275
+ this.tabs[id] = loader;
276
+ }
277
+
278
+ /**
279
+ * Build the TabData for a graph tab, resolving (or lazily creating) its
280
+ * session and wrapping the canvas in a {@link GraphProvider} so it stays bound
281
+ * to its own graph regardless of which tab is focused.
282
+ */
283
+ private buildGraphTab(tabId: string): TabData {
284
+ const sessionId = sessionIdFromTabId(tabId);
285
+ const session = this.system.getOrCreateSession(sessionId);
286
+ return {
287
+ id: tabIdForSession(sessionId),
288
+ closable: true,
289
+ cached: true,
290
+ group: 'graph',
291
+ title: <GraphTabTitle session={session} />,
292
+ content: () => (
293
+ <ErrorBoundary fallback={'whoops'}>
294
+ <GraphProvider value={session}>
295
+ <HotKeys>
296
+ <Flow />
297
+ </HotKeys>
298
+ </GraphProvider>
299
+ </ErrorBoundary>
300
+ )
301
+ };
302
+ }
303
+ }
@@ -0,0 +1,103 @@
1
+ import { create } from 'zustand';
2
+
3
+ export interface Command {
4
+ name: string;
5
+ execute(): void;
6
+ undo(): void;
7
+ /**
8
+ * Optional redo method if different from execute
9
+ */
10
+ redo?(): void;
11
+ }
12
+
13
+ export type UndoStackEntry = {
14
+ name: string;
15
+ };
16
+
17
+ export type UndoStore = {
18
+ canUndo: boolean;
19
+ canRedo: boolean;
20
+ history: UndoStackEntry[];
21
+ redoStack: UndoStackEntry[];
22
+ setSnapshot: (snapshot: {
23
+ canUndo: boolean;
24
+ canRedo: boolean;
25
+ history: UndoStackEntry[];
26
+ redoStack: UndoStackEntry[];
27
+ }) => void;
28
+ };
29
+
30
+ const undoStoreFactory = () =>
31
+ create<UndoStore>((set) => ({
32
+ canUndo: false,
33
+ canRedo: false,
34
+ history: [],
35
+ redoStack: [],
36
+ setSnapshot: (snapshot) => set(() => snapshot)
37
+ }));
38
+
39
+ export class UndoManager {
40
+ private history: Command[] = [];
41
+ private stack: Command[] = [];
42
+ private limit = 100; // optional limit
43
+ public store = undoStoreFactory();
44
+
45
+ constructor() {
46
+ this.syncStore();
47
+ }
48
+
49
+ private syncStore() {
50
+ this.store.getState().setSnapshot({
51
+ canUndo: this.canUndo(),
52
+ canRedo: this.canRedo(),
53
+ history: this.history.map((c) => ({ name: c.name })),
54
+ redoStack: this.stack.map((c) => ({ name: c.name }))
55
+ });
56
+ }
57
+
58
+ execute(command: Command) {
59
+ command.execute();
60
+ this.history.push(command);
61
+ this.stack = []; // clear redo stack
62
+
63
+ if (this.history.length > this.limit) {
64
+ this.history.shift();
65
+ }
66
+
67
+ this.syncStore();
68
+ }
69
+
70
+ undo() {
71
+ const command = this.history.pop();
72
+ if (command) {
73
+ command.undo();
74
+ this.stack.push(command);
75
+ this.syncStore();
76
+ }
77
+ }
78
+
79
+ redo() {
80
+ const command = this.stack.pop();
81
+ if (command) {
82
+ if (command.redo) {
83
+ command.redo();
84
+ } else {
85
+ command.execute();
86
+ }
87
+ this.history.push(command);
88
+ this.syncStore();
89
+ }
90
+ }
91
+
92
+ canUndo() {
93
+ return this.history.length > 0;
94
+ }
95
+ canRedo() {
96
+ return this.stack.length > 0;
97
+ }
98
+ clear() {
99
+ this.history = [];
100
+ this.stack = [];
101
+ this.syncStore();
102
+ }
103
+ }
@@ -0,0 +1,61 @@
1
+ import type { GraphSession } from '@/system/graphSession';
2
+ import { annotatedTitle, uiVersion } from '@/annotations';
3
+ import type { UIGraphJSON } from '@/types/graph';
4
+
5
+ const DEFAULT_UI_GRAPH_VERSION = '1.0.0';
6
+ const DEFAULT_UI_GRAPH_NAME = 'Untitled Graph';
7
+
8
+ function getStringAnnotation(
9
+ annotations: Record<string, unknown>,
10
+ key: string
11
+ ): string | undefined {
12
+ const value = annotations[key];
13
+ return typeof value === 'string' && value.trim().length > 0
14
+ ? value
15
+ : undefined;
16
+ }
17
+
18
+ /**
19
+ * Assembles the full UI graph definition for saving.
20
+ */
21
+ export function buildUIGraphJSON(system: GraphSession): UIGraphJSON {
22
+ system.flowStore.getState().invalidateCache();
23
+
24
+ const flow = system.flowStore.getState().getGraph();
25
+ const nodes = system.nodeStore.getState().nodes;
26
+ const edges = system.edgeStore.getState().edges;
27
+
28
+ const annotations = system.graph.getAnnotations?.() ?? {};
29
+
30
+ const reactflow = system.refStore.getState().getRef('reactflow');
31
+ const viewport = reactflow?.getViewport?.() ??
32
+ system.graph.viewports[0] ?? { x: 0, y: 0, zoom: 1 };
33
+
34
+ const graphVersion =
35
+ getStringAnnotation(annotations, uiVersion) ?? DEFAULT_UI_GRAPH_VERSION;
36
+ const graphName =
37
+ system.metaStore.getState().name ||
38
+ getStringAnnotation(annotations, annotatedTitle) ||
39
+ flow.name ||
40
+ DEFAULT_UI_GRAPH_NAME;
41
+
42
+ const viewports = system.graph.viewports.length
43
+ ? system.graph.viewports.map((v) => ({ x: v.x, y: v.y, zoom: v.zoom }))
44
+ : undefined;
45
+
46
+ return {
47
+ v: graphVersion,
48
+ name: graphName,
49
+ annotations,
50
+ data: {
51
+ layers: system.layerStore.getState().serialize()
52
+ },
53
+ flow,
54
+ nodes,
55
+ edges,
56
+ user: {
57
+ viewport: { x: viewport.x, y: viewport.y, zoom: viewport.zoom },
58
+ viewports
59
+ }
60
+ };
61
+ }
@@ -1,3 +1,4 @@
1
+ import type { IBehaveNode } from '@/types/nodes';
1
2
  import type { GraphJSON } from '@kiberon-labs/behave-graph';
2
3
  import type { Edge, Node } from 'reactflow';
3
4
  import { v4 as uuidv4 } from 'uuid';
@@ -7,9 +8,9 @@ export const behaveToFlow = (graph: GraphJSON): [Node[], Edge[]] => {
7
8
  const edges: Edge[] = [];
8
9
 
9
10
  graph.nodes?.forEach((nodeJSON) => {
10
- const node: Node = {
11
+ const node: IBehaveNode = {
11
12
  id: nodeJSON.id,
12
- type: nodeJSON.type,
13
+ type: 'behaveNode',
13
14
  position: {
14
15
  x: nodeJSON.metadata?.positionX
15
16
  ? Number(nodeJSON.metadata?.positionX)
@@ -18,11 +19,21 @@ export const behaveToFlow = (graph: GraphJSON): [Node[], Edge[]] => {
18
19
  ? Number(nodeJSON.metadata?.positionY)
19
20
  : 0
20
21
  },
21
- data: {} as { [key: string]: any }
22
+ data: {
23
+ annotations: {},
24
+ configuration: {},
25
+ type: nodeJSON.type,
26
+ ports: {},
27
+ dynamicPorts: {}
28
+ }
22
29
  };
23
30
 
24
31
  nodes.push(node);
25
32
 
33
+ if (nodeJSON.configuration && typeof nodeJSON.configuration === 'object') {
34
+ node.data.configuration = { ...nodeJSON.configuration };
35
+ }
36
+
26
37
  if (nodeJSON.parameters) {
27
38
  for (const [inputKey, input] of Object.entries(nodeJSON.parameters)) {
28
39
  if ('link' in input && input.link !== undefined) {
@@ -35,7 +46,8 @@ export const behaveToFlow = (graph: GraphJSON): [Node[], Edge[]] => {
35
46
  });
36
47
  }
37
48
  if ('value' in input) {
38
- node.data[inputKey] = input.value;
49
+ node.data.ports ??= {};
50
+ node.data.ports[inputKey] = input.value;
39
51
  }
40
52
  }
41
53
  }
@@ -0,0 +1,87 @@
1
+ import type { Node } from 'reactflow';
2
+ import type { GraphSocketJSON } from '@kiberon-labs/behave-graph';
3
+ import type { Socket } from '@/types';
4
+
5
+ export const GRAPH_INPUT_TYPE = 'graph/input';
6
+ export const GRAPH_OUTPUT_TYPE = 'graph/output';
7
+ export const CALL_SUBGRAPH_TYPE = 'flow/callSubgraph';
8
+
9
+ export type ContractParam = {
10
+ /** Stable identifier (socket key / contract key). Independent of the name. */
11
+ id?: string;
12
+ /** User-facing display name; editable without breaking wiring. */
13
+ name: string;
14
+ valueTypeName: string;
15
+ defaultValue?: any;
16
+ };
17
+
18
+ export type GraphContract = {
19
+ graphInputs: GraphSocketJSON[];
20
+ graphOutputs: GraphSocketJSON[];
21
+ };
22
+
23
+ /** Stable identity of a param , its id, falling back to name for legacy data. */
24
+ export const paramId = (param: ContractParam): string => param.id ?? param.name;
25
+
26
+ const readParams = (node: Node): ContractParam[] => {
27
+ const params = (node.data as any)?.configuration?.parameters;
28
+ return Array.isArray(params) ? (params as ContractParam[]) : [];
29
+ };
30
+
31
+ const toSocket = (param: ContractParam): GraphSocketJSON => ({
32
+ key: paramId(param),
33
+ valueType: param.valueTypeName,
34
+ ...(param.defaultValue !== undefined
35
+ ? { defaultValue: param.defaultValue }
36
+ : {}),
37
+ label: param.name
38
+ });
39
+
40
+ /**
41
+ * Derive a graph's contract from its boundary nodes. The `graph/input` /
42
+ * `graph/output` nodes are the source of truth; their configured parameters
43
+ * become the graph's `graphInputs` / `graphOutputs`.
44
+ */
45
+ export const deriveContract = (nodes: Node[]): GraphContract => {
46
+ const graphInputs: GraphSocketJSON[] = [];
47
+ const graphOutputs: GraphSocketJSON[] = [];
48
+
49
+ for (const node of nodes) {
50
+ const type = (node.data as any)?.type;
51
+ if (type === GRAPH_INPUT_TYPE) {
52
+ graphInputs.push(...readParams(node).map(toSocket));
53
+ } else if (type === GRAPH_OUTPUT_TYPE) {
54
+ graphOutputs.push(...readParams(node).map(toSocket));
55
+ }
56
+ }
57
+
58
+ return { graphInputs, graphOutputs };
59
+ };
60
+
61
+ /**
62
+ * Convert a derived contract's sockets back into editable {@link ContractParam}s
63
+ * , the form stored in a Call Subgraph node's configuration. The socket `key`
64
+ * is the stable param id; its `label` is the display name.
65
+ */
66
+ export const contractToParams = (sockets: GraphSocketJSON[]): ContractParam[] =>
67
+ sockets.map((s) => ({
68
+ id: s.key,
69
+ name: s.label ?? s.key,
70
+ valueTypeName: s.valueType,
71
+ ...(s.defaultValue !== undefined ? { defaultValue: s.defaultValue } : {})
72
+ }));
73
+
74
+ /**
75
+ * Convert contract params into dynamic-port sockets. The socket identity
76
+ * (name/key/handle id) is the stable param id; the display label is the name.
77
+ */
78
+ export const paramsToSockets = (params: ContractParam[]): Socket[] =>
79
+ params.map((p) => {
80
+ const id = paramId(p);
81
+ return {
82
+ name: id,
83
+ key: id,
84
+ label: p.name || id,
85
+ valueType: p.valueTypeName || 'string'
86
+ };
87
+ });
@@ -4,40 +4,60 @@ import type {
4
4
  NodeSpecJSON
5
5
  } from '@kiberon-labs/behave-graph';
6
6
  import type { Edge, Node } from 'reactflow';
7
+ import type { GraphSession } from '../system/graphSession';
8
+ import { writeVariablesToJSON } from '../util/serializeVariables';
9
+ import { isBehaveNode } from '@/util/isBehaveNode';
10
+ import { deriveContract } from './contract';
7
11
 
8
12
  const isNullish = (value: any): value is null | undefined =>
9
13
  value === undefined || value === null;
10
14
 
11
15
  export const flowToBehave = (
16
+ session: GraphSession,
12
17
  nodes: Node[],
13
18
  edges: Edge[],
14
19
  nodeSpecJSON: NodeSpecJSON[]
15
20
  ): GraphJSON => {
16
- const graph: GraphJSON = { nodes: [], variables: [], customEvents: [] };
21
+ const graph: GraphJSON = {
22
+ nodes: [],
23
+ variables: [],
24
+ customEvents: session.eventsStore.getState().getCustomEvents()
25
+ };
26
+
27
+ const registry = session.editor.registry.getState();
28
+ const varStore = session.variableStore.getState().variables;
17
29
 
18
30
  nodes.forEach((node) => {
19
- if (node.type === undefined) return;
31
+ if (!isBehaveNode(node)) return;
32
+
33
+ const nodeType = node.data.type as string;
20
34
 
21
35
  const nodeSpec = nodeSpecJSON.find(
22
- (nodeSpec) => nodeSpec.type === node.type
36
+ (nodeSpec) => nodeSpec.type === nodeType
23
37
  );
24
38
 
25
39
  if (nodeSpec === undefined) return;
26
40
 
27
41
  const behaveNode: NodeJSON = {
28
42
  id: node.id,
29
- type: node.type,
30
- metadata: {
31
- positionX: String(node.position.x),
32
- positionY: String(node.position.y)
33
- }
43
+ type: nodeType
34
44
  };
35
45
 
36
- Object.entries(node.data).forEach(([key, value]) => {
46
+ const configuration = node.data?.configuration;
47
+ if (
48
+ configuration &&
49
+ typeof configuration === 'object' &&
50
+ Array.isArray(configuration) === false &&
51
+ Object.keys(configuration).length > 0
52
+ ) {
53
+ behaveNode.configuration = { ...configuration };
54
+ }
55
+
56
+ Object.entries(node.data.ports ?? {}).forEach(([key, value]) => {
37
57
  if (behaveNode.parameters === undefined) {
38
58
  behaveNode.parameters = {};
39
59
  }
40
- behaveNode.parameters[key] = { value: value as string };
60
+ behaveNode.parameters[key] = { value: value };
41
61
  });
42
62
 
43
63
  edges
@@ -56,7 +76,6 @@ export const flowToBehave = (
56
76
  if (isNullish(edge.targetHandle)) return;
57
77
  if (isNullish(edge.sourceHandle)) return;
58
78
 
59
- // TODO: some of these are flow outputs, and should be saved differently. -Ben, Oct 11, 2022
60
79
  behaveNode.parameters[edge.targetHandle] = {
61
80
  link: { nodeId: edge.source, socket: edge.sourceHandle }
62
81
  };
@@ -77,7 +96,6 @@ export const flowToBehave = (
77
96
  if (isNullish(edge.targetHandle)) return;
78
97
  if (isNullish(edge.sourceHandle)) return;
79
98
 
80
- // TODO: some of these are flow outputs, and should be saved differently. -Ben, Oct 11, 2022
81
99
  behaveNode.flows[edge.sourceHandle] = {
82
100
  nodeId: edge.target,
83
101
  socket: edge.targetHandle
@@ -89,5 +107,15 @@ export const flowToBehave = (
89
107
  graph.nodes?.push(behaveNode);
90
108
  });
91
109
 
110
+ if (Object.keys(varStore).length > 0) {
111
+ graph.variables = writeVariablesToJSON(registry, varStore);
112
+ }
113
+
114
+ // Derive the graph's contract (inputs/outputs) from its boundary nodes so
115
+ // callers and the runtime can read it.
116
+ const { graphInputs, graphOutputs } = deriveContract(nodes);
117
+ if (graphInputs.length > 0) graph.graphInputs = graphInputs;
118
+ if (graphOutputs.length > 0) graph.graphOutputs = graphOutputs;
119
+
92
120
  return graph;
93
121
  };