@runtypelabs/persona 4.14.0 → 4.16.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.
Files changed (119) hide show
  1. package/README.md +4 -4
  2. package/dist/animations/glyph-cycle.d.cts +1 -1
  3. package/dist/animations/glyph-cycle.d.ts +1 -1
  4. package/dist/animations/{types-DveIaNx6.d.cts → types-BpWGm7_6.d.cts} +17 -0
  5. package/dist/animations/{types-DveIaNx6.d.ts → types-BpWGm7_6.d.ts} +17 -0
  6. package/dist/animations/wipe.d.cts +1 -1
  7. package/dist/animations/wipe.d.ts +1 -1
  8. package/dist/chunk-QJ4LV2KW.js +1 -0
  9. package/dist/codegen.cjs +12 -11
  10. package/dist/codegen.js +14 -13
  11. package/dist/{context-mentions-ONG7A7M6.js → context-mentions-BTSTIBFC.js} +1 -1
  12. package/dist/context-mentions.cjs +11 -8
  13. package/dist/context-mentions.d.cts +520 -21
  14. package/dist/context-mentions.d.ts +520 -21
  15. package/dist/context-mentions.js +11 -8
  16. package/dist/index.cjs +69 -68
  17. package/dist/index.cjs.map +1 -1
  18. package/dist/index.d.cts +595 -46
  19. package/dist/index.d.ts +595 -46
  20. package/dist/index.global.js +60 -57
  21. package/dist/index.global.js.map +1 -1
  22. package/dist/index.js +69 -68
  23. package/dist/index.js.map +1 -1
  24. package/dist/launcher.global.js +5 -2
  25. package/dist/launcher.global.js.map +1 -1
  26. package/dist/smart-dom-reader.d.cts +520 -21
  27. package/dist/smart-dom-reader.d.ts +520 -21
  28. package/dist/testing.cjs +3 -3
  29. package/dist/testing.d.cts +7 -0
  30. package/dist/testing.d.ts +7 -0
  31. package/dist/testing.js +3 -3
  32. package/dist/theme-editor-preview.cjs +67 -67
  33. package/dist/theme-editor-preview.d.cts +534 -22
  34. package/dist/theme-editor-preview.d.ts +534 -22
  35. package/dist/theme-editor-preview.js +57 -57
  36. package/dist/theme-editor.cjs +10 -10
  37. package/dist/theme-editor.d.cts +521 -23
  38. package/dist/theme-editor.d.ts +521 -23
  39. package/dist/theme-editor.js +10 -10
  40. package/dist/theme-reference.cjs +1 -1
  41. package/dist/theme-reference.d.cts +104 -3
  42. package/dist/theme-reference.d.ts +104 -3
  43. package/dist/theme-reference.js +1 -1
  44. package/dist/widget.css +1 -1
  45. package/package.json +1 -1
  46. package/src/ask-user-question-tool.ts +10 -7
  47. package/src/components/artifact-pane.test.ts +27 -0
  48. package/src/components/artifact-pane.ts +7 -3
  49. package/src/components/artifact-preview.ts +1 -1
  50. package/src/components/composer-parts.test.ts +103 -4
  51. package/src/components/composer-parts.ts +53 -15
  52. package/src/components/header-builder.ts +27 -2
  53. package/src/components/header-layouts.test.ts +56 -0
  54. package/src/components/header-layouts.ts +29 -9
  55. package/src/components/launcher-surface.test.ts +403 -0
  56. package/src/components/launcher.ts +297 -2
  57. package/src/components/messages.ts +5 -2
  58. package/src/components/panel.ts +92 -71
  59. package/src/components/pill-composer-builder.test.ts +18 -0
  60. package/src/components/suggestions.test.ts +273 -0
  61. package/src/components/suggestions.ts +528 -86
  62. package/src/components/welcome.test.ts +121 -0
  63. package/src/components/welcome.ts +305 -0
  64. package/src/components/widget-view.test.ts +5 -3
  65. package/src/components/widget-view.ts +18 -7
  66. package/src/defaults.ts +7 -5
  67. package/src/generated/runtype-openapi-contract.ts +17 -0
  68. package/src/index-core.ts +29 -2
  69. package/src/launcher-global.ts +11 -8
  70. package/src/plugins/types.ts +136 -3
  71. package/src/presets.ts +3 -3
  72. package/src/session.ts +10 -8
  73. package/src/styles/widget-styles.test.ts +382 -0
  74. package/src/styles/widget.css +778 -4
  75. package/src/suggest-replies-tool.test.ts +233 -2
  76. package/src/suggest-replies-tool.ts +115 -39
  77. package/src/testing/mock-stream.test.ts +19 -0
  78. package/src/testing/mock-stream.ts +20 -0
  79. package/src/theme-editor/preview-utils.test.ts +34 -0
  80. package/src/theme-editor/preview-utils.ts +77 -2
  81. package/src/theme-editor/sections.test.ts +33 -0
  82. package/src/theme-editor/sections.ts +83 -6
  83. package/src/theme-reference.ts +34 -5
  84. package/src/types/theme.ts +72 -3
  85. package/src/types.ts +312 -18
  86. package/src/ui.body-top-slot.test.ts +95 -0
  87. package/src/ui.content-width.test.ts +91 -0
  88. package/src/ui.detached-panel.test.ts +1 -1
  89. package/src/ui.docked.test.ts +7 -4
  90. package/src/ui.launcher-teaser.test.ts +162 -0
  91. package/src/ui.rebuild-composer.test.ts +491 -0
  92. package/src/ui.render-welcome.test.ts +505 -0
  93. package/src/ui.scroll-additive.test.ts +91 -21
  94. package/src/ui.scroll.test.ts +302 -14
  95. package/src/ui.suggest-replies.test.ts +1112 -1
  96. package/src/ui.ts +1008 -149
  97. package/src/ui.welcome.test.ts +504 -0
  98. package/src/utils/artifact-file.test.ts +1 -1
  99. package/src/utils/artifact-gate.test.ts +27 -0
  100. package/src/utils/artifact-gate.ts +9 -0
  101. package/src/utils/attachment-manager.test.ts +37 -0
  102. package/src/utils/attachment-manager.ts +15 -0
  103. package/src/utils/auto-follow.test.ts +23 -0
  104. package/src/utils/auto-follow.ts +11 -1
  105. package/src/utils/code-generators.test.ts +40 -0
  106. package/src/utils/code-generators.ts +22 -0
  107. package/src/utils/config-merge.test.ts +24 -0
  108. package/src/utils/config-merge.ts +2 -0
  109. package/src/utils/content-width.test.ts +37 -0
  110. package/src/utils/content-width.ts +17 -0
  111. package/src/utils/icons.test.ts +26 -0
  112. package/src/utils/icons.ts +8 -0
  113. package/src/utils/plugin-storage.test.ts +94 -0
  114. package/src/utils/plugin-storage.ts +98 -0
  115. package/src/utils/theme.test.ts +216 -0
  116. package/src/utils/tokens.ts +113 -3
  117. package/src/welcome.test.ts +213 -0
  118. package/src/welcome.ts +130 -0
  119. package/dist/chunk-MMUPR2JW.js +0 -1
@@ -186,6 +186,15 @@ interface PanelTokens extends ComponentTokenSet {
186
186
  /** Background of the region revealed behind a detached panel. */
187
187
  canvasBackground?: string;
188
188
  }
189
+ /** Per-element text styling shared by themable text surfaces. */
190
+ interface TextStyleTokens {
191
+ fontFamily?: string;
192
+ fontSize?: string;
193
+ fontWeight?: string;
194
+ lineHeight?: string;
195
+ letterSpacing?: string;
196
+ color?: TokenReference<'color'>;
197
+ }
189
198
  interface HeaderTokens extends ComponentTokenSet {
190
199
  background: TokenReference<'color'>;
191
200
  border: TokenReference<'color'>;
@@ -194,10 +203,14 @@ interface HeaderTokens extends ComponentTokenSet {
194
203
  iconBackground: TokenReference<'color'>;
195
204
  /** Foreground (glyph stroke or emoji text) on the header avatar tile. */
196
205
  iconForeground: TokenReference<'color'>;
197
- /** Header title line (next to the icon, or minimal layout title). */
206
+ /** Legacy alias of `title.color`; `title.color` wins when both are set. */
198
207
  titleForeground: TokenReference<'color'>;
199
- /** Header subtitle line under the title. */
208
+ /** Legacy alias of `subtitle.color`; `subtitle.color` wins when both are set. */
200
209
  subtitleForeground: TokenReference<'color'>;
210
+ /** Header title typography (next to the icon, or minimal layout title). */
211
+ title?: TextStyleTokens;
212
+ /** Header subtitle typography, for the line under the title. */
213
+ subtitle?: TextStyleTokens;
201
214
  /** Default color for clear / close icon buttons when launcher overrides are unset. */
202
215
  actionIconForeground: TokenReference<'color'>;
203
216
  /** Box-shadow on the header (e.g., a fade shadow to replace the default border). */
@@ -227,7 +240,7 @@ interface MessageTokens {
227
240
  }
228
241
  /**
229
242
  * Welcome / intro card rendered above the message list when no messages exist.
230
- * Set `copy.showWelcomeCard: false` to hide it; use `layout.slots["body-top"]`
243
+ * Set `welcome.variant: "none"` to hide it; use `layout.slots["body-top"]`
231
244
  * to replace it wholesale.
232
245
  */
233
246
  interface IntroCardTokens extends ComponentTokenSet {
@@ -236,6 +249,12 @@ interface IntroCardTokens extends ComponentTokenSet {
236
249
  padding?: TokenReference<'spacing'>;
237
250
  /** Box-shadow on the intro card (token ref or raw CSS, e.g. `none`). */
238
251
  shadow?: string;
252
+ /** Full border shorthand on the intro card (raw CSS, e.g. `"1px solid rgba(0,0,0,0.1)"`). @default "none" */
253
+ border?: string;
254
+ /** Welcome title typography. */
255
+ title?: TextStyleTokens;
256
+ /** Welcome subtitle typography. */
257
+ subtitle?: TextStyleTokens;
239
258
  }
240
259
  /** Collapsible widget chrome (tool bubbles, reasoning bubbles, approval bubbles). */
241
260
  interface CollapsibleWidgetTokens {
@@ -278,6 +297,8 @@ interface MarkdownTokens {
278
297
  background?: TokenReference<'color'>;
279
298
  borderColor?: TokenReference<'color'>;
280
299
  textColor?: TokenReference<'color'>;
300
+ /** Corner radius; follows `palette.radius.md` by default so square-corner themes get square code blocks. */
301
+ borderRadius?: TokenReference<'radius'>;
281
302
  };
282
303
  /** Table styling. */
283
304
  table?: {
@@ -335,10 +356,27 @@ interface ToolBubbleTokens {
335
356
  interface ReasoningBubbleTokens {
336
357
  shadow: string;
337
358
  }
359
+ /** Scrollbar appearance shared by every scroller in the widget. */
360
+ interface ScrollbarTokens {
361
+ /** Thumb color. @default semantic.colors.border */
362
+ thumb?: TokenReference<'color'>;
363
+ /** Track color. @default "transparent" */
364
+ track?: TokenReference<'color'>;
365
+ }
338
366
  /** Composer (message input) chrome. */
339
367
  interface ComposerChromeTokens {
340
368
  /** Box-shadow on the composer form (raw CSS, e.g. `none`). */
341
369
  shadow: string;
370
+ /** Border color of the composer form. @default semantic.colors.border */
371
+ borderColor?: TokenReference<'color'>;
372
+ /** Inner padding of the composer form (raw CSS shorthand). @default "0.75rem 1rem" */
373
+ padding?: string;
374
+ /** Gap between the textarea row and the actions row. @default "0.5rem" */
375
+ gap?: string;
376
+ /** Composer textarea font-size. @default "0.875rem" */
377
+ fontSize?: string;
378
+ /** Composer textarea line-height. @default "1.25rem" */
379
+ lineHeight?: string;
342
380
  }
343
381
  /** Artifact toolbar chrome. */
344
382
  interface ArtifactToolbarTokens {
@@ -488,6 +526,29 @@ interface ScrollToBottomTokens extends ComponentTokenSet {
488
526
  fontSize?: string;
489
527
  iconSize?: string;
490
528
  }
529
+ /** Visual tokens shared by one suggestion presentation variant. */
530
+ interface SuggestionVariantTokens extends ComponentTokenSet {
531
+ /** Space inside one item, between its icon and its copy. */
532
+ gap?: string;
533
+ /** Space between suggestion items in the container. */
534
+ itemGap?: string;
535
+ minHeight?: string;
536
+ fontSize?: string;
537
+ lineHeight?: string;
538
+ iconSize?: string;
539
+ hoverBackground?: TokenReference<'color'>;
540
+ hoverForeground?: TokenReference<'color'>;
541
+ hoverBorder?: TokenReference<'color'>;
542
+ pressedBackground?: TokenReference<'color'>;
543
+ focusRing?: TokenReference<'color'>;
544
+ disabledOpacity?: string;
545
+ }
546
+ /** Starter and follow-up suggestion chrome. */
547
+ interface SuggestionTokens {
548
+ chip: SuggestionVariantTokens;
549
+ card: SuggestionVariantTokens;
550
+ list: SuggestionVariantTokens;
551
+ }
491
552
  /** Toggle group chrome (used by createToggleGroup). */
492
553
  interface ToggleGroupTokens {
493
554
  /** Gap between toggle buttons. Default: 0 (connected). */
@@ -512,12 +573,16 @@ interface ComponentTokens {
512
573
  toolBubble: ToolBubbleTokens;
513
574
  reasoningBubble: ReasoningBubbleTokens;
514
575
  composer: ComposerChromeTokens;
576
+ /** Scrollbar appearance for every scroller in the widget. */
577
+ scrollbar?: ScrollbarTokens;
515
578
  /** Icon button styling tokens. */
516
579
  iconButton?: IconButtonTokens;
517
580
  /** Label button styling tokens. */
518
581
  labelButton?: LabelButtonTokens;
519
582
  /** Scroll-to-bottom indicator styling tokens. */
520
583
  scrollToBottom?: ScrollToBottomTokens;
584
+ /** Starter prompt and follow-up suggestion styling tokens. */
585
+ suggestion?: SuggestionTokens;
521
586
  /** Toggle group styling tokens. */
522
587
  toggleGroup?: ToggleGroupTokens;
523
588
  /** Artifact toolbar, tab strip, and pane chrome. */
@@ -559,6 +624,82 @@ type DeepPartial<T> = T extends object ? {
559
624
  [P in keyof T]?: DeepPartial<T[P]>;
560
625
  } : T;
561
626
 
627
+ interface ResolvedWelcomeConfig {
628
+ title: string;
629
+ subtitle: string;
630
+ icon?: AgentWidgetWelcomeIcon;
631
+ variant: AgentWidgetWelcomeVariant;
632
+ dismiss: AgentWidgetWelcomeDismiss;
633
+ /** Undefined under `variant: "hero"`, which suppresses the greeting. */
634
+ message?: string;
635
+ }
636
+
637
+ /**
638
+ * Synchronous key-value store handed to plugin render hooks. Backed by
639
+ * `localStorage`, namespaced per plugin id. The async `storageAdapter` cannot
640
+ * back a synchronous API and `persistState` is not a general key-value surface.
641
+ */
642
+ interface AgentWidgetPluginStorage {
643
+ get: (key: string) => string | null;
644
+ set: (key: string, value: string) => void;
645
+ remove: (key: string) => void;
646
+ }
647
+
648
+ type AgentWidgetTransformSuggestionsContext = {
649
+ /**
650
+ * Fresh copy of the suggestions entering this plugin, already normalized:
651
+ * shorthand strings expanded and the effective send/fill behavior resolved.
652
+ */
653
+ suggestions: AgentWidgetResolvedSuggestion[];
654
+ surface: AgentWidgetSuggestionSurface;
655
+ source: AgentWidgetSuggestionSource;
656
+ config: AgentWidgetConfig;
657
+ };
658
+ type AgentWidgetRenderSuggestionContext = {
659
+ /** Fully normalized suggestion, including the effective send/fill behavior. */
660
+ suggestion: AgentWidgetResolvedSuggestion;
661
+ index: number;
662
+ surface: AgentWidgetSuggestionSurface;
663
+ source: AgentWidgetSuggestionSource;
664
+ variant: AgentWidgetSuggestionVariant;
665
+ streaming: boolean;
666
+ config: AgentWidgetConfig;
667
+ /** Build Persona's standard chip, card, or list item. */
668
+ defaultRenderer: () => HTMLElement;
669
+ /**
670
+ * Run the normal selection pipeline: DOM event, plugin selection hooks, then
671
+ * send or fill. Custom renderers should call this instead of sending directly.
672
+ */
673
+ select: () => void;
674
+ };
675
+ type AgentWidgetRenderWelcomeContext = {
676
+ /** Alias-resolved welcome config; never the raw `copy.welcome*` shape. */
677
+ config: ResolvedWelcomeConfig;
678
+ variant: AgentWidgetWelcomeVariant;
679
+ /** Derived visibility for this render; governs the default renderer only. */
680
+ visible: boolean;
681
+ /** The core-owned welcome card, live-updated by `controller.update()`. */
682
+ defaultRenderer: () => HTMLElement;
683
+ sendMessage: (text: string) => void;
684
+ /** Re-run welcome arbitration: cleanups run, previous content is removed. */
685
+ requestRender: () => void;
686
+ /**
687
+ * Persona's starter renderer, wired through the full select pipeline:
688
+ * `onSuggestionSelect`, cancelable `persona:suggestion:*` events, send/fill.
689
+ */
690
+ renderStarter: (suggestion: AgentWidgetSuggestion) => HTMLElement;
691
+ /** Sync store namespaced by `persistState.keyPrefix` plus the plugin id. */
692
+ storage: AgentWidgetPluginStorage;
693
+ /** Teardown for this render; runs before the next one and on destroy. */
694
+ onCleanup: (fn: () => void) => void;
695
+ };
696
+ type AgentWidgetSuggestionSelectContext = {
697
+ suggestion: AgentWidgetResolvedSuggestion;
698
+ surface: AgentWidgetSuggestionSurface;
699
+ source: AgentWidgetSuggestionSource;
700
+ variant: AgentWidgetSuggestionVariant;
701
+ config: AgentWidgetConfig;
702
+ };
562
703
  /**
563
704
  * Plugin interface for customizing widget components
564
705
  */
@@ -571,6 +712,25 @@ interface AgentWidgetPlugin {
571
712
  * Optional priority (higher = runs first). Default: 0
572
713
  */
573
714
  priority?: number;
715
+ /**
716
+ * Transform, filter, enrich, or reorder suggestions. Hooks receive normalized
717
+ * items and compose in plugin priority order; the return value may use the
718
+ * loose shape (string shorthand included) and is re-normalized before the next
719
+ * hook. A per-item `behavior` set here survives. `maxItems` caps the list
720
+ * after the full chain. Return an empty array to hide the surface.
721
+ */
722
+ transformSuggestions?: (context: AgentWidgetTransformSuggestionsContext) => AgentWidgetSuggestion[];
723
+ /**
724
+ * Render one starter or follow-up suggestion. Return null to use Persona's
725
+ * default chip/card/list renderer. Call `select()` from custom interaction
726
+ * controls to preserve events, selection hooks, and send/fill behavior.
727
+ */
728
+ renderSuggestion?: (context: AgentWidgetRenderSuggestionContext) => HTMLElement | null;
729
+ /**
730
+ * Observe or intercept a suggestion selection. Return false to cancel the
731
+ * built-in send/fill action. Hooks run in plugin priority order.
732
+ */
733
+ onSuggestionSelect?: (context: AgentWidgetSuggestionSelectContext) => void | boolean;
574
734
  /**
575
735
  * Custom renderer for message bubbles
576
736
  * Return null to use default renderer
@@ -589,6 +749,34 @@ interface AgentWidgetPlugin {
589
749
  defaultRenderer: () => HTMLElement;
590
750
  onToggle: () => void;
591
751
  }) => HTMLElement | null;
752
+ /**
753
+ * Custom renderer for the welcome surface (card, hero, greeting stack).
754
+ * First plugin returning an element wins; null falls through to the default,
755
+ * same contract as `renderSuggestion`.
756
+ *
757
+ * The core owns the welcome host: it stays mounted for the panel's lifetime
758
+ * and content is swapped inside it. A plugin element renders regardless of
759
+ * `ctx.visible` (derived visibility governs the default renderer only) and
760
+ * the host overlays the transcript while that element is active, so a home
761
+ * screen can return over an existing conversation. Return null again to
762
+ * clear the overlay.
763
+ *
764
+ * The ctx carries no controller: plugins are host-instantiated, so close a
765
+ * factory over the init handle (`plugin.attach(controller)`).
766
+ *
767
+ * @example
768
+ * ```typescript
769
+ * renderWelcome: ({ config, renderStarter, requestRender, onCleanup }) => {
770
+ * const root = document.createElement("div");
771
+ * root.textContent = config.title;
772
+ * root.appendChild(renderStarter({ label: "Track my order" }));
773
+ * const timer = setInterval(requestRender, 60_000);
774
+ * onCleanup(() => clearInterval(timer));
775
+ * return root;
776
+ * }
777
+ * ```
778
+ */
779
+ renderWelcome?: (context: AgentWidgetRenderWelcomeContext) => HTMLElement | null;
592
780
  /**
593
781
  * Custom renderer for panel header
594
782
  * Return null to use default renderer
@@ -633,6 +821,15 @@ interface AgentWidgetPlugin {
633
821
  * Omitted when `config.voiceRecognition.enabled` is not true.
634
822
  */
635
823
  onVoiceToggle?: () => void;
824
+ /**
825
+ * Re-run composer arbitration and swap the footer in place. The hook runs
826
+ * once at panel construction, so this is how a composer plugin unlocks
827
+ * (returns null) or re-renders later. Pending attachments, the mention
828
+ * affordances, and the composer listener registry are re-wired by the core.
829
+ */
830
+ requestRender: () => void;
831
+ /** Same sync store as the `renderWelcome` ctx, namespaced per plugin id. */
832
+ storage: AgentWidgetPluginStorage;
636
833
  }) => HTMLElement | null;
637
834
  /**
638
835
  * Custom renderer for reasoning bubbles
@@ -1080,7 +1277,24 @@ type RuntypeExecutionStreamEvent = ({
1080
1277
  type: "source";
1081
1278
  url?: string;
1082
1279
  [key: string]: unknown;
1280
+ } | {
1281
+ executionId: string;
1282
+ iteration?: number;
1283
+ seq: number;
1284
+ state: Record<string, unknown>;
1285
+ type: "state_snapshot";
1083
1286
  } | ({
1287
+ executionId: string;
1288
+ iteration?: number;
1289
+ patch: Array<{
1290
+ from?: string;
1291
+ op: "add" | "remove" | "replace" | "move" | "copy" | "test";
1292
+ path: string;
1293
+ value?: unknown;
1294
+ }>;
1295
+ seq: number;
1296
+ type: "state_delta";
1297
+ }) | ({
1084
1298
  executionId: string;
1085
1299
  hiddenParameterNames?: Array<string>;
1086
1300
  iteration?: number;
@@ -1322,6 +1536,7 @@ declare const LUCIDE_ICONS: {
1322
1536
  readonly plus: IconNode;
1323
1537
  readonly minus: IconNode;
1324
1538
  readonly pencil: IconNode;
1539
+ readonly "pen-line": IconNode;
1325
1540
  readonly trash: IconNode;
1326
1541
  readonly "trash-2": IconNode;
1327
1542
  readonly save: IconNode;
@@ -1364,11 +1579,13 @@ declare const LUCIDE_ICONS: {
1364
1579
  readonly folder: IconNode;
1365
1580
  readonly "folder-open": IconNode;
1366
1581
  readonly files: IconNode;
1582
+ readonly "chart-column": IconNode;
1367
1583
  readonly sparkles: IconNode;
1368
1584
  readonly zap: IconNode;
1369
1585
  readonly sun: IconNode;
1370
1586
  readonly moon: IconNode;
1371
1587
  readonly flag: IconNode;
1588
+ readonly lightbulb: IconNode;
1372
1589
  readonly monitor: IconNode;
1373
1590
  readonly smartphone: IconNode;
1374
1591
  };
@@ -2366,6 +2583,13 @@ type AgentWidgetArtifactsLayoutConfig = {
2366
2583
  * @default 520
2367
2584
  */
2368
2585
  narrowHostMaxWidth?: number;
2586
+ /**
2587
+ * Width of the slide-over artifact drawer (the narrow-host and mobile
2588
+ * presentations; `paneWidth`/`paneMaxWidth` only size the desktop split).
2589
+ * CSS length; `"100%"` makes the drawer cover the whole panel.
2590
+ * @default min(calc(100% - 1rem), 22rem)
2591
+ */
2592
+ drawerWidth?: string;
2369
2593
  /**
2370
2594
  * When true (default), widen the launcher panel while artifacts are visible and not user-dismissed.
2371
2595
  * No-op for inline embed (`launcher.enabled === false`).
@@ -2994,6 +3218,18 @@ type AgentWidgetScrollMode = "follow" | "anchor-top" | "none";
2994
3218
  * restored thread opens at a readable place rather than at the very bottom.
2995
3219
  */
2996
3220
  type AgentWidgetScrollRestorePosition = "bottom" | "last-user-turn";
3221
+ /**
3222
+ * Scrollbar visibility policy for every scroll surface in the widget.
3223
+ *
3224
+ * - `"on-scroll"` hides bars at rest and reveals them on genuine reader
3225
+ * input, keeping them visible while the reader is away from the resting
3226
+ * position: overlay-scrollbar semantics on every platform.
3227
+ * - `"auto"` keeps the themed bar under native visibility semantics: overlay
3228
+ * platforms still auto-hide, classic-scrollbar platforms (Windows,
3229
+ * always-show macOS) show it persistently.
3230
+ * - `"hidden"` never shows an indicator. Scrolling itself is unaffected.
3231
+ */
3232
+ type AgentWidgetScrollbarPolicy = "on-scroll" | "auto" | "hidden";
2997
3233
  type AgentWidgetScrollBehaviorFeature = {
2998
3234
  /** Scroll behavior during streamed responses. @default "anchor-top" */
2999
3235
  mode?: AgentWidgetScrollMode;
@@ -3038,6 +3274,13 @@ type AgentWidgetScrollBehaviorFeature = {
3038
3274
  * @default false
3039
3275
  */
3040
3276
  announce?: boolean;
3277
+ /**
3278
+ * Scrollbar visibility policy, applied to the transcript and every inner
3279
+ * scroller through one root attribute. Themable via
3280
+ * `--persona-scrollbar-thumb` and `--persona-scrollbar-track`.
3281
+ * @default "on-scroll"
3282
+ */
3283
+ scrollbar?: AgentWidgetScrollbarPolicy;
3041
3284
  };
3042
3285
  type AgentWidgetScrollToBottomFeature = {
3043
3286
  /**
@@ -3327,10 +3570,13 @@ type AgentWidgetFeatureFlags = {
3327
3570
  */
3328
3571
  askUserQuestion?: AgentWidgetAskUserQuestionFeature;
3329
3572
  /**
3330
- * Built-in `suggest_replies` quick-reply chips. When the assistant invokes
3331
- * the tool, the widget shows the suggestions as tappable chips above the
3332
- * composer (reusing the suggestion-chips surface) and immediately resumes
3333
- * the execution: fire-and-forget, no user input awaited.
3573
+ * Built-in `suggest_replies` follow-ups. When the assistant invokes the
3574
+ * tool, the widget shows the suggestions using `suggestions.followUps` and
3575
+ * immediately resumes the execution: fire-and-forget, no user input awaited.
3576
+ *
3577
+ * @deprecated Both keys moved to `suggestions.followUps`: use
3578
+ * `suggestions.followUps.enabled` and `suggestions.followUps.expose`. This
3579
+ * alias keeps working per key, with `suggestions.followUps` winning.
3334
3580
  */
3335
3581
  suggestReplies?: AgentWidgetSuggestRepliesFeature;
3336
3582
  };
@@ -3375,11 +3621,12 @@ type WidgetPreferenceSlice = {
3375
3621
  };
3376
3622
  };
3377
3623
  /**
3378
- * Feature config for the built-in `suggest_replies` quick-reply chips.
3379
- * Chips render in the existing suggestions slot above the composer and are
3380
- * styled by the widget-level `suggestionChipsConfig`. A tapped chip is sent
3381
- * verbatim as the user's next message; chips clear once any user message
3382
- * follows them.
3624
+ * Feature config for the built-in `suggest_replies` follow-ups.
3625
+ *
3626
+ * @deprecated Both keys moved to `suggestions.followUps`
3627
+ * (`suggestions.followUps.enabled` / `suggestions.followUps.expose`), which
3628
+ * also owns presentation, placement, and send/fill behavior. Resolution is
3629
+ * per key with `suggestions.followUps` winning; removal waits for 5.0.
3383
3630
  */
3384
3631
  type AgentWidgetSuggestRepliesFeature = {
3385
3632
  /**
@@ -3387,14 +3634,18 @@ type AgentWidgetSuggestRepliesFeature = {
3387
3634
  * renders as a regular tool bubble and is NOT auto-resumed: only set this
3388
3635
  * with no server-side `suggest_replies` declaration, or the execution
3389
3636
  * parks awaiting a resume that never comes.
3637
+ * @deprecated Use `suggestions.followUps.enabled`.
3390
3638
  */
3391
3639
  enabled?: boolean;
3392
3640
  /**
3393
3641
  * Advertise the built-in `suggest_replies` tool to the agent on every
3394
3642
  * dispatch via `clientTools[]`: no server-side `runtimeTools` declaration
3395
- * needed. Defaults to `false`: flows that already declare the tool via
3396
- * `runtimeTools` would otherwise present it to the model twice. Ignored
3397
- * when `enabled` is `false`.
3643
+ * needed. Defaults to `false`. Declare the tool in one place: the API
3644
+ * dedupes a double declaration by name with `clientTools[]` winning, so the
3645
+ * model still sees exactly one tool, but the widget's description and schema
3646
+ * win and the effective tool type becomes `local` (the execution pauses and
3647
+ * the widget auto-resumes it). Ignored when `enabled` is `false`.
3648
+ * @deprecated Use `suggestions.followUps.expose`.
3398
3649
  */
3399
3650
  expose?: boolean;
3400
3651
  };
@@ -3464,10 +3715,13 @@ type AgentWidgetAskUserQuestionFeature = {
3464
3715
  * matching {@link AskUserQuestionPayload}; when the model calls it, the
3465
3716
  * existing answer-pill sheet renders and the answer resumes the execution.
3466
3717
  *
3467
- * Defaults to `false`: flows that already declare `ask_user_question` via
3468
- * `runtimeTools` would otherwise present the tool to the model twice.
3469
- * Ignored when `enabled` is `false`: never offer the agent a question
3470
- * tool the widget can't render an answer UI for.
3718
+ * Defaults to `false`. Declare the tool in one place: the API dedupes a
3719
+ * double declaration by name with `clientTools[]` winning, so the model
3720
+ * still sees exactly one tool, but the widget's description and schema win
3721
+ * and the effective tool type becomes `local` (the execution pauses and the
3722
+ * widget resumes it with the user's answer). Ignored when `enabled` is
3723
+ * `false`: never offer the agent a question tool the widget can't render an
3724
+ * answer UI for.
3471
3725
  */
3472
3726
  expose?: boolean;
3473
3727
  /** Slide-in animation duration in ms. Defaults to 180. */
@@ -3932,6 +4186,57 @@ type AgentWidgetLauncherConfig = {
3932
4186
  * @example "min(380px, calc(100vw - 48px))"
3933
4187
  */
3934
4188
  collapsedMaxWidth?: string;
4189
+ /**
4190
+ * Proactive nudge bubble anchored above the collapsed floating launcher.
4191
+ * Omit it (the default) and no teaser renders.
4192
+ */
4193
+ teaser?: AgentWidgetLauncherTeaserConfig;
4194
+ };
4195
+ /**
4196
+ * Launcher teaser: a small bubble above the collapsed launcher. Clicking it
4197
+ * opens the panel and consumes the teaser exactly like an explicit dismissal.
4198
+ * Within a single page load the teaser appears at most once under either
4199
+ * frequency.
4200
+ *
4201
+ * @example
4202
+ * ```typescript
4203
+ * launcher: {
4204
+ * teaser: { text: "Need a hand picking a plan?", delayMs: 3000 }
4205
+ * }
4206
+ * ```
4207
+ */
4208
+ type AgentWidgetLauncherTeaserConfig = {
4209
+ /** Bubble copy. An empty string renders no teaser. */
4210
+ text: string;
4211
+ /**
4212
+ * Delay before the bubble appears, in milliseconds.
4213
+ * @default 0
4214
+ */
4215
+ delayMs?: number;
4216
+ /**
4217
+ * How often the teaser may return.
4218
+ *
4219
+ * `"once"`: a dismissal or a click-through is remembered in `localStorage`
4220
+ * under `` `${persistState.keyPrefix ?? "persona-"}teaser-dismissed` `` and
4221
+ * the teaser never returns on that browser. `"always"`: shows on every page
4222
+ * load, tracked in memory only. `persistState: false` downgrades `"once"` to
4223
+ * in-memory too, so the teaser reappears each load.
4224
+ *
4225
+ * Custom `storageAdapter` implementations do not participate in teaser state.
4226
+ *
4227
+ * @default "once"
4228
+ */
4229
+ frequency?: "once" | "always";
4230
+ /**
4231
+ * Render an x affordance that dismisses the teaser without opening the panel.
4232
+ * @default true
4233
+ */
4234
+ dismissible?: boolean;
4235
+ /**
4236
+ * Accessible label for the dismiss affordance.
4237
+ * @default "Dismiss message"
4238
+ */
4239
+ dismissLabel?: string;
3935
4240
  };
3936
4241
  type AgentWidgetSendButtonConfig = {
3937
4242
  borderWidth?: string;
@@ -3940,6 +4245,10 @@ type AgentWidgetSendButtonConfig = {
3940
4245
  paddingY?: string;
3941
4246
  iconText?: string;
3942
4247
  iconName?: string;
4248
+ /** Icon glyph box in icon mode, e.g. "20px". Defaults to half of `size`. */
4249
+ iconSize?: string;
4250
+ /** Stroke width for the icon glyph, in viewBox units. Default 2. */
4251
+ iconStrokeWidth?: number;
3943
4252
  useIcon?: boolean;
3944
4253
  tooltipText?: string;
3945
4254
  showTooltip?: boolean;
@@ -4663,6 +4972,177 @@ type AgentWidgetSuggestionChipsConfig = {
4663
4972
  paddingX?: string;
4664
4973
  paddingY?: string;
4665
4974
  };
4975
+ /** A suggested next action shown to the user. Strings remain supported as shorthand. */
4976
+ type AgentWidgetSuggestion = string | {
4977
+ /** Stable analytics / DOM identity. Falls back to the prompt or label. */
4978
+ id?: string;
4979
+ /** Concise visible action label. */
4980
+ label: string;
4981
+ /** Text placed in the composer or sent. Defaults to `label`. */
4982
+ prompt?: string;
4983
+ /**
4984
+ * Optional supporting copy, most useful with the `card` variant. The
4985
+ * `chip` variant ignores it and renders the label alone.
4986
+ */
4987
+ description?: string;
4988
+ /** Optional icon from Persona's bundled Lucide registry. */
4989
+ icon?: IconName;
4990
+ /**
4991
+ * CSS color for this item's glyph. Tints the icon only: label, border,
4992
+ * and background stay neutral. Ignored without an `icon`.
4993
+ */
4994
+ iconColor?: string;
4995
+ /** Override the surface's click behavior for this item. */
4996
+ behavior?: AgentWidgetSuggestionBehavior;
4997
+ /** Visually promote one high-confidence action. */
4998
+ emphasis?: "default" | "primary";
4999
+ };
5000
+ type AgentWidgetSuggestionBehavior = "send" | "fill";
5001
+ type AgentWidgetSuggestionVariant = "chip" | "card" | "list";
5002
+ type AgentWidgetSuggestionSurface = "starter" | "followUp";
5003
+ /**
5004
+ * Who produced the rendered suggestions: static config, the agent's
5005
+ * `suggest_replies` tool, or `controller.setFollowUpSuggestions`.
5006
+ */
5007
+ type AgentWidgetSuggestionSource = "config" | "agent" | "host";
5008
+ /**
5009
+ * A suggestion after Persona has normalized shorthand strings and resolved the
5010
+ * effective click behavior. Plugin hooks receive this stable shape.
5011
+ */
5012
+ type AgentWidgetResolvedSuggestion = {
5013
+ id: string;
5014
+ label: string;
5015
+ prompt: string;
5016
+ description?: string;
5017
+ icon?: IconName;
5018
+ /** CSS color for the glyph only; never the label, border, or background. */
5019
+ iconColor?: string;
5020
+ behavior: AgentWidgetSuggestionBehavior;
5021
+ emphasis: "default" | "primary";
5022
+ };
5023
+ /** Presentation keys shared by every suggestion surface. */
5024
+ type AgentWidgetSuggestionSurfaceConfig = {
5025
+ /** Item density. Defaults to `card` for starters and `chip` for follow-ups. */
5026
+ variant?: AgentWidgetSuggestionVariant;
5027
+ /** Default click behavior, overridable per item. Defaults to `send`. */
5028
+ behavior?: AgentWidgetSuggestionBehavior;
5029
+ /**
5030
+ * Layout for items past the surface width. Defaults to `wrap` on every
5031
+ * surface; `scroll` opts into a horizontal strip for large sets. Applies
5032
+ * to the `chip` variant only; the `card` and `list` layouts manage their
5033
+ * own stacking.
5034
+ */
5035
+ overflow?: "scroll" | "wrap";
5036
+ /** Maximum visible items. Defaults to 4. */
5037
+ maxItems?: number;
5038
+ };
5039
+ type AgentWidgetStarterSuggestionsConfig = AgentWidgetSuggestionSurfaceConfig & {
5040
+ /** Suggestions shown before the first user message. */
5041
+ items?: AgentWidgetSuggestion[];
5042
+ /**
5043
+ * `auto` uses the welcome surface when the welcome card renders and the
5044
+ * composer otherwise. Explicit values are literal: `welcome` renders
5045
+ * nothing when the welcome card is hidden. Defaults to `auto`.
5046
+ */
5047
+ placement?: "auto" | "welcome" | "composer";
5048
+ };
5049
+ type AgentWidgetFollowUpSuggestionsConfig = AgentWidgetSuggestionSurfaceConfig & {
5050
+ /**
5051
+ * Enable the built-in `suggest_replies` follow-ups. Defaults to true. When
5052
+ * false, `suggest_replies` renders as a regular tool bubble and is NOT
5053
+ * auto-resumed: only set this with no server-side `suggest_replies`
5054
+ * declaration, or the execution parks awaiting a resume that never comes.
5055
+ */
5056
+ enabled?: boolean;
5057
+ /**
5058
+ * Advertise the built-in `suggest_replies` tool to the agent on every
5059
+ * dispatch via `clientTools[]`: no server-side `runtimeTools` declaration
5060
+ * needed. Defaults to `false`. Declare the tool in one place: the API
5061
+ * dedupes a double declaration by name with `clientTools[]` winning, so
5062
+ * the model still sees exactly one tool, but the widget's description and
5063
+ * schema win and the effective tool type becomes `local` (the execution
5064
+ * pauses and the widget auto-resumes it). Ignored when `enabled` is
5065
+ * `false`.
5066
+ */
5067
+ expose?: boolean;
5068
+ /**
5069
+ * `auto` places follow-ups after the transcript in regular panels and above
5070
+ * the composer in composer-bar mode. Defaults to `auto`.
5071
+ */
5072
+ placement?: "auto" | "after-message" | "composer";
5073
+ };
5074
+ /**
5075
+ * Structured suggestions configuration. The legacy `suggestionChips` and
5076
+ * `suggestionChipsConfig` fields remain supported for backwards compatibility.
5077
+ */
5078
+ type AgentWidgetSuggestionsConfig = {
5079
+ starters?: AgentWidgetStarterSuggestionsConfig;
5080
+ followUps?: AgentWidgetFollowUpSuggestionsConfig;
5081
+ };
5082
+ /**
5083
+ * Which welcome surface renders.
5084
+ * `"card"` is the top-of-scroll intro card (default, back-compatible),
5085
+ * `"hero"` centers it in the empty conversation, `"none"` renders no surface.
5086
+ */
5087
+ type AgentWidgetWelcomeVariant = "card" | "hero" | "none";
5088
+ /**
5089
+ * When the welcome surface goes away. `"never"` is the default for `"card"`;
5090
+ * `"on-first-message"` is the default for `"hero"` and cannot be overridden
5091
+ * there.
5092
+ */
5093
+ type AgentWidgetWelcomeDismiss = "never" | "on-first-message";
5094
+ /**
5095
+ * Avatar or logo shown above the welcome title. Discriminated union; the
5096
+ * function form is the escape hatch for custom markup. There is deliberately
5097
+ * no raw HTML string variant (sanitization surface plus accessibility hole).
5098
+ */
5099
+ type AgentWidgetWelcomeIcon = {
5100
+ type: "lucide";
5101
+ name: IconName;
5102
+ }
5103
+ /** `alt` is required, and may be `""` for a decorative logo. */
5104
+ | {
5105
+ type: "image";
5106
+ url: string;
5107
+ alt: string;
5108
+ }
5109
+ /** Emoji or short text glyph. */
5110
+ | {
5111
+ type: "text";
5112
+ text: string;
5113
+ } | (() => HTMLElement | SVGElement);
5114
+ /**
5115
+ * First-open welcome surface. Consolidates the deprecated
5116
+ * `copy.welcomeTitle` / `copy.welcomeSubtitle` / `copy.showWelcomeCard`
5117
+ * options; a field present here wins over its legacy alias.
5118
+ *
5119
+ * All defaults live in the resolver (`resolveWelcomeConfig`), never in
5120
+ * `DEFAULT_WIDGET_CONFIG`: presence on this object is what distinguishes a
5121
+ * host-set value from a filled-in default.
5122
+ */
5123
+ interface AgentWidgetWelcomeConfig {
5124
+ /** Card or hero title. Defaults to "Hello 👋". */
5125
+ title?: string;
5126
+ /** Scope statement in the assistant's voice. Empty string omits it. */
5127
+ subtitle?: string;
5128
+ /** Avatar or logo shown above the title. */
5129
+ icon?: AgentWidgetWelcomeIcon;
5130
+ /** @default "card" */
5131
+ variant?: AgentWidgetWelcomeVariant;
5132
+ /** @default "never" for `card`, always `"on-first-message"` for `hero`. */
5133
+ dismiss?: AgentWidgetWelcomeDismiss;
5134
+ /**
5135
+ * Display-only greeting bubble pinned at transcript position zero. It is UI
5136
+ * chrome derived from config, never a session message: it does not appear in
5137
+ * `getMessages()`, is never persisted or sent to the model, `onMessage` does
5138
+ * not fire for it, and it survives `clearChat()`. Use an assistant
5139
+ * `initialMessages` entry instead when the model should see the greeting.
5140
+ *
5141
+ * Ignored (with a debug-mode warning) when `variant` is `"hero"`: the hero
5142
+ * is the greeting.
5143
+ */
5144
+ message?: string;
5145
+ }
4666
5146
  /**
4667
5147
  * Interface for pluggable stream parsers that extract text from streaming responses.
4668
5148
  * Parsers handle incremental parsing to extract text values from structured formats (JSON, XML, etc.).
@@ -4844,7 +5324,9 @@ type AgentWidgetHeaderLayoutConfig = {
4844
5324
  */
4845
5325
  render?: (context: HeaderRenderContext) => HTMLElement;
4846
5326
  /**
4847
- * Shown after the title in `minimal` header layout (e.g. chevron menu affordance).
5327
+ * Icon action buttons at the trailing edge of the `minimal` header layout,
5328
+ * clustered with the close button and sharing its chrome. For a menu
5329
+ * affordance next to the title, use `titleMenu` instead.
4848
5330
  */
4849
5331
  trailingActions?: AgentWidgetHeaderTrailingAction[];
4850
5332
  /** Called when a `trailingActions` button is clicked. */
@@ -5024,7 +5506,11 @@ type AgentWidgetLayoutConfig = {
5024
5506
  /**
5025
5507
  * Max width for the content area (messages + composer).
5026
5508
  * Applied with `margin: 0 auto` for centering.
5027
- * Accepts any CSS width value (e.g. "90ch", "720px", "80%").
5509
+ * Accepts any CSS width value (e.g. "90ch", "720px", "80%"), or "none"
5510
+ * for a full-width column. Only engages on panels wider than the cap,
5511
+ * so launcher-width panels are unaffected.
5512
+ * @default "768px" ("720px" in composer-bar mode via
5513
+ * `launcher.composerBar.contentMaxWidth`)
5028
5514
  */
5029
5515
  contentMaxWidth?: string;
5030
5516
  };
@@ -5772,7 +6258,9 @@ type AgentWidgetConfig = {
5772
6258
  */
5773
6259
  getHeaders?: AgentWidgetHeadersFunction;
5774
6260
  copy?: {
6261
+ /** @deprecated Use `welcome.title`. */
5775
6262
  welcomeTitle?: string;
6263
+ /** @deprecated Use `welcome.subtitle`. */
5776
6264
  welcomeSubtitle?: string;
5777
6265
  inputPlaceholder?: string;
5778
6266
  sendButtonLabel?: string;
@@ -5780,6 +6268,7 @@ type AgentWidgetConfig = {
5780
6268
  stopButtonLabel?: string;
5781
6269
  /**
5782
6270
  * When false, the welcome / intro card is not shown above the message list.
6271
+ * @deprecated Use `welcome.variant: "none"`.
5783
6272
  * @default true
5784
6273
  */
5785
6274
  showWelcomeCard?: boolean;
@@ -5844,7 +6333,17 @@ type AgentWidgetConfig = {
5844
6333
  * with `initialArtifacts`.
5845
6334
  */
5846
6335
  initialSelectedArtifactId?: string | null;
6336
+ /** Rich starter and follow-up suggestion surfaces. */
6337
+ suggestions?: AgentWidgetSuggestionsConfig;
6338
+ /**
6339
+ * First-open welcome surface (card, hero, or none) plus the optional
6340
+ * display-only greeting bubble. Supersedes `copy.welcomeTitle`,
6341
+ * `copy.welcomeSubtitle`, and `copy.showWelcomeCard`.
6342
+ */
6343
+ welcome?: AgentWidgetWelcomeConfig;
6344
+ /** @deprecated Prefer `suggestions.starters.items`. */
5847
6345
  suggestionChips?: string[];
6346
+ /** @deprecated Prefer semantic tokens under `theme.components.suggestion`. */
5848
6347
  suggestionChipsConfig?: AgentWidgetSuggestionChipsConfig;
5849
6348
  debug?: boolean;
5850
6349
  formEndpoint?: string;
@@ -6799,7 +7298,6 @@ declare const STYLE_SECTIONS: SectionDef[];
6799
7298
  declare const PALETTE_SECTION: SectionDef;
6800
7299
  declare const SEMANTIC_COLORS_SECTION: SectionDef;
6801
7300
  declare const COLORS_SECTIONS: SectionDef[];
6802
- /** Shared shape sections (not scoped to light/dark) */
6803
7301
  declare const COMPONENT_SHAPE_SECTIONS: SectionDef[];
6804
7302
  /** Component color sections (can be scoped for light/dark) */
6805
7303
  declare const COMPONENT_COLOR_SECTIONS: SectionDef[];
@@ -6880,7 +7378,7 @@ declare const MOCK_WORKSPACE_CONTENT = "\n <div class=\"preview-workspace-con
6880
7378
  * using the exported templates and shell CSS utilities.
6881
7379
  */
6882
7380
  declare function buildSrcdoc(mountId: string, shellMode: 'light' | 'dark', docked: boolean, widgetCssPath: string): string;
6883
- type PreviewScene = 'home' | 'conversation' | 'minimized' | 'artifact';
7381
+ type PreviewScene = 'home' | 'conversation' | 'follow-ups' | 'minimized' | 'artifact';
6884
7382
  type PreviewTranscriptEntryPreset = 'user-message' | 'assistant-message' | 'assistant-code-block' | 'assistant-markdown-table' | 'assistant-image' | 'reasoning-streaming' | 'reasoning-complete' | 'tool-running' | 'tool-complete' | 'approval-request';
6885
7383
  declare function getPreviewTranscriptPresetLabel(preset: PreviewTranscriptEntryPreset): string;
6886
7384
  declare function createPreviewTranscriptEntry(preset: PreviewTranscriptEntryPreset, index?: number): AgentWidgetMessage;