@datalayer/agent-runtimes 1.5.20 → 1.5.21

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 (277) hide show
  1. package/dist-embed/chunks/{AgentDetails-DZyyuD5F.js → AgentDetails-C7tCazwB.js} +1 -1
  2. package/dist-embed/chunks/{AgentDetailsDialog-DaQyQxlm.js → AgentDetailsDialog-Cwps4GeH.js} +1 -1
  3. package/dist-embed/chunks/{AgentInspector-CBNiiRtv.js → AgentInspector-Gk7jbg8t.js} +1 -1
  4. package/dist-embed/chunks/{AgentInspectorDialog-BxMOAc7K.js → AgentInspectorDialog-BSSDOFrT.js} +1 -1
  5. package/dist-embed/chunks/{CellSidebarExtension-Dwe7PfXi.js → CellSidebarExtension-p2BAkwis.js} +9 -9
  6. package/dist-embed/chunks/ChatView-fHb_i4kH.js +32 -0
  7. package/dist-embed/chunks/{ContextPie-n1y886z-.js → ContextPie-bd_YOjzP.js} +1 -1
  8. package/dist-embed/chunks/{DeckComponent-BSeEBNHt.js → DeckComponent-4gxuEH4A.js} +2 -2
  9. package/dist-embed/chunks/{DocumentView-OIdQEk_n.js → DocumentView-BZSYqTh_.js} +1 -1
  10. package/dist-embed/chunks/{EphemeralDocument-C-uLD1W7.js → EphemeralDocument-Cevnk5OF.js} +1 -1
  11. package/dist-embed/chunks/{EphemeralNotebook-C_peDfqf.js → EphemeralNotebook-JvALIbK2.js} +1 -1
  12. package/dist-embed/chunks/{ExcalidrawComponent-DHSxnPc9.js → ExcalidrawComponent-CbghNk-F.js} +1 -1
  13. package/dist-embed/chunks/{ExcalidrawModal-BpsfNG-u.js → ExcalidrawModal-BOVvWzYQ.js} +1 -1
  14. package/dist-embed/chunks/{JupyterLexicalExtension-BUSLnJVL.js → JupyterLexicalExtension-CRccZ2h7.js} +29 -29
  15. package/dist-embed/chunks/{KernelVariables-Cu7UeFhT.js → KernelVariables-ompObBEM.js} +1 -1
  16. package/dist-embed/chunks/{LexicalToolRegistry-CNg1T5sQ.js → LexicalToolRegistry-BlBEZPP4.js} +4 -4
  17. package/dist-embed/chunks/{NotebookToolSurfaces-Cm6-oE_W.js → NotebookToolSurfaces-DP8sWqVy.js} +1 -1
  18. package/dist-embed/chunks/{NotebookView-Be2lNZjS.js → NotebookView-DC6BDVEp.js} +1 -1
  19. package/dist-embed/chunks/{Output-OIgTyxpD.js → Output-C4hBhZ5k.js} +1 -1
  20. package/dist-embed/chunks/{SandboxDetailsDialog-BMq0tlcE.js → SandboxDetailsDialog-CX8wvCLJ.js} +1 -1
  21. package/dist-embed/chunks/{SchemaForm-D3mmq2C1.js → SchemaForm-BuhXDyz6.js} +1 -1
  22. package/dist-embed/chunks/{WidgetVariableView-DnuwkCHl.js → WidgetVariableView-C2X5Ehcg.js} +1 -1
  23. package/dist-embed/chunks/{YouTubePlugin-Bum16ua6.js → YouTubePlugin-CjgOnMCz.js} +1 -1
  24. package/dist-embed/chunks/{abnfDiagram-VCTEODGH-BMkFygW4.js → abnfDiagram-VCTEODGH-kzVu7pzT.js} +1 -1
  25. package/dist-embed/chunks/{abnfDiagram-VCTEODGH-Dac38D-P.js → abnfDiagram-VCTEODGH-wvUaPpVC.js} +1 -1
  26. package/dist-embed/chunks/{ar-SA-G6X2FPQ2-JDFjD_Dk.js → ar-SA-G6X2FPQ2-ArgZTGSp.js} +1 -1
  27. package/dist-embed/chunks/{architectureDiagram-5GKGNRK7-DXJTBh9S.js → architectureDiagram-5GKGNRK7-CwbfxDHw.js} +1 -1
  28. package/dist-embed/chunks/{architectureDiagram-5GKGNRK7-D7VBU0uf.js → architectureDiagram-5GKGNRK7-DVZUrWEx.js} +1 -1
  29. package/dist-embed/chunks/{az-AZ-76LH7QW2-AbN1w5Zy.js → az-AZ-76LH7QW2-DQgz6n32.js} +1 -1
  30. package/dist-embed/chunks/{bg-BG-XCXSNQG7-BULkJsTf.js → bg-BG-XCXSNQG7-Cx0dPt6-.js} +1 -1
  31. package/dist-embed/chunks/{blockDiagram-868be97b-Bk9MNjmt.js → blockDiagram-868be97b-DEQh5CUO.js} +1 -1
  32. package/dist-embed/chunks/{blockDiagram-I7D4REHJ-CKjKQ6Dq.js → blockDiagram-I7D4REHJ-C6gbEBfg.js} +1 -1
  33. package/dist-embed/chunks/{blockDiagram-I7D4REHJ-BwenaP7n.js → blockDiagram-I7D4REHJ-DUIcpkIN.js} +1 -1
  34. package/dist-embed/chunks/{bn-BD-2XOGV67Q-B6EtUyIk.js → bn-BD-2XOGV67Q-BkekmuYO.js} +1 -1
  35. package/dist-embed/chunks/{c4Diagram-3f4bdde3-BGoSdP5p.js → c4Diagram-3f4bdde3-CUcRctJE.js} +1 -1
  36. package/dist-embed/chunks/{c4Diagram-7LVT6UL2-DlkcVfDa.js → c4Diagram-7LVT6UL2-DSQiEaxC.js} +1 -1
  37. package/dist-embed/chunks/{c4Diagram-7LVT6UL2-BZRokUDB.js → c4Diagram-7LVT6UL2-f7UaZWVg.js} +1 -1
  38. package/dist-embed/chunks/{ca-ES-6MX7JW3Y-BZ0wzUck.js → ca-ES-6MX7JW3Y-Yr14RtMP.js} +1 -1
  39. package/dist-embed/chunks/{celltoolbartracker-CCRqu43G.js → celltoolbartracker-Bx9x9aeh.js} +1 -1
  40. package/dist-embed/chunks/{chunk-2Q5K7J3B-CfYiHpfd.js → chunk-2Q5K7J3B-BBPiCQqO.js} +1 -1
  41. package/dist-embed/chunks/{chunk-2Q5K7J3B-DLu9zZx0.js → chunk-2Q5K7J3B-DbzMjK_L.js} +1 -1
  42. package/dist-embed/chunks/{chunk-5VM5RSS4-yHAygNq4.js → chunk-5VM5RSS4-CcNPo9qP.js} +1 -1
  43. package/dist-embed/chunks/{chunk-5VM5RSS4-dV5IUPYK.js → chunk-5VM5RSS4-rEZEdbpi.js} +1 -1
  44. package/dist-embed/chunks/{chunk-F27PBJKO-BeY8iI19.js → chunk-F27PBJKO-BH7lDumP.js} +1 -1
  45. package/dist-embed/chunks/{chunk-F27PBJKO-BArvzx7H.js → chunk-F27PBJKO-DTgjd0wN.js} +1 -1
  46. package/dist-embed/chunks/{chunk-IMKFNOWR-iUeFNxCU.js → chunk-IMKFNOWR-BA-vmq_V.js} +1 -1
  47. package/dist-embed/chunks/{chunk-IMKFNOWR-BJRUyuXy.js → chunk-IMKFNOWR-DuzpuE1w.js} +1 -1
  48. package/dist-embed/chunks/{chunk-JWPE2WC7-BDUBU4vN.js → chunk-JWPE2WC7-BfRI4eJ2.js} +1 -1
  49. package/dist-embed/chunks/{chunk-JWPE2WC7-Djk-1JPJ.js → chunk-JWPE2WC7-CAdvd3EQ.js} +1 -1
  50. package/dist-embed/chunks/{chunk-POPQ4Y6H-E4731IOt.js → chunk-POPQ4Y6H-B7pT6rUf.js} +1 -1
  51. package/dist-embed/chunks/{chunk-POPQ4Y6H-CibXbz_c.js → chunk-POPQ4Y6H-Dw1h_9lT.js} +1 -1
  52. package/dist-embed/chunks/{chunk-SVP7TREG-DeRyA6Ek.js → chunk-SVP7TREG-BxpYXJab.js} +1 -1
  53. package/dist-embed/chunks/{chunk-SVP7TREG-o7JviCXQ.js → chunk-SVP7TREG-VsO48dck.js} +1 -1
  54. package/dist-embed/chunks/{chunk-TICWLB2K-BIhZcpwn.js → chunk-TICWLB2K-CU2oQRJ9.js} +1 -1
  55. package/dist-embed/chunks/{chunk-TICWLB2K-Zk_gUXIu.js → chunk-TICWLB2K-LCiyX33a.js} +1 -1
  56. package/dist-embed/chunks/{chunk-XXDRQBXY-DATpHkZD.js → chunk-XXDRQBXY-CL1cUI4w.js} +1 -1
  57. package/dist-embed/chunks/{chunk-XXDRQBXY-Cp6f69YK.js → chunk-XXDRQBXY-islJGiCO.js} +1 -1
  58. package/dist-embed/chunks/{classDiagram-ZZMXUADV-DcutslOq.js → classDiagram-ZZMXUADV-C7-Ca_nP.js} +1 -1
  59. package/dist-embed/chunks/{classDiagram-ZZMXUADV-BfpWJKcC.js → classDiagram-ZZMXUADV-Ctw7VU-m.js} +1 -1
  60. package/dist-embed/chunks/{classDiagram-f62afe4f-BVLyWZwA.js → classDiagram-f62afe4f-BaJUb6H9.js} +1 -1
  61. package/dist-embed/chunks/{classDiagram-v2-604399ef-CgcAzr_L.js → classDiagram-v2-604399ef-s6LKeK41.js} +1 -1
  62. package/dist-embed/chunks/{classDiagram-v2-VYDZK3BY-DcutslOq.js → classDiagram-v2-VYDZK3BY-C7-Ca_nP.js} +1 -1
  63. package/dist-embed/chunks/{classDiagram-v2-VYDZK3BY-BfpWJKcC.js → classDiagram-v2-VYDZK3BY-Ctw7VU-m.js} +1 -1
  64. package/dist-embed/chunks/{code-block-IT6T5CEO-D5_yhrdD.js → code-block-IT6T5CEO-BieLU8ls.js} +1 -1
  65. package/dist-embed/chunks/{component-DoyMsR16.js → component-p2xkjXeh.js} +3 -3
  66. package/dist-embed/chunks/{cose-bilkent-JH36ORCC-B-LvsoyE.js → cose-bilkent-JH36ORCC-BkezndW_.js} +1 -1
  67. package/dist-embed/chunks/{cose-bilkent-JH36ORCC-DhPsWJev.js → cose-bilkent-JH36ORCC-DrOmRWVI.js} +1 -1
  68. package/dist-embed/chunks/{createText-aed3d8b3-CnP7VdTn.js → createText-aed3d8b3-Dw8k7JC8.js} +1 -1
  69. package/dist-embed/chunks/{cs-CZ-2BRQDIVT-CHIiQJ-9.js → cs-CZ-2BRQDIVT-DYR-S6bD.js} +1 -1
  70. package/dist-embed/chunks/{cynefinDiagram-5FMLGOSQ-D4zzGd7W.js → cynefinDiagram-5FMLGOSQ-DqoI6t3s.js} +1 -1
  71. package/dist-embed/chunks/{cynefinDiagram-5FMLGOSQ-B4k-OykO.js → cynefinDiagram-5FMLGOSQ-qZ6StjuY.js} +1 -1
  72. package/dist-embed/chunks/{da-DK-5WZEPLOC-dfN2SAKQ.js → da-DK-5WZEPLOC-DhaHIgKI.js} +1 -1
  73. package/dist-embed/chunks/{dagre-GXQ25YYZ-DUrWhbsC.js → dagre-GXQ25YYZ-Bb0_WA3x.js} +1 -1
  74. package/dist-embed/chunks/{dagre-GXQ25YYZ-BlWkzzlo.js → dagre-GXQ25YYZ-pcAHu_bK.js} +1 -1
  75. package/dist-embed/chunks/{de-DE-XR44H4JA-BKsKfmfo.js → de-DE-XR44H4JA-CJpRH2Fy.js} +1 -1
  76. package/dist-embed/chunks/{diagram-S7CK7UJ4-FxHXDIYr.js → diagram-S7CK7UJ4-CwINt91M.js} +1 -1
  77. package/dist-embed/chunks/{diagram-S7CK7UJ4-BuRBzTwI.js → diagram-S7CK7UJ4-W17wgXHY.js} +1 -1
  78. package/dist-embed/chunks/{diagram-UQ7AKVKN-FxYHrvzF.js → diagram-UQ7AKVKN-CXRpfLBt.js} +1 -1
  79. package/dist-embed/chunks/{diagram-UQ7AKVKN-CeDT8Vz4.js → diagram-UQ7AKVKN-mH7QBO8y.js} +1 -1
  80. package/dist-embed/chunks/{diagram-VSXAHHWV-Cv0WAiv8.js → diagram-VSXAHHWV-Bg68Bv82.js} +1 -1
  81. package/dist-embed/chunks/{diagram-VSXAHHWV-C2icUdkA.js → diagram-VSXAHHWV-CFHqpDaB.js} +1 -1
  82. package/dist-embed/chunks/{diagram-VX7I27RA-D6VPVMhu.js → diagram-VX7I27RA-BEO0D7jE.js} +1 -1
  83. package/dist-embed/chunks/{diagram-VX7I27RA-AoxkG7BW.js → diagram-VX7I27RA-DQ6XlKLw.js} +1 -1
  84. package/dist-embed/chunks/{diagram-Z3DM3KII-DxunLDOr.js → diagram-Z3DM3KII-BLJQK61P.js} +1 -1
  85. package/dist-embed/chunks/{diagram-Z3DM3KII-CHxtPQ6F.js → diagram-Z3DM3KII-Cenqf76m.js} +1 -1
  86. package/dist-embed/chunks/{ebnfDiagram-PWID7BFC-CfsTBJc5.js → ebnfDiagram-PWID7BFC-6H6OSebp.js} +1 -1
  87. package/dist-embed/chunks/{ebnfDiagram-PWID7BFC-CmJlfM6d.js → ebnfDiagram-PWID7BFC-Cqmnghct.js} +1 -1
  88. package/dist-embed/chunks/{edges-b2856ca0-Cl5rq6T8.js → edges-b2856ca0-ChO7JKaP.js} +1 -1
  89. package/dist-embed/chunks/{el-GR-BZB4AONW-Cs0zPSU1.js → el-GR-BZB4AONW-DPGB1p8K.js} +1 -1
  90. package/dist-embed/chunks/{erDiagram-5d81789a-C0jmz-br.js → erDiagram-5d81789a-jzhAXdZi.js} +1 -1
  91. package/dist-embed/chunks/{erDiagram-RLTQ6QDP-Dyljy6tN.js → erDiagram-RLTQ6QDP-DEAWMrMT.js} +1 -1
  92. package/dist-embed/chunks/{erDiagram-RLTQ6QDP-FFD_URlX.js → erDiagram-RLTQ6QDP-hAbP0vV0.js} +1 -1
  93. package/dist-embed/chunks/{es-ES-U4NZUMDT-fGOqRf0o.js → es-ES-U4NZUMDT-CLztgM3g.js} +1 -1
  94. package/dist-embed/chunks/{eu-ES-A7QVB2H4-CLZ09rVe.js → eu-ES-A7QVB2H4--ffZf65_.js} +1 -1
  95. package/dist-embed/chunks/{fa-IR-HGAKTJCU-Cjimbc8n.js → fa-IR-HGAKTJCU-Cwwej6FC.js} +1 -1
  96. package/dist-embed/chunks/{fi-FI-Z5N7JZ37-ZXNEW916.js → fi-FI-Z5N7JZ37-Tw-dUSxy.js} +1 -1
  97. package/dist-embed/chunks/{flowDb-185abca5-Cden9aoH.js → flowDb-185abca5-DDUaXZ_Q.js} +1 -1
  98. package/dist-embed/chunks/{flowDiagram-1629c991-Bar9YxSW.js → flowDiagram-1629c991-DpvDtFPK.js} +1 -1
  99. package/dist-embed/chunks/{flowDiagram-HODETNUW-bg09n0_F.js → flowDiagram-HODETNUW-DENY4Bvt.js} +1 -1
  100. package/dist-embed/chunks/{flowDiagram-HODETNUW-02Xo2-6n.js → flowDiagram-HODETNUW-Hr-elwWq.js} +1 -1
  101. package/dist-embed/chunks/{flowDiagram-v2-1d953310-C6FnOAb2.js → flowDiagram-v2-1d953310-TxFSXMN7.js} +1 -1
  102. package/dist-embed/chunks/{flowchart-elk-definition-6df44142-DcmMV2Wi.js → flowchart-elk-definition-6df44142-BGFxwidp.js} +1 -1
  103. package/dist-embed/chunks/{fr-FR-RHASNOE6-DQaq_g67.js → fr-FR-RHASNOE6-CT1NyjSV.js} +1 -1
  104. package/dist-embed/chunks/{ganttDiagram-3b0b3873-BN61xNrz.js → ganttDiagram-3b0b3873-DJqKtGUz.js} +1 -1
  105. package/dist-embed/chunks/{ganttDiagram-EL5Y4UJY-BCLyiaOJ.js → ganttDiagram-EL5Y4UJY-3bErrKpg.js} +1 -1
  106. package/dist-embed/chunks/{ganttDiagram-EL5Y4UJY-JviVPOnF.js → ganttDiagram-EL5Y4UJY-Ddh9hVkO.js} +1 -1
  107. package/dist-embed/chunks/{gitGraphDiagram-WWUBYQGX-CzBMuAvA.js → gitGraphDiagram-WWUBYQGX-B3BVHs36.js} +1 -1
  108. package/dist-embed/chunks/{gitGraphDiagram-WWUBYQGX-CNc3l-2t.js → gitGraphDiagram-WWUBYQGX-BiEolUQH.js} +1 -1
  109. package/dist-embed/chunks/{gitGraphDiagram-f01e8bc2-7ecaKDp7.js → gitGraphDiagram-f01e8bc2-vOvP_sU8.js} +1 -1
  110. package/dist-embed/chunks/{gl-ES-HMX3MZ6V-BlrLF7Sk.js → gl-ES-HMX3MZ6V-BKTaXj_2.js} +1 -1
  111. package/dist-embed/chunks/{he-IL-6SHJWFNN-DLfo2nov.js → he-IL-6SHJWFNN-BJ5SwTG5.js} +1 -1
  112. package/dist-embed/chunks/{hi-IN-IWLTKZ5I-BcbS0I1h.js → hi-IN-IWLTKZ5I-D5ZQxogx.js} +1 -1
  113. package/dist-embed/chunks/{hu-HU-A5ZG7DT2-B_-3TehM.js → hu-HU-A5ZG7DT2-CoAAAzpy.js} +1 -1
  114. package/dist-embed/chunks/{id-ID-SAP4L64H-C920eBs5.js → id-ID-SAP4L64H-DFWbGjYj.js} +1 -1
  115. package/dist-embed/chunks/{index-D_-7qr4x.js → index-1MXuxaax.js} +1 -1
  116. package/dist-embed/chunks/{index-CGhVy6OJ.js → index-6feFd5AZ.js} +1 -1
  117. package/dist-embed/chunks/{index-MNZ1LVAM.js → index-8Jy3Vws8.js} +6 -6
  118. package/dist-embed/chunks/{index-9bae90f3-_mZDJyzh.js → index-9bae90f3-YA-Pbv-C.js} +1 -1
  119. package/dist-embed/chunks/{index-C2UmIEOV.js → index-B0MhQWhs.js} +1 -1
  120. package/dist-embed/chunks/{index-DcbXB4Ou.js → index-B0omKuYl.js} +1 -1
  121. package/dist-embed/chunks/{index-CLojGXLe.js → index-B8y71UkT.js} +1 -1
  122. package/dist-embed/chunks/{index-DmKOrT_f.js → index-B9vBhR-p.js} +1 -1
  123. package/dist-embed/chunks/{index-B3qU5V3s.js → index-BL4KuFQP.js} +1 -1
  124. package/dist-embed/chunks/{index-BMqDh5WU.js → index-BNFZYAJT.js} +1 -1
  125. package/dist-embed/chunks/{index-BVkaRzYN.js → index-BTeNnRc_.js} +1 -1
  126. package/dist-embed/chunks/{index-W-qUA31l.js → index-BVzIb3Wy.js} +1 -1
  127. package/dist-embed/chunks/{index-D1CRwrf9.js → index-BfMo5nXi.js} +2 -2
  128. package/dist-embed/chunks/{index-C3p2Hbbg.js → index-BgWf1G8H.js} +1 -1
  129. package/dist-embed/chunks/{index-C3zGthUI.js → index-BuyZwxeT.js} +1 -1
  130. package/dist-embed/chunks/{index-7V4MgoX0.js → index-BzQxauhZ.js} +1 -1
  131. package/dist-embed/chunks/{index-Dyv67BU9.js → index-C7os26P7.js} +2 -2
  132. package/dist-embed/chunks/{index-BbtA7ppb.js → index-CCA_V9Td.js} +1 -1
  133. package/dist-embed/chunks/{index-oJ3M8HYJ.js → index-CIDdX0nc.js} +1 -1
  134. package/dist-embed/chunks/{index-C8N5z7FZ.js → index-CkOZcvYl.js} +1 -1
  135. package/dist-embed/chunks/{index-DV2fNvY7.js → index-CxIZHPCc.js} +1 -1
  136. package/dist-embed/chunks/{index-BST3vALX.js → index-D62kZnWZ.js} +3 -3
  137. package/dist-embed/chunks/{index-CuqMWXgT.js → index-DMf0f7ny.js} +3 -3
  138. package/dist-embed/chunks/{index-OZDJ7kli.js → index-DPzPvDBn.js} +1 -1
  139. package/dist-embed/chunks/{index-B0VC_nl2.js → index-DSgHh0-i.js} +1 -1
  140. package/dist-embed/chunks/{index-DmYrjwOw.js → index-DTCcg1ap.js} +1 -1
  141. package/dist-embed/chunks/{index-D95mZTII.js → index-DTbF6Y7O.js} +1 -1
  142. package/dist-embed/chunks/{index-DbHMJ-IM.js → index-Db1qHC1a.js} +1 -1
  143. package/dist-embed/chunks/{index--rbc1jdS.js → index-DiBcWu6d.js} +1 -1
  144. package/dist-embed/chunks/{index-DSts8s_N.js → index-DpJpQnPn.js} +1 -1
  145. package/dist-embed/chunks/{index-DqwL86GY.js → index-Dw1P-H6s.js} +12 -12
  146. package/dist-embed/chunks/{index-k3ISgWrJ.js → index-FbZJIbu_.js} +1 -1
  147. package/dist-embed/chunks/{index-DMTXHmrU.js → index-JhvHCMRQ.js} +1 -1
  148. package/dist-embed/chunks/{index-BVdp0AG7.js → index-TDpnbl90.js} +4 -4
  149. package/dist-embed/chunks/{index-CW0DxnfF.js → index-fQxrRXLD.js} +1 -1
  150. package/dist-embed/chunks/{index.esm-Dy7cyZyH.js → index.esm-B6P80s3J.js} +1 -1
  151. package/dist-embed/chunks/{index.esm-jFa95d0B.js → index.esm-z-R1Ypx2.js} +1 -1
  152. package/dist-embed/chunks/{infoDiagram-27XIBGKW-CuQ0a02I.js → infoDiagram-27XIBGKW-8DlnjSdf.js} +1 -1
  153. package/dist-embed/chunks/{infoDiagram-27XIBGKW-CDc0DV-6.js → infoDiagram-27XIBGKW-CZPNcDbH.js} +1 -1
  154. package/dist-embed/chunks/{infoDiagram-a29d40f1-BKWmVk4B.js → infoDiagram-a29d40f1-Di_kmyTC.js} +1 -1
  155. package/dist-embed/chunks/{isEqual-SWNqZJZT.js → isEqual-D0eOPSLC.js} +1 -1
  156. package/dist-embed/chunks/{ishikawaDiagram-5VMMS53U-BY7eKNmA.js → ishikawaDiagram-5VMMS53U-DD5TaPvH.js} +1 -1
  157. package/dist-embed/chunks/{ishikawaDiagram-5VMMS53U-CPu6wHAG.js → ishikawaDiagram-5VMMS53U-ri4cvaWs.js} +1 -1
  158. package/dist-embed/chunks/{it-IT-JPQ66NNP-CsJELR-H.js → it-IT-JPQ66NNP-C7p9bCWQ.js} +1 -1
  159. package/dist-embed/chunks/{ja-JP-DBVTYXUO-Bh4bW0cv.js → ja-JP-DBVTYXUO-DupAM7Cv.js} +1 -1
  160. package/dist-embed/chunks/{journeyDiagram-3NMN7TZE-6CRYfcQL.js → journeyDiagram-3NMN7TZE-1NqbTyL4.js} +1 -1
  161. package/dist-embed/chunks/{journeyDiagram-3NMN7TZE-Cv_KZqY3.js → journeyDiagram-3NMN7TZE-BpYgEBLO.js} +1 -1
  162. package/dist-embed/chunks/{journeyDiagram-95396277-yJruA0Fm.js → journeyDiagram-95396277-xr9Xk_mL.js} +1 -1
  163. package/dist-embed/chunks/{kaa-6HZHGXH3-BmDtc0g0.js → kaa-6HZHGXH3-DrthOcPY.js} +1 -1
  164. package/dist-embed/chunks/{kab-KAB-ZGHBKWFO-Bluox3dD.js → kab-KAB-ZGHBKWFO-C4hr0kbU.js} +1 -1
  165. package/dist-embed/chunks/{kanban-definition-UXKFOSKX-Dps45ZlJ.js → kanban-definition-UXKFOSKX-B5nUu45Q.js} +1 -1
  166. package/dist-embed/chunks/{kanban-definition-UXKFOSKX-Biauy1A4.js → kanban-definition-UXKFOSKX-DlSwjr3b.js} +1 -1
  167. package/dist-embed/chunks/{kk-KZ-P5N5QNE5-EZjFhsK8.js → kk-KZ-P5N5QNE5-CrjDkh9r.js} +1 -1
  168. package/dist-embed/chunks/{km-KH-HSX4SM5Z-BpZu76AC.js → km-KH-HSX4SM5Z-JHWf7VZ6.js} +1 -1
  169. package/dist-embed/chunks/{ko-KR-MTYHY66A-C5JZPTHd.js → ko-KR-MTYHY66A-CJ4JxKMG.js} +1 -1
  170. package/dist-embed/chunks/{ku-TR-6OUDTVRD-BUaf6TOB.js → ku-TR-6OUDTVRD-YSlLPag_.js} +1 -1
  171. package/dist-embed/chunks/{layout-C8INuwYa.js → layout-5FOjTADt.js} +1 -1
  172. package/dist-embed/chunks/{layout-CEbgEIwd.js → layout-Bdtul_rg.js} +1 -1
  173. package/dist-embed/chunks/{lexicalHooks-DFMSPigW.js → lexicalHooks-eqXJbnX9.js} +1 -1
  174. package/dist-embed/chunks/{lt-LT-XHIRWOB4-CuGmKRQr.js → lt-LT-XHIRWOB4-2v6r2YYq.js} +1 -1
  175. package/dist-embed/chunks/{lv-LV-5QDEKY6T-EYERw_NP.js → lv-LV-5QDEKY6T-DVGd68q4.js} +1 -1
  176. package/dist-embed/chunks/{mermaid.core-hzdTpjmh.js → mermaid.core-BU1Nkb56.js} +5 -5
  177. package/dist-embed/chunks/{mermaid.core-BeAq5EQp.js → mermaid.core-DY5DKOtx.js} +3 -3
  178. package/dist-embed/chunks/{mindmap-definition-YA3MSWOX--O06aygF.js → mindmap-definition-YA3MSWOX-CEuIjXO2.js} +1 -1
  179. package/dist-embed/chunks/{mindmap-definition-YA3MSWOX-iB7eW5x9.js → mindmap-definition-YA3MSWOX-sSfUfKt8.js} +1 -1
  180. package/dist-embed/chunks/{mindmap-definition-e4c1d938-DCwgMhNw.js → mindmap-definition-e4c1d938-btrk6STt.js} +1 -1
  181. package/dist-embed/chunks/{mr-IN-CRQNXWMA-SKx4bMeU.js → mr-IN-CRQNXWMA-D1q8zjMr.js} +1 -1
  182. package/dist-embed/chunks/{my-MM-5M5IBNSE-BG-vgEXz.js → my-MM-5M5IBNSE-CCWuEpIN.js} +1 -1
  183. package/dist-embed/chunks/{nb-NO-T6EIAALU-BbW-11AI.js → nb-NO-T6EIAALU-eJ92wx2h.js} +1 -1
  184. package/dist-embed/chunks/{nl-NL-IS3SIHDZ-CSKGpuSJ.js → nl-NL-IS3SIHDZ-DmkMgsvp.js} +1 -1
  185. package/dist-embed/chunks/{nn-NO-6E72VCQL-P1tnp9TQ.js → nn-NO-6E72VCQL-CWYEaXBn.js} +1 -1
  186. package/dist-embed/chunks/{oc-FR-POXYY2M6-vpu8tuQT.js → oc-FR-POXYY2M6-CayriaEZ.js} +1 -1
  187. package/dist-embed/chunks/{pa-IN-N4M65BXN-CIpdGll2.js → pa-IN-N4M65BXN-CydiKcR8.js} +1 -1
  188. package/dist-embed/chunks/{pegDiagram-XKGWAZYB-ZPizxhEX.js → pegDiagram-XKGWAZYB--dcG-x2B.js} +1 -1
  189. package/dist-embed/chunks/{pegDiagram-XKGWAZYB-Bon6jQ3L.js → pegDiagram-XKGWAZYB-CqRRvKft.js} +1 -1
  190. package/dist-embed/chunks/{percentages-BXMCSKIN-hVEpOtFm.js → percentages-BXMCSKIN-fzYCDL7m.js} +5 -5
  191. package/dist-embed/chunks/{pieDiagram-E7YTZNPT-C0Pc9GUi.js → pieDiagram-E7YTZNPT-CkHpKSua.js} +1 -1
  192. package/dist-embed/chunks/{pieDiagram-E7YTZNPT-Di8dEHt9.js → pieDiagram-E7YTZNPT-D-uncTun.js} +1 -1
  193. package/dist-embed/chunks/{pieDiagram-c941bede-C--hwbRv.js → pieDiagram-c941bede-BoVaJIdw.js} +1 -1
  194. package/dist-embed/chunks/{pl-PL-T2D74RX3-Ckyj0Mzv.js → pl-PL-T2D74RX3-DhiK4YSC.js} +1 -1
  195. package/dist-embed/chunks/{pt-BR-5N22H2LF-3jDc9_Aa.js → pt-BR-5N22H2LF-CwSVxIqs.js} +1 -1
  196. package/dist-embed/chunks/{pt-PT-UZXXM6DQ-lhLbXf7Q.js → pt-PT-UZXXM6DQ-BnxquNJT.js} +1 -1
  197. package/dist-embed/chunks/{quadrantDiagram-AXDQQJYC-Ffo3hgR0.js → quadrantDiagram-AXDQQJYC-ClE_bWPS.js} +1 -1
  198. package/dist-embed/chunks/{quadrantDiagram-AXDQQJYC-D0QYtpIp.js → quadrantDiagram-AXDQQJYC-nOA8Q9nG.js} +1 -1
  199. package/dist-embed/chunks/{quadrantDiagram-cf8b8fe0-Bqmed-0s.js → quadrantDiagram-cf8b8fe0-V_e2KgDu.js} +1 -1
  200. package/dist-embed/chunks/{railroadDiagram-O6MQD6OU-BMC9Ldnh.js → railroadDiagram-O6MQD6OU-CkhmY0tS.js} +1 -1
  201. package/dist-embed/chunks/{railroadDiagram-O6MQD6OU-aTc7bF4I.js → railroadDiagram-O6MQD6OU-D-SNyKIn.js} +1 -1
  202. package/dist-embed/chunks/{renderer-CR6Lxa3d.js → renderer-BwlsmtXF.js} +1 -1
  203. package/dist-embed/chunks/{requirementDiagram-53bda41b-DExdw0ey.js → requirementDiagram-53bda41b-BZw7Ipej.js} +1 -1
  204. package/dist-embed/chunks/{requirementDiagram-BXWQKSXE-mBFLHcqA.js → requirementDiagram-BXWQKSXE-1A97ivzl.js} +1 -1
  205. package/dist-embed/chunks/{requirementDiagram-BXWQKSXE-DBj1iVv5.js → requirementDiagram-BXWQKSXE-BXwXUXrr.js} +1 -1
  206. package/dist-embed/chunks/{ro-RO-JPDTUUEW-Dy9oeW3b.js → ro-RO-JPDTUUEW-D3G2f_fQ.js} +1 -1
  207. package/dist-embed/chunks/{ru-RU-B4JR7IUQ-CK16-wfD.js → ru-RU-B4JR7IUQ-SnVfNwaW.js} +1 -1
  208. package/dist-embed/chunks/{sankeyDiagram-P5KCCOFB-DzaadHXz.js → sankeyDiagram-P5KCCOFB-0B_Kvjm2.js} +1 -1
  209. package/dist-embed/chunks/{sankeyDiagram-P5KCCOFB-9W9X5V7a.js → sankeyDiagram-P5KCCOFB-ktT6v9aY.js} +1 -1
  210. package/dist-embed/chunks/{sankeyDiagram-c3ef121a-B6u8wnkU.js → sankeyDiagram-c3ef121a-e1QLivkZ.js} +1 -1
  211. package/dist-embed/chunks/{sequenceDiagram-82a5b84f-Bq8bvLh8.js → sequenceDiagram-82a5b84f-N-16oABv.js} +1 -1
  212. package/dist-embed/chunks/{sequenceDiagram-WJ2MYXX4-BNfJw8_y.js → sequenceDiagram-WJ2MYXX4-CtbkJYCv.js} +1 -1
  213. package/dist-embed/chunks/{sequenceDiagram-WJ2MYXX4-B76NTf4c.js → sequenceDiagram-WJ2MYXX4-DYY-dZgX.js} +1 -1
  214. package/dist-embed/chunks/{sessions-XxjScqnJ.js → sessions-C9DBCyZI.js} +1 -1
  215. package/dist-embed/chunks/{si-LK-N5RQ5JYF-AJdaUbzl.js → si-LK-N5RQ5JYF-Da7Bfexz.js} +1 -1
  216. package/dist-embed/chunks/{sizeCapture-INFHLROL-KZBUxNmb.js → sizeCapture-INFHLROL-B3xt8UaI.js} +1 -1
  217. package/dist-embed/chunks/{sizeCapture-INFHLROL-DQ5s0TIW.js → sizeCapture-INFHLROL-DJOph387.js} +1 -1
  218. package/dist-embed/chunks/{sk-SK-C5VTKIMK-Bk82hIVU.js → sk-SK-C5VTKIMK-BB-Ks1b-.js} +1 -1
  219. package/dist-embed/chunks/{sl-SI-NN7IZMDC-DSFcvf6W.js → sl-SI-NN7IZMDC-DF3fUKHX.js} +1 -1
  220. package/dist-embed/chunks/{stateDiagram-43e79a5f-BiTTNI1Z.js → stateDiagram-43e79a5f-BJcJNr41.js} +1 -1
  221. package/dist-embed/chunks/{stateDiagram-D77RDMKH-D4hQpdZ2.js → stateDiagram-D77RDMKH-DVd0MOrg.js} +1 -1
  222. package/dist-embed/chunks/{stateDiagram-D77RDMKH-lndPMO3D.js → stateDiagram-D77RDMKH-LjWP-fRB.js} +1 -1
  223. package/dist-embed/chunks/{stateDiagram-v2-2041ed4f-BbFiQEfG.js → stateDiagram-v2-2041ed4f-DTEruWg2.js} +1 -1
  224. package/dist-embed/chunks/{stateDiagram-v2-MP3YSRHH-pqcRT12A.js → stateDiagram-v2-MP3YSRHH-CJD5_Eji.js} +1 -1
  225. package/dist-embed/chunks/{stateDiagram-v2-MP3YSRHH-C-kIBdBJ.js → stateDiagram-v2-MP3YSRHH-_xCQcvgo.js} +1 -1
  226. package/dist-embed/chunks/{styles-455b33cd-U9lx7mAf.js → styles-455b33cd-OIhmfs6N.js} +1 -1
  227. package/dist-embed/chunks/{styles-f932cba9-S-lYZYdK.js → styles-f932cba9-CwLjreIv.js} +1 -1
  228. package/dist-embed/chunks/{styles-fcc2142b-DfudfB3j.js → styles-fcc2142b-DP74dQpR.js} +1 -1
  229. package/dist-embed/chunks/{subset-shared.chunk-f2gmZjeG.js → subset-shared.chunk-Cf9zgTA9.js} +1 -1
  230. package/dist-embed/chunks/{subset-worker.chunk-De1CPIQ6.js → subset-worker.chunk-WYW3AHku.js} +1 -1
  231. package/dist-embed/chunks/{sv-SE-XGPEYMSR-BbGfLHIi.js → sv-SE-XGPEYMSR-CeR-pJHy.js} +1 -1
  232. package/dist-embed/chunks/{svgDrawCommon-148a3cd9-ClgHG0vb.js → svgDrawCommon-148a3cd9-CgE5QJIv.js} +1 -1
  233. package/dist-embed/chunks/{swimlanes-42K2YHIH-OqZ4t-07.js → swimlanes-42K2YHIH-CZyflHYJ.js} +1 -1
  234. package/dist-embed/chunks/{swimlanes-42K2YHIH-CjV1bdPk.js → swimlanes-42K2YHIH-Cj4fdAYa.js} +1 -1
  235. package/dist-embed/chunks/{swimlanesDiagram-VR7AAH4N-9twpvQtj.js → swimlanesDiagram-VR7AAH4N-B2gk37ys.js} +1 -1
  236. package/dist-embed/chunks/{swimlanesDiagram-VR7AAH4N-BdS4NGOx.js → swimlanesDiagram-VR7AAH4N-Bmr6N4fj.js} +1 -1
  237. package/dist-embed/chunks/{ta-IN-2NMHFXQM-BWMJgnI2.js → ta-IN-2NMHFXQM-lmsodGuU.js} +1 -1
  238. package/dist-embed/chunks/{th-TH-HPSO5L25-DiP_CZXl.js → th-TH-HPSO5L25-DQCWr96I.js} +1 -1
  239. package/dist-embed/chunks/{timeline-definition-24CTP7MA-Cs4Bwobu.js → timeline-definition-24CTP7MA-D5dMAy5U.js} +1 -1
  240. package/dist-embed/chunks/{timeline-definition-24CTP7MA-B7uSaXDu.js → timeline-definition-24CTP7MA-DqY5EM6p.js} +1 -1
  241. package/dist-embed/chunks/{timeline-definition-7545f45a-CHrBluu1.js → timeline-definition-7545f45a-B8wMEyZY.js} +1 -1
  242. package/dist-embed/chunks/{tr-TR-DEFEU3FU-CKMBvOkr.js → tr-TR-DEFEU3FU-CqnvlGZW.js} +1 -1
  243. package/dist-embed/chunks/{uk-UA-QMV73CPH-CQL0E0jU.js → uk-UA-QMV73CPH-DdWFjbHe.js} +1 -1
  244. package/dist-embed/chunks/{vennDiagram-4TSXK5OY-uwWpr4uC.js → vennDiagram-4TSXK5OY-63-O_xI8.js} +1 -1
  245. package/dist-embed/chunks/{vennDiagram-4TSXK5OY-CHSyRZN_.js → vennDiagram-4TSXK5OY-BMg6wc5A.js} +1 -1
  246. package/dist-embed/chunks/{vi-VN-M7AON7JQ-BpvEBNJo.js → vi-VN-M7AON7JQ-CydTT0Fi.js} +1 -1
  247. package/dist-embed/chunks/{wardleyDiagram-VM6X3IG4-0UuvD-IO.js → wardleyDiagram-VM6X3IG4-C5wMQ_qe.js} +1 -1
  248. package/dist-embed/chunks/{wardleyDiagram-VM6X3IG4-zIfOyYBf.js → wardleyDiagram-VM6X3IG4-C9vLUvHf.js} +1 -1
  249. package/dist-embed/chunks/{xychartDiagram-3f383b91-ChbRPzo8.js → xychartDiagram-3f383b91-BfoQg8n9.js} +1 -1
  250. package/dist-embed/chunks/{xychartDiagram-S5SC5T6Z-hCGgyjir.js → xychartDiagram-S5SC5T6Z-BZr3T3n_.js} +1 -1
  251. package/dist-embed/chunks/{xychartDiagram-S5SC5T6Z-q9gcUSF1.js → xychartDiagram-S5SC5T6Z-DthHDnAV.js} +1 -1
  252. package/dist-embed/chunks/{zh-CN-LNUGB5OW-DWmzAIjK.js → zh-CN-LNUGB5OW-DEn1TFfK.js} +1 -1
  253. package/dist-embed/chunks/{zh-HK-E62DVLB3-CQ-xPzHX.js → zh-HK-E62DVLB3-DJQRmOHH.js} +1 -1
  254. package/dist-embed/chunks/{zh-TW-RAJ6MFWO-DvlSTykD.js → zh-TW-RAJ6MFWO-B7s9vmSf.js} +1 -1
  255. package/dist-embed/datalayer-app-main.js +52 -52
  256. package/lib/apps/embed/visitorApp.d.ts +1 -1
  257. package/lib/apps/embed/visitorApp.js +1 -1
  258. package/lib/apps/plugins/chat/ChatView.js +13 -2
  259. package/lib/chat/ChatFloating.js +4 -1
  260. package/lib/chat/base/ChatBase.js +11 -3
  261. package/lib/chat/prompt/InputPrompt.d.ts +6 -1
  262. package/lib/chat/prompt/InputPrompt.js +12 -2
  263. package/lib/voice/ComposerVoice.d.ts +15 -2
  264. package/lib/voice/ComposerVoice.js +23 -17
  265. package/lib/voice/VoiceMenu.d.ts +27 -0
  266. package/lib/voice/VoiceMenu.js +32 -0
  267. package/lib/voice/chatVoice.js +2 -2
  268. package/lib/voice/choices.d.ts +33 -0
  269. package/lib/voice/choices.js +70 -0
  270. package/lib/voice/index.d.ts +4 -0
  271. package/lib/voice/index.js +3 -0
  272. package/lib/voice/settings.d.ts +17 -1
  273. package/lib/voice/settings.js +64 -1
  274. package/lib/voice/useVoiceSettings.d.ts +6 -0
  275. package/lib/voice/useVoiceSettings.js +25 -0
  276. package/package.json +1 -1
  277. package/dist-embed/chunks/ChatView-C2La9033.js +0 -32
@@ -35,7 +35,7 @@
35
35
  import type { AppSpec } from '../../types/agentspecs';
36
36
  import type { DatalayerVisitors } from '../apps/visitorToken';
37
37
  /** Where the visitors' runtime is published, on ai-agents' host (its chart). */
38
- export declare const VISITORS_PATH = "/api/loop-visitors";
38
+ export declare const VISITORS_PATH = "/api/runtime-visitors";
39
39
  /** The examples the visitors' runtime keeps warm (its chart's `AGENT_RUNTIMES_VISITORS`). */
40
40
  export declare const VISITOR_EXAMPLES: readonly string[];
41
41
  /** The key of an application at its address, as a visitor's token names it. */
@@ -6,7 +6,7 @@ import { getApp } from '../../specs/apps';
6
6
  import { parseAppspec } from '../apps/appspec';
7
7
  import { runnable } from './embedConfig';
8
8
  /** Where the visitors' runtime is published, on ai-agents' host (its chart). */
9
- export const VISITORS_PATH = '/api/loop-visitors';
9
+ export const VISITORS_PATH = '/api/runtime-visitors';
10
10
  /** The examples the visitors' runtime keeps warm (its chart's `AGENT_RUNTIMES_VISITORS`). */
11
11
  export const VISITOR_EXAMPLES = [
12
12
  'web-research',
@@ -56,6 +56,7 @@ import { latestSaying, newestIsAnswer, } from '../../../chat/assistant/state';
56
56
  import { useChatWords } from '../../../chat/ChatLanguage';
57
57
  import { ComposerVoice } from '../../../voice/ComposerVoice';
58
58
  import { settledVoice, voiceAskedAs } from '../../../voice/chatVoice';
59
+ import { useVoiceSettings } from '../../../voice/useVoiceSettings';
59
60
  /** No editor: the conversation on its own. */
60
61
  const NO_SURFACE = '';
61
62
  /**
@@ -1177,7 +1178,11 @@ export default function ChatView({ workspace }) {
1177
1178
  * workspace's composer, which this view holds — the words written in it as
1178
1179
  * they are heard. The chat speaks its answers itself (`voice` below).
1179
1180
  */
1180
- const voice = useMemo(() => (config?.voice ? settledVoice(config.voice) : undefined), [config?.voice]);
1181
+ // The person's own settings, followed as the voice menu changes them (VO-30).
1182
+ const [personVoice] = useVoiceSettings();
1183
+ const voice = useMemo(() => (config?.voice ? settledVoice(config.voice, personVoice) : undefined), [config?.voice, personVoice]);
1184
+ // The words in the box are still being heard: greyed until final (VO-11).
1185
+ const [voiceInterim, setVoiceInterim] = useState(false);
1181
1186
  /*
1182
1187
  * The model this conversation is on.
1183
1188
  *
@@ -1672,6 +1677,7 @@ export default function ChatView({ workspace }) {
1672
1677
  suggestions: chatSuggestions,
1673
1678
  disableInputPrompt: chatDisabled,
1674
1679
  connectionConfirmed: !chatDisabled,
1680
+ interim: voiceInterim,
1675
1681
  // Tighter on top: every pixel of the composer is a pixel of the editor
1676
1682
  // under it pushed down, and the bar reads as a command line at this size.
1677
1683
  // Both of the page layout's placements are that bar — one floating over
@@ -1693,7 +1699,12 @@ export default function ChatView({ workspace }) {
1693
1699
  footerExtras: promptActions.length > 0 || (voice && voice.input !== 'off') ? (_jsxs(_Fragment, { children: [promptActions.length > 0 ? (_jsx(ReactorSlot, { slot: LoopSlots.promptAction, props: { workspace } })) : null, voice && voice.input !== 'off' ? (_jsx(ComposerVoice, { voice: voice, input: draft, setInput: setDraft, disabled: chatDisabled,
1694
1700
  // The chat's own speaker, never a second one: the microphone
1695
1701
  // opening stops it, and *Stop speaking* while it speaks.
1696
- speaking: speaking, onStopSpeaking: () => controlsRef.current?.stopSpeaking?.(), onSpoken: metadata => {
1702
+ speaking: speaking, onStopSpeaking: () => controlsRef.current?.stopSpeaking?.(), onInterimChange: setVoiceInterim,
1703
+ // The menu offers when answers are heard where the
1704
+ // application lets them be (VO-21, VO-30).
1705
+ answers: Boolean(config?.voice?.output &&
1706
+ config.voice.output !== 'off' &&
1707
+ config.voice.speechUrl), onSpoken: metadata => {
1697
1708
  spokenRef.current = metadata;
1698
1709
  }, send: (text, metadata) => {
1699
1710
  spokenRef.current = metadata;
@@ -36,6 +36,7 @@ import { DecisionAsk } from './assistant/DecisionAsk';
36
36
  import { useSpokenAnswers } from '../voice/useSpokenAnswers';
37
37
  import { useVoiceSpeaker } from '../voice/useVoiceSpeaker';
38
38
  import { settledVoice } from '../voice/chatVoice';
39
+ import { useVoiceSettings } from '../voice/useVoiceSettings';
39
40
  import { BalloonApprovalMessage, CONVERSATION_BALLOON_WIDTH, ConversationBalloonClose, balloonTailAt, conversationBalloonHeight, conversationBalloonSx, CURRENT_BALLOON_HEIGHT, peekLine, } from './assistant/ConversationBalloon';
40
41
  import { ConversationBalloonHeader, CurrentBalloonBody, } from './assistant/BalloonParts';
41
42
  import { DEFAULT_BALLOON_DISPLAY, conversationCount, newestToolLine, toolLineText, } from './assistant/toolLine';
@@ -163,7 +164,9 @@ export function ChatFloating({ endpoint, protocol: protocolProp, useStore: useSt
163
164
  * they are written (VO-20), the state following the sound (VO-22).
164
165
  */
165
166
  const [voiceItems, setVoiceItems] = useState([]);
166
- const settledVoiceOf = useMemo(() => (voice ? settledVoice(voice) : undefined), [voice]);
167
+ // The person's own settings, followed as the voice menu changes them (VO-30).
168
+ const [personVoice] = useVoiceSettings();
169
+ const settledVoiceOf = useMemo(() => (voice ? settledVoice(voice, personVoice) : undefined), [voice, personVoice]);
167
170
  const { speaker, state: speakerState, stop: stopSpeaking, read: readAnswerAloud, level: mouthLevel, } = useVoiceSpeaker(settledVoiceOf);
168
171
  // `always`: each answer heard as it is written; `on_request`: a *Read
169
172
  // aloud* under each (VO-21).
@@ -51,6 +51,7 @@ import { InputPrompt } from '../prompt/InputPrompt';
51
51
  import { ComposerVoice, spokenOf } from '../../voice/ComposerVoice';
52
52
  import { ReadAloud, readsAloud } from '../../voice/ReadAloud';
53
53
  import { settledVoice } from '../../voice/chatVoice';
54
+ import { useVoiceSettings } from '../../voice/useVoiceSettings';
54
55
  import { useVoiceSpeaker } from '../../voice/useVoiceSpeaker';
55
56
  import { useSpokenAnswers } from '../../voice/useSpokenAnswers';
56
57
  import { isFloatingChatViewMode } from '../viewModes';
@@ -3014,7 +3015,11 @@ showToolApprovalBanner = true, pendingApprovals: pendingApprovalsProp, onApprove
3014
3015
  // Voice (VOICE.md V1): what was said and put in the composer, until sent.
3015
3016
  const spokenRef = useRef(undefined);
3016
3017
  // Its voice with what it leaves unsaid filled in: Datalayer's models and packages.
3017
- const settled = useMemo(() => (voice ? settledVoice(voice) : undefined), [voice]);
3018
+ // The person's own settings, followed as the voice menu changes them (VO-30).
3019
+ const [personVoice] = useVoiceSettings();
3020
+ const settled = useMemo(() => (voice ? settledVoice(voice, personVoice) : undefined), [voice, personVoice]);
3021
+ // The words in the box are still being heard: greyed until final (VO-11).
3022
+ const [voiceInterim, setVoiceInterim] = useState(false);
3018
3023
  /*
3019
3024
  * Its answers heard (VO-20, VO-21), by Datalayer's speech service: the
3020
3025
  * host's speaker when it gives one (`ChatFloating`, whose assistant's mouth
@@ -3802,12 +3807,15 @@ showToolApprovalBanner = true, pendingApprovals: pendingApprovalsProp, onApprove
3802
3807
  // so every chat with a headless notebook gets the same transcript.
3803
3808
  notebookToolSurfacesId: notebookToolSurfacesId, approvalConfig: approvalConfig, messagesEndRef: messagesEndRef, onRespond: handleRespond, showTurnFooters: showTurnFooter, renderMessageFooter: readAloudFooter, agentUsage: agentUsage, onRemoveItems: handleRemoveItems, mcpServers: filteredMcpServers, emptyContent: launching ? null : (_jsx(ChatEmptyState, { emptyState: emptyState, brandIcon: brandIcon, description: resolvedDescription, suggestions: resolvedSuggestions, submitOnSuggestionClick: submitOnSuggestionClick, onSuggestionSubmit: handleSuggestionSubmit, onSuggestionFill: handleSuggestionFill })) }), trailingContent] }));
3804
3809
  // The microphone, in the composer's footer (VO-10, VO-11).
3805
- const voiceControl = settled && settled.input !== 'off' ? (_jsx(ComposerVoice, { voice: settled, input: input, setInput: setInput, disabled: disabled || launching, speaking: speakingNow, onStopSpeaking: stopSpeaking, onSpoken: metadata => {
3810
+ const voiceControl = settled && settled.input !== 'off' ? (_jsx(ComposerVoice, { voice: settled, input: input, setInput: setInput, disabled: disabled || launching, speaking: speakingNow, onStopSpeaking: stopSpeaking, onInterimChange: setVoiceInterim,
3811
+ // The menu offers when answers are heard where the application
3812
+ // lets them be (VO-21, VO-30).
3813
+ answers: Boolean(voice?.output && voice.output !== 'off' && voice.speechUrl), onSpoken: metadata => {
3806
3814
  spokenRef.current = metadata;
3807
3815
  }, send: (text, metadata) => void handleSend(text, undefined, metadata) })) : undefined;
3808
3816
  // Why an answer could not be heard, in a sentence, by the composer.
3809
3817
  const voiceRefused = !hostSpeaks && ownVoice.state.refused ? (_jsx(Text, { role: "alert", sx: { fontSize: 0, color: 'danger.fg', maxWidth: 260 }, "data-voice-refused": "", children: ownVoice.state.refused })) : null;
3810
- const inputToolbar = showInput ? (_jsx(InputPrompt, { footerExtras: voiceRefused ? (_jsxs(_Fragment, { children: [voiceRefused, voiceControl] })) : (voiceControl), input: input, setInput: setInput, isLoading: isLoading, kernelStatus: liveKernelStatus, connectionConfirmed: connectionConfirmed, placeholder: placeholder,
3818
+ const inputToolbar = showInput ? (_jsx(InputPrompt, { footerExtras: voiceRefused ? (_jsxs(_Fragment, { children: [voiceRefused, voiceControl] })) : (voiceControl), interim: voiceInterim, input: input, setInput: setInput, isLoading: isLoading, kernelStatus: liveKernelStatus, connectionConfirmed: connectionConfirmed, placeholder: placeholder,
3811
3819
  /*
3812
3820
  The same openers the empty state offers, typed into the box they would
3813
3821
  be typed into.
@@ -50,6 +50,11 @@ export interface InputPromptProps {
50
50
  * additions rather than reshuffling the controls people know.
51
51
  */
52
52
  footerExtras?: ReactNode;
53
+ /**
54
+ * The words in the box are still being heard by the microphone (VOICE.md
55
+ * VO-11): shown greyed, in italics, until they are final.
56
+ */
57
+ interim?: boolean;
53
58
  /**
54
59
  * Panels inside the prompt's card, above and below the composer itself.
55
60
  *
@@ -226,4 +231,4 @@ export interface InputPromptProps {
226
231
  /** Pre-fetched MCP status from WebSocket — bypasses REST polling */
227
232
  mcpStatusData?: McpToolsetsStatusResponse | null;
228
233
  }
229
- export declare function InputPrompt({ input, setInput, isLoading, kernelStatus, connectionConfirmed, placeholder, typingSuggestions, autoFocus, focusTrigger, padding, placement, floatingAnchor, draggable, container, footerExtras, leadingPanel, trailingPanel, onSend, onStop, disableInputPrompt, promptVariant, mentionableAgents, promptCommands, promptHistory, headerContent, showAgentsMenu, showInlineAgentsMenu, agents, selectedAgentId, onSelectAgent, showTokenUsage, showContextRing, agentUsage, showModelSelector, showToolsMenu, showSkillsMenu, showSuggestionsMenu, suggestions, codemodeEnabled, onToggleCodemode, isA2AProtocol, hasConfigData, hasSkillsData, configLoading, models, decisions, selectedModel, onModelSelect, availableTools, availableFrontendTools, mcpServers, enabledMcpTools, enabledMcpToolCount, onToggleMcpTool, onToggleAllMcpServerTools, approvedMcpTools, onToggleMcpToolApproval, skills, skillsLoading, enabledSkills, onToggleSkill, onToggleAllSkills, approvedSkills, onToggleSkillApproval, apiBase, authToken, mcpStatusData, }: InputPromptProps): import("react").JSX.Element;
234
+ export declare function InputPrompt({ input, setInput, isLoading, kernelStatus, connectionConfirmed, placeholder, typingSuggestions, autoFocus, focusTrigger, padding, placement, floatingAnchor, draggable, container, footerExtras, interim, leadingPanel, trailingPanel, onSend, onStop, disableInputPrompt, promptVariant, mentionableAgents, promptCommands, promptHistory, headerContent, showAgentsMenu, showInlineAgentsMenu, agents, selectedAgentId, onSelectAgent, showTokenUsage, showContextRing, agentUsage, showModelSelector, showToolsMenu, showSkillsMenu, showSuggestionsMenu, suggestions, codemodeEnabled, onToggleCodemode, isA2AProtocol, hasConfigData, hasSkillsData, configLoading, models, decisions, selectedModel, onModelSelect, availableTools, availableFrontendTools, mcpServers, enabledMcpTools, enabledMcpToolCount, onToggleMcpTool, onToggleAllMcpServerTools, approvedMcpTools, onToggleMcpToolApproval, skills, skillsLoading, enabledSkills, onToggleSkill, onToggleAllSkills, approvedSkills, onToggleSkillApproval, apiBase, authToken, mcpStatusData, }: InputPromptProps): import("react").JSX.Element;
@@ -30,7 +30,7 @@ const EMPTY_ID_SET = new Set();
30
30
  // ---------------------------------------------------------------------------
31
31
  // Component
32
32
  // ---------------------------------------------------------------------------
33
- export function InputPrompt({ input, setInput, isLoading, kernelStatus, connectionConfirmed, placeholder, typingSuggestions, autoFocus, focusTrigger, padding, placement, floatingAnchor = 'bottom', draggable = false, container, footerExtras, leadingPanel, trailingPanel, onSend, onStop, disableInputPrompt = false, promptVariant, mentionableAgents, promptCommands, promptHistory, headerContent, showAgentsMenu = false, showInlineAgentsMenu = true, agents = [], selectedAgentId, onSelectAgent, showTokenUsage, showContextRing = false, agentUsage, showModelSelector, showToolsMenu, showSkillsMenu, showSuggestionsMenu = true, suggestions, codemodeEnabled, onToggleCodemode, isA2AProtocol, hasConfigData, hasSkillsData, configLoading = false, models = [], decisions, selectedModel = '', onModelSelect = () => { }, availableTools = [], availableFrontendTools = [], mcpServers = [], enabledMcpTools = EMPTY_TOOL_MAP, enabledMcpToolCount = 0, onToggleMcpTool = () => { }, onToggleAllMcpServerTools = () => { }, approvedMcpTools = EMPTY_TOOL_MAP, onToggleMcpToolApproval = () => { }, skills = [], skillsLoading = false, enabledSkills = EMPTY_ID_SET, onToggleSkill = () => { }, onToggleAllSkills = () => { }, approvedSkills = EMPTY_ID_SET, onToggleSkillApproval = () => { }, apiBase, authToken, mcpStatusData, }) {
33
+ export function InputPrompt({ input, setInput, isLoading, kernelStatus, connectionConfirmed, placeholder, typingSuggestions, autoFocus, focusTrigger, padding, placement, floatingAnchor = 'bottom', draggable = false, container, footerExtras, interim = false, leadingPanel, trailingPanel, onSend, onStop, disableInputPrompt = false, promptVariant, mentionableAgents, promptCommands, promptHistory, headerContent, showAgentsMenu = false, showInlineAgentsMenu = true, agents = [], selectedAgentId, onSelectAgent, showTokenUsage, showContextRing = false, agentUsage, showModelSelector, showToolsMenu, showSkillsMenu, showSuggestionsMenu = true, suggestions, codemodeEnabled, onToggleCodemode, isA2AProtocol, hasConfigData, hasSkillsData, configLoading = false, models = [], decisions, selectedModel = '', onModelSelect = () => { }, availableTools = [], availableFrontendTools = [], mcpServers = [], enabledMcpTools = EMPTY_TOOL_MAP, enabledMcpToolCount = 0, onToggleMcpTool = () => { }, onToggleAllMcpServerTools = () => { }, approvedMcpTools = EMPTY_TOOL_MAP, onToggleMcpToolApproval = () => { }, skills = [], skillsLoading = false, enabledSkills = EMPTY_ID_SET, onToggleSkill = () => { }, onToggleAllSkills = () => { }, approvedSkills = EMPTY_ID_SET, onToggleSkillApproval = () => { }, apiBase, authToken, mcpStatusData, }) {
34
34
  const chatText = useChatWords();
35
35
  const isKernelBusy = kernelStatus === 'busy';
36
36
  /*
@@ -107,7 +107,17 @@ export function InputPrompt({ input, setInput, isLoading, kernelStatus, connecti
107
107
  * from the start; this shows it.
108
108
  */
109
109
  const hasContext = Boolean(agentUsage && !agentUsage.error);
110
- const body = (_jsxs(Box, { children: [leadingPanel, _jsx(InputPromptBase, { variant: promptVariant, mentionableAgents: mentionableAgents, promptCommands: promptCommands, promptHistory: promptHistory,
110
+ const body = (_jsxs(Box
111
+ // Words still being heard, greyed until final (VO-11); the same Box
112
+ // either way, so the editor is never mounted again.
113
+ , { "data-voice-interim": interim ? '' : undefined, sx: interim
114
+ ? {
115
+ '& [contenteditable="true"], & textarea': {
116
+ color: 'fg.muted',
117
+ fontStyle: 'italic',
118
+ },
119
+ }
120
+ : undefined, children: [leadingPanel, _jsx(InputPromptBase, { variant: promptVariant, mentionableAgents: mentionableAgents, promptCommands: promptCommands, promptHistory: promptHistory,
111
121
  /*
112
122
  Whatever the host puts inside the prompt, and the agent chip beside
113
123
  it. Both, rather than either: a host contributing its own controls
@@ -4,7 +4,10 @@
4
4
  * whose composer is a plugin of its own). What the box held when the
5
5
  * microphone opened stays; the words heard go after it as they come, and the
6
6
  * whole of what was heard replaces them once it stops. Put there for the
7
- * person to edit and send — or sent at once with *Send what I say*.
7
+ * person to edit and send — or sent at once with *Send what I say*. While
8
+ * the words are still being heard the host is told (`onInterimChange`), to
9
+ * grey them until they are final (VO-11). Beside the microphone, the
10
+ * person's voice menu (`VoiceMenu`, VO-30).
8
11
  *
9
12
  * @module voice/ComposerVoice
10
13
  */
@@ -26,8 +29,18 @@ export interface ComposerVoiceProps {
26
29
  speaking?: boolean;
27
30
  /** Stops the agent's voice, also when the microphone opens (VO-13). */
28
31
  onStopSpeaking?: () => void;
32
+ /**
33
+ * The words in the box are still being heard (`true`), or final
34
+ * (`false`): the host greys them until they are (VO-11).
35
+ */
36
+ onInterimChange?: (interim: boolean) => void;
37
+ /**
38
+ * The application lets its answers be heard: the voice menu offers when,
39
+ * the voice, its speed and loudness (VO-21, VO-25, VO-30).
40
+ */
41
+ answers?: boolean;
29
42
  }
30
43
  /** Whether something rides on a run as a spoken message's metadata (VO-27). */
31
44
  export declare function spokenOf(value: unknown): SpokenMetadata | undefined;
32
- export declare function ComposerVoice({ voice, input, setInput, onSpoken, send, disabled, speaking, onStopSpeaking, }: ComposerVoiceProps): JSX.Element | null;
45
+ export declare function ComposerVoice({ voice, input, setInput, onSpoken, send, disabled, speaking, onStopSpeaking, onInterimChange, answers, }: ComposerVoiceProps): JSX.Element | null;
33
46
  export default ComposerVoice;
@@ -1,7 +1,8 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useMemo, useRef } from 'react';
3
3
  import { DeviceHearing } from './hearing';
4
4
  import { VoiceInput } from './VoiceInput';
5
+ import { VoiceMenu } from './VoiceMenu';
5
6
  /** Whether something rides on a run as a spoken message's metadata (VO-27). */
6
7
  export function spokenOf(value) {
7
8
  const said = value;
@@ -12,7 +13,7 @@ export function spokenOf(value) {
12
13
  ? said
13
14
  : undefined;
14
15
  }
15
- export function ComposerVoice({ voice, input, setInput, onSpoken, send, disabled = false, speaking = false, onStopSpeaking, }) {
16
+ export function ComposerVoice({ voice, input, setInput, onSpoken, send, disabled = false, speaking = false, onStopSpeaking, onInterimChange, answers = false, }) {
16
17
  const hearing = useMemo(() => voice.input !== 'off'
17
18
  ? new DeviceHearing(voice.modelsUrl, voice.engines)
18
19
  : undefined, [voice.input, voice.modelsUrl, voice.engines]);
@@ -22,20 +23,25 @@ export function ComposerVoice({ voice, input, setInput, onSpoken, send, disabled
22
23
  if (!hearing) {
23
24
  return null;
24
25
  }
25
- return (_jsx(VoiceInput, { hearing: hearing, language: voice.language, consentKey: voice.consentKey ?? 'chat', silenceMs: voice.silenceMs, microphoneId: voice.microphoneId, disabled: disabled, speaking: speaking, onStopSpeaking: onStopSpeaking, onListen: () => {
26
- base.current = input.trim();
27
- onStopSpeaking?.();
28
- },
29
- // The words as they are heard, in the box (VO-11); '' gives it back.
30
- onInterim: (words) => setInput(afterBase(words)), onTranscript: (transcript) => {
31
- if (voice.sendWhatISay) {
32
- setInput(base.current);
33
- send(transcript.text, transcript.metadata);
34
- return;
35
- }
36
- // In the box, for the person to edit and send: never sent here.
37
- onSpoken(transcript.metadata);
38
- setInput(afterBase(transcript.text));
39
- } }));
26
+ return (_jsxs("span", { "data-composer-voice": "", style: { display: 'inline-flex', alignItems: 'center', gap: 2 }, children: [_jsx(VoiceMenu, { voice: voice, answers: answers, disabled: disabled }), _jsx(VoiceInput, { hearing: hearing, language: voice.language, consentKey: voice.consentKey ?? 'chat', silenceMs: voice.silenceMs, microphoneId: voice.microphoneId, disabled: disabled, speaking: speaking, onStopSpeaking: onStopSpeaking, onListen: () => {
27
+ base.current = input.trim();
28
+ onStopSpeaking?.();
29
+ },
30
+ // The words as they are heard, in the box (VO-11), greyed until
31
+ // final; '' gives it back.
32
+ onInterim: (words) => {
33
+ setInput(afterBase(words));
34
+ onInterimChange?.(words !== '');
35
+ }, onTranscript: (transcript) => {
36
+ onInterimChange?.(false);
37
+ if (voice.sendWhatISay) {
38
+ setInput(base.current);
39
+ send(transcript.text, transcript.metadata);
40
+ return;
41
+ }
42
+ // In the box, for the person to edit and send: never sent here.
43
+ onSpoken(transcript.metadata);
44
+ setInput(afterBase(transcript.text));
45
+ } })] }));
40
46
  }
41
47
  export default ComposerVoice;
@@ -0,0 +1,27 @@
1
+ /**
2
+ * The composer's voice menu (VOICE.md VO-14, VO-21, VO-25, VO-30): beside
3
+ * the microphone, what a person chooses for themselves — the language they
4
+ * speak and hear, when answers are heard, the voice, its speed and loudness,
5
+ * *Send what I say*, the microphone, and *Keep speech on this device*. Each
6
+ * choice is kept in the person's settings and heard at once by every chat
7
+ * on the page; *Use the application's* forgets them all.
8
+ *
9
+ * When answers are heard is offered only where the application lets them be
10
+ * heard: a menu may not turn on what the application turned off.
11
+ *
12
+ * @module voice/VoiceMenu
13
+ */
14
+ import type { JSX } from 'react';
15
+ import type { SettledVoice } from './chatVoice';
16
+ export interface VoiceMenuProps {
17
+ /** The chat's voice as it is heard now (`settledVoice`). */
18
+ voice: SettledVoice;
19
+ /**
20
+ * The application lets its answers be heard (its own `output` is not
21
+ * `off`, and it names the speech service): the menu offers when.
22
+ */
23
+ answers: boolean;
24
+ disabled?: boolean;
25
+ }
26
+ export declare function VoiceMenu({ voice, answers, disabled, }: VoiceMenuProps): JSX.Element;
27
+ export default VoiceMenu;
@@ -0,0 +1,32 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { useState } from 'react';
3
+ import { ActionList, ActionMenu, IconButton } from '@primer/react';
4
+ import { GearIcon } from '@primer/octicons-react';
5
+ import { OUTPUT_CHOICES, RATE_CHOICES, VOLUME_CHOICES, catalogueVoiceSpeaks, voiceLanguages, voicesSpeaking, } from './choices';
6
+ import { withVoiceSetting } from './settings';
7
+ import { useVoiceSettings } from './useVoiceSettings';
8
+ /** The microphones the browser lists; named only once one was allowed. */
9
+ async function microphones() {
10
+ try {
11
+ const devices = await navigator.mediaDevices.enumerateDevices();
12
+ return devices.filter(device => device.kind === 'audioinput');
13
+ }
14
+ catch {
15
+ return [];
16
+ }
17
+ }
18
+ export function VoiceMenu({ voice, answers, disabled = false, }) {
19
+ const [settings, keep] = useVoiceSettings();
20
+ const [devices, setDevices] = useState([]);
21
+ const choose = (key, value) => keep(withVoiceSetting(settings, key, value, catalogueVoiceSpeaks));
22
+ const onDevice = Boolean(settings.onDeviceOnly);
23
+ const voices = voicesSpeaking(voice.language);
24
+ const named = devices.filter(device => device.label);
25
+ return (_jsxs(ActionMenu, { onOpenChange: open => {
26
+ if (open) {
27
+ void microphones().then(setDevices);
28
+ }
29
+ }, children: [_jsx(ActionMenu.Anchor, { children: _jsx(IconButton, { icon: GearIcon, size: "small", variant: "invisible", "aria-label": "Voice settings", "data-voice-menu": "", disabled: disabled }) }), _jsx(ActionMenu.Overlay, { width: "medium", children: _jsxs(ActionList, { children: [_jsxs(ActionList.Group, { selectionVariant: "single", children: [_jsx(ActionList.GroupHeading, { children: "Language" }), voiceLanguages().map(language => (_jsx(ActionList.Item, { selected: language.value === voice.language, onSelect: () => choose('language', language.value), "data-voice-language": language.value, children: language.label }, language.value)))] }), answers && !onDevice ? (_jsxs(_Fragment, { children: [_jsx(ActionList.Divider, {}), _jsxs(ActionList.Group, { selectionVariant: "single", children: [_jsx(ActionList.GroupHeading, { children: "Answers heard" }), OUTPUT_CHOICES.map(output => (_jsx(ActionList.Item, { selected: output.value === voice.output, onSelect: () => choose('output', output.value), "data-voice-output": output.value, children: output.label }, output.value)))] }), voices.length > 0 ? (_jsxs(ActionList.Group, { selectionVariant: "single", children: [_jsx(ActionList.GroupHeading, { children: "Voice" }), voices.map(spoken => (_jsx(ActionList.Item, { selected: spoken.id === voice.voice, onSelect: () => choose('voice', spoken.id), "data-voice-voice": spoken.id, children: spoken.name }, spoken.id)))] })) : null, _jsxs(ActionList.Group, { selectionVariant: "single", children: [_jsx(ActionList.GroupHeading, { children: "Speed" }), RATE_CHOICES.map(rate => (_jsx(ActionList.Item, { selected: rate.value === (voice.rate ?? 1), onSelect: () => choose('rate', rate.value), "data-voice-rate": rate.value, children: rate.label }, rate.value)))] }), _jsxs(ActionList.Group, { selectionVariant: "single", children: [_jsx(ActionList.GroupHeading, { children: "Loudness" }), VOLUME_CHOICES.map(volume => (_jsx(ActionList.Item, { selected: volume.value === (voice.volume ?? 1), onSelect: () => choose('volume', volume.value), "data-voice-volume": volume.value, children: volume.label }, volume.value)))] })] })) : null, named.length > 1 ? (_jsxs(_Fragment, { children: [_jsx(ActionList.Divider, {}), _jsxs(ActionList.Group, { selectionVariant: "single", children: [_jsx(ActionList.GroupHeading, { children: "Microphone" }), named.map(device => (_jsx(ActionList.Item, { selected: device.deviceId ===
30
+ (voice.microphoneId ?? named[0].deviceId), onSelect: () => choose('microphoneId', device.deviceId), "data-voice-microphone": device.deviceId, children: device.label }, device.deviceId)))] })] })) : null, _jsx(ActionList.Divider, {}), _jsxs(ActionList.Group, { selectionVariant: "multiple", children: [_jsxs(ActionList.Item, { selected: Boolean(voice.sendWhatISay), onSelect: () => choose('sendWhatISay', !voice.sendWhatISay), "data-voice-send-what-i-say": "", children: ["Send what I say", _jsx(ActionList.Description, { variant: "block", children: "Sent as soon as it is heard, not left in the box." })] }), _jsxs(ActionList.Item, { selected: onDevice, onSelect: () => choose('onDeviceOnly', !onDevice), "data-voice-on-device": "", children: ["Keep speech on this device", _jsx(ActionList.Description, { variant: "block", children: "Nothing is sent to Datalayer\u2019s speech service: you are heard in the browser, answers are not spoken." })] })] }), Object.keys(settings).length > 0 ? (_jsxs(_Fragment, { children: [_jsx(ActionList.Divider, {}), _jsx(ActionList.Item, { onSelect: () => keep({}), "data-voice-settings-reset": "", children: "Use the application\u2019s" })] })) : null] }) })] }));
31
+ }
32
+ export default VoiceMenu;
@@ -11,7 +11,7 @@
11
11
  * @module voice/chatVoice
12
12
  */
13
13
  import { voiceFor } from '../specs/voices';
14
- import { keptVoiceSettings, voiceForPerson, } from './settings';
14
+ import { heldVoiceSettings, voiceForPerson, } from './settings';
15
15
  /**
16
16
  * Datalayer's origin for the browser's speech models, as pinned
17
17
  * (`s3://datalayer-models-speech` behind its CDN; VO-48, VO-49): each model
@@ -88,7 +88,7 @@ export const SILENCE_MS = 1500;
88
88
  * Datalayer's models and packages, a silence of 1.5 s. Answers heard need
89
89
  * the speech service's address: refused without.
90
90
  */
91
- export function settledVoice(given, person = keptVoiceSettings()) {
91
+ export function settledVoice(given, person = heldVoiceSettings()) {
92
92
  const voice = voiceForPerson(given, person);
93
93
  const output = voice.output ?? 'off';
94
94
  if (output !== 'off' && !voice.speechUrl) {
@@ -0,0 +1,33 @@
1
+ /**
2
+ * What a person may choose for their voice (VOICE.md VO-14, VO-21, VO-25,
3
+ * VO-30), from the catalogue: the languages a voice speaks and the device
4
+ * hears, the voices of each, the speeds and loudnesses offered, and when
5
+ * answers are heard. Read by the composer's menu (`VoiceMenu`) and by a
6
+ * settings page, so both offer the same.
7
+ *
8
+ * @module voice/choices
9
+ */
10
+ import { type VoiceSpec } from '../specs/voices';
11
+ import type { ChatVoice } from './index';
12
+ /** A choice as a menu or a page lists it. */
13
+ export interface VoiceChoice<T> {
14
+ value: T;
15
+ label: string;
16
+ }
17
+ /** A language's name, in English, as the menu says it: `en-GB` is *British English*. */
18
+ export declare function languageName(language: string): string;
19
+ /**
20
+ * The languages a person may speak and hear: each a voice of the catalogue
21
+ * speaks and a model on the device hears, in the catalogue's order.
22
+ */
23
+ export declare function voiceLanguages(): VoiceChoice<string>[];
24
+ /** The voices that speak a language, in the catalogue's order. */
25
+ export declare function voicesSpeaking(language: string): VoiceSpec[];
26
+ /** Whether a voice of the catalogue speaks a language: what a new language keeps of a chosen voice. */
27
+ export declare function catalogueVoiceSpeaks(voice: string, language: string): boolean;
28
+ /** The speeds offered, as multipliers of the voice's own. */
29
+ export declare const RATE_CHOICES: VoiceChoice<number>[];
30
+ /** The loudnesses offered, 0 to 1. */
31
+ export declare const VOLUME_CHOICES: VoiceChoice<number>[];
32
+ /** When answers are heard (VO-21): what a person may choose where the application speaks. */
33
+ export declare const OUTPUT_CHOICES: VoiceChoice<NonNullable<ChatVoice['output']>>[];
@@ -0,0 +1,70 @@
1
+ /*
2
+ * Copyright (c) 2025-2026 Datalayer, Inc.
3
+ * Distributed under the terms of the Modified BSD License.
4
+ */
5
+ /**
6
+ * What a person may choose for their voice (VOICE.md VO-14, VO-21, VO-25,
7
+ * VO-30), from the catalogue: the languages a voice speaks and the device
8
+ * hears, the voices of each, the speeds and loudnesses offered, and when
9
+ * answers are heard. Read by the composer's menu (`VoiceMenu`) and by a
10
+ * settings page, so both offer the same.
11
+ *
12
+ * @module voice/choices
13
+ */
14
+ import { VOICE_CATALOGUE, transcriberFor, voiceSpeaks, } from '../specs/voices';
15
+ /** A language's name, in English, as the menu says it: `en-GB` is *British English*. */
16
+ export function languageName(language) {
17
+ try {
18
+ const names = new Intl.DisplayNames(['en'], { type: 'language' });
19
+ return names.of(language) ?? language;
20
+ }
21
+ catch {
22
+ return language;
23
+ }
24
+ }
25
+ /**
26
+ * The languages a person may speak and hear: each a voice of the catalogue
27
+ * speaks and a model on the device hears, in the catalogue's order.
28
+ */
29
+ export function voiceLanguages() {
30
+ const seen = new Set();
31
+ const languages = [];
32
+ for (const voice of Object.values(VOICE_CATALOGUE)) {
33
+ for (const language of voice.languages) {
34
+ if (!seen.has(language) && transcriberFor(language)) {
35
+ seen.add(language);
36
+ languages.push({ value: language, label: languageName(language) });
37
+ }
38
+ }
39
+ }
40
+ return languages;
41
+ }
42
+ /** The voices that speak a language, in the catalogue's order. */
43
+ export function voicesSpeaking(language) {
44
+ return Object.values(VOICE_CATALOGUE).filter(voice => voiceSpeaks(voice, language) ||
45
+ voiceSpeaks(voice, language.split('-')[0]));
46
+ }
47
+ /** Whether a voice of the catalogue speaks a language: what a new language keeps of a chosen voice. */
48
+ export function catalogueVoiceSpeaks(voice, language) {
49
+ return voicesSpeaking(language).some(spoken => spoken.id === voice);
50
+ }
51
+ /** The speeds offered, as multipliers of the voice's own. */
52
+ export const RATE_CHOICES = [
53
+ { value: 0.75, label: 'Slower' },
54
+ { value: 1, label: 'Normal' },
55
+ { value: 1.25, label: 'Faster' },
56
+ { value: 1.5, label: 'Fastest' },
57
+ ];
58
+ /** The loudnesses offered, 0 to 1. */
59
+ export const VOLUME_CHOICES = [
60
+ { value: 0.25, label: 'Quiet' },
61
+ { value: 0.5, label: 'Half' },
62
+ { value: 0.75, label: 'Loud' },
63
+ { value: 1, label: 'Full' },
64
+ ];
65
+ /** When answers are heard (VO-21): what a person may choose where the application speaks. */
66
+ export const OUTPUT_CHOICES = [
67
+ { value: 'off', label: 'Never' },
68
+ { value: 'on_request', label: 'When I ask (Read aloud)' },
69
+ { value: 'always', label: 'Always, as they are written' },
70
+ ];
@@ -16,6 +16,10 @@ export * from './hearing';
16
16
  export * from './speaker';
17
17
  export * from './consent';
18
18
  export * from './settings';
19
+ export * from './choices';
20
+ export { useVoiceSettings } from './useVoiceSettings';
21
+ export { VoiceMenu } from './VoiceMenu';
22
+ export type { VoiceMenuProps } from './VoiceMenu';
19
23
  export * from './useSpokenAnswers';
20
24
  export { VoiceInput } from './VoiceInput';
21
25
  export type { VoiceInputProps, ListeningState } from './VoiceInput';
@@ -10,6 +10,9 @@ export * from './hearing';
10
10
  export * from './speaker';
11
11
  export * from './consent';
12
12
  export * from './settings';
13
+ export * from './choices';
14
+ export { useVoiceSettings } from './useVoiceSettings';
15
+ export { VoiceMenu } from './VoiceMenu';
13
16
  export * from './useSpokenAnswers';
14
17
  export { VoiceInput } from './VoiceInput';
15
18
  export { ReadAloud, readAloud, readsAloud } from './ReadAloud';
@@ -62,8 +62,24 @@ export interface VoiceSettings {
62
62
  export declare function saneVoiceSettings(settings: VoiceSettings | null | undefined): VoiceSettings;
63
63
  /** What was kept, or nothing. Storage may be refused, or hold nonsense. */
64
64
  export declare function keptVoiceSettings(): VoiceSettings;
65
- /** Keep what the person chose; an empty choice forgets it. */
65
+ /** The person's settings as the page holds them (VO-30). */
66
+ export declare function heldVoiceSettings(): VoiceSettings;
67
+ /**
68
+ * Be told when the person's settings change — from a menu on this page, or
69
+ * from another tab, whose storage event is read here. Returns the unsubscribe.
70
+ */
71
+ export declare function onVoiceSettingsChange(listener: (settings: VoiceSettings) => void): () => void;
72
+ /**
73
+ * Keep what the person chose; an empty choice forgets it. Every chat on the
74
+ * page is told, so the menu's choice is heard at once (VO-30).
75
+ */
66
76
  export declare function keepVoiceSettings(settings: VoiceSettings): VoiceSettings;
77
+ /**
78
+ * The settings with one choice changed (VO-30): `undefined` forgets that
79
+ * choice, giving it back to the application. A new language drops a voice
80
+ * the person chose that does not speak it, for the language's own.
81
+ */
82
+ export declare function withVoiceSetting<K extends keyof VoiceSettings>(settings: VoiceSettings, key: K, value: VoiceSettings[K] | undefined, speaks?: (voice: string, language: string) => boolean): VoiceSettings;
67
83
  /** The language the browser says the person reads, or nothing. */
68
84
  export declare function browserLanguage(): string | undefined;
69
85
  /**
@@ -54,7 +54,47 @@ export function keptVoiceSettings() {
54
54
  return {};
55
55
  }
56
56
  }
57
- /** Keep what the person chose; an empty choice forgets it. */
57
+ /**
58
+ * What the page holds: the kept settings, or the choice made on this page
59
+ * when storage refused it. Read once, then told of each change.
60
+ */
61
+ let held;
62
+ /** Who is told when the person's settings change: every chat on the page (VO-30). */
63
+ const listeners = new Set();
64
+ /** The person's settings as the page holds them (VO-30). */
65
+ export function heldVoiceSettings() {
66
+ if (held === undefined) {
67
+ held = keptVoiceSettings();
68
+ }
69
+ return held;
70
+ }
71
+ /**
72
+ * Be told when the person's settings change — from a menu on this page, or
73
+ * from another tab, whose storage event is read here. Returns the unsubscribe.
74
+ */
75
+ export function onVoiceSettingsChange(listener) {
76
+ listeners.add(listener);
77
+ return () => {
78
+ listeners.delete(listener);
79
+ };
80
+ }
81
+ function told(settings) {
82
+ held = settings;
83
+ for (const listener of [...listeners]) {
84
+ listener(settings);
85
+ }
86
+ }
87
+ if (typeof window !== 'undefined') {
88
+ window.addEventListener('storage', event => {
89
+ if (event.key === VOICE_SETTINGS_KEY || event.key === null) {
90
+ told(keptVoiceSettings());
91
+ }
92
+ });
93
+ }
94
+ /**
95
+ * Keep what the person chose; an empty choice forgets it. Every chat on the
96
+ * page is told, so the menu's choice is heard at once (VO-30).
97
+ */
58
98
  export function keepVoiceSettings(settings) {
59
99
  const sane = saneVoiceSettings(settings);
60
100
  try {
@@ -68,8 +108,31 @@ export function keepVoiceSettings(settings) {
68
108
  catch {
69
109
  // Without storage the choice holds for the page.
70
110
  }
111
+ told(sane);
71
112
  return sane;
72
113
  }
114
+ /**
115
+ * The settings with one choice changed (VO-30): `undefined` forgets that
116
+ * choice, giving it back to the application. A new language drops a voice
117
+ * the person chose that does not speak it, for the language's own.
118
+ */
119
+ export function withVoiceSetting(settings, key, value, speaks) {
120
+ const next = { ...saneVoiceSettings(settings) };
121
+ if (value === undefined) {
122
+ delete next[key];
123
+ }
124
+ else {
125
+ next[key] = value;
126
+ }
127
+ if (key === 'language' &&
128
+ typeof value === 'string' &&
129
+ next.voice &&
130
+ speaks &&
131
+ !speaks(next.voice, value)) {
132
+ delete next.voice;
133
+ }
134
+ return saneVoiceSettings(next);
135
+ }
73
136
  /** The language the browser says the person reads, or nothing. */
74
137
  export function browserLanguage() {
75
138
  try {
@@ -0,0 +1,6 @@
1
+ import { type VoiceSettings } from './settings';
2
+ /** The person's settings, and a setter that keeps them and tells every chat. */
3
+ export declare function useVoiceSettings(): [
4
+ VoiceSettings,
5
+ (settings: VoiceSettings) => void
6
+ ];
@@ -0,0 +1,25 @@
1
+ /*
2
+ * Copyright (c) 2025-2026 Datalayer, Inc.
3
+ * Distributed under the terms of the Modified BSD License.
4
+ */
5
+ /**
6
+ * A person's voice settings, as a React state that follows every change —
7
+ * the composer's menu, a settings page, another tab (VOICE.md VO-30).
8
+ *
9
+ * @module voice/useVoiceSettings
10
+ */
11
+ import { useCallback, useEffect, useState } from 'react';
12
+ import { heldVoiceSettings, keepVoiceSettings, onVoiceSettingsChange, } from './settings';
13
+ /** The person's settings, and a setter that keeps them and tells every chat. */
14
+ export function useVoiceSettings() {
15
+ const [settings, setSettings] = useState(heldVoiceSettings);
16
+ useEffect(() => {
17
+ // A change between the first draw and this subscription is read here.
18
+ setSettings(heldVoiceSettings());
19
+ return onVoiceSettingsChange(setSettings);
20
+ }, []);
21
+ const keep = useCallback((next) => {
22
+ keepVoiceSettings(next);
23
+ }, []);
24
+ return [settings, keep];
25
+ }