@runtypelabs/persona 3.18.0 → 3.20.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 (42) hide show
  1. package/README.md +45 -2
  2. package/dist/index.cjs +47 -47
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.d.cts +383 -6
  5. package/dist/index.d.ts +383 -6
  6. package/dist/index.global.js +102 -1636
  7. package/dist/index.global.js.map +1 -1
  8. package/dist/index.js +47 -47
  9. package/dist/index.js.map +1 -1
  10. package/dist/theme-editor.cjs +1514 -626
  11. package/dist/theme-editor.d.cts +192 -1
  12. package/dist/theme-editor.d.ts +192 -1
  13. package/dist/theme-editor.js +1628 -626
  14. package/dist/widget.css +348 -0
  15. package/package.json +1 -1
  16. package/src/components/composer-builder.test.ts +52 -0
  17. package/src/components/composer-builder.ts +67 -490
  18. package/src/components/composer-parts.test.ts +152 -0
  19. package/src/components/composer-parts.ts +452 -0
  20. package/src/components/header-builder.ts +22 -299
  21. package/src/components/header-parts.ts +360 -0
  22. package/src/components/panel.test.ts +61 -0
  23. package/src/components/panel.ts +262 -5
  24. package/src/components/pill-composer-builder.test.ts +85 -0
  25. package/src/components/pill-composer-builder.ts +183 -0
  26. package/src/index.ts +5 -0
  27. package/src/runtime/init.ts +4 -2
  28. package/src/runtime/persist-state.test.ts +152 -0
  29. package/src/session.test.ts +123 -0
  30. package/src/session.ts +58 -4
  31. package/src/styles/widget.css +348 -0
  32. package/src/types.ts +196 -1
  33. package/src/ui.component-directive.test.ts +183 -0
  34. package/src/ui.composer-bar.test.ts +1009 -0
  35. package/src/ui.ts +827 -72
  36. package/src/utils/attachment-manager.ts +1 -1
  37. package/src/utils/component-middleware.test.ts +134 -0
  38. package/src/utils/component-middleware.ts +44 -13
  39. package/src/utils/dock.test.ts +45 -0
  40. package/src/utils/dock.ts +3 -0
  41. package/src/utils/icons.ts +314 -58
  42. package/src/utils/stream-animation.ts +7 -2
@@ -1726,6 +1726,101 @@ type AgentWidgetDockConfig = {
1726
1726
  */
1727
1727
  reveal?: "resize" | "overlay" | "push" | "emerge";
1728
1728
  };
1729
+ /**
1730
+ * Layout configuration for `mountMode: "composer-bar"`. Controls how the
1731
+ * collapsed pill is positioned and sized, and how the panel expands when
1732
+ * the user opens it.
1733
+ */
1734
+ type AgentWidgetComposerBarConfig = {
1735
+ /**
1736
+ * Max-width of the collapsed pill composer at the bottom of the viewport.
1737
+ * @default "720px"
1738
+ */
1739
+ collapsedMaxWidth?: string;
1740
+ /**
1741
+ * Bottom offset (CSS length) from the viewport edge in the collapsed state.
1742
+ * @default "16px"
1743
+ */
1744
+ bottomOffset?: string;
1745
+ /**
1746
+ * Auto-expand the panel when the user submits a message while the composer
1747
+ * is collapsed. When false, the message still sends but the panel remains
1748
+ * collapsed (the host can drive expansion programmatically).
1749
+ * @default true
1750
+ */
1751
+ expandOnSubmit?: boolean;
1752
+ /**
1753
+ * Size of the expanded chat panel.
1754
+ * - `"anchored"` (default): the pill stays at the bottom of the viewport
1755
+ * and the chat history grows upward into a centered column above it.
1756
+ * Width is driven by `expandedMaxWidth`; the panel's top edge sits at
1757
+ * `expandedTopOffset` from the viewport top.
1758
+ * - `"fullscreen"`: covers the entire viewport (mobile-app style). Inner
1759
+ * content is centered horizontally via `contentMaxWidth`.
1760
+ * - `"modal"`: centered sheet with margins; size driven by
1761
+ * `modalMaxWidth` / `modalMaxHeight`.
1762
+ * @default "anchored"
1763
+ */
1764
+ expandedSize?: "anchored" | "fullscreen" | "modal";
1765
+ /**
1766
+ * When `expandedSize === "anchored"`, max-width of the expanded panel
1767
+ * column. Capped at `calc(100vw - 32px)` on narrow viewports.
1768
+ * @default "880px"
1769
+ */
1770
+ expandedMaxWidth?: string;
1771
+ /**
1772
+ * When `expandedSize === "anchored"`, distance from the viewport top to
1773
+ * the panel's top edge. Accepts any CSS length.
1774
+ * @default "5vh"
1775
+ */
1776
+ expandedTopOffset?: string;
1777
+ /**
1778
+ * Max-width applied to messages, composer form, suggestions, and
1779
+ * attachment previews so they center horizontally inside the expanded
1780
+ * panel. Falls back to `layout.contentMaxWidth` when set; otherwise
1781
+ * defaults to this value.
1782
+ * @default "720px"
1783
+ */
1784
+ contentMaxWidth?: string;
1785
+ /**
1786
+ * When `expandedSize === "modal"`, max-width of the expanded sheet.
1787
+ * @default "880px"
1788
+ */
1789
+ modalMaxWidth?: string;
1790
+ /**
1791
+ * When `expandedSize === "modal"`, max-height of the expanded sheet.
1792
+ * @default "min(90vh, 800px)"
1793
+ */
1794
+ modalMaxHeight?: string;
1795
+ /**
1796
+ * Configuration for the "peek" banner — the chrome-less row above the
1797
+ * collapsed pill that previews the most recent assistant message.
1798
+ */
1799
+ peek?: AgentWidgetComposerBarPeekConfig;
1800
+ };
1801
+ /**
1802
+ * Configuration for the composer-bar peek banner. Reuses the same
1803
+ * `streamAnimation` shape developers already configure for the main message
1804
+ * stream, so the surface for animations is identical across both contexts.
1805
+ *
1806
+ * Resolution order:
1807
+ * - If `peek.streamAnimation` is set, those values apply to the peek.
1808
+ * - Otherwise the peek inherits from `features.streamAnimation`.
1809
+ *
1810
+ * Per-surface carve-outs:
1811
+ * - `bubbleClass` from a plugin (used by `pop-bubble`) is ignored — the peek
1812
+ * has no bubble analog.
1813
+ * - `containerClass`, `wrap` ("char" | "word"), `useCaret`, `placeholder`
1814
+ * ("skeleton"), `buffer` ("word" | "line"), `speed`, `duration`, and
1815
+ * custom plugins all apply unchanged.
1816
+ */
1817
+ type AgentWidgetComposerBarPeekConfig = {
1818
+ /**
1819
+ * Reveal animation for the peek's trailing-message preview. Same shape as
1820
+ * `features.streamAnimation`. Omit to inherit from the main stream config.
1821
+ */
1822
+ streamAnimation?: AgentWidgetStreamAnimationFeature;
1823
+ };
1729
1824
  type AgentWidgetLauncherConfig = {
1730
1825
  enabled?: boolean;
1731
1826
  title?: string;
@@ -1740,14 +1835,22 @@ type AgentWidgetLauncherConfig = {
1740
1835
  * Controls how the launcher panel is mounted relative to the host page.
1741
1836
  * - "floating": default floating launcher / panel behavior
1742
1837
  * - "docked": wraps the target container and renders as a sibling dock
1838
+ * - "composer-bar": persistent rounded-pill composer fixed to the bottom of
1839
+ * the viewport that morphs into a fullscreen (or modal) chat panel on
1840
+ * submit and minimizes back to the pill on close.
1743
1841
  *
1744
1842
  * @default "floating"
1745
1843
  */
1746
- mountMode?: "floating" | "docked";
1844
+ mountMode?: "floating" | "docked" | "composer-bar";
1747
1845
  /**
1748
1846
  * Layout configuration for docked mode.
1749
1847
  */
1750
1848
  dock?: AgentWidgetDockConfig;
1849
+ /**
1850
+ * Layout configuration for composer-bar mode.
1851
+ * Only applies when `mountMode === "composer-bar"`.
1852
+ */
1853
+ composerBar?: AgentWidgetComposerBarConfig;
1751
1854
  autoExpand?: boolean;
1752
1855
  width?: string;
1753
1856
  /**
@@ -3715,6 +3818,13 @@ type AgentWidgetConfig = {
3715
3818
  * When `true`, uses default settings with sessionStorage.
3716
3819
  * When an object, allows customizing storage type, key prefix, and what to persist.
3717
3820
  *
3821
+ * Setting this to `false` is the explicit kill-switch: it disables UI-state
3822
+ * persistence **and** message-history persistence. When `false`, any
3823
+ * `storageAdapter` you configure is ignored and the default localStorage
3824
+ * adapter is not created — no chat history is read or written. Pass `true`
3825
+ * (or omit) to keep the default behavior of persisting messages via the
3826
+ * configured `storageAdapter` (or the built-in localStorage adapter).
3827
+ *
3718
3828
  * @example
3719
3829
  * ```typescript
3720
3830
  * // Simple usage - persist open state in sessionStorage
@@ -3737,6 +3847,14 @@ type AgentWidgetConfig = {
3737
3847
  * }
3738
3848
  * }
3739
3849
  * ```
3850
+ *
3851
+ * @example
3852
+ * ```typescript
3853
+ * // Ephemeral widget — no message history written anywhere
3854
+ * config: {
3855
+ * persistState: false
3856
+ * }
3857
+ * ```
3740
3858
  */
3741
3859
  persistState?: boolean | AgentWidgetPersistStateConfig;
3742
3860
  /**
@@ -3979,6 +4097,22 @@ type InjectMessageOptions = {
3979
4097
  * Consumers can detect this in `messageTransform` to render custom UI.
3980
4098
  */
3981
4099
  voiceProcessing?: boolean;
4100
+ /**
4101
+ * Raw structured payload (typically a JSON string) representing the
4102
+ * full directive that produced this message — e.g. `{ "text": "...",
4103
+ * "component": "Foo", "props": {...} }`.
4104
+ *
4105
+ * Mirrors the field populated by stream parsers during normal LLM
4106
+ * responses. Set this when injecting a message that should render as a
4107
+ * component directive (`hasComponentDirective` /
4108
+ * `extractComponentDirectiveFromMessage` look at `rawContent` first).
4109
+ *
4110
+ * Priority for the API payload remains:
4111
+ * `contentParts > llmContent > rawContent > content`. Pass `llmContent`
4112
+ * alongside `rawContent` if the LLM should see something other than the
4113
+ * raw directive.
4114
+ */
4115
+ rawContent?: string;
3982
4116
  };
3983
4117
  /**
3984
4118
  * Options for injecting assistant messages (most common case).
@@ -3995,6 +4129,57 @@ type InjectUserMessageOptions = Omit<InjectMessageOptions, "role">;
3995
4129
  * Role defaults to 'system'.
3996
4130
  */
3997
4131
  type InjectSystemMessageOptions = Omit<InjectMessageOptions, "role">;
4132
+ /**
4133
+ * Options for injecting an assistant message that renders as a component
4134
+ * directive — sugar over `injectAssistantMessage` for the common case of
4135
+ * "render this registered component, same as if the LLM had emitted it".
4136
+ *
4137
+ * Equivalent to calling `injectAssistantMessage({ content: text, rawContent:
4138
+ * JSON.stringify({ text, component, props }), llmContent })`.
4139
+ *
4140
+ * @example
4141
+ * widget.injectComponentDirective({
4142
+ * component: "DynamicForm",
4143
+ * props: { title: "Book a demo", fields: [...] },
4144
+ * text: "Share your details to book a demo.",
4145
+ * llmContent: "[Showed booking form]"
4146
+ * });
4147
+ */
4148
+ type InjectComponentDirectiveOptions = {
4149
+ /**
4150
+ * Name of a renderer registered via `componentRegistry.register(...)`.
4151
+ */
4152
+ component: string;
4153
+ /**
4154
+ * Props passed to the component renderer.
4155
+ */
4156
+ props?: Record<string, unknown>;
4157
+ /**
4158
+ * Bubble copy displayed above (or with) the rendered component.
4159
+ * Mirrors the `text` field in a streamed JSON directive.
4160
+ * @default ""
4161
+ */
4162
+ text?: string;
4163
+ /**
4164
+ * Content sent to the LLM in API requests. When omitted, the raw
4165
+ * directive JSON is what the LLM would see (per the standard
4166
+ * priority chain). Provide a redacted/short version to avoid sending
4167
+ * the full directive in subsequent turns.
4168
+ */
4169
+ llmContent?: string;
4170
+ /**
4171
+ * Optional message ID. If omitted, an assistant id is auto-generated.
4172
+ */
4173
+ id?: string;
4174
+ /**
4175
+ * Optional creation timestamp (ISO string). If omitted, uses current time.
4176
+ */
4177
+ createdAt?: string;
4178
+ /**
4179
+ * Optional sequence number for ordering.
4180
+ */
4181
+ sequence?: number;
4182
+ };
3998
4183
  type PersonaArtifactRecord = {
3999
4184
  id: string;
4000
4185
  artifactType: PersonaArtifactKind;
@@ -4362,6 +4547,12 @@ type Controller = {
4362
4547
  * Inject multiple messages in a single batch with one sort and one render pass.
4363
4548
  */
4364
4549
  injectMessageBatch: (optionsList: InjectMessageOptions[]) => AgentWidgetMessage[];
4550
+ /**
4551
+ * Convenience method for injecting an assistant message that renders as a
4552
+ * registered component — same shape Persona produces from a streamed
4553
+ * `{ "text": "...", "component": "...", "props": {...} }` payload.
4554
+ */
4555
+ injectComponentDirective: (options: InjectComponentDirectiveOptions) => AgentWidgetMessage;
4365
4556
  /**
4366
4557
  * @deprecated Use injectMessage() instead.
4367
4558
  */
@@ -1726,6 +1726,101 @@ type AgentWidgetDockConfig = {
1726
1726
  */
1727
1727
  reveal?: "resize" | "overlay" | "push" | "emerge";
1728
1728
  };
1729
+ /**
1730
+ * Layout configuration for `mountMode: "composer-bar"`. Controls how the
1731
+ * collapsed pill is positioned and sized, and how the panel expands when
1732
+ * the user opens it.
1733
+ */
1734
+ type AgentWidgetComposerBarConfig = {
1735
+ /**
1736
+ * Max-width of the collapsed pill composer at the bottom of the viewport.
1737
+ * @default "720px"
1738
+ */
1739
+ collapsedMaxWidth?: string;
1740
+ /**
1741
+ * Bottom offset (CSS length) from the viewport edge in the collapsed state.
1742
+ * @default "16px"
1743
+ */
1744
+ bottomOffset?: string;
1745
+ /**
1746
+ * Auto-expand the panel when the user submits a message while the composer
1747
+ * is collapsed. When false, the message still sends but the panel remains
1748
+ * collapsed (the host can drive expansion programmatically).
1749
+ * @default true
1750
+ */
1751
+ expandOnSubmit?: boolean;
1752
+ /**
1753
+ * Size of the expanded chat panel.
1754
+ * - `"anchored"` (default): the pill stays at the bottom of the viewport
1755
+ * and the chat history grows upward into a centered column above it.
1756
+ * Width is driven by `expandedMaxWidth`; the panel's top edge sits at
1757
+ * `expandedTopOffset` from the viewport top.
1758
+ * - `"fullscreen"`: covers the entire viewport (mobile-app style). Inner
1759
+ * content is centered horizontally via `contentMaxWidth`.
1760
+ * - `"modal"`: centered sheet with margins; size driven by
1761
+ * `modalMaxWidth` / `modalMaxHeight`.
1762
+ * @default "anchored"
1763
+ */
1764
+ expandedSize?: "anchored" | "fullscreen" | "modal";
1765
+ /**
1766
+ * When `expandedSize === "anchored"`, max-width of the expanded panel
1767
+ * column. Capped at `calc(100vw - 32px)` on narrow viewports.
1768
+ * @default "880px"
1769
+ */
1770
+ expandedMaxWidth?: string;
1771
+ /**
1772
+ * When `expandedSize === "anchored"`, distance from the viewport top to
1773
+ * the panel's top edge. Accepts any CSS length.
1774
+ * @default "5vh"
1775
+ */
1776
+ expandedTopOffset?: string;
1777
+ /**
1778
+ * Max-width applied to messages, composer form, suggestions, and
1779
+ * attachment previews so they center horizontally inside the expanded
1780
+ * panel. Falls back to `layout.contentMaxWidth` when set; otherwise
1781
+ * defaults to this value.
1782
+ * @default "720px"
1783
+ */
1784
+ contentMaxWidth?: string;
1785
+ /**
1786
+ * When `expandedSize === "modal"`, max-width of the expanded sheet.
1787
+ * @default "880px"
1788
+ */
1789
+ modalMaxWidth?: string;
1790
+ /**
1791
+ * When `expandedSize === "modal"`, max-height of the expanded sheet.
1792
+ * @default "min(90vh, 800px)"
1793
+ */
1794
+ modalMaxHeight?: string;
1795
+ /**
1796
+ * Configuration for the "peek" banner — the chrome-less row above the
1797
+ * collapsed pill that previews the most recent assistant message.
1798
+ */
1799
+ peek?: AgentWidgetComposerBarPeekConfig;
1800
+ };
1801
+ /**
1802
+ * Configuration for the composer-bar peek banner. Reuses the same
1803
+ * `streamAnimation` shape developers already configure for the main message
1804
+ * stream, so the surface for animations is identical across both contexts.
1805
+ *
1806
+ * Resolution order:
1807
+ * - If `peek.streamAnimation` is set, those values apply to the peek.
1808
+ * - Otherwise the peek inherits from `features.streamAnimation`.
1809
+ *
1810
+ * Per-surface carve-outs:
1811
+ * - `bubbleClass` from a plugin (used by `pop-bubble`) is ignored — the peek
1812
+ * has no bubble analog.
1813
+ * - `containerClass`, `wrap` ("char" | "word"), `useCaret`, `placeholder`
1814
+ * ("skeleton"), `buffer` ("word" | "line"), `speed`, `duration`, and
1815
+ * custom plugins all apply unchanged.
1816
+ */
1817
+ type AgentWidgetComposerBarPeekConfig = {
1818
+ /**
1819
+ * Reveal animation for the peek's trailing-message preview. Same shape as
1820
+ * `features.streamAnimation`. Omit to inherit from the main stream config.
1821
+ */
1822
+ streamAnimation?: AgentWidgetStreamAnimationFeature;
1823
+ };
1729
1824
  type AgentWidgetLauncherConfig = {
1730
1825
  enabled?: boolean;
1731
1826
  title?: string;
@@ -1740,14 +1835,22 @@ type AgentWidgetLauncherConfig = {
1740
1835
  * Controls how the launcher panel is mounted relative to the host page.
1741
1836
  * - "floating": default floating launcher / panel behavior
1742
1837
  * - "docked": wraps the target container and renders as a sibling dock
1838
+ * - "composer-bar": persistent rounded-pill composer fixed to the bottom of
1839
+ * the viewport that morphs into a fullscreen (or modal) chat panel on
1840
+ * submit and minimizes back to the pill on close.
1743
1841
  *
1744
1842
  * @default "floating"
1745
1843
  */
1746
- mountMode?: "floating" | "docked";
1844
+ mountMode?: "floating" | "docked" | "composer-bar";
1747
1845
  /**
1748
1846
  * Layout configuration for docked mode.
1749
1847
  */
1750
1848
  dock?: AgentWidgetDockConfig;
1849
+ /**
1850
+ * Layout configuration for composer-bar mode.
1851
+ * Only applies when `mountMode === "composer-bar"`.
1852
+ */
1853
+ composerBar?: AgentWidgetComposerBarConfig;
1751
1854
  autoExpand?: boolean;
1752
1855
  width?: string;
1753
1856
  /**
@@ -3715,6 +3818,13 @@ type AgentWidgetConfig = {
3715
3818
  * When `true`, uses default settings with sessionStorage.
3716
3819
  * When an object, allows customizing storage type, key prefix, and what to persist.
3717
3820
  *
3821
+ * Setting this to `false` is the explicit kill-switch: it disables UI-state
3822
+ * persistence **and** message-history persistence. When `false`, any
3823
+ * `storageAdapter` you configure is ignored and the default localStorage
3824
+ * adapter is not created — no chat history is read or written. Pass `true`
3825
+ * (or omit) to keep the default behavior of persisting messages via the
3826
+ * configured `storageAdapter` (or the built-in localStorage adapter).
3827
+ *
3718
3828
  * @example
3719
3829
  * ```typescript
3720
3830
  * // Simple usage - persist open state in sessionStorage
@@ -3737,6 +3847,14 @@ type AgentWidgetConfig = {
3737
3847
  * }
3738
3848
  * }
3739
3849
  * ```
3850
+ *
3851
+ * @example
3852
+ * ```typescript
3853
+ * // Ephemeral widget — no message history written anywhere
3854
+ * config: {
3855
+ * persistState: false
3856
+ * }
3857
+ * ```
3740
3858
  */
3741
3859
  persistState?: boolean | AgentWidgetPersistStateConfig;
3742
3860
  /**
@@ -3979,6 +4097,22 @@ type InjectMessageOptions = {
3979
4097
  * Consumers can detect this in `messageTransform` to render custom UI.
3980
4098
  */
3981
4099
  voiceProcessing?: boolean;
4100
+ /**
4101
+ * Raw structured payload (typically a JSON string) representing the
4102
+ * full directive that produced this message — e.g. `{ "text": "...",
4103
+ * "component": "Foo", "props": {...} }`.
4104
+ *
4105
+ * Mirrors the field populated by stream parsers during normal LLM
4106
+ * responses. Set this when injecting a message that should render as a
4107
+ * component directive (`hasComponentDirective` /
4108
+ * `extractComponentDirectiveFromMessage` look at `rawContent` first).
4109
+ *
4110
+ * Priority for the API payload remains:
4111
+ * `contentParts > llmContent > rawContent > content`. Pass `llmContent`
4112
+ * alongside `rawContent` if the LLM should see something other than the
4113
+ * raw directive.
4114
+ */
4115
+ rawContent?: string;
3982
4116
  };
3983
4117
  /**
3984
4118
  * Options for injecting assistant messages (most common case).
@@ -3995,6 +4129,57 @@ type InjectUserMessageOptions = Omit<InjectMessageOptions, "role">;
3995
4129
  * Role defaults to 'system'.
3996
4130
  */
3997
4131
  type InjectSystemMessageOptions = Omit<InjectMessageOptions, "role">;
4132
+ /**
4133
+ * Options for injecting an assistant message that renders as a component
4134
+ * directive — sugar over `injectAssistantMessage` for the common case of
4135
+ * "render this registered component, same as if the LLM had emitted it".
4136
+ *
4137
+ * Equivalent to calling `injectAssistantMessage({ content: text, rawContent:
4138
+ * JSON.stringify({ text, component, props }), llmContent })`.
4139
+ *
4140
+ * @example
4141
+ * widget.injectComponentDirective({
4142
+ * component: "DynamicForm",
4143
+ * props: { title: "Book a demo", fields: [...] },
4144
+ * text: "Share your details to book a demo.",
4145
+ * llmContent: "[Showed booking form]"
4146
+ * });
4147
+ */
4148
+ type InjectComponentDirectiveOptions = {
4149
+ /**
4150
+ * Name of a renderer registered via `componentRegistry.register(...)`.
4151
+ */
4152
+ component: string;
4153
+ /**
4154
+ * Props passed to the component renderer.
4155
+ */
4156
+ props?: Record<string, unknown>;
4157
+ /**
4158
+ * Bubble copy displayed above (or with) the rendered component.
4159
+ * Mirrors the `text` field in a streamed JSON directive.
4160
+ * @default ""
4161
+ */
4162
+ text?: string;
4163
+ /**
4164
+ * Content sent to the LLM in API requests. When omitted, the raw
4165
+ * directive JSON is what the LLM would see (per the standard
4166
+ * priority chain). Provide a redacted/short version to avoid sending
4167
+ * the full directive in subsequent turns.
4168
+ */
4169
+ llmContent?: string;
4170
+ /**
4171
+ * Optional message ID. If omitted, an assistant id is auto-generated.
4172
+ */
4173
+ id?: string;
4174
+ /**
4175
+ * Optional creation timestamp (ISO string). If omitted, uses current time.
4176
+ */
4177
+ createdAt?: string;
4178
+ /**
4179
+ * Optional sequence number for ordering.
4180
+ */
4181
+ sequence?: number;
4182
+ };
3998
4183
  type PersonaArtifactRecord = {
3999
4184
  id: string;
4000
4185
  artifactType: PersonaArtifactKind;
@@ -4362,6 +4547,12 @@ type Controller = {
4362
4547
  * Inject multiple messages in a single batch with one sort and one render pass.
4363
4548
  */
4364
4549
  injectMessageBatch: (optionsList: InjectMessageOptions[]) => AgentWidgetMessage[];
4550
+ /**
4551
+ * Convenience method for injecting an assistant message that renders as a
4552
+ * registered component — same shape Persona produces from a streamed
4553
+ * `{ "text": "...", "component": "...", "props": {...} }` payload.
4554
+ */
4555
+ injectComponentDirective: (options: InjectComponentDirectiveOptions) => AgentWidgetMessage;
4365
4556
  /**
4366
4557
  * @deprecated Use injectMessage() instead.
4367
4558
  */