@flowdrop/flowdrop 1.14.0 → 2.0.0-beta.1
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 +475 -0
- package/MIGRATION-2.0.md +472 -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/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 +162 -192
- package/dist/components/App.svelte.d.ts +47 -8
- package/dist/components/ConfigForm.svelte +110 -66
- 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 +16 -67
- package/dist/components/PortCoordinateTracker.svelte +5 -6
- package/dist/components/SchemaForm.stories.svelte +1 -3
- package/dist/components/SchemaForm.svelte +45 -40
- 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 +118 -111
- package/dist/components/WorkflowEditor.svelte.d.ts +18 -10
- package/dist/components/chat/AIChatPanel.svelte +93 -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 +29 -13
- package/dist/components/form/FormField.svelte +4 -2
- package/dist/components/form/FormFieldLight.svelte +4 -2
- 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/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 +16 -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 +292 -0
- package/dist/components/nodes/AtomNode.svelte.d.ts +26 -0
- 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 +65 -6
- package/dist/components/playground/PipelinePanel.svelte +11 -5
- package/dist/components/playground/PipelineTableView.svelte +186 -44
- package/dist/components/playground/Playground.svelte +95 -92
- package/dist/components/playground/Playground.svelte.d.ts +2 -0
- package/dist/components/playground/PlaygroundApp.svelte +6 -1
- package/dist/components/playground/PlaygroundApp.svelte.d.ts +3 -0
- package/dist/components/playground/PlaygroundModal.svelte +13 -3
- package/dist/components/playground/PlaygroundModal.svelte.d.ts +3 -0
- package/dist/components/playground/PlaygroundStudio.svelte +34 -32
- package/dist/components/playground/PlaygroundStudio.svelte.d.ts +3 -0
- package/dist/components/playground/SessionManager.svelte +9 -12
- package/dist/components/playground/pipelineViewUtils.svelte.d.ts +28 -0
- package/dist/components/playground/pipelineViewUtils.svelte.js +38 -1
- package/dist/config/endpoints.d.ts +0 -7
- package/dist/config/endpoints.js +2 -10
- package/dist/core/index.d.ts +4 -4
- package/dist/core/index.js +6 -6
- package/dist/display/index.d.ts +0 -2
- package/dist/display/index.js +0 -6
- package/dist/editor/index.d.ts +19 -20
- package/dist/editor/index.js +25 -35
- 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 +17 -13
- package/dist/form/full.js +22 -27
- package/dist/form/index.d.ts +3 -3
- package/dist/form/index.js +3 -3
- package/dist/form/markdown.d.ts +13 -8
- package/dist/form/markdown.js +22 -23
- package/dist/helpers/proximityConnect.d.ts +7 -3
- package/dist/helpers/proximityConnect.js +19 -6
- package/dist/helpers/workflowEditorHelper.d.ts +12 -5
- package/dist/helpers/workflowEditorHelper.js +27 -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 +227 -164
- package/dist/playground/index.d.ts +2 -3
- package/dist/playground/index.js +2 -30
- package/dist/playground/mount.d.ts +15 -0
- package/dist/playground/mount.js +46 -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/builtinNodes.d.ts +1 -26
- package/dist/registry/builtinNodes.js +14 -50
- 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 +53 -6
- package/dist/services/agentSpecExecutionService.js +0 -1
- package/dist/services/apiVariableService.d.ts +2 -1
- package/dist/services/apiVariableService.js +5 -22
- package/dist/services/autoSaveService.d.ts +7 -0
- package/dist/services/autoSaveService.js +6 -4
- package/dist/services/chatService.d.ts +8 -4
- package/dist/services/chatService.js +15 -15
- 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 +14 -9
- package/dist/services/interruptService.js +27 -27
- package/dist/services/nodeExecutionService.d.ts +18 -3
- package/dist/services/nodeExecutionService.js +71 -45
- package/dist/services/playgroundService.d.ts +14 -9
- package/dist/services/playgroundService.js +31 -30
- 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 +45 -0
- package/dist/stores/apiContext.js +65 -0
- package/dist/stores/categoriesStore.svelte.d.ts +28 -23
- package/dist/stores/categoriesStore.svelte.js +70 -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 -216
- package/dist/stores/playgroundStore.svelte.js +515 -572
- 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 +157 -53
- package/dist/types/events.d.ts +6 -3
- package/dist/types/index.d.ts +71 -6
- 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/formMerge.d.ts +36 -0
- package/dist/utils/formMerge.js +70 -0
- 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 -19
- package/dist/utils/performanceUtils.js +7 -0
- package/package.json +6 -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
|
@@ -10,15 +10,11 @@
|
|
|
10
10
|
<script lang="ts">
|
|
11
11
|
import Icon from '@iconify/svelte';
|
|
12
12
|
import ChatInput from './ChatInput.svelte';
|
|
13
|
-
import {
|
|
14
|
-
getCurrentSession,
|
|
15
|
-
getSessions,
|
|
16
|
-
getIsLoading,
|
|
17
|
-
getShowLogs,
|
|
18
|
-
playgroundActions
|
|
19
|
-
} from '../../stores/playgroundStore.svelte.js';
|
|
13
|
+
import { getInstance } from '../../stores/getInstance.svelte.js';
|
|
20
14
|
import { m } from '../../messages/index.js';
|
|
21
15
|
|
|
16
|
+
const fd = getInstance();
|
|
17
|
+
|
|
22
18
|
interface Props {
|
|
23
19
|
// Session management
|
|
24
20
|
onCreateSession: () => void;
|
|
@@ -38,6 +34,10 @@
|
|
|
38
34
|
showRunButton?: boolean;
|
|
39
35
|
predefinedMessage?: string;
|
|
40
36
|
placeholder?: string;
|
|
37
|
+
// Session UI config
|
|
38
|
+
showSessionHeader?: boolean;
|
|
39
|
+
showNewSessionButton?: boolean;
|
|
40
|
+
showSessionList?: boolean;
|
|
41
41
|
style?: string;
|
|
42
42
|
}
|
|
43
43
|
|
|
@@ -56,11 +56,14 @@
|
|
|
56
56
|
showRunButton = true,
|
|
57
57
|
predefinedMessage,
|
|
58
58
|
placeholder,
|
|
59
|
+
showSessionHeader = true,
|
|
60
|
+
showNewSessionButton = true,
|
|
61
|
+
showSessionList = true,
|
|
59
62
|
style
|
|
60
63
|
}: Props = $props();
|
|
61
64
|
|
|
62
65
|
const cp = $derived(m().playground.controlPanel);
|
|
63
|
-
const logsTitle = $derived(
|
|
66
|
+
const logsTitle = $derived(fd.playground.showLogs ? cp.hideLogs : cp.showLogs);
|
|
64
67
|
|
|
65
68
|
let sessionDropdownOpen = $state(false);
|
|
66
69
|
let chipWrapEl = $state<HTMLElement | null>(null);
|
|
@@ -107,136 +110,144 @@
|
|
|
107
110
|
</script>
|
|
108
111
|
|
|
109
112
|
<section class="control-panel" {style}>
|
|
110
|
-
|
|
111
|
-
<
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
class="control-panel__session-chip"
|
|
118
|
-
class:control-panel__session-chip--open={sessionDropdownOpen}
|
|
119
|
-
bind:this={sessionChipEl}
|
|
120
|
-
aria-haspopup="menu"
|
|
121
|
-
aria-expanded={sessionDropdownOpen}
|
|
122
|
-
onclick={() => (sessionDropdownOpen = !sessionDropdownOpen)}
|
|
123
|
-
onkeydown={(e) => {
|
|
124
|
-
if (e.key === 'Escape') sessionDropdownOpen = false;
|
|
125
|
-
}}
|
|
126
|
-
title={cp.switchSession}
|
|
127
|
-
>
|
|
128
|
-
<span class="control-panel__session-chip-name">
|
|
129
|
-
{getCurrentSession()?.name ?? cp.noSession}
|
|
130
|
-
</span>
|
|
131
|
-
<Icon
|
|
132
|
-
icon={sessionDropdownOpen ? 'mdi:chevron-up' : 'mdi:chevron-down'}
|
|
133
|
-
class="control-panel__session-chip-chevron"
|
|
134
|
-
/>
|
|
135
|
-
</button>
|
|
136
|
-
|
|
137
|
-
{#if sessionDropdownOpen}
|
|
138
|
-
<div
|
|
139
|
-
class="control-panel__session-popover"
|
|
140
|
-
bind:this={sessionPopoverEl}
|
|
141
|
-
role="menu"
|
|
142
|
-
tabindex="-1"
|
|
143
|
-
onkeydown={(e) => {
|
|
144
|
-
if (e.key === 'Escape') {
|
|
145
|
-
sessionDropdownOpen = false;
|
|
146
|
-
sessionChipEl?.focus();
|
|
147
|
-
}
|
|
148
|
-
}}
|
|
149
|
-
>
|
|
113
|
+
{#if showSessionHeader}
|
|
114
|
+
<header class="control-panel__header">
|
|
115
|
+
<Icon icon="mdi:message-text-outline" class="control-panel__icon" />
|
|
116
|
+
<span class="control-panel__label">{cp.sessionsLabel}</span>
|
|
117
|
+
|
|
118
|
+
{#if showSessionList}
|
|
119
|
+
<div class="control-panel__session-chip-wrap" bind:this={chipWrapEl}>
|
|
150
120
|
<button
|
|
151
121
|
type="button"
|
|
152
|
-
|
|
153
|
-
class
|
|
154
|
-
|
|
155
|
-
|
|
122
|
+
class="control-panel__session-chip"
|
|
123
|
+
class:control-panel__session-chip--open={sessionDropdownOpen}
|
|
124
|
+
bind:this={sessionChipEl}
|
|
125
|
+
aria-haspopup="menu"
|
|
126
|
+
aria-expanded={sessionDropdownOpen}
|
|
127
|
+
onclick={() => (sessionDropdownOpen = !sessionDropdownOpen)}
|
|
128
|
+
onkeydown={(e) => {
|
|
129
|
+
if (e.key === 'Escape') sessionDropdownOpen = false;
|
|
130
|
+
}}
|
|
131
|
+
title={cp.switchSession}
|
|
156
132
|
>
|
|
157
|
-
<
|
|
158
|
-
|
|
133
|
+
<span class="control-panel__session-chip-name">
|
|
134
|
+
{fd.playground.currentSession?.name ?? cp.noSession}
|
|
135
|
+
</span>
|
|
136
|
+
<Icon
|
|
137
|
+
icon={sessionDropdownOpen ? 'mdi:chevron-up' : 'mdi:chevron-down'}
|
|
138
|
+
class="control-panel__session-chip-chevron"
|
|
139
|
+
/>
|
|
159
140
|
</button>
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
<div
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
141
|
+
|
|
142
|
+
{#if sessionDropdownOpen}
|
|
143
|
+
<div
|
|
144
|
+
class="control-panel__session-popover"
|
|
145
|
+
bind:this={sessionPopoverEl}
|
|
146
|
+
role="menu"
|
|
147
|
+
tabindex="-1"
|
|
148
|
+
onkeydown={(e) => {
|
|
149
|
+
if (e.key === 'Escape') {
|
|
150
|
+
sessionDropdownOpen = false;
|
|
151
|
+
sessionChipEl?.focus();
|
|
152
|
+
}
|
|
153
|
+
}}
|
|
154
|
+
>
|
|
155
|
+
{#if showNewSessionButton}
|
|
156
|
+
<button
|
|
157
|
+
type="button"
|
|
158
|
+
role="menuitem"
|
|
159
|
+
class="control-panel__session-popover-item control-panel__session-popover-item--new"
|
|
160
|
+
disabled={fd.playground.isLoading}
|
|
161
|
+
onclick={handleCreate}
|
|
162
|
+
>
|
|
163
|
+
<Icon icon="mdi:plus" />
|
|
164
|
+
<span>{cp.newSession}</span>
|
|
165
|
+
</button>
|
|
166
|
+
{/if}
|
|
167
|
+
{#if showSessionList && fd.playground.sessions.length > 0}
|
|
168
|
+
{#if showNewSessionButton}
|
|
169
|
+
<div class="control-panel__session-popover-divider"></div>
|
|
170
|
+
{/if}
|
|
171
|
+
<div class="control-panel__session-popover-list">
|
|
172
|
+
{#each fd.playground.sessions as session (session.id)}
|
|
173
|
+
{@const isActive = fd.playground.currentSession?.id === session.id}
|
|
174
|
+
<div class="control-panel__session-popover-row">
|
|
175
|
+
<button
|
|
176
|
+
type="button"
|
|
177
|
+
role="menuitem"
|
|
178
|
+
class="control-panel__session-popover-item"
|
|
179
|
+
class:control-panel__session-popover-item--active={isActive}
|
|
180
|
+
onclick={() => handleSelect(session.id)}
|
|
181
|
+
>
|
|
182
|
+
{#if isActive}
|
|
183
|
+
<Icon icon="mdi:check" class="control-panel__session-popover-check" />
|
|
184
|
+
{:else}
|
|
185
|
+
<Icon icon="mdi:message-outline" />
|
|
186
|
+
{/if}
|
|
187
|
+
<span>{session.name}</span>
|
|
188
|
+
</button>
|
|
189
|
+
<button
|
|
190
|
+
type="button"
|
|
191
|
+
role="menuitem"
|
|
192
|
+
class="control-panel__session-popover-delete"
|
|
193
|
+
onclick={(e) => handleDelete(e, session.id)}
|
|
194
|
+
title={cp.deleteSession}
|
|
195
|
+
aria-label={cp.deleteSession}
|
|
196
|
+
>
|
|
197
|
+
<Icon icon="mdi:delete-outline" />
|
|
198
|
+
</button>
|
|
199
|
+
</div>
|
|
200
|
+
{/each}
|
|
190
201
|
</div>
|
|
191
|
-
{/
|
|
202
|
+
{/if}
|
|
192
203
|
</div>
|
|
193
204
|
{/if}
|
|
194
205
|
</div>
|
|
195
206
|
{/if}
|
|
196
|
-
</div>
|
|
197
207
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
208
|
+
<div class="control-panel__header-actions">
|
|
209
|
+
{#if onTogglePanel}
|
|
210
|
+
{@const pipelineTitle = isPipelinePanelOpen ? cp.hidePipeline : cp.showPipeline}
|
|
211
|
+
<button
|
|
212
|
+
type="button"
|
|
213
|
+
class="control-panel__toolbar-btn"
|
|
214
|
+
class:control-panel__toolbar-btn--active={isPipelinePanelOpen}
|
|
215
|
+
onclick={onTogglePanel}
|
|
216
|
+
title={pipelineTitle}
|
|
217
|
+
aria-label={pipelineTitle}
|
|
218
|
+
>
|
|
219
|
+
<Icon icon="mdi:source-branch" />
|
|
220
|
+
{cp.pipeline}
|
|
221
|
+
</button>
|
|
222
|
+
{/if}
|
|
223
|
+
{#if fd.playground.currentSession}
|
|
224
|
+
<button
|
|
225
|
+
type="button"
|
|
226
|
+
class="control-panel__toolbar-btn"
|
|
227
|
+
class:control-panel__toolbar-btn--spinning={isRefreshing}
|
|
228
|
+
onclick={onRefresh}
|
|
229
|
+
disabled={isRefreshing}
|
|
230
|
+
title={cp.refreshTitle}
|
|
231
|
+
aria-label={cp.refreshTitle}
|
|
232
|
+
>
|
|
233
|
+
<Icon icon="mdi:refresh" />
|
|
234
|
+
{cp.refresh}
|
|
235
|
+
</button>
|
|
236
|
+
{/if}
|
|
214
237
|
<button
|
|
215
238
|
type="button"
|
|
216
239
|
class="control-panel__toolbar-btn"
|
|
217
|
-
class:control-panel__toolbar-btn--
|
|
218
|
-
onclick={
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
aria-label={cp.refreshTitle}
|
|
240
|
+
class:control-panel__toolbar-btn--active={fd.playground.showLogs}
|
|
241
|
+
onclick={() => fd.playground.toggleShowLogs()}
|
|
242
|
+
title={logsTitle}
|
|
243
|
+
aria-label={logsTitle}
|
|
222
244
|
>
|
|
223
|
-
<Icon icon="mdi:
|
|
224
|
-
{cp.
|
|
245
|
+
<Icon icon="mdi:console" />
|
|
246
|
+
{cp.logs}
|
|
225
247
|
</button>
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
class="control-panel__toolbar-btn"
|
|
230
|
-
class:control-panel__toolbar-btn--active={getShowLogs()}
|
|
231
|
-
onclick={() => playgroundActions.toggleShowLogs()}
|
|
232
|
-
title={logsTitle}
|
|
233
|
-
aria-label={logsTitle}
|
|
234
|
-
>
|
|
235
|
-
<Icon icon="mdi:console" />
|
|
236
|
-
{cp.logs}
|
|
237
|
-
</button>
|
|
238
|
-
</div>
|
|
239
|
-
</header>
|
|
248
|
+
</div>
|
|
249
|
+
</header>
|
|
250
|
+
{/if}
|
|
240
251
|
|
|
241
252
|
<ChatInput
|
|
242
253
|
showTextarea={showChatInput}
|
|
@@ -13,6 +13,9 @@ interface Props {
|
|
|
13
13
|
showRunButton?: boolean;
|
|
14
14
|
predefinedMessage?: string;
|
|
15
15
|
placeholder?: string;
|
|
16
|
+
showSessionHeader?: boolean;
|
|
17
|
+
showNewSessionButton?: boolean;
|
|
18
|
+
showSessionList?: boolean;
|
|
16
19
|
style?: string;
|
|
17
20
|
}
|
|
18
21
|
declare const ControlPanel: import("svelte").Component<Props, {}, "">;
|
|
@@ -9,8 +9,10 @@
|
|
|
9
9
|
<script lang="ts">
|
|
10
10
|
import Icon from '@iconify/svelte';
|
|
11
11
|
import { slide } from 'svelte/transition';
|
|
12
|
-
import type {
|
|
13
|
-
import {
|
|
12
|
+
import type { PlaygroundMessageLevel } from '../../types/playground.js';
|
|
13
|
+
import { getInstance } from '../../stores/getInstance.svelte.js';
|
|
14
|
+
|
|
15
|
+
const fd = getInstance();
|
|
14
16
|
|
|
15
17
|
/**
|
|
16
18
|
* Component props
|
|
@@ -37,19 +39,19 @@
|
|
|
37
39
|
*/
|
|
38
40
|
const filteredLogs = $derived(
|
|
39
41
|
levelFilter === 'all'
|
|
40
|
-
?
|
|
41
|
-
:
|
|
42
|
+
? fd.playground.logMessages
|
|
43
|
+
: fd.playground.logMessages.filter((log) => log.metadata?.level === levelFilter)
|
|
42
44
|
);
|
|
43
45
|
|
|
44
46
|
/**
|
|
45
47
|
* Count of logs by level
|
|
46
48
|
*/
|
|
47
49
|
const logCounts = $derived({
|
|
48
|
-
all:
|
|
49
|
-
info:
|
|
50
|
-
warning:
|
|
51
|
-
error:
|
|
52
|
-
debug:
|
|
50
|
+
all: fd.playground.logMessages.length,
|
|
51
|
+
info: fd.playground.logMessages.filter((l) => l.metadata?.level === 'info').length,
|
|
52
|
+
warning: fd.playground.logMessages.filter((l) => l.metadata?.level === 'warning').length,
|
|
53
|
+
error: fd.playground.logMessages.filter((l) => l.metadata?.level === 'error').length,
|
|
54
|
+
debug: fd.playground.logMessages.filter((l) => l.metadata?.level === 'debug').length
|
|
53
55
|
});
|
|
54
56
|
|
|
55
57
|
/**
|
|
@@ -10,7 +10,9 @@
|
|
|
10
10
|
import Icon from '@iconify/svelte';
|
|
11
11
|
import { slide } from 'svelte/transition';
|
|
12
12
|
import type { PlaygroundInputField } from '../../types/playground.js';
|
|
13
|
-
import {
|
|
13
|
+
import { getInstance } from '../../stores/getInstance.svelte.js';
|
|
14
|
+
|
|
15
|
+
const fd = getInstance();
|
|
14
16
|
|
|
15
17
|
/**
|
|
16
18
|
* Component props
|
|
@@ -41,14 +43,14 @@
|
|
|
41
43
|
*/
|
|
42
44
|
$effect(() => {
|
|
43
45
|
// Only initialize once when we have input fields and haven't initialized yet
|
|
44
|
-
if (
|
|
46
|
+
if (fd.playground.inputFields.length > 0 && !hasInitializedDefaults) {
|
|
45
47
|
hasInitializedDefaults = true;
|
|
46
48
|
|
|
47
49
|
// Only set values if there are actual defaults to set
|
|
48
50
|
const initialValues: Record<string, unknown> = {};
|
|
49
51
|
let hasDefaults = false;
|
|
50
52
|
|
|
51
|
-
|
|
53
|
+
fd.playground.inputFields.forEach((field) => {
|
|
52
54
|
if (field.defaultValue !== undefined) {
|
|
53
55
|
initialValues[`${field.nodeId}:${field.fieldId}`] = field.defaultValue;
|
|
54
56
|
hasDefaults = true;
|
|
@@ -117,7 +119,7 @@
|
|
|
117
119
|
*/
|
|
118
120
|
function resetToDefaults(): void {
|
|
119
121
|
const defaultValues: Record<string, unknown> = {};
|
|
120
|
-
|
|
122
|
+
fd.playground.inputFields.forEach((field) => {
|
|
121
123
|
if (field.defaultValue !== undefined) {
|
|
122
124
|
defaultValues[`${field.nodeId}:${field.fieldId}`] = field.defaultValue;
|
|
123
125
|
}
|
|
@@ -127,7 +129,7 @@
|
|
|
127
129
|
}
|
|
128
130
|
</script>
|
|
129
131
|
|
|
130
|
-
{#if
|
|
132
|
+
{#if fd.playground.inputFields.length > 0}
|
|
131
133
|
<div class="input-collector" class:input-collector--expanded={isExpanded}>
|
|
132
134
|
<!-- Header -->
|
|
133
135
|
<button
|
|
@@ -139,7 +141,7 @@
|
|
|
139
141
|
<div class="input-collector__title">
|
|
140
142
|
<Icon icon="mdi:form-textbox" />
|
|
141
143
|
<span>Workflow Inputs</span>
|
|
142
|
-
<span class="input-collector__count">{
|
|
144
|
+
<span class="input-collector__count">{fd.playground.inputFields.length}</span>
|
|
143
145
|
</div>
|
|
144
146
|
<Icon
|
|
145
147
|
icon="mdi:chevron-down"
|
|
@@ -150,7 +152,7 @@
|
|
|
150
152
|
<!-- Content -->
|
|
151
153
|
{#if isExpanded}
|
|
152
154
|
<div class="input-collector__content" transition:slide={{ duration: 200 }}>
|
|
153
|
-
{#if
|
|
155
|
+
{#if fd.playground.hasChatInput}
|
|
154
156
|
<div class="input-collector__hint">
|
|
155
157
|
<Icon icon="mdi:information-outline" />
|
|
156
158
|
<span>Chat input will be collected from the message field below</span>
|
|
@@ -158,7 +160,7 @@
|
|
|
158
160
|
{/if}
|
|
159
161
|
|
|
160
162
|
<div class="input-collector__fields">
|
|
161
|
-
{#each
|
|
163
|
+
{#each fd.playground.inputFields as field (field.nodeId + ':' + field.fieldId)}
|
|
162
164
|
<div class="input-collector__field">
|
|
163
165
|
<label class="input-collector__label" for="input-{field.nodeId}-{field.fieldId}">
|
|
164
166
|
{field.label}
|
|
@@ -176,7 +178,7 @@
|
|
|
176
178
|
onchange={(e) => updateValue(field, e.currentTarget.value)}
|
|
177
179
|
>
|
|
178
180
|
<option value="">Select {field.label}</option>
|
|
179
|
-
{#each field.schema?.enum ?? [] as option}
|
|
181
|
+
{#each field.schema?.enum ?? [] as option (option)}
|
|
180
182
|
<option value={String(option)}>{option}</option>
|
|
181
183
|
{/each}
|
|
182
184
|
</select>
|
|
@@ -19,21 +19,11 @@
|
|
|
19
19
|
extractInterruptMetadata,
|
|
20
20
|
metadataToInterrupt
|
|
21
21
|
} from '../../types/interrupt.js';
|
|
22
|
-
import {
|
|
23
|
-
getMessages,
|
|
24
|
-
getChatMessages,
|
|
25
|
-
getIsExecuting,
|
|
26
|
-
getCurrentSession,
|
|
27
|
-
getShowLogs,
|
|
28
|
-
getHasOlder
|
|
29
|
-
} from '../../stores/playgroundStore.svelte.js';
|
|
30
|
-
import {
|
|
31
|
-
getInterruptsMap,
|
|
32
|
-
interruptActions,
|
|
33
|
-
getInterruptByMessageId
|
|
34
|
-
} from '../../stores/interruptStore.svelte.js';
|
|
22
|
+
import { getInstance } from '../../stores/getInstance.svelte.js';
|
|
35
23
|
import { m } from '../../messages/index.js';
|
|
36
24
|
|
|
25
|
+
const fd = getInstance();
|
|
26
|
+
|
|
37
27
|
interface Props {
|
|
38
28
|
/** Whether to show timestamps on messages */
|
|
39
29
|
showTimestamps?: boolean;
|
|
@@ -80,7 +70,9 @@
|
|
|
80
70
|
/** Reference to the messages container for scrolling */
|
|
81
71
|
let messagesContainer = $state<HTMLDivElement | undefined>();
|
|
82
72
|
|
|
83
|
-
const displayMessages = $derived(
|
|
73
|
+
const displayMessages = $derived(
|
|
74
|
+
allowLogs && fd.playground.showLogs ? fd.playground.messages : fd.playground.chatMessages
|
|
75
|
+
);
|
|
84
76
|
|
|
85
77
|
let previousMessageCount = 0;
|
|
86
78
|
let userScrolledUp = false;
|
|
@@ -117,7 +109,7 @@
|
|
|
117
109
|
* prepend doesn't shift the reading position.
|
|
118
110
|
*/
|
|
119
111
|
async function loadOlder() {
|
|
120
|
-
if (!onLoadOlder || !messagesContainer || isLoadingOlder || !
|
|
112
|
+
if (!onLoadOlder || !messagesContainer || isLoadingOlder || !fd.playground.hasOlder) return;
|
|
121
113
|
|
|
122
114
|
const anchor = topSentinel?.nextElementSibling as HTMLElement | null;
|
|
123
115
|
const anchorTopBefore = anchor?.getBoundingClientRect().top ?? 0;
|
|
@@ -160,17 +152,17 @@
|
|
|
160
152
|
const interruptMessages = displayMessages.filter(isInterruptMessage);
|
|
161
153
|
|
|
162
154
|
for (const message of interruptMessages) {
|
|
163
|
-
const existing =
|
|
155
|
+
const existing = fd.interrupts.getByMessageId(message.id);
|
|
164
156
|
if (!existing) {
|
|
165
157
|
const metadata = extractInterruptMetadata(
|
|
166
158
|
message.metadata as Record<string, unknown> | undefined
|
|
167
159
|
);
|
|
168
160
|
if (metadata) {
|
|
169
161
|
const interrupt = metadataToInterrupt(metadata, message.id, message.content);
|
|
170
|
-
|
|
162
|
+
fd.interrupts.addInterrupt(interrupt);
|
|
171
163
|
|
|
172
164
|
if (message.status === 'completed') {
|
|
173
|
-
|
|
165
|
+
fd.interrupts.resolveInterrupt(interrupt.id, metadata.response_value);
|
|
174
166
|
}
|
|
175
167
|
}
|
|
176
168
|
}
|
|
@@ -179,7 +171,7 @@
|
|
|
179
171
|
|
|
180
172
|
const interruptsByMessageId = $derived(
|
|
181
173
|
new Map(
|
|
182
|
-
Array.from(
|
|
174
|
+
Array.from(fd.interrupts.getMap().values())
|
|
183
175
|
.filter((i) => i.messageId)
|
|
184
176
|
.map((i) => [i.messageId, i])
|
|
185
177
|
)
|
|
@@ -189,12 +181,14 @@
|
|
|
189
181
|
return interruptsByMessageId.get(message.id);
|
|
190
182
|
}
|
|
191
183
|
|
|
192
|
-
const showWelcome = $derived(!
|
|
193
|
-
const showEmptyChat = $derived(
|
|
184
|
+
const showWelcome = $derived(!fd.playground.currentSession && displayMessages.length === 0);
|
|
185
|
+
const showEmptyChat = $derived(
|
|
186
|
+
fd.playground.currentSession !== null && displayMessages.length === 0
|
|
187
|
+
);
|
|
194
188
|
|
|
195
189
|
// Reset scroll-tracking when session changes
|
|
196
190
|
$effect(() => {
|
|
197
|
-
if (
|
|
191
|
+
if (fd.playground.currentSession) {
|
|
198
192
|
userScrolledUp = false;
|
|
199
193
|
}
|
|
200
194
|
});
|
|
@@ -271,7 +265,7 @@
|
|
|
271
265
|
{/if}
|
|
272
266
|
{/each}
|
|
273
267
|
|
|
274
|
-
{#if
|
|
268
|
+
{#if fd.playground.isExecuting}
|
|
275
269
|
<div class="message-stream__typing">
|
|
276
270
|
<div class="message-stream__typing-indicator">
|
|
277
271
|
<span></span>
|
|
@@ -42,6 +42,7 @@
|
|
|
42
42
|
getStatusTextColor,
|
|
43
43
|
getStatusBackgroundColor
|
|
44
44
|
} from '../../utils/nodeStatus.js';
|
|
45
|
+
import { formatMicroseconds } from '../../utils/duration.js';
|
|
45
46
|
import type { NodeStatus } from './pipelineViewUtils.svelte.js';
|
|
46
47
|
import type { Workflow, WorkflowNode } from '../../types/index.js';
|
|
47
48
|
import type { EndpointConfig } from '../../config/endpoints.js';
|
|
@@ -55,7 +56,8 @@
|
|
|
55
56
|
|
|
56
57
|
let { pipelineId, workflow, endpointConfig, refreshTrigger = 0 }: Props = $props();
|
|
57
58
|
|
|
58
|
-
//
|
|
59
|
+
// endpointConfig is consumed once to build the API client; it must be stable
|
|
60
|
+
// svelte-ignore state_referenced_locally
|
|
59
61
|
const fetcher = createPipelineDataFetcher(() => pipelineId, endpointConfig);
|
|
60
62
|
|
|
61
63
|
$effect(() => {
|
|
@@ -65,8 +67,13 @@
|
|
|
65
67
|
});
|
|
66
68
|
|
|
67
69
|
interface CardItem {
|
|
68
|
-
|
|
70
|
+
/** Stable key: job id, or node id for nodes without a job yet */
|
|
71
|
+
key: string;
|
|
72
|
+
label: string;
|
|
73
|
+
typeId: string;
|
|
69
74
|
status: NodeStatus;
|
|
75
|
+
/** Duration in microseconds, for finished jobs */
|
|
76
|
+
durationUs?: number | null;
|
|
70
77
|
}
|
|
71
78
|
|
|
72
79
|
const columnedNodes = $derived.by(() => {
|
|
@@ -85,10 +92,37 @@
|
|
|
85
92
|
nodesByColumn.set(col.key, []);
|
|
86
93
|
}
|
|
87
94
|
|
|
95
|
+
const nodesById = new Map<string, WorkflowNode>(workflow.nodes.map((node) => [node.id, node]));
|
|
96
|
+
|
|
97
|
+
// One card per job: loop iterations create multiple jobs for the same
|
|
98
|
+
// node, and each deserves its own card (label carries the #N suffix).
|
|
99
|
+
const nodesWithJobs = new Set<string>();
|
|
100
|
+
for (const job of fetcher.jobs) {
|
|
101
|
+
const node = nodesById.get(job.nodeId);
|
|
102
|
+
if (!node) continue;
|
|
103
|
+
nodesWithJobs.add(job.nodeId);
|
|
104
|
+
const status = resolveStatus({ status: job.status });
|
|
105
|
+
const colKey = statusToColumn.get(status) ?? fallbackKey;
|
|
106
|
+
nodesByColumn.get(colKey)?.push({
|
|
107
|
+
key: job.id,
|
|
108
|
+
label: job.label || node.data.label,
|
|
109
|
+
typeId: node.data.metadata.id,
|
|
110
|
+
status,
|
|
111
|
+
durationUs: job.executionTimeUs
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Nodes without a job yet keep a single card (pending / not reached).
|
|
88
116
|
for (const node of workflow.nodes) {
|
|
117
|
+
if (nodesWithJobs.has(node.id)) continue;
|
|
89
118
|
const status = resolveStatus(fetcher.nodeStatusMap[node.id]);
|
|
90
119
|
const colKey = statusToColumn.get(status) ?? fallbackKey;
|
|
91
|
-
nodesByColumn.get(colKey)?.push({
|
|
120
|
+
nodesByColumn.get(colKey)?.push({
|
|
121
|
+
key: node.id,
|
|
122
|
+
label: node.data.label,
|
|
123
|
+
typeId: node.data.metadata.id,
|
|
124
|
+
status
|
|
125
|
+
});
|
|
92
126
|
}
|
|
93
127
|
|
|
94
128
|
return { columns, nodesByColumn };
|
|
@@ -122,11 +156,11 @@
|
|
|
122
156
|
<span class="pipeline-kanban__col-count">{items.length}</span>
|
|
123
157
|
</div>
|
|
124
158
|
<div class="pipeline-kanban__cards">
|
|
125
|
-
{#each items as {
|
|
159
|
+
{#each items as { key, label, typeId, status, durationUs } (key)}
|
|
126
160
|
<div class="pipeline-kanban__card">
|
|
127
161
|
<div class="pipeline-kanban__card-body">
|
|
128
162
|
<div class="pipeline-kanban__card-top">
|
|
129
|
-
<span class="pipeline-kanban__card-label">{
|
|
163
|
+
<span class="pipeline-kanban__card-label">{label}</span>
|
|
130
164
|
{#if showStatusPill}
|
|
131
165
|
<span
|
|
132
166
|
class="pipeline-kanban__card-status"
|
|
@@ -137,7 +171,14 @@
|
|
|
137
171
|
>
|
|
138
172
|
{/if}
|
|
139
173
|
</div>
|
|
140
|
-
<
|
|
174
|
+
<div class="pipeline-kanban__card-meta">
|
|
175
|
+
<span class="pipeline-kanban__card-type">{typeId}</span>
|
|
176
|
+
{#if durationUs != null}
|
|
177
|
+
<span class="pipeline-kanban__card-duration"
|
|
178
|
+
>{formatMicroseconds(durationUs)}</span
|
|
179
|
+
>
|
|
180
|
+
{/if}
|
|
181
|
+
</div>
|
|
141
182
|
</div>
|
|
142
183
|
</div>
|
|
143
184
|
{/each}
|
|
@@ -296,12 +337,30 @@
|
|
|
296
337
|
flex-shrink: 0;
|
|
297
338
|
}
|
|
298
339
|
|
|
340
|
+
.pipeline-kanban__card-meta {
|
|
341
|
+
display: flex;
|
|
342
|
+
align-items: center;
|
|
343
|
+
gap: var(--fd-space-xs);
|
|
344
|
+
min-width: 0;
|
|
345
|
+
}
|
|
346
|
+
|
|
299
347
|
.pipeline-kanban__card-type {
|
|
300
348
|
color: var(--fd-muted-foreground);
|
|
301
349
|
font-size: var(--fd-text-2xs);
|
|
302
350
|
overflow: hidden;
|
|
303
351
|
text-overflow: ellipsis;
|
|
304
352
|
white-space: nowrap;
|
|
353
|
+
flex: 1;
|
|
354
|
+
min-width: 0;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
.pipeline-kanban__card-duration {
|
|
358
|
+
color: var(--fd-muted-foreground);
|
|
359
|
+
font-size: var(--fd-text-2xs);
|
|
360
|
+
font-family: var(--fd-font-mono, monospace);
|
|
361
|
+
font-variant-numeric: tabular-nums;
|
|
362
|
+
white-space: nowrap;
|
|
363
|
+
flex-shrink: 0;
|
|
305
364
|
}
|
|
306
365
|
|
|
307
366
|
.pipeline-kanban__empty {
|