@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
package/src/types.ts CHANGED
@@ -4614,6 +4614,24 @@ export type AgentWidgetStatusIndicatorConfig = {
4614
4614
  resumingText?: string;
4615
4615
  };
4616
4616
 
4617
+ /** Built-in `voiceRecognition.prewarm` triggers. See {@link AgentWidgetVoiceRecognitionConfig.prewarm}. */
4618
+ export type AgentWidgetVoicePrewarmTrigger = 'hover';
4619
+
4620
+ /**
4621
+ * Custom `voiceRecognition.prewarm` trigger. Runs while the composer has a mic
4622
+ * button, and again when the button is rebuilt or `update()` swaps in a
4623
+ * different function. Call `warm()` whenever the visitor shows intent to talk
4624
+ * (it is safe to call repeatedly). Return a cleanup to run on replacement.
4625
+ */
4626
+ export type AgentWidgetVoicePrewarmHook = (context: {
4627
+ /** Fire-and-forget voice warm-up; latched and error-swallowing. */
4628
+ warm: () => void;
4629
+ /** The composer's current mic button. */
4630
+ micButton: HTMLButtonElement;
4631
+ /** The widget's mount element. */
4632
+ mount: HTMLElement;
4633
+ }) => void | (() => void);
4634
+
4617
4635
  export type AgentWidgetVoiceRecognitionConfig = {
4618
4636
  /**
4619
4637
  * Enable the mic button and voice input. The mic still only renders when the
@@ -4685,6 +4703,30 @@ export type AgentWidgetVoiceRecognitionConfig = {
4685
4703
  */
4686
4704
  onMetrics?: (metrics: VoiceMetrics) => void;
4687
4705
 
4706
+ /**
4707
+ * Warm the voice path when the visitor shows intent to talk, before the mic
4708
+ * click, so the call starts faster.
4709
+ *
4710
+ * - `'hover'`: when the pointer enters the mic button, it receives focus, or
4711
+ * (on touch) the first pointer-down on it.
4712
+ * - `false`: never.
4713
+ * - A function: custom trigger. Called with `{ warm, micButton, mount }`
4714
+ * while the mic button exists (and again when the button is rebuilt or
4715
+ * `update()` swaps in a different function); call `warm()` whenever you
4716
+ * decide, e.g. when the panel opens. May return a cleanup that runs on
4717
+ * destroy, rebuild, or replacement. Replaces the built-in trigger.
4718
+ *
4719
+ * What `warm()` does depends on the provider: `runtype` fires its prewarm
4720
+ * (see `provider.runtype.prewarmMode`), a `custom` provider's optional
4721
+ * {@link VoiceProvider.prewarm} runs, and the browser (Web Speech) path
4722
+ * starts the client-token session init (as `sessionInit` does), since speech
4723
+ * recognition itself cannot start before the click. Warming is
4724
+ * fire-and-forget, latched, and never surfaces an error or UI state.
4725
+ *
4726
+ * @default 'hover' in client token mode, otherwise `false`
4727
+ */
4728
+ prewarm?: AgentWidgetVoicePrewarmTrigger | AgentWidgetVoicePrewarmHook | false;
4729
+
4688
4730
  // Voice provider configuration
4689
4731
  provider?: {
4690
4732
  type: 'browser' | 'runtype' | 'custom';
@@ -4707,6 +4749,62 @@ export type AgentWidgetVoiceRecognitionConfig = {
4707
4749
  * `@runtypelabs/persona/voice-worklet-player` for a jitter-buffered engine.
4708
4750
  */
4709
4751
  createPlaybackEngine?: () => VoicePlaybackEngine | Promise<VoicePlaybackEngine>;
4752
+ /**
4753
+ * How `prewarm()` warms the voice path (see `voiceRecognition.prewarm`).
4754
+ *
4755
+ * - `'request'` (default): a fire-and-forget
4756
+ * `POST {host}/v1/client/agents/{agentId}/voice/prewarm`.
4757
+ * - `'attach'`: open the voice WebSocket ahead of the click without
4758
+ * starting a call; the click then starts the call on that socket. It can
4759
+ * create server work before the visitor clicks, so it is opt-in.
4760
+ * @default 'request'
4761
+ */
4762
+ prewarmMode?: 'request' | 'attach';
4763
+ /**
4764
+ * `'attach'` mode: how long (ms) an attached socket waits for the click
4765
+ * before it closes. The server clamps it to 30000..600000.
4766
+ * @default 30000
4767
+ */
4768
+ attachIdleMs?: number;
4769
+ /**
4770
+ * Full-duplex (speech-to-speech, e.g. GPT-Live) calls: run the turns the
4771
+ * voice model hands off to the agent through this widget's normal chat
4772
+ * pipeline. The spoken request becomes the user message, and the answer
4773
+ * renders as a regular assistant message (streaming, tool and approval
4774
+ * UI, WebMCP page tools, persistence) that the voice model then reads
4775
+ * aloud. Only takes effect when the server supports it (it confirms in
4776
+ * `session_config`); otherwise the agent turn runs on the server and its
4777
+ * spoken reply is transcribed, as before. Set `false` to always keep the
4778
+ * agent turn on the server.
4779
+ * @default true
4780
+ */
4781
+ clientDelegation?: boolean;
4782
+ /**
4783
+ * Full-duplex calls: extra context for the voice model (for example the
4784
+ * page the visitor is on), sent after the chat history as of call start.
4785
+ * The frame goes out once, when the visitor finishes their first
4786
+ * utterance (or at the first agent hand-off). A function is
4787
+ * called at call start and may be async. This text is capped at 4000 characters and the whole frame
4788
+ * (history included) at 8000. Sent only to servers that accept call
4789
+ * context (they announce it in `session_config`).
4790
+ */
4791
+ callContext?: string | (() => string | Promise<string>);
4792
+ /**
4793
+ * Full-duplex calls with client delegation: how long a tool approval
4794
+ * that a spoken request raised may wait before it is declined as
4795
+ * expired (and the voice model says so). Server-side approval gates
4796
+ * keep their own timeout too. Hanging up never declines it: the
4797
+ * approval card in the chat stays usable. Capped at 540000 (9 minutes),
4798
+ * under the server's 10-minute delegation deadline.
4799
+ * @default 300000
4800
+ */
4801
+ approvalTimeoutMs?: number;
4802
+ /**
4803
+ * Speech-to-speech calls: the one-line notice shown in the composer
4804
+ * status area when the call starts. `false` hides it.
4805
+ * @default "You're talking to an AI assistant. Voice is processed by OpenAI."
4806
+ */
4807
+ disclosureText?: string | false;
4710
4808
  /** @deprecated No-op on the realtime path: the server's STT owns turn-taking. */
4711
4809
  pauseDuration?: number;
4712
4810
  /** @deprecated No-op on the realtime path: the server's STT owns turn-taking. */
@@ -4965,6 +5063,13 @@ export interface VoicePlaybackEngine {
4965
5063
  onFinished(callback: () => void): void;
4966
5064
  /** Release all audio resources. */
4967
5065
  destroy(): Promise<void> | void;
5066
+ /**
5067
+ * Optional. Speech-to-speech calls stream reply audio with no end-of-stream
5068
+ * marker, so an engine that holds audio below a prebuffer waterline must, while
5069
+ * continuous, release that held tail on its own (e.g. after a short input gap)
5070
+ * instead of waiting for {@link markStreamEnd}. Engines without a prebuffer can omit it.
5071
+ */
5072
+ setContinuousMode?(enabled: boolean): void;
4968
5073
  }
4969
5074
 
4970
5075
  /**
@@ -5014,6 +5119,18 @@ export type VoiceConfig = {
5014
5119
  * `@runtypelabs/persona/voice-worklet-player` for a jitter-buffered engine.
5015
5120
  */
5016
5121
  createPlaybackEngine?: () => VoicePlaybackEngine | Promise<VoicePlaybackEngine>;
5122
+ /** See `voiceRecognition.provider.runtype.prewarmMode`. @default 'request' */
5123
+ prewarmMode?: 'request' | 'attach';
5124
+ /** See `voiceRecognition.provider.runtype.attachIdleMs`. @default 30000 */
5125
+ attachIdleMs?: number;
5126
+ /** See `voiceRecognition.provider.runtype.clientDelegation`. @default true */
5127
+ clientDelegation?: boolean;
5128
+ /** See `voiceRecognition.provider.runtype.callContext`. */
5129
+ callContext?: string | (() => string | Promise<string>);
5130
+ /** See `voiceRecognition.provider.runtype.approvalTimeoutMs`. @default 300000 (capped at 540000) */
5131
+ approvalTimeoutMs?: number;
5132
+ /** See `voiceRecognition.provider.runtype.disclosureText`. */
5133
+ disclosureText?: string | false;
5017
5134
  /** @deprecated No-op on the realtime path: the server's STT owns turn-taking. */
5018
5135
  pauseDuration?: number;
5019
5136
  /** @deprecated No-op on the realtime path: the server's STT owns turn-taking. */
@@ -5051,13 +5168,24 @@ export interface VoiceProvider {
5051
5168
  * Register a callback for incremental transcript updates during a voice turn.
5052
5169
  * `isFinal=false` is a live interim update (user partials, or assistant deltas
5053
5170
  * on providers that stream them); `isFinal=true` finalizes that role's text.
5054
- * On the realtime `runtype` path, interim updates fire for the `user` only and
5055
- * the `assistant` arrives as a single final. Providers with overlapping turns
5056
- * must include the same turnId on user and assistant finals; without IDs,
5057
- * providers must discard cancelled output before emitting the next user final.
5171
+ * On the classic realtime `runtype` path, interim updates fire for the `user`
5172
+ * only and the `assistant` arrives as a single final; without a turnId the
5173
+ * session assumes strictly alternating turns, and providers must discard
5174
+ * cancelled output before emitting the next user final.
5175
+ *
5176
+ * When `metadata.turnId` is present (full-duplex / speech-to-speech, e.g.
5177
+ * GPT-Live), the session reconciles by `(turnId, role)`: each pair owns one
5178
+ * bubble that later updates replace in place, turns may overlap or arrive in
5179
+ * any order, and no empty assistant placeholder is injected. User and
5180
+ * assistant may share a turnId (a late user bubble then renders above its
5181
+ * reply) or use distinct ones. `metadata.startMs` (call-relative ms when the
5182
+ * utterance began) orders a new bubble among the call's other keyed bubbles;
5183
+ * without it bubbles order by first arrival. After a stop, keyed providers
5184
+ * must drop the cancelled reply's output until the server acknowledges the
5185
+ * cancel: the session renders every reply it receives.
5058
5186
  */
5059
5187
  onTranscript?(
5060
- callback: (role: 'user' | 'assistant', text: string, isFinal: boolean, metadata?: { turnId?: string }) => void,
5188
+ callback: (role: 'user' | 'assistant', text: string, isFinal: boolean, metadata?: VoiceTranscriptMetadata) => void,
5061
5189
  ): void;
5062
5190
 
5063
5191
  /** Register a callback for per-turn latency metrics (realtime path). */
@@ -5085,6 +5213,125 @@ export interface VoiceProvider {
5085
5213
 
5086
5214
  /** Stop playback / cancel in-flight request without starting recording */
5087
5215
  stopPlayback?(): void;
5216
+
5217
+ /**
5218
+ * Warm the provider ahead of `startListening()` (the widget calls it on mic
5219
+ * intent, see `voiceRecognition.prewarm`). Must be fire-and-forget: never
5220
+ * throw, emit errors or status, or acquire the microphone. May be called
5221
+ * repeatedly; throttle as needed.
5222
+ */
5223
+ prewarm?(): void;
5224
+
5225
+ /**
5226
+ * Called by the session once after construction with the chat-side surface
5227
+ * a full-duplex provider uses to hand agent turns to the chat pipeline
5228
+ * ({@link VoiceSessionBridge}). Providers without client delegation omit it.
5229
+ */
5230
+ setSessionBridge?(bridge: VoiceSessionBridge): void;
5231
+ /** The AI-disclosure notice for the live call, if one should show (speech-to-speech). */
5232
+ getDisclosure?(): string | null;
5233
+ }
5234
+
5235
+ /** Metadata on a {@link VoiceProvider.onTranscript} update. */
5236
+ export type VoiceTranscriptMetadata = {
5237
+ /** Groups updates that belong to one utterance bubble (full duplex). */
5238
+ turnId?: string;
5239
+ /** Call-relative ms when the utterance began; orders late bubbles. */
5240
+ startMs?: number;
5241
+ /** Call-relative ms of the latest audio this update covers. */
5242
+ endMs?: number;
5243
+ /**
5244
+ * The bubble only captions speech (see `AgentWidgetMessage.voiceCaption`).
5245
+ * The chat pipeline owns the conversation, as with client delegation.
5246
+ */
5247
+ caption?: boolean;
5248
+ };
5249
+
5250
+ /** An agent turn a full-duplex voice model handed to the widget. */
5251
+ export type VoiceDelegationRequest = {
5252
+ /** The voice model's delegation id (`delegation_started.delegationId`). */
5253
+ delegationId: string;
5254
+ /** What the visitor asked, as the voice model heard it. */
5255
+ userText: string;
5256
+ /**
5257
+ * The user transcript utterances `userText` joins, oldest first (the last
5258
+ * is the one it came from). May be empty.
5259
+ */
5260
+ userUtteranceIds: string[];
5261
+ /** The voice model's view of the conversation it delegated from. */
5262
+ messages: Array<{ role: string; content: unknown }>;
5263
+ };
5264
+
5265
+ /**
5266
+ * How a delegated turn ended, or that it waits on an approval (contract
5267
+ * Amendment 5). `pending_approval` is the only non-terminal status. Open:
5268
+ * a receiver treats an unknown terminal status as `failed`.
5269
+ * - `completed`: the work ran.
5270
+ * - `denied`: the visitor said no (Deny tap, or a spoken decline).
5271
+ * - `timeout`: the approval lapsed (`approvalTimeoutMs`, or the server's own timeout).
5272
+ * - `cancelled`: replaced by a newer request, or abandoned by the system.
5273
+ * - `failed`: an error.
5274
+ */
5275
+ export type VoiceDelegationStatus =
5276
+ | 'completed'
5277
+ | 'pending_approval'
5278
+ | 'denied'
5279
+ | 'timeout'
5280
+ | 'cancelled'
5281
+ | 'failed'
5282
+ | (string & {});
5283
+
5284
+ /** The terminal result of a turn that parked on approvals. */
5285
+ export type VoiceDelegationFollowUp = {
5286
+ status: VoiceDelegationStatus;
5287
+ /** What to read aloud (Markdown allowed). May be empty: nothing more to say. */
5288
+ text: string;
5289
+ };
5290
+
5291
+ /** The delegated turn's answer, sent back for the voice model to read aloud. */
5292
+ export type VoiceDelegationResult = {
5293
+ /** `pending_approval` when `followUp` is set; otherwise terminal. */
5294
+ status: VoiceDelegationStatus;
5295
+ /** The assistant text (Markdown allowed). */
5296
+ text: string;
5297
+ /**
5298
+ * Set when the turn parked on approvals (`text` then asks for the decision).
5299
+ * Resolves with the terminal result once the visitor decides (or the
5300
+ * approval is replaced, declined by voice, or unanswered for
5301
+ * `approvalTimeoutMs`) and the resumed turn finishes; `null` only when
5302
+ * `signal` aborts first (hang-up, or the server cancelled the delegation).
5303
+ */
5304
+ followUp?: (options: {
5305
+ signal: AbortSignal;
5306
+ approvalTimeoutMs?: number;
5307
+ /** `false`: run only the approval bookkeeping (expiry, supersede); nothing will be read back. @default true */
5308
+ readBack?: boolean;
5309
+ /** The resumed turn stopped on another approval: ask for it too (`text` is its approval script). */
5310
+ onUpdate?: (text: string) => void;
5311
+ }) => Promise<VoiceDelegationFollowUp | null>;
5312
+ };
5313
+
5314
+ /**
5315
+ * Chat-side surface the session hands a full-duplex provider: the visible
5316
+ * history (for the call-start context) and a way to run a delegated turn
5317
+ * through the normal chat pipeline.
5318
+ */
5319
+ export interface VoiceSessionBridge {
5320
+ /** Visible user/assistant messages, oldest first. */
5321
+ getHistory(): Array<{ role: 'user' | 'assistant'; content: string }>;
5322
+ /**
5323
+ * Submit the turn as the visitor's message (reusing its transcript bubble)
5324
+ * and resolve with the assistant's final answer once the turn settles.
5325
+ * Waits for any chat turn already in flight first. Never rejects.
5326
+ */
5327
+ runDelegatedTurn(request: VoiceDelegationRequest): Promise<VoiceDelegationResult>;
5328
+ /**
5329
+ * The server dropped this delegation's result (cancelled it, or refused a
5330
+ * late result): its chat answer is no longer spoken, so browser TTS may read it.
5331
+ * `expired`: the server's deadline passed, so its pending approvals are
5332
+ * declined too, as the approval TTL would.
5333
+ */
5334
+ dropDelegation?(delegationId: string, expired?: boolean): void;
5088
5335
  }
5089
5336
 
5090
5337
  /**
@@ -7967,6 +8214,11 @@ export type AgentWidgetToolCall = {
7967
8214
  startedAt?: number;
7968
8215
  completedAt?: number;
7969
8216
  durationMs?: number;
8217
+ /**
8218
+ * The call paused for an approval that was granted, and the agent re-ran it
8219
+ * as a new tool call: that later call carries the result, this one has none.
8220
+ */
8221
+ superseded?: boolean;
7970
8222
  };
7971
8223
 
7972
8224
  /**
@@ -7989,6 +8241,8 @@ export type AgentWidgetApproval = {
7989
8241
  */
7990
8242
  reason?: string;
7991
8243
  parameters?: unknown;
8244
+ /** The paused tool call this approval gates (`approval_start.toolCallId`). */
8245
+ toolCallId?: string;
7992
8246
  resolvedAt?: number;
7993
8247
  };
7994
8248
 
@@ -8091,6 +8345,13 @@ export type AgentWidgetMessage = {
8091
8345
  * }
8092
8346
  */
8093
8347
  voiceProcessing?: boolean;
8348
+ /**
8349
+ * Display-only caption of full-duplex voice speech, such as the voice
8350
+ * model's own words, or something the visitor said that wasn't submitted
8351
+ * as a chat turn. It renders in the transcript but is never sent to the
8352
+ * model as conversation.
8353
+ */
8354
+ voiceCaption?: boolean;
8094
8355
  /**
8095
8356
  * Raw structured payload for this message (e.g., JSON action response).
8096
8357
  * Populated automatically when structured parsers run.
@@ -8220,6 +8481,9 @@ export type InjectMessageOptions = {
8220
8481
  */
8221
8482
  voiceProcessing?: boolean;
8222
8483
 
8484
+ /** See {@link AgentWidgetMessage.voiceCaption}. */
8485
+ voiceCaption?: boolean;
8486
+
8223
8487
  /**
8224
8488
  * Raw structured payload (typically a JSON string) representing the
8225
8489
  * full directive that produced this message: e.g. `{ "text": "...",