@xopcai/xopc 0.0.242 → 0.0.243

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 (234) hide show
  1. package/dist/browser-ext/manifest.json +1 -1
  2. package/dist/extensions/telegram/xopc.extension.json +1 -1
  3. package/dist/gateway/static/root/assets/{activity-store-MU5XrVv8.js → activity-store-CAah-_8h.js} +1 -1
  4. package/dist/gateway/static/root/assets/{agent-avatar-dicebear-B_Wc0wuL.js → agent-avatar-dicebear-DDH4HgP7.js} +1 -1
  5. package/dist/gateway/static/root/assets/agent-defaults-settings-panel-BDCfJZhh.js +1 -0
  6. package/dist/gateway/static/root/assets/agents-B0ZWgf-U.js +1 -0
  7. package/dist/gateway/static/root/assets/{api-DLyc8BQp.js → api-B2tKxbcz.js} +1 -1
  8. package/dist/gateway/static/root/assets/app-management-settings-panel-Blfwszzn.js +1 -0
  9. package/dist/gateway/static/root/assets/{appearance-settings-DB5gEQhN.js → appearance-settings-C3V7Na75.js} +1 -1
  10. package/dist/gateway/static/root/assets/apps-page-BiEks0-F.js +1 -0
  11. package/dist/gateway/static/root/assets/{archive-plugin-BOx0EJZs.js → archive-plugin-BmSx7wzY.js} +1 -1
  12. package/dist/gateway/static/root/assets/{attachment-load-CYnYIyLr.js → attachment-load-BS-S4LJ9.js} +1 -1
  13. package/dist/gateway/static/root/assets/{automations-page-ChTflpmA.js → automations-page-C7Y3L30D.js} +1 -1
  14. package/dist/gateway/static/root/assets/automations-workspace-A3zPkPuo.js +6 -0
  15. package/dist/gateway/static/root/assets/{binary-plugins-BjbLfNwG.js → binary-plugins-BM9B5kcm.js} +1 -1
  16. package/dist/gateway/static/root/assets/block-editor-BbnpkYP9.js +185 -0
  17. package/dist/gateway/static/root/assets/browser-settings-page-Dk4FQ7fY.js +8 -0
  18. package/dist/gateway/static/root/assets/{browser-workflow-inputs-DGQxD0vD.js → browser-workflow-inputs-CRnkgZHI.js} +1 -1
  19. package/dist/gateway/static/root/assets/{browser-workflows-page-B9gfdd7L.js → browser-workflows-page-B9qGL-it.js} +2 -2
  20. package/dist/gateway/static/root/assets/{button-CSEbl4zT.js → button-CtTvuElV.js} +1 -1
  21. package/dist/gateway/static/root/assets/capabilities-settings-panel--tR_El9e.js +7 -0
  22. package/dist/gateway/static/root/assets/channels-settings-D347vl_J.js +1 -0
  23. package/dist/gateway/static/root/assets/{channels-status-swr-TkU42f-W.js → channels-status-swr-DuY4MGxe.js} +1 -1
  24. package/dist/gateway/static/root/assets/{chat-terminal-dock-CWMPcnoN.js → chat-terminal-dock-DABPvwBT.js} +2 -2
  25. package/dist/gateway/static/root/assets/connectors-page-B-tvJkRJ.js +2 -0
  26. package/dist/gateway/static/root/assets/{cron-expression-3h3rR0cf.js → cron-expression-D3bsKbNd.js} +1 -1
  27. package/dist/gateway/static/root/assets/{date-picker-Bz1sLBEx.js → date-picker-BsGM6Yty.js} +1 -1
  28. package/dist/gateway/static/root/assets/{dependency-picker-p9DWR8uU.js → dependency-picker-Dj3g6YXZ.js} +1 -1
  29. package/dist/gateway/static/root/assets/{desktop-pet-D1TDB_gR.js → desktop-pet-C1QT0Sur.js} +1 -1
  30. package/dist/gateway/static/root/assets/{desktop-pet-settings-DWPZpoB7.js → desktop-pet-settings-r6kAOnfY.js} +1 -1
  31. package/dist/gateway/static/root/assets/dist-CpzYSoz7.js +1 -0
  32. package/dist/gateway/static/root/assets/{dist-DaxPZj9e.js → dist-DBS3OB8K.js} +1 -1
  33. package/dist/gateway/static/root/assets/dist-DLmwHyAh.js +1 -0
  34. package/dist/gateway/static/root/assets/es2015-BvLh9GaE.js +41 -0
  35. package/dist/gateway/static/root/assets/{extension-debug-page-BrRbK2rJ.js → extension-debug-page-DOkf7nh9.js} +1 -1
  36. package/dist/gateway/static/root/assets/{extension-page-CD65czfS.js → extension-page-Cq2IA4Ho.js} +1 -1
  37. package/dist/gateway/static/root/assets/{extension-settings-page-BRDDKhpi.js → extension-settings-page-DQn4qjDZ.js} +1 -1
  38. package/dist/gateway/static/root/assets/{files-DQjhZjr2.js → files-D6vf3S30.js} +1 -1
  39. package/dist/gateway/static/root/assets/{gateway-config-api-CjbBsr5M.js → gateway-config-api-DM3poL22.js} +1 -1
  40. package/dist/gateway/static/root/assets/{gateway-config-swr-HT7sLeO9.js → gateway-config-swr-BC3pgb_P.js} +1 -1
  41. package/dist/gateway/static/root/assets/{gateway-settings-BQjmfYD4.js → gateway-settings-DPgH1hnh.js} +1 -1
  42. package/dist/gateway/static/root/assets/{gateway-startup-retry-iBCtaAuT.js → gateway-startup-retry-uMcSfLru.js} +1 -1
  43. package/dist/gateway/static/root/assets/{heartbeat-settings-BzZxLgrw.js → heartbeat-settings-Bk80-E3b.js} +1 -1
  44. package/dist/gateway/static/root/assets/home-page-DKo5JiMR.js +1 -0
  45. package/dist/gateway/static/root/assets/{image-generation-api-dj9TNEn2.js → image-generation-api-D1qlQA-A.js} +1 -1
  46. package/dist/gateway/static/root/assets/index-B0WJL9N1.js +71 -0
  47. package/dist/gateway/static/root/assets/index-Dbh5SXyV.css +2 -0
  48. package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-BEnuEPD3.js → keyboard-shortcuts-settings-BEwvd8ZU.js} +1 -1
  49. package/dist/gateway/static/root/assets/local-app-workbench-page--eJ5rmNj.js +2 -0
  50. package/dist/gateway/static/root/assets/{local-apps-page-DXQtppWq.js → local-apps-page-CgkY9E-r.js} +1 -1
  51. package/dist/gateway/static/root/assets/{locale-store-DVzTJSj2.js → locale-store-CMZljTJx.js} +1 -1
  52. package/dist/gateway/static/root/assets/logs-page-Z49Td0J9.js +2 -0
  53. package/dist/gateway/static/root/assets/{management-settings-DIpBMWrA.js → management-settings-Dv8NSJKt.js} +1 -1
  54. package/dist/gateway/static/root/assets/{markdown-split-BFHyGwNF.js → markdown-split-Cm0RBB-t.js} +1 -1
  55. package/dist/gateway/static/root/assets/{markdown-view-DR3yVwtV.js → markdown-view-PPCLt7fu.js} +3 -3
  56. package/dist/gateway/static/root/assets/{media-plugins-BjjMxC5_.js → media-plugins-Bcr5sU1f.js} +1 -1
  57. package/dist/gateway/static/root/assets/messages-CTSgFlE4.js +3 -0
  58. package/dist/gateway/static/root/assets/mobile-pairing-wizard-kKDiXofY.js +1 -0
  59. package/dist/gateway/static/root/assets/models-hub-cache-ZrbGRiGY.js +1 -0
  60. package/dist/gateway/static/root/assets/{notes-page-BbvtelJa.js → notes-page-CgsaRaGi.js} +1 -1
  61. package/dist/gateway/static/root/assets/notes-workbench-C1DEE09k.js +4 -0
  62. package/dist/gateway/static/root/assets/{oauth-api-BB-VYJ5j.js → oauth-api-4VeMbkTJ.js} +1 -1
  63. package/dist/gateway/static/root/assets/popover-select-C-Hj-nXR.js +1 -0
  64. package/dist/gateway/static/root/assets/{product-delivery-dUJgmBQZ.js → product-delivery-CV4pDOtG.js} +1 -1
  65. package/dist/gateway/static/root/assets/product-open-page-BU0HiZtv.js +1 -0
  66. package/dist/gateway/static/root/assets/project-detail-page-isRapnp5.js +1 -0
  67. package/dist/gateway/static/root/assets/projects-page-zvsjg0mi.js +1 -0
  68. package/dist/gateway/static/root/assets/{registry-api-DXsR8oGN.js → registry-api-CWOtPFrE.js} +1 -1
  69. package/dist/gateway/static/root/assets/remote-access-hub-C9TGZ9Hc.js +1 -0
  70. package/dist/gateway/static/root/assets/{runtime-tools-settings-panel-DoEfLjPB.js → runtime-tools-settings-panel-2zm9edMA.js} +2 -2
  71. package/dist/gateway/static/root/assets/{schema-form-BsqpbBDv.js → schema-form-54A5gzkN.js} +1 -1
  72. package/dist/gateway/static/root/assets/{schemas-zIBW3wiV.js → schemas-BHS7bo06.js} +1 -1
  73. package/dist/gateway/static/root/assets/sessions-page-BP8RyiUn.js +1 -0
  74. package/dist/gateway/static/root/assets/settings-advanced-gate-D4EMxWAZ.js +1 -0
  75. package/dist/gateway/static/root/assets/{settings-page-CE7ZcCTK.js → settings-page-DzDhoyxv.js} +1 -1
  76. package/dist/gateway/static/root/assets/{setup-status-panel-CGlne9i0.js → setup-status-panel-uDicHU1w.js} +1 -1
  77. package/dist/gateway/static/root/assets/{share-preview-page-Bn0qMX8V.js → share-preview-page-lOmLCWFS.js} +1 -1
  78. package/dist/gateway/static/root/assets/shares-settings-T4Yvouvv.js +1 -0
  79. package/dist/gateway/static/root/assets/skill-reload-api-DVb7nrXz.js +1 -0
  80. package/dist/gateway/static/root/assets/{skills-page-dRkeYh5P.js → skills-page-CnyNH3To.js} +1 -1
  81. package/dist/gateway/static/root/assets/skills-page.utils-CgDtf2qs.js +1 -0
  82. package/dist/gateway/static/root/assets/{system-settings-panel-C0ZCuCM4.js → system-settings-panel-C8yWfwtR.js} +1 -1
  83. package/dist/gateway/static/root/assets/task-detail-page-Tzfjlbf3.js +1 -0
  84. package/dist/gateway/static/root/assets/{theme-store-Cth-eChE.js → theme-store-uxUwr10D.js} +1 -1
  85. package/dist/gateway/static/root/assets/tunnel-api-Bvg679no.js +1 -0
  86. package/dist/gateway/static/root/assets/{use-autosave-PSV89QuQ.js → use-autosave-D88VGoyG.js} +1 -1
  87. package/dist/gateway/static/root/assets/user-context-page-RijPtyfO.js +1 -0
  88. package/dist/gateway/static/root/assets/{voice-api-key-field-DXWdJ8cR.js → voice-api-key-field-CBHLsMcc.js} +1 -1
  89. package/dist/gateway/static/root/assets/voice-config-api-MqyI6cgq.js +1 -0
  90. package/dist/gateway/static/root/assets/work-discovery-overlay-GGe2TQ98.js +1 -0
  91. package/dist/gateway/static/root/assets/workflow-run-setup-panel-C0layUE9.js +3 -0
  92. package/dist/gateway/static/root/assets/workflows-page-DQXIzBAc.js +5 -0
  93. package/dist/gateway/static/root/index.html +21 -22
  94. package/dist/package.js +1 -1
  95. package/dist/packages/realtime-protocol/src/voice-audio.js +20 -0
  96. package/dist/packages/realtime-protocol/src/voice.js +208 -0
  97. package/dist/src/agent/embedded/run-for-session.d.ts +1 -0
  98. package/dist/src/agent/embedded/run-for-session.js +2 -1
  99. package/dist/src/agent/inbound/turn-dispatcher.d.ts +1 -0
  100. package/dist/src/agent/inbound/turn-dispatcher.js +2 -1
  101. package/dist/src/agent/prompt/voice-presentation.d.ts +2 -0
  102. package/dist/src/agent/prompt/voice-presentation.js +12 -0
  103. package/dist/src/agent/service/direct-turn-helpers.d.ts +1 -0
  104. package/dist/src/agent/service/direct-turn-helpers.js +1 -0
  105. package/dist/src/agent/service/process-direct-streaming.d.ts +1 -0
  106. package/dist/src/agent/service/process-direct-streaming.js +2 -1
  107. package/dist/src/agent/session/session-config-service.js +4 -2
  108. package/dist/src/automations/draft/automation-draft-service.js +1 -1
  109. package/dist/src/config/models-json.d.ts +8 -8
  110. package/dist/src/config/schema.d.ts +60 -0
  111. package/dist/src/config/schema.js +31 -1
  112. package/dist/src/files/file-service.d.ts +1 -0
  113. package/dist/src/files/file-service.js +4 -0
  114. package/dist/src/gateway/chat-stream/thinking-delta-coalescer.js +8 -3
  115. package/dist/src/gateway/hono/lib/config-payload.d.ts +1 -11
  116. package/dist/src/gateway/hono/lib/config-payload.js +2 -2
  117. package/dist/src/gateway/hono/lib/safe-voice-config.d.ts +14 -0
  118. package/dist/src/gateway/hono/lib/safe-voice-config.js +29 -1
  119. package/dist/src/gateway/hono/routes/config-patch/misc.js +2 -2
  120. package/dist/src/gateway/hono/routes/files.js +7 -0
  121. package/dist/src/gateway/hono/routes/lazy-fallback.js +18 -4
  122. package/dist/src/gateway/hono/routes/session-input-handler.js +14 -0
  123. package/dist/src/gateway/hono/routes/sessions.js +4 -1
  124. package/dist/src/gateway/hono/routes/voice.js +139 -2
  125. package/dist/src/gateway/server.js +1 -0
  126. package/dist/src/gateway/service/agent-runner.d.ts +1 -0
  127. package/dist/src/gateway/service/agent-runner.js +1 -6
  128. package/dist/src/gateway/service/run-gateway-agent.d.ts +1 -0
  129. package/dist/src/gateway/service/run-gateway-agent.js +19 -1
  130. package/dist/src/gateway/service.d.ts +2 -0
  131. package/dist/src/gateway/service.js +73 -0
  132. package/dist/src/media-understanding/types.d.ts +61 -0
  133. package/dist/src/session/client-history.js +12 -0
  134. package/dist/src/session/manager.d.ts +1 -0
  135. package/dist/src/session/session-context-for-llm.js +8 -0
  136. package/dist/src/session/store.d.ts +1 -0
  137. package/dist/src/session/store.js +1 -0
  138. package/dist/src/session/stored-rows-to-file-entries.js +5 -1
  139. package/dist/src/session/voice-transcript.d.ts +9 -0
  140. package/dist/src/session/voice-transcript.js +45 -0
  141. package/dist/src/storage/sqlite/config-repository.js +9 -0
  142. package/dist/src/storage/sqlite/remote-context-repository.d.ts +3 -0
  143. package/dist/src/storage/sqlite/remote-context-repository.js +40 -0
  144. package/dist/src/storage/sqlite/session-repository.js +13 -0
  145. package/dist/src/storage/sqlite/user-context-repository.d.ts +3 -1
  146. package/dist/src/storage/sqlite/user-context-repository.js +50 -4
  147. package/dist/src/tui/tui.js +2 -1
  148. package/dist/src/user-context/automatic-context.d.ts +17 -0
  149. package/dist/src/user-context/automatic-context.js +85 -0
  150. package/dist/src/user-context/changes.d.ts +7 -0
  151. package/dist/src/user-context/changes.js +28 -0
  152. package/dist/src/user-context/planner.js +1 -24
  153. package/dist/src/user-context/retriever.js +10 -11
  154. package/dist/src/user-context/selection-policy.d.ts +20 -0
  155. package/dist/src/user-context/selection-policy.js +33 -0
  156. package/dist/src/user-context/sources/index.js +2 -2
  157. package/dist/src/user-context/sources/repository.d.ts +2 -1
  158. package/dist/src/user-context/sources/repository.js +26 -5
  159. package/dist/src/voice/dashscope/streaming-stt-session.d.ts +2 -0
  160. package/dist/src/voice/dashscope/streaming-stt-session.js +249 -0
  161. package/dist/src/voice/dashscope/streaming-tts-stream.d.ts +12 -0
  162. package/dist/src/voice/dashscope/streaming-tts-stream.js +153 -0
  163. package/dist/src/voice/realtime/agentEngine.d.ts +10 -0
  164. package/dist/src/voice/realtime/agentEngine.js +403 -0
  165. package/dist/src/voice/realtime/audio-playback-window.d.ts +9 -0
  166. package/dist/src/voice/realtime/audio-playback-window.js +49 -0
  167. package/dist/src/voice/realtime/conversation-context.d.ts +11 -0
  168. package/dist/src/voice/realtime/conversation-context.js +76 -0
  169. package/dist/src/voice/realtime/engine.d.ts +13 -0
  170. package/dist/src/voice/realtime/engine.js +1 -0
  171. package/dist/src/voice/realtime/memory-context.d.ts +17 -0
  172. package/dist/src/voice/realtime/memory-context.js +100 -0
  173. package/dist/src/voice/realtime/omniEngine.d.ts +18 -0
  174. package/dist/src/voice/realtime/omniEngine.js +443 -0
  175. package/dist/src/voice/realtime/omniRoute.d.ts +10 -0
  176. package/dist/src/voice/realtime/omniRoute.js +31 -0
  177. package/dist/src/voice/realtime/runtime.d.ts +99 -0
  178. package/dist/src/voice/realtime/runtime.js +622 -0
  179. package/dist/src/voice/realtime/speakable-segmenter.d.ts +10 -0
  180. package/dist/src/voice/realtime/speakable-segmenter.js +87 -0
  181. package/dist/src/voice/stt/list-providers.js +2 -1
  182. package/dist/src/voice/stt/providers/alibaba-transcription.js +13 -1
  183. package/dist/src/voice/stt/providers/xopc-cloud-transcription.js +23 -0
  184. package/dist/src/voice/tts/factory.js +1 -0
  185. package/dist/src/voice/tts/openai-compatible-speech.js +3 -1
  186. package/dist/src/voice/tts/providers/alibaba-speech.d.ts +1 -5
  187. package/dist/src/voice/tts/providers/alibaba-speech.js +25 -8
  188. package/dist/src/voice/tts/providers/edge-speech.js +21 -22
  189. package/dist/src/voice/tts/providers/minimax-speech.js +6 -3
  190. package/dist/src/voice/tts/providers/xopc-cloud-speech.js +26 -1
  191. package/dist/src/voice/tts/speak-core.d.ts +6 -2
  192. package/dist/src/voice/tts/speak-core.js +46 -34
  193. package/dist/src/voice/tts/speech-provider-types.d.ts +1 -0
  194. package/package.json +5 -5
  195. package/dist/gateway/static/root/assets/Combination-14nmIgxH.js +0 -41
  196. package/dist/gateway/static/root/assets/agent-defaults-settings-panel-Cf7U2aUi.js +0 -1
  197. package/dist/gateway/static/root/assets/agents-Ce9oOnwE.js +0 -1
  198. package/dist/gateway/static/root/assets/app-chrome-BeB4KgOf.js +0 -1
  199. package/dist/gateway/static/root/assets/app-management-settings-panel-CACOOS-a.js +0 -1
  200. package/dist/gateway/static/root/assets/apps-page-BaTFOCmR.js +0 -1
  201. package/dist/gateway/static/root/assets/automations-workspace-DK6EreCr.js +0 -6
  202. package/dist/gateway/static/root/assets/block-editor-DgAs5aJc.js +0 -184
  203. package/dist/gateway/static/root/assets/browser-settings-page-CHStw5UW.js +0 -8
  204. package/dist/gateway/static/root/assets/capabilities-settings-panel-JGH6Kfkr.js +0 -7
  205. package/dist/gateway/static/root/assets/channels-settings-YkUaaWkY.js +0 -1
  206. package/dist/gateway/static/root/assets/connectors-page-BI0FG3gA.js +0 -2
  207. package/dist/gateway/static/root/assets/dist-BPoKqzeH.js +0 -1
  208. package/dist/gateway/static/root/assets/dist-DqPZM2MH.js +0 -1
  209. package/dist/gateway/static/root/assets/home-page--9fKq0mL.js +0 -1
  210. package/dist/gateway/static/root/assets/index-D499B1qS.css +0 -2
  211. package/dist/gateway/static/root/assets/index-J3FsIvTs.js +0 -70
  212. package/dist/gateway/static/root/assets/local-app-workbench-page-FqG00zS1.js +0 -2
  213. package/dist/gateway/static/root/assets/logs-page-c6CfZ8PA.js +0 -2
  214. package/dist/gateway/static/root/assets/messages-_tYhRAHD.js +0 -3
  215. package/dist/gateway/static/root/assets/mobile-pairing-wizard-CHnXZTwb.js +0 -1
  216. package/dist/gateway/static/root/assets/models-hub-cache-DiXjKuuY.js +0 -1
  217. package/dist/gateway/static/root/assets/notes-workbench-DIR37b-K.js +0 -4
  218. package/dist/gateway/static/root/assets/popover-select-DrILF6mR.js +0 -1
  219. package/dist/gateway/static/root/assets/product-open-page-CRm9Q66h.js +0 -1
  220. package/dist/gateway/static/root/assets/project-detail-page-DHiLTiRW.js +0 -1
  221. package/dist/gateway/static/root/assets/projects-page-God7NCcI.js +0 -1
  222. package/dist/gateway/static/root/assets/remote-access-hub-YpF0-mx2.js +0 -1
  223. package/dist/gateway/static/root/assets/sessions-page-CP8O1TxR.js +0 -1
  224. package/dist/gateway/static/root/assets/settings-advanced-gate-DzdbK3j9.js +0 -1
  225. package/dist/gateway/static/root/assets/shares-settings-B7NeVl4g.js +0 -1
  226. package/dist/gateway/static/root/assets/skill-reload-api-DDTmi4a7.js +0 -1
  227. package/dist/gateway/static/root/assets/skills-page.utils--q8p7MAn.js +0 -1
  228. package/dist/gateway/static/root/assets/task-detail-page-yiMzii2b.js +0 -1
  229. package/dist/gateway/static/root/assets/tunnel-api-CC3jOB4n.js +0 -1
  230. package/dist/gateway/static/root/assets/user-context-page-Vtwg7fQc.js +0 -1
  231. package/dist/gateway/static/root/assets/voice-config-api-BDoeXgww.js +0 -1
  232. package/dist/gateway/static/root/assets/work-discovery-overlay-BV_Jj5iD.js +0 -1
  233. package/dist/gateway/static/root/assets/workflow-run-setup-panel-DNHbWGPq.js +0 -3
  234. package/dist/gateway/static/root/assets/workflows-page-BkFIbMrz.js +0 -5
@@ -13,7 +13,7 @@ import { GENERIC_MASKED_SECRET, maskSecretLength } from "./mask-secret-length.js
13
13
  import { safeToolsWebForGet } from "../../config-tools-web.js";
14
14
  import { maskTunnelSecretForWeb } from "../../../tunnel/env.js";
15
15
  import { buildSafeProvidersConfigForWeb } from "./safe-providers-config.js";
16
- import { maskSttConfigForWeb, maskTtsConfigForWeb } from "./safe-voice-config.js";
16
+ import { maskRealtimeVoiceConfigForWeb, maskSttConfigForWeb, maskTtsConfigForWeb } from "./safe-voice-config.js";
17
17
  //#region src/gateway/hono/lib/config-payload.ts
18
18
  init_agent_scope();
19
19
  init_channel_catalog_service();
@@ -195,7 +195,7 @@ async function buildSafeWebConfigPayload(service, options = {}) {
195
195
  update: { ...resolveUpdateConfigForWeb(config) },
196
196
  stt: maskSttConfigForWeb(config.tools?.media?.audio),
197
197
  tts: maskTtsConfigForWeb(config.messages?.tts),
198
- voice: config.voice,
198
+ voice: maskRealtimeVoiceConfigForWeb(config.voice),
199
199
  tools: safeToolsWebForGet(config),
200
200
  bindings: Array.isArray(config.bindings) ? config.bindings : [],
201
201
  mcp: buildSafeMcpConfigForWeb(config)
@@ -1,3 +1,17 @@
1
+ export declare function maskRealtimeVoiceConfigForWeb(voice: {
2
+ realtime?: {
3
+ omni?: {
4
+ apiKey?: string;
5
+ };
6
+ };
7
+ } | undefined): unknown;
8
+ export declare function mergeRealtimeVoiceConfigPatch(previous: {
9
+ realtime?: {
10
+ omni?: {
11
+ apiKey?: string;
12
+ };
13
+ };
14
+ } | undefined, incoming: unknown): unknown;
1
15
  /** Mask STT api keys for GET `/api/config`. */
2
16
  export declare function maskSttConfigForWeb(stt: unknown): unknown;
3
17
  /** Mask TTS api keys for GET `/api/config`. */
@@ -1,6 +1,34 @@
1
1
  import { maskSecretLength } from "./mask-secret-length.js";
2
2
  import { isMaskedApiKey } from "../../config-tools-web.js";
3
3
  //#region src/gateway/hono/lib/safe-voice-config.ts
4
+ function maskRealtimeVoiceConfigForWeb(voice) {
5
+ if (!voice?.realtime?.omni) return voice;
6
+ return {
7
+ ...voice,
8
+ realtime: {
9
+ ...voice.realtime,
10
+ omni: maskProviderSlice(voice.realtime.omni)
11
+ }
12
+ };
13
+ }
14
+ function mergeRealtimeVoiceConfigPatch(previous, incoming) {
15
+ if (!incoming || typeof incoming !== "object" || Array.isArray(incoming)) return incoming;
16
+ const patch = incoming;
17
+ const realtime = patch.realtime;
18
+ const omni = realtime?.omni;
19
+ if (!omni || typeof omni !== "object" || Array.isArray(omni)) return incoming;
20
+ const apiKey = omni.apiKey === "" ? void 0 : mergeApiKeyField(omni.apiKey, previous?.realtime?.omni?.apiKey);
21
+ return {
22
+ ...patch,
23
+ realtime: {
24
+ ...realtime,
25
+ omni: {
26
+ ...omni,
27
+ ...omni.apiKey !== void 0 ? { apiKey } : {}
28
+ }
29
+ }
30
+ };
31
+ }
4
32
  function maskProviderSlice(slice) {
5
33
  const next = { ...slice };
6
34
  if (typeof next.apiKey === "string" && next.apiKey.trim()) next.apiKey = maskSecretLength(next.apiKey);
@@ -64,4 +92,4 @@ function mergeTtsConfigPatch(previous, incoming) {
64
92
  return mergeVoiceConfigPatch(previous, incoming);
65
93
  }
66
94
  //#endregion
67
- export { maskSttConfigForWeb, maskTtsConfigForWeb, mergeSttConfigPatch, mergeTtsConfigPatch };
95
+ export { maskRealtimeVoiceConfigForWeb, maskSttConfigForWeb, maskTtsConfigForWeb, mergeRealtimeVoiceConfigPatch, mergeSttConfigPatch, mergeTtsConfigPatch };
@@ -9,7 +9,7 @@ import { isMaskedSecretPatchValue } from "../../lib/mask-secret-length.js";
9
9
  import { applyToolsWebPatch } from "../../../config-tools-web.js";
10
10
  import { mergeTunnelConfigPatch } from "../../../../tunnel/tunnel-config.js";
11
11
  import { assertGatewayRuntimeConfig } from "../../../runtime-config.js";
12
- import { mergeSttConfigPatch, mergeTtsConfigPatch } from "../../lib/safe-voice-config.js";
12
+ import { mergeRealtimeVoiceConfigPatch, mergeSttConfigPatch, mergeTtsConfigPatch } from "../../lib/safe-voice-config.js";
13
13
  import { PATCH_OK, patchError } from "./result.js";
14
14
  //#region src/gateway/hono/routes/config-patch/misc.ts
15
15
  init_schema();
@@ -137,7 +137,7 @@ async function applyMiscPatch(config, body) {
137
137
  config.messages.tts = mergeTtsConfigPatch(config.messages.tts, body.tts);
138
138
  }
139
139
  if (body.voice !== void 0) {
140
- const parsed = VoiceConfigSchema.safeParse(body.voice);
140
+ const parsed = VoiceConfigSchema.safeParse(mergeRealtimeVoiceConfigPatch(config.voice, body.voice));
141
141
  if (!parsed.success) return patchError(parsed.error.issues.map((i) => i.message).join("; "));
142
142
  config.voice = parsed.data;
143
143
  }
@@ -86,6 +86,13 @@ function registerFilesRoutes(authenticated, deps) {
86
86
  return errorResponse(c, error);
87
87
  }
88
88
  });
89
+ authenticated.get("/api/files/spaces/:id/root", async (c) => {
90
+ try {
91
+ return c.json({ resource: await files.rootResource(c.req.param("id")) });
92
+ } catch (error) {
93
+ return errorResponse(c, error);
94
+ }
95
+ });
89
96
  authenticated.get("/api/files/recent", async (c) => {
90
97
  try {
91
98
  const limit = Math.min(100, Math.max(1, Number(c.req.query("limit")) || 50));
@@ -3,6 +3,16 @@ import { APP_LAZY_ROUTE_BUNDLES, AUTHENTICATED_LAZY_ROUTE_BUNDLES, findAuthentic
3
3
  import { Hono } from "hono";
4
4
  //#region src/gateway/hono/routes/lazy-fallback.ts
5
5
  const log = createGatewayRouteLogger("LazyRoutes");
6
+ const FORWARDED_VARIABLES = Symbol("gateway.forwardedVariables");
7
+ function createSubApp() {
8
+ const sub = new Hono();
9
+ sub.use(async (c, next) => {
10
+ const variables = c.env?.[FORWARDED_VARIABLES];
11
+ for (const [key, value] of Object.entries(variables ?? {})) c.set(key, value);
12
+ await next();
13
+ });
14
+ return sub;
15
+ }
6
16
  const authenticatedSubApps = /* @__PURE__ */ new Map();
7
17
  const appSubApps = /* @__PURE__ */ new Map();
8
18
  const authenticatedLoadPromises = /* @__PURE__ */ new Map();
@@ -28,7 +38,7 @@ async function ensureAuthenticatedLazyBundle(bundleId, deps) {
28
38
  if (!bundle) return null;
29
39
  pending = (async () => {
30
40
  const mod = await bundle.load();
31
- const sub = new Hono();
41
+ const sub = createSubApp();
32
42
  mod.register(sub, deps);
33
43
  authenticatedSubApps.set(bundleId, sub);
34
44
  authenticatedLoadPromises.delete(bundleId);
@@ -47,7 +57,7 @@ async function ensureAppLazyBundle(bundleId, params) {
47
57
  if (!bundle) return null;
48
58
  pending = (async () => {
49
59
  const mod = await bundle.load();
50
- const sub = new Hono();
60
+ const sub = createSubApp();
51
61
  if (mod.registerOnApp) mod.registerOnApp(sub, params.service);
52
62
  appSubApps.set(bundleId, sub);
53
63
  appLoadPromises.delete(bundleId);
@@ -58,10 +68,14 @@ async function ensureAppLazyBundle(bundleId, params) {
58
68
  return pending;
59
69
  }
60
70
  async function forwardToSubApp(c, sub) {
71
+ const env = {
72
+ ...c.env,
73
+ [FORWARDED_VARIABLES]: { ...c.var }
74
+ };
61
75
  try {
62
- return await sub.fetch(c.req.raw, c.env, c.executionCtx);
76
+ return await sub.fetch(c.req.raw, env, c.executionCtx);
63
77
  } catch (error) {
64
- if (error instanceof Error && error.message.includes("ExecutionContext")) return sub.fetch(c.req.raw, c.env);
78
+ if (error instanceof Error && error.message.includes("ExecutionContext")) return sub.fetch(c.req.raw, env);
65
79
  logRouteError(log, c, error, "gateway.route.lazy_forward");
66
80
  throw error;
67
81
  }
@@ -73,6 +73,13 @@ async function submitSessionInput(c, deps, sessionKey) {
73
73
  }
74
74
  }, 400);
75
75
  return withModelConfigLock(sessionKey, async () => {
76
+ if (deps.service.voiceRealtime?.hasConversation(sessionKey)) return c.json({
77
+ ok: false,
78
+ error: {
79
+ code: "SESSION_BUSY",
80
+ message: "End the voice call before sending text"
81
+ }
82
+ }, 409);
76
83
  const selection = body.configVersion !== void 0 ? await deps.service.sessions.getAgentConfig(sessionKey) : void 0;
77
84
  if (selection) {
78
85
  if (!Number.isSafeInteger(body.configVersion) || selection.configVersion !== body.configVersion || !selection.fixedModel) return c.json({
@@ -181,6 +188,13 @@ async function replaceLatestSessionTurn(c, deps, sessionKey, targetTurnId) {
181
188
  }
182
189
  }, 401);
183
190
  return withModelConfigLock(sessionKey, async () => {
191
+ if (deps.service.voiceRealtime?.hasConversation(sessionKey)) return c.json({
192
+ ok: false,
193
+ error: {
194
+ code: "SESSION_BUSY",
195
+ message: "End the voice call before editing a turn"
196
+ }
197
+ }, 409);
184
198
  const selection = body.configVersion !== void 0 ? await deps.service.sessions.getAgentConfig(sessionKey) : void 0;
185
199
  if (selection) {
186
200
  if (!Number.isSafeInteger(body.configVersion) || selection.configVersion !== body.configVersion || !selection.fixedModel) return c.json({
@@ -3,13 +3,13 @@ import { resolveProjectAgentId } from "../../../projects/project-agent.js";
3
3
  import "../../../projects/index.js";
4
4
  import { evictEmbeddedSessionRunner } from "../../../agent/embedded/session-runner.js";
5
5
  import { messagesToClientHistory } from "../../../session/client-history.js";
6
- import { SessionEnvironmentService } from "../../../execution-environments/session-environment-service.js";
7
6
  import { deleteMediaUrisNoLongerReferenced } from "../../../media/session-references.js";
8
7
  import { getGatewayPrincipal } from "../../security/gateway-principal.js";
9
8
  import { createGatewayRouteLogger, logRouteError } from "../lib/route-logger.js";
10
9
  import { patchChatModelConfig } from "./chat-model-config.js";
11
10
  import { getSessionContextSummary } from "../../session-context-summary.js";
12
11
  import { respondStartupUnavailable } from "../lib/startup-unavailable.js";
12
+ import { SessionEnvironmentService } from "../../../execution-environments/session-environment-service.js";
13
13
  import { randomUUID } from "node:crypto";
14
14
  //#region src/gateway/hono/routes/sessions.ts
15
15
  init_session_key();
@@ -785,6 +785,7 @@ function registerSessionsRoutes(authenticated, deps) {
785
785
  });
786
786
  authenticated.delete("/api/sessions/:key/messages", async (c) => {
787
787
  const key = c.req.param("key");
788
+ if (service.voiceRealtime?.hasConversation(key)) return c.json({ error: "End the voice call before editing its history" }, 409);
788
789
  const body = await c.req.json().catch(() => ({}));
789
790
  const userRoundIndex = typeof body.userRoundIndex === "number" ? body.userRoundIndex : void 0;
790
791
  if (userRoundIndex === void 0 || !Number.isInteger(userRoundIndex) || userRoundIndex < 0) return c.json({ error: "userRoundIndex must be a non-negative integer" }, 400);
@@ -805,6 +806,7 @@ function registerSessionsRoutes(authenticated, deps) {
805
806
  const blocked = ensureGatewayReadyForSessions(c, service, "sessions.reset");
806
807
  if (blocked) return blocked;
807
808
  const key = c.req.param("key");
809
+ if (service.voiceRealtime?.hasConversation(key)) return c.json({ error: "End the voice call before resetting the session" }, 409);
808
810
  const result = await service.sessions.reset(key);
809
811
  if (result.ok === false) {
810
812
  const status = result.error === "Session not found" ? 404 : 400;
@@ -824,6 +826,7 @@ function registerSessionsRoutes(authenticated, deps) {
824
826
  });
825
827
  authenticated.delete("/api/sessions/:key", async (c) => {
826
828
  const key = c.req.param("key");
829
+ if (service.voiceRealtime?.hasConversation(key)) return c.json({ error: "End the voice call before deleting the session" }, 409);
827
830
  if (environments.get(key) && service.getActiveWebchatRunId(key)) return c.json({
828
831
  ok: false,
829
832
  error: "Stop the active session run before deleting its environment"
@@ -2,7 +2,7 @@ import { getDefaultModelSync, init_providers, resolveModel } from "../../../prov
2
2
  import { completeWithResolvedCredentials } from "../../../providers/model-call.js";
3
3
  import { resolveTtsProviderConfigSlice } from "../../../voice/tts/config-slice.js";
4
4
  import { isTTSAvailable, resolveSpeechProvider } from "../../../voice/tts/factory.js";
5
- import { speak } from "../../../voice/tts/speak-core.js";
5
+ import { speak, speakStream } from "../../../voice/tts/speak-core.js";
6
6
  import { mergeTtsConfigFromAppConfig } from "../../../voice/tts/merge-config.js";
7
7
  import { getLocalVoiceRuntimeClient } from "../../../voice/local/runtime-client.js";
8
8
  import { getAudioDecoderStatus } from "../../../voice/audio/normalize.js";
@@ -13,6 +13,11 @@ import { mergeSttConfigFromAppConfig } from "../../../voice/stt/config.js";
13
13
  import "../../../voice/stt/index.js";
14
14
  import { listSttProvidersForApi } from "../../../voice/stt/list-providers.js";
15
15
  import "../../../voice/tts/index.js";
16
+ import { withModelConfigLock } from "../../../session/model-config-lock.js";
17
+ import { createVoiceSessionRequestSchema } from "../../../../packages/realtime-protocol/src/voice.js";
18
+ import { resolveOmniRoute } from "../../../voice/realtime/omniRoute.js";
19
+ import { VoiceSessionCreationError, resolveStreamingStt, resolveStreamingTts } from "../../../voice/realtime/runtime.js";
20
+ import { getGatewayPrincipal } from "../../security/gateway-principal.js";
16
21
  import { createGatewayRouteLogger } from "../lib/route-logger.js";
17
22
  import { listLocalVoiceModelStatuses, removeLocalVoiceModel, startLocalVoiceModelInstall } from "../../../voice/local/model-manager.js";
18
23
  import { listTtsProvidersForApi } from "../../../voice/tts/list-providers.js";
@@ -107,6 +112,134 @@ async function refineTranscript(raw, config, signal) {
107
112
  }
108
113
  function registerVoiceRoutes(authenticated, deps) {
109
114
  const { service, strictRateLimitMiddleware } = deps;
115
+ authenticated.get("/api/voice/realtime/status", async (c) => {
116
+ const config = service.currentConfig;
117
+ const stt = resolveStreamingStt(config);
118
+ const tts = resolveStreamingTts(config);
119
+ const omni = await resolveOmniRoute(config).catch(() => null);
120
+ const enabled = config.voice?.realtime?.enabled === true;
121
+ const availability = (configured) => ({
122
+ available: enabled && configured,
123
+ ...!enabled ? { reasonCode: "VOICE_DISABLED" } : !configured ? { reasonCode: "PROVIDER_UNAVAILABLE" } : {}
124
+ });
125
+ return c.json({
126
+ ok: true,
127
+ payload: {
128
+ enabled,
129
+ capabilities: {
130
+ dictation: availability(Boolean(stt)),
131
+ agent: availability(Boolean(stt && tts)),
132
+ omni: availability(Boolean(omni)),
133
+ languages: ["zh", "en"],
134
+ bargeIn: config.voice?.realtime?.bargeIn ?? true
135
+ },
136
+ defaultEngine: config.voice?.realtime?.defaultEngine ?? "agent",
137
+ omni: omni?.route ?? null,
138
+ stt: stt?.route ?? null,
139
+ tts: tts ? {
140
+ ...tts.route,
141
+ voice: tts.config.providers?.[tts.route.provider]?.voice ?? tts.provider.providerConfig.voice
142
+ } : null
143
+ }
144
+ });
145
+ });
146
+ authenticated.post("/api/voice/realtime/preview", strictRateLimitMiddleware, async (c) => {
147
+ const config = service.currentConfig;
148
+ const route = resolveStreamingTts(config);
149
+ if (!route) return c.json({
150
+ ok: false,
151
+ error: { message: "Realtime voice output is not configured" }
152
+ }, 503);
153
+ const controller = new AbortController();
154
+ const signal = AbortSignal.any([
155
+ c.req.raw.signal,
156
+ controller.signal,
157
+ AbortSignal.timeout(2e4)
158
+ ]);
159
+ let result;
160
+ let reader;
161
+ try {
162
+ result = await speakStream(config.voice?.language === "en" ? "Hello, I am your assistant. You can talk to me naturally." : "你好,我是你的助手。现在可以和我自然对话了。", route.config, {
163
+ signal,
164
+ appConfig: config,
165
+ allowFallback: false,
166
+ parseDirectives: false
167
+ });
168
+ if (result.outputFormat !== "pcm") throw new Error("Realtime preview requires PCM audio");
169
+ reader = result.audioStream.getReader();
170
+ const chunks = [];
171
+ let size = 0;
172
+ while (true) {
173
+ signal.throwIfAborted();
174
+ const { value, done } = await reader.read();
175
+ if (done) break;
176
+ size += value.byteLength;
177
+ if (size > 96e4) throw new Error("Realtime preview audio exceeds the limit");
178
+ chunks.push(value);
179
+ }
180
+ if (size === 0 || size % 2 !== 0) throw new Error("Realtime preview returned invalid audio");
181
+ return c.json({
182
+ ok: true,
183
+ payload: {
184
+ audio: Buffer.concat(chunks).toString("base64"),
185
+ sampleRate: 24e3
186
+ }
187
+ });
188
+ } catch (error) {
189
+ log.warn({
190
+ err: error,
191
+ provider: route.route.provider
192
+ }, "Realtime voice preview failed");
193
+ return c.json({
194
+ ok: false,
195
+ error: { message: "Voice preview failed. Check the provider credentials and try again." }
196
+ }, 502);
197
+ } finally {
198
+ controller.abort();
199
+ await reader?.cancel().catch(() => void 0);
200
+ reader?.releaseLock();
201
+ await result?.release();
202
+ }
203
+ });
204
+ for (const action of ["preflight", "sessions"]) authenticated.post(`/api/voice/realtime/${action}`, strictRateLimitMiddleware, async (c) => {
205
+ const parsed = createVoiceSessionRequestSchema.safeParse(await c.req.json().catch(() => null));
206
+ if (!parsed.success) return c.json({
207
+ ok: false,
208
+ error: {
209
+ code: "INVALID_REQUEST",
210
+ message: "Invalid realtime voice session request"
211
+ }
212
+ }, 400);
213
+ try {
214
+ if (action === "preflight") {
215
+ await service.voiceRealtime.preflight(parsed.data);
216
+ return c.json({ ok: true });
217
+ }
218
+ const principal = getGatewayPrincipal(c);
219
+ const create = () => service.voiceRealtime.createSession(parsed.data, principal.principalId);
220
+ const payload = parsed.data.sessionKey ? await withModelConfigLock(parsed.data.sessionKey, create) : await create();
221
+ return c.json({
222
+ ok: true,
223
+ payload
224
+ });
225
+ } catch (error) {
226
+ const message = error instanceof Error ? error.message : "Realtime voice is unavailable";
227
+ if (error instanceof VoiceSessionCreationError) return c.json({
228
+ ok: false,
229
+ error: {
230
+ code: error.code,
231
+ message
232
+ }
233
+ }, error.status);
234
+ return c.json({
235
+ ok: false,
236
+ error: {
237
+ code: "PROVIDER_UNAVAILABLE",
238
+ message
239
+ }
240
+ }, 503);
241
+ }
242
+ });
110
243
  authenticated.post("/api/voice/language", strictRateLimitMiddleware, async (c) => {
111
244
  let body = {};
112
245
  try {
@@ -153,7 +286,11 @@ function registerVoiceRoutes(authenticated, deps) {
153
286
  error: { message: "provider and model are required" }
154
287
  }, 400);
155
288
  const config = service.currentConfig;
156
- const baseConfig = mergeTtsConfigFromAppConfig(config.messages?.tts);
289
+ const baseConfig = c.req.query("purpose") === "realtime" ? resolveStreamingTts(config)?.config : mergeTtsConfigFromAppConfig(config.messages?.tts);
290
+ if (!baseConfig) return c.json({
291
+ ok: true,
292
+ payload: { voices: [] }
293
+ });
157
294
  const resolved = resolveSpeechProvider(provider, {
158
295
  ...baseConfig,
159
296
  provider,
@@ -68,6 +68,7 @@ var GatewayServer = class {
68
68
  });
69
69
  inner.on("upgrade", (req, socket, head) => {
70
70
  try {
71
+ if (this.service.voiceRealtime.handleUpgrade(req, socket, head)) return;
71
72
  if (this.service.realtime.handleUpgrade(req, socket, head)) return;
72
73
  if (handleSiteShareUpgrade(this.service, req, socket, head)) return;
73
74
  socket.destroy();
@@ -71,6 +71,7 @@ export declare class GatewayAgentRunner {
71
71
  signal?: AbortSignal;
72
72
  runId?: string;
73
73
  sourceContexts?: AgentSourceContext[];
74
+ presentation?: 'voice';
74
75
  }): AsyncGenerator<{
75
76
  type: string;
76
77
  [key: string]: unknown;
@@ -128,12 +128,7 @@ var GatewayAgentRunner = class {
128
128
  completeRealtimeTopic: this.opts.completeRealtimeTopic
129
129
  }, message, channel, chatId, origin, attachments, thinking, runOptions);
130
130
  try {
131
- let step = await iter.next();
132
- while (!step.done) {
133
- yield step.value;
134
- step = await iter.next();
135
- }
136
- return step.value;
131
+ return yield* iter;
137
132
  } finally {
138
133
  if (trackedRunId) {
139
134
  this.resolveRunCompletions.get(trackedRunId)?.();
@@ -25,6 +25,7 @@ export declare function runGatewayAgent(deps: RunGatewayAgentDeps, message: stri
25
25
  signal?: AbortSignal;
26
26
  runId?: string;
27
27
  sourceContexts?: AgentSourceContext[];
28
+ presentation?: 'voice';
28
29
  }): AsyncGenerator<RunGatewayAgentYield, {
29
30
  status: string;
30
31
  summary: string;
@@ -131,7 +131,8 @@ async function* runGatewayAgent(deps, message, channel, chatId, origin, attachme
131
131
  const eventStream = agentService.turnDispatcher.processDirectStreaming(stampedMessage, sessionKey, origin, prepared, thinking, {
132
132
  signal: mergedSignal,
133
133
  runId,
134
- sourceContexts: runOptions?.sourceContexts
134
+ sourceContexts: runOptions?.sourceContexts,
135
+ presentation: runOptions?.presentation
135
136
  });
136
137
  const mappedEvents = (async function* () {
137
138
  for await (const event of eventStream) yield* mapper.map(event);
@@ -150,6 +151,18 @@ async function* runGatewayAgent(deps, message, channel, chatId, origin, attachme
150
151
  summary: mergedSignal.aborted ? "Interrupted" : "Message processed successfully"
151
152
  };
152
153
  } catch (error) {
154
+ if (mergedSignal.aborted) {
155
+ terminalStatus = "cancelled";
156
+ taskRunStatus = "cancelled";
157
+ taskRunSummary = "Interrupted";
158
+ yield* emitAndYield(mapper.end("cancelled", "Interrupted"));
159
+ completeRealtimeTopic(`run:${runId}`);
160
+ runTopicCompleted = true;
161
+ return {
162
+ status: "aborted",
163
+ summary: "Interrupted"
164
+ };
165
+ }
153
166
  const em = error instanceof Error ? error.message : String(error);
154
167
  log.error({
155
168
  err: error,
@@ -173,6 +186,11 @@ async function* runGatewayAgent(deps, message, channel, chatId, origin, attachme
173
186
  summary: streamError
174
187
  };
175
188
  } finally {
189
+ if (mergedSignal.aborted) {
190
+ terminalStatus = "cancelled";
191
+ taskRunStatus = "cancelled";
192
+ taskRunSummary = "Interrupted";
193
+ }
176
194
  if (registeredActiveWebchatRun && activeWebchatRunBySession.get(sessionKey) === runId) {
177
195
  activeWebchatRunBySession.delete(sessionKey);
178
196
  publishRealtime("sessions", "run.completed", {
@@ -19,6 +19,7 @@ import { GatewaySessionsApi } from './service/sessions-api.js';
19
19
  import { GatewayMarketplaceService } from './service/marketplace-service.js';
20
20
  import { GatewayAgentRunner } from './service/agent-runner.js';
21
21
  import { RealtimeRuntime } from '../realtime/runtime.js';
22
+ import { VoiceRealtimeRuntime } from '../voice/realtime/runtime.js';
22
23
  import type { GatewayServiceConfig } from './service/types.js';
23
24
  import { type GatewayReadinessSnapshot } from './startup-readiness.js';
24
25
  import { type ConnectorLearningCoordinator } from '../connectors/learning-coordinator.js';
@@ -51,6 +52,7 @@ export declare class GatewayService {
51
52
  private auth;
52
53
  readonly endpointTools: EndpointToolRuntime;
53
54
  readonly realtime: RealtimeRuntime;
55
+ readonly voiceRealtime: VoiceRealtimeRuntime;
54
56
  getConfig(): Config;
55
57
  getModelCatalogSync(): ModelCatalogSyncService;
56
58
  get browserRecipes(): BrowserRecipeService;
@@ -6,6 +6,8 @@ import { getRuntimeLogStats } from "../utils/logger/stats.js";
6
6
  import { createLogger } from "../utils/logger/index.js";
7
7
  import { init_logger } from "../utils/logger.js";
8
8
  import { closeXopcDatabase, openXopcDatabase } from "../storage/sqlite/connection.js";
9
+ import { notifyUserContextChange } from "../user-context/changes.js";
10
+ import { getSessionConfig } from "../storage/sqlite/config-repository.js";
9
11
  import "../storage/sqlite/index.js";
10
12
  import { getAgentDefaultModelRef, init_schema } from "../config/schema.js";
11
13
  import { init_agent_scope, listAgentEntries, normalizeAgentId, resolveDefaultAgentId } from "../agent/agent-scope.js";
@@ -18,6 +20,7 @@ import { loadConfig, saveConfig } from "../config/loader.js";
18
20
  import { buildSessionKey, init_session_key, sanitizeSegment } from "../routing/session-key.js";
19
21
  import { getDefaultAgentId, init_resolve_route } from "../routing/resolve-route.js";
20
22
  import { init_providers, providers_exports } from "../providers/index.js";
23
+ import { resolveEffectiveAgentProfileForSession } from "../config/agent-profile.js";
21
24
  import { TaskRepository } from "../tasks/task-repository.js";
22
25
  import { TaskConversationRepository } from "../tasks/task-conversation-repository.js";
23
26
  import { disposeAllSessionMcpRuntimes } from "../agent/mcp/bundle-mcp-runtime.js";
@@ -68,6 +71,8 @@ import { assertGatewayAuthConfigured, extractToken, resolveGatewayAuth, validate
68
71
  import { prepareAutomationAgentSession } from "./automation-agent-session.js";
69
72
  import { stopTailscaleExposure } from "./tailscale-lifecycle.js";
70
73
  import { reconcileDreamingAutomations } from "./dreaming-automation-reconciler.js";
74
+ import { buildVoiceMemoryContext } from "../voice/realtime/memory-context.js";
75
+ import { voiceMemoryBudget } from "../voice/realtime/conversation-context.js";
71
76
  import { NotesStore } from "../notes/store.js";
72
77
  import { buildNoteAgentContext } from "../notes/agent-context.js";
73
78
  import { NotesService } from "../notes/service.js";
@@ -114,6 +119,7 @@ import { GatewayMarketplaceService } from "./service/marketplace-service.js";
114
119
  import { GatewayConfigCoordinator } from "./service/config-coordinator.js";
115
120
  import { GatewayAgentRunner } from "./service/agent-runner.js";
116
121
  import { RealtimeRuntime } from "../realtime/runtime.js";
122
+ import { VoiceRealtimeRuntime } from "../voice/realtime/runtime.js";
117
123
  import { GatewayReadiness } from "./startup-readiness.js";
118
124
  import { createGatewayStartupTrace } from "./startup-trace.js";
119
125
  import { applyAutomaticVoiceLanguage, inferProductLanguageFromEnvironment, initializeVoiceDefaults } from "../voice/language-profile.js";
@@ -158,6 +164,71 @@ var GatewayService = class {
158
164
  auth;
159
165
  endpointTools = new EndpointToolRuntime();
160
166
  realtime = new RealtimeRuntime(this.endpointTools);
167
+ voiceRealtime = new VoiceRealtimeRuntime({
168
+ getConversationContext: async (sessionKey, expectedSessionId) => {
169
+ if ((await this.sessionIndex.getSessionMetadata(sessionKey))?.sessionId !== expectedSessionId) throw new Error("Conversation changed before voice connection");
170
+ const messages = await this.sessionIndex.loadMessages(sessionKey);
171
+ const after = await this.sessionIndex.getSessionMetadata(sessionKey);
172
+ if (after?.sessionId !== expectedSessionId) throw new Error("Conversation changed while loading voice context");
173
+ const profile = resolveEffectiveAgentProfileForSession(this.config, sessionKey);
174
+ const context = {
175
+ identity: [`Your name is ${profile.config.profile?.name ?? profile.agentId}.`, profile.customInstructions ?? ""].join("\n"),
176
+ history: messages
177
+ };
178
+ const memory = buildVoiceMemoryContext({
179
+ getConfig: () => this.config,
180
+ sessionKey,
181
+ workspaceId: getSessionConfig(sessionKey)?.workingDirectoryOverride ?? profile.resolvedWorkspacePath,
182
+ projectId: after?.projectId,
183
+ history: messages,
184
+ maxChars: voiceMemoryBudget(this.config.voice.realtime.omni.instructions, context)
185
+ });
186
+ return {
187
+ ...context,
188
+ ...memory ? { memory } : {}
189
+ };
190
+ },
191
+ getSessionIdentity: async (sessionKey) => (await this.sessionIndex.getSessionMetadata(sessionKey))?.sessionId,
192
+ recordOmniTranscript: async (sessionKey, callId, entry, expectedSessionId) => {
193
+ await this.sessionIndex.appendTranscriptCustomMessageEntry(sessionKey, {
194
+ expectedSessionId,
195
+ customType: "voice_omni_transcript",
196
+ content: entry.text,
197
+ display: true,
198
+ details: {
199
+ callId,
200
+ itemId: entry.itemId,
201
+ role: entry.role,
202
+ interrupted: entry.interrupted,
203
+ engine: "omni"
204
+ }
205
+ });
206
+ this.emit("session.transcript_updated", { key: sessionKey });
207
+ },
208
+ getConfig: () => this.config,
209
+ sessionExists: async (sessionKey) => Boolean(await this.sessionIndex.getSessionMetadata(sessionKey)),
210
+ sessionBusy: (sessionKey) => Boolean(this.agentRunner.getActiveRunId(sessionKey)) || this.agentRunner.inputs.snapshot(sessionKey).inputs.some((input) => input.status === "queued"),
211
+ recordInterruption: (entry) => this.sessionIndex.appendTranscriptContextEntry(entry.sessionKey, {
212
+ text: "Voice response was interrupted before playback completed.",
213
+ data: {
214
+ type: "voice_response_interrupted",
215
+ responseId: entry.responseId,
216
+ reason: entry.reason,
217
+ generatedCharacters: entry.generatedCharacters,
218
+ interruptedDuring: entry.interruptedDuring
219
+ }
220
+ }),
221
+ runAgent: (text, sessionKey, signal) => {
222
+ if (this.agentRunner.hasActiveRun(sessionKey)) throw new Error("Conversation session already has an active response");
223
+ return this.agentRunner.runAgent(text, "webchat", sessionKey, {
224
+ type: "channel",
225
+ channel: "webchat"
226
+ }, void 0, void 0, {
227
+ signal,
228
+ presentation: "voice"
229
+ });
230
+ }
231
+ });
161
232
  getConfig() {
162
233
  return this.config;
163
234
  }
@@ -1097,6 +1168,7 @@ var GatewayService = class {
1097
1168
  this.endpointTools.close();
1098
1169
  await this.sideChats.disposeAll();
1099
1170
  this.realtime.close();
1171
+ this.voiceRealtime.close();
1100
1172
  await this.proactiveWorker.stop();
1101
1173
  await this.discussionWorker.stop();
1102
1174
  await this.discussionSealer.stop();
@@ -1543,6 +1615,7 @@ var GatewayService = class {
1543
1615
  });
1544
1616
  }
1545
1617
  emit(type, payload) {
1618
+ if (type === "config.reload") notifyUserContextChange({ kind: "policy" });
1546
1619
  this.realtime.broker.publish("gateway", type, payload);
1547
1620
  this.createNotificationService().handleGatewayEvent(type, payload);
1548
1621
  }