@flowdrop/flowdrop 1.15.0 → 2.0.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +508 -0
- package/MIGRATION-2.0.md +629 -0
- package/README.md +23 -23
- package/dist/adapters/WorkflowAdapter.d.ts +1 -1
- package/dist/adapters/WorkflowAdapter.js +14 -8
- package/dist/adapters/agentspec/AgentSpecAdapter.js +7 -7
- package/dist/api/enhanced-client.js +6 -11
- package/dist/chat/batchFeedback.d.ts +39 -0
- package/dist/chat/batchFeedback.js +51 -0
- package/dist/commands/executor.js +15 -1
- package/dist/commands/storeIntegration.svelte.d.ts +4 -1
- package/dist/commands/storeIntegration.svelte.js +26 -21
- package/dist/commands/types.d.ts +2 -0
- package/dist/components/App.svelte +163 -192
- package/dist/components/App.svelte.d.ts +47 -8
- package/dist/components/ConfigForm.svelte +77 -49
- package/dist/components/ConfigModal.svelte +7 -2
- package/dist/components/ConnectionLine.svelte +4 -2
- package/dist/components/Navbar.svelte +61 -1
- package/dist/components/NodeSidebar.svelte +27 -45
- package/dist/components/NodeStatusOverlay.svelte +94 -6
- package/dist/components/NodeSwapPicker.svelte +10 -8
- package/dist/components/PipelineStatus.svelte +22 -68
- package/dist/components/PipelineStatus.svelte.d.ts +3 -0
- package/dist/components/PortCoordinateTracker.svelte +5 -6
- package/dist/components/SchemaForm.stories.svelte +1 -3
- package/dist/components/SchemaForm.svelte +22 -27
- package/dist/components/SchemaForm.svelte.d.ts +0 -8
- package/dist/components/SettingsModal.svelte +8 -3
- package/dist/components/SettingsPanel.svelte +20 -4
- package/dist/components/SwapMappingEditor.svelte +67 -49
- package/dist/components/SwapMappingEditor.svelte.d.ts +0 -2
- package/dist/components/UniversalNode.svelte +9 -7
- package/dist/components/WorkflowEditor.svelte +121 -111
- package/dist/components/WorkflowEditor.svelte.d.ts +21 -10
- package/dist/components/chat/AIChatPanel.svelte +98 -89
- package/dist/components/chat/AIChatPanel.svelte.d.ts +0 -4
- package/dist/components/chat/CommandPreview.svelte +2 -1
- package/dist/components/console/CommandConsole.svelte +7 -5
- package/dist/components/console/ConsoleAutocomplete.svelte +10 -11
- package/dist/components/console/ConsoleAutocomplete.svelte.d.ts +6 -0
- package/dist/components/console/ConsoleInput.svelte +15 -6
- package/dist/components/console/ConsoleOutput.svelte +2 -1
- package/dist/components/form/FormArray.svelte +5 -9
- package/dist/components/form/FormArray.svelte.d.ts +2 -1
- package/dist/components/form/FormAutocomplete.svelte +16 -15
- package/dist/components/form/FormField.svelte +4 -2
- package/dist/components/form/FormFieldLight.svelte +34 -3
- package/dist/components/form/FormFieldLight.svelte.d.ts +12 -0
- package/dist/components/form/FormMarkdownEditor.svelte +9 -4
- package/dist/components/form/FormRangeField.svelte +1 -0
- package/dist/components/form/FormTemplateEditor.svelte +11 -3
- package/dist/components/form/FormToggle.svelte +5 -12
- package/dist/components/form/FormToggle.svelte.d.ts +4 -2
- package/dist/components/form/FormUISchemaRenderer.svelte +3 -1
- package/dist/components/form/templateAutocomplete.js +1 -5
- package/dist/components/form/types.d.ts +1 -14
- package/dist/components/interrupt/FormPrompt.svelte +3 -2
- package/dist/components/interrupt/InterruptBubble.svelte +25 -17
- package/dist/components/interrupt/ReviewPrompt.svelte +10 -3
- package/dist/components/interrupt/TextInputPrompt.svelte +2 -1
- package/dist/components/layouts/MainLayout.svelte +20 -13
- package/dist/components/layouts/MainLayout.svelte.d.ts +4 -0
- package/dist/components/nodes/AtomNode.svelte +17 -5
- package/dist/components/nodes/GatewayNode.svelte +19 -10
- package/dist/components/nodes/IdeaNode.svelte +7 -0
- package/dist/components/nodes/SimpleNode.svelte +11 -6
- package/dist/components/nodes/SquareNode.svelte +15 -8
- package/dist/components/nodes/TerminalNode.svelte +9 -4
- package/dist/components/nodes/ToolNode.svelte +7 -1
- package/dist/components/nodes/WorkflowNode.svelte +16 -7
- package/dist/components/playground/ChatInput.svelte +11 -14
- package/dist/components/playground/ChatPanel.svelte +6 -49
- package/dist/components/playground/ChatPanel.svelte.d.ts +0 -14
- package/dist/components/playground/ControlPanel.svelte +134 -123
- package/dist/components/playground/ControlPanel.svelte.d.ts +3 -0
- package/dist/components/playground/ExecutionLogs.svelte +11 -9
- package/dist/components/playground/InputCollector.svelte +11 -9
- package/dist/components/playground/MessageStream.svelte +17 -23
- package/dist/components/playground/PipelineKanbanView.svelte +69 -8
- package/dist/components/playground/PipelineKanbanView.svelte.d.ts +2 -0
- package/dist/components/playground/PipelinePanel.svelte +31 -8
- package/dist/components/playground/PipelinePanel.svelte.d.ts +2 -0
- package/dist/components/playground/PipelineTableView.svelte +188 -44
- package/dist/components/playground/PipelineTableView.svelte.d.ts +2 -0
- package/dist/components/playground/Playground.svelte +154 -105
- package/dist/components/playground/Playground.svelte.d.ts +5 -0
- package/dist/components/playground/PlaygroundApp.svelte +11 -1
- package/dist/components/playground/PlaygroundApp.svelte.d.ts +6 -0
- package/dist/components/playground/PlaygroundModal.svelte +18 -3
- package/dist/components/playground/PlaygroundModal.svelte.d.ts +6 -0
- package/dist/components/playground/PlaygroundStudio.svelte +40 -32
- package/dist/components/playground/PlaygroundStudio.svelte.d.ts +6 -0
- package/dist/components/playground/SessionManager.svelte +9 -12
- package/dist/components/playground/pipelineViewUtils.svelte.d.ts +30 -1
- package/dist/components/playground/pipelineViewUtils.svelte.js +40 -3
- package/dist/config/endpoints.d.ts +23 -7
- package/dist/config/endpoints.js +30 -10
- package/dist/core/index.d.ts +5 -6
- package/dist/core/index.js +8 -12
- package/dist/display/index.d.ts +6 -3
- package/dist/display/index.js +7 -5
- package/dist/editor/index.d.ts +20 -21
- package/dist/editor/index.js +26 -36
- package/dist/form/code.d.ts +25 -15
- package/dist/form/code.js +44 -41
- package/dist/form/fieldRegistry.d.ts +17 -13
- package/dist/form/fieldRegistry.js +32 -12
- package/dist/form/full.d.ts +19 -14
- package/dist/form/full.js +26 -28
- package/dist/form/index.d.ts +3 -4
- package/dist/form/index.js +6 -5
- package/dist/form/markdown.d.ts +13 -8
- package/dist/form/markdown.js +22 -23
- package/dist/helpers/proximityConnect.d.ts +3 -2
- package/dist/helpers/proximityConnect.js +2 -5
- package/dist/helpers/workflowEditorHelper.d.ts +14 -5
- package/dist/helpers/workflowEditorHelper.js +28 -25
- package/dist/index.d.ts +28 -24
- package/dist/index.js +27 -50
- package/dist/messages/defaults.d.ts +2 -5
- package/dist/messages/defaults.js +3 -6
- package/dist/messages/index.d.ts +0 -1
- package/dist/messages/index.js +0 -1
- package/dist/mocks/app-forms.d.ts +6 -2
- package/dist/mocks/app-forms.js +11 -4
- package/dist/openapi/v1/openapi.yaml +3 -3
- package/dist/playground/index.d.ts +4 -5
- package/dist/playground/index.js +4 -32
- package/dist/playground/mount.d.ts +25 -0
- package/dist/playground/mount.js +50 -20
- package/dist/registry/{BaseRegistry.d.ts → BaseRegistry.svelte.d.ts} +22 -1
- package/dist/registry/{BaseRegistry.js → BaseRegistry.svelte.js} +37 -1
- package/dist/registry/builtinFormats.d.ts +9 -18
- package/dist/registry/builtinFormats.js +9 -39
- package/dist/registry/builtinNodeTypes.d.ts +53 -0
- package/dist/registry/builtinNodeTypes.js +67 -0
- package/dist/registry/builtinNodes.d.ts +2 -64
- package/dist/registry/builtinNodes.js +7 -103
- package/dist/registry/index.d.ts +3 -4
- package/dist/registry/index.js +4 -6
- package/dist/registry/nodeComponentRegistry.d.ts +182 -15
- package/dist/registry/nodeComponentRegistry.js +235 -17
- package/dist/registry/workflowFormatRegistry.d.ts +14 -9
- package/dist/registry/workflowFormatRegistry.js +24 -8
- package/dist/{schema → schemas}/index.d.ts +2 -2
- package/dist/{schema → schemas}/index.js +2 -2
- package/dist/schemas/v1/workflow.schema.json +3 -3
- package/dist/services/agentSpecExecutionService.d.ts +0 -2
- package/dist/services/agentSpecExecutionService.js +0 -3
- package/dist/services/apiVariableService.d.ts +2 -1
- package/dist/services/apiVariableService.js +16 -47
- package/dist/services/autoSaveService.d.ts +7 -0
- package/dist/services/autoSaveService.js +6 -4
- package/dist/services/categoriesApi.js +3 -6
- package/dist/services/chatService.d.ts +9 -4
- package/dist/services/chatService.js +23 -28
- package/dist/services/draftStorage.d.ts +129 -13
- package/dist/services/draftStorage.js +185 -37
- package/dist/services/dynamicSchemaService.d.ts +2 -1
- package/dist/services/dynamicSchemaService.js +5 -22
- package/dist/services/globalSave.d.ts +13 -12
- package/dist/services/globalSave.js +29 -51
- package/dist/services/historyService.d.ts +9 -3
- package/dist/services/historyService.js +9 -3
- package/dist/services/interruptService.d.ts +15 -9
- package/dist/services/interruptService.js +35 -37
- package/dist/services/nodeExecutionService.d.ts +18 -3
- package/dist/services/nodeExecutionService.js +71 -45
- package/dist/services/playgroundService.d.ts +16 -10
- package/dist/services/playgroundService.js +42 -43
- package/dist/services/portConfigApi.js +3 -6
- package/dist/services/settingsService.d.ts +9 -4
- package/dist/services/settingsService.js +23 -12
- package/dist/services/variableService.d.ts +2 -1
- package/dist/services/variableService.js +2 -2
- package/dist/services/workflowStorage.js +6 -6
- package/dist/stores/apiContext.d.ts +56 -0
- package/dist/stores/apiContext.js +80 -0
- package/dist/stores/categoriesStore.svelte.d.ts +28 -23
- package/dist/stores/categoriesStore.svelte.js +69 -64
- package/dist/stores/getInstance.svelte.d.ts +39 -0
- package/dist/stores/getInstance.svelte.js +65 -0
- package/dist/stores/historyStore.svelte.d.ts +77 -93
- package/dist/stores/historyStore.svelte.js +134 -160
- package/dist/stores/instanceContainer.svelte.d.ts +111 -0
- package/dist/stores/instanceContainer.svelte.js +114 -0
- package/dist/stores/interruptStore.svelte.d.ts +112 -82
- package/dist/stores/interruptStore.svelte.js +253 -226
- package/dist/stores/pipelinePanelStore.svelte.d.ts +27 -3
- package/dist/stores/pipelinePanelStore.svelte.js +61 -14
- package/dist/stores/playgroundStore.svelte.d.ts +169 -222
- package/dist/stores/playgroundStore.svelte.js +513 -580
- package/dist/stores/portCoordinateStore.svelte.d.ts +57 -51
- package/dist/stores/portCoordinateStore.svelte.js +109 -98
- package/dist/stores/settingsStore.svelte.d.ts +4 -1
- package/dist/stores/settingsStore.svelte.js +47 -12
- package/dist/stores/workflowStore.svelte.d.ts +178 -213
- package/dist/stores/workflowStore.svelte.js +449 -501
- package/dist/stories/EdgeDecorator.svelte +5 -2
- package/dist/stories/NodeDecorator.svelte +5 -3
- package/dist/svelte-app.d.ts +60 -10
- package/dist/svelte-app.js +159 -54
- package/dist/types/auth.d.ts +9 -51
- package/dist/types/auth.js +4 -54
- package/dist/types/events.d.ts +6 -3
- package/dist/types/index.d.ts +37 -5
- package/dist/types/index.js +0 -1
- package/dist/types/navbar.d.ts +7 -0
- package/dist/types/playground.d.ts +18 -3
- package/dist/types/settings.d.ts +13 -0
- package/dist/types/settings.js +1 -0
- package/dist/utils/colors.d.ts +47 -21
- package/dist/utils/colors.js +69 -68
- package/dist/utils/connections.d.ts +9 -15
- package/dist/utils/connections.js +13 -32
- package/dist/utils/duration.d.ts +13 -0
- package/dist/utils/duration.js +45 -0
- package/dist/utils/edgeStyling.js +9 -5
- package/dist/utils/fetchWithAuth.d.ts +36 -15
- package/dist/utils/fetchWithAuth.js +53 -23
- package/dist/utils/icons.d.ts +5 -2
- package/dist/utils/icons.js +6 -5
- package/dist/utils/nodeSwap.d.ts +6 -2
- package/dist/utils/nodeSwap.js +62 -126
- package/dist/utils/nodeTypes.d.ts +17 -8
- package/dist/utils/nodeTypes.js +27 -20
- package/dist/utils/performanceUtils.js +7 -0
- package/package.json +7 -5
- package/dist/messages/deprecation.d.ts +0 -20
- package/dist/messages/deprecation.js +0 -33
- package/dist/registry/plugin.d.ts +0 -215
- package/dist/registry/plugin.js +0 -249
- package/dist/services/api.d.ts +0 -129
- package/dist/services/api.js +0 -217
package/README.md
CHANGED
|
@@ -50,7 +50,7 @@ No vendor lock-in. No data leaving your walls. No surprise bills.
|
|
|
50
50
|
npm install @flowdrop/flowdrop
|
|
51
51
|
```
|
|
52
52
|
|
|
53
|
-
> **Note:** FlowDrop supports **
|
|
53
|
+
> **Note:** FlowDrop supports **multiple editor instances per page** — each mount gets its own isolated state container. See [Architecture Notes](#architecture-notes) for details.
|
|
54
54
|
|
|
55
55
|
You get a production-ready workflow UI. You keep full control of everything else.
|
|
56
56
|
|
|
@@ -58,11 +58,11 @@ You get a production-ready workflow UI. You keep full control of everything else
|
|
|
58
58
|
|
|
59
59
|
```svelte
|
|
60
60
|
<script lang="ts">
|
|
61
|
-
import {
|
|
61
|
+
import { App } from '@flowdrop/flowdrop';
|
|
62
62
|
import '@flowdrop/flowdrop/styles/base.css';
|
|
63
63
|
</script>
|
|
64
64
|
|
|
65
|
-
<
|
|
65
|
+
<App />
|
|
66
66
|
```
|
|
67
67
|
|
|
68
68
|
**5 lines. One fully-functional workflow editor.**
|
|
@@ -80,7 +80,7 @@ You get a production-ready workflow UI. You keep full control of everything else
|
|
|
80
80
|
|
|
81
81
|
## Architecture Notes
|
|
82
82
|
|
|
83
|
-
- **
|
|
83
|
+
- **Multiple instances per page.** Each mount gets its own `FlowDropInstance` state container (workflow, undo/redo history, playground sessions, registries, API context, drafts), so editors on the same page are fully isolated. In 2.0 there are no module-level store APIs — resolve state with `getInstance()` inside the component tree or the mount handle's `.instance` outside it. The first mount without an `instanceId` becomes the page-default instance; pass `instanceId` to additional mounts to scope their draft/panel storage keys. Theme and settings remain page-global by design.
|
|
84
84
|
- **Svelte 5 required.** FlowDrop uses Svelte 5 runes (`$state`, `$derived`, `$effect`) throughout. Svelte 4 is not supported.
|
|
85
85
|
- **Modern browsers only.** The library targets ES2020+ and does not include polyfills for older browsers.
|
|
86
86
|
|
|
@@ -112,12 +112,12 @@ FlowDrop includes a theme system with built-in light/dark support:
|
|
|
112
112
|
|
|
113
113
|
```svelte
|
|
114
114
|
<script lang="ts">
|
|
115
|
-
import {
|
|
115
|
+
import { App } from '@flowdrop/flowdrop';
|
|
116
116
|
import '@flowdrop/flowdrop/styles';
|
|
117
117
|
</script>
|
|
118
118
|
|
|
119
119
|
<!-- Built-in themes: 'default' or 'minimal' -->
|
|
120
|
-
<
|
|
120
|
+
<App theme="minimal" />
|
|
121
121
|
```
|
|
122
122
|
|
|
123
123
|
Themes bundle a visual skin (CSS token palette) with behavioral UI defaults. You can also pass a custom theme object with your own skin tokens for full control over the light and dark palettes.
|
|
@@ -136,7 +136,7 @@ const app = await mountFlowDropApp(container, {
|
|
|
136
136
|
Every user-facing string flows through a typed `Messages` tree. Pass a callback to override any subset:
|
|
137
137
|
|
|
138
138
|
```svelte
|
|
139
|
-
<
|
|
139
|
+
<App messages={() => ({ form: { schema: { save: 'Apply' } } })} />
|
|
140
140
|
```
|
|
141
141
|
|
|
142
142
|
Wire the callback to your i18n library (paraglide-js, sveltekit-i18n, etc.) — locale changes propagate automatically. See the [i18n & Custom Messages guide](https://docs.flowdrop.io/guides/i18n) for the full shape and a paraglide-js worked example.
|
|
@@ -145,20 +145,20 @@ Wire the callback to your i18n library (paraglide-js, sveltekit-i18n, etc.) —
|
|
|
145
145
|
|
|
146
146
|
FlowDrop provides tree-shakeable sub-module exports so you can import only what you need:
|
|
147
147
|
|
|
148
|
-
| Export Path | Contents
|
|
149
|
-
| ---------------------------------- |
|
|
150
|
-
| `@flowdrop/flowdrop` |
|
|
151
|
-
| `@flowdrop/flowdrop/core` | Types and utilities only (no heavy dependencies)
|
|
152
|
-
| `@flowdrop/flowdrop/editor` | WorkflowEditor, stores, services
|
|
153
|
-
| `@flowdrop/flowdrop/form` | SchemaForm, form fields, registry
|
|
154
|
-
| `@flowdrop/flowdrop/form/code` | Code editor field (CodeMirror)
|
|
155
|
-
| `@flowdrop/flowdrop/form/markdown` | Markdown editor field
|
|
156
|
-
| `@flowdrop/flowdrop/display` | MarkdownDisplay component
|
|
157
|
-
| `@flowdrop/flowdrop/playground` | Playground components and services
|
|
158
|
-
| `@flowdrop/flowdrop/settings` | SettingsPanel, stores, services
|
|
159
|
-
| `@flowdrop/flowdrop/styles` | Base CSS stylesheet
|
|
160
|
-
| `@flowdrop/flowdrop/schema` | Workflow JSON schema
|
|
161
|
-
| `@flowdrop/flowdrop/openapi` | OpenAPI spec (YAML) for the FlowDrop backend API
|
|
148
|
+
| Export Path | Contents |
|
|
149
|
+
| ---------------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
|
|
150
|
+
| `@flowdrop/flowdrop` | Slim front door: `App`, mount functions, `createFlowDropInstance`, `getInstance`, auth providers, core bootstrap types |
|
|
151
|
+
| `@flowdrop/flowdrop/core` | Types and utilities only (no heavy dependencies) |
|
|
152
|
+
| `@flowdrop/flowdrop/editor` | WorkflowEditor, stores, services |
|
|
153
|
+
| `@flowdrop/flowdrop/form` | SchemaForm, form fields, registry |
|
|
154
|
+
| `@flowdrop/flowdrop/form/code` | Code editor field (CodeMirror) |
|
|
155
|
+
| `@flowdrop/flowdrop/form/markdown` | Markdown editor field |
|
|
156
|
+
| `@flowdrop/flowdrop/display` | MarkdownDisplay component |
|
|
157
|
+
| `@flowdrop/flowdrop/playground` | Playground components and services |
|
|
158
|
+
| `@flowdrop/flowdrop/settings` | SettingsPanel, stores, services |
|
|
159
|
+
| `@flowdrop/flowdrop/styles` | Base CSS stylesheet |
|
|
160
|
+
| `@flowdrop/flowdrop/schema` | Workflow JSON schema |
|
|
161
|
+
| `@flowdrop/flowdrop/openapi` | OpenAPI spec (YAML) for the FlowDrop backend API |
|
|
162
162
|
|
|
163
163
|
### OpenAPI spec
|
|
164
164
|
|
|
@@ -170,12 +170,12 @@ The full OpenAPI spec for the FlowDrop backend API ships with the package, versi
|
|
|
170
170
|
|
|
171
171
|
```svelte
|
|
172
172
|
<script>
|
|
173
|
-
import { WorkflowEditor, NodeSidebar } from '@flowdrop/flowdrop';
|
|
173
|
+
import { WorkflowEditor, NodeSidebar } from '@flowdrop/flowdrop/editor';
|
|
174
174
|
</script>
|
|
175
175
|
|
|
176
176
|
<div class="flex h-screen">
|
|
177
177
|
<NodeSidebar {nodes} />
|
|
178
|
-
<WorkflowEditor
|
|
178
|
+
<WorkflowEditor />
|
|
179
179
|
</div>
|
|
180
180
|
```
|
|
181
181
|
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
* - External applications that want to integrate with FlowDrop
|
|
14
14
|
* - Systems that need to generate or modify workflows programmatically
|
|
15
15
|
*/
|
|
16
|
+
import { WORKFLOW_SCHEMA_VERSION } from '../schemas/index.js';
|
|
16
17
|
import { v4 as uuidv4 } from 'uuid';
|
|
17
18
|
import { generateNodeId } from '../utils/nodeIds.js';
|
|
18
19
|
/**
|
|
@@ -35,7 +36,7 @@ export class WorkflowAdapter {
|
|
|
35
36
|
nodes: [],
|
|
36
37
|
edges: [],
|
|
37
38
|
metadata: {
|
|
38
|
-
|
|
39
|
+
schemaVersion: '1.0.0',
|
|
39
40
|
createdAt: new Date().toISOString(),
|
|
40
41
|
updatedAt: new Date().toISOString()
|
|
41
42
|
}
|
|
@@ -222,13 +223,14 @@ export class WorkflowAdapter {
|
|
|
222
223
|
if (!validation.valid) {
|
|
223
224
|
throw new Error(`Invalid workflow: ${validation.errors.join(', ')}`);
|
|
224
225
|
}
|
|
225
|
-
// Update metadata
|
|
226
|
+
// Update metadata — heal legacy 1.x `version` key into `schemaVersion`.
|
|
227
|
+
const incoming = workflow.metadata;
|
|
226
228
|
workflow.metadata = {
|
|
227
|
-
|
|
228
|
-
createdAt:
|
|
229
|
+
schemaVersion: incoming?.schemaVersion || incoming?.version || '1.0.0',
|
|
230
|
+
createdAt: incoming?.createdAt || new Date().toISOString(),
|
|
229
231
|
updatedAt: new Date().toISOString(),
|
|
230
|
-
author:
|
|
231
|
-
tags:
|
|
232
|
+
author: incoming?.author,
|
|
233
|
+
tags: incoming?.tags
|
|
232
234
|
};
|
|
233
235
|
return workflow;
|
|
234
236
|
}
|
|
@@ -291,7 +293,11 @@ export class WorkflowAdapter {
|
|
|
291
293
|
sourceHandle: edge.sourceHandle,
|
|
292
294
|
targetHandle: edge.targetHandle
|
|
293
295
|
})),
|
|
294
|
-
metadata: workflow.metadata
|
|
296
|
+
metadata: workflow.metadata ?? {
|
|
297
|
+
schemaVersion: WORKFLOW_SCHEMA_VERSION,
|
|
298
|
+
createdAt: new Date().toISOString(),
|
|
299
|
+
updatedAt: new Date().toISOString()
|
|
300
|
+
}
|
|
295
301
|
};
|
|
296
302
|
}
|
|
297
303
|
/**
|
|
@@ -337,7 +343,7 @@ export class WorkflowAdapter {
|
|
|
337
343
|
cloned.id = uuidv4();
|
|
338
344
|
cloned.name = newName || `${workflow.name} (Copy)`;
|
|
339
345
|
cloned.metadata = {
|
|
340
|
-
|
|
346
|
+
schemaVersion: cloned.metadata?.schemaVersion || '1.0.0',
|
|
341
347
|
createdAt: new Date().toISOString(),
|
|
342
348
|
updatedAt: new Date().toISOString(),
|
|
343
349
|
author: cloned.metadata?.author,
|
|
@@ -13,7 +13,7 @@ import { getComponentTypeDefaults, extractComponentType, AGENTSPEC_NAMESPACE } f
|
|
|
13
13
|
import { computeAutoLayout } from './autoLayout.js';
|
|
14
14
|
import { v4 as uuidv4 } from 'uuid';
|
|
15
15
|
import { logger } from '../../utils/logger.js';
|
|
16
|
-
import { buildHandleId, extractPortId
|
|
16
|
+
import { buildHandleId, extractPortId } from '../../utils/handleIds.js';
|
|
17
17
|
// ============================================================================
|
|
18
18
|
// Property ↔ Port Conversion
|
|
19
19
|
// ============================================================================
|
|
@@ -138,7 +138,7 @@ export class AgentSpecAdapter {
|
|
|
138
138
|
}
|
|
139
139
|
}
|
|
140
140
|
// Find start node
|
|
141
|
-
const startNodeName = this.findStartNodeName(agentSpecNodes
|
|
141
|
+
const startNodeName = this.findStartNodeName(agentSpecNodes);
|
|
142
142
|
return {
|
|
143
143
|
component_type: 'flow',
|
|
144
144
|
name: workflow.name,
|
|
@@ -149,7 +149,7 @@ export class AgentSpecAdapter {
|
|
|
149
149
|
data_flow_connections: dataFlowEdges.length > 0 ? dataFlowEdges : null,
|
|
150
150
|
metadata: {
|
|
151
151
|
'flowdrop:workflow_id': workflow.id,
|
|
152
|
-
'flowdrop:version': workflow.metadata?.
|
|
152
|
+
'flowdrop:version': workflow.metadata?.schemaVersion,
|
|
153
153
|
...(workflow.metadata?.author ? { 'flowdrop:author': workflow.metadata.author } : {}),
|
|
154
154
|
...(workflow.metadata?.tags ? { 'flowdrop:tags': workflow.metadata.tags } : {})
|
|
155
155
|
}
|
|
@@ -196,7 +196,7 @@ export class AgentSpecAdapter {
|
|
|
196
196
|
const edges = [];
|
|
197
197
|
// Control-flow edges → trigger port connections
|
|
198
198
|
for (const cfEdge of agentSpecFlow.control_flow_connections) {
|
|
199
|
-
const edge = this.convertFromControlFlowEdge(cfEdge, nameToNodeId
|
|
199
|
+
const edge = this.convertFromControlFlowEdge(cfEdge, nameToNodeId);
|
|
200
200
|
if (edge)
|
|
201
201
|
edges.push(edge);
|
|
202
202
|
}
|
|
@@ -215,7 +215,7 @@ export class AgentSpecAdapter {
|
|
|
215
215
|
nodes,
|
|
216
216
|
edges,
|
|
217
217
|
metadata: {
|
|
218
|
-
|
|
218
|
+
schemaVersion: agentSpecFlow.metadata?.['flowdrop:version'] || '1.0.0',
|
|
219
219
|
createdAt: new Date().toISOString(),
|
|
220
220
|
updatedAt: new Date().toISOString(),
|
|
221
221
|
author: agentSpecFlow.metadata?.['flowdrop:author'],
|
|
@@ -578,7 +578,7 @@ export class AgentSpecAdapter {
|
|
|
578
578
|
/**
|
|
579
579
|
* Convert an Agent Spec ControlFlowEdge to a FlowDrop edge.
|
|
580
580
|
*/
|
|
581
|
-
convertFromControlFlowEdge(cfEdge, nameToNodeId
|
|
581
|
+
convertFromControlFlowEdge(cfEdge, nameToNodeId) {
|
|
582
582
|
const sourceId = nameToNodeId.get(cfEdge.from_node);
|
|
583
583
|
const targetId = nameToNodeId.get(cfEdge.to_node);
|
|
584
584
|
if (!sourceId || !targetId)
|
|
@@ -615,7 +615,7 @@ export class AgentSpecAdapter {
|
|
|
615
615
|
/**
|
|
616
616
|
* Find the start node name from converted Agent Spec nodes.
|
|
617
617
|
*/
|
|
618
|
-
findStartNodeName(nodes
|
|
618
|
+
findStartNodeName(nodes) {
|
|
619
619
|
// Look for an explicit start_node
|
|
620
620
|
const startNode = nodes.find((n) => n.component_type === 'start_node');
|
|
621
621
|
if (startNode)
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*
|
|
6
6
|
* @module api/enhanced-client
|
|
7
7
|
*/
|
|
8
|
-
import { buildEndpointUrl, getEndpointMethod,
|
|
8
|
+
import { buildEndpointUrl, getEndpointMethod, getRequestHeaders } from '../config/endpoints.js';
|
|
9
9
|
import { NoAuthProvider } from '../types/auth.js';
|
|
10
10
|
import { getApiSettings } from '../stores/settingsStore.svelte.js';
|
|
11
11
|
import { logger } from '../utils/logger.js';
|
|
@@ -56,15 +56,12 @@ export class EnhancedFlowDropApiClient {
|
|
|
56
56
|
async request(endpointKey, endpointPath, params, options = {}, operation = 'API request') {
|
|
57
57
|
const url = buildEndpointUrl(this.config, endpointPath, params);
|
|
58
58
|
const method = options.method ?? getEndpointMethod(this.config, endpointKey);
|
|
59
|
-
const configHeaders = getEndpointHeaders(this.config, endpointKey);
|
|
60
59
|
// Get user settings for timeout and retry
|
|
61
60
|
const userApiSettings = getApiSettings();
|
|
62
|
-
//
|
|
63
|
-
|
|
64
|
-
// Merge headers: config headers < auth headers < request-specific headers
|
|
61
|
+
// Merge headers via the shared path: static endpoint headers < auth headers
|
|
62
|
+
// < request-specific headers.
|
|
65
63
|
const headers = {
|
|
66
|
-
...
|
|
67
|
-
...authHeaders,
|
|
64
|
+
...(await getRequestHeaders(this.config, endpointKey, this.authProvider)),
|
|
68
65
|
...options.headers
|
|
69
66
|
};
|
|
70
67
|
// Create AbortController for timeout
|
|
@@ -93,11 +90,9 @@ export class EnhancedFlowDropApiClient {
|
|
|
93
90
|
if (this.authProvider.onUnauthorized) {
|
|
94
91
|
const refreshed = await this.authProvider.onUnauthorized();
|
|
95
92
|
if (refreshed && attempt < maxAttempts) {
|
|
96
|
-
//
|
|
97
|
-
const newAuthHeaders = await this.authProvider.getAuthHeaders();
|
|
93
|
+
// Rebuild headers via the shared path to pick up the fresh token.
|
|
98
94
|
fetchConfig.headers = {
|
|
99
|
-
...
|
|
100
|
-
...newAuthHeaders,
|
|
95
|
+
...(await getRequestHeaders(this.config, endpointKey, this.authProvider)),
|
|
101
96
|
...options.headers
|
|
102
97
|
};
|
|
103
98
|
continue; // Retry with new headers
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Batch retry feedback for the AI Assistant.
|
|
3
|
+
*
|
|
4
|
+
* When a batch of DSL commands finishes with failures — some couldn't be
|
|
5
|
+
* parsed, or one failed to execute and the batch rolled back — the assistant
|
|
6
|
+
* needs concrete, specific feedback to self-correct. This module builds that
|
|
7
|
+
* message.
|
|
8
|
+
*
|
|
9
|
+
* Specificity is the point: the parse-error feedback names the offending text
|
|
10
|
+
* and the exact parser reason. The old generic "provide corrected commands"
|
|
11
|
+
* ask is what made auto-retry on parse errors loop on the same malformed shape
|
|
12
|
+
* — so it was disabled. Pinpointing the failure makes re-enabling it safe.
|
|
13
|
+
*
|
|
14
|
+
* @module chat/batchFeedback
|
|
15
|
+
*/
|
|
16
|
+
/** A command that could not be parsed, with the reason and its raw text. */
|
|
17
|
+
export interface ParseFailure {
|
|
18
|
+
raw: string;
|
|
19
|
+
error: string;
|
|
20
|
+
}
|
|
21
|
+
/** Summary of how a batch finished, used to build retry feedback. */
|
|
22
|
+
export interface BatchOutcome {
|
|
23
|
+
/** Number of commands that executed successfully before stopping. */
|
|
24
|
+
completedCount: number;
|
|
25
|
+
/** Error from the first command that failed to execute, if any. */
|
|
26
|
+
executionError?: string;
|
|
27
|
+
/** Whether the executed commands were rolled back (atomic execution failure). */
|
|
28
|
+
rolledBack: boolean;
|
|
29
|
+
/** Commands that could not be parsed and were skipped. */
|
|
30
|
+
parseErrors: ParseFailure[];
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Build feedback for the assistant after a batch finished with failures.
|
|
34
|
+
*
|
|
35
|
+
* Pinpoints *what* went wrong — the specific parser error and offending text
|
|
36
|
+
* for unparseable commands, and/or the execution error — so the assistant has
|
|
37
|
+
* a concrete, different target to correct.
|
|
38
|
+
*/
|
|
39
|
+
export declare function buildRetryFeedback(outcome: BatchOutcome): string;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Batch retry feedback for the AI Assistant.
|
|
3
|
+
*
|
|
4
|
+
* When a batch of DSL commands finishes with failures — some couldn't be
|
|
5
|
+
* parsed, or one failed to execute and the batch rolled back — the assistant
|
|
6
|
+
* needs concrete, specific feedback to self-correct. This module builds that
|
|
7
|
+
* message.
|
|
8
|
+
*
|
|
9
|
+
* Specificity is the point: the parse-error feedback names the offending text
|
|
10
|
+
* and the exact parser reason. The old generic "provide corrected commands"
|
|
11
|
+
* ask is what made auto-retry on parse errors loop on the same malformed shape
|
|
12
|
+
* — so it was disabled. Pinpointing the failure makes re-enabling it safe.
|
|
13
|
+
*
|
|
14
|
+
* @module chat/batchFeedback
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* Build feedback for the assistant after a batch finished with failures.
|
|
18
|
+
*
|
|
19
|
+
* Pinpoints *what* went wrong — the specific parser error and offending text
|
|
20
|
+
* for unparseable commands, and/or the execution error — so the assistant has
|
|
21
|
+
* a concrete, different target to correct.
|
|
22
|
+
*/
|
|
23
|
+
export function buildRetryFeedback(outcome) {
|
|
24
|
+
const { completedCount, executionError, rolledBack, parseErrors } = outcome;
|
|
25
|
+
const lines = [];
|
|
26
|
+
if (executionError) {
|
|
27
|
+
lines.push(`A command failed to execute: ${executionError}`);
|
|
28
|
+
lines.push(rolledBack && completedCount > 0
|
|
29
|
+
? `The ${completedCount} command(s) that had succeeded were rolled back, so no changes were applied.`
|
|
30
|
+
: 'No changes were applied.');
|
|
31
|
+
}
|
|
32
|
+
else if (completedCount > 0) {
|
|
33
|
+
lines.push(`${completedCount} command(s) were applied successfully.`);
|
|
34
|
+
}
|
|
35
|
+
if (parseErrors.length > 0) {
|
|
36
|
+
lines.push(`\n${parseErrors.length} command(s) could not be parsed and were skipped:`);
|
|
37
|
+
for (const pe of parseErrors) {
|
|
38
|
+
const firstLine = pe.raw.split('\n')[0];
|
|
39
|
+
const preview = pe.raw.includes('\n') ? `${firstLine} …` : firstLine;
|
|
40
|
+
lines.push(` • ${preview}\n reason: ${pe.error}`);
|
|
41
|
+
}
|
|
42
|
+
lines.push('\nNote: multiline values must close with """ on its own line.');
|
|
43
|
+
}
|
|
44
|
+
if (rolledBack) {
|
|
45
|
+
lines.push('\nPlease re-send the full corrected batch to achieve the original goal.');
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
lines.push('\nThe successful changes are reflected in the current workflow state. Re-send only corrected versions of the skipped command(s).');
|
|
49
|
+
}
|
|
50
|
+
return lines.join('\n');
|
|
51
|
+
}
|
|
@@ -888,17 +888,31 @@ function executeSwapNode(command, context) {
|
|
|
888
888
|
edges: swapResult.updatedEdges
|
|
889
889
|
});
|
|
890
890
|
}
|
|
891
|
+
// Name each dropped edge so the user can see exactly what was lost
|
|
892
|
+
const droppedEdgeDetails = preview.droppedEdges.map(({ edge }) => {
|
|
893
|
+
const sourcePort = extractPortId(edge.sourceHandle ?? undefined) ?? '?';
|
|
894
|
+
const targetPort = extractPortId(edge.targetHandle ?? undefined) ?? '?';
|
|
895
|
+
return `${toShortId(edge.source)}:${sourcePort} → ${toShortId(edge.target)}:${targetPort}`;
|
|
896
|
+
});
|
|
891
897
|
const resultData = {
|
|
892
898
|
oldNodeId: toShortId(node.id),
|
|
893
899
|
newNodeId: toShortId(preview.newNodeId),
|
|
894
900
|
newType: command.newTypeId,
|
|
895
901
|
keptEdges: preview.keptEdges.length,
|
|
896
902
|
droppedEdges: preview.droppedEdges.length,
|
|
903
|
+
droppedEdgeDetails,
|
|
897
904
|
hasDataLoss: preview.hasDataLoss,
|
|
898
905
|
configCarriedOver: preview.configCarriedOver,
|
|
899
906
|
configReset: preview.configReset
|
|
900
907
|
};
|
|
901
|
-
|
|
908
|
+
// Cap the inline list — a badly mismatched swap can drop dozens of edges,
|
|
909
|
+
// and the full list is always available in resultData.droppedEdgeDetails
|
|
910
|
+
const MAX_NAMED_DROPPED_EDGES = 5;
|
|
911
|
+
const namedDropped = droppedEdgeDetails.slice(0, MAX_NAMED_DROPPED_EDGES);
|
|
912
|
+
const unnamedCount = droppedEdgeDetails.length - namedDropped.length;
|
|
913
|
+
const droppedMsg = preview.droppedEdges.length > 0
|
|
914
|
+
? ` (${preview.droppedEdges.length} edge(s) dropped: ${namedDropped.join(', ')}${unnamedCount > 0 ? `, … and ${unnamedCount} more` : ''})`
|
|
915
|
+
: '';
|
|
902
916
|
return {
|
|
903
917
|
ok: true,
|
|
904
918
|
message: `Swapped ${toShortId(node.id)} → ${toShortId(preview.newNodeId)} (${command.newTypeId})${droppedMsg}`,
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Bridges the command system to the live Svelte stores.
|
|
5
5
|
* This is the only Svelte-coupled file in commands/.
|
|
6
6
|
*/
|
|
7
|
+
import { type FlowDropInstance } from '../stores/instanceContainer.svelte.js';
|
|
7
8
|
import { type CommandContext, type UIAction } from './types.js';
|
|
8
9
|
import type { NodeMetadata } from '../types/index.js';
|
|
9
10
|
/**
|
|
@@ -11,6 +12,8 @@ import type { NodeMetadata } from '../types/index.js';
|
|
|
11
12
|
*
|
|
12
13
|
* @param nodeTypes - Available node type definitions
|
|
13
14
|
* @param onUIAction - Optional callback for UI-side actions (open config panel, select node)
|
|
15
|
+
* @param instance - The FlowDrop instance to operate on; defaults to the
|
|
16
|
+
* page-default instance when omitted
|
|
14
17
|
* @returns CommandContext connected to live stores, or null if no workflow is loaded
|
|
15
18
|
*/
|
|
16
|
-
export declare function createStoreCommandContext(nodeTypes: NodeMetadata[], onUIAction?: (action: UIAction) => void): CommandContext | null;
|
|
19
|
+
export declare function createStoreCommandContext(nodeTypes: NodeMetadata[], onUIAction?: (action: UIAction) => void, instance?: FlowDropInstance): CommandContext | null;
|
|
@@ -4,62 +4,67 @@
|
|
|
4
4
|
* Bridges the command system to the live Svelte stores.
|
|
5
5
|
* This is the only Svelte-coupled file in commands/.
|
|
6
6
|
*/
|
|
7
|
-
import {
|
|
8
|
-
import { historyService } from '../services/historyService.js';
|
|
7
|
+
import { getDefaultInstance } from '../stores/instanceContainer.svelte.js';
|
|
9
8
|
import { buildTypeMap } from './types.js';
|
|
10
9
|
/**
|
|
11
10
|
* Creates a CommandContext that bridges the command system to the live Svelte stores.
|
|
12
11
|
*
|
|
13
12
|
* @param nodeTypes - Available node type definitions
|
|
14
13
|
* @param onUIAction - Optional callback for UI-side actions (open config panel, select node)
|
|
14
|
+
* @param instance - The FlowDrop instance to operate on; defaults to the
|
|
15
|
+
* page-default instance when omitted
|
|
15
16
|
* @returns CommandContext connected to live stores, or null if no workflow is loaded
|
|
16
17
|
*/
|
|
17
|
-
export function createStoreCommandContext(nodeTypes, onUIAction) {
|
|
18
|
-
const
|
|
18
|
+
export function createStoreCommandContext(nodeTypes, onUIAction, instance) {
|
|
19
|
+
const fd = instance ?? getDefaultInstance();
|
|
20
|
+
const readWorkflow = () => fd.workflow.current;
|
|
21
|
+
const actions = fd.workflow.actions;
|
|
22
|
+
const history = fd.history;
|
|
23
|
+
const workflow = readWorkflow();
|
|
19
24
|
if (!workflow) {
|
|
20
25
|
return null;
|
|
21
26
|
}
|
|
22
27
|
const dispatch = {
|
|
23
|
-
addNode: (node) =>
|
|
24
|
-
removeNode: (nodeId) =>
|
|
25
|
-
updateNode: (nodeId, updates) =>
|
|
26
|
-
addEdge: (edge) =>
|
|
27
|
-
removeEdge: (edgeId) =>
|
|
28
|
-
batchUpdate: (updates) =>
|
|
28
|
+
addNode: (node) => actions.addNode(node),
|
|
29
|
+
removeNode: (nodeId) => actions.removeNode(nodeId),
|
|
30
|
+
updateNode: (nodeId, updates) => actions.updateNode(nodeId, updates),
|
|
31
|
+
addEdge: (edge) => actions.addEdge(edge),
|
|
32
|
+
removeEdge: (edgeId) => actions.removeEdge(edgeId),
|
|
33
|
+
batchUpdate: (updates) => actions.batchUpdate(updates),
|
|
29
34
|
undo: () => {
|
|
30
|
-
const previousState =
|
|
35
|
+
const previousState = history.undo();
|
|
31
36
|
if (previousState) {
|
|
32
|
-
|
|
37
|
+
actions.restoreFromHistory(previousState);
|
|
33
38
|
return true;
|
|
34
39
|
}
|
|
35
40
|
return false;
|
|
36
41
|
},
|
|
37
42
|
redo: () => {
|
|
38
|
-
const nextState =
|
|
43
|
+
const nextState = history.redo();
|
|
39
44
|
if (nextState) {
|
|
40
|
-
|
|
45
|
+
actions.restoreFromHistory(nextState);
|
|
41
46
|
return true;
|
|
42
47
|
}
|
|
43
48
|
return false;
|
|
44
49
|
},
|
|
45
50
|
startTransaction: (description) => {
|
|
46
|
-
const currentWorkflow =
|
|
51
|
+
const currentWorkflow = readWorkflow();
|
|
47
52
|
if (currentWorkflow) {
|
|
48
|
-
|
|
53
|
+
history.startTransaction(currentWorkflow, description);
|
|
49
54
|
}
|
|
50
55
|
},
|
|
51
|
-
commitTransaction: () =>
|
|
56
|
+
commitTransaction: () => history.commitTransaction(),
|
|
52
57
|
cancelTransaction: () => {
|
|
53
|
-
const snapshot =
|
|
58
|
+
const snapshot = history.cancelTransaction();
|
|
54
59
|
if (snapshot) {
|
|
55
|
-
|
|
60
|
+
actions.restoreFromHistory(snapshot);
|
|
56
61
|
}
|
|
57
62
|
},
|
|
58
63
|
emitUIAction: onUIAction,
|
|
59
|
-
swapNode: (updates) =>
|
|
64
|
+
swapNode: (updates) => actions.swapNode(updates)
|
|
60
65
|
};
|
|
61
66
|
return {
|
|
62
|
-
getWorkflow: () =>
|
|
67
|
+
getWorkflow: () => readWorkflow(),
|
|
63
68
|
nodeTypes,
|
|
64
69
|
typeMap: buildTypeMap(nodeTypes),
|
|
65
70
|
dispatch
|
package/dist/commands/types.d.ts
CHANGED
|
@@ -244,6 +244,8 @@ export interface SwapNodeResultData {
|
|
|
244
244
|
newType: string;
|
|
245
245
|
keptEdges: number;
|
|
246
246
|
droppedEdges: number;
|
|
247
|
+
/** Human-readable descriptions of each dropped edge, e.g. "node.1:text → node.2:message" */
|
|
248
|
+
droppedEdgeDetails: string[];
|
|
247
249
|
hasDataLoss: boolean;
|
|
248
250
|
configCarriedOver: string[];
|
|
249
251
|
configReset: string[];
|