@runtypelabs/persona 3.34.0 → 3.35.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 (186) hide show
  1. package/README.md +11 -11
  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-CthJFfNx.d.cts → types-DgYsuwXL.d.cts} +15 -14
  5. package/dist/animations/{types-CthJFfNx.d.ts → types-DgYsuwXL.d.ts} +15 -14
  6. package/dist/animations/wipe.d.cts +1 -1
  7. package/dist/animations/wipe.d.ts +1 -1
  8. package/dist/codegen.cjs +11 -11
  9. package/dist/codegen.js +10 -10
  10. package/dist/index.cjs +46 -44
  11. package/dist/index.cjs.map +1 -1
  12. package/dist/index.d.cts +514 -158
  13. package/dist/index.d.ts +514 -158
  14. package/dist/index.global.js +41 -89
  15. package/dist/index.global.js.map +1 -1
  16. package/dist/index.js +46 -44
  17. package/dist/index.js.map +1 -1
  18. package/dist/install.global.js +1 -1
  19. package/dist/install.global.js.map +1 -1
  20. package/dist/launcher.global.js +2 -2
  21. package/dist/launcher.global.js.map +1 -1
  22. package/dist/markdown-parsers.js +53 -0
  23. package/dist/plugin-kit.d.cts +4 -4
  24. package/dist/plugin-kit.d.ts +4 -4
  25. package/dist/runtype-tts.js +1 -0
  26. package/dist/smart-dom-reader.cjs +1 -1
  27. package/dist/smart-dom-reader.d.cts +352 -103
  28. package/dist/smart-dom-reader.d.ts +352 -103
  29. package/dist/smart-dom-reader.js +1 -1
  30. package/dist/theme-editor-preview.cjs +203 -0
  31. package/dist/theme-editor-preview.d.cts +5748 -0
  32. package/dist/theme-editor-preview.d.ts +5748 -0
  33. package/dist/theme-editor-preview.js +203 -0
  34. package/dist/theme-editor.cjs +14 -131
  35. package/dist/theme-editor.d.cts +362 -574
  36. package/dist/theme-editor.d.ts +362 -574
  37. package/dist/theme-editor.js +14 -131
  38. package/dist/theme-reference.cjs +1 -1
  39. package/dist/theme-reference.d.cts +1 -1
  40. package/dist/theme-reference.d.ts +1 -1
  41. package/dist/theme-reference.js +1 -1
  42. package/dist/voice-worklet-player.cjs +80 -0
  43. package/dist/voice-worklet-player.d.cts +215 -0
  44. package/dist/voice-worklet-player.d.ts +215 -0
  45. package/dist/voice-worklet-player.js +80 -0
  46. package/dist/widget.css +54 -36
  47. package/package.json +16 -2
  48. package/src/animations/glyph-cycle.ts +11 -14
  49. package/src/animations/wipe.ts +1 -1
  50. package/src/ask-user-question-tool.test.ts +1 -1
  51. package/src/ask-user-question-tool.ts +6 -8
  52. package/src/client.test.ts +67 -12
  53. package/src/client.ts +40 -32
  54. package/src/codegen.test.ts +1 -1
  55. package/src/codegen.ts +1 -1
  56. package/src/components/approval-bubble.test.ts +1 -1
  57. package/src/components/approval-bubble.ts +3 -3
  58. package/src/components/artifact-pane.ts +3 -3
  59. package/src/components/ask-user-question-bubble.test.ts +14 -14
  60. package/src/components/ask-user-question-bubble.ts +10 -10
  61. package/src/components/composer-builder.ts +17 -16
  62. package/src/components/composer-parts.test.ts +54 -0
  63. package/src/components/composer-parts.ts +95 -126
  64. package/src/components/demo-carousel.ts +1 -1
  65. package/src/components/event-stream-view.test.ts +7 -7
  66. package/src/components/event-stream-view.ts +5 -5
  67. package/src/components/header-builder.ts +33 -27
  68. package/src/components/header-layouts.ts +1 -1
  69. package/src/components/header-parts.test.ts +90 -0
  70. package/src/components/header-parts.ts +62 -93
  71. package/src/components/launcher.test.ts +11 -0
  72. package/src/components/launcher.ts +1 -1
  73. package/src/components/message-bubble.test.ts +74 -2
  74. package/src/components/message-bubble.ts +25 -11
  75. package/src/components/messages.ts +2 -2
  76. package/src/components/panel.test.ts +1 -1
  77. package/src/components/panel.ts +92 -97
  78. package/src/components/pill-composer-builder.ts +28 -24
  79. package/src/components/reasoning-bubble.ts +2 -2
  80. package/src/components/suggestions.ts +1 -1
  81. package/src/components/tool-bubble.ts +1 -1
  82. package/src/components/widget-view.test.ts +181 -0
  83. package/src/components/widget-view.ts +234 -0
  84. package/src/defaults.ts +54 -51
  85. package/src/generated/runtype-openapi-contract.ts +5 -0
  86. package/src/index-core.ts +30 -4
  87. package/src/index-global.ts +73 -6
  88. package/src/index.ts +7 -1
  89. package/src/install.test.ts +11 -11
  90. package/src/install.ts +28 -18
  91. package/src/launcher-global.ts +25 -14
  92. package/src/markdown-parsers-eager.ts +20 -0
  93. package/src/markdown-parsers-entry.ts +4 -0
  94. package/src/markdown-parsers-loader.ts +49 -0
  95. package/src/plugin-kit.test.ts +1 -1
  96. package/src/plugin-kit.ts +7 -7
  97. package/src/plugins/types.ts +5 -5
  98. package/src/postprocessors.ts +27 -14
  99. package/src/runtime/host-layout.test.ts +1 -1
  100. package/src/runtime/host-layout.ts +4 -5
  101. package/src/runtime/init.ts +2 -2
  102. package/src/session.test.ts +5 -6
  103. package/src/session.ts +333 -227
  104. package/src/session.voice.test.ts +146 -0
  105. package/src/session.webmcp.test.ts +24 -25
  106. package/src/smart-dom-reader.ts +3 -4
  107. package/src/styles/widget.css +54 -36
  108. package/src/suggest-replies-tool.test.ts +3 -3
  109. package/src/suggest-replies-tool.ts +5 -5
  110. package/src/testing/index.ts +1 -1
  111. package/src/theme-editor/color-utils.ts +2 -2
  112. package/src/theme-editor/index.ts +4 -13
  113. package/src/theme-editor/presets.ts +1 -1
  114. package/src/theme-editor/preview-utils.ts +22 -20
  115. package/src/theme-editor/preview.ts +4 -1
  116. package/src/theme-editor/role-mappings.ts +3 -3
  117. package/src/theme-editor/sections.ts +21 -20
  118. package/src/theme-editor/types.ts +1 -1
  119. package/src/theme-editor/webmcp/index.ts +1 -1
  120. package/src/theme-editor/webmcp/summary.ts +1 -2
  121. package/src/theme-editor/webmcp/tools.ts +30 -30
  122. package/src/theme-editor/webmcp/types.ts +2 -2
  123. package/src/theme-editor-preview.ts +10 -0
  124. package/src/theme-reference.ts +26 -26
  125. package/src/types.ts +368 -99
  126. package/src/ui.approval-plugin.test.ts +3 -3
  127. package/src/ui.ask-user-question-plugin.test.ts +9 -9
  128. package/src/ui.component-directive.test.ts +4 -4
  129. package/src/ui.composer-bar.test.ts +10 -11
  130. package/src/ui.composer-keyboard.test.ts +5 -5
  131. package/src/ui.header-icon-color.test.ts +59 -0
  132. package/src/ui.scroll.test.ts +5 -6
  133. package/src/ui.stop-button.test.ts +3 -4
  134. package/src/ui.suggest-replies.test.ts +2 -2
  135. package/src/ui.ts +292 -131
  136. package/src/utils/buttons.ts +1 -1
  137. package/src/utils/code-generators.ts +1 -1
  138. package/src/utils/composer-history.ts +3 -3
  139. package/src/utils/dom-context.test.ts +2 -2
  140. package/src/utils/dom-context.ts +7 -7
  141. package/src/utils/dom.test.ts +67 -0
  142. package/src/utils/dom.ts +75 -0
  143. package/src/utils/dropdown.ts +2 -2
  144. package/src/utils/event-stream-buffer.test.ts +2 -2
  145. package/src/utils/message-fingerprint.test.ts +9 -0
  146. package/src/utils/message-fingerprint.ts +5 -0
  147. package/src/utils/morph.ts +1 -1
  148. package/src/utils/sanitize.ts +32 -16
  149. package/src/utils/sequence-buffer.test.ts +8 -8
  150. package/src/utils/sequence-buffer.ts +4 -4
  151. package/src/utils/smart-dom-adapter.test.ts +1 -1
  152. package/src/utils/smart-dom-adapter.ts +4 -5
  153. package/src/utils/speech-text.test.ts +122 -0
  154. package/src/utils/speech-text.ts +101 -0
  155. package/src/utils/stream-animation.test.ts +3 -3
  156. package/src/utils/stream-animation.ts +6 -6
  157. package/src/utils/theme.test.ts +1 -1
  158. package/src/utils/throughput-tracker.test.ts +11 -11
  159. package/src/utils/throughput-tracker.ts +9 -9
  160. package/src/utils/tokens.ts +13 -13
  161. package/src/utils/virtual-scroller.ts +1 -1
  162. package/src/vendor/smart-dom-reader/README.md +4 -4
  163. package/src/vendor/smart-dom-reader/index.d.ts +1 -1
  164. package/src/vendor/smart-dom-reader/index.js +2 -2
  165. package/src/version.ts +1 -1
  166. package/src/voice/audio-playback-manager.test.ts +159 -0
  167. package/src/voice/audio-playback-manager.ts +145 -30
  168. package/src/voice/browser-speech-engine.ts +130 -0
  169. package/src/voice/fallback-speech-engine.ts +89 -0
  170. package/src/voice/index.ts +21 -0
  171. package/src/voice/read-aloud-controller.test.ts +143 -0
  172. package/src/voice/read-aloud-controller.ts +136 -0
  173. package/src/voice/runtype-speech-engine.test.ts +280 -0
  174. package/src/voice/runtype-speech-engine.ts +211 -0
  175. package/src/voice/runtype-tts-entry.ts +10 -0
  176. package/src/voice/runtype-tts-loader.test.ts +47 -0
  177. package/src/voice/runtype-tts-loader.ts +42 -0
  178. package/src/voice/runtype-voice-provider.ts +332 -537
  179. package/src/voice/voice-factory.ts +26 -4
  180. package/src/voice/voice.test.ts +321 -7
  181. package/src/voice/worklet-playback-engine.ts +272 -0
  182. package/src/voice-worklet-player.ts +39 -0
  183. package/src/webmcp-bridge.test.ts +6 -6
  184. package/src/webmcp-bridge.ts +24 -25
  185. package/src/webmcp-polyfill.ts +1 -1
  186. package/src/voice/voice-activity-detector.ts +0 -90
package/dist/index.d.ts CHANGED
@@ -48,7 +48,7 @@ interface AgentWidgetPlugin {
48
48
  defaultRenderer: () => HTMLElement;
49
49
  onSubmit: (text: string) => void;
50
50
  /**
51
- * When true, the assistant stream is active same moment `session.isStreaming()` becomes true.
51
+ * When true, the assistant stream is active: same moment `session.isStreaming()` becomes true.
52
52
  * Prefer wiring controls to `data-persona-composer-disable-when-streaming` plus `setComposerDisabled`
53
53
  * in the host, or react to `footer.dataset.personaComposerStreaming === "true"`.
54
54
  */
@@ -97,14 +97,14 @@ interface AgentWidgetPlugin {
97
97
  * Custom renderer for `ask_user_question` tool calls.
98
98
  *
99
99
  * When a plugin returns an `HTMLElement`, it is inserted into the transcript
100
- * in place of the default (which is no transcript bubble the built-in
100
+ * in place of the default (which is no transcript bubble: the built-in
101
101
  * renders a sheet over the composer). The built-in composer-overlay sheet
102
102
  * is suppressed so the plugin's UI fully owns the interaction.
103
103
  *
104
104
  * Return `null` to fall through to the built-in overlay sheet.
105
105
  *
106
106
  * The context gives you a pre-parsed `payload` (may be partial while the
107
- * tool call is still streaming check `complete`) and two callbacks:
107
+ * tool call is still streaming: check `complete`) and two callbacks:
108
108
  * `resolve(answer)` resumes the paused LOCAL tool with the user's answer,
109
109
  * and `dismiss()` cancels with the sentinel `"(dismissed)"`.
110
110
  *
@@ -153,8 +153,8 @@ interface AgentWidgetPlugin {
153
153
  *
154
154
  * Return an `HTMLElement` to fully own the approval UI, `defaultRenderer()`
155
155
  * to render (or wrap) the built-in bubble, or `null` to fall through to the
156
- * default. Unlike the built-in bubble whose Approve/Deny buttons are wired
157
- * via delegation a fully custom element resolves the approval by calling
156
+ * default. Unlike the built-in bubble: whose Approve/Deny buttons are wired
157
+ * via delegation: a fully custom element resolves the approval by calling
158
158
  * the `approve`/`deny` callbacks. Both route through the same path the
159
159
  * built-in buttons use (optimistic update, `onDecision`, in-place anchoring).
160
160
  *
@@ -1055,6 +1055,7 @@ type RuntypeFlowSSEEvent = {
1055
1055
  totalSteps?: number;
1056
1056
  type: "flow_start";
1057
1057
  } | {
1058
+ claudeManagedAgentId?: string;
1058
1059
  completedAt?: string;
1059
1060
  completedSteps?: number;
1060
1061
  duration?: number;
@@ -1169,6 +1170,7 @@ type RuntypeFlowSSEEvent = {
1169
1170
  toolId: string;
1170
1171
  };
1171
1172
  type: "step_complete";
1173
+ unresolvedVariables?: Array<string>;
1172
1174
  }) | {
1173
1175
  error: string;
1174
1176
  executionId?: string;
@@ -1605,6 +1607,7 @@ type RuntypeDispatchSSEEvent = {
1605
1607
  totalSteps?: number;
1606
1608
  type: "flow_start";
1607
1609
  } | {
1610
+ claudeManagedAgentId?: string;
1608
1611
  completedAt?: string;
1609
1612
  completedSteps?: number;
1610
1613
  duration?: number;
@@ -1719,6 +1722,7 @@ type RuntypeDispatchSSEEvent = {
1719
1722
  toolId: string;
1720
1723
  };
1721
1724
  type: "step_complete";
1725
+ unresolvedVariables?: Array<string>;
1722
1726
  }) | {
1723
1727
  error: string;
1724
1728
  executionId?: string;
@@ -2005,6 +2009,7 @@ type RuntypeClientFeedbackRequest = {
2005
2009
  metadata?: Record<string, unknown>;
2006
2010
  rating?: number;
2007
2011
  sessionId: string;
2012
+ token: string;
2008
2013
  type: "upvote" | "downvote" | "copy" | "csat" | "nps";
2009
2014
  };
2010
2015
  type RuntypeClientFeedbackResponse = {
@@ -2180,7 +2185,7 @@ type AgentConfig = {
2180
2185
  temperature?: number;
2181
2186
  /** Tool configuration for the agent */
2182
2187
  tools?: AgentToolsConfig;
2183
- /** Persona artifacts sibling of tools (virtual agent / API parity) */
2188
+ /** Persona artifacts: sibling of tools (virtual agent / API parity) */
2184
2189
  artifacts?: ArtifactConfigPayload;
2185
2190
  /** Loop configuration for multi-turn execution */
2186
2191
  loopConfig?: AgentLoopConfig;
@@ -2208,7 +2213,7 @@ type AgentWidgetAgentRequestPayload = {
2208
2213
  context?: Record<string, unknown>;
2209
2214
  metadata?: Record<string, unknown>;
2210
2215
  /**
2211
- * Per-turn page-discovered tools (WebMCP) same shape as
2216
+ * Per-turn page-discovered tools (WebMCP): same shape as
2212
2217
  * `AgentWidgetRequestPayload.clientTools`.
2213
2218
  */
2214
2219
  clientTools?: ClientToolDefinition[];
@@ -2217,7 +2222,7 @@ type AgentWidgetAgentRequestPayload = {
2217
2222
  * Wire shape for a single client-discovered tool sent on `dispatch.clientTools[]`.
2218
2223
  *
2219
2224
  * Mirrors the SDK's `ClientToolDefinition` in `@runtypelabs/sdk`. Only the
2220
- * JSON-serializable surface of a WebMCP tool the `execute` function stays
2225
+ * JSON-serializable surface of a WebMCP tool: the `execute` function stays
2221
2226
  * client-side; the server merges these into the agent's tool catalog under
2222
2227
  * the `webmcp:` namespace.
2223
2228
  */
@@ -2225,16 +2230,16 @@ type ClientToolDefinition = {
2225
2230
  /** Bare tool name; the server prepends `webmcp:` on the wire. */
2226
2231
  name: string;
2227
2232
  description: string;
2228
- /** JSON Schema (per WebMCP spec) passed through as-is. */
2233
+ /** JSON Schema (per WebMCP spec): passed through as-is. */
2229
2234
  parametersSchema?: object;
2230
2235
  /**
2231
2236
  * `'webmcp'` for tools discovered via the polyfill (server prepends the
2232
2237
  * `webmcp:` wire prefix); `'sdk'` for widget/SDK-provided tools (name stays
2233
- * bare on the wire). Matches the server's accepted enum any other value
2238
+ * bare on the wire). Matches the server's accepted enum: any other value
2234
2239
  * fails dispatch validation.
2235
2240
  */
2236
2241
  origin?: 'webmcp' | 'sdk';
2237
- /** Origin of the page that registered the tool for server-side audit. */
2242
+ /** Origin of the page that registered the tool: for server-side audit. */
2238
2243
  pageOrigin?: string;
2239
2244
  /**
2240
2245
  * WebMCP `Tool.annotations` (spec). Not used for gating server-side; the
@@ -2266,7 +2271,7 @@ type WebMcpConfirmInfo = {
2266
2271
  untrustedContentHint?: boolean;
2267
2272
  };
2268
2273
  /**
2269
- * Why the confirm was requested. Currently always `'gate'` the default
2274
+ * Why the confirm was requested. Currently always `'gate'`: the default
2270
2275
  * confirm-by-default gate that fires before every `webmcp:*` call. (The
2271
2276
  * `@mcp-b/webmcp-polyfill` owns the spec's `requestUserInteraction` callback
2272
2277
  * internally, so Persona no longer surfaces a nested in-tool confirm.)
@@ -2299,7 +2304,7 @@ type WebMcpToolResult = {
2299
2304
  /**
2300
2305
  * Widget-level WebMCP configuration. Set `enabled: true` to opt in. The
2301
2306
  * surface's server-side `webmcp` policy is the source of truth for which
2302
- * tools are accepted these client-side options are convenience filters.
2307
+ * tools are accepted: these client-side options are convenience filters.
2303
2308
  */
2304
2309
  type AgentWidgetWebMcpConfig = {
2305
2310
  /** Master switch. Default: `false` (widget never installs the polyfill). */
@@ -2315,7 +2320,7 @@ type AgentWidgetWebMcpConfig = {
2315
2320
  * `webmcp:*` call; return `true` to approve immediately and skip the
2316
2321
  * confirmation UI entirely. Use this to auto-allow read-only tools (e.g.
2317
2322
  * a catalog search) while still gating mutating ones. Only consulted on
2318
- * the default-UI path a custom `onConfirm` takes full control instead.
2323
+ * the default-UI path: a custom `onConfirm` takes full control instead.
2319
2324
  */
2320
2325
  autoApprove?: (info: WebMcpConfirmInfo) => boolean;
2321
2326
  /**
@@ -2372,7 +2377,7 @@ type AgentMessageMetadata = {
2372
2377
  * `flow_await` events for a LOCAL tool (core#3878). Present only when the
2373
2378
  * server emits it. Two PARALLEL calls to the same tool in one turn share a
2374
2379
  * `toolName` (and a collapsed `toolId`) but get DISTINCT `webMcpToolCallId`s,
2375
- * so this is the key the widget batches a single `/resume` on preferred
2380
+ * so this is the key the widget batches a single `/resume` on: preferred
2376
2381
  * over tool name, which collides for same-tool parallel calls. Absent →
2377
2382
  * fall back to the legacy name-keyed resume contract.
2378
2383
  */
@@ -2462,10 +2467,35 @@ type AgentWidgetVoiceStateEvent = {
2462
2467
  source: "user" | "auto" | "restore" | "system";
2463
2468
  timestamp: number;
2464
2469
  };
2470
+ /**
2471
+ * Fired on every voice `VoiceStatus` transition (listening / processing /
2472
+ * speaking / idle / …). Unlike `voice:state` (a coarse active on/off), this
2473
+ * exposes the granular status so consumers can render their own per-state UI
2474
+ * (e.g. a listening/speaking status dock).
2475
+ */
2476
+ type AgentWidgetVoiceStatusEvent = {
2477
+ status: VoiceStatus;
2478
+ timestamp: number;
2479
+ };
2465
2480
  type AgentWidgetActionEventPayload = {
2466
2481
  action: AgentWidgetParsedAction;
2467
2482
  message: AgentWidgetMessage;
2468
2483
  };
2484
+ /**
2485
+ * Fired on every "Read aloud" (text-to-speech) state transition for a message:
2486
+ * `loading` (press) → `playing` → `paused`/`playing` → `idle` (finished or
2487
+ * stopped). On the terminal `idle` transition, `messageId`/`message` still
2488
+ * identify the message that just stopped.
2489
+ */
2490
+ type AgentWidgetReadAloudEvent = {
2491
+ /** The message being read aloud (or that just finished/stopped), if known. */
2492
+ messageId: string | null;
2493
+ /** The message object, when still present in the thread. */
2494
+ message: AgentWidgetMessage | null;
2495
+ /** The new playback state for this message. */
2496
+ state: ReadAloudState;
2497
+ timestamp: number;
2498
+ };
2469
2499
  /**
2470
2500
  * Feedback event payload for upvote/downvote actions on messages
2471
2501
  */
@@ -2517,6 +2547,14 @@ type AgentWidgetMessageActionsConfig = {
2517
2547
  * @default false
2518
2548
  */
2519
2549
  showDownvote?: boolean;
2550
+ /**
2551
+ * Show a "Read aloud" button that speaks the assistant message via
2552
+ * text-to-speech (play / pause / resume). Uses the browser Web Speech API by
2553
+ * default, or a hosted engine supplied via `textToSpeech.createEngine`.
2554
+ * Voice, rate and pitch are read from the `textToSpeech` config.
2555
+ * @default false
2556
+ */
2557
+ showReadAloud?: boolean;
2520
2558
  /**
2521
2559
  * Visibility mode: 'always' shows buttons always, 'hover' shows on hover only
2522
2560
  * @default 'hover'
@@ -2567,6 +2605,7 @@ type AgentWidgetControllerEventMap = {
2567
2605
  "assistant:message": AgentWidgetMessage;
2568
2606
  "assistant:complete": AgentWidgetMessage;
2569
2607
  "voice:state": AgentWidgetVoiceStateEvent;
2608
+ "voice:status": AgentWidgetVoiceStatusEvent;
2570
2609
  "action:detected": AgentWidgetActionEventPayload;
2571
2610
  "action:resubmit": AgentWidgetActionEventPayload;
2572
2611
  "widget:opened": AgentWidgetStateEvent;
@@ -2574,6 +2613,7 @@ type AgentWidgetControllerEventMap = {
2574
2613
  "widget:state": AgentWidgetStateSnapshot;
2575
2614
  "message:feedback": AgentWidgetMessageFeedback;
2576
2615
  "message:copy": AgentWidgetMessage;
2616
+ "message:read-aloud": AgentWidgetReadAloudEvent;
2577
2617
  "eventStream:opened": {
2578
2618
  timestamp: number;
2579
2619
  };
@@ -2629,8 +2669,8 @@ type AgentWidgetArtifactsLayoutConfig = {
2629
2669
  resizableMaxWidth?: string;
2630
2670
  /**
2631
2671
  * Visual treatment for the artifact column in split mode.
2632
- * - `'panel'` bordered sidebar with left border, gap, and shadow (default).
2633
- * - `'seamless'` flush with chat: no border or shadow, container background, zero gap.
2672
+ * - `'panel'`: bordered sidebar with left border, gap, and shadow (default).
2673
+ * - `'seamless'`: flush with chat: no border or shadow, container background, zero gap.
2634
2674
  * @default 'panel'
2635
2675
  */
2636
2676
  paneAppearance?: "panel" | "seamless";
@@ -2644,7 +2684,7 @@ type AgentWidgetArtifactsLayoutConfig = {
2644
2684
  */
2645
2685
  paneBorder?: string;
2646
2686
  /**
2647
- * `border-left` shorthand only typical for split view next to chat (with or without resizer).
2687
+ * `border-left` shorthand only: typical for split view next to chat (with or without resizer).
2648
2688
  * Ignored if `paneBorder` is set. Example: `"1px solid #cccccc"`.
2649
2689
  */
2650
2690
  paneBorderLeft?: string;
@@ -2671,8 +2711,8 @@ type AgentWidgetArtifactsLayoutConfig = {
2671
2711
  panePadding?: string;
2672
2712
  /**
2673
2713
  * Toolbar layout preset.
2674
- * - `default` "Artifacts" title, horizontal tabs, text close.
2675
- * - `document` view/source toggle, document title, copy / refresh / close; tab strip hidden when only one artifact.
2714
+ * - `default`: "Artifacts" title, horizontal tabs, text close.
2715
+ * - `document`: view/source toggle, document title, copy / refresh / close; tab strip hidden when only one artifact.
2676
2716
  * @default 'default'
2677
2717
  */
2678
2718
  toolbarPreset?: "default" | "document";
@@ -2684,7 +2724,7 @@ type AgentWidgetArtifactsLayoutConfig = {
2684
2724
  * When `toolbarPreset` is `document`, show a small chevron after the copy control (e.g. menu affordance).
2685
2725
  */
2686
2726
  documentToolbarShowCopyChevron?: boolean;
2687
- /** Document toolbar icon buttons (view, code, copy, refresh, close) CSS color. Sets `--persona-artifact-doc-toolbar-icon-color` on the widget root. */
2727
+ /** Document toolbar icon buttons (view, code, copy, refresh, close): CSS color. Sets `--persona-artifact-doc-toolbar-icon-color` on the widget root. */
2688
2728
  documentToolbarIconColor?: string;
2689
2729
  /** Active view/source toggle background. Sets `--persona-artifact-doc-toggle-active-bg`. */
2690
2730
  documentToolbarToggleActiveBackground?: string;
@@ -2828,11 +2868,11 @@ type AgentWidgetToolCallDisplayFeature = {
2828
2868
  expandable?: boolean;
2829
2869
  /**
2830
2870
  * Animation mode applied to the tool call header text while the tool is active.
2831
- * - "none" static text, no animation
2832
- * - "pulse" opacity pulse on the entire header text
2833
- * - "shimmer" monochrome opacity sweep per character
2834
- * - "shimmer-color" color gradient sweep per character
2835
- * - "rainbow" rainbow color cycle per character
2871
+ * - "none": static text, no animation
2872
+ * - "pulse": opacity pulse on the entire header text
2873
+ * - "shimmer": monochrome opacity sweep per character
2874
+ * - "shimmer-color": color gradient sweep per character
2875
+ * - "rainbow": rainbow color cycle per character
2836
2876
  * @default "none"
2837
2877
  */
2838
2878
  loadingAnimation?: AgentWidgetToolCallLoadingAnimation;
@@ -2861,11 +2901,11 @@ type AgentWidgetReasoningDisplayFeature = {
2861
2901
  /**
2862
2902
  * Animation mode applied to the reasoning header text while reasoning is active.
2863
2903
  * Reuses the same modes as tool call animations.
2864
- * - "none" static text, no animation
2865
- * - "pulse" opacity pulse on the entire header text
2866
- * - "shimmer" monochrome opacity sweep per character
2867
- * - "shimmer-color" color gradient sweep per character
2868
- * - "rainbow" rainbow color cycle per character
2904
+ * - "none": static text, no animation
2905
+ * - "pulse": opacity pulse on the entire header text
2906
+ * - "shimmer": monochrome opacity sweep per character
2907
+ * - "shimmer-color": color gradient sweep per character
2908
+ * - "rainbow": rainbow color cycle per character
2869
2909
  * @default "none"
2870
2910
  */
2871
2911
  loadingAnimation?: AgentWidgetToolCallLoadingAnimation;
@@ -2874,34 +2914,34 @@ type AgentWidgetReasoningDisplayFeature = {
2874
2914
  * Reveal animation applied to assistant message text while it is streaming.
2875
2915
  *
2876
2916
  * Built-in types always available:
2877
- * - `none` text appears as tokens arrive (default).
2878
- * - `typewriter` characters fade in with a blinking caret.
2879
- * - `pop-bubble` the bubble scales in; text streams normally afterward.
2880
- * - `letter-rise` per-char translateY + fade reveal.
2881
- * - `word-fade` per-word blur + translateY fade-in.
2917
+ * - `none`: text appears as tokens arrive (default).
2918
+ * - `typewriter`: characters fade in with a blinking caret.
2919
+ * - `pop-bubble`: the bubble scales in; text streams normally afterward.
2920
+ * - `letter-rise`: per-char translateY + fade reveal.
2921
+ * - `word-fade`: per-word blur + translateY fade-in.
2882
2922
  *
2883
2923
  * Subpath plugins (import from `@runtypelabs/persona/animations/*` to register):
2884
2924
  * - `wipe`, `glyph-cycle`.
2885
2925
  *
2886
- * Custom types are allowed register a plugin with any string name and
2926
+ * Custom types are allowed: register a plugin with any string name and
2887
2927
  * reference it by that name in `type`.
2888
2928
  */
2889
2929
  type AgentWidgetStreamAnimationBuiltinType = "none" | "typewriter" | "word-fade" | "letter-rise" | "glyph-cycle" | "wipe" | "pop-bubble";
2890
2930
  type AgentWidgetStreamAnimationType = AgentWidgetStreamAnimationBuiltinType | (string & {});
2891
2931
  /**
2892
2932
  * Placeholder shown inside a streaming assistant bubble before the first token arrives.
2893
- * - `none` use the default typing-dots indicator (existing behavior).
2894
- * - `skeleton` shimmer bars, replaced by streaming content once it starts.
2933
+ * - `none`: use the default typing-dots indicator (existing behavior).
2934
+ * - `skeleton`: shimmer bars, replaced by streaming content once it starts.
2895
2935
  */
2896
2936
  type AgentWidgetStreamAnimationPlaceholder = "none" | "skeleton";
2897
2937
  /**
2898
2938
  * How much of the accumulated streaming content to display while tokens are
2899
2939
  * still arriving. Trimming to a boundary means in-progress words or lines
2900
- * stay hidden until they complete useful for animations that benefit from
2940
+ * stay hidden until they complete: useful for animations that benefit from
2901
2941
  * unit-complete reveals (e.g. wipe, glyph-cycle).
2902
- * - `none` show every character as it arrives (default).
2903
- * - `word` trim to the last whitespace boundary.
2904
- * - `line` trim to the last newline boundary.
2942
+ * - `none`: show every character as it arrives (default).
2943
+ * - `word`: trim to the last whitespace boundary.
2944
+ * - `line`: trim to the last newline boundary.
2905
2945
  */
2906
2946
  type AgentWidgetStreamAnimationBuffer = "none" | "word" | "line";
2907
2947
  /**
@@ -2932,7 +2972,7 @@ type StreamAnimationContext = {
2932
2972
  * widget's style host.
2933
2973
  * - For each streaming assistant message whose `type` matches `name`, the
2934
2974
  * widget applies `containerClass` / `bubbleClass`, wraps text per `wrap`,
2935
- * and if `useCaret` is true appends a blinking caret.
2975
+ * and, if `useCaret` is true, appends a blinking caret.
2936
2976
  * - Hooks fire after the live DOM is morphed; plugins use stable element IDs
2937
2977
  * and `data-preserve-animation` to safely mutate per-char or per-word spans
2938
2978
  * without idiomorph clobbering in-flight work.
@@ -2948,7 +2988,7 @@ type StreamAnimationPlugin = {
2948
2988
  wrap?: "none" | "char" | "word";
2949
2989
  /**
2950
2990
  * HTML tags whose descendant text is skipped during wrapping. Defaults to
2951
- * `["pre", "code", "a", "script", "style"]` useful for keeping code
2991
+ * `["pre", "code", "a", "script", "style"]`: useful for keeping code
2952
2992
  * blocks legible and link click-targets intact. Plugins that want to
2953
2993
  * animate characters inside inline code (e.g. `glyph-cycle`) can narrow
2954
2994
  * the list.
@@ -2977,8 +3017,7 @@ type StreamAnimationPlugin = {
2977
3017
  /**
2978
3018
  * Report whether the plugin still has in-flight animation work for a
2979
3019
  * message. When `true`, the widget keeps rendering the message in its
2980
- * "streaming-animated" mode even after `message.streaming` flips false
2981
- * preventing the final non-animated render from yanking the rug out from
3020
+ * "streaming-animated" mode even after `message.streaming` flips false: * preventing the final non-animated render from yanking the rug out from
2982
3021
  * under unfinished per-char cycles or reveals.
2983
3022
  */
2984
3023
  isAnimating?: (message: AgentWidgetMessage) => boolean;
@@ -2991,7 +3030,7 @@ type AgentWidgetStreamAnimationFeature = {
2991
3030
  /**
2992
3031
  * Per-unit animation duration (ms) for `typewriter`, `letter-rise`, `word-fade`,
2993
3032
  * and per-unit plugin animations. Each arriving character/word animates from
2994
- * invisible to visible over this duration, independent of its position the
3033
+ * invisible to visible over this duration, independent of its position: the
2995
3034
  * streaming cadence itself provides the visible stagger.
2996
3035
  * @default 120
2997
3036
  */
@@ -3051,7 +3090,7 @@ type AgentWidgetFeatureFlags = {
3051
3090
  * Built-in `suggest_replies` quick-reply chips. When the assistant invokes
3052
3091
  * the tool, the widget shows the suggestions as tappable chips above the
3053
3092
  * composer (reusing the suggestion-chips surface) and immediately resumes
3054
- * the execution fire-and-forget, no user input awaited.
3093
+ * the execution: fire-and-forget, no user input awaited.
3055
3094
  */
3056
3095
  suggestReplies?: AgentWidgetSuggestRepliesFeature;
3057
3096
  };
@@ -3065,14 +3104,14 @@ type AgentWidgetFeatureFlags = {
3065
3104
  type AgentWidgetSuggestRepliesFeature = {
3066
3105
  /**
3067
3106
  * Enable the feature. Defaults to true. When false, `suggest_replies`
3068
- * renders as a regular tool bubble and is NOT auto-resumed only set this
3107
+ * renders as a regular tool bubble and is NOT auto-resumed: only set this
3069
3108
  * with no server-side `suggest_replies` declaration, or the execution
3070
3109
  * parks awaiting a resume that never comes.
3071
3110
  */
3072
3111
  enabled?: boolean;
3073
3112
  /**
3074
3113
  * Advertise the built-in `suggest_replies` tool to the agent on every
3075
- * dispatch via `clientTools[]` no server-side `runtimeTools` declaration
3114
+ * dispatch via `clientTools[]`: no server-side `runtimeTools` declaration
3076
3115
  * needed. Defaults to `false`: flows that already declare the tool via
3077
3116
  * `runtimeTools` would otherwise present it to the model twice. Ignored
3078
3117
  * when `enabled` is `false`.
@@ -3088,7 +3127,7 @@ type AskUserQuestionOption = {
3088
3127
  label: string;
3089
3128
  /** Optional long-form description (shown as a subtitle on tap-hover). */
3090
3129
  description?: string;
3091
- /** Optional rich preview reserved for future rendering; ignored in v1. */
3130
+ /** Optional rich preview: reserved for future rendering; ignored in v1. */
3092
3131
  preview?: string;
3093
3132
  };
3094
3133
  /**
@@ -3140,14 +3179,14 @@ type AgentWidgetAskUserQuestionFeature = {
3140
3179
  enabled?: boolean;
3141
3180
  /**
3142
3181
  * Advertise the built-in `ask_user_question` tool to the agent on every
3143
- * dispatch via `clientTools[]` no server-side `runtimeTools` declaration
3182
+ * dispatch via `clientTools[]`: no server-side `runtimeTools` declaration
3144
3183
  * needed. The tool ships with a model-facing description and JSON schema
3145
3184
  * matching {@link AskUserQuestionPayload}; when the model calls it, the
3146
3185
  * existing answer-pill sheet renders and the answer resumes the execution.
3147
3186
  *
3148
3187
  * Defaults to `false`: flows that already declare `ask_user_question` via
3149
3188
  * `runtimeTools` would otherwise present the tool to the model twice.
3150
- * Ignored when `enabled` is `false` never offer the agent a question
3189
+ * Ignored when `enabled` is `false`: never offer the agent a question
3151
3190
  * tool the widget can't render an answer UI for.
3152
3191
  */
3153
3192
  expose?: boolean;
@@ -3168,17 +3207,17 @@ type AgentWidgetAskUserQuestionFeature = {
3168
3207
  /**
3169
3208
  * In grouped (multi-question) mode, auto-advance to the next page after a
3170
3209
  * single-select pill pick or free-text submit on intermediate pages.
3171
- * Defaults to `true`. The final page never auto-submits users always
3210
+ * Defaults to `true`. The final page never auto-submits: users always
3172
3211
  * confirm with an explicit "Submit all" click. Multi-select pages always
3173
3212
  * require an explicit Next regardless of this setting.
3174
3213
  */
3175
3214
  groupedAutoAdvance?: boolean;
3176
3215
  /**
3177
3216
  * Visual layout for the option list.
3178
- * - `"rows"` (default) full-width stacked rows with always-visible
3217
+ * - `"rows"` (default): full-width stacked rows with always-visible
3179
3218
  * descriptions, right-edge number badges (single-select) or checkboxes
3180
3219
  * (multi-select), and an always-visible inline "Other" input.
3181
- * - `"pills"` legacy compact pill list with horizontal wrap; description
3220
+ * - `"pills"`: legacy compact pill list with horizontal wrap; description
3182
3221
  * surfaces as a tooltip and the "Other…" pill expands on click.
3183
3222
  */
3184
3223
  layout?: "rows" | "pills";
@@ -3346,7 +3385,7 @@ type AgentWidgetDockConfig = {
3346
3385
  *
3347
3386
  * - Set a CSS length (e.g. `"600px"`, `"80vh"`) to override the cap.
3348
3387
  * - Set `false` to disable the guard entirely (the panel then sizes purely
3349
- * from the surrounding layout make sure your page provides a definite
3388
+ * from the surrounding layout: make sure your page provides a definite
3350
3389
  * height all the way down to the dock target's parent).
3351
3390
  *
3352
3391
  * @default "100dvh"
@@ -3420,7 +3459,7 @@ type AgentWidgetComposerBarConfig = {
3420
3459
  */
3421
3460
  modalMaxHeight?: string;
3422
3461
  /**
3423
- * Configuration for the "peek" banner the chrome-less row above the
3462
+ * Configuration for the "peek" banner: the chrome-less row above the
3424
3463
  * collapsed pill that previews the most recent assistant message.
3425
3464
  */
3426
3465
  peek?: AgentWidgetComposerBarPeekConfig;
@@ -3435,7 +3474,7 @@ type AgentWidgetComposerBarConfig = {
3435
3474
  * - Otherwise the peek inherits from `features.streamAnimation`.
3436
3475
  *
3437
3476
  * Per-surface carve-outs:
3438
- * - `bubbleClass` from a plugin (used by `pop-bubble`) is ignored the peek
3477
+ * - `bubbleClass` from a plugin (used by `pop-bubble`) is ignored: the peek
3439
3478
  * has no bubble analog.
3440
3479
  * - `containerClass`, `wrap` ("char" | "word"), `useCaret`, `placeholder`
3441
3480
  * ("skeleton"), `buffer` ("word" | "line"), `speed`, `duration`, and
@@ -3681,6 +3720,11 @@ type AgentWidgetVoiceRecognitionConfig = {
3681
3720
  /** Button border color while speaking. Inherits idle borderColor if not set */
3682
3721
  speakingBorderColor?: string;
3683
3722
  autoResume?: boolean | "assistant";
3723
+ /**
3724
+ * Called with per-turn latency metrics on the realtime (`runtype`) voice path.
3725
+ * Fires once per turn after the reply completes.
3726
+ */
3727
+ onMetrics?: (metrics: VoiceMetrics) => void;
3684
3728
  provider?: {
3685
3729
  type: 'browser' | 'runtype' | 'custom';
3686
3730
  browser?: {
@@ -3689,15 +3733,31 @@ type AgentWidgetVoiceRecognitionConfig = {
3689
3733
  };
3690
3734
  runtype?: {
3691
3735
  agentId: string;
3692
- clientToken: string;
3736
+ /** Defaults to the widget's `clientToken` when omitted. */
3737
+ clientToken?: string;
3738
+ /** Defaults to the widget's `apiUrl` when omitted. */
3693
3739
  host?: string;
3694
3740
  voiceId?: string;
3695
- /** Duration of silence (ms) before auto-stopping recording. Default: 2000 */
3741
+ /**
3742
+ * Optional custom streaming playback engine. Defaults to the built-in
3743
+ * `AudioPlaybackManager`. Import `createWorkletPlaybackEngine` from
3744
+ * `@runtypelabs/persona/voice-worklet-player` for a jitter-buffered engine.
3745
+ */
3746
+ createPlaybackEngine?: () => VoicePlaybackEngine | Promise<VoicePlaybackEngine>;
3747
+ /** @deprecated No-op on the realtime path: the server's STT owns turn-taking. */
3696
3748
  pauseDuration?: number;
3697
- /** RMS volume threshold below which counts as silence. Default: 0.01 */
3749
+ /** @deprecated No-op on the realtime path: the server's STT owns turn-taking. */
3698
3750
  silenceThreshold?: number;
3699
3751
  };
3700
- custom?: any;
3752
+ /**
3753
+ * Bring-your-own voice provider. Set `type: 'custom'` and pass either a
3754
+ * ready {@link VoiceProvider} instance or a `() => VoiceProvider` factory
3755
+ * (the factory defers construction until voice is set up). STT-style
3756
+ * providers deliver a final transcript via `onResult` (sent as a user
3757
+ * message); full-duplex providers can drive `onTranscript`/`onMetrics` like
3758
+ * the realtime `runtype` provider.
3759
+ */
3760
+ custom?: VoiceProvider | (() => VoiceProvider);
3701
3761
  };
3702
3762
  };
3703
3763
  /**
@@ -3720,18 +3780,68 @@ type TextToSpeechConfig = {
3720
3780
  enabled: boolean;
3721
3781
  /**
3722
3782
  * TTS provider.
3723
- * - `'browser'` Use the Web Speech API for all assistant messages (default).
3724
- * - `'runtype'` Server handles TTS for voice interactions.
3725
- * Set `browserFallback: true` to also speak text-typed responses via the browser.
3783
+ * - `'browser'`: Use the Web Speech API for all assistant messages (default).
3784
+ * - `'runtype'`: Use Runtype-hosted TTS. The realtime voice path speaks
3785
+ * replies during a voice call, and the per-message "Read aloud" button (and
3786
+ * auto-speak of text-typed replies) stream from Runtype's
3787
+ * `POST {host}/v1/agents/:agentId/speak` endpoint via the built-in
3788
+ * {@link SpeechEngine}. `host`/`agentId`/`clientToken` are derived from the
3789
+ * widget config (see `agentId`/`host` below); unless `browserFallback` is
3790
+ * `false`, a missing endpoint or transient failure falls back to the browser
3791
+ * voice so the button is never broken.
3726
3792
  */
3727
3793
  provider?: 'browser' | 'runtype';
3728
3794
  /**
3729
- * When `provider` is `'runtype'`, fall back to browser TTS for assistant
3730
- * messages that the server didn't already speak (e.g. text-typed messages).
3795
+ * When `provider` is `'runtype'`:
3796
+ * - Read-aloud / auto-speak: acts as a safety net — if Runtype TTS is
3797
+ * unreachable (no endpoint yet, network/auth failure) or the Runtype config
3798
+ * is incomplete, speech falls back to the browser Web Speech API instead of
3799
+ * erroring. Set to `false` to surface Runtype errors instead. **Defaults to
3800
+ * on for this path.**
3801
+ * - Auto-speak of text-typed replies also requires this to be truthy (the
3802
+ * realtime voice path already speaks voice-call replies).
3803
+ *
3731
3804
  * Has no effect when provider is `'browser'` (browser TTS is always used).
3732
- * @default false
3733
3805
  */
3734
3806
  browserFallback?: boolean;
3807
+ /**
3808
+ * When `provider` is `'runtype'`, the agent whose configured voice synthesizes
3809
+ * read-aloud / auto-speak audio. Falls back to
3810
+ * `voiceRecognition.provider.runtype.agentId` when omitted. Required (here or
3811
+ * there) for Runtype TTS to activate; without it the browser voice is used.
3812
+ */
3813
+ agentId?: string;
3814
+ /**
3815
+ * When `provider` is `'runtype'`, the Runtype API host (e.g.
3816
+ * `https://api.runtype.com`). Defaults to the widget's `apiUrl`.
3817
+ */
3818
+ host?: string;
3819
+ /**
3820
+ * When `provider` is `'runtype'`, audio (ms) the streaming player buffers
3821
+ * before the first sample and after an underrun. Lower = snappier start;
3822
+ * higher = rides out delivery hiccups. Default 200. Applies to the default
3823
+ * in-bundle player; a custom `createPlaybackEngine` manages its own prebuffer.
3824
+ */
3825
+ prebufferMs?: number;
3826
+ /**
3827
+ * When `provider` is `'runtype'`, an optional factory for the streaming PCM
3828
+ * player that synthesizes read-aloud / auto-speak audio. Defaults to the
3829
+ * in-bundle, main-thread `AudioPlaybackManager` (smooth for steady Runtype
3830
+ * streams, no AudioWorklet — keeps the widget bundle lean).
3831
+ *
3832
+ * For the higher-quality, jitter-buffered AudioWorklet player, import
3833
+ * `createPcmStreamPlayer` from `@runtypelabs/persona/voice-worklet-player` and
3834
+ * pass it here — it then ships in your bundle, not Persona's:
3835
+ *
3836
+ * @example
3837
+ * import { createPcmStreamPlayer } from '@runtypelabs/persona/voice-worklet-player'
3838
+ * textToSpeech: {
3839
+ * enabled: true,
3840
+ * provider: 'runtype',
3841
+ * createPlaybackEngine: () => createPcmStreamPlayer({ prebufferMs: 400 }),
3842
+ * }
3843
+ */
3844
+ createPlaybackEngine?: () => PcmStreamPlayer | Promise<PcmStreamPlayer>;
3735
3845
  /** Voice name to use for browser TTS (e.g., 'Google US English'). If not found, uses auto-detect. */
3736
3846
  voice?: string;
3737
3847
  /**
@@ -3750,7 +3860,73 @@ type TextToSpeechConfig = {
3750
3860
  rate?: number;
3751
3861
  /** Speech pitch (0 - 2). Default: 1 */
3752
3862
  pitch?: number;
3863
+ /**
3864
+ * Factory for a custom {@link SpeechEngine}, used by both the auto-speak path
3865
+ * and the per-message "Read aloud" action. When omitted, the browser Web
3866
+ * Speech API engine is used. Return a hosted engine here to use server-side
3867
+ * TTS (e.g. Runtype) — such an engine can stream audio through the realtime
3868
+ * voice {@link VoicePlaybackEngine}. May be async (it is resolved on first
3869
+ * playback, inside the user gesture).
3870
+ */
3871
+ createEngine?: () => SpeechEngine | Promise<SpeechEngine>;
3753
3872
  };
3873
+ /**
3874
+ * Playback state of the per-message "Read aloud" action.
3875
+ * - `idle`: not reading this message.
3876
+ * - `loading`: the engine is preparing audio (e.g. a hosted TTS fetch). Browser
3877
+ * engines pass through this state almost instantly.
3878
+ * - `playing`: audio is playing.
3879
+ * - `paused`: playback is paused and resumable.
3880
+ */
3881
+ type ReadAloudState = "idle" | "loading" | "playing" | "paused";
3882
+ /** A unit of speech handed to a {@link SpeechEngine}. */
3883
+ interface SpeechRequest {
3884
+ /** Plain text to speak. The widget strips Markdown before calling the engine. */
3885
+ text: string;
3886
+ /** Preferred voice identifier (engine-specific; browser = voice name). */
3887
+ voice?: string;
3888
+ /** Speech rate (engine-specific range; browser: 0.1–10, default 1). */
3889
+ rate?: number;
3890
+ /** Speech pitch (engine-specific range; browser: 0–2, default 1). */
3891
+ pitch?: number;
3892
+ }
3893
+ /** Lifecycle callbacks a {@link SpeechEngine} invokes during playback. */
3894
+ interface SpeechCallbacks {
3895
+ /** Audio has started playing. */
3896
+ onStart?: () => void;
3897
+ /** Playback finished naturally (or was canceled). */
3898
+ onEnd?: () => void;
3899
+ /** Playback failed. */
3900
+ onError?: (error: Error) => void;
3901
+ }
3902
+ /**
3903
+ * Pluggable text-to-speech engine behind the "Read aloud" message action.
3904
+ *
3905
+ * The widget ships a browser Web Speech API engine by default. Provide a hosted
3906
+ * engine (Runtype TTS, ElevenLabs, a server proxy, …) by implementing this
3907
+ * interface and returning it from {@link TextToSpeechConfig.createEngine}; a
3908
+ * server engine can stream audio into the realtime voice
3909
+ * {@link VoicePlaybackEngine}.
3910
+ */
3911
+ interface SpeechEngine {
3912
+ /** Stable identifier, e.g. `"browser"`, `"runtype"`, or a custom id. */
3913
+ readonly id: string;
3914
+ /**
3915
+ * Whether {@link pause}/{@link resume} are supported. When `false`, the UI
3916
+ * offers play/stop only (tapping a playing message stops it).
3917
+ */
3918
+ readonly supportsPause: boolean;
3919
+ /** Begin speaking. Drives the lifecycle through `callbacks`. */
3920
+ speak(request: SpeechRequest, callbacks: SpeechCallbacks): void;
3921
+ /** Pause playback (no-op if unsupported). */
3922
+ pause(): void;
3923
+ /** Resume paused playback (no-op if unsupported). */
3924
+ resume(): void;
3925
+ /** Stop playback and discard any queued audio. */
3926
+ stop(): void;
3927
+ /** Optional teardown of engine resources. */
3928
+ destroy?(): void;
3929
+ }
3754
3930
  /**
3755
3931
  * Voice recognition result with transcript and optional audio
3756
3932
  */
@@ -3770,6 +3946,66 @@ type VoiceResult = {
3770
3946
  * Voice provider status states
3771
3947
  */
3772
3948
  type VoiceStatus = 'disconnected' | 'connected' | 'listening' | 'processing' | 'speaking' | 'error' | 'idle';
3949
+ /**
3950
+ * Per-turn latency metrics emitted by the realtime voice path.
3951
+ * The wire frame is snake_case (`metrics`); decoded to camelCase at the
3952
+ * provider boundary before being surfaced through `onMetrics`.
3953
+ */
3954
+ type VoiceMetrics = {
3955
+ /** LLM generation time (ms). */
3956
+ llmMs?: number;
3957
+ /** Text-to-speech synthesis time (ms). */
3958
+ ttsMs?: number;
3959
+ /** Time to first audio frame (ms). */
3960
+ firstAudioMs?: number;
3961
+ /** Total turn time (ms). */
3962
+ totalMs?: number;
3963
+ };
3964
+ /**
3965
+ * Streaming PCM playback engine used by the realtime voice provider.
3966
+ *
3967
+ * The provider feeds raw PCM16 LE mono @ 24kHz (WAV header already stripped)
3968
+ * via `enqueue`, signals end-of-reply with `markStreamEnd`, and learns when
3969
+ * playback has fully drained via `onFinished`. The default implementation is
3970
+ * `AudioPlaybackManager`; an optional jitter-buffered AudioWorklet engine ships
3971
+ * from `@runtypelabs/persona/voice-worklet-player` and can be injected via the
3972
+ * `runtype.createPlaybackEngine` config hook.
3973
+ */
3974
+ interface VoicePlaybackEngine {
3975
+ /** Enqueue a raw PCM16 LE mono @ 24kHz chunk (no WAV header). */
3976
+ enqueue(pcm: Uint8Array): void;
3977
+ /** Signal that no more chunks will arrive for the current reply. */
3978
+ markStreamEnd(): void;
3979
+ /** Immediately stop playback and discard queued audio. */
3980
+ flush(): void;
3981
+ /** Register a callback fired once all queued audio has finished playing. */
3982
+ onFinished(callback: () => void): void;
3983
+ /** Release all audio resources. */
3984
+ destroy(): Promise<void> | void;
3985
+ }
3986
+ /**
3987
+ * A {@link VoicePlaybackEngine} that also supports pause/resume. Returned by
3988
+ * `createPcmStreamPlayer` (`@runtypelabs/persona/voice-worklet-player`): a
3989
+ * jitter-buffered AudioWorklet player for raw PCM16 / 24 kHz / mono streams.
3990
+ * Reuse it inside a hosted {@link SpeechEngine} to get gapless playback with a
3991
+ * configurable prebuffer and graceful underrun handling — feed each streamed
3992
+ * chunk to {@link VoicePlaybackEngine.enqueue} and the worklet does the rest.
3993
+ */
3994
+ interface PcmStreamPlayer extends VoicePlaybackEngine {
3995
+ /** Pause playback; the audio clock suspends and {@link resume} continues in place. */
3996
+ pause(): void;
3997
+ /** Resume playback after {@link pause}. */
3998
+ resume(): void;
3999
+ /**
4000
+ * Register a callback fired once audible playback actually begins — i.e. the
4001
+ * prebuffer waterline filled and the first sample reached the output. Use this
4002
+ * (rather than "first chunk enqueued") to flip a UI from loading to playing, so
4003
+ * the spinner holds through the prebuffer. Fires once per playback session
4004
+ * (cleared by {@link VoicePlaybackEngine.flush}); a mid-reply underrun re-buffer
4005
+ * does not re-fire it.
4006
+ */
4007
+ onStarted(callback: () => void): void;
4008
+ }
3773
4009
  /**
3774
4010
  * Voice provider configuration
3775
4011
  * Determines which voice provider to use and its specific settings
@@ -3782,15 +4018,29 @@ type VoiceConfig = {
3782
4018
  };
3783
4019
  runtype?: {
3784
4020
  agentId: string;
3785
- clientToken: string;
4021
+ /** Defaults to the widget's `clientToken` when omitted. */
4022
+ clientToken?: string;
4023
+ /** Defaults to the widget's `apiUrl` (as a ws(s):// base) when omitted. */
3786
4024
  host?: string;
3787
4025
  voiceId?: string;
3788
- /** Duration of silence (ms) before auto-stopping recording. Default: 2000 */
4026
+ /**
4027
+ * Optional custom streaming playback engine. Defaults to the built-in
4028
+ * `AudioPlaybackManager`. Import `createWorkletPlaybackEngine` from
4029
+ * `@runtypelabs/persona/voice-worklet-player` for a jitter-buffered engine.
4030
+ */
4031
+ createPlaybackEngine?: () => VoicePlaybackEngine | Promise<VoicePlaybackEngine>;
4032
+ /** @deprecated No-op on the realtime path: the server's STT owns turn-taking. */
3789
4033
  pauseDuration?: number;
3790
- /** RMS volume threshold below which counts as silence. Default: 0.01 */
4034
+ /** @deprecated No-op on the realtime path: the server's STT owns turn-taking. */
3791
4035
  silenceThreshold?: number;
3792
4036
  };
3793
- custom?: any;
4037
+ /**
4038
+ * Bring-your-own voice provider for `type: 'custom'`: either a ready
4039
+ * {@link VoiceProvider} instance or a `() => VoiceProvider` factory. The
4040
+ * factory form defers construction (WebSocket/AudioContext/etc.) until
4041
+ * `createVoiceProvider` runs.
4042
+ */
4043
+ custom?: VoiceProvider | (() => VoiceProvider);
3794
4044
  };
3795
4045
  /**
3796
4046
  * Voice provider interface
@@ -3807,11 +4057,21 @@ interface VoiceProvider {
3807
4057
  onStatusChange(callback: (status: VoiceStatus) => void): void;
3808
4058
  /** Register a callback fired when recording stops and audio is about to be sent */
3809
4059
  onProcessingStart?(callback: () => void): void;
4060
+ /**
4061
+ * Register a callback for incremental transcript updates during a voice turn.
4062
+ * `isFinal=false` is a live interim update (user partials, or assistant deltas
4063
+ * on providers that stream them); `isFinal=true` finalizes that role's text.
4064
+ * On the realtime `runtype` path, interim updates fire for the `user` only and
4065
+ * the `assistant` arrives as a single final.
4066
+ */
4067
+ onTranscript?(callback: (role: 'user' | 'assistant', text: string, isFinal: boolean) => void): void;
4068
+ /** Register a callback for per-turn latency metrics (realtime path). */
4069
+ onMetrics?(callback: (metrics: VoiceMetrics) => void): void;
3810
4070
  /** Returns the current interruption mode (only meaningful for Runtype provider) */
3811
4071
  getInterruptionMode?(): "none" | "cancel" | "barge-in";
3812
4072
  /** Returns true if the barge-in mic stream is alive (hot mic between turns) */
3813
4073
  isBargeInActive?(): boolean;
3814
- /** Tear down the barge-in mic pipeline "hang up" the always-on mic */
4074
+ /** Tear down the barge-in mic pipeline: "hang up" the always-on mic */
3815
4075
  deactivateBargeIn?(): Promise<void>;
3816
4076
  /** Stop playback / cancel in-flight request without starting recording */
3817
4077
  stopPlayback?(): void;
@@ -3824,7 +4084,7 @@ type AgentWidgetApprovalDecisionOptions = {
3824
4084
  /**
3825
4085
  * The user chose a "remember this" affordance (e.g. an "Always allow"
3826
4086
  * button) rather than a one-time decision. The widget resolves the *current*
3827
- * approval identically whether or not this is set an approval bubble is a
4087
+ * approval identically whether or not this is set: an approval bubble is a
3828
4088
  * single binary gate (`approved`/`denied`). Persisting a don't-ask-again
3829
4089
  * policy for *future* approvals (auto-resolving them, or not surfacing them)
3830
4090
  * is the integrator's responsibility, typically inside `onDecision`.
@@ -3878,9 +4138,9 @@ type AgentWidgetApprovalConfig = {
3878
4138
  /**
3879
4139
  * How the technical details (the tool's agent-facing description and the
3880
4140
  * raw parameters JSON) are presented:
3881
- * - `"collapsed"` (default) hidden behind a "Show details" toggle
3882
- * - `"expanded"` visible, with the toggle available to hide them
3883
- * - `"hidden"` never rendered
4141
+ * - `"collapsed"` (default): hidden behind a "Show details" toggle
4142
+ * - `"expanded"`: visible, with the toggle available to hide them
4143
+ * - `"hidden"`: never rendered
3884
4144
  */
3885
4145
  detailsDisplay?: "collapsed" | "expanded" | "hidden";
3886
4146
  /** Label for the toggle that reveals the technical details */
@@ -3902,7 +4162,7 @@ type AgentWidgetApprovalConfig = {
3902
4162
  displayTitle?: string;
3903
4163
  /**
3904
4164
  * Agent-authored justification for this specific call, when the agent
3905
- * provided one. It is the agent's own claim if you fold it into the
4165
+ * provided one. It is the agent's own claim: if you fold it into the
3906
4166
  * summary, keep it attributed to the agent.
3907
4167
  */
3908
4168
  reason?: string;
@@ -4008,7 +4268,7 @@ type AgentWidgetToolCallConfig = {
4008
4268
  *
4009
4269
  * **Placeholders:** `{toolName}` (tool name), `{duration}` (live-updating elapsed time).
4010
4270
  *
4011
- * **Inline formatting:** `~dim~`, `*italic*`, `**bold**` parsed at render time and
4271
+ * **Inline formatting:** `~dim~`, `*italic*`, `**bold**`: parsed at render time and
4012
4272
  * applied as styled `<span>` elements. Works with all animation modes.
4013
4273
  *
4014
4274
  * When not set, falls back to the current `collapsedMode` behavior.
@@ -4021,7 +4281,7 @@ type AgentWidgetToolCallConfig = {
4021
4281
  *
4022
4282
  * **Placeholders:** `{toolName}` (tool name), `{duration}` (final elapsed time).
4023
4283
  *
4024
- * **Inline formatting:** `~dim~`, `*italic*`, `**bold**` same syntax as `activeTextTemplate`.
4284
+ * **Inline formatting:** `~dim~`, `*italic*`, `**bold**`: same syntax as `activeTextTemplate`.
4025
4285
  *
4026
4286
  * When not set, falls back to the existing "Used tool for X seconds" text.
4027
4287
  * @example "Finished {toolName} ~{duration}~"
@@ -4082,7 +4342,7 @@ type AgentWidgetReasoningConfig = {
4082
4342
  *
4083
4343
  * **Placeholders:** `{duration}` (live-updating elapsed time).
4084
4344
  *
4085
- * **Inline formatting:** `~dim~`, `*italic*`, `**bold**` parsed at render time.
4345
+ * **Inline formatting:** `~dim~`, `*italic*`, `**bold**`: parsed at render time.
4086
4346
  *
4087
4347
  * When not set, falls back to the default "Thinking..." text.
4088
4348
  * @example "Thinking... ~{duration}~"
@@ -4093,7 +4353,7 @@ type AgentWidgetReasoningConfig = {
4093
4353
  *
4094
4354
  * **Placeholders:** `{duration}` (final elapsed time).
4095
4355
  *
4096
- * **Inline formatting:** `~dim~`, `*italic*`, `**bold**` same syntax as `activeTextTemplate`.
4356
+ * **Inline formatting:** `~dim~`, `*italic*`, `**bold**`: same syntax as `activeTextTemplate`.
4097
4357
  *
4098
4358
  * When not set, falls back to the default "Thought for X seconds" text.
4099
4359
  * @example "Thought for ~{duration}~"
@@ -4192,7 +4452,7 @@ type AgentWidgetSSEEventResult = {
4192
4452
  done?: boolean;
4193
4453
  /** Error message if an error occurred */
4194
4454
  error?: string;
4195
- /** Text segment identity when this changes, a new assistant message bubble is created */
4455
+ /** Text segment identity: when this changes, a new assistant message bubble is created */
4196
4456
  partId?: string;
4197
4457
  } | null;
4198
4458
  /**
@@ -4264,7 +4524,7 @@ type ClientChatRequest = {
4264
4524
  /** Per-turn inputs for Runtype prompt templates (e.g. {{page_url}}). */
4265
4525
  inputs?: Record<string, unknown>;
4266
4526
  context?: Record<string, unknown>;
4267
- /** WebMCP page-discovered tools same shape as `dispatch.clientTools[]`. */
4527
+ /** WebMCP page-discovered tools: same shape as `dispatch.clientTools[]`. */
4268
4528
  clientTools?: ClientToolDefinition[];
4269
4529
  /**
4270
4530
  * Diff-only / send-once: order-independent fingerprint of the client tool set.
@@ -5237,7 +5497,7 @@ type AgentWidgetConfig = {
5237
5497
  * Per-stop-reason copy for the inline notice rendered on assistant
5238
5498
  * bubbles when the runtime reports a non-natural stop (e.g. the agent
5239
5499
  * loop hit `max_tool_calls` and was cut off mid-loop). Each key is
5240
- * optional keys you omit fall back to the built-in defaults. Set a
5500
+ * optional: keys you omit fall back to the built-in defaults. Set a
5241
5501
  * key to an empty string to suppress the notice for that reason.
5242
5502
  */
5243
5503
  stopReasonNotice?: Partial<Record<StopReasonKind, string>>;
@@ -5330,12 +5590,12 @@ type AgentWidgetConfig = {
5330
5590
  */
5331
5591
  approval?: AgentWidgetApprovalConfig | false;
5332
5592
  /**
5333
- * WebMCP consume page-registered tools (`document.modelContext.registerTool`).
5593
+ * WebMCP: consume page-registered tools (`document.modelContext.registerTool`).
5334
5594
  * When `enabled`, the widget installs `@mcp-b/webmcp-polyfill`, snapshots the
5335
5595
  * registry on every dispatch, ships it as `clientTools[]`, and executes
5336
5596
  * returned `webmcp:*` tool calls with confirm-by-default gating.
5337
5597
  *
5338
- * Server-side policy on the chat surface is the source of truth these
5598
+ * Server-side policy on the chat surface is the source of truth: these
5339
5599
  * fields layer on top.
5340
5600
  *
5341
5601
  * @example
@@ -5369,7 +5629,7 @@ type AgentWidgetConfig = {
5369
5629
  * This hook runs synchronously and must return the (potentially modified) state.
5370
5630
  *
5371
5631
  * Returning `{ state, open: true }` also signals that the widget panel should
5372
- * open after initialization useful when injecting a post-navigation message
5632
+ * open after initialization: useful when injecting a post-navigation message
5373
5633
  * that the user should immediately see.
5374
5634
  *
5375
5635
  * @example
@@ -5688,7 +5948,7 @@ type AgentWidgetConfig = {
5688
5948
  * Setting this to `false` is the explicit kill-switch: it disables UI-state
5689
5949
  * persistence **and** message-history persistence. When `false`, any
5690
5950
  * `storageAdapter` you configure is ignored and the default localStorage
5691
- * adapter is not created no chat history is read or written. Pass `true`
5951
+ * adapter is not created: no chat history is read or written. Pass `true`
5692
5952
  * (or omit) to keep the default behavior of persisting messages via the
5693
5953
  * configured `storageAdapter` (or the built-in localStorage adapter).
5694
5954
  *
@@ -5717,7 +5977,7 @@ type AgentWidgetConfig = {
5717
5977
  *
5718
5978
  * @example
5719
5979
  * ```typescript
5720
- * // Ephemeral widget no message history written anywhere
5980
+ * // Ephemeral widget: no message history written anywhere
5721
5981
  * config: {
5722
5982
  * persistState: false
5723
5983
  * }
@@ -5784,7 +6044,7 @@ type AgentWidgetApproval = {
5784
6044
  * Agent-authored justification for this specific call (the agent's own
5785
6045
  * claim about its intent, extracted server-side from the reserved
5786
6046
  * `_approvalReason` parameter). Render it attributed to the agent and as
5787
- * plain text it is approver context, not a system statement.
6047
+ * plain text: it is approver context, not a system statement.
5788
6048
  */
5789
6049
  reason?: string;
5790
6050
  parameters?: unknown;
@@ -5794,16 +6054,16 @@ type AgentWidgetMessageVariant = "assistant" | "reasoning" | "tool" | "approval"
5794
6054
  /**
5795
6055
  * Per-turn / per-step stop reason emitted by the runtime on
5796
6056
  * `agent_turn_complete` and `step_complete` SSE events. The vocabulary is
5797
- * owned by the upstream Runtype API do not extend without coordination.
6057
+ * owned by the upstream Runtype API: do not extend without coordination.
5798
6058
  *
5799
- * - `end_turn` natural completion (no affordance needed)
5800
- * - `max_tool_calls` agent loop tripped the configured tool-call ceiling
5801
- * - `length` provider hit max output tokens
5802
- * - `content_filter` provider content filter intervened
5803
- * - `error` provider/runtime error (prefer existing error rendering)
5804
- * - `unknown` explicitly reported but uninformative
6059
+ * - `end_turn`: natural completion (no affordance needed)
6060
+ * - `max_tool_calls`: agent loop tripped the configured tool-call ceiling
6061
+ * - `length`: provider hit max output tokens
6062
+ * - `content_filter`: provider content filter intervened
6063
+ * - `error`: provider/runtime error (prefer existing error rendering)
6064
+ * - `unknown`: explicitly reported but uninformative
5805
6065
  *
5806
- * Absent (`undefined`) means "not reported" distinct from `'unknown'`.
6066
+ * Absent (`undefined`) means "not reported": distinct from `'unknown'`.
5807
6067
  */
5808
6068
  type StopReasonKind = RuntypeStopReasonKind;
5809
6069
  /**
@@ -5973,7 +6233,7 @@ type InjectMessageOptions = {
5973
6233
  voiceProcessing?: boolean;
5974
6234
  /**
5975
6235
  * Raw structured payload (typically a JSON string) representing the
5976
- * full directive that produced this message e.g. `{ "text": "...",
6236
+ * full directive that produced this message: e.g. `{ "text": "...",
5977
6237
  * "component": "Foo", "props": {...} }`.
5978
6238
  *
5979
6239
  * Mirrors the field populated by stream parsers during normal LLM
@@ -6005,7 +6265,7 @@ type InjectUserMessageOptions = Omit<InjectMessageOptions, "role">;
6005
6265
  type InjectSystemMessageOptions = Omit<InjectMessageOptions, "role">;
6006
6266
  /**
6007
6267
  * Options for injecting an assistant message that renders as a component
6008
- * directive sugar over `injectAssistantMessage` for the common case of
6268
+ * directive: sugar over `injectAssistantMessage` for the common case of
6009
6269
  * "render this registered component, same as if the LLM had emitted it".
6010
6270
  *
6011
6271
  * Equivalent to calling `injectAssistantMessage({ content: text, rawContent:
@@ -6146,8 +6406,8 @@ declare class AgentWidgetClient {
6146
6406
  * Refresh config in place WITHOUT tearing down the live connection or the
6147
6407
  * WebMCP bridge. `AgentWidgetSession.updateConfig` calls this when only
6148
6408
  * connection-irrelevant fields changed (theme, copy, layout, suggestions, …),
6149
- * so a UI update that lands mid-turn e.g. a `webmcp:*` tool restyling the
6150
- * widget while the agent's turn is still streaming doesn't abandon the
6409
+ * so a UI update that lands mid-turn: e.g. a `webmcp:*` tool restyling the
6410
+ * widget while the agent's turn is still streaming: doesn't abandon the
6151
6411
  * in-flight stream/resume. Connection or request-shaping changes (apiUrl,
6152
6412
  * clientToken, webmcp, headers, parser, …) take the full client rebuild path
6153
6413
  * in the session instead, which is the only place the bridge is recreated.
@@ -6155,7 +6415,7 @@ declare class AgentWidgetClient {
6155
6415
  * Only the live-read `config` is refreshed (e.g. `iterationDisplay`); the
6156
6416
  * constructor-derived request-shaping fields (apiUrl, headers, parser,
6157
6417
  * contextProviders, middleware, …) are left untouched because the session
6158
- * routes any change to those down the full-rebuild path instead so they are
6418
+ * routes any change to those down the full-rebuild path instead, so they are
6159
6419
  * guaranteed unchanged here. The `webMcpBridge` instance and its
6160
6420
  * installed-polyfill memo are deliberately preserved, which keeps any
6161
6421
  * in-flight resolve alive.
@@ -6182,7 +6442,7 @@ declare class AgentWidgetClient {
6182
6442
  * WebMCP: execute a returned `webmcp:<name>` tool call against the page's
6183
6443
  * registry and return the normalized MCP-shaped result for `/resume`. The
6184
6444
  * bridge handles confirm-bubble gating, the 30s timeout, error
6185
- * normalization, and `signal`-driven abort callers never see throws.
6445
+ * normalization, and `signal`-driven abort: callers never see throws.
6186
6446
  *
6187
6447
  * Returns `null` when WebMCP is not enabled on this client (signal to the
6188
6448
  * session that it should fall back to the legacy local-tool resume path,
@@ -6326,10 +6586,10 @@ declare class AgentWidgetClient {
6326
6586
  * Routes by mode:
6327
6587
  * - **client-token mode**: POST `${apiBase}/v1/client/resume` (the
6328
6588
  * session-authenticated sibling of `/v1/client/chat`; runtypelabs/core#3889),
6329
- * with the active `sessionId` in the body and no Bearer key a browser
6589
+ * with the active `sessionId` in the body and no Bearer key: a browser
6330
6590
  * client-token page holds no secret. `clientTools` are already persisted
6331
6591
  * server-side from the dispatch turn, so only `toolOutputs` is re-sent.
6332
- * - **dispatch / proxy mode**: POST `${apiUrl}/resume` Runtype mounts
6592
+ * - **dispatch / proxy mode**: POST `${apiUrl}/resume`: Runtype mounts
6333
6593
  * resume as a child of `/v1/dispatch`, so the URL is `${apiUrl}/resume`,
6334
6594
  * and proxies follow the same shape (`/api/chat/dispatch/resume`).
6335
6595
  *
@@ -6354,6 +6614,75 @@ declare class AgentWidgetClient {
6354
6614
  private streamResponse;
6355
6615
  }
6356
6616
 
6617
+ declare function createVoiceProvider(config: VoiceConfig): VoiceProvider;
6618
+ declare function createBestAvailableVoiceProvider(config?: Partial<VoiceConfig>): VoiceProvider;
6619
+ declare function isVoiceSupported(config?: Partial<VoiceConfig>): boolean;
6620
+
6621
+ /**
6622
+ * Pick the best available English voice from the browser's voice list.
6623
+ * Prefers high-quality remote/natural voices, then enhanced local voices,
6624
+ * then standard local voices, then any English voice, then the first voice.
6625
+ */
6626
+ declare function pickBestVoice(voices: SpeechSynthesisVoice[]): SpeechSynthesisVoice;
6627
+ interface BrowserSpeechEngineOptions {
6628
+ /** Custom voice picker, used when no exact `voice` name is requested. */
6629
+ pickVoice?: (voices: SpeechSynthesisVoice[]) => SpeechSynthesisVoice;
6630
+ }
6631
+ /** Default `SpeechEngine` backed by the browser Web Speech API. */
6632
+ declare class BrowserSpeechEngine implements SpeechEngine {
6633
+ private options;
6634
+ readonly id = "browser";
6635
+ readonly supportsPause = true;
6636
+ constructor(options?: BrowserSpeechEngineOptions);
6637
+ /** Whether the Web Speech API is available in this environment. */
6638
+ static isSupported(): boolean;
6639
+ speak(request: SpeechRequest, callbacks: SpeechCallbacks): void;
6640
+ pause(): void;
6641
+ resume(): void;
6642
+ stop(): void;
6643
+ }
6644
+
6645
+ interface FallbackSpeechEngineOptions {
6646
+ /**
6647
+ * Called once when the primary engine fails before audio starts and the
6648
+ * fallback takes over — so a silent downgrade is still observable in dev/
6649
+ * telemetry even though the user keeps hearing speech.
6650
+ */
6651
+ onFallback?: (error: Error) => void;
6652
+ }
6653
+
6654
+ type ReadAloudListener = (activeId: string | null, state: ReadAloudState) => void;
6655
+ declare class ReadAloudController {
6656
+ private resolveEngine;
6657
+ private engine;
6658
+ private activeId;
6659
+ private state;
6660
+ private listeners;
6661
+ private generation;
6662
+ constructor(resolveEngine: () => SpeechEngine | Promise<SpeechEngine> | null);
6663
+ /** Whether the active engine supports pause/resume (vs. stop-only). */
6664
+ get supportsPause(): boolean;
6665
+ /** Playback state for a message id (`idle` unless it's the active message). */
6666
+ stateFor(id: string): ReadAloudState;
6667
+ /** The message currently being read aloud, if any. */
6668
+ activeMessageId(): string | null;
6669
+ /** Subscribe to state changes. Returns an unsubscribe function. */
6670
+ onChange(listener: ReadAloudListener): () => void;
6671
+ /**
6672
+ * Primary entry point for the button: cycle this message through
6673
+ * play → pause → resume (or play → stop when the engine can't pause), and
6674
+ * start fresh when a different message is requested.
6675
+ */
6676
+ toggle(id: string, request: SpeechRequest): void;
6677
+ /** Start (or restart) playback for a message, stopping any current playback. */
6678
+ play(id: string, request: SpeechRequest): Promise<void>;
6679
+ /** Stop playback and return to idle. */
6680
+ stop(): void;
6681
+ /** Drop the controller and its engine (called on widget teardown). */
6682
+ destroy(): void;
6683
+ private set;
6684
+ }
6685
+
6357
6686
  type AgentWidgetSessionStatus = "idle" | "connecting" | "connected" | "error";
6358
6687
  type SessionCallbacks = {
6359
6688
  onMessagesChanged: (messages: AgentWidgetMessage[]) => void;
@@ -6390,6 +6719,16 @@ declare class AgentWidgetSession {
6390
6719
  private voiceActive;
6391
6720
  private voiceStatus;
6392
6721
  constructor(config: AgentWidgetConfig | undefined, callbacks: SessionCallbacks);
6722
+ /**
6723
+ * Warm the deferred Runtype TTS engine chunk at init so it's resolved before
6724
+ * the first "Read aloud" click. Module fetch only — no AudioContext (that
6725
+ * still waits for the user gesture on first playback). In the IIFE/CDN build
6726
+ * this fetches the standalone `runtype-tts.js`; in bundler builds the module
6727
+ * is already inlined, so this is a cheap no-op. Errors are swallowed: a failed
6728
+ * prefetch just means the chunk loads on first click instead (or, on a hard
6729
+ * failure, the browser-voice fallback kicks in).
6730
+ */
6731
+ private prefetchRuntypeTts;
6393
6732
  /**
6394
6733
  * Set callback for capturing raw SSE events (forwards to client)
6395
6734
  */
@@ -6433,11 +6772,24 @@ declare class AgentWidgetSession {
6433
6772
  stopVoicePlayback(): void;
6434
6773
  /** Returns true if the barge-in mic stream is alive (hot mic between turns) */
6435
6774
  isBargeInActive(): boolean;
6436
- /** Tear down the barge-in mic pipeline "hang up" the always-on mic */
6775
+ /** Tear down the barge-in mic pipeline: "hang up" the always-on mic */
6437
6776
  deactivateBargeIn(): Promise<void>;
6438
6777
  private pendingVoiceUserMessageId;
6439
6778
  private pendingVoiceAssistantMessageId;
6440
6779
  private ttsSpokenMessageIds;
6780
+ private readAloud;
6781
+ /**
6782
+ * Resolve the speech engine behind read-aloud (and auto-speak):
6783
+ * 1. An explicit `textToSpeech.createEngine` always wins (full BYO control).
6784
+ * 2. `provider: 'runtype'` builds the hosted {@link RuntypeSpeechEngine}
6785
+ * from the widget config (host = `apiUrl`, `agentId`, `clientToken`),
6786
+ * wrapped in a browser {@link FallbackSpeechEngine} unless
6787
+ * `browserFallback: false` — so a missing endpoint or transient failure
6788
+ * degrades to the browser voice instead of erroring, and auto-upgrades to
6789
+ * Runtype voices the day the endpoint ships.
6790
+ * 3. Otherwise the browser Web Speech API engine.
6791
+ */
6792
+ private createSpeechEngine;
6441
6793
  /**
6442
6794
  * Setup voice recognition with the given configuration
6443
6795
  */
@@ -6584,7 +6936,7 @@ declare class AgentWidgetSession {
6584
6936
  injectMessageBatch(optionsList: InjectMessageOptions[]): AgentWidgetMessage[];
6585
6937
  /**
6586
6938
  * Convenience method for injecting a registered component directive as
6587
- * an assistant message the same shape Persona produces from a streamed
6939
+ * an assistant message: the same shape Persona produces from a streamed
6588
6940
  * `{ "text": "...", "component": "...", "props": {...} }` payload.
6589
6941
  *
6590
6942
  * Sets `content` to `text`, `rawContent` to the JSON directive (so
@@ -6679,7 +7031,7 @@ declare class AgentWidgetSession {
6679
7031
  * Flip an `ask_user_question` tool message from awaiting → answered so
6680
7032
  * render passes stop re-mounting its answer-pill sheet. Idempotent.
6681
7033
  * When `answers` is provided, persists the full structured answer Record
6682
- * atomically with the answered flag guarding against later events that
7034
+ * atomically with the answered flag: guarding against later events that
6683
7035
  * could re-emit the tool message and clobber the per-pick persisted
6684
7036
  * answers via top-level merge.
6685
7037
  */
@@ -6700,17 +7052,17 @@ declare class AgentWidgetSession {
6700
7052
  * before a resolve grabs it.
6701
7053
  *
6702
7054
  * Awaits without an `executionId` or `toolCall.id` can't be batched (no key)
6703
- * route them straight to the single-call path, which surfaces the malformed
7055
+ *: route them straight to the single-call path, which surfaces the malformed
6704
7056
  * wire shape via `onError` / an `isError` resume.
6705
7057
  */
6706
7058
  private enqueueWebMcpAwait;
6707
7059
  /**
6708
7060
  * Flush every buffered local-tool await batch, one `/resume` per executionId.
6709
- * Called once a stream ends (`status: idle` / `error`) by then all parallel
7061
+ * Called once a stream ends (`status: idle` / `error`): by then all parallel
6710
7062
  * `step_await`s the stream carried have been collected, even if split across
6711
7063
  * SSE chunks. Deferred via `queueMicrotask` (epoch-guarded) so the idle
6712
7064
  * handler returns first and the stream's end-of-stream teardown (streaming /
6713
- * abortController) settles before a resolve grabs them the same ordering the
7065
+ * abortController) settles before a resolve grabs them: the same ordering the
6714
7066
  * single-call resolve always relied on.
6715
7067
  */
6716
7068
  private scheduleWebMcpBatchFlush;
@@ -6728,7 +7080,7 @@ declare class AgentWidgetSession {
6728
7080
  * Persisted-resolution guard for `suggest_replies`. The in-memory dedupe
6729
7081
  * sets (`webMcpInflightKeys` / `webMcpResolvedKeys`) are cleared by
6730
7082
  * hydrateMessages/clearMessages/cancel, but `suggestRepliesResolved`
6731
- * survives on the stored message so a stale `step_await` re-emit after a
7083
+ * survives on the stored message, so a stale `step_await` re-emit after a
6732
7084
  * hydration must not re-POST `/resume` for an already-resolved call (the
6733
7085
  * historical double-resume failure mode the batching work exists to avoid).
6734
7086
  * Checks the LIVE message first; the handleEvent snapshot is a fresh wire
@@ -6740,7 +7092,7 @@ declare class AgentWidgetSession {
6740
7092
  /**
6741
7093
  * Resolve TWO OR MORE parallel local-tool awaits sharing one paused
6742
7094
  * executionId with a SINGLE `/resume` (core#3878). Each call is executed
6743
- * against the page registry concurrently every gated call renders its own
7095
+ * against the page registry concurrently: every gated call renders its own
6744
7096
  * native approval bubble, and a sibling's confirm Promise never blocks
6745
7097
  * another's execution. Outputs are keyed by per-call `webMcpToolCallId`
6746
7098
  * (server prefers it over tool name; name-keying remains the fallback for
@@ -6760,13 +7112,13 @@ declare class AgentWidgetSession {
6760
7112
  * list, not from this resolve).
6761
7113
  *
6762
7114
  * Triggered automatically from `handleEvent` when a `step_await`-derived
6763
- * message arrives for such a tool the user does not click a pill; the
7115
+ * message arrives for such a tool: the user does not click a pill; the
6764
7116
  * bridge's confirm-bubble gate (WebMCP only) is the only interactive
6765
7117
  * surface.
6766
7118
  *
6767
7119
  * Idempotent on the message's `toolCall.id`: re-emits of the same step_await
6768
7120
  * (e.g. from message coalescing) won't double-fire `tool.execute`. Failure
6769
- * modes declined, timed out, throw, unknown tool all resolve into a
7121
+ * modes, declined, timed out, throw, unknown tool, all resolve into a
6770
7122
  * `{ isError: true, content: [...] }` payload that resumes the dispatch
6771
7123
  * cleanly so the agent can recover.
6772
7124
  */
@@ -6789,8 +7141,7 @@ declare class AgentWidgetSession {
6789
7141
  * resolve owns a dedicated AbortController (chained/parallel resolves don't
6790
7142
  * share one), so we abort them individually; the aborts propagate into the
6791
7143
  * bridge's execute race and into each `/resume` fetch signal. Bumping
6792
- * `webMcpEpoch` strands any resolve still deferred in a queued microtask
6793
- * it captured the prior epoch and bails before installing a fresh
7144
+ * `webMcpEpoch` strands any resolve still deferred in a queued microtask: * it captured the prior epoch and bails before installing a fresh
6794
7145
  * controller, so it can't escape this teardown. Called from every stop /
6795
7146
  * new-turn boundary (cancel, clearMessages, hydrateMessages, sendMessage).
6796
7147
  */
@@ -6816,19 +7167,26 @@ declare class AgentWidgetSession {
6816
7167
  * if text-to-speech is enabled in the config.
6817
7168
  */
6818
7169
  private speakLatestAssistantMessage;
6819
- /**
6820
- * Speak text using the Web Speech API.
6821
- * Cancels any in-progress speech before starting.
6822
- */
6823
- private speak;
6824
7170
  /**
6825
7171
  * Pick the best available English voice from a list of SpeechSynthesisVoices.
6826
7172
  * Prefers high-quality remote/natural voices, then enhanced local voices,
6827
- * then standard local voices.
7173
+ * then standard local voices. Retained for backwards compatibility; delegates
7174
+ * to the browser speech engine's picker.
6828
7175
  */
6829
7176
  static pickBestVoice(voices: SpeechSynthesisVoice[]): SpeechSynthesisVoice;
6830
7177
  /**
6831
- * Stop any in-progress text-to-speech playback.
7178
+ * Toggle the per-message "Read aloud" action: play → pause → resume (or
7179
+ * play → stop when the engine can't pause). Speaks the assistant message's
7180
+ * text via the configured speech engine (browser Web Speech API by default,
7181
+ * or a hosted engine from `textToSpeech.createEngine`).
7182
+ */
7183
+ toggleReadAloud(messageId: string): void;
7184
+ /** Current read-aloud playback state for a message (`idle` unless active). */
7185
+ getReadAloudState(messageId: string): ReadAloudState;
7186
+ /** Subscribe to read-aloud state changes. Returns an unsubscribe function. */
7187
+ onReadAloudChange(listener: ReadAloudListener): () => void;
7188
+ /**
7189
+ * Stop any in-progress text-to-speech / read-aloud playback.
6832
7190
  */
6833
7191
  stopSpeaking(): void;
6834
7192
  private appendMessage;
@@ -6928,7 +7286,7 @@ type Controller = {
6928
7286
  injectMessageBatch: (optionsList: InjectMessageOptions[]) => AgentWidgetMessage[];
6929
7287
  /**
6930
7288
  * Convenience method for injecting an assistant message that renders as a
6931
- * registered component same shape Persona produces from a streamed
7289
+ * registered component: same shape Persona produces from a streamed
6932
7290
  * `{ "text": "...", "component": "...", "props": {...} }` payload.
6933
7291
  */
6934
7292
  injectComponentDirective: (options: InjectComponentDirectiveOptions) => AgentWidgetMessage;
@@ -6944,6 +7302,10 @@ type Controller = {
6944
7302
  off: <K extends keyof AgentWidgetControllerEventMap>(event: K, handler: (payload: AgentWidgetControllerEventMap[K]) => void) => void;
6945
7303
  isOpen: () => boolean;
6946
7304
  isVoiceActive: () => boolean;
7305
+ toggleReadAloud: (messageId: string) => void;
7306
+ stopReadAloud: () => void;
7307
+ getReadAloudState: (messageId: string) => ReadAloudState;
7308
+ onReadAloudChange: (listener: (activeId: string | null, state: ReadAloudState) => void) => () => void;
6947
7309
  getState: () => AgentWidgetStateSnapshot;
6948
7310
  showCSATFeedback: (options?: Partial<CSATFeedbackOptions>) => void;
6949
7311
  showNPSFeedback: (options?: Partial<NPSFeedbackOptions>) => void;
@@ -7007,7 +7369,7 @@ declare const ASK_USER_QUESTION_TOOL_NAME = "ask_user_question";
7007
7369
  declare const isAskUserQuestionMessage: (message: AgentWidgetMessage) => boolean;
7008
7370
  /**
7009
7371
  * Parse an `ask_user_question` tool-variant message into a partial payload.
7010
- * Safe to call mid-stream will walk the tool call's `chunks` via
7372
+ * Safe to call mid-stream: will walk the tool call's `chunks` via
7011
7373
  * `partial-json` and return `{ payload: null, complete: false }` when there
7012
7374
  * isn't enough data yet. `complete` flips to `true` once the tool call
7013
7375
  * reports status `"complete"`.
@@ -7020,13 +7382,13 @@ declare const parseAskUserQuestionPayload: (message: AgentWidgetMessage) => {
7020
7382
  };
7021
7383
  /**
7022
7384
  * Create the small in-transcript stub for an `ask_user_question` tool call.
7023
- * The stub is passive the interactive sheet is mounted separately into
7385
+ * The stub is passive: the interactive sheet is mounted separately into
7024
7386
  * the composer overlay via `ensureAskUserQuestionSheet`.
7025
7387
  */
7026
7388
  declare const createAskUserQuestionBubble: (message: AgentWidgetMessage, config?: AgentWidgetConfig) => HTMLElement;
7027
7389
  /**
7028
7390
  * Mount or update the interactive answer-pill sheet for a given message.
7029
- * Idempotent if a sheet already exists for the tool-call id, it is hydrated
7391
+ * Idempotent: if a sheet already exists for the tool-call id, it is hydrated
7030
7392
  * in-place instead of remounted, so streaming updates don't flicker.
7031
7393
  */
7032
7394
  declare const ensureAskUserQuestionSheet: (message: AgentWidgetMessage, config: AgentWidgetConfig | undefined, overlay: HTMLElement | null | undefined) => void;
@@ -7040,7 +7402,7 @@ declare const removeAskUserQuestionSheet: (overlay: HTMLElement | null | undefin
7040
7402
  * Built-in `ask_user_question` client tool.
7041
7403
  *
7042
7404
  * The widget can advertise this tool to the agent on every dispatch via
7043
- * `clientTools[]` (set `features.askUserQuestion.expose: true`) the same
7405
+ * `clientTools[]` (set `features.askUserQuestion.expose: true`): the same
7044
7406
  * wire surface WebMCP page tools ride. The server registers it as a LOCAL
7045
7407
  * tool under its bare name (`origin: 'sdk'` tools are not `webmcp:`-prefixed),
7046
7408
  * so when the model calls it the execution pauses with a `step_await`
@@ -7051,13 +7413,12 @@ declare const removeAskUserQuestionSheet: (overlay: HTMLElement | null | undefin
7051
7413
  * This replaces the previous integrator burden of hand-declaring the tool in
7052
7414
  * a flow's `runtimeTools` and keeping that schema in sync with the renderer.
7053
7415
  * Flows that already declare `ask_user_question` server-side should leave
7054
- * `expose` off the model would otherwise see the tool twice.
7416
+ * `expose` off: the model would otherwise see the tool twice.
7055
7417
  */
7056
7418
 
7057
7419
  /**
7058
7420
  * JSON Schema for the tool's parameters. Mirrors {@link AskUserQuestionPayload}
7059
- * the shape `parseAskUserQuestionPayload` hydrates the answer sheet from
7060
- * so the schema the model is held to and the schema the renderer expects can
7421
+ *, the shape `parseAskUserQuestionPayload` hydrates the answer sheet from, * so the schema the model is held to and the schema the renderer expects can
7061
7422
  * never drift.
7062
7423
  */
7063
7424
  declare const ASK_USER_QUESTION_PARAMETERS_SCHEMA: {
@@ -7084,7 +7445,7 @@ declare const ASK_USER_QUESTION_PARAMETERS_SCHEMA: {
7084
7445
  readonly type: "array";
7085
7446
  readonly minItems: 2;
7086
7447
  readonly maxItems: 4;
7087
- readonly description: "2-4 distinct choices. Do NOT add an \"Other\" option free text is automatic.";
7448
+ readonly description: "2-4 distinct choices. Do NOT add an \"Other\" option: free text is automatic.";
7088
7449
  readonly items: {
7089
7450
  readonly type: "object";
7090
7451
  readonly properties: {
@@ -7132,8 +7493,7 @@ declare const ASK_USER_QUESTION_CLIENT_TOOL: ClientToolDefinition;
7132
7493
  *
7133
7494
  * Each tool is gated on BOTH of its feature flags: `expose` opts the tool
7134
7495
  * into the agent's catalog, and `enabled !== false` guarantees the widget can
7135
- * actually render UI (and, for fire-and-forget tools, auto-resume) for it
7136
- * exposing a tool with its feature disabled would park the execution on a
7496
+ * actually render UI (and, for fire-and-forget tools, auto-resume) for it: * exposing a tool with its feature disabled would park the execution on a
7137
7497
  * generic tool bubble with no way to advance.
7138
7498
  */
7139
7499
  declare const builtInClientToolsForDispatch: (config: AgentWidgetConfig | undefined) => ClientToolDefinition[];
@@ -7142,11 +7502,11 @@ declare const builtInClientToolsForDispatch: (config: AgentWidgetConfig | undefi
7142
7502
  * Built-in `suggest_replies` client tool.
7143
7503
  *
7144
7504
  * The widget can advertise this tool to the agent on every dispatch via
7145
- * `clientTools[]` (set `features.suggestReplies.expose: true`) the same
7505
+ * `clientTools[]` (set `features.suggestReplies.expose: true`): the same
7146
7506
  * wire surface as `ask_user_question` and WebMCP page tools. When the model
7147
7507
  * calls it, the execution pauses with a `step_await`
7148
7508
  * (`awaitReason: "local_tool_required"`); unlike `ask_user_question`, the
7149
- * widget resolves it FIRE-AND-FORGET it renders the suggestions as tappable
7509
+ * widget resolves it FIRE-AND-FORGET: it renders the suggestions as tappable
7150
7510
  * chips above the composer and immediately resumes the execution with a
7151
7511
  * canned "shown" result, so the agent's turn completes without waiting on the
7152
7512
  * user. Tapping a chip sends its text verbatim as the user's next message.
@@ -7237,15 +7597,15 @@ declare const createWidgetHostLayout: (target: HTMLElement, config?: AgentWidget
7237
7597
  * with no MCP-B-only extensions. The spec standardizes the *producer* side;
7238
7598
  * Persona is an in-page *consumer*, so it reads the registry via the
7239
7599
  * producer-facing preview API:
7240
- * - `getTools()` async; returns `{ name, description, inputSchema }` where
7600
+ * - `getTools()`: async; returns `{ name, description, inputSchema }` where
7241
7601
  * `inputSchema` is a JSON *string*. Annotations are not exposed here.
7242
- * - `executeTool(toolInfo, inputArgsJson, { signal })` async; validates args
7602
+ * - `executeTool(toolInfo, inputArgsJson, { signal })`: async; validates args
7243
7603
  * against the tool's schema, runs `execute()`, and returns the raw result as
7244
7604
  * a JSON *string* (or `null` for `undefined`). Honors `signal` for abort.
7245
7605
  *
7246
7606
  * The polyfill auto-installs `document.modelContext` at module-evaluation time,
7247
7607
  * so it is imported *dynamically* and only when `config.webmcp.enabled === true`
7248
- * a static import would install the global for every widget consumer,
7608
+ *: a static import would install the global for every widget consumer,
7249
7609
  * including those that never opted into WebMCP.
7250
7610
  *
7251
7611
  * Confirm model: every `webmcp:*` call goes through one confirm gate before
@@ -7279,7 +7639,7 @@ declare class WebMcpBridge {
7279
7639
  setConfirmHandler(handler: WebMcpConfirmHandler | null): void;
7280
7640
  /**
7281
7641
  * `true` when the bridge can both snapshot the registry AND execute returned
7282
- * tool calls i.e. the polyfill is installed and `document.modelContext`
7642
+ * tool calls: i.e. the polyfill is installed and `document.modelContext`
7283
7643
  * exposes the consumer surface (`getTools` / `executeTool`). Native browsers
7284
7644
  * that ship `document.modelContext` satisfy this too.
7285
7645
  *
@@ -7290,7 +7650,7 @@ declare class WebMcpBridge {
7290
7650
  isOperational(): boolean;
7291
7651
  /**
7292
7652
  * Per-turn snapshot for `dispatch.clientTools[]`. Returns the JSON-only
7293
- * surface `execute` stays client-side, reached later via `executeToolCall`.
7653
+ * surface: `execute` stays client-side, reached later via `executeToolCall`.
7294
7654
  *
7295
7655
  * Async because the strict polyfill's `getTools()` is async. Both payload
7296
7656
  * builders in `client.ts` already `await`, so this adds no new ceremony.
@@ -7300,7 +7660,7 @@ declare class WebMcpBridge {
7300
7660
  * Execute a `webmcp:<name>` tool call returned by the agent and return the
7301
7661
  * normalized MCP-shaped result for `/resume`.
7302
7662
  *
7303
- * Failure modes all return `{ isError: true, content: [...] }` rather than
7663
+ * Failure modes: all return `{ isError: true, content: [...] }` rather than
7304
7664
  * throwing, so the dispatch can resume cleanly:
7305
7665
  * - bridge not operational
7306
7666
  * - tool not in registry (e.g. unmounted between snapshot and call)
@@ -7324,7 +7684,7 @@ declare class WebMcpBridge {
7324
7684
  * widget consumers that never enable WebMCP.
7325
7685
  *
7326
7686
  * Producer pages should still install the polyfill themselves (or import it)
7327
- * before registering tools Persona's install is a fallback, and a page that
7687
+ * before registering tools: Persona's install is a fallback, and a page that
7328
7688
  * registers tools at load before Persona's first dispatch needs the global to
7329
7689
  * already exist.
7330
7690
  */
@@ -7562,14 +7922,14 @@ declare function validateImageFile(file: File, acceptedTypes?: string[], maxSize
7562
7922
  * Enriched DOM context collection for providing richer page information to AI.
7563
7923
  *
7564
7924
  * Captures interactive elements, stable CSS selectors, ARIA roles, data attributes,
7565
- * and visibility state giving the LLM much better context than basic className/innerText.
7925
+ * and visibility state: giving the LLM much better context than basic className/innerText.
7566
7926
  *
7567
7927
  * ## Modes
7568
7928
  *
7569
7929
  * - **structured** (default): collects candidates, scores them with optional {@link ParseRule}
7570
7930
  * hooks, then applies `maxElements`. Rich containers (e.g. product cards) can surface
7571
7931
  * before unrelated static noise.
7572
- * - **simple**: legacy behavior cap during traversal, interactive-first ordering, no rule
7932
+ * - **simple**: legacy behavior: cap during traversal, interactive-first ordering, no rule
7573
7933
  * scoring or {@link EnrichedPageElement.formattedSummary}.
7574
7934
  */
7575
7935
  interface EnrichedPageElement {
@@ -7601,7 +7961,7 @@ type DomContextMode = "simple" | "structured";
7601
7961
  interface ParseOptionsConfig {
7602
7962
  /**
7603
7963
  * `structured` (default): score candidates with rules, then apply `maxElements`.
7604
- * `simple`: legacy traversal cap and ordering only rules are ignored (with a warning
7964
+ * `simple`: legacy traversal cap and ordering only: rules are ignored (with a warning
7605
7965
  * if `rules` was passed on {@link DomContextOptions}).
7606
7966
  */
7607
7967
  mode?: DomContextMode;
@@ -7680,7 +8040,7 @@ declare function generateStableSelector(el: HTMLElement): string;
7680
8040
  * - **Default (structured):** walks up to `maxCandidates` nodes, scores with
7681
8041
  * {@link defaultParseRules} (or `rules`), suppresses redundant descendants when a
7682
8042
  * formatting rule matches, then keeps the top `maxElements` by score (DOM order tie-break).
7683
- * - **simple:** legacy path stops once `maxElements` nodes are collected during traversal
8043
+ * - **simple:** legacy path: stops once `maxElements` nodes are collected during traversal
7684
8044
  * and sorts interactive before static.
7685
8045
  *
7686
8046
  * Pass `options: { mode: "simple" }` to disable rules. If `mode` is `simple` and `rules` is
@@ -8196,7 +8556,7 @@ interface ComboButtonHandle {
8196
8556
  destroy: () => void;
8197
8557
  }
8198
8558
  /**
8199
- * Creates a combo button a clickable label with a chevron that opens a dropdown menu.
8559
+ * Creates a combo button: a clickable label with a chevron that opens a dropdown menu.
8200
8560
  *
8201
8561
  * The entire label + chevron area acts as a single interactive unit with an optional
8202
8562
  * hover pill effect. Clicking anywhere on it toggles the dropdown.
@@ -8780,10 +9140,6 @@ declare const getHeaderLayout: (layoutName: string) => HeaderLayoutRenderer;
8780
9140
  */
8781
9141
  declare const buildHeaderWithLayout: (config: AgentWidgetConfig, layoutConfig?: AgentWidgetHeaderLayoutConfig, context?: Partial<HeaderLayoutContext>) => HeaderElements;
8782
9142
 
8783
- declare function createVoiceProvider(config: VoiceConfig): VoiceProvider;
8784
- declare function createBestAvailableVoiceProvider(config?: Partial<VoiceConfig>): VoiceProvider;
8785
- declare function isVoiceSupported(config?: Partial<VoiceConfig>): boolean;
8786
-
8787
9143
  type CodeFormat = "esm" | "script-installer" | "script-manual" | "script-advanced" | "react-component" | "react-advanced";
8788
9144
  /**
8789
9145
  * Hook code templates for code generation.
@@ -8983,4 +9339,4 @@ interface DemoCarouselHandle {
8983
9339
  }
8984
9340
  declare function createDemoCarousel(container: HTMLElement, options: DemoCarouselOptions): DemoCarouselHandle;
8985
9341
 
8986
- export { ASK_USER_QUESTION_CLIENT_TOOL, ASK_USER_QUESTION_PARAMETERS_SCHEMA, ASK_USER_QUESTION_TOOL_NAME, type AgentConfig, type AgentExecutionState, type AgentLoopConfig, type AgentMessageMetadata, type AgentRequestOptions, type AgentToolsConfig, type AgentWidgetActionContext, type AgentWidgetActionEventPayload, type AgentWidgetActionHandler, type AgentWidgetActionHandlerResult, type AgentWidgetActionParser, type AgentWidgetAgentRequestPayload, type AgentWidgetApproval, type AgentWidgetApprovalConfig, type AgentWidgetApprovalDecisionOptions, type AgentWidgetArtifactsFeature, type AgentWidgetArtifactsLayoutConfig, type AgentWidgetAskUserQuestionFeature, type AgentWidgetAskUserQuestionStyles, type AgentWidgetAttachmentsConfig, type AgentWidgetAvatarConfig, AgentWidgetClient, type AgentWidgetComposerConfig, type AgentWidgetConfig, type AgentWidgetContextProvider, type AgentWidgetContextProviderContext, type AgentWidgetController, type AgentWidgetControllerEventMap, type AgentWidgetCustomFetch, type AgentWidgetDockConfig, type AgentWidgetEvent, type AgentWidgetFeatureFlags, type AgentWidgetHeaderLayoutConfig, type AgentWidgetHeadersFunction, type AgentWidgetInitHandle, type AgentWidgetInitOptions, type AgentWidgetLauncherConfig, type AgentWidgetLayoutConfig, type AgentWidgetLoadingIndicatorConfig, type AgentWidgetMarkdownConfig, type AgentWidgetMarkdownOptions, type AgentWidgetMarkdownRendererOverrides, type AgentWidgetMessage, type AgentWidgetMessageActionsConfig, type AgentWidgetMessageFeedback, type AgentWidgetMessageLayoutConfig, type AgentWidgetParsedAction, type AgentWidgetPlugin, type AgentWidgetRequestPayload, type AgentWidgetSSEEventParser, type AgentWidgetSSEEventResult, AgentWidgetSession, type AgentWidgetSessionStatus, type AgentWidgetStreamAnimationBuffer, type AgentWidgetStreamAnimationBuiltinType, type AgentWidgetStreamAnimationFeature, type AgentWidgetStreamAnimationPlaceholder, type AgentWidgetStreamAnimationType, type AgentWidgetStreamParser, type AgentWidgetStreamParserResult, type AgentWidgetTimestampConfig, type AgentWidgetWebMcpConfig, type ArtifactConfigPayload, type ArtifactPaneTokens, type ArtifactTabTokens, type ArtifactToolbarTokens, type AskUserQuestionOption, type AskUserQuestionPayload, type AskUserQuestionPrompt, AttachmentManager, type AttachmentManagerConfig, type BorderScale, type CSATFeedbackOptions, type ClientChatRequest, type ClientFeedbackRequest, type ClientFeedbackType, type ClientInitResponse, type ClientSession, type ClientToolDefinition, type CodeFormat, type CodeGeneratorHooks, type CodeGeneratorOptions, type ColorPalette, type ColorShade, type ComboButtonHandle, type ComponentContext, type ComponentDirective, type ComponentRenderer, type ComponentTokens, type ComposerBuildContext, type ComposerElements, type ContentPart, type CreateComboButtonOptions, type CreateDropdownOptions, type CreateIconButtonOptions, type CreateLabelButtonOptions, type CreateStandardBubbleOptions, type CreateThemeOptions, type CreateToggleGroupOptions, DEFAULT_COMPONENTS, DEFAULT_FLOATING_LAUNCHER_MAX_WIDTH, DEFAULT_FLOATING_LAUNCHER_WIDTH, DEFAULT_PALETTE, DEFAULT_SEMANTIC, DEFAULT_WIDGET_CONFIG, type DeepPartial, type DemoCarouselHandle, type DemoCarouselItem, type DemoCarouselOptions, type DomContextMode, type DomContextOptions, type DropdownMenuHandle, type DropdownMenuItem, type EnrichedPageElement, type EventStreamBadgeColor, type EventStreamConfig, type EventStreamPayloadRenderContext, type EventStreamRowRenderContext, type EventStreamToolbarRenderContext, type EventStreamViewRenderContext, type FormatEnrichedContextOptions, type HeaderBuildContext, type HeaderElements, type HeaderLayoutContext, type HeaderLayoutRenderer, type HeaderRenderContext, type IconButtonTokens, type IconName, type IdleIndicatorRenderContext, type ImageContentPart, type InjectAssistantMessageOptions, type InjectComponentDirectiveOptions, type InjectMessageOptions, type InjectSystemMessageOptions, type InjectUserMessageOptions, type LabelButtonTokens, type LoadingIndicatorRenderContext, type LoadingIndicatorRenderer, type MarkdownProcessorOptions, type MessageActionCallbacks, type MessageContent, type MessageRenderContext, type MessageTransform, type NPSFeedbackOptions, PRESETS, PRESET_FULLSCREEN, PRESET_MINIMAL, PRESET_SHOP, type ParseOptionsConfig, type ParseRule, type PendingAttachment, type PersonaArtifactKind, type PersonaArtifactManualUpsert, type PersonaArtifactRecord, type PersonaTheme, type PersonaThemePlugin, type RadiusScale, type RuleScoringContext, type RuntypeAgentSSEEvent, type RuntypeAgentTurnCompleteEvent, type RuntypeClientChatRequest, type RuntypeClientChatStreamEvent, type RuntypeClientFeedbackRequest, type RuntypeClientFeedbackResponse, type RuntypeClientFeedbackType, type RuntypeClientInitRequest, type RuntypeClientInitResponse, type RuntypeClientResumeRequest, type RuntypeClientResumeStreamEvent, type RuntypeDispatchSSEEvent, type RuntypeFlowSSEEvent, type RuntypeStepCompleteEvent, type RuntypeStopReasonKind, type RuntypeStreamEventOf, type SSEEventCallback, type SSEEventRecord, SUGGEST_REPLIES_CLIENT_TOOL, SUGGEST_REPLIES_PARAMETERS_SCHEMA, SUGGEST_REPLIES_TOOL_NAME, type SanitizeFunction, type SemanticColors, type SemanticSpacing, type SemanticTypography, type ShadowScale, type SlotRenderContext, type SlotRenderer, type SpacingScale, type StreamAnimationContext, type StreamAnimationPlugin, THEME_ZONES, type TextContentPart, type ThemeValidationError, type ThemeValidationResult, type ThemeZone, type ToggleGroupHandle, type ToggleGroupItem, type ToggleGroupTokens, type TokenReference, type TypographyScale, VERSION, type VoiceConfig, type VoiceProvider, type VoiceResult, type VoiceStatus, WEBMCP_TOOL_PREFIX, WebMcpBridge, type WebMcpConfirmHandler, type WebMcpConfirmInfo, type WebMcpToolResult, type WidgetHostLayout, type WidgetHostLayoutMode, type WidgetLayoutSlot, type WidgetPreset, accessibilityPlugin, animationsPlugin, applyThemeVariables, attachHeaderToContainer, brandPlugin, buildComposer, buildDefaultHeader, buildHeader, buildHeaderWithLayout, buildMinimalHeader, builtInClientToolsForDispatch, collectEnrichedPageContext, componentRegistry, createActionManager, createAgentExperience, createAskUserQuestionBubble, createBestAvailableVoiceProvider, createBubbleWithLayout, createCSATFeedback, createComboButton, createComponentMiddleware, createComponentStreamParser, createDefaultSanitizer, createDemoCarousel, createDirectivePostprocessor, createDropdownMenu, createFlexibleJsonStreamParser, createIconButton, createImagePart, createJsonStreamParser, createLabelButton, createLocalStorageAdapter, createMarkdownProcessor, createMarkdownProcessorFromConfig, createMessageActions, createNPSFeedback, createPlainTextParser, createPlugin, createRegexJsonParser, createStandardBubble, createTextPart, createTheme, createThemeObserver, createToggleGroup, createTypingIndicator, createVoiceProvider, createWidgetHostLayout, createXmlParser, initAgentWidget as default, defaultActionHandlers, defaultJsonActionParser, defaultParseRules, detectColorScheme, directivePostprocessor, ensureAskUserQuestionSheet, escapeHtml, extractComponentDirectiveFromMessage, fileToImagePart, formatEnrichedContext, generateAssistantMessageId, generateCodeSnippet, generateMessageId, generateStableSelector, generateUserMessageId, getActiveTheme, getColorScheme, getDisplayText, getHeaderLayout, getImageParts, getPreset, hasComponentDirective, hasImages, headerLayouts, highContrastPlugin, initAgentWidget, isAskUserQuestionMessage, isComponentDirectiveType, isDockedMountMode, isSuggestRepliesMessage, isVoiceSupported, isWebMcpToolName, latestAgentSuggestions, listRegisteredStreamAnimations, markdownPostprocessor, mergeWithDefaults, normalizeContent, parseAskUserQuestionPayload, parseSuggestRepliesPayload, pluginRegistry, reducedMotionPlugin, registerStreamAnimationPlugin, removeAskUserQuestionSheet, renderComponentDirective, renderLoadingIndicatorWithFallback, renderLucideIcon, resolveDockConfig, resolveSanitizer, resolveTokens, stripWebMcpPrefix, themeToCssVariables, unregisterStreamAnimationPlugin, validateImageFile, validateTheme };
9342
+ export { ASK_USER_QUESTION_CLIENT_TOOL, ASK_USER_QUESTION_PARAMETERS_SCHEMA, ASK_USER_QUESTION_TOOL_NAME, type AgentConfig, type AgentExecutionState, type AgentLoopConfig, type AgentMessageMetadata, type AgentRequestOptions, type AgentToolsConfig, type AgentWidgetActionContext, type AgentWidgetActionEventPayload, type AgentWidgetActionHandler, type AgentWidgetActionHandlerResult, type AgentWidgetActionParser, type AgentWidgetAgentRequestPayload, type AgentWidgetApproval, type AgentWidgetApprovalConfig, type AgentWidgetApprovalDecisionOptions, type AgentWidgetArtifactsFeature, type AgentWidgetArtifactsLayoutConfig, type AgentWidgetAskUserQuestionFeature, type AgentWidgetAskUserQuestionStyles, type AgentWidgetAttachmentsConfig, type AgentWidgetAvatarConfig, AgentWidgetClient, type AgentWidgetComposerConfig, type AgentWidgetConfig, type AgentWidgetContextProvider, type AgentWidgetContextProviderContext, type AgentWidgetController, type AgentWidgetControllerEventMap, type AgentWidgetCustomFetch, type AgentWidgetDockConfig, type AgentWidgetEvent, type AgentWidgetFeatureFlags, type AgentWidgetHeaderLayoutConfig, type AgentWidgetHeadersFunction, type AgentWidgetInitHandle, type AgentWidgetInitOptions, type AgentWidgetLauncherConfig, type AgentWidgetLayoutConfig, type AgentWidgetLoadingIndicatorConfig, type AgentWidgetMarkdownConfig, type AgentWidgetMarkdownOptions, type AgentWidgetMarkdownRendererOverrides, type AgentWidgetMessage, type AgentWidgetMessageActionsConfig, type AgentWidgetMessageFeedback, type AgentWidgetMessageLayoutConfig, type AgentWidgetParsedAction, type AgentWidgetPlugin, type AgentWidgetReadAloudEvent, type AgentWidgetRequestPayload, type AgentWidgetSSEEventParser, type AgentWidgetSSEEventResult, AgentWidgetSession, type AgentWidgetSessionStatus, type AgentWidgetStreamAnimationBuffer, type AgentWidgetStreamAnimationBuiltinType, type AgentWidgetStreamAnimationFeature, type AgentWidgetStreamAnimationPlaceholder, type AgentWidgetStreamAnimationType, type AgentWidgetStreamParser, type AgentWidgetStreamParserResult, type AgentWidgetTimestampConfig, type AgentWidgetVoiceStatusEvent, type AgentWidgetWebMcpConfig, type ArtifactConfigPayload, type ArtifactPaneTokens, type ArtifactTabTokens, type ArtifactToolbarTokens, type AskUserQuestionOption, type AskUserQuestionPayload, type AskUserQuestionPrompt, AttachmentManager, type AttachmentManagerConfig, type BorderScale, BrowserSpeechEngine, type BrowserSpeechEngineOptions, type CSATFeedbackOptions, type ClientChatRequest, type ClientFeedbackRequest, type ClientFeedbackType, type ClientInitResponse, type ClientSession, type ClientToolDefinition, type CodeFormat, type CodeGeneratorHooks, type CodeGeneratorOptions, type ColorPalette, type ColorShade, type ComboButtonHandle, type ComponentContext, type ComponentDirective, type ComponentRenderer, type ComponentTokens, type ComposerBuildContext, type ComposerElements, type ContentPart, type CreateComboButtonOptions, type CreateDropdownOptions, type CreateIconButtonOptions, type CreateLabelButtonOptions, type CreateStandardBubbleOptions, type CreateThemeOptions, type CreateToggleGroupOptions, DEFAULT_COMPONENTS, DEFAULT_FLOATING_LAUNCHER_MAX_WIDTH, DEFAULT_FLOATING_LAUNCHER_WIDTH, DEFAULT_PALETTE, DEFAULT_SEMANTIC, DEFAULT_WIDGET_CONFIG, type DeepPartial, type DemoCarouselHandle, type DemoCarouselItem, type DemoCarouselOptions, type DomContextMode, type DomContextOptions, type DropdownMenuHandle, type DropdownMenuItem, type EnrichedPageElement, type EventStreamBadgeColor, type EventStreamConfig, type EventStreamPayloadRenderContext, type EventStreamRowRenderContext, type EventStreamToolbarRenderContext, type EventStreamViewRenderContext, type FallbackSpeechEngineOptions, type FormatEnrichedContextOptions, type HeaderBuildContext, type HeaderElements, type HeaderLayoutContext, type HeaderLayoutRenderer, type HeaderRenderContext, type IconButtonTokens, type IconName, type IdleIndicatorRenderContext, type ImageContentPart, type InjectAssistantMessageOptions, type InjectComponentDirectiveOptions, type InjectMessageOptions, type InjectSystemMessageOptions, type InjectUserMessageOptions, type LabelButtonTokens, type LoadingIndicatorRenderContext, type LoadingIndicatorRenderer, type MarkdownProcessorOptions, type MessageActionCallbacks, type MessageContent, type MessageRenderContext, type MessageTransform, type NPSFeedbackOptions, PRESETS, PRESET_FULLSCREEN, PRESET_MINIMAL, PRESET_SHOP, type ParseOptionsConfig, type ParseRule, type PcmStreamPlayer, type PendingAttachment, type PersonaArtifactKind, type PersonaArtifactManualUpsert, type PersonaArtifactRecord, type PersonaTheme, type PersonaThemePlugin, type RadiusScale, ReadAloudController, type ReadAloudListener, type ReadAloudState, type RuleScoringContext, type RuntypeAgentSSEEvent, type RuntypeAgentTurnCompleteEvent, type RuntypeClientChatRequest, type RuntypeClientChatStreamEvent, type RuntypeClientFeedbackRequest, type RuntypeClientFeedbackResponse, type RuntypeClientFeedbackType, type RuntypeClientInitRequest, type RuntypeClientInitResponse, type RuntypeClientResumeRequest, type RuntypeClientResumeStreamEvent, type RuntypeDispatchSSEEvent, type RuntypeFlowSSEEvent, type RuntypeStepCompleteEvent, type RuntypeStopReasonKind, type RuntypeStreamEventOf, type SSEEventCallback, type SSEEventRecord, SUGGEST_REPLIES_CLIENT_TOOL, SUGGEST_REPLIES_PARAMETERS_SCHEMA, SUGGEST_REPLIES_TOOL_NAME, type SanitizeFunction, type SemanticColors, type SemanticSpacing, type SemanticTypography, type ShadowScale, type SlotRenderContext, type SlotRenderer, type SpacingScale, type SpeechCallbacks, type SpeechEngine, type SpeechRequest, type StreamAnimationContext, type StreamAnimationPlugin, THEME_ZONES, type TextContentPart, type ThemeValidationError, type ThemeValidationResult, type ThemeZone, type ToggleGroupHandle, type ToggleGroupItem, type ToggleGroupTokens, type TokenReference, type TypographyScale, VERSION, type VoiceConfig, type VoiceMetrics, type VoicePlaybackEngine, type VoiceProvider, type VoiceResult, type VoiceStatus, WEBMCP_TOOL_PREFIX, WebMcpBridge, type WebMcpConfirmHandler, type WebMcpConfirmInfo, type WebMcpToolResult, type WidgetHostLayout, type WidgetHostLayoutMode, type WidgetLayoutSlot, type WidgetPreset, accessibilityPlugin, animationsPlugin, applyThemeVariables, attachHeaderToContainer, brandPlugin, buildComposer, buildDefaultHeader, buildHeader, buildHeaderWithLayout, buildMinimalHeader, builtInClientToolsForDispatch, collectEnrichedPageContext, componentRegistry, createActionManager, createAgentExperience, createAskUserQuestionBubble, createBestAvailableVoiceProvider, createBubbleWithLayout, createCSATFeedback, createComboButton, createComponentMiddleware, createComponentStreamParser, createDefaultSanitizer, createDemoCarousel, createDirectivePostprocessor, createDropdownMenu, createFlexibleJsonStreamParser, createIconButton, createImagePart, createJsonStreamParser, createLabelButton, createLocalStorageAdapter, createMarkdownProcessor, createMarkdownProcessorFromConfig, createMessageActions, createNPSFeedback, createPlainTextParser, createPlugin, createRegexJsonParser, createStandardBubble, createTextPart, createTheme, createThemeObserver, createToggleGroup, createTypingIndicator, createVoiceProvider, createWidgetHostLayout, createXmlParser, initAgentWidget as default, defaultActionHandlers, defaultJsonActionParser, defaultParseRules, detectColorScheme, directivePostprocessor, ensureAskUserQuestionSheet, escapeHtml, extractComponentDirectiveFromMessage, fileToImagePart, formatEnrichedContext, generateAssistantMessageId, generateCodeSnippet, generateMessageId, generateStableSelector, generateUserMessageId, getActiveTheme, getColorScheme, getDisplayText, getHeaderLayout, getImageParts, getPreset, hasComponentDirective, hasImages, headerLayouts, highContrastPlugin, initAgentWidget, isAskUserQuestionMessage, isComponentDirectiveType, isDockedMountMode, isSuggestRepliesMessage, isVoiceSupported, isWebMcpToolName, latestAgentSuggestions, listRegisteredStreamAnimations, markdownPostprocessor, mergeWithDefaults, normalizeContent, parseAskUserQuestionPayload, parseSuggestRepliesPayload, pickBestVoice, pluginRegistry, reducedMotionPlugin, registerStreamAnimationPlugin, removeAskUserQuestionSheet, renderComponentDirective, renderLoadingIndicatorWithFallback, renderLucideIcon, resolveDockConfig, resolveSanitizer, resolveTokens, stripWebMcpPrefix, themeToCssVariables, unregisterStreamAnimationPlugin, validateImageFile, validateTheme };