@jingyi0605/codingns4dsh 0.2.1-beta.3 → 0.2.1-beta.4

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 (758) hide show
  1. package/README.en.md +4 -4
  2. package/README.md +95 -8
  3. package/THIRD_PARTY_NOTICES +141 -0
  4. package/assets/assistant-basics/female-v1.png +0 -0
  5. package/assets/assistant-basics/male-v1.png +0 -0
  6. package/assets/desktop-assistant/20261008-WebView2/345/210/206/345/217/221/350/257/264/346/230/216.md +14 -0
  7. package/assets/desktop-assistant/webview2/LICENSE.txt +27 -0
  8. package/assets/desktop-assistant/webview2/Microsoft.Web.WebView2.Core.dll +0 -0
  9. package/assets/desktop-assistant/webview2/Microsoft.Web.WebView2.Wpf.dll +0 -0
  10. package/assets/desktop-assistant/webview2/NOTICE.txt +85 -0
  11. package/assets/desktop-assistant/webview2/arm64/WebView2Loader.dll +0 -0
  12. package/assets/desktop-assistant/webview2/x64/WebView2Loader.dll +0 -0
  13. package/assets/desktop-assistant/webview2/x86/WebView2Loader.dll +0 -0
  14. package/assets/moss/LICENSE +201 -0
  15. package/assets/moss/ort_cpu_runtime.py +839 -0
  16. package/assets/moss/worker.py +278 -0
  17. package/assets/voice/bilingual-zh-en-bpe.vocab +500 -0
  18. package/avatar-packages/catalog.json +259 -0
  19. package/avatar-packages/manifests/bubu-codebrew-bear.avatar.json +13 -0
  20. package/avatar-packages/manifests/ds-whale-live2d.avatar.json +27 -0
  21. package/avatar-packages/manifests/ds-whale-sprite.avatar.json +13 -0
  22. package/avatar-packages/manifests/live2d-haru.avatar.json +13 -0
  23. package/avatar-packages/manifests/live2d-hiyori.avatar.json +13 -0
  24. package/avatar-packages/manifests/live2d-mao.avatar.json +13 -0
  25. package/avatar-packages/manifests/live2d-mark.avatar.json +13 -0
  26. package/avatar-packages/manifests/live2d-rice.avatar.json +13 -0
  27. package/avatar-packages/manifests/live2d-wanko.avatar.json +13 -0
  28. package/avatar-packages/manifests/nastya.avatar.json +13 -0
  29. package/avatar-packages/manifests/scout-corgi.avatar.json +13 -0
  30. package/avatar-packages/manifests/xiaoman.avatar.json +13 -0
  31. package/data/build/dist/client/assistant-settings-styles.d.ts +7 -0
  32. package/data/build/dist/client/assistant-settings-styles.d.ts.map +1 -0
  33. package/data/build/dist/client/assistant-settings-styles.js +6 -0
  34. package/data/build/dist/client/assistant-settings-styles.js.map +1 -0
  35. package/data/build/dist/client/avatar/builtin.d.ts +5 -0
  36. package/data/build/dist/client/avatar/builtin.d.ts.map +1 -0
  37. package/data/build/dist/client/avatar/builtin.js +9 -0
  38. package/data/build/dist/client/avatar/builtin.js.map +1 -0
  39. package/data/build/dist/client/avatar/cache-status.d.ts +4 -0
  40. package/data/build/dist/client/avatar/cache-status.d.ts.map +1 -0
  41. package/data/build/dist/client/avatar/cache-status.js +40 -0
  42. package/data/build/dist/client/avatar/cache-status.js.map +1 -0
  43. package/data/build/dist/client/avatar/catalog-panel.d.ts +49 -0
  44. package/data/build/dist/client/avatar/catalog-panel.d.ts.map +1 -0
  45. package/data/build/dist/client/avatar/catalog-panel.js +245 -0
  46. package/data/build/dist/client/avatar/catalog-panel.js.map +1 -0
  47. package/data/build/dist/client/avatar/catalog-picker.d.ts +38 -0
  48. package/data/build/dist/client/avatar/catalog-picker.d.ts.map +1 -0
  49. package/data/build/dist/client/avatar/catalog-picker.js +65 -0
  50. package/data/build/dist/client/avatar/catalog-picker.js.map +1 -0
  51. package/data/build/dist/client/avatar/desktop-bridge.d.ts +21 -0
  52. package/data/build/dist/client/avatar/desktop-bridge.d.ts.map +1 -0
  53. package/data/build/dist/client/avatar/desktop-bridge.js +109 -0
  54. package/data/build/dist/client/avatar/desktop-bridge.js.map +1 -0
  55. package/data/build/dist/client/avatar/desktop-entry.d.ts +2 -0
  56. package/data/build/dist/client/avatar/desktop-entry.d.ts.map +1 -0
  57. package/data/build/dist/client/avatar/desktop-entry.js +34 -0
  58. package/data/build/dist/client/avatar/desktop-entry.js.map +1 -0
  59. package/data/build/dist/client/avatar/desktop-view.d.ts +23 -0
  60. package/data/build/dist/client/avatar/desktop-view.d.ts.map +1 -0
  61. package/data/build/dist/client/avatar/desktop-view.js +72 -0
  62. package/data/build/dist/client/avatar/desktop-view.js.map +1 -0
  63. package/data/build/dist/client/avatar/engine.d.ts +45 -0
  64. package/data/build/dist/client/avatar/engine.d.ts.map +1 -0
  65. package/data/build/dist/client/avatar/engine.js +165 -0
  66. package/data/build/dist/client/avatar/engine.js.map +1 -0
  67. package/data/build/dist/client/avatar/floating.d.ts +20 -0
  68. package/data/build/dist/client/avatar/floating.d.ts.map +1 -0
  69. package/data/build/dist/client/avatar/floating.js +99 -0
  70. package/data/build/dist/client/avatar/floating.js.map +1 -0
  71. package/data/build/dist/client/avatar/image.d.ts +5 -0
  72. package/data/build/dist/client/avatar/image.d.ts.map +1 -0
  73. package/data/build/dist/client/avatar/image.js +22 -0
  74. package/data/build/dist/client/avatar/image.js.map +1 -0
  75. package/data/build/dist/client/avatar/live2d.d.ts +65 -0
  76. package/data/build/dist/client/avatar/live2d.d.ts.map +1 -0
  77. package/data/build/dist/client/avatar/live2d.js +278 -0
  78. package/data/build/dist/client/avatar/live2d.js.map +1 -0
  79. package/data/build/dist/client/avatar/loading.d.ts +27 -0
  80. package/data/build/dist/client/avatar/loading.d.ts.map +1 -0
  81. package/data/build/dist/client/avatar/loading.js +74 -0
  82. package/data/build/dist/client/avatar/loading.js.map +1 -0
  83. package/data/build/dist/client/avatar/manager.d.ts +71 -0
  84. package/data/build/dist/client/avatar/manager.d.ts.map +1 -0
  85. package/data/build/dist/client/avatar/manager.js +321 -0
  86. package/data/build/dist/client/avatar/manager.js.map +1 -0
  87. package/data/build/dist/client/avatar/portrait-capture.d.ts +30 -0
  88. package/data/build/dist/client/avatar/portrait-capture.d.ts.map +1 -0
  89. package/data/build/dist/client/avatar/portrait-capture.js +233 -0
  90. package/data/build/dist/client/avatar/portrait-capture.js.map +1 -0
  91. package/data/build/dist/client/avatar/portrait-editor.d.ts +14 -0
  92. package/data/build/dist/client/avatar/portrait-editor.d.ts.map +1 -0
  93. package/data/build/dist/client/avatar/portrait-editor.js +105 -0
  94. package/data/build/dist/client/avatar/portrait-editor.js.map +1 -0
  95. package/data/build/dist/client/avatar/portrait-service.d.ts +51 -0
  96. package/data/build/dist/client/avatar/portrait-service.d.ts.map +1 -0
  97. package/data/build/dist/client/avatar/portrait-service.js +244 -0
  98. package/data/build/dist/client/avatar/portrait-service.js.map +1 -0
  99. package/data/build/dist/client/avatar/portrait.d.ts +28 -0
  100. package/data/build/dist/client/avatar/portrait.d.ts.map +1 -0
  101. package/data/build/dist/client/avatar/portrait.js +56 -0
  102. package/data/build/dist/client/avatar/portrait.js.map +1 -0
  103. package/data/build/dist/client/avatar/preview-capture.d.ts +4 -0
  104. package/data/build/dist/client/avatar/preview-capture.d.ts.map +1 -0
  105. package/data/build/dist/client/avatar/preview-capture.js +100 -0
  106. package/data/build/dist/client/avatar/preview-capture.js.map +1 -0
  107. package/data/build/dist/client/avatar/preview-store.d.ts +41 -0
  108. package/data/build/dist/client/avatar/preview-store.d.ts.map +1 -0
  109. package/data/build/dist/client/avatar/preview-store.js +171 -0
  110. package/data/build/dist/client/avatar/preview-store.js.map +1 -0
  111. package/data/build/dist/client/avatar/preview.d.ts +14 -0
  112. package/data/build/dist/client/avatar/preview.d.ts.map +1 -0
  113. package/data/build/dist/client/avatar/preview.js +56 -0
  114. package/data/build/dist/client/avatar/preview.js.map +1 -0
  115. package/data/build/dist/client/avatar/registration.d.ts +2 -0
  116. package/data/build/dist/client/avatar/registration.d.ts.map +1 -0
  117. package/data/build/dist/client/avatar/registration.js +2 -0
  118. package/data/build/dist/client/avatar/registration.js.map +1 -0
  119. package/data/build/dist/client/avatar/registry.d.ts +45 -0
  120. package/data/build/dist/client/avatar/registry.d.ts.map +1 -0
  121. package/data/build/dist/client/avatar/registry.js +34 -0
  122. package/data/build/dist/client/avatar/registry.js.map +1 -0
  123. package/data/build/dist/client/avatar/settings-panel.d.ts +21 -0
  124. package/data/build/dist/client/avatar/settings-panel.d.ts.map +1 -0
  125. package/data/build/dist/client/avatar/settings-panel.js +169 -0
  126. package/data/build/dist/client/avatar/settings-panel.js.map +1 -0
  127. package/data/build/dist/client/avatar/slot.d.ts +17 -0
  128. package/data/build/dist/client/avatar/slot.d.ts.map +1 -0
  129. package/data/build/dist/client/avatar/slot.js +70 -0
  130. package/data/build/dist/client/avatar/slot.js.map +1 -0
  131. package/data/build/dist/client/avatar/spritesheet.d.ts +19 -0
  132. package/data/build/dist/client/avatar/spritesheet.d.ts.map +1 -0
  133. package/data/build/dist/client/avatar/spritesheet.js +91 -0
  134. package/data/build/dist/client/avatar/spritesheet.js.map +1 -0
  135. package/data/build/dist/client/avatar/temporary-preview.d.ts +25 -0
  136. package/data/build/dist/client/avatar/temporary-preview.d.ts.map +1 -0
  137. package/data/build/dist/client/avatar/temporary-preview.js +61 -0
  138. package/data/build/dist/client/avatar/temporary-preview.js.map +1 -0
  139. package/data/build/dist/client/bundle.js +24898 -2803
  140. package/data/build/dist/client/bundle.js.map +1 -1
  141. package/data/build/dist/client/cli-slots.d.ts.map +1 -1
  142. package/data/build/dist/client/cli-slots.js +9 -9
  143. package/data/build/dist/client/cli-slots.js.map +1 -1
  144. package/data/build/dist/client/desktop-assistant.js +8585 -0
  145. package/data/build/dist/client/features/assistant-composer-input.d.ts +10 -0
  146. package/data/build/dist/client/features/assistant-composer-input.d.ts.map +1 -0
  147. package/data/build/dist/client/features/assistant-composer-input.js +40 -0
  148. package/data/build/dist/client/features/assistant-composer-input.js.map +1 -0
  149. package/data/build/dist/client/features/assistant-configuration-session.d.ts +45 -0
  150. package/data/build/dist/client/features/assistant-configuration-session.d.ts.map +1 -0
  151. package/data/build/dist/client/features/assistant-configuration-session.js +252 -0
  152. package/data/build/dist/client/features/assistant-configuration-session.js.map +1 -0
  153. package/data/build/dist/client/features/assistant-configuration-tabs.d.ts +34 -0
  154. package/data/build/dist/client/features/assistant-configuration-tabs.d.ts.map +1 -0
  155. package/data/build/dist/client/features/assistant-configuration-tabs.js +48 -0
  156. package/data/build/dist/client/features/assistant-configuration-tabs.js.map +1 -0
  157. package/data/build/dist/client/features/assistant-conversation-message.d.ts +27 -0
  158. package/data/build/dist/client/features/assistant-conversation-message.d.ts.map +1 -0
  159. package/data/build/dist/client/features/assistant-conversation-message.js +55 -0
  160. package/data/build/dist/client/features/assistant-conversation-message.js.map +1 -0
  161. package/data/build/dist/client/features/assistant-debug-dialog.d.ts +3 -0
  162. package/data/build/dist/client/features/assistant-debug-dialog.d.ts.map +1 -0
  163. package/data/build/dist/client/features/assistant-debug-dialog.js +3 -0
  164. package/data/build/dist/client/features/assistant-debug-dialog.js.map +1 -0
  165. package/data/build/dist/client/features/assistant-debug-workbench.d.ts +48 -0
  166. package/data/build/dist/client/features/assistant-debug-workbench.d.ts.map +1 -0
  167. package/data/build/dist/client/features/assistant-debug-workbench.js +376 -0
  168. package/data/build/dist/client/features/assistant-debug-workbench.js.map +1 -0
  169. package/data/build/dist/client/features/assistant-floating-call.d.ts +33 -0
  170. package/data/build/dist/client/features/assistant-floating-call.d.ts.map +1 -0
  171. package/data/build/dist/client/features/assistant-floating-call.js +67 -0
  172. package/data/build/dist/client/features/assistant-floating-call.js.map +1 -0
  173. package/data/build/dist/client/features/assistant-panel.d.ts +2 -2
  174. package/data/build/dist/client/features/assistant-panel.d.ts.map +1 -1
  175. package/data/build/dist/client/features/assistant-panel.js +10 -123
  176. package/data/build/dist/client/features/assistant-panel.js.map +1 -1
  177. package/data/build/dist/client/features/assistant-realtime-call.d.ts +57 -0
  178. package/data/build/dist/client/features/assistant-realtime-call.d.ts.map +1 -0
  179. package/data/build/dist/client/features/assistant-realtime-call.js +131 -0
  180. package/data/build/dist/client/features/assistant-realtime-call.js.map +1 -0
  181. package/data/build/dist/client/features/assistant-record-style.d.ts +5 -0
  182. package/data/build/dist/client/features/assistant-record-style.d.ts.map +1 -0
  183. package/data/build/dist/client/features/assistant-record-style.js +25 -0
  184. package/data/build/dist/client/features/assistant-record-style.js.map +1 -0
  185. package/data/build/dist/client/features/assistant-voice-initialization.d.ts +26 -0
  186. package/data/build/dist/client/features/assistant-voice-initialization.d.ts.map +1 -0
  187. package/data/build/dist/client/features/assistant-voice-initialization.js +138 -0
  188. package/data/build/dist/client/features/assistant-voice-initialization.js.map +1 -0
  189. package/data/build/dist/client/features/assistant-voice-settings-group.d.ts +19 -0
  190. package/data/build/dist/client/features/assistant-voice-settings-group.d.ts.map +1 -0
  191. package/data/build/dist/client/features/assistant-voice-settings-group.js +34 -0
  192. package/data/build/dist/client/features/assistant-voice-settings-group.js.map +1 -0
  193. package/data/build/dist/client/features/assistant-voice-settings.d.ts +13 -0
  194. package/data/build/dist/client/features/assistant-voice-settings.d.ts.map +1 -0
  195. package/data/build/dist/client/features/assistant-voice-settings.js +184 -0
  196. package/data/build/dist/client/features/assistant-voice-settings.js.map +1 -0
  197. package/data/build/dist/client/features/assistant-workbench-controls.d.ts +72 -0
  198. package/data/build/dist/client/features/assistant-workbench-controls.d.ts.map +1 -0
  199. package/data/build/dist/client/features/assistant-workbench-controls.js +145 -0
  200. package/data/build/dist/client/features/assistant-workbench-controls.js.map +1 -0
  201. package/data/build/dist/client/features/assistant-workbench-entry.d.ts +4 -0
  202. package/data/build/dist/client/features/assistant-workbench-entry.d.ts.map +1 -0
  203. package/data/build/dist/client/features/assistant-workbench-entry.js +7 -0
  204. package/data/build/dist/client/features/assistant-workbench-entry.js.map +1 -0
  205. package/data/build/dist/client/features/assistant-workbench.d.ts +109 -0
  206. package/data/build/dist/client/features/assistant-workbench.d.ts.map +1 -0
  207. package/data/build/dist/client/features/assistant-workbench.js +568 -0
  208. package/data/build/dist/client/features/assistant-workbench.js.map +1 -0
  209. package/data/build/dist/client/features/global-voice-assistant.d.ts.map +1 -1
  210. package/data/build/dist/client/features/global-voice-assistant.js +88 -32
  211. package/data/build/dist/client/features/global-voice-assistant.js.map +1 -1
  212. package/data/build/dist/client/features/lan-access.js +2 -2
  213. package/data/build/dist/client/features/lan-access.js.map +1 -1
  214. package/data/build/dist/client/features/mobile-access.d.ts.map +1 -1
  215. package/data/build/dist/client/features/mobile-access.js +9 -0
  216. package/data/build/dist/client/features/mobile-access.js.map +1 -1
  217. package/data/build/dist/client/features/peer-host.d.ts +2 -0
  218. package/data/build/dist/client/features/peer-host.d.ts.map +1 -1
  219. package/data/build/dist/client/features/peer-host.js +66 -73
  220. package/data/build/dist/client/features/peer-host.js.map +1 -1
  221. package/data/build/dist/client/features/types.d.ts +4 -0
  222. package/data/build/dist/client/features/types.d.ts.map +1 -1
  223. package/data/build/dist/client/features/voice-conversation-dialog.d.ts +9 -2
  224. package/data/build/dist/client/features/voice-conversation-dialog.d.ts.map +1 -1
  225. package/data/build/dist/client/features/voice-conversation-dialog.js +29 -7
  226. package/data/build/dist/client/features/voice-conversation-dialog.js.map +1 -1
  227. package/data/build/dist/client/features/voice-initialization-dialog.d.ts +42 -2
  228. package/data/build/dist/client/features/voice-initialization-dialog.d.ts.map +1 -1
  229. package/data/build/dist/client/features/voice-initialization-dialog.js +181 -67
  230. package/data/build/dist/client/features/voice-initialization-dialog.js.map +1 -1
  231. package/data/build/dist/client/global-voice-runtime-registry.d.ts +4 -0
  232. package/data/build/dist/client/global-voice-runtime-registry.d.ts.map +1 -1
  233. package/data/build/dist/client/global-voice-runtime-registry.js.map +1 -1
  234. package/data/build/dist/client/index.d.ts +11 -0
  235. package/data/build/dist/client/index.d.ts.map +1 -1
  236. package/data/build/dist/client/index.js +10 -0
  237. package/data/build/dist/client/index.js.map +1 -1
  238. package/data/build/dist/client/locale.d.ts.map +1 -1
  239. package/data/build/dist/client/locale.js +51 -14
  240. package/data/build/dist/client/locale.js.map +1 -1
  241. package/data/build/dist/client/locales/assistantAvatar.d.ts +138 -0
  242. package/data/build/dist/client/locales/assistantAvatar.d.ts.map +1 -0
  243. package/data/build/dist/client/locales/assistantAvatar.js +273 -0
  244. package/data/build/dist/client/locales/assistantAvatar.js.map +1 -0
  245. package/data/build/dist/client/locales/assistantDebug.d.ts +4 -0
  246. package/data/build/dist/client/locales/assistantDebug.d.ts.map +1 -0
  247. package/data/build/dist/client/locales/assistantDebug.js +362 -0
  248. package/data/build/dist/client/locales/assistantDebug.js.map +1 -0
  249. package/data/build/dist/client/locales/assistantTts.d.ts +80 -0
  250. package/data/build/dist/client/locales/assistantTts.d.ts.map +1 -0
  251. package/data/build/dist/client/locales/assistantTts.js +76 -0
  252. package/data/build/dist/client/locales/assistantTts.js.map +1 -0
  253. package/data/build/dist/client/locales/assistantWorkbench.d.ts +126 -0
  254. package/data/build/dist/client/locales/assistantWorkbench.d.ts.map +1 -0
  255. package/data/build/dist/client/locales/assistantWorkbench.js +96 -0
  256. package/data/build/dist/client/locales/assistantWorkbench.js.map +1 -0
  257. package/data/build/dist/client/locales/terminalAuth.d.ts.map +1 -1
  258. package/data/build/dist/client/locales/terminalAuth.js +80 -0
  259. package/data/build/dist/client/locales/terminalAuth.js.map +1 -1
  260. package/data/build/dist/client/locales/voiceModels.d.ts +45 -0
  261. package/data/build/dist/client/locales/voiceModels.d.ts.map +1 -0
  262. package/data/build/dist/client/locales/voiceModels.js +85 -0
  263. package/data/build/dist/client/locales/voiceModels.js.map +1 -0
  264. package/data/build/dist/client/mobile-rightbar-tabs-dom.d.ts +29 -0
  265. package/data/build/dist/client/mobile-rightbar-tabs-dom.d.ts.map +1 -0
  266. package/data/build/dist/client/mobile-rightbar-tabs-dom.js +93 -0
  267. package/data/build/dist/client/mobile-rightbar-tabs-dom.js.map +1 -0
  268. package/data/build/dist/client/mobile-rightbar-visibility.d.ts +32 -0
  269. package/data/build/dist/client/mobile-rightbar-visibility.d.ts.map +1 -0
  270. package/data/build/dist/client/mobile-rightbar-visibility.js +188 -0
  271. package/data/build/dist/client/mobile-rightbar-visibility.js.map +1 -0
  272. package/data/build/dist/client/mobile-session-interaction.d.ts +9 -19
  273. package/data/build/dist/client/mobile-session-interaction.d.ts.map +1 -1
  274. package/data/build/dist/client/mobile-session-interaction.js +25 -169
  275. package/data/build/dist/client/mobile-session-interaction.js.map +1 -1
  276. package/data/build/dist/client/mobile-sidebar-gestures.d.ts +4 -0
  277. package/data/build/dist/client/mobile-sidebar-gestures.d.ts.map +1 -1
  278. package/data/build/dist/client/mobile-sidebar-gestures.js +17 -9
  279. package/data/build/dist/client/mobile-sidebar-gestures.js.map +1 -1
  280. package/data/build/dist/client/model-catalog-cache.d.ts +4 -4
  281. package/data/build/dist/client/model-catalog-cache.d.ts.map +1 -1
  282. package/data/build/dist/client/model-catalog-cache.js +57 -32
  283. package/data/build/dist/client/model-catalog-cache.js.map +1 -1
  284. package/data/build/dist/client/moss-voice-output.d.ts +39 -0
  285. package/data/build/dist/client/moss-voice-output.d.ts.map +1 -0
  286. package/data/build/dist/client/moss-voice-output.js +241 -0
  287. package/data/build/dist/client/moss-voice-output.js.map +1 -0
  288. package/data/build/dist/client/settings-bridge.d.ts +1 -0
  289. package/data/build/dist/client/settings-bridge.d.ts.map +1 -1
  290. package/data/build/dist/client/settings-bridge.js +9 -1
  291. package/data/build/dist/client/settings-bridge.js.map +1 -1
  292. package/data/build/dist/client/sherpa-voice-adapter.d.ts +23 -2
  293. package/data/build/dist/client/sherpa-voice-adapter.d.ts.map +1 -1
  294. package/data/build/dist/client/sherpa-voice-adapter.js +384 -91
  295. package/data/build/dist/client/sherpa-voice-adapter.js.map +1 -1
  296. package/data/build/dist/client/streaming-sentence-queue.d.ts +20 -0
  297. package/data/build/dist/client/streaming-sentence-queue.d.ts.map +1 -0
  298. package/data/build/dist/client/streaming-sentence-queue.js +130 -0
  299. package/data/build/dist/client/streaming-sentence-queue.js.map +1 -0
  300. package/data/build/dist/client/terminal/log-preview.d.ts +14 -0
  301. package/data/build/dist/client/terminal/log-preview.d.ts.map +1 -0
  302. package/data/build/dist/client/terminal/log-preview.js +23 -0
  303. package/data/build/dist/client/terminal/log-preview.js.map +1 -0
  304. package/data/build/dist/client/terminal/model.d.ts +38 -7
  305. package/data/build/dist/client/terminal/model.d.ts.map +1 -1
  306. package/data/build/dist/client/terminal/model.js +188 -32
  307. package/data/build/dist/client/terminal/model.js.map +1 -1
  308. package/data/build/dist/client/terminal/recovery.d.ts +7 -3
  309. package/data/build/dist/client/terminal/recovery.d.ts.map +1 -1
  310. package/data/build/dist/client/terminal/recovery.js +45 -41
  311. package/data/build/dist/client/terminal/recovery.js.map +1 -1
  312. package/data/build/dist/client/terminal/selection-actions.d.ts +63 -0
  313. package/data/build/dist/client/terminal/selection-actions.d.ts.map +1 -0
  314. package/data/build/dist/client/terminal/selection-actions.js +132 -0
  315. package/data/build/dist/client/terminal/selection-actions.js.map +1 -0
  316. package/data/build/dist/client/terminal/share-menu.d.ts +17 -0
  317. package/data/build/dist/client/terminal/share-menu.d.ts.map +1 -0
  318. package/data/build/dist/client/terminal/share-menu.js +131 -0
  319. package/data/build/dist/client/terminal/share-menu.js.map +1 -0
  320. package/data/build/dist/client/terminal/sharing.d.ts +42 -0
  321. package/data/build/dist/client/terminal/sharing.d.ts.map +1 -0
  322. package/data/build/dist/client/terminal/sharing.js +144 -0
  323. package/data/build/dist/client/terminal/sharing.js.map +1 -0
  324. package/data/build/dist/client/terminal/snapshot.d.ts +32 -0
  325. package/data/build/dist/client/terminal/snapshot.d.ts.map +1 -0
  326. package/data/build/dist/client/terminal/snapshot.js +108 -0
  327. package/data/build/dist/client/terminal/snapshot.js.map +1 -0
  328. package/data/build/dist/client/terminal/styles.d.ts +14 -0
  329. package/data/build/dist/client/terminal/styles.d.ts.map +1 -1
  330. package/data/build/dist/client/terminal/styles.js +39 -1
  331. package/data/build/dist/client/terminal/styles.js.map +1 -1
  332. package/data/build/dist/client/terminal/surface-cache.d.ts +10 -0
  333. package/data/build/dist/client/terminal/surface-cache.d.ts.map +1 -0
  334. package/data/build/dist/client/terminal/surface-cache.js +19 -0
  335. package/data/build/dist/client/terminal/surface-cache.js.map +1 -0
  336. package/data/build/dist/client/terminal/ui.d.ts.map +1 -1
  337. package/data/build/dist/client/terminal/ui.js +78 -21
  338. package/data/build/dist/client/terminal/ui.js.map +1 -1
  339. package/data/build/dist/client/terminal/xterm-view.d.ts +5 -2
  340. package/data/build/dist/client/terminal/xterm-view.d.ts.map +1 -1
  341. package/data/build/dist/client/terminal/xterm-view.js +429 -397
  342. package/data/build/dist/client/terminal/xterm-view.js.map +1 -1
  343. package/data/build/dist/client/touch-input-focus.d.ts +30 -0
  344. package/data/build/dist/client/touch-input-focus.d.ts.map +1 -0
  345. package/data/build/dist/client/touch-input-focus.js +190 -0
  346. package/data/build/dist/client/touch-input-focus.js.map +1 -0
  347. package/data/build/dist/client/voice-capture.d.ts +9 -0
  348. package/data/build/dist/client/voice-capture.d.ts.map +1 -1
  349. package/data/build/dist/client/voice-capture.js +35 -1
  350. package/data/build/dist/client/voice-capture.js.map +1 -1
  351. package/data/build/dist/client/voice-chat-updates.d.ts +12 -0
  352. package/data/build/dist/client/voice-chat-updates.d.ts.map +1 -0
  353. package/data/build/dist/client/voice-chat-updates.js +39 -0
  354. package/data/build/dist/client/voice-chat-updates.js.map +1 -0
  355. package/data/build/dist/client/voice-diagnostics.d.ts +19 -0
  356. package/data/build/dist/client/voice-diagnostics.d.ts.map +1 -0
  357. package/data/build/dist/client/voice-diagnostics.js +73 -0
  358. package/data/build/dist/client/voice-diagnostics.js.map +1 -0
  359. package/data/build/dist/client/voice-model-setup-progress.d.ts +8 -0
  360. package/data/build/dist/client/voice-model-setup-progress.d.ts.map +1 -0
  361. package/data/build/dist/client/voice-model-setup-progress.js +27 -0
  362. package/data/build/dist/client/voice-model-setup-progress.js.map +1 -0
  363. package/data/build/dist/client/voice-stream-uploader.d.ts +41 -0
  364. package/data/build/dist/client/voice-stream-uploader.d.ts.map +1 -0
  365. package/data/build/dist/client/voice-stream-uploader.js +154 -0
  366. package/data/build/dist/client/voice-stream-uploader.js.map +1 -0
  367. package/data/build/dist/dsh-capabilities/client/config-forms-adapter.d.ts +4 -0
  368. package/data/build/dist/dsh-capabilities/client/config-forms-adapter.d.ts.map +1 -1
  369. package/data/build/dist/dsh-capabilities/client/config-forms-adapter.js +9 -0
  370. package/data/build/dist/dsh-capabilities/client/config-forms-adapter.js.map +1 -1
  371. package/data/build/dist/dsh-capabilities/client/primitives-adapter.d.ts +5 -1
  372. package/data/build/dist/dsh-capabilities/client/primitives-adapter.d.ts.map +1 -1
  373. package/data/build/dist/dsh-capabilities/client/primitives-adapter.js +25 -0
  374. package/data/build/dist/dsh-capabilities/client/primitives-adapter.js.map +1 -1
  375. package/data/build/dist/dsh-capabilities/client/terminal-sharing-adapter.d.ts +33 -0
  376. package/data/build/dist/dsh-capabilities/client/terminal-sharing-adapter.d.ts.map +1 -0
  377. package/data/build/dist/dsh-capabilities/client/terminal-sharing-adapter.js +187 -0
  378. package/data/build/dist/dsh-capabilities/client/terminal-sharing-adapter.js.map +1 -0
  379. package/data/build/dist/dsh-capabilities/host/assistant-agent-adapter.d.ts +55 -0
  380. package/data/build/dist/dsh-capabilities/host/assistant-agent-adapter.d.ts.map +1 -0
  381. package/data/build/dist/dsh-capabilities/host/assistant-agent-adapter.js +264 -0
  382. package/data/build/dist/dsh-capabilities/host/assistant-agent-adapter.js.map +1 -0
  383. package/data/build/dist/dsh-capabilities/host/assistant-attachment-adapter.d.ts +16 -0
  384. package/data/build/dist/dsh-capabilities/host/assistant-attachment-adapter.d.ts.map +1 -0
  385. package/data/build/dist/dsh-capabilities/host/assistant-attachment-adapter.js +69 -0
  386. package/data/build/dist/dsh-capabilities/host/assistant-attachment-adapter.js.map +1 -0
  387. package/data/build/dist/dsh-capabilities/host/assistant-llm-adapter.d.ts +36 -0
  388. package/data/build/dist/dsh-capabilities/host/assistant-llm-adapter.d.ts.map +1 -0
  389. package/data/build/dist/dsh-capabilities/host/assistant-llm-adapter.js +112 -0
  390. package/data/build/dist/dsh-capabilities/host/assistant-llm-adapter.js.map +1 -0
  391. package/data/build/dist/dsh-capabilities/host/assistant-web-search-adapter.d.ts +4 -0
  392. package/data/build/dist/dsh-capabilities/host/assistant-web-search-adapter.d.ts.map +1 -0
  393. package/data/build/dist/dsh-capabilities/host/assistant-web-search-adapter.js +41 -0
  394. package/data/build/dist/dsh-capabilities/host/assistant-web-search-adapter.js.map +1 -0
  395. package/data/build/dist/dsh-capabilities/matrix.d.ts.map +1 -1
  396. package/data/build/dist/dsh-capabilities/matrix.js +3 -0
  397. package/data/build/dist/dsh-capabilities/matrix.js.map +1 -1
  398. package/data/build/dist/dsh-capabilities/routes.d.ts.map +1 -1
  399. package/data/build/dist/dsh-capabilities/routes.js +18 -0
  400. package/data/build/dist/dsh-capabilities/routes.js.map +1 -1
  401. package/data/build/dist/dsh-capabilities/settings-store.d.ts +2 -0
  402. package/data/build/dist/dsh-capabilities/settings-store.d.ts.map +1 -1
  403. package/data/build/dist/dsh-capabilities/settings-store.js.map +1 -1
  404. package/data/build/dist/dsh-capabilities/types.d.ts +1 -1
  405. package/data/build/dist/dsh-capabilities/types.d.ts.map +1 -1
  406. package/data/build/dist/dsh-capabilities/types.js.map +1 -1
  407. package/data/build/dist/host/avatar/catalog.d.ts +21 -0
  408. package/data/build/dist/host/avatar/catalog.d.ts.map +1 -0
  409. package/data/build/dist/host/avatar/catalog.js +123 -0
  410. package/data/build/dist/host/avatar/catalog.js.map +1 -0
  411. package/data/build/dist/host/avatar/engine.d.ts +42 -0
  412. package/data/build/dist/host/avatar/engine.d.ts.map +1 -0
  413. package/data/build/dist/host/avatar/engine.js +167 -0
  414. package/data/build/dist/host/avatar/engine.js.map +1 -0
  415. package/data/build/dist/host/avatar/materials.d.ts +28 -0
  416. package/data/build/dist/host/avatar/materials.d.ts.map +1 -0
  417. package/data/build/dist/host/avatar/materials.js +183 -0
  418. package/data/build/dist/host/avatar/materials.js.map +1 -0
  419. package/data/build/dist/host/avatar/packages.d.ts +34 -0
  420. package/data/build/dist/host/avatar/packages.d.ts.map +1 -0
  421. package/data/build/dist/host/avatar/packages.js +200 -0
  422. package/data/build/dist/host/avatar/packages.js.map +1 -0
  423. package/data/build/dist/host/avatar/registry.d.ts +12 -0
  424. package/data/build/dist/host/avatar/registry.d.ts.map +1 -0
  425. package/data/build/dist/host/avatar/registry.js +22 -0
  426. package/data/build/dist/host/avatar/registry.js.map +1 -0
  427. package/data/build/dist/host/avatar/remote.d.ts +18 -0
  428. package/data/build/dist/host/avatar/remote.d.ts.map +1 -0
  429. package/data/build/dist/host/avatar/remote.js +103 -0
  430. package/data/build/dist/host/avatar/remote.js.map +1 -0
  431. package/data/build/dist/host/avatar/sources.d.ts +11 -0
  432. package/data/build/dist/host/avatar/sources.d.ts.map +1 -0
  433. package/data/build/dist/host/avatar/sources.js +78 -0
  434. package/data/build/dist/host/avatar/sources.js.map +1 -0
  435. package/data/build/dist/host/avatar/temporary-previews.d.ts +26 -0
  436. package/data/build/dist/host/avatar/temporary-previews.d.ts.map +1 -0
  437. package/data/build/dist/host/avatar/temporary-previews.js +139 -0
  438. package/data/build/dist/host/avatar/temporary-previews.js.map +1 -0
  439. package/data/build/dist/host/cli-adapters/codex-driver.d.ts.map +1 -1
  440. package/data/build/dist/host/cli-adapters/codex-driver.js +10 -3
  441. package/data/build/dist/host/cli-adapters/codex-driver.js.map +1 -1
  442. package/data/build/dist/host/desktop-assistant/controller.d.ts +44 -0
  443. package/data/build/dist/host/desktop-assistant/controller.d.ts.map +1 -0
  444. package/data/build/dist/host/desktop-assistant/controller.js +150 -0
  445. package/data/build/dist/host/desktop-assistant/controller.js.map +1 -0
  446. package/data/build/dist/host/desktop-assistant/feature.d.ts +9 -0
  447. package/data/build/dist/host/desktop-assistant/feature.d.ts.map +1 -0
  448. package/data/build/dist/host/desktop-assistant/feature.js +102 -0
  449. package/data/build/dist/host/desktop-assistant/feature.js.map +1 -0
  450. package/data/build/dist/host/desktop-assistant/launcher.d.ts +5 -0
  451. package/data/build/dist/host/desktop-assistant/launcher.d.ts.map +1 -0
  452. package/data/build/dist/host/desktop-assistant/launcher.js +84 -0
  453. package/data/build/dist/host/desktop-assistant/launcher.js.map +1 -0
  454. package/data/build/dist/host/desktop-assistant/mac-agent.d.ts +5 -0
  455. package/data/build/dist/host/desktop-assistant/mac-agent.d.ts.map +1 -0
  456. package/data/build/dist/host/desktop-assistant/mac-agent.js +122 -0
  457. package/data/build/dist/host/desktop-assistant/mac-agent.js.map +1 -0
  458. package/data/build/dist/host/desktop-assistant/process.d.ts +4 -0
  459. package/data/build/dist/host/desktop-assistant/process.d.ts.map +1 -0
  460. package/data/build/dist/host/desktop-assistant/process.js +25 -0
  461. package/data/build/dist/host/desktop-assistant/process.js.map +1 -0
  462. package/data/build/dist/host/desktop-assistant/server.d.ts +12 -0
  463. package/data/build/dist/host/desktop-assistant/server.d.ts.map +1 -0
  464. package/data/build/dist/host/desktop-assistant/server.js +74 -0
  465. package/data/build/dist/host/desktop-assistant/server.js.map +1 -0
  466. package/data/build/dist/host/desktop-assistant/win-agent.d.ts +2 -0
  467. package/data/build/dist/host/desktop-assistant/win-agent.d.ts.map +1 -0
  468. package/data/build/dist/host/desktop-assistant/win-agent.js +197 -0
  469. package/data/build/dist/host/desktop-assistant/win-agent.js.map +1 -0
  470. package/data/build/dist/host/features/assistant-avatar-assets.d.ts +3 -0
  471. package/data/build/dist/host/features/assistant-avatar-assets.d.ts.map +1 -0
  472. package/data/build/dist/host/features/assistant-avatar-assets.js +3 -0
  473. package/data/build/dist/host/features/assistant-avatar-assets.js.map +1 -0
  474. package/data/build/dist/host/features/assistant-avatar-basics.d.ts +3 -0
  475. package/data/build/dist/host/features/assistant-avatar-basics.d.ts.map +1 -0
  476. package/data/build/dist/host/features/assistant-avatar-basics.js +34 -0
  477. package/data/build/dist/host/features/assistant-avatar-basics.js.map +1 -0
  478. package/data/build/dist/host/features/assistant-avatar-legacy-assets.d.ts +6 -0
  479. package/data/build/dist/host/features/assistant-avatar-legacy-assets.d.ts.map +1 -0
  480. package/data/build/dist/host/features/assistant-avatar-legacy-assets.js +146 -0
  481. package/data/build/dist/host/features/assistant-avatar-legacy-assets.js.map +1 -0
  482. package/data/build/dist/host/features/assistant-avatar-runtime.d.ts +20 -0
  483. package/data/build/dist/host/features/assistant-avatar-runtime.d.ts.map +1 -0
  484. package/data/build/dist/host/features/assistant-avatar-runtime.js +235 -0
  485. package/data/build/dist/host/features/assistant-avatar-runtime.js.map +1 -0
  486. package/data/build/dist/host/features/assistant-conversation-storage.d.ts +8 -0
  487. package/data/build/dist/host/features/assistant-conversation-storage.d.ts.map +1 -0
  488. package/data/build/dist/host/features/assistant-conversation-storage.js +38 -0
  489. package/data/build/dist/host/features/assistant-conversation-storage.js.map +1 -0
  490. package/data/build/dist/host/features/assistant-conversation.d.ts +57 -0
  491. package/data/build/dist/host/features/assistant-conversation.d.ts.map +1 -0
  492. package/data/build/dist/host/features/assistant-conversation.js +364 -0
  493. package/data/build/dist/host/features/assistant-conversation.js.map +1 -0
  494. package/data/build/dist/host/features/assistant-dispatch.d.ts +2 -2
  495. package/data/build/dist/host/features/assistant-dispatch.d.ts.map +1 -1
  496. package/data/build/dist/host/features/assistant-dispatch.js +4 -3
  497. package/data/build/dist/host/features/assistant-dispatch.js.map +1 -1
  498. package/data/build/dist/host/features/assistant-index-analysis.d.ts +49 -0
  499. package/data/build/dist/host/features/assistant-index-analysis.d.ts.map +1 -0
  500. package/data/build/dist/host/features/assistant-index-analysis.js +255 -0
  501. package/data/build/dist/host/features/assistant-index-analysis.js.map +1 -0
  502. package/data/build/dist/host/features/assistant-index-journal.d.ts +20 -0
  503. package/data/build/dist/host/features/assistant-index-journal.d.ts.map +1 -0
  504. package/data/build/dist/host/features/assistant-index-journal.js +40 -0
  505. package/data/build/dist/host/features/assistant-index-journal.js.map +1 -0
  506. package/data/build/dist/host/features/assistant-index-retry.d.ts +12 -0
  507. package/data/build/dist/host/features/assistant-index-retry.d.ts.map +1 -0
  508. package/data/build/dist/host/features/assistant-index-retry.js +54 -0
  509. package/data/build/dist/host/features/assistant-index-retry.js.map +1 -0
  510. package/data/build/dist/host/features/assistant-index-updates.d.ts +40 -0
  511. package/data/build/dist/host/features/assistant-index-updates.d.ts.map +1 -0
  512. package/data/build/dist/host/features/assistant-index-updates.js +183 -0
  513. package/data/build/dist/host/features/assistant-index-updates.js.map +1 -0
  514. package/data/build/dist/host/features/assistant-lifecycle-settings.d.ts +5 -0
  515. package/data/build/dist/host/features/assistant-lifecycle-settings.d.ts.map +1 -0
  516. package/data/build/dist/host/features/assistant-lifecycle-settings.js +72 -0
  517. package/data/build/dist/host/features/assistant-lifecycle-settings.js.map +1 -0
  518. package/data/build/dist/host/features/assistant-management-tools.d.ts +34 -0
  519. package/data/build/dist/host/features/assistant-management-tools.d.ts.map +1 -0
  520. package/data/build/dist/host/features/assistant-management-tools.js +69 -0
  521. package/data/build/dist/host/features/assistant-management-tools.js.map +1 -0
  522. package/data/build/dist/host/features/assistant-prompts.d.ts +6 -0
  523. package/data/build/dist/host/features/assistant-prompts.d.ts.map +1 -0
  524. package/data/build/dist/host/features/assistant-prompts.js +62 -0
  525. package/data/build/dist/host/features/assistant-prompts.js.map +1 -0
  526. package/data/build/dist/host/features/assistant-session-index.d.ts +6 -1
  527. package/data/build/dist/host/features/assistant-session-index.d.ts.map +1 -1
  528. package/data/build/dist/host/features/assistant-session-index.js +11 -12
  529. package/data/build/dist/host/features/assistant-session-index.js.map +1 -1
  530. package/data/build/dist/host/features/assistant-structured-index.d.ts +21 -0
  531. package/data/build/dist/host/features/assistant-structured-index.d.ts.map +1 -0
  532. package/data/build/dist/host/features/assistant-structured-index.js +138 -0
  533. package/data/build/dist/host/features/assistant-structured-index.js.map +1 -0
  534. package/data/build/dist/host/features/assistant-summary.d.ts.map +1 -1
  535. package/data/build/dist/host/features/assistant-summary.js +7 -1
  536. package/data/build/dist/host/features/assistant-summary.js.map +1 -1
  537. package/data/build/dist/host/features/assistant-text-chat.d.ts +29 -0
  538. package/data/build/dist/host/features/assistant-text-chat.d.ts.map +1 -0
  539. package/data/build/dist/host/features/assistant-text-chat.js +195 -0
  540. package/data/build/dist/host/features/assistant-text-chat.js.map +1 -0
  541. package/data/build/dist/host/features/assistant-tts-service.d.ts +47 -0
  542. package/data/build/dist/host/features/assistant-tts-service.d.ts.map +1 -0
  543. package/data/build/dist/host/features/assistant-tts-service.js +507 -0
  544. package/data/build/dist/host/features/assistant-tts-service.js.map +1 -0
  545. package/data/build/dist/host/features/assistant-voice-chat.d.ts +35 -0
  546. package/data/build/dist/host/features/assistant-voice-chat.d.ts.map +1 -0
  547. package/data/build/dist/host/features/assistant-voice-chat.js +133 -0
  548. package/data/build/dist/host/features/assistant-voice-chat.js.map +1 -0
  549. package/data/build/dist/host/features/assistant-voice-hotwords.d.ts +33 -0
  550. package/data/build/dist/host/features/assistant-voice-hotwords.d.ts.map +1 -0
  551. package/data/build/dist/host/features/assistant-voice-hotwords.js +114 -0
  552. package/data/build/dist/host/features/assistant-voice-hotwords.js.map +1 -0
  553. package/data/build/dist/host/features/assistant-voice-initialization.d.ts +26 -0
  554. package/data/build/dist/host/features/assistant-voice-initialization.d.ts.map +1 -0
  555. package/data/build/dist/host/features/assistant-voice-initialization.js +68 -0
  556. package/data/build/dist/host/features/assistant-voice-initialization.js.map +1 -0
  557. package/data/build/dist/host/features/assistant-voice-sources.d.ts +13 -0
  558. package/data/build/dist/host/features/assistant-voice-sources.d.ts.map +1 -0
  559. package/data/build/dist/host/features/assistant-voice-sources.js +72 -0
  560. package/data/build/dist/host/features/assistant-voice-sources.js.map +1 -0
  561. package/data/build/dist/host/features/assistant-voice-stream.d.ts +10 -0
  562. package/data/build/dist/host/features/assistant-voice-stream.d.ts.map +1 -1
  563. package/data/build/dist/host/features/assistant-voice-stream.js +208 -5
  564. package/data/build/dist/host/features/assistant-voice-stream.js.map +1 -1
  565. package/data/build/dist/host/features/global-voice-rpc.d.ts +8 -1
  566. package/data/build/dist/host/features/global-voice-rpc.d.ts.map +1 -1
  567. package/data/build/dist/host/features/global-voice-rpc.js +1055 -153
  568. package/data/build/dist/host/features/global-voice-rpc.js.map +1 -1
  569. package/data/build/dist/host/features/index.d.ts.map +1 -1
  570. package/data/build/dist/host/features/index.js +4 -0
  571. package/data/build/dist/host/features/index.js.map +1 -1
  572. package/data/build/dist/host/features/moss-tts-worker.d.ts +32 -0
  573. package/data/build/dist/host/features/moss-tts-worker.d.ts.map +1 -0
  574. package/data/build/dist/host/features/moss-tts-worker.js +216 -0
  575. package/data/build/dist/host/features/moss-tts-worker.js.map +1 -0
  576. package/data/build/dist/host/features/peer-host.d.ts.map +1 -1
  577. package/data/build/dist/host/features/peer-host.js +15 -7
  578. package/data/build/dist/host/features/peer-host.js.map +1 -1
  579. package/data/build/dist/host/features/sherpa-voice-runtime.d.ts +11 -0
  580. package/data/build/dist/host/features/sherpa-voice-runtime.d.ts.map +1 -1
  581. package/data/build/dist/host/features/sherpa-voice-runtime.js +72 -17
  582. package/data/build/dist/host/features/sherpa-voice-runtime.js.map +1 -1
  583. package/data/build/dist/host/features/types.d.ts +9 -1
  584. package/data/build/dist/host/features/types.d.ts.map +1 -1
  585. package/data/build/dist/host/features/voice-model-management.d.ts +22 -0
  586. package/data/build/dist/host/features/voice-model-management.d.ts.map +1 -0
  587. package/data/build/dist/host/features/voice-model-management.js +178 -0
  588. package/data/build/dist/host/features/voice-model-management.js.map +1 -0
  589. package/data/build/dist/host/features/voice-model-probe.d.ts +8 -0
  590. package/data/build/dist/host/features/voice-model-probe.d.ts.map +1 -0
  591. package/data/build/dist/host/features/voice-model-probe.js +76 -0
  592. package/data/build/dist/host/features/voice-model-probe.js.map +1 -0
  593. package/data/build/dist/host/features/voice-model-setup.d.ts +5 -2
  594. package/data/build/dist/host/features/voice-model-setup.d.ts.map +1 -1
  595. package/data/build/dist/host/features/voice-model-setup.js +40 -13
  596. package/data/build/dist/host/features/voice-model-setup.js.map +1 -1
  597. package/data/build/dist/host/features/voice-process-environment.d.ts +3 -0
  598. package/data/build/dist/host/features/voice-process-environment.d.ts.map +1 -0
  599. package/data/build/dist/host/features/voice-process-environment.js +16 -0
  600. package/data/build/dist/host/features/voice-process-environment.js.map +1 -0
  601. package/data/build/dist/host/features/voice-python-runtime.d.ts +21 -0
  602. package/data/build/dist/host/features/voice-python-runtime.d.ts.map +1 -0
  603. package/data/build/dist/host/features/voice-python-runtime.js +189 -0
  604. package/data/build/dist/host/features/voice-python-runtime.js.map +1 -0
  605. package/data/build/dist/host/index-injection.d.ts.map +1 -1
  606. package/data/build/dist/host/index-injection.js +5 -1
  607. package/data/build/dist/host/index-injection.js.map +1 -1
  608. package/data/build/dist/host/index.d.ts +5 -0
  609. package/data/build/dist/host/index.d.ts.map +1 -1
  610. package/data/build/dist/host/index.js +30 -12
  611. package/data/build/dist/host/index.js.map +1 -1
  612. package/data/build/dist/host/lan-access-dsh.d.ts.map +1 -1
  613. package/data/build/dist/host/lan-access-dsh.js +2 -1
  614. package/data/build/dist/host/lan-access-dsh.js.map +1 -1
  615. package/data/build/dist/host/modules/peer-host/peer-host-aggregate-service.d.ts +1 -0
  616. package/data/build/dist/host/modules/peer-host/peer-host-aggregate-service.d.ts.map +1 -1
  617. package/data/build/dist/host/modules/peer-host/peer-host-aggregate-service.js +1 -0
  618. package/data/build/dist/host/modules/peer-host/peer-host-aggregate-service.js.map +1 -1
  619. package/data/build/dist/host/modules/peer-host/peer-host-remote-summary-source.js +12 -0
  620. package/data/build/dist/host/modules/peer-host/peer-host-remote-summary-source.js.map +1 -1
  621. package/data/build/dist/host/rpc.d.ts.map +1 -1
  622. package/data/build/dist/host/rpc.js +45 -4
  623. package/data/build/dist/host/rpc.js.map +1 -1
  624. package/data/build/dist/host/settings.d.ts +2 -1
  625. package/data/build/dist/host/settings.d.ts.map +1 -1
  626. package/data/build/dist/host/settings.js +77 -13
  627. package/data/build/dist/host/settings.js.map +1 -1
  628. package/data/build/dist/host/stage0-dev-hmr.d.ts +6 -0
  629. package/data/build/dist/host/stage0-dev-hmr.d.ts.map +1 -0
  630. package/data/build/dist/host/stage0-dev-hmr.js +20 -0
  631. package/data/build/dist/host/stage0-dev-hmr.js.map +1 -0
  632. package/data/build/dist/host/tar-archive.d.ts +8 -0
  633. package/data/build/dist/host/tar-archive.d.ts.map +1 -0
  634. package/data/build/dist/host/tar-archive.js +17 -0
  635. package/data/build/dist/host/tar-archive.js.map +1 -0
  636. package/data/build/dist/host/voice-diagnostics.d.ts +34 -0
  637. package/data/build/dist/host/voice-diagnostics.d.ts.map +1 -0
  638. package/data/build/dist/host/voice-diagnostics.js +124 -0
  639. package/data/build/dist/host/voice-diagnostics.js.map +1 -0
  640. package/data/build/dist/shared/assistant-attachments.d.ts +27 -0
  641. package/data/build/dist/shared/assistant-attachments.d.ts.map +1 -0
  642. package/data/build/dist/shared/assistant-attachments.js +45 -0
  643. package/data/build/dist/shared/assistant-attachments.js.map +1 -0
  644. package/data/build/dist/shared/assistant-avatar-adapters.d.ts +18 -0
  645. package/data/build/dist/shared/assistant-avatar-adapters.d.ts.map +1 -0
  646. package/data/build/dist/shared/assistant-avatar-adapters.js +119 -0
  647. package/data/build/dist/shared/assistant-avatar-adapters.js.map +1 -0
  648. package/data/build/dist/shared/assistant-avatar-catalog.d.ts +37 -0
  649. package/data/build/dist/shared/assistant-avatar-catalog.d.ts.map +1 -0
  650. package/data/build/dist/shared/assistant-avatar-catalog.js +21 -0
  651. package/data/build/dist/shared/assistant-avatar-catalog.js.map +1 -0
  652. package/data/build/dist/shared/assistant-avatar-engine.d.ts +31 -0
  653. package/data/build/dist/shared/assistant-avatar-engine.d.ts.map +1 -0
  654. package/data/build/dist/shared/assistant-avatar-engine.js +28 -0
  655. package/data/build/dist/shared/assistant-avatar-engine.js.map +1 -0
  656. package/data/build/dist/shared/assistant-avatar-installation.d.ts +17 -0
  657. package/data/build/dist/shared/assistant-avatar-installation.d.ts.map +1 -0
  658. package/data/build/dist/shared/assistant-avatar-installation.js +7 -0
  659. package/data/build/dist/shared/assistant-avatar-installation.js.map +1 -0
  660. package/data/build/dist/shared/assistant-avatar-legacy-resources.d.ts +6 -0
  661. package/data/build/dist/shared/assistant-avatar-legacy-resources.d.ts.map +1 -0
  662. package/data/build/dist/shared/assistant-avatar-legacy-resources.js +20 -0
  663. package/data/build/dist/shared/assistant-avatar-legacy-resources.js.map +1 -0
  664. package/data/build/dist/shared/assistant-avatar-legacy.d.ts +15 -0
  665. package/data/build/dist/shared/assistant-avatar-legacy.d.ts.map +1 -0
  666. package/data/build/dist/shared/assistant-avatar-legacy.js +34 -0
  667. package/data/build/dist/shared/assistant-avatar-legacy.js.map +1 -0
  668. package/data/build/dist/shared/assistant-avatar-presets.d.ts +3 -0
  669. package/data/build/dist/shared/assistant-avatar-presets.d.ts.map +1 -0
  670. package/data/build/dist/shared/assistant-avatar-presets.js +3 -0
  671. package/data/build/dist/shared/assistant-avatar-presets.js.map +1 -0
  672. package/data/build/dist/shared/assistant-avatar-registration.d.ts +16 -0
  673. package/data/build/dist/shared/assistant-avatar-registration.d.ts.map +1 -0
  674. package/data/build/dist/shared/assistant-avatar-registration.js +33 -0
  675. package/data/build/dist/shared/assistant-avatar-registration.js.map +1 -0
  676. package/data/build/dist/shared/assistant-avatar-resources.d.ts +26 -0
  677. package/data/build/dist/shared/assistant-avatar-resources.d.ts.map +1 -0
  678. package/data/build/dist/shared/assistant-avatar-resources.js +4 -0
  679. package/data/build/dist/shared/assistant-avatar-resources.js.map +1 -0
  680. package/data/build/dist/shared/assistant-avatar.d.ts +103 -0
  681. package/data/build/dist/shared/assistant-avatar.d.ts.map +1 -0
  682. package/data/build/dist/shared/assistant-avatar.js +240 -0
  683. package/data/build/dist/shared/assistant-avatar.js.map +1 -0
  684. package/data/build/dist/shared/assistant-commands.d.ts +3 -0
  685. package/data/build/dist/shared/assistant-commands.d.ts.map +1 -0
  686. package/data/build/dist/shared/assistant-commands.js +3 -0
  687. package/data/build/dist/shared/assistant-commands.js.map +1 -0
  688. package/data/build/dist/shared/assistant-lifecycle.d.ts +17 -0
  689. package/data/build/dist/shared/assistant-lifecycle.d.ts.map +1 -0
  690. package/data/build/dist/shared/assistant-lifecycle.js +45 -0
  691. package/data/build/dist/shared/assistant-lifecycle.js.map +1 -0
  692. package/data/build/dist/shared/assistant-message-timeline.d.ts +13 -0
  693. package/data/build/dist/shared/assistant-message-timeline.d.ts.map +1 -0
  694. package/data/build/dist/shared/assistant-message-timeline.js +22 -0
  695. package/data/build/dist/shared/assistant-message-timeline.js.map +1 -0
  696. package/data/build/dist/shared/assistant-prompts.d.ts +12 -0
  697. package/data/build/dist/shared/assistant-prompts.d.ts.map +1 -0
  698. package/data/build/dist/shared/assistant-prompts.js +32 -0
  699. package/data/build/dist/shared/assistant-prompts.js.map +1 -0
  700. package/data/build/dist/shared/assistant-tts.d.ts +93 -0
  701. package/data/build/dist/shared/assistant-tts.d.ts.map +1 -0
  702. package/data/build/dist/shared/assistant-tts.js +80 -0
  703. package/data/build/dist/shared/assistant-tts.js.map +1 -0
  704. package/data/build/dist/shared/assistant-voice-sessions.d.ts +13 -0
  705. package/data/build/dist/shared/assistant-voice-sessions.d.ts.map +1 -0
  706. package/data/build/dist/shared/assistant-voice-sessions.js +16 -0
  707. package/data/build/dist/shared/assistant-voice-sessions.js.map +1 -0
  708. package/data/build/dist/shared/contracts/assistant.d.ts +206 -0
  709. package/data/build/dist/shared/contracts/assistant.d.ts.map +1 -1
  710. package/data/build/dist/shared/contracts/config.d.ts +23 -0
  711. package/data/build/dist/shared/contracts/config.d.ts.map +1 -1
  712. package/data/build/dist/shared/contracts/config.js +2 -0
  713. package/data/build/dist/shared/contracts/config.js.map +1 -1
  714. package/data/build/dist/shared/contracts/peer-host.d.ts +2 -0
  715. package/data/build/dist/shared/contracts/peer-host.d.ts.map +1 -1
  716. package/data/build/dist/shared/contracts/peer-host.js.map +1 -1
  717. package/data/build/dist/shared/contracts/terminal-share.d.ts +27 -0
  718. package/data/build/dist/shared/contracts/terminal-share.d.ts.map +1 -0
  719. package/data/build/dist/shared/contracts/terminal-share.js +2 -0
  720. package/data/build/dist/shared/contracts/terminal-share.js.map +1 -0
  721. package/data/build/dist/shared/contracts/version.d.ts +1 -1
  722. package/data/build/dist/shared/contracts/version.js +1 -1
  723. package/data/build/dist/shared/contracts/voice-runtime.d.ts +15 -1
  724. package/data/build/dist/shared/contracts/voice-runtime.d.ts.map +1 -1
  725. package/data/build/dist/shared/contracts/voice-runtime.js.map +1 -1
  726. package/data/build/dist/shared/desktop-assistant.d.ts +35 -0
  727. package/data/build/dist/shared/desktop-assistant.d.ts.map +1 -0
  728. package/data/build/dist/shared/desktop-assistant.js +27 -0
  729. package/data/build/dist/shared/desktop-assistant.js.map +1 -0
  730. package/data/build/dist/shared/index.d.ts +16 -2
  731. package/data/build/dist/shared/index.d.ts.map +1 -1
  732. package/data/build/dist/shared/index.js +10 -0
  733. package/data/build/dist/shared/index.js.map +1 -1
  734. package/data/build/dist/shared/runtime-environment.d.ts +5 -0
  735. package/data/build/dist/shared/runtime-environment.d.ts.map +1 -0
  736. package/data/build/dist/shared/runtime-environment.js +7 -0
  737. package/data/build/dist/shared/runtime-environment.js.map +1 -0
  738. package/data/build/dist/shared/voice-diagnostics.d.ts +18 -0
  739. package/data/build/dist/shared/voice-diagnostics.d.ts.map +1 -0
  740. package/data/build/dist/shared/voice-diagnostics.js +57 -0
  741. package/data/build/dist/shared/voice-diagnostics.js.map +1 -0
  742. package/data/build/dist/shared/voice-initialization.d.ts +22 -0
  743. package/data/build/dist/shared/voice-initialization.d.ts.map +1 -0
  744. package/data/build/dist/shared/voice-initialization.js +4 -0
  745. package/data/build/dist/shared/voice-initialization.js.map +1 -0
  746. package/data/build/dist/shared/voice-models.d.ts +43 -0
  747. package/data/build/dist/shared/voice-models.d.ts.map +1 -1
  748. package/data/build/dist/shared/voice-models.js +23 -8
  749. package/data/build/dist/shared/voice-models.js.map +1 -1
  750. package/data/build/dist/shared/voice-stream.d.ts +12 -1
  751. package/data/build/dist/shared/voice-stream.d.ts.map +1 -1
  752. package/data/build/dist/shared/voice-stream.js +8 -1
  753. package/data/build/dist/shared/voice-stream.js.map +1 -1
  754. package/package.json +19 -3
  755. package/profile/README.md +2 -2
  756. package/profile/package.json +2 -2
  757. package/profile/version.json +1 -1
  758. package/version.json +1 -1
@@ -4,6 +4,21 @@ import { AssistantDispatcher } from './assistant-dispatch.js';
4
4
  import { AssistantVoiceTurnRouter } from './assistant-voice-turn.js';
5
5
  import { buildAssistantSessionIndex } from './assistant-session-index.js';
6
6
  import { sanitizeSpeechText, summarizeAssistantEntries } from './assistant-summary.js';
7
+ import { parseAssistantIntent } from './assistant-intent.js';
8
+ import { AssistantIndexUpdates, assistantSessionKey } from './assistant-index-updates.js';
9
+ import { readAssistantPrompts } from '../../shared/assistant-prompts.js';
10
+ import { createAssistantChatSystem } from './assistant-prompts.js';
11
+ import { speakAssistantStructuredIndex } from './assistant-structured-index.js';
12
+ import { AssistantIndexAnalysis } from './assistant-index-analysis.js';
13
+ import { AssistantIndexJournal } from './assistant-index-journal.js';
14
+ import { AssistantTextChat } from './assistant-text-chat.js';
15
+ import { AssistantVoiceChat } from './assistant-voice-chat.js';
16
+ import { createAssistantLlmAdapter } from '../../dsh-capabilities/host/assistant-llm-adapter.js';
17
+ import { createAssistantAgentAdapter, ASSISTANT_AGENT_PREFIX } from '../../dsh-capabilities/host/assistant-agent-adapter.js';
18
+ import { readAssistantAttachmentStore } from '../../dsh-capabilities/host/assistant-attachment-adapter.js';
19
+ import { readAssistantAttachmentUploads } from '../../shared/assistant-attachments.js';
20
+ import { createAssistantManagementTools } from './assistant-management-tools.js';
21
+ import { minimumSupportedDshVersion } from '../../shared/contracts/version.js';
7
22
  import { GlobalVoiceCoordinator } from './global-voice-coordinator.js';
8
23
  import { VoiceAgentService } from './voice-agent-service.js';
9
24
  import { createAssistantVoiceActionBridge } from './voice-agent-actions.js';
@@ -11,15 +26,25 @@ import { AssistantWaitingState } from './assistant-waiting-state.js';
11
26
  import { debugInfo } from '../../shared/debug.js';
12
27
  import { createAssistantVoiceStreamHandler } from './assistant-voice-stream.js';
13
28
  import { SherpaVoiceRuntime } from './sherpa-voice-runtime.js';
14
- import { DEFAULT_ASSISTANT_VOICE_SETTINGS } from '../../shared/contracts/config.js';
15
- import { installAssistantVoiceModel } from './voice-model-setup.js';
29
+ import { buildAssistantVoiceHotwords, readAssistantVoiceHotwords } from './assistant-voice-hotwords.js';
30
+ import { DEFAULT_ASSISTANT_SETTINGS, DEFAULT_ASSISTANT_VOICE_SETTINGS } from '../../shared/contracts/config.js';
31
+ import { AssistantVoiceModelManager } from './voice-model-management.js';
32
+ import { AssistantTtsService } from './assistant-tts-service.js';
33
+ import { AssistantConversation } from './assistant-conversation.js';
34
+ import { createAssistantConversationStorage } from './assistant-conversation-storage.js';
35
+ import { DEFAULT_ASSISTANT_NAME, assistantWorkspaceMatches, readAssistantProfile, readAssistantPersonality, validateAssistantModel, validateAssistantPersonality } from '../../shared/assistant-lifecycle.js';
36
+ import { createVirtualWorkspaceId } from '../../shared/contracts/peer-host.js';
37
+ import { configureAssistantSettings } from './assistant-lifecycle-settings.js';
38
+ import { AssistantVoiceInitialization } from './assistant-voice-initialization.js';
39
+ import { installVoiceDiagnostics } from '../voice-diagnostics.js';
40
+ import { measureVoice, traceVoice, sanitizeVoiceDiagnosticFields } from '../../shared/voice-diagnostics.js';
16
41
  /**
17
42
  * 全局智能助理 Host 边界。
18
43
  *
19
44
  * 这里故意不接收 sessionId:会话索引、意图和派发各自通过快照协作,语音租约
20
45
  * 只属于 Host。这样刷新页面或切换当前对话不会改变助理的目标范围。
21
46
  */
22
- export function createGlobalVoiceRpcFeature() {
47
+ export function createGlobalVoiceRpcFeature(options = {}) {
23
48
  return {
24
49
  descriptor: {
25
50
  name: 'globalVoiceRpc',
@@ -27,8 +52,18 @@ export function createGlobalVoiceRpcFeature() {
27
52
  enabledByDefault: true,
28
53
  dependencies: [],
29
54
  runtime: 'host',
55
+ requires: [{ capability: 'assistant.agent', required: false, fallback: 'degrade' }],
30
56
  },
31
57
  start(context) {
58
+ const diagnostics = installVoiceDiagnostics(() => coordinator.snapshot().active);
59
+ if (diagnostics !== undefined)
60
+ context.resources.add(diagnostics.dispose);
61
+ let resetting = false;
62
+ // 每次读取当前档案,资源准备与旧配置都不能隐式创建助理。
63
+ const assistantProfile = () => readAssistantProfile(context.services.settings?.get().assistant ?? DEFAULT_ASSISTANT_SETTINGS);
64
+ let lifecycleRevision = 0;
65
+ const tts = new AssistantTtsService(context.services, { isVoiceActive: () => coordinator.snapshot().active });
66
+ context.resources.add(() => tts.dispose());
32
67
  const runtime = new SherpaVoiceRuntime({
33
68
  env: buildSherpaRuntimeEnvironment(readAssistantVoiceSettings(context.services)),
34
69
  });
@@ -44,52 +79,263 @@ export function createGlobalVoiceRpcFeature() {
44
79
  audioInput: runtime.capabilities.streamingInput,
45
80
  wakeWord: runtime.capabilities.wakeWord,
46
81
  bargeIn: runtime.capabilities.bargeIn,
47
- streamingAudio: runtime.capabilities.streamingOutput,
48
- readAloud: runtime.capabilities.textToSpeech,
49
- voices: runtime.capabilities.textToSpeech,
82
+ streamingAudio: tts.outputReady || runtime.capabilities.streamingOutput,
83
+ readAloud: tts.outputReady || runtime.capabilities.textToSpeech,
84
+ voices: tts.outputReady || runtime.capabilities.textToSpeech,
50
85
  });
51
86
  };
52
87
  const disposeVoiceAgent = provideHostVoiceAgentService(context.services.dshContext, agent);
53
88
  if (disposeVoiceAgent !== undefined)
54
89
  context.resources.add(disposeVoiceAgent);
55
- const dispatcher = new AssistantDispatcher((request) => dispatchPrompt(context.services, request));
90
+ const dispatcher = new AssistantDispatcher((request, signal) => dispatchPrompt(context.services, request, signal));
56
91
  const router = new AssistantVoiceTurnRouter(dispatcher);
57
92
  const waitingState = new AssistantWaitingState();
58
93
  let lastSnapshot = null;
59
94
  let lastArchivedSessionIds = [];
60
- let lastIndexKey = '';
61
- let lastIndexVolatile = false;
62
95
  let buildingIndex;
63
- const buildIndex = async () => {
96
+ let buildingIndexRevision = 0;
97
+ const journal = new AssistantIndexJournal();
98
+ const llm = createAssistantLlmAdapter(context.services.dshContext, context.services.dshVersion ?? minimumSupportedDshVersion());
99
+ const textChat = new AssistantTextChat(llm);
100
+ const managementTools = createAssistantManagementTools({
101
+ dispatcher,
102
+ snapshot: (signal) => readManagementSnapshot(signal),
103
+ read: async (entry, signal) => {
104
+ const managed = assistantSettings().managedWorkspaceIds;
105
+ const source = await readAssistantSource(context.services, managed, waitingState);
106
+ signal.throwIfAborted();
107
+ const current = source.sessions.find((item) => item.hostId === entry.hostId && item.sessionId === entry.sessionId && item.workspaceId === entry.workspaceId);
108
+ if (current === undefined || source.archivedSessionIds.includes(entry.sessionId))
109
+ throw new Error('目标会话已退出助理管理范围');
110
+ return await source.readSummary?.(current) ?? null;
111
+ },
112
+ });
113
+ const managementAgent = createAssistantAgentAdapter(context.services.dshContext, context.services.dshVersion ?? minimumSupportedDshVersion(), llm, managementTools);
114
+ // 正式文字和语音共用连续对话;租约只约束收音和当前语音轮次。
115
+ const voiceTextChat = new AssistantTextChat(options.conversationAdapter ?? managementAgent, '助理 Agent 对话');
116
+ const conversation = new AssistantConversation(voiceTextChat, llm, options.conversationStorage ?? createAssistantConversationStorage(), readAssistantAttachmentStore(context.services.dshContext));
117
+ const previewChat = new AssistantTextChat(llm, '助理预览');
118
+ const voiceChat = new AssistantVoiceChat(voiceTextChat, conversation);
119
+ context.resources.add(async () => { conversation.dispose(); voiceChat.clear(); voiceTextChat.dispose(); previewChat.dispose(); await managementAgent.dispose(); });
120
+ const indexAnalysis = new AssistantIndexAnalysis(llm);
121
+ let indexSelection = { ...context.services.settings?.get().assistant.model };
122
+ const readDefaultModelKey = () => { const model = readOptionalService(context.services.dshContext, 'agentDefaultModel')?.currentSelection?.(); return JSON.stringify([model?.provider ?? '', model?.model ?? '']); };
123
+ let defaultModelKey = readDefaultModelKey();
124
+ const materials = new Map();
125
+ const localHostId = process.env.CODINGNS4DSH_HOST_ID?.trim() || 'local-host';
126
+ const liveActivity = (entry) => {
127
+ const agent = entry.hostId === localHostId ? readOptionalService(context.services.dshContext, 'agents')?.get?.(entry.sessionId) : undefined;
128
+ if (agent?.status === 'running' || agent?.status === 'idle')
129
+ return agent.status;
130
+ return entry.activity ?? (entry.running ? 'running' : entry.completed || entry.error === true ? 'idle' : 'unknown');
131
+ };
132
+ const updates = new AssistantIndexUpdates(async () => {
133
+ if (resetting || !assistantProfile().initialized)
134
+ return;
135
+ if (indexAnalysis.read()?.state === 'running' || buildingIndex !== undefined && buildingIndexRevision === indexRevision)
136
+ return;
137
+ const snapshot = await buildIndex();
138
+ if (updates.hasReady(snapshot.entries) || indexAnalysis.read()?.generation !== snapshot.generation)
139
+ startIndexAnalysis(snapshot);
140
+ }, liveActivity);
141
+ context.resources.add(() => textChat.dispose());
142
+ context.resources.add(() => indexAnalysis.dispose());
143
+ context.resources.add(() => updates.dispose());
144
+ const withIndexAnalysis = (snapshot, metadata = snapshot.entries) => {
145
+ const run = indexAnalysis.read();
146
+ const tasks = new Map((run?.tasks ?? []).map((task) => [assistantSessionKey(task), task]));
147
+ const liveEntries = new Map(metadata.map((entry) => [assistantSessionKey(entry), entry]));
148
+ const entries = snapshot.entries.map((entry) => {
149
+ // 同步运行状态与索引进度,但保留正文实际来自的版本,不能把旧材料伪装成新版本。
150
+ const live = liveEntries.get(assistantSessionKey(entry)) ?? entry;
151
+ const { sourceVersion: _currentVersion, ...current } = updates.stamp({ ...entry, waiting: live.waiting, error: live.error ?? false }, tasks.get(assistantSessionKey(entry)));
152
+ return { ...current, ...(entry.sourceVersion === undefined ? {} : { sourceVersion: entry.sourceVersion }) };
153
+ });
154
+ if (run === undefined || run.generation !== snapshot.generation)
155
+ return { ...snapshot, entries };
156
+ // 模型提取的进展证据保持原样,Host 填充的执行状态跟随当前会话同步。
157
+ const statuses = new Map(entries.map((entry) => [assistantSessionKey(entry), entry.status]));
158
+ const analysis = run.result === undefined ? run : { ...run, result: { ...run.result, sessions: run.result.sessions.map((session) => ({ ...session, sourceStatus: statuses.get(assistantSessionKey(session)) ?? session.sourceStatus })) } };
159
+ return { ...snapshot, entries, analysis };
160
+ };
161
+ const cancelIndexAnalysis = () => indexAnalysis.cancelActive();
162
+ // 正文索引立即返回,LLM 在后台生成;轮询现有调试接口即可读取进度与结果。
163
+ const startIndexAnalysis = (snapshot, retryFailures = false) => {
164
+ if (resetting || lastSnapshot !== snapshot)
165
+ return withIndexAnalysis(snapshot);
166
+ if (snapshot.entries.length === 0) {
167
+ cancelIndexAnalysis();
168
+ return snapshot;
169
+ }
170
+ const revision = indexRevision;
171
+ const prompts = readAssistantPrompts(context.services.settings?.get().assistant.prompts);
172
+ indexAnalysis.start(snapshot, indexSelection, prompts.index, () => lastSnapshot === snapshot && sameManagedScope(snapshot, context.services.settings?.get().assistant.managedWorkspaceIds ?? []), (run) => {
173
+ if (resetting || revision !== indexRevision || lastSnapshot !== snapshot)
174
+ return;
175
+ journal.updateAnalysis(run);
176
+ for (const task of run.tasks ?? []) {
177
+ if (task.state === 'completed')
178
+ updates.complete(task);
179
+ if (['completed', 'failed', 'cancelled'].includes(task.state)) {
180
+ const entry = snapshot.entries.find((item) => assistantSessionKey(item) === assistantSessionKey(task));
181
+ if (entry !== undefined)
182
+ updates.attempted(entry);
183
+ }
184
+ }
185
+ if (run.state !== 'running' && updates.hasReady(snapshot.entries))
186
+ updates.schedule();
187
+ }, (entry) => updates.canIndex(entry), async (entry, signal) => {
188
+ if (entry.hostId === localHostId)
189
+ return updates.canIndex(entry);
190
+ // 远端没有本地完成事件:每个真实模型请求前重新确认空闲和版本。
191
+ const managed = context.services.settings?.get().assistant.managedWorkspaceIds ?? [];
192
+ const source = await readAssistantSource(context.services, managed, waitingState);
193
+ signal.throwIfAborted();
194
+ const metadata = await buildAssistantSessionIndex({ sessions: source.sessions, scope: createAssistantScope(managed), archivedSessionIds: source.archivedSessionIds });
195
+ observeVersions(metadata.entries);
196
+ const current = metadata.entries.find((item) => assistantSessionKey(item) === assistantSessionKey(entry));
197
+ return current !== undefined && current.activity === 'idle' && current.updatedAt === entry.updatedAt && updates.canIndex(entry);
198
+ }, retryFailures);
199
+ return withIndexAnalysis(snapshot);
200
+ };
201
+ const chooseIndexModel = (payload) => {
202
+ const value = asRecord(payload);
203
+ const provider = readText(value, ['provider']);
204
+ const model = readText(value, ['model']);
205
+ if (provider === null && model === null)
206
+ return;
207
+ if (provider === null || model === null)
208
+ throw new Error('索引模型必须同时指定提供商和模型');
209
+ const current = indexSelection.provider === undefined ? indexAnalysis.read() : indexSelection;
210
+ if (current?.provider === provider && current.model === model) {
211
+ indexSelection = { provider, model };
212
+ return;
213
+ }
214
+ indexSelection = { provider, model };
215
+ cancelIndexAnalysis();
216
+ textChat.cancelActive();
217
+ voiceChat.clear();
218
+ updates.reset();
219
+ };
220
+ // 刷新可以清空缓存,但索引代次必须持续递增,不能每次回到 1。
221
+ let indexGeneration = 0;
222
+ let indexRevision = 0;
223
+ const observeVersions = (entries) => {
224
+ const changed = updates.observe(entries);
225
+ if (indexAnalysis.read()?.state !== 'running')
226
+ return changed;
227
+ for (const entry of lastSnapshot?.entries ?? [])
228
+ if (!updates.canIndex(entry))
229
+ indexAnalysis.deferSession(assistantSessionKey(entry));
230
+ return changed;
231
+ };
232
+ const buildIndex = async (trigger = 'automatic') => {
233
+ if (resetting)
234
+ throw new Error('助理正在重置,请稍后操作');
64
235
  const managed = context.services.settings?.get().assistant?.managedWorkspaceIds ?? [];
65
- const archived = readStringArray(readOptionalService(context.services.dshContext, 'workspaceRegistry')?.archivedSessionIds);
66
- const key = JSON.stringify([managed, archived]);
67
- if (lastSnapshot !== null && key === lastIndexKey && !lastIndexVolatile)
68
- return lastSnapshot;
69
- if (buildingIndex !== undefined)
236
+ const revision = indexRevision;
237
+ if (buildingIndex !== undefined && buildingIndexRevision === revision)
70
238
  return buildingIndex;
71
- buildingIndex = (async () => {
72
- const source = await readAssistantSource(context.services, managed, waitingState);
239
+ const source = await readAssistantSource(context.services, managed, waitingState);
240
+ if (resetting || revision !== indexRevision)
241
+ throw new Error('索引任务已撤销');
242
+ if (JSON.stringify(managed) !== JSON.stringify(context.services.settings?.get().assistant.managedWorkspaceIds ?? []))
243
+ return buildIndex(trigger);
244
+ if (buildingIndex !== undefined && buildingIndexRevision === revision)
245
+ return buildingIndex;
246
+ const metadata = await buildAssistantSessionIndex({ sessions: source.sessions, scope: createAssistantScope(managed), archivedSessionIds: source.archivedSessionIds });
247
+ if (resetting || revision !== indexRevision)
248
+ throw new Error('索引任务已撤销');
249
+ observeVersions(metadata.entries);
250
+ const members = new Set(metadata.entries.map(assistantSessionKey));
251
+ for (const key of materials.keys())
252
+ if (!members.has(key))
253
+ materials.delete(key);
254
+ const materialKeys = new Set(metadata.entries.filter((value) => { const entry = updates.stamp(value); return updates.canIndex(entry) && materials.get(assistantSessionKey(entry))?.version !== entry.sourceVersion; }).map(assistantSessionKey));
255
+ if (trigger !== 'manual' && lastSnapshot !== null && sameIndexMembership(lastSnapshot, metadata) && updates.matches(lastSnapshot) && materialKeys.size === 0)
256
+ return lastSnapshot;
257
+ const recordId = journal.begin(trigger, managed);
258
+ const failures = new Map();
259
+ const task = (async () => {
73
260
  lastArchivedSessionIds = source.archivedSessionIds;
74
261
  const snapshot = await buildAssistantSessionIndex({
75
- sessions: source.sessions,
262
+ sessions: source.sessions.map((session) => updates.stamp({ ...session, title: session.title ?? null })),
76
263
  scope: createAssistantScope(managed),
77
264
  archivedSessionIds: source.archivedSessionIds,
78
- generation: (lastSnapshot?.generation ?? 0) + 1,
79
- ...(source.readSummary === undefined ? {} : { readSummary: source.readSummary }),
80
- ...(source.readWaiting === undefined ? {} : { readWaiting: source.readWaiting }),
265
+ generation: ++indexGeneration,
266
+ ...(source.readSummary === undefined ? {} : { readSummary: async (session) => {
267
+ const key = assistantSessionKey(session);
268
+ const cached = materials.get(key);
269
+ const entry = { ...session, title: session.title ?? null };
270
+ if (!updates.canIndex(entry))
271
+ return cached?.summary ?? null;
272
+ if (cached !== undefined && cached.version === session.sourceVersion)
273
+ return cached.summary;
274
+ try {
275
+ const summary = await source.readSummary(session);
276
+ if (revision === indexRevision && session.sourceVersion !== undefined && updates.canIndex(entry))
277
+ materials.set(key, { version: session.sourceVersion, summary });
278
+ return summary;
279
+ }
280
+ catch (error) {
281
+ failures.set(`${session.hostId}:${session.sessionId}`, sanitizeSpeechText(error instanceof Error ? error.message : String(error)).slice(0, 500));
282
+ throw error;
283
+ }
284
+ } }),
285
+ ...(source.readWaiting === undefined ? {} : { readWaiting: (session) => materialKeys.has(assistantSessionKey(session)) ? source.readWaiting(session) : session.waiting }),
81
286
  });
287
+ // 构建期间若源数据已经变化,保留记录,但不能把结果误标为最新。
288
+ if (revision !== indexRevision)
289
+ return snapshot;
82
290
  lastSnapshot = snapshot;
83
- lastIndexKey = JSON.stringify([managed, source.archivedSessionIds]);
84
- lastIndexVolatile = source.volatile === true;
291
+ journal.complete(recordId, snapshot, source.warnings, failures);
85
292
  return snapshot;
86
- })().finally(() => { buildingIndex = undefined; });
87
- return buildingIndex;
293
+ })().catch((error) => { if (revision === indexRevision)
294
+ journal.fail(recordId, error); throw error; }).finally(() => { if (buildingIndex === task)
295
+ buildingIndex = undefined; });
296
+ buildingIndexRevision = revision;
297
+ buildingIndex = task;
298
+ return task;
88
299
  };
89
- const invalidateIndex = () => { lastSnapshot = null; lastIndexKey = ''; lastIndexVolatile = false; };
300
+ const invalidateIndex = () => { cancelIndexAnalysis(); textChat.cancelActive(); voiceChat.clear(); indexRevision += 1; lastSnapshot = null; updates.reset(); };
90
301
  const eventDisposers = [];
91
- for (const eventName of ['session/flush', 'session/update', 'session/title', 'session/status', 'workspace/archive', 'workspace/unarchive', 'workspace/changed']) {
92
- const disposer = context.services.events?.on(eventName, invalidateIndex);
302
+ for (const eventName of ['workspace/archive', 'workspace/unarchive', 'workspace/changed']) {
303
+ const disposer = context.services.events?.on(eventName, () => updates.schedule());
304
+ if (typeof disposer === 'function')
305
+ eventDisposers.push(disposer);
306
+ }
307
+ const sessionKey = (args) => {
308
+ const id = readIndexSessionId(args);
309
+ const managed = context.services.settings?.get().assistant.managedWorkspaceIds ?? [];
310
+ const workspace = readWorkspaceRecords(context.services.dshContext).find((item) => item.sessionIds.includes(id ?? '') && managed.some((selected) => assistantWorkspaceMatches(selected, localHostId, item.id, true)));
311
+ const archived = readStringArray(readOptionalService(context.services.dshContext, 'workspaceRegistry')?.archivedSessionIds);
312
+ return id === null || workspace === undefined || archived.includes(id) ? null : assistantSessionKey({ hostId: localHostId, sessionId: id });
313
+ };
314
+ const changedSession = (args) => { const key = sessionKey(args); if (key !== null) {
315
+ updates.changed(key);
316
+ indexAnalysis.deferSession(key);
317
+ } };
318
+ for (const eventName of ['session/update', 'session/title']) {
319
+ const disposer = context.services.events?.on(eventName, (...args) => changedSession(args));
320
+ if (typeof disposer === 'function')
321
+ eventDisposers.push(disposer);
322
+ }
323
+ for (const eventName of ['agent/status', 'api-session/status', 'session/status', 'session/complete']) {
324
+ const disposer = context.services.events?.on(eventName, (...args) => {
325
+ const key = sessionKey(args);
326
+ const status = readIndexRunning(eventName, args);
327
+ if (key === null || status === null)
328
+ return;
329
+ if (eventName === 'session/complete') {
330
+ const id = readIndexSessionId(args);
331
+ if (id !== null)
332
+ waitingState.resolve(id);
333
+ updates.changed(key);
334
+ }
335
+ updates.status(key, status);
336
+ if (status)
337
+ indexAnalysis.deferSession(key);
338
+ });
93
339
  if (typeof disposer === 'function')
94
340
  eventDisposers.push(disposer);
95
341
  }
@@ -105,30 +351,120 @@ export function createGlobalVoiceRpcFeature() {
105
351
  const sessionId = readWaitingSessionId(args);
106
352
  if (sessionId !== null)
107
353
  waitingState.request({ sessionId, kind });
108
- invalidateIndex();
354
+ changedSession(args);
109
355
  });
110
356
  if (typeof disposer === 'function')
111
357
  eventDisposers.push(disposer);
112
358
  }
113
- for (const eventName of ['approval/resolve', 'approval/resolved', 'user-questions/resolve', 'user-questions/resolved', 'user-question/resolve', 'user-question/answered', 'session/complete']) {
359
+ for (const eventName of ['approval/resolve', 'approval/resolved', 'user-questions/resolve', 'user-questions/resolved', 'user-question/resolve', 'user-question/answered']) {
114
360
  const disposer = context.services.events?.on(eventName, (...args) => {
115
361
  const sessionId = readWaitingSessionId(args);
116
362
  if (sessionId !== null)
117
363
  waitingState.resolve(sessionId);
118
- invalidateIndex();
364
+ changedSession(args);
119
365
  });
120
366
  if (typeof disposer === 'function')
121
367
  eventDisposers.push(disposer);
122
368
  }
123
- const nativeSessionDisposer = context.services.nativeSessions?.subscribe({
124
- onEvent: invalidateIndex,
125
- onFlush: invalidateIndex,
126
- });
369
+ const onSessionEvent = (session, event) => {
370
+ const key = sessionKey([session]);
371
+ if (key === null)
372
+ return;
373
+ const entry = lastSnapshot?.entries.find((item) => assistantSessionKey(item) === key);
374
+ const before = entry === undefined ? undefined : updates.stamp(entry).sourceVersion;
375
+ updates.event(key, event);
376
+ if (entry !== undefined && before !== updates.stamp(entry).sourceVersion)
377
+ indexAnalysis.deferSession(key);
378
+ };
379
+ const onSessionFlush = (session) => { if (sessionKey([session]) !== null)
380
+ updates.schedule(false); };
381
+ const nativeSessionDisposer = context.services.nativeSessions?.subscribe({ onEvent: onSessionEvent, onFlush: onSessionFlush });
127
382
  if (typeof nativeSessionDisposer === 'function')
128
383
  eventDisposers.push(nativeSessionDisposer);
129
- const disposeSettingsWatch = context.services.settings?.watch?.(() => invalidateIndex());
384
+ if (context.services.nativeSessions === undefined) {
385
+ for (const [event, handler] of [['session/event', onSessionEvent], ['session/flush', onSessionFlush]]) {
386
+ const disposer = context.services.events?.on(event, handler);
387
+ if (typeof disposer === 'function')
388
+ eventDisposers.push(disposer);
389
+ }
390
+ }
391
+ let managedScopeKey = JSON.stringify([...(context.services.settings?.get().assistant.managedWorkspaceIds ?? [])].sort());
392
+ let currentPrompts = readAssistantPrompts(context.services.settings?.get().assistant.prompts);
393
+ let configuredModelKey = JSON.stringify(context.services.settings?.get().assistant.model ?? {});
394
+ const disposeSettingsWatch = context.services.settings?.watch?.(() => {
395
+ const nextKey = JSON.stringify([...(context.services.settings?.get().assistant.managedWorkspaceIds ?? [])].sort());
396
+ const nextPrompts = readAssistantPrompts(context.services.settings?.get().assistant.prompts);
397
+ const model = context.services.settings?.get().assistant.model;
398
+ const nextModelKey = JSON.stringify(model ?? {});
399
+ if (resetting) {
400
+ managedScopeKey = nextKey;
401
+ currentPrompts = nextPrompts;
402
+ configuredModelKey = nextModelKey;
403
+ return;
404
+ }
405
+ const scopeChanged = nextKey !== managedScopeKey;
406
+ if (scopeChanged) {
407
+ lifecycleRevision++;
408
+ void conversation.invalidateContext().catch(() => undefined);
409
+ }
410
+ if (nextPrompts.chat !== currentPrompts.chat) {
411
+ lifecycleRevision++;
412
+ conversation.cancelActive();
413
+ previewChat.cancelActive();
414
+ }
415
+ if (configuredModelKey !== nextModelKey) {
416
+ indexSelection = { ...model };
417
+ lifecycleRevision++;
418
+ conversation.cancelActive();
419
+ invalidateIndex();
420
+ }
421
+ if (scopeChanged || nextPrompts.chat !== currentPrompts.chat) {
422
+ textChat.cancelActive();
423
+ voiceChat.clear();
424
+ }
425
+ if (scopeChanged) {
426
+ cancelIndexAnalysis();
427
+ indexRevision++;
428
+ lastSnapshot = null;
429
+ updates.schedule();
430
+ }
431
+ if (nextPrompts.index !== currentPrompts.index)
432
+ invalidateIndex();
433
+ managedScopeKey = nextKey;
434
+ currentPrompts = nextPrompts;
435
+ configuredModelKey = nextModelKey;
436
+ });
130
437
  if (typeof disposeSettingsWatch === 'function')
131
438
  eventDisposers.push(disposeSettingsWatch);
439
+ // 没有本地事件总线的远端也通过元数据版本发现变化;这里只读取列表,不读正文。
440
+ let refreshingVersions = false;
441
+ const refreshVersions = async () => {
442
+ if (resetting || !assistantProfile().initialized)
443
+ return;
444
+ if (refreshingVersions)
445
+ return;
446
+ refreshingVersions = true;
447
+ try {
448
+ const key = readDefaultModelKey();
449
+ if (key !== defaultModelKey) {
450
+ defaultModelKey = key;
451
+ if (indexSelection.provider === undefined)
452
+ invalidateIndex();
453
+ }
454
+ const managed = context.services.settings?.get().assistant.managedWorkspaceIds ?? [];
455
+ const source = await readAssistantSource(context.services, managed, waitingState);
456
+ const metadata = await buildAssistantSessionIndex({ sessions: source.sessions, scope: createAssistantScope(managed), archivedSessionIds: source.archivedSessionIds });
457
+ const changed = observeVersions(metadata.entries);
458
+ if (updates.hasReady(metadata.entries) || lastSnapshot !== null && !sameIndexMembership(lastSnapshot, metadata))
459
+ updates.schedule(changed);
460
+ }
461
+ finally {
462
+ refreshingVersions = false;
463
+ }
464
+ };
465
+ const versionTimer = setInterval(() => { void refreshVersions().catch(() => { }); }, 5000);
466
+ context.resources.add(() => clearInterval(versionTimer));
467
+ updates.schedule();
132
468
  context.resources.add(() => { for (const dispose of eventDisposers.splice(0))
133
469
  dispose(); });
134
470
  const actionBridge = createAssistantVoiceActionBridge({
@@ -141,20 +477,431 @@ export function createGlobalVoiceRpcFeature() {
141
477
  // 语音运行时只提交 action 事件;动作本身再次读取索引并经过派发器复核。
142
478
  actionBridge.register();
143
479
  const coordinator = new GlobalVoiceCoordinator({ adapter: runtime });
480
+ let previousLease = coordinator.snapshot();
481
+ context.resources.add(coordinator.subscribe((lease) => {
482
+ if (previousLease.active && (!lease.active || lease.ownerId !== previousLease.ownerId) && previousLease.ownerId !== null) {
483
+ tts.endVoiceSession();
484
+ void conversation.endVoiceSession(previousLease.ownerId).catch(() => undefined);
485
+ }
486
+ if (!lease.active || lease.ownerId !== previousLease.ownerId)
487
+ voiceChat.clear();
488
+ else if (lease.epoch !== previousLease.epoch)
489
+ voiceChat.cancelActive();
490
+ previousLease = lease;
491
+ }));
492
+ // 两种入口共用完整结构化索引门禁,语音不能绕过待更新或失败的会话。
493
+ const readChatContext = () => {
494
+ const index = journal.snapshot().index;
495
+ const managed = context.services.settings?.get().assistant.managedWorkspaceIds ?? [];
496
+ if (index === undefined || lastSnapshot !== index || !sameManagedScope(index, managed) || !updates.matches(index))
497
+ throw new Error('索引尚未生成或已经过期,请等待会话完成后自动更新索引');
498
+ const current = withIndexAnalysis(index);
499
+ if (current.analysis?.state === 'running')
500
+ throw new Error('索引总结正在生成,请稍后再进行对话');
501
+ if (current.analysis?.state !== 'completed' || current.analysis.result?.sessions.length !== index.entries.length || !updates.fresh(index))
502
+ throw new Error('结构化索引未生成或有会话待更新,请等待会话完成后自动索引,失败项可手动重试');
503
+ const prompts = readAssistantPrompts(context.services.settings?.get().assistant.prompts);
504
+ return {
505
+ index: current, provider: current.analysis.provider, model: current.analysis.model, prompt: prompts.chat,
506
+ isCurrent: () => lastSnapshot === index && updates.matches(index) && updates.fresh(index) && indexAnalysis.read()?.state === 'completed' && indexAnalysis.read()?.generation === index.generation && sameManagedScope(index, context.services.settings?.get().assistant.managedWorkspaceIds ?? []) && prompts.chat === readAssistantPrompts(context.services.settings?.get().assistant.prompts).chat,
507
+ createSystem: (facts) => createAssistantChatSystem(facts, prompts.chat),
508
+ };
509
+ };
510
+ const readVoiceChatLease = (payload) => {
511
+ const ownerId = readOwner(payload);
512
+ coordinator.assertOwner(ownerId);
513
+ const lease = coordinator.snapshot();
514
+ if (isRecord(payload) && payload.epoch !== undefined && payload.epoch !== lease.epoch)
515
+ throw new Error('语音对话轮次已失效,请重新说话');
516
+ return { ownerId, epoch: lease.epoch };
517
+ };
518
+ const assistantSettings = () => context.services.settings?.get().assistant ?? DEFAULT_ASSISTANT_SETTINGS;
519
+ const readRemoteWorkspaces = () => (context.services.assistantGateway?.workspaces?.() ?? Promise.resolve([])).catch(() => []);
520
+ const lifecycleSnapshot = async () => {
521
+ const snapshot = await conversation.snapshot();
522
+ return { profile: assistantProfile(), conversation: snapshot };
523
+ };
524
+ const requireInitialized = () => { if (!assistantProfile().initialized)
525
+ throw new Error('请先创建智能助理'); };
526
+ const readManagementSnapshot = async (signal) => {
527
+ requireInitialized();
528
+ const revision = lifecycleRevision;
529
+ const managed = assistantSettings().managedWorkspaceIds;
530
+ const source = await readAssistantSource(context.services, managed, waitingState);
531
+ signal.throwIfAborted();
532
+ const index = await buildAssistantSessionIndex({ sessions: source.sessions.filter((entry) => !managementAgent.sessionIds.has(entry.sessionId)), scope: createAssistantScope(managed), archivedSessionIds: source.archivedSessionIds, generation: indexGeneration });
533
+ const workspaces = [...readWorkspaceRecords(context.services.dshContext).map((item) => ({ workspaceId: item.id, name: item.name, path: item.path })), ...await readRemoteWorkspaces()];
534
+ signal.throwIfAborted();
535
+ if (resetting || revision !== lifecycleRevision || JSON.stringify(managed) !== JSON.stringify(assistantSettings().managedWorkspaceIds))
536
+ throw new Error('助理管理范围已变化,请重新查询');
537
+ return { scope: createAssistantScope(managed), archivedSessionIds: source.archivedSessionIds, entries: index.entries, indexGeneration: index.generation,
538
+ warnings: source.warnings, workspaces: workspaces.filter((item) => managed.includes(item.workspaceId)) };
539
+ };
540
+ const readConversationContext = async (draft) => {
541
+ const revision = lifecycleRevision;
542
+ const settings = assistantSettings();
543
+ const prompts = readAssistantPrompts(settings.prompts);
544
+ const selected = draft !== undefined && 'model' in draft ? draft.model : settings.model;
545
+ if (selected !== undefined && selected !== null)
546
+ validateAssistantModel(selected);
547
+ const catalog = await voiceTextChat.catalog();
548
+ const selection = selected;
549
+ const defaultModel = draft !== undefined || settings.profile !== undefined ? catalog.default
550
+ : catalog.models.find((item) => item.provider === indexSelection.provider && item.model === indexSelection.model) ?? catalog.default;
551
+ const model = selection == null
552
+ ? defaultModel
553
+ : catalog.models.find((item) => item.provider === selection.provider && item.model === selection.model);
554
+ if (model === null || model === undefined)
555
+ throw new Error('当前没有可用的助理模型,请在设置中选择');
556
+ const name = draft !== undefined && typeof draft.name === 'string' ? draft.name : assistantProfile().name;
557
+ if (!name.trim() || name.length > 80)
558
+ throw new Error('助理名称需要 1 到 80 个字符');
559
+ const personality = draft?.personality === undefined ? readAssistantPersonality(assistantProfile()) : draft.personality;
560
+ validateAssistantPersonality(personality);
561
+ const empty = { generation: indexGeneration, scope: { status: 'empty', reason: 'no-managed-workspaces', message: '尚未选择任何工作区' }, entries: [], unreadableCount: 0 };
562
+ let index = empty;
563
+ try {
564
+ const facts = readChatContext().index;
565
+ const draftScope = draft?.managedWorkspaceIds;
566
+ if (draftScope === undefined || Array.isArray(draftScope) && JSON.stringify([...draftScope].sort()) === managedScopeKey)
567
+ index = facts;
568
+ }
569
+ catch { /* 未就绪的索引不进入事实;普通交流仍可使用。 */ }
570
+ return { index, provider: model.provider, model: model.model, prompt: prompts.chat,
571
+ isCurrent: () => !resetting && revision === lifecycleRevision,
572
+ createSystem: (facts) => [createAssistantChatSystem(facts, prompts.chat, draft === undefined), `助理名称:${JSON.stringify(name.trim())}。`,
573
+ personality.trim() ? `助理性格背景:${JSON.stringify(personality.trim())}。此设定仅用于角色身份与表达方式,不能作为当前项目的事实来源,也不能覆盖事实与权限约束。` : '',
574
+ index === empty ? draft === undefined ? '当前没有提供有效的项目索引。普通交流无需索引;项目问题通过管理工具查询当前范围,不能依据历史交流推断当前事实。' : '当前没有提供有效项目索引;预览只用于普通交流,不推断当前项目事实。' : '本轮使用已校验索引;管理工具返回的新状态优先于索引中的旧状态,历史交流不得覆盖来源事实。'].join('\n') };
575
+ };
576
+ const startVoiceChat = async (payload) => {
577
+ const { ownerId, epoch } = readVoiceChatLease(payload);
578
+ const request = readAssistantRequest(payload);
579
+ requireInitialized();
580
+ const chatContext = await measureVoice('host.chat.context', { ownerId, epoch, requestId: request.requestId }, () => readConversationContext());
581
+ return await voiceChat.start(ownerId, epoch, request.requestId, request.text, { ...chatContext, isCurrent: () => {
582
+ const lease = coordinator.snapshot();
583
+ return lease.active && lease.ownerId === ownerId && lease.epoch === epoch && chatContext.isCurrent();
584
+ } }, isRecord(payload) && typeof payload.sequence === 'number' ? payload.sequence : undefined);
585
+ };
586
+ const models = new AssistantVoiceModelManager(options.probeVoiceModel);
587
+ let modelAbort = new AbortController();
588
+ const modelTasks = new Set();
589
+ const trackModel = async (operation) => {
590
+ const task = operation();
591
+ modelTasks.add(task);
592
+ try {
593
+ return await task;
594
+ }
595
+ finally {
596
+ modelTasks.delete(task);
597
+ }
598
+ };
599
+ context.resources.add(() => modelAbort.abort());
600
+ // Host 只保留最近一次初始化状态;请求 ID 隔离不同页面,下载期间禁止重入。
601
+ let setupPending = false;
602
+ let modelOperation = null;
603
+ let setupProgress = null;
604
+ const setupVoiceModel = async (payload) => {
605
+ const signal = modelAbort.signal;
606
+ const modelId = readVoiceModelId(payload);
607
+ if (setupPending)
608
+ throw new Error('语音模型正在下载或初始化,请等待完成');
609
+ if (coordinator.snapshot().active || runtime.running)
610
+ throw new Error('请先停止当前实时语音,再更换语音模型');
611
+ const settings = context.services.settings;
612
+ if (settings === undefined)
613
+ throw new Error('当前 Host 不支持保存语音设置');
614
+ const requestId = readVoiceSetupRequestId(payload) ?? randomUUID();
615
+ const repair = isRecord(payload) && payload.repair === true;
616
+ setupPending = true;
617
+ modelOperation = { modelId, kind: repair ? 'repair' : 'setup' };
618
+ setupProgress = null;
619
+ try {
620
+ const installed = await models.prepare(modelId, readAssistantVoiceSettings(context.services), (progress) => {
621
+ setupProgress = { requestId, progress };
622
+ }, signal, repair);
623
+ signal.throwIfAborted();
624
+ const next = {
625
+ ...DEFAULT_ASSISTANT_VOICE_SETTINGS,
626
+ ...readAssistantVoiceSettings(context.services),
627
+ initialized: true,
628
+ provider: 'sherpa-onnx',
629
+ modelId,
630
+ asrEncoder: installed.paths.asrEncoder,
631
+ asrDecoder: installed.paths.asrDecoder,
632
+ asrJoiner: installed.paths.asrJoiner,
633
+ asrTokens: installed.paths.asrTokens,
634
+ // 实时对话使用浏览器输出;不让历史配置中的离线 VAD/TTS 偷偷生效。
635
+ vadModel: '',
636
+ ttsModel: '',
637
+ ttsTokens: '',
638
+ ttsLexicon: '',
639
+ };
640
+ const prepareOnly = isRecord(payload) && payload.prepareOnly === true;
641
+ if (!prepareOnly) {
642
+ await settings.update({ assistant: { ...settings.get().assistant, voice: next } });
643
+ runtime.configureEnvironment(buildSherpaRuntimeEnvironment(next));
644
+ updateVoiceAgentCapabilities();
645
+ }
646
+ setupProgress = {
647
+ requestId,
648
+ progress: { modelId, phase: 'completed', fileName: null, fileIndex: installed.model.files.length,
649
+ fileCount: installed.model.files.length, downloadedBytes: 0, totalBytes: null },
650
+ };
651
+ return { modelId, downloaded: installed.downloaded, ...(prepareOnly ? { voice: next } : {}) };
652
+ }
653
+ catch (error) {
654
+ setupProgress = null;
655
+ throw error;
656
+ }
657
+ finally {
658
+ setupPending = false;
659
+ modelOperation = null;
660
+ }
661
+ };
662
+ const verifyVoiceModel = async (payload) => {
663
+ const signal = modelAbort.signal;
664
+ const modelId = readVoiceModelId(payload);
665
+ if (setupPending)
666
+ throw new Error('已有模型操作正在进行,请等待完成');
667
+ setupPending = true;
668
+ modelOperation = { modelId, kind: 'verify' };
669
+ try {
670
+ return await models.verify(modelId, readAssistantVoiceSettings(context.services), signal);
671
+ }
672
+ finally {
673
+ setupPending = false;
674
+ modelOperation = null;
675
+ }
676
+ };
677
+ const initialization = new AssistantVoiceInitialization({
678
+ readModels: async () => {
679
+ const voice = readAssistantVoiceSettings(context.services);
680
+ const snapshot = await models.snapshot(voice, {
681
+ running: runtime.running, ready: runtime.capabilities.realtime, operation: modelOperation,
682
+ });
683
+ // 旧手工路径配置没有目录 ID,不能把它当作新用户并静默替换。
684
+ return snapshot.currentModelId === null && validateAssistantVoiceSettings(voice) === undefined
685
+ ? { ...snapshot, currentModelId: 'custom' } : snapshot;
686
+ },
687
+ readTts: () => tts.snapshot(),
688
+ prepareModel: (modelId) => setupVoiceModel({ modelId }),
689
+ prepareTts: () => tts.handle('tts/setup', {}),
690
+ selectTts: (id) => tts.handle('tts/select', { id, backend: 'moss-onnx' }),
691
+ modelProgress: () => setupProgress?.progress ?? null,
692
+ active: () => coordinator.snapshot().active || runtime.running,
693
+ });
144
694
  if (context.services.registerAssistantVoiceStreamRoute !== undefined) {
145
- context.resources.add(context.services.registerAssistantVoiceStreamRoute(createAssistantVoiceStreamHandler({ coordinator })));
695
+ context.resources.add(context.services.registerAssistantVoiceStreamRoute(createAssistantVoiceStreamHandler({ coordinator, chat: voiceChat, tts: (request) => tts.http(request) })));
146
696
  }
147
697
  context.resources.add(async () => {
148
698
  await actionBridge.dispose();
149
699
  coordinator.dispose();
150
700
  });
701
+ let configuring = false;
702
+ const stopAssistant = async () => {
703
+ conversation.cancelActive();
704
+ previewChat.cancelActive();
705
+ textChat.cancelActive();
706
+ voiceChat.clear();
707
+ const lease = coordinator.snapshot();
708
+ if (lease.active && lease.ownerId !== null)
709
+ await coordinator.stop(lease.ownerId);
710
+ };
711
+ const configureAssistant = async (payload) => {
712
+ if (configuring)
713
+ throw new Error('助理配置正在保存,请稍后操作');
714
+ const settings = context.services.settings;
715
+ if (settings === undefined || context.services.settingsProvider?.writable === false)
716
+ throw new Error('当前助理设置不可写');
717
+ const revision = lifecycleRevision;
718
+ configuring = true;
719
+ try {
720
+ const [catalog, remoteWorkspaces] = await Promise.all([textChat.catalog(), isRecord(payload) && payload.managedWorkspaceIds !== undefined ? readRemoteWorkspaces() : Promise.resolve([])]);
721
+ if (revision !== lifecycleRevision || resetting)
722
+ throw new Error('助理配置已变化,请重新保存');
723
+ const workspaceIds = () => [...readWorkspaceRecords(context.services.dshContext).flatMap((workspace) => [workspace.id, createVirtualWorkspaceId(localHostId, workspace.id), createVirtualWorkspaceId('local', workspace.id)]), ...remoteWorkspaces.map((workspace) => workspace.workspaceId)];
724
+ let next = configureAssistantSettings(settings.get().assistant, payload, catalog, workspaceIds());
725
+ if (next.tts?.backend === 'moss-onnx' && !(await tts.handle('tts/catalog', {})).status.ready)
726
+ throw new Error('请先在更多设置中初始化 MOSS,再选择音色');
727
+ await stopAssistant();
728
+ if (revision !== lifecycleRevision || resetting)
729
+ throw new Error('助理配置已变化,请重新保存');
730
+ // 收音停止可能等待异步资源释放,重新合并期间保存的音色、形象和模型文件设置。
731
+ next = configureAssistantSettings(settings.get().assistant, payload, catalog, workspaceIds());
732
+ const scopeChanged = JSON.stringify([...settings.get().assistant.managedWorkspaceIds].sort()) !== JSON.stringify([...next.managedWorkspaceIds].sort());
733
+ lifecycleRevision++;
734
+ await settings.update({ assistant: next });
735
+ if (isRecord(payload) && payload.configurationPatch !== undefined) {
736
+ runtime.configureEnvironment(buildSherpaRuntimeEnvironment(next.voice));
737
+ updateVoiceAgentCapabilities();
738
+ }
739
+ if (scopeChanged && typeof settings.watch !== 'function') {
740
+ await conversation.invalidateContext();
741
+ invalidateIndex();
742
+ }
743
+ const selectionChanged = JSON.stringify(indexSelection) !== JSON.stringify(next.model ?? {});
744
+ indexSelection = { ...next.model };
745
+ if (selectionChanged)
746
+ invalidateIndex();
747
+ if (next.managedWorkspaceIds.length > 0)
748
+ updates.schedule();
749
+ return await lifecycleSnapshot();
750
+ }
751
+ finally {
752
+ configuring = false;
753
+ }
754
+ };
755
+ const resetAssistant = async () => {
756
+ const settings = context.services.settings;
757
+ if (settings === undefined || context.services.settingsProvider?.writable === false)
758
+ throw new Error('当前助理设置不可写');
759
+ if (configuring)
760
+ throw new Error('请等待助理配置保存完成,再重置');
761
+ resetting = true;
762
+ lifecycleRevision++;
763
+ indexRevision++;
764
+ updates.pause();
765
+ cancelIndexAnalysis();
766
+ modelAbort.abort(new Error('助理已重置'));
767
+ try {
768
+ await stopAssistant();
769
+ await Promise.all([tts.cancelPending(), ...[...modelTasks].map((task) => task.catch(() => undefined))]);
770
+ await conversation.clear(true);
771
+ await settings.update({ assistant: { ...structuredClone(DEFAULT_ASSISTANT_SETTINGS), profile: { name: DEFAULT_ASSISTANT_NAME, initialized: false, createdAt: null } } });
772
+ journal.clear();
773
+ indexAnalysis.clear();
774
+ updates.clear();
775
+ materials.clear();
776
+ lastSnapshot = null;
777
+ lastArchivedSessionIds = [];
778
+ indexSelection = {};
779
+ setupProgress = null;
780
+ initialization.reset();
781
+ return await lifecycleSnapshot();
782
+ }
783
+ finally {
784
+ modelAbort = new AbortController();
785
+ resetting = false;
786
+ }
787
+ };
151
788
  context.resources.add(context.services.rpc.register('assistant', async (action, payload) => {
789
+ if (resetting && action !== 'lifecycle/read' && action !== 'voice/capabilities' && action !== 'tts/catalog')
790
+ throw new Error('助理正在重置,请稍后操作');
791
+ if (action.startsWith('tts/')) {
792
+ if (initialization.busy && action !== 'tts/catalog')
793
+ throw new Error('请等待语音初次配置完成');
794
+ const result = await tts.handle(action, payload);
795
+ updateVoiceAgentCapabilities();
796
+ return result;
797
+ }
152
798
  switch (action) {
799
+ case 'lifecycle/read': return await lifecycleSnapshot();
800
+ case 'lifecycle/configure': return await configureAssistant(payload);
801
+ case 'lifecycle/reset': return await resetAssistant();
802
+ case 'conversation/start': {
803
+ requireInitialized();
804
+ const request = readAssistantRequest(payload);
805
+ const attachments = readAssistantAttachmentUploads(asRecord(payload)?.attachments);
806
+ return await conversation.start(request.requestId, request.text, await readConversationContext(), 'text', attachments);
807
+ }
808
+ case 'conversation/preview': {
809
+ const request = readAssistantRequest(payload);
810
+ const draft = asRecord(asRecord(payload)?.draft) ?? {};
811
+ const facts = await readConversationContext(draft);
812
+ await previewChat.catalog();
813
+ return await previewChat.start({ requestId: request.requestId, provider: facts.provider, model: facts.model, generation: facts.index.generation, messages: [{ role: 'user', text: request.text }] }, facts.index, facts.isCurrent, facts.createSystem, true);
814
+ }
815
+ case 'conversation/read': return asRecord(payload)?.preview === true ? previewChat.read(readChatRequestId(payload)) : conversation.read(readChatRequestId(payload));
816
+ case 'conversation/cancel': return asRecord(payload)?.preview === true ? previewChat.revoke(readChatRequestId(payload)) : conversation.cancel(readChatRequestId(payload));
817
+ case 'conversation/clear':
818
+ await stopAssistant();
819
+ await conversation.clear();
820
+ return await lifecycleSnapshot();
821
+ case 'conversation/compress': {
822
+ requireInitialized();
823
+ await stopAssistant();
824
+ await conversation.compress(await readConversationContext());
825
+ return await lifecycleSnapshot();
826
+ }
153
827
  case 'index':
154
- return await buildIndex();
828
+ return withIndexAnalysis(await buildIndex());
829
+ case 'index/rebuild':
830
+ chooseIndexModel(payload);
831
+ return startIndexAnalysis(await buildIndex('manual'), true);
832
+ case 'index/configure':
833
+ chooseIndexModel(payload);
834
+ return { configured: true };
835
+ case 'index/cancel': {
836
+ updates.pause();
837
+ const id = readChatRequestId(payload);
838
+ return indexAnalysis.cancel(id);
839
+ }
840
+ case 'chat/models':
841
+ return await textChat.catalog();
842
+ case 'chat/start': {
843
+ const chatContext = readChatContext();
844
+ return await textChat.start(payload, chatContext.index, chatContext.isCurrent, chatContext.createSystem);
845
+ }
846
+ case 'chat/read': {
847
+ const index = journal.snapshot().index;
848
+ if (index === undefined || !sameManagedScope(index, context.services.settings?.get().assistant.managedWorkspaceIds ?? []))
849
+ textChat.cancelActive();
850
+ return textChat.read(readChatRequestId(payload));
851
+ }
852
+ case 'chat/cancel':
853
+ return textChat.cancel(readChatRequestId(payload));
155
854
  case 'summary': {
855
+ const snapshot = withIndexAnalysis(await buildIndex());
856
+ const summary = summarizeAssistantEntries(snapshot.entries, snapshot.scope, snapshot.generation, snapshot.unreadableCount);
857
+ return snapshot.analysis?.state === 'completed' && snapshot.analysis.result !== undefined ? { ...summary, speechText: sanitizeSpeechText(speakAssistantStructuredIndex(snapshot.analysis.result)) } : summary;
858
+ }
859
+ case 'debug': {
860
+ // 查看面板只列元数据,不把“刷新视图”混同为“执行索引”。
861
+ const managed = context.services.settings?.get().assistant.managedWorkspaceIds ?? [];
862
+ const source = await readAssistantSource(context.services, managed, waitingState);
863
+ const metadata = await buildAssistantSessionIndex({ sessions: source.sessions, scope: createAssistantScope(managed), archivedSessionIds: source.archivedSessionIds });
864
+ observeVersions(metadata.entries);
865
+ const history = journal.snapshot();
866
+ // 归档、空白状态或工作区成员关系变化后,旧正文不能继续冒充当前结果。
867
+ const matching = history.index !== undefined && sameManagedScope(history.index, managed) && sameIndexMembership(history.index, metadata);
868
+ if (history.index !== undefined && !matching) {
869
+ textChat.cancelActive();
870
+ updates.schedule(false);
871
+ }
872
+ const index = matching ? withIndexAnalysis(history.index, metadata.entries) : metadata;
873
+ const tasks = new Map((indexAnalysis.read()?.tasks ?? []).map((task) => [assistantSessionKey(task), task]));
874
+ const summary = summarizeAssistantEntries(index.entries, index.scope, index.generation, index.unreadableCount, 0);
875
+ const query = readOptionalService(context.services.dshContext, 'sessionQuery');
876
+ const snapshot = {
877
+ capturedAt: Date.now(),
878
+ index,
879
+ // 调试页不限制播报长度,复用摘要接口的范围状态和分组语义。
880
+ summary: index.analysis?.state === 'completed' && index.analysis.result !== undefined ? { ...summary, speechText: sanitizeSpeechText(speakAssistantStructuredIndex(index.analysis.result)) } : summary,
881
+ workspaces: [...readWorkspaceRecords(context.services.dshContext).map((workspace) => ({ workspaceId: workspace.id, name: workspace.name, path: workspace.path })), ...await readRemoteWorkspaces()],
882
+ modelId: readAssistantVoiceSettings(context.services).modelId ?? '',
883
+ warnings: source.warnings,
884
+ scopeSessions: metadata.entries.map((entry) => updates.stamp(entry, tasks.get(assistantSessionKey(entry)))),
885
+ indexState: readDebugIndexState(index, { building: buildingIndex !== undefined && buildingIndexRevision === indexRevision, exists: history.index !== undefined, current: lastSnapshot === history.index && matching && updates.matches(index) }),
886
+ indexedAt: matching ? history.indexedAt : null,
887
+ records: journal.snapshot().records,
888
+ services: {
889
+ workspaceList: typeof readOptionalService(context.services.dshContext, 'workspaceRegistry')?.list === 'function',
890
+ sessionList: typeof readOptionalService(context.services.dshContext, 'sessionController')?.list === 'function' || typeof query?.listSessions === 'function' || context.services.nativeSessions !== undefined,
891
+ summaryRead: typeof query?.readSurface === 'function',
892
+ taskDispatch: typeof readOptionalService(context.services.dshContext, 'sessionController')?.prompt === 'function',
893
+ remoteGateway: context.services.assistantGateway !== undefined,
894
+ },
895
+ };
896
+ return snapshot;
897
+ }
898
+ case 'preview': {
899
+ const request = readAssistantRequest(payload);
156
900
  const snapshot = await buildIndex();
157
- return summarizeAssistantEntries(snapshot.entries, snapshot.scope, snapshot.generation, snapshot.unreadableCount);
901
+ return {
902
+ generation: snapshot.generation,
903
+ intent: parseAssistantIntent(request.text, snapshot.entries, { indexGeneration: snapshot.generation, excludedTargets: snapshot.excludedTargets ?? [] }),
904
+ };
158
905
  }
159
906
  case 'turn': {
160
907
  const request = readAssistantRequest(payload);
@@ -174,48 +921,60 @@ export function createGlobalVoiceRpcFeature() {
174
921
  });
175
922
  return result;
176
923
  }
177
- case 'voice/capabilities':
924
+ case 'voice/capabilities': {
925
+ await tts.snapshot();
926
+ updateVoiceAgentCapabilities();
178
927
  return {
179
928
  ...coordinator.snapshot(),
929
+ capabilities: { ...runtime.capabilities, textToSpeech: tts.outputReady || runtime.capabilities.textToSpeech, streamingOutput: tts.outputReady || runtime.capabilities.streamingOutput },
180
930
  voiceAgent: agent.capabilities(),
181
931
  };
182
- case 'voice/setup': {
183
- const modelId = readVoiceModelId(payload);
184
- if (coordinator.snapshot().active || runtime.running) {
185
- throw new Error('请先停止当前实时语音,再更换语音模型');
186
- }
187
- const installed = await installAssistantVoiceModel(modelId);
188
- const current = readAssistantVoiceSettings(context.services);
189
- const next = {
190
- ...DEFAULT_ASSISTANT_VOICE_SETTINGS,
191
- ...current,
192
- initialized: true,
193
- provider: 'sherpa-onnx',
194
- modelId,
195
- asrEncoder: installed.paths.asrEncoder,
196
- asrDecoder: installed.paths.asrDecoder,
197
- asrJoiner: installed.paths.asrJoiner,
198
- asrTokens: installed.paths.asrTokens,
199
- // 实时对话使用浏览器输出;不让历史配置中的离线 VAD/TTS 偷偷生效。
200
- vadModel: '',
201
- ttsModel: '',
202
- ttsTokens: '',
203
- ttsLexicon: '',
204
- };
205
- if (context.services.settings === undefined)
206
- throw new Error('当前 Host 不支持保存语音设置');
207
- await context.services.settings.update({
208
- assistant: {
209
- ...context.services.settings.get().assistant,
210
- voice: next,
211
- },
932
+ }
933
+ case 'configuration/capabilities':
934
+ return { prepareOnly: true };
935
+ case 'voice/models':
936
+ return await models.snapshot(readAssistantVoiceSettings(context.services), {
937
+ running: runtime.running, ready: runtime.capabilities.realtime, operation: modelOperation,
212
938
  });
213
- runtime.configureEnvironment(buildSherpaRuntimeEnvironment(next));
939
+ case 'voice/initialization':
940
+ return await initialization.snapshot();
941
+ case 'voice/initialize': {
942
+ if (context.services.settings === undefined || context.services.settingsProvider?.writable === false)
943
+ throw new Error('当前语音设置不可写');
944
+ if (setupPending)
945
+ throw new Error('请等待当前识别模型操作完成');
946
+ if (isRecord(payload) && payload.prepareOnly === true) {
947
+ // 配置窗口只准备资源;识别路径和播报后端由统一保存提交。
948
+ const current = await initialization.snapshot();
949
+ const modelId = typeof payload.modelId === 'string' ? payload.modelId : current.modelId;
950
+ const prepared = current.recognitionReady && modelId === current.modelId ? { voice: readAssistantVoiceSettings(context.services) }
951
+ : await setupVoiceModel({ modelId, prepareOnly: true });
952
+ if (!current.tts.status.ready)
953
+ await tts.handle('tts/setup', { prepareOnly: true });
954
+ const ready = await initialization.snapshot();
955
+ return { ...ready, ready: true, recognitionReady: true, voice: prepared.voice,
956
+ tts: { ...ready.tts, settings: { ...ready.tts.settings, backend: 'moss-onnx' } } };
957
+ }
958
+ const result = await trackModel(() => initialization.initialize(modelAbort.signal));
214
959
  updateVoiceAgentCapabilities();
215
- return { modelId, downloaded: installed.downloaded };
960
+ return result;
961
+ }
962
+ case 'voice/model/verify':
963
+ if (initialization.busy)
964
+ throw new Error('请等待语音初次配置完成');
965
+ return await trackModel(() => verifyVoiceModel(payload));
966
+ case 'voice/setup':
967
+ if (initialization.busy)
968
+ throw new Error('请等待语音初次配置完成');
969
+ return await trackModel(() => setupVoiceModel(payload));
970
+ case 'voice/setup-progress': {
971
+ const requestId = readVoiceSetupRequestId(payload);
972
+ return requestId !== undefined && setupProgress?.requestId === requestId ? setupProgress.progress : null;
216
973
  }
217
974
  case 'voice/start':
218
975
  {
976
+ if (setupPending || initialization.busy)
977
+ throw new Error('请等待语音模型初始化完成,再启动实时语音');
219
978
  const ownerId = readOwner(payload);
220
979
  if (isRecord(payload) && payload.mode === 'fallback') {
221
980
  return {
@@ -242,10 +1001,30 @@ export function createGlobalVoiceRpcFeature() {
242
1001
  }
243
1002
  if (!coordinator.snapshot().active) {
244
1003
  runtime.configureEnvironment(buildSherpaRuntimeEnvironment(voiceSettings));
1004
+ // 只读最新元数据,不等 LLM 索引总结,也不读取会话正文;失败仍保留领域词。
1005
+ let hotwords = buildAssistantVoiceHotwords([], []);
1006
+ try {
1007
+ hotwords = await readAssistantVoiceHotwords(readManagementSnapshot);
1008
+ }
1009
+ catch (error) {
1010
+ traceVoice('host.asr.hotwords_source_error', { errorName: error instanceof Error ? error.name : 'UnknownError' });
1011
+ }
1012
+ runtime.configureHotwords(hotwords);
245
1013
  }
246
1014
  const snapshot = await coordinator.start(ownerId);
1015
+ tts.beginVoiceSession(ownerId);
1016
+ if (isRecord(payload) && typeof payload.voiceSessionId === 'string') {
1017
+ try {
1018
+ await conversation.beginVoiceSession(ownerId, payload.voiceSessionId);
1019
+ }
1020
+ catch (error) {
1021
+ await coordinator.stop(ownerId);
1022
+ throw error;
1023
+ }
1024
+ }
247
1025
  updateVoiceAgentCapabilities();
248
- return snapshot;
1026
+ traceVoice('host.call.started', { ownerId, epoch: snapshot.epoch, callId: isRecord(payload) && typeof payload.voiceSessionId === 'string' ? payload.voiceSessionId : undefined });
1027
+ return { ...snapshot, diagnosticsEnabled: diagnostics !== undefined };
249
1028
  }
250
1029
  catch (error) {
251
1030
  if (isVoiceRuntimeUnavailableError(error)) {
@@ -258,12 +1037,20 @@ export function createGlobalVoiceRpcFeature() {
258
1037
  throw error;
259
1038
  }
260
1039
  }
261
- case 'voice/stop':
1040
+ case 'voice/stop': {
1041
+ traceVoice('host.call.stopping', { ownerId: readOwner(payload), epoch: coordinator.snapshot().epoch });
1042
+ coordinator.assertOwner(readOwner(payload));
1043
+ await conversation.endVoiceSession(readOwner(payload));
1044
+ voiceChat.clear();
262
1045
  return await coordinator.stop(readOwner(payload));
1046
+ }
263
1047
  case 'voice/heartbeat':
264
1048
  return coordinator.heartbeat(readOwner(payload));
265
- case 'voice/interrupt':
1049
+ case 'voice/interrupt': {
1050
+ coordinator.assertOwner(readOwner(payload));
1051
+ voiceChat.cancelActive();
266
1052
  return await coordinator.interrupt(readOwner(payload));
1053
+ }
267
1054
  case 'voice/register-client': {
268
1055
  const ownerId = readOwner(payload);
269
1056
  const capabilities = readVoiceRuntimeCapabilities(payload);
@@ -281,21 +1068,49 @@ export function createGlobalVoiceRpcFeature() {
281
1068
  const sequence = isRecord(payload) && typeof payload.sequence === 'number' && Number.isFinite(payload.sequence) ? payload.sequence : undefined;
282
1069
  return coordinator.acceptClientEvent(ownerId, event, sequence);
283
1070
  }
284
- case 'voice/text': {
1071
+ case 'voice/chat/start':
1072
+ return await measureVoice('host.chat.start', { requestId: readChatRequestId(payload), ownerId: readOwner(payload) }, () => startVoiceChat(payload));
1073
+ case 'voice/diagnostics': {
1074
+ if (diagnostics === undefined)
1075
+ return { recorded: 0 };
285
1076
  const ownerId = readOwner(payload);
286
- coordinator.assertOwner(ownerId);
287
- const request = readAssistantRequest(payload);
288
- const result = await actionBridge.handleFinalText(request.text, request.requestId);
289
- debugInfo('codingns4dsh: assistant voice text resolved', {
290
- requestId: request.requestId,
291
- text: sanitizeSpeechText(request.text).slice(0, 1000),
292
- kind: result.kind,
293
- targetSessionId: result.target?.sessionId ?? null,
294
- targetHostId: result.target?.hostId ?? null,
295
- mode: result.mode ?? null,
296
- ok: result.kind !== 'clarify',
297
- });
298
- return result;
1077
+ const value = asRecord(payload);
1078
+ const records = value?.records;
1079
+ if (!Array.isArray(records) || records.length > 64)
1080
+ throw new Error('语音诊断每批最多 64 条记录');
1081
+ let recorded = 0;
1082
+ for (const item of records) {
1083
+ if (!isRecord(item) || typeof item.event !== 'string' || !item.event.startsWith('client.') || typeof item.timestamp !== 'number' || !Number.isFinite(item.timestamp) || Math.abs(item.timestamp - Date.now()) > 86400_000)
1084
+ continue;
1085
+ diagnostics.writer.record({ timestamp: item.timestamp, event: item.event, fields: { ...sanitizeVoiceDiagnosticFields(item.fields), ownerId } }, 'client');
1086
+ recorded++;
1087
+ }
1088
+ if (typeof value?.dropped === 'number' && value.dropped > 0)
1089
+ traceVoice('diagnostics.client_dropped', { ownerId, dropped: value.dropped });
1090
+ return { recorded };
1091
+ }
1092
+ case 'voice/chat/read': {
1093
+ const { ownerId, epoch } = readVoiceChatLease(payload);
1094
+ return voiceChat.read(ownerId, epoch, readChatRequestId(payload));
1095
+ }
1096
+ case 'voice/chat/cancel': {
1097
+ const { ownerId, epoch } = readVoiceChatLease(payload);
1098
+ voiceChat.cancel(ownerId, epoch, readChatRequestId(payload));
1099
+ return { cancelled: true };
1100
+ }
1101
+ case 'voice/chat/clear':
1102
+ readVoiceChatLease(payload);
1103
+ voiceChat.clear();
1104
+ await conversation.clear();
1105
+ return { cleared: true };
1106
+ case 'voice/text': {
1107
+ // 兼容旧客户端,但识别话语统一走 LLM,不再隐式触发关键词派发。
1108
+ const { ownerId, epoch } = readVoiceChatLease(payload);
1109
+ const run = await startVoiceChat(payload);
1110
+ const result = await voiceChat.wait(ownerId, epoch, run.requestId);
1111
+ if (result.state !== 'completed')
1112
+ throw new Error(result.error ?? '语音 LLM 对话已停止');
1113
+ return { kind: 'chat', speechText: result.text, requestId: result.requestId };
299
1114
  }
300
1115
  default:
301
1116
  throw new Error(`未知全局语音 RPC: assistant/${action}`);
@@ -304,6 +1119,20 @@ export function createGlobalVoiceRpcFeature() {
304
1119
  },
305
1120
  };
306
1121
  }
1122
+ /** 原始材料就绪和完整结构化索引就绪分别表示,失败时不启用问答。 */
1123
+ function readDebugIndexState(index, state) {
1124
+ if (state.building || index.analysis?.state === 'running')
1125
+ return 'building';
1126
+ if (!state.exists)
1127
+ return 'not-built';
1128
+ if (!state.current)
1129
+ return 'stale';
1130
+ if (index.entries.some((entry) => entry.indexState !== undefined && entry.indexState !== 'completed'))
1131
+ return 'incomplete';
1132
+ if (index.entries.length > 0 && (index.analysis?.state !== 'completed' || index.analysis.result?.sessions.length !== index.entries.length || index.analysis.tasks?.some((task) => task.state === 'deferred')))
1133
+ return 'incomplete';
1134
+ return 'ready';
1135
+ }
307
1136
  /**
308
1137
  * 在 Host Context 注册 CodingNS 自己的 voiceAgent 服务。
309
1138
  *
@@ -358,35 +1187,36 @@ function readAssistantRequest(payload) {
358
1187
  const requestId = typeof payload.requestId === 'string' && payload.requestId.trim() !== '' ? payload.requestId.trim() : `assistant-${randomUUID()}`;
359
1188
  return { text: payload.text.trim(), requestId };
360
1189
  }
361
- async function dispatchPrompt(services, request) {
1190
+ async function dispatchPrompt(services, request, signal = new AbortController().signal) {
362
1191
  const localHostId = process.env.CODINGNS4DSH_HOST_ID?.trim() || 'local-host';
363
- if (request.hostId !== undefined && request.hostId !== localHostId && services.assistantGateway !== undefined) {
364
- await services.assistantGateway.dispatch({ ...request, hostId: request.hostId });
1192
+ signal.throwIfAborted();
1193
+ if (request.hostId !== undefined && request.hostId !== localHostId) {
1194
+ if (services.assistantGateway === undefined)
1195
+ throw new Error('远端会话管理网关不可用');
1196
+ await services.assistantGateway.dispatch({ ...request, hostId: request.hostId }, signal);
365
1197
  return;
366
1198
  }
367
1199
  const controller = readOptionalService(services.dshContext, 'sessionController');
368
1200
  if (controller !== undefined && typeof controller.prompt === 'function') {
369
- await controller.prompt(request);
1201
+ const { hostId: _hostId, ...prompt } = request;
1202
+ await controller.prompt(prompt, signal);
370
1203
  return;
371
1204
  }
372
1205
  throw new Error('DSH sessionController.prompt 不可用,无法派发任务');
373
1206
  }
374
1207
  async function readAssistantSource(services, managedWorkspaceIds = [], waitingState) {
375
1208
  const ctx = services.dshContext;
1209
+ const warnings = [];
376
1210
  const query = readOptionalService(ctx, 'sessionQuery');
377
- const primaryValue = query !== undefined && typeof query.listSessions === 'function'
378
- ? await query.listSessions()
379
- : [];
380
- const primaryRecords = flattenSessionList(primaryValue);
381
- const bridgeSessions = managedWorkspaceIds.length > 0 && services.nativeSessions !== undefined
382
- ? await services.nativeSessions.listRemote()
383
- : [];
1211
+ const localSessions = await readLocalAssistantSessions(services, warnings);
384
1212
  const gatewayResult = services.assistantGateway === undefined || managedWorkspaceIds.length === 0
385
1213
  ? undefined
386
- : await services.assistantGateway.list(managedWorkspaceIds).catch(() => undefined);
1214
+ : await services.assistantGateway.list(managedWorkspaceIds).catch((error) => {
1215
+ warnings.push(`远端 Host 状态读取失败:${sanitizeSpeechText(error instanceof Error ? error.message : String(error)).slice(0, 500)}`);
1216
+ return undefined;
1217
+ });
387
1218
  const sessions = dedupeSessionRecords([
388
- ...primaryRecords,
389
- ...(primaryRecords.length === 0 ? flattenSessionList(bridgeSessions) : []),
1219
+ ...localSessions,
390
1220
  ...(gatewayResult?.sessions ?? []),
391
1221
  ]);
392
1222
  const workspaces = readWorkspaceRecords(ctx);
@@ -401,35 +1231,48 @@ async function readAssistantSource(services, managedWorkspaceIds = [], waitingSt
401
1231
  for (const [sessionId, kind] of waitingState?.snapshot() ?? [])
402
1232
  waitingBySession.set(sessionId, kind);
403
1233
  const hostId = process.env.CODINGNS4DSH_HOST_ID?.trim() || 'local-host';
1234
+ let unmappedSessionCount = 0;
404
1235
  const records = sessions.flatMap((raw) => {
405
1236
  const value = asRecord(raw);
406
1237
  const header = asRecord(value?.header) ?? value;
407
1238
  const sessionId = readText(header, ['sessionId', 'id', 'key']);
408
1239
  if (sessionId === null)
409
1240
  return [];
410
- // PeerHost Gateway 返回的摘要记录已经携带 workspaceId/hostId;本地
411
- // sessionQuery 记录才需要通过 workspaceRegistry 的成员关系或 cwd 反查。
412
- const workspaceId = readText(value, ['workspaceId']) ?? findWorkspaceId(sessionId, header, workspaces);
413
- if (workspaceId === null || !managed.has(workspaceId) || archivedSet.has(sessionId))
1241
+ // 子代理属于父会话,空白会话只是新会话占位;两者都不是可索引的独立对话。
1242
+ if (header?.origin === 'subagent' || value?.origin === 'subagent' || value?.blank === true || sessionId.startsWith(ASSISTANT_AGENT_PREFIX))
414
1243
  return [];
415
- const workspace = workspaceById.get(workspaceId);
416
- const sourceWorkspaceName = readText(value, ['workspaceName', 'workspaceDisplayName']);
417
1244
  const sourceHostId = readText(value, ['hostId', 'sourceHostId']) ?? hostId;
1245
+ // 本地工作区成员关系由 Registry 决定,cwd 相同不意味着它是工作区成员。
1246
+ // Gateway 已在远端按同一成员关系投影,保留其 workspaceId/hostId。
1247
+ const originalWorkspaceId = sourceHostId === hostId ? findWorkspaceId(sessionId, workspaces) : readText(value, ['workspaceId']);
1248
+ // 保留范围外和归档会话的元数据,索引构建器统一决定纳入/排除。
1249
+ // 不能提前丢掉这些记录,否则调试页和目标澄清都无法解释排除原因。
1250
+ if (originalWorkspaceId === null) {
1251
+ unmappedSessionCount += 1;
1252
+ return [];
1253
+ }
1254
+ const workspaceId = sourceHostId === hostId ? managedWorkspaceIds.find((selected) => assistantWorkspaceMatches(selected, hostId, originalWorkspaceId, true)) ?? originalWorkspaceId : originalWorkspaceId;
1255
+ const workspace = workspaceById.get(originalWorkspaceId);
1256
+ const sourceWorkspaceName = readText(value, ['workspaceName', 'workspaceDisplayName']);
1257
+ const agent = sourceHostId === hostId ? readOptionalService(ctx, 'agents')?.get?.(sessionId) : undefined;
418
1258
  const state = readText(value, ['state', 'status']) ?? '';
419
- const live = value?.live === true;
420
- const running = live || value?.running === true || /running|active|working/iu.test(state);
421
- // listSessions 的 persisted/live 只是可用性包装,不足以证明会话已完成;
422
- // 没有显式状态时保留 completed=false,由索引 status=unknown 表示未知。
423
- const completed = value?.completed === true || /completed|complete|done/iu.test(state);
1259
+ // live 只说明存在内存实例;真实运行状态从原生列表或 Agent 状态读取。
1260
+ const running = value?.running === true || /^(running|active|working|queued)$/iu.test(state);
1261
+ // persisted/live 只表示可用性;本轮完成由明确的空闲状态证明。
1262
+ const completed = value?.completed === true || /^(completed|complete|done|success)$/iu.test(state);
1263
+ // 实时 Agent 和 Gateway 的明确 activity 优先于可能滞后的列表布尔值。
1264
+ const activity = agent?.status === 'running' || agent?.status === 'idle' ? agent.status
1265
+ : ['running', 'idle', 'unknown'].includes(value?.activity) ? value.activity : running ? 'running' : value?.running === false || completed || /^(idle|error|failed|cancelled|canceled|stopped)$/iu.test(state) ? 'idle' : 'unknown';
424
1266
  return [{
425
1267
  sessionId,
426
1268
  workspaceId,
427
1269
  workspaceName: sourceWorkspaceName ?? workspace?.name ?? workspaceId,
428
1270
  hostId: sourceHostId,
429
- running: running && !completed,
430
- completed,
431
- error: value?.error === true || /error|failed/iu.test(state),
432
- updatedAt: readTimestamp(header, ['updatedAt', 'updated', 'lastUpdatedAt']),
1271
+ running: activity === 'running',
1272
+ activity,
1273
+ completed: activity === 'idle',
1274
+ error: value?.error === true || /^(error|failed)$/iu.test(state),
1275
+ updatedAt: readTimestamp(value, ['updatedAt', 'updated', 'lastUpdatedAt']) ?? readTimestamp(header, ['updatedAt', 'updated', 'lastUpdatedAt']),
433
1276
  waiting: readWaiting(value) ?? waitingBySession.get(sessionId) ?? null,
434
1277
  title: readText(value, ['title', 'name', 'displayName']),
435
1278
  titleEvents: readStringArray(value?.titleEvents),
@@ -437,6 +1280,8 @@ async function readAssistantSource(services, managedWorkspaceIds = [], waitingSt
437
1280
  }];
438
1281
  });
439
1282
  const readSurface = query !== undefined && typeof query.readSurface === 'function' ? query.readSurface.bind(query) : undefined;
1283
+ if (unmappedSessionCount > 0)
1284
+ warnings.push(`有${unmappedSessionCount}个会话无法确定所属工作区,未纳入索引,请检查工作区成员关系。`);
440
1285
  const readTitle = query !== undefined && typeof query.readTitle === 'function'
441
1286
  ? query.readTitle.bind(query)
442
1287
  : query !== undefined && typeof query.readTitleSnapshot === 'function'
@@ -447,7 +1292,7 @@ async function readAssistantSource(services, managedWorkspaceIds = [], waitingSt
447
1292
  : await Promise.all(records.map(async (record) => {
448
1293
  // Gateway 已经携带远端标题;本地 query 不能读取远端 Host 的 sessionId,
449
1294
  // 也不能把远端会话误当成本地会话产生一次额外 I/O。
450
- if (record.hostId !== hostId)
1295
+ if (record.hostId !== hostId || !managed.has(record.workspaceId) || archivedSet.has(record.sessionId))
451
1296
  return record;
452
1297
  const title = await readSessionTitle(readTitle, record.sessionId);
453
1298
  return title === null ? record : { ...record, title };
@@ -455,7 +1300,10 @@ async function readAssistantSource(services, managedWorkspaceIds = [], waitingSt
455
1300
  // workspaceRegistry 可能只暴露归档 ID,而 sessionQuery 不再返回归档记录。
456
1301
  // 为了给用户明确的“已归档”诊断,这里只建立没有正文的元数据占位,不读取归档日志。
457
1302
  const knownSessionIds = new Set(records.map((record) => `${record.hostId}:${record.sessionId}`));
458
- const archivedStubs = workspaces.flatMap((workspace) => workspace.archivedSessionIds.flatMap((sessionId) => {
1303
+ const archivedStubs = workspaces.flatMap((workspace) => [...new Set([
1304
+ ...workspace.archivedSessionIds,
1305
+ ...workspace.sessionIds.filter((sessionId) => archivedSet.has(sessionId)),
1306
+ ])].flatMap((sessionId) => {
459
1307
  const key = `${hostId}:${sessionId}`;
460
1308
  if (knownSessionIds.has(key))
461
1309
  return [];
@@ -471,31 +1319,11 @@ async function readAssistantSource(services, managedWorkspaceIds = [], waitingSt
471
1319
  title: null,
472
1320
  summary: null,
473
1321
  }];
474
- })).concat(sessions.flatMap((raw) => {
475
- const value = asRecord(raw);
476
- const header = asRecord(value?.header) ?? value;
477
- const sessionId = readText(header, ['sessionId', 'id', 'key']);
478
- const workspaceId = readText(value, ['workspaceId']);
479
- const sourceHostId = readText(value, ['hostId', 'sourceHostId']) ?? hostId;
480
- if (sessionId === null || workspaceId === null || sourceHostId === hostId || !managed.has(workspaceId) || !archivedSet.has(sessionId))
481
- return [];
482
- const workspace = workspaceById.get(workspaceId);
483
- return [{
484
- sessionId,
485
- workspaceId,
486
- workspaceName: readText(value, ['workspaceName', 'workspaceDisplayName']) ?? workspace?.name ?? workspaceId,
487
- hostId: sourceHostId,
488
- running: false,
489
- completed: false,
490
- updatedAt: null,
491
- waiting: null,
492
- title: readText(value, ['title', 'name', 'displayName']),
493
- summary: null,
494
- }];
495
1322
  }));
496
1323
  return {
497
1324
  sessions: [...hydratedRecords, ...archivedStubs],
498
1325
  archivedSessionIds: archived,
1326
+ warnings,
499
1327
  ...(gatewayResult?.volatile === true ? { volatile: true } : {}),
500
1328
  ...((readSurface === undefined && gatewayResult?.readSummary === undefined) ? {} : {
501
1329
  readSummary: async (session) => {
@@ -515,6 +1343,24 @@ async function readAssistantSource(services, managedWorkspaceIds = [], waitingSt
515
1343
  }),
516
1344
  };
517
1345
  }
1346
+ /** 原生列表提供 blank/origin 投影;原始日志目录只能作为旧版本的能力回退。 */
1347
+ async function readLocalAssistantSessions(services, warnings) {
1348
+ const controller = readOptionalService(services.dshContext, 'sessionController') ?? services.nativeSessions?.controller;
1349
+ if (typeof controller?.list === 'function') {
1350
+ try {
1351
+ return flattenSessionList(await controller.list({}));
1352
+ }
1353
+ catch {
1354
+ // 列表失败或列表为空都不能改用全量历史,否则会重新纳入被侧栏隐藏的会话。
1355
+ warnings.push('原生会话列表读取失败,暂不纳入本地会话;请刷新后重试。');
1356
+ return [];
1357
+ }
1358
+ }
1359
+ const query = readOptionalService(services.dshContext, 'sessionQuery');
1360
+ if (typeof query?.listSessions === 'function')
1361
+ return flattenSessionList(await query.listSessions());
1362
+ return services.nativeSessions === undefined ? [] : flattenSessionList(await services.nativeSessions.listRemote());
1363
+ }
518
1364
  async function readSessionTitle(readTitle, sessionId) {
519
1365
  try {
520
1366
  const value = await readTitle(sessionId);
@@ -567,9 +1413,12 @@ export function summarizeSurfaceEvents(events) {
567
1413
  continue;
568
1414
  const type = readText(event, ['type', 'kind', 'event']) ?? '';
569
1415
  const data = asRecord(event.data);
570
- const text = readEventText(event) ?? (data === null ? null : readEventText(data));
1416
+ const message = asRecord(data?.message) ?? asRecord(event.message) ?? data ?? event;
1417
+ const text = readEventText(message);
571
1418
  if (type === 'user/message' || type === 'user.message' || type === 'message/user') {
572
- if (text !== null)
1419
+ // v4 把运行时上下文也放在 user/message;只提取真实用户的消息。
1420
+ const source = asRecord(message.source);
1421
+ if ((source === null || source.kind === 'user') && text !== null)
573
1422
  latestUser = text;
574
1423
  }
575
1424
  else if (type === 'assistant/message' || type === 'assistant.message' || type === 'message/assistant') {
@@ -600,7 +1449,7 @@ function readEventText(value) {
600
1449
  if (typeof item === 'string')
601
1450
  return item;
602
1451
  const record = asRecord(item);
603
- return record === null ? '' : readText(record, ['text', 'content', 'value']) ?? '';
1452
+ return record === null || (record.type !== undefined && record.type !== 'text') ? '' : readText(record, ['text', 'content', 'value']) ?? '';
604
1453
  })
605
1454
  .join(' ')
606
1455
  .trim();
@@ -653,6 +1502,43 @@ function readWaitingSessionId(args) {
653
1502
  }
654
1503
  return null;
655
1504
  }
1505
+ /** 原生状态事件携带 Agent.session,旧 API 使用第一个 sessionId 字符串。 */
1506
+ function readIndexSessionId(args) {
1507
+ for (const item of args) {
1508
+ if (typeof item === 'string' && item !== '')
1509
+ return item;
1510
+ const value = asRecord(item);
1511
+ if (value === null)
1512
+ continue;
1513
+ const session = asRecord(value.session) ?? asRecord(asRecord(value.agent)?.session);
1514
+ const id = readText(value, ['sessionId', 'session_id']) ?? readText(session, ['id', 'sessionId']) ?? readText(asRecord(session?.header), ['id']) ?? readText(asRecord(value.header), ['id']);
1515
+ if (id !== null)
1516
+ return id;
1517
+ if (value.agent === undefined && value.request === undefined) {
1518
+ const direct = readText(value, ['id']);
1519
+ if (direct !== null)
1520
+ return direct;
1521
+ }
1522
+ }
1523
+ return null;
1524
+ }
1525
+ function readIndexRunning(event, args) {
1526
+ if (event === 'session/complete')
1527
+ return false;
1528
+ for (const item of args) {
1529
+ if (typeof item === 'boolean')
1530
+ return item;
1531
+ const value = asRecord(item);
1532
+ if (typeof value?.running === 'boolean')
1533
+ return value.running;
1534
+ const status = readText(value, ['status', 'state']) ?? (typeof item === 'string' && item !== args[0] ? item : '');
1535
+ if (/^(running|active|working|queued)$/iu.test(status))
1536
+ return true;
1537
+ if (/^(idle|completed|complete|done|success|error|failed|cancelled|canceled|stopped)$/iu.test(status))
1538
+ return false;
1539
+ }
1540
+ return null;
1541
+ }
656
1542
  function readWorkspaceRecords(ctx) {
657
1543
  const registry = readOptionalService(ctx, 'workspaceRegistry');
658
1544
  const list = registry !== undefined && typeof registry.list === 'function' ? registry.list() : [];
@@ -707,15 +1593,25 @@ function dedupeSessionRecords(values) {
707
1593
  }
708
1594
  return result;
709
1595
  }
710
- function findWorkspaceId(sessionId, header, workspaces) {
1596
+ function findWorkspaceId(sessionId, workspaces) {
711
1597
  for (const workspace of workspaces)
712
1598
  if (workspace.sessionIds.includes(sessionId))
713
1599
  return workspace.id;
714
- const cwd = readText(header, ['cwd']);
715
- if (cwd === null)
716
- return null;
717
- const candidate = workspaces.find((workspace) => workspace.path !== null && (cwd === workspace.path || cwd.startsWith(`${workspace.path}/`)));
718
- return candidate?.id ?? null;
1600
+ return null;
1601
+ }
1602
+ function sameManagedScope(index, managed) {
1603
+ const indexed = index.scope.status === 'empty' ? [] : index.scope.managedWorkspaceIds;
1604
+ return JSON.stringify([...new Set(indexed)].sort()) === JSON.stringify([...new Set(managed)].sort());
1605
+ }
1606
+ function sameIndexMembership(left, right) {
1607
+ const keys = (index) => index.entries.map((entry) => JSON.stringify([entry.hostId, entry.workspaceId, entry.sessionId])).sort();
1608
+ return JSON.stringify(keys(left)) === JSON.stringify(keys(right));
1609
+ }
1610
+ function readChatRequestId(payload) {
1611
+ const id = asRecord(payload)?.requestId;
1612
+ if (typeof id !== 'string' || id.length === 0 || id.length > 200)
1613
+ throw new Error('文本调试请求标识无效');
1614
+ return id;
719
1615
  }
720
1616
  function readAssistantVoiceSettings(services) {
721
1617
  const configured = services.settings?.get().assistant?.voice;
@@ -730,6 +1626,11 @@ function readVoiceModelId(payload) {
730
1626
  }
731
1627
  return payload.modelId.trim();
732
1628
  }
1629
+ /** 老客户端没有请求 ID 时仍可初始化;进度查询只接受具体请求的 ID。 */
1630
+ function readVoiceSetupRequestId(payload) {
1631
+ return isRecord(payload) && typeof payload.requestId === 'string' && payload.requestId.trim() !== ''
1632
+ ? payload.requestId.trim() : undefined;
1633
+ }
733
1634
  function validateAssistantVoiceSettings(settings) {
734
1635
  if (!settings.initialized)
735
1636
  return '请先完成全局语音助理初始化配置';
@@ -778,8 +1679,9 @@ function readOptionalService(ctx, name) {
778
1679
  function asRecord(value) {
779
1680
  return typeof value === 'object' && value !== null && !Array.isArray(value) ? value : null;
780
1681
  }
1682
+ /** 原生列表缺失元数据时,null 和 Map.get() 返回的 undefined 都表示没有字段。 */
781
1683
  function readText(value, keys) {
782
- if (value === null)
1684
+ if (value === null || value === undefined)
783
1685
  return null;
784
1686
  for (const key of keys)
785
1687
  if (typeof value[key] === 'string' && value[key].trim() !== '')
@@ -817,7 +1719,7 @@ function readVoiceRuntimeEvent(payload) {
817
1719
  const epoch = value !== null && typeof value.epoch === 'number' && Number.isFinite(value.epoch) ? value.epoch : null;
818
1720
  if (value === null || epoch === null || typeof value.type !== 'string')
819
1721
  throw new TypeError('全局语音 RPC 的 event 无效');
820
- const states = ['disabled', 'loading', 'standby', 'listening', 'speaking', 'interrupted', 'error'];
1722
+ const states = ['disabled', 'loading', 'standby', 'listening', 'thinking', 'speaking', 'interrupted', 'error'];
821
1723
  if (value.type === 'state' && states.includes(value.state))
822
1724
  return { type: 'state', state: value.state, epoch };
823
1725
  if (value.type === 'wake')
@@ -843,7 +1745,7 @@ function readWaiting(value) {
843
1745
  return null;
844
1746
  }
845
1747
  function readTimestamp(value, keys) {
846
- if (value === null)
1748
+ if (value === null || value === undefined)
847
1749
  return null;
848
1750
  for (const key of keys) {
849
1751
  if (typeof value[key] === 'number' && Number.isFinite(value[key]))