@kiberon-labs/behave-graph-flow 2.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.
- package/.storybook/manager.ts +6 -0
- package/.storybook/preview.ts +49 -1
- package/.storybook/styles.css +9 -3
- package/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +368 -0
- package/dist/AnyControlImpl-Ds-CShIB.js +20 -0
- package/dist/AnyControlImpl-Ds-CShIB.js.map +1 -0
- package/dist/DocumentationBrowserPanelImpl-deZNzFX8.js +166 -0
- package/dist/DocumentationBrowserPanelImpl-deZNzFX8.js.map +1 -0
- package/dist/index.css +36 -33
- package/dist/index.css.map +1 -1
- package/dist/index.d.ts +1865 -550
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +14357 -11221
- package/dist/index.js.map +1 -1
- package/dist/noteImpl-KkrrWgJd.js +242 -0
- package/dist/noteImpl-KkrrWgJd.js.map +1 -0
- package/dist/styles.module-CvmpDkZj.css +3 -0
- package/dist/styles.module-CvmpDkZj.css.map +1 -0
- package/dist/styles.module-DZxg8aW9.js +271 -0
- package/dist/styles.module-DZxg8aW9.js.map +1 -0
- package/dist/useChangeNodeData-ChQGK7AI.js +23 -0
- package/dist/useChangeNodeData-ChQGK7AI.js.map +1 -0
- package/docs/protocol.md +43 -20
- package/package.json +5 -9
- package/src/components/FloatingToolbar/index.module.css +5 -13
- package/src/components/FloatingToolbar/index.tsx +9 -9
- package/src/components/Flow.tsx +34 -23
- package/src/components/contextMenus/DynamicContextMenu.tsx +85 -0
- package/src/components/contextMenus/NodePicker.module.css +13 -13
- package/src/components/contextMenus/edge.tsx +9 -95
- package/src/components/contextMenus/node.tsx +9 -149
- package/src/components/contextMenus/selection.tsx +5 -71
- package/src/components/controls/any/AnyControlImpl.tsx +14 -0
- package/src/components/controls/any/index.tsx +13 -2
- package/src/components/edges/index.tsx +75 -69
- package/src/components/layoutController/index.module.css +3 -0
- package/src/components/layoutController/index.tsx +24 -1
- package/src/components/layoutController/utils.ts +46 -3
- package/src/components/menubar/defaults.tsx +55 -19
- package/src/components/menubar/menuItem.module.css +18 -3
- package/src/components/menubar/menuItem.tsx +34 -1
- package/src/components/nodes/behave/NodeContainer.module.css +26 -25
- package/src/components/nodes/group/index.tsx +3 -3
- package/src/components/nodes/wrapper/styles.module.css +6 -32
- package/src/components/panels/alignment/index.module.css +0 -10
- package/src/components/panels/alignment/index.tsx +4 -4
- package/src/components/panels/base/styles.module.css +2 -2
- package/src/components/panels/common/PanelHeader.module.css +24 -0
- package/src/components/panels/common/PanelHeader.tsx +22 -0
- package/src/components/panels/common/SectionTitle.module.css +13 -0
- package/src/components/panels/common/SectionTitle.tsx +10 -0
- package/src/components/panels/events/EditEventPanel.tsx +14 -5
- package/src/components/panels/events/ManageEventsPanel.tsx +11 -8
- package/src/components/panels/events/styles.module.css +6 -64
- package/src/components/panels/graphProperties/index.tsx +125 -0
- package/src/components/panels/history/index.tsx +2 -2
- package/src/components/panels/history/styles.module.css +0 -9
- package/src/components/panels/keymaps/index.module.css +3 -13
- package/src/components/panels/keymaps/index.tsx +1 -2
- package/src/components/panels/layers/index.tsx +20 -15
- package/src/components/panels/layers/styles.module.css +9 -12
- package/src/components/panels/legend/index.tsx +1 -1
- package/src/components/panels/logs/index.module.css +25 -19
- package/src/components/panels/logs/index.tsx +7 -7
- package/src/components/panels/nodeInputs/InputsGroup.tsx +1 -0
- package/src/components/panels/nodeInputs/NodeSettings.tsx +2 -2
- package/src/components/panels/nodeInputs/NodeTitleEditor.tsx +1 -1
- package/src/components/panels/nodeInputs/OutputsGroup.tsx +2 -12
- package/src/components/panels/nodeInputs/index.module.css +99 -75
- package/src/components/panels/nodeInputs/index.tsx +21 -11
- package/src/components/panels/nodeInputs/useNodeHandlers.ts +2 -2
- package/src/components/panels/nodeInputs/useNodeInputsData.ts +23 -43
- package/src/components/panels/nodePicker/index.tsx +8 -8
- package/src/components/panels/panel/index.module.css +7 -7
- package/src/components/panels/search/index.module.css +0 -50
- package/src/components/panels/search/index.tsx +2 -2
- package/src/components/panels/systemSettings/ConversionsSettings.tsx +203 -0
- package/src/components/panels/systemSettings/index.tsx +221 -176
- package/src/components/panels/systemSettings/styles.module.css +135 -8
- package/src/components/panels/traces/GridLines.tsx +1 -1
- package/src/components/panels/traces/TimeGrid.tsx +3 -3
- package/src/components/panels/traces/TraceLane.tsx +1 -1
- package/src/components/panels/traces/index.module.css +1 -8
- package/src/components/panels/traces/index.tsx +8 -4
- package/src/components/panels/traces/useDerivedSpans.ts +241 -146
- package/src/components/panels/traces/utils.ts +8 -0
- package/src/components/panels/variables/CreateVariableScreen.tsx +3 -3
- package/src/components/panels/variables/ManageVariablesScreen.tsx +12 -9
- package/src/components/panels/variables/index.tsx +2 -2
- package/src/components/panels/variables/styles.module.css +4 -91
- package/src/components/primitives/icon.module.css +4 -4
- package/src/components/sockets/input/index.tsx +9 -2
- package/src/components/sockets/input/styles.module.css +2 -3
- package/src/components/sockets/output/index.tsx +10 -3
- package/src/components/sockets/output/styles.module.css +1 -6
- package/src/css/notes.css +135 -0
- package/src/css/prosemirror.css +3 -3
- package/src/css/rc-dock.css +143 -43
- package/src/css/rc-menu.css +56 -55
- package/src/css/themes/kiberon.css +127 -0
- package/src/css/vars.css +197 -13
- package/src/css/vscode-elements.css +124 -0
- package/src/generators/CallSubgraphGenerator.tsx +136 -0
- package/src/generators/CustomEventOnTriggeredGenerator.tsx +2 -2
- package/src/generators/GraphBoundaryGenerator.module.css +32 -0
- package/src/generators/GraphBoundaryGenerator.tsx +193 -0
- package/src/generators/SequenceGenerator.tsx +2 -2
- package/src/generators/SwitchOnIntegerGenerator.tsx +2 -2
- package/src/generators/SwitchOnStringGenerator.tsx +2 -2
- package/src/generators/callSubgraphSync.ts +126 -0
- package/src/generators/registerDefaultGenerators.ts +21 -0
- package/src/generators/registerDefaults.ts +26 -0
- package/src/hooks/useBehaveGraphFlow.ts +2 -2
- package/src/hooks/useFlowHandlers.ts +47 -9
- package/src/hooks/useWasdPan.ts +26 -4
- package/src/index.css +4 -16
- package/src/index.ts +17 -0
- package/src/manifest/contributionRegistry.ts +93 -0
- package/src/manifest/index.ts +4 -0
- package/src/manifest/loadManifest.ts +82 -0
- package/src/manifest/manifestPlugin.ts +29 -0
- package/src/manifest/passthroughValueType.ts +40 -0
- package/src/plugin/alignment/index.ts +22 -12
- package/src/plugin/autosave/controller.ts +366 -0
- package/src/plugin/autosave/index.tsx +114 -0
- package/src/plugin/autosave/panel/BackupPanel.tsx +141 -0
- package/src/plugin/autosave/panel/index.tsx +1 -0
- package/src/plugin/autosave/panel/styles.module.css +56 -0
- package/src/plugin/autosave/settings.ts +65 -0
- package/src/plugin/autosave/storage.ts +147 -0
- package/src/plugin/docs/index.tsx +2 -4
- package/src/plugin/docs/panel/DocumentationBrowserPanelImpl.tsx +200 -0
- package/src/plugin/docs/panel/index.tsx +15 -194
- package/src/plugin/docs/panel/styles.module.css +8 -8
- package/src/plugin/graphrunner/actions.ts +258 -185
- package/src/plugin/graphrunner/buttons.tsx +34 -26
- package/src/plugin/graphrunner/client.ts +4 -1
- package/src/plugin/graphrunner/index.tsx +29 -100
- package/src/plugin/graphrunner/panel.tsx +2 -2
- package/src/plugin/graphrunner/runController.ts +283 -0
- package/src/plugin/graphrunner/runner.ts +21 -192
- package/src/plugin/graphrunner/store.ts +14 -24
- package/src/plugin/graphrunner/styles.module.css +17 -57
- package/src/plugin/graphrunner/transport.ts +26 -0
- package/src/plugin/graphrunner/types.ts +21 -0
- package/src/plugin/graphrunner-local/execution-utils.ts +260 -80
- package/src/plugin/graphrunner-local/index.tsx +8 -2
- package/src/plugin/graphrunner-local/panel.tsx +131 -175
- package/src/plugin/graphrunner-local/styles.module.css +57 -76
- package/src/plugin/graphrunner-local/transport.ts +151 -184
- package/src/plugin/graphrunner-webworker/graph-executor.worker.ts +2 -0
- package/src/plugin/graphrunner-webworker/index.tsx +4 -10
- package/src/plugin/graphrunner-webworker/store.ts +9 -0
- package/src/plugin/kitchen-sink/index.ts +38 -0
- package/src/{layout/dagre.tsx → plugin/layout/dagre.ts} +17 -5
- package/src/{layout → plugin/layout}/elk.ts +22 -6
- package/src/plugin/layout/index.ts +80 -0
- package/src/plugin/notes/FormatToolbar.tsx +200 -0
- package/src/plugin/notes/index.tsx +191 -0
- package/src/plugin/notes/nodeActions.ts +100 -0
- package/src/plugin/notes/note.tsx +20 -0
- package/src/plugin/notes/noteImpl.tsx +89 -0
- package/src/plugin/realtime/realtimeRunner.ts +58 -4
- package/src/specifics/CustomEventOnTriggeredSpecific.tsx +2 -2
- package/src/specifics/CustomEventTriggerSpecific.tsx +2 -2
- package/src/specifics/VariableGetSpecific.tsx +2 -2
- package/src/specifics/VariableSetSpecific.tsx +2 -2
- package/src/store/actions.tsx +5 -5
- package/src/store/commands.ts +278 -0
- package/src/store/contextMenu.ts +192 -0
- package/src/store/conversions.ts +47 -0
- package/src/store/flow.tsx +23 -38
- package/src/store/graphMeta.ts +39 -0
- package/src/store/hotKeys.tsx +301 -260
- package/src/store/layers.ts +3 -3
- package/src/store/registry.ts +12 -4
- package/src/store/selection.ts +3 -3
- package/src/store/settings.ts +82 -82
- package/src/store/settingsSchema.ts +210 -0
- package/src/store/tabs.ts +5 -1
- package/src/store/traces.ts +3 -3
- package/src/system/graph.ts +11 -14
- package/src/system/graphSession.ts +172 -0
- package/src/system/index.ts +3 -0
- package/src/system/notifications.ts +13 -0
- package/src/system/persistence.ts +82 -0
- package/src/system/plugin.ts +28 -0
- package/src/system/provider.tsx +64 -0
- package/src/system/system.ts +518 -88
- package/src/system/tabLoader.tsx +70 -32
- package/src/system/undoRedo.ts +1 -1
- package/src/transformers/Uigraph.ts +5 -4
- package/src/transformers/contract.ts +87 -0
- package/src/transformers/flowToBehave.ts +13 -5
- package/src/types/nodes.ts +8 -3
- package/src/types.ts +2 -0
- package/src/util/autoConvert.ts +200 -0
- package/src/util/isValidConnection.ts +23 -2
- package/stories/defaults/defaultStoryProvider.tsx +17 -14
- package/stories/defaults/systemGenerator.ts +6 -1
- package/stories/{components/nodes/comment.stories.tsx → plugins/notes.stories.tsx} +24 -30
- package/tests/autoConvert.test.ts +329 -0
- package/tests/autosavePlugin.test.ts +204 -0
- package/tests/callSubgraphSync.test.ts +148 -0
- package/tests/commandRegistry.test.ts +137 -0
- package/tests/contract.test.ts +51 -0
- package/tests/contractSerialize.test.ts +62 -0
- package/tests/deriveSpans.test.ts +71 -0
- package/tests/flowToBehave.test.ts +2 -1
- package/tests/hotkeys.test.ts +79 -0
- package/tests/keepAliveLifecycle.test.ts +167 -0
- package/tests/loadManifest.test.ts +113 -0
- package/tests/noteMarkdown.test.ts +65 -0
- package/tests/notesPlugin.test.ts +162 -0
- package/tests/persistence.test.ts +51 -0
- package/tests/saveLoad.test.ts +7 -6
- package/tests/settings.test.ts +178 -0
- package/tests/traceStore.test.ts +46 -0
- package/tests/visual/README.md +2 -2
- 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-localGraphRunner-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-variables-chromium-win32.png +0 -0
- package/tests/visual/panels.visual.test.tsx +3 -3
- package/tests/wasdPan.test.ts +71 -0
- package/vitest.config.ts +1 -1
- package/vitest.visual.config.ts +7 -0
- package/.storybook/vscode.css +0 -814
- package/src/components/nodes/comment/FormatToolbar.tsx +0 -118
- package/src/components/nodes/comment/comment.tsx +0 -103
- package/src/components/nodes/comment/styles.module.css +0 -150
- package/src/components/panels/conversation/index.module.css +0 -151
- package/src/components/panels/conversation/index.tsx +0 -162
- package/src/components/panels/events/CustomEventsEditor.tsx +0 -384
- package/src/css/vscode.css +0 -13
- package/src/hooks/useDetachNodes.ts +0 -39
- package/src/plugin/graphrunner-webworker/types.ts +0 -17
- package/src/specifics/registerDefaultSpecifics.ts +0 -5
- package/src/store/chat.ts +0 -73
- package/src/store/graphRunnerClient.ts +0 -110
|
@@ -13,15 +13,16 @@ import type { StoreApi } from 'zustand';
|
|
|
13
13
|
import type { GraphRunnerClientStore } from './store';
|
|
14
14
|
import { GraphRunnerButtons } from './buttons';
|
|
15
15
|
import { plugin } from '@/system/plugin';
|
|
16
|
-
import { isBehaveNode } from '@/util/isBehaveNode';
|
|
17
|
-
import type { Node } from 'reactflow';
|
|
18
16
|
import { GraphRunner } from './runner';
|
|
17
|
+
import { GraphRunController } from './runController';
|
|
18
|
+
import type { GraphSession } from '@/system/graphSession';
|
|
19
19
|
|
|
20
20
|
export * from './types';
|
|
21
21
|
export * from './client';
|
|
22
22
|
export * from './transport';
|
|
23
23
|
export * from './panel';
|
|
24
24
|
export * from './runner';
|
|
25
|
+
export * from './runController';
|
|
25
26
|
export * from './store';
|
|
26
27
|
export * from './session';
|
|
27
28
|
/**
|
|
@@ -86,25 +87,33 @@ export async function graphRunnerClientPluginLoader(
|
|
|
86
87
|
}
|
|
87
88
|
}
|
|
88
89
|
|
|
89
|
-
//
|
|
90
|
+
// Shared connection. Per-session run controllers are created below.
|
|
90
91
|
const runner = new GraphRunner(system, store);
|
|
91
92
|
system.decorate('runner', runner);
|
|
92
93
|
|
|
93
|
-
//
|
|
94
|
+
// Attach a run controller to every graph session (existing + future) so each
|
|
95
|
+
// open graph runs independently over the shared connection. The editor applies
|
|
96
|
+
// this to graphs already open and to every graph created later, and tears the
|
|
97
|
+
// controller down when a graph's tab is closed.
|
|
98
|
+
system.registerSessionExtension((session: GraphSession) => {
|
|
99
|
+
if (!session.runController) {
|
|
100
|
+
session.decorate(
|
|
101
|
+
'runController',
|
|
102
|
+
new GraphRunController(session, runner)
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
return () => {
|
|
106
|
+
session.runController?.dispose();
|
|
107
|
+
session.decorate('runController', undefined);
|
|
108
|
+
};
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
// Add toolbar buttons for graph execution control. Rendered inside each graph
|
|
112
|
+
// tab, GraphRunnerButtons resolves its own session's controller.
|
|
94
113
|
system.toolbarStore.getState().addGroup({
|
|
95
114
|
id: 'graph-runner-controls',
|
|
96
115
|
label: 'Graph Runner',
|
|
97
|
-
buttons: [
|
|
98
|
-
<GraphRunnerButtons
|
|
99
|
-
key="graph-runner-buttons"
|
|
100
|
-
store={store}
|
|
101
|
-
onPlay={() => runner.play()}
|
|
102
|
-
onPause={() => runner.pause()}
|
|
103
|
-
onResume={() => runner.resume()}
|
|
104
|
-
onStep={() => runner.step()}
|
|
105
|
-
onStop={() => runner.stop()}
|
|
106
|
-
/>
|
|
107
|
-
]
|
|
116
|
+
buttons: [<GraphRunnerButtons key="graph-runner-buttons" />]
|
|
108
117
|
});
|
|
109
118
|
|
|
110
119
|
system.hotKeyStore.getState().register({
|
|
@@ -112,10 +121,12 @@ export async function graphRunnerClientPluginLoader(
|
|
|
112
121
|
description: 'Triggers playing the graph',
|
|
113
122
|
trigger: 'p',
|
|
114
123
|
handler: () => {
|
|
115
|
-
|
|
116
|
-
|
|
124
|
+
const controller = system.session?.runController;
|
|
125
|
+
if (!controller) return;
|
|
126
|
+
if (controller.store.getState().isExecuting) {
|
|
127
|
+
controller.stop();
|
|
117
128
|
} else {
|
|
118
|
-
|
|
129
|
+
controller.play();
|
|
119
130
|
}
|
|
120
131
|
}
|
|
121
132
|
});
|
|
@@ -163,88 +174,6 @@ export async function graphRunnerClientPluginLoader(
|
|
|
163
174
|
}
|
|
164
175
|
}
|
|
165
176
|
|
|
166
|
-
system.pubsub.subscribe('node:added', (_, node: Node) => {
|
|
167
|
-
if (!isBehaveNode(node)) {
|
|
168
|
-
return;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
const client = runner.store.getState().client;
|
|
172
|
-
const currentRunId = runner.store.getState().currentRunId;
|
|
173
|
-
const graphId = runner.store.getState().currentGraphId;
|
|
174
|
-
|
|
175
|
-
// Only send if we have an active run and realtime is enabled
|
|
176
|
-
if (client && currentRunId && graphId) {
|
|
177
|
-
const capabilities = runner.store.getState().connectionInfo.capabilities;
|
|
178
|
-
if (capabilities?.realtime) {
|
|
179
|
-
client.addNode(
|
|
180
|
-
currentRunId,
|
|
181
|
-
node.id,
|
|
182
|
-
node.data.type,
|
|
183
|
-
node.data as Record<string, unknown>,
|
|
184
|
-
node.position
|
|
185
|
-
);
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
});
|
|
189
|
-
|
|
190
|
-
system.pubsub.subscribe('edge:added', (_, edge) => {
|
|
191
|
-
const client = runner.store.getState().client;
|
|
192
|
-
const currentRunId = runner.store.getState().currentRunId;
|
|
193
|
-
const graphId = runner.store.getState().currentGraphId;
|
|
194
|
-
|
|
195
|
-
// Only send if we have an active run and realtime is enabled
|
|
196
|
-
if (client && currentRunId && graphId && edge.source && edge.target) {
|
|
197
|
-
const capabilities = runner.store.getState().connectionInfo.capabilities;
|
|
198
|
-
if (capabilities?.realtime) {
|
|
199
|
-
client.createLink(
|
|
200
|
-
currentRunId,
|
|
201
|
-
edge.source,
|
|
202
|
-
edge.sourceHandle || '',
|
|
203
|
-
edge.target,
|
|
204
|
-
edge.targetHandle || ''
|
|
205
|
-
);
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
});
|
|
209
|
-
|
|
210
|
-
system.pubsub.subscribe('edge:removed', (_, edge) => {
|
|
211
|
-
const client = runner.store.getState().client;
|
|
212
|
-
const currentRunId = runner.store.getState().currentRunId;
|
|
213
|
-
const graphId = runner.store.getState().currentGraphId;
|
|
214
|
-
|
|
215
|
-
// Only send if we have an active run and realtime is enabled
|
|
216
|
-
if (client && currentRunId && graphId && edge.source && edge.target) {
|
|
217
|
-
const capabilities = runner.store.getState().connectionInfo.capabilities;
|
|
218
|
-
if (capabilities?.realtime) {
|
|
219
|
-
client.removeLink(
|
|
220
|
-
currentRunId,
|
|
221
|
-
edge.source,
|
|
222
|
-
edge.sourceHandle || '',
|
|
223
|
-
edge.target,
|
|
224
|
-
edge.targetHandle || ''
|
|
225
|
-
);
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
});
|
|
229
|
-
|
|
230
|
-
system.pubsub.subscribe('node:removed', (_, node: Node) => {
|
|
231
|
-
if (!isBehaveNode(node)) {
|
|
232
|
-
return;
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
const client = runner.store.getState().client;
|
|
236
|
-
const currentRunId = runner.store.getState().currentRunId;
|
|
237
|
-
const graphId = runner.store.getState().currentGraphId;
|
|
238
|
-
|
|
239
|
-
// Only send if we have an active run and realtime is enabled
|
|
240
|
-
if (client && currentRunId && graphId) {
|
|
241
|
-
const capabilities = runner.store.getState().connectionInfo.capabilities;
|
|
242
|
-
if (capabilities?.realtime) {
|
|
243
|
-
client.removeNode(currentRunId, node.id);
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
});
|
|
247
|
-
|
|
248
177
|
if (!options.skipAutoConnect) {
|
|
249
178
|
await runner.connect();
|
|
250
179
|
}
|
|
@@ -348,8 +348,8 @@ export const GraphRunnerPanel: React.FC<GraphRunnerPanelProps> = ({
|
|
|
348
348
|
).toLocaleTimeString();
|
|
349
349
|
const directionColor =
|
|
350
350
|
activity.direction === 'sent'
|
|
351
|
-
? 'var(--
|
|
352
|
-
: 'var(--
|
|
351
|
+
? 'var(--ds-git-modified)'
|
|
352
|
+
: 'var(--ds-git-added)';
|
|
353
353
|
|
|
354
354
|
return (
|
|
355
355
|
<div key={activity.id} className={styles.messageCard}>
|
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
import { createStore, type StoreApi } from 'zustand';
|
|
2
|
+
import type { GraphSession } from '@/system/graphSession';
|
|
3
|
+
import type { GraphRunner } from './runner';
|
|
4
|
+
import { buildUIGraphJSON } from '../../transformers/Uigraph';
|
|
5
|
+
import { isBehaveNode } from '@/util/isBehaveNode';
|
|
6
|
+
import { supportsExecutionControl } from './transport';
|
|
7
|
+
|
|
8
|
+
// Contribute the per-session run controller to the graph session as a typed,
|
|
9
|
+
// plugin-owned property. Core no longer declares this field , the graph runner
|
|
10
|
+
// plugin attaches it via `session.decorate('runController', …)` from a session
|
|
11
|
+
// extension (see ./index.tsx).
|
|
12
|
+
declare module '@/system/graphSession' {
|
|
13
|
+
interface IGraphSession {
|
|
14
|
+
runController?: GraphRunController;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Per-run state for a single graph. Each {@link GraphSession} owns one of these,
|
|
20
|
+
* so multiple graphs can run independently and concurrently.
|
|
21
|
+
*/
|
|
22
|
+
export interface RunControllerStore {
|
|
23
|
+
currentRunId: string | null;
|
|
24
|
+
currentGraphId: string | null;
|
|
25
|
+
isExecuting: boolean;
|
|
26
|
+
isPaused: boolean;
|
|
27
|
+
setCurrentRunId: (runId: string | null) => void;
|
|
28
|
+
setCurrentGraphId: (graphId: string | null) => void;
|
|
29
|
+
setIsExecuting: (isExecuting: boolean) => void;
|
|
30
|
+
setIsPaused: (isPaused: boolean) => void;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const runControllerStoreFactory = (): StoreApi<RunControllerStore> =>
|
|
34
|
+
createStore<RunControllerStore>((set) => ({
|
|
35
|
+
currentRunId: null,
|
|
36
|
+
currentGraphId: null,
|
|
37
|
+
isExecuting: false,
|
|
38
|
+
isPaused: false,
|
|
39
|
+
setCurrentRunId: (currentRunId) => set({ currentRunId }),
|
|
40
|
+
setCurrentGraphId: (currentGraphId) => set({ currentGraphId }),
|
|
41
|
+
setIsExecuting: (isExecuting) => set({ isExecuting }),
|
|
42
|
+
setIsPaused: (isPaused) => set({ isPaused })
|
|
43
|
+
}));
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Drives execution for a single graph session. Run lifecycle and run state are
|
|
47
|
+
* per-session; the underlying connection/client is shared via {@link GraphRunner}.
|
|
48
|
+
* Incoming server messages are routed back to the originating controller by run
|
|
49
|
+
* id (see `GraphRunner.runIndex`).
|
|
50
|
+
*/
|
|
51
|
+
export class GraphRunController {
|
|
52
|
+
public readonly session: GraphSession;
|
|
53
|
+
public readonly runner: GraphRunner;
|
|
54
|
+
public readonly store: StoreApi<RunControllerStore> =
|
|
55
|
+
runControllerStoreFactory();
|
|
56
|
+
private readonly disposers: Array<() => void> = [];
|
|
57
|
+
|
|
58
|
+
constructor(session: GraphSession, runner: GraphRunner) {
|
|
59
|
+
this.session = session;
|
|
60
|
+
this.runner = runner;
|
|
61
|
+
this.setupRealtimeForwarding();
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
private get notifications() {
|
|
65
|
+
return this.session.editor.notifications;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** Run the graph for this session. */
|
|
69
|
+
async play(): Promise<void> {
|
|
70
|
+
const { clearLogsOnRun, clearTracesOnRun } = this.runner.store.getState();
|
|
71
|
+
|
|
72
|
+
if (clearLogsOnRun) {
|
|
73
|
+
this.session.logsStore.getState().clear();
|
|
74
|
+
}
|
|
75
|
+
if (clearTracesOnRun) {
|
|
76
|
+
this.session.traceStore.getState().clear();
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const graphId = this.session.id;
|
|
80
|
+
const uiGraphData = buildUIGraphJSON(this.session);
|
|
81
|
+
try {
|
|
82
|
+
await this.runRemotely(graphId, { graph: uiGraphData.flow });
|
|
83
|
+
} catch {
|
|
84
|
+
// Error already surfaced in runRemotely
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
async runRemotely(
|
|
89
|
+
graphId: string,
|
|
90
|
+
options?: { graph?: unknown; inputs?: unknown }
|
|
91
|
+
): Promise<void> {
|
|
92
|
+
const client = this.runner.store.getState().client;
|
|
93
|
+
const { enableTracing } = this.runner.store.getState();
|
|
94
|
+
const { setCurrentRunId, setCurrentGraphId, setIsExecuting, setIsPaused } =
|
|
95
|
+
this.store.getState();
|
|
96
|
+
|
|
97
|
+
if (!client) {
|
|
98
|
+
this.notifications.error('No graph runner connection');
|
|
99
|
+
throw new Error('No graph runner connection');
|
|
100
|
+
}
|
|
101
|
+
if (this.store.getState().isExecuting) {
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
try {
|
|
106
|
+
const runId = await client.runGraph(graphId, {
|
|
107
|
+
...options,
|
|
108
|
+
trace: enableTracing
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
setCurrentRunId(runId);
|
|
112
|
+
setCurrentGraphId(graphId);
|
|
113
|
+
setIsExecuting(true);
|
|
114
|
+
setIsPaused(false);
|
|
115
|
+
this.runner.registerRun(runId, this);
|
|
116
|
+
|
|
117
|
+
this.notifications.info(`Graph execution started: ${graphId}`);
|
|
118
|
+
} catch (error) {
|
|
119
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
120
|
+
setIsExecuting(false);
|
|
121
|
+
setIsPaused(false);
|
|
122
|
+
setCurrentRunId(null);
|
|
123
|
+
setCurrentGraphId(null);
|
|
124
|
+
this.notifications.error(`Failed to run graph: ${message}`);
|
|
125
|
+
throw error;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
async stop(): Promise<void> {
|
|
130
|
+
const client = this.runner.store.getState().client;
|
|
131
|
+
const { currentRunId } = this.store.getState();
|
|
132
|
+
if (!client || !currentRunId) return;
|
|
133
|
+
|
|
134
|
+
try {
|
|
135
|
+
await client.stopGraph(currentRunId);
|
|
136
|
+
this.notifications.info('Stopping graph execution');
|
|
137
|
+
this.finishRun();
|
|
138
|
+
} catch (error) {
|
|
139
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
140
|
+
this.notifications.error(`Failed to stop graph: ${message}`);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
async pause(): Promise<void> {
|
|
145
|
+
const client = this.runner.store.getState().client;
|
|
146
|
+
const { currentRunId, setIsPaused } = this.store.getState();
|
|
147
|
+
if (!client || !currentRunId) return;
|
|
148
|
+
|
|
149
|
+
try {
|
|
150
|
+
const transport = client.transport;
|
|
151
|
+
if (supportsExecutionControl(transport)) {
|
|
152
|
+
transport.pauseExecution(currentRunId);
|
|
153
|
+
setIsPaused(true);
|
|
154
|
+
this.notifications.info('Execution paused');
|
|
155
|
+
} else {
|
|
156
|
+
await this.stop();
|
|
157
|
+
}
|
|
158
|
+
} catch (error) {
|
|
159
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
160
|
+
this.notifications.error(`Failed to pause graph: ${message}`);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
async resume(): Promise<void> {
|
|
165
|
+
const client = this.runner.store.getState().client;
|
|
166
|
+
const { currentRunId, setIsPaused } = this.store.getState();
|
|
167
|
+
if (!client || !currentRunId) return;
|
|
168
|
+
|
|
169
|
+
try {
|
|
170
|
+
const transport = client.transport;
|
|
171
|
+
if (supportsExecutionControl(transport)) {
|
|
172
|
+
setIsPaused(false);
|
|
173
|
+
this.notifications.info('Resuming execution');
|
|
174
|
+
await transport.resumeExecution(currentRunId);
|
|
175
|
+
}
|
|
176
|
+
} catch (error) {
|
|
177
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
178
|
+
this.notifications.error(`Failed to resume graph: ${message}`);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
async step(): Promise<void> {
|
|
183
|
+
const client = this.runner.store.getState().client;
|
|
184
|
+
const { currentRunId, setIsPaused } = this.store.getState();
|
|
185
|
+
if (!client || !currentRunId) return;
|
|
186
|
+
|
|
187
|
+
try {
|
|
188
|
+
const transport = client.transport;
|
|
189
|
+
if (supportsExecutionControl(transport)) {
|
|
190
|
+
setIsPaused(true);
|
|
191
|
+
await transport.stepExecution(currentRunId);
|
|
192
|
+
} else {
|
|
193
|
+
this.notifications.info(
|
|
194
|
+
'Step execution not supported for this transport'
|
|
195
|
+
);
|
|
196
|
+
}
|
|
197
|
+
} catch (error) {
|
|
198
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
199
|
+
this.notifications.error(`Failed to step graph: ${message}`);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/** Reset run state after completion/stop/error and unregister the run. */
|
|
204
|
+
finishRun(): void {
|
|
205
|
+
const runId = this.store.getState().currentRunId;
|
|
206
|
+
if (runId) this.runner.unregisterRun(runId);
|
|
207
|
+
const s = this.store.getState();
|
|
208
|
+
s.setIsExecuting(false);
|
|
209
|
+
s.setIsPaused(false);
|
|
210
|
+
s.setCurrentRunId(null);
|
|
211
|
+
s.setCurrentGraphId(null);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Forward live graph edits to the server while this graph is running, tagged
|
|
216
|
+
* with this controller's run id so concurrent graphs stay isolated.
|
|
217
|
+
*/
|
|
218
|
+
private setupRealtimeForwarding(): void {
|
|
219
|
+
const pubsub = this.session.pubsub;
|
|
220
|
+
const canForward = () => {
|
|
221
|
+
const client = this.runner.store.getState().client;
|
|
222
|
+
const runId = this.store.getState().currentRunId;
|
|
223
|
+
const caps = this.runner.store.getState().connectionInfo.capabilities;
|
|
224
|
+
return client && runId && caps?.realtime ? { client, runId } : null;
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
const tokens = [
|
|
228
|
+
pubsub.subscribe('node:added', (_, node) => {
|
|
229
|
+
if (!isBehaveNode(node)) return;
|
|
230
|
+
const ctx = canForward();
|
|
231
|
+
if (!ctx) return;
|
|
232
|
+
ctx.client.addNode(
|
|
233
|
+
ctx.runId,
|
|
234
|
+
node.id,
|
|
235
|
+
node.data.type,
|
|
236
|
+
node.data as Record<string, unknown>,
|
|
237
|
+
node.position
|
|
238
|
+
);
|
|
239
|
+
}),
|
|
240
|
+
pubsub.subscribe('edge:added', (_, edge) => {
|
|
241
|
+
const ctx = canForward();
|
|
242
|
+
if (!ctx || !edge.source || !edge.target) return;
|
|
243
|
+
ctx.client.createLink(
|
|
244
|
+
ctx.runId,
|
|
245
|
+
edge.source,
|
|
246
|
+
edge.sourceHandle || '',
|
|
247
|
+
edge.target,
|
|
248
|
+
edge.targetHandle || ''
|
|
249
|
+
);
|
|
250
|
+
}),
|
|
251
|
+
pubsub.subscribe('edge:removed', (_, edge) => {
|
|
252
|
+
const ctx = canForward();
|
|
253
|
+
if (!ctx || !edge.source || !edge.target) return;
|
|
254
|
+
ctx.client.removeLink(
|
|
255
|
+
ctx.runId,
|
|
256
|
+
edge.source,
|
|
257
|
+
edge.sourceHandle || '',
|
|
258
|
+
edge.target,
|
|
259
|
+
edge.targetHandle || ''
|
|
260
|
+
);
|
|
261
|
+
}),
|
|
262
|
+
pubsub.subscribe('node:removed', (_, node) => {
|
|
263
|
+
if (!isBehaveNode(node)) return;
|
|
264
|
+
const ctx = canForward();
|
|
265
|
+
if (!ctx) return;
|
|
266
|
+
ctx.client.removeNode(ctx.runId, node.id);
|
|
267
|
+
})
|
|
268
|
+
];
|
|
269
|
+
|
|
270
|
+
for (const token of tokens) {
|
|
271
|
+
if (typeof token === 'string') {
|
|
272
|
+
this.disposers.push(() => pubsub.unsubscribe(token));
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
dispose(): void {
|
|
278
|
+
const runId = this.store.getState().currentRunId;
|
|
279
|
+
if (runId) this.runner.unregisterRun(runId);
|
|
280
|
+
this.disposers.forEach((d) => d());
|
|
281
|
+
this.disposers.length = 0;
|
|
282
|
+
}
|
|
283
|
+
}
|