@d34dman/flowdrop 0.0.37 → 0.0.39

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 (50) hide show
  1. package/LICENSE +21 -0
  2. package/dist/components/NodeSidebar.svelte +1 -0
  3. package/dist/components/form/FormCodeEditor.svelte +6 -1
  4. package/dist/components/interrupt/ChoicePrompt.svelte +389 -0
  5. package/dist/components/interrupt/ChoicePrompt.svelte.d.ts +21 -0
  6. package/dist/components/interrupt/ConfirmationPrompt.svelte +280 -0
  7. package/dist/components/interrupt/ConfirmationPrompt.svelte.d.ts +23 -0
  8. package/dist/components/interrupt/FormPrompt.svelte +223 -0
  9. package/dist/components/interrupt/FormPrompt.svelte.d.ts +21 -0
  10. package/dist/components/interrupt/InterruptBubble.svelte +621 -0
  11. package/dist/components/interrupt/InterruptBubble.svelte.d.ts +16 -0
  12. package/dist/components/interrupt/TextInputPrompt.svelte +333 -0
  13. package/dist/components/interrupt/TextInputPrompt.svelte.d.ts +21 -0
  14. package/dist/components/interrupt/index.d.ts +13 -0
  15. package/dist/components/interrupt/index.js +15 -0
  16. package/dist/components/nodes/GatewayNode.svelte +1 -3
  17. package/dist/components/nodes/IdeaNode.svelte +30 -35
  18. package/dist/components/nodes/IdeaNode.svelte.d.ts +1 -1
  19. package/dist/components/nodes/SimpleNode.svelte +1 -3
  20. package/dist/components/nodes/TerminalNode.svelte +1 -3
  21. package/dist/components/nodes/ToolNode.svelte +2 -2
  22. package/dist/components/nodes/WorkflowNode.svelte +1 -3
  23. package/dist/components/playground/ChatPanel.svelte +144 -7
  24. package/dist/components/playground/ChatPanel.svelte.d.ts +2 -0
  25. package/dist/components/playground/MessageBubble.svelte +1 -3
  26. package/dist/components/playground/Playground.svelte +50 -5
  27. package/dist/components/playground/PlaygroundModal.svelte +8 -7
  28. package/dist/components/playground/PlaygroundModal.svelte.d.ts +3 -3
  29. package/dist/config/endpoints.d.ts +12 -0
  30. package/dist/config/endpoints.js +7 -0
  31. package/dist/playground/index.d.ts +5 -0
  32. package/dist/playground/index.js +21 -0
  33. package/dist/playground/mount.d.ts +3 -3
  34. package/dist/playground/mount.js +30 -22
  35. package/dist/services/interruptService.d.ts +133 -0
  36. package/dist/services/interruptService.js +279 -0
  37. package/dist/stores/interruptStore.d.ts +200 -0
  38. package/dist/stores/interruptStore.js +424 -0
  39. package/dist/stores/playgroundStore.d.ts +11 -1
  40. package/dist/stores/playgroundStore.js +34 -0
  41. package/dist/styles/base.css +89 -0
  42. package/dist/types/index.d.ts +1 -1
  43. package/dist/types/interrupt.d.ts +305 -0
  44. package/dist/types/interrupt.js +126 -0
  45. package/dist/types/interruptState.d.ts +211 -0
  46. package/dist/types/interruptState.js +308 -0
  47. package/dist/utils/colors.js +1 -0
  48. package/dist/utils/connections.js +2 -2
  49. package/dist/utils/icons.js +1 -0
  50. package/package.json +1 -1
@@ -10,7 +10,13 @@
10
10
  import Icon from '@iconify/svelte';
11
11
  import { tick } from 'svelte';
12
12
  import MessageBubble from './MessageBubble.svelte';
13
+ import { InterruptBubble } from '../interrupt/index.js';
13
14
  import type { PlaygroundMessage } from '../../types/playground.js';
15
+ import {
16
+ isInterruptMetadata,
17
+ extractInterruptMetadata,
18
+ metadataToInterrupt
19
+ } from '../../types/interrupt.js';
14
20
  import {
15
21
  messages,
16
22
  chatMessages,
@@ -18,6 +24,11 @@
18
24
  sessionStatus,
19
25
  currentSession
20
26
  } from '../../stores/playgroundStore.js';
27
+ import {
28
+ interrupts,
29
+ interruptActions,
30
+ getInterruptByMessageId
31
+ } from '../../stores/interruptStore.js';
21
32
 
22
33
  /**
23
34
  * Component props
@@ -37,6 +48,8 @@
37
48
  showLogsInline?: boolean;
38
49
  /** Whether to enable markdown rendering in messages */
39
50
  enableMarkdown?: boolean;
51
+ /** Callback when an interrupt is resolved (to refresh messages) */
52
+ onInterruptResolved?: () => void;
40
53
  }
41
54
 
42
55
  let {
@@ -46,7 +59,8 @@
46
59
  onSendMessage,
47
60
  onStopExecution,
48
61
  showLogsInline = false,
49
- enableMarkdown = true
62
+ enableMarkdown = true,
63
+ onInterruptResolved
50
64
  }: Props = $props();
51
65
 
52
66
  /** Input field value */
@@ -63,6 +77,71 @@
63
77
  */
64
78
  const displayMessages = $derived(showLogsInline ? $messages : $chatMessages);
65
79
 
80
+ /**
81
+ * Check if a message is an interrupt request
82
+ */
83
+ function isInterruptMessage(message: PlaygroundMessage): boolean {
84
+ return isInterruptMetadata(message.metadata as Record<string, unknown> | undefined);
85
+ }
86
+
87
+ /**
88
+ * Sync interrupt messages to the interrupt store.
89
+ * This effect runs when messages change and adds any new interrupt messages
90
+ * to the interrupt store. We do this in an effect rather than during render
91
+ * to avoid Svelte 5's state_unsafe_mutation error.
92
+ *
93
+ * If a message has status 'completed', the interrupt is marked as resolved
94
+ * to show the "Confirmation Submitted" header, disabled buttons, and
95
+ * "Response submitted" indicator.
96
+ */
97
+ $effect(() => {
98
+ // Get all messages that are interrupt requests
99
+ const interruptMessages = displayMessages.filter(isInterruptMessage);
100
+
101
+ for (const message of interruptMessages) {
102
+ // Check if we already have this interrupt in the store
103
+ const existing = getInterruptByMessageId(message.id);
104
+ if (!existing) {
105
+ // Extract and validate interrupt metadata
106
+ const metadata = extractInterruptMetadata(
107
+ message.metadata as Record<string, unknown> | undefined
108
+ );
109
+ if (metadata) {
110
+ const interrupt = metadataToInterrupt(metadata, message.id, message.content);
111
+ interruptActions.addInterrupt(interrupt);
112
+
113
+ // If the message status is 'completed', mark the interrupt as resolved
114
+ // This ensures completed interrupts show proper UI state:
115
+ // - "Confirmation Submitted" header
116
+ // - Disabled buttons
117
+ // - "Response submitted" indicator
118
+ if (message.status === 'completed') {
119
+ interruptActions.resolveInterrupt(interrupt.id, metadata.response_value);
120
+ }
121
+ }
122
+ }
123
+ }
124
+ });
125
+
126
+ /**
127
+ * Reactive map of message IDs to interrupts.
128
+ * This ensures the component re-renders when interrupts are added to the store.
129
+ */
130
+ const interruptsByMessageId = $derived(
131
+ new Map(
132
+ Array.from($interrupts.values())
133
+ .filter((i) => i.messageId)
134
+ .map((i) => [i.messageId, i])
135
+ )
136
+ );
137
+
138
+ /**
139
+ * Get interrupt data for a message from the reactive map
140
+ */
141
+ function getInterruptForMessage(message: PlaygroundMessage) {
142
+ return interruptsByMessageId.get(message.id);
143
+ }
144
+
66
145
  /**
67
146
  * Check if we should show the welcome state
68
147
  */
@@ -126,6 +205,52 @@
126
205
  }
127
206
  });
128
207
 
208
+ /**
209
+ * Track previous executing state to detect when execution completes
210
+ */
211
+ let wasExecuting = $state(false);
212
+
213
+ /**
214
+ * Auto-focus input when execution completes or session becomes ready
215
+ */
216
+ $effect(() => {
217
+ const currentlyExecuting = $isExecuting;
218
+
219
+ // Focus input when execution completes (was executing, now not)
220
+ if (wasExecuting && !currentlyExecuting && inputField) {
221
+ tick().then(() => {
222
+ inputField?.focus();
223
+ });
224
+ }
225
+
226
+ // Update tracking state
227
+ wasExecuting = currentlyExecuting;
228
+ });
229
+
230
+ /**
231
+ * Focus input when session status changes to idle or completed
232
+ */
233
+ $effect(() => {
234
+ const status = $sessionStatus;
235
+ if ((status === 'idle' || status === 'completed') && inputField && !$isExecuting) {
236
+ tick().then(() => {
237
+ inputField?.focus();
238
+ });
239
+ }
240
+ });
241
+
242
+ /**
243
+ * Focus input when a new session is created/loaded
244
+ */
245
+ $effect(() => {
246
+ const session = $currentSession;
247
+ if (session && inputField && !$isExecuting) {
248
+ tick().then(() => {
249
+ inputField?.focus();
250
+ });
251
+ }
252
+ });
253
+
129
254
  /**
130
255
  * Auto-resize textarea based on content
131
256
  */
@@ -205,12 +330,24 @@
205
330
  {:else}
206
331
  <!-- Messages -->
207
332
  {#each displayMessages as message, index (message.id)}
208
- <MessageBubble
209
- {message}
210
- showTimestamp={showTimestamps}
211
- isLast={index === displayMessages.length - 1}
212
- {enableMarkdown}
213
- />
333
+ {#if isInterruptMessage(message)}
334
+ <!-- Render interrupt inline -->
335
+ {@const interrupt = getInterruptForMessage(message)}
336
+ {#if interrupt}
337
+ <InterruptBubble
338
+ {interrupt}
339
+ showTimestamp={showTimestamps}
340
+ onResolved={onInterruptResolved}
341
+ />
342
+ {/if}
343
+ {:else}
344
+ <MessageBubble
345
+ {message}
346
+ showTimestamp={showTimestamps}
347
+ isLast={index === displayMessages.length - 1}
348
+ {enableMarkdown}
349
+ />
350
+ {/if}
214
351
  {/each}
215
352
 
216
353
  {#if $isExecuting}
@@ -16,6 +16,8 @@ interface Props {
16
16
  showLogsInline?: boolean;
17
17
  /** Whether to enable markdown rendering in messages */
18
18
  enableMarkdown?: boolean;
19
+ /** Callback when an interrupt is resolved (to refresh messages) */
20
+ onInterruptResolved?: () => void;
19
21
  }
20
22
  declare const ChatPanel: import("svelte").Component<Props, {}, "">;
21
23
  type ChatPanel = ReturnType<typeof ChatPanel>;
@@ -32,9 +32,7 @@
32
32
  * Render content as markdown or plain text
33
33
  */
34
34
  const renderedContent = $derived(
35
- enableMarkdown && message.role !== 'log'
36
- ? marked.parse(message.content || '')
37
- : message.content
35
+ enableMarkdown && message.role !== 'log' ? marked.parse(message.content || '') : message.content
38
36
  );
39
37
 
40
38
  /**
@@ -19,6 +19,7 @@
19
19
  PlaygroundMessagesApiResponse
20
20
  } from '../../types/playground.js';
21
21
  import { playgroundService } from '../../services/playgroundService.js';
22
+ import { interruptService } from '../../services/interruptService.js';
22
23
  import { setEndpointConfig } from '../../services/api.js';
23
24
  import {
24
25
  currentSession,
@@ -30,6 +31,7 @@
30
31
  playgroundActions,
31
32
  inputFields
32
33
  } from '../../stores/playgroundStore.js';
34
+ import { interruptActions } from '../../stores/interruptStore.js';
33
35
  import { get } from 'svelte/store';
34
36
 
35
37
  /**
@@ -109,7 +111,9 @@
109
111
  */
110
112
  onDestroy(() => {
111
113
  playgroundService.stopPolling();
114
+ interruptService.stopPolling();
112
115
  playgroundActions.reset();
116
+ interruptActions.reset();
113
117
  });
114
118
 
115
119
  /**
@@ -241,8 +245,14 @@
241
245
  */
242
246
  function handleCloseSession(): void {
243
247
  playgroundService.stopPolling();
248
+ interruptService.stopPolling();
244
249
  playgroundActions.setCurrentSession(null);
245
250
  playgroundActions.clearMessages();
251
+ // Clear interrupts for this session
252
+ const sessionId = get(currentSession)?.id;
253
+ if (sessionId) {
254
+ interruptActions.clearSessionInterrupts(sessionId);
255
+ }
246
256
  }
247
257
 
248
258
  /**
@@ -335,12 +345,46 @@
335
345
  playgroundActions.addMessages(response.data);
336
346
  }
337
347
 
348
+ // Update session status
349
+ if (response.sessionStatus) {
350
+ playgroundActions.updateSessionStatus(response.sessionStatus);
351
+
352
+ // Stop executing if idle, completed, or failed
353
+ // "idle" means no processing is happening (execution finished)
354
+ if (
355
+ response.sessionStatus === 'idle' ||
356
+ response.sessionStatus === 'completed' ||
357
+ response.sessionStatus === 'failed'
358
+ ) {
359
+ playgroundActions.setExecuting(false);
360
+ }
361
+ }
362
+ },
363
+ pollingInterval
364
+ );
365
+ }
366
+
367
+ /**
368
+ * Refresh messages for the current session
369
+ * Called after interrupt resolution when polling has stopped
370
+ */
371
+ async function handleInterruptResolved(): Promise<void> {
372
+ const sessionId = get(currentSession)?.id;
373
+ if (!sessionId) return;
374
+
375
+ try {
376
+ const response = await playgroundService.getMessages(sessionId);
377
+
378
+ // Add new messages (deduplicates automatically)
379
+ if (response.data && response.data.length > 0) {
380
+ playgroundActions.addMessages(response.data);
381
+ }
382
+
338
383
  // Update session status
339
384
  if (response.sessionStatus) {
340
385
  playgroundActions.updateSessionStatus(response.sessionStatus);
341
386
 
342
- // Stop executing if idle, completed, or failed
343
- // "idle" means no processing is happening (execution finished)
387
+ // Update executing state based on session status
344
388
  if (
345
389
  response.sessionStatus === 'idle' ||
346
390
  response.sessionStatus === 'completed' ||
@@ -349,9 +393,9 @@
349
393
  playgroundActions.setExecuting(false);
350
394
  }
351
395
  }
352
- },
353
- pollingInterval
354
- );
396
+ } catch (err) {
397
+ console.error('[Playground] Failed to refresh messages after interrupt:', err);
398
+ }
355
399
  }
356
400
 
357
401
  /**
@@ -521,6 +565,7 @@
521
565
  enableMarkdown={config.enableMarkdown ?? true}
522
566
  onSendMessage={handleSendMessage}
523
567
  onStopExecution={handleStopExecution}
568
+ onInterruptResolved={handleInterruptResolved}
524
569
  />
525
570
  {/if}
526
571
  </div>
@@ -7,11 +7,11 @@
7
7
  -->
8
8
 
9
9
  <script lang="ts">
10
- import Icon from "@iconify/svelte";
11
- import Playground from "./Playground.svelte";
12
- import type { Workflow } from "../../types/index.js";
13
- import type { EndpointConfig } from "../../config/endpoints.js";
14
- import type { PlaygroundConfig } from "../../types/playground.js";
10
+ import Icon from '@iconify/svelte';
11
+ import Playground from './Playground.svelte';
12
+ import type { Workflow } from '../../types/index.js';
13
+ import type { EndpointConfig } from '../../config/endpoints.js';
14
+ import type { PlaygroundConfig } from '../../types/playground.js';
15
15
 
16
16
  /**
17
17
  * Component props
@@ -47,7 +47,7 @@
47
47
  * Close modal on Escape key
48
48
  */
49
49
  function handleKeydown(event: KeyboardEvent): void {
50
- if (event.key === "Escape") {
50
+ if (event.key === 'Escape') {
51
51
  onClose();
52
52
  }
53
53
  }
@@ -74,7 +74,8 @@
74
74
  tabindex="-1"
75
75
  >
76
76
  <!-- Modal Container -->
77
- <div class="playground-modal" onclick={(e) => e.stopPropagation()}>
77
+ <!-- svelte-ignore a11y_no_static_element_interactions a11y_click_events_have_key_events -->
78
+ <div class="playground-modal" onclick={(e) => e.stopPropagation()} role="presentation">
78
79
  <!-- Modal Header -->
79
80
  <div class="playground-modal__header">
80
81
  <div class="playground-modal__title" id="playground-modal-title">
@@ -1,6 +1,6 @@
1
- import type { Workflow } from "../../types/index.js";
2
- import type { EndpointConfig } from "../../config/endpoints.js";
3
- import type { PlaygroundConfig } from "../../types/playground.js";
1
+ import type { Workflow } from '../../types/index.js';
2
+ import type { EndpointConfig } from '../../config/endpoints.js';
3
+ import type { PlaygroundConfig } from '../../types/playground.js';
4
4
  /**
5
5
  * Component props
6
6
  */
@@ -58,6 +58,18 @@ export interface EndpointConfig {
58
58
  /** Stop execution in a session */
59
59
  stopExecution: string;
60
60
  };
61
+ interrupts: {
62
+ /** Get interrupt details by ID */
63
+ get: string;
64
+ /** Resolve an interrupt with user response */
65
+ resolve: string;
66
+ /** Cancel a pending interrupt */
67
+ cancel: string;
68
+ /** List interrupts for a playground session */
69
+ listBySession: string;
70
+ /** List interrupts for a pipeline */
71
+ listByPipeline: string;
72
+ };
61
73
  templates: {
62
74
  list: string;
63
75
  get: string;
@@ -52,6 +52,13 @@ export const defaultEndpointConfig = {
52
52
  sendMessage: '/playground/sessions/{sessionId}/messages',
53
53
  stopExecution: '/playground/sessions/{sessionId}/stop'
54
54
  },
55
+ interrupts: {
56
+ get: '/interrupts/{interruptId}',
57
+ resolve: '/interrupts/{interruptId}',
58
+ cancel: '/interrupts/{interruptId}/cancel',
59
+ listBySession: '/playground/sessions/{sessionId}/interrupts',
60
+ listByPipeline: '/pipelines/{pipelineId}/interrupts'
61
+ },
55
62
  templates: {
56
63
  list: '/templates',
57
64
  get: '/templates/{id}',
@@ -117,9 +117,14 @@ export { default as SessionManager } from '../components/playground/SessionManag
117
117
  export { default as InputCollector } from '../components/playground/InputCollector.svelte';
118
118
  export { default as ExecutionLogs } from '../components/playground/ExecutionLogs.svelte';
119
119
  export { default as MessageBubble } from '../components/playground/MessageBubble.svelte';
120
+ export { InterruptBubble, ConfirmationPrompt, ChoicePrompt, TextInputPrompt, FormPrompt } from '../components/interrupt/index.js';
120
121
  export { PlaygroundService, playgroundService } from '../services/playgroundService.js';
122
+ export { InterruptService, interruptService } from '../services/interruptService.js';
121
123
  export { currentSession, sessions, messages, isExecuting, isLoading, error as playgroundError, currentWorkflow, lastPollTimestamp, sessionStatus, messageCount, chatMessages, logMessages, latestMessage, inputFields, hasChatInput, sessionCount, playgroundActions, getCurrentSessionId, isSessionSelected, getMessagesSnapshot, getLatestMessageTimestamp } from '../stores/playgroundStore.js';
122
124
  export type { PlaygroundSession, PlaygroundMessage, PlaygroundInputField, PlaygroundMessageRequest, PlaygroundMessagesResult, PlaygroundConfig, PlaygroundMode, PlaygroundSessionStatus, PlaygroundMessageRole, PlaygroundMessageLevel, PlaygroundMessageMetadata, PlaygroundApiResponse, PlaygroundSessionsResponse, PlaygroundSessionResponse, PlaygroundMessageResponse, PlaygroundMessagesApiResponse } from '../types/playground.js';
123
125
  export { isChatInputNode, CHAT_INPUT_PATTERNS } from '../types/playground.js';
126
+ export type { InterruptType, InterruptStatus, Interrupt, InterruptChoice, InterruptConfig, ConfirmationConfig, ChoiceConfig, TextConfig, FormConfig, InterruptResolution, InterruptApiResponse, InterruptListResponse, InterruptResponse, InterruptMessageMetadata, InterruptPollingConfig } from '../types/interrupt.js';
127
+ export { isInterruptMetadata, extractInterruptMetadata, metadataToInterrupt, defaultInterruptPollingConfig } from '../types/interrupt.js';
128
+ export { interrupts, submittingInterrupts, interruptErrors, pendingInterruptIds, pendingInterrupts, pendingInterruptCount, resolvedInterrupts, isAnySubmitting, interruptActions, getInterrupt, isInterruptPending, isInterruptSubmitting, getInterruptError, getInterruptByMessageId } from '../stores/interruptStore.js';
124
129
  export { mountPlayground, unmountPlayground, type PlaygroundMountOptions, type MountedPlayground } from './mount.js';
125
130
  export { createEndpointConfig, defaultEndpointConfig, buildEndpointUrl, type EndpointConfig } from '../config/endpoints.js';
@@ -121,10 +121,18 @@ export { default as InputCollector } from '../components/playground/InputCollect
121
121
  export { default as ExecutionLogs } from '../components/playground/ExecutionLogs.svelte';
122
122
  export { default as MessageBubble } from '../components/playground/MessageBubble.svelte';
123
123
  // ============================================================================
124
+ // Interrupt Components (Human-in-the-Loop)
125
+ // ============================================================================
126
+ export { InterruptBubble, ConfirmationPrompt, ChoicePrompt, TextInputPrompt, FormPrompt } from '../components/interrupt/index.js';
127
+ // ============================================================================
124
128
  // Playground Service
125
129
  // ============================================================================
126
130
  export { PlaygroundService, playgroundService } from '../services/playgroundService.js';
127
131
  // ============================================================================
132
+ // Interrupt Service (Human-in-the-Loop)
133
+ // ============================================================================
134
+ export { InterruptService, interruptService } from '../services/interruptService.js';
135
+ // ============================================================================
128
136
  // Playground Store
129
137
  // ============================================================================
130
138
  export {
@@ -137,6 +145,19 @@ playgroundActions,
137
145
  // Utilities
138
146
  getCurrentSessionId, isSessionSelected, getMessagesSnapshot, getLatestMessageTimestamp } from '../stores/playgroundStore.js';
139
147
  export { isChatInputNode, CHAT_INPUT_PATTERNS } from '../types/playground.js';
148
+ export { isInterruptMetadata, extractInterruptMetadata, metadataToInterrupt, defaultInterruptPollingConfig } from '../types/interrupt.js';
149
+ // ============================================================================
150
+ // Interrupt Store (Human-in-the-Loop)
151
+ // ============================================================================
152
+ export {
153
+ // Core stores
154
+ interrupts, submittingInterrupts, interruptErrors,
155
+ // Derived stores
156
+ pendingInterruptIds, pendingInterrupts, pendingInterruptCount, resolvedInterrupts, isAnySubmitting,
157
+ // Actions
158
+ interruptActions,
159
+ // Utilities
160
+ getInterrupt, isInterruptPending, isInterruptSubmitting, getInterruptError, getInterruptByMessageId } from '../stores/interruptStore.js';
140
161
  // ============================================================================
141
162
  // Playground Mount Functions (for vanilla JS / Drupal / IIFE integration)
142
163
  // ============================================================================
@@ -43,9 +43,9 @@
43
43
  * })(Drupal, window.FlowDrop);
44
44
  * ```
45
45
  */
46
- import type { Workflow } from "../types/index.js";
47
- import type { EndpointConfig } from "../config/endpoints.js";
48
- import type { PlaygroundMode, PlaygroundConfig, PlaygroundSession } from "../types/playground.js";
46
+ import type { Workflow } from '../types/index.js';
47
+ import type { EndpointConfig } from '../config/endpoints.js';
48
+ import type { PlaygroundMode, PlaygroundConfig, PlaygroundSession } from '../types/playground.js';
49
49
  /**
50
50
  * Mount options for Playground component
51
51
  */
@@ -43,13 +43,13 @@
43
43
  * })(Drupal, window.FlowDrop);
44
44
  * ```
45
45
  */
46
- import { mount, unmount } from "svelte";
47
- import Playground from "../components/playground/Playground.svelte";
48
- import PlaygroundModal from "../components/playground/PlaygroundModal.svelte";
49
- import { setEndpointConfig } from "../services/api.js";
50
- import { playgroundService } from "../services/playgroundService.js";
51
- import { currentSession, sessions, messages, playgroundActions } from "../stores/playgroundStore.js";
52
- import { get } from "svelte/store";
46
+ import { mount, unmount } from 'svelte';
47
+ import Playground from '../components/playground/Playground.svelte';
48
+ import PlaygroundModal from '../components/playground/PlaygroundModal.svelte';
49
+ import { setEndpointConfig } from '../services/api.js';
50
+ import { playgroundService } from '../services/playgroundService.js';
51
+ import { currentSession, sessions, messages, playgroundActions } from '../stores/playgroundStore.js';
52
+ import { get } from 'svelte/store';
53
53
  /**
54
54
  * Mount the Playground component in a container
55
55
  *
@@ -80,23 +80,23 @@ import { get } from "svelte/store";
80
80
  * ```
81
81
  */
82
82
  export async function mountPlayground(container, options) {
83
- const { workflowId, workflow, mode = "standalone", initialSessionId, endpointConfig, config = {}, height = "100%", width = "100%", onClose } = options;
83
+ const { workflowId, workflow, mode = 'standalone', initialSessionId, endpointConfig, config = {}, height = '100%', width = '100%', onClose } = options;
84
84
  // Validate required parameters
85
85
  if (!workflowId) {
86
- throw new Error("workflowId is required for mountPlayground()");
86
+ throw new Error('workflowId is required for mountPlayground()');
87
87
  }
88
88
  if (!container) {
89
- throw new Error("container element is required for mountPlayground()");
89
+ throw new Error('container element is required for mountPlayground()');
90
90
  }
91
91
  // Validate onClose for modal mode
92
- if (mode === "modal" && !onClose) {
93
- throw new Error("onClose callback is required for modal mode");
92
+ if (mode === 'modal' && !onClose) {
93
+ throw new Error('onClose callback is required for modal mode');
94
94
  }
95
95
  // Set endpoint configuration if provided
96
96
  let finalEndpointConfig;
97
97
  if (endpointConfig) {
98
98
  // Merge with default configuration to ensure all required endpoints are present
99
- const { defaultEndpointConfig } = await import("../config/endpoints.js");
99
+ const { defaultEndpointConfig } = await import('../config/endpoints.js');
100
100
  finalEndpointConfig = {
101
101
  ...defaultEndpointConfig,
102
102
  ...endpointConfig,
@@ -111,7 +111,7 @@ export async function mountPlayground(container, options) {
111
111
  // For modal mode, PlaygroundModal creates its own backdrop, so we mount directly to body
112
112
  // For other modes, use the provided container
113
113
  let targetContainer = container;
114
- if (mode === "modal") {
114
+ if (mode === 'modal') {
115
115
  // For modal mode, create a container in the body
116
116
  // PlaygroundModal will handle the backdrop itself
117
117
  targetContainer = document.body;
@@ -122,10 +122,12 @@ export async function mountPlayground(container, options) {
122
122
  container.style.width = width;
123
123
  }
124
124
  // Mount the appropriate component
125
- const svelteApp = mount(mode === "modal" ? PlaygroundModal : Playground, {
126
- target: targetContainer,
127
- props: mode === "modal"
128
- ? {
125
+ // Separate the mount calls to avoid TypeScript inference issues with different props types
126
+ let svelteApp;
127
+ if (mode === 'modal') {
128
+ svelteApp = mount(PlaygroundModal, {
129
+ target: targetContainer,
130
+ props: {
129
131
  isOpen: true,
130
132
  workflowId,
131
133
  workflow,
@@ -138,7 +140,12 @@ export async function mountPlayground(container, options) {
138
140
  }
139
141
  }
140
142
  }
141
- : {
143
+ });
144
+ }
145
+ else {
146
+ svelteApp = mount(Playground, {
147
+ target: targetContainer,
148
+ props: {
142
149
  workflowId,
143
150
  workflow,
144
151
  mode,
@@ -147,12 +154,13 @@ export async function mountPlayground(container, options) {
147
154
  config,
148
155
  onClose
149
156
  }
150
- });
157
+ });
158
+ }
151
159
  // Store state for cleanup
152
160
  const state = {
153
161
  svelteApp,
154
162
  container: targetContainer,
155
- originalContainer: mode === "modal" ? container : undefined,
163
+ originalContainer: mode === 'modal' ? container : undefined,
156
164
  workflowId
157
165
  };
158
166
  // Create the mounted playground interface
@@ -203,7 +211,7 @@ export async function mountPlayground(container, options) {
203
211
  * ```
204
212
  */
205
213
  export function unmountPlayground(app) {
206
- if (app && typeof app.destroy === "function") {
214
+ if (app && typeof app.destroy === 'function') {
207
215
  app.destroy();
208
216
  }
209
217
  }