@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
@@ -1,5 +1,81 @@
1
1
  import { IconNode } from 'lucide';
2
2
 
3
+ interface ResolvedWelcomeConfig {
4
+ title: string;
5
+ subtitle: string;
6
+ icon?: AgentWidgetWelcomeIcon;
7
+ variant: AgentWidgetWelcomeVariant;
8
+ dismiss: AgentWidgetWelcomeDismiss;
9
+ /** Undefined under `variant: "hero"`, which suppresses the greeting. */
10
+ message?: string;
11
+ }
12
+
13
+ /**
14
+ * Synchronous key-value store handed to plugin render hooks. Backed by
15
+ * `localStorage`, namespaced per plugin id. The async `storageAdapter` cannot
16
+ * back a synchronous API and `persistState` is not a general key-value surface.
17
+ */
18
+ interface AgentWidgetPluginStorage {
19
+ get: (key: string) => string | null;
20
+ set: (key: string, value: string) => void;
21
+ remove: (key: string) => void;
22
+ }
23
+
24
+ type AgentWidgetTransformSuggestionsContext = {
25
+ /**
26
+ * Fresh copy of the suggestions entering this plugin, already normalized:
27
+ * shorthand strings expanded and the effective send/fill behavior resolved.
28
+ */
29
+ suggestions: AgentWidgetResolvedSuggestion[];
30
+ surface: AgentWidgetSuggestionSurface;
31
+ source: AgentWidgetSuggestionSource;
32
+ config: AgentWidgetConfig;
33
+ };
34
+ type AgentWidgetRenderSuggestionContext = {
35
+ /** Fully normalized suggestion, including the effective send/fill behavior. */
36
+ suggestion: AgentWidgetResolvedSuggestion;
37
+ index: number;
38
+ surface: AgentWidgetSuggestionSurface;
39
+ source: AgentWidgetSuggestionSource;
40
+ variant: AgentWidgetSuggestionVariant;
41
+ streaming: boolean;
42
+ config: AgentWidgetConfig;
43
+ /** Build Persona's standard chip, card, or list item. */
44
+ defaultRenderer: () => HTMLElement;
45
+ /**
46
+ * Run the normal selection pipeline: DOM event, plugin selection hooks, then
47
+ * send or fill. Custom renderers should call this instead of sending directly.
48
+ */
49
+ select: () => void;
50
+ };
51
+ type AgentWidgetRenderWelcomeContext = {
52
+ /** Alias-resolved welcome config; never the raw `copy.welcome*` shape. */
53
+ config: ResolvedWelcomeConfig;
54
+ variant: AgentWidgetWelcomeVariant;
55
+ /** Derived visibility for this render; governs the default renderer only. */
56
+ visible: boolean;
57
+ /** The core-owned welcome card, live-updated by `controller.update()`. */
58
+ defaultRenderer: () => HTMLElement;
59
+ sendMessage: (text: string) => void;
60
+ /** Re-run welcome arbitration: cleanups run, previous content is removed. */
61
+ requestRender: () => void;
62
+ /**
63
+ * Persona's starter renderer, wired through the full select pipeline:
64
+ * `onSuggestionSelect`, cancelable `persona:suggestion:*` events, send/fill.
65
+ */
66
+ renderStarter: (suggestion: AgentWidgetSuggestion) => HTMLElement;
67
+ /** Sync store namespaced by `persistState.keyPrefix` plus the plugin id. */
68
+ storage: AgentWidgetPluginStorage;
69
+ /** Teardown for this render; runs before the next one and on destroy. */
70
+ onCleanup: (fn: () => void) => void;
71
+ };
72
+ type AgentWidgetSuggestionSelectContext = {
73
+ suggestion: AgentWidgetResolvedSuggestion;
74
+ surface: AgentWidgetSuggestionSurface;
75
+ source: AgentWidgetSuggestionSource;
76
+ variant: AgentWidgetSuggestionVariant;
77
+ config: AgentWidgetConfig;
78
+ };
3
79
  /**
4
80
  * Plugin interface for customizing widget components
5
81
  */
@@ -12,6 +88,25 @@ interface AgentWidgetPlugin {
12
88
  * Optional priority (higher = runs first). Default: 0
13
89
  */
14
90
  priority?: number;
91
+ /**
92
+ * Transform, filter, enrich, or reorder suggestions. Hooks receive normalized
93
+ * items and compose in plugin priority order; the return value may use the
94
+ * loose shape (string shorthand included) and is re-normalized before the next
95
+ * hook. A per-item `behavior` set here survives. `maxItems` caps the list
96
+ * after the full chain. Return an empty array to hide the surface.
97
+ */
98
+ transformSuggestions?: (context: AgentWidgetTransformSuggestionsContext) => AgentWidgetSuggestion[];
99
+ /**
100
+ * Render one starter or follow-up suggestion. Return null to use Persona's
101
+ * default chip/card/list renderer. Call `select()` from custom interaction
102
+ * controls to preserve events, selection hooks, and send/fill behavior.
103
+ */
104
+ renderSuggestion?: (context: AgentWidgetRenderSuggestionContext) => HTMLElement | null;
105
+ /**
106
+ * Observe or intercept a suggestion selection. Return false to cancel the
107
+ * built-in send/fill action. Hooks run in plugin priority order.
108
+ */
109
+ onSuggestionSelect?: (context: AgentWidgetSuggestionSelectContext) => void | boolean;
15
110
  /**
16
111
  * Custom renderer for message bubbles
17
112
  * Return null to use default renderer
@@ -30,6 +125,34 @@ interface AgentWidgetPlugin {
30
125
  defaultRenderer: () => HTMLElement;
31
126
  onToggle: () => void;
32
127
  }) => HTMLElement | null;
128
+ /**
129
+ * Custom renderer for the welcome surface (card, hero, greeting stack).
130
+ * First plugin returning an element wins; null falls through to the default,
131
+ * same contract as `renderSuggestion`.
132
+ *
133
+ * The core owns the welcome host: it stays mounted for the panel's lifetime
134
+ * and content is swapped inside it. A plugin element renders regardless of
135
+ * `ctx.visible` (derived visibility governs the default renderer only) and
136
+ * the host overlays the transcript while that element is active, so a home
137
+ * screen can return over an existing conversation. Return null again to
138
+ * clear the overlay.
139
+ *
140
+ * The ctx carries no controller: plugins are host-instantiated, so close a
141
+ * factory over the init handle (`plugin.attach(controller)`).
142
+ *
143
+ * @example
144
+ * ```typescript
145
+ * renderWelcome: ({ config, renderStarter, requestRender, onCleanup }) => {
146
+ * const root = document.createElement("div");
147
+ * root.textContent = config.title;
148
+ * root.appendChild(renderStarter({ label: "Track my order" }));
149
+ * const timer = setInterval(requestRender, 60_000);
150
+ * onCleanup(() => clearInterval(timer));
151
+ * return root;
152
+ * }
153
+ * ```
154
+ */
155
+ renderWelcome?: (context: AgentWidgetRenderWelcomeContext) => HTMLElement | null;
33
156
  /**
34
157
  * Custom renderer for panel header
35
158
  * Return null to use default renderer
@@ -74,6 +197,15 @@ interface AgentWidgetPlugin {
74
197
  * Omitted when `config.voiceRecognition.enabled` is not true.
75
198
  */
76
199
  onVoiceToggle?: () => void;
200
+ /**
201
+ * Re-run composer arbitration and swap the footer in place. The hook runs
202
+ * once at panel construction, so this is how a composer plugin unlocks
203
+ * (returns null) or re-renders later. Pending attachments, the mention
204
+ * affordances, and the composer listener registry are re-wired by the core.
205
+ */
206
+ requestRender: () => void;
207
+ /** Same sync store as the `renderWelcome` ctx, namespaced per plugin id. */
208
+ storage: AgentWidgetPluginStorage;
77
209
  }) => HTMLElement | null;
78
210
  /**
79
211
  * Custom renderer for reasoning bubbles
@@ -454,6 +586,15 @@ interface PanelTokens extends ComponentTokenSet {
454
586
  /** Background of the region revealed behind a detached panel. */
455
587
  canvasBackground?: string;
456
588
  }
589
+ /** Per-element text styling shared by themable text surfaces. */
590
+ interface TextStyleTokens {
591
+ fontFamily?: string;
592
+ fontSize?: string;
593
+ fontWeight?: string;
594
+ lineHeight?: string;
595
+ letterSpacing?: string;
596
+ color?: TokenReference<'color'>;
597
+ }
457
598
  interface HeaderTokens extends ComponentTokenSet {
458
599
  background: TokenReference<'color'>;
459
600
  border: TokenReference<'color'>;
@@ -462,10 +603,14 @@ interface HeaderTokens extends ComponentTokenSet {
462
603
  iconBackground: TokenReference<'color'>;
463
604
  /** Foreground (glyph stroke or emoji text) on the header avatar tile. */
464
605
  iconForeground: TokenReference<'color'>;
465
- /** Header title line (next to the icon, or minimal layout title). */
606
+ /** Legacy alias of `title.color`; `title.color` wins when both are set. */
466
607
  titleForeground: TokenReference<'color'>;
467
- /** Header subtitle line under the title. */
608
+ /** Legacy alias of `subtitle.color`; `subtitle.color` wins when both are set. */
468
609
  subtitleForeground: TokenReference<'color'>;
610
+ /** Header title typography (next to the icon, or minimal layout title). */
611
+ title?: TextStyleTokens;
612
+ /** Header subtitle typography, for the line under the title. */
613
+ subtitle?: TextStyleTokens;
469
614
  /** Default color for clear / close icon buttons when launcher overrides are unset. */
470
615
  actionIconForeground: TokenReference<'color'>;
471
616
  /** Box-shadow on the header (e.g., a fade shadow to replace the default border). */
@@ -495,7 +640,7 @@ interface MessageTokens {
495
640
  }
496
641
  /**
497
642
  * Welcome / intro card rendered above the message list when no messages exist.
498
- * Set `copy.showWelcomeCard: false` to hide it; use `layout.slots["body-top"]`
643
+ * Set `welcome.variant: "none"` to hide it; use `layout.slots["body-top"]`
499
644
  * to replace it wholesale.
500
645
  */
501
646
  interface IntroCardTokens extends ComponentTokenSet {
@@ -504,6 +649,12 @@ interface IntroCardTokens extends ComponentTokenSet {
504
649
  padding?: TokenReference<'spacing'>;
505
650
  /** Box-shadow on the intro card (token ref or raw CSS, e.g. `none`). */
506
651
  shadow?: string;
652
+ /** Full border shorthand on the intro card (raw CSS, e.g. `"1px solid rgba(0,0,0,0.1)"`). @default "none" */
653
+ border?: string;
654
+ /** Welcome title typography. */
655
+ title?: TextStyleTokens;
656
+ /** Welcome subtitle typography. */
657
+ subtitle?: TextStyleTokens;
507
658
  }
508
659
  /** Collapsible widget chrome (tool bubbles, reasoning bubbles, approval bubbles). */
509
660
  interface CollapsibleWidgetTokens {
@@ -546,6 +697,8 @@ interface MarkdownTokens {
546
697
  background?: TokenReference<'color'>;
547
698
  borderColor?: TokenReference<'color'>;
548
699
  textColor?: TokenReference<'color'>;
700
+ /** Corner radius; follows `palette.radius.md` by default so square-corner themes get square code blocks. */
701
+ borderRadius?: TokenReference<'radius'>;
549
702
  };
550
703
  /** Table styling. */
551
704
  table?: {
@@ -603,10 +756,27 @@ interface ToolBubbleTokens {
603
756
  interface ReasoningBubbleTokens {
604
757
  shadow: string;
605
758
  }
759
+ /** Scrollbar appearance shared by every scroller in the widget. */
760
+ interface ScrollbarTokens {
761
+ /** Thumb color. @default semantic.colors.border */
762
+ thumb?: TokenReference<'color'>;
763
+ /** Track color. @default "transparent" */
764
+ track?: TokenReference<'color'>;
765
+ }
606
766
  /** Composer (message input) chrome. */
607
767
  interface ComposerChromeTokens {
608
768
  /** Box-shadow on the composer form (raw CSS, e.g. `none`). */
609
769
  shadow: string;
770
+ /** Border color of the composer form. @default semantic.colors.border */
771
+ borderColor?: TokenReference<'color'>;
772
+ /** Inner padding of the composer form (raw CSS shorthand). @default "0.75rem 1rem" */
773
+ padding?: string;
774
+ /** Gap between the textarea row and the actions row. @default "0.5rem" */
775
+ gap?: string;
776
+ /** Composer textarea font-size. @default "0.875rem" */
777
+ fontSize?: string;
778
+ /** Composer textarea line-height. @default "1.25rem" */
779
+ lineHeight?: string;
610
780
  }
611
781
  /** Artifact toolbar chrome. */
612
782
  interface ArtifactToolbarTokens {
@@ -756,6 +926,29 @@ interface ScrollToBottomTokens extends ComponentTokenSet {
756
926
  fontSize?: string;
757
927
  iconSize?: string;
758
928
  }
929
+ /** Visual tokens shared by one suggestion presentation variant. */
930
+ interface SuggestionVariantTokens extends ComponentTokenSet {
931
+ /** Space inside one item, between its icon and its copy. */
932
+ gap?: string;
933
+ /** Space between suggestion items in the container. */
934
+ itemGap?: string;
935
+ minHeight?: string;
936
+ fontSize?: string;
937
+ lineHeight?: string;
938
+ iconSize?: string;
939
+ hoverBackground?: TokenReference<'color'>;
940
+ hoverForeground?: TokenReference<'color'>;
941
+ hoverBorder?: TokenReference<'color'>;
942
+ pressedBackground?: TokenReference<'color'>;
943
+ focusRing?: TokenReference<'color'>;
944
+ disabledOpacity?: string;
945
+ }
946
+ /** Starter and follow-up suggestion chrome. */
947
+ interface SuggestionTokens {
948
+ chip: SuggestionVariantTokens;
949
+ card: SuggestionVariantTokens;
950
+ list: SuggestionVariantTokens;
951
+ }
759
952
  /** Toggle group chrome (used by createToggleGroup). */
760
953
  interface ToggleGroupTokens {
761
954
  /** Gap between toggle buttons. Default: 0 (connected). */
@@ -780,12 +973,16 @@ interface ComponentTokens {
780
973
  toolBubble: ToolBubbleTokens;
781
974
  reasoningBubble: ReasoningBubbleTokens;
782
975
  composer: ComposerChromeTokens;
976
+ /** Scrollbar appearance for every scroller in the widget. */
977
+ scrollbar?: ScrollbarTokens;
783
978
  /** Icon button styling tokens. */
784
979
  iconButton?: IconButtonTokens;
785
980
  /** Label button styling tokens. */
786
981
  labelButton?: LabelButtonTokens;
787
982
  /** Scroll-to-bottom indicator styling tokens. */
788
983
  scrollToBottom?: ScrollToBottomTokens;
984
+ /** Starter prompt and follow-up suggestion styling tokens. */
985
+ suggestion?: SuggestionTokens;
789
986
  /** Toggle group styling tokens. */
790
987
  toggleGroup?: ToggleGroupTokens;
791
988
  /** Artifact toolbar, tab strip, and pane chrome. */
@@ -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
  };
@@ -2456,6 +2673,13 @@ type AgentWidgetArtifactsLayoutConfig = {
2456
2673
  * @default 520
2457
2674
  */
2458
2675
  narrowHostMaxWidth?: number;
2676
+ /**
2677
+ * Width of the slide-over artifact drawer (the narrow-host and mobile
2678
+ * presentations; `paneWidth`/`paneMaxWidth` only size the desktop split).
2679
+ * CSS length; `"100%"` makes the drawer cover the whole panel.
2680
+ * @default min(calc(100% - 1rem), 22rem)
2681
+ */
2682
+ drawerWidth?: string;
2459
2683
  /**
2460
2684
  * When true (default), widen the launcher panel while artifacts are visible and not user-dismissed.
2461
2685
  * No-op for inline embed (`launcher.enabled === false`).
@@ -3084,6 +3308,18 @@ type AgentWidgetScrollMode = "follow" | "anchor-top" | "none";
3084
3308
  * restored thread opens at a readable place rather than at the very bottom.
3085
3309
  */
3086
3310
  type AgentWidgetScrollRestorePosition = "bottom" | "last-user-turn";
3311
+ /**
3312
+ * Scrollbar visibility policy for every scroll surface in the widget.
3313
+ *
3314
+ * - `"on-scroll"` hides bars at rest and reveals them on genuine reader
3315
+ * input, keeping them visible while the reader is away from the resting
3316
+ * position: overlay-scrollbar semantics on every platform.
3317
+ * - `"auto"` keeps the themed bar under native visibility semantics: overlay
3318
+ * platforms still auto-hide, classic-scrollbar platforms (Windows,
3319
+ * always-show macOS) show it persistently.
3320
+ * - `"hidden"` never shows an indicator. Scrolling itself is unaffected.
3321
+ */
3322
+ type AgentWidgetScrollbarPolicy = "on-scroll" | "auto" | "hidden";
3087
3323
  type AgentWidgetScrollBehaviorFeature = {
3088
3324
  /** Scroll behavior during streamed responses. @default "anchor-top" */
3089
3325
  mode?: AgentWidgetScrollMode;
@@ -3128,6 +3364,13 @@ type AgentWidgetScrollBehaviorFeature = {
3128
3364
  * @default false
3129
3365
  */
3130
3366
  announce?: boolean;
3367
+ /**
3368
+ * Scrollbar visibility policy, applied to the transcript and every inner
3369
+ * scroller through one root attribute. Themable via
3370
+ * `--persona-scrollbar-thumb` and `--persona-scrollbar-track`.
3371
+ * @default "on-scroll"
3372
+ */
3373
+ scrollbar?: AgentWidgetScrollbarPolicy;
3131
3374
  };
3132
3375
  type AgentWidgetScrollToBottomFeature = {
3133
3376
  /**
@@ -3417,10 +3660,13 @@ type AgentWidgetFeatureFlags = {
3417
3660
  */
3418
3661
  askUserQuestion?: AgentWidgetAskUserQuestionFeature;
3419
3662
  /**
3420
- * Built-in `suggest_replies` quick-reply chips. When the assistant invokes
3421
- * the tool, the widget shows the suggestions as tappable chips above the
3422
- * composer (reusing the suggestion-chips surface) and immediately resumes
3423
- * the execution: fire-and-forget, no user input awaited.
3663
+ * Built-in `suggest_replies` follow-ups. When the assistant invokes the
3664
+ * tool, the widget shows the suggestions using `suggestions.followUps` and
3665
+ * immediately resumes the execution: fire-and-forget, no user input awaited.
3666
+ *
3667
+ * @deprecated Both keys moved to `suggestions.followUps`: use
3668
+ * `suggestions.followUps.enabled` and `suggestions.followUps.expose`. This
3669
+ * alias keeps working per key, with `suggestions.followUps` winning.
3424
3670
  */
3425
3671
  suggestReplies?: AgentWidgetSuggestRepliesFeature;
3426
3672
  };
@@ -3460,11 +3706,12 @@ type WidgetPreferenceSlice = {
3460
3706
  };
3461
3707
  };
3462
3708
  /**
3463
- * Feature config for the built-in `suggest_replies` quick-reply chips.
3464
- * Chips render in the existing suggestions slot above the composer and are
3465
- * styled by the widget-level `suggestionChipsConfig`. A tapped chip is sent
3466
- * verbatim as the user's next message; chips clear once any user message
3467
- * follows them.
3709
+ * Feature config for the built-in `suggest_replies` follow-ups.
3710
+ *
3711
+ * @deprecated Both keys moved to `suggestions.followUps`
3712
+ * (`suggestions.followUps.enabled` / `suggestions.followUps.expose`), which
3713
+ * also owns presentation, placement, and send/fill behavior. Resolution is
3714
+ * per key with `suggestions.followUps` winning; removal waits for 5.0.
3468
3715
  */
3469
3716
  type AgentWidgetSuggestRepliesFeature = {
3470
3717
  /**
@@ -3472,14 +3719,18 @@ type AgentWidgetSuggestRepliesFeature = {
3472
3719
  * renders as a regular tool bubble and is NOT auto-resumed: only set this
3473
3720
  * with no server-side `suggest_replies` declaration, or the execution
3474
3721
  * parks awaiting a resume that never comes.
3722
+ * @deprecated Use `suggestions.followUps.enabled`.
3475
3723
  */
3476
3724
  enabled?: boolean;
3477
3725
  /**
3478
3726
  * Advertise the built-in `suggest_replies` tool to the agent on every
3479
3727
  * dispatch via `clientTools[]`: no server-side `runtimeTools` declaration
3480
- * needed. Defaults to `false`: flows that already declare the tool via
3481
- * `runtimeTools` would otherwise present it to the model twice. Ignored
3482
- * when `enabled` is `false`.
3728
+ * needed. Defaults to `false`. Declare the tool in one place: the API
3729
+ * dedupes a double declaration by name with `clientTools[]` winning, so the
3730
+ * model still sees exactly one tool, but the widget's description and schema
3731
+ * win and the effective tool type becomes `local` (the execution pauses and
3732
+ * the widget auto-resumes it). Ignored when `enabled` is `false`.
3733
+ * @deprecated Use `suggestions.followUps.expose`.
3483
3734
  */
3484
3735
  expose?: boolean;
3485
3736
  };
@@ -3549,10 +3800,13 @@ type AgentWidgetAskUserQuestionFeature = {
3549
3800
  * matching {@link AskUserQuestionPayload}; when the model calls it, the
3550
3801
  * existing answer-pill sheet renders and the answer resumes the execution.
3551
3802
  *
3552
- * Defaults to `false`: flows that already declare `ask_user_question` via
3553
- * `runtimeTools` would otherwise present the tool to the model twice.
3554
- * Ignored when `enabled` is `false`: never offer the agent a question
3555
- * tool the widget can't render an answer UI for.
3803
+ * Defaults to `false`. Declare the tool in one place: the API dedupes a
3804
+ * double declaration by name with `clientTools[]` winning, so the model
3805
+ * still sees exactly one tool, but the widget's description and schema win
3806
+ * and the effective tool type becomes `local` (the execution pauses and the
3807
+ * widget resumes it with the user's answer). Ignored when `enabled` is
3808
+ * `false`: never offer the agent a question tool the widget can't render an
3809
+ * answer UI for.
3556
3810
  */
3557
3811
  expose?: boolean;
3558
3812
  /** Slide-in animation duration in ms. Defaults to 180. */
@@ -4017,6 +4271,57 @@ type AgentWidgetLauncherConfig = {
4017
4271
  * @example "min(380px, calc(100vw - 48px))"
4018
4272
  */
4019
4273
  collapsedMaxWidth?: string;
4274
+ /**
4275
+ * Proactive nudge bubble anchored above the collapsed floating launcher.
4276
+ * Omit it (the default) and no teaser renders.
4277
+ */
4278
+ teaser?: AgentWidgetLauncherTeaserConfig;
4279
+ };
4280
+ /**
4281
+ * Launcher teaser: a small bubble above the collapsed launcher. Clicking it
4282
+ * opens the panel and consumes the teaser exactly like an explicit dismissal.
4283
+ * Within a single page load the teaser appears at most once under either
4284
+ * frequency.
4285
+ *
4286
+ * @example
4287
+ * ```typescript
4288
+ * launcher: {
4289
+ * teaser: { text: "Need a hand picking a plan?", delayMs: 3000 }
4290
+ * }
4291
+ * ```
4292
+ */
4293
+ type AgentWidgetLauncherTeaserConfig = {
4294
+ /** Bubble copy. An empty string renders no teaser. */
4295
+ text: string;
4296
+ /**
4297
+ * Delay before the bubble appears, in milliseconds.
4298
+ * @default 0
4299
+ */
4300
+ delayMs?: number;
4301
+ /**
4302
+ * How often the teaser may return.
4303
+ *
4304
+ * `"once"`: a dismissal or a click-through is remembered in `localStorage`
4305
+ * under `` `${persistState.keyPrefix ?? "persona-"}teaser-dismissed` `` and
4306
+ * the teaser never returns on that browser. `"always"`: shows on every page
4307
+ * load, tracked in memory only. `persistState: false` downgrades `"once"` to
4308
+ * in-memory too, so the teaser reappears each load.
4309
+ *
4310
+ * Custom `storageAdapter` implementations do not participate in teaser state.
4311
+ *
4312
+ * @default "once"
4313
+ */
4314
+ frequency?: "once" | "always";
4315
+ /**
4316
+ * Render an x affordance that dismisses the teaser without opening the panel.
4317
+ * @default true
4318
+ */
4319
+ dismissible?: boolean;
4320
+ /**
4321
+ * Accessible label for the dismiss affordance.
4322
+ * @default "Dismiss message"
4323
+ */
4324
+ dismissLabel?: string;
4020
4325
  };
4021
4326
  type AgentWidgetSendButtonConfig = {
4022
4327
  borderWidth?: string;
@@ -4025,6 +4330,10 @@ type AgentWidgetSendButtonConfig = {
4025
4330
  paddingY?: string;
4026
4331
  iconText?: string;
4027
4332
  iconName?: string;
4333
+ /** Icon glyph box in icon mode, e.g. "20px". Defaults to half of `size`. */
4334
+ iconSize?: string;
4335
+ /** Stroke width for the icon glyph, in viewBox units. Default 2. */
4336
+ iconStrokeWidth?: number;
4028
4337
  useIcon?: boolean;
4029
4338
  tooltipText?: string;
4030
4339
  showTooltip?: boolean;
@@ -4757,6 +5066,177 @@ type AgentWidgetSuggestionChipsConfig = {
4757
5066
  paddingX?: string;
4758
5067
  paddingY?: string;
4759
5068
  };
5069
+ /** A suggested next action shown to the user. Strings remain supported as shorthand. */
5070
+ type AgentWidgetSuggestion = string | {
5071
+ /** Stable analytics / DOM identity. Falls back to the prompt or label. */
5072
+ id?: string;
5073
+ /** Concise visible action label. */
5074
+ label: string;
5075
+ /** Text placed in the composer or sent. Defaults to `label`. */
5076
+ prompt?: string;
5077
+ /**
5078
+ * Optional supporting copy, most useful with the `card` variant. The
5079
+ * `chip` variant ignores it and renders the label alone.
5080
+ */
5081
+ description?: string;
5082
+ /** Optional icon from Persona's bundled Lucide registry. */
5083
+ icon?: IconName;
5084
+ /**
5085
+ * CSS color for this item's glyph. Tints the icon only: label, border,
5086
+ * and background stay neutral. Ignored without an `icon`.
5087
+ */
5088
+ iconColor?: string;
5089
+ /** Override the surface's click behavior for this item. */
5090
+ behavior?: AgentWidgetSuggestionBehavior;
5091
+ /** Visually promote one high-confidence action. */
5092
+ emphasis?: "default" | "primary";
5093
+ };
5094
+ type AgentWidgetSuggestionBehavior = "send" | "fill";
5095
+ type AgentWidgetSuggestionVariant = "chip" | "card" | "list";
5096
+ type AgentWidgetSuggestionSurface = "starter" | "followUp";
5097
+ /**
5098
+ * Who produced the rendered suggestions: static config, the agent's
5099
+ * `suggest_replies` tool, or `controller.setFollowUpSuggestions`.
5100
+ */
5101
+ type AgentWidgetSuggestionSource = "config" | "agent" | "host";
5102
+ /**
5103
+ * A suggestion after Persona has normalized shorthand strings and resolved the
5104
+ * effective click behavior. Plugin hooks receive this stable shape.
5105
+ */
5106
+ type AgentWidgetResolvedSuggestion = {
5107
+ id: string;
5108
+ label: string;
5109
+ prompt: string;
5110
+ description?: string;
5111
+ icon?: IconName;
5112
+ /** CSS color for the glyph only; never the label, border, or background. */
5113
+ iconColor?: string;
5114
+ behavior: AgentWidgetSuggestionBehavior;
5115
+ emphasis: "default" | "primary";
5116
+ };
5117
+ /** Presentation keys shared by every suggestion surface. */
5118
+ type AgentWidgetSuggestionSurfaceConfig = {
5119
+ /** Item density. Defaults to `card` for starters and `chip` for follow-ups. */
5120
+ variant?: AgentWidgetSuggestionVariant;
5121
+ /** Default click behavior, overridable per item. Defaults to `send`. */
5122
+ behavior?: AgentWidgetSuggestionBehavior;
5123
+ /**
5124
+ * Layout for items past the surface width. Defaults to `wrap` on every
5125
+ * surface; `scroll` opts into a horizontal strip for large sets. Applies
5126
+ * to the `chip` variant only; the `card` and `list` layouts manage their
5127
+ * own stacking.
5128
+ */
5129
+ overflow?: "scroll" | "wrap";
5130
+ /** Maximum visible items. Defaults to 4. */
5131
+ maxItems?: number;
5132
+ };
5133
+ type AgentWidgetStarterSuggestionsConfig = AgentWidgetSuggestionSurfaceConfig & {
5134
+ /** Suggestions shown before the first user message. */
5135
+ items?: AgentWidgetSuggestion[];
5136
+ /**
5137
+ * `auto` uses the welcome surface when the welcome card renders and the
5138
+ * composer otherwise. Explicit values are literal: `welcome` renders
5139
+ * nothing when the welcome card is hidden. Defaults to `auto`.
5140
+ */
5141
+ placement?: "auto" | "welcome" | "composer";
5142
+ };
5143
+ type AgentWidgetFollowUpSuggestionsConfig = AgentWidgetSuggestionSurfaceConfig & {
5144
+ /**
5145
+ * Enable the built-in `suggest_replies` follow-ups. Defaults to true. When
5146
+ * false, `suggest_replies` renders as a regular tool bubble and is NOT
5147
+ * auto-resumed: only set this with no server-side `suggest_replies`
5148
+ * declaration, or the execution parks awaiting a resume that never comes.
5149
+ */
5150
+ enabled?: boolean;
5151
+ /**
5152
+ * Advertise the built-in `suggest_replies` tool to the agent on every
5153
+ * dispatch via `clientTools[]`: no server-side `runtimeTools` declaration
5154
+ * needed. Defaults to `false`. Declare the tool in one place: the API
5155
+ * dedupes a double declaration by name with `clientTools[]` winning, so
5156
+ * the model still sees exactly one tool, but the widget's description and
5157
+ * schema win and the effective tool type becomes `local` (the execution
5158
+ * pauses and the widget auto-resumes it). Ignored when `enabled` is
5159
+ * `false`.
5160
+ */
5161
+ expose?: boolean;
5162
+ /**
5163
+ * `auto` places follow-ups after the transcript in regular panels and above
5164
+ * the composer in composer-bar mode. Defaults to `auto`.
5165
+ */
5166
+ placement?: "auto" | "after-message" | "composer";
5167
+ };
5168
+ /**
5169
+ * Structured suggestions configuration. The legacy `suggestionChips` and
5170
+ * `suggestionChipsConfig` fields remain supported for backwards compatibility.
5171
+ */
5172
+ type AgentWidgetSuggestionsConfig = {
5173
+ starters?: AgentWidgetStarterSuggestionsConfig;
5174
+ followUps?: AgentWidgetFollowUpSuggestionsConfig;
5175
+ };
5176
+ /**
5177
+ * Which welcome surface renders.
5178
+ * `"card"` is the top-of-scroll intro card (default, back-compatible),
5179
+ * `"hero"` centers it in the empty conversation, `"none"` renders no surface.
5180
+ */
5181
+ type AgentWidgetWelcomeVariant = "card" | "hero" | "none";
5182
+ /**
5183
+ * When the welcome surface goes away. `"never"` is the default for `"card"`;
5184
+ * `"on-first-message"` is the default for `"hero"` and cannot be overridden
5185
+ * there.
5186
+ */
5187
+ type AgentWidgetWelcomeDismiss = "never" | "on-first-message";
5188
+ /**
5189
+ * Avatar or logo shown above the welcome title. Discriminated union; the
5190
+ * function form is the escape hatch for custom markup. There is deliberately
5191
+ * no raw HTML string variant (sanitization surface plus accessibility hole).
5192
+ */
5193
+ type AgentWidgetWelcomeIcon = {
5194
+ type: "lucide";
5195
+ name: IconName;
5196
+ }
5197
+ /** `alt` is required, and may be `""` for a decorative logo. */
5198
+ | {
5199
+ type: "image";
5200
+ url: string;
5201
+ alt: string;
5202
+ }
5203
+ /** Emoji or short text glyph. */
5204
+ | {
5205
+ type: "text";
5206
+ text: string;
5207
+ } | (() => HTMLElement | SVGElement);
5208
+ /**
5209
+ * First-open welcome surface. Consolidates the deprecated
5210
+ * `copy.welcomeTitle` / `copy.welcomeSubtitle` / `copy.showWelcomeCard`
5211
+ * options; a field present here wins over its legacy alias.
5212
+ *
5213
+ * All defaults live in the resolver (`resolveWelcomeConfig`), never in
5214
+ * `DEFAULT_WIDGET_CONFIG`: presence on this object is what distinguishes a
5215
+ * host-set value from a filled-in default.
5216
+ */
5217
+ interface AgentWidgetWelcomeConfig {
5218
+ /** Card or hero title. Defaults to "Hello 👋". */
5219
+ title?: string;
5220
+ /** Scope statement in the assistant's voice. Empty string omits it. */
5221
+ subtitle?: string;
5222
+ /** Avatar or logo shown above the title. */
5223
+ icon?: AgentWidgetWelcomeIcon;
5224
+ /** @default "card" */
5225
+ variant?: AgentWidgetWelcomeVariant;
5226
+ /** @default "never" for `card`, always `"on-first-message"` for `hero`. */
5227
+ dismiss?: AgentWidgetWelcomeDismiss;
5228
+ /**
5229
+ * Display-only greeting bubble pinned at transcript position zero. It is UI
5230
+ * chrome derived from config, never a session message: it does not appear in
5231
+ * `getMessages()`, is never persisted or sent to the model, `onMessage` does
5232
+ * not fire for it, and it survives `clearChat()`. Use an assistant
5233
+ * `initialMessages` entry instead when the model should see the greeting.
5234
+ *
5235
+ * Ignored (with a debug-mode warning) when `variant` is `"hero"`: the hero
5236
+ * is the greeting.
5237
+ */
5238
+ message?: string;
5239
+ }
4760
5240
  /**
4761
5241
  * Interface for pluggable stream parsers that extract text from streaming responses.
4762
5242
  * Parsers handle incremental parsing to extract text values from structured formats (JSON, XML, etc.).
@@ -4938,7 +5418,9 @@ type AgentWidgetHeaderLayoutConfig = {
4938
5418
  */
4939
5419
  render?: (context: HeaderRenderContext) => HTMLElement;
4940
5420
  /**
4941
- * Shown after the title in `minimal` header layout (e.g. chevron menu affordance).
5421
+ * Icon action buttons at the trailing edge of the `minimal` header layout,
5422
+ * clustered with the close button and sharing its chrome. For a menu
5423
+ * affordance next to the title, use `titleMenu` instead.
4942
5424
  */
4943
5425
  trailingActions?: AgentWidgetHeaderTrailingAction[];
4944
5426
  /** Called when a `trailingActions` button is clicked. */
@@ -5118,7 +5600,11 @@ type AgentWidgetLayoutConfig = {
5118
5600
  /**
5119
5601
  * Max width for the content area (messages + composer).
5120
5602
  * Applied with `margin: 0 auto` for centering.
5121
- * Accepts any CSS width value (e.g. "90ch", "720px", "80%").
5603
+ * Accepts any CSS width value (e.g. "90ch", "720px", "80%"), or "none"
5604
+ * for a full-width column. Only engages on panels wider than the cap,
5605
+ * so launcher-width panels are unaffected.
5606
+ * @default "768px" ("720px" in composer-bar mode via
5607
+ * `launcher.composerBar.contentMaxWidth`)
5122
5608
  */
5123
5609
  contentMaxWidth?: string;
5124
5610
  };
@@ -5866,7 +6352,9 @@ type AgentWidgetConfig = {
5866
6352
  */
5867
6353
  getHeaders?: AgentWidgetHeadersFunction;
5868
6354
  copy?: {
6355
+ /** @deprecated Use `welcome.title`. */
5869
6356
  welcomeTitle?: string;
6357
+ /** @deprecated Use `welcome.subtitle`. */
5870
6358
  welcomeSubtitle?: string;
5871
6359
  inputPlaceholder?: string;
5872
6360
  sendButtonLabel?: string;
@@ -5874,6 +6362,7 @@ type AgentWidgetConfig = {
5874
6362
  stopButtonLabel?: string;
5875
6363
  /**
5876
6364
  * When false, the welcome / intro card is not shown above the message list.
6365
+ * @deprecated Use `welcome.variant: "none"`.
5877
6366
  * @default true
5878
6367
  */
5879
6368
  showWelcomeCard?: boolean;
@@ -5938,7 +6427,17 @@ type AgentWidgetConfig = {
5938
6427
  * with `initialArtifacts`.
5939
6428
  */
5940
6429
  initialSelectedArtifactId?: string | null;
6430
+ /** Rich starter and follow-up suggestion surfaces. */
6431
+ suggestions?: AgentWidgetSuggestionsConfig;
6432
+ /**
6433
+ * First-open welcome surface (card, hero, or none) plus the optional
6434
+ * display-only greeting bubble. Supersedes `copy.welcomeTitle`,
6435
+ * `copy.welcomeSubtitle`, and `copy.showWelcomeCard`.
6436
+ */
6437
+ welcome?: AgentWidgetWelcomeConfig;
6438
+ /** @deprecated Prefer `suggestions.starters.items`. */
5941
6439
  suggestionChips?: string[];
6440
+ /** @deprecated Prefer semantic tokens under `theme.components.suggestion`. */
5942
6441
  suggestionChipsConfig?: AgentWidgetSuggestionChipsConfig;
5943
6442
  debug?: boolean;
5944
6443
  formEndpoint?: string;
@@ -7007,6 +7506,19 @@ type Controller = {
7007
7506
  * @deprecated Use injectMessage() instead.
7008
7507
  */
7009
7508
  injectTestMessage: (event: AgentWidgetEvent) => void;
7509
+ /**
7510
+ * Show follow-up suggestions from host code. An ephemeral UI overlay: the
7511
+ * items never enter the transcript, the wire payload, or persisted state, so
7512
+ * they do not survive a refresh. Cleared automatically when the next user
7513
+ * message appends. Latest writer wins against the agent's `suggest_replies`
7514
+ * payloads: this call overrides chips shown now, and a payload arriving
7515
+ * afterwards overrides these. Renders through the `suggestions.followUps`
7516
+ * presentation config and the full plugin and `persona:suggestReplies:*`
7517
+ * event pipeline, with source `"host"`. An empty array clears.
7518
+ */
7519
+ setFollowUpSuggestions: (items: AgentWidgetSuggestion[]) => void;
7520
+ /** Remove host-set follow-up suggestions. Agent-set chips are untouched. */
7521
+ clearFollowUpSuggestions: () => void;
7010
7522
  getMessages: () => AgentWidgetMessage[];
7011
7523
  getStatus: () => AgentWidgetSessionStatus;
7012
7524
  getPersistentMetadata: () => Record<string, unknown>;
@@ -7076,7 +7588,7 @@ type AgentWidgetController = Controller;
7076
7588
  * advanced preview system. Separate file for code-splitting.
7077
7589
  */
7078
7590
 
7079
- type PreviewScene = 'home' | 'conversation' | 'minimized' | 'artifact';
7591
+ type PreviewScene = 'home' | 'conversation' | 'follow-ups' | 'minimized' | 'artifact';
7080
7592
 
7081
7593
  /**
7082
7594
  * Imperative preview renderer for the theme editor.