@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.
Files changed (235) hide show
  1. package/CHANGELOG.md +508 -0
  2. package/MIGRATION-2.0.md +629 -0
  3. package/README.md +23 -23
  4. package/dist/adapters/WorkflowAdapter.d.ts +1 -1
  5. package/dist/adapters/WorkflowAdapter.js +14 -8
  6. package/dist/adapters/agentspec/AgentSpecAdapter.js +7 -7
  7. package/dist/api/enhanced-client.js +6 -11
  8. package/dist/chat/batchFeedback.d.ts +39 -0
  9. package/dist/chat/batchFeedback.js +51 -0
  10. package/dist/commands/executor.js +15 -1
  11. package/dist/commands/storeIntegration.svelte.d.ts +4 -1
  12. package/dist/commands/storeIntegration.svelte.js +26 -21
  13. package/dist/commands/types.d.ts +2 -0
  14. package/dist/components/App.svelte +163 -192
  15. package/dist/components/App.svelte.d.ts +47 -8
  16. package/dist/components/ConfigForm.svelte +77 -49
  17. package/dist/components/ConfigModal.svelte +7 -2
  18. package/dist/components/ConnectionLine.svelte +4 -2
  19. package/dist/components/Navbar.svelte +61 -1
  20. package/dist/components/NodeSidebar.svelte +27 -45
  21. package/dist/components/NodeStatusOverlay.svelte +94 -6
  22. package/dist/components/NodeSwapPicker.svelte +10 -8
  23. package/dist/components/PipelineStatus.svelte +22 -68
  24. package/dist/components/PipelineStatus.svelte.d.ts +3 -0
  25. package/dist/components/PortCoordinateTracker.svelte +5 -6
  26. package/dist/components/SchemaForm.stories.svelte +1 -3
  27. package/dist/components/SchemaForm.svelte +22 -27
  28. package/dist/components/SchemaForm.svelte.d.ts +0 -8
  29. package/dist/components/SettingsModal.svelte +8 -3
  30. package/dist/components/SettingsPanel.svelte +20 -4
  31. package/dist/components/SwapMappingEditor.svelte +67 -49
  32. package/dist/components/SwapMappingEditor.svelte.d.ts +0 -2
  33. package/dist/components/UniversalNode.svelte +9 -7
  34. package/dist/components/WorkflowEditor.svelte +121 -111
  35. package/dist/components/WorkflowEditor.svelte.d.ts +21 -10
  36. package/dist/components/chat/AIChatPanel.svelte +98 -89
  37. package/dist/components/chat/AIChatPanel.svelte.d.ts +0 -4
  38. package/dist/components/chat/CommandPreview.svelte +2 -1
  39. package/dist/components/console/CommandConsole.svelte +7 -5
  40. package/dist/components/console/ConsoleAutocomplete.svelte +10 -11
  41. package/dist/components/console/ConsoleAutocomplete.svelte.d.ts +6 -0
  42. package/dist/components/console/ConsoleInput.svelte +15 -6
  43. package/dist/components/console/ConsoleOutput.svelte +2 -1
  44. package/dist/components/form/FormArray.svelte +5 -9
  45. package/dist/components/form/FormArray.svelte.d.ts +2 -1
  46. package/dist/components/form/FormAutocomplete.svelte +16 -15
  47. package/dist/components/form/FormField.svelte +4 -2
  48. package/dist/components/form/FormFieldLight.svelte +34 -3
  49. package/dist/components/form/FormFieldLight.svelte.d.ts +12 -0
  50. package/dist/components/form/FormMarkdownEditor.svelte +9 -4
  51. package/dist/components/form/FormRangeField.svelte +1 -0
  52. package/dist/components/form/FormTemplateEditor.svelte +11 -3
  53. package/dist/components/form/FormToggle.svelte +5 -12
  54. package/dist/components/form/FormToggle.svelte.d.ts +4 -2
  55. package/dist/components/form/FormUISchemaRenderer.svelte +3 -1
  56. package/dist/components/form/templateAutocomplete.js +1 -5
  57. package/dist/components/form/types.d.ts +1 -14
  58. package/dist/components/interrupt/FormPrompt.svelte +3 -2
  59. package/dist/components/interrupt/InterruptBubble.svelte +25 -17
  60. package/dist/components/interrupt/ReviewPrompt.svelte +10 -3
  61. package/dist/components/interrupt/TextInputPrompt.svelte +2 -1
  62. package/dist/components/layouts/MainLayout.svelte +20 -13
  63. package/dist/components/layouts/MainLayout.svelte.d.ts +4 -0
  64. package/dist/components/nodes/AtomNode.svelte +17 -5
  65. package/dist/components/nodes/GatewayNode.svelte +19 -10
  66. package/dist/components/nodes/IdeaNode.svelte +7 -0
  67. package/dist/components/nodes/SimpleNode.svelte +11 -6
  68. package/dist/components/nodes/SquareNode.svelte +15 -8
  69. package/dist/components/nodes/TerminalNode.svelte +9 -4
  70. package/dist/components/nodes/ToolNode.svelte +7 -1
  71. package/dist/components/nodes/WorkflowNode.svelte +16 -7
  72. package/dist/components/playground/ChatInput.svelte +11 -14
  73. package/dist/components/playground/ChatPanel.svelte +6 -49
  74. package/dist/components/playground/ChatPanel.svelte.d.ts +0 -14
  75. package/dist/components/playground/ControlPanel.svelte +134 -123
  76. package/dist/components/playground/ControlPanel.svelte.d.ts +3 -0
  77. package/dist/components/playground/ExecutionLogs.svelte +11 -9
  78. package/dist/components/playground/InputCollector.svelte +11 -9
  79. package/dist/components/playground/MessageStream.svelte +17 -23
  80. package/dist/components/playground/PipelineKanbanView.svelte +69 -8
  81. package/dist/components/playground/PipelineKanbanView.svelte.d.ts +2 -0
  82. package/dist/components/playground/PipelinePanel.svelte +31 -8
  83. package/dist/components/playground/PipelinePanel.svelte.d.ts +2 -0
  84. package/dist/components/playground/PipelineTableView.svelte +188 -44
  85. package/dist/components/playground/PipelineTableView.svelte.d.ts +2 -0
  86. package/dist/components/playground/Playground.svelte +154 -105
  87. package/dist/components/playground/Playground.svelte.d.ts +5 -0
  88. package/dist/components/playground/PlaygroundApp.svelte +11 -1
  89. package/dist/components/playground/PlaygroundApp.svelte.d.ts +6 -0
  90. package/dist/components/playground/PlaygroundModal.svelte +18 -3
  91. package/dist/components/playground/PlaygroundModal.svelte.d.ts +6 -0
  92. package/dist/components/playground/PlaygroundStudio.svelte +40 -32
  93. package/dist/components/playground/PlaygroundStudio.svelte.d.ts +6 -0
  94. package/dist/components/playground/SessionManager.svelte +9 -12
  95. package/dist/components/playground/pipelineViewUtils.svelte.d.ts +30 -1
  96. package/dist/components/playground/pipelineViewUtils.svelte.js +40 -3
  97. package/dist/config/endpoints.d.ts +23 -7
  98. package/dist/config/endpoints.js +30 -10
  99. package/dist/core/index.d.ts +5 -6
  100. package/dist/core/index.js +8 -12
  101. package/dist/display/index.d.ts +6 -3
  102. package/dist/display/index.js +7 -5
  103. package/dist/editor/index.d.ts +20 -21
  104. package/dist/editor/index.js +26 -36
  105. package/dist/form/code.d.ts +25 -15
  106. package/dist/form/code.js +44 -41
  107. package/dist/form/fieldRegistry.d.ts +17 -13
  108. package/dist/form/fieldRegistry.js +32 -12
  109. package/dist/form/full.d.ts +19 -14
  110. package/dist/form/full.js +26 -28
  111. package/dist/form/index.d.ts +3 -4
  112. package/dist/form/index.js +6 -5
  113. package/dist/form/markdown.d.ts +13 -8
  114. package/dist/form/markdown.js +22 -23
  115. package/dist/helpers/proximityConnect.d.ts +3 -2
  116. package/dist/helpers/proximityConnect.js +2 -5
  117. package/dist/helpers/workflowEditorHelper.d.ts +14 -5
  118. package/dist/helpers/workflowEditorHelper.js +28 -25
  119. package/dist/index.d.ts +28 -24
  120. package/dist/index.js +27 -50
  121. package/dist/messages/defaults.d.ts +2 -5
  122. package/dist/messages/defaults.js +3 -6
  123. package/dist/messages/index.d.ts +0 -1
  124. package/dist/messages/index.js +0 -1
  125. package/dist/mocks/app-forms.d.ts +6 -2
  126. package/dist/mocks/app-forms.js +11 -4
  127. package/dist/openapi/v1/openapi.yaml +3 -3
  128. package/dist/playground/index.d.ts +4 -5
  129. package/dist/playground/index.js +4 -32
  130. package/dist/playground/mount.d.ts +25 -0
  131. package/dist/playground/mount.js +50 -20
  132. package/dist/registry/{BaseRegistry.d.ts → BaseRegistry.svelte.d.ts} +22 -1
  133. package/dist/registry/{BaseRegistry.js → BaseRegistry.svelte.js} +37 -1
  134. package/dist/registry/builtinFormats.d.ts +9 -18
  135. package/dist/registry/builtinFormats.js +9 -39
  136. package/dist/registry/builtinNodeTypes.d.ts +53 -0
  137. package/dist/registry/builtinNodeTypes.js +67 -0
  138. package/dist/registry/builtinNodes.d.ts +2 -64
  139. package/dist/registry/builtinNodes.js +7 -103
  140. package/dist/registry/index.d.ts +3 -4
  141. package/dist/registry/index.js +4 -6
  142. package/dist/registry/nodeComponentRegistry.d.ts +182 -15
  143. package/dist/registry/nodeComponentRegistry.js +235 -17
  144. package/dist/registry/workflowFormatRegistry.d.ts +14 -9
  145. package/dist/registry/workflowFormatRegistry.js +24 -8
  146. package/dist/{schema → schemas}/index.d.ts +2 -2
  147. package/dist/{schema → schemas}/index.js +2 -2
  148. package/dist/schemas/v1/workflow.schema.json +3 -3
  149. package/dist/services/agentSpecExecutionService.d.ts +0 -2
  150. package/dist/services/agentSpecExecutionService.js +0 -3
  151. package/dist/services/apiVariableService.d.ts +2 -1
  152. package/dist/services/apiVariableService.js +16 -47
  153. package/dist/services/autoSaveService.d.ts +7 -0
  154. package/dist/services/autoSaveService.js +6 -4
  155. package/dist/services/categoriesApi.js +3 -6
  156. package/dist/services/chatService.d.ts +9 -4
  157. package/dist/services/chatService.js +23 -28
  158. package/dist/services/draftStorage.d.ts +129 -13
  159. package/dist/services/draftStorage.js +185 -37
  160. package/dist/services/dynamicSchemaService.d.ts +2 -1
  161. package/dist/services/dynamicSchemaService.js +5 -22
  162. package/dist/services/globalSave.d.ts +13 -12
  163. package/dist/services/globalSave.js +29 -51
  164. package/dist/services/historyService.d.ts +9 -3
  165. package/dist/services/historyService.js +9 -3
  166. package/dist/services/interruptService.d.ts +15 -9
  167. package/dist/services/interruptService.js +35 -37
  168. package/dist/services/nodeExecutionService.d.ts +18 -3
  169. package/dist/services/nodeExecutionService.js +71 -45
  170. package/dist/services/playgroundService.d.ts +16 -10
  171. package/dist/services/playgroundService.js +42 -43
  172. package/dist/services/portConfigApi.js +3 -6
  173. package/dist/services/settingsService.d.ts +9 -4
  174. package/dist/services/settingsService.js +23 -12
  175. package/dist/services/variableService.d.ts +2 -1
  176. package/dist/services/variableService.js +2 -2
  177. package/dist/services/workflowStorage.js +6 -6
  178. package/dist/stores/apiContext.d.ts +56 -0
  179. package/dist/stores/apiContext.js +80 -0
  180. package/dist/stores/categoriesStore.svelte.d.ts +28 -23
  181. package/dist/stores/categoriesStore.svelte.js +69 -64
  182. package/dist/stores/getInstance.svelte.d.ts +39 -0
  183. package/dist/stores/getInstance.svelte.js +65 -0
  184. package/dist/stores/historyStore.svelte.d.ts +77 -93
  185. package/dist/stores/historyStore.svelte.js +134 -160
  186. package/dist/stores/instanceContainer.svelte.d.ts +111 -0
  187. package/dist/stores/instanceContainer.svelte.js +114 -0
  188. package/dist/stores/interruptStore.svelte.d.ts +112 -82
  189. package/dist/stores/interruptStore.svelte.js +253 -226
  190. package/dist/stores/pipelinePanelStore.svelte.d.ts +27 -3
  191. package/dist/stores/pipelinePanelStore.svelte.js +61 -14
  192. package/dist/stores/playgroundStore.svelte.d.ts +169 -222
  193. package/dist/stores/playgroundStore.svelte.js +513 -580
  194. package/dist/stores/portCoordinateStore.svelte.d.ts +57 -51
  195. package/dist/stores/portCoordinateStore.svelte.js +109 -98
  196. package/dist/stores/settingsStore.svelte.d.ts +4 -1
  197. package/dist/stores/settingsStore.svelte.js +47 -12
  198. package/dist/stores/workflowStore.svelte.d.ts +178 -213
  199. package/dist/stores/workflowStore.svelte.js +449 -501
  200. package/dist/stories/EdgeDecorator.svelte +5 -2
  201. package/dist/stories/NodeDecorator.svelte +5 -3
  202. package/dist/svelte-app.d.ts +60 -10
  203. package/dist/svelte-app.js +159 -54
  204. package/dist/types/auth.d.ts +9 -51
  205. package/dist/types/auth.js +4 -54
  206. package/dist/types/events.d.ts +6 -3
  207. package/dist/types/index.d.ts +37 -5
  208. package/dist/types/index.js +0 -1
  209. package/dist/types/navbar.d.ts +7 -0
  210. package/dist/types/playground.d.ts +18 -3
  211. package/dist/types/settings.d.ts +13 -0
  212. package/dist/types/settings.js +1 -0
  213. package/dist/utils/colors.d.ts +47 -21
  214. package/dist/utils/colors.js +69 -68
  215. package/dist/utils/connections.d.ts +9 -15
  216. package/dist/utils/connections.js +13 -32
  217. package/dist/utils/duration.d.ts +13 -0
  218. package/dist/utils/duration.js +45 -0
  219. package/dist/utils/edgeStyling.js +9 -5
  220. package/dist/utils/fetchWithAuth.d.ts +36 -15
  221. package/dist/utils/fetchWithAuth.js +53 -23
  222. package/dist/utils/icons.d.ts +5 -2
  223. package/dist/utils/icons.js +6 -5
  224. package/dist/utils/nodeSwap.d.ts +6 -2
  225. package/dist/utils/nodeSwap.js +62 -126
  226. package/dist/utils/nodeTypes.d.ts +17 -8
  227. package/dist/utils/nodeTypes.js +27 -20
  228. package/dist/utils/performanceUtils.js +7 -0
  229. package/package.json +7 -5
  230. package/dist/messages/deprecation.d.ts +0 -20
  231. package/dist/messages/deprecation.js +0 -33
  232. package/dist/registry/plugin.d.ts +0 -215
  233. package/dist/registry/plugin.js +0 -249
  234. package/dist/services/api.d.ts +0 -129
  235. package/dist/services/api.js +0 -217
@@ -5,16 +5,14 @@
5
5
  MessageStream (message + interrupt feed) and ChatInput (textarea +
6
6
  send/run/stop). Use this for chat-style agent interactions.
7
7
 
8
- For view-only execution surfaces, prefer the MessageStream primitive
9
- directly ChatPanel's showChatInput/showRunButton flags are kept for
10
- backwards compatibility but are deprecated.
8
+ For view-only execution surfaces, use the MessageStream primitive directly.
9
+ Log visibility is managed by the playground store (fd.playground.setShowLogs).
11
10
  -->
12
11
 
13
12
  <script lang="ts">
14
13
  import Icon from '@iconify/svelte';
15
14
  import MessageStream from './MessageStream.svelte';
16
15
  import ChatInput from './ChatInput.svelte';
17
- import { playgroundActions } from '../../stores/playgroundStore.svelte.js';
18
16
  import { m } from '../../messages/index.js';
19
17
 
20
18
  interface Props {
@@ -28,22 +26,8 @@
28
26
  onInterruptResolved?: () => void;
29
27
  /** Render a "New session" CTA in the welcome state */
30
28
  onCreateSession?: () => void;
31
- /**
32
- * @deprecated Use `<MessageStream />` directly for view-only feeds.
33
- * Kept for backwards compatibility with PlaygroundConfig URL params.
34
- */
35
- showChatInput?: boolean;
36
- /**
37
- * @deprecated Use `<MessageStream />` directly for view-only feeds.
38
- */
39
- showRunButton?: boolean;
40
29
  predefinedMessage?: string;
41
30
  compactSystemMessages?: boolean;
42
- /**
43
- * @deprecated `showLogs` is now managed by playgroundStore.
44
- * Setting it here syncs to the store on mount for backwards compatibility.
45
- */
46
- showLogs?: boolean;
47
31
  }
48
32
 
49
33
  let {
@@ -56,23 +40,11 @@
56
40
  enableMarkdown = true,
57
41
  onInterruptResolved,
58
42
  onCreateSession,
59
- showChatInput = true,
60
- showRunButton = true,
61
43
  predefinedMessage,
62
- compactSystemMessages = true,
63
- showLogs
44
+ compactSystemMessages = true
64
45
  }: Props = $props();
65
46
 
66
47
  const states = $derived(m().playground.states);
67
-
68
- const noInputsAvailable = $derived(!showChatInput && !showRunButton);
69
-
70
- // Back-compat: sync legacy showLogs prop into the store whenever it changes.
71
- $effect(() => {
72
- if (showLogs !== undefined) {
73
- playgroundActions.setShowLogs(showLogs);
74
- }
75
- });
76
48
  </script>
77
49
 
78
50
  <div class="chat-panel">
@@ -87,14 +59,7 @@
87
59
  emptySession={emptyChatState}
88
60
  />
89
61
 
90
- <ChatInput
91
- {placeholder}
92
- {predefinedMessage}
93
- {onSendMessage}
94
- {onStopExecution}
95
- showTextarea={showChatInput}
96
- {showRunButton}
97
- />
62
+ <ChatInput {placeholder} {predefinedMessage} {onSendMessage} {onStopExecution} />
98
63
  </div>
99
64
 
100
65
  {#snippet welcomeIcon()}
@@ -115,16 +80,8 @@
115
80
  {/snippet}
116
81
 
117
82
  {#snippet welcomeCopy()}
118
- {#if noInputsAvailable}
119
- <h2 class="chat-panel__welcome-title">{states.viewOnlyTitle}</h2>
120
- <p class="chat-panel__welcome-text">{states.viewOnlyText}</p>
121
- {:else if showChatInput}
122
- <h2 class="chat-panel__welcome-title">{states.newSessionTitle}</h2>
123
- <p class="chat-panel__welcome-text">{states.newSessionText}</p>
124
- {:else}
125
- <h2 class="chat-panel__welcome-title">{states.readyTitle}</h2>
126
- <p class="chat-panel__welcome-text">{states.readyText}</p>
127
- {/if}
83
+ <h2 class="chat-panel__welcome-title">{states.newSessionTitle}</h2>
84
+ <p class="chat-panel__welcome-text">{states.newSessionText}</p>
128
85
  {/snippet}
129
86
 
130
87
  {#snippet welcomeState()}
@@ -9,22 +9,8 @@ interface Props {
9
9
  onInterruptResolved?: () => void;
10
10
  /** Render a "New session" CTA in the welcome state */
11
11
  onCreateSession?: () => void;
12
- /**
13
- * @deprecated Use `<MessageStream />` directly for view-only feeds.
14
- * Kept for backwards compatibility with PlaygroundConfig URL params.
15
- */
16
- showChatInput?: boolean;
17
- /**
18
- * @deprecated Use `<MessageStream />` directly for view-only feeds.
19
- */
20
- showRunButton?: boolean;
21
12
  predefinedMessage?: string;
22
13
  compactSystemMessages?: boolean;
23
- /**
24
- * @deprecated `showLogs` is now managed by playgroundStore.
25
- * Setting it here syncs to the store on mount for backwards compatibility.
26
- */
27
- showLogs?: boolean;
28
14
  }
29
15
  declare const ChatPanel: import("svelte").Component<Props, {}, "">;
30
16
  type ChatPanel = ReturnType<typeof ChatPanel>;
@@ -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(getShowLogs() ? cp.hideLogs : cp.showLogs);
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
- <header class="control-panel__header">
111
- <Icon icon="mdi:message-text-outline" class="control-panel__icon" />
112
- <span class="control-panel__label">{cp.sessionsLabel}</span>
113
-
114
- <div class="control-panel__session-chip-wrap" bind:this={chipWrapEl}>
115
- <button
116
- type="button"
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
- role="menuitem"
153
- class="control-panel__session-popover-item control-panel__session-popover-item--new"
154
- disabled={getIsLoading()}
155
- onclick={handleCreate}
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
- <Icon icon="mdi:plus" />
158
- <span>{cp.newSession}</span>
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
- {#if getSessions().length > 0}
161
- <div class="control-panel__session-popover-divider"></div>
162
- <div class="control-panel__session-popover-list">
163
- {#each getSessions() as session (session.id)}
164
- {@const isActive = getCurrentSession()?.id === session.id}
165
- <div class="control-panel__session-popover-row">
166
- <button
167
- type="button"
168
- role="menuitem"
169
- class="control-panel__session-popover-item"
170
- class:control-panel__session-popover-item--active={isActive}
171
- onclick={() => handleSelect(session.id)}
172
- >
173
- {#if isActive}
174
- <Icon icon="mdi:check" class="control-panel__session-popover-check" />
175
- {:else}
176
- <Icon icon="mdi:message-outline" />
177
- {/if}
178
- <span>{session.name}</span>
179
- </button>
180
- <button
181
- type="button"
182
- role="menuitem"
183
- class="control-panel__session-popover-delete"
184
- onclick={(e) => handleDelete(e, session.id)}
185
- title={cp.deleteSession}
186
- aria-label={cp.deleteSession}
187
- >
188
- <Icon icon="mdi:delete-outline" />
189
- </button>
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
- {/each}
202
+ {/if}
192
203
  </div>
193
204
  {/if}
194
205
  </div>
195
206
  {/if}
196
- </div>
197
207
 
198
- <div class="control-panel__header-actions">
199
- {#if onTogglePanel}
200
- {@const pipelineTitle = isPipelinePanelOpen ? cp.hidePipeline : cp.showPipeline}
201
- <button
202
- type="button"
203
- class="control-panel__toolbar-btn"
204
- class:control-panel__toolbar-btn--active={isPipelinePanelOpen}
205
- onclick={onTogglePanel}
206
- title={pipelineTitle}
207
- aria-label={pipelineTitle}
208
- >
209
- <Icon icon="mdi:source-branch" />
210
- {cp.pipeline}
211
- </button>
212
- {/if}
213
- {#if getCurrentSession()}
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--spinning={isRefreshing}
218
- onclick={onRefresh}
219
- disabled={isRefreshing}
220
- title={cp.refreshTitle}
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:refresh" />
224
- {cp.refresh}
245
+ <Icon icon="mdi:console" />
246
+ {cp.logs}
225
247
  </button>
226
- {/if}
227
- <button
228
- type="button"
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 { PlaygroundMessage, PlaygroundMessageLevel } from '../../types/playground.js';
13
- import { getLogMessages } from '../../stores/playgroundStore.svelte.js';
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
- ? getLogMessages()
41
- : getLogMessages().filter((log) => log.metadata?.level === levelFilter)
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: getLogMessages().length,
49
- info: getLogMessages().filter((l) => l.metadata?.level === 'info').length,
50
- warning: getLogMessages().filter((l) => l.metadata?.level === 'warning').length,
51
- error: getLogMessages().filter((l) => l.metadata?.level === 'error').length,
52
- debug: getLogMessages().filter((l) => l.metadata?.level === 'debug').length
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 { getInputFields, getHasChatInput } from '../../stores/playgroundStore.svelte.js';
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 (getInputFields().length > 0 && !hasInitializedDefaults) {
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
- getInputFields().forEach((field) => {
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
- getInputFields().forEach((field) => {
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 getInputFields().length > 0}
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">{getInputFields().length}</span>
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 getHasChatInput()}
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 getInputFields() as field (field.nodeId + ':' + field.fieldId)}
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(allowLogs && getShowLogs() ? getMessages() : getChatMessages());
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 || !getHasOlder()) return;
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 = getInterruptByMessageId(message.id);
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
- interruptActions.addInterrupt(interrupt);
162
+ fd.interrupts.addInterrupt(interrupt);
171
163
 
172
164
  if (message.status === 'completed') {
173
- interruptActions.resolveInterrupt(interrupt.id, metadata.response_value);
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(getInterruptsMap().values())
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(!getCurrentSession() && displayMessages.length === 0);
193
- const showEmptyChat = $derived(getCurrentSession() !== null && displayMessages.length === 0);
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 (getCurrentSession()) {
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 getIsExecuting()}
268
+ {#if fd.playground.isExecuting}
275
269
  <div class="message-stream__typing">
276
270
  <div class="message-stream__typing-indicator">
277
271
  <span></span>