@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.
- package/.fallowrc.json +16 -0
- package/.storybook/main.ts +32 -0
- package/.storybook/preview.ts +16 -0
- package/.storybook/styles.css +10 -0
- package/.storybook/vscode.css +814 -0
- package/.turbo/turbo-build.log +7 -0
- package/LICENSE +6 -0
- package/README.md +2 -2
- package/data/Polynomial.json +510 -0
- package/data/sequence.json +337 -0
- package/data/trigger-event.json +241 -0
- package/data/variable-change.json +210 -0
- package/dist/entry.css +4 -0
- package/dist/index.css +39 -0
- package/dist/index.css.map +1 -0
- package/dist/index.d.ts +2282 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +14873 -0
- package/dist/index.js.map +1 -0
- package/docs/notifications.md +246 -0
- package/docs/protocol.md +679 -0
- package/docs/specifics.md +191 -0
- package/package.json +85 -21
- package/postcss.config.ts +3 -4
- package/src/annotations/index.ts +32 -0
- package/src/components/FloatingToolbar/index.module.css +45 -0
- package/src/components/FloatingToolbar/index.tsx +256 -0
- package/src/components/Flow.tsx +276 -75
- package/src/components/contextMenus/NodePicker.module.css +274 -0
- package/src/components/contextMenus/NodePicker.tsx +481 -0
- package/src/components/contextMenus/edge.tsx +108 -0
- package/src/components/contextMenus/node.tsx +155 -0
- package/src/components/contextMenus/selection.tsx +77 -0
- package/src/components/controls/any/index.tsx +8 -0
- package/src/components/controls/boolean/index.tsx +13 -0
- package/src/components/controls/colorPicker/InputPopover.module.css +100 -0
- package/src/components/controls/colorPicker/InputPopover.tsx +31 -0
- package/src/components/controls/colorPicker/index.module.css +18 -0
- package/src/components/controls/colorPicker/index.tsx +61 -0
- package/src/components/controls/number/index.tsx +35 -0
- package/src/components/controls/string/index.tsx +16 -0
- package/src/components/edges/index.tsx +469 -0
- package/src/components/edges/offsetBezier.ts +134 -0
- package/src/components/hotKeys.tsx +20 -0
- package/src/components/layoutController/index.module.css +10 -0
- package/src/components/layoutController/index.tsx +117 -0
- package/src/components/layoutController/utils.ts +205 -0
- package/src/components/menubar/defaults.tsx +480 -0
- package/src/components/menubar/index.tsx +49 -0
- package/src/components/menubar/menuItem.module.css +16 -0
- package/src/components/menubar/menuItem.tsx +32 -0
- package/src/components/nodes/behave/Node.module.css +23 -0
- package/src/components/nodes/behave/Node.tsx +176 -0
- package/src/components/nodes/behave/NodeContainer.module.css +87 -0
- package/src/components/nodes/behave/NodeContainer.tsx +46 -0
- package/src/components/nodes/behave/index.tsx +14 -0
- package/src/components/nodes/comment/FormatToolbar.tsx +118 -0
- package/src/components/nodes/comment/comment.tsx +103 -0
- package/src/components/nodes/comment/styles.module.css +150 -0
- package/src/components/nodes/group/index.tsx +109 -0
- package/src/components/nodes/wrapper/index.tsx +73 -0
- package/src/components/nodes/wrapper/styles.module.css +113 -0
- package/src/components/notifications/NotificationProvider.tsx +81 -0
- package/src/components/notifications/index.ts +2 -0
- package/src/components/notifications/utils.ts +71 -0
- package/src/components/panels/alignment/index.module.css +20 -0
- package/src/components/panels/alignment/index.tsx +244 -0
- package/src/components/panels/base/index.tsx +5 -0
- package/src/components/panels/base/styles.module.css +12 -0
- package/src/components/panels/conversation/index.module.css +151 -0
- package/src/components/panels/conversation/index.tsx +162 -0
- package/src/components/panels/events/CustomEventsEditor.tsx +384 -0
- package/src/components/panels/events/EditEventPanel.tsx +315 -0
- package/src/components/panels/events/ManageEventsPanel.tsx +98 -0
- package/src/components/panels/events/index.tsx +23 -0
- package/src/components/panels/events/styles.module.css +236 -0
- package/src/components/panels/history/index.tsx +92 -0
- package/src/components/panels/history/styles.module.css +106 -0
- package/src/components/panels/keymaps/index.module.css +78 -0
- package/src/components/panels/keymaps/index.tsx +167 -0
- package/src/components/panels/layers/index.tsx +240 -0
- package/src/components/panels/layers/styles.module.css +110 -0
- package/src/components/panels/legend/index.module.css +6 -0
- package/src/components/panels/legend/index.tsx +76 -0
- package/src/components/panels/logs/index.module.css +212 -0
- package/src/components/panels/logs/index.tsx +288 -0
- package/src/components/panels/nodeInputs/InputControl.tsx +63 -0
- package/src/components/panels/nodeInputs/InputsGroup.tsx +64 -0
- package/src/components/panels/nodeInputs/MultipleNodesView.tsx +37 -0
- package/src/components/panels/nodeInputs/NodeSettings.tsx +92 -0
- package/src/components/panels/nodeInputs/NodeTitleEditor.tsx +125 -0
- package/src/components/panels/nodeInputs/OutputsGroup.tsx +65 -0
- package/src/components/panels/nodeInputs/SocketGenerators.tsx +32 -0
- package/src/components/panels/nodeInputs/index.module.css +284 -0
- package/src/components/panels/nodeInputs/index.tsx +339 -0
- package/src/components/panels/nodeInputs/useNodeHandlers.ts +76 -0
- package/src/components/panels/nodeInputs/useNodeInputsData.ts +173 -0
- package/src/components/panels/nodePicker/index.tsx +115 -0
- package/src/components/panels/panel/index.module.css +66 -0
- package/src/components/panels/panel/index.tsx +88 -0
- package/src/components/panels/search/index.module.css +66 -0
- package/src/components/panels/search/index.tsx +215 -0
- package/src/components/panels/systemSettings/index.tsx +206 -0
- package/src/components/panels/systemSettings/styles.module.css +11 -0
- package/src/components/panels/traces/GridLines.tsx +38 -0
- package/src/components/panels/traces/TimeGrid.tsx +48 -0
- package/src/components/panels/traces/TraceLane.tsx +62 -0
- package/src/components/panels/traces/TraceTooltip.tsx +22 -0
- package/src/components/panels/traces/TracesHeader.tsx +56 -0
- package/src/components/panels/traces/index.module.css +166 -0
- package/src/components/panels/traces/index.tsx +294 -0
- package/src/components/panels/traces/types.ts +48 -0
- package/src/components/panels/traces/useDerivedSpans.ts +212 -0
- package/src/components/panels/traces/utils.ts +25 -0
- package/src/components/panels/variables/CreateVariableScreen.tsx +162 -0
- package/src/components/panels/variables/ManageVariablesScreen.tsx +144 -0
- package/src/components/panels/variables/index.tsx +125 -0
- package/src/components/panels/variables/styles.module.css +236 -0
- package/src/components/primitives/icon.module.css +45 -0
- package/src/components/primitives/icon.tsx +38 -0
- package/src/components/sockets/input/index.tsx +76 -0
- package/src/components/sockets/input/styles.module.css +27 -0
- package/src/components/sockets/output/index.tsx +61 -0
- package/src/components/sockets/output/styles.module.css +27 -0
- package/src/css/prosemirror.css +57 -0
- package/src/css/rc-dock.css +112 -0
- package/src/css/rc-menu.css +100 -0
- package/src/css/vars.css +14 -0
- package/src/css/vscode.css +13 -0
- package/src/entry.css +4 -0
- package/src/generators/CustomEventOnTriggeredGenerator.tsx +85 -0
- package/src/generators/SequenceGenerator.tsx +104 -0
- package/src/generators/SwitchOnIntegerGenerator.tsx +256 -0
- package/src/generators/SwitchOnStringGenerator.tsx +263 -0
- package/src/generators/registerDefaultGenerators.ts +34 -0
- package/src/hooks/useBehaveGraphFlow.ts +17 -16
- package/src/hooks/useDetachNodes.ts +39 -0
- package/src/hooks/useFlowHandlers.ts +115 -29
- package/src/hooks/useWasdPan.ts +188 -0
- package/src/index.css +146 -0
- package/src/index.ts +36 -18
- package/src/layout/dagre.tsx +119 -0
- package/src/layout/elk.ts +200 -0
- package/src/plugin/alignment/index.ts +81 -0
- package/src/plugin/docs/index.tsx +299 -0
- package/src/plugin/docs/panel/index.tsx +200 -0
- package/src/plugin/docs/panel/styles.module.css +174 -0
- package/src/plugin/graphrunner/actions.ts +253 -0
- package/src/plugin/graphrunner/buttons.tsx +87 -0
- package/src/plugin/graphrunner/client.ts +704 -0
- package/src/plugin/graphrunner/index.tsx +255 -0
- package/src/plugin/graphrunner/panel.tsx +386 -0
- package/src/plugin/graphrunner/runner.ts +358 -0
- package/src/plugin/graphrunner/session.ts +243 -0
- package/src/plugin/graphrunner/store.ts +206 -0
- package/src/plugin/graphrunner/styles.module.css +211 -0
- package/src/plugin/graphrunner/transport.ts +224 -0
- package/src/plugin/graphrunner/types.ts +672 -0
- package/src/plugin/graphrunner-local/execution-utils.ts +457 -0
- package/src/plugin/graphrunner-local/index.tsx +166 -0
- package/src/plugin/graphrunner-local/panel.tsx +231 -0
- package/src/plugin/graphrunner-local/store.ts +41 -0
- package/src/plugin/graphrunner-local/styles.module.css +101 -0
- package/src/plugin/graphrunner-local/transport.ts +1372 -0
- package/src/plugin/graphrunner-local/types.ts +10 -0
- package/src/plugin/graphrunner-webworker/graph-executor.worker.ts +633 -0
- package/src/plugin/graphrunner-webworker/index.tsx +146 -0
- package/src/plugin/graphrunner-webworker/panel.tsx +173 -0
- package/src/plugin/graphrunner-webworker/store.ts +89 -0
- package/src/plugin/graphrunner-webworker/types.ts +17 -0
- package/src/plugin/graphrunner-webworker/worker-transport.ts +123 -0
- package/src/plugin/realtime/realtimeRunner.ts +570 -0
- package/src/specifics/CustomEventOnTriggeredSpecific.tsx +92 -0
- package/src/specifics/CustomEventTriggerSpecific.tsx +141 -0
- package/src/specifics/VariableGetSpecific.tsx +110 -0
- package/src/specifics/VariableSetSpecific.tsx +110 -0
- package/src/specifics/registerDefaultSpecifics.ts +5 -0
- package/src/store/actions.tsx +698 -0
- package/src/store/chat.ts +73 -0
- package/src/store/controls.tsx +62 -0
- package/src/store/documentation.tsx +69 -0
- package/src/store/events.tsx +116 -0
- package/src/store/flow.tsx +245 -0
- package/src/store/graphRunnerClient.ts +110 -0
- package/src/store/hotKeys.tsx +323 -0
- package/src/store/layers.ts +259 -0
- package/src/store/legend.tsx +76 -0
- package/src/store/logs.ts +28 -0
- package/src/store/menubar.ts +41 -0
- package/src/store/refs.ts +84 -0
- package/src/store/registry.ts +43 -0
- package/src/store/selection.ts +22 -0
- package/src/store/settings.ts +99 -0
- package/src/store/socketGenerator.tsx +54 -0
- package/src/store/specific.tsx +75 -0
- package/src/store/specs.tsx +35 -0
- package/src/store/tabs.ts +278 -0
- package/src/store/toolbar.tsx +45 -0
- package/src/store/traces.ts +240 -0
- package/src/store/variables.ts +37 -0
- package/src/system/graph.ts +134 -0
- package/src/system/index.ts +3 -0
- package/src/system/notifications.ts +98 -0
- package/src/system/plugin.ts +27 -0
- package/src/system/provider.tsx +22 -0
- package/src/system/pubsub.ts +323 -0
- package/src/system/system.ts +223 -0
- package/src/system/tabLoader.tsx +265 -0
- package/src/system/undoRedo.ts +103 -0
- package/src/transformers/Uigraph.ts +60 -0
- package/src/transformers/behaveToFlow.ts +16 -4
- package/src/transformers/flowToBehave.ts +32 -12
- package/src/types/NodeMetadata.ts +27 -0
- package/src/types/graph.ts +49 -0
- package/src/types/nodes.ts +45 -0
- package/src/types.ts +16 -0
- package/src/util/colors.ts +1 -29
- package/src/util/downloadJson.ts +18 -0
- package/src/util/extractNodeMetadata.ts +16 -0
- package/src/util/getPickerFilters.ts +1 -1
- package/src/util/isBehaveNode.ts +6 -0
- package/src/util/isValidConnection.ts +28 -15
- package/src/util/mergeSockets.ts +29 -0
- package/src/util/serializeVariables.ts +66 -0
- package/src/util/sockets.ts +43 -0
- package/stories/apex/layoutController/example-graph.worker.ts +39 -0
- package/stories/apex/layoutController/index.stories.tsx +48 -0
- package/stories/apex/layoutController/webworker.stories.tsx +103 -0
- package/stories/apex/menubar/menubar.stories.tsx +19 -0
- package/stories/components/colorpicker/index.stories.tsx +20 -0
- package/stories/components/contextMenus/edge.stories.tsx +32 -0
- package/stories/components/contextMenus/node.stories.tsx +26 -0
- package/stories/components/contextMenus/nodePicker.stories.tsx +115 -0
- package/stories/components/controls/any/index.stories.tsx +19 -0
- package/stories/components/controls/boolean/index.stories.tsx +19 -0
- package/stories/components/controls/colorPicker/index.stories.tsx +49 -0
- package/stories/components/controls/number/index.stories.tsx +19 -0
- package/stories/components/controls/string/index.stories.tsx +19 -0
- package/stories/components/nodes/behaveNode.stories.tsx +108 -0
- package/stories/components/nodes/comment.stories.tsx +106 -0
- package/stories/components/panels/alignment.stories.tsx +24 -0
- package/stories/components/panels/events.stories.tsx +38 -0
- package/stories/components/panels/graphRunner.stories.tsx +317 -0
- package/stories/components/panels/history.stories.tsx +37 -0
- package/stories/components/panels/keymaps.stories.tsx +21 -0
- package/stories/components/panels/legend.stories.tsx +37 -0
- package/stories/components/panels/logs.stories.tsx +24 -0
- package/stories/components/panels/nodeInputs.stories.tsx +21 -0
- package/stories/components/panels/nodePicker.stories.tsx +37 -0
- package/stories/components/panels/panel.stories.tsx +39 -0
- package/stories/components/panels/search.stories.tsx +24 -0
- package/stories/components/panels/systemSettings.stories.tsx +26 -0
- package/stories/components/panels/traces.stories.tsx +225 -0
- package/stories/components/panels/variables.stories.tsx +24 -0
- package/stories/defaults/defaultStoryProvider.tsx +167 -0
- package/stories/defaults/systemGenerator.ts +38 -0
- package/tests/components/edges/offsetBezier.test.ts +51 -0
- package/tests/components/layoutController/utils.test.ts +68 -0
- package/tests/components/panels/traces/utils.test.ts +52 -0
- package/tests/flowToBehave.test.ts +26 -4
- package/tests/notifications.test.ts +87 -0
- package/tests/saveLoad.test.ts +372 -0
- package/tests/util/calculateNewEdge.test.ts +98 -0
- package/tests/util/getSocketsByNodeTypeAndHandleType.test.ts +31 -0
- package/tests/util/hasPositionMetaData.test.ts +33 -0
- package/tests/util/isBehaveNode.test.ts +22 -0
- package/tests/util/isHandleConnected.test.ts +37 -0
- package/tests/util/mergeSockets.test.ts +43 -0
- package/tests/visual/README.md +64 -0
- package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-alignment-chromium-win32.png +0 -0
- package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-conversation-chromium-win32.png +0 -0
- package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-events-chromium-win32.png +0 -0
- package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-history-chromium-win32.png +0 -0
- package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-keymaps-chromium-win32.png +0 -0
- package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-layers-chromium-win32.png +0 -0
- package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-legend-chromium-win32.png +0 -0
- package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-logs-chromium-win32.png +0 -0
- package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-nodeInputs-chromium-win32.png +0 -0
- package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-nodePicker-chromium-win32.png +0 -0
- package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-panel-chromium-win32.png +0 -0
- package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-search-chromium-win32.png +0 -0
- package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-systemSettings-chromium-win32.png +0 -0
- package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-traces-chromium-win32.png +0 -0
- package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-variables-chromium-win32.png +0 -0
- package/tests/visual/panels.visual.test.tsx +76 -0
- package/tsconfig.base.json +39 -0
- package/tsconfig.json +18 -59
- package/tsconfig.prod.json +23 -0
- package/tsdown.config.ts +15 -3
- package/typedoc.json +7 -7
- package/vite.config.js +7 -0
- package/vitest.config.ts +5 -2
- package/vitest.visual.config.ts +48 -0
- package/src/components/AutoSizeInput.tsx +0 -65
- package/src/components/Controls.tsx +0 -87
- package/src/components/InputSocket.tsx +0 -142
- package/src/components/Node.tsx +0 -68
- package/src/components/NodeContainer.tsx +0 -46
- package/src/components/NodePicker.tsx +0 -77
- package/src/components/OutputSocket.tsx +0 -58
- package/src/components/modals/ClearModal.tsx +0 -40
- package/src/components/modals/HelpModal.tsx +0 -36
- package/src/components/modals/LoadModal.tsx +0 -96
- package/src/components/modals/Modal.tsx +0 -64
- package/src/components/modals/SaveModal.tsx +0 -60
- package/src/hooks/useCustomNodeTypes.tsx +0 -31
- package/src/hooks/useGraphRunner.ts +0 -104
- package/src/hooks/useMergeMap.ts +0 -14
- package/src/hooks/useNodeSpecJson.ts +0 -20
- package/src/hooks/useQueriableDefinitions.ts +0 -22
- package/src/styles.css +0 -8
- package/tailwind.config.ts +0 -19
- package/tests/tsconfig.json +0 -10
- /package/src/{types.d.ts → types-declarations.d.ts} +0 -0
|
@@ -0,0 +1,457 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared graph execution utilities for both local and worker runners
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
Engine,
|
|
7
|
+
type GraphInstance,
|
|
8
|
+
type ILifecycleEventEmitter,
|
|
9
|
+
readGraphFromJSON,
|
|
10
|
+
validateGraph,
|
|
11
|
+
ManualLifecycleEventEmitter,
|
|
12
|
+
DefaultLogger,
|
|
13
|
+
type ILogger,
|
|
14
|
+
type IRegistry,
|
|
15
|
+
writeNodeSpecsToJSON,
|
|
16
|
+
type NodeSpecJSON,
|
|
17
|
+
type GraphJSON
|
|
18
|
+
} from '@kiberon-labs/behave-graph';
|
|
19
|
+
import type {
|
|
20
|
+
GraphRunnerCapabilities,
|
|
21
|
+
RunStatus,
|
|
22
|
+
ServerGraphRunnerMessage,
|
|
23
|
+
ServerVariable,
|
|
24
|
+
ServerEvent
|
|
25
|
+
} from '../graphrunner/types.js';
|
|
26
|
+
import { sleep } from '@kiberon-labs/behave-graph';
|
|
27
|
+
|
|
28
|
+
export interface ActiveRun {
|
|
29
|
+
runId: string;
|
|
30
|
+
graphId: string;
|
|
31
|
+
engine: Engine;
|
|
32
|
+
graphInstance: GraphInstance;
|
|
33
|
+
registry: IRegistry;
|
|
34
|
+
status: RunStatus;
|
|
35
|
+
startedAt: number;
|
|
36
|
+
performance: {
|
|
37
|
+
nodesExecuted: number;
|
|
38
|
+
eventsEmitted: number;
|
|
39
|
+
variableChanges: number;
|
|
40
|
+
};
|
|
41
|
+
isPaused: boolean;
|
|
42
|
+
executionPhase: 'start' | 'tick' | 'end' | 'completed';
|
|
43
|
+
currentTick: number;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface MessageContext {
|
|
47
|
+
sendMessage: (message: ServerGraphRunnerMessage) => void;
|
|
48
|
+
sendError: (
|
|
49
|
+
code: string,
|
|
50
|
+
message: string,
|
|
51
|
+
details?: Record<string, unknown>
|
|
52
|
+
) => void;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Create a logger that forwards messages through a callback
|
|
57
|
+
*/
|
|
58
|
+
export function createForwardingLogger(
|
|
59
|
+
runId: string,
|
|
60
|
+
graphId: string,
|
|
61
|
+
onLog: (message: ServerGraphRunnerMessage) => void
|
|
62
|
+
): ILogger {
|
|
63
|
+
const baseLogger = new DefaultLogger();
|
|
64
|
+
|
|
65
|
+
return {
|
|
66
|
+
log: (severity: string, text: string) => {
|
|
67
|
+
baseLogger.log(severity as any, text);
|
|
68
|
+
onLog({
|
|
69
|
+
type: 'log',
|
|
70
|
+
runId,
|
|
71
|
+
graphId,
|
|
72
|
+
level: severity,
|
|
73
|
+
message: text
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Prepare a registry with required dependencies injected
|
|
81
|
+
*/
|
|
82
|
+
export function prepareRegistryWithDependencies(
|
|
83
|
+
registry: IRegistry,
|
|
84
|
+
logger: ILogger
|
|
85
|
+
): IRegistry {
|
|
86
|
+
// Ensure lifecycle event emitter and logger are available in registry
|
|
87
|
+
if (
|
|
88
|
+
!registry.dependencies?.ILifecycleEventEmitter ||
|
|
89
|
+
!registry.dependencies?.ILogger
|
|
90
|
+
) {
|
|
91
|
+
// Create a new registry with required dependencies injected
|
|
92
|
+
return {
|
|
93
|
+
...registry,
|
|
94
|
+
dependencies: {
|
|
95
|
+
...registry.dependencies,
|
|
96
|
+
ILifecycleEventEmitter:
|
|
97
|
+
registry.dependencies?.ILifecycleEventEmitter ||
|
|
98
|
+
new ManualLifecycleEventEmitter(),
|
|
99
|
+
ILogger: logger
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
} else {
|
|
103
|
+
// Replace the existing logger
|
|
104
|
+
return {
|
|
105
|
+
...registry,
|
|
106
|
+
dependencies: {
|
|
107
|
+
...registry.dependencies,
|
|
108
|
+
ILogger: logger
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Parse and validate a graph
|
|
116
|
+
*/
|
|
117
|
+
export function parseAndValidateGraph(
|
|
118
|
+
graphData: GraphJSON,
|
|
119
|
+
registry: IRegistry
|
|
120
|
+
): { graphInstance: GraphInstance; errors: string[] } {
|
|
121
|
+
const graphInstance = readGraphFromJSON({
|
|
122
|
+
graphJson: graphData,
|
|
123
|
+
registry
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
const errors = validateGraph(graphInstance);
|
|
127
|
+
return { graphInstance, errors };
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Generate a unique ID
|
|
132
|
+
*/
|
|
133
|
+
export function generateId(prefix: string): string {
|
|
134
|
+
return `${prefix}-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Handle hello message
|
|
139
|
+
*/
|
|
140
|
+
export function handleHello(
|
|
141
|
+
message: { type: 'hello'; protocolVersion: string },
|
|
142
|
+
serverId: string,
|
|
143
|
+
ctx: MessageContext
|
|
144
|
+
): void {
|
|
145
|
+
ctx.sendMessage({
|
|
146
|
+
type: 'welcome',
|
|
147
|
+
protocolVersion: message.protocolVersion,
|
|
148
|
+
serverId,
|
|
149
|
+
authenticated: true,
|
|
150
|
+
userId: 'local-user'
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Handle createSession message
|
|
156
|
+
*/
|
|
157
|
+
export function handleCreateSession(
|
|
158
|
+
_message: { type: 'createSession'; metadata?: Record<string, unknown> },
|
|
159
|
+
ctx: MessageContext
|
|
160
|
+
): string {
|
|
161
|
+
const sessionId = generateId('session');
|
|
162
|
+
ctx.sendMessage({
|
|
163
|
+
type: 'sessionCreated',
|
|
164
|
+
sessionId,
|
|
165
|
+
expiresAt: Date.now() + 24 * 60 * 60 * 1000
|
|
166
|
+
});
|
|
167
|
+
return sessionId;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Handle getCapabilities message
|
|
172
|
+
*/
|
|
173
|
+
export function handleGetCapabilities(ctx: MessageContext): void {
|
|
174
|
+
const capabilities: GraphRunnerCapabilities = {
|
|
175
|
+
trace: true,
|
|
176
|
+
validation: true,
|
|
177
|
+
graphRegistry: false,
|
|
178
|
+
eventFiltering: false,
|
|
179
|
+
batchOperations: false,
|
|
180
|
+
runHistory: false,
|
|
181
|
+
runtimeMetadata: true,
|
|
182
|
+
maxConcurrentRuns: 10
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
ctx.sendMessage({
|
|
186
|
+
type: 'capabilities',
|
|
187
|
+
capabilities
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Setup tracing for a run
|
|
193
|
+
*/
|
|
194
|
+
export function setupTracing(
|
|
195
|
+
run: ActiveRun,
|
|
196
|
+
graphId: string,
|
|
197
|
+
ctx: MessageContext
|
|
198
|
+
): void {
|
|
199
|
+
run.engine.onNodeExecutionStart.addListener((node) => {
|
|
200
|
+
run.performance.nodesExecuted++;
|
|
201
|
+
ctx.sendMessage({
|
|
202
|
+
type: 'trace',
|
|
203
|
+
runId: run.runId,
|
|
204
|
+
graphId,
|
|
205
|
+
nodeId: node.id,
|
|
206
|
+
event: 'start',
|
|
207
|
+
data: { typeName: node.description.typeName },
|
|
208
|
+
timestamp: Date.now() - run.startedAt
|
|
209
|
+
});
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
run.engine.onNodeExecutionEnd.addListener((node) => {
|
|
213
|
+
ctx.sendMessage({
|
|
214
|
+
type: 'trace',
|
|
215
|
+
runId: run.runId,
|
|
216
|
+
graphId,
|
|
217
|
+
nodeId: node.id,
|
|
218
|
+
event: 'end',
|
|
219
|
+
data: { typeName: node.description.typeName },
|
|
220
|
+
timestamp: Date.now() - run.startedAt
|
|
221
|
+
});
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Setup variable change tracking for a run
|
|
227
|
+
*/
|
|
228
|
+
export function setupVariableChangeTracking(
|
|
229
|
+
run: ActiveRun,
|
|
230
|
+
graphId: string,
|
|
231
|
+
ctx: MessageContext
|
|
232
|
+
): void {
|
|
233
|
+
// Track old values so we can report them in the change event
|
|
234
|
+
const variableOldValues = new Map<string, unknown>();
|
|
235
|
+
|
|
236
|
+
const variables = Object.values(run.graphInstance.variables);
|
|
237
|
+
|
|
238
|
+
for (const variable of variables) {
|
|
239
|
+
// Store initial value as the "old" value
|
|
240
|
+
variableOldValues.set(variable.id, variable.get());
|
|
241
|
+
|
|
242
|
+
variable.onChanged.addListener(() => {
|
|
243
|
+
run.performance.variableChanges++;
|
|
244
|
+
const oldValue = variableOldValues.get(variable.id);
|
|
245
|
+
const newValue = variable.get();
|
|
246
|
+
|
|
247
|
+
// Update tracked value for next change
|
|
248
|
+
variableOldValues.set(variable.id, newValue);
|
|
249
|
+
|
|
250
|
+
ctx.sendMessage({
|
|
251
|
+
type: 'variableChanged',
|
|
252
|
+
runId: run.runId,
|
|
253
|
+
graphId,
|
|
254
|
+
variableName: variable.name,
|
|
255
|
+
oldValue,
|
|
256
|
+
newValue
|
|
257
|
+
});
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Execute a graph through its lifecycle phases
|
|
264
|
+
*/
|
|
265
|
+
export async function executeGraphLifecycle(
|
|
266
|
+
run: ActiveRun,
|
|
267
|
+
graphId: string,
|
|
268
|
+
ctx: MessageContext,
|
|
269
|
+
options?: {
|
|
270
|
+
tickInterval?: number;
|
|
271
|
+
onStepComplete?: () => Promise<void>;
|
|
272
|
+
autoEnd?: boolean;
|
|
273
|
+
}
|
|
274
|
+
): Promise<void> {
|
|
275
|
+
try {
|
|
276
|
+
const eventEmitter = run.registry.dependencies?.ILifecycleEventEmitter as
|
|
277
|
+
| ILifecycleEventEmitter
|
|
278
|
+
| undefined;
|
|
279
|
+
|
|
280
|
+
// Execute start event
|
|
281
|
+
if (run.executionPhase === 'start') {
|
|
282
|
+
if (
|
|
283
|
+
eventEmitter?.startEvent &&
|
|
284
|
+
eventEmitter.startEvent.listenerCount > 0
|
|
285
|
+
) {
|
|
286
|
+
eventEmitter.startEvent.emit();
|
|
287
|
+
await run.engine.executeAllAsync();
|
|
288
|
+
}
|
|
289
|
+
run.executionPhase = 'tick';
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// Execute tick events
|
|
293
|
+
if (run.executionPhase === 'tick') {
|
|
294
|
+
if (eventEmitter?.tickEvent && eventEmitter.tickEvent.listenerCount > 0) {
|
|
295
|
+
while (!run.isPaused && run.status === 'running') {
|
|
296
|
+
eventEmitter.tickEvent.emit();
|
|
297
|
+
await run.engine.executeAllAsync();
|
|
298
|
+
run.currentTick++;
|
|
299
|
+
|
|
300
|
+
if (options?.onStepComplete) {
|
|
301
|
+
await options.onStepComplete();
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
if (run.isPaused || run.status !== 'running') {
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
await sleep((options?.tickInterval ?? 50) / 1000);
|
|
309
|
+
}
|
|
310
|
+
} else {
|
|
311
|
+
run.executionPhase = 'end';
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
// Execute end event
|
|
316
|
+
if (run.executionPhase === 'end' && !run.isPaused) {
|
|
317
|
+
if (eventEmitter?.endEvent && eventEmitter.endEvent.listenerCount > 0) {
|
|
318
|
+
eventEmitter.endEvent.emit();
|
|
319
|
+
await run.engine.executeAllAsync();
|
|
320
|
+
}
|
|
321
|
+
run.executionPhase = 'completed';
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
// Complete if not paused
|
|
325
|
+
if (!run.isPaused && !options?.autoEnd) {
|
|
326
|
+
run.status = 'completed';
|
|
327
|
+
const elapsedMs = Date.now() - run.startedAt;
|
|
328
|
+
|
|
329
|
+
ctx.sendMessage({
|
|
330
|
+
type: 'completed',
|
|
331
|
+
runId: run.runId,
|
|
332
|
+
graphId,
|
|
333
|
+
completedAt: Date.now(),
|
|
334
|
+
elapsedMs,
|
|
335
|
+
result: null,
|
|
336
|
+
performance: run.performance
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
run.engine.dispose();
|
|
340
|
+
}
|
|
341
|
+
} catch (error) {
|
|
342
|
+
run.status = 'error';
|
|
343
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
344
|
+
ctx.sendError('NODE_EXECUTION_ERROR', errorMessage, {
|
|
345
|
+
runId: run.runId,
|
|
346
|
+
graphId
|
|
347
|
+
});
|
|
348
|
+
run.engine.dispose();
|
|
349
|
+
throw error;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* Handle getServerVariables message
|
|
355
|
+
*/
|
|
356
|
+
export function handleGetServerVariables(
|
|
357
|
+
variables: ServerVariable[],
|
|
358
|
+
ctx: MessageContext
|
|
359
|
+
): void {
|
|
360
|
+
ctx.sendMessage({
|
|
361
|
+
type: 'serverVariables',
|
|
362
|
+
variables
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
/**
|
|
367
|
+
* Handle getServerEvents message
|
|
368
|
+
*/
|
|
369
|
+
export function handleGetServerEvents(
|
|
370
|
+
events: ServerEvent[],
|
|
371
|
+
ctx: MessageContext
|
|
372
|
+
): void {
|
|
373
|
+
ctx.sendMessage({
|
|
374
|
+
type: 'serverEvents',
|
|
375
|
+
events
|
|
376
|
+
});
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
/**
|
|
380
|
+
* Handle getSocketConstraints message
|
|
381
|
+
*/
|
|
382
|
+
export function handleGetSocketConstraints(
|
|
383
|
+
message: {
|
|
384
|
+
nodeType: string;
|
|
385
|
+
socketName: string;
|
|
386
|
+
},
|
|
387
|
+
registry: IRegistry,
|
|
388
|
+
ctx: MessageContext
|
|
389
|
+
): void {
|
|
390
|
+
const nodeSpec = writeNodeSpecsToJSON(registry).find(
|
|
391
|
+
(spec) => spec.type === message.nodeType
|
|
392
|
+
);
|
|
393
|
+
if (!nodeSpec) {
|
|
394
|
+
ctx.sendError('INVALID_GRAPH', `Node type not found: ${message.nodeType}`);
|
|
395
|
+
return;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
const socket = [...nodeSpec.inputs, ...nodeSpec.outputs].find(
|
|
399
|
+
(s) => s.name === message.socketName
|
|
400
|
+
);
|
|
401
|
+
|
|
402
|
+
if (!socket) {
|
|
403
|
+
ctx.sendError(
|
|
404
|
+
'INVALID_GRAPH',
|
|
405
|
+
`Socket not found: ${message.socketName} on node ${message.nodeType}`
|
|
406
|
+
);
|
|
407
|
+
return;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
const constraints: {
|
|
411
|
+
type: 'enum' | 'range' | 'pattern' | 'custom';
|
|
412
|
+
choices?: Array<{ value: unknown; label: string }>;
|
|
413
|
+
min?: number;
|
|
414
|
+
max?: number;
|
|
415
|
+
pattern?: string;
|
|
416
|
+
validator?: string;
|
|
417
|
+
} = {
|
|
418
|
+
type: 'custom'
|
|
419
|
+
};
|
|
420
|
+
|
|
421
|
+
if ('choices' in socket && Array.isArray(socket.choices)) {
|
|
422
|
+
constraints.type = 'enum';
|
|
423
|
+
constraints.choices = socket.choices.map(
|
|
424
|
+
(choice: { text: string; value: unknown } | string) =>
|
|
425
|
+
typeof choice === 'string'
|
|
426
|
+
? { value: choice, label: choice }
|
|
427
|
+
: { value: choice.value, label: choice.text }
|
|
428
|
+
);
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
ctx.sendMessage({
|
|
432
|
+
type: 'socketConstraints',
|
|
433
|
+
nodeType: message.nodeType,
|
|
434
|
+
socketName: message.socketName,
|
|
435
|
+
valueType: socket.valueType,
|
|
436
|
+
constraints
|
|
437
|
+
});
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
/**
|
|
441
|
+
* Handle getNodeTypes message
|
|
442
|
+
*/
|
|
443
|
+
export function handleGetNodeTypes(
|
|
444
|
+
registry: IRegistry,
|
|
445
|
+
ctx: MessageContext
|
|
446
|
+
): void {
|
|
447
|
+
let nodes: NodeSpecJSON[] = [];
|
|
448
|
+
|
|
449
|
+
if (registry.nodes) {
|
|
450
|
+
nodes = writeNodeSpecsToJSON(registry);
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
ctx.sendMessage({
|
|
454
|
+
type: 'nodeTypes',
|
|
455
|
+
nodes
|
|
456
|
+
});
|
|
457
|
+
}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local graph runner plugin for in-browser graph execution
|
|
3
|
+
* Uses the local Engine instead of a remote server
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { System } from '../../system/system.js';
|
|
7
|
+
import { plugin } from '../../system/plugin.js';
|
|
8
|
+
import type { IRegistry } from '@kiberon-labs/behave-graph';
|
|
9
|
+
import { GraphRunnerClient } from '../graphrunner/client.js';
|
|
10
|
+
import { LocalTransport } from './transport.js';
|
|
11
|
+
import {
|
|
12
|
+
graphRunnerClientPlugin,
|
|
13
|
+
type ServerEvent,
|
|
14
|
+
type ServerVariable,
|
|
15
|
+
type SessionFactory
|
|
16
|
+
} from '../graphrunner/index.js';
|
|
17
|
+
import { DefaultSessionFactory } from '../graphrunner/session.js';
|
|
18
|
+
import { localGraphRunnerStoreFactory } from './store.js';
|
|
19
|
+
import { LocalGraphRunnerPanel } from './panel.js';
|
|
20
|
+
import { MenuItemElement } from '../../components/menubar/menuItem.js';
|
|
21
|
+
import { ErrorBoundary } from 'react-error-boundary';
|
|
22
|
+
|
|
23
|
+
export * from './transport.js';
|
|
24
|
+
export * from './store.js';
|
|
25
|
+
export * from './panel.js';
|
|
26
|
+
export * from './types.js';
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Options for the local graph runner plugin
|
|
30
|
+
*/
|
|
31
|
+
export interface LocalGraphRunnerPluginOptions {
|
|
32
|
+
/**
|
|
33
|
+
* Node registry with registered nodes, values, and dependencies.
|
|
34
|
+
* Required for graph execution.
|
|
35
|
+
*/
|
|
36
|
+
registry: IRegistry;
|
|
37
|
+
variables?: ServerVariable[];
|
|
38
|
+
events?: ServerEvent[];
|
|
39
|
+
sessionFactory?: SessionFactory;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Custom tick strategy hook for controlling timing between tick events.
|
|
43
|
+
* If not provided, defaults to requestAnimationFrame for smooth browser refresh sync.
|
|
44
|
+
*/
|
|
45
|
+
tickStrategy?: () => Promise<void>;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Whether to skip automatic connection.
|
|
49
|
+
* Default: false (will attempt to connect immediately)
|
|
50
|
+
*/
|
|
51
|
+
skipAutoConnect?: boolean;
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Whether to add the menu item to the Window menu.
|
|
55
|
+
* Default: true
|
|
56
|
+
*/
|
|
57
|
+
addMenuItem?: boolean;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Default RAF-based tick strategy for smooth browser animation frame sync
|
|
62
|
+
*/
|
|
63
|
+
const defaultRafTickStrategy = (): Promise<void> => {
|
|
64
|
+
return new Promise((resolve) => {
|
|
65
|
+
requestAnimationFrame(() => resolve());
|
|
66
|
+
});
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Plugin initialization function for local graph execution
|
|
71
|
+
* Registers a GraphRunnerClient with a local transport that executes graphs in-browser
|
|
72
|
+
*/
|
|
73
|
+
export async function localGraphRunnerPluginLoader(
|
|
74
|
+
system: System,
|
|
75
|
+
options: LocalGraphRunnerPluginOptions
|
|
76
|
+
): Promise<void> {
|
|
77
|
+
// Create local graph runner store
|
|
78
|
+
const localStore = localGraphRunnerStoreFactory();
|
|
79
|
+
system.decorate('localGraphRunnerStore', localStore);
|
|
80
|
+
|
|
81
|
+
// Create or use provided session factory with tick strategy
|
|
82
|
+
const tickStrategy = options.tickStrategy ?? defaultRafTickStrategy;
|
|
83
|
+
const sessionFactory =
|
|
84
|
+
options.sessionFactory ??
|
|
85
|
+
new DefaultSessionFactory({
|
|
86
|
+
tickStrategy
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
// Create local transport with access to the node registry and store
|
|
90
|
+
const transport = new LocalTransport(options.registry, {
|
|
91
|
+
...options,
|
|
92
|
+
store: localStore,
|
|
93
|
+
sessionFactory
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
// Create client with the local transport and message activity tracking
|
|
97
|
+
const client = new GraphRunnerClient({
|
|
98
|
+
transport,
|
|
99
|
+
protocolVersion: '1.0.0',
|
|
100
|
+
auth: { type: 'none' },
|
|
101
|
+
onMessageActivity: (direction, message) => {
|
|
102
|
+
// Access the store from the system after it's registered
|
|
103
|
+
const graphRunnerStore = system.runner.store;
|
|
104
|
+
if (graphRunnerStore) {
|
|
105
|
+
graphRunnerStore.getState().addMessageActivity(direction, message);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
// Register the graph runner client plugin
|
|
111
|
+
// This will create the graphRunnerClientStore and decorate it on the system
|
|
112
|
+
system.registerPlugin(graphRunnerClientPlugin, {
|
|
113
|
+
client
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
// Register the local graph runner panel
|
|
117
|
+
system.tabLoader.register('localGraphRunner', () => {
|
|
118
|
+
return {
|
|
119
|
+
id: 'localGraphRunner',
|
|
120
|
+
closable: true,
|
|
121
|
+
title: 'Local Graph Runner',
|
|
122
|
+
group: 'default',
|
|
123
|
+
content: () => (
|
|
124
|
+
<ErrorBoundary
|
|
125
|
+
fallback={<div>Error loading Local Graph Runner panel</div>}
|
|
126
|
+
>
|
|
127
|
+
<LocalGraphRunnerPanel />
|
|
128
|
+
</ErrorBoundary>
|
|
129
|
+
)
|
|
130
|
+
};
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
// Add menu item to Window menu (unless disabled)
|
|
134
|
+
if (options.addMenuItem !== false) {
|
|
135
|
+
const menuStore = system.menubarStore;
|
|
136
|
+
const currentItems = menuStore.getState().items;
|
|
137
|
+
const windowMenu = currentItems.find((menu) => menu.name === 'window');
|
|
138
|
+
|
|
139
|
+
if (windowMenu) {
|
|
140
|
+
// Add the Local Graph Runner menu item to the Window menu
|
|
141
|
+
const newMenuItem = {
|
|
142
|
+
name: 'localGraphRunner',
|
|
143
|
+
render: function LocalGraphRunnerMenuItem() {
|
|
144
|
+
return (
|
|
145
|
+
<MenuItemElement
|
|
146
|
+
onClick={() =>
|
|
147
|
+
system.tabStore.getState().openTab('localGraphRunner')
|
|
148
|
+
}
|
|
149
|
+
key="localGraphRunner"
|
|
150
|
+
>
|
|
151
|
+
Local Graph Runner
|
|
152
|
+
</MenuItemElement>
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
menuStore
|
|
158
|
+
.getState()
|
|
159
|
+
.setSubMenuItems('window', [...windowMenu.items, newMenuItem]);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export const localGraphRunnerPlugin = plugin(localGraphRunnerPluginLoader, {
|
|
165
|
+
name: 'graphrunner-local'
|
|
166
|
+
});
|