@flowdrop/flowdrop 1.10.0 → 1.12.0
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/dist/api/enhanced-client.d.ts +29 -16
- package/dist/api/enhanced-client.js +0 -14
- package/dist/components/Navbar.svelte +1 -10
- package/dist/components/Navbar.svelte.d.ts +1 -9
- package/dist/components/PipelineStatus.svelte +9 -12
- package/dist/components/WorkflowEditor.svelte +3 -0
- package/dist/components/interrupt/ChoicePrompt.svelte +24 -5
- package/dist/components/interrupt/ConfirmationPrompt.svelte +5 -0
- package/dist/components/interrupt/InterruptBubble.svelte +12 -0
- package/dist/components/interrupt/ReviewPrompt.svelte +20 -0
- package/dist/components/interrupt/TextInputPrompt.svelte +5 -0
- package/dist/components/nodes/GatewayNode.svelte +2 -6
- package/dist/components/nodes/WorkflowNode.svelte +2 -6
- package/dist/components/playground/ChatInput.svelte +359 -0
- package/dist/components/playground/ChatInput.svelte.d.ts +14 -0
- package/dist/components/playground/ChatPanel.svelte +100 -724
- package/dist/components/playground/ChatPanel.svelte.d.ts +9 -26
- package/dist/components/playground/ControlPanel.svelte +496 -0
- package/dist/components/playground/ControlPanel.svelte.d.ts +20 -0
- package/dist/components/playground/ExecutionConsole.svelte +163 -0
- package/dist/components/playground/ExecutionConsole.svelte.d.ts +14 -0
- package/dist/components/playground/MessageStream.svelte +283 -0
- package/dist/components/playground/MessageStream.svelte.d.ts +27 -0
- package/dist/components/playground/PipelineKanbanView.svelte +284 -0
- package/dist/components/playground/PipelineKanbanView.svelte.d.ts +11 -0
- package/dist/components/playground/PipelinePanel.svelte +204 -65
- package/dist/components/playground/PipelinePanel.svelte.d.ts +3 -1
- package/dist/components/playground/PipelineTableView.svelte +376 -0
- package/dist/components/playground/PipelineTableView.svelte.d.ts +11 -0
- package/dist/components/playground/Playground.svelte +262 -1200
- package/dist/components/playground/Playground.svelte.d.ts +0 -13
- package/dist/components/playground/PlaygroundApp.svelte +110 -0
- package/dist/components/playground/PlaygroundApp.svelte.d.ts +28 -0
- package/dist/components/playground/PlaygroundStudio.svelte +35 -61
- package/dist/components/playground/PlaygroundStudio.svelte.d.ts +3 -1
- package/dist/components/playground/pipelineViewUtils.svelte.d.ts +22 -0
- package/dist/components/playground/pipelineViewUtils.svelte.js +77 -0
- package/dist/messages/defaults.d.ts +24 -0
- package/dist/messages/defaults.js +24 -0
- package/dist/playground/index.d.ts +8 -2
- package/dist/playground/index.js +8 -1
- package/dist/playground/mount.d.ts +59 -4
- package/dist/playground/mount.js +102 -9
- package/dist/stores/playgroundStore.svelte.d.ts +6 -0
- package/dist/stores/playgroundStore.svelte.js +21 -1
- package/dist/svelte-app.d.ts +2 -10
- package/dist/types/index.d.ts +28 -2
- package/dist/types/navbar.d.ts +14 -0
- package/dist/types/navbar.js +1 -0
- package/dist/types/playground.d.ts +5 -2
- package/dist/types/playground.js +5 -7
- package/dist/utils/nodeStatus.js +15 -5
- package/package.json +1 -1
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
ExecutionConsole Component
|
|
3
|
+
|
|
4
|
+
The running workflow's runtime surface. Renders the message feed via
|
|
5
|
+
MessageStream and surfaces the flow's own UI (interrupts) inline during
|
|
6
|
+
execution. This is *not* a chat — it's the console where the flow speaks
|
|
7
|
+
to the user during a run. User-initiated commands live in ControlPanel.
|
|
8
|
+
-->
|
|
9
|
+
|
|
10
|
+
<script lang="ts">
|
|
11
|
+
import Icon from '@iconify/svelte';
|
|
12
|
+
import MessageStream from './MessageStream.svelte';
|
|
13
|
+
import { m } from '../../messages/index.js';
|
|
14
|
+
|
|
15
|
+
interface Props {
|
|
16
|
+
showTimestamps?: boolean;
|
|
17
|
+
autoScroll?: boolean;
|
|
18
|
+
enableMarkdown?: boolean;
|
|
19
|
+
/** Whether log messages can appear when the user toggle is on. Defaults to true for the execution console. */
|
|
20
|
+
allowLogs?: boolean;
|
|
21
|
+
compactSystemMessages?: boolean;
|
|
22
|
+
onInterruptResolved?: () => void;
|
|
23
|
+
/** Optional callback that, when provided, shows a "New session" CTA in the welcome state */
|
|
24
|
+
onCreateSession?: () => void;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
let {
|
|
28
|
+
showTimestamps = true,
|
|
29
|
+
autoScroll = true,
|
|
30
|
+
enableMarkdown = true,
|
|
31
|
+
allowLogs = true,
|
|
32
|
+
compactSystemMessages = true,
|
|
33
|
+
onInterruptResolved,
|
|
34
|
+
onCreateSession
|
|
35
|
+
}: Props = $props();
|
|
36
|
+
|
|
37
|
+
const ec = $derived(m().playground.executionConsole);
|
|
38
|
+
</script>
|
|
39
|
+
|
|
40
|
+
<section class="execution-console">
|
|
41
|
+
<header class="execution-console__header">
|
|
42
|
+
<Icon icon="mdi:console-line" class="execution-console__icon" />
|
|
43
|
+
<span class="execution-console__title">{ec.header}</span>
|
|
44
|
+
</header>
|
|
45
|
+
|
|
46
|
+
<MessageStream
|
|
47
|
+
{showTimestamps}
|
|
48
|
+
{autoScroll}
|
|
49
|
+
{enableMarkdown}
|
|
50
|
+
{allowLogs}
|
|
51
|
+
{compactSystemMessages}
|
|
52
|
+
{onInterruptResolved}
|
|
53
|
+
welcome={welcomeState}
|
|
54
|
+
emptySession={readyState}
|
|
55
|
+
/>
|
|
56
|
+
</section>
|
|
57
|
+
|
|
58
|
+
{#snippet welcomeState()}
|
|
59
|
+
<div class="execution-console__placeholder">
|
|
60
|
+
<Icon icon="mdi:play-circle-outline" class="execution-console__placeholder-icon" />
|
|
61
|
+
<h2 class="execution-console__placeholder-title">{ec.noExecutionTitle}</h2>
|
|
62
|
+
<p class="execution-console__placeholder-text">{ec.noExecutionText}</p>
|
|
63
|
+
{#if onCreateSession}
|
|
64
|
+
<button type="button" class="execution-console__cta" onclick={onCreateSession}>
|
|
65
|
+
<Icon icon="mdi:plus" />
|
|
66
|
+
{ec.newSession}
|
|
67
|
+
</button>
|
|
68
|
+
{/if}
|
|
69
|
+
</div>
|
|
70
|
+
{/snippet}
|
|
71
|
+
|
|
72
|
+
{#snippet readyState()}
|
|
73
|
+
<div class="execution-console__placeholder">
|
|
74
|
+
<Icon icon="mdi:play-circle-outline" class="execution-console__placeholder-icon" />
|
|
75
|
+
<h2 class="execution-console__placeholder-title">{ec.readyTitle}</h2>
|
|
76
|
+
<p class="execution-console__placeholder-text">{ec.readyText}</p>
|
|
77
|
+
</div>
|
|
78
|
+
{/snippet}
|
|
79
|
+
|
|
80
|
+
<style>
|
|
81
|
+
.execution-console {
|
|
82
|
+
flex: 1;
|
|
83
|
+
min-height: 0;
|
|
84
|
+
display: flex;
|
|
85
|
+
flex-direction: column;
|
|
86
|
+
overflow: hidden;
|
|
87
|
+
background-color: var(--fd-background);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.execution-console__header {
|
|
91
|
+
display: flex;
|
|
92
|
+
align-items: center;
|
|
93
|
+
gap: var(--fd-space-xs);
|
|
94
|
+
padding: 0 var(--fd-space-xl);
|
|
95
|
+
height: var(--fd-playground-header-height);
|
|
96
|
+
min-height: var(--fd-playground-header-height);
|
|
97
|
+
border-bottom: 1px solid var(--fd-border);
|
|
98
|
+
flex-shrink: 0;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
:global(.execution-console__icon) {
|
|
102
|
+
font-size: var(--fd-text-base);
|
|
103
|
+
color: var(--fd-muted-foreground);
|
|
104
|
+
flex-shrink: 0;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.execution-console__title {
|
|
108
|
+
font-size: var(--fd-text-sm);
|
|
109
|
+
font-weight: 600;
|
|
110
|
+
color: var(--fd-foreground);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.execution-console__placeholder {
|
|
114
|
+
display: flex;
|
|
115
|
+
flex-direction: column;
|
|
116
|
+
align-items: center;
|
|
117
|
+
justify-content: center;
|
|
118
|
+
height: 100%;
|
|
119
|
+
text-align: center;
|
|
120
|
+
padding: var(--fd-space-4xl);
|
|
121
|
+
color: var(--fd-muted-foreground);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
:global(.execution-console__placeholder-icon) {
|
|
125
|
+
font-size: var(--fd-space-6xl);
|
|
126
|
+
color: var(--fd-border-strong);
|
|
127
|
+
margin-bottom: var(--fd-space-xl);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
.execution-console__placeholder-title {
|
|
131
|
+
font-size: var(--fd-text-xl);
|
|
132
|
+
font-weight: 600;
|
|
133
|
+
color: var(--fd-foreground);
|
|
134
|
+
margin: 0 0 var(--fd-space-xs) 0;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
.execution-console__placeholder-text {
|
|
138
|
+
font-size: var(--fd-text-sm);
|
|
139
|
+
color: var(--fd-muted-foreground);
|
|
140
|
+
margin: 0;
|
|
141
|
+
max-width: 360px;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
.execution-console__cta {
|
|
145
|
+
display: inline-flex;
|
|
146
|
+
align-items: center;
|
|
147
|
+
gap: var(--fd-space-xs);
|
|
148
|
+
margin-top: var(--fd-space-2xl);
|
|
149
|
+
padding: var(--fd-space-sm) var(--fd-space-xl);
|
|
150
|
+
border: none;
|
|
151
|
+
border-radius: var(--fd-radius-md);
|
|
152
|
+
background: var(--fd-primary);
|
|
153
|
+
color: var(--fd-primary-foreground);
|
|
154
|
+
font-size: var(--fd-text-base);
|
|
155
|
+
font-weight: 500;
|
|
156
|
+
cursor: pointer;
|
|
157
|
+
transition: opacity var(--fd-transition-fast);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
.execution-console__cta:hover {
|
|
161
|
+
opacity: 0.9;
|
|
162
|
+
}
|
|
163
|
+
</style>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
interface Props {
|
|
2
|
+
showTimestamps?: boolean;
|
|
3
|
+
autoScroll?: boolean;
|
|
4
|
+
enableMarkdown?: boolean;
|
|
5
|
+
/** Whether log messages can appear when the user toggle is on. Defaults to true for the execution console. */
|
|
6
|
+
allowLogs?: boolean;
|
|
7
|
+
compactSystemMessages?: boolean;
|
|
8
|
+
onInterruptResolved?: () => void;
|
|
9
|
+
/** Optional callback that, when provided, shows a "New session" CTA in the welcome state */
|
|
10
|
+
onCreateSession?: () => void;
|
|
11
|
+
}
|
|
12
|
+
declare const ExecutionConsole: import("svelte").Component<Props, {}, "">;
|
|
13
|
+
type ExecutionConsole = ReturnType<typeof ExecutionConsole>;
|
|
14
|
+
export default ExecutionConsole;
|
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
MessageStream Component
|
|
3
|
+
|
|
4
|
+
Renders the playground message feed with interrupt UI inline. No input area.
|
|
5
|
+
This is the shared primitive used by ChatPanel (conversational) and
|
|
6
|
+
ExecutionConsole (workflow runtime surface).
|
|
7
|
+
|
|
8
|
+
The empty/welcome state is delegated to consumers via the `welcome` and
|
|
9
|
+
`emptySession` snippets so each wrapper renders context-appropriate copy.
|
|
10
|
+
-->
|
|
11
|
+
|
|
12
|
+
<script lang="ts">
|
|
13
|
+
import { tick, untrack, type Snippet } from 'svelte';
|
|
14
|
+
import MessageBubble from './MessageBubble.svelte';
|
|
15
|
+
import { InterruptBubble } from '../interrupt/index.js';
|
|
16
|
+
import type { PlaygroundMessage } from '../../types/playground.js';
|
|
17
|
+
import {
|
|
18
|
+
isInterruptMetadata,
|
|
19
|
+
extractInterruptMetadata,
|
|
20
|
+
metadataToInterrupt
|
|
21
|
+
} from '../../types/interrupt.js';
|
|
22
|
+
import {
|
|
23
|
+
getMessages,
|
|
24
|
+
getChatMessages,
|
|
25
|
+
getIsExecuting,
|
|
26
|
+
getCurrentSession,
|
|
27
|
+
getShowLogs
|
|
28
|
+
} from '../../stores/playgroundStore.svelte.js';
|
|
29
|
+
import {
|
|
30
|
+
getInterruptsMap,
|
|
31
|
+
interruptActions,
|
|
32
|
+
getInterruptByMessageId
|
|
33
|
+
} from '../../stores/interruptStore.svelte.js';
|
|
34
|
+
import { m } from '../../messages/index.js';
|
|
35
|
+
|
|
36
|
+
interface Props {
|
|
37
|
+
/** Whether to show timestamps on messages */
|
|
38
|
+
showTimestamps?: boolean;
|
|
39
|
+
/** Whether to auto-scroll to bottom on new messages */
|
|
40
|
+
autoScroll?: boolean;
|
|
41
|
+
/** Whether to enable markdown rendering in messages */
|
|
42
|
+
enableMarkdown?: boolean;
|
|
43
|
+
/**
|
|
44
|
+
* Whether this surface is permitted to show log messages.
|
|
45
|
+
* When true, the store's showLogs toggle takes effect.
|
|
46
|
+
* When false (default), only chat messages are ever shown regardless of the toggle.
|
|
47
|
+
* Set to true on execution surfaces (e.g. ExecutionConsole); leave false on pure chat surfaces.
|
|
48
|
+
*/
|
|
49
|
+
allowLogs?: boolean;
|
|
50
|
+
/** Render system messages in compact inline form */
|
|
51
|
+
compactSystemMessages?: boolean;
|
|
52
|
+
/** Called when an interrupt is resolved */
|
|
53
|
+
onInterruptResolved?: () => void;
|
|
54
|
+
/** Custom render for the no-session welcome state */
|
|
55
|
+
welcome?: Snippet;
|
|
56
|
+
/** Custom render for the empty-session state */
|
|
57
|
+
emptySession?: Snippet;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
let {
|
|
61
|
+
showTimestamps = true,
|
|
62
|
+
autoScroll = true,
|
|
63
|
+
enableMarkdown = true,
|
|
64
|
+
allowLogs = false,
|
|
65
|
+
compactSystemMessages = true,
|
|
66
|
+
onInterruptResolved,
|
|
67
|
+
welcome,
|
|
68
|
+
emptySession
|
|
69
|
+
}: Props = $props();
|
|
70
|
+
|
|
71
|
+
const states = $derived(m().playground.states);
|
|
72
|
+
|
|
73
|
+
/** Reference to the messages container for scrolling */
|
|
74
|
+
let messagesContainer: HTMLDivElement | undefined;
|
|
75
|
+
|
|
76
|
+
const displayMessages = $derived(
|
|
77
|
+
allowLogs && getShowLogs() ? getMessages() : getChatMessages()
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
let previousMessageCount = 0;
|
|
81
|
+
let userScrolledUp = false;
|
|
82
|
+
|
|
83
|
+
function handleScroll() {
|
|
84
|
+
if (!messagesContainer) return;
|
|
85
|
+
const { scrollTop, scrollHeight, clientHeight } = messagesContainer;
|
|
86
|
+
userScrolledUp = scrollHeight - scrollTop - clientHeight > 50;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function isFormFocused(): boolean {
|
|
90
|
+
if (!messagesContainer) return false;
|
|
91
|
+
const activeElement = document.activeElement;
|
|
92
|
+
if (!activeElement) return false;
|
|
93
|
+
const isFormControl =
|
|
94
|
+
activeElement.tagName === 'INPUT' ||
|
|
95
|
+
activeElement.tagName === 'TEXTAREA' ||
|
|
96
|
+
activeElement.tagName === 'SELECT' ||
|
|
97
|
+
activeElement.tagName === 'BUTTON' ||
|
|
98
|
+
activeElement.getAttribute('contenteditable') === 'true';
|
|
99
|
+
return isFormControl && messagesContainer.contains(activeElement);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function isInterruptMessage(message: PlaygroundMessage): boolean {
|
|
103
|
+
return isInterruptMetadata(message.metadata as Record<string, unknown> | undefined);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Sync interrupt messages into the interrupt store. Runs in an effect to
|
|
108
|
+
* avoid Svelte 5's state_unsafe_mutation error during render.
|
|
109
|
+
*/
|
|
110
|
+
$effect(() => {
|
|
111
|
+
const interruptMessages = displayMessages.filter(isInterruptMessage);
|
|
112
|
+
|
|
113
|
+
for (const message of interruptMessages) {
|
|
114
|
+
const existing = getInterruptByMessageId(message.id);
|
|
115
|
+
if (!existing) {
|
|
116
|
+
const metadata = extractInterruptMetadata(
|
|
117
|
+
message.metadata as Record<string, unknown> | undefined
|
|
118
|
+
);
|
|
119
|
+
if (metadata) {
|
|
120
|
+
const interrupt = metadataToInterrupt(metadata, message.id, message.content);
|
|
121
|
+
interruptActions.addInterrupt(interrupt);
|
|
122
|
+
|
|
123
|
+
if (message.status === 'completed') {
|
|
124
|
+
interruptActions.resolveInterrupt(interrupt.id, metadata.response_value);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
const interruptsByMessageId = $derived(
|
|
132
|
+
new Map(
|
|
133
|
+
Array.from(getInterruptsMap().values())
|
|
134
|
+
.filter((i) => i.messageId)
|
|
135
|
+
.map((i) => [i.messageId, i])
|
|
136
|
+
)
|
|
137
|
+
);
|
|
138
|
+
|
|
139
|
+
function getInterruptForMessage(message: PlaygroundMessage) {
|
|
140
|
+
return interruptsByMessageId.get(message.id);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const showWelcome = $derived(!getCurrentSession() && displayMessages.length === 0);
|
|
144
|
+
const showEmptyChat = $derived(getCurrentSession() !== null && displayMessages.length === 0);
|
|
145
|
+
|
|
146
|
+
// Reset scroll-tracking when session changes
|
|
147
|
+
$effect(() => {
|
|
148
|
+
if (getCurrentSession()) {
|
|
149
|
+
userScrolledUp = false;
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
$effect(() => {
|
|
154
|
+
const currentCount = displayMessages.length;
|
|
155
|
+
|
|
156
|
+
if (!autoScroll || !messagesContainer) {
|
|
157
|
+
untrack(() => { previousMessageCount = currentCount; });
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const hasNewMessage = currentCount > previousMessageCount;
|
|
162
|
+
untrack(() => { previousMessageCount = currentCount; });
|
|
163
|
+
|
|
164
|
+
if (!hasNewMessage || userScrolledUp || isFormFocused()) return;
|
|
165
|
+
|
|
166
|
+
tick().then(() => {
|
|
167
|
+
if (messagesContainer) {
|
|
168
|
+
messagesContainer.scrollTop = messagesContainer.scrollHeight;
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
</script>
|
|
173
|
+
|
|
174
|
+
<div class="message-stream" role="log" aria-label={m().playground.controlPanel.messageStreamLabel} bind:this={messagesContainer} onscroll={handleScroll}>
|
|
175
|
+
{#if showWelcome}
|
|
176
|
+
{#if welcome}
|
|
177
|
+
{@render welcome()}
|
|
178
|
+
{/if}
|
|
179
|
+
{:else if showEmptyChat}
|
|
180
|
+
{#if emptySession}
|
|
181
|
+
{@render emptySession()}
|
|
182
|
+
{/if}
|
|
183
|
+
{:else}
|
|
184
|
+
{#each displayMessages as message, index (message.id)}
|
|
185
|
+
{#if isInterruptMessage(message)}
|
|
186
|
+
{@const interrupt = getInterruptForMessage(message)}
|
|
187
|
+
{#if interrupt}
|
|
188
|
+
<InterruptBubble
|
|
189
|
+
{interrupt}
|
|
190
|
+
showTimestamp={showTimestamps}
|
|
191
|
+
onResolved={onInterruptResolved}
|
|
192
|
+
/>
|
|
193
|
+
{/if}
|
|
194
|
+
{:else}
|
|
195
|
+
<MessageBubble
|
|
196
|
+
{message}
|
|
197
|
+
showTimestamp={showTimestamps}
|
|
198
|
+
isLast={index === displayMessages.length - 1}
|
|
199
|
+
{enableMarkdown}
|
|
200
|
+
{compactSystemMessages}
|
|
201
|
+
/>
|
|
202
|
+
{/if}
|
|
203
|
+
{/each}
|
|
204
|
+
|
|
205
|
+
{#if getIsExecuting()}
|
|
206
|
+
<div class="message-stream__typing">
|
|
207
|
+
<div class="message-stream__typing-indicator">
|
|
208
|
+
<span></span>
|
|
209
|
+
<span></span>
|
|
210
|
+
<span></span>
|
|
211
|
+
</div>
|
|
212
|
+
<span class="message-stream__typing-text">{states.processing}</span>
|
|
213
|
+
</div>
|
|
214
|
+
{/if}
|
|
215
|
+
{/if}
|
|
216
|
+
</div>
|
|
217
|
+
|
|
218
|
+
<style>
|
|
219
|
+
.message-stream {
|
|
220
|
+
flex: 1;
|
|
221
|
+
min-height: 0;
|
|
222
|
+
overflow-y: auto;
|
|
223
|
+
padding: var(--fd-space-3xl);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
.message-stream__typing {
|
|
227
|
+
display: flex;
|
|
228
|
+
align-items: center;
|
|
229
|
+
gap: var(--fd-space-xs);
|
|
230
|
+
padding: var(--fd-space-md) var(--fd-space-xl);
|
|
231
|
+
margin-top: var(--fd-space-xs);
|
|
232
|
+
background-color: var(--fd-muted);
|
|
233
|
+
border-radius: var(--fd-radius-2xl);
|
|
234
|
+
width: fit-content;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
.message-stream__typing-indicator {
|
|
238
|
+
display: flex;
|
|
239
|
+
gap: var(--fd-space-3xs);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
.message-stream__typing-indicator span {
|
|
243
|
+
width: var(--fd-space-2xs);
|
|
244
|
+
height: var(--fd-space-2xs);
|
|
245
|
+
background-color: var(--fd-muted-foreground);
|
|
246
|
+
border-radius: var(--fd-radius-full);
|
|
247
|
+
animation: message-stream-bounce 1.4s ease-in-out infinite;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
.message-stream__typing-indicator span:nth-child(1) {
|
|
251
|
+
animation-delay: 0s;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
.message-stream__typing-indicator span:nth-child(2) {
|
|
255
|
+
animation-delay: 0.2s;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
.message-stream__typing-indicator span:nth-child(3) {
|
|
259
|
+
animation-delay: 0.4s;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
@keyframes message-stream-bounce {
|
|
263
|
+
0%,
|
|
264
|
+
60%,
|
|
265
|
+
100% {
|
|
266
|
+
transform: translateY(0);
|
|
267
|
+
}
|
|
268
|
+
30% {
|
|
269
|
+
transform: translateY(-0.25rem);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
.message-stream__typing-text {
|
|
274
|
+
font-size: var(--fd-text-sm);
|
|
275
|
+
color: var(--fd-muted-foreground);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
@media (max-width: 640px) {
|
|
279
|
+
.message-stream {
|
|
280
|
+
padding: var(--fd-space-xl);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
</style>
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { type Snippet } from 'svelte';
|
|
2
|
+
interface Props {
|
|
3
|
+
/** Whether to show timestamps on messages */
|
|
4
|
+
showTimestamps?: boolean;
|
|
5
|
+
/** Whether to auto-scroll to bottom on new messages */
|
|
6
|
+
autoScroll?: boolean;
|
|
7
|
+
/** Whether to enable markdown rendering in messages */
|
|
8
|
+
enableMarkdown?: boolean;
|
|
9
|
+
/**
|
|
10
|
+
* Whether this surface is permitted to show log messages.
|
|
11
|
+
* When true, the store's showLogs toggle takes effect.
|
|
12
|
+
* When false (default), only chat messages are ever shown regardless of the toggle.
|
|
13
|
+
* Set to true on execution surfaces (e.g. ExecutionConsole); leave false on pure chat surfaces.
|
|
14
|
+
*/
|
|
15
|
+
allowLogs?: boolean;
|
|
16
|
+
/** Render system messages in compact inline form */
|
|
17
|
+
compactSystemMessages?: boolean;
|
|
18
|
+
/** Called when an interrupt is resolved */
|
|
19
|
+
onInterruptResolved?: () => void;
|
|
20
|
+
/** Custom render for the no-session welcome state */
|
|
21
|
+
welcome?: Snippet;
|
|
22
|
+
/** Custom render for the empty-session state */
|
|
23
|
+
emptySession?: Snippet;
|
|
24
|
+
}
|
|
25
|
+
declare const MessageStream: import("svelte").Component<Props, {}, "">;
|
|
26
|
+
type MessageStream = ReturnType<typeof MessageStream>;
|
|
27
|
+
export default MessageStream;
|