@d34dman/flowdrop 0.0.32 → 0.0.33

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.
@@ -35,6 +35,8 @@
35
35
  onStopExecution?: () => void;
36
36
  /** Whether to show log messages inline (false = hide them) */
37
37
  showLogsInline?: boolean;
38
+ /** Whether to enable markdown rendering in messages */
39
+ enableMarkdown?: boolean;
38
40
  }
39
41
 
40
42
  let {
@@ -43,7 +45,8 @@
43
45
  placeholder = 'Type your message...',
44
46
  onSendMessage,
45
47
  onStopExecution,
46
- showLogsInline = false
48
+ showLogsInline = false,
49
+ enableMarkdown = true
47
50
  }: Props = $props();
48
51
 
49
52
  /** Input field value */
@@ -206,6 +209,7 @@
206
209
  {message}
207
210
  showTimestamp={showTimestamps}
208
211
  isLast={index === displayMessages.length - 1}
212
+ {enableMarkdown}
209
213
  />
210
214
  {/each}
211
215
 
@@ -14,6 +14,8 @@ interface Props {
14
14
  onStopExecution?: () => void;
15
15
  /** Whether to show log messages inline (false = hide them) */
16
16
  showLogsInline?: boolean;
17
+ /** Whether to enable markdown rendering in messages */
18
+ enableMarkdown?: boolean;
17
19
  }
18
20
  declare const ChatPanel: import("svelte").Component<Props, {}, "">;
19
21
  type ChatPanel = ReturnType<typeof ChatPanel>;
@@ -3,11 +3,13 @@
3
3
 
4
4
  Renders individual messages in the playground chat interface.
5
5
  Supports different message roles with distinct styling.
6
+ Supports markdown rendering for message content.
6
7
  Styled with BEM syntax.
7
8
  -->
8
9
 
9
10
  <script lang="ts">
10
11
  import Icon from '@iconify/svelte';
12
+ import { marked } from 'marked';
11
13
  import type { PlaygroundMessage, PlaygroundMessageRole } from '../../types/playground.js';
12
14
 
13
15
  /**
@@ -20,9 +22,20 @@
20
22
  showTimestamp?: boolean;
21
23
  /** Whether this is the last message (affects styling) */
22
24
  isLast?: boolean;
25
+ /** Whether to render markdown content */
26
+ enableMarkdown?: boolean;
23
27
  }
24
28
 
25
- let { message, showTimestamp = true, isLast = false }: Props = $props();
29
+ let { message, showTimestamp = true, isLast = false, enableMarkdown = true }: Props = $props();
30
+
31
+ /**
32
+ * Render content as markdown or plain text
33
+ */
34
+ const renderedContent = $derived(
35
+ enableMarkdown && message.role !== 'log'
36
+ ? marked.parse(message.content || '')
37
+ : message.content
38
+ );
26
39
 
27
40
  /**
28
41
  * Get the icon for the message role
@@ -144,7 +157,13 @@
144
157
 
145
158
  <!-- Message Text -->
146
159
  <div class="message-bubble__text">
147
- {message.content}
160
+ {#if enableMarkdown && message.role !== 'log'}
161
+ <!-- Markdown content - marked.js sanitizes content by default -->
162
+ <!-- eslint-disable-next-line svelte/no-at-html-tags -->
163
+ {@html renderedContent}
164
+ {:else}
165
+ {message.content}
166
+ {/if}
148
167
  </div>
149
168
 
150
169
  <!-- Metadata Footer -->
@@ -188,32 +207,33 @@
188
207
  }
189
208
  }
190
209
 
191
- /* Role-specific styling */
210
+ /* Role-specific styling - Neutral theme */
192
211
  .message-bubble--user {
193
- background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%);
194
- color: #ffffff;
212
+ background-color: #f1f5f9;
213
+ border: 1px solid #e2e8f0;
214
+ color: #1e293b;
195
215
  margin-left: 2rem;
196
216
  flex-direction: row-reverse;
197
217
  }
198
218
 
199
219
  .message-bubble--assistant {
200
- background-color: #f8fafc;
201
- border: 1px solid #e2e8f0;
202
- color: #1e293b;
220
+ background-color: #ffffff;
221
+ border: 1px solid #e5e7eb;
222
+ color: #1f2937;
203
223
  margin-right: 2rem;
204
224
  }
205
225
 
206
226
  .message-bubble--system {
207
- background-color: #fef3c7;
208
- border: 1px solid #fcd34d;
209
- color: #92400e;
227
+ background-color: #f9fafb;
228
+ border: 1px solid #e5e7eb;
229
+ color: #6b7280;
210
230
  margin: 0 1rem;
211
231
  font-size: 0.875rem;
212
232
  }
213
233
 
214
234
  .message-bubble--log {
215
- background-color: #f1f5f9;
216
- border: 1px solid #cbd5e1;
235
+ background-color: #f8fafc;
236
+ border: 1px solid #e2e8f0;
217
237
  color: #475569;
218
238
  margin: 0 1rem;
219
239
  font-size: 0.8125rem;
@@ -249,18 +269,18 @@
249
269
  }
250
270
 
251
271
  .message-bubble--user .message-bubble__avatar {
252
- background-color: rgba(255, 255, 255, 0.2);
253
- color: #ffffff;
272
+ background-color: #e2e8f0;
273
+ color: #475569;
254
274
  }
255
275
 
256
276
  .message-bubble--assistant .message-bubble__avatar {
257
- background-color: #dbeafe;
258
- color: #2563eb;
277
+ background-color: #e5e7eb;
278
+ color: #374151;
259
279
  }
260
280
 
261
281
  .message-bubble--system .message-bubble__avatar {
262
- background-color: #fde68a;
263
- color: #92400e;
282
+ background-color: #f3f4f6;
283
+ color: #6b7280;
264
284
  }
265
285
 
266
286
  .message-bubble--log .message-bubble__avatar {
@@ -292,14 +312,15 @@
292
312
  .message-bubble__role {
293
313
  font-weight: 600;
294
314
  font-size: 0.8125rem;
315
+ color: #374151;
295
316
  }
296
317
 
297
318
  .message-bubble--user .message-bubble__role {
298
- color: rgba(255, 255, 255, 0.9);
319
+ color: #475569;
299
320
  }
300
321
 
301
322
  .message-bubble--assistant .message-bubble__role {
302
- color: #3b82f6;
323
+ color: #374151;
303
324
  }
304
325
 
305
326
  .message-bubble--log .message-bubble__role {
@@ -319,8 +340,8 @@
319
340
  }
320
341
 
321
342
  .message-bubble__log-level--info {
322
- background-color: #dbeafe;
323
- color: #1d4ed8;
343
+ background-color: #e0f2fe;
344
+ color: #0369a1;
324
345
  }
325
346
 
326
347
  .message-bubble__log-level--warning {
@@ -340,24 +361,152 @@
340
361
 
341
362
  .message-bubble__timestamp {
342
363
  font-size: 0.6875rem;
343
- opacity: 0.7;
364
+ color: #9ca3af;
344
365
  font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
345
366
  }
346
367
 
347
368
  .message-bubble--user .message-bubble__timestamp {
348
- color: rgba(255, 255, 255, 0.7);
369
+ color: #9ca3af;
349
370
  }
350
371
 
351
372
  /* Message text */
352
373
  .message-bubble__text {
353
- line-height: 1.5;
354
- white-space: pre-wrap;
374
+ line-height: 1.6;
355
375
  word-break: break-word;
356
376
  }
357
377
 
358
378
  .message-bubble--log .message-bubble__text {
359
379
  font-size: 0.8125rem;
360
380
  line-height: 1.4;
381
+ white-space: pre-wrap;
382
+ }
383
+
384
+ /* Markdown styling for message content */
385
+ .message-bubble__text :global(p) {
386
+ margin: 0 0 0.75rem 0;
387
+ }
388
+
389
+ .message-bubble__text :global(p:last-child) {
390
+ margin-bottom: 0;
391
+ }
392
+
393
+ .message-bubble__text :global(h1),
394
+ .message-bubble__text :global(h2),
395
+ .message-bubble__text :global(h3),
396
+ .message-bubble__text :global(h4),
397
+ .message-bubble__text :global(h5),
398
+ .message-bubble__text :global(h6) {
399
+ margin: 1rem 0 0.5rem 0;
400
+ font-weight: 600;
401
+ line-height: 1.3;
402
+ }
403
+
404
+ .message-bubble__text :global(h1:first-child),
405
+ .message-bubble__text :global(h2:first-child),
406
+ .message-bubble__text :global(h3:first-child),
407
+ .message-bubble__text :global(h4:first-child),
408
+ .message-bubble__text :global(h5:first-child),
409
+ .message-bubble__text :global(h6:first-child) {
410
+ margin-top: 0;
411
+ }
412
+
413
+ .message-bubble__text :global(h1) {
414
+ font-size: 1.25rem;
415
+ }
416
+
417
+ .message-bubble__text :global(h2) {
418
+ font-size: 1.125rem;
419
+ }
420
+
421
+ .message-bubble__text :global(h3) {
422
+ font-size: 1rem;
423
+ }
424
+
425
+ .message-bubble__text :global(ul),
426
+ .message-bubble__text :global(ol) {
427
+ margin: 0.5rem 0;
428
+ padding-left: 1.5rem;
429
+ }
430
+
431
+ .message-bubble__text :global(li) {
432
+ margin: 0.25rem 0;
433
+ }
434
+
435
+ .message-bubble__text :global(code) {
436
+ background-color: rgba(0, 0, 0, 0.06);
437
+ padding: 0.125rem 0.375rem;
438
+ border-radius: 0.25rem;
439
+ font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
440
+ font-size: 0.875em;
441
+ }
442
+
443
+ .message-bubble__text :global(pre) {
444
+ background-color: #1e293b;
445
+ color: #e2e8f0;
446
+ padding: 0.75rem 1rem;
447
+ border-radius: 0.5rem;
448
+ overflow-x: auto;
449
+ margin: 0.75rem 0;
450
+ font-size: 0.8125rem;
451
+ line-height: 1.5;
452
+ }
453
+
454
+ .message-bubble__text :global(pre code) {
455
+ background-color: transparent;
456
+ padding: 0;
457
+ border-radius: 0;
458
+ color: inherit;
459
+ font-size: inherit;
460
+ }
461
+
462
+ .message-bubble__text :global(blockquote) {
463
+ border-left: 3px solid #d1d5db;
464
+ padding-left: 1rem;
465
+ margin: 0.75rem 0;
466
+ color: #6b7280;
467
+ font-style: italic;
468
+ }
469
+
470
+ .message-bubble__text :global(a) {
471
+ color: #2563eb;
472
+ text-decoration: none;
473
+ }
474
+
475
+ .message-bubble__text :global(a:hover) {
476
+ text-decoration: underline;
477
+ }
478
+
479
+ .message-bubble__text :global(hr) {
480
+ border: none;
481
+ border-top: 1px solid #e5e7eb;
482
+ margin: 1rem 0;
483
+ }
484
+
485
+ .message-bubble__text :global(table) {
486
+ border-collapse: collapse;
487
+ width: 100%;
488
+ margin: 0.75rem 0;
489
+ font-size: 0.875rem;
490
+ }
491
+
492
+ .message-bubble__text :global(th),
493
+ .message-bubble__text :global(td) {
494
+ border: 1px solid #e5e7eb;
495
+ padding: 0.5rem 0.75rem;
496
+ text-align: left;
497
+ }
498
+
499
+ .message-bubble__text :global(th) {
500
+ background-color: #f9fafb;
501
+ font-weight: 600;
502
+ }
503
+
504
+ .message-bubble__text :global(strong) {
505
+ font-weight: 600;
506
+ }
507
+
508
+ .message-bubble__text :global(em) {
509
+ font-style: italic;
361
510
  }
362
511
 
363
512
  /* Footer */
@@ -367,7 +516,7 @@
367
516
  gap: 0.75rem;
368
517
  margin-top: 0.5rem;
369
518
  font-size: 0.6875rem;
370
- opacity: 0.7;
519
+ color: #9ca3af;
371
520
  }
372
521
 
373
522
  .message-bubble--user .message-bubble__footer {
@@ -9,6 +9,8 @@ interface Props {
9
9
  showTimestamp?: boolean;
10
10
  /** Whether this is the last message (affects styling) */
11
11
  isLast?: boolean;
12
+ /** Whether to render markdown content */
13
+ enableMarkdown?: boolean;
12
14
  }
13
15
  declare const MessageBubble: import("svelte").Component<Props, {}, "">;
14
16
  type MessageBubble = ReturnType<typeof MessageBubble>;
@@ -335,15 +335,20 @@
335
335
  playgroundActions.addMessages(response.data);
336
336
  }
337
337
 
338
- // Update session status
339
- if (response.sessionStatus) {
340
- playgroundActions.updateSessionStatus(response.sessionStatus);
341
-
342
- // Stop executing if completed or failed
343
- if (response.sessionStatus === 'completed' || response.sessionStatus === 'failed') {
344
- playgroundActions.setExecuting(false);
345
- }
338
+ // Update session status
339
+ if (response.sessionStatus) {
340
+ playgroundActions.updateSessionStatus(response.sessionStatus);
341
+
342
+ // Stop executing if idle, completed, or failed
343
+ // "idle" means no processing is happening (execution finished)
344
+ if (
345
+ response.sessionStatus === 'idle' ||
346
+ response.sessionStatus === 'completed' ||
347
+ response.sessionStatus === 'failed'
348
+ ) {
349
+ playgroundActions.setExecuting(false);
346
350
  }
351
+ }
347
352
  },
348
353
  pollingInterval
349
354
  );
@@ -513,6 +518,7 @@
513
518
  showTimestamps={config.showTimestamps ?? true}
514
519
  autoScroll={config.autoScroll ?? true}
515
520
  showLogsInline={config.logDisplayMode === 'inline'}
521
+ enableMarkdown={config.enableMarkdown ?? true}
516
522
  onSendMessage={handleSendMessage}
517
523
  onStopExecution={handleStopExecution}
518
524
  />
@@ -263,8 +263,11 @@ export class PlaygroundService {
263
263
  this.currentBackoff = interval;
264
264
  // Call the callback with new messages
265
265
  callback(response);
266
- // Stop polling if session is completed or failed
267
- if (response.sessionStatus === 'completed' || response.sessionStatus === 'failed') {
266
+ // Stop polling if session is idle, completed, or failed
267
+ // "idle" means no processing is happening (execution finished)
268
+ if (response.sessionStatus === 'idle' ||
269
+ response.sessionStatus === 'completed' ||
270
+ response.sessionStatus === 'failed') {
268
271
  this.stopPolling();
269
272
  return;
270
273
  }
@@ -178,6 +178,8 @@ export interface PlaygroundConfig {
178
178
  showTimestamps?: boolean;
179
179
  /** Show log messages inline or in collapsible section (default: "collapsible") */
180
180
  logDisplayMode?: 'inline' | 'collapsible';
181
+ /** Enable markdown rendering in messages (default: true) */
182
+ enableMarkdown?: boolean;
181
183
  }
182
184
  /**
183
185
  * Display mode for the Playground component
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@d34dman/flowdrop",
3
3
  "license": "MIT",
4
4
  "private": false,
5
- "version": "0.0.32",
5
+ "version": "0.0.33",
6
6
  "scripts": {
7
7
  "dev": "vite dev",
8
8
  "build": "vite build && npm run prepack",