@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.
- package/LICENSE +21 -0
- package/dist/components/NodeSidebar.svelte +1 -0
- package/dist/components/form/FormCodeEditor.svelte +6 -1
- package/dist/components/interrupt/ChoicePrompt.svelte +389 -0
- package/dist/components/interrupt/ChoicePrompt.svelte.d.ts +21 -0
- package/dist/components/interrupt/ConfirmationPrompt.svelte +280 -0
- package/dist/components/interrupt/ConfirmationPrompt.svelte.d.ts +23 -0
- package/dist/components/interrupt/FormPrompt.svelte +223 -0
- package/dist/components/interrupt/FormPrompt.svelte.d.ts +21 -0
- package/dist/components/interrupt/InterruptBubble.svelte +621 -0
- package/dist/components/interrupt/InterruptBubble.svelte.d.ts +16 -0
- package/dist/components/interrupt/TextInputPrompt.svelte +333 -0
- package/dist/components/interrupt/TextInputPrompt.svelte.d.ts +21 -0
- package/dist/components/interrupt/index.d.ts +13 -0
- package/dist/components/interrupt/index.js +15 -0
- package/dist/components/nodes/GatewayNode.svelte +1 -3
- package/dist/components/nodes/IdeaNode.svelte +30 -35
- package/dist/components/nodes/IdeaNode.svelte.d.ts +1 -1
- package/dist/components/nodes/SimpleNode.svelte +1 -3
- package/dist/components/nodes/TerminalNode.svelte +1 -3
- package/dist/components/nodes/ToolNode.svelte +2 -2
- package/dist/components/nodes/WorkflowNode.svelte +1 -3
- package/dist/components/playground/ChatPanel.svelte +144 -7
- package/dist/components/playground/ChatPanel.svelte.d.ts +2 -0
- package/dist/components/playground/MessageBubble.svelte +1 -3
- package/dist/components/playground/Playground.svelte +50 -5
- package/dist/components/playground/PlaygroundModal.svelte +8 -7
- package/dist/components/playground/PlaygroundModal.svelte.d.ts +3 -3
- package/dist/config/endpoints.d.ts +12 -0
- package/dist/config/endpoints.js +7 -0
- package/dist/playground/index.d.ts +5 -0
- package/dist/playground/index.js +21 -0
- package/dist/playground/mount.d.ts +3 -3
- package/dist/playground/mount.js +30 -22
- package/dist/services/interruptService.d.ts +133 -0
- package/dist/services/interruptService.js +279 -0
- package/dist/stores/interruptStore.d.ts +200 -0
- package/dist/stores/interruptStore.js +424 -0
- package/dist/stores/playgroundStore.d.ts +11 -1
- package/dist/stores/playgroundStore.js +34 -0
- package/dist/styles/base.css +89 -0
- package/dist/types/index.d.ts +1 -1
- package/dist/types/interrupt.d.ts +305 -0
- package/dist/types/interrupt.js +126 -0
- package/dist/types/interruptState.d.ts +211 -0
- package/dist/types/interruptState.js +308 -0
- package/dist/utils/colors.js +1 -0
- package/dist/utils/connections.js +2 -2
- package/dist/utils/icons.js +1 -0
- 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
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
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
|
-
//
|
|
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
|
-
|
|
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
|
|
11
|
-
import Playground from
|
|
12
|
-
import type { Workflow } from
|
|
13
|
-
import type { EndpointConfig } from
|
|
14
|
-
import type { PlaygroundConfig } from
|
|
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 ===
|
|
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
|
-
|
|
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
|
|
2
|
-
import type { EndpointConfig } from
|
|
3
|
-
import type { PlaygroundConfig } from
|
|
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;
|
package/dist/config/endpoints.js
CHANGED
|
@@ -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';
|
package/dist/playground/index.js
CHANGED
|
@@ -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
|
|
47
|
-
import type { EndpointConfig } from
|
|
48
|
-
import type { PlaygroundMode, PlaygroundConfig, PlaygroundSession } from
|
|
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
|
*/
|
package/dist/playground/mount.js
CHANGED
|
@@ -43,13 +43,13 @@
|
|
|
43
43
|
* })(Drupal, window.FlowDrop);
|
|
44
44
|
* ```
|
|
45
45
|
*/
|
|
46
|
-
import { mount, unmount } from
|
|
47
|
-
import Playground from
|
|
48
|
-
import PlaygroundModal from
|
|
49
|
-
import { setEndpointConfig } from
|
|
50
|
-
import { playgroundService } from
|
|
51
|
-
import { currentSession, sessions, messages, playgroundActions } from
|
|
52
|
-
import { get } from
|
|
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 =
|
|
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(
|
|
86
|
+
throw new Error('workflowId is required for mountPlayground()');
|
|
87
87
|
}
|
|
88
88
|
if (!container) {
|
|
89
|
-
throw new Error(
|
|
89
|
+
throw new Error('container element is required for mountPlayground()');
|
|
90
90
|
}
|
|
91
91
|
// Validate onClose for modal mode
|
|
92
|
-
if (mode ===
|
|
93
|
-
throw new Error(
|
|
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(
|
|
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 ===
|
|
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
|
-
|
|
126
|
-
|
|
127
|
-
|
|
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 ===
|
|
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 ===
|
|
214
|
+
if (app && typeof app.destroy === 'function') {
|
|
207
215
|
app.destroy();
|
|
208
216
|
}
|
|
209
217
|
}
|