@runtypelabs/persona 4.24.0 → 4.26.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 (237) hide show
  1. package/dist/animations/glyph-cycle.d.cts +1 -1
  2. package/dist/animations/glyph-cycle.d.ts +1 -1
  3. package/dist/animations/{types-Db61aI9J.d.cts → types-BwKTZhg9.d.cts} +14 -0
  4. package/dist/animations/{types-Db61aI9J.d.ts → types-BwKTZhg9.d.ts} +14 -0
  5. package/dist/animations/wipe.d.cts +1 -1
  6. package/dist/animations/wipe.d.ts +1 -1
  7. package/dist/animations-extra.d.cts +14 -0
  8. package/dist/animations-extra.d.ts +14 -0
  9. package/dist/approval-ui-QAKWNFNM.js +1 -0
  10. package/dist/approval-ui.cjs +2 -2
  11. package/dist/approval-ui.d.cts +243 -8
  12. package/dist/approval-ui.d.ts +243 -8
  13. package/dist/approval-ui.js +2 -2
  14. package/dist/{artifacts-ui-IGB5YKLO.js → artifacts-ui-NJGMM27I.js} +1 -1
  15. package/dist/artifacts-ui.cjs +4 -4
  16. package/dist/artifacts-ui.d.cts +243 -8
  17. package/dist/artifacts-ui.d.ts +243 -8
  18. package/dist/artifacts-ui.js +5 -5
  19. package/dist/chunk-2ANTRKTV.js +1 -0
  20. package/dist/chunk-4HPTPUC6.js +1 -0
  21. package/dist/chunk-6V3MNEKB.js +1 -0
  22. package/dist/chunk-HGUCGM3K.js +9 -0
  23. package/dist/chunk-IO5VVUKP.js +3 -0
  24. package/dist/chunk-J4J3Y2P2.js +1 -0
  25. package/dist/chunk-K6HKIP5K.js +1 -0
  26. package/dist/chunk-K7NA7G7J.js +1 -0
  27. package/dist/chunk-MXUTS3LB.js +1 -0
  28. package/dist/chunk-PDPVORUF.js +1 -0
  29. package/dist/chunk-QPPJUSZH.js +1 -0
  30. package/dist/chunk-QRKGQPU7.js +1 -0
  31. package/dist/chunk-S6PBWE75.js +1 -0
  32. package/dist/chunk-T7QM7YMF.js +1 -0
  33. package/dist/chunk-TR2H475E.js +1 -0
  34. package/dist/chunk-UPO4GUFC.js +1 -0
  35. package/dist/chunk-ZC66NAIR.js +1 -0
  36. package/dist/client-history-YPEG45Q4.js +1 -0
  37. package/dist/client-history.js +1 -0
  38. package/dist/client-stream-42FOI3EC.js +4 -0
  39. package/dist/client-stream.js +5 -0
  40. package/dist/codegen.cjs +1 -1
  41. package/dist/codegen.js +1 -1
  42. package/dist/context-mentions-E7HJYWO6.js +161 -0
  43. package/dist/{context-mentions-inline-I2RDEBAK.js → context-mentions-inline-QVESLW55.js} +1 -1
  44. package/dist/context-mentions.cjs +7 -7
  45. package/dist/context-mentions.d.cts +243 -8
  46. package/dist/context-mentions.d.ts +243 -8
  47. package/dist/context-mentions.js +8 -8
  48. package/dist/event-stream-view-FOIJHFQO.js +1 -0
  49. package/dist/event-stream-view.cjs +1 -1
  50. package/dist/event-stream-view.d.cts +246 -31
  51. package/dist/event-stream-view.d.ts +246 -31
  52. package/dist/event-stream-view.js +1 -1
  53. package/dist/forms-ui.d.cts +295 -667
  54. package/dist/forms-ui.d.ts +295 -667
  55. package/dist/history-shell-QDQ44PSE.js +3 -0
  56. package/dist/history-shell.js +3 -0
  57. package/dist/{history-view-BD6OXLNA.js → history-view-NCFBI5GR.js} +2 -2
  58. package/dist/history-view.cjs +2 -2
  59. package/dist/history-view.d.cts +35 -1
  60. package/dist/history-view.d.ts +35 -1
  61. package/dist/history-view.js +2 -2
  62. package/dist/index.cjs +80 -74
  63. package/dist/index.cjs.map +1 -1
  64. package/dist/index.d.cts +301 -738
  65. package/dist/index.d.ts +301 -738
  66. package/dist/index.global.js +3 -215
  67. package/dist/index.global.js.map +1 -1
  68. package/dist/index.js +81 -75
  69. package/dist/index.js.map +1 -1
  70. package/dist/install.global.js +1 -1
  71. package/dist/install.global.js.map +1 -1
  72. package/dist/launcher.global.js +3 -67
  73. package/dist/launcher.global.js.map +1 -1
  74. package/dist/markdown-parsers.js +22 -22
  75. package/dist/runtype-tts-entry-NFBVWR7N.js +1 -0
  76. package/dist/runtype-tts.js +1 -1
  77. package/dist/session-actions-ISSKSI66.js +1 -0
  78. package/dist/session-actions.js +1 -0
  79. package/dist/session-reconnect.d.cts +243 -8
  80. package/dist/session-reconnect.d.ts +243 -8
  81. package/dist/smart-dom-reader.cjs +13 -13
  82. package/dist/smart-dom-reader.d.cts +243 -8
  83. package/dist/smart-dom-reader.d.ts +243 -8
  84. package/dist/smart-dom-reader.js +11 -11
  85. package/dist/theme-editor-preview.cjs +116 -98
  86. package/dist/theme-editor-preview.d.cts +245 -8
  87. package/dist/theme-editor-preview.d.ts +245 -8
  88. package/dist/theme-editor-preview.js +49 -54
  89. package/dist/theme-editor.cjs +2 -2
  90. package/dist/theme-editor.d.cts +244 -23
  91. package/dist/theme-editor.d.ts +244 -23
  92. package/dist/theme-editor.js +2 -2
  93. package/dist/theme-reference.d.cts +14 -0
  94. package/dist/theme-reference.d.ts +14 -0
  95. package/dist/ui-extras-entry-WAYFKVNW.js +3 -0
  96. package/dist/ui-extras.js +72 -0
  97. package/dist/voice-runtime-UOQOFAFY.js +17 -0
  98. package/dist/voice-runtime.cjs +17 -1
  99. package/dist/voice-runtime.d.cts +11643 -192
  100. package/dist/voice-runtime.d.ts +11643 -192
  101. package/dist/voice-runtime.js +17 -1
  102. package/dist/voice-worklet-player.cjs +19 -4
  103. package/dist/voice-worklet-player.d.cts +9 -10
  104. package/dist/voice-worklet-player.d.ts +9 -10
  105. package/dist/voice-worklet-player.js +19 -4
  106. package/dist/webmcp-polyfill.js +1 -1
  107. package/dist/webmcp-runtime-V6ZWW3PI.js +6 -0
  108. package/dist/webmcp-runtime.cjs +2 -2
  109. package/dist/webmcp-runtime.d.cts +1 -33
  110. package/dist/webmcp-runtime.d.ts +1 -33
  111. package/dist/webmcp-runtime.js +2 -2
  112. package/dist/widget.css +1 -1
  113. package/package.json +11 -5
  114. package/src/approval-paused-tool-settle.test.ts +221 -0
  115. package/src/client-approve.test.ts +311 -0
  116. package/src/client-history-eager.ts +9 -0
  117. package/src/client-history-loader.ts +23 -0
  118. package/src/client-history.ts +579 -0
  119. package/src/client-resume.ts +177 -0
  120. package/src/client-stream-eager.ts +12 -0
  121. package/src/client-stream-loader.ts +25 -0
  122. package/src/client-stream.ts +1880 -0
  123. package/src/client.test.ts +31 -1
  124. package/src/client.ts +293 -2607
  125. package/src/components/approval-actions.test.ts +27 -0
  126. package/src/components/approval-actions.ts +27 -3
  127. package/src/components/message-bubble.test.ts +19 -0
  128. package/src/components/message-bubble.ts +2 -0
  129. package/src/components/registry.ts +6 -6
  130. package/src/components/tool-bubble.test.ts +9 -0
  131. package/src/components/tool-bubble.ts +1 -0
  132. package/src/history-shell-bundle.test.ts +54 -0
  133. package/src/history-shell-eager.ts +12 -0
  134. package/src/history-shell-loader.ts +27 -0
  135. package/src/history-shell.ts +2362 -0
  136. package/src/history-view-loader.ts +2 -0
  137. package/src/history-view.ts +3 -0
  138. package/src/index-core.ts +8 -0
  139. package/src/index-global.ts +90 -248
  140. package/src/index.ts +13 -0
  141. package/src/install.ts +6 -4
  142. package/src/internal/runtype-history-provider.test.ts +1 -0
  143. package/src/internal/runtype-history-provider.ts +28 -13
  144. package/src/plugins/registry.ts +8 -8
  145. package/src/session-actions-chunk.test.ts +55 -0
  146. package/src/session-actions-eager.ts +11 -0
  147. package/src/session-actions-loader.ts +37 -0
  148. package/src/session-actions.ts +909 -0
  149. package/src/session-history.test.ts +3 -1
  150. package/src/session.ts +875 -1530
  151. package/src/session.voice.test.ts +1241 -5
  152. package/src/styles/widget.css +58 -0
  153. package/src/theme-editor/state.ts +91 -91
  154. package/src/types.ts +269 -5
  155. package/src/ui-ask-user-sheet.ts +382 -0
  156. package/src/ui-extras-eager.ts +10 -0
  157. package/src/ui-extras-entry.ts +9 -0
  158. package/src/ui-extras-loader.ts +26 -0
  159. package/src/ui.artifact-rail-resize.test.ts +2 -1
  160. package/src/ui.ask-user-chunk.test.ts +93 -0
  161. package/src/ui.history-chunk.test.ts +2 -1
  162. package/src/ui.history-config-provider.test.ts +2 -1
  163. package/src/ui.history-confirm-fallback.test.ts +142 -0
  164. package/src/ui.history-controller.test.ts +2 -1
  165. package/src/ui.history-lifecycle.test.ts +2 -1
  166. package/src/ui.history-render-hooks.test.ts +2 -1
  167. package/src/ui.history-shell.test.ts +2 -1
  168. package/src/ui.rail-overlay.test.ts +2 -1
  169. package/src/ui.rail-resize.test.ts +2 -1
  170. package/src/ui.rail-trigger-pending.test.ts +2 -1
  171. package/src/ui.ts +399 -2770
  172. package/src/ui.voice-prewarm.test.ts +222 -0
  173. package/src/utils/attachment-manager.ts +67 -67
  174. package/src/utils/constants.ts +3 -0
  175. package/src/utils/context-mention-controller.ts +323 -323
  176. package/src/utils/context-mention-manager.ts +40 -40
  177. package/src/utils/context-mention-orchestrator.ts +28 -0
  178. package/src/utils/event-stream-buffer.ts +50 -50
  179. package/src/utils/event-stream-store.ts +43 -43
  180. package/src/utils/throughput-tracker.ts +34 -34
  181. package/src/utils/virtual-scroller.ts +67 -67
  182. package/src/utils/visitor-store.test.ts +50 -0
  183. package/src/utils/visitor-store.ts +23 -5
  184. package/src/voice/__fixtures__/voice-wire/README.md +1 -0
  185. package/src/voice/__fixtures__/voice-wire/client/cancel.json +3 -0
  186. package/src/voice/__fixtures__/voice-wire/client/context.json +4 -0
  187. package/src/voice/__fixtures__/voice-wire/client/delegation_result.json +6 -0
  188. package/src/voice/__fixtures__/voice-wire/client/delegation_update.json +6 -0
  189. package/src/voice/__fixtures__/voice-wire/client/ping.json +3 -0
  190. package/src/voice/__fixtures__/voice-wire/client/playback_progress.json +5 -0
  191. package/src/voice/__fixtures__/voice-wire/client/start.json +3 -0
  192. package/src/voice/__fixtures__/voice-wire/server/artifact.json +11 -0
  193. package/src/voice/__fixtures__/voice-wire/server/attached.json +4 -0
  194. package/src/voice/__fixtures__/voice-wire/server/audio_clear.json +4 -0
  195. package/src/voice/__fixtures__/voice-wire/server/audio_end.json +3 -0
  196. package/src/voice/__fixtures__/voice-wire/server/delegation_cancelled.json +5 -0
  197. package/src/voice/__fixtures__/voice-wire/server/delegation_completed.json +8 -0
  198. package/src/voice/__fixtures__/voice-wire/server/delegation_started.json +15 -0
  199. package/src/voice/__fixtures__/voice-wire/server/error.json +6 -0
  200. package/src/voice/__fixtures__/voice-wire/server/metrics.json +10 -0
  201. package/src/voice/__fixtures__/voice-wire/server/pong.json +3 -0
  202. package/src/voice/__fixtures__/voice-wire/server/session_config.json +16 -0
  203. package/src/voice/__fixtures__/voice-wire/server/transcript_final.json +7 -0
  204. package/src/voice/__fixtures__/voice-wire/server/transcript_interim.json +4 -0
  205. package/src/voice/__fixtures__/voice-wire/server/transcript_partial.json +6 -0
  206. package/src/voice/__fixtures__/voice-wire/server/transcript_update.json +10 -0
  207. package/src/voice/__fixtures__/voice-wire/server/warning.json +5 -0
  208. package/src/voice/audio-playback-manager.test.ts +57 -0
  209. package/src/voice/audio-playback-manager.ts +120 -98
  210. package/src/voice/browser-voice-provider.ts +37 -37
  211. package/src/voice/fallback-speech-engine.ts +22 -16
  212. package/src/voice/keyed-voice-transcript.ts +314 -0
  213. package/src/voice/mic-state-styles.ts +182 -0
  214. package/src/voice/read-aloud-controller.ts +46 -44
  215. package/src/voice/runtype-speech-engine.ts +35 -33
  216. package/src/voice/runtype-voice-provider.ts +856 -164
  217. package/src/voice/session-voice-wiring.ts +266 -0
  218. package/src/voice/voice-delegation.test.ts +71 -0
  219. package/src/voice/voice-delegation.ts +364 -0
  220. package/src/voice/voice-turn-tracker.ts +6 -6
  221. package/src/voice/voice.test.ts +1250 -7
  222. package/src/voice/worklet-playback-engine.test.ts +81 -0
  223. package/src/voice/worklet-playback-engine.ts +21 -3
  224. package/src/voice-runtime-loader.ts +4 -1
  225. package/src/voice-runtime.ts +7 -0
  226. package/src/webmcp-runtime-entry.ts +41 -39
  227. package/dist/approval-ui-3NMYNXBD.js +0 -1
  228. package/dist/chunk-5EIIHQLQ.js +0 -1
  229. package/dist/chunk-7CO4T5KB.js +0 -1
  230. package/dist/chunk-EFJBUH5F.js +0 -1
  231. package/dist/chunk-R2TMIMDI.js +0 -3
  232. package/dist/chunk-UTVLOTWB.js +0 -9
  233. package/dist/context-mentions-45MODWOY.js +0 -161
  234. package/dist/event-stream-view-GL3ADRY2.js +0 -1
  235. package/dist/runtype-tts-entry-UJAEF7NZ.js +0 -1
  236. package/dist/voice-runtime-EFR3R5ES.js +0 -1
  237. package/dist/webmcp-runtime-JI7T4QYF.js +0 -6
@@ -6720,6 +6720,22 @@ type AgentWidgetStatusIndicatorConfig = {
6720
6720
  /** Status text while a reconnect attempt is in flight. */
6721
6721
  resumingText?: string;
6722
6722
  };
6723
+ /** Built-in `voiceRecognition.prewarm` triggers. See {@link AgentWidgetVoiceRecognitionConfig.prewarm}. */
6724
+ type AgentWidgetVoicePrewarmTrigger = 'hover';
6725
+ /**
6726
+ * Custom `voiceRecognition.prewarm` trigger. Runs while the composer has a mic
6727
+ * button, and again when the button is rebuilt or `update()` swaps in a
6728
+ * different function. Call `warm()` whenever the visitor shows intent to talk
6729
+ * (it is safe to call repeatedly). Return a cleanup to run on replacement.
6730
+ */
6731
+ type AgentWidgetVoicePrewarmHook = (context: {
6732
+ /** Fire-and-forget voice warm-up; latched and error-swallowing. */
6733
+ warm: () => void;
6734
+ /** The composer's current mic button. */
6735
+ micButton: HTMLButtonElement;
6736
+ /** The widget's mount element. */
6737
+ mount: HTMLElement;
6738
+ }) => void | (() => void);
6723
6739
  type AgentWidgetVoiceRecognitionConfig = {
6724
6740
  /**
6725
6741
  * Enable the mic button and voice input. The mic still only renders when the
@@ -6785,6 +6801,29 @@ type AgentWidgetVoiceRecognitionConfig = {
6785
6801
  * Fires once per turn after the reply completes.
6786
6802
  */
6787
6803
  onMetrics?: (metrics: VoiceMetrics) => void;
6804
+ /**
6805
+ * Warm the voice path when the visitor shows intent to talk, before the mic
6806
+ * click, so the call starts faster.
6807
+ *
6808
+ * - `'hover'`: when the pointer enters the mic button, it receives focus, or
6809
+ * (on touch) the first pointer-down on it.
6810
+ * - `false`: never.
6811
+ * - A function: custom trigger. Called with `{ warm, micButton, mount }`
6812
+ * while the mic button exists (and again when the button is rebuilt or
6813
+ * `update()` swaps in a different function); call `warm()` whenever you
6814
+ * decide, e.g. when the panel opens. May return a cleanup that runs on
6815
+ * destroy, rebuild, or replacement. Replaces the built-in trigger.
6816
+ *
6817
+ * What `warm()` does depends on the provider: `runtype` fires its prewarm
6818
+ * (see `provider.runtype.prewarmMode`), a `custom` provider's optional
6819
+ * {@link VoiceProvider.prewarm} runs, and the browser (Web Speech) path
6820
+ * starts the client-token session init (as `sessionInit` does), since speech
6821
+ * recognition itself cannot start before the click. Warming is
6822
+ * fire-and-forget, latched, and never surfaces an error or UI state.
6823
+ *
6824
+ * @default 'hover' in client token mode, otherwise `false`
6825
+ */
6826
+ prewarm?: AgentWidgetVoicePrewarmTrigger | AgentWidgetVoicePrewarmHook | false;
6788
6827
  provider?: {
6789
6828
  type: 'browser' | 'runtype' | 'custom';
6790
6829
  browser?: {
@@ -6806,6 +6845,62 @@ type AgentWidgetVoiceRecognitionConfig = {
6806
6845
  * `@runtypelabs/persona/voice-worklet-player` for a jitter-buffered engine.
6807
6846
  */
6808
6847
  createPlaybackEngine?: () => VoicePlaybackEngine | Promise<VoicePlaybackEngine>;
6848
+ /**
6849
+ * How `prewarm()` warms the voice path (see `voiceRecognition.prewarm`).
6850
+ *
6851
+ * - `'request'` (default): a fire-and-forget
6852
+ * `POST {host}/v1/client/agents/{agentId}/voice/prewarm`.
6853
+ * - `'attach'`: open the voice WebSocket ahead of the click without
6854
+ * starting a call; the click then starts the call on that socket. It can
6855
+ * create server work before the visitor clicks, so it is opt-in.
6856
+ * @default 'request'
6857
+ */
6858
+ prewarmMode?: 'request' | 'attach';
6859
+ /**
6860
+ * `'attach'` mode: how long (ms) an attached socket waits for the click
6861
+ * before it closes. The server clamps it to 30000..600000.
6862
+ * @default 30000
6863
+ */
6864
+ attachIdleMs?: number;
6865
+ /**
6866
+ * Full-duplex (speech-to-speech, e.g. GPT-Live) calls: run the turns the
6867
+ * voice model hands off to the agent through this widget's normal chat
6868
+ * pipeline. The spoken request becomes the user message, and the answer
6869
+ * renders as a regular assistant message (streaming, tool and approval
6870
+ * UI, WebMCP page tools, persistence) that the voice model then reads
6871
+ * aloud. Only takes effect when the server supports it (it confirms in
6872
+ * `session_config`); otherwise the agent turn runs on the server and its
6873
+ * spoken reply is transcribed, as before. Set `false` to always keep the
6874
+ * agent turn on the server.
6875
+ * @default true
6876
+ */
6877
+ clientDelegation?: boolean;
6878
+ /**
6879
+ * Full-duplex calls: extra context for the voice model (for example the
6880
+ * page the visitor is on), sent after the chat history as of call start.
6881
+ * The frame goes out once, when the visitor finishes their first
6882
+ * utterance (or at the first agent hand-off). A function is
6883
+ * called at call start and may be async. This text is capped at 4000 characters and the whole frame
6884
+ * (history included) at 8000. Sent only to servers that accept call
6885
+ * context (they announce it in `session_config`).
6886
+ */
6887
+ callContext?: string | (() => string | Promise<string>);
6888
+ /**
6889
+ * Full-duplex calls with client delegation: how long a tool approval
6890
+ * that a spoken request raised may wait before it is declined as
6891
+ * expired (and the voice model says so). Server-side approval gates
6892
+ * keep their own timeout too. Hanging up never declines it: the
6893
+ * approval card in the chat stays usable. Capped at 540000 (9 minutes),
6894
+ * under the server's 10-minute delegation deadline.
6895
+ * @default 300000
6896
+ */
6897
+ approvalTimeoutMs?: number;
6898
+ /**
6899
+ * Speech-to-speech calls: the one-line notice shown in the composer
6900
+ * status area when the call starts. `false` hides it.
6901
+ * @default "You're talking to an AI assistant. Voice is processed by OpenAI."
6902
+ */
6903
+ disclosureText?: string | false;
6809
6904
  /** @deprecated No-op on the realtime path: the server's STT owns turn-taking. */
6810
6905
  pauseDuration?: number;
6811
6906
  /** @deprecated No-op on the realtime path: the server's STT owns turn-taking. */
@@ -7044,6 +7139,13 @@ interface VoicePlaybackEngine {
7044
7139
  onFinished(callback: () => void): void;
7045
7140
  /** Release all audio resources. */
7046
7141
  destroy(): Promise<void> | void;
7142
+ /**
7143
+ * Optional. Speech-to-speech calls stream reply audio with no end-of-stream
7144
+ * marker, so an engine that holds audio below a prebuffer waterline must, while
7145
+ * continuous, release that held tail on its own (e.g. after a short input gap)
7146
+ * instead of waiting for {@link markStreamEnd}. Engines without a prebuffer can omit it.
7147
+ */
7148
+ setContinuousMode?(enabled: boolean): void;
7047
7149
  }
7048
7150
  /**
7049
7151
  * A {@link VoicePlaybackEngine} that also supports pause/resume. Returned by
@@ -7087,14 +7189,23 @@ interface VoiceProvider {
7087
7189
  * Register a callback for incremental transcript updates during a voice turn.
7088
7190
  * `isFinal=false` is a live interim update (user partials, or assistant deltas
7089
7191
  * on providers that stream them); `isFinal=true` finalizes that role's text.
7090
- * On the realtime `runtype` path, interim updates fire for the `user` only and
7091
- * the `assistant` arrives as a single final. Providers with overlapping turns
7092
- * must include the same turnId on user and assistant finals; without IDs,
7093
- * providers must discard cancelled output before emitting the next user final.
7094
- */
7095
- onTranscript?(callback: (role: 'user' | 'assistant', text: string, isFinal: boolean, metadata?: {
7096
- turnId?: string;
7097
- }) => void): void;
7192
+ * On the classic realtime `runtype` path, interim updates fire for the `user`
7193
+ * only and the `assistant` arrives as a single final; without a turnId the
7194
+ * session assumes strictly alternating turns, and providers must discard
7195
+ * cancelled output before emitting the next user final.
7196
+ *
7197
+ * When `metadata.turnId` is present (full-duplex / speech-to-speech, e.g.
7198
+ * GPT-Live), the session reconciles by `(turnId, role)`: each pair owns one
7199
+ * bubble that later updates replace in place, turns may overlap or arrive in
7200
+ * any order, and no empty assistant placeholder is injected. User and
7201
+ * assistant may share a turnId (a late user bubble then renders above its
7202
+ * reply) or use distinct ones. `metadata.startMs` (call-relative ms when the
7203
+ * utterance began) orders a new bubble among the call's other keyed bubbles;
7204
+ * without it bubbles order by first arrival. After a stop, keyed providers
7205
+ * must drop the cancelled reply's output until the server acknowledges the
7206
+ * cancel: the session renders every reply it receives.
7207
+ */
7208
+ onTranscript?(callback: (role: 'user' | 'assistant', text: string, isFinal: boolean, metadata?: VoiceTranscriptMetadata) => void): void;
7098
7209
  /** Register a callback for per-turn latency metrics (realtime path). */
7099
7210
  onMetrics?(callback: (metrics: VoiceMetrics) => void): void;
7100
7211
  /**
@@ -7115,6 +7226,116 @@ interface VoiceProvider {
7115
7226
  deactivateBargeIn?(): Promise<void>;
7116
7227
  /** Stop playback / cancel in-flight request without starting recording */
7117
7228
  stopPlayback?(): void;
7229
+ /**
7230
+ * Warm the provider ahead of `startListening()` (the widget calls it on mic
7231
+ * intent, see `voiceRecognition.prewarm`). Must be fire-and-forget: never
7232
+ * throw, emit errors or status, or acquire the microphone. May be called
7233
+ * repeatedly; throttle as needed.
7234
+ */
7235
+ prewarm?(): void;
7236
+ /**
7237
+ * Called by the session once after construction with the chat-side surface
7238
+ * a full-duplex provider uses to hand agent turns to the chat pipeline
7239
+ * ({@link VoiceSessionBridge}). Providers without client delegation omit it.
7240
+ */
7241
+ setSessionBridge?(bridge: VoiceSessionBridge): void;
7242
+ /** The AI-disclosure notice for the live call, if one should show (speech-to-speech). */
7243
+ getDisclosure?(): string | null;
7244
+ }
7245
+ /** Metadata on a {@link VoiceProvider.onTranscript} update. */
7246
+ type VoiceTranscriptMetadata = {
7247
+ /** Groups updates that belong to one utterance bubble (full duplex). */
7248
+ turnId?: string;
7249
+ /** Call-relative ms when the utterance began; orders late bubbles. */
7250
+ startMs?: number;
7251
+ /** Call-relative ms of the latest audio this update covers. */
7252
+ endMs?: number;
7253
+ /**
7254
+ * The bubble only captions speech (see `AgentWidgetMessage.voiceCaption`).
7255
+ * The chat pipeline owns the conversation, as with client delegation.
7256
+ */
7257
+ caption?: boolean;
7258
+ };
7259
+ /** An agent turn a full-duplex voice model handed to the widget. */
7260
+ type VoiceDelegationRequest = {
7261
+ /** The voice model's delegation id (`delegation_started.delegationId`). */
7262
+ delegationId: string;
7263
+ /** What the visitor asked, as the voice model heard it. */
7264
+ userText: string;
7265
+ /**
7266
+ * The user transcript utterances `userText` joins, oldest first (the last
7267
+ * is the one it came from). May be empty.
7268
+ */
7269
+ userUtteranceIds: string[];
7270
+ /** The voice model's view of the conversation it delegated from. */
7271
+ messages: Array<{
7272
+ role: string;
7273
+ content: unknown;
7274
+ }>;
7275
+ };
7276
+ /**
7277
+ * How a delegated turn ended, or that it waits on an approval (contract
7278
+ * Amendment 5). `pending_approval` is the only non-terminal status. Open:
7279
+ * a receiver treats an unknown terminal status as `failed`.
7280
+ * - `completed`: the work ran.
7281
+ * - `denied`: the visitor said no (Deny tap, or a spoken decline).
7282
+ * - `timeout`: the approval lapsed (`approvalTimeoutMs`, or the server's own timeout).
7283
+ * - `cancelled`: replaced by a newer request, or abandoned by the system.
7284
+ * - `failed`: an error.
7285
+ */
7286
+ type VoiceDelegationStatus = 'completed' | 'pending_approval' | 'denied' | 'timeout' | 'cancelled' | 'failed' | (string & {});
7287
+ /** The terminal result of a turn that parked on approvals. */
7288
+ type VoiceDelegationFollowUp = {
7289
+ status: VoiceDelegationStatus;
7290
+ /** What to read aloud (Markdown allowed). May be empty: nothing more to say. */
7291
+ text: string;
7292
+ };
7293
+ /** The delegated turn's answer, sent back for the voice model to read aloud. */
7294
+ type VoiceDelegationResult = {
7295
+ /** `pending_approval` when `followUp` is set; otherwise terminal. */
7296
+ status: VoiceDelegationStatus;
7297
+ /** The assistant text (Markdown allowed). */
7298
+ text: string;
7299
+ /**
7300
+ * Set when the turn parked on approvals (`text` then asks for the decision).
7301
+ * Resolves with the terminal result once the visitor decides (or the
7302
+ * approval is replaced, declined by voice, or unanswered for
7303
+ * `approvalTimeoutMs`) and the resumed turn finishes; `null` only when
7304
+ * `signal` aborts first (hang-up, or the server cancelled the delegation).
7305
+ */
7306
+ followUp?: (options: {
7307
+ signal: AbortSignal;
7308
+ approvalTimeoutMs?: number;
7309
+ /** `false`: run only the approval bookkeeping (expiry, supersede); nothing will be read back. @default true */
7310
+ readBack?: boolean;
7311
+ /** The resumed turn stopped on another approval: ask for it too (`text` is its approval script). */
7312
+ onUpdate?: (text: string) => void;
7313
+ }) => Promise<VoiceDelegationFollowUp | null>;
7314
+ };
7315
+ /**
7316
+ * Chat-side surface the session hands a full-duplex provider: the visible
7317
+ * history (for the call-start context) and a way to run a delegated turn
7318
+ * through the normal chat pipeline.
7319
+ */
7320
+ interface VoiceSessionBridge {
7321
+ /** Visible user/assistant messages, oldest first. */
7322
+ getHistory(): Array<{
7323
+ role: 'user' | 'assistant';
7324
+ content: string;
7325
+ }>;
7326
+ /**
7327
+ * Submit the turn as the visitor's message (reusing its transcript bubble)
7328
+ * and resolve with the assistant's final answer once the turn settles.
7329
+ * Waits for any chat turn already in flight first. Never rejects.
7330
+ */
7331
+ runDelegatedTurn(request: VoiceDelegationRequest): Promise<VoiceDelegationResult>;
7332
+ /**
7333
+ * The server dropped this delegation's result (cancelled it, or refused a
7334
+ * late result): its chat answer is no longer spoken, so browser TTS may read it.
7335
+ * `expired`: the server's deadline passed, so its pending approvals are
7336
+ * declined too, as the approval TTL would.
7337
+ */
7338
+ dropDelegation?(delegationId: string, expired?: boolean): void;
7118
7339
  }
7119
7340
  /**
7120
7341
  * Extra context for an approval decision, surfaced to `onDecision` and to the
@@ -9722,6 +9943,11 @@ type AgentWidgetToolCall = {
9722
9943
  startedAt?: number;
9723
9944
  completedAt?: number;
9724
9945
  durationMs?: number;
9946
+ /**
9947
+ * The call paused for an approval that was granted, and the agent re-ran it
9948
+ * as a new tool call: that later call carries the result, this one has none.
9949
+ */
9950
+ superseded?: boolean;
9725
9951
  };
9726
9952
  /**
9727
9953
  * Represents a tool approval request in the chat conversation.
@@ -9743,6 +9969,8 @@ type AgentWidgetApproval = {
9743
9969
  */
9744
9970
  reason?: string;
9745
9971
  parameters?: unknown;
9972
+ /** The paused tool call this approval gates (`approval_start.toolCallId`). */
9973
+ toolCallId?: string;
9746
9974
  resolvedAt?: number;
9747
9975
  };
9748
9976
  type AgentWidgetMessageVariant = "assistant" | "reasoning" | "tool" | "approval";
@@ -9842,6 +10070,13 @@ type AgentWidgetMessage = {
9842
10070
  * }
9843
10071
  */
9844
10072
  voiceProcessing?: boolean;
10073
+ /**
10074
+ * Display-only caption of full-duplex voice speech, such as the voice
10075
+ * model's own words, or something the visitor said that wasn't submitted
10076
+ * as a chat turn. It renders in the transcript but is never sent to the
10077
+ * model as conversation.
10078
+ */
10079
+ voiceCaption?: boolean;
9845
10080
  /**
9846
10081
  * Raw structured payload for this message (e.g., JSON action response).
9847
10082
  * Populated automatically when structured parsers run.
@@ -9957,6 +10192,8 @@ type InjectMessageOptions = {
9957
10192
  * Consumers can detect this in `messageTransform` to render custom UI.
9958
10193
  */
9959
10194
  voiceProcessing?: boolean;
10195
+ /** See {@link AgentWidgetMessage.voiceCaption}. */
10196
+ voiceCaption?: boolean;
9960
10197
  /**
9961
10198
  * Raw structured payload (typically a JSON string) representing the
9962
10199
  * full directive that produced this message: e.g. `{ "text": "...",
@@ -6720,6 +6720,22 @@ type AgentWidgetStatusIndicatorConfig = {
6720
6720
  /** Status text while a reconnect attempt is in flight. */
6721
6721
  resumingText?: string;
6722
6722
  };
6723
+ /** Built-in `voiceRecognition.prewarm` triggers. See {@link AgentWidgetVoiceRecognitionConfig.prewarm}. */
6724
+ type AgentWidgetVoicePrewarmTrigger = 'hover';
6725
+ /**
6726
+ * Custom `voiceRecognition.prewarm` trigger. Runs while the composer has a mic
6727
+ * button, and again when the button is rebuilt or `update()` swaps in a
6728
+ * different function. Call `warm()` whenever the visitor shows intent to talk
6729
+ * (it is safe to call repeatedly). Return a cleanup to run on replacement.
6730
+ */
6731
+ type AgentWidgetVoicePrewarmHook = (context: {
6732
+ /** Fire-and-forget voice warm-up; latched and error-swallowing. */
6733
+ warm: () => void;
6734
+ /** The composer's current mic button. */
6735
+ micButton: HTMLButtonElement;
6736
+ /** The widget's mount element. */
6737
+ mount: HTMLElement;
6738
+ }) => void | (() => void);
6723
6739
  type AgentWidgetVoiceRecognitionConfig = {
6724
6740
  /**
6725
6741
  * Enable the mic button and voice input. The mic still only renders when the
@@ -6785,6 +6801,29 @@ type AgentWidgetVoiceRecognitionConfig = {
6785
6801
  * Fires once per turn after the reply completes.
6786
6802
  */
6787
6803
  onMetrics?: (metrics: VoiceMetrics) => void;
6804
+ /**
6805
+ * Warm the voice path when the visitor shows intent to talk, before the mic
6806
+ * click, so the call starts faster.
6807
+ *
6808
+ * - `'hover'`: when the pointer enters the mic button, it receives focus, or
6809
+ * (on touch) the first pointer-down on it.
6810
+ * - `false`: never.
6811
+ * - A function: custom trigger. Called with `{ warm, micButton, mount }`
6812
+ * while the mic button exists (and again when the button is rebuilt or
6813
+ * `update()` swaps in a different function); call `warm()` whenever you
6814
+ * decide, e.g. when the panel opens. May return a cleanup that runs on
6815
+ * destroy, rebuild, or replacement. Replaces the built-in trigger.
6816
+ *
6817
+ * What `warm()` does depends on the provider: `runtype` fires its prewarm
6818
+ * (see `provider.runtype.prewarmMode`), a `custom` provider's optional
6819
+ * {@link VoiceProvider.prewarm} runs, and the browser (Web Speech) path
6820
+ * starts the client-token session init (as `sessionInit` does), since speech
6821
+ * recognition itself cannot start before the click. Warming is
6822
+ * fire-and-forget, latched, and never surfaces an error or UI state.
6823
+ *
6824
+ * @default 'hover' in client token mode, otherwise `false`
6825
+ */
6826
+ prewarm?: AgentWidgetVoicePrewarmTrigger | AgentWidgetVoicePrewarmHook | false;
6788
6827
  provider?: {
6789
6828
  type: 'browser' | 'runtype' | 'custom';
6790
6829
  browser?: {
@@ -6806,6 +6845,62 @@ type AgentWidgetVoiceRecognitionConfig = {
6806
6845
  * `@runtypelabs/persona/voice-worklet-player` for a jitter-buffered engine.
6807
6846
  */
6808
6847
  createPlaybackEngine?: () => VoicePlaybackEngine | Promise<VoicePlaybackEngine>;
6848
+ /**
6849
+ * How `prewarm()` warms the voice path (see `voiceRecognition.prewarm`).
6850
+ *
6851
+ * - `'request'` (default): a fire-and-forget
6852
+ * `POST {host}/v1/client/agents/{agentId}/voice/prewarm`.
6853
+ * - `'attach'`: open the voice WebSocket ahead of the click without
6854
+ * starting a call; the click then starts the call on that socket. It can
6855
+ * create server work before the visitor clicks, so it is opt-in.
6856
+ * @default 'request'
6857
+ */
6858
+ prewarmMode?: 'request' | 'attach';
6859
+ /**
6860
+ * `'attach'` mode: how long (ms) an attached socket waits for the click
6861
+ * before it closes. The server clamps it to 30000..600000.
6862
+ * @default 30000
6863
+ */
6864
+ attachIdleMs?: number;
6865
+ /**
6866
+ * Full-duplex (speech-to-speech, e.g. GPT-Live) calls: run the turns the
6867
+ * voice model hands off to the agent through this widget's normal chat
6868
+ * pipeline. The spoken request becomes the user message, and the answer
6869
+ * renders as a regular assistant message (streaming, tool and approval
6870
+ * UI, WebMCP page tools, persistence) that the voice model then reads
6871
+ * aloud. Only takes effect when the server supports it (it confirms in
6872
+ * `session_config`); otherwise the agent turn runs on the server and its
6873
+ * spoken reply is transcribed, as before. Set `false` to always keep the
6874
+ * agent turn on the server.
6875
+ * @default true
6876
+ */
6877
+ clientDelegation?: boolean;
6878
+ /**
6879
+ * Full-duplex calls: extra context for the voice model (for example the
6880
+ * page the visitor is on), sent after the chat history as of call start.
6881
+ * The frame goes out once, when the visitor finishes their first
6882
+ * utterance (or at the first agent hand-off). A function is
6883
+ * called at call start and may be async. This text is capped at 4000 characters and the whole frame
6884
+ * (history included) at 8000. Sent only to servers that accept call
6885
+ * context (they announce it in `session_config`).
6886
+ */
6887
+ callContext?: string | (() => string | Promise<string>);
6888
+ /**
6889
+ * Full-duplex calls with client delegation: how long a tool approval
6890
+ * that a spoken request raised may wait before it is declined as
6891
+ * expired (and the voice model says so). Server-side approval gates
6892
+ * keep their own timeout too. Hanging up never declines it: the
6893
+ * approval card in the chat stays usable. Capped at 540000 (9 minutes),
6894
+ * under the server's 10-minute delegation deadline.
6895
+ * @default 300000
6896
+ */
6897
+ approvalTimeoutMs?: number;
6898
+ /**
6899
+ * Speech-to-speech calls: the one-line notice shown in the composer
6900
+ * status area when the call starts. `false` hides it.
6901
+ * @default "You're talking to an AI assistant. Voice is processed by OpenAI."
6902
+ */
6903
+ disclosureText?: string | false;
6809
6904
  /** @deprecated No-op on the realtime path: the server's STT owns turn-taking. */
6810
6905
  pauseDuration?: number;
6811
6906
  /** @deprecated No-op on the realtime path: the server's STT owns turn-taking. */
@@ -7044,6 +7139,13 @@ interface VoicePlaybackEngine {
7044
7139
  onFinished(callback: () => void): void;
7045
7140
  /** Release all audio resources. */
7046
7141
  destroy(): Promise<void> | void;
7142
+ /**
7143
+ * Optional. Speech-to-speech calls stream reply audio with no end-of-stream
7144
+ * marker, so an engine that holds audio below a prebuffer waterline must, while
7145
+ * continuous, release that held tail on its own (e.g. after a short input gap)
7146
+ * instead of waiting for {@link markStreamEnd}. Engines without a prebuffer can omit it.
7147
+ */
7148
+ setContinuousMode?(enabled: boolean): void;
7047
7149
  }
7048
7150
  /**
7049
7151
  * A {@link VoicePlaybackEngine} that also supports pause/resume. Returned by
@@ -7087,14 +7189,23 @@ interface VoiceProvider {
7087
7189
  * Register a callback for incremental transcript updates during a voice turn.
7088
7190
  * `isFinal=false` is a live interim update (user partials, or assistant deltas
7089
7191
  * on providers that stream them); `isFinal=true` finalizes that role's text.
7090
- * On the realtime `runtype` path, interim updates fire for the `user` only and
7091
- * the `assistant` arrives as a single final. Providers with overlapping turns
7092
- * must include the same turnId on user and assistant finals; without IDs,
7093
- * providers must discard cancelled output before emitting the next user final.
7094
- */
7095
- onTranscript?(callback: (role: 'user' | 'assistant', text: string, isFinal: boolean, metadata?: {
7096
- turnId?: string;
7097
- }) => void): void;
7192
+ * On the classic realtime `runtype` path, interim updates fire for the `user`
7193
+ * only and the `assistant` arrives as a single final; without a turnId the
7194
+ * session assumes strictly alternating turns, and providers must discard
7195
+ * cancelled output before emitting the next user final.
7196
+ *
7197
+ * When `metadata.turnId` is present (full-duplex / speech-to-speech, e.g.
7198
+ * GPT-Live), the session reconciles by `(turnId, role)`: each pair owns one
7199
+ * bubble that later updates replace in place, turns may overlap or arrive in
7200
+ * any order, and no empty assistant placeholder is injected. User and
7201
+ * assistant may share a turnId (a late user bubble then renders above its
7202
+ * reply) or use distinct ones. `metadata.startMs` (call-relative ms when the
7203
+ * utterance began) orders a new bubble among the call's other keyed bubbles;
7204
+ * without it bubbles order by first arrival. After a stop, keyed providers
7205
+ * must drop the cancelled reply's output until the server acknowledges the
7206
+ * cancel: the session renders every reply it receives.
7207
+ */
7208
+ onTranscript?(callback: (role: 'user' | 'assistant', text: string, isFinal: boolean, metadata?: VoiceTranscriptMetadata) => void): void;
7098
7209
  /** Register a callback for per-turn latency metrics (realtime path). */
7099
7210
  onMetrics?(callback: (metrics: VoiceMetrics) => void): void;
7100
7211
  /**
@@ -7115,6 +7226,116 @@ interface VoiceProvider {
7115
7226
  deactivateBargeIn?(): Promise<void>;
7116
7227
  /** Stop playback / cancel in-flight request without starting recording */
7117
7228
  stopPlayback?(): void;
7229
+ /**
7230
+ * Warm the provider ahead of `startListening()` (the widget calls it on mic
7231
+ * intent, see `voiceRecognition.prewarm`). Must be fire-and-forget: never
7232
+ * throw, emit errors or status, or acquire the microphone. May be called
7233
+ * repeatedly; throttle as needed.
7234
+ */
7235
+ prewarm?(): void;
7236
+ /**
7237
+ * Called by the session once after construction with the chat-side surface
7238
+ * a full-duplex provider uses to hand agent turns to the chat pipeline
7239
+ * ({@link VoiceSessionBridge}). Providers without client delegation omit it.
7240
+ */
7241
+ setSessionBridge?(bridge: VoiceSessionBridge): void;
7242
+ /** The AI-disclosure notice for the live call, if one should show (speech-to-speech). */
7243
+ getDisclosure?(): string | null;
7244
+ }
7245
+ /** Metadata on a {@link VoiceProvider.onTranscript} update. */
7246
+ type VoiceTranscriptMetadata = {
7247
+ /** Groups updates that belong to one utterance bubble (full duplex). */
7248
+ turnId?: string;
7249
+ /** Call-relative ms when the utterance began; orders late bubbles. */
7250
+ startMs?: number;
7251
+ /** Call-relative ms of the latest audio this update covers. */
7252
+ endMs?: number;
7253
+ /**
7254
+ * The bubble only captions speech (see `AgentWidgetMessage.voiceCaption`).
7255
+ * The chat pipeline owns the conversation, as with client delegation.
7256
+ */
7257
+ caption?: boolean;
7258
+ };
7259
+ /** An agent turn a full-duplex voice model handed to the widget. */
7260
+ type VoiceDelegationRequest = {
7261
+ /** The voice model's delegation id (`delegation_started.delegationId`). */
7262
+ delegationId: string;
7263
+ /** What the visitor asked, as the voice model heard it. */
7264
+ userText: string;
7265
+ /**
7266
+ * The user transcript utterances `userText` joins, oldest first (the last
7267
+ * is the one it came from). May be empty.
7268
+ */
7269
+ userUtteranceIds: string[];
7270
+ /** The voice model's view of the conversation it delegated from. */
7271
+ messages: Array<{
7272
+ role: string;
7273
+ content: unknown;
7274
+ }>;
7275
+ };
7276
+ /**
7277
+ * How a delegated turn ended, or that it waits on an approval (contract
7278
+ * Amendment 5). `pending_approval` is the only non-terminal status. Open:
7279
+ * a receiver treats an unknown terminal status as `failed`.
7280
+ * - `completed`: the work ran.
7281
+ * - `denied`: the visitor said no (Deny tap, or a spoken decline).
7282
+ * - `timeout`: the approval lapsed (`approvalTimeoutMs`, or the server's own timeout).
7283
+ * - `cancelled`: replaced by a newer request, or abandoned by the system.
7284
+ * - `failed`: an error.
7285
+ */
7286
+ type VoiceDelegationStatus = 'completed' | 'pending_approval' | 'denied' | 'timeout' | 'cancelled' | 'failed' | (string & {});
7287
+ /** The terminal result of a turn that parked on approvals. */
7288
+ type VoiceDelegationFollowUp = {
7289
+ status: VoiceDelegationStatus;
7290
+ /** What to read aloud (Markdown allowed). May be empty: nothing more to say. */
7291
+ text: string;
7292
+ };
7293
+ /** The delegated turn's answer, sent back for the voice model to read aloud. */
7294
+ type VoiceDelegationResult = {
7295
+ /** `pending_approval` when `followUp` is set; otherwise terminal. */
7296
+ status: VoiceDelegationStatus;
7297
+ /** The assistant text (Markdown allowed). */
7298
+ text: string;
7299
+ /**
7300
+ * Set when the turn parked on approvals (`text` then asks for the decision).
7301
+ * Resolves with the terminal result once the visitor decides (or the
7302
+ * approval is replaced, declined by voice, or unanswered for
7303
+ * `approvalTimeoutMs`) and the resumed turn finishes; `null` only when
7304
+ * `signal` aborts first (hang-up, or the server cancelled the delegation).
7305
+ */
7306
+ followUp?: (options: {
7307
+ signal: AbortSignal;
7308
+ approvalTimeoutMs?: number;
7309
+ /** `false`: run only the approval bookkeeping (expiry, supersede); nothing will be read back. @default true */
7310
+ readBack?: boolean;
7311
+ /** The resumed turn stopped on another approval: ask for it too (`text` is its approval script). */
7312
+ onUpdate?: (text: string) => void;
7313
+ }) => Promise<VoiceDelegationFollowUp | null>;
7314
+ };
7315
+ /**
7316
+ * Chat-side surface the session hands a full-duplex provider: the visible
7317
+ * history (for the call-start context) and a way to run a delegated turn
7318
+ * through the normal chat pipeline.
7319
+ */
7320
+ interface VoiceSessionBridge {
7321
+ /** Visible user/assistant messages, oldest first. */
7322
+ getHistory(): Array<{
7323
+ role: 'user' | 'assistant';
7324
+ content: string;
7325
+ }>;
7326
+ /**
7327
+ * Submit the turn as the visitor's message (reusing its transcript bubble)
7328
+ * and resolve with the assistant's final answer once the turn settles.
7329
+ * Waits for any chat turn already in flight first. Never rejects.
7330
+ */
7331
+ runDelegatedTurn(request: VoiceDelegationRequest): Promise<VoiceDelegationResult>;
7332
+ /**
7333
+ * The server dropped this delegation's result (cancelled it, or refused a
7334
+ * late result): its chat answer is no longer spoken, so browser TTS may read it.
7335
+ * `expired`: the server's deadline passed, so its pending approvals are
7336
+ * declined too, as the approval TTL would.
7337
+ */
7338
+ dropDelegation?(delegationId: string, expired?: boolean): void;
7118
7339
  }
7119
7340
  /**
7120
7341
  * Extra context for an approval decision, surfaced to `onDecision` and to the
@@ -9722,6 +9943,11 @@ type AgentWidgetToolCall = {
9722
9943
  startedAt?: number;
9723
9944
  completedAt?: number;
9724
9945
  durationMs?: number;
9946
+ /**
9947
+ * The call paused for an approval that was granted, and the agent re-ran it
9948
+ * as a new tool call: that later call carries the result, this one has none.
9949
+ */
9950
+ superseded?: boolean;
9725
9951
  };
9726
9952
  /**
9727
9953
  * Represents a tool approval request in the chat conversation.
@@ -9743,6 +9969,8 @@ type AgentWidgetApproval = {
9743
9969
  */
9744
9970
  reason?: string;
9745
9971
  parameters?: unknown;
9972
+ /** The paused tool call this approval gates (`approval_start.toolCallId`). */
9973
+ toolCallId?: string;
9746
9974
  resolvedAt?: number;
9747
9975
  };
9748
9976
  type AgentWidgetMessageVariant = "assistant" | "reasoning" | "tool" | "approval";
@@ -9842,6 +10070,13 @@ type AgentWidgetMessage = {
9842
10070
  * }
9843
10071
  */
9844
10072
  voiceProcessing?: boolean;
10073
+ /**
10074
+ * Display-only caption of full-duplex voice speech, such as the voice
10075
+ * model's own words, or something the visitor said that wasn't submitted
10076
+ * as a chat turn. It renders in the transcript but is never sent to the
10077
+ * model as conversation.
10078
+ */
10079
+ voiceCaption?: boolean;
9845
10080
  /**
9846
10081
  * Raw structured payload for this message (e.g., JSON action response).
9847
10082
  * Populated automatically when structured parsers run.
@@ -9957,6 +10192,8 @@ type InjectMessageOptions = {
9957
10192
  * Consumers can detect this in `messageTransform` to render custom UI.
9958
10193
  */
9959
10194
  voiceProcessing?: boolean;
10195
+ /** See {@link AgentWidgetMessage.voiceCaption}. */
10196
+ voiceCaption?: boolean;
9960
10197
  /**
9961
10198
  * Raw structured payload (typically a JSON string) representing the
9962
10199
  * full directive that produced this message: e.g. `{ "text": "...",