@d34dman/flowdrop 0.0.56 → 0.0.58

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/README.md +4 -4
  2. package/dist/adapters/WorkflowAdapter.d.ts +2 -1
  3. package/dist/adapters/agentspec/AgentSpecAdapter.d.ts +96 -0
  4. package/dist/adapters/agentspec/AgentSpecAdapter.js +663 -0
  5. package/dist/adapters/agentspec/agentAdapter.d.ts +59 -0
  6. package/dist/adapters/agentspec/agentAdapter.js +91 -0
  7. package/dist/adapters/agentspec/autoLayout.d.ts +34 -0
  8. package/dist/adapters/agentspec/autoLayout.js +127 -0
  9. package/dist/adapters/agentspec/componentTypeDefaults.d.ts +73 -0
  10. package/dist/adapters/agentspec/componentTypeDefaults.js +238 -0
  11. package/dist/adapters/agentspec/defaultNodeTypes.d.ts +53 -0
  12. package/dist/adapters/agentspec/defaultNodeTypes.js +561 -0
  13. package/dist/adapters/agentspec/index.d.ts +37 -0
  14. package/dist/adapters/agentspec/index.js +39 -0
  15. package/dist/adapters/agentspec/validator.d.ts +34 -0
  16. package/dist/adapters/agentspec/validator.js +169 -0
  17. package/dist/components/App.svelte +57 -13
  18. package/dist/components/ConfigForm.svelte +46 -12
  19. package/dist/components/ConfigForm.svelte.d.ts +8 -0
  20. package/dist/components/NodeSidebar.svelte +20 -8
  21. package/dist/components/NodeSidebar.svelte.d.ts +2 -1
  22. package/dist/components/SchemaForm.svelte +34 -12
  23. package/dist/components/SchemaForm.svelte.d.ts +8 -0
  24. package/dist/components/WorkflowEditor.svelte +14 -13
  25. package/dist/components/form/FormFieldset.svelte +142 -0
  26. package/dist/components/form/FormFieldset.svelte.d.ts +11 -0
  27. package/dist/components/form/FormMarkdownEditor.svelte +546 -422
  28. package/dist/components/form/FormMarkdownEditor.svelte.d.ts +2 -0
  29. package/dist/components/form/FormUISchemaRenderer.svelte +136 -0
  30. package/dist/components/form/FormUISchemaRenderer.svelte.d.ts +32 -0
  31. package/dist/components/form/index.d.ts +2 -0
  32. package/dist/components/form/index.js +3 -0
  33. package/dist/components/form/types.d.ts +1 -1
  34. package/dist/components/nodes/WorkflowNode.svelte +1 -2
  35. package/dist/config/agentSpecEndpoints.d.ts +70 -0
  36. package/dist/config/agentSpecEndpoints.js +65 -0
  37. package/dist/config/endpoints.d.ts +6 -0
  38. package/dist/core/index.d.ts +29 -3
  39. package/dist/core/index.js +31 -1
  40. package/dist/form/code.js +6 -1
  41. package/dist/form/fieldRegistry.d.ts +79 -15
  42. package/dist/form/fieldRegistry.js +104 -49
  43. package/dist/form/full.d.ts +2 -2
  44. package/dist/form/full.js +2 -2
  45. package/dist/form/index.d.ts +5 -3
  46. package/dist/form/index.js +9 -2
  47. package/dist/form/markdown.d.ts +3 -3
  48. package/dist/form/markdown.js +8 -4
  49. package/dist/helpers/workflowEditorHelper.d.ts +24 -0
  50. package/dist/helpers/workflowEditorHelper.js +55 -0
  51. package/dist/index.d.ts +2 -2
  52. package/dist/index.js +2 -2
  53. package/dist/registry/BaseRegistry.d.ts +92 -0
  54. package/dist/registry/BaseRegistry.js +124 -0
  55. package/dist/registry/builtinFormats.d.ts +23 -0
  56. package/dist/registry/builtinFormats.js +70 -0
  57. package/dist/registry/builtinNodes.js +4 -0
  58. package/dist/registry/index.d.ts +2 -1
  59. package/dist/registry/index.js +2 -0
  60. package/dist/registry/nodeComponentRegistry.d.ts +26 -57
  61. package/dist/registry/nodeComponentRegistry.js +29 -82
  62. package/dist/registry/workflowFormatRegistry.d.ts +122 -0
  63. package/dist/registry/workflowFormatRegistry.js +96 -0
  64. package/dist/schema/index.d.ts +23 -0
  65. package/dist/schema/index.js +23 -0
  66. package/dist/services/agentSpecExecutionService.d.ts +106 -0
  67. package/dist/services/agentSpecExecutionService.js +333 -0
  68. package/dist/stores/portCoordinateStore.js +1 -4
  69. package/dist/stores/workflowStore.d.ts +3 -0
  70. package/dist/stores/workflowStore.js +3 -0
  71. package/dist/svelte-app.d.ts +4 -0
  72. package/dist/svelte-app.js +9 -1
  73. package/dist/types/agentspec.d.ts +318 -0
  74. package/dist/types/agentspec.js +48 -0
  75. package/dist/types/events.d.ts +28 -1
  76. package/dist/types/index.d.ts +31 -0
  77. package/dist/types/index.js +5 -0
  78. package/dist/types/uischema.d.ts +144 -0
  79. package/dist/types/uischema.js +51 -0
  80. package/dist/utils/uischema.d.ts +52 -0
  81. package/dist/utils/uischema.js +88 -0
  82. package/package.json +231 -225
  83. package/schemas/v1/workflow.schema.json +952 -0
@@ -0,0 +1,333 @@
1
+ /**
2
+ * Agent Spec Execution Service
3
+ *
4
+ * Connects FlowDrop to Agent Spec runtimes (WayFlow/PyAgentSpec) for
5
+ * workflow execution, status tracking, and result retrieval.
6
+ *
7
+ * Follows the same singleton pattern as NodeExecutionService.
8
+ */
9
+ import { buildAgentSpecUrl, getAgentSpecAuthHeaders } from '../config/agentSpecEndpoints.js';
10
+ import { AgentSpecAdapter } from '../adapters/agentspec/AgentSpecAdapter.js';
11
+ /**
12
+ * Service for executing FlowDrop workflows on Agent Spec runtimes.
13
+ *
14
+ * @example
15
+ * ```typescript
16
+ * const service = AgentSpecExecutionService.getInstance();
17
+ * service.configure(myRuntimeConfig);
18
+ *
19
+ * // Check runtime availability
20
+ * const healthy = await service.checkHealth();
21
+ *
22
+ * // Execute a workflow
23
+ * const handle = await service.executeWorkflow(workflow, inputs, {
24
+ * onNodeUpdate: (nodeId, info) => updateNodeVisual(nodeId, info),
25
+ * onComplete: (results) => showResults(results),
26
+ * onError: (error) => showError(error)
27
+ * });
28
+ *
29
+ * // Cancel if needed
30
+ * await service.cancelExecution(handle.executionId);
31
+ * ```
32
+ */
33
+ export class AgentSpecExecutionService {
34
+ static instance;
35
+ config = null;
36
+ adapter;
37
+ activeExecutions = new Map();
38
+ constructor() {
39
+ this.adapter = new AgentSpecAdapter();
40
+ }
41
+ static getInstance() {
42
+ if (!AgentSpecExecutionService.instance) {
43
+ AgentSpecExecutionService.instance = new AgentSpecExecutionService();
44
+ }
45
+ return AgentSpecExecutionService.instance;
46
+ }
47
+ /**
48
+ * Configure the runtime connection.
49
+ */
50
+ configure(config) {
51
+ this.config = config;
52
+ }
53
+ /**
54
+ * Check if the service has been configured with a runtime.
55
+ */
56
+ isConfigured() {
57
+ return this.config !== null;
58
+ }
59
+ /**
60
+ * Check runtime health.
61
+ */
62
+ async checkHealth() {
63
+ if (!this.config)
64
+ return false;
65
+ try {
66
+ const url = buildAgentSpecUrl(this.config, this.config.endpoints.health);
67
+ const response = await fetch(url, {
68
+ headers: getAgentSpecAuthHeaders(this.config),
69
+ signal: AbortSignal.timeout(5000)
70
+ });
71
+ return response.ok;
72
+ }
73
+ catch {
74
+ return false;
75
+ }
76
+ }
77
+ /**
78
+ * Execute a FlowDrop workflow on the Agent Spec runtime.
79
+ *
80
+ * 1. Converts StandardWorkflow → AgentSpecFlow using the adapter
81
+ * 2. POSTs the flow JSON to the runtime
82
+ * 3. Starts polling for execution status
83
+ * 4. Maps runtime node statuses to FlowDrop's NodeExecutionInfo
84
+ */
85
+ async executeWorkflow(workflow, inputs, callbacks, pollingIntervalMs = 2000) {
86
+ this.ensureConfigured();
87
+ // Convert to Agent Spec format
88
+ const agentSpecFlow = this.adapter.toAgentSpec(workflow);
89
+ // POST to runtime
90
+ const url = buildAgentSpecUrl(this.getConfig(), this.getConfig().endpoints.execute);
91
+ const response = await fetch(url, {
92
+ method: 'POST',
93
+ headers: getAgentSpecAuthHeaders(this.getConfig()),
94
+ body: JSON.stringify({
95
+ flow: agentSpecFlow,
96
+ inputs: inputs || {}
97
+ }),
98
+ signal: AbortSignal.timeout(this.getConfig().timeout || 60000)
99
+ });
100
+ if (!response.ok) {
101
+ const errorText = await response.text().catch(() => 'Unknown error');
102
+ throw new Error(`Agent Spec runtime error (${response.status}): ${errorText}`);
103
+ }
104
+ const result = await response.json();
105
+ const executionId = result.execution_id || result.id;
106
+ if (!executionId) {
107
+ throw new Error('Runtime did not return an execution ID');
108
+ }
109
+ // Track execution
110
+ const state = {
111
+ id: executionId,
112
+ status: 'running',
113
+ startedAt: new Date().toISOString(),
114
+ nodeStatuses: {}
115
+ };
116
+ this.activeExecutions.set(executionId, state);
117
+ // Build node name → FlowDrop node ID mapping for status updates
118
+ const nameToNodeId = new Map();
119
+ for (const node of workflow.nodes) {
120
+ const label = node.data.label || node.id;
121
+ nameToNodeId.set(label, node.id);
122
+ }
123
+ // Start polling
124
+ const stop = () => this.stopPolling(executionId);
125
+ if (callbacks) {
126
+ this.startPolling(executionId, nameToNodeId, callbacks.onNodeUpdate, callbacks.onComplete, callbacks.onError, pollingIntervalMs);
127
+ }
128
+ return { executionId, stop };
129
+ }
130
+ /**
131
+ * Get current execution status.
132
+ */
133
+ async getExecutionStatus(executionId) {
134
+ this.ensureConfigured();
135
+ try {
136
+ const url = buildAgentSpecUrl(this.getConfig(), this.getConfig().endpoints.status, {
137
+ id: executionId
138
+ });
139
+ const response = await fetch(url, {
140
+ headers: getAgentSpecAuthHeaders(this.getConfig())
141
+ });
142
+ if (!response.ok)
143
+ return null;
144
+ const data = await response.json();
145
+ return this.mapRuntimeStatusToNodeInfo(data);
146
+ }
147
+ catch {
148
+ return null;
149
+ }
150
+ }
151
+ /**
152
+ * Cancel a running execution.
153
+ */
154
+ async cancelExecution(executionId) {
155
+ this.ensureConfigured();
156
+ this.stopPolling(executionId);
157
+ const url = buildAgentSpecUrl(this.getConfig(), this.getConfig().endpoints.cancel, {
158
+ id: executionId
159
+ });
160
+ await fetch(url, {
161
+ method: 'POST',
162
+ headers: getAgentSpecAuthHeaders(this.getConfig())
163
+ });
164
+ const state = this.activeExecutions.get(executionId);
165
+ if (state) {
166
+ state.status = 'cancelled';
167
+ }
168
+ }
169
+ /**
170
+ * Get execution results.
171
+ */
172
+ async getResults(executionId) {
173
+ this.ensureConfigured();
174
+ try {
175
+ const url = buildAgentSpecUrl(this.getConfig(), this.getConfig().endpoints.results, {
176
+ id: executionId
177
+ });
178
+ const response = await fetch(url, {
179
+ headers: getAgentSpecAuthHeaders(this.getConfig())
180
+ });
181
+ if (!response.ok)
182
+ return null;
183
+ return await response.json();
184
+ }
185
+ catch {
186
+ return null;
187
+ }
188
+ }
189
+ /**
190
+ * Validate a workflow against the runtime.
191
+ */
192
+ async validateOnRuntime(workflow) {
193
+ this.ensureConfigured();
194
+ const agentSpecFlow = this.adapter.toAgentSpec(workflow);
195
+ const url = buildAgentSpecUrl(this.getConfig(), this.getConfig().endpoints.validate);
196
+ const response = await fetch(url, {
197
+ method: 'POST',
198
+ headers: getAgentSpecAuthHeaders(this.getConfig()),
199
+ body: JSON.stringify(agentSpecFlow)
200
+ });
201
+ if (!response.ok) {
202
+ return { valid: false, errors: [`Runtime validation failed: ${response.status}`] };
203
+ }
204
+ return await response.json();
205
+ }
206
+ /**
207
+ * Clean up all active executions.
208
+ */
209
+ destroy() {
210
+ for (const [id] of this.activeExecutions) {
211
+ this.stopPolling(id);
212
+ }
213
+ this.activeExecutions.clear();
214
+ }
215
+ // ========================================================================
216
+ // Private
217
+ // ========================================================================
218
+ ensureConfigured() {
219
+ if (!this.config) {
220
+ throw new Error('AgentSpecExecutionService not configured. Call configure() with runtime endpoint config first.');
221
+ }
222
+ }
223
+ /** Get the config, throwing if not configured */
224
+ getConfig() {
225
+ this.ensureConfigured();
226
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
227
+ return this.config;
228
+ }
229
+ startPolling(executionId, nameToNodeId, onNodeUpdate, onComplete, onError, intervalMs = 2000) {
230
+ const state = this.activeExecutions.get(executionId);
231
+ if (!state)
232
+ return;
233
+ const poll = async () => {
234
+ try {
235
+ const url = buildAgentSpecUrl(this.getConfig(), this.getConfig().endpoints.status, {
236
+ id: executionId
237
+ });
238
+ const response = await fetch(url, {
239
+ headers: getAgentSpecAuthHeaders(this.getConfig())
240
+ });
241
+ if (!response.ok) {
242
+ throw new Error(`Status check failed: ${response.status}`);
243
+ }
244
+ const data = await response.json();
245
+ const executionStatus = data.status || data.execution_status;
246
+ // Map node statuses
247
+ const nodeStatuses = data.node_statuses || data.nodes || {};
248
+ for (const [nodeName, status] of Object.entries(nodeStatuses)) {
249
+ const nodeId = nameToNodeId.get(nodeName) || nodeName;
250
+ const info = this.mapSingleNodeStatus(status);
251
+ state.nodeStatuses[nodeId] = info;
252
+ onNodeUpdate?.(nodeId, info);
253
+ }
254
+ // Check if execution is done
255
+ if (executionStatus === 'completed' || executionStatus === 'success') {
256
+ state.status = 'completed';
257
+ this.stopPolling(executionId);
258
+ const results = await this.getResults(executionId);
259
+ onComplete?.(results || {});
260
+ }
261
+ else if (executionStatus === 'failed' || executionStatus === 'error') {
262
+ state.status = 'failed';
263
+ this.stopPolling(executionId);
264
+ const errorMsg = data.error || data.message || 'Execution failed';
265
+ onError?.(new Error(errorMsg));
266
+ }
267
+ else if (executionStatus === 'cancelled') {
268
+ state.status = 'cancelled';
269
+ this.stopPolling(executionId);
270
+ }
271
+ }
272
+ catch (error) {
273
+ // Don't stop polling on transient errors — let it retry
274
+ console.error('[AgentSpecExecution] Polling error:', error);
275
+ }
276
+ };
277
+ // Initial poll immediately, then at interval
278
+ poll();
279
+ state.pollingInterval = setInterval(poll, intervalMs);
280
+ }
281
+ stopPolling(executionId) {
282
+ const state = this.activeExecutions.get(executionId);
283
+ if (state?.pollingInterval) {
284
+ clearInterval(state.pollingInterval);
285
+ state.pollingInterval = undefined;
286
+ }
287
+ }
288
+ mapRuntimeStatusToNodeInfo(data) {
289
+ const result = {};
290
+ const nodeStatuses = (data.node_statuses || data.nodes || {});
291
+ for (const [nodeName, status] of Object.entries(nodeStatuses)) {
292
+ result[nodeName] = this.mapSingleNodeStatus(status);
293
+ }
294
+ return result;
295
+ }
296
+ mapSingleNodeStatus(status) {
297
+ const runtimeStatus = (status.status || status.state || 'idle');
298
+ return {
299
+ status: this.mapToFlowDropStatus(runtimeStatus),
300
+ executionCount: status.execution_count || 0,
301
+ isExecuting: runtimeStatus === 'running' || runtimeStatus === 'executing',
302
+ lastExecuted: status.started_at,
303
+ lastExecutionDuration: status.duration_ms,
304
+ lastError: status.error
305
+ };
306
+ }
307
+ mapToFlowDropStatus(runtimeStatus) {
308
+ switch (runtimeStatus) {
309
+ case 'running':
310
+ case 'executing':
311
+ return 'running';
312
+ case 'completed':
313
+ case 'success':
314
+ case 'done':
315
+ return 'completed';
316
+ case 'failed':
317
+ case 'error':
318
+ return 'failed';
319
+ case 'cancelled':
320
+ case 'canceled':
321
+ return 'cancelled';
322
+ case 'pending':
323
+ case 'queued':
324
+ return 'pending';
325
+ case 'skipped':
326
+ return 'skipped';
327
+ default:
328
+ return 'idle';
329
+ }
330
+ }
331
+ }
332
+ /** Singleton instance */
333
+ export const agentSpecExecutionService = AgentSpecExecutionService.getInstance();
@@ -65,10 +65,7 @@ function computeNodePortCoordinates(node, internalNode) {
65
65
  const posAbs = internalNode.internals.positionAbsolute;
66
66
  const dataTypeLookup = buildPortDataTypeLookup(node);
67
67
  const coordinates = [];
68
- const allHandles = [
69
- ...(handleBounds.source ?? []),
70
- ...(handleBounds.target ?? [])
71
- ];
68
+ const allHandles = [...(handleBounds.source ?? []), ...(handleBounds.target ?? [])];
72
69
  for (const handle of allHandles) {
73
70
  if (!handle.id)
74
71
  continue;
@@ -86,7 +86,10 @@ export declare const workflowMetadata: import("svelte/store").Readable<{
86
86
  tags?: string[];
87
87
  versionId?: string;
88
88
  updateNumber?: number;
89
+ format?: import("../types").WorkflowFormat;
89
90
  }>;
91
+ /** Derived store for the current workflow format */
92
+ export declare const workflowFormat: import("svelte/store").Readable<import("../types").WorkflowFormat>;
90
93
  /**
91
94
  * Actions for updating the workflow
92
95
  *
@@ -7,6 +7,7 @@
7
7
  * @module stores/workflowStore
8
8
  */
9
9
  import { writable, derived, get } from 'svelte/store';
10
+ import { DEFAULT_WORKFLOW_FORMAT } from '../types/index.js';
10
11
  import { historyService } from '../services/historyService.js';
11
12
  // =========================================================================
12
13
  // Core Workflow Store
@@ -220,6 +221,8 @@ export const workflowMetadata = derived(workflowStore, ($workflow) => $workflow?
220
221
  versionId: `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
221
222
  updateNumber: 0
222
223
  });
224
+ /** Derived store for the current workflow format */
225
+ export const workflowFormat = derived(workflowStore, ($workflow) => $workflow?.metadata?.format ?? DEFAULT_WORKFLOW_FORMAT);
223
226
  // =========================================================================
224
227
  // Helper Functions
225
228
  // =========================================================================
@@ -10,6 +10,8 @@ import type { Workflow, NodeMetadata, PortConfig, CategoryDefinition } from './t
10
10
  import type { EndpointConfig } from './config/endpoints.js';
11
11
  import type { AuthProvider } from './types/auth.js';
12
12
  import type { FlowDropEventHandlers, FlowDropFeatures } from './types/events.js';
13
+ import type { WorkflowFormatAdapter } from './registry/workflowFormatRegistry.js';
14
+ import './registry/builtinFormats.js';
13
15
  import type { PartialSettings } from './types/settings.js';
14
16
  declare global {
15
17
  interface Window {
@@ -73,6 +75,8 @@ export interface FlowDropMountOptions {
73
75
  settings?: PartialSettings;
74
76
  /** Custom storage key for localStorage drafts */
75
77
  draftStorageKey?: string;
78
+ /** Custom workflow format adapters to register */
79
+ formatAdapters?: WorkflowFormatAdapter[];
76
80
  }
77
81
  /**
78
82
  * Return type for mounted FlowDrop app
@@ -9,6 +9,8 @@
9
9
  import { mount, unmount } from 'svelte';
10
10
  import WorkflowEditor from './components/WorkflowEditor.svelte';
11
11
  import App from './components/App.svelte';
12
+ import { workflowFormatRegistry } from './registry/workflowFormatRegistry.js';
13
+ import './registry/builtinFormats.js';
12
14
  import { initializePortCompatibility } from './utils/connections.js';
13
15
  import { DEFAULT_PORT_CONFIG } from './config/defaultPortConfig.js';
14
16
  import { fetchPortConfig } from './services/portConfigApi.js';
@@ -43,7 +45,13 @@ import { initializeSettings } from './stores/settingsStore.js';
43
45
  * ```
44
46
  */
45
47
  export async function mountFlowDropApp(container, options = {}) {
46
- const { workflow, nodes, endpointConfig, portConfig, categories, height = '100vh', width = '100%', showNavbar = false, disableSidebar, lockWorkflow, readOnly, nodeStatuses, pipelineId, navbarTitle, navbarActions, showSettings, authProvider, eventHandlers, features: userFeatures, settings: initialSettings, draftStorageKey: customDraftKey } = options;
48
+ const { workflow, nodes, endpointConfig, portConfig, categories, height = '100vh', width = '100%', showNavbar = false, disableSidebar, lockWorkflow, readOnly, nodeStatuses, pipelineId, navbarTitle, navbarActions, showSettings, authProvider, eventHandlers, features: userFeatures, settings: initialSettings, draftStorageKey: customDraftKey, formatAdapters } = options;
49
+ // Register custom format adapters before mounting
50
+ if (formatAdapters) {
51
+ for (const adapter of formatAdapters) {
52
+ workflowFormatRegistry.register(adapter);
53
+ }
54
+ }
47
55
  // Merge features with defaults
48
56
  const features = mergeFeatures(userFeatures);
49
57
  // Apply initial settings overrides and initialize theme