@xopcai/xopc 0.0.389 → 0.0.391

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 (321) hide show
  1. package/dist/browser-ext/manifest.json +1 -1
  2. package/dist/extensions/telegram/xopc.extension.json +1 -1
  3. package/dist/gateway/static/root/assets/{activity-store-dvik6t7Z.js → activity-store-DWQCDi8M.js} +1 -1
  4. package/dist/gateway/static/root/assets/{agent-avatar-dicebear-bWMd5TDC.js → agent-avatar-dicebear-CzS0TUv9.js} +1 -1
  5. package/dist/gateway/static/root/assets/agent-defaults-settings-panel-DE910MyU.js +1 -0
  6. package/dist/gateway/static/root/assets/{agent-plugin-dialog-UunIxc1q.js → agent-plugin-dialog-0SlvsYl7.js} +1 -1
  7. package/dist/gateway/static/root/assets/agents-BZh28Qn1.js +77 -0
  8. package/dist/gateway/static/root/assets/{agents-admin-api-BlNGyXpm.js → agents-admin-api-Bb3Kvz3X.js} +1 -1
  9. package/dist/gateway/static/root/assets/app-management-settings-panel-9A7JN5V5.js +1 -0
  10. package/dist/gateway/static/root/assets/{appearance-settings-CUAdx44v.js → appearance-settings-BPdLEo6L.js} +1 -1
  11. package/dist/gateway/static/root/assets/{apps-page-D5zDB6gp.js → apps-page-Cz7LypV9.js} +1 -1
  12. package/dist/gateway/static/root/assets/{archive-plugin-Du6dJNcl.js → archive-plugin-DFnHPNie.js} +1 -1
  13. package/dist/gateway/static/root/assets/{automations-page-BO8Ig5Z4.js → automations-page-CnBLPVNh.js} +1 -1
  14. package/dist/gateway/static/root/assets/automations-workspace-BBjS-sk-.js +6 -0
  15. package/dist/gateway/static/root/assets/{binary-plugins-D7VJjwnr.js → binary-plugins-BQC0Tzoi.js} +1 -1
  16. package/dist/gateway/static/root/assets/{block-editor-CaJlWTAn.js → block-editor-DSh5019z.js} +4 -4
  17. package/dist/gateway/static/root/assets/{browser-automation-inputs-iyMBJmQX.js → browser-automation-inputs-C5tIrIRL.js} +1 -1
  18. package/dist/gateway/static/root/assets/browser-automations-page-CFCMNfJN.js +3 -0
  19. package/dist/gateway/static/root/assets/browser-settings-page-C__tyPwu.js +3 -0
  20. package/dist/gateway/static/root/assets/{capabilities-CEH1AnXc.js → capabilities-D6RJG4QY.js} +1 -1
  21. package/dist/gateway/static/root/assets/{capabilities-MCKRMZDK.js → capabilities-DGEmBQnF.js} +1 -1
  22. package/dist/gateway/static/root/assets/capabilities-page-B5AZa7ir.js +2 -0
  23. package/dist/gateway/static/root/assets/capabilities-settings-panel-Dskz2_bh.js +8 -0
  24. package/dist/gateway/static/root/assets/{capability-header-actions-BIA0Lwt5.js → capability-header-actions-xzjWZVbg.js} +1 -1
  25. package/dist/gateway/static/root/assets/channels-DRse_dD3.js +1 -0
  26. package/dist/gateway/static/root/assets/chat-terminal-dock-CQF0M4kE.js +36 -0
  27. package/dist/gateway/static/root/assets/{computer-settings-page-DvY3zgyY.js → computer-settings-page-ZfzCTS0N.js} +1 -1
  28. package/dist/gateway/static/root/assets/{connector-service-page-St2-Fj3y.js → connector-service-page-CwAeWVLK.js} +1 -1
  29. package/dist/gateway/static/root/assets/connectors-page-CanakKaj.js +1 -0
  30. package/dist/gateway/static/root/assets/{date-picker-C0-D80ny.js → date-picker-hmJlEAQZ.js} +1 -1
  31. package/dist/gateway/static/root/assets/{dependency-picker-CNd7mwMU.js → dependency-picker-Us_Juz6I.js} +1 -1
  32. package/dist/gateway/static/root/assets/{desktop-pet-C-2wDANn.js → desktop-pet-CvOTI4uw.js} +1 -1
  33. package/dist/gateway/static/root/assets/{desktop-pet-settings-DyhxLrdJ.js → desktop-pet-settings-DYg-Gb8t.js} +1 -1
  34. package/dist/gateway/static/root/assets/device-pairing-wizard-B1FbZ8C1.js +1 -0
  35. package/dist/gateway/static/root/assets/{directory-picker-path-field-CNivVIPT.js → directory-picker-path-field-DZN9EDvM.js} +1 -1
  36. package/dist/gateway/static/root/assets/{extension-debug-page-CGYO3JPw.js → extension-debug-page-YIibp6Kk.js} +1 -1
  37. package/dist/gateway/static/root/assets/{extension-page-Dc51ALAg.js → extension-page-DkcGyb28.js} +1 -1
  38. package/dist/gateway/static/root/assets/{extension-provider-BXPILdlw.js → extension-provider-B1PQGTtY.js} +1 -1
  39. package/dist/gateway/static/root/assets/extension-settings-page-C_rJiSKo.js +1 -0
  40. package/dist/gateway/static/root/assets/{gateway-config-swr-Bc2MytsF.js → gateway-config-swr-Dv_A5FMu.js} +1 -1
  41. package/dist/gateway/static/root/assets/{gateway-realtime-BFK-vlME.js → gateway-realtime-DghCGfY_.js} +1 -1
  42. package/dist/gateway/static/root/assets/gateway-realtime-store-CMJVSnvi.js +1 -0
  43. package/dist/gateway/static/root/assets/gateway-settings-CjCWPHNJ.js +1 -0
  44. package/dist/gateway/static/root/assets/{gateway-startup-retry-BDPMttPx.js → gateway-startup-retry-CkTVSESs.js} +1 -1
  45. package/dist/gateway/static/root/assets/{highlighted-body-KQOG7T2V-DAlRGMge.js → highlighted-body-KQOG7T2V-DV2wNqBn.js} +1 -1
  46. package/dist/gateway/static/root/assets/home-page-fAYsd7kG.js +2 -0
  47. package/dist/gateway/static/root/assets/image-generation-api-B98iXt6A.js +1 -0
  48. package/dist/gateway/static/root/assets/imports-page-DoBCBN8G.js +1 -0
  49. package/dist/gateway/static/root/assets/index-DFgXwLsv.js +260 -0
  50. package/dist/gateway/static/root/assets/index-a6ZvhclR.css +1 -0
  51. package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-BYYC9Qmw.js → keyboard-shortcuts-settings-DXVu4lqV.js} +1 -1
  52. package/dist/gateway/static/root/assets/local-app-workbench-page-B3fz6uRi.js +1 -0
  53. package/dist/gateway/static/root/assets/{local-apps-page-BU8pUsVM.js → local-apps-page-BC6xhmUh.js} +1 -1
  54. package/dist/gateway/static/root/assets/{local-session-drafts-kFc_MAA9.js → local-session-drafts-DFnZQu9A.js} +1 -1
  55. package/dist/gateway/static/root/assets/{locale-store-Dr43FCty.js → locale-store-BpK9AiDq.js} +1 -1
  56. package/dist/gateway/static/root/assets/logs-page-CSqSFDRU.js +2 -0
  57. package/dist/gateway/static/root/assets/management-settings-gq5L0THs.js +1 -0
  58. package/dist/gateway/static/root/assets/{markdown-view-CdKlPjJM.js → markdown-view-IsYTotu6.js} +18 -18
  59. package/dist/gateway/static/root/assets/{media-plugins-DE9zt88i.js → media-plugins-oSChWbcP.js} +1 -1
  60. package/dist/gateway/static/root/assets/mermaid-MCJ5UELQ-C_QKwqDN.js +1 -0
  61. package/dist/gateway/static/root/assets/messages-CKTo_sIF.js +3 -0
  62. package/dist/gateway/static/root/assets/models-hub-cache-TjpL7hZ5.js +1 -0
  63. package/dist/gateway/static/root/assets/note-detail-panel-CdpNXre-.js +5 -0
  64. package/dist/gateway/static/root/assets/{notes-api-BHouNL6-.js → notes-api-CBb944yw.js} +1 -1
  65. package/dist/gateway/static/root/assets/notes-page-EGvGw8MN.js +8 -0
  66. package/dist/gateway/static/root/assets/{page-context-capture-button-TQr8NnSc.js → page-context-capture-button-CoWb7BYP.js} +1 -1
  67. package/dist/gateway/static/root/assets/personal-page-DYzbNTyN.js +1 -0
  68. package/dist/gateway/static/root/assets/{product-open-page-BEl6syFp.js → product-open-page-CTyy7H7-.js} +1 -1
  69. package/dist/gateway/static/root/assets/{product-preview-content-BxSHnbqz.js → product-preview-content-D4xqTaEy.js} +1 -1
  70. package/dist/gateway/static/root/assets/project-detail-page-DIVCw0QQ.js +1 -0
  71. package/dist/gateway/static/root/assets/projects-page-B4L9VnBN.js +1 -0
  72. package/dist/gateway/static/root/assets/{registry-api-BD5IgDOA.js → registry-api-Dsa2LvRt.js} +1 -1
  73. package/dist/gateway/static/root/assets/remote-access-hub-B8PvgLVz.js +1 -0
  74. package/dist/gateway/static/root/assets/{runtime-tools-api-CjTRoQWT.js → runtime-tools-api-C2Uw89eY.js} +1 -1
  75. package/dist/gateway/static/root/assets/runtime-tools-settings-panel-Bqnp3tyt.js +1 -0
  76. package/dist/gateway/static/root/assets/scenes-page-D50g4GM2.js +2 -0
  77. package/dist/gateway/static/root/assets/{schema-form-ByG-R6N2.js → schema-form-h_RCNfiO.js} +1 -1
  78. package/dist/gateway/static/root/assets/{send-session-input-UAVStisp.js → send-session-input-DypbVTT7.js} +1 -1
  79. package/dist/gateway/static/root/assets/{session-api-DvgEiNRS.js → session-api-ga-SUOq_.js} +1 -1
  80. package/dist/gateway/static/root/assets/{session-manager-BOb1tC_Z.js → session-manager-C_OiKblh.js} +8 -8
  81. package/dist/gateway/static/root/assets/sessions-page-BsqDIbIr.js +1 -0
  82. package/dist/gateway/static/root/assets/settings-advanced-gate-D3zJAW4p.js +1 -0
  83. package/dist/gateway/static/root/assets/{settings-page-C1e9m23j.js → settings-page-DPCgrICd.js} +1 -1
  84. package/dist/gateway/static/root/assets/setup-status-panel-jjSYJpDd.js +1 -0
  85. package/dist/gateway/static/root/assets/{share-link-dialog-kE_6v5Dp.js → share-link-dialog-BGicglAS.js} +1 -1
  86. package/dist/gateway/static/root/assets/{share-preview-page-BT-_yR1h.js → share-preview-page-BORe9rLB.js} +1 -1
  87. package/dist/gateway/static/root/assets/{shares-api-Dg_SqHQE.js → shares-api-Dbx3z6-1.js} +1 -1
  88. package/dist/gateway/static/root/assets/shares-settings-C13FgfWk.js +1 -0
  89. package/dist/gateway/static/root/assets/{skill-api-BslUYMnX.js → skill-api-Cq6O1DZK.js} +1 -1
  90. package/dist/gateway/static/root/assets/{skill-reload-api-BQ2rTOP1.js → skill-reload-api-Cq7QDjMA.js} +1 -1
  91. package/dist/gateway/static/root/assets/skills-page-BM1ShEjx.js +2 -0
  92. package/dist/gateway/static/root/assets/{system-settings-panel-GpbPfWwo.js → system-settings-panel-BNCGFO1e.js} +1 -1
  93. package/dist/gateway/static/root/assets/task-detail-page-4VG82wcF.js +2 -0
  94. package/dist/gateway/static/root/assets/{task-expandable-content-DJrrEBB4.js → task-expandable-content-DAZGz5YC.js} +1 -1
  95. package/dist/gateway/static/root/assets/{theme-store-BKpYnggg.js → theme-store-Db7hDESt.js} +1 -1
  96. package/dist/gateway/static/root/assets/{tracing-settings-page-D71w7dwV.js → tracing-settings-page-C6p2Mu92.js} +1 -1
  97. package/dist/gateway/static/root/assets/{tunnel-api-BV46CvS8.js → tunnel-api-Dw15EJp0.js} +1 -1
  98. package/dist/gateway/static/root/assets/usage-page-DDrIqgGe.js +1 -0
  99. package/dist/gateway/static/root/assets/{use-autosave-CzyqRffr.js → use-autosave-DDjIdW4U.js} +1 -1
  100. package/dist/gateway/static/root/assets/{use-composer-attachments-Dviq-1f6.js → use-composer-attachments-DNl7O3Vb.js} +1 -1
  101. package/dist/gateway/static/root/assets/{use-file-preview-expanded-D5Kk7Hon.js → use-file-preview-expanded-DMHehhwG.js} +2 -2
  102. package/dist/gateway/static/root/assets/user-model-page-CaS9dOIr.js +2 -0
  103. package/dist/gateway/static/root/assets/{voice-api-key-field-DWtbmacd.js → voice-api-key-field-ByAxHE4P.js} +1 -1
  104. package/dist/gateway/static/root/assets/{voice-config-api-DnIjZm_9.js → voice-config-api-Dl39b27p.js} +1 -1
  105. package/dist/gateway/static/root/assets/voice-transcribe-api-CVaU83Jc.js +1 -0
  106. package/dist/gateway/static/root/assets/{work-discovery-overlay-ChEG71hz.js → work-discovery-overlay-BvVvPA1T.js} +1 -1
  107. package/dist/gateway/static/root/assets/workflow-run-setup-panel-BcFm9QcC.js +3 -0
  108. package/dist/gateway/static/root/assets/workflows-page-DMec_XZB.js +6 -0
  109. package/dist/gateway/static/root/assets/{workspace-api-CZDvu7uA.js → workspace-api-BpfKsrtP.js} +2 -2
  110. package/dist/gateway/static/root/assets/{xopc-cloud-account-card-CbUgg1SK.js → xopc-cloud-account-card-CU5lzzE9.js} +1 -1
  111. package/dist/gateway/static/root/index.html +28 -35
  112. package/dist/package.js +1 -1
  113. package/dist/packages/gateway-contract/src/discussions.js +3 -2
  114. package/dist/packages/gateway-contract/src/index.js +4 -0
  115. package/dist/packages/gateway-contract/src/provider-setup.js +6 -0
  116. package/dist/packages/gateway-contract/src/recording-outcome.js +6 -0
  117. package/dist/packages/image-providers/src/catalog.js +10 -0
  118. package/dist/packages/image-providers/src/execute.js +5 -1
  119. package/dist/packages/image-providers/src/validation.js +19 -1
  120. package/dist/src/agent/agent-manager.d.ts +1 -0
  121. package/dist/src/agent/agent-manager.js +4 -1
  122. package/dist/src/agent/background-review/run-background-review.d.ts +0 -1
  123. package/dist/src/agent/background-review/run-background-review.js +10 -2
  124. package/dist/src/agent/context/execution-scope.js +1 -1
  125. package/dist/src/agent/embedded/execution-tool-policy.d.ts +2 -0
  126. package/dist/src/agent/embedded/execution-tool-policy.js +8 -3
  127. package/dist/src/agent/embedded/run-for-session.js +26 -3
  128. package/dist/src/agent/embedded/run-turn.js +14 -1
  129. package/dist/src/agent/embedded/session-runner.js +1 -1
  130. package/dist/src/agent/embedded/xopc-stream-bridge.js +3 -0
  131. package/dist/src/agent/image/generation/runtime.js +12 -14
  132. package/dist/src/agent/image/understanding/runtime.js +5 -0
  133. package/dist/src/agent/inbound/inbound-loop.d.ts +1 -15
  134. package/dist/src/agent/inbound/inbound-loop.js +5 -0
  135. package/dist/src/agent/mcp/connection-errors.d.ts +3 -0
  136. package/dist/src/agent/mcp/connection-errors.js +32 -0
  137. package/dist/src/agent/mcp/connection-setup.d.ts +2 -0
  138. package/dist/src/agent/mcp/connection-setup.js +38 -18
  139. package/dist/src/agent/memory/compaction.js +5 -1
  140. package/dist/src/agent/memory/idle-compaction-scheduler.js +3 -1
  141. package/dist/src/agent/models/manager.d.ts +1 -0
  142. package/dist/src/agent/models/manager.js +4 -2
  143. package/dist/src/agent/orchestration/agent-orchestrator.d.ts +1 -6
  144. package/dist/src/agent/orchestration/agent-orchestrator.js +5 -0
  145. package/dist/src/agent/service/process-direct-one-shot.js +5 -0
  146. package/dist/src/agent/service/process-direct-streaming.d.ts +1 -0
  147. package/dist/src/agent/service/process-direct-streaming.js +17 -1
  148. package/dist/src/agent/tools/factory.js +14 -12
  149. package/dist/src/agent/tools/image-generate-tool.js +5 -1
  150. package/dist/src/agent/tools/personal-read-tool.js +4 -0
  151. package/dist/src/agent/tools/task-collaboration-tool.js +1 -1
  152. package/dist/src/agent-config/resolver.js +5 -0
  153. package/dist/src/agent-config/schema.d.ts +26 -6
  154. package/dist/src/agent-config/schema.js +2 -0
  155. package/dist/src/ai-assist/text-assist.js +5 -16
  156. package/dist/src/automations/service/action-executor.js +3 -1
  157. package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
  158. package/dist/src/config/agent-model-intents.js +4 -1
  159. package/dist/src/config/schema.d.ts +11 -5
  160. package/dist/src/config/schema.js +11 -3
  161. package/dist/src/discussions/analyzer.d.ts +2 -0
  162. package/dist/src/discussions/analyzer.js +38 -9
  163. package/dist/src/discussions/audio-clip.d.ts +3 -0
  164. package/dist/src/discussions/audio-clip.js +72 -0
  165. package/dist/src/discussions/live-worker.js +3 -1
  166. package/dist/src/discussions/long-review.d.ts +17 -0
  167. package/dist/src/discussions/long-review.js +278 -0
  168. package/dist/src/discussions/media-timeline.d.ts +21 -0
  169. package/dist/src/discussions/media-timeline.js +134 -0
  170. package/dist/src/discussions/organizer-worker.d.ts +4 -1
  171. package/dist/src/discussions/organizer-worker.js +17 -12
  172. package/dist/src/discussions/organizer.js +2 -0
  173. package/dist/src/discussions/processing.d.ts +43 -0
  174. package/dist/src/discussions/processing.js +125 -0
  175. package/dist/src/discussions/recording.js +202 -42
  176. package/dist/src/discussions/recordingJobs.js +2 -0
  177. package/dist/src/discussions/repository.js +4 -2
  178. package/dist/src/discussions/review.d.ts +8 -0
  179. package/dist/src/discussions/review.js +183 -0
  180. package/dist/src/discussions/sealer.d.ts +7 -1
  181. package/dist/src/discussions/sealer.js +163 -87
  182. package/dist/src/discussions/service.d.ts +7 -1
  183. package/dist/src/discussions/service.js +51 -15
  184. package/dist/src/discussions/types.d.ts +2 -1
  185. package/dist/src/gateway/agent-builtin-tools.d.ts +1 -1
  186. package/dist/src/gateway/global-defaults-admin.d.ts +3 -1
  187. package/dist/src/gateway/global-defaults-admin.js +14 -2
  188. package/dist/src/gateway/hono/lib/config-payload.d.ts +11 -2
  189. package/dist/src/gateway/hono/lib/config-payload.js +2 -0
  190. package/dist/src/gateway/hono/lib/voice-settings-revisions.d.ts +5 -0
  191. package/dist/src/gateway/hono/lib/voice-settings-revisions.js +24 -0
  192. package/dist/src/gateway/hono/routes/commands-skills.js +15 -0
  193. package/dist/src/gateway/hono/routes/config-patch/misc.js +8 -1
  194. package/dist/src/gateway/hono/routes/config.js +12 -0
  195. package/dist/src/gateway/hono/routes/discussions.js +63 -1
  196. package/dist/src/gateway/hono/routes/global-defaults.js +8 -1
  197. package/dist/src/gateway/hono/routes/models.js +12 -4
  198. package/dist/src/gateway/hono/routes/provider-setup.d.ts +3 -0
  199. package/dist/src/gateway/hono/routes/provider-setup.js +106 -0
  200. package/dist/src/gateway/hono/routes/status.js +2 -0
  201. package/dist/src/gateway/hono/routes/voice.js +23 -10
  202. package/dist/src/gateway/provider-model-setup.d.ts +4 -0
  203. package/dist/src/gateway/provider-model-setup.js +56 -0
  204. package/dist/src/gateway/service/config-coordinator.d.ts +2 -2
  205. package/dist/src/gateway/service.js +2 -0
  206. package/dist/src/media-shared/http/provider-http.d.ts +0 -6
  207. package/dist/src/media-shared/http/provider-http.js +5 -4
  208. package/dist/src/media-understanding/runner.d.ts +0 -28
  209. package/dist/src/media-understanding/runner.js +4 -0
  210. package/dist/src/platform/client.d.ts +1 -1
  211. package/dist/src/platform/contracts.d.ts +1 -1
  212. package/dist/src/providers/env-keys.js +3 -0
  213. package/dist/src/providers/extension-stream-bridge.js +3 -0
  214. package/dist/src/providers/index.js +15 -0
  215. package/dist/src/providers/model-call.d.ts +5 -2
  216. package/dist/src/providers/model-call.js +13 -2
  217. package/dist/src/providers/model-reference-auditor.js +1 -0
  218. package/dist/src/providers/model-response.js +1 -1
  219. package/dist/src/providers/model-usage.d.ts +15 -0
  220. package/dist/src/providers/model-usage.js +50 -0
  221. package/dist/src/providers/presentation.js +8 -0
  222. package/dist/src/providers/setup/engine.d.ts +37 -0
  223. package/dist/src/providers/setup/engine.js +177 -0
  224. package/dist/src/providers/setup/profiles.d.ts +4 -0
  225. package/dist/src/providers/setup/profiles.js +78 -0
  226. package/dist/src/providers/setup/voice.d.ts +23 -0
  227. package/dist/src/providers/setup/voice.js +234 -0
  228. package/dist/src/scenes/agentExecutor.d.ts +1 -0
  229. package/dist/src/scenes/agentExecutor.js +5 -0
  230. package/dist/src/storage/sqlite/migrations/253_discussion_processing_recovery.sql +20 -0
  231. package/dist/src/storage/sqlite/migrations/254_discussion_annotations.sql +17 -0
  232. package/dist/src/storage/sqlite/migrations/255_discussion_chapter_progress.sql +10 -0
  233. package/dist/src/storage/sqlite/migrations/256_task_main_update_retries.sql +21 -0
  234. package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
  235. package/dist/src/storage/sqlite/migrations/runner.js +3 -3
  236. package/dist/src/storage/sqlite/schema.js +1 -1
  237. package/dist/src/tasks/task-collaboration-repository.d.ts +2 -0
  238. package/dist/src/tasks/task-collaboration-repository.js +7 -1
  239. package/dist/src/tasks/task-main-update-delivery.js +11 -4
  240. package/dist/src/tasks/task-main-update-input.js +2 -1
  241. package/dist/src/tasks/task-main-update-retry.d.ts +5 -0
  242. package/dist/src/tasks/task-main-update-retry.js +15 -0
  243. package/dist/src/usage/recorder.js +2 -1
  244. package/dist/src/usage/scenario-registry.js +128 -123
  245. package/dist/src/voice/dashscope/streaming-stt-session.js +3 -0
  246. package/dist/src/voice/dashscope/streaming-tts-stream.js +3 -0
  247. package/dist/src/voice/dictation.d.ts +12 -0
  248. package/dist/src/voice/dictation.js +22 -0
  249. package/dist/src/voice/metadata/builtin.js +54 -0
  250. package/dist/src/voice/platform-streams.js +3 -0
  251. package/dist/src/voice/realtime/omniEngine.js +3 -0
  252. package/dist/src/voice/realtime/omniRoute.js +3 -2
  253. package/dist/src/voice/realtime/runtime.js +4 -2
  254. package/dist/src/voice/stt/factory.js +9 -3
  255. package/dist/src/voice/stt/providers/bailian-plan-transcription.d.ts +2 -0
  256. package/dist/src/voice/stt/providers/bailian-plan-transcription.js +32 -0
  257. package/dist/src/voice/stt/providers/index.d.ts +1 -0
  258. package/dist/src/voice/stt/providers/index.js +2 -1
  259. package/dist/src/voice/token-plan.d.ts +8 -0
  260. package/dist/src/voice/token-plan.js +11 -0
  261. package/dist/src/voice/tts/factory.js +4 -1
  262. package/dist/src/voice/tts/providers/bailian-plan-speech.d.ts +2 -0
  263. package/dist/src/voice/tts/providers/bailian-plan-speech.js +84 -0
  264. package/dist/src/voice/tts/providers/index.d.ts +1 -0
  265. package/dist/src/voice/tts/providers/index.js +2 -1
  266. package/dist/src/voice/tts/speak-core.js +10 -1
  267. package/package.json +2 -2
  268. package/dist/gateway/static/root/assets/agent-defaults-settings-panel-Ds0Ue2FB.js +0 -1
  269. package/dist/gateway/static/root/assets/agents-BLRM4o-U.js +0 -77
  270. package/dist/gateway/static/root/assets/app-management-settings-panel-Dmy828Pe.js +0 -1
  271. package/dist/gateway/static/root/assets/automations-workspace-UcCneEs3.js +0 -6
  272. package/dist/gateway/static/root/assets/bot-DjLkhyZL.js +0 -1
  273. package/dist/gateway/static/root/assets/browser-automations-page-BjvQnYfO.js +0 -3
  274. package/dist/gateway/static/root/assets/browser-settings-page-D5ZghI28.js +0 -3
  275. package/dist/gateway/static/root/assets/capabilities-page-MC8qIrXo.js +0 -2
  276. package/dist/gateway/static/root/assets/capabilities-settings-panel-Blz3hEzp.js +0 -8
  277. package/dist/gateway/static/root/assets/channels-DSg_iCVC.js +0 -1
  278. package/dist/gateway/static/root/assets/chat-terminal-dock-C97SJEwd.js +0 -36
  279. package/dist/gateway/static/root/assets/circle-pause-CN9jYH2s.js +0 -1
  280. package/dist/gateway/static/root/assets/clock-3-DnrAnuyZ.js +0 -1
  281. package/dist/gateway/static/root/assets/connectors-page-DXk-GAsd.js +0 -1
  282. package/dist/gateway/static/root/assets/device-pairing-wizard-BeSuq__I.js +0 -1
  283. package/dist/gateway/static/root/assets/extension-settings-page-jYu6qpY2.js +0 -1
  284. package/dist/gateway/static/root/assets/fallback-models-CoyzvDo7.js +0 -1
  285. package/dist/gateway/static/root/assets/gateway-realtime-store-C3vH-Iup.js +0 -1
  286. package/dist/gateway/static/root/assets/gateway-settings-JlT1dlSj.js +0 -1
  287. package/dist/gateway/static/root/assets/git-branch-Dh9uxTot.js +0 -1
  288. package/dist/gateway/static/root/assets/home-page-DOVl8s-1.js +0 -2
  289. package/dist/gateway/static/root/assets/image-generation-api-BZBiYDmV.js +0 -1
  290. package/dist/gateway/static/root/assets/imports-page-DgdBTp_0.js +0 -1
  291. package/dist/gateway/static/root/assets/index-CmC8JkSM.js +0 -260
  292. package/dist/gateway/static/root/assets/index-Dgzc0oBu.css +0 -1
  293. package/dist/gateway/static/root/assets/local-app-workbench-page-BKZfn-MS.js +0 -1
  294. package/dist/gateway/static/root/assets/logs-page-BSepiACn.js +0 -2
  295. package/dist/gateway/static/root/assets/management-settings-dE_ykPNY.js +0 -1
  296. package/dist/gateway/static/root/assets/mermaid-MCJ5UELQ-65SE6j-_.js +0 -1
  297. package/dist/gateway/static/root/assets/message-square-fVE7Ghj1.js +0 -1
  298. package/dist/gateway/static/root/assets/messages-DlTNQI92.js +0 -3
  299. package/dist/gateway/static/root/assets/models-hub-cache-C7FAsEe_.js +0 -1
  300. package/dist/gateway/static/root/assets/note-detail-panel-D9oqhdyk.js +0 -5
  301. package/dist/gateway/static/root/assets/notes-page-Bd4_7ph8.js +0 -8
  302. package/dist/gateway/static/root/assets/pause-DuPxgSxk.js +0 -1
  303. package/dist/gateway/static/root/assets/personal-page-BvWzq4Wp.js +0 -1
  304. package/dist/gateway/static/root/assets/play-kxZvpBg8.js +0 -1
  305. package/dist/gateway/static/root/assets/project-detail-page-D-qkIXVT.js +0 -1
  306. package/dist/gateway/static/root/assets/projects-page-BQtw1Dfn.js +0 -1
  307. package/dist/gateway/static/root/assets/remote-access-hub-CYFNz0Jc.js +0 -1
  308. package/dist/gateway/static/root/assets/runtime-tools-settings-panel-Qq_NyYx_.js +0 -1
  309. package/dist/gateway/static/root/assets/scenes-page-hGr-ppYk.js +0 -2
  310. package/dist/gateway/static/root/assets/sessions-page-CpX1Rluw.js +0 -1
  311. package/dist/gateway/static/root/assets/settings-advanced-gate-D2s_MlxR.js +0 -1
  312. package/dist/gateway/static/root/assets/settings-loading-skeleton-BTqvr_Fw.js +0 -1
  313. package/dist/gateway/static/root/assets/setup-status-panel-BiHRYDHq.js +0 -1
  314. package/dist/gateway/static/root/assets/shares-settings-DfcAu08T.js +0 -1
  315. package/dist/gateway/static/root/assets/skills-page-CvKc5nBN.js +0 -2
  316. package/dist/gateway/static/root/assets/sparkles-DHlfQFAF.js +0 -1
  317. package/dist/gateway/static/root/assets/task-detail-page-5B5ZVAu0.js +0 -2
  318. package/dist/gateway/static/root/assets/usage-page-rMuwNpJi.js +0 -1
  319. package/dist/gateway/static/root/assets/user-model-page-Dhqw3v_u.js +0 -2
  320. package/dist/gateway/static/root/assets/workflow-run-setup-panel-pdiRKLxP.js +0 -3
  321. package/dist/gateway/static/root/assets/workflows-page-D9LMxINt.js +0 -6
@@ -0,0 +1,72 @@
1
+ import { spawnProcess } from "../process/run-process.js";
2
+ import { DiscussionServiceError } from "./errors.js";
3
+ import { getDiscussionCapture } from "./repository.js";
4
+ //#region src/discussions/audio-clip.ts
5
+ let active = 0;
6
+ /** A bounded playback derivative for native clients that require per-request device proofs. */
7
+ async function discussionAudioClip(id, startMs, endMs, notes, signal) {
8
+ if (!Number.isFinite(startMs) || !Number.isFinite(endMs) || startMs < 0 || endMs <= startMs || endMs - startMs > 12e4) throw new DiscussionServiceError("invalid_input", "Audio clip must be at most 120 seconds");
9
+ const capture = getDiscussionCapture(id);
10
+ if (!capture || !capture.audioAttachmentId || capture.audioDeletedAt) throw new DiscussionServiceError("not_found", "Original audio unavailable");
11
+ const source = await notes.getAttachmentPath(capture.noteId, capture.audioAttachmentId);
12
+ if (!source) throw new DiscussionServiceError("not_found", "Original audio unavailable");
13
+ if (active >= 2) throw new DiscussionServiceError("conflict", "Audio playback is busy; retry shortly");
14
+ active++;
15
+ try {
16
+ return await new Promise((resolve, reject) => {
17
+ signal.throwIfAborted();
18
+ const handle = spawnProcess({
19
+ program: process.env.XOPC_FFMPEG_PATH || "ffmpeg",
20
+ args: [
21
+ "-v",
22
+ "error",
23
+ "-protocol_whitelist",
24
+ "file,pipe",
25
+ "-ss",
26
+ String(startMs / 1e3),
27
+ "-i",
28
+ source.filePath,
29
+ "-t",
30
+ String((endMs - startMs) / 1e3),
31
+ "-map",
32
+ "0:a:0",
33
+ "-vn",
34
+ "-ar",
35
+ "16000",
36
+ "-ac",
37
+ "1",
38
+ "-f",
39
+ "wav",
40
+ "pipe:1"
41
+ ],
42
+ maxOutputBytes: 0
43
+ });
44
+ const child = handle.child;
45
+ const chunks = [];
46
+ let bytes = 0;
47
+ const abort = () => {
48
+ handle.terminate();
49
+ reject(/* @__PURE__ */ new Error("Audio clip interrupted"));
50
+ };
51
+ const timer = setTimeout(abort, 3e4);
52
+ timer.unref();
53
+ signal.addEventListener("abort", abort, { once: true });
54
+ child.stdout?.on("data", (chunk) => {
55
+ bytes += chunk.length;
56
+ if (bytes > 4 * 1024 * 1024) abort();
57
+ else chunks.push(chunk);
58
+ });
59
+ child.once("error", reject);
60
+ child.once("close", (code) => {
61
+ clearTimeout(timer);
62
+ signal.removeEventListener("abort", abort);
63
+ if (code || bytes <= 44) reject(/* @__PURE__ */ new Error("Audio clip unavailable"));
64
+ else resolve(Buffer.concat(chunks));
65
+ });
66
+ });
67
+ } finally {
68
+ active--;
69
+ }
70
+ }
71
+ //#endregion
72
+ export { discussionAudioClip };
@@ -1,6 +1,7 @@
1
1
  import { createLogger } from "../utils/logger/index.js";
2
2
  import { init_logger } from "../utils/logger.js";
3
3
  import { ObjectLinkService } from "../activity/service.js";
4
+ import { init_model_usage, withModelUsageOrigin } from "../providers/model-usage.js";
4
5
  import { transcribe } from "../voice/stt/transcribe-core.js";
5
6
  import { isSTTAvailable } from "../voice/stt/availability.js";
6
7
  import { mergeSttConfigFromAppConfig } from "../voice/stt/config.js";
@@ -11,6 +12,7 @@ import { enrichLiveDiscussion } from "./analyzer.js";
11
12
  import { acceptRankedProject, findExactProjectMention } from "./project-inference.js";
12
13
  import { randomUUID } from "node:crypto";
13
14
  //#region src/discussions/live-worker.ts
15
+ init_model_usage();
14
16
  init_logger();
15
17
  const log = createLogger("DiscussionLiveWorker");
16
18
  const MAX_ATTEMPTS = 3;
@@ -58,7 +60,7 @@ var DiscussionLiveWorker = class {
58
60
  if (!segment) return;
59
61
  try {
60
62
  try {
61
- const result = this.deps.transcribeSegment ? await this.deps.transcribeSegment(segment.audioBuffer) : await this.transcribeSegment(segment.audioBuffer);
63
+ const result = await withModelUsageOrigin("interactive", () => this.deps.transcribeSegment ? this.deps.transcribeSegment(segment.audioBuffer) : this.transcribeSegment(segment.audioBuffer));
62
64
  const completed = completeDiscussionTranscriptSegment(segment.discussionId, segment.sequence, this.owner, result.text.trim(), result.provider);
63
65
  if (!completed) return;
64
66
  this.deps.onTranscriptUpdated?.(completed);
@@ -0,0 +1,17 @@
1
+ import type { DiscussionOrganization, DiscussionReview, DiscussionPlaybackRange } from '@xopcai/gateway-contract';
2
+ import type { NotesService } from '../notes/service.js';
3
+ export type ChapterScope = {
4
+ source: string;
5
+ revision: number;
6
+ transcript: string;
7
+ };
8
+ export declare function chapterScope(id: string): ChapterScope;
9
+ export declare function saveReviewChapter(id: string, hash: string, position: number, chapter: DiscussionOrganization, scope: ChapterScope): void;
10
+ /** Union, rather than the latest timestamp or sum, describes verified coverage. */
11
+ export declare function unionReviewRanges(ranges: DiscussionPlaybackRange[], duration: number): DiscussionPlaybackRange[];
12
+ export declare function longRecordingReview(id: string, notes: NotesService, options?: {
13
+ query?: string;
14
+ offset?: number;
15
+ limit?: number;
16
+ version?: string;
17
+ }): Promise<DiscussionReview>;
@@ -0,0 +1,278 @@
1
+ import { getSqliteDatabase, init_transaction, runSqliteWriteTransaction } from "../storage/sqlite/transaction.js";
2
+ import { DiscussionServiceError } from "./errors.js";
3
+ import { getDiscussionCapture, getLatestDiscussionOrganization, listDiscussionTranscriptSegments } from "./repository.js";
4
+ import { readTranscriptRevision } from "./revisions.js";
5
+ import { getProcessingRun } from "./processing.js";
6
+ import { playbackRanges, pointToPcm } from "./media-timeline.js";
7
+ import { listAnnotations, recordingTimeline } from "./review.js";
8
+ import { createHash } from "node:crypto";
9
+ //#region src/discussions/long-review.ts
10
+ init_transaction();
11
+ function chapterScope(id) {
12
+ const capture = getDiscussionCapture(id);
13
+ return {
14
+ source: capture.audioSha256 ?? "",
15
+ revision: capture.transcriptRevision,
16
+ transcript: capture.canonicalTranscriptSha256 ?? ""
17
+ };
18
+ }
19
+ function saveReviewChapter(id, hash, position, chapter, scope) {
20
+ runSqliteWriteTransaction((db) => {
21
+ if (JSON.stringify(chapterScope(id)) !== JSON.stringify(scope)) return;
22
+ db.prepare(`DELETE FROM discussion_chapter_progress WHERE discussion_id=? AND source_sha256=? AND transcript_revision=? AND transcript_sha256=? AND position=?`).run(id, scope.source, scope.revision, scope.transcript, position);
23
+ db.prepare("INSERT OR REPLACE INTO discussion_chapter_progress VALUES (?,?,?,?,?,?,?)").run(id, scope.source, scope.revision, scope.transcript, hash, position, JSON.stringify(chapter));
24
+ });
25
+ }
26
+ /** Union, rather than the latest timestamp or sum, describes verified coverage. */
27
+ function unionReviewRanges(ranges, duration) {
28
+ const sorted = ranges.filter((r) => Number.isFinite(r.startedAtMs) && Number.isFinite(r.endedAtMs) && r.endedAtMs > r.startedAtMs).map((r) => ({
29
+ startedAtMs: Math.max(0, r.startedAtMs),
30
+ endedAtMs: Math.min(duration, r.endedAtMs)
31
+ })).filter((r) => r.endedAtMs > r.startedAtMs).sort((a, b) => a.startedAtMs - b.startedAtMs);
32
+ const output = [];
33
+ for (const range of sorted) {
34
+ const last = output.at(-1);
35
+ if (last && range.startedAtMs <= last.endedAtMs) last.endedAtMs = Math.max(last.endedAtMs, range.endedAtMs);
36
+ else output.push({ ...range });
37
+ }
38
+ return output;
39
+ }
40
+ const fold = (value) => value.normalize("NFKC").toLocaleLowerCase();
41
+ function excerpt(text, query) {
42
+ if (text.length <= 700) return text;
43
+ const at = query ? Math.max(0, fold(text).indexOf(query) - 180) : 0;
44
+ return `${at ? "…" : ""}${text.slice(at, at + 700)}${at + 700 < text.length ? "…" : ""}`;
45
+ }
46
+ async function longRecordingReview(id, notes, options = {}) {
47
+ const capture = getDiscussionCapture(id);
48
+ if (!capture) throw new DiscussionServiceError("not_found", "Discussion not found");
49
+ const query = (options.query ?? "").trim();
50
+ const offset = options.offset ?? 0;
51
+ const limit = options.limit ?? 20;
52
+ if (query.length > 200 || !Number.isSafeInteger(offset) || offset < 0 || offset > 1e5 || !Number.isSafeInteger(limit) || limit < 1 || limit > 50) throw new DiscussionServiceError("invalid_input", "Invalid review query or pagination");
53
+ const sourceSegments = listDiscussionTranscriptSegments(id).filter((s) => s.status === "confirmed");
54
+ const record = getLatestDiscussionOrganization(id);
55
+ const organization = record?.organization;
56
+ const duration = capture.durationMs ?? Math.max(0, ...sourceSegments.map((s) => s.endedAtMs));
57
+ const run = getProcessingRun(id);
58
+ const checkpoints = run && run.audio_sha256 === (capture.audioSha256 ?? null) ? getSqliteDatabase().prepare("SELECT started_at_ms,ended_at_ms,result_json FROM discussion_transcription_checkpoints WHERE run_id=? ORDER BY started_at_ms").all(run.run_id) : [];
59
+ const scope = chapterScope(id);
60
+ const partialChapters = getSqliteDatabase().prepare(`SELECT chapter_json FROM discussion_chapter_progress WHERE discussion_id=? AND source_sha256=? AND transcript_revision=? AND transcript_sha256=? ORDER BY position`).all(id, scope.source, scope.revision, scope.transcript).map((row) => JSON.parse(row.chapter_json));
61
+ const timeline = await recordingTimeline(id, notes);
62
+ const attachment = capture.audioAttachmentId && !capture.audioDeletedAt ? await notes.getAttachmentPath(capture.noteId, capture.audioAttachmentId) : null;
63
+ const playable = (start, end) => attachment && timeline ? playbackRanges(timeline, start, end) : [];
64
+ const segment = (s) => ({
65
+ sequence: s.sequence,
66
+ startedAtMs: s.startedAtMs,
67
+ endedAtMs: s.endedAtMs,
68
+ text: s.displayText ?? s.rawText ?? "",
69
+ speakerLabel: s.speakerLabel,
70
+ playback: playable(s.startedAtMs, s.endedAtMs)
71
+ });
72
+ const entries = sourceSegments.map((s, index) => ({
73
+ id: `transcript:${capture.transcriptRevision}:${s.sequence}`,
74
+ kind: "transcript",
75
+ title: s.speakerLabel ?? "",
76
+ text: s.displayText ?? s.rawText ?? "",
77
+ transcriptRevision: capture.transcriptRevision,
78
+ provisional: false,
79
+ stale: false,
80
+ startedAtMs: s.startedAtMs,
81
+ endedAtMs: s.endedAtMs,
82
+ segments: sourceSegments.slice(Math.max(0, index - 1), index + 2).map(segment),
83
+ playback: playable(Math.max(0, s.startedAtMs - 3e3), Math.min(duration, s.endedAtMs + 5e3))
84
+ }));
85
+ if (capture.status === "sealing" || capture.status === "needs_attention" && capture.failureStage === "transcript_sealing") for (const row of checkpoints) {
86
+ const checkpoint = JSON.parse(row.result_json);
87
+ for (const [index, s] of checkpoint.segments.entries()) entries.push({
88
+ id: `checkpoint:${run.run_id}:${row.started_at_ms}:${index}`,
89
+ kind: "transcript",
90
+ title: "",
91
+ text: s.text,
92
+ provisional: true,
93
+ stale: false,
94
+ startedAtMs: s.startedAtMs,
95
+ endedAtMs: s.endedAtMs,
96
+ segments: [{
97
+ sequence: index,
98
+ startedAtMs: s.startedAtMs,
99
+ endedAtMs: s.endedAtMs,
100
+ text: s.text,
101
+ playback: playable(s.startedAtMs, s.endedAtMs)
102
+ }],
103
+ playback: playable(Math.max(0, s.startedAtMs - 3e3), Math.min(duration, s.endedAtMs + 5e3))
104
+ });
105
+ }
106
+ const revisions = new Map([[capture.transcriptRevision, sourceSegments]]);
107
+ const revisionSegments = (revision) => {
108
+ if (!revisions.has(revision)) revisions.set(revision, (readTranscriptRevision(id, revision) ?? []).filter((s) => s.status === "confirmed"));
109
+ return revisions.get(revision);
110
+ };
111
+ const annotations = listAnnotations(id).map((annotation) => {
112
+ const anchor = annotation.anchor;
113
+ const epoch = timeline?.epochs[anchor.epoch ?? 0];
114
+ const position = anchor.positionMs ?? (epoch && anchor.offsetMs !== void 0 ? anchor.coordinate === "pcm" ? anchor.offsetMs < epoch.durationMs ? epoch.baseMs + anchor.offsetMs : void 0 : pointToPcm(epoch, anchor.offsetMs) : void 0);
115
+ const durable = !!attachment && position !== void 0 && position >= 0 && position < duration;
116
+ const revision = anchor.transcriptRevision ?? capture.transcriptRevision;
117
+ const refs = anchor.type === "transcript" ? revisionSegments(revision).filter((s) => anchor.segmentIds?.includes(s.sequence)) : durable ? sourceSegments.filter((s) => s.startedAtMs <= position && s.endedAtMs > position) : [];
118
+ const valid = anchor.type === "transcript" ? refs.length === anchor.segmentIds?.length : durable;
119
+ const evidence = refs.length && valid ? {
120
+ transcriptRevision: revision,
121
+ stale: revision !== capture.transcriptRevision,
122
+ segments: refs.map(segment)
123
+ } : void 0;
124
+ return {
125
+ annotation,
126
+ positionMs: durable ? position : void 0,
127
+ evidence,
128
+ state: valid ? "located" : !capture.audioAttachmentId && !capture.audioDeletedAt ? "pending" : "unavailable",
129
+ playback: anchor.type === "transcript" ? evidence?.segments.flatMap((s) => s.playback) ?? [] : durable ? playable(Math.max(0, position - 2e3), Math.min(duration, position + 8e3)) : []
130
+ };
131
+ });
132
+ const chapters = [];
133
+ const appendChapters = (org, revision, provisional, prefix) => {
134
+ const historical = revisionSegments(revision);
135
+ org.chapters.forEach((c, index) => {
136
+ if (!Number.isFinite(c.startedAtMs) || !Number.isFinite(c.endedAtMs) || c.startedAtMs < 0 || c.endedAtMs <= c.startedAtMs || c.endedAtMs > duration) return;
137
+ const within = historical.filter((s) => s.status === "confirmed" && s.endedAtMs > c.startedAtMs && s.startedAtMs < c.endedAtMs);
138
+ chapters.push({
139
+ id: `${prefix}:${index}`,
140
+ kind: "chapter",
141
+ title: c.title,
142
+ text: c.summary,
143
+ transcriptRevision: revision,
144
+ provisional,
145
+ stale: revision !== capture.transcriptRevision,
146
+ startedAtMs: c.startedAtMs,
147
+ endedAtMs: c.endedAtMs,
148
+ segments: within.slice(0, 3).map(segment),
149
+ playback: playable(c.startedAtMs, Math.min(c.endedAtMs, c.startedAtMs + 12e4)),
150
+ highlightCount: annotations.filter((a) => !a.annotation.deleted && (a.positionMs ?? a.evidence?.segments[0]?.startedAtMs ?? -1) >= c.startedAtMs && (a.positionMs ?? a.evidence?.segments[0]?.startedAtMs ?? -1) < c.endedAtMs).length,
151
+ actionCount: org.actionItems.filter((a) => !a.ignored && a.evidenceSegmentIds.some((seq) => within.some((s) => s.sequence === seq))).length
152
+ });
153
+ });
154
+ };
155
+ if (organization) appendChapters(organization, record.transcriptRevision, false, `chapter:${record.revision}`);
156
+ if (capture.status !== "completed") partialChapters.forEach((org, index) => appendChapters(org, capture.transcriptRevision, true, `partial:${index}`));
157
+ entries.push(...chapters);
158
+ if (organization) {
159
+ const revision = record.transcriptRevision;
160
+ const historical = revisionSegments(revision);
161
+ const facts = [
162
+ {
163
+ id: "summary",
164
+ text: organization.summary,
165
+ evidenceSegmentIds: organization.summaryEvidenceSegmentIds ?? []
166
+ },
167
+ ...organization.keyPointEvidence ?? [],
168
+ ...organization.decisions,
169
+ ...organization.risks,
170
+ ...organization.openQuestions,
171
+ ...organization.actionItems.map((a) => ({
172
+ ...a,
173
+ text: a.title
174
+ }))
175
+ ];
176
+ for (const fact of facts) {
177
+ if ("ignored" in fact && fact.ignored) continue;
178
+ const rev = "evidenceRevision" in fact ? fact.evidenceRevision ?? revision : revision;
179
+ const referenced = (rev === revision ? historical : revisionSegments(rev)).filter((s) => s.status === "confirmed" && fact.evidenceSegmentIds.includes(s.sequence));
180
+ entries.push({
181
+ id: `analysis:${record.revision}:${fact.id}`,
182
+ kind: "analysis",
183
+ title: "",
184
+ text: fact.text,
185
+ transcriptRevision: rev,
186
+ provisional: false,
187
+ stale: rev !== capture.transcriptRevision,
188
+ startedAtMs: referenced[0]?.startedAtMs,
189
+ endedAtMs: referenced.at(-1)?.endedAtMs,
190
+ segments: referenced.slice(0, 3).map(segment),
191
+ playback: referenced.slice(0, 3).flatMap((s) => playable(s.startedAtMs, s.endedAtMs))
192
+ });
193
+ }
194
+ if (!organization.keyPointEvidence?.length) organization.keyPoints.forEach((text, index) => entries.push({
195
+ id: `keypoint:${index}`,
196
+ kind: "analysis",
197
+ title: "",
198
+ text,
199
+ provisional: false,
200
+ stale: revision !== capture.transcriptRevision,
201
+ transcriptRevision: revision,
202
+ segments: [],
203
+ playback: []
204
+ }));
205
+ }
206
+ for (const a of annotations.filter((a) => !a.annotation.deleted)) entries.push({
207
+ id: `annotation:${a.annotation.id}`,
208
+ kind: "annotation",
209
+ title: a.annotation.kind,
210
+ text: a.annotation.text,
211
+ transcriptRevision: a.evidence?.transcriptRevision,
212
+ provisional: a.state === "pending",
213
+ stale: a.evidence?.stale ?? false,
214
+ startedAtMs: a.positionMs ?? a.evidence?.segments[0]?.startedAtMs,
215
+ segments: a.evidence?.segments.slice(0, 3) ?? [],
216
+ playback: a.playback
217
+ });
218
+ const processedRanges = unionReviewRanges((capture.status === "organizing" || capture.status === "completed") && capture.canonicalTranscript && duration > 0 ? [{
219
+ startedAtMs: 0,
220
+ endedAtMs: duration
221
+ }] : [...run?.force_audio ? [] : sourceSegments, ...checkpoints.map((r) => ({
222
+ startedAtMs: r.started_at_ms,
223
+ endedAtMs: r.ended_at_ms
224
+ }))], duration);
225
+ const analysisRanges = unionReviewRanges(chapters.filter((c) => c.provisional || !c.stale).map((c) => ({
226
+ startedAtMs: c.startedAtMs,
227
+ endedAtMs: c.endedAtMs
228
+ })), duration);
229
+ const needle = fold(query);
230
+ const matches = entries.filter((e) => needle ? fold(`${e.title}\n${e.text}\n${e.kind === "annotation" ? e.segments.map((s) => s.text).join("\n") : ""}`).includes(needle) : e.provisional && e.kind === "transcript");
231
+ const version = createHash("sha256").update(JSON.stringify([
232
+ capture.audioSha256,
233
+ capture.audioDeletedAt,
234
+ capture.status,
235
+ capture.transcriptRevision,
236
+ record?.revision,
237
+ processedRanges,
238
+ analysisRanges,
239
+ entries.map((e) => [
240
+ e.id,
241
+ e.title,
242
+ e.text,
243
+ e.startedAtMs,
244
+ e.endedAtMs,
245
+ e.stale,
246
+ e.provisional
247
+ ])
248
+ ])).digest("hex").slice(0, 24);
249
+ if (options.version && options.version !== version) throw new DiscussionServiceError("conflict", "Review updated; restart search");
250
+ const fresh = getDiscussionCapture(id);
251
+ if (fresh?.audioSha256 !== capture.audioSha256 || fresh?.transcriptRevision !== capture.transcriptRevision || fresh?.audioDeletedAt !== capture.audioDeletedAt) throw new DiscussionServiceError("conflict", "Review updated; retry");
252
+ return {
253
+ version,
254
+ query,
255
+ offset,
256
+ total: matches.length,
257
+ hasMore: offset + limit < matches.length,
258
+ hits: matches.slice(offset, offset + limit).map((e) => ({
259
+ ...e,
260
+ text: excerpt(e.text, needle)
261
+ })),
262
+ chapters,
263
+ coverage: {
264
+ durationMs: duration,
265
+ audioAvailable: !!attachment,
266
+ transcriptRanges: unionReviewRanges(sourceSegments, duration),
267
+ processedRanges,
268
+ processedMs: processedRanges.reduce((sum, r) => sum + r.endedAtMs - r.startedAtMs, 0),
269
+ continuousThroughMs: processedRanges[0]?.startedAtMs === 0 ? processedRanges[0].endedAtMs : 0,
270
+ analysisRanges,
271
+ analysisRevision: record?.transcriptRevision,
272
+ analysisStale: !!record && record.transcriptRevision !== capture.transcriptRevision,
273
+ complete: capture.status === "completed"
274
+ }
275
+ };
276
+ }
277
+ //#endregion
278
+ export { chapterScope, longRecordingReview, saveReviewChapter, unionReviewRanges };
@@ -0,0 +1,21 @@
1
+ import type { DiscussionPlaybackRange } from '@xopcai/gateway-contract';
2
+ export interface MediaSpan {
3
+ sourceMs: number;
4
+ pcmMs: number;
5
+ durationMs: number;
6
+ }
7
+ export interface MediaEpoch {
8
+ baseMs: number;
9
+ durationMs: number;
10
+ spans: MediaSpan[];
11
+ verified: boolean;
12
+ }
13
+ export interface RecordingTimeline {
14
+ primary: 'encoded' | 'pcm';
15
+ epochs: MediaEpoch[];
16
+ }
17
+ export declare const pcmEpoch: (durationMs: number, baseMs?: number) => MediaEpoch;
18
+ /** Packet timestamps expose pauses without decoding the recording into memory. */
19
+ export declare function probeMediaEpoch(path: string, durationMs: number, baseMs: number, signal: AbortSignal): Promise<MediaEpoch>;
20
+ export declare function pointToPcm(epoch: MediaEpoch, sourceMs: number): number | undefined;
21
+ export declare function playbackRanges(timeline: RecordingTimeline, start: number, end: number): DiscussionPlaybackRange[];
@@ -0,0 +1,134 @@
1
+ import { spawnProcess } from "../process/run-process.js";
2
+ //#region src/discussions/media-timeline.ts
3
+ const pcmEpoch = (durationMs, baseMs = 0) => ({
4
+ baseMs,
5
+ durationMs,
6
+ verified: true,
7
+ spans: [{
8
+ sourceMs: 0,
9
+ pcmMs: 0,
10
+ durationMs
11
+ }]
12
+ });
13
+ /** Packet timestamps expose pauses without decoding the recording into memory. */
14
+ async function probeMediaEpoch(path, durationMs, baseMs, signal) {
15
+ const result = {
16
+ baseMs,
17
+ durationMs,
18
+ spans: [],
19
+ verified: false
20
+ };
21
+ try {
22
+ await new Promise((resolve, reject) => {
23
+ signal.throwIfAborted();
24
+ const handle = spawnProcess({
25
+ program: process.env.XOPC_FFPROBE_PATH || "ffprobe",
26
+ args: [
27
+ "-v",
28
+ "error",
29
+ "-select_streams",
30
+ "a:0",
31
+ "-show_packets",
32
+ "-show_entries",
33
+ "packet=pts_time,duration_time:packet_side_data=skip_samples,discard_padding",
34
+ "-of",
35
+ "compact=p=0",
36
+ path
37
+ ],
38
+ maxOutputBytes: 0
39
+ });
40
+ const child = handle.child;
41
+ let pending = "";
42
+ let pcm = 0;
43
+ let packets = 0;
44
+ let lastStart = -Infinity;
45
+ const abort = () => {
46
+ handle.terminate();
47
+ reject(/* @__PURE__ */ new Error("Timing inspection cancelled"));
48
+ };
49
+ const timer = setTimeout(abort, 3e4);
50
+ timer.unref();
51
+ signal.addEventListener("abort", abort, { once: true });
52
+ child.stdout?.setEncoding("utf8");
53
+ child.stdout?.on("data", (text) => {
54
+ pending += text;
55
+ const lines = pending.split("\n");
56
+ pending = lines.pop();
57
+ if (pending.length > 8192) {
58
+ abort();
59
+ return;
60
+ }
61
+ for (const line of lines) {
62
+ if (!line.trim()) continue;
63
+ const fields = Object.fromEntries(line.split("|").map((part) => part.split("=")));
64
+ const pts = Number(fields.pts_time) * 1e3;
65
+ const duration = Number(fields.duration_time) * 1e3;
66
+ if (++packets > 1e6 || !Number.isFinite(pts) || !Number.isFinite(duration) || duration <= 0 || Number(fields.skip_samples ?? 0) !== 0 || Number(fields.discard_padding ?? 0) !== 0) {
67
+ abort();
68
+ return;
69
+ }
70
+ const start = Math.max(0, pts);
71
+ const length = duration - (start - pts);
72
+ if (length <= 0) continue;
73
+ const previous = result.spans.at(-1);
74
+ if (start <= lastStart) {
75
+ abort();
76
+ return;
77
+ }
78
+ lastStart = start;
79
+ if (previous && Math.abs(start - previous.sourceMs - previous.durationMs) <= 2) previous.durationMs += length;
80
+ else result.spans.push({
81
+ sourceMs: start,
82
+ pcmMs: pcm,
83
+ durationMs: length
84
+ });
85
+ pcm += length;
86
+ if (result.spans.length > 1e4) {
87
+ abort();
88
+ return;
89
+ }
90
+ }
91
+ });
92
+ child.once("error", reject);
93
+ child.once("close", (code) => {
94
+ clearTimeout(timer);
95
+ signal.removeEventListener("abort", abort);
96
+ if (code !== 0 || !result.spans.length || Math.abs(pcm - durationMs) > 100) {
97
+ reject(/* @__PURE__ */ new Error("Unverified media timing"));
98
+ return;
99
+ }
100
+ result.spans.at(-1).durationMs += durationMs - pcm;
101
+ result.verified = result.spans.at(-1).durationMs > 0;
102
+ resolve();
103
+ });
104
+ });
105
+ } catch {
106
+ result.verified = false;
107
+ }
108
+ return result;
109
+ }
110
+ function pointToPcm(epoch, sourceMs) {
111
+ if (!epoch.verified || !Number.isFinite(sourceMs)) return;
112
+ const matches = epoch.spans.filter((span) => sourceMs >= span.sourceMs && sourceMs < span.sourceMs + span.durationMs);
113
+ const span = matches.length === 1 ? matches[0] : void 0;
114
+ return span ? epoch.baseMs + span.pcmMs + sourceMs - span.sourceMs : void 0;
115
+ }
116
+ function playbackRanges(timeline, start, end) {
117
+ const total = timeline.epochs.reduce((sum, epoch) => sum + epoch.durationMs, 0);
118
+ if (!Number.isFinite(start) || !Number.isFinite(end) || start < 0 || end <= start || end > total + 1) return [];
119
+ if (timeline.primary === "pcm") return [{
120
+ startedAtMs: start,
121
+ endedAtMs: end
122
+ }];
123
+ if (!timeline.epochs.every((epoch) => epoch.verified)) return [];
124
+ return timeline.epochs[0].spans.flatMap((span) => {
125
+ const left = Math.max(start, span.pcmMs);
126
+ const right = Math.min(end, span.pcmMs + span.durationMs);
127
+ return right > left ? [{
128
+ startedAtMs: span.sourceMs + left - span.pcmMs,
129
+ endedAtMs: span.sourceMs + right - span.pcmMs
130
+ }] : [];
131
+ });
132
+ }
133
+ //#endregion
134
+ export { pcmEpoch, playbackRanges, pointToPcm, probeMediaEpoch };
@@ -6,10 +6,13 @@ export declare class DiscussionOrganizerWorker {
6
6
  private readonly processor;
7
7
  private readonly onUpdated?;
8
8
  private readonly intervalMs;
9
+ private readonly requestTimeoutMs;
9
10
  private readonly owner;
10
11
  private timer?;
11
12
  private running;
12
- constructor(processor: DiscussionOrganizerProcessor, onUpdated?: (capture: DiscussionCapture) => void, intervalMs?: number);
13
+ private stopping;
14
+ private controller?;
15
+ constructor(processor: DiscussionOrganizerProcessor, onUpdated?: (capture: DiscussionCapture) => void, intervalMs?: number, requestTimeoutMs?: number);
13
16
  start(): void;
14
17
  stop(): Promise<void>;
15
18
  tick(): Promise<void>;
@@ -1,6 +1,7 @@
1
1
  import { createLogger } from "../utils/logger/index.js";
2
2
  import { init_logger } from "../utils/logger.js";
3
- import { claimNextDiscussionCapture, getDiscussionCapture, releaseDiscussionWorkLease, renewDiscussionWorkLease, updateDiscussionCapture } from "./repository.js";
3
+ import { claimNextDiscussionCapture, getDiscussionCapture, releaseDiscussionWorkLease, renewDiscussionWorkLease } from "./repository.js";
4
+ import { failOrRetryProcessing, resetProcessingRetry, withProcessingDeadline } from "./processing.js";
4
5
  import { randomUUID } from "node:crypto";
5
6
  //#region src/discussions/organizer-worker.ts
6
7
  init_logger();
@@ -9,47 +10,50 @@ var DiscussionOrganizerWorker = class {
9
10
  owner = randomUUID();
10
11
  timer;
11
12
  running = false;
12
- constructor(processor, onUpdated, intervalMs = 1e3) {
13
+ stopping = false;
14
+ controller;
15
+ constructor(processor, onUpdated, intervalMs = 1e3, requestTimeoutMs = 10 * 6e4) {
13
16
  this.processor = processor;
14
17
  this.onUpdated = onUpdated;
15
18
  this.intervalMs = intervalMs;
19
+ this.requestTimeoutMs = requestTimeoutMs;
16
20
  }
17
21
  start() {
18
22
  if (this.timer) return;
19
- this.timer = setInterval(() => void this.tick(), this.intervalMs);
23
+ this.stopping = false;
24
+ this.timer = setInterval(() => void this.tick().catch((error) => log.error({ err: error }, "Discussion organizer tick failed")), this.intervalMs);
20
25
  this.timer.unref();
21
- this.tick();
26
+ this.tick().catch((error) => log.error({ err: error }, "Discussion organizer tick failed"));
22
27
  }
23
28
  async stop() {
29
+ this.stopping = true;
30
+ this.controller?.abort(/* @__PURE__ */ new Error("Discussion processing stopped"));
24
31
  if (this.timer) clearInterval(this.timer);
25
32
  this.timer = void 0;
26
33
  while (this.running) await new Promise((resolve) => setTimeout(resolve, 10));
27
34
  }
28
35
  async tick() {
29
- if (this.running) return;
36
+ if (this.running || this.stopping) return;
30
37
  this.running = true;
31
38
  try {
32
39
  const capture = claimNextDiscussionCapture(this.owner);
33
40
  if (!capture) return;
34
41
  const controller = new AbortController();
42
+ this.controller = controller;
35
43
  const renewal = setInterval(() => {
36
44
  if (!renewDiscussionWorkLease(capture.id, this.owner)) controller.abort();
37
45
  }, 3e4);
38
46
  renewal.unref();
39
47
  try {
40
- await this.processor.process(capture, this.owner, controller.signal);
48
+ await withProcessingDeadline((signal) => this.processor.process(capture, this.owner, signal), controller.signal, this.requestTimeoutMs);
49
+ resetProcessingRetry(capture.id);
41
50
  releaseDiscussionWorkLease(capture.id, this.owner);
42
51
  } catch (error) {
43
52
  const message = error instanceof Error ? error.message : String(error);
44
53
  const ownsLease = renewDiscussionWorkLease(capture.id, this.owner);
45
54
  releaseDiscussionWorkLease(capture.id, this.owner);
46
55
  const current = getDiscussionCapture(capture.id);
47
- const updated = ownsLease && current && updateDiscussionCapture(capture.id, {
48
- status: "needs_attention",
49
- failureStage: "organization",
50
- failureCode: "organization_failed",
51
- failureMessage: message.slice(0, 1e3)
52
- }, ["organizing"]);
56
+ const updated = ownsLease && !controller.signal.aborted && current ? failOrRetryProcessing(current, "organization", error) : null;
53
57
  if (updated) this.onUpdated?.(updated);
54
58
  log.warn({
55
59
  err: error,
@@ -57,6 +61,7 @@ var DiscussionOrganizerWorker = class {
57
61
  }, `Discussion organization failed: ${message}`);
58
62
  } finally {
59
63
  clearInterval(renewal);
64
+ this.controller = void 0;
60
65
  }
61
66
  } finally {
62
67
  this.running = false;
@@ -2,6 +2,7 @@ import { init_transaction, runSqliteWriteTransaction } from "../storage/sqlite/t
2
2
  import { ObjectLinkService } from "../activity/service.js";
3
3
  import { completeDiscussionOrganization, createDiscussionOrganization, getDiscussionCapture, getLatestDiscussionOrganization, listDiscussionTranscriptSegments, renewDiscussionWorkLease, updateDiscussionCapture } from "./repository.js";
4
4
  import { saveTranscriptRevision } from "./revisions.js";
5
+ import { chapterScope } from "./long-review.js";
5
6
  import { analyzeDiscussion } from "./analyzer.js";
6
7
  import { applyMeetingEdits } from "./edits.js";
7
8
  import { acceptRankedProject, findExactProjectMention } from "./project-inference.js";
@@ -27,6 +28,7 @@ var DiscussionOrganizer = class {
27
28
  transcript,
28
29
  segments: listDiscussionTranscriptSegments(capture.id),
29
30
  discussionId: capture.id,
31
+ reviewScope: chapterScope(capture.id),
30
32
  template: capture.template,
31
33
  projects: projects.map(({ id, name }) => ({
32
34
  id,