@athenaintel/react 0.43.0 → 0.50.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 (746) hide show
  1. package/README.md +258 -8
  2. package/dist/agent-runtime/src/answer-label.cjs +137 -0
  3. package/dist/agent-runtime/src/answer-label.cjs.map +1 -0
  4. package/dist/agent-runtime/src/answer-label.d.ts +104 -0
  5. package/dist/agent-runtime/src/answer-label.js +137 -0
  6. package/dist/agent-runtime/src/answer-label.js.map +1 -0
  7. package/dist/agent-runtime/src/answer-rows.cjs +180 -0
  8. package/dist/agent-runtime/src/answer-rows.cjs.map +1 -0
  9. package/dist/agent-runtime/src/answer-rows.d.ts +86 -0
  10. package/dist/agent-runtime/src/answer-rows.js +180 -0
  11. package/dist/agent-runtime/src/answer-rows.js.map +1 -0
  12. package/dist/agent-runtime/src/call-recap.cjs +319 -0
  13. package/dist/agent-runtime/src/call-recap.cjs.map +1 -0
  14. package/dist/agent-runtime/src/call-recap.d.ts +142 -0
  15. package/dist/agent-runtime/src/call-recap.js +319 -0
  16. package/dist/agent-runtime/src/call-recap.js.map +1 -0
  17. package/dist/agent-runtime/src/chat-outbox-store.cjs +1 -0
  18. package/dist/agent-runtime/src/chat-outbox-store.cjs.map +1 -1
  19. package/dist/agent-runtime/src/chat-outbox-store.d.ts +7 -0
  20. package/dist/agent-runtime/src/chat-outbox-store.js +1 -0
  21. package/dist/agent-runtime/src/chat-outbox-store.js.map +1 -1
  22. package/dist/agent-runtime/src/chat-outbox.cjs +46 -5
  23. package/dist/agent-runtime/src/chat-outbox.cjs.map +1 -1
  24. package/dist/agent-runtime/src/chat-outbox.d.ts +29 -0
  25. package/dist/agent-runtime/src/chat-outbox.js +46 -5
  26. package/dist/agent-runtime/src/chat-outbox.js.map +1 -1
  27. package/dist/agent-runtime/src/client-tool-bridge.cjs +15 -15
  28. package/dist/agent-runtime/src/client-tool-bridge.cjs.map +1 -1
  29. package/dist/agent-runtime/src/conversation-index.cjs +8 -8
  30. package/dist/agent-runtime/src/conversation-index.cjs.map +1 -1
  31. package/dist/agent-runtime/src/conversation-index.d.ts +7 -0
  32. package/dist/agent-runtime/src/conversation-index.js.map +1 -1
  33. package/dist/agent-runtime/src/conversation-list.cjs +2 -1
  34. package/dist/agent-runtime/src/conversation-list.cjs.map +1 -1
  35. package/dist/agent-runtime/src/conversation-list.d.ts +19 -3
  36. package/dist/agent-runtime/src/conversation-list.js +2 -1
  37. package/dist/agent-runtime/src/conversation-list.js.map +1 -1
  38. package/dist/agent-runtime/src/decision-checks.cjs +207 -0
  39. package/dist/agent-runtime/src/decision-checks.cjs.map +1 -0
  40. package/dist/agent-runtime/src/decision-checks.d.ts +142 -0
  41. package/dist/agent-runtime/src/decision-checks.js +207 -0
  42. package/dist/agent-runtime/src/decision-checks.js.map +1 -0
  43. package/dist/agent-runtime/src/desktop-handoff.d.ts +12 -0
  44. package/dist/agent-runtime/src/errors.cjs +18 -0
  45. package/dist/agent-runtime/src/errors.cjs.map +1 -1
  46. package/dist/agent-runtime/src/errors.d.ts +7 -0
  47. package/dist/agent-runtime/src/errors.js +18 -0
  48. package/dist/agent-runtime/src/errors.js.map +1 -1
  49. package/dist/agent-runtime/src/generated/runconfig-contract.cjs +12 -0
  50. package/dist/agent-runtime/src/generated/runconfig-contract.cjs.map +1 -1
  51. package/dist/agent-runtime/src/generated/runconfig-contract.d.ts +6 -6
  52. package/dist/agent-runtime/src/generated/runconfig-contract.js +12 -0
  53. package/dist/agent-runtime/src/generated/runconfig-contract.js.map +1 -1
  54. package/dist/agent-runtime/src/handoff-arrival.cjs +60 -0
  55. package/dist/agent-runtime/src/handoff-arrival.cjs.map +1 -0
  56. package/dist/agent-runtime/src/handoff-arrival.d.ts +46 -0
  57. package/dist/agent-runtime/src/handoff-arrival.js +60 -0
  58. package/dist/agent-runtime/src/handoff-arrival.js.map +1 -0
  59. package/dist/agent-runtime/src/index.d.ts +16 -9
  60. package/dist/agent-runtime/src/interrupts.cjs +71 -19
  61. package/dist/agent-runtime/src/interrupts.cjs.map +1 -1
  62. package/dist/agent-runtime/src/interrupts.d.ts +40 -3
  63. package/dist/agent-runtime/src/interrupts.js +56 -4
  64. package/dist/agent-runtime/src/interrupts.js.map +1 -1
  65. package/dist/agent-runtime/src/lane-history.cjs +8 -8
  66. package/dist/agent-runtime/src/lane-history.cjs.map +1 -1
  67. package/dist/agent-runtime/src/messages.cjs +43 -8
  68. package/dist/agent-runtime/src/messages.cjs.map +1 -1
  69. package/dist/agent-runtime/src/messages.d.ts +25 -3
  70. package/dist/agent-runtime/src/messages.js +43 -8
  71. package/dist/agent-runtime/src/messages.js.map +1 -1
  72. package/dist/agent-runtime/src/model-context.cjs +3 -2
  73. package/dist/agent-runtime/src/model-context.cjs.map +1 -1
  74. package/dist/agent-runtime/src/model-context.d.ts +6 -1
  75. package/dist/agent-runtime/src/model-context.js +3 -2
  76. package/dist/agent-runtime/src/model-context.js.map +1 -1
  77. package/dist/agent-runtime/src/offline-status.cjs +36 -0
  78. package/dist/agent-runtime/src/offline-status.cjs.map +1 -0
  79. package/dist/agent-runtime/src/offline-status.d.ts +118 -3
  80. package/dist/agent-runtime/src/offline-status.js +36 -0
  81. package/dist/agent-runtime/src/offline-status.js.map +1 -0
  82. package/dist/agent-runtime/src/queue.cjs +0 -9
  83. package/dist/agent-runtime/src/queue.cjs.map +1 -1
  84. package/dist/agent-runtime/src/queue.js +0 -9
  85. package/dist/agent-runtime/src/queue.js.map +1 -1
  86. package/dist/agent-runtime/src/quota-safe-local-storage-session.cjs +9 -9
  87. package/dist/agent-runtime/src/quota-safe-local-storage-session.cjs.map +1 -1
  88. package/dist/agent-runtime/src/runtime-catalog.cjs +42 -0
  89. package/dist/agent-runtime/src/runtime-catalog.cjs.map +1 -0
  90. package/dist/agent-runtime/src/runtime-catalog.d.ts +35 -0
  91. package/dist/agent-runtime/src/runtime-catalog.js +42 -0
  92. package/dist/agent-runtime/src/runtime-catalog.js.map +1 -0
  93. package/dist/agent-runtime/src/runtime-messages.cjs.map +1 -1
  94. package/dist/agent-runtime/src/runtime-messages.d.ts +1 -1
  95. package/dist/agent-runtime/src/runtime-messages.js.map +1 -1
  96. package/dist/agent-runtime/src/runtime.d.ts +41 -0
  97. package/dist/agent-runtime/src/send-recovery.cjs +37 -3
  98. package/dist/agent-runtime/src/send-recovery.cjs.map +1 -1
  99. package/dist/agent-runtime/src/send-recovery.d.ts +19 -0
  100. package/dist/agent-runtime/src/send-recovery.js +37 -3
  101. package/dist/agent-runtime/src/send-recovery.js.map +1 -1
  102. package/dist/agent-runtime/src/statewire-suspended.cjs +3 -3
  103. package/dist/agent-runtime/src/statewire-suspended.cjs.map +1 -1
  104. package/dist/agent-runtime/src/subagents.cjs +32 -2
  105. package/dist/agent-runtime/src/subagents.cjs.map +1 -1
  106. package/dist/agent-runtime/src/subagents.d.ts +9 -0
  107. package/dist/agent-runtime/src/subagents.js +30 -0
  108. package/dist/agent-runtime/src/subagents.js.map +1 -1
  109. package/dist/agent-runtime/src/thread-driver.cjs +67 -0
  110. package/dist/agent-runtime/src/thread-driver.cjs.map +1 -0
  111. package/dist/agent-runtime/src/thread-driver.d.ts +49 -0
  112. package/dist/agent-runtime/src/thread-driver.js +67 -0
  113. package/dist/agent-runtime/src/thread-driver.js.map +1 -0
  114. package/dist/agent-runtime/src/thread-handoff-flow-machine.d.ts +172 -0
  115. package/dist/agent-runtime/src/thread-handoff-protocol.d.ts +868 -0
  116. package/dist/agent-runtime/src/thread-handoff-qr.d.ts +11 -0
  117. package/dist/agent-runtime/src/thread-handoff.d.ts +3 -364
  118. package/dist/agent-runtime/src/thread-status.cjs +3 -3
  119. package/dist/agent-runtime/src/thread-status.cjs.map +1 -1
  120. package/dist/agent-runtime/src/tool-metadata.cjs +210 -25
  121. package/dist/agent-runtime/src/tool-metadata.cjs.map +1 -1
  122. package/dist/agent-runtime/src/tool-metadata.d.ts +12 -0
  123. package/dist/agent-runtime/src/tool-metadata.js +210 -25
  124. package/dist/agent-runtime/src/tool-metadata.js.map +1 -1
  125. package/dist/agent-runtime/src/tool-names.cjs +2 -0
  126. package/dist/agent-runtime/src/tool-names.cjs.map +1 -1
  127. package/dist/agent-runtime/src/tool-names.d.ts +2 -0
  128. package/dist/agent-runtime/src/tool-names.js +2 -0
  129. package/dist/agent-runtime/src/tool-names.js.map +1 -1
  130. package/dist/agent-runtime/src/types.d.ts +10 -2
  131. package/dist/agent-runtime/src/use-conversation-list.cjs +14 -13
  132. package/dist/agent-runtime/src/use-conversation-list.cjs.map +1 -1
  133. package/dist/agent-runtime/src/use-conversation-list.d.ts +6 -0
  134. package/dist/agent-runtime/src/use-conversation-list.js +3 -2
  135. package/dist/agent-runtime/src/use-conversation-list.js.map +1 -1
  136. package/dist/agent-runtime/src/use-deep-agent-chat-outbox.cjs +45 -20
  137. package/dist/agent-runtime/src/use-deep-agent-chat-outbox.cjs.map +1 -1
  138. package/dist/agent-runtime/src/use-deep-agent-chat-outbox.d.ts +10 -3
  139. package/dist/agent-runtime/src/use-deep-agent-chat-outbox.js +27 -2
  140. package/dist/agent-runtime/src/use-deep-agent-chat-outbox.js.map +1 -1
  141. package/dist/agent-runtime/src/use-deep-agent-config.cjs +14 -14
  142. package/dist/agent-runtime/src/use-deep-agent-config.cjs.map +1 -1
  143. package/dist/agent-runtime/src/use-deep-agent-edit-submit.cjs +6 -6
  144. package/dist/agent-runtime/src/use-deep-agent-edit-submit.cjs.map +1 -1
  145. package/dist/agent-runtime/src/use-deep-agent-runtime.cjs +40 -22
  146. package/dist/agent-runtime/src/use-deep-agent-runtime.cjs.map +1 -1
  147. package/dist/agent-runtime/src/use-deep-agent-runtime.d.ts +17 -0
  148. package/dist/agent-runtime/src/use-deep-agent-runtime.js +24 -6
  149. package/dist/agent-runtime/src/use-deep-agent-runtime.js.map +1 -1
  150. package/dist/agent-runtime/src/use-deep-agent-thread.cjs +45 -45
  151. package/dist/agent-runtime/src/use-deep-agent-thread.cjs.map +1 -1
  152. package/dist/agent-runtime/src/use-deep-agent-voice.cjs +588 -130
  153. package/dist/agent-runtime/src/use-deep-agent-voice.cjs.map +1 -1
  154. package/dist/agent-runtime/src/use-deep-agent-voice.d.ts +162 -10
  155. package/dist/agent-runtime/src/use-deep-agent-voice.js +529 -71
  156. package/dist/agent-runtime/src/use-deep-agent-voice.js.map +1 -1
  157. package/dist/agent-runtime/src/use-deep-agent-window-sync.cjs +26 -26
  158. package/dist/agent-runtime/src/use-deep-agent-window-sync.cjs.map +1 -1
  159. package/dist/agent-runtime/src/use-historical-edit-attachments.cjs +4 -4
  160. package/dist/agent-runtime/src/use-historical-edit-attachments.cjs.map +1 -1
  161. package/dist/agent-runtime/src/use-thread-handoff-flow.d.ts +34 -26
  162. package/dist/agent-runtime/src/voice-earcon.cjs +139 -0
  163. package/dist/agent-runtime/src/voice-earcon.cjs.map +1 -0
  164. package/dist/agent-runtime/src/voice-earcon.d.ts +38 -0
  165. package/dist/agent-runtime/src/voice-earcon.js +139 -0
  166. package/dist/agent-runtime/src/voice-earcon.js.map +1 -0
  167. package/dist/agent-runtime/src/voice-media.cjs +117 -0
  168. package/dist/agent-runtime/src/voice-media.cjs.map +1 -0
  169. package/dist/agent-runtime/src/voice-media.d.ts +63 -0
  170. package/dist/agent-runtime/src/voice-media.js +117 -0
  171. package/dist/agent-runtime/src/voice-media.js.map +1 -0
  172. package/dist/agent-runtime/src/voice-presentation.cjs +2 -0
  173. package/dist/agent-runtime/src/voice-presentation.cjs.map +1 -1
  174. package/dist/agent-runtime/src/voice-presentation.js +2 -0
  175. package/dist/agent-runtime/src/voice-presentation.js.map +1 -1
  176. package/dist/agent-runtime/src/voice-wire-types.d.ts +32 -0
  177. package/dist/assets/AssetPanel.cjs +11 -11
  178. package/dist/assets/AssetPanel.cjs.map +1 -1
  179. package/dist/assets/AthenaAssetEmbed.cjs +11 -9
  180. package/dist/assets/AthenaAssetEmbed.cjs.map +1 -1
  181. package/dist/assets/AthenaAssetEmbed.d.ts +18 -5
  182. package/dist/assets/AthenaAssetEmbed.js +4 -2
  183. package/dist/assets/AthenaAssetEmbed.js.map +1 -1
  184. package/dist/assets/AthenaLayout.cjs +16 -16
  185. package/dist/assets/AthenaLayout.cjs.map +1 -1
  186. package/dist/assets/use-asset-content.cjs +4 -4
  187. package/dist/assets/use-asset-content.cjs.map +1 -1
  188. package/dist/assets/use-asset-embed.cjs +14 -7
  189. package/dist/assets/use-asset-embed.cjs.map +1 -1
  190. package/dist/assets/use-asset-embed.d.ts +23 -6
  191. package/dist/assets/use-asset-embed.js +10 -3
  192. package/dist/assets/use-asset-embed.js.map +1 -1
  193. package/dist/auth/AthenaAuthContext.cjs +3 -3
  194. package/dist/auth/AthenaAuthContext.cjs.map +1 -1
  195. package/dist/auth/AthenaAuthProvider.cjs +8 -8
  196. package/dist/auth/AthenaAuthProvider.cjs.map +1 -1
  197. package/dist/auth/AthenaCredentialSourceContext.cjs +5 -5
  198. package/dist/auth/AthenaCredentialSourceContext.cjs.map +1 -1
  199. package/dist/auth/AthenaSSOProvider.cjs +14 -14
  200. package/dist/auth/AthenaSSOProvider.cjs.map +1 -1
  201. package/dist/auth/credential-source.cjs +26 -13
  202. package/dist/auth/credential-source.cjs.map +1 -1
  203. package/dist/auth/credential-source.d.ts +8 -0
  204. package/dist/auth/credential-source.js +26 -13
  205. package/dist/auth/credential-source.js.map +1 -1
  206. package/dist/catalog/agent-model-options.cjs +25 -17
  207. package/dist/catalog/agent-model-options.cjs.map +1 -1
  208. package/dist/catalog/agent-model-options.d.ts +38 -5
  209. package/dist/catalog/agent-model-options.js +25 -17
  210. package/dist/catalog/agent-model-options.js.map +1 -1
  211. package/dist/catalog/channel-refusal.cjs +36 -0
  212. package/dist/catalog/channel-refusal.cjs.map +1 -0
  213. package/dist/catalog/channel-refusal.d.ts +29 -0
  214. package/dist/catalog/channel-refusal.js +36 -0
  215. package/dist/catalog/channel-refusal.js.map +1 -0
  216. package/dist/catalog/chat-pickers.cjs +60 -24
  217. package/dist/catalog/chat-pickers.cjs.map +1 -1
  218. package/dist/catalog/chat-pickers.d.ts +12 -2
  219. package/dist/catalog/chat-pickers.js +56 -20
  220. package/dist/catalog/chat-pickers.js.map +1 -1
  221. package/dist/catalog/runtime-catalog.cjs +89 -23
  222. package/dist/catalog/runtime-catalog.cjs.map +1 -1
  223. package/dist/catalog/runtime-catalog.d.ts +8 -2
  224. package/dist/catalog/runtime-catalog.js +83 -17
  225. package/dist/catalog/runtime-catalog.js.map +1 -1
  226. package/dist/catalog/use-athena-chat-mode.cjs +12 -12
  227. package/dist/catalog/use-athena-chat-mode.cjs.map +1 -1
  228. package/dist/chat/AthenaChat.cjs +155 -67
  229. package/dist/chat/AthenaChat.cjs.map +1 -1
  230. package/dist/chat/AthenaChat.d.ts +42 -2
  231. package/dist/chat/AthenaChat.js +106 -18
  232. package/dist/chat/AthenaChat.js.map +1 -1
  233. package/dist/chat/AthenaChatErrorBoundary.cjs +3 -3
  234. package/dist/chat/AthenaChatErrorBoundary.cjs.map +1 -1
  235. package/dist/chat/DrivingOnChip.cjs +23 -0
  236. package/dist/chat/DrivingOnChip.cjs.map +1 -0
  237. package/dist/chat/DrivingOnChip.d.ts +17 -0
  238. package/dist/chat/DrivingOnChip.js +23 -0
  239. package/dist/chat/DrivingOnChip.js.map +1 -0
  240. package/dist/chat/StatewireApprovalCard.cjs +166 -37
  241. package/dist/chat/StatewireApprovalCard.cjs.map +1 -1
  242. package/dist/chat/StatewireApprovalCard.d.ts +91 -2
  243. package/dist/chat/StatewireApprovalCard.js +156 -27
  244. package/dist/chat/StatewireApprovalCard.js.map +1 -1
  245. package/dist/chat/StatewireClientToolBridge.cjs +2 -2
  246. package/dist/chat/StatewireClientToolBridge.cjs.map +1 -1
  247. package/dist/chat/StatewireQueuedMessages.cjs +81 -69
  248. package/dist/chat/StatewireQueuedMessages.cjs.map +1 -1
  249. package/dist/chat/StatewireQueuedMessages.d.ts +25 -13
  250. package/dist/chat/StatewireQueuedMessages.js +73 -61
  251. package/dist/chat/StatewireQueuedMessages.js.map +1 -1
  252. package/dist/chat/WaitingOnYouBanner.cjs +9 -5
  253. package/dist/chat/WaitingOnYouBanner.cjs.map +1 -1
  254. package/dist/chat/WaitingOnYouBanner.js +7 -3
  255. package/dist/chat/WaitingOnYouBanner.js.map +1 -1
  256. package/dist/chat/athena-chat-welcome.cjs +2 -2
  257. package/dist/chat/athena-chat-welcome.cjs.map +1 -1
  258. package/dist/chat/athena-citation-links.cjs +5 -5
  259. package/dist/chat/athena-citation-links.cjs.map +1 -1
  260. package/dist/chat/athena-composer-controls.cjs +26 -16
  261. package/dist/chat/athena-composer-controls.cjs.map +1 -1
  262. package/dist/chat/athena-composer-controls.d.ts +6 -0
  263. package/dist/chat/athena-composer-controls.js +26 -16
  264. package/dist/chat/athena-composer-controls.js.map +1 -1
  265. package/dist/chat/athena-turn-end-status.cjs +42 -0
  266. package/dist/chat/athena-turn-end-status.cjs.map +1 -0
  267. package/dist/chat/athena-turn-end-status.d.ts +24 -0
  268. package/dist/chat/athena-turn-end-status.js +42 -0
  269. package/dist/chat/athena-turn-end-status.js.map +1 -0
  270. package/dist/chat/browser-decision-check.cjs +131 -0
  271. package/dist/chat/browser-decision-check.cjs.map +1 -0
  272. package/dist/chat/browser-decision-check.d.ts +61 -0
  273. package/dist/chat/browser-decision-check.js +131 -0
  274. package/dist/chat/browser-decision-check.js.map +1 -0
  275. package/dist/chat/chat-outbox-rows.cjs +3 -3
  276. package/dist/chat/chat-outbox-rows.cjs.map +1 -1
  277. package/dist/chat/chat-voice-controls.cjs +96 -29
  278. package/dist/chat/chat-voice-controls.cjs.map +1 -1
  279. package/dist/chat/chat-voice-controls.d.ts +42 -3
  280. package/dist/chat/chat-voice-controls.js +92 -25
  281. package/dist/chat/chat-voice-controls.js.map +1 -1
  282. package/dist/chat/composer-keyboard-hint.cjs +5 -5
  283. package/dist/chat/composer-keyboard-hint.cjs.map +1 -1
  284. package/dist/chat/device-operation.cjs +29 -0
  285. package/dist/chat/device-operation.cjs.map +1 -0
  286. package/dist/chat/device-operation.d.ts +34 -0
  287. package/dist/chat/device-operation.js +29 -0
  288. package/dist/chat/device-operation.js.map +1 -0
  289. package/dist/chat/super-grouping/CollapsibleGroup.cjs +14 -14
  290. package/dist/chat/super-grouping/CollapsibleGroup.cjs.map +1 -1
  291. package/dist/chat/super-grouping/GroupedMessageParts.cjs +4 -4
  292. package/dist/chat/super-grouping/GroupedMessageParts.cjs.map +1 -1
  293. package/dist/chat/super-grouping/SuperGroupingCard.cjs +52 -36
  294. package/dist/chat/super-grouping/SuperGroupingCard.cjs.map +1 -1
  295. package/dist/chat/super-grouping/SuperGroupingCard.d.ts +19 -4
  296. package/dist/chat/super-grouping/SuperGroupingCard.js +29 -13
  297. package/dist/chat/super-grouping/SuperGroupingCard.js.map +1 -1
  298. package/dist/chat/super-grouping/SuperGroupingTranscript.cjs +32 -32
  299. package/dist/chat/super-grouping/SuperGroupingTranscript.cjs.map +1 -1
  300. package/dist/chat/super-grouping/SuperGroupingTranscript.js +3 -3
  301. package/dist/chat/super-grouping/SuperGroupingTranscript.js.map +1 -1
  302. package/dist/chat/super-grouping/ToolTimeline.cjs +73 -40
  303. package/dist/chat/super-grouping/ToolTimeline.cjs.map +1 -1
  304. package/dist/chat/super-grouping/ToolTimeline.d.ts +10 -2
  305. package/dist/chat/super-grouping/ToolTimeline.js +69 -36
  306. package/dist/chat/super-grouping/ToolTimeline.js.map +1 -1
  307. package/dist/chat/super-grouping/activity-timeline.cjs +47 -12
  308. package/dist/chat/super-grouping/activity-timeline.cjs.map +1 -1
  309. package/dist/chat/super-grouping/activity-timeline.d.ts +21 -0
  310. package/dist/chat/super-grouping/activity-timeline.js +47 -12
  311. package/dist/chat/super-grouping/activity-timeline.js.map +1 -1
  312. package/dist/chat/super-grouping/grouping-function.cjs +4 -0
  313. package/dist/chat/super-grouping/grouping-function.cjs.map +1 -1
  314. package/dist/chat/super-grouping/grouping-function.d.ts +7 -0
  315. package/dist/chat/super-grouping/grouping-function.js +5 -1
  316. package/dist/chat/super-grouping/grouping-function.js.map +1 -1
  317. package/dist/chat/super-grouping/index.cjs +6 -0
  318. package/dist/chat/super-grouping/index.cjs.map +1 -1
  319. package/dist/chat/super-grouping/index.d.ts +5 -2
  320. package/dist/chat/super-grouping/index.js +7 -1
  321. package/dist/chat/super-grouping/index.js.map +1 -1
  322. package/dist/chat/super-grouping/tool-part-placement.cjs +17 -0
  323. package/dist/chat/super-grouping/tool-part-placement.cjs.map +1 -0
  324. package/dist/chat/super-grouping/tool-part-placement.d.ts +22 -0
  325. package/dist/chat/super-grouping/tool-part-placement.js +17 -0
  326. package/dist/chat/super-grouping/tool-part-placement.js.map +1 -0
  327. package/dist/chat/thread-scroll-to-bottom.cjs +2 -2
  328. package/dist/chat/thread-scroll-to-bottom.cjs.map +1 -1
  329. package/dist/chat/thread-scroll-to-bottom.d.ts +10 -7
  330. package/dist/chat/thread-scroll-to-bottom.js +2 -2
  331. package/dist/chat/thread-scroll-to-bottom.js.map +1 -1
  332. package/dist/chat/tooltip-icon-button.cjs +2 -2
  333. package/dist/chat/tooltip-icon-button.cjs.map +1 -1
  334. package/dist/chat/use-athena-voice-live.cjs +11 -0
  335. package/dist/chat/use-athena-voice-live.cjs.map +1 -0
  336. package/dist/chat/use-athena-voice-live.d.ts +11 -0
  337. package/dist/chat/use-athena-voice-live.js +11 -0
  338. package/dist/chat/use-athena-voice-live.js.map +1 -0
  339. package/dist/chat/use-statewire-approval-request.cjs +56 -24
  340. package/dist/chat/use-statewire-approval-request.cjs.map +1 -1
  341. package/dist/chat/use-statewire-approval-request.d.ts +33 -4
  342. package/dist/chat/use-statewire-approval-request.js +41 -9
  343. package/dist/chat/use-statewire-approval-request.js.map +1 -1
  344. package/dist/chat-ui/auth/sign-in-card.cjs +2 -2
  345. package/dist/chat-ui/auth/sign-in-card.cjs.map +1 -1
  346. package/dist/chat-ui/composer/tiptap-composer.cjs +138 -107
  347. package/dist/chat-ui/composer/tiptap-composer.cjs.map +1 -1
  348. package/dist/chat-ui/composer/tiptap-composer.d.ts +20 -4
  349. package/dist/chat-ui/composer/tiptap-composer.js +85 -54
  350. package/dist/chat-ui/composer/tiptap-composer.js.map +1 -1
  351. package/dist/chat-ui/header/conversation-history-panel.cjs +49 -23
  352. package/dist/chat-ui/header/conversation-history-panel.cjs.map +1 -1
  353. package/dist/chat-ui/header/conversation-history-panel.d.ts +12 -1
  354. package/dist/chat-ui/header/conversation-history-panel.js +38 -12
  355. package/dist/chat-ui/header/conversation-history-panel.js.map +1 -1
  356. package/dist/chat-ui/index.cjs +21 -0
  357. package/dist/chat-ui/index.cjs.map +1 -1
  358. package/dist/chat-ui/index.d.ts +8 -1
  359. package/dist/chat-ui/index.js +21 -0
  360. package/dist/chat-ui/index.js.map +1 -1
  361. package/dist/chat-ui/mentions/mention-chip.cjs +4 -4
  362. package/dist/chat-ui/mentions/mention-chip.cjs.map +1 -1
  363. package/dist/chat-ui/mentions/suggestions/components/mention-suggestion-list.cjs +10 -9
  364. package/dist/chat-ui/mentions/suggestions/components/mention-suggestion-list.cjs.map +1 -1
  365. package/dist/chat-ui/mentions/suggestions/components/mention-suggestion-list.js +3 -2
  366. package/dist/chat-ui/mentions/suggestions/components/mention-suggestion-list.js.map +1 -1
  367. package/dist/chat-ui/mentions/suggestions/components/mention-suggestion-popup.cjs +2 -2
  368. package/dist/chat-ui/mentions/suggestions/components/mention-suggestion-popup.cjs.map +1 -1
  369. package/dist/chat-ui/mentions/suggestions/components/menu-list.cjs +29 -6
  370. package/dist/chat-ui/mentions/suggestions/components/menu-list.cjs.map +1 -1
  371. package/dist/chat-ui/mentions/suggestions/components/menu-list.d.ts +7 -1
  372. package/dist/chat-ui/mentions/suggestions/components/menu-list.js +25 -2
  373. package/dist/chat-ui/mentions/suggestions/components/menu-list.js.map +1 -1
  374. package/dist/chat-ui/mentions/suggestions/components/use-keyboard-navigation.cjs +2 -2
  375. package/dist/chat-ui/mentions/suggestions/components/use-keyboard-navigation.cjs.map +1 -1
  376. package/dist/chat-ui/mentions/suggestions/components/use-menu-navigation.cjs +2 -2
  377. package/dist/chat-ui/mentions/suggestions/components/use-menu-navigation.cjs.map +1 -1
  378. package/dist/chat-ui/mentions/suggestions/data/api-client.cjs +3 -3
  379. package/dist/chat-ui/mentions/suggestions/data/api-client.cjs.map +1 -1
  380. package/dist/chat-ui/mentions/suggestions/data/orchestrator.cjs +56 -2
  381. package/dist/chat-ui/mentions/suggestions/data/orchestrator.cjs.map +1 -1
  382. package/dist/chat-ui/mentions/suggestions/data/orchestrator.d.ts +12 -0
  383. package/dist/chat-ui/mentions/suggestions/data/orchestrator.js +56 -2
  384. package/dist/chat-ui/mentions/suggestions/data/orchestrator.js.map +1 -1
  385. package/dist/chat-ui/mentions/suggestions/data/sources/index.cjs +24 -3
  386. package/dist/chat-ui/mentions/suggestions/data/sources/index.cjs.map +1 -1
  387. package/dist/chat-ui/mentions/suggestions/data/sources/index.d.ts +7 -0
  388. package/dist/chat-ui/mentions/suggestions/data/sources/index.js +24 -3
  389. package/dist/chat-ui/mentions/suggestions/data/sources/index.js.map +1 -1
  390. package/dist/chat-ui/mentions/suggestions/data/use-mention-suggestions.cjs +35 -13
  391. package/dist/chat-ui/mentions/suggestions/data/use-mention-suggestions.cjs.map +1 -1
  392. package/dist/chat-ui/mentions/suggestions/data/use-mention-suggestions.d.ts +15 -1
  393. package/dist/chat-ui/mentions/suggestions/data/use-mention-suggestions.js +28 -6
  394. package/dist/chat-ui/mentions/suggestions/data/use-mention-suggestions.js.map +1 -1
  395. package/dist/chat-ui/mentions/suggestions/data/use-menu-items.cjs +9 -6
  396. package/dist/chat-ui/mentions/suggestions/data/use-menu-items.cjs.map +1 -1
  397. package/dist/chat-ui/mentions/suggestions/data/use-menu-items.d.ts +3 -0
  398. package/dist/chat-ui/mentions/suggestions/data/use-menu-items.js +5 -2
  399. package/dist/chat-ui/mentions/suggestions/data/use-menu-items.js.map +1 -1
  400. package/dist/chat-ui/mentions/use-account-workspace-id.cjs +45 -10
  401. package/dist/chat-ui/mentions/use-account-workspace-id.cjs.map +1 -1
  402. package/dist/chat-ui/mentions/use-account-workspace-id.d.ts +24 -1
  403. package/dist/chat-ui/mentions/use-account-workspace-id.js +46 -11
  404. package/dist/chat-ui/mentions/use-account-workspace-id.js.map +1 -1
  405. package/dist/chat-ui/mentions/use-member-avatar.cjs +4 -4
  406. package/dist/chat-ui/mentions/use-member-avatar.cjs.map +1 -1
  407. package/dist/chat-ui/mentions/use-mention-asset.cjs +3 -3
  408. package/dist/chat-ui/mentions/use-mention-asset.cjs.map +1 -1
  409. package/dist/chat-ui/messages/answer-label.cjs +42 -0
  410. package/dist/chat-ui/messages/answer-label.cjs.map +1 -0
  411. package/dist/chat-ui/messages/answer-label.d.ts +33 -0
  412. package/dist/chat-ui/messages/answer-label.js +42 -0
  413. package/dist/chat-ui/messages/answer-label.js.map +1 -0
  414. package/dist/chat-ui/messages/arrival-animation.cjs +13 -0
  415. package/dist/chat-ui/messages/arrival-animation.cjs.map +1 -0
  416. package/dist/chat-ui/messages/arrival-animation.d.ts +14 -0
  417. package/dist/chat-ui/messages/arrival-animation.js +13 -0
  418. package/dist/chat-ui/messages/arrival-animation.js.map +1 -0
  419. package/dist/chat-ui/messages/continue-pill.cjs +5 -5
  420. package/dist/chat-ui/messages/continue-pill.cjs.map +1 -1
  421. package/dist/chat-ui/messages/from-the-call-card.cjs +124 -0
  422. package/dist/chat-ui/messages/from-the-call-card.cjs.map +1 -0
  423. package/dist/chat-ui/messages/from-the-call-card.d.ts +17 -0
  424. package/dist/chat-ui/messages/from-the-call-card.js +124 -0
  425. package/dist/chat-ui/messages/from-the-call-card.js.map +1 -0
  426. package/dist/chat-ui/messages/handoff-arrival-divider.cjs +44 -0
  427. package/dist/chat-ui/messages/handoff-arrival-divider.cjs.map +1 -0
  428. package/dist/chat-ui/messages/handoff-arrival-divider.d.ts +17 -0
  429. package/dist/chat-ui/messages/handoff-arrival-divider.js +44 -0
  430. package/dist/chat-ui/messages/handoff-arrival-divider.js.map +1 -0
  431. package/dist/chat-ui/messages/message-actions-config.cjs +3 -3
  432. package/dist/chat-ui/messages/message-actions-config.cjs.map +1 -1
  433. package/dist/chat-ui/messages/message-components.cjs +8 -4
  434. package/dist/chat-ui/messages/message-components.cjs.map +1 -1
  435. package/dist/chat-ui/messages/message-components.js +5 -1
  436. package/dist/chat-ui/messages/message-components.js.map +1 -1
  437. package/dist/chat-ui/messages/message-images.cjs +66 -0
  438. package/dist/chat-ui/messages/message-images.cjs.map +1 -0
  439. package/dist/chat-ui/messages/message-images.d.ts +16 -0
  440. package/dist/chat-ui/messages/message-images.js +66 -0
  441. package/dist/chat-ui/messages/message-images.js.map +1 -0
  442. package/dist/chat-ui/messages/user-edit-composer.cjs +2 -2
  443. package/dist/chat-ui/messages/user-edit-composer.cjs.map +1 -1
  444. package/dist/chat-ui/messages/wake-marker.cjs +3 -3
  445. package/dist/chat-ui/messages/wake-marker.cjs.map +1 -1
  446. package/dist/chat-ui/rich-text/chat-link.cjs +3 -2
  447. package/dist/chat-ui/rich-text/chat-link.cjs.map +1 -1
  448. package/dist/chat-ui/rich-text/chat-link.d.ts +4 -0
  449. package/dist/chat-ui/rich-text/chat-link.js +4 -3
  450. package/dist/chat-ui/rich-text/chat-link.js.map +1 -1
  451. package/dist/chat-ui/rich-text/chat-message-body.cjs +9 -8
  452. package/dist/chat-ui/rich-text/chat-message-body.cjs.map +1 -1
  453. package/dist/chat-ui/rich-text/chat-message-body.d.ts +12 -0
  454. package/dist/chat-ui/rich-text/chat-message-body.js +2 -1
  455. package/dist/chat-ui/rich-text/chat-message-body.js.map +1 -1
  456. package/dist/chat-ui/rich-text/chat-node-views.cjs +6 -6
  457. package/dist/chat-ui/rich-text/chat-node-views.cjs.map +1 -1
  458. package/dist/chat-ui/rich-text/dom-output-spec.cjs +2 -2
  459. package/dist/chat-ui/rich-text/dom-output-spec.cjs.map +1 -1
  460. package/dist/chat-ui/statewire.cjs +3 -0
  461. package/dist/chat-ui/statewire.cjs.map +1 -1
  462. package/dist/chat-ui/statewire.d.ts +2 -1
  463. package/dist/chat-ui/statewire.js +3 -0
  464. package/dist/chat-ui/statewire.js.map +1 -1
  465. package/dist/chat-ui/thread/chat-thread-shell.cjs +45 -14
  466. package/dist/chat-ui/thread/chat-thread-shell.cjs.map +1 -1
  467. package/dist/chat-ui/thread/chat-thread-shell.d.ts +16 -2
  468. package/dist/chat-ui/thread/chat-thread-shell.js +37 -6
  469. package/dist/chat-ui/thread/chat-thread-shell.js.map +1 -1
  470. package/dist/chat-ui/thread/composer-send-or-stop.cjs +30 -20
  471. package/dist/chat-ui/thread/composer-send-or-stop.cjs.map +1 -1
  472. package/dist/chat-ui/thread/composer-send-or-stop.d.ts +8 -0
  473. package/dist/chat-ui/thread/composer-send-or-stop.js +29 -19
  474. package/dist/chat-ui/thread/composer-send-or-stop.js.map +1 -1
  475. package/dist/chat-ui/thread/statewire-history-edge.cjs +20 -21
  476. package/dist/chat-ui/thread/statewire-history-edge.cjs.map +1 -1
  477. package/dist/chat-ui/thread/statewire-history-edge.js +3 -4
  478. package/dist/chat-ui/thread/statewire-history-edge.js.map +1 -1
  479. package/dist/chat-ui/thread/thread-loading-overlay.cjs +5 -5
  480. package/dist/chat-ui/thread/thread-loading-overlay.cjs.map +1 -1
  481. package/dist/collab/client.cjs +52 -3
  482. package/dist/collab/client.cjs.map +1 -1
  483. package/dist/collab/client.d.ts +27 -0
  484. package/dist/collab/client.js +52 -3
  485. package/dist/collab/client.js.map +1 -1
  486. package/dist/collab/document-status.cjs +150 -0
  487. package/dist/collab/document-status.cjs.map +1 -0
  488. package/dist/collab/document-status.d.ts +68 -0
  489. package/dist/collab/document-status.js +150 -0
  490. package/dist/collab/document-status.js.map +1 -0
  491. package/dist/collab/index.cjs +7 -0
  492. package/dist/collab/index.cjs.map +1 -1
  493. package/dist/collab/index.d.ts +6 -1
  494. package/dist/collab/index.js +7 -0
  495. package/dist/collab/index.js.map +1 -1
  496. package/dist/collab/presence-react.cjs +11 -11
  497. package/dist/collab/presence-react.cjs.map +1 -1
  498. package/dist/collab/react.cjs +6 -6
  499. package/dist/collab/react.cjs.map +1 -1
  500. package/dist/composer/AttachmentContext.cjs +24 -11
  501. package/dist/composer/AttachmentContext.cjs.map +1 -1
  502. package/dist/composer/AttachmentContext.js +18 -5
  503. package/dist/composer/AttachmentContext.js.map +1 -1
  504. package/dist/composer/ComposerAttachmentPreview.cjs +78 -23
  505. package/dist/composer/ComposerAttachmentPreview.cjs.map +1 -1
  506. package/dist/composer/ComposerAttachmentPreview.d.ts +5 -3
  507. package/dist/composer/ComposerAttachmentPreview.js +79 -24
  508. package/dist/composer/ComposerAttachmentPreview.js.map +1 -1
  509. package/dist/composer/ComposerDropZone.cjs +7 -7
  510. package/dist/composer/ComposerDropZone.cjs.map +1 -1
  511. package/dist/composer/FileUploadButton.cjs +37 -22
  512. package/dist/composer/FileUploadButton.cjs.map +1 -1
  513. package/dist/composer/FileUploadButton.d.ts +6 -0
  514. package/dist/composer/FileUploadButton.js +34 -19
  515. package/dist/composer/FileUploadButton.js.map +1 -1
  516. package/dist/composer/QuoteContext.cjs +8 -8
  517. package/dist/composer/QuoteContext.cjs.map +1 -1
  518. package/dist/composer/composer-handoff.cjs +4 -4
  519. package/dist/composer/composer-handoff.cjs.map +1 -1
  520. package/dist/composer/index.d.ts +1 -1
  521. package/dist/composer/useAppendToComposer.cjs +4 -4
  522. package/dist/composer/useAppendToComposer.cjs.map +1 -1
  523. package/dist/composer/useAttachFiles.cjs +23 -6
  524. package/dist/composer/useAttachFiles.cjs.map +1 -1
  525. package/dist/composer/useAttachFiles.d.ts +15 -7
  526. package/dist/composer/useAttachFiles.js +22 -5
  527. package/dist/composer/useAttachFiles.js.map +1 -1
  528. package/dist/composer/useComposerAttachment.cjs +4 -4
  529. package/dist/composer/useComposerAttachment.cjs.map +1 -1
  530. package/dist/composer/useFileUpload.cjs +21 -16
  531. package/dist/composer/useFileUpload.cjs.map +1 -1
  532. package/dist/composer/useFileUpload.d.ts +12 -0
  533. package/dist/composer/useFileUpload.js +12 -7
  534. package/dist/composer/useFileUpload.js.map +1 -1
  535. package/dist/composer/useReadComposerDraft.cjs +27 -8
  536. package/dist/composer/useReadComposerDraft.cjs.map +1 -1
  537. package/dist/composer/useReadComposerDraft.d.ts +23 -1
  538. package/dist/composer/useReadComposerDraft.js +27 -8
  539. package/dist/composer/useReadComposerDraft.js.map +1 -1
  540. package/dist/composer/useSendMessage.cjs +4 -4
  541. package/dist/composer/useSendMessage.cjs.map +1 -1
  542. package/dist/diagnostics/useAthenaDiagnostics.cjs +4 -4
  543. package/dist/diagnostics/useAthenaDiagnostics.cjs.map +1 -1
  544. package/dist/dictation/audio-level-history.cjs +3 -3
  545. package/dist/dictation/audio-level-history.cjs.map +1 -1
  546. package/dist/dictation/dictation-controls.cjs +24 -20
  547. package/dist/dictation/dictation-controls.cjs.map +1 -1
  548. package/dist/dictation/dictation-controls.d.ts +6 -1
  549. package/dist/dictation/dictation-controls.js +24 -20
  550. package/dist/dictation/dictation-controls.js.map +1 -1
  551. package/dist/dictation/use-athena-dictation-engine.cjs +3 -3
  552. package/dist/dictation/use-athena-dictation-engine.cjs.map +1 -1
  553. package/dist/dictation/use-dictation.cjs +22 -22
  554. package/dist/dictation/use-dictation.cjs.map +1 -1
  555. package/dist/index.cjs +29 -2
  556. package/dist/index.cjs.map +1 -1
  557. package/dist/index.d.ts +18 -4
  558. package/dist/index.js +30 -3
  559. package/dist/index.js.map +1 -1
  560. package/dist/keryx-http/src/receive-only-socket.cjs +40 -0
  561. package/dist/keryx-http/src/receive-only-socket.cjs.map +1 -0
  562. package/dist/keryx-http/src/receive-only-socket.d.ts +27 -0
  563. package/dist/keryx-http/src/receive-only-socket.js +40 -0
  564. package/dist/keryx-http/src/receive-only-socket.js.map +1 -0
  565. package/dist/keryx-http/src/unconfirmed-update-attributions.cjs +190 -0
  566. package/dist/keryx-http/src/unconfirmed-update-attributions.cjs.map +1 -0
  567. package/dist/keryx-http/src/unconfirmed-update-attributions.d.ts +132 -0
  568. package/dist/keryx-http/src/unconfirmed-update-attributions.js +190 -0
  569. package/dist/keryx-http/src/unconfirmed-update-attributions.js.map +1 -0
  570. package/dist/keryx-http/src/update-attributions.cjs +141 -0
  571. package/dist/keryx-http/src/update-attributions.cjs.map +1 -0
  572. package/dist/keryx-http/src/update-attributions.d.ts +107 -0
  573. package/dist/keryx-http/src/update-attributions.js +141 -0
  574. package/dist/keryx-http/src/update-attributions.js.map +1 -0
  575. package/dist/lib/owner-document.cjs +6 -6
  576. package/dist/lib/owner-document.cjs.map +1 -1
  577. package/dist/lib/use-athena-rest-query.cjs +4 -4
  578. package/dist/lib/use-athena-rest-query.cjs.map +1 -1
  579. package/dist/lib/use-document-active.cjs +4 -4
  580. package/dist/lib/use-document-active.cjs.map +1 -1
  581. package/dist/lib/use-prefers-reduced-motion.cjs +2 -2
  582. package/dist/lib/use-prefers-reduced-motion.cjs.map +1 -1
  583. package/dist/offline/offline-history.cjs +7 -7
  584. package/dist/offline/offline-history.cjs.map +1 -1
  585. package/dist/provider/AthenaContext.cjs +3 -3
  586. package/dist/provider/AthenaContext.cjs.map +1 -1
  587. package/dist/provider/AthenaProvider.cjs +120 -79
  588. package/dist/provider/AthenaProvider.cjs.map +1 -1
  589. package/dist/provider/AthenaProvider.d.ts +11 -1
  590. package/dist/provider/AthenaProvider.js +44 -3
  591. package/dist/provider/AthenaProvider.js.map +1 -1
  592. package/dist/provider/PostHogProvider.cjs +2 -2
  593. package/dist/provider/PostHogProvider.cjs.map +1 -1
  594. package/dist/provider/agent-selection-context.cjs +2 -2
  595. package/dist/provider/agent-selection-context.cjs.map +1 -1
  596. package/dist/provider/chat-mode-context.cjs +2 -2
  597. package/dist/provider/chat-mode-context.cjs.map +1 -1
  598. package/dist/provider/session-persistence-context.cjs +10 -0
  599. package/dist/provider/session-persistence-context.cjs.map +1 -0
  600. package/dist/provider/session-persistence-context.d.ts +15 -0
  601. package/dist/provider/session-persistence-context.js +10 -0
  602. package/dist/provider/session-persistence-context.js.map +1 -0
  603. package/dist/provider/statewire-history-context.cjs +4 -4
  604. package/dist/provider/statewire-history-context.cjs.map +1 -1
  605. package/dist/provider/statewire-lifecycle-context.cjs +3 -3
  606. package/dist/provider/statewire-lifecycle-context.cjs.map +1 -1
  607. package/dist/provider/statewire-window-context.cjs +3 -3
  608. package/dist/provider/statewire-window-context.cjs.map +1 -1
  609. package/dist/provider/theme-style-context.cjs +3 -3
  610. package/dist/provider/theme-style-context.cjs.map +1 -1
  611. package/dist/react/package.json.cjs +1 -1
  612. package/dist/react/package.json.js +1 -1
  613. package/dist/runtime/StatewireThreadConfigLaneSync.cjs +10 -10
  614. package/dist/runtime/StatewireThreadConfigLaneSync.cjs.map +1 -1
  615. package/dist/runtime/auth-refusal-restart.cjs +7 -7
  616. package/dist/runtime/auth-refusal-restart.cjs.map +1 -1
  617. package/dist/runtime/auth.cjs +13 -13
  618. package/dist/runtime/auth.cjs.map +1 -1
  619. package/dist/runtime/statewire-lifecycle.cjs +1 -0
  620. package/dist/runtime/statewire-lifecycle.cjs.map +1 -1
  621. package/dist/runtime/statewire-lifecycle.d.ts +3 -1
  622. package/dist/runtime/statewire-lifecycle.js +2 -1
  623. package/dist/runtime/statewire-lifecycle.js.map +1 -1
  624. package/dist/runtime/statewire-server-lane-context.cjs +2 -2
  625. package/dist/runtime/statewire-server-lane-context.cjs.map +1 -1
  626. package/dist/runtime/statewire-session-lane.cjs +4 -4
  627. package/dist/runtime/statewire-session-lane.cjs.map +1 -1
  628. package/dist/runtime/useAthenaStatewireRuntime.cjs +10 -8
  629. package/dist/runtime/useAthenaStatewireRuntime.cjs.map +1 -1
  630. package/dist/runtime/useAthenaStatewireRuntime.d.ts +2 -0
  631. package/dist/runtime/useAthenaStatewireRuntime.js +2 -0
  632. package/dist/runtime/useAthenaStatewireRuntime.js.map +1 -1
  633. package/dist/styles.css +1 -1
  634. package/dist/threads/Inbox.cjs +8 -8
  635. package/dist/threads/Inbox.cjs.map +1 -1
  636. package/dist/threads/SessionList.cjs +9 -9
  637. package/dist/threads/SessionList.cjs.map +1 -1
  638. package/dist/threads/SessionsPage.cjs +11 -11
  639. package/dist/threads/SessionsPage.cjs.map +1 -1
  640. package/dist/threads/api.cjs.map +1 -1
  641. package/dist/threads/api.d.ts +15 -0
  642. package/dist/threads/api.js.map +1 -1
  643. package/dist/threads/conversation-list-fetcher.cjs +13 -5
  644. package/dist/threads/conversation-list-fetcher.cjs.map +1 -1
  645. package/dist/threads/conversation-list-fetcher.d.ts +4 -1
  646. package/dist/threads/conversation-list-fetcher.js +13 -5
  647. package/dist/threads/conversation-list-fetcher.js.map +1 -1
  648. package/dist/threads/index-triggered-refresh.cjs +10 -10
  649. package/dist/threads/index-triggered-refresh.cjs.map +1 -1
  650. package/dist/threads/mark-viewed-thread-read.cjs +12 -12
  651. package/dist/threads/mark-viewed-thread-read.cjs.map +1 -1
  652. package/dist/threads/offline-session-list.cjs +3 -3
  653. package/dist/threads/offline-session-list.cjs.map +1 -1
  654. package/dist/threads/session-list-tab-share.cjs +5 -5
  655. package/dist/threads/session-list-tab-share.cjs.map +1 -1
  656. package/dist/threads/statewire-thread-list.cjs +79 -57
  657. package/dist/threads/statewire-thread-list.cjs.map +1 -1
  658. package/dist/threads/statewire-thread-list.d.ts +20 -8
  659. package/dist/threads/statewire-thread-list.js +28 -6
  660. package/dist/threads/statewire-thread-list.js.map +1 -1
  661. package/dist/threads/thread-id-context.cjs +5 -5
  662. package/dist/threads/thread-id-context.cjs.map +1 -1
  663. package/dist/threads/use-athena-session-attention.cjs +2 -2
  664. package/dist/threads/use-athena-session-attention.cjs.map +1 -1
  665. package/dist/threads/use-athena-sessions.cjs +37 -15
  666. package/dist/threads/use-athena-sessions.cjs.map +1 -1
  667. package/dist/threads/use-athena-sessions.d.ts +10 -5
  668. package/dist/threads/use-athena-sessions.js +28 -6
  669. package/dist/threads/use-athena-sessions.js.map +1 -1
  670. package/dist/threads/use-athena-thread-model.cjs +3 -3
  671. package/dist/threads/use-athena-thread-model.cjs.map +1 -1
  672. package/dist/threads/use-rest-conversation-history.cjs +3 -3
  673. package/dist/threads/use-rest-conversation-history.cjs.map +1 -1
  674. package/dist/threads/use-rest-conversation-history.d.ts +1 -0
  675. package/dist/threads/use-statewire-conversation-history.cjs +8 -8
  676. package/dist/threads/use-statewire-conversation-history.cjs.map +1 -1
  677. package/dist/threads/use-thread-archive.cjs +9 -9
  678. package/dist/threads/use-thread-archive.cjs.map +1 -1
  679. package/dist/threads/use-thread-favorite.cjs +2 -2
  680. package/dist/threads/use-thread-favorite.cjs.map +1 -1
  681. package/dist/threads/use-thread-field-override.cjs +20 -20
  682. package/dist/threads/use-thread-field-override.cjs.map +1 -1
  683. package/dist/threads/use-thread-read-state.cjs +4 -4
  684. package/dist/threads/use-thread-read-state.cjs.map +1 -1
  685. package/dist/threads/use-thread-rename.cjs +2 -2
  686. package/dist/threads/use-thread-rename.cjs.map +1 -1
  687. package/dist/threads/useAthenaThreadManager.cjs +2 -2
  688. package/dist/threads/useAthenaThreadManager.cjs.map +1 -1
  689. package/dist/tools/NestedPtcMessages.cjs +6 -6
  690. package/dist/tools/NestedPtcMessages.cjs.map +1 -1
  691. package/dist/tools/append-document-tool-ui.cjs +7 -7
  692. package/dist/tools/append-document-tool-ui.cjs.map +1 -1
  693. package/dist/tools/file-tool-uis.cjs +2 -2
  694. package/dist/tools/file-tool-uis.cjs.map +1 -1
  695. package/dist/tools/misc-tool-uis.cjs +2 -2
  696. package/dist/tools/misc-tool-uis.cjs.map +1 -1
  697. package/dist/tools/primitives.cjs +6 -6
  698. package/dist/tools/primitives.cjs.map +1 -1
  699. package/dist/tools/read-asset-tool-ui.cjs +6 -6
  700. package/dist/tools/read-asset-tool-ui.cjs.map +1 -1
  701. package/dist/tools/subagent-task-tool-ui.cjs +21 -21
  702. package/dist/tools/subagent-task-tool-ui.cjs.map +1 -1
  703. package/dist/tools/test-recording-tool-uis.cjs +16 -16
  704. package/dist/tools/test-recording-tool-uis.cjs.map +1 -1
  705. package/dist/tools/todo-plan-store.cjs +4 -4
  706. package/dist/tools/todo-plan-store.cjs.map +1 -1
  707. package/dist/tools/tool-appearance.cjs +3 -3
  708. package/dist/tools/tool-appearance.cjs.map +1 -1
  709. package/dist/tools/tool-fallback.cjs +14 -14
  710. package/dist/tools/tool-fallback.cjs.map +1 -1
  711. package/dist/tools/tool-uis.cjs +74 -74
  712. package/dist/tools/tool-uis.cjs.map +1 -1
  713. package/dist/tools/use-elapsed-seconds.cjs +3 -3
  714. package/dist/tools/use-elapsed-seconds.cjs.map +1 -1
  715. package/dist/tools/write-todos-tool-ui.cjs +9 -9
  716. package/dist/tools/write-todos-tool-ui.cjs.map +1 -1
  717. package/dist/ui/image-viewer.cjs +382 -0
  718. package/dist/ui/image-viewer.cjs.map +1 -0
  719. package/dist/ui/image-viewer.d.ts +50 -0
  720. package/dist/ui/image-viewer.js +382 -0
  721. package/dist/ui/image-viewer.js.map +1 -0
  722. package/dist/voice/chat.cjs +6 -0
  723. package/dist/voice/chat.cjs.map +1 -1
  724. package/dist/voice/chat.d.ts +1 -1
  725. package/dist/voice/chat.js +8 -2
  726. package/dist/voice/livekit-join.cjs +52 -101
  727. package/dist/voice/livekit-join.cjs.map +1 -1
  728. package/dist/voice/livekit-join.d.ts +1 -6
  729. package/dist/voice/livekit-join.js +52 -101
  730. package/dist/voice/livekit-join.js.map +1 -1
  731. package/dist/voice/livekit.cjs.map +1 -1
  732. package/dist/voice/livekit.d.ts +11 -1
  733. package/dist/voice/livekit.js.map +1 -1
  734. package/dist/voice/use-athena-voice-session.cjs +34 -34
  735. package/dist/voice/use-athena-voice-session.cjs.map +1 -1
  736. package/dist/workbench/ComputerLiveDesktop.cjs +13 -13
  737. package/dist/workbench/ComputerLiveDesktop.cjs.map +1 -1
  738. package/dist/workbench/SessionWorkbench.cjs +22 -22
  739. package/dist/workbench/SessionWorkbench.cjs.map +1 -1
  740. package/dist/workbench/session-workbench-context.cjs +3 -3
  741. package/dist/workbench/session-workbench-context.cjs.map +1 -1
  742. package/dist/workbench/session-workbench-panes.cjs +8 -8
  743. package/dist/workbench/session-workbench-panes.cjs.map +1 -1
  744. package/dist/workbench/workbench-layout-context.cjs +3 -3
  745. package/dist/workbench/workbench-layout-context.cjs.map +1 -1
  746. package/package.json +2 -1
@@ -1 +1 @@
1
- {"version":3,"file":"use-deep-agent-voice.js","sources":["../../../../agent-runtime/src/use-deep-agent-voice.ts"],"sourcesContent":["import { useStatewireSendCommand, useStatewireState } from '@assistant-ui/react-statewire';\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { statewireRejectionPayload } from './errors';\nimport { isDeepAgentStateHydrated, readDeepAgentStreamValues } from './statewire-state';\nimport type { DeepAgentVoiceWireError } from './voice-wire-types';\n\ndeclare module '@assistant-ui/core' {\n namespace Assistant {\n interface Commands {\n /**\n * Opens a voice session (`DeepAgentThread.voice_start`). `offer` is the\n * WebRTC SDP offer, {@link VOICE_WEBSOCKET_OFFER} to request the\n * WebSocket audio transport (the answer is then a relay ticket), or\n * {@link VOICE_LIVEKIT_OFFER} to request a LiveKit room (the answer is\n * then the room's join credentials). `model` picks the realtime model\n * (`gpt-live-1`, `gemini-3.8-live`, …); omitted → the host's default.\n */\n voiceStart: {\n type: 'voice/start';\n offer: string;\n model?: string;\n /** Correlates commands with this call, including delayed cleanup. */\n attemptId?: string;\n previousAttemptId?: string;\n };\n /** Ends the live voice session (`DeepAgentThread.voice_end`). */\n voiceEnd: {\n type: 'voice/end';\n attemptId?: string;\n };\n /**\n * No-op whose INGRESS refreshes the caller's server-stored context\n * (context syncs ride command sends), so runConfig changes made while a\n * voice session is live reach the delegated runs.\n */\n voiceProfileSync: {\n type: 'voice/profile-sync';\n attemptId?: string;\n };\n /**\n * Mute/unmute the live session's microphone at the protocol level\n * (`DeepAgentThread.voice_set_mic` → `session.input_audio.mute`/`unmute`).\n */\n voiceSetMic: {\n type: 'voice/set-mic';\n attemptId?: string;\n paused: boolean;\n };\n /**\n * Route a typed message into the live conversation\n * (`DeepAgentThread.voice_user_text`): commits durably as a\n * `source: \"text\"` user turn and reaches the live model as speakable\n * context, so it responds by voice exactly as it would to speech.\n * `messageId` is client-minted so a durable-command redelivery after a\n * host crash commits idempotently instead of duplicating the turn.\n */\n voiceUserText: {\n type: 'voice/user-text';\n attemptId?: string;\n text: string;\n messageId: string;\n };\n /**\n * Tell the live session what the user is looking at\n * (`DeepAgentThread.voice_context`): one short description of the open\n * asset or page, appended as silent commentary so the live model can\n * resolve \"this document\" without delegating. Never spoken, never\n * persisted; identical consecutive descriptions are dropped server-side.\n */\n voiceContext: {\n type: 'voice/context';\n attemptId?: string;\n text: string;\n };\n }\n }\n}\n\n/** A voice-delegated frontend tool call projected by legacy hosts\n * (`arguments` is a JSON string). Current hosts run frontend tools through\n * the delegated run's client-tool interrupts, so this stays empty. */\nexport interface DeepAgentVoiceToolCall {\n callId: string;\n name: string;\n arguments: string;\n}\n\n/** The host's `state.voice` projection while a session exists. */\nexport interface DeepAgentVoiceWireState {\n clientId: string;\n status: 'connecting' | 'live';\n toolCalls: DeepAgentVoiceToolCall[];\n /** The delegated voice task currently running, if any. */\n activeTask?: { taskId: string; text: string } | null;\n}\n\nexport type DeepAgentVoicePhase = 'idle' | 'connecting' | 'live' | 'error';\n\n/**\n * Why a voice session failed, classified where the failure happened rather\n * than by parsing the message afterwards. `server_rejected` carries the\n * host's structured code (`voice-active`, `voice-not-enabled`,\n * `voice-unavailable`, `checkpointer_unavailable`, …); `media_lost` carries the\n * transport state that ended the session. Every surface reports and words the\n * same kinds, so telemetry across Olympus, Chrome, and mobile joins on them.\n */\nexport type DeepAgentVoiceFailureKind =\n | 'unsupported'\n | 'audio_session'\n | 'microphone_denied'\n | 'capture_failed'\n | 'offer_failed'\n | 'answer_timeout'\n | 'server_rejected'\n | 'command_failed'\n | 'no_answer'\n | 'answer_failed'\n | 'relay_failed'\n | 'room_failed'\n | 'playback_failed'\n | 'media_lost'\n | 'unknown';\n\n/** Where in the session's lifecycle a failure happened. */\nexport type DeepAgentVoiceFailureStage =\n | 'preflight'\n | 'audio-session'\n | 'capture'\n | 'offer'\n | 'negotiate'\n | 'answer'\n | 'relay'\n | 'room'\n | 'media'\n | 'playback';\n\nexport interface DeepAgentVoiceFailure {\n kind: DeepAgentVoiceFailureKind;\n stage: DeepAgentVoiceFailureStage;\n /** The message surfaces render (the same value as `error`). */\n message: string;\n /** The host's rejection reason / structured `detail.code`, when it sent one. */\n code?: string;\n /** The rejection's HTTP-style status, when the host sent a structured one. */\n status?: number;\n /** The statewire send fate when the command settled without a verdict. */\n fate?: string;\n /**\n * The lower-level reason: the media state that ended the session\n * (`failed` / `closed` / `disconnected` / `relay-closed` / `relay-error`), or\n * the channel death that settled the command (`unmount` / `stream-gone` /\n * `session-lost`).\n */\n reason?: string;\n}\n\n/**\n * Lifecycle milestones of a session attempt, for surfaces that record them\n * (crash breadcrumbs, latency telemetry). `attempt` groups one start's\n * events; `sinceStartMs` is measured from that attempt's `start-requested`.\n */\nexport type DeepAgentVoiceDiagnosticEvent =\n | 'start-requested'\n | 'audio-session-ready'\n | 'microphone-captured'\n | 'offer-ready'\n | 'ice-gathering-timeout'\n | 'answer-received'\n | 'room-joined'\n | 'live'\n | 'media-state'\n | 'media-loss'\n | 'auto-restart'\n | 'server-ended'\n | 'end'\n | 'error'\n | 'stale-attempt';\n\nexport interface DeepAgentVoiceDiagnostic {\n event: DeepAgentVoiceDiagnosticEvent;\n attempt: number;\n /** Epoch ms. */\n at: number;\n sinceStartMs: number;\n data?: Record<string, string | number | boolean | null>;\n}\n\n/** The statewire send failure a rejected/failed command carries (`error.failure`). */\ninterface VoiceCommandSendFailure {\n fate: string;\n cause?: string;\n code?: string;\n message?: string;\n payload?: unknown;\n}\n\nconst readSendFailure = (error: unknown): VoiceCommandSendFailure | null => {\n const failure = (error as { failure?: unknown } | null | undefined)?.failure;\n if (failure === null || typeof failure !== 'object') return null;\n return typeof (failure as { fate?: unknown }).fate === 'string'\n ? (failure as VoiceCommandSendFailure)\n : null;\n};\n\nconst errorMessage = (error: unknown): string =>\n error instanceof Error ? error.message : String(error);\n\n/** Marker for the local answer deadline, so the timeout classifies by identity. */\nclass VoiceAnswerTimeoutError extends Error {\n constructor() {\n super('The voice session did not answer in time');\n this.name = 'VoiceAnswerTimeoutError';\n }\n}\n\n/**\n * Classify a failed `voice/start` command. A host rejection keeps the host's\n * reason (`payload.reason` from the voice manager, `payload.detail.code` from\n * the command gate's structured envelope) and its own user-worded message; a\n * command the channel settled without a verdict reports its fate.\n */\nexport const classifyVoiceStartError = (\n error: unknown\n): Pick<DeepAgentVoiceFailure, 'kind' | 'message' | 'code' | 'status' | 'fate' | 'reason'> => {\n if (error instanceof VoiceAnswerTimeoutError) {\n return { kind: 'answer_timeout', message: error.message };\n }\n const failure = readSendFailure(error);\n if (failure === null) return { kind: 'unknown', message: errorMessage(error) };\n if (failure.fate === 'rejected') {\n const payload = failure.payload as\n | { reason?: unknown; status?: unknown; detail?: unknown }\n | null\n | undefined;\n const detail = payload?.detail as { code?: unknown; message?: unknown } | null | undefined;\n const reason = typeof payload?.reason === 'string' ? payload.reason : undefined;\n const detailCode = typeof detail?.code === 'string' ? detail.code : undefined;\n const detailMessage = typeof detail?.message === 'string' ? detail.message : undefined;\n const code = reason ?? detailCode ?? failure.code;\n const status = typeof payload?.status === 'number' ? payload.status : undefined;\n return {\n kind: 'server_rejected',\n message: failure.message ?? detailMessage ?? errorMessage(error),\n ...(code !== undefined && { code }),\n ...(status !== undefined && { status }),\n };\n }\n return {\n kind: 'command_failed',\n message: failure.message ?? errorMessage(error),\n fate: failure.fate,\n ...(failure.cause !== undefined && failure.cause !== 'server' && { reason: failure.cause }),\n };\n};\n\n/** Marker for a verdict that carried no SDP answer / relay ticket / room. */\nclass VoiceNoAnswerError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'VoiceNoAnswerError';\n }\n}\n\n/**\n * Decode a `voice/start` answer on the `livekit` transport. Throws (as a\n * `no_answer` failure when raised in the `answer` stage) on a missing prefix,\n * malformed JSON, or a missing/non-string field — a host that answered with\n * something else did not open a LiveKit room for this client.\n */\nexport const parseVoiceLiveKitAnswer = (answer: string): DeepAgentVoiceLiveKitAnswer => {\n if (!answer.startsWith(VOICE_LIVEKIT_ANSWER_PREFIX)) {\n throw new VoiceNoAnswerError('voice/start returned no voice room');\n }\n let parsed: unknown;\n try {\n parsed = JSON.parse(answer.slice(VOICE_LIVEKIT_ANSWER_PREFIX.length));\n } catch {\n throw new VoiceNoAnswerError('voice/start returned a malformed voice room');\n }\n const record = (parsed ?? null) as {\n serverUrl?: unknown;\n token?: unknown;\n roomName?: unknown;\n } | null;\n const serverUrl = record?.serverUrl;\n const token = record?.token;\n const roomName = record?.roomName;\n if (\n typeof serverUrl !== 'string' ||\n serverUrl === '' ||\n typeof token !== 'string' ||\n token === '' ||\n typeof roomName !== 'string' ||\n roomName === ''\n ) {\n throw new VoiceNoAnswerError('voice/start returned an incomplete voice room');\n }\n return { serverUrl, token, roomName };\n};\n\n/** The failure for an error thrown while `stage` was under way. */\nconst classifyStartFailure = (\n error: unknown,\n stage: DeepAgentVoiceFailureStage\n): DeepAgentVoiceFailure => {\n const message = errorMessage(error);\n switch (stage) {\n case 'preflight':\n return { kind: 'unsupported', stage, message };\n case 'audio-session':\n return { kind: 'audio_session', stage, message };\n case 'capture':\n return {\n kind: isMicrophoneDenied(error) ? 'microphone_denied' : 'capture_failed',\n stage,\n message,\n };\n case 'offer':\n return { kind: 'offer_failed', stage, message };\n case 'negotiate':\n return { ...classifyVoiceStartError(error), stage };\n case 'answer':\n return {\n kind: error instanceof VoiceNoAnswerError ? 'no_answer' : 'answer_failed',\n stage,\n message,\n };\n case 'relay':\n return { kind: 'relay_failed', stage, message };\n case 'room':\n // LiveKit captures the microphone while joining, so a permission\n // refusal surfaces here rather than in a `capture` stage.\n return {\n kind: isMicrophoneDenied(error) ? 'microphone_denied' : 'room_failed',\n stage,\n message,\n };\n default:\n return { kind: 'unknown', stage, message };\n }\n};\n\nconst isMicrophoneDenied = (error: unknown): boolean => {\n const name = (error as { name?: unknown } | null | undefined)?.name;\n if (\n name === 'SecurityError' ||\n name === 'NotAllowedError' ||\n name === 'PermissionDeniedError'\n ) {\n return true;\n }\n return /permission|denied|not allowed/i.test(errorMessage(error));\n};\n\n/**\n * User-facing copy for a failure, shared so every surface words the same\n * cause alike. Host rejections keep the host's own wording (it already names\n * the actionable cause); the local kinds get a sentence the user can act on.\n */\nexport const describeVoiceFailure = (failure: DeepAgentVoiceFailure): string => {\n switch (failure.kind) {\n case 'microphone_denied':\n return 'Microphone access is blocked. Allow the microphone for Athena and try again.';\n case 'unsupported':\n return 'Voice mode is not available in this environment.';\n case 'audio_session':\n return `The audio session could not start: ${failure.message}`;\n case 'answer_timeout':\n return 'The voice session did not answer in time. Check your connection and try again.';\n case 'room_failed':\n return 'The voice room could not be joined. Check your connection and try again.';\n case 'media_lost':\n return 'The voice connection was lost. Start voice again to continue.';\n case 'server_rejected':\n if (failure.code === 'voice-active') {\n return 'A voice session is already live on another device or tab. End it there first.';\n }\n if (failure.code === 'voice-not-enabled') {\n return 'Voice mode is not enabled for this workspace.';\n }\n return failure.message;\n default:\n return failure.message;\n }\n};\n\n/**\n * How the session's audio travels. `webrtc` (the default) negotiates a peer\n * connection straight to OpenAI; `websocket` captures PCM locally and streams\n * it to Agora's relay endpoint, for surfaces where WebRTC is unavailable\n * (Office add-in webviews, UDP-blocked networks) — web only: it needs\n * `AudioContext` and `WebSocket` globals. `livekit` joins the LiveKit room the\n * host mints for the session through a caller-supplied\n * {@link DeepAgentVoiceLiveKitAdapter}; Agora joins the same room as the agent\n * participant, so this is the only transport on which the realtime model is a\n * per-session choice (`gpt-live-1`, `gemini-3.8-live`, …) — the other two are\n * OpenAI-direct media legs and stay GPT Live only.\n */\nexport type DeepAgentVoiceTransport = 'webrtc' | 'websocket' | 'livekit';\n\n/**\n * The `voice/start` offer that requests the WebSocket transport. Mirrors\n * `agora.services.voice_relay.VOICE_WEBSOCKET_OFFER`.\n */\nexport const VOICE_WEBSOCKET_OFFER = 'athena-voice-transport:websocket/v1';\n/** Prefix of a `voice/start` answer that carries a relay ticket, not an SDP answer. */\nexport const VOICE_RELAY_ANSWER_PREFIX = 'athena-voice-relay:';\n/** The relay's wire format: raw PCM16, mono, 24 kHz (the Live API's PCM format). */\nexport const VOICE_RELAY_SAMPLE_RATE = 24_000;\n/**\n * The `voice/start` offer that requests the LiveKit transport. Mirrors\n * `agora.graphs.athena_deep_agent.voice_media.VOICE_LIVEKIT_OFFER`.\n */\nexport const VOICE_LIVEKIT_OFFER = 'athena-voice-transport:livekit/v1';\n/**\n * Prefix of a `voice/start` answer that carries LiveKit room credentials: the\n * rest is `JSON.stringify({ serverUrl, token, roomName })`. Mirrors\n * `agora.graphs.athena_deep_agent.voice_media.VOICE_LIVEKIT_ANSWER_PREFIX`.\n */\nexport const VOICE_LIVEKIT_ANSWER_PREFIX = 'athena-voice-livekit:';\n\n/** The room the host minted for the session, decoded from the `voice/start` answer. */\nexport interface DeepAgentVoiceLiveKitAnswer {\n /** LiveKit signalling URL, already `wss://`. */\n serverUrl: string;\n /** The browser participant's join token (`room_join`, publish, subscribe). */\n token: string;\n roomName: string;\n}\n\n/** A joined LiveKit room, as far as the session state machine drives it. */\nexport interface DeepAgentVoiceLiveKitSession {\n /** Publish/unpublish (or unmute/mute) the local microphone track. */\n setMicrophoneEnabled(enabled: boolean): Promise<void>;\n /** Leave the room and release the microphone. Idempotent. */\n disconnect(): Promise<void>;\n}\n\n/**\n * The LiveKit leg of the `livekit` transport, supplied by the surface so this\n * package never depends on `livekit-client` (web surfaces wrap `Room`; native\n * ones wrap the React Native SDK). Structural on purpose: tests inject fakes.\n */\nexport interface DeepAgentVoiceLiveKitAdapter {\n /**\n * Join the room, publish the microphone (respecting `micMuted`), play remote\n * audio; rejects on failure (a microphone-permission error keeps its DOM\n * `name`, so it classifies as `microphone_denied`). `onDisconnected` fires\n * once when the room drops AFTER a successful join — never for the session's\n * own `disconnect()`. An aborted `signal` must stop pending/joined media and\n * reject a pending join; the runtime also releases late results from older\n * adapters that do not implement cancellation.\n */\n connect(\n answer: DeepAgentVoiceLiveKitAnswer,\n handlers: {\n micMuted: boolean;\n /** Abort a pending join and release media when this attempt ends. */\n signal?: AbortSignal;\n onDisconnected: (reason: string) => void;\n }\n ): Promise<DeepAgentVoiceLiveKitSession>;\n}\n\n/** One realtime model the host offers for voice sessions (`state.voiceModelOptions`). */\nexport interface DeepAgentVoiceModelOption {\n id: string;\n label: string;\n provider: 'openai_live' | 'google';\n /** `false` when the deployment lacks the provider's credentials. */\n enabled: boolean;\n description: string;\n}\n\nconst VOICE_MODEL_PROVIDERS: ReadonlySet<string> = new Set(['openai_live', 'google']);\n\n/**\n * Validate the host's `state.voiceModelOptions`: `null` when absent or not a\n * list, otherwise the well-formed entries (a malformed entry is dropped, not\n * fatal — an older or newer host must never blank the whole picker).\n */\nexport const parseVoiceModelOptions = (value: unknown): DeepAgentVoiceModelOption[] | null => {\n if (!Array.isArray(value)) return null;\n const options: DeepAgentVoiceModelOption[] = [];\n for (const entry of value) {\n if (entry === null || typeof entry !== 'object') continue;\n const { id, label, provider, enabled, description } = entry as Record<string, unknown>;\n if (\n typeof id !== 'string' ||\n id === '' ||\n typeof label !== 'string' ||\n typeof provider !== 'string' ||\n !VOICE_MODEL_PROVIDERS.has(provider) ||\n typeof enabled !== 'boolean' ||\n typeof description !== 'string'\n ) {\n continue;\n }\n options.push({\n id,\n label,\n provider: provider as DeepAgentVoiceModelOption['provider'],\n enabled,\n description,\n });\n }\n return options;\n};\n\nconst sameVoiceModelOptions = (\n a: readonly DeepAgentVoiceModelOption[],\n b: readonly DeepAgentVoiceModelOption[]\n): boolean =>\n a.length === b.length &&\n a.every((option, index) => {\n const other = b[index];\n return (\n other !== undefined &&\n option.id === other.id &&\n option.label === other.label &&\n option.provider === other.provider &&\n option.enabled === other.enabled &&\n option.description === other.description\n );\n });\n\n// This package compiles without the DOM lib; the WebRTC / Web Audio /\n// WebSocket surfaces the hook touches are declared structurally and resolved\n// from `globalThis` (browser, extension page, or react-native-webrtc's\n// registerGlobals).\ninterface VoiceMediaStreamTrack {\n /** Standard WebRTC mute lever: a disabled track transmits silence. */\n enabled: boolean;\n stop(): void;\n}\n\nexport interface DeepAgentVoiceRemoteStream {\n getTracks(): VoiceMediaStreamTrack[];\n /** React Native WebRTC owns native stream/track entries beyond track.stop(). */\n release?(): void;\n}\n\nfunction releaseCaptureStream(stream: DeepAgentVoiceRemoteStream | null): void {\n if (!stream) return;\n releaseSafely(() => {\n for (const track of stream.getTracks()) releaseSafely(() => track.stop());\n });\n releaseSafely(() => stream.release?.());\n}\n\n/** One failed native/browser cleanup must not strand the remaining media. */\nfunction releaseSafely(release: () => unknown): void {\n try {\n void Promise.resolve(release()).catch(() => undefined);\n } catch {\n // Teardown is best-effort, including synchronous native bridge failures.\n }\n}\n\ninterface VoiceTrackEvent {\n track: VoiceMediaStreamTrack;\n streams: DeepAgentVoiceRemoteStream[];\n}\n\ntype VoiceConnectionStateEvent = 'connectionstatechange' | 'iceconnectionstatechange';\n\ninterface VoicePeerConnection {\n readonly iceGatheringState: string;\n /** Aggregate transport state (`connected`, `disconnected`, `failed`, `closed`). */\n readonly connectionState?: string;\n /** ICE-only state; the fallback where an implementation lacks `connectionState`. */\n readonly iceConnectionState?: string;\n readonly localDescription: { readonly sdp?: string } | null;\n addTrack(track: VoiceMediaStreamTrack, stream: DeepAgentVoiceRemoteStream): unknown;\n addEventListener(type: 'track', listener: (event: VoiceTrackEvent) => void): void;\n addEventListener(type: 'icegatheringstatechange', listener: () => void): void;\n addEventListener(type: VoiceConnectionStateEvent, listener: () => void): void;\n removeEventListener(type: 'icegatheringstatechange', listener: () => void): void;\n removeEventListener(type: 'track', listener: (event: VoiceTrackEvent) => void): void;\n removeEventListener(type: VoiceConnectionStateEvent, listener: () => void): void;\n createOffer(): Promise<{ sdp?: string }>;\n setLocalDescription(description: { sdp?: string }): Promise<void>;\n setRemoteDescription(description: { type: 'answer'; sdp: string }): Promise<void>;\n close(): void;\n}\n\ninterface VoiceWebSocket {\n binaryType: string;\n /** 0 connecting, 1 open, 2 closing, 3 closed. */\n readonly readyState: number;\n send(data: ArrayBufferLike): void;\n close(code?: number, reason?: string): void;\n addEventListener(type: 'open' | 'close' | 'error', listener: () => void): void;\n addEventListener(type: 'message', listener: (event: { data: unknown }) => void): void;\n}\n\ninterface VoiceAudioNode {\n connect(destination: VoiceAudioNode): unknown;\n disconnect(): void;\n}\n\ninterface VoiceAudioBuffer {\n readonly duration: number;\n copyToChannel(source: Float32Array, channel: number): void;\n}\n\ninterface VoiceBufferSource extends VoiceAudioNode {\n buffer: VoiceAudioBuffer | null;\n start(when?: number): void;\n}\n\ninterface VoiceScriptProcessor extends VoiceAudioNode {\n onaudioprocess:\n | ((event: { inputBuffer: { getChannelData(channel: number): Float32Array } }) => void)\n | null;\n}\n\ninterface VoiceGainNode extends VoiceAudioNode {\n gain: { value: number };\n}\n\ninterface VoiceAudioContext {\n readonly currentTime: number;\n readonly destination: VoiceAudioNode;\n createMediaStreamSource(stream: DeepAgentVoiceRemoteStream): VoiceAudioNode;\n createScriptProcessor(\n bufferSize: number,\n inputChannels: number,\n outputChannels: number\n ): VoiceScriptProcessor;\n createGain(): VoiceGainNode;\n createBuffer(channels: number, length: number, sampleRate: number): VoiceAudioBuffer;\n createBufferSource(): VoiceBufferSource;\n resume?(): Promise<void>;\n close(): Promise<void>;\n}\n\nconst voiceGlobals = globalThis as {\n RTCPeerConnection?: new () => VoicePeerConnection;\n MediaStream?: new (tracks: VoiceMediaStreamTrack[]) => DeepAgentVoiceRemoteStream;\n WebSocket?: new (url: string) => VoiceWebSocket;\n AudioContext?: new (options?: { sampleRate?: number }) => VoiceAudioContext;\n navigator?: {\n mediaDevices?: {\n getUserMedia(constraints: { audio: boolean }): Promise<DeepAgentVoiceRemoteStream>;\n };\n };\n};\n\n// Covers the host's own worst case: up to 30 s for the realtime provider's\n// session.started (`_START_TIMEOUT_SECONDS`, agora gpt_live_provider.py), then\n// the LiveKit room create and join. A tenant egress proxy in front of the\n// provider pushes a healthy start past 15 s; a shorter deadline abandons a\n// session the host is about to answer. scripts/voice-answer-timeout.test.ts\n// keeps the two in step.\nconst ANSWER_TIMEOUT_MS = 45_000;\nconst ICE_TIMEOUT_MS = 10_000;\nconst RELAY_OPEN_TIMEOUT_MS = 10_000;\n/** Capture frame for the WebSocket transport: ~43 ms of audio at 24 kHz. */\nconst RELAY_CAPTURE_FRAME_SAMPLES = 1024;\n/** Playback lead so a chunk scheduled \"now\" never lands in the past. */\nconst RELAY_PLAYBACK_LEAD_SECONDS = 0.02;\n/**\n * How long a `disconnected` transport may try to recover on its own before it\n * counts as lost. ICE routinely reports `disconnected` for a few seconds on a\n * network change and then reconnects; `failed` and `closed` are final.\n */\nconst MEDIA_DISCONNECT_GRACE_MS = 5_000;\n/**\n * Upper bound on waiting for the server to acknowledge `voice/end` before a\n * media-loss restart sends its `voice/start`: a start that races the old\n * session's teardown is rejected `voice-active`.\n */\nconst END_BEFORE_RESTART_TIMEOUT_MS = 3_000;\n\n/** Operation IDs for voice turns and calls (uniqueness, not secrecy) —\n * platform-free on purpose: React Native lacks full webcrypto. */\nconst mintVoiceId = ({ kind }: { kind: 'text' | 'attempt' }): string =>\n `voice${kind}_${Date.now().toString(36)}${Math.random().toString(36).slice(2, 12)}`;\n\n/** `m:ss` / `h:mm:ss` for the live-session timer strips (shared so the three\n * surfaces cannot drift on formatting). */\nexport const formatVoiceElapsed = (sinceMs: number, nowMs: number = Date.now()): string => {\n const total = Math.max(0, Math.floor((nowMs - sinceMs) / 1000));\n const hours = Math.floor(total / 3600);\n const minutes = Math.floor((total % 3600) / 60);\n const seconds = total % 60;\n const mmss = `${minutes}:${String(seconds).padStart(2, '0')}`;\n return hours > 0 ? `${hours}:${String(minutes).padStart(2, '0')}:${String(seconds).padStart(2, '0')}` : mmss;\n};\n\n/** Ticking elapsed-call string for a live session — the one timer\n * implementation all surfaces share (interval lifecycle + formatting).\n * Returns `null` when there is no live session. Callers isolate it in a\n * leaf component so only that leaf re-renders per second. */\nexport const useVoiceElapsed = (since: number | null): string | null => {\n const [now, setNow] = useState(() => Date.now());\n useEffect(() => {\n if (since === null) return;\n setNow(Date.now());\n const timer = setInterval(() => setNow(Date.now()), 1000);\n return () => clearInterval(timer);\n }, [since]);\n return since === null ? null : formatVoiceElapsed(since, now);\n};\n\nconst REQUEST_LABELS: Record<string, string> = {\n 'session.commentary.append': 'a result for the voice conversation',\n 'session.thinking.append': 'a context update',\n 'session.input_audio.mute': 'the mute request',\n 'session.input_audio.unmute': 'the unmute request',\n 'response.item.create': 'a tool result',\n};\n\n/**\n * One-line, user-facing rendering of a Live API rejection the host projected\n * (`state.voiceLastError`). Shared so every surface words the notice alike.\n */\nexport const describeVoiceWireError = (error: DeepAgentVoiceWireError): string => {\n const subject = error.requestType\n ? (REQUEST_LABELS[error.requestType] ?? `a ${error.requestType} event`)\n : 'a session event';\n return `The voice service rejected ${subject}: ${error.message}`;\n};\n\n/** The relay endpoint for a ticket: `wss://<agora>/api/voice/relay?ticket=…`. */\nexport const voiceRelayUrl = (relayUrl: string, ticket: string): string =>\n `${relayUrl.replace(/^http/, 'ws').replace(/\\/+$/, '')}/api/voice/relay?ticket=${encodeURIComponent(ticket)}`;\n\n/** Float32 samples in [-1, 1] → little-endian PCM16 (the relay wire format). */\nexport const pcm16FromFloat32 = (samples: Float32Array): Int16Array => {\n const pcm = new Int16Array(samples.length);\n for (let index = 0; index < samples.length; index += 1) {\n const clamped = Math.max(-1, Math.min(1, samples[index] ?? 0));\n pcm[index] = clamped < 0 ? Math.round(clamped * 0x8000) : Math.round(clamped * 0x7fff);\n }\n return pcm;\n};\n\n/** PCM16 → Float32 samples in [-1, 1] for Web Audio playback. */\nexport const float32FromPcm16 = (pcm: Int16Array): Float32Array => {\n const samples = new Float32Array(pcm.length);\n for (let index = 0; index < pcm.length; index += 1) {\n samples[index] = (pcm[index] ?? 0) / 0x8000;\n }\n return samples;\n};\n\nconst isRecoveredCommandAuthRejection = (error: unknown): boolean => {\n const payload = statewireRejectionPayload(error);\n if (payload?.status !== 503) return false;\n const detail = payload.detail as { code?: unknown; retryable?: unknown } | undefined;\n return detail?.code === 'command_auth_context_expired' && detail.retryable === true;\n};\n\n/**\n * Wait for ICE gathering, bounded. Gathering that has not completed by the\n * deadline is NOT a failure: the offer carries the candidates gathered so far\n * and the Live API's answer supplies the server side, so the connectivity\n * checks the client initiates still establish the media path (the API's own\n * reference client sends the offer without waiting at all). Mobile radios with\n * several interfaces routinely take long to declare gathering complete, and\n * failing the whole session on that was a needless hard stop.\n */\nconst waitForIce = (\n pc: VoicePeerConnection,\n timeoutMs: number\n): Promise<'complete' | 'timeout'> =>\n new Promise((resolve) => {\n if (pc.iceGatheringState === 'complete') {\n resolve('complete');\n return;\n }\n const timeout = setTimeout(() => {\n pc.removeEventListener('icegatheringstatechange', check);\n resolve('timeout');\n }, timeoutMs);\n const check = (): void => {\n if (pc.iceGatheringState !== 'complete') return;\n clearTimeout(timeout);\n pc.removeEventListener('icegatheringstatechange', check);\n resolve('complete');\n };\n pc.addEventListener('icegatheringstatechange', check);\n });\n\nconst waitForRelayOpen = (ws: VoiceWebSocket, timeoutMs: number): Promise<void> =>\n new Promise((resolve, reject) => {\n const timeout = setTimeout(\n () => reject(new Error('The voice relay did not open in time')),\n timeoutMs\n );\n ws.addEventListener('open', () => {\n clearTimeout(timeout);\n resolve();\n });\n ws.addEventListener('error', () => {\n clearTimeout(timeout);\n reject(new Error('The voice relay connection failed'));\n });\n ws.addEventListener('close', () => {\n clearTimeout(timeout);\n reject(new Error('The voice relay closed before it opened'));\n });\n });\n\nexport interface UseDeepAgentVoiceOptions {\n /**\n * Remote-audio sink: called with the remote stream when the session answers\n * and with `null` on teardown. Web surfaces attach it to an `<audio>`\n * element; react-native-webrtc plays remote audio natively, so native\n * surfaces omit it. A rejected promise fails the session. WebRTC only: the\n * WebSocket transport plays through its own `AudioContext`.\n */\n onRemoteStream?: (stream: DeepAgentVoiceRemoteStream | null) => void | Promise<void>;\n /**\n * Platform audio-session ownership for the whole call: `start` runs before\n * mic capture (a rejection fails the session), `stop` runs on every\n * teardown path. Native surfaces pass their call-audio module (on iOS the\n * non-mixable playAndRecord/voiceChat session that entitles the app to\n * keep a live call running); web surfaces omit it.\n */\n audioSession?: {\n start: () => Promise<void>;\n stop: () => Promise<void>;\n /** Synchronously mark an in-flight start for cleanup before a new owner starts. */\n cancelStart?: () => void;\n };\n /** Media transport; see {@link DeepAgentVoiceTransport}. Default `webrtc`. */\n transport?: DeepAgentVoiceTransport;\n /**\n * Agora's base URL (e.g. `https://api.athenaintel.com`) whose\n * `/api/voice/relay` endpoint carries the audio on the `websocket`\n * transport. Required for that transport, ignored otherwise.\n */\n relayUrl?: string;\n /**\n * The room leg for the `livekit` transport (required for it, ignored\n * otherwise); see {@link DeepAgentVoiceLiveKitAdapter}. Read through a\n * per-render ref, so a fresh adapter never restarts anything.\n */\n livekit?: DeepAgentVoiceLiveKitAdapter;\n /**\n * The realtime model to ask for, sent as `voice/start.model` — a value or a\n * getter resolved when each attempt (user start or automatic restart)\n * negotiates. `undefined`/empty omits the key and the host picks its\n * default. Only the `livekit` transport can honour a non-GPT-Live model.\n */\n model?: string | (() => string | undefined);\n /**\n * Lifecycle observer for the session attempts (negotiation milestones with\n * timings, media-state changes, losses, restarts, ends). Surfaces feed it to\n * their crash breadcrumbs / telemetry; read through a per-render ref, so a\n * fresh closure never restarts anything. Must not throw.\n */\n onDiagnostic?: (entry: DeepAgentVoiceDiagnostic) => void;\n /** Per-surface overrides of the negotiation deadlines (ms). */\n timeouts?: {\n /** How long to wait for ICE gathering to complete before sending the offer with the candidates so far. */\n iceGatheringMs?: number;\n /** How long `voice/start` may take to answer. */\n answerMs?: number;\n /** How long the relay WebSocket may take to open (`websocket` transport). */\n relayOpenMs?: number;\n };\n}\n\nexport interface UseDeepAgentVoiceReturn {\n phase: DeepAgentVoicePhase;\n /** The failure message while `phase === 'error'` (same as `failure.message`). */\n error: string | null;\n /**\n * The classified failure while `phase === 'error'`; `null` otherwise. Where\n * `error` is only words, this says WHICH step failed and, for a host\n * rejection, the host's reason code — the key telemetry and support join on.\n */\n failure: DeepAgentVoiceFailure | null;\n start: () => Promise<void>;\n end: () => void;\n /** The delegated voice task currently running server-side, if any. */\n activeTask: { taskId: string; text: string } | null;\n /** Epoch ms when the session went live; `null` outside a live session.\n * Surfaces render an elapsed-call timer from it. */\n liveSince: number | null;\n /**\n * Whether the local microphone is muted. Mute is distinct from `end`: the\n * session (and any delegated work) stays live while the local track is\n * disabled AND the server mutes protocol input (`session.input_audio.mute`\n * — muted speech is discarded server-side, the model keeps speaking).\n */\n micMuted: boolean;\n /** Mute/unmute the live session's microphone; a no-op unless live. */\n setMicMuted: (muted: boolean) => void;\n /**\n * Bimodal input: send typed text into the live conversation as if spoken.\n * Resolves `true` once the server accepted it; `false` when there is no\n * live session or the command was rejected — the caller falls back to a\n * normal run send so the message is never lost.\n */\n sendUserText: (text: string) => Promise<boolean>;\n /**\n * The delegated task that was still running when the last session ended.\n * The run itself continues on the thread — surfaces render a \"voice ended,\n * still working\" note from this until the run settles or a new session\n * starts, at which point it clears itself.\n */\n handoffTask: { taskId: string; text: string } | null;\n /**\n * Push the client's current synced context (runConfig included) to the\n * server so the NEXT delegated run uses it. Call after a runConfig change\n * while the session is live; a no-op otherwise.\n */\n syncProfile: () => void;\n /**\n * Non-fatal notice for the live session: the most recent Live API\n * rejection the host projected (a refused context update, a failed mute),\n * worded for the user. The session stays live; `null` when there is none\n * or the session is not live.\n */\n notice: string | null;\n /**\n * Tell the live session what the user is looking at (one short line, e.g.\n * `spreadsheet \"Q3 Budget\"`). Silent context for reference resolution;\n * fire-and-forget, a no-op unless live.\n */\n sendContext: (text: string) => void;\n /**\n * The realtime model the host resolved for the current/last session\n * (`state.voiceModel`, stamped when a session starts), or `null` before\n * any session or while the snapshot is not hydrated. Stale after an end is\n * inert — surfaces gate on `phase`, like `micMuted`.\n */\n model: string | null;\n /**\n * The realtime models this host offers (`state.voiceModelOptions`,\n * published at host boot), validated; `null` on an older host that does\n * not publish them — surfaces fall back to their static list.\n */\n modelOptions: DeepAgentVoiceModelOption[] | null;\n}\n\n/**\n * The experimental voice-mode session against the thread's `voice/start` /\n * `voice/end` commands: mic capture and media negotiation (WebRTC by default,\n * or PCM over Agora's relay WebSocket); the live turns stream into the chat\n * log as `ephemeral: true` entries in `state.messages`.\n */\nexport const useDeepAgentVoice = (\n options: UseDeepAgentVoiceOptions = {}\n): UseDeepAgentVoiceReturn => {\n const wireSendCommand = useStatewireSendCommand();\n const sendCommandRef = useRef(wireSendCommand);\n sendCommandRef.current = wireSendCommand;\n // Normalize synchronous dispatch failures and async verdicts in one place.\n // Callers can always catch a rejection, even while the thread unmounts.\n const sendCommand = useCallback(\n async (command: Parameters<typeof wireSendCommand>[0]) => sendCommandRef.current(command),\n []\n );\n const voice = useStatewireState(\n // The raw wire state is non-object until the attach snapshot hydrates it.\n (s) => (readDeepAgentStreamValues(s).voice as DeepAgentVoiceWireState | null | undefined) ?? null\n );\n const [phase, setPhase] = useState<DeepAgentVoicePhase>('idle');\n const [failure, setFailure] = useState<DeepAgentVoiceFailure | null>(null);\n const error = failure?.message ?? null;\n const [micMuted, setMicMutedState] = useState(false);\n // Mute is user intent, not media state. A replacement stream must inherit it\n // before any track is attached, including during automatic recovery.\n const micMutedRef = useRef(false);\n const micChangeRef = useRef(0);\n const [liveSince, setLiveSince] = useState<number | null>(null);\n // The task that was running when the last session ended: the run continues\n // on the thread, so surfaces keep a \"still working\" note until it settles.\n const [handoffTask, setHandoffTask] = useState<{\n taskId: string;\n text: string;\n } | null>(null);\n const lastActiveTaskRef = useRef<{ taskId: string; text: string } | null>(null);\n const pcRef = useRef<VoicePeerConnection | null>(null);\n const releasePeerListenersRef = useRef<(() => void) | null>(null);\n const streamRef = useRef<DeepAgentVoiceRemoteStream | null>(null);\n // WebSocket transport state: the relay socket and the local audio graph.\n const wsRef = useRef<VoiceWebSocket | null>(null);\n const audioContextRef = useRef<VoiceAudioContext | null>(null);\n const audioNodesRef = useRef<VoiceAudioNode[]>([]);\n const playheadRef = useRef(0);\n // LiveKit transport state: the joined room.\n const livekitRef = useRef<DeepAgentVoiceLiveKitSession | null>(null);\n const livekitAbortRef = useRef<AbortController | null>(null);\n // Bumped by teardown and by every start(): a startup attempt that awakes\n // from an await into a different generation is stale — it must release\n // whatever it acquired and exit without touching session state.\n const attemptRef = useRef(0);\n const callAttemptIdRef = useRef('');\n const observedAttempt = useStatewireState((s) => {\n if (!isDeepAgentStateHydrated(s)) return undefined;\n const values = readDeepAgentStreamValues(s);\n const value = values.voiceStartFence ?? values.voiceAttemptId;\n return typeof value === 'string' ? value : null;\n });\n const observedAttemptRef = useRef<string | undefined>(undefined);\n // Preserve the last hydrated observation through transient replay snapshots.\n if (observedAttempt !== undefined) observedAttemptRef.current = observedAttempt ?? undefined;\n const startingRef = useRef(false);\n // The in-flight startup, so a media-loss restart can wait for a startup\n // that died mid-negotiation to release its guard before it retries.\n const startPromiseRef = useRef<Promise<void> | null>(null);\n // One-shot resurrection budget: a session the SERVER dropped (connection\n // blip, host rotation) or whose MEDIA path died restarts once per\n // user-initiated session; a second drop — or a failed restart — settles to\n // idle/error so a flapping host or network can never loop the mic grant.\n const autoRestartedRef = useRef(false);\n const onRemoteStreamRef = useRef(options.onRemoteStream);\n onRemoteStreamRef.current = options.onRemoteStream;\n const audioSessionRef = useRef(options.audioSession);\n audioSessionRef.current = options.audioSession;\n const transportRef = useRef(options.transport ?? 'webrtc');\n transportRef.current = options.transport ?? 'webrtc';\n const relayUrlRef = useRef(options.relayUrl);\n relayUrlRef.current = options.relayUrl;\n const livekitAdapterRef = useRef(options.livekit);\n livekitAdapterRef.current = options.livekit;\n const modelRef = useRef(options.model);\n modelRef.current = options.model;\n const onDiagnosticRef = useRef(options.onDiagnostic);\n onDiagnosticRef.current = options.onDiagnostic;\n const timeoutsRef = useRef(options.timeouts);\n timeoutsRef.current = options.timeouts;\n // The phase as of the last render, for the unmount cleanup (which runs\n // outside React's render cycle and cannot read state).\n const phaseRef = useRef<DeepAgentVoicePhase>('idle');\n phaseRef.current = phase;\n // When the current attempt's start was requested, for diagnostic timings.\n const attemptStartedAtRef = useRef(0);\n // The session object whose start() succeeded — teardown must stop that\n // same object even if `options.audioSession` changes mid-session.\n const activeAudioSessionRef = useRef<UseDeepAgentVoiceOptions['audioSession'] | null>(null);\n const startingAudioSessionRef = useRef<UseDeepAgentVoiceOptions['audioSession'] | null>(null);\n // Serializes stop -> start: the next start() waits for the previous\n // session's shutdown to settle before claiming the platform audio session.\n const audioSessionIdleRef = useRef<Promise<void>>(Promise.resolve());\n\n const report = useCallback(\n (\n event: DeepAgentVoiceDiagnosticEvent,\n attempt: number,\n data?: DeepAgentVoiceDiagnostic['data']\n ): void => {\n const observer = onDiagnosticRef.current;\n if (!observer) return;\n const at = Date.now();\n try {\n observer({\n event,\n attempt,\n at,\n sinceStartMs: Math.max(0, at - attemptStartedAtRef.current),\n ...(data !== undefined && { data }),\n });\n } catch {\n // An observer is telemetry: it must never take the session down.\n }\n },\n []\n );\n\n const releaseAudioSession = useCallback((): void => {\n const session = activeAudioSessionRef.current;\n if (!session) return;\n activeAudioSessionRef.current = null;\n audioSessionIdleRef.current = audioSessionIdleRef.current\n .then(() => session.stop())\n .catch(() => undefined);\n }, []);\n\n const teardown = useCallback((): void => {\n attemptRef.current += 1;\n const livekitAbort = livekitAbortRef.current;\n livekitAbortRef.current = null;\n releaseSafely(() => livekitAbort?.abort());\n releaseSafely(() => startingAudioSessionRef.current?.cancelStart?.());\n releaseAudioSession();\n const releasePeerListeners = releasePeerListenersRef.current;\n releasePeerListenersRef.current = null;\n releaseSafely(() => releasePeerListeners?.());\n const pc = pcRef.current;\n pcRef.current = null;\n releaseSafely(() => pc?.close());\n const ws = wsRef.current;\n wsRef.current = null;\n releaseSafely(() => {\n if (ws && ws.readyState < 2) ws.close(1000, 'client end');\n });\n const nodes = audioNodesRef.current;\n audioNodesRef.current = [];\n for (const node of nodes) releaseSafely(() => node.disconnect());\n const audio = audioContextRef.current;\n audioContextRef.current = null;\n releaseSafely(() => audio?.close());\n playheadRef.current = 0;\n const livekit = livekitRef.current;\n livekitRef.current = null;\n releaseSafely(() => livekit?.disconnect());\n const stream = streamRef.current;\n streamRef.current = null;\n releaseCaptureStream(stream);\n setLiveSince(null);\n releaseSafely(() => onRemoteStreamRef.current?.(null));\n }, [releaseAudioSession]);\n\n const fail = useCallback(\n (nextFailure: DeepAgentVoiceFailure): void => {\n report('error', attemptRef.current, {\n kind: nextFailure.kind,\n stage: nextFailure.stage,\n message: nextFailure.message,\n code: nextFailure.code ?? null,\n status: nextFailure.status ?? null,\n fate: nextFailure.fate ?? null,\n reason: nextFailure.reason ?? null,\n });\n teardown();\n setFailure(nextFailure);\n setPhase('error');\n },\n [report, teardown]\n );\n\n // Forward reference: the media-loss handler restarts through the same\n // startSession the user start uses, and startSession installs the watcher\n // that calls the handler.\n const handleMediaLossRef = useRef<(attempt: number, reason: string) => Promise<void>>(\n async () => undefined\n );\n\n /**\n * Watch the peer connection's transport. The sideband can outlive a dead\n * media path (the server keeps a \"live\" session nobody can hear), so the\n * client is the only side that can notice: `failed`/`closed` are final,\n * `disconnected` gets a short grace to recover on its own.\n */\n const watchConnection = useCallback((pc: VoicePeerConnection, attempt: number): (() => void) => {\n let disconnectTimer: ReturnType<typeof setTimeout> | null = null;\n const clearDisconnectTimer = (): void => {\n if (disconnectTimer === null) return;\n clearTimeout(disconnectTimer);\n disconnectTimer = null;\n };\n const onChange = (): void => {\n if (attemptRef.current !== attempt) {\n clearDisconnectTimer();\n return;\n }\n const state = pc.connectionState ?? pc.iceConnectionState;\n report('media-state', attempt, {\n connectionState: pc.connectionState ?? null,\n iceConnectionState: pc.iceConnectionState ?? null,\n });\n if (state === 'failed' || state === 'closed') {\n clearDisconnectTimer();\n void handleMediaLossRef.current(attempt, state);\n return;\n }\n if (state === 'disconnected') {\n if (disconnectTimer !== null) return;\n disconnectTimer = setTimeout(() => {\n disconnectTimer = null;\n if (attemptRef.current !== attempt) return;\n void handleMediaLossRef.current(attempt, 'disconnected');\n }, MEDIA_DISCONNECT_GRACE_MS);\n return;\n }\n // connected / connecting / new: a transient disconnect recovered.\n clearDisconnectTimer();\n };\n pc.addEventListener('connectionstatechange', onChange);\n pc.addEventListener('iceconnectionstatechange', onChange);\n return () => {\n clearDisconnectTimer();\n releaseSafely(() => pc.removeEventListener('connectionstatechange', onChange));\n releaseSafely(() => pc.removeEventListener('iceconnectionstatechange', onChange));\n };\n }, [report]);\n\n /** Schedule one relayed PCM chunk gaplessly after the previous one. */\n const playRelayChunk = useCallback((audio: VoiceAudioContext, data: ArrayBuffer): void => {\n const pcm = new Int16Array(data);\n if (pcm.length === 0) return;\n const samples = float32FromPcm16(pcm);\n const buffer = audio.createBuffer(1, samples.length, VOICE_RELAY_SAMPLE_RATE);\n buffer.copyToChannel(samples, 0);\n const node = audio.createBufferSource();\n node.buffer = buffer;\n node.connect(audio.destination);\n const startAt = Math.max(audio.currentTime + RELAY_PLAYBACK_LEAD_SECONDS, playheadRef.current);\n node.start(startAt);\n playheadRef.current = startAt + buffer.duration;\n }, []);\n\n const runStartSession = useCallback(async (): Promise<void> => {\n const attempt = (attemptRef.current += 1);\n const attemptId = mintVoiceId({ kind: 'attempt' });\n const previousAttemptId = observedAttemptRef.current;\n callAttemptIdRef.current = attemptId;\n startingRef.current = true;\n attemptStartedAtRef.current = Date.now();\n setFailure(null);\n setPhase('connecting');\n // The step under way, so a thrown error is classified by WHERE it\n // happened rather than by its wording.\n let stage: DeepAgentVoiceFailureStage = 'preflight';\n const timeouts = timeoutsRef.current;\n const iceGatheringMs = timeouts?.iceGatheringMs ?? ICE_TIMEOUT_MS;\n const answerMs = timeouts?.answerMs ?? ANSWER_TIMEOUT_MS;\n const relayOpenMs = timeouts?.relayOpenMs ?? RELAY_OPEN_TIMEOUT_MS;\n const stale = (): void => {\n report('stale-attempt', attempt, { stage });\n releaseAudioSession();\n };\n report('start-requested', attempt, { transport: transportRef.current });\n try {\n const transport = transportRef.current;\n const mediaDevices = voiceGlobals.navigator?.mediaDevices;\n const PeerConnection = voiceGlobals.RTCPeerConnection;\n const WebSocketCtor = voiceGlobals.WebSocket;\n const AudioContextCtor = voiceGlobals.AudioContext;\n const livekitAdapter = livekitAdapterRef.current;\n // LiveKit captures the microphone itself, inside the adapter.\n if (transport === 'livekit' && !livekitAdapter)\n throw new Error('Voice is unavailable in this environment');\n if (transport !== 'livekit' && !mediaDevices)\n throw new Error('Microphone capture is unavailable in this environment');\n if (transport === 'webrtc' && !PeerConnection)\n throw new Error('WebRTC is unavailable in this environment');\n if (transport === 'websocket' && (!WebSocketCtor || !AudioContextCtor))\n throw new Error('WebSocket audio is unavailable in this environment');\n const relayUrl = relayUrlRef.current;\n if (transport === 'websocket' && !relayUrl)\n throw new Error('The websocket voice transport needs a relay URL');\n const audioSession = audioSessionRef.current;\n if (audioSession) {\n stage = 'audio-session';\n await audioSessionIdleRef.current;\n if (attemptRef.current !== attempt) {\n report('stale-attempt', attempt, { stage });\n return;\n }\n startingAudioSessionRef.current = audioSession;\n try {\n await audioSession.start();\n } finally {\n startingAudioSessionRef.current = null;\n }\n activeAudioSessionRef.current = audioSession;\n if (attemptRef.current !== attempt) {\n stale();\n return;\n }\n report('audio-session-ready', attempt);\n }\n // Resolved once per attempt, so an automatic restart re-asks for the\n // model the user had picked when this session started.\n const modelOption = modelRef.current;\n const requestedModel = typeof modelOption === 'function' ? modelOption() : modelOption;\n const model =\n typeof requestedModel === 'string' && requestedModel !== '' ? requestedModel : undefined;\n const sendVoiceStart = (offer: string) =>\n sendCommand({\n type: 'voice/start',\n offer,\n attemptId,\n ...(previousAttemptId !== undefined && { previousAttemptId }),\n ...(model !== undefined && { model }),\n }) as Promise<{\n answer?: unknown;\n } | null>;\n // A durable command accepted immediately before host rotation can be\n // replayed on the replacement host after its socket-scoped auth result\n // has expired. The server rejects that replay fail-closed with an exact\n // retriable code. By the time the client receives the verdict it is\n // attached to the replacement host, so repeat the SAME offer once. Do\n // not retry generic 5xx/channel failures: boundedness avoids duplicate\n // live sessions and unbounded GPT Live spend.\n const negotiateStart = async (offer: string): Promise<string> => {\n stage = 'negotiate';\n const negotiationStartedAt = Date.now();\n const commandPromise = sendVoiceStart(offer).catch((commandError: unknown) => {\n if (!isRecoveredCommandAuthRejection(commandError)) throw commandError;\n if (attemptRef.current !== attempt) throw commandError;\n return sendVoiceStart(offer);\n });\n // A session that opens server-side after this attempt was torn down\n // (local end, unmount, or the answer timeout below) must not linger.\n void commandPromise\n .then(() => {\n if (attemptRef.current !== attempt)\n void sendCommand({ type: 'voice/end', attemptId }).catch(() => undefined);\n })\n .catch(() => undefined);\n let answerTimer: ReturnType<typeof setTimeout> | null = null;\n let result: { answer?: unknown } | null;\n try {\n result = await Promise.race([\n commandPromise,\n new Promise<never>((_, reject) => {\n answerTimer = setTimeout(() => reject(new VoiceAnswerTimeoutError()), answerMs);\n }),\n ]);\n } finally {\n if (answerTimer !== null) clearTimeout(answerTimer);\n }\n report('answer-received', attempt, {\n negotiationMs: Date.now() - negotiationStartedAt,\n });\n stage = 'answer';\n const answer = result?.answer;\n if (typeof answer !== 'string' || answer === '')\n throw new VoiceNoAnswerError('voice/start returned no answer');\n return answer;\n };\n\n if (transport === 'livekit') {\n if (!livekitAdapter) return;\n const answer = await negotiateStart(VOICE_LIVEKIT_OFFER);\n if (attemptRef.current !== attempt) {\n stale();\n return;\n }\n // From here the host holds an open session (it answered): a client\n // that cannot use the room must end it, or the model session keeps\n // running with no media leg until the attach departure reaps it.\n try {\n const room = parseVoiceLiveKitAnswer(answer);\n stage = 'room';\n // A drop is only a media loss once the join completed; the adapter\n // owns the failure of a join that never completed.\n let joined = false;\n let disconnectedWhileJoining = false;\n const controller = new AbortController();\n livekitAbortRef.current = controller;\n const session = await livekitAdapter.connect(room, {\n micMuted: micMutedRef.current,\n signal: controller.signal,\n onDisconnected: (reason) => {\n if (attemptRef.current !== attempt) return;\n if (!joined) {\n disconnectedWhileJoining = true;\n return;\n }\n void handleMediaLossRef.current(attempt, reason);\n },\n });\n if (attemptRef.current !== attempt) {\n releaseSafely(() => session.disconnect());\n stale();\n return;\n }\n if (disconnectedWhileJoining) {\n releaseSafely(() => session.disconnect());\n throw new Error('The voice room disconnected while joining');\n }\n joined = true;\n livekitRef.current = session;\n report('room-joined', attempt, { roomName: room.roomName });\n } catch (roomError) {\n if (attemptRef.current === attempt)\n void sendCommand({ type: 'voice/end', attemptId }).catch(() => undefined);\n throw roomError;\n }\n report('live', attempt, { transport, ...(model !== undefined && { model }) });\n if (micMutedRef.current) {\n void sendCommand({ type: 'voice/set-mic', paused: true, attemptId }).catch(() => undefined);\n }\n setPhase('live');\n setLiveSince(Date.now());\n return;\n }\n\n if (!mediaDevices) return;\n stage = 'capture';\n const stream = await mediaDevices.getUserMedia({ audio: true });\n if (attemptRef.current !== attempt) {\n releaseCaptureStream(stream);\n stale();\n return;\n }\n streamRef.current = stream;\n for (const track of stream.getTracks()) track.enabled = !micMutedRef.current;\n report('microphone-captured', attempt, {\n tracks: stream.getTracks().length,\n });\n\n if (transport === 'websocket') {\n if (!WebSocketCtor || !AudioContextCtor || !relayUrl) return;\n const answer = await negotiateStart(VOICE_WEBSOCKET_OFFER);\n if (attemptRef.current !== attempt) {\n stale();\n return;\n }\n if (!answer.startsWith(VOICE_RELAY_ANSWER_PREFIX))\n throw new VoiceNoAnswerError('voice/start returned no relay ticket');\n stage = 'relay';\n const ticket = answer.slice(VOICE_RELAY_ANSWER_PREFIX.length);\n const ws = new WebSocketCtor(voiceRelayUrl(relayUrl, ticket));\n ws.binaryType = 'arraybuffer';\n wsRef.current = ws;\n await waitForRelayOpen(ws, relayOpenMs);\n if (attemptRef.current !== attempt) {\n stale();\n return;\n }\n // Capture at the relay's rate so no client-side resampling is needed:\n // the browser resamples the microphone into the context's rate.\n const audio = new AudioContextCtor({\n sampleRate: VOICE_RELAY_SAMPLE_RATE,\n });\n audioContextRef.current = audio;\n await audio.resume?.();\n if (attemptRef.current !== attempt) {\n stale();\n return;\n }\n const source = audio.createMediaStreamSource(stream);\n const processor = audio.createScriptProcessor(RELAY_CAPTURE_FRAME_SAMPLES, 1, 1);\n // A processor only runs while connected to the destination; the\n // silent gain keeps the microphone from playing back locally.\n const sink = audio.createGain();\n sink.gain.value = 0;\n processor.onaudioprocess = (event) => {\n if (attemptRef.current !== attempt || ws.readyState !== 1) return;\n // A muted track yields silence, which keeps the frame cadence the\n // Live API expects while input is paused.\n ws.send(pcm16FromFloat32(event.inputBuffer.getChannelData(0)).buffer);\n };\n source.connect(processor);\n processor.connect(sink);\n sink.connect(audio.destination);\n audioNodesRef.current = [source, processor, sink];\n playheadRef.current = 0;\n ws.addEventListener('message', (event) => {\n if (attemptRef.current !== attempt) return;\n // Text frames are relay control (`ready`, `pong`); audio is binary.\n if (event.data instanceof ArrayBuffer) playRelayChunk(audio, event.data);\n });\n ws.addEventListener('close', () => {\n if (attemptRef.current !== attempt) return;\n void handleMediaLossRef.current(attempt, 'relay-closed');\n });\n ws.addEventListener('error', () => {\n if (attemptRef.current !== attempt) return;\n void handleMediaLossRef.current(attempt, 'relay-error');\n });\n report('live', attempt, { transport });\n if (micMutedRef.current) {\n void sendCommand({ type: 'voice/set-mic', paused: true, attemptId }).catch(() => undefined);\n }\n setPhase('live');\n setLiveSince(Date.now());\n return;\n }\n\n if (!PeerConnection) return;\n stage = 'offer';\n const pc = new PeerConnection();\n pcRef.current = pc;\n for (const track of stream.getTracks()) pc.addTrack(track, stream);\n const onTrack = async (trackEvent: VoiceTrackEvent): Promise<void> => {\n if (attemptRef.current !== attempt) return;\n try {\n const remote =\n trackEvent.streams[0] ??\n (voiceGlobals.MediaStream ? new voiceGlobals.MediaStream([trackEvent.track]) : null);\n if (!remote) return;\n await onRemoteStreamRef.current?.(remote);\n } catch (playError) {\n // audio.play() can reject after hangup has already opened another call.\n if (attemptRef.current !== attempt) return;\n void sendCommand({ type: 'voice/end', attemptId }).catch(() => undefined);\n fail({\n kind: 'playback_failed',\n stage: 'playback',\n message: `Audio playback: ${errorMessage(playError)}`,\n });\n }\n };\n pc.addEventListener('track', onTrack);\n const unwatchConnection = watchConnection(pc, attempt);\n releasePeerListenersRef.current = () => {\n unwatchConnection();\n releaseSafely(() => pc.removeEventListener('track', onTrack));\n };\n const offer = await pc.createOffer();\n await pc.setLocalDescription(offer);\n const iceStartedAt = Date.now();\n const iceOutcome = await waitForIce(pc, iceGatheringMs);\n if (attemptRef.current !== attempt) {\n stale();\n return;\n }\n if (iceOutcome === 'timeout') {\n report('ice-gathering-timeout', attempt, {\n waitedMs: Date.now() - iceStartedAt,\n iceGatheringState: pc.iceGatheringState,\n });\n }\n const sdp = pc.localDescription?.sdp;\n if (!sdp) throw new Error('failed to create a local SDP offer');\n report('offer-ready', attempt, {\n iceGatheringMs: Date.now() - iceStartedAt,\n iceGathering: iceOutcome,\n sdpBytes: sdp.length,\n });\n const answer = await negotiateStart(sdp);\n if (attemptRef.current !== attempt) {\n stale();\n return;\n }\n await pc.setRemoteDescription({ type: 'answer', sdp: answer });\n if (attemptRef.current !== attempt) {\n stale();\n return;\n }\n report('live', attempt, { transport });\n if (micMutedRef.current) {\n void sendCommand({ type: 'voice/set-mic', paused: true, attemptId }).catch(() => undefined);\n }\n setPhase('live');\n setLiveSince(Date.now());\n } catch (startError) {\n if (attemptRef.current !== attempt) {\n stale();\n return;\n }\n fail(classifyStartFailure(startError, stage));\n } finally {\n startingRef.current = false;\n }\n }, [fail, playRelayChunk, releaseAudioSession, report, sendCommand, watchConnection]);\n\n const startSession = useCallback(async (): Promise<void> => {\n if (pcRef.current || wsRef.current || livekitRef.current || startingRef.current) return;\n const run = runStartSession();\n startPromiseRef.current = run;\n try {\n await run;\n } finally {\n if (startPromiseRef.current === run) startPromiseRef.current = null;\n }\n }, [runStartSession]);\n const startRef = useRef(startSession);\n startRef.current = startSession;\n\n /**\n * The media path died while the server still holds a live session. End it\n * server-side first (a `voice/start` racing the old session's teardown is\n * rejected `voice-active`), then spend the one-shot restart budget — or,\n * if it is already spent, settle to an error the surface can show.\n *\n * The restart is cancelled by anything that supersedes this recovery while\n * it waits: an explicit `end()`, an unmount, or a user start all bump the\n * attempt generation, and a stale recovery must never reopen the mic.\n */\n const handleMediaLoss = useCallback(\n async (attempt: number, reason: string): Promise<void> => {\n if (attemptRef.current !== attempt) return;\n report('media-loss', attempt, {\n reason,\n restartBudgetLeft: !autoRestartedRef.current,\n });\n if (lastActiveTaskRef.current) setHandoffTask(lastActiveTaskRef.current);\n const ending: Promise<unknown> = sendCommand({ type: 'voice/end', attemptId: callAttemptIdRef.current }).catch(() => undefined);\n teardown();\n const recovery = attemptRef.current;\n setPhase('idle');\n let endTimer: ReturnType<typeof setTimeout> | undefined;\n try {\n await Promise.race([\n ending,\n new Promise<void>((resolve) => {\n endTimer = setTimeout(resolve, END_BEFORE_RESTART_TIMEOUT_MS);\n }),\n ]);\n } finally {\n clearTimeout(endTimer);\n }\n // A startup that was still negotiating when the transport died exits\n // at its next generation check; wait for it to release its guard so\n // the replacement start is not refused as \"already starting\".\n const inflight = startPromiseRef.current;\n if (inflight) await inflight.catch(() => undefined);\n if (attemptRef.current !== recovery) return;\n if (!autoRestartedRef.current) {\n autoRestartedRef.current = true;\n report('auto-restart', recovery, { trigger: 'media-loss', reason });\n await startRef.current();\n return;\n }\n // The server-drop effect may already be restarting — do not override it.\n if (startingRef.current || pcRef.current || wsRef.current || livekitRef.current) return;\n const lost: DeepAgentVoiceFailure = {\n kind: 'media_lost',\n stage: 'media',\n message: `The voice connection was lost (${reason})`,\n reason,\n };\n report('error', recovery, {\n kind: lost.kind,\n stage: lost.stage,\n message: lost.message,\n reason,\n });\n setFailure(lost);\n setPhase('error');\n },\n [report, sendCommand, teardown]\n );\n handleMediaLossRef.current = handleMediaLoss;\n\n // The public start is a USER start: it re-arms the one-shot auto-restart\n // budget the server-drop effect consumes (the automatic hop itself calls\n // `startSession` directly, so it can never re-arm its own budget).\n const start = useCallback(async (): Promise<void> => {\n if (pcRef.current || wsRef.current || livekitRef.current || startingRef.current) return;\n micMutedRef.current = false;\n setMicMutedState(false);\n autoRestartedRef.current = false;\n setHandoffTask(null);\n await startSession();\n }, [startSession]);\n\n const end = useCallback((): void => {\n if (phase === 'connecting' || phase === 'live') {\n report('end', attemptRef.current, { source: 'user', phase });\n void sendCommand({ type: 'voice/end', attemptId: callAttemptIdRef.current }).catch(() => undefined);\n if (lastActiveTaskRef.current) setHandoffTask(lastActiveTaskRef.current);\n }\n teardown();\n micMutedRef.current = false;\n setMicMutedState(false);\n setPhase('idle');\n }, [phase, report, sendCommand, teardown]);\n\n const setMicMuted = useCallback(\n (muted: boolean): void => {\n if (phase !== 'live') return;\n const attempt = attemptRef.current;\n const change = ++micChangeRef.current;\n const applyLocal = (value: boolean): void => {\n micMutedRef.current = value;\n setMicMutedState(value);\n for (const track of streamRef.current?.getTracks() ?? []) track.enabled = !value;\n // LiveKit owns the microphone track on its transport: best effort,\n // the protocol pause below is what actually silences the model.\n const room = livekitRef.current;\n if (room) releaseSafely(() => room.setMicrophoneEnabled(!value));\n };\n // Local track disable is the instant lever; the protocol pause is the\n // authoritative one (server discards paused speech).\n applyLocal(muted);\n void sendCommand({ type: 'voice/set-mic', paused: muted, attemptId: callAttemptIdRef.current }).catch(() => {\n // A failed MUTE is safe — the disabled track transmits nothing either\n // way. A failed UNMUTE would claim live audio while the server still\n // discards it, so fall back to the muted truth (unless this session\n // was already torn down, whose reset wins).\n if (!muted && attemptRef.current === attempt && micChangeRef.current === change) {\n applyLocal(true);\n }\n });\n },\n [phase, sendCommand]\n );\n\n // A server-side end (connection drop, another surface, host shutdown)\n // clears `state.voice`; follow it down. Gate on a HYDRATED snapshot: the\n // raw wire state republishes `undefined` on replay boundaries (reconnects,\n // optimistic windows around sends), and tearing down on that transient\n // would kill a perfectly live session every time the user typed a message.\n const sessionGone = useStatewireState(\n (s) => isDeepAgentStateHydrated(s) && (readDeepAgentStreamValues(s).voice ?? null) === null\n );\n useEffect(() => {\n if (phase !== 'live' || !sessionGone) return;\n report('server-ended', attemptRef.current, {\n restartBudgetLeft: !autoRestartedRef.current,\n });\n if (lastActiveTaskRef.current) setHandoffTask(lastActiveTaskRef.current);\n teardown();\n setPhase('idle');\n if (!autoRestartedRef.current) {\n autoRestartedRef.current = true;\n report('auto-restart', attemptRef.current, { trigger: 'server-ended' });\n void startRef.current?.();\n }\n }, [phase, report, sessionGone, teardown]);\n\n // Unmount: release the media, and — when a session is still underway — end\n // it server-side too. The host would reap an orphaned session once this\n // client's attach departs (its departure grace), but a surface that\n // unmounts its voice controls while the thread connection stays up (a\n // remount of the composer, a navigation that keeps the runtime) would\n // otherwise leave the Live API session running and billing with no media\n // leg until the grace expired. Best-effort: the transport may already be\n // closing, in which case the departure path finishes the job.\n useEffect(\n () => () => {\n const phaseAtUnmount = phaseRef.current;\n if (phaseAtUnmount === 'connecting' || phaseAtUnmount === 'live') {\n report('end', attemptRef.current, {\n source: 'unmount',\n phase: phaseAtUnmount,\n });\n void sendCommand({ type: 'voice/end', attemptId: callAttemptIdRef.current }).catch(() => undefined);\n }\n teardown();\n },\n [report, sendCommand, teardown]\n );\n\n // Mirror the live session's delegated task so an end (local or server-side)\n // can hand it off: the run outlives the session, the projection does not.\n const activeTask = voice?.activeTask ?? null;\n useEffect(() => {\n if (phase === 'live') lastActiveTaskRef.current = activeTask;\n else if (phase === 'idle' || phase === 'error') lastActiveTaskRef.current = null;\n }, [phase, activeTask]);\n\n // The handoff note self-clears when the thread's run settles (the work it\n // pointed at is finished — or was never running to begin with). Unhydrated\n // snapshots keep the note: the raw wire state republishes `undefined` on\n // replay boundaries and must not read as \"settled\".\n const handoffRunActive = useStatewireState((s) => {\n if (!isDeepAgentStateHydrated(s)) return true;\n const status = readDeepAgentStreamValues(s).status;\n return status === 'running' || status === 'stopping' || status === 'input-required';\n });\n useEffect(() => {\n if (handoffTask !== null && !handoffRunActive) setHandoffTask(null);\n }, [handoffTask, handoffRunActive]);\n\n // The host projects the latest Live API rejection; every `voice/start`\n // resets it, so the wire value is always this session's. Hidden outside a\n // live session (a stale value after an end is inert).\n const wireError = useStatewireState((s) =>\n isDeepAgentStateHydrated(s) ? (readDeepAgentStreamValues(s).voiceLastError ?? null) : null\n );\n const notice = phase === 'live' && wireError ? describeVoiceWireError(wireError) : null;\n\n // The host stamps the resolved model when a session starts and publishes\n // its model catalogue at boot. Both are read raw off the hydrated snapshot\n // (the selectors must return referentially stable values — `Object.is`);\n // the catalogue is validated once per wire change below.\n const model = useStatewireState((s) => {\n if (!isDeepAgentStateHydrated(s)) return null;\n const value = readDeepAgentStreamValues(s).voiceModel;\n return typeof value === 'string' && value !== '' ? value : null;\n });\n const wireModelOptions = useStatewireState((s) =>\n isDeepAgentStateHydrated(s) ? (readDeepAgentStreamValues(s).voiceModelOptions ?? null) : null\n );\n // Replication may hand back a fresh array for unchanged content (a snapshot\n // replay, a reconnect); keep the previous validated list so memoized\n // consumers (the composer's picker) do not re-render on every wire update.\n const modelOptionsRef = useRef<DeepAgentVoiceModelOption[] | null>(null);\n const modelOptions = useMemo(() => {\n const next = parseVoiceModelOptions(wireModelOptions);\n const previous = modelOptionsRef.current;\n if (previous !== null && next !== null && sameVoiceModelOptions(previous, next)) return previous;\n modelOptionsRef.current = next;\n return next;\n }, [wireModelOptions]);\n\n const syncProfile = useCallback((): void => {\n if (phase !== 'connecting' && phase !== 'live') return;\n void sendCommand({ type: 'voice/profile-sync', attemptId: callAttemptIdRef.current }).catch(() => undefined);\n }, [phase, sendCommand]);\n\n const sendContext = useCallback(\n (text: string): void => {\n const trimmed = text.trim();\n if (phase !== 'live' || !trimmed) return;\n void sendCommand({ type: 'voice/context', text: trimmed, attemptId: callAttemptIdRef.current }).catch(() => undefined);\n },\n [phase, sendCommand]\n );\n\n const sendUserText = useCallback(\n async (text: string): Promise<boolean> => {\n if (phase !== 'live' || !text.trim()) return false;\n // Client-minted id: a durable command replayed on a replacement host\n // reuses it, and the checkpoint append is idempotent by message id —\n // a crash between the server's commit and its ack cannot duplicate.\n const messageId = mintVoiceId({ kind: 'text' });\n try {\n await sendCommand({ type: 'voice/user-text', text, messageId, attemptId: callAttemptIdRef.current });\n return true;\n } catch {\n return false;\n }\n },\n [phase, sendCommand]\n );\n\n // One object per change of what it reports: surfaces pass the session down whole (the composer's\n // voice controls, its mic and end buttons), so a fresh literal per render re-rendered them on\n // every render of their host, e.g. every keystroke in the composer.\n return useMemo(\n () => ({\n phase,\n error,\n failure,\n start,\n end,\n activeTask,\n liveSince,\n micMuted,\n setMicMuted,\n sendUserText,\n handoffTask,\n syncProfile,\n notice,\n sendContext,\n model,\n modelOptions,\n }),\n [\n phase,\n error,\n failure,\n start,\n end,\n activeTask,\n liveSince,\n micMuted,\n setMicMuted,\n sendUserText,\n handoffTask,\n syncProfile,\n notice,\n sendContext,\n model,\n modelOptions,\n ]\n );\n};\n"],"names":["model","offer","answer","_a"],"mappings":"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"}
1
+ {"version":3,"file":"use-deep-agent-voice.js","sources":["../../../../agent-runtime/src/use-deep-agent-voice.ts"],"sourcesContent":["import { useStatewireSendCommand, useStatewireState } from '@assistant-ui/react-statewire';\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { statewireRejectionPayload } from './errors';\nimport { isDeepAgentStateHydrated, readDeepAgentStreamValues } from './statewire-state';\nimport type { VoiceMediaEvent } from './voice-media';\nimport type {\n DeepAgentVoiceOwnerWireState,\n DeepAgentVoiceSurface,\n DeepAgentVoiceWireError,\n} from './voice-wire-types';\n\nexport type {\n DeepAgentVoiceOwnerWireState,\n DeepAgentVoiceSurface,\n DeepAgentVoiceTransferWireState,\n} from './voice-wire-types';\nexport {\n playVoiceMoveEarcon,\n VOICE_MOVE_EARCON_MS,\n VOICE_MOVE_EARCON_PEAK,\n VOICE_MOVE_EARCON_SAMPLE_RATE,\n voiceMoveEarconDataUri,\n voiceMoveEarconSamples,\n voiceMoveEarconWav,\n} from './voice-earcon';\n\ndeclare module '@assistant-ui/core' {\n namespace Assistant {\n interface Commands {\n /**\n * Opens a voice session (`DeepAgentThread.voice_start`). `offer` is the\n * WebRTC SDP offer, {@link VOICE_WEBSOCKET_OFFER} to request the\n * WebSocket audio transport (the answer is then a relay ticket), or\n * {@link VOICE_LIVEKIT_OFFER} to request a LiveKit room (the answer is\n * then the room's join credentials). `model` picks the realtime model\n * (`gpt-live-1`, `gemini-3.8-live`, …); omitted → the host's default.\n * `opening: 'recap'` asks the model to open by saying where the\n * conversation stands (a call continued from another device); the host\n * applies it only to a thread with history and a profile that speaks\n * first.\n */\n voiceStart: {\n type: 'voice/start';\n offer: string;\n model?: string;\n /** Correlates commands with this call, including delayed cleanup. */\n attemptId?: string;\n previousAttemptId?: string;\n opening?: DeepAgentVoiceOpening;\n };\n /** Ends the live voice session (`DeepAgentThread.voice_end`). */\n voiceEnd: {\n type: 'voice/end';\n attemptId?: string;\n };\n /**\n * No-op whose INGRESS refreshes the caller's server-stored context\n * (context syncs ride command sends), so runConfig changes made while a\n * voice session is live reach the delegated runs.\n */\n voiceProfileSync: {\n type: 'voice/profile-sync';\n attemptId?: string;\n };\n /**\n * Mute/unmute the live session's microphone at the protocol level\n * (`DeepAgentThread.voice_set_mic` → `session.input_audio.mute`/`unmute`).\n */\n voiceSetMic: {\n type: 'voice/set-mic';\n attemptId?: string;\n paused: boolean;\n };\n /**\n * Route a typed message into the live conversation\n * (`DeepAgentThread.voice_user_text`): commits durably as a\n * `source: \"text\"` user turn and reaches the live model as speakable\n * context, so it responds by voice exactly as it would to speech.\n * `messageId` is client-minted so a durable-command redelivery after a\n * host crash commits idempotently instead of duplicating the turn.\n */\n voiceUserText: {\n type: 'voice/user-text';\n attemptId?: string;\n text: string;\n messageId: string;\n };\n /**\n * Tell the live session what the user is looking at\n * (`DeepAgentThread.voice_context`): one short description of the open\n * asset or page, appended as silent commentary so the live model can\n * resolve \"this document\" without delegating. Never spoken, never\n * persisted; identical consecutive descriptions are dropped server-side.\n */\n voiceContext: {\n type: 'voice/context';\n attemptId?: string;\n text: string;\n };\n /**\n * Ask to take the conversation's live call from another of the caller's\n * own devices (`DeepAgentThread.voice_transfer_offer`, LiveKit sessions\n * only). `attemptId` is a fresh call attempt id, minted like\n * `voice/start`'s; the result is `{ answer, transferId }`, `answer` in\n * `voice/start`'s LiveKit format with a join token for this client.\n */\n voiceTransferOffer: {\n type: 'voice/transfer-offer';\n attemptId: string;\n };\n /**\n * Sent once this client has joined the room and published its\n * microphone: the host moves the call's owner, media input and attempt\n * fence to this client (`DeepAgentThread.voice_transfer_commit`).\n */\n voiceTransferCommit: {\n type: 'voice/transfer-commit';\n transferId: string;\n attemptId: string;\n };\n /** Withdraw a pending transfer; idempotent (`DeepAgentThread.voice_transfer_cancel`). */\n voiceTransferCancel: {\n type: 'voice/transfer-cancel';\n transferId: string;\n };\n }\n }\n}\n\n/** A voice-delegated frontend tool call projected by legacy hosts\n * (`arguments` is a JSON string). Current hosts run frontend tools through\n * the delegated run's client-tool interrupts, so this stays empty. */\nexport interface DeepAgentVoiceToolCall {\n callId: string;\n name: string;\n arguments: string;\n}\n\n/** The host's `state.voice` projection while a session exists. */\nexport interface DeepAgentVoiceWireState {\n clientId: string;\n status: 'connecting' | 'live';\n toolCalls: DeepAgentVoiceToolCall[];\n /** The delegated voice task currently running, if any. */\n activeTask?: { taskId: string; text: string } | null;\n}\n\nexport type DeepAgentVoicePhase = 'idle' | 'connecting' | 'live' | 'error';\n\n/**\n * How the realtime model opens a call: `recap` says where the conversation\n * stands first (mirrors agora's `VOICE_RECAP_OPENING`).\n */\nexport type DeepAgentVoiceOpening = 'recap';\n\n/** Options of a user start (`useDeepAgentVoice().start`). */\nexport interface DeepAgentVoiceStartOptions {\n /**\n * Ask the model to open with a recap: the one-tap \"Continue by voice\" after\n * a handover the person sent in voice mode. Sent on this start's\n * `voice/start` only, never on the automatic restart or a transfer.\n */\n opening?: DeepAgentVoiceOpening;\n}\n\n/**\n * Why a voice session failed, classified where the failure happened rather\n * than by parsing the message afterwards. `server_rejected` carries the\n * host's structured code (`voice-active`, `voice-not-enabled`,\n * `voice-unavailable`, `checkpointer_unavailable`, …); `media_lost` carries the\n * transport state that ended the session. `transfer_failed` is a move of a\n * call live on another of the person's devices that did not complete (the\n * call stays there): `reason` names the underlying kind (`server_rejected`,\n * `room_failed`, `microphone_denied`, `answer_timeout`, …) and `code` the\n * host's rejection reason (`voice-transfer-busy`, `voice-transfer-media`, …).\n * Every surface reports and words the same kinds, so telemetry across\n * Olympus, Chrome, and mobile joins on them.\n */\nexport type DeepAgentVoiceFailureKind =\n | 'unsupported'\n | 'audio_session'\n | 'microphone_denied'\n | 'capture_failed'\n | 'offer_failed'\n | 'answer_timeout'\n | 'server_rejected'\n | 'command_failed'\n | 'no_answer'\n | 'answer_failed'\n | 'relay_failed'\n | 'room_failed'\n | 'playback_failed'\n | 'media_lost'\n | 'transfer_failed'\n | 'unknown';\n\n/** Where in the session's lifecycle a failure happened. */\nexport type DeepAgentVoiceFailureStage =\n | 'preflight'\n | 'audio-session'\n | 'capture'\n | 'offer'\n | 'negotiate'\n | 'answer'\n | 'relay'\n | 'room'\n | 'media'\n | 'playback'\n /** `voice/transfer-commit`: the host moving a call to this client. */\n | 'commit';\n\nexport interface DeepAgentVoiceFailure {\n kind: DeepAgentVoiceFailureKind;\n stage: DeepAgentVoiceFailureStage;\n /** The message surfaces render (the same value as `error`). */\n message: string;\n /** The host's rejection reason / structured `detail.code`, when it sent one. */\n code?: string;\n /** The rejection's HTTP-style status, when the host sent a structured one. */\n status?: number;\n /** The statewire send fate when the command settled without a verdict. */\n fate?: string;\n /**\n * The lower-level reason: the media state that ended the session\n * (`failed` / `closed` / `disconnected` / `relay-closed` / `relay-error`),\n * the channel death that settled the command (`unmount` / `stream-gone` /\n * `session-lost`), or, for `transfer_failed`, the underlying failure kind.\n */\n reason?: string;\n}\n\n/**\n * Lifecycle milestones of a session attempt, for surfaces that record them\n * (crash breadcrumbs, latency telemetry). `attempt` groups one start's\n * events; `sinceStartMs` is measured from that attempt's `start-requested`.\n */\nexport type DeepAgentVoiceDiagnosticEvent =\n | 'start-requested'\n | 'audio-session-ready'\n | 'microphone-captured'\n | 'offer-ready'\n | 'ice-gathering-timeout'\n | 'answer-received'\n | 'room-joined'\n | 'live'\n | 'media-state'\n | 'media-loss'\n | 'auto-restart'\n | 'server-ended'\n | 'end'\n | 'error'\n | 'stale-attempt'\n /** The live call moved to another of the person's devices; this client let go of it. */\n | 'moved'\n /**\n * The platform's room reported something about the call's media (the\n * adapter's `onEvent`): `data.type` names it — a reconnect, the agent\n * leaving, connection quality, an audio-quality sample or summary.\n */\n | 'media-event';\n\nexport interface DeepAgentVoiceDiagnostic {\n event: DeepAgentVoiceDiagnosticEvent;\n attempt: number;\n /** Epoch ms. */\n at: number;\n sinceStartMs: number;\n data?: Record<string, string | number | boolean | null>;\n}\n\n/** The statewire send failure a rejected/failed command carries (`error.failure`). */\ninterface VoiceCommandSendFailure {\n fate: string;\n cause?: string;\n code?: string;\n message?: string;\n payload?: unknown;\n}\n\nconst readSendFailure = (error: unknown): VoiceCommandSendFailure | null => {\n const failure = (error as { failure?: unknown } | null | undefined)?.failure;\n if (failure === null || typeof failure !== 'object') return null;\n return typeof (failure as { fate?: unknown }).fate === 'string'\n ? (failure as VoiceCommandSendFailure)\n : null;\n};\n\nconst errorMessage = (error: unknown): string =>\n error instanceof Error ? error.message : String(error);\n\n/** Marker for the local answer deadline, so the timeout classifies by identity. */\nclass VoiceAnswerTimeoutError extends Error {\n constructor() {\n super('The voice session did not answer in time');\n this.name = 'VoiceAnswerTimeoutError';\n }\n}\n\n/**\n * Classify a failed `voice/start` command. A host rejection keeps the host's\n * reason (`payload.reason` from the voice manager, `payload.detail.code` from\n * the command gate's structured envelope) and its own user-worded message; a\n * command the channel settled without a verdict reports its fate.\n */\nexport const classifyVoiceStartError = (\n error: unknown\n): Pick<DeepAgentVoiceFailure, 'kind' | 'message' | 'code' | 'status' | 'fate' | 'reason'> => {\n if (error instanceof VoiceAnswerTimeoutError) {\n return { kind: 'answer_timeout', message: error.message };\n }\n const failure = readSendFailure(error);\n if (failure === null) return { kind: 'unknown', message: errorMessage(error) };\n if (failure.fate === 'rejected') {\n const payload = failure.payload as\n | { reason?: unknown; status?: unknown; detail?: unknown }\n | null\n | undefined;\n const detail = payload?.detail as { code?: unknown; message?: unknown } | null | undefined;\n const reason = typeof payload?.reason === 'string' ? payload.reason : undefined;\n const detailCode = typeof detail?.code === 'string' ? detail.code : undefined;\n const detailMessage = typeof detail?.message === 'string' ? detail.message : undefined;\n const code = reason ?? detailCode ?? failure.code;\n const status = typeof payload?.status === 'number' ? payload.status : undefined;\n return {\n kind: 'server_rejected',\n message: failure.message ?? detailMessage ?? errorMessage(error),\n ...(code !== undefined && { code }),\n ...(status !== undefined && { status }),\n };\n }\n return {\n kind: 'command_failed',\n message: failure.message ?? errorMessage(error),\n fate: failure.fate,\n ...(failure.cause !== undefined && failure.cause !== 'server' && { reason: failure.cause }),\n };\n};\n\n/** Marker for a verdict that carried no SDP answer / relay ticket / room. */\nclass VoiceNoAnswerError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'VoiceNoAnswerError';\n }\n}\n\n/**\n * Decode a `voice/start` answer on the `livekit` transport. Throws (as a\n * `no_answer` failure when raised in the `answer` stage) on a missing prefix,\n * malformed JSON, or a missing/non-string field — a host that answered with\n * something else did not open a LiveKit room for this client.\n */\nexport const parseVoiceLiveKitAnswer = (answer: string): DeepAgentVoiceLiveKitAnswer => {\n if (!answer.startsWith(VOICE_LIVEKIT_ANSWER_PREFIX)) {\n throw new VoiceNoAnswerError('voice/start returned no voice room');\n }\n let parsed: unknown;\n try {\n parsed = JSON.parse(answer.slice(VOICE_LIVEKIT_ANSWER_PREFIX.length));\n } catch {\n throw new VoiceNoAnswerError('voice/start returned a malformed voice room');\n }\n const record = (parsed ?? null) as {\n serverUrl?: unknown;\n token?: unknown;\n roomName?: unknown;\n } | null;\n const serverUrl = record?.serverUrl;\n const token = record?.token;\n const roomName = record?.roomName;\n if (\n typeof serverUrl !== 'string' ||\n serverUrl === '' ||\n typeof token !== 'string' ||\n token === '' ||\n typeof roomName !== 'string' ||\n roomName === ''\n ) {\n throw new VoiceNoAnswerError('voice/start returned an incomplete voice room');\n }\n return { serverUrl, token, roomName };\n};\n\n/** Marker for this client's room dropping while a transfer was still committing. */\nclass VoiceTransferRoomDroppedError extends Error {\n constructor(readonly reason: string) {\n super(`The voice room disconnected before the call moved (${reason})`);\n this.name = 'VoiceTransferRoomDroppedError';\n }\n}\n\n/** Reject with the answer-deadline marker unless `promise` settles within `ms`. */\nconst withAnswerDeadline = async <T>(promise: Promise<T>, ms: number): Promise<T> => {\n let timer: ReturnType<typeof setTimeout> | null = null;\n try {\n return await Promise.race([\n promise,\n new Promise<never>((_, reject) => {\n timer = setTimeout(() => reject(new VoiceAnswerTimeoutError()), ms);\n }),\n ]);\n } finally {\n if (timer !== null) clearTimeout(timer);\n }\n};\n\n/** The `voice/transfer-offer` verdict's fields, each `null` when missing or not a non-empty string. */\nconst readTransferOffer = (result: unknown): { answer: string | null; transferId: string | null } => {\n const record =\n result !== null && typeof result === 'object'\n ? (result as { answer?: unknown; transferId?: unknown })\n : null;\n const answer = record?.answer;\n const transferId = record?.transferId;\n return {\n answer: typeof answer === 'string' && answer !== '' ? answer : null,\n transferId: typeof transferId === 'string' && transferId !== '' ? transferId : null,\n };\n};\n\n/**\n * The failure for a move that did not complete while `stage` was under way:\n * always `transfer_failed` (the call stays on the other device), worded for\n * the person, with the underlying kind in `reason` and the host's code kept.\n */\nconst classifyTransferFailure = (\n error: unknown,\n stage: DeepAgentVoiceFailureStage\n): DeepAgentVoiceFailure => {\n const underlying: Pick<DeepAgentVoiceFailure, 'kind' | 'code' | 'status' | 'fate'> =\n stage === 'commit'\n ? error instanceof VoiceTransferRoomDroppedError\n ? { kind: 'room_failed' }\n : classifyVoiceStartError(error)\n : classifyStartFailure(error, stage);\n return {\n kind: 'transfer_failed',\n stage,\n message: describeVoiceTransferFailure({ reason: underlying.kind }),\n reason: underlying.kind,\n ...(underlying.code !== undefined && { code: underlying.code }),\n ...(underlying.status !== undefined && { status: underlying.status }),\n ...(underlying.fate !== undefined && { fate: underlying.fate }),\n };\n};\n\n/** The failure for an error thrown while `stage` was under way. */\nconst classifyStartFailure = (\n error: unknown,\n stage: DeepAgentVoiceFailureStage\n): DeepAgentVoiceFailure => {\n const message = errorMessage(error);\n switch (stage) {\n case 'preflight':\n return { kind: 'unsupported', stage, message };\n case 'audio-session':\n return { kind: 'audio_session', stage, message };\n case 'capture':\n return {\n kind: isMicrophoneDenied(error) ? 'microphone_denied' : 'capture_failed',\n stage,\n message,\n };\n case 'offer':\n return { kind: 'offer_failed', stage, message };\n case 'negotiate':\n return { ...classifyVoiceStartError(error), stage };\n case 'answer':\n return {\n kind: error instanceof VoiceNoAnswerError ? 'no_answer' : 'answer_failed',\n stage,\n message,\n };\n case 'relay':\n return { kind: 'relay_failed', stage, message };\n case 'room':\n // LiveKit captures the microphone while joining, so a permission\n // refusal surfaces here rather than in a `capture` stage.\n return {\n kind: isMicrophoneDenied(error) ? 'microphone_denied' : 'room_failed',\n stage,\n message,\n };\n default:\n return { kind: 'unknown', stage, message };\n }\n};\n\nconst isMicrophoneDenied = (error: unknown): boolean => {\n const name = (error as { name?: unknown } | null | undefined)?.name;\n if (\n name === 'SecurityError' ||\n name === 'NotAllowedError' ||\n name === 'PermissionDeniedError'\n ) {\n return true;\n }\n return /permission|denied|not allowed/i.test(errorMessage(error));\n};\n\n/** The words for a move that did not complete; the call stays on the other device. */\nconst describeVoiceTransferFailure = ({ reason }: { reason?: string }): string =>\n reason === 'microphone_denied'\n ? 'Microphone access is blocked, so the call stayed on your other device. Allow the microphone for Athena and try again.'\n : \"The call couldn't move here and is still on your other device. Try again.\";\n\n/**\n * User-facing copy for a failure, shared so every surface words the same\n * cause alike. Host rejections keep the host's own wording (it already names\n * the actionable cause); the local kinds get a sentence the user can act on.\n */\nexport const describeVoiceFailure = (failure: DeepAgentVoiceFailure): string => {\n switch (failure.kind) {\n case 'microphone_denied':\n return 'Microphone access is blocked. Allow the microphone for Athena and try again.';\n case 'unsupported':\n return 'Voice mode is not available in this environment.';\n case 'audio_session':\n return `The audio session could not start: ${failure.message}`;\n case 'answer_timeout':\n return 'The voice session did not answer in time. Check your connection and try again.';\n case 'room_failed':\n return 'The voice room could not be joined. Check your connection and try again.';\n case 'media_lost':\n return 'The voice connection was lost. Start voice again to continue.';\n case 'transfer_failed':\n return describeVoiceTransferFailure({ reason: failure.reason });\n case 'server_rejected':\n if (failure.code === 'voice-active') {\n return 'A voice session is already live on another device or tab. End it there first.';\n }\n if (failure.code === 'voice-not-enabled') {\n return 'Voice mode is not enabled for this workspace.';\n }\n return failure.message;\n default:\n return failure.message;\n }\n};\n\n/**\n * How the session's audio travels. `webrtc` (the default) negotiates a peer\n * connection straight to OpenAI; `websocket` captures PCM locally and streams\n * it to Agora's relay endpoint, for surfaces where WebRTC is unavailable\n * (Office add-in webviews, UDP-blocked networks) — web only: it needs\n * `AudioContext` and `WebSocket` globals. `livekit` joins the LiveKit room the\n * host mints for the session through a caller-supplied\n * {@link DeepAgentVoiceLiveKitAdapter}; Agora joins the same room as the agent\n * participant, so this is the only transport on which the realtime model is a\n * per-session choice (`gpt-live-1`, `gemini-3.8-live`, …) — the other two are\n * OpenAI-direct media legs and stay GPT Live only.\n */\nexport type DeepAgentVoiceTransport = 'webrtc' | 'websocket' | 'livekit';\n\n/**\n * The `voice/start` offer that requests the WebSocket transport. Mirrors\n * `agora.services.voice_relay.VOICE_WEBSOCKET_OFFER`.\n */\nexport const VOICE_WEBSOCKET_OFFER = 'athena-voice-transport:websocket/v1';\n/** Prefix of a `voice/start` answer that carries a relay ticket, not an SDP answer. */\nexport const VOICE_RELAY_ANSWER_PREFIX = 'athena-voice-relay:';\n/** The relay's wire format: raw PCM16, mono, 24 kHz (the Live API's PCM format). */\nexport const VOICE_RELAY_SAMPLE_RATE = 24_000;\n/**\n * The `voice/start` offer that requests the LiveKit transport. Mirrors\n * `agora.graphs.athena_deep_agent.voice_media.VOICE_LIVEKIT_OFFER`.\n */\nexport const VOICE_LIVEKIT_OFFER = 'athena-voice-transport:livekit/v1';\n/**\n * Prefix of a `voice/start` answer that carries LiveKit room credentials: the\n * rest is `JSON.stringify({ serverUrl, token, roomName })`. Mirrors\n * `agora.graphs.athena_deep_agent.voice_media.VOICE_LIVEKIT_ANSWER_PREFIX`.\n */\nexport const VOICE_LIVEKIT_ANSWER_PREFIX = 'athena-voice-livekit:';\n\n/** The room the host minted for the session, decoded from the `voice/start` answer. */\nexport interface DeepAgentVoiceLiveKitAnswer {\n /** LiveKit signalling URL, already `wss://`. */\n serverUrl: string;\n /** The browser participant's join token (`room_join`, publish, subscribe). */\n token: string;\n roomName: string;\n}\n\n/** A joined LiveKit room, as far as the session state machine drives it. */\nexport interface DeepAgentVoiceLiveKitSession {\n /** Publish/unpublish (or unmute/mute) the local microphone track. */\n setMicrophoneEnabled(enabled: boolean): Promise<void>;\n /** Leave the room and release the microphone. Idempotent. */\n disconnect(): Promise<void>;\n}\n\n/**\n * The LiveKit leg of the `livekit` transport, supplied by the surface so this\n * package never depends on `livekit-client` (web surfaces wrap `Room`; native\n * ones wrap the React Native SDK). Structural on purpose: tests inject fakes.\n */\nexport interface DeepAgentVoiceLiveKitAdapter {\n /**\n * Join the room, publish the microphone (respecting `micMuted`), play remote\n * audio; rejects on failure (a microphone-permission error keeps its DOM\n * `name`, so it classifies as `microphone_denied`). `onDisconnected` fires\n * once when the room drops AFTER a successful join — never for the session's\n * own `disconnect()`. An aborted `signal` must stop pending/joined media and\n * reject a pending join; the runtime also releases late results from older\n * adapters that do not implement cancellation.\n */\n connect(\n answer: DeepAgentVoiceLiveKitAnswer,\n handlers: {\n micMuted: boolean;\n /** Abort a pending join and release media when this attempt ends. */\n signal?: AbortSignal;\n onDisconnected: (reason: string) => void;\n /**\n * Media telemetry while the room lasts (reconnects, the agent leaving,\n * audio quality); reported as `media-event` diagnostics. Optional.\n */\n onEvent?: (event: VoiceMediaEvent) => void;\n }\n ): Promise<DeepAgentVoiceLiveKitSession>;\n}\n\n/** One realtime model the host offers for voice sessions (`state.voiceModelOptions`). */\nexport interface DeepAgentVoiceModelOption {\n id: string;\n label: string;\n provider: 'openai_live' | 'google';\n /** `false` when the deployment lacks the provider's credentials. */\n enabled: boolean;\n description: string;\n}\n\nconst VOICE_MODEL_PROVIDERS: ReadonlySet<string> = new Set(['openai_live', 'google']);\n\n/**\n * Validate the host's `state.voiceModelOptions`: `null` when absent or not a\n * list, otherwise the well-formed entries (a malformed entry is dropped, not\n * fatal — an older or newer host must never blank the whole picker).\n */\nexport const parseVoiceModelOptions = (value: unknown): DeepAgentVoiceModelOption[] | null => {\n if (!Array.isArray(value)) return null;\n const options: DeepAgentVoiceModelOption[] = [];\n for (const entry of value) {\n if (entry === null || typeof entry !== 'object') continue;\n const { id, label, provider, enabled, description } = entry as Record<string, unknown>;\n if (\n typeof id !== 'string' ||\n id === '' ||\n typeof label !== 'string' ||\n typeof provider !== 'string' ||\n !VOICE_MODEL_PROVIDERS.has(provider) ||\n typeof enabled !== 'boolean' ||\n typeof description !== 'string'\n ) {\n continue;\n }\n options.push({\n id,\n label,\n provider: provider as DeepAgentVoiceModelOption['provider'],\n enabled,\n description,\n });\n }\n return options;\n};\n\nconst sameVoiceModelOptions = (\n a: readonly DeepAgentVoiceModelOption[],\n b: readonly DeepAgentVoiceModelOption[]\n): boolean =>\n a.length === b.length &&\n a.every((option, index) => {\n const other = b[index];\n return (\n other !== undefined &&\n option.id === other.id &&\n option.label === other.label &&\n option.provider === other.provider &&\n option.enabled === other.enabled &&\n option.description === other.description\n );\n });\n\n// This package compiles without the DOM lib; the WebRTC / Web Audio /\n// WebSocket surfaces the hook touches are declared structurally and resolved\n// from `globalThis` (browser, extension page, or react-native-webrtc's\n// registerGlobals).\ninterface VoiceMediaStreamTrack {\n /** Standard WebRTC mute lever: a disabled track transmits silence. */\n enabled: boolean;\n stop(): void;\n}\n\nexport interface DeepAgentVoiceRemoteStream {\n getTracks(): VoiceMediaStreamTrack[];\n /** React Native WebRTC owns native stream/track entries beyond track.stop(). */\n release?(): void;\n}\n\nfunction releaseCaptureStream(stream: DeepAgentVoiceRemoteStream | null): void {\n if (!stream) return;\n releaseSafely(() => {\n for (const track of stream.getTracks()) releaseSafely(() => track.stop());\n });\n releaseSafely(() => stream.release?.());\n}\n\n/** One failed native/browser cleanup must not strand the remaining media. */\nfunction releaseSafely(release: () => unknown): void {\n try {\n void Promise.resolve(release()).catch(() => undefined);\n } catch {\n // Teardown is best-effort, including synchronous native bridge failures.\n }\n}\n\ninterface VoiceTrackEvent {\n track: VoiceMediaStreamTrack;\n streams: DeepAgentVoiceRemoteStream[];\n}\n\ntype VoiceConnectionStateEvent = 'connectionstatechange' | 'iceconnectionstatechange';\n\ninterface VoicePeerConnection {\n readonly iceGatheringState: string;\n /** Aggregate transport state (`connected`, `disconnected`, `failed`, `closed`). */\n readonly connectionState?: string;\n /** ICE-only state; the fallback where an implementation lacks `connectionState`. */\n readonly iceConnectionState?: string;\n readonly localDescription: { readonly sdp?: string } | null;\n addTrack(track: VoiceMediaStreamTrack, stream: DeepAgentVoiceRemoteStream): unknown;\n addEventListener(type: 'track', listener: (event: VoiceTrackEvent) => void): void;\n addEventListener(type: 'icegatheringstatechange', listener: () => void): void;\n addEventListener(type: VoiceConnectionStateEvent, listener: () => void): void;\n removeEventListener(type: 'icegatheringstatechange', listener: () => void): void;\n removeEventListener(type: 'track', listener: (event: VoiceTrackEvent) => void): void;\n removeEventListener(type: VoiceConnectionStateEvent, listener: () => void): void;\n createOffer(): Promise<{ sdp?: string }>;\n setLocalDescription(description: { sdp?: string }): Promise<void>;\n setRemoteDescription(description: { type: 'answer'; sdp: string }): Promise<void>;\n close(): void;\n}\n\ninterface VoiceWebSocket {\n binaryType: string;\n /** 0 connecting, 1 open, 2 closing, 3 closed. */\n readonly readyState: number;\n send(data: ArrayBufferLike): void;\n close(code?: number, reason?: string): void;\n addEventListener(type: 'open' | 'close' | 'error', listener: () => void): void;\n addEventListener(type: 'message', listener: (event: { data: unknown }) => void): void;\n}\n\ninterface VoiceAudioNode {\n connect(destination: VoiceAudioNode): unknown;\n disconnect(): void;\n}\n\ninterface VoiceAudioBuffer {\n readonly duration: number;\n copyToChannel(source: Float32Array, channel: number): void;\n}\n\ninterface VoiceBufferSource extends VoiceAudioNode {\n buffer: VoiceAudioBuffer | null;\n start(when?: number): void;\n}\n\ninterface VoiceScriptProcessor extends VoiceAudioNode {\n onaudioprocess:\n | ((event: { inputBuffer: { getChannelData(channel: number): Float32Array } }) => void)\n | null;\n}\n\ninterface VoiceGainNode extends VoiceAudioNode {\n gain: { value: number };\n}\n\ninterface VoiceAudioContext {\n readonly currentTime: number;\n readonly destination: VoiceAudioNode;\n createMediaStreamSource(stream: DeepAgentVoiceRemoteStream): VoiceAudioNode;\n createScriptProcessor(\n bufferSize: number,\n inputChannels: number,\n outputChannels: number\n ): VoiceScriptProcessor;\n createGain(): VoiceGainNode;\n createBuffer(channels: number, length: number, sampleRate: number): VoiceAudioBuffer;\n createBufferSource(): VoiceBufferSource;\n resume?(): Promise<void>;\n close(): Promise<void>;\n}\n\nconst voiceGlobals = globalThis as {\n RTCPeerConnection?: new () => VoicePeerConnection;\n MediaStream?: new (tracks: VoiceMediaStreamTrack[]) => DeepAgentVoiceRemoteStream;\n WebSocket?: new (url: string) => VoiceWebSocket;\n AudioContext?: new (options?: { sampleRate?: number }) => VoiceAudioContext;\n navigator?: {\n mediaDevices?: {\n getUserMedia(constraints: { audio: boolean }): Promise<DeepAgentVoiceRemoteStream>;\n };\n };\n};\n\n// Covers the host's own worst case: up to 30 s for the realtime provider's\n// session.started (`_START_TIMEOUT_SECONDS`, agora gpt_live_provider.py), then\n// the LiveKit room create and join. A tenant egress proxy in front of the\n// provider pushes a healthy start past 15 s; a shorter deadline abandons a\n// session the host is about to answer. scripts/voice-answer-timeout.test.ts\n// keeps the two in step.\nconst ANSWER_TIMEOUT_MS = 45_000;\nconst ICE_TIMEOUT_MS = 10_000;\nconst RELAY_OPEN_TIMEOUT_MS = 10_000;\n/** Capture frame for the WebSocket transport: ~43 ms of audio at 24 kHz. */\nconst RELAY_CAPTURE_FRAME_SAMPLES = 1024;\n/** Playback lead so a chunk scheduled \"now\" never lands in the past. */\nconst RELAY_PLAYBACK_LEAD_SECONDS = 0.02;\n/**\n * How long a `disconnected` transport may try to recover on its own before it\n * counts as lost. ICE routinely reports `disconnected` for a few seconds on a\n * network change and then reconnects; `failed` and `closed` are final.\n */\nconst MEDIA_DISCONNECT_GRACE_MS = 5_000;\n/**\n * Upper bound on waiting for the server to acknowledge `voice/end` before a\n * media-loss restart sends its `voice/start`: a start that races the old\n * session's teardown is rejected `voice-active`.\n */\nconst END_BEFORE_RESTART_TIMEOUT_MS = 3_000;\n/**\n * Upper bound on `voice/transfer-offer` (the host only mints a join token;\n * `timeouts.answerMs` lowers it). The host drops a pending transfer after\n * 20 s, so waiting longer than that could never succeed.\n */\nconst TRANSFER_OFFER_TIMEOUT_MS = 15_000;\n/**\n * `voice/transfer-commit` holds up to ~1.2 s for a turn boundary plus up to\n * 5 s for this client's microphone track to reach the host; 15 s covers both\n * and the round trips, inside the host's 20 s transfer deadline.\n */\nconst TRANSFER_COMMIT_TIMEOUT_MS = 15_000;\n\n/** Operation IDs for voice turns and calls (uniqueness, not secrecy) —\n * platform-free on purpose: React Native lacks full webcrypto. */\nconst mintVoiceId = ({ kind }: { kind: 'text' | 'attempt' }): string =>\n `voice${kind}_${Date.now().toString(36)}${Math.random().toString(36).slice(2, 12)}`;\n\n/** `m:ss` / `h:mm:ss` for the live-session timer strips (shared so the three\n * surfaces cannot drift on formatting). */\nexport const formatVoiceElapsed = (sinceMs: number, nowMs: number = Date.now()): string => {\n const total = Math.max(0, Math.floor((nowMs - sinceMs) / 1000));\n const hours = Math.floor(total / 3600);\n const minutes = Math.floor((total % 3600) / 60);\n const seconds = total % 60;\n const mmss = `${minutes}:${String(seconds).padStart(2, '0')}`;\n return hours > 0 ? `${hours}:${String(minutes).padStart(2, '0')}:${String(seconds).padStart(2, '0')}` : mmss;\n};\n\n/** Ticking elapsed-call string for a live session — the one timer\n * implementation all surfaces share (interval lifecycle + formatting).\n * Returns `null` when there is no live session. Callers isolate it in a\n * leaf component so only that leaf re-renders per second. */\nexport const useVoiceElapsed = (since: number | null): string | null => {\n const [now, setNow] = useState(() => Date.now());\n useEffect(() => {\n if (since === null) return;\n setNow(Date.now());\n const timer = setInterval(() => setNow(Date.now()), 1000);\n return () => clearInterval(timer);\n }, [since]);\n return since === null ? null : formatVoiceElapsed(since, now);\n};\n\nconst VOICE_SURFACE_LABELS: Record<DeepAgentVoiceSurface, string> = {\n web: 'browser',\n mobile: 'phone',\n chrome: 'Chrome',\n desktop: 'desktop app',\n office: 'Office',\n};\n\n/** How the person's own device of a kind is named in voice copy (\"your phone\"). */\nexport const voiceSurfaceLabel = (surface: DeepAgentVoiceSurface): string =>\n VOICE_SURFACE_LABELS[surface];\n\n/** The mic control's label while the call is live on another of the person's devices. */\nexport const VOICE_MOVE_CALL_HERE_LABEL = 'Move call here';\n/** The action on the live-elsewhere banner. */\nexport const VOICE_MOVE_HERE_ACTION = 'Move here';\n\n/**\n * The one-tap offer a destination shows after a handover the person sent in\n * voice mode; it starts a call with the recap opening (`start({ opening:\n * 'recap' })`), never on its own.\n */\nexport const VOICE_CONTINUE_BY_VOICE_LABEL = 'Continue by voice';\n\n/** The live-elsewhere banner's text, before its {@link VOICE_MOVE_HERE_ACTION}. */\nexport const describeVoiceLiveElsewhere = (surface: DeepAgentVoiceSurface): string =>\n `Live call on your ${voiceSurfaceLabel(surface)}`;\n\n/** The notice on the device a call just moved away from. */\nexport const describeVoiceMovedTo = (surface: DeepAgentVoiceSurface): string =>\n `Call moved to your ${voiceSurfaceLabel(surface)}`;\n\n/** How long the moved notice stays up. */\nexport const VOICE_MOVED_NOTICE_MS = 6_000;\n\n/**\n * The transient \"Call moved to your …\" notice for a hook's `movedTo`: the\n * words for {@link VOICE_MOVED_NOTICE_MS} after each move, then `null`. One\n * implementation so every surface keeps it up equally long.\n */\nexport const useVoiceMovedNotice = (\n movedTo: { surface: DeepAgentVoiceSurface } | null\n): string | null => {\n const [expired, setExpired] = useState<object | null>(null);\n useEffect(() => {\n if (movedTo === null) return;\n const timer = setTimeout(() => setExpired(movedTo), VOICE_MOVED_NOTICE_MS);\n return () => clearTimeout(timer);\n }, [movedTo]);\n return movedTo !== null && expired !== movedTo ? describeVoiceMovedTo(movedTo.surface) : null;\n};\n\nconst VOICE_SURFACES: ReadonlySet<string> = new Set(Object.keys(VOICE_SURFACE_LABELS));\n\n/**\n * Validate the host's `state.voiceOwner`: `null` when absent or malformed. An\n * unknown surface reads as `web`, as the host labels any client it does not\n * recognize; anything but `transferable: true` cannot move.\n */\nexport const parseVoiceOwner = (value: unknown): DeepAgentVoiceOwnerWireState | null => {\n if (value === null || typeof value !== 'object') return null;\n const { clientId, surface, since, transferable } = value as Record<string, unknown>;\n if (typeof clientId !== 'string' || clientId === '') return null;\n if (typeof since !== 'number' || !Number.isFinite(since)) return null;\n return {\n clientId,\n surface:\n typeof surface === 'string' && VOICE_SURFACES.has(surface)\n ? (surface as DeepAgentVoiceSurface)\n : 'web',\n since,\n transferable: transferable === true,\n };\n};\n\nconst REQUEST_LABELS: Record<string, string> = {\n 'session.commentary.append': 'a result for the voice conversation',\n 'session.thinking.append': 'a context update',\n 'session.input_audio.mute': 'the mute request',\n 'session.input_audio.unmute': 'the unmute request',\n 'response.item.create': 'a tool result',\n};\n\n/**\n * One-line, user-facing rendering of a Live API rejection the host projected\n * (`state.voiceLastError`). Shared so every surface words the notice alike.\n */\nexport const describeVoiceWireError = (error: DeepAgentVoiceWireError): string => {\n const subject = error.requestType\n ? (REQUEST_LABELS[error.requestType] ?? `a ${error.requestType} event`)\n : 'a session event';\n return `The voice service rejected ${subject}: ${error.message}`;\n};\n\n/** The relay endpoint for a ticket: `wss://<agora>/api/voice/relay?ticket=…`. */\nexport const voiceRelayUrl = (relayUrl: string, ticket: string): string =>\n `${relayUrl.replace(/^http/, 'ws').replace(/\\/+$/, '')}/api/voice/relay?ticket=${encodeURIComponent(ticket)}`;\n\n/** Float32 samples in [-1, 1] → little-endian PCM16 (the relay wire format). */\nexport const pcm16FromFloat32 = (samples: Float32Array): Int16Array => {\n const pcm = new Int16Array(samples.length);\n for (let index = 0; index < samples.length; index += 1) {\n const clamped = Math.max(-1, Math.min(1, samples[index] ?? 0));\n pcm[index] = clamped < 0 ? Math.round(clamped * 0x8000) : Math.round(clamped * 0x7fff);\n }\n return pcm;\n};\n\n/** PCM16 → Float32 samples in [-1, 1] for Web Audio playback. */\nexport const float32FromPcm16 = (pcm: Int16Array): Float32Array => {\n const samples = new Float32Array(pcm.length);\n for (let index = 0; index < pcm.length; index += 1) {\n samples[index] = (pcm[index] ?? 0) / 0x8000;\n }\n return samples;\n};\n\nconst isRecoveredCommandAuthRejection = (error: unknown): boolean => {\n const payload = statewireRejectionPayload(error);\n if (payload?.status !== 503) return false;\n const detail = payload.detail as { code?: unknown; retryable?: unknown } | undefined;\n return detail?.code === 'command_auth_context_expired' && detail.retryable === true;\n};\n\n/**\n * Wait for ICE gathering, bounded. Gathering that has not completed by the\n * deadline is NOT a failure: the offer carries the candidates gathered so far\n * and the Live API's answer supplies the server side, so the connectivity\n * checks the client initiates still establish the media path (the API's own\n * reference client sends the offer without waiting at all). Mobile radios with\n * several interfaces routinely take long to declare gathering complete, and\n * failing the whole session on that was a needless hard stop.\n */\nconst waitForIce = (\n pc: VoicePeerConnection,\n timeoutMs: number\n): Promise<'complete' | 'timeout'> =>\n new Promise((resolve) => {\n if (pc.iceGatheringState === 'complete') {\n resolve('complete');\n return;\n }\n const timeout = setTimeout(() => {\n pc.removeEventListener('icegatheringstatechange', check);\n resolve('timeout');\n }, timeoutMs);\n const check = (): void => {\n if (pc.iceGatheringState !== 'complete') return;\n clearTimeout(timeout);\n pc.removeEventListener('icegatheringstatechange', check);\n resolve('complete');\n };\n pc.addEventListener('icegatheringstatechange', check);\n });\n\nconst waitForRelayOpen = (ws: VoiceWebSocket, timeoutMs: number): Promise<void> =>\n new Promise((resolve, reject) => {\n const timeout = setTimeout(\n () => reject(new Error('The voice relay did not open in time')),\n timeoutMs\n );\n ws.addEventListener('open', () => {\n clearTimeout(timeout);\n resolve();\n });\n ws.addEventListener('error', () => {\n clearTimeout(timeout);\n reject(new Error('The voice relay connection failed'));\n });\n ws.addEventListener('close', () => {\n clearTimeout(timeout);\n reject(new Error('The voice relay closed before it opened'));\n });\n });\n\n/** The latest hydrated selection, held through unhydrated (`undefined`) replay snapshots. */\nconst useRetainedHydrated = <T>(value: T | undefined, initial: T): T => {\n const ref = useRef<T>(initial);\n if (value !== undefined) ref.current = value;\n return ref.current;\n};\n\n/** A call this device held or took moving between the person's own devices; see `onCallMoved`. */\nexport interface DeepAgentVoiceCallMove {\n /** `here`: this device now holds the call. `away`: the call left this device. */\n direction: 'here' | 'away';\n /** The other device: where the call came from (`here`) or went (`away`). */\n surface: DeepAgentVoiceSurface;\n}\n\nexport interface UseDeepAgentVoiceOptions {\n /**\n * Remote-audio sink: called with the remote stream when the session answers\n * and with `null` on teardown. Web surfaces attach it to an `<audio>`\n * element; react-native-webrtc plays remote audio natively, so native\n * surfaces omit it. A rejected promise fails the session. WebRTC only: the\n * WebSocket transport plays through its own `AudioContext`.\n */\n onRemoteStream?: (stream: DeepAgentVoiceRemoteStream | null) => void | Promise<void>;\n /**\n * Platform audio-session ownership for the whole call: `start` runs before\n * mic capture (a rejection fails the session), `stop` runs on every\n * teardown path. Native surfaces pass their call-audio module (on iOS the\n * non-mixable playAndRecord/voiceChat session that entitles the app to\n * keep a live call running); web surfaces omit it.\n */\n audioSession?: {\n start: () => Promise<void>;\n stop: () => Promise<void>;\n /** Synchronously mark an in-flight start for cleanup before a new owner starts. */\n cancelStart?: () => void;\n };\n /** Media transport; see {@link DeepAgentVoiceTransport}. Default `webrtc`. */\n transport?: DeepAgentVoiceTransport;\n /**\n * Agora's base URL (e.g. `https://api.athenaintel.com`) whose\n * `/api/voice/relay` endpoint carries the audio on the `websocket`\n * transport. Required for that transport, ignored otherwise.\n */\n relayUrl?: string;\n /**\n * The room leg for the `livekit` transport (required for it, ignored\n * otherwise); see {@link DeepAgentVoiceLiveKitAdapter}. Read through a\n * per-render ref, so a fresh adapter never restarts anything.\n */\n livekit?: DeepAgentVoiceLiveKitAdapter;\n /**\n * The realtime model to ask for, sent as `voice/start.model` — a value or a\n * getter resolved when each attempt (user start or automatic restart)\n * negotiates. `undefined`/empty omits the key and the host picks its\n * default. Only the `livekit` transport can honour a non-GPT-Live model.\n */\n model?: string | (() => string | undefined);\n /**\n * Lifecycle observer for the session attempts (negotiation milestones with\n * timings, media-state changes, losses, restarts, ends). Surfaces feed it to\n * their crash breadcrumbs / telemetry; read through a per-render ref, so a\n * fresh closure never restarts anything. Must not throw.\n */\n onDiagnostic?: (entry: DeepAgentVoiceDiagnostic) => void;\n /**\n * Called when this device's call moves between the person's own devices:\n * `here` once {@link UseDeepAgentVoiceReturn.transferHere} took the call\n * (it is live here), `away` when the host moved it to another device\n * (alongside `movedTo`). Hosts play the move earcon from it\n * ({@link playVoiceMoveEarcon} on the web). For `away` it runs before the\n * hook lets go of the call's platform audio session, which it then releases\n * at once (`audioSession.stop`): a host that plays the cue inside that\n * session holds the session's stop itself, in its shared session queue, so\n * a chat started meanwhile waits rather than finds the session taken. Read\n * through a per-render ref; a throw or a rejected promise is ignored.\n */\n onCallMoved?: (move: DeepAgentVoiceCallMove) => void | Promise<void>;\n /** Per-surface overrides of the negotiation deadlines (ms). */\n timeouts?: {\n /** How long to wait for ICE gathering to complete before sending the offer with the candidates so far. */\n iceGatheringMs?: number;\n /** How long `voice/start` may take to answer. */\n answerMs?: number;\n /** How long the relay WebSocket may take to open (`websocket` transport). */\n relayOpenMs?: number;\n /** How long `voice/transfer-commit` may take to move a call here (default 15 s). */\n transferCommitMs?: number;\n };\n}\n\nexport interface UseDeepAgentVoiceReturn {\n phase: DeepAgentVoicePhase;\n /** The failure message while `phase === 'error'` (same as `failure.message`). */\n error: string | null;\n /**\n * The classified failure while `phase === 'error'`; `null` otherwise. Where\n * `error` is only words, this says WHICH step failed and, for a host\n * rejection, the host's reason code — the key telemetry and support join on.\n */\n failure: DeepAgentVoiceFailure | null;\n /** Start a call: a user action (it re-arms the one-shot restart); see {@link DeepAgentVoiceStartOptions}. */\n start: (options?: DeepAgentVoiceStartOptions) => Promise<void>;\n end: () => void;\n /** The delegated voice task currently running server-side, if any. */\n activeTask: { taskId: string; text: string } | null;\n /** Epoch ms when the session went live; `null` outside a live session.\n * Surfaces render an elapsed-call timer from it. */\n liveSince: number | null;\n /**\n * Whether the local microphone is muted. Mute is distinct from `end`: the\n * session (and any delegated work) stays live while the local track is\n * disabled AND the server mutes protocol input (`session.input_audio.mute`\n * — muted speech is discarded server-side, the model keeps speaking).\n */\n micMuted: boolean;\n /** Mute/unmute the live session's microphone; a no-op unless live. */\n setMicMuted: (muted: boolean) => void;\n /**\n * Bimodal input: send typed text into the live conversation as if spoken.\n * Resolves `true` once the server accepted it; `false` when there is no\n * live session or the command was rejected — the caller falls back to a\n * normal run send so the message is never lost.\n */\n sendUserText: (text: string) => Promise<boolean>;\n /**\n * The delegated task that was still running when the last session ended.\n * The run itself continues on the thread — surfaces render a \"voice ended,\n * still working\" note from this until the run settles or a new session\n * starts, at which point it clears itself.\n */\n handoffTask: { taskId: string; text: string } | null;\n /**\n * Push the client's current synced context (runConfig included) to the\n * server so the NEXT delegated run uses it. Call after a runConfig change\n * while the session is live; a no-op otherwise.\n */\n syncProfile: () => void;\n /**\n * Non-fatal notice for the live session: the most recent Live API\n * rejection the host projected (a refused context update, a failed mute),\n * worded for the user. The session stays live; `null` when there is none\n * or the session is not live.\n */\n notice: string | null;\n /**\n * Tell the live session what the user is looking at (one short line, e.g.\n * `spreadsheet \"Q3 Budget\"`). Silent context for reference resolution;\n * fire-and-forget, a no-op unless live.\n */\n sendContext: (text: string) => void;\n /**\n * The realtime model the host resolved for the current/last session\n * (`state.voiceModel`, stamped when a session starts), or `null` before\n * any session or while the snapshot is not hydrated. Stale after an end is\n * inert — surfaces gate on `phase`, like `micMuted`.\n */\n model: string | null;\n /**\n * The realtime models this host offers (`state.voiceModelOptions`,\n * published at host boot), validated; `null` on an older host that does\n * not publish them — surfaces fall back to their static list.\n */\n modelOptions: DeepAgentVoiceModelOption[] | null;\n /**\n * The call live on another of the person's own devices that this one can\n * take: set while the thread's session is live, the host projects its owner\n * as transferable (`state.voiceOwner`), this hook holds no media (`idle` or\n * `error`) and its transport is `livekit`. `null` otherwise, and always on a\n * host that cannot move calls (it never projects `voiceOwner`). Surfaces\n * turn the mic into \"Move call here\" and show a banner from it.\n */\n liveElsewhere: { surface: DeepAgentVoiceSurface; since: number } | null;\n /**\n * Move the call named by `liveElsewhere` to this device: offer, join the\n * room, commit, then `live`. A move that does not complete withdraws the\n * offer, releases the room and settles to `error` with\n * `failure.kind === 'transfer_failed'` while the call stays on the other\n * device. A user action, like `start`: re-arms the one-shot restart. A\n * no-op without `liveElsewhere`.\n */\n transferHere: () => Promise<void>;\n /**\n * Where this device's live call just moved: set when the host moves the\n * session's owner to another client (this hook let go of its media without\n * ending the call), cleared by the next `start` or `transferHere`. Surfaces\n * show a transient notice ({@link useVoiceMovedNotice}).\n */\n movedTo: { surface: DeepAgentVoiceSurface } | null;\n}\n\n/**\n * The experimental voice-mode session against the thread's `voice/start` /\n * `voice/end` commands: mic capture and media negotiation (WebRTC by default,\n * or PCM over Agora's relay WebSocket); the live turns stream into the chat\n * log as `ephemeral: true` entries in `state.messages`.\n */\nexport const useDeepAgentVoice = (\n options: UseDeepAgentVoiceOptions = {}\n): UseDeepAgentVoiceReturn => {\n const wireSendCommand = useStatewireSendCommand();\n const sendCommandRef = useRef(wireSendCommand);\n sendCommandRef.current = wireSendCommand;\n // Normalize synchronous dispatch failures and async verdicts in one place.\n // Callers can always catch a rejection, even while the thread unmounts.\n const sendCommand = useCallback(\n async (command: Parameters<typeof wireSendCommand>[0]) => sendCommandRef.current(command),\n []\n );\n const voice = useStatewireState(\n // The raw wire state is non-object until the attach snapshot hydrates it.\n (s) => (readDeepAgentStreamValues(s).voice as DeepAgentVoiceWireState | null | undefined) ?? null\n );\n const [phase, setPhase] = useState<DeepAgentVoicePhase>('idle');\n const [failure, setFailure] = useState<DeepAgentVoiceFailure | null>(null);\n const error = failure?.message ?? null;\n const [micMuted, setMicMutedState] = useState(false);\n // Mute is user intent, not media state. A replacement stream must inherit it\n // before any track is attached, including during automatic recovery.\n const micMutedRef = useRef(false);\n const micChangeRef = useRef(0);\n const [liveSince, setLiveSince] = useState<number | null>(null);\n // The task that was running when the last session ended: the run continues\n // on the thread, so surfaces keep a \"still working\" note until it settles.\n const [handoffTask, setHandoffTask] = useState<{\n taskId: string;\n text: string;\n } | null>(null);\n const lastActiveTaskRef = useRef<{ taskId: string; text: string } | null>(null);\n const pcRef = useRef<VoicePeerConnection | null>(null);\n const releasePeerListenersRef = useRef<(() => void) | null>(null);\n const streamRef = useRef<DeepAgentVoiceRemoteStream | null>(null);\n // WebSocket transport state: the relay socket and the local audio graph.\n const wsRef = useRef<VoiceWebSocket | null>(null);\n const audioContextRef = useRef<VoiceAudioContext | null>(null);\n const audioNodesRef = useRef<VoiceAudioNode[]>([]);\n const playheadRef = useRef(0);\n // LiveKit transport state: the joined room.\n const livekitRef = useRef<DeepAgentVoiceLiveKitSession | null>(null);\n const livekitAbortRef = useRef<AbortController | null>(null);\n // Bumped by teardown and by every start(): a startup attempt that awakes\n // from an await into a different generation is stale — it must release\n // whatever it acquired and exit without touching session state.\n const attemptRef = useRef(0);\n const callAttemptIdRef = useRef('');\n const observedAttempt = useStatewireState((s) => {\n if (!isDeepAgentStateHydrated(s)) return undefined;\n const values = readDeepAgentStreamValues(s);\n const value = values.voiceStartFence ?? values.voiceAttemptId;\n return typeof value === 'string' ? value : null;\n });\n const observedAttemptRef = useRef<string | undefined>(undefined);\n // Preserve the last hydrated observation through transient replay snapshots.\n if (observedAttempt !== undefined) observedAttemptRef.current = observedAttempt ?? undefined;\n const startingRef = useRef(false);\n // The in-flight startup, so a media-loss restart can wait for a startup\n // that died mid-negotiation to release its guard before it retries.\n const startPromiseRef = useRef<Promise<void> | null>(null);\n // One-shot resurrection budget: a session the SERVER dropped (connection\n // blip, host rotation) or whose MEDIA path died restarts once per\n // user-initiated session; a second drop — or a failed restart — settles to\n // idle/error so a flapping host or network can never loop the mic grant.\n const autoRestartedRef = useRef(false);\n const onRemoteStreamRef = useRef(options.onRemoteStream);\n onRemoteStreamRef.current = options.onRemoteStream;\n const audioSessionRef = useRef(options.audioSession);\n audioSessionRef.current = options.audioSession;\n const transportRef = useRef(options.transport ?? 'webrtc');\n transportRef.current = options.transport ?? 'webrtc';\n const relayUrlRef = useRef(options.relayUrl);\n relayUrlRef.current = options.relayUrl;\n const livekitAdapterRef = useRef(options.livekit);\n livekitAdapterRef.current = options.livekit;\n const modelRef = useRef(options.model);\n modelRef.current = options.model;\n const onDiagnosticRef = useRef(options.onDiagnostic);\n onDiagnosticRef.current = options.onDiagnostic;\n const onCallMovedRef = useRef(options.onCallMoved);\n onCallMovedRef.current = options.onCallMoved;\n const timeoutsRef = useRef(options.timeouts);\n timeoutsRef.current = options.timeouts;\n // The phase as of the last render, for the unmount cleanup (which runs\n // outside React's render cycle and cannot read state).\n const phaseRef = useRef<DeepAgentVoicePhase>('idle');\n phaseRef.current = phase;\n // When the current attempt's start was requested, for diagnostic timings.\n const attemptStartedAtRef = useRef(0);\n // The session object whose start() succeeded — teardown must stop that\n // same object even if `options.audioSession` changes mid-session.\n const activeAudioSessionRef = useRef<UseDeepAgentVoiceOptions['audioSession'] | null>(null);\n const startingAudioSessionRef = useRef<UseDeepAgentVoiceOptions['audioSession'] | null>(null);\n // Serializes stop -> start: the next start() waits for the previous\n // session's shutdown to settle before claiming the platform audio session.\n const audioSessionIdleRef = useRef<Promise<void>>(Promise.resolve());\n // The client the host names as this call's owner (`state.voice.clientId`),\n // captured once the wire reflects this call: a later change means the host\n // moved the call to another of the person's devices.\n const ownClientIdRef = useRef<string | null>(null);\n // The owner id this hook last held, kept after the call ends: this client\n // is never \"elsewhere\", even while its own ended call is winding down.\n const lastOwnedClientIdRef = useRef<string | null>(null);\n // The move in flight (offer → join → commit), so an end or unmount withdraws\n // the offer rather than ending a call this client does not own yet.\n const transferRef = useRef<{ attempt: number; transferId: string | null } | null>(null);\n const [movedTo, setMovedTo] = useState<{ surface: DeepAgentVoiceSurface } | null>(null);\n\n // What voice transfer reads off the wire, each held through unhydrated\n // replay snapshots like the attempt fence above, so a typed send never\n // blinks the live-elsewhere banner. `voiceOwner` is stamped at boot by a\n // host that can move calls: the key's presence is the capability.\n const hydratedTransferCapable = useStatewireState((s) =>\n isDeepAgentStateHydrated(s) ? 'voiceOwner' in readDeepAgentStreamValues(s) : undefined\n );\n const hydratedVoiceOwner = useStatewireState((s) =>\n isDeepAgentStateHydrated(s) ? (readDeepAgentStreamValues(s).voiceOwner ?? null) : undefined\n );\n const hydratedWireOwnerId = useStatewireState((s) => {\n if (!isDeepAgentStateHydrated(s)) return undefined;\n const wire = readDeepAgentStreamValues(s).voice as { clientId?: unknown } | null | undefined;\n return typeof wire?.clientId === 'string' && wire.clientId !== '' ? wire.clientId : null;\n });\n const hydratedWireLive = useStatewireState((s) => {\n if (!isDeepAgentStateHydrated(s)) return undefined;\n const wire = readDeepAgentStreamValues(s).voice as { status?: unknown } | null | undefined;\n return wire?.status === 'live';\n });\n const transferCapable = useRetainedHydrated(hydratedTransferCapable, false);\n const wireVoiceOwner = useRetainedHydrated<unknown>(hydratedVoiceOwner, null);\n const wireOwnerId = useRetainedHydrated<string | null>(hydratedWireOwnerId, null);\n const wireLive = useRetainedHydrated(hydratedWireLive, false);\n const voiceOwner = useMemo(\n () => (transferCapable ? parseVoiceOwner(wireVoiceOwner) : null),\n [transferCapable, wireVoiceOwner]\n );\n const transferCapableRef = useRef(transferCapable);\n transferCapableRef.current = transferCapable;\n const voiceOwnerRef = useRef(voiceOwner);\n voiceOwnerRef.current = voiceOwner;\n const wireOwnerIdRef = useRef(wireOwnerId);\n wireOwnerIdRef.current = wireOwnerId;\n // Only a LiveKit leg can join the room a moved call lives in.\n const canTakeCall = transportRef.current === 'livekit' && livekitAdapterRef.current !== undefined;\n const elsewhere =\n voiceOwner !== null &&\n voiceOwner.transferable &&\n wireLive &&\n canTakeCall &&\n (phase === 'idle' || phase === 'error') &&\n voiceOwner.clientId !== lastOwnedClientIdRef.current\n ? voiceOwner\n : null;\n const elsewhereSurface = elsewhere?.surface ?? null;\n const elsewhereSince = elsewhere?.since ?? null;\n const liveElsewhere = useMemo(\n () =>\n elsewhereSurface === null || elsewhereSince === null\n ? null\n : { surface: elsewhereSurface, since: elsewhereSince },\n [elsewhereSurface, elsewhereSince]\n );\n const liveElsewhereRef = useRef(liveElsewhere);\n liveElsewhereRef.current = liveElsewhere;\n\n const report = useCallback(\n (\n event: DeepAgentVoiceDiagnosticEvent,\n attempt: number,\n data?: DeepAgentVoiceDiagnostic['data']\n ): void => {\n const observer = onDiagnosticRef.current;\n if (!observer) return;\n const at = Date.now();\n try {\n observer({\n event,\n attempt,\n at,\n sinceStartMs: Math.max(0, at - attemptStartedAtRef.current),\n ...(data !== undefined && { data }),\n });\n } catch {\n // An observer is telemetry: it must never take the session down.\n }\n },\n []\n );\n\n const releaseAudioSession = useCallback((): void => {\n const session = activeAudioSessionRef.current;\n if (!session) return;\n activeAudioSessionRef.current = null;\n audioSessionIdleRef.current = audioSessionIdleRef.current\n .then(() => session.stop())\n .catch(() => undefined);\n }, []);\n\n /** Tell the host a call moved, so it can mark it (the earcon). A cue is a courtesy: it never affects the call. */\n const notifyCallMoved = useCallback((move: DeepAgentVoiceCallMove): void => {\n const observer = onCallMovedRef.current;\n if (!observer) return;\n try {\n // Any thenable: a React Native host's promise may not be this realm's `Promise`.\n void Promise.resolve(observer(move)).catch(() => undefined);\n } catch {\n // Ignored, like a rejection.\n }\n }, []);\n\n /**\n * Release everything the current attempt holds. `keepAudioSession` is for\n * the automatic restart that follows a lost connection: the platform audio\n * session stays held for the replacement attempt, which adopts it. On iOS\n * that session is what keeps a locked phone's app running — releasing it\n * and asking for it back from the background got the app suspended, and a\n * non-mixable record session generally cannot be re-activated there, so a\n * restart while locked never came back.\n */\n const teardown = useCallback((options?: { keepAudioSession?: boolean }): void => {\n attemptRef.current += 1;\n const livekitAbort = livekitAbortRef.current;\n livekitAbortRef.current = null;\n releaseSafely(() => livekitAbort?.abort());\n releaseSafely(() => startingAudioSessionRef.current?.cancelStart?.());\n if (options?.keepAudioSession !== true) releaseAudioSession();\n const releasePeerListeners = releasePeerListenersRef.current;\n releasePeerListenersRef.current = null;\n releaseSafely(() => releasePeerListeners?.());\n const pc = pcRef.current;\n pcRef.current = null;\n releaseSafely(() => pc?.close());\n const ws = wsRef.current;\n wsRef.current = null;\n releaseSafely(() => {\n if (ws && ws.readyState < 2) ws.close(1000, 'client end');\n });\n const nodes = audioNodesRef.current;\n audioNodesRef.current = [];\n for (const node of nodes) releaseSafely(() => node.disconnect());\n const audio = audioContextRef.current;\n audioContextRef.current = null;\n releaseSafely(() => audio?.close());\n playheadRef.current = 0;\n const livekit = livekitRef.current;\n livekitRef.current = null;\n releaseSafely(() => livekit?.disconnect());\n const stream = streamRef.current;\n streamRef.current = null;\n releaseCaptureStream(stream);\n setLiveSince(null);\n releaseSafely(() => onRemoteStreamRef.current?.(null));\n }, [releaseAudioSession]);\n\n const fail = useCallback(\n (nextFailure: DeepAgentVoiceFailure): void => {\n report('error', attemptRef.current, {\n kind: nextFailure.kind,\n stage: nextFailure.stage,\n message: nextFailure.message,\n code: nextFailure.code ?? null,\n status: nextFailure.status ?? null,\n fate: nextFailure.fate ?? null,\n reason: nextFailure.reason ?? null,\n });\n teardown();\n setFailure(nextFailure);\n setPhase('error');\n },\n [report, teardown]\n );\n\n /**\n * The host moved this call to another of the person's devices: let go of\n * the media WITHOUT `voice/end` (the session is no longer this client's,\n * and its commands would be refused), and settle to idle with `movedTo`.\n */\n const handleMovedAway = useCallback((): void => {\n const surface = voiceOwnerRef.current?.surface ?? 'web';\n report('moved', attemptRef.current, { toSurface: surface });\n // Before the teardown lets go of the call's audio session: a native cue can\n // still start inside it (the host holds the session's stop for it).\n notifyCallMoved({ direction: 'away', surface });\n teardown();\n ownClientIdRef.current = null;\n micMutedRef.current = false;\n setMicMutedState(false);\n setHandoffTask(null);\n setFailure(null);\n setPhase('idle');\n setMovedTo({ surface });\n }, [notifyCallMoved, report, teardown]);\n\n /** Whether the host now names another client as the owner of the call this hook held. */\n const ownerMovedAway = useCallback((): boolean => {\n const own = ownClientIdRef.current;\n const current = wireOwnerIdRef.current;\n return transferCapableRef.current && own !== null && current !== null && current !== own;\n }, []);\n\n /**\n * Claim the platform audio session for `attempt` (after the previous\n * call's release settled). `false` when the attempt went stale meanwhile —\n * reported, and the session released; a failed start throws.\n */\n const acquireAudioSession = useCallback(\n async ({\n attempt,\n audioSession,\n }: {\n attempt: number;\n audioSession: NonNullable<UseDeepAgentVoiceOptions['audioSession']>;\n }): Promise<boolean> => {\n const held = activeAudioSessionRef.current;\n if (held !== null && held !== audioSession) releaseAudioSession();\n await audioSessionIdleRef.current;\n if (attemptRef.current !== attempt) {\n report('stale-attempt', attempt, { stage: 'audio-session' });\n // A session kept for this restart stays with whoever superseded it:\n // their teardown releases it, their start adopts it.\n return false;\n }\n if (activeAudioSessionRef.current === audioSession) {\n // Kept across an automatic restart (`teardown({ keepAudioSession })`):\n // the call never let go of it, so there is nothing to activate.\n report('audio-session-ready', attempt, { reused: true });\n return true;\n }\n startingAudioSessionRef.current = audioSession;\n try {\n await audioSession.start();\n } finally {\n startingAudioSessionRef.current = null;\n }\n activeAudioSessionRef.current = audioSession;\n if (attemptRef.current !== attempt) {\n report('stale-attempt', attempt, { stage: 'audio-session' });\n releaseAudioSession();\n return false;\n }\n report('audio-session-ready', attempt);\n return true;\n },\n [releaseAudioSession, report]\n );\n\n /**\n * Join `room` through the surface's LiveKit adapter for `attempt`, with the\n * microphone as the person left it. `false` when the attempt went stale\n * during the join (the late room is released); throws when the join fails\n * or the room drops before it completes. A drop AFTER the join goes to\n * `onDisconnectedAfterJoin`.\n */\n const joinVoiceRoom = useCallback(\n async ({\n attempt,\n room,\n adapter,\n controller = new AbortController(),\n onDisconnectedAfterJoin,\n }: {\n attempt: number;\n room: DeepAgentVoiceLiveKitAnswer;\n adapter: DeepAgentVoiceLiveKitAdapter;\n /** Aborted by teardown; a caller passes its own to abort its other waits with it. */\n controller?: AbortController;\n onDisconnectedAfterJoin: (reason: string) => void;\n }): Promise<boolean> => {\n // A drop is only a media loss once the join completed; the adapter\n // owns the failure of a join that never completed.\n let joined = false;\n let disconnectedWhileJoining = false;\n livekitAbortRef.current = controller;\n const session = await adapter.connect(room, {\n micMuted: micMutedRef.current,\n signal: controller.signal,\n onDisconnected: (reason) => {\n if (attemptRef.current !== attempt) return;\n if (!joined) {\n disconnectedWhileJoining = true;\n return;\n }\n onDisconnectedAfterJoin(reason);\n },\n // Telemetry about this attempt's room stays this attempt's even after\n // it ended: the room's closing summary arrives after teardown.\n onEvent: (event) => {\n report('media-event', attempt, { ...event.data, type: event.type });\n },\n });\n if (attemptRef.current !== attempt) {\n releaseSafely(() => session.disconnect());\n return false;\n }\n if (disconnectedWhileJoining) {\n releaseSafely(() => session.disconnect());\n throw new Error('The voice room disconnected while joining');\n }\n joined = true;\n livekitRef.current = session;\n report('room-joined', attempt, { roomName: room.roomName });\n return true;\n },\n [report]\n );\n\n // Forward reference: the media-loss handler restarts through the same\n // startSession the user start uses, and startSession installs the watcher\n // that calls the handler.\n const handleMediaLossRef = useRef<(attempt: number, reason: string) => Promise<void>>(\n async () => undefined\n );\n\n /**\n * Watch the peer connection's transport. The sideband can outlive a dead\n * media path (the server keeps a \"live\" session nobody can hear), so the\n * client is the only side that can notice: `failed`/`closed` are final,\n * `disconnected` gets a short grace to recover on its own.\n */\n const watchConnection = useCallback((pc: VoicePeerConnection, attempt: number): (() => void) => {\n let disconnectTimer: ReturnType<typeof setTimeout> | null = null;\n const clearDisconnectTimer = (): void => {\n if (disconnectTimer === null) return;\n clearTimeout(disconnectTimer);\n disconnectTimer = null;\n };\n const onChange = (): void => {\n if (attemptRef.current !== attempt) {\n clearDisconnectTimer();\n return;\n }\n const state = pc.connectionState ?? pc.iceConnectionState;\n report('media-state', attempt, {\n connectionState: pc.connectionState ?? null,\n iceConnectionState: pc.iceConnectionState ?? null,\n });\n if (state === 'failed' || state === 'closed') {\n clearDisconnectTimer();\n void handleMediaLossRef.current(attempt, state);\n return;\n }\n if (state === 'disconnected') {\n if (disconnectTimer !== null) return;\n disconnectTimer = setTimeout(() => {\n disconnectTimer = null;\n if (attemptRef.current !== attempt) return;\n void handleMediaLossRef.current(attempt, 'disconnected');\n }, MEDIA_DISCONNECT_GRACE_MS);\n return;\n }\n // connected / connecting / new: a transient disconnect recovered.\n clearDisconnectTimer();\n };\n pc.addEventListener('connectionstatechange', onChange);\n pc.addEventListener('iceconnectionstatechange', onChange);\n return () => {\n clearDisconnectTimer();\n releaseSafely(() => pc.removeEventListener('connectionstatechange', onChange));\n releaseSafely(() => pc.removeEventListener('iceconnectionstatechange', onChange));\n };\n }, [report]);\n\n /** Schedule one relayed PCM chunk gaplessly after the previous one. */\n const playRelayChunk = useCallback((audio: VoiceAudioContext, data: ArrayBuffer): void => {\n const pcm = new Int16Array(data);\n if (pcm.length === 0) return;\n const samples = float32FromPcm16(pcm);\n const buffer = audio.createBuffer(1, samples.length, VOICE_RELAY_SAMPLE_RATE);\n buffer.copyToChannel(samples, 0);\n const node = audio.createBufferSource();\n node.buffer = buffer;\n node.connect(audio.destination);\n const startAt = Math.max(audio.currentTime + RELAY_PLAYBACK_LEAD_SECONDS, playheadRef.current);\n node.start(startAt);\n playheadRef.current = startAt + buffer.duration;\n }, []);\n\n const runStartSession = useCallback(async ({\n opening,\n }: { opening?: DeepAgentVoiceOpening } = {}): Promise<void> => {\n const attempt = (attemptRef.current += 1);\n const attemptId = mintVoiceId({ kind: 'attempt' });\n const previousAttemptId = observedAttemptRef.current;\n callAttemptIdRef.current = attemptId;\n ownClientIdRef.current = null;\n startingRef.current = true;\n attemptStartedAtRef.current = Date.now();\n setFailure(null);\n setPhase('connecting');\n // The step under way, so a thrown error is classified by WHERE it\n // happened rather than by its wording.\n let stage: DeepAgentVoiceFailureStage = 'preflight';\n const timeouts = timeoutsRef.current;\n const iceGatheringMs = timeouts?.iceGatheringMs ?? ICE_TIMEOUT_MS;\n const answerMs = timeouts?.answerMs ?? ANSWER_TIMEOUT_MS;\n const relayOpenMs = timeouts?.relayOpenMs ?? RELAY_OPEN_TIMEOUT_MS;\n const stale = (): void => {\n report('stale-attempt', attempt, { stage });\n releaseAudioSession();\n };\n report('start-requested', attempt, {\n transport: transportRef.current,\n ...(opening !== undefined && { opening }),\n });\n try {\n const transport = transportRef.current;\n const mediaDevices = voiceGlobals.navigator?.mediaDevices;\n const PeerConnection = voiceGlobals.RTCPeerConnection;\n const WebSocketCtor = voiceGlobals.WebSocket;\n const AudioContextCtor = voiceGlobals.AudioContext;\n const livekitAdapter = livekitAdapterRef.current;\n // LiveKit captures the microphone itself, inside the adapter.\n if (transport === 'livekit' && !livekitAdapter)\n throw new Error('Voice is unavailable in this environment');\n if (transport !== 'livekit' && !mediaDevices)\n throw new Error('Microphone capture is unavailable in this environment');\n if (transport === 'webrtc' && !PeerConnection)\n throw new Error('WebRTC is unavailable in this environment');\n if (transport === 'websocket' && (!WebSocketCtor || !AudioContextCtor))\n throw new Error('WebSocket audio is unavailable in this environment');\n const relayUrl = relayUrlRef.current;\n if (transport === 'websocket' && !relayUrl)\n throw new Error('The websocket voice transport needs a relay URL');\n const audioSession = audioSessionRef.current;\n if (audioSession) {\n stage = 'audio-session';\n if (!(await acquireAudioSession({ attempt, audioSession }))) return;\n }\n // Resolved once per attempt, so an automatic restart re-asks for the\n // model the user had picked when this session started.\n const modelOption = modelRef.current;\n const requestedModel = typeof modelOption === 'function' ? modelOption() : modelOption;\n const model =\n typeof requestedModel === 'string' && requestedModel !== '' ? requestedModel : undefined;\n const sendVoiceStart = (offer: string) =>\n sendCommand({\n type: 'voice/start',\n offer,\n attemptId,\n ...(previousAttemptId !== undefined && { previousAttemptId }),\n ...(model !== undefined && { model }),\n ...(opening !== undefined && { opening }),\n }) as Promise<{\n answer?: unknown;\n } | null>;\n // A durable command accepted immediately before host rotation can be\n // replayed on the replacement host after its socket-scoped auth result\n // has expired. The server rejects that replay fail-closed with an exact\n // retriable code. By the time the client receives the verdict it is\n // attached to the replacement host, so repeat the SAME offer once. Do\n // not retry generic 5xx/channel failures: boundedness avoids duplicate\n // live sessions and unbounded GPT Live spend.\n const negotiateStart = async (offer: string): Promise<string> => {\n stage = 'negotiate';\n const negotiationStartedAt = Date.now();\n const commandPromise = sendVoiceStart(offer).catch((commandError: unknown) => {\n if (!isRecoveredCommandAuthRejection(commandError)) throw commandError;\n if (attemptRef.current !== attempt) throw commandError;\n return sendVoiceStart(offer);\n });\n // A session that opens server-side after this attempt was torn down\n // (local end, unmount, or the answer timeout below) must not linger.\n void commandPromise\n .then(() => {\n if (attemptRef.current !== attempt)\n void sendCommand({ type: 'voice/end', attemptId }).catch(() => undefined);\n })\n .catch(() => undefined);\n let answerTimer: ReturnType<typeof setTimeout> | null = null;\n let result: { answer?: unknown } | null;\n try {\n result = await Promise.race([\n commandPromise,\n new Promise<never>((_, reject) => {\n answerTimer = setTimeout(() => reject(new VoiceAnswerTimeoutError()), answerMs);\n }),\n ]);\n } finally {\n if (answerTimer !== null) clearTimeout(answerTimer);\n }\n report('answer-received', attempt, {\n negotiationMs: Date.now() - negotiationStartedAt,\n });\n stage = 'answer';\n const answer = result?.answer;\n if (typeof answer !== 'string' || answer === '')\n throw new VoiceNoAnswerError('voice/start returned no answer');\n return answer;\n };\n\n if (transport === 'livekit') {\n if (!livekitAdapter) return;\n const answer = await negotiateStart(VOICE_LIVEKIT_OFFER);\n if (attemptRef.current !== attempt) {\n stale();\n return;\n }\n // From here the host holds an open session (it answered): a client\n // that cannot use the room must end it, or the model session keeps\n // running with no media leg until the attach departure reaps it.\n try {\n const room = parseVoiceLiveKitAnswer(answer);\n stage = 'room';\n const joinedRoom = await joinVoiceRoom({\n attempt,\n room,\n adapter: livekitAdapter,\n onDisconnectedAfterJoin: (reason) => void handleMediaLossRef.current(attempt, reason),\n });\n if (!joinedRoom) {\n stale();\n return;\n }\n } catch (roomError) {\n if (attemptRef.current === attempt)\n void sendCommand({ type: 'voice/end', attemptId }).catch(() => undefined);\n throw roomError;\n }\n report('live', attempt, { transport, ...(model !== undefined && { model }) });\n if (micMutedRef.current) {\n void sendCommand({ type: 'voice/set-mic', paused: true, attemptId }).catch(() => undefined);\n }\n setPhase('live');\n setLiveSince(Date.now());\n return;\n }\n\n if (!mediaDevices) return;\n stage = 'capture';\n const stream = await mediaDevices.getUserMedia({ audio: true });\n if (attemptRef.current !== attempt) {\n releaseCaptureStream(stream);\n stale();\n return;\n }\n streamRef.current = stream;\n for (const track of stream.getTracks()) track.enabled = !micMutedRef.current;\n report('microphone-captured', attempt, {\n tracks: stream.getTracks().length,\n });\n\n if (transport === 'websocket') {\n if (!WebSocketCtor || !AudioContextCtor || !relayUrl) return;\n const answer = await negotiateStart(VOICE_WEBSOCKET_OFFER);\n if (attemptRef.current !== attempt) {\n stale();\n return;\n }\n if (!answer.startsWith(VOICE_RELAY_ANSWER_PREFIX))\n throw new VoiceNoAnswerError('voice/start returned no relay ticket');\n stage = 'relay';\n const ticket = answer.slice(VOICE_RELAY_ANSWER_PREFIX.length);\n const ws = new WebSocketCtor(voiceRelayUrl(relayUrl, ticket));\n ws.binaryType = 'arraybuffer';\n wsRef.current = ws;\n await waitForRelayOpen(ws, relayOpenMs);\n if (attemptRef.current !== attempt) {\n stale();\n return;\n }\n // Capture at the relay's rate so no client-side resampling is needed:\n // the browser resamples the microphone into the context's rate.\n const audio = new AudioContextCtor({\n sampleRate: VOICE_RELAY_SAMPLE_RATE,\n });\n audioContextRef.current = audio;\n await audio.resume?.();\n if (attemptRef.current !== attempt) {\n stale();\n return;\n }\n const source = audio.createMediaStreamSource(stream);\n const processor = audio.createScriptProcessor(RELAY_CAPTURE_FRAME_SAMPLES, 1, 1);\n // A processor only runs while connected to the destination; the\n // silent gain keeps the microphone from playing back locally.\n const sink = audio.createGain();\n sink.gain.value = 0;\n processor.onaudioprocess = (event) => {\n if (attemptRef.current !== attempt || ws.readyState !== 1) return;\n // A muted track yields silence, which keeps the frame cadence the\n // Live API expects while input is paused.\n ws.send(pcm16FromFloat32(event.inputBuffer.getChannelData(0)).buffer);\n };\n source.connect(processor);\n processor.connect(sink);\n sink.connect(audio.destination);\n audioNodesRef.current = [source, processor, sink];\n playheadRef.current = 0;\n ws.addEventListener('message', (event) => {\n if (attemptRef.current !== attempt) return;\n // Text frames are relay control (`ready`, `pong`); audio is binary.\n if (event.data instanceof ArrayBuffer) playRelayChunk(audio, event.data);\n });\n ws.addEventListener('close', () => {\n if (attemptRef.current !== attempt) return;\n void handleMediaLossRef.current(attempt, 'relay-closed');\n });\n ws.addEventListener('error', () => {\n if (attemptRef.current !== attempt) return;\n void handleMediaLossRef.current(attempt, 'relay-error');\n });\n report('live', attempt, { transport });\n if (micMutedRef.current) {\n void sendCommand({ type: 'voice/set-mic', paused: true, attemptId }).catch(() => undefined);\n }\n setPhase('live');\n setLiveSince(Date.now());\n return;\n }\n\n if (!PeerConnection) return;\n stage = 'offer';\n const pc = new PeerConnection();\n pcRef.current = pc;\n for (const track of stream.getTracks()) pc.addTrack(track, stream);\n const onTrack = async (trackEvent: VoiceTrackEvent): Promise<void> => {\n if (attemptRef.current !== attempt) return;\n try {\n const remote =\n trackEvent.streams[0] ??\n (voiceGlobals.MediaStream ? new voiceGlobals.MediaStream([trackEvent.track]) : null);\n if (!remote) return;\n await onRemoteStreamRef.current?.(remote);\n } catch (playError) {\n // audio.play() can reject after hangup has already opened another call.\n if (attemptRef.current !== attempt) return;\n void sendCommand({ type: 'voice/end', attemptId }).catch(() => undefined);\n fail({\n kind: 'playback_failed',\n stage: 'playback',\n message: `Audio playback: ${errorMessage(playError)}`,\n });\n }\n };\n pc.addEventListener('track', onTrack);\n const unwatchConnection = watchConnection(pc, attempt);\n releasePeerListenersRef.current = () => {\n unwatchConnection();\n releaseSafely(() => pc.removeEventListener('track', onTrack));\n };\n const offer = await pc.createOffer();\n await pc.setLocalDescription(offer);\n const iceStartedAt = Date.now();\n const iceOutcome = await waitForIce(pc, iceGatheringMs);\n if (attemptRef.current !== attempt) {\n stale();\n return;\n }\n if (iceOutcome === 'timeout') {\n report('ice-gathering-timeout', attempt, {\n waitedMs: Date.now() - iceStartedAt,\n iceGatheringState: pc.iceGatheringState,\n });\n }\n const sdp = pc.localDescription?.sdp;\n if (!sdp) throw new Error('failed to create a local SDP offer');\n report('offer-ready', attempt, {\n iceGatheringMs: Date.now() - iceStartedAt,\n iceGathering: iceOutcome,\n sdpBytes: sdp.length,\n });\n const answer = await negotiateStart(sdp);\n if (attemptRef.current !== attempt) {\n stale();\n return;\n }\n await pc.setRemoteDescription({ type: 'answer', sdp: answer });\n if (attemptRef.current !== attempt) {\n stale();\n return;\n }\n report('live', attempt, { transport });\n if (micMutedRef.current) {\n void sendCommand({ type: 'voice/set-mic', paused: true, attemptId }).catch(() => undefined);\n }\n setPhase('live');\n setLiveSince(Date.now());\n } catch (startError) {\n if (attemptRef.current !== attempt) {\n stale();\n return;\n }\n fail(classifyStartFailure(startError, stage));\n } finally {\n startingRef.current = false;\n }\n }, [\n acquireAudioSession,\n fail,\n joinVoiceRoom,\n playRelayChunk,\n releaseAudioSession,\n report,\n sendCommand,\n watchConnection,\n ]);\n\n // The automatic restart calls this without options: an opening belongs to\n // the user start that asked for it, never to a reconnect.\n const startSession = useCallback(async (options: {\n opening?: DeepAgentVoiceOpening;\n } = {}): Promise<void> => {\n if (pcRef.current || wsRef.current || livekitRef.current || startingRef.current) return;\n const run = runStartSession(options);\n startPromiseRef.current = run;\n try {\n await run;\n } finally {\n if (startPromiseRef.current === run) startPromiseRef.current = null;\n }\n }, [runStartSession]);\n const startRef = useRef(startSession);\n startRef.current = startSession;\n\n /**\n * The media path died while the server still holds a live session. End it\n * server-side first (a `voice/start` racing the old session's teardown is\n * rejected `voice-active`), then spend the one-shot restart budget — or,\n * if it is already spent, settle to an error the surface can show.\n *\n * The restart is cancelled by anything that supersedes this recovery while\n * it waits: an explicit `end()`, an unmount, or a user start all bump the\n * attempt generation, and a stale recovery must never reopen the mic.\n */\n const handleMediaLoss = useCallback(\n async (attempt: number, reason: string): Promise<void> => {\n if (attemptRef.current !== attempt) return;\n // The host already moved this call to another of the person's devices:\n // this drop is the room letting go of this client, not a lost call.\n if (ownerMovedAway()) {\n handleMovedAway();\n return;\n }\n const restarting = !autoRestartedRef.current;\n report('media-loss', attempt, {\n reason,\n restartBudgetLeft: restarting,\n });\n if (lastActiveTaskRef.current) setHandoffTask(lastActiveTaskRef.current);\n const ending: Promise<unknown> = sendCommand({ type: 'voice/end', attemptId: callAttemptIdRef.current }).catch(() => undefined);\n // The restart below adopts the call's audio session instead of\n // releasing it and asking for it back (see `teardown`).\n teardown({ keepAudioSession: restarting });\n const recovery = attemptRef.current;\n setPhase('idle');\n let endTimer: ReturnType<typeof setTimeout> | undefined;\n try {\n await Promise.race([\n ending,\n new Promise<void>((resolve) => {\n endTimer = setTimeout(resolve, END_BEFORE_RESTART_TIMEOUT_MS);\n }),\n ]);\n } finally {\n clearTimeout(endTimer);\n }\n // A startup that was still negotiating when the transport died exits\n // at its next generation check; wait for it to release its guard so\n // the replacement start is not refused as \"already starting\".\n const inflight = startPromiseRef.current;\n if (inflight) await inflight.catch(() => undefined);\n if (attemptRef.current !== recovery) return;\n // The move landed while the end was refused: never restart a call that\n // now lives on another device (its start would be refused anyway).\n if (ownerMovedAway()) {\n handleMovedAway();\n return;\n }\n if (!autoRestartedRef.current) {\n autoRestartedRef.current = true;\n report('auto-restart', recovery, { trigger: 'media-loss', reason });\n await startRef.current();\n return;\n }\n // The server-drop effect may already be restarting — do not override it.\n if (startingRef.current || pcRef.current || wsRef.current || livekitRef.current) return;\n const lost: DeepAgentVoiceFailure = {\n kind: 'media_lost',\n stage: 'media',\n message: `The voice connection was lost (${reason})`,\n reason,\n };\n report('error', recovery, {\n kind: lost.kind,\n stage: lost.stage,\n message: lost.message,\n reason,\n });\n setFailure(lost);\n setPhase('error');\n },\n [handleMovedAway, ownerMovedAway, report, sendCommand, teardown]\n );\n handleMediaLossRef.current = handleMediaLoss;\n\n // The public start is a USER start: it re-arms the one-shot auto-restart\n // budget the server-drop effect consumes (the automatic hop itself calls\n // `startSession` directly, so it can never re-arm its own budget).\n const start = useCallback(async (options?: DeepAgentVoiceStartOptions): Promise<void> => {\n if (pcRef.current || wsRef.current || livekitRef.current || startingRef.current) return;\n micMutedRef.current = false;\n setMicMutedState(false);\n autoRestartedRef.current = false;\n setHandoffTask(null);\n setMovedTo(null);\n // Read strictly: a host that hands `start` to an event prop passes an\n // event object here, which must never become an opening.\n await startSession(options?.opening === 'recap' ? { opening: 'recap' } : {});\n }, [startSession]);\n\n /**\n * Move the call live on another of the person's devices here: offer, join\n * the room it lives in, commit, then live. Every exit after the host\n * answered the offer withdraws it unless the call moved: a stale attempt\n * (end, unmount) cancels, a commit that lands after the attempt was\n * abandoned ends the call this client then owns without media.\n */\n const runTransferHere = useCallback(async (): Promise<void> => {\n const fromSurface = liveElsewhereRef.current?.surface ?? 'web';\n const attempt = (attemptRef.current += 1);\n const attemptId = mintVoiceId({ kind: 'attempt' });\n callAttemptIdRef.current = attemptId;\n ownClientIdRef.current = null;\n const transfer: { attempt: number; transferId: string | null } = { attempt, transferId: null };\n transferRef.current = transfer;\n startingRef.current = true;\n attemptStartedAtRef.current = Date.now();\n setFailure(null);\n setPhase('connecting');\n let stage: DeepAgentVoiceFailureStage = 'preflight';\n const timeouts = timeoutsRef.current;\n const offerMs = Math.min(timeouts?.answerMs ?? ANSWER_TIMEOUT_MS, TRANSFER_OFFER_TIMEOUT_MS);\n const commitMs = timeouts?.transferCommitMs ?? TRANSFER_COMMIT_TIMEOUT_MS;\n const cancel = (): void => {\n const transferId = transfer.transferId;\n if (transferId === null) return;\n void sendCommand({ type: 'voice/transfer-cancel', transferId }).catch(() => undefined);\n };\n let promotedCallEnded = false;\n const endPromotedCall = (): void => {\n if (promotedCallEnded) return;\n promotedCallEnded = true;\n void sendCommand({ type: 'voice/end', attemptId }).catch(() => undefined);\n };\n const stale = (): void => {\n report('stale-attempt', attempt, { stage, transfer: true });\n // An end or unmount already withdrew it (`releaseCall`).\n if (transferRef.current === transfer) {\n transferRef.current = null;\n cancel();\n }\n releaseAudioSession();\n };\n // Aborted by teardown (end, unmount, a failure): every wait below races\n // it, so a superseded move exits at once instead of at its deadline.\n const controller = new AbortController();\n livekitAbortRef.current = controller;\n const superseded = new Promise<never>((_, reject) => {\n controller.signal.addEventListener('abort', () => reject(new Error('The move was superseded')), {\n once: true,\n });\n });\n void superseded.catch(() => undefined);\n report('start-requested', attempt, { transport: 'livekit', transfer: true });\n try {\n const livekitAdapter = livekitAdapterRef.current;\n if (transportRef.current !== 'livekit' || !livekitAdapter)\n throw new Error('Voice is unavailable in this environment');\n const audioSession = audioSessionRef.current;\n if (audioSession) {\n stage = 'audio-session';\n if (!(await acquireAudioSession({ attempt, audioSession }))) {\n stale();\n return;\n }\n }\n stage = 'negotiate';\n const negotiationStartedAt = Date.now();\n const offer: Promise<unknown> = sendCommand({ type: 'voice/transfer-offer', attemptId });\n // An offer the host accepts after this attempt was abandoned (end,\n // unmount, the deadline below) would hold the call's owner departure\n // until the host's deadline: withdraw it.\n void offer\n .then((result) => {\n if (attemptRef.current === attempt) return;\n const { transferId } = readTransferOffer(result);\n if (transferId !== null)\n void sendCommand({ type: 'voice/transfer-cancel', transferId }).catch(() => undefined);\n })\n .catch(() => undefined);\n const offered = readTransferOffer(\n await withAnswerDeadline(Promise.race([offer, superseded]), offerMs)\n );\n report('answer-received', attempt, {\n negotiationMs: Date.now() - negotiationStartedAt,\n transfer: true,\n });\n if (attemptRef.current !== attempt) {\n stale();\n return;\n }\n stage = 'answer';\n transfer.transferId = offered.transferId;\n if (offered.transferId === null || offered.answer === null)\n throw new VoiceNoAnswerError('voice/transfer-offer returned no voice room');\n const room = parseVoiceLiveKitAnswer(offered.answer);\n stage = 'room';\n // Until the host moves the call, this client's room dropping fails the\n // move (the call stays where it is); after it, it is a lost call like\n // any other.\n let moved = false;\n let roomDropped: (reason: string) => void = () => undefined;\n const dropped = new Promise<never>((_, reject) => {\n roomDropped = (reason) => reject(new VoiceTransferRoomDroppedError(reason));\n });\n void dropped.catch(() => undefined);\n const joinedRoom = await joinVoiceRoom({\n attempt,\n room,\n adapter: livekitAdapter,\n controller,\n onDisconnectedAfterJoin: (reason) => {\n if (moved) void handleMediaLossRef.current(attempt, reason);\n else roomDropped(reason);\n },\n });\n if (!joinedRoom) {\n stale();\n return;\n }\n stage = 'commit';\n const commit: Promise<unknown> = sendCommand({\n type: 'voice/transfer-commit',\n transferId: offered.transferId,\n attemptId,\n });\n // A commit that lands after this attempt was abandoned made this client\n // the owner of a call it holds no media for, and one the channel\n // settled without a verdict may have: end that call (the host refuses\n // this end unless it did promote). Once, whichever path sees it first.\n void commit.then(\n () => {\n if (attemptRef.current !== attempt) endPromotedCall();\n },\n (commitError: unknown) => {\n if (attemptRef.current === attempt) return;\n const failure = readSendFailure(commitError);\n if (failure !== null && failure.fate !== 'rejected') endPromotedCall();\n }\n );\n await withAnswerDeadline(Promise.race([commit, dropped, superseded]), commitMs);\n if (attemptRef.current !== attempt) {\n stale();\n return;\n }\n moved = true;\n transferRef.current = null;\n report('live', attempt, { transport: 'livekit', transfer: true });\n setPhase('live');\n setLiveSince(Date.now());\n notifyCallMoved({ direction: 'here', surface: fromSurface });\n } catch (transferError) {\n if (attemptRef.current !== attempt) {\n stale();\n return;\n }\n cancel();\n // A commit the channel settled without a verdict may still have moved\n // the call here: end it (the host refuses this unless it did).\n const sendFailure = readSendFailure(transferError);\n if (stage === 'commit' && sendFailure !== null && sendFailure.fate !== 'rejected')\n endPromotedCall();\n transferRef.current = null;\n fail(classifyTransferFailure(transferError, stage));\n } finally {\n startingRef.current = false;\n }\n }, [\n acquireAudioSession,\n fail,\n joinVoiceRoom,\n notifyCallMoved,\n releaseAudioSession,\n report,\n sendCommand,\n ]);\n\n // A USER action like `start`: re-arms the one-shot auto-restart budget.\n const transferHere = useCallback(async (): Promise<void> => {\n if (pcRef.current || wsRef.current || livekitRef.current || startingRef.current) return;\n if (liveElsewhereRef.current === null) return;\n micMutedRef.current = false;\n setMicMutedState(false);\n autoRestartedRef.current = false;\n setHandoffTask(null);\n setMovedTo(null);\n const run = runTransferHere();\n startPromiseRef.current = run;\n try {\n await run;\n } finally {\n if (startPromiseRef.current === run) startPromiseRef.current = null;\n }\n }, [runTransferHere]);\n\n /** End what this client holds: its call, or a move it has not completed (the call stays put). */\n const releaseCall = useCallback((): void => {\n const transfer = transferRef.current;\n transferRef.current = null;\n if (transfer !== null) {\n if (transfer.transferId !== null) {\n void sendCommand({ type: 'voice/transfer-cancel', transferId: transfer.transferId }).catch(\n () => undefined\n );\n }\n return;\n }\n void sendCommand({ type: 'voice/end', attemptId: callAttemptIdRef.current }).catch(() => undefined);\n }, [sendCommand]);\n\n const end = useCallback((): void => {\n if (phase === 'connecting' || phase === 'live') {\n report('end', attemptRef.current, { source: 'user', phase });\n const moving = transferRef.current !== null;\n releaseCall();\n if (!moving && lastActiveTaskRef.current) setHandoffTask(lastActiveTaskRef.current);\n }\n teardown();\n micMutedRef.current = false;\n setMicMutedState(false);\n setPhase('idle');\n }, [phase, releaseCall, report, teardown]);\n\n const setMicMuted = useCallback(\n (muted: boolean): void => {\n if (phase !== 'live') return;\n const attempt = attemptRef.current;\n const attemptId = callAttemptIdRef.current;\n const change = ++micChangeRef.current;\n const applyLocal = (value: boolean): boolean => {\n micMutedRef.current = value;\n setMicMutedState(value);\n const room = livekitRef.current;\n const mediaFailed = (): void => {\n // An older operation must never end a replacement call or override\n // a newer mute choice. The media path and protocol pause are both\n // required: showing a muted microphone while capture failed to stop\n // is unsafe, even when the model currently discards the audio.\n if (\n attemptRef.current !== attempt ||\n micChangeRef.current !== change ||\n livekitRef.current !== room\n ) return;\n void sendCommand({ type: 'voice/end', attemptId }).catch(() => undefined);\n if (lastActiveTaskRef.current) setHandoffTask(lastActiveTaskRef.current);\n fail({\n kind: 'media_lost',\n stage: 'media',\n reason: 'microphone-control-failed',\n message: 'Voice ended because the microphone could not be changed. Start a new call to try again.',\n });\n };\n try {\n for (const track of streamRef.current?.getTracks() ?? []) track.enabled = !value;\n if (room) void room.setMicrophoneEnabled(!value).catch(mediaFailed);\n return true;\n } catch {\n mediaFailed();\n return false;\n }\n };\n // Local track disable is the instant lever; the protocol pause is the\n // authoritative one (server discards paused speech).\n if (!applyLocal(muted)) return;\n void sendCommand({ type: 'voice/set-mic', paused: muted, attemptId }).catch(() => {\n // A failed MUTE is safe — the disabled track transmits nothing either\n // way. A failed UNMUTE would claim live audio while the server still\n // discards it, so fall back to the muted truth (unless this session\n // was already torn down, whose reset wins).\n if (!muted && attemptRef.current === attempt && micChangeRef.current === change) {\n applyLocal(true);\n }\n });\n },\n [phase, sendCommand, fail]\n );\n\n // A server-side end (connection drop, another surface, host shutdown)\n // clears `state.voice`; follow it down. Gate on a HYDRATED snapshot: the\n // raw wire state republishes `undefined` on replay boundaries (reconnects,\n // optimistic windows around sends), and tearing down on that transient\n // would kill a perfectly live session every time the user typed a message.\n const sessionGone = useStatewireState(\n (s) => isDeepAgentStateHydrated(s) && (readDeepAgentStreamValues(s).voice ?? null) === null\n );\n useEffect(() => {\n if (phase !== 'live' || !sessionGone) return;\n const restarting = !autoRestartedRef.current;\n report('server-ended', attemptRef.current, {\n restartBudgetLeft: restarting,\n });\n if (lastActiveTaskRef.current) setHandoffTask(lastActiveTaskRef.current);\n teardown({ keepAudioSession: restarting });\n setPhase('idle');\n if (restarting) {\n autoRestartedRef.current = true;\n report('auto-restart', attemptRef.current, { trigger: 'server-ended' });\n void startRef.current?.();\n }\n }, [phase, report, sessionGone, teardown]);\n\n // A live call this client holds moves when the host names another client\n // as its owner (`voice/transfer-commit` from another of the person's\n // devices). The owner is captured once the wire reflects THIS call — its\n // attempt fence is this call's, or the host projects none — so a snapshot\n // still showing the previous call's owner never reads as a move.\n useEffect(() => {\n if (phase !== 'live' || !transferCapable || wireOwnerId === null) return;\n const own = ownClientIdRef.current;\n if (own === null) {\n const fence = observedAttemptRef.current;\n if (fence !== undefined && fence !== callAttemptIdRef.current) return;\n ownClientIdRef.current = wireOwnerId;\n lastOwnedClientIdRef.current = wireOwnerId;\n return;\n }\n if (wireOwnerId !== own) handleMovedAway();\n }, [phase, transferCapable, wireOwnerId, observedAttempt, handleMovedAway]);\n\n // Unmount: release the media, and — when a session is still underway — end\n // it server-side too. The host would reap an orphaned session once this\n // client's attach departs (its departure grace), but a surface that\n // unmounts its voice controls while the thread connection stays up (a\n // remount of the composer, a navigation that keeps the runtime) would\n // otherwise leave the Live API session running and billing with no media\n // leg until the grace expired. Best-effort: the transport may already be\n // closing, in which case the departure path finishes the job.\n useEffect(\n () => () => {\n const phaseAtUnmount = phaseRef.current;\n if (phaseAtUnmount === 'connecting' || phaseAtUnmount === 'live') {\n report('end', attemptRef.current, {\n source: 'unmount',\n phase: phaseAtUnmount,\n });\n releaseCall();\n }\n transferRef.current = null;\n teardown();\n },\n [releaseCall, report, teardown]\n );\n\n // Mirror the live session's delegated task so an end (local or server-side)\n // can hand it off: the run outlives the session, the projection does not.\n const activeTask = voice?.activeTask ?? null;\n useEffect(() => {\n if (phase === 'live') lastActiveTaskRef.current = activeTask;\n else if (phase === 'idle' || phase === 'error') lastActiveTaskRef.current = null;\n }, [phase, activeTask]);\n\n // The handoff note self-clears when the thread's run settles (the work it\n // pointed at is finished — or was never running to begin with). Unhydrated\n // snapshots keep the note: the raw wire state republishes `undefined` on\n // replay boundaries and must not read as \"settled\".\n const handoffRunActive = useStatewireState((s) => {\n if (!isDeepAgentStateHydrated(s)) return true;\n const status = readDeepAgentStreamValues(s).status;\n return status === 'running' || status === 'stopping' || status === 'input-required';\n });\n useEffect(() => {\n if (handoffTask !== null && !handoffRunActive) setHandoffTask(null);\n }, [handoffTask, handoffRunActive]);\n\n // The host projects the latest Live API rejection; every `voice/start`\n // resets it, so the wire value is always this session's. Hidden outside a\n // live session (a stale value after an end is inert).\n const wireError = useStatewireState((s) =>\n isDeepAgentStateHydrated(s) ? (readDeepAgentStreamValues(s).voiceLastError ?? null) : null\n );\n const notice = phase === 'live' && wireError ? describeVoiceWireError(wireError) : null;\n\n // The host stamps the resolved model when a session starts and publishes\n // its model catalogue at boot. Both are read raw off the hydrated snapshot\n // (the selectors must return referentially stable values — `Object.is`);\n // the catalogue is validated once per wire change below.\n const model = useStatewireState((s) => {\n if (!isDeepAgentStateHydrated(s)) return null;\n const value = readDeepAgentStreamValues(s).voiceModel;\n return typeof value === 'string' && value !== '' ? value : null;\n });\n const wireModelOptions = useStatewireState((s) =>\n isDeepAgentStateHydrated(s) ? (readDeepAgentStreamValues(s).voiceModelOptions ?? null) : null\n );\n // Replication may hand back a fresh array for unchanged content (a snapshot\n // replay, a reconnect); keep the previous validated list so memoized\n // consumers (the composer's picker) do not re-render on every wire update.\n const modelOptionsRef = useRef<DeepAgentVoiceModelOption[] | null>(null);\n const modelOptions = useMemo(() => {\n const next = parseVoiceModelOptions(wireModelOptions);\n const previous = modelOptionsRef.current;\n if (previous !== null && next !== null && sameVoiceModelOptions(previous, next)) return previous;\n modelOptionsRef.current = next;\n return next;\n }, [wireModelOptions]);\n\n const syncProfile = useCallback((): void => {\n if (phase !== 'connecting' && phase !== 'live') return;\n void sendCommand({ type: 'voice/profile-sync', attemptId: callAttemptIdRef.current }).catch(() => undefined);\n }, [phase, sendCommand]);\n\n const sendContext = useCallback(\n (text: string): void => {\n const trimmed = text.trim();\n if (phase !== 'live' || !trimmed) return;\n void sendCommand({ type: 'voice/context', text: trimmed, attemptId: callAttemptIdRef.current }).catch(() => undefined);\n },\n [phase, sendCommand]\n );\n\n const sendUserText = useCallback(\n async (text: string): Promise<boolean> => {\n if (phase !== 'live' || !text.trim()) return false;\n // Client-minted id: a durable command replayed on a replacement host\n // reuses it, and the checkpoint append is idempotent by message id —\n // a crash between the server's commit and its ack cannot duplicate.\n const messageId = mintVoiceId({ kind: 'text' });\n try {\n await sendCommand({ type: 'voice/user-text', text, messageId, attemptId: callAttemptIdRef.current });\n return true;\n } catch {\n return false;\n }\n },\n [phase, sendCommand]\n );\n\n // One object per change of what it reports: surfaces pass the session down whole (the composer's\n // voice controls, its mic and end buttons), so a fresh literal per render re-rendered them on\n // every render of their host, e.g. every keystroke in the composer.\n return useMemo(\n () => ({\n phase,\n error,\n failure,\n start,\n end,\n activeTask,\n liveSince,\n micMuted,\n setMicMuted,\n sendUserText,\n handoffTask,\n syncProfile,\n notice,\n sendContext,\n model,\n modelOptions,\n liveElsewhere,\n transferHere,\n movedTo,\n }),\n [\n phase,\n error,\n failure,\n start,\n end,\n activeTask,\n liveSince,\n micMuted,\n setMicMuted,\n sendUserText,\n handoffTask,\n syncProfile,\n notice,\n sendContext,\n model,\n modelOptions,\n liveElsewhere,\n transferHere,\n movedTo,\n ]\n );\n};\n"],"names":["options","model","offer","answer","_a","failure"],"mappings":"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"}