@xopcai/xopc 0.0.241 → 0.0.243

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (257) 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-CLnbVm9G.js → activity-store-CAah-_8h.js} +1 -1
  4. package/dist/gateway/static/root/assets/{agent-avatar-dicebear-DuBewmbW.js → agent-avatar-dicebear-DDH4HgP7.js} +1 -1
  5. package/dist/gateway/static/root/assets/agent-defaults-settings-panel-BDCfJZhh.js +1 -0
  6. package/dist/gateway/static/root/assets/agents-B0ZWgf-U.js +1 -0
  7. package/dist/gateway/static/root/assets/{api-DjBZe303.js → api-B2tKxbcz.js} +1 -1
  8. package/dist/gateway/static/root/assets/app-management-settings-panel-Blfwszzn.js +1 -0
  9. package/dist/gateway/static/root/assets/{appearance-settings-B-iul0RG.js → appearance-settings-C3V7Na75.js} +1 -1
  10. package/dist/gateway/static/root/assets/apps-page-BiEks0-F.js +1 -0
  11. package/dist/gateway/static/root/assets/{archive-plugin-BOx0EJZs.js → archive-plugin-BmSx7wzY.js} +1 -1
  12. package/dist/gateway/static/root/assets/{attachment-load-Cfk1lwBo.js → attachment-load-BS-S4LJ9.js} +1 -1
  13. package/dist/gateway/static/root/assets/{automations-page-BTSGvaeS.js → automations-page-C7Y3L30D.js} +1 -1
  14. package/dist/gateway/static/root/assets/automations-workspace-A3zPkPuo.js +6 -0
  15. package/dist/gateway/static/root/assets/{binary-plugins-ChZyZK45.js → binary-plugins-BM9B5kcm.js} +1 -1
  16. package/dist/gateway/static/root/assets/block-editor-BbnpkYP9.js +185 -0
  17. package/dist/gateway/static/root/assets/browser-settings-page-Dk4FQ7fY.js +8 -0
  18. package/dist/gateway/static/root/assets/{browser-workflow-inputs-jvfcgFG-.js → browser-workflow-inputs-CRnkgZHI.js} +1 -1
  19. package/dist/gateway/static/root/assets/{browser-workflows-page-DrHW7XNi.js → browser-workflows-page-B9qGL-it.js} +2 -2
  20. package/dist/gateway/static/root/assets/{button-CSEbl4zT.js → button-CtTvuElV.js} +1 -1
  21. package/dist/gateway/static/root/assets/capabilities-settings-panel--tR_El9e.js +7 -0
  22. package/dist/gateway/static/root/assets/channels-settings-D347vl_J.js +1 -0
  23. package/dist/gateway/static/root/assets/{channels-status-swr-CC9MFway.js → channels-status-swr-DuY4MGxe.js} +1 -1
  24. package/dist/gateway/static/root/assets/{chat-terminal-dock-DeeZrVbV.js → chat-terminal-dock-DABPvwBT.js} +2 -2
  25. package/dist/gateway/static/root/assets/connectors-page-B-tvJkRJ.js +2 -0
  26. package/dist/gateway/static/root/assets/{cron-expression-CiqQOeQ3.js → cron-expression-D3bsKbNd.js} +1 -1
  27. package/dist/gateway/static/root/assets/{date-picker-CGAMGPfU.js → date-picker-BsGM6Yty.js} +1 -1
  28. package/dist/gateway/static/root/assets/{dependency-picker-CxWeUTsc.js → dependency-picker-Dj3g6YXZ.js} +1 -1
  29. package/dist/gateway/static/root/assets/{desktop-pet-C3QmYO75.js → desktop-pet-C1QT0Sur.js} +1 -1
  30. package/dist/gateway/static/root/assets/{desktop-pet-settings-CAADkWYy.js → desktop-pet-settings-r6kAOnfY.js} +1 -1
  31. package/dist/gateway/static/root/assets/dist-CpzYSoz7.js +1 -0
  32. package/dist/gateway/static/root/assets/{dist-DaxPZj9e.js → dist-DBS3OB8K.js} +1 -1
  33. package/dist/gateway/static/root/assets/dist-DLmwHyAh.js +1 -0
  34. package/dist/gateway/static/root/assets/es2015-BvLh9GaE.js +41 -0
  35. package/dist/gateway/static/root/assets/{extension-debug-page-FQXjDJ8P.js → extension-debug-page-DOkf7nh9.js} +1 -1
  36. package/dist/gateway/static/root/assets/{extension-page-BJE1D5Ji.js → extension-page-Cq2IA4Ho.js} +1 -1
  37. package/dist/gateway/static/root/assets/{extension-settings-page-5Ik2tNry.js → extension-settings-page-DQn4qjDZ.js} +1 -1
  38. package/dist/gateway/static/root/assets/{files-DQjhZjr2.js → files-D6vf3S30.js} +1 -1
  39. package/dist/gateway/static/root/assets/{gateway-config-api-cTj71t2a.js → gateway-config-api-DM3poL22.js} +1 -1
  40. package/dist/gateway/static/root/assets/{gateway-config-swr-Bxe_R-JH.js → gateway-config-swr-BC3pgb_P.js} +1 -1
  41. package/dist/gateway/static/root/assets/{gateway-settings-KXBUjNcx.js → gateway-settings-DPgH1hnh.js} +1 -1
  42. package/dist/gateway/static/root/assets/{gateway-startup-retry-DJG-I0wW.js → gateway-startup-retry-uMcSfLru.js} +1 -1
  43. package/dist/gateway/static/root/assets/{heartbeat-settings-C8cVzIcs.js → heartbeat-settings-Bk80-E3b.js} +1 -1
  44. package/dist/gateway/static/root/assets/home-page-DKo5JiMR.js +1 -0
  45. package/dist/gateway/static/root/assets/{image-generation-api-Dc_ojQuj.js → image-generation-api-D1qlQA-A.js} +1 -1
  46. package/dist/gateway/static/root/assets/index-B0WJL9N1.js +71 -0
  47. package/dist/gateway/static/root/assets/index-Dbh5SXyV.css +2 -0
  48. package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-pOKl7blR.js → keyboard-shortcuts-settings-BEwvd8ZU.js} +1 -1
  49. package/dist/gateway/static/root/assets/local-app-workbench-page--eJ5rmNj.js +2 -0
  50. package/dist/gateway/static/root/assets/{local-apps-page-Bi6wwKgm.js → local-apps-page-CgkY9E-r.js} +1 -1
  51. package/dist/gateway/static/root/assets/{locale-store-C5wr3_pc.js → locale-store-CMZljTJx.js} +1 -1
  52. package/dist/gateway/static/root/assets/logs-page-Z49Td0J9.js +2 -0
  53. package/dist/gateway/static/root/assets/{management-settings-DGlVizWi.js → management-settings-Dv8NSJKt.js} +1 -1
  54. package/dist/gateway/static/root/assets/{markdown-split-CXP5zBx_.js → markdown-split-Cm0RBB-t.js} +1 -1
  55. package/dist/gateway/static/root/assets/{markdown-view-D6LxlDxr.js → markdown-view-PPCLt7fu.js} +3 -3
  56. package/dist/gateway/static/root/assets/{media-plugins-BsENGLr2.js → media-plugins-Bcr5sU1f.js} +1 -1
  57. package/dist/gateway/static/root/assets/messages-CTSgFlE4.js +3 -0
  58. package/dist/gateway/static/root/assets/mobile-pairing-wizard-kKDiXofY.js +1 -0
  59. package/dist/gateway/static/root/assets/{models-hub-cache-Y7GUjxHx.js → models-hub-cache-ZrbGRiGY.js} +1 -1
  60. package/dist/gateway/static/root/assets/{notes-page-D2EqpDyo.js → notes-page-CgsaRaGi.js} +1 -1
  61. package/dist/gateway/static/root/assets/notes-workbench-C1DEE09k.js +4 -0
  62. package/dist/gateway/static/root/assets/{oauth-api-C5NVcsKE.js → oauth-api-4VeMbkTJ.js} +1 -1
  63. package/dist/gateway/static/root/assets/popover-select-C-Hj-nXR.js +1 -0
  64. package/dist/gateway/static/root/assets/{product-delivery-dUJgmBQZ.js → product-delivery-CV4pDOtG.js} +1 -1
  65. package/dist/gateway/static/root/assets/product-open-page-BU0HiZtv.js +1 -0
  66. package/dist/gateway/static/root/assets/project-detail-page-isRapnp5.js +1 -0
  67. package/dist/gateway/static/root/assets/projects-page-zvsjg0mi.js +1 -0
  68. package/dist/gateway/static/root/assets/{registry-api-FXdFaoWM.js → registry-api-CWOtPFrE.js} +1 -1
  69. package/dist/gateway/static/root/assets/remote-access-hub-C9TGZ9Hc.js +1 -0
  70. package/dist/gateway/static/root/assets/runtime-tools-settings-panel-2zm9edMA.js +5 -0
  71. package/dist/gateway/static/root/assets/{schema-form-BUzdHWx6.js → schema-form-54A5gzkN.js} +1 -1
  72. package/dist/gateway/static/root/assets/{schemas-zIBW3wiV.js → schemas-BHS7bo06.js} +1 -1
  73. package/dist/gateway/static/root/assets/sessions-page-BP8RyiUn.js +1 -0
  74. package/dist/gateway/static/root/assets/settings-advanced-gate-D4EMxWAZ.js +1 -0
  75. package/dist/gateway/static/root/assets/{settings-page-C0OBLqpu.js → settings-page-DzDhoyxv.js} +1 -1
  76. package/dist/gateway/static/root/assets/{setup-status-panel-NpLQkFCh.js → setup-status-panel-uDicHU1w.js} +1 -1
  77. package/dist/gateway/static/root/assets/{share-preview-page-BtbPYaYC.js → share-preview-page-lOmLCWFS.js} +1 -1
  78. package/dist/gateway/static/root/assets/shares-settings-T4Yvouvv.js +1 -0
  79. package/dist/gateway/static/root/assets/skill-reload-api-DVb7nrXz.js +1 -0
  80. package/dist/gateway/static/root/assets/{skills-page-CYk8pN97.js → skills-page-CnyNH3To.js} +1 -1
  81. package/dist/gateway/static/root/assets/skills-page.utils-CgDtf2qs.js +1 -0
  82. package/dist/gateway/static/root/assets/{system-settings-panel-DmCRSvtd.js → system-settings-panel-C8yWfwtR.js} +1 -1
  83. package/dist/gateway/static/root/assets/task-detail-page-Tzfjlbf3.js +1 -0
  84. package/dist/gateway/static/root/assets/{theme-store-DUko1ZnE.js → theme-store-uxUwr10D.js} +1 -1
  85. package/dist/gateway/static/root/assets/tunnel-api-Bvg679no.js +1 -0
  86. package/dist/gateway/static/root/assets/{use-autosave-W_P8Kiv4.js → use-autosave-D88VGoyG.js} +1 -1
  87. package/dist/gateway/static/root/assets/user-context-page-RijPtyfO.js +1 -0
  88. package/dist/gateway/static/root/assets/{voice-api-key-field-BZD0j1jc.js → voice-api-key-field-CBHLsMcc.js} +1 -1
  89. package/dist/gateway/static/root/assets/voice-config-api-MqyI6cgq.js +1 -0
  90. package/dist/gateway/static/root/assets/work-discovery-overlay-GGe2TQ98.js +1 -0
  91. package/dist/gateway/static/root/assets/workflow-run-setup-panel-C0layUE9.js +3 -0
  92. package/dist/gateway/static/root/assets/workflows-page-DQXIzBAc.js +5 -0
  93. package/dist/gateway/static/root/index.html +21 -22
  94. package/dist/package.js +1 -1
  95. package/dist/packages/realtime-protocol/src/voice-audio.js +20 -0
  96. package/dist/packages/realtime-protocol/src/voice.js +208 -0
  97. package/dist/src/agent/agent-manager.js +1 -0
  98. package/dist/src/agent/embedded/run-for-session.d.ts +1 -0
  99. package/dist/src/agent/embedded/run-for-session.js +2 -1
  100. package/dist/src/agent/inbound/turn-dispatcher.d.ts +1 -0
  101. package/dist/src/agent/inbound/turn-dispatcher.js +2 -1
  102. package/dist/src/agent/prompt/voice-presentation.d.ts +2 -0
  103. package/dist/src/agent/prompt/voice-presentation.js +12 -0
  104. package/dist/src/agent/service/direct-turn-helpers.d.ts +1 -0
  105. package/dist/src/agent/service/direct-turn-helpers.js +1 -0
  106. package/dist/src/agent/service/process-direct-streaming.d.ts +1 -0
  107. package/dist/src/agent/service/process-direct-streaming.js +2 -1
  108. package/dist/src/agent/session/session-config-service.js +4 -2
  109. package/dist/src/agent/skills/installer.d.ts +1 -0
  110. package/dist/src/agent/skills/installer.js +9 -6
  111. package/dist/src/agent/tools/factory.d.ts +2 -0
  112. package/dist/src/agent/tools/factory.js +5 -1
  113. package/dist/src/automations/draft/automation-draft-service.js +1 -1
  114. package/dist/src/config/models-json.d.ts +8 -8
  115. package/dist/src/config/schema.d.ts +60 -0
  116. package/dist/src/config/schema.js +36 -4
  117. package/dist/src/extensions/install.js +1 -1
  118. package/dist/src/files/file-service.d.ts +1 -0
  119. package/dist/src/files/file-service.js +4 -0
  120. package/dist/src/gateway/chat-stream/thinking-delta-coalescer.js +8 -3
  121. package/dist/src/gateway/hono/lib/config-payload.d.ts +1 -11
  122. package/dist/src/gateway/hono/lib/config-payload.js +2 -2
  123. package/dist/src/gateway/hono/lib/safe-voice-config.d.ts +14 -0
  124. package/dist/src/gateway/hono/lib/safe-voice-config.js +29 -1
  125. package/dist/src/gateway/hono/routes/config-patch/misc.js +2 -2
  126. package/dist/src/gateway/hono/routes/files.js +7 -0
  127. package/dist/src/gateway/hono/routes/lazy-fallback.js +18 -4
  128. package/dist/src/gateway/hono/routes/runtime-tools.js +7 -1
  129. package/dist/src/gateway/hono/routes/session-input-handler.js +14 -0
  130. package/dist/src/gateway/hono/routes/sessions.js +4 -1
  131. package/dist/src/gateway/hono/routes/voice.js +140 -3
  132. package/dist/src/gateway/server.js +1 -0
  133. package/dist/src/gateway/service/agent-runner.d.ts +1 -0
  134. package/dist/src/gateway/service/agent-runner.js +1 -6
  135. package/dist/src/gateway/service/run-gateway-agent.d.ts +1 -0
  136. package/dist/src/gateway/service/run-gateway-agent.js +19 -1
  137. package/dist/src/gateway/service.d.ts +2 -0
  138. package/dist/src/gateway/service.js +73 -0
  139. package/dist/src/media-understanding/types.d.ts +61 -0
  140. package/dist/src/runtime-tools/archive.js +17 -3
  141. package/dist/src/runtime-tools/command.d.ts +1 -0
  142. package/dist/src/runtime-tools/command.js +29 -8
  143. package/dist/src/runtime-tools/environment.d.ts +1 -0
  144. package/dist/src/runtime-tools/environment.js +11 -16
  145. package/dist/src/runtime-tools/install-lock.d.ts +1 -1
  146. package/dist/src/runtime-tools/install-lock.js +34 -21
  147. package/dist/src/runtime-tools/manager.d.ts +1 -1
  148. package/dist/src/runtime-tools/manager.js +99 -64
  149. package/dist/src/runtime-tools/manifest-store.d.ts +2 -0
  150. package/dist/src/runtime-tools/manifest-store.js +29 -8
  151. package/dist/src/runtime-tools/paths.d.ts +2 -1
  152. package/dist/src/runtime-tools/paths.js +19 -8
  153. package/dist/src/runtime-tools/probe.d.ts +2 -0
  154. package/dist/src/runtime-tools/probe.js +13 -1
  155. package/dist/src/runtime-tools/prune.js +21 -7
  156. package/dist/src/session/client-history.js +12 -0
  157. package/dist/src/session/manager.d.ts +1 -0
  158. package/dist/src/session/session-context-for-llm.js +8 -0
  159. package/dist/src/session/store.d.ts +1 -0
  160. package/dist/src/session/store.js +1 -0
  161. package/dist/src/session/stored-rows-to-file-entries.js +5 -1
  162. package/dist/src/session/voice-transcript.d.ts +9 -0
  163. package/dist/src/session/voice-transcript.js +45 -0
  164. package/dist/src/storage/sqlite/config-repository.js +9 -0
  165. package/dist/src/storage/sqlite/remote-context-repository.d.ts +3 -0
  166. package/dist/src/storage/sqlite/remote-context-repository.js +40 -0
  167. package/dist/src/storage/sqlite/session-repository.js +13 -0
  168. package/dist/src/storage/sqlite/user-context-repository.d.ts +3 -1
  169. package/dist/src/storage/sqlite/user-context-repository.js +50 -4
  170. package/dist/src/tui/tui.js +2 -1
  171. package/dist/src/user-context/automatic-context.d.ts +17 -0
  172. package/dist/src/user-context/automatic-context.js +85 -0
  173. package/dist/src/user-context/changes.d.ts +7 -0
  174. package/dist/src/user-context/changes.js +28 -0
  175. package/dist/src/user-context/planner.js +1 -24
  176. package/dist/src/user-context/retriever.js +10 -11
  177. package/dist/src/user-context/selection-policy.d.ts +20 -0
  178. package/dist/src/user-context/selection-policy.js +33 -0
  179. package/dist/src/user-context/sources/index.js +2 -2
  180. package/dist/src/user-context/sources/repository.d.ts +2 -1
  181. package/dist/src/user-context/sources/repository.js +26 -5
  182. package/dist/src/voice/dashscope/streaming-stt-session.d.ts +2 -0
  183. package/dist/src/voice/dashscope/streaming-stt-session.js +249 -0
  184. package/dist/src/voice/dashscope/streaming-tts-stream.d.ts +12 -0
  185. package/dist/src/voice/dashscope/streaming-tts-stream.js +153 -0
  186. package/dist/src/voice/realtime/agentEngine.d.ts +10 -0
  187. package/dist/src/voice/realtime/agentEngine.js +403 -0
  188. package/dist/src/voice/realtime/audio-playback-window.d.ts +9 -0
  189. package/dist/src/voice/realtime/audio-playback-window.js +49 -0
  190. package/dist/src/voice/realtime/conversation-context.d.ts +11 -0
  191. package/dist/src/voice/realtime/conversation-context.js +76 -0
  192. package/dist/src/voice/realtime/engine.d.ts +13 -0
  193. package/dist/src/voice/realtime/engine.js +1 -0
  194. package/dist/src/voice/realtime/memory-context.d.ts +17 -0
  195. package/dist/src/voice/realtime/memory-context.js +100 -0
  196. package/dist/src/voice/realtime/omniEngine.d.ts +18 -0
  197. package/dist/src/voice/realtime/omniEngine.js +443 -0
  198. package/dist/src/voice/realtime/omniRoute.d.ts +10 -0
  199. package/dist/src/voice/realtime/omniRoute.js +31 -0
  200. package/dist/src/voice/realtime/runtime.d.ts +99 -0
  201. package/dist/src/voice/realtime/runtime.js +622 -0
  202. package/dist/src/voice/realtime/speakable-segmenter.d.ts +10 -0
  203. package/dist/src/voice/realtime/speakable-segmenter.js +87 -0
  204. package/dist/src/voice/stt/list-providers.js +2 -1
  205. package/dist/src/voice/stt/providers/alibaba-transcription.js +13 -1
  206. package/dist/src/voice/stt/providers/xopc-cloud-transcription.js +23 -0
  207. package/dist/src/voice/tts/factory.js +1 -0
  208. package/dist/src/voice/tts/openai-compatible-speech.js +3 -1
  209. package/dist/src/voice/tts/providers/alibaba-speech.d.ts +1 -5
  210. package/dist/src/voice/tts/providers/alibaba-speech.js +25 -8
  211. package/dist/src/voice/tts/providers/edge-speech.js +21 -22
  212. package/dist/src/voice/tts/providers/minimax-speech.js +6 -3
  213. package/dist/src/voice/tts/providers/xopc-cloud-speech.js +26 -1
  214. package/dist/src/voice/tts/speak-core.d.ts +6 -2
  215. package/dist/src/voice/tts/speak-core.js +46 -34
  216. package/dist/src/voice/tts/speech-provider-types.d.ts +1 -0
  217. package/package.json +6 -6
  218. package/dist/gateway/static/root/assets/Combination-14nmIgxH.js +0 -41
  219. package/dist/gateway/static/root/assets/agent-defaults-settings-panel-DbdgX6AA.js +0 -1
  220. package/dist/gateway/static/root/assets/agents-BX3uRVm4.js +0 -1
  221. package/dist/gateway/static/root/assets/app-chrome-BeB4KgOf.js +0 -1
  222. package/dist/gateway/static/root/assets/app-management-settings-panel-D8evZyFQ.js +0 -1
  223. package/dist/gateway/static/root/assets/apps-page-CoZd_cZu.js +0 -1
  224. package/dist/gateway/static/root/assets/automations-workspace-C8RRKT-a.js +0 -6
  225. package/dist/gateway/static/root/assets/block-editor-DCH9b2Ht.js +0 -184
  226. package/dist/gateway/static/root/assets/browser-settings-page-D1GPwIfx.js +0 -8
  227. package/dist/gateway/static/root/assets/capabilities-settings-panel-CrXB1Q-l.js +0 -7
  228. package/dist/gateway/static/root/assets/channels-settings-DWMSYaNZ.js +0 -1
  229. package/dist/gateway/static/root/assets/connectors-page-DXTl1fNB.js +0 -2
  230. package/dist/gateway/static/root/assets/dist-BPoKqzeH.js +0 -1
  231. package/dist/gateway/static/root/assets/dist-DqPZM2MH.js +0 -1
  232. package/dist/gateway/static/root/assets/home-page-NdWtBda5.js +0 -1
  233. package/dist/gateway/static/root/assets/index-7i2P3312.js +0 -70
  234. package/dist/gateway/static/root/assets/index-DTo3IcbW.css +0 -2
  235. package/dist/gateway/static/root/assets/local-app-workbench-page-C_j_od5f.js +0 -2
  236. package/dist/gateway/static/root/assets/logs-page-D6PDZEVP.js +0 -2
  237. package/dist/gateway/static/root/assets/messages-_tYhRAHD.js +0 -3
  238. package/dist/gateway/static/root/assets/mobile-pairing-wizard-DcEz7qcX.js +0 -1
  239. package/dist/gateway/static/root/assets/notes-workbench-Bu0a83Oj.js +0 -4
  240. package/dist/gateway/static/root/assets/popover-select-DrILF6mR.js +0 -1
  241. package/dist/gateway/static/root/assets/product-open-page-DMhf1rdz.js +0 -1
  242. package/dist/gateway/static/root/assets/project-detail-page-DDHi0Y4Q.js +0 -1
  243. package/dist/gateway/static/root/assets/projects-page-CVMFKpmu.js +0 -1
  244. package/dist/gateway/static/root/assets/remote-access-hub-B74aErBY.js +0 -1
  245. package/dist/gateway/static/root/assets/runtime-tools-settings-panel-Bv-akndY.js +0 -5
  246. package/dist/gateway/static/root/assets/sessions-page-D2wmGNZE.js +0 -1
  247. package/dist/gateway/static/root/assets/settings-advanced-gate-CYCCUMEt.js +0 -1
  248. package/dist/gateway/static/root/assets/shares-settings-rf8f1OGq.js +0 -1
  249. package/dist/gateway/static/root/assets/skill-reload-api-BkvclZ_o.js +0 -1
  250. package/dist/gateway/static/root/assets/skills-page.utils-DGjnz-NG.js +0 -1
  251. package/dist/gateway/static/root/assets/task-detail-page-6a2RdDl2.js +0 -1
  252. package/dist/gateway/static/root/assets/tunnel-api-Chfiba_x.js +0 -1
  253. package/dist/gateway/static/root/assets/user-context-page-SeOHP6XO.js +0 -1
  254. package/dist/gateway/static/root/assets/voice-config-api-BO6A8V3Z.js +0 -1
  255. package/dist/gateway/static/root/assets/work-discovery-overlay-BfwEoOGL.js +0 -1
  256. package/dist/gateway/static/root/assets/workflow-run-setup-panel-X7Z5_lRX.js +0 -3
  257. package/dist/gateway/static/root/assets/workflows-page-BklMzkg8.js +0 -5
@@ -1,4 +1,5 @@
1
1
  import { getSqliteDatabase, runSqliteWriteTransaction } from "./transaction.js";
2
+ import { notifyUserContextChange } from "../../user-context/changes.js";
2
3
  import { sessionConfigRowToConfig } from "./row-mappers.js";
3
4
  import { ensureSessionInTransaction } from "./session-repository.js";
4
5
  //#region src/storage/sqlite/config-repository.ts
@@ -21,6 +22,10 @@ function listSessionWorkspaceOverrides() {
21
22
  `).all();
22
23
  }
23
24
  function setSessionConfig(sessionKey, config, cwd) {
25
+ notifyUserContextChange({
26
+ kind: "session",
27
+ id: sessionKey
28
+ });
24
29
  return runSqliteWriteTransaction((db) => {
25
30
  ensureSessionInTransaction(db, sessionKey, cwd);
26
31
  const updatedAt = Math.max(Date.now(), (readConfigRow(db, sessionKey)?.updated_at ?? 0) + 1);
@@ -54,6 +59,10 @@ function updateSessionConfig(sessionKey, partial, cwd) {
54
59
  }, cwd);
55
60
  }
56
61
  function deleteSessionConfig(sessionKey) {
62
+ notifyUserContextChange({
63
+ kind: "session",
64
+ id: sessionKey
65
+ });
57
66
  runSqliteWriteTransaction((db) => {
58
67
  db.prepare(`DELETE FROM session_config WHERE session_key = ?`).run(sessionKey);
59
68
  });
@@ -0,0 +1,3 @@
1
+ export type RemoteContextKind = 'understanding' | 'focus';
2
+ /** Check all provenance, including older evidence, without loading private excerpts. */
3
+ export declare function remoteContextEligibleIds(kind: RemoteContextKind, ids: string[]): Set<string>;
@@ -0,0 +1,40 @@
1
+ import { getSqliteDatabase } from "./transaction.js";
2
+ import { USER_CONTEXT_PRINCIPAL_ID } from "../../user-context/domain.js";
3
+ //#region src/storage/sqlite/remote-context-repository.ts
4
+ /** Check all provenance, including older evidence, without loading private excerpts. */
5
+ function remoteContextEligibleIds(kind, ids) {
6
+ if (!ids.length) return /* @__PURE__ */ new Set();
7
+ if (ids.length > 200) throw new Error("Context candidate limit exceeded");
8
+ const focus = kind === "focus";
9
+ const table = focus ? "user_focuses" : "user_understandings";
10
+ const versions = focus ? "user_focus_versions" : "user_understanding_versions";
11
+ const links = focus ? "user_focus_evidence_links" : "understanding_evidence_links";
12
+ const id = focus ? "focus_id" : "understanding_id";
13
+ const rows = getSqliteDatabase().prepare(`
14
+ SELECT u.${id} AS id, v.created_by, u.explicitness,
15
+ COUNT(e.evidence_id) AS evidence_count,
16
+ MAX(CASE WHEN e.evidence_id IS NOT NULL AND (
17
+ (e.processing_policy IS NOT NULL AND e.processing_policy <> 'remote_allowed')
18
+ OR e.trust_level = 'untrusted' OR e.principal_id <> u.principal_id
19
+ OR (e.source_run_id IS NOT NULL AND (g.grant_id IS NULL OR g.status <> 'active' OR g.processing_policy <> 'remote_allowed'))
20
+ OR (e.source_type = 'connector' AND (e.processing_policy IS NULL OR e.source_run_id IS NULL))
21
+ OR (e.processing_policy IS NULL AND e.source_type <> 'user' AND e.trust_level <> 'owner')
22
+ ) THEN 1 ELSE 0 END) AS blocked
23
+ FROM ${table} u
24
+ JOIN ${versions} v ON v.version_id = u.current_version_id
25
+ LEFT JOIN ${versions} history ON history.${id} = u.${id}
26
+ LEFT JOIN ${links} l ON l.version_id = history.version_id
27
+ LEFT JOIN context_evidence e ON e.evidence_id = l.evidence_id
28
+ LEFT JOIN understanding_source_runs r ON r.run_id = e.source_run_id
29
+ LEFT JOIN understanding_source_grants g ON g.grant_id = r.grant_id
30
+ WHERE u.principal_id = ? AND u.${id} IN (${ids.map(() => "?").join(",")})
31
+ ${focus ? `AND (u.source_run_id IS NULL OR EXISTS (
32
+ SELECT 1 FROM understanding_source_runs fr JOIN understanding_source_grants fg ON fg.grant_id = fr.grant_id
33
+ WHERE fr.run_id = u.source_run_id AND fg.status = 'active' AND fg.processing_policy = 'remote_allowed'
34
+ ))` : ""}
35
+ GROUP BY u.${id}
36
+ `).all(USER_CONTEXT_PRINCIPAL_ID, ...ids);
37
+ return new Set(rows.filter((row) => !row.blocked && (row.evidence_count > 0 || row.explicitness === "explicit" && row.created_by === "user")).map((row) => row.id));
38
+ }
39
+ //#endregion
40
+ export { remoteContextEligibleIds };
@@ -1,4 +1,5 @@
1
1
  import { getSqliteDatabase, runSqliteWriteTransaction } from "./transaction.js";
2
+ import { notifyUserContextChange } from "../../user-context/changes.js";
2
3
  import { buildFts5SearchQuery } from "./fts.js";
3
4
  import { validateSessionId } from "../../session/session-id.js";
4
5
  import { buildDefaultSessionMetadata } from "./session-metadata.js";
@@ -175,6 +176,10 @@ function sessionSortColumn(sortBy) {
175
176
  }
176
177
  }
177
178
  function patchSessionMetadata(sessionKey, updates) {
179
+ if ("projectId" in updates) notifyUserContextChange({
180
+ kind: "session-reset",
181
+ id: sessionKey
182
+ });
178
183
  return runSqliteWriteTransaction((db) => {
179
184
  const existing = readSessionRow(db, sessionKey);
180
185
  if (!existing) throw new Error(`Session not found: ${sessionKey}`);
@@ -242,6 +247,10 @@ function incrementSessionStatsOnAppend(sessionKey, tokenDelta = 0) {
242
247
  });
243
248
  }
244
249
  function resetSessionRecord(sessionKey, cwd) {
250
+ notifyUserContextChange({
251
+ kind: "session-reset",
252
+ id: sessionKey
253
+ });
245
254
  return runSqliteWriteTransaction((db) => {
246
255
  const existing = readSessionRow(db, sessionKey);
247
256
  if (!existing) return null;
@@ -267,6 +276,10 @@ function resetSessionRecord(sessionKey, cwd) {
267
276
  });
268
277
  }
269
278
  function deleteSessionRecord(sessionKey) {
279
+ notifyUserContextChange({
280
+ kind: "session-reset",
281
+ id: sessionKey
282
+ });
270
283
  return runSqliteWriteTransaction((db) => {
271
284
  const existing = readSessionRow(db, sessionKey);
272
285
  if (!existing) return false;
@@ -18,7 +18,7 @@ export type CreateUnderstandingInput = Omit<UserUnderstanding, 'id' | 'versionId
18
18
  };
19
19
  export declare function createUnderstanding(input: CreateUnderstandingInput, principalId?: string): UserUnderstanding;
20
20
  export declare function getUnderstanding(id: string): UserUnderstanding | undefined;
21
- export declare function listUnderstandings(statuses?: UnderstandingStatus[], principalId?: string): UserUnderstanding[];
21
+ export declare function listUnderstandings(statuses?: UnderstandingStatus[], principalId?: string, limit?: number): UserUnderstanding[];
22
22
  export declare function searchActiveUnderstandings(query: string, limit?: number): Array<{
23
23
  understanding: UserUnderstanding;
24
24
  score: number;
@@ -52,6 +52,8 @@ export declare function createContextEvidence(input: Omit<ContextEvidence, 'id'
52
52
  }, principalId?: string): ContextEvidence;
53
53
  export declare function linkUnderstandingEvidence(versionId: string, evidenceId: string, relation: 'supports' | 'contradicts' | 'supersedes', confidence: number): void;
54
54
  export declare function listUnderstandingEvidence(understandingId: string, relation?: 'supports' | 'contradicts' | 'supersedes'): ContextEvidence[];
55
+ /** Latest source labels for ranking, without fetching evidence bodies per candidate. */
56
+ export declare function understandingSourceBuckets(ids: string[]): Map<string, string>;
55
57
  export declare function recordContextRun(input: {
56
58
  turnId: string;
57
59
  sessionKey: string;
@@ -1,5 +1,6 @@
1
1
  import { getSqliteDatabase, runSqliteWriteTransaction } from "./transaction.js";
2
2
  import { USER_CONTEXT_PRINCIPAL_ID } from "../../user-context/domain.js";
3
+ import { notifyUserContextChange } from "../../user-context/changes.js";
3
4
  import { retrievalQueryAuditValue } from "../../retrieval/audit.js";
4
5
  import { buildFts5SearchQuery, fts5RankToScore } from "./fts.js";
5
6
  import { createHash, randomUUID } from "node:crypto";
@@ -108,6 +109,10 @@ function getUserProfile(principalId = USER_CONTEXT_PRINCIPAL_ID) {
108
109
  };
109
110
  }
110
111
  function updateUserProfile(patch, principalId = USER_CONTEXT_PRINCIPAL_ID) {
112
+ notifyUserContextChange({
113
+ kind: "profile",
114
+ id: "profile"
115
+ });
111
116
  const current = getUserProfile(principalId);
112
117
  const now = Date.now();
113
118
  const next = {
@@ -163,11 +168,12 @@ function getUnderstanding(id) {
163
168
  const row = getSqliteDatabase().prepare(`${UNDERSTANDING_SELECT} WHERE u.understanding_id = ?`).get(id);
164
169
  return row ? understandingFromRow(row) : void 0;
165
170
  }
166
- function listUnderstandings(statuses, principalId = USER_CONTEXT_PRINCIPAL_ID) {
171
+ function listUnderstandings(statuses, principalId = USER_CONTEXT_PRINCIPAL_ID, limit) {
167
172
  const db = getSqliteDatabase();
168
- if (!statuses?.length) return db.prepare(`${UNDERSTANDING_SELECT} WHERE u.principal_id = ? ORDER BY u.updated_at DESC`).all(principalId).map(understandingFromRow);
173
+ const maxRows = limit === void 0 ? -1 : Math.max(1, Math.min(500, Math.floor(limit)));
174
+ if (!statuses?.length) return db.prepare(`${UNDERSTANDING_SELECT} WHERE u.principal_id = ? ORDER BY u.updated_at DESC LIMIT ?`).all(principalId, maxRows).map(understandingFromRow);
169
175
  const placeholders = statuses.map(() => "?").join(", ");
170
- return db.prepare(`${UNDERSTANDING_SELECT} WHERE u.principal_id = ? AND u.status IN (${placeholders}) ORDER BY u.updated_at DESC`).all(principalId, ...statuses).map(understandingFromRow);
176
+ return db.prepare(`${UNDERSTANDING_SELECT} WHERE u.principal_id = ? AND u.status IN (${placeholders}) ORDER BY u.updated_at DESC LIMIT ?`).all(principalId, ...statuses, maxRows).map(understandingFromRow);
171
177
  }
172
178
  function searchActiveUnderstandings(query, limit = 50) {
173
179
  const ftsQuery = buildFts5SearchQuery(query);
@@ -193,6 +199,10 @@ function searchActiveUnderstandings(query, limit = 50) {
193
199
  }));
194
200
  }
195
201
  function reviseUnderstanding(id, statement, options) {
202
+ notifyUserContextChange({
203
+ kind: "understanding",
204
+ id
205
+ });
196
206
  const current = getUnderstanding(id);
197
207
  if (!current) throw new Error(`User understanding not found: ${id}`);
198
208
  const versionId = randomUUID();
@@ -210,6 +220,10 @@ function reviseUnderstanding(id, statement, options) {
210
220
  return getUnderstanding(id);
211
221
  }
212
222
  function setUnderstandingStatus(id, status, options) {
223
+ notifyUserContextChange({
224
+ kind: "understanding",
225
+ id
226
+ });
213
227
  const current = getUnderstanding(id);
214
228
  if (!current) throw new Error(`User understanding not found: ${id}`);
215
229
  const now = Date.now();
@@ -237,6 +251,10 @@ function setUnderstandingStatus(id, status, options) {
237
251
  return result;
238
252
  }
239
253
  function closeUnderstandingValidity(id, validTo = Date.now()) {
254
+ notifyUserContextChange({
255
+ kind: "understanding",
256
+ id
257
+ });
240
258
  getSqliteDatabase().prepare(`UPDATE user_understandings SET valid_to = ?, updated_at = ?
241
259
  WHERE understanding_id = ?`).run(validTo, validTo, id);
242
260
  const result = getUnderstanding(id);
@@ -244,6 +262,10 @@ function closeUnderstandingValidity(id, validTo = Date.now()) {
244
262
  return result;
245
263
  }
246
264
  function rejectUnderstanding(id, reason, actorType = "runtime") {
265
+ notifyUserContextChange({
266
+ kind: "understanding",
267
+ id
268
+ });
247
269
  const current = getUnderstanding(id);
248
270
  if (!current) throw new Error(`User understanding not found: ${id}`);
249
271
  const now = Date.now();
@@ -277,6 +299,10 @@ function listUnderstandingStatusEvents(id) {
277
299
  }));
278
300
  }
279
301
  function deleteUnderstanding(id) {
302
+ notifyUserContextChange({
303
+ kind: "understanding",
304
+ id
305
+ });
280
306
  return runSqliteWriteTransaction((db) => {
281
307
  db.prepare("DELETE FROM user_understanding_fts WHERE understanding_id = ?").run(id);
282
308
  return Number(db.prepare("DELETE FROM user_understandings WHERE understanding_id = ?").run(id).changes) > 0;
@@ -342,6 +368,7 @@ function createContextEvidence(input, principalId = USER_CONTEXT_PRINCIPAL_ID) {
342
368
  AND COALESCE(source_instance_id, '') = COALESCE(?, '') AND source_ref = ?`).get(principalId, input.sourceType, input.sourceInstanceId ?? null, input.sourceRef);
343
369
  const derivedHash = input.contentHash ?? (input.redactedExcerpt ? createHash("sha256").update(input.redactedExcerpt).digest("hex") : void 0);
344
370
  if (existing) {
371
+ notifyUserContextChange({ kind: "policy" });
345
372
  getSqliteDatabase().prepare(`UPDATE context_evidence SET
346
373
  source_run_id = COALESCE(source_run_id, ?), source_item_id = COALESCE(source_item_id, ?),
347
374
  session_id = COALESCE(session_id, ?), turn_id = COALESCE(turn_id, ?),
@@ -373,6 +400,11 @@ function createContextEvidence(input, principalId = USER_CONTEXT_PRINCIPAL_ID) {
373
400
  return evidence;
374
401
  }
375
402
  function linkUnderstandingEvidence(versionId, evidenceId, relation, confidence) {
403
+ const owner = getSqliteDatabase().prepare("SELECT understanding_id AS id FROM user_understanding_versions WHERE version_id = ?").get(versionId);
404
+ if (owner) notifyUserContextChange({
405
+ kind: "understanding",
406
+ id: owner.id
407
+ });
376
408
  getSqliteDatabase().prepare(`INSERT INTO understanding_evidence_links (
377
409
  version_id, evidence_id, relation, confidence
378
410
  ) VALUES (?, ?, ?, ?)
@@ -385,6 +417,20 @@ function listUnderstandingEvidence(understandingId, relation) {
385
417
  WHERE v.understanding_id = ? AND (? IS NULL OR l.relation = ?)
386
418
  ORDER BY e.observed_at DESC`).all(understandingId, relation ?? null, relation ?? null).map(evidenceFromRow);
387
419
  }
420
+ /** Latest source labels for ranking, without fetching evidence bodies per candidate. */
421
+ function understandingSourceBuckets(ids) {
422
+ if (!ids.length) return /* @__PURE__ */ new Map();
423
+ const rows = getSqliteDatabase().prepare(`
424
+ SELECT understanding_id, source_type, source_instance_id, source_ref FROM (
425
+ SELECT v.understanding_id, e.source_type, e.source_instance_id, e.source_ref,
426
+ ROW_NUMBER() OVER (PARTITION BY v.understanding_id ORDER BY e.observed_at DESC) AS rank
427
+ FROM context_evidence e JOIN understanding_evidence_links l ON l.evidence_id = e.evidence_id
428
+ JOIN user_understanding_versions v ON v.version_id = l.version_id
429
+ WHERE v.understanding_id IN (${ids.map(() => "?").join(",")})
430
+ ) WHERE rank = 1
431
+ `).all(...ids);
432
+ return new Map(rows.map((row) => [row.understanding_id, `${row.source_type}:${row.source_instance_id ?? row.source_ref.split(":entry:")[0]}`]));
433
+ }
388
434
  function recordContextRun(input) {
389
435
  const auditedQuery = retrievalQueryAuditValue(input.query);
390
436
  const existing = getSqliteDatabase().prepare("SELECT context_run_id FROM context_runs WHERE turn_id = ?").get(input.turnId);
@@ -486,4 +532,4 @@ function decideContextConsent(id, decision) {
486
532
  return Number(result.changes) > 0;
487
533
  }
488
534
  //#endregion
489
- export { closeUnderstandingValidity, consumeContextConsent, createCollaborationRule, createContextEvidence, createUnderstanding, decideContextConsent, deleteCollaborationRule, deleteUnderstanding, ensureContextConsent, getCollaborationRule, getTurnPersonalization, getUnderstanding, getUserProfile, hasContextConsent, isUnderstandingSuppressed, linkUnderstandingEvidence, listCollaborationRules, listUnderstandingEvidence, listUnderstandingStatusEvents, listUnderstandings, recordContextFeedback, recordContextRun, rejectUnderstanding, reviseCollaborationRule, reviseUnderstanding, searchActiveUnderstandings, setCollaborationRuleStatus, setUnderstandingStatus, updateUserProfile };
535
+ export { closeUnderstandingValidity, consumeContextConsent, createCollaborationRule, createContextEvidence, createUnderstanding, decideContextConsent, deleteCollaborationRule, deleteUnderstanding, ensureContextConsent, getCollaborationRule, getTurnPersonalization, getUnderstanding, getUserProfile, hasContextConsent, isUnderstandingSuppressed, linkUnderstandingEvidence, listCollaborationRules, listUnderstandingEvidence, listUnderstandingStatusEvents, listUnderstandings, recordContextFeedback, recordContextRun, rejectUnderstanding, reviseCollaborationRule, reviseUnderstanding, searchActiveUnderstandings, setCollaborationRuleStatus, setUnderstandingStatus, understandingSourceBuckets, updateUserProfile };
@@ -477,7 +477,8 @@ async function runTui(opts) {
477
477
  isHidden: () => hidden,
478
478
  focus: () => tui.setFocus(component),
479
479
  unfocus: () => tui.setFocus(editor),
480
- isFocused: () => false
480
+ isFocused: () => false,
481
+ getBounds: () => void 0
481
482
  };
482
483
  };
483
484
  const closeCommandOverlay = () => {
@@ -0,0 +1,17 @@
1
+ import { type RemoteContextKind } from '../storage/sqlite/remote-context-repository.js';
2
+ import type { UserContextScopeTarget } from './scope.js';
3
+ export interface AutomaticContextReference {
4
+ kind: RemoteContextKind | 'profile';
5
+ id: string;
6
+ version: string;
7
+ }
8
+ export interface AutomaticContextSelection {
9
+ block: string;
10
+ references: AutomaticContextReference[];
11
+ }
12
+ /** Read-only background selection. Never consumes consent or starts a model turn. */
13
+ export declare function selectAutomaticContext(input: UserContextScopeTarget & {
14
+ query: string;
15
+ maxChars: number;
16
+ deadline: number;
17
+ }): AutomaticContextSelection;
@@ -0,0 +1,85 @@
1
+ import { getUserProfile, listUnderstandings } from "../storage/sqlite/user-context-repository.js";
2
+ import { listUserFocuses } from "./sources/repository.js";
3
+ import { UserUnderstandingRetriever } from "./retriever.js";
4
+ import { allowsAutomaticDisclosure, focusRejectionReason, focusScore, rejectionReason } from "./selection-policy.js";
5
+ import { remoteContextEligibleIds } from "../storage/sqlite/remote-context-repository.js";
6
+ //#region src/user-context/automatic-context.ts
7
+ /** Read-only background selection. Never consumes consent or starts a model turn. */
8
+ function selectAutomaticContext(input) {
9
+ const references = [];
10
+ const facts = [];
11
+ const profile = {};
12
+ const render = () => JSON.stringify({ backgroundMemory: {
13
+ profile,
14
+ facts
15
+ } });
16
+ const withinDeadline = () => performance.now() < input.deadline;
17
+ if (input.maxChars < 128 || !withinDeadline()) return {
18
+ block: "",
19
+ references
20
+ };
21
+ const user = getUserProfile();
22
+ for (const key of [
23
+ "callName",
24
+ "locale",
25
+ "timezone",
26
+ "pronouns",
27
+ "role",
28
+ "primaryGoal"
29
+ ]) {
30
+ if (!user[key] || user[key].length > 300) continue;
31
+ profile[key] = user[key];
32
+ if (render().length > input.maxChars) delete profile[key];
33
+ }
34
+ if (Object.keys(profile).length) references.push({
35
+ kind: "profile",
36
+ id: "profile",
37
+ version: JSON.stringify(user)
38
+ });
39
+ const query = input.query.trim();
40
+ const candidates = !withinDeadline() ? [] : query ? new UserUnderstandingRetriever().retrieve({
41
+ ...input,
42
+ maxCandidates: 50
43
+ }) : listUnderstandings(["active"], void 0, 200).filter((item) => item.explicitness === "explicit" && ["preference", "boundary"].includes(item.kind) && item.durability === "durable").map((understanding) => ({
44
+ understanding,
45
+ score: 1
46
+ }));
47
+ const now = Date.now();
48
+ const eligible = candidates.filter(({ understanding: item, score }) => item.status === "active" && allowsAutomaticDisclosure(item) && !rejectionReason(item, input, now, []) && score > .25);
49
+ const allowed = withinDeadline() ? remoteContextEligibleIds("understanding", eligible.map(({ understanding }) => understanding.id)) : /* @__PURE__ */ new Set();
50
+ const append = (text, origin, reference) => {
51
+ if (!withinDeadline() || facts.length >= 6 || !text.trim()) return;
52
+ facts.push({
53
+ text,
54
+ origin
55
+ });
56
+ if (render().length > input.maxChars) {
57
+ facts.pop();
58
+ return;
59
+ }
60
+ references.push(reference);
61
+ };
62
+ for (const { understanding: item } of eligible) if (allowed.has(item.id)) append(item.statement, item.explicitness, {
63
+ kind: "understanding",
64
+ id: item.id,
65
+ version: item.versionId
66
+ });
67
+ if (query && withinDeadline() && facts.length < 6) {
68
+ const focuses = listUserFocuses(["active"], 50).filter((item) => allowsAutomaticDisclosure(item) && !focusRejectionReason(item, input, now)).map((item) => ({
69
+ item,
70
+ score: focusScore(item, query, input)
71
+ })).filter(({ score }) => score > .25).sort((a, b) => b.score - a.score);
72
+ const allowedFocuses = remoteContextEligibleIds("focus", focuses.map(({ item }) => item.id));
73
+ for (const { item } of focuses) if (allowedFocuses.has(item.id)) append(`${item.title}: ${item.summary}`, item.explicitness, {
74
+ kind: "focus",
75
+ id: item.id,
76
+ version: item.versionId ?? String(item.updatedAt)
77
+ });
78
+ }
79
+ return {
80
+ block: references.length ? render() : "",
81
+ references
82
+ };
83
+ }
84
+ //#endregion
85
+ export { selectAutomaticContext };
@@ -0,0 +1,7 @@
1
+ export interface UserContextChange {
2
+ kind: 'profile' | 'understanding' | 'focus' | 'policy' | 'session' | 'session-reset';
3
+ id?: string;
4
+ }
5
+ export declare function onUserContextChange(listener: (change: UserContextChange) => void): () => void;
6
+ /** Dispatch after the synchronous write/outer transaction has left the stack. */
7
+ export declare function notifyUserContextChange(change: UserContextChange): void;
@@ -0,0 +1,28 @@
1
+ import { createLogger } from "../utils/logger/index.js";
2
+ import { init_logger } from "../utils/logger.js";
3
+ //#region src/user-context/changes.ts
4
+ init_logger();
5
+ const listeners = /* @__PURE__ */ new Set();
6
+ const log = createLogger("UserContextChanges");
7
+ function onUserContextChange(listener) {
8
+ listeners.add(listener);
9
+ return () => {
10
+ listeners.delete(listener);
11
+ };
12
+ }
13
+ /** Dispatch after the synchronous write/outer transaction has left the stack. */
14
+ function notifyUserContextChange(change) {
15
+ if (!listeners.size) return;
16
+ queueMicrotask(() => {
17
+ for (const listener of listeners) try {
18
+ listener(change);
19
+ } catch (err) {
20
+ log.error({
21
+ err,
22
+ kind: change.kind
23
+ }, "User context change listener failed");
24
+ }
25
+ });
26
+ }
27
+ //#endregion
28
+ export { notifyUserContextChange, onUserContextChange };
@@ -1,5 +1,4 @@
1
1
  import { consumeContextConsent, ensureContextConsent, getUserProfile, listCollaborationRules, listUnderstandingEvidence, listUnderstandings, recordContextRun } from "../storage/sqlite/user-context-repository.js";
2
- import { retrievalLexicalSimilarity } from "../retrieval/textFeatures.js";
3
2
  import { buildRetrievalQueryProfile } from "../retrieval/queryProfile.js";
4
3
  import "../storage/sqlite/index.js";
5
4
  import { init_session_key, parseSessionKey } from "../routing/session-key.js";
@@ -9,6 +8,7 @@ import { buildUserContextBlock } from "../agent/memory/context-fence.js";
9
8
  import { getUnderstandingSourceGrant, getUnderstandingSourceRun, listUserFocuses } from "./sources/repository.js";
10
9
  import { matchesUserContextScope } from "./scope.js";
11
10
  import { UserUnderstandingRetriever } from "./retriever.js";
11
+ import { focusRejectionReason, focusScore, rejectionReason } from "./selection-policy.js";
12
12
  import { randomUUID } from "node:crypto";
13
13
  //#region src/user-context/planner.ts
14
14
  init_session_key();
@@ -103,35 +103,12 @@ function focusSourceDescription(focus) {
103
103
  label: "Suggested from prior work"
104
104
  };
105
105
  }
106
- function rejectionReason(item, input, now, timeHints) {
107
- const historical = timeHints.includes("historical") && item.validTo !== void 0;
108
- if (item.status === "needs_review" || item.status === "candidate" || item.status === "stale" && !historical) return "needs_review";
109
- if (item.status === "rejected" || item.status === "archived" && !historical) return "disabled";
110
- if (!matchesUserContextScope(item.scope, input)) return "scope_mismatch";
111
- if (item.validFrom && item.validFrom > now && !timeHints.includes("future")) return "not_yet_valid";
112
- if ((item.validTo && item.validTo < now || item.expiresAt && item.expiresAt < now) && !historical) return "expired";
113
- if (item.sensitivity === "secret" || item.sensitivity === "regulated") return "sensitive";
114
- if (item.conflictGroupId) return "conflict";
115
- }
116
106
  function ruleMatches(rule, input) {
117
107
  if (rule.status !== "active" || !matchesUserContextScope(rule.scope, input)) return false;
118
108
  const channel = typeof rule.conditions.channel === "string" ? rule.conditions.channel : void 0;
119
109
  const agentId = typeof rule.conditions.agentId === "string" ? rule.conditions.agentId : void 0;
120
110
  return (!channel || channel === input.channel) && (!agentId || agentId === input.agentId);
121
111
  }
122
- function focusRejectionReason(focus, input, now) {
123
- if (focus.status !== "active") return "disabled";
124
- if (!matchesUserContextScope(focus.scope, input)) return "scope_mismatch";
125
- if (focus.validFrom && focus.validFrom > now) return "not_yet_valid";
126
- if (focus.validTo && focus.validTo < now) return "expired";
127
- if (focus.sensitivity === "secret" || focus.sensitivity === "regulated") return "sensitive";
128
- if (focus.disclosurePolicy === "ask_before_reference") return "requires_consent";
129
- }
130
- function focusScore(focus, query, scopeInput) {
131
- const lexical = retrievalLexicalSimilarity(buildRetrievalQueryProfile(query, scopeInput).normalized, `${focus.title} ${focus.summary}`);
132
- const scoped = focus.scope.type !== "global" && matchesUserContextScope(focus.scope, scopeInput);
133
- return Math.min(1, lexical * .75 + focus.confidence * .15 + (scoped ? .25 : 0));
134
- }
135
112
  function renderContextBlock(params) {
136
113
  const understandingItems = params.items.filter((item) => item.objectType === "understanding");
137
114
  return [
@@ -1,5 +1,5 @@
1
1
  import { summarizeUnderstandingFeedback } from "../storage/sqlite/user-context-quality-repository.js";
2
- import { listUnderstandingEvidence, listUnderstandings, searchActiveUnderstandings } from "../storage/sqlite/user-context-repository.js";
2
+ import { listUnderstandings, searchActiveUnderstandings, understandingSourceBuckets } from "../storage/sqlite/user-context-repository.js";
3
3
  import { normalizeRetrievalText, retrievalLexicalSimilarity } from "../retrieval/textFeatures.js";
4
4
  import { buildRetrievalQueryProfile } from "../retrieval/queryProfile.js";
5
5
  import "../storage/sqlite/index.js";
@@ -32,23 +32,18 @@ function temporalAdjustment(item, hints, now) {
32
32
  }
33
33
  return score;
34
34
  }
35
- function sourceBucket(item) {
36
- if (item.explicitness === "explicit") return "user";
37
- const evidence = listUnderstandingEvidence(item.id)[0];
38
- if (!evidence) return `unknown:${item.id}`;
39
- if (evidence.sourceInstanceId) return `${evidence.sourceType}:${evidence.sourceInstanceId}`;
40
- return `${evidence.sourceType}:${evidence.sourceRef.split(":entry:")[0]}`;
41
- }
42
35
  function diversify(results, limit) {
43
36
  const remaining = [...results];
44
37
  const selected = [];
45
38
  const sourceCounts = /* @__PURE__ */ new Map();
46
- const sourceBuckets = new Map(results.map((result) => [result.understanding.id, sourceBucket(result.understanding)]));
39
+ const redundancies = /* @__PURE__ */ new Map();
40
+ const evidenceBuckets = understandingSourceBuckets(results.filter((result) => result.understanding.explicitness !== "explicit").map((result) => result.understanding.id));
41
+ const sourceBuckets = new Map(results.map(({ understanding: item }) => [item.id, item.explicitness === "explicit" ? "user" : evidenceBuckets.get(item.id) ?? `unknown:${item.id}`]));
47
42
  while (remaining.length && selected.length < limit) {
48
43
  let bestIndex = 0;
49
44
  let bestScore = Number.NEGATIVE_INFINITY;
50
45
  for (const [index, candidate] of remaining.entries()) {
51
- const redundancy = selected.reduce((maximum, chosen) => Math.max(maximum, retrievalLexicalSimilarity(candidate.understanding.statement, chosen.understanding.statement)), 0);
46
+ const redundancy = redundancies.get(candidate.understanding.id) ?? 0;
52
47
  const bucket = sourceBuckets.get(candidate.understanding.id);
53
48
  const sourcePenalty = candidate.understanding.explicitness === "explicit" ? 0 : (sourceCounts.get(bucket) ?? 0) * .04;
54
49
  const adjusted = candidate.score - redundancy * .18 - sourcePenalty;
@@ -65,6 +60,10 @@ function diversify(results, limit) {
65
60
  score: Math.max(0, bestScore),
66
61
  reasons: bestScore < candidate.score ? [...candidate.reasons, "diversified"] : candidate.reasons
67
62
  });
63
+ if (selected.length < limit) for (const remainingItem of remaining) {
64
+ const id = remainingItem.understanding.id;
65
+ redundancies.set(id, Math.max(redundancies.get(id) ?? 0, retrievalLexicalSimilarity(remainingItem.understanding.statement, candidate.understanding.statement)));
66
+ }
68
67
  }
69
68
  return selected;
70
69
  }
@@ -90,7 +89,7 @@ var UserUnderstandingRetriever = class {
90
89
  "active",
91
90
  "archived",
92
91
  "stale"
93
- ] : ["active"]]).slice(0, recentLimit);
92
+ ] : ["active"]], void 0, recentLimit);
94
93
  const candidates = /* @__PURE__ */ new Map();
95
94
  for (const result of fts) candidates.set(result.understanding.id, result.understanding);
96
95
  for (const item of recent) candidates.set(item.id, item);
@@ -0,0 +1,20 @@
1
+ import type { UserContextRejectionReason } from '../agent/memory/context/types.js';
2
+ import type { UserUnderstanding } from './domain.js';
3
+ import type { UserFocus } from './sources/types.js';
4
+ /** Automatic remote context never uses sensitive, consent-gated or weakly inferred facts. */
5
+ export declare function allowsAutomaticDisclosure(item: Pick<UserUnderstanding, 'sensitivity' | 'disclosurePolicy' | 'explicitness' | 'confidence'>): boolean;
6
+ export declare function rejectionReason(item: UserUnderstanding, input: {
7
+ sessionKey: string;
8
+ workspaceId: string;
9
+ projectId?: string;
10
+ }, now: number, timeHints: string[]): UserContextRejectionReason | undefined;
11
+ export declare function focusRejectionReason(focus: UserFocus, input: {
12
+ sessionKey: string;
13
+ workspaceId: string;
14
+ projectId?: string;
15
+ }, now: number): UserContextRejectionReason | undefined;
16
+ export declare function focusScore(focus: UserFocus, query: string, scopeInput: {
17
+ sessionKey: string;
18
+ workspaceId: string;
19
+ projectId?: string;
20
+ }): number;
@@ -0,0 +1,33 @@
1
+ import { retrievalLexicalSimilarity } from "../retrieval/textFeatures.js";
2
+ import { buildRetrievalQueryProfile } from "../retrieval/queryProfile.js";
3
+ import { matchesUserContextScope } from "./scope.js";
4
+ //#region src/user-context/selection-policy.ts
5
+ /** Automatic remote context never uses sensitive, consent-gated or weakly inferred facts. */
6
+ function allowsAutomaticDisclosure(item) {
7
+ return item.sensitivity === "normal" && item.disclosurePolicy !== "ask_before_reference" && (item.explicitness !== "inferred" || item.confidence >= .8);
8
+ }
9
+ function rejectionReason(item, input, now, timeHints) {
10
+ const historical = timeHints.includes("historical") && item.validTo !== void 0;
11
+ if (item.status === "needs_review" || item.status === "candidate" || item.status === "stale" && !historical) return "needs_review";
12
+ if (item.status === "rejected" || item.status === "archived" && !historical) return "disabled";
13
+ if (!matchesUserContextScope(item.scope, input)) return "scope_mismatch";
14
+ if (item.validFrom && item.validFrom > now && !timeHints.includes("future")) return "not_yet_valid";
15
+ if ((item.validTo && item.validTo < now || item.expiresAt && item.expiresAt < now) && !historical) return "expired";
16
+ if (item.sensitivity === "secret" || item.sensitivity === "regulated") return "sensitive";
17
+ if (item.conflictGroupId) return "conflict";
18
+ }
19
+ function focusRejectionReason(focus, input, now) {
20
+ if (focus.status !== "active") return "disabled";
21
+ if (!matchesUserContextScope(focus.scope, input)) return "scope_mismatch";
22
+ if (focus.validFrom && focus.validFrom > now) return "not_yet_valid";
23
+ if (focus.validTo && focus.validTo < now) return "expired";
24
+ if (focus.sensitivity === "secret" || focus.sensitivity === "regulated") return "sensitive";
25
+ if (focus.disclosurePolicy === "ask_before_reference") return "requires_consent";
26
+ }
27
+ function focusScore(focus, query, scopeInput) {
28
+ const lexical = retrievalLexicalSimilarity(buildRetrievalQueryProfile(query, scopeInput).normalized, `${focus.title} ${focus.summary}`);
29
+ const scoped = focus.scope.type !== "global" && matchesUserContextScope(focus.scope, scopeInput);
30
+ return Math.min(1, lexical * .75 + focus.confidence * .15 + (scoped ? .25 : 0));
31
+ }
32
+ //#endregion
33
+ export { allowsAutomaticDisclosure, focusRejectionReason, focusScore, rejectionReason };
@@ -1,4 +1,4 @@
1
- import { createUnderstandingSourceRun, deleteUserFocus, getUnderstandingSourceGrant, getUnderstandingSourceRun, listUnderstandingSourceGrants, listUnderstandingSourceRuns, listUserFocusEvidence, listUserFocuses, revokeUnderstandingSourceGrant, updateUnderstandingSourceGrantCheckpoint, updateUnderstandingSourceGrantPolicies, updateUnderstandingSourceRun, updateUserFocus, upsertUnderstandingSourceGrant, upsertUserFocus } from "./repository.js";
1
+ import { createUnderstandingSourceRun, deleteUserFocus, getUnderstandingSourceGrant, getUnderstandingSourceRun, getUserFocus, listUnderstandingSourceGrants, listUnderstandingSourceRuns, listUserFocusEvidence, listUserFocuses, revokeUnderstandingSourceGrant, updateUnderstandingSourceGrantCheckpoint, updateUnderstandingSourceGrantPolicies, updateUnderstandingSourceRun, updateUserFocus, upsertUnderstandingSourceGrant, upsertUserFocus } from "./repository.js";
2
2
  import { clusterUnderstandingSignals, tokenizeUnderstandingSignal } from "./signal-clustering.js";
3
3
  import { listUnderstandingSourceDefinitions } from "./catalog.js";
4
- export { clusterUnderstandingSignals, createUnderstandingSourceRun, deleteUserFocus, getUnderstandingSourceGrant, getUnderstandingSourceRun, listUnderstandingSourceDefinitions, listUnderstandingSourceGrants, listUnderstandingSourceRuns, listUserFocusEvidence, listUserFocuses, revokeUnderstandingSourceGrant, tokenizeUnderstandingSignal, updateUnderstandingSourceGrantCheckpoint, updateUnderstandingSourceGrantPolicies, updateUnderstandingSourceRun, updateUserFocus, upsertUnderstandingSourceGrant, upsertUserFocus };
4
+ export { clusterUnderstandingSignals, createUnderstandingSourceRun, deleteUserFocus, getUnderstandingSourceGrant, getUnderstandingSourceRun, getUserFocus, listUnderstandingSourceDefinitions, listUnderstandingSourceGrants, listUnderstandingSourceRuns, listUserFocusEvidence, listUserFocuses, revokeUnderstandingSourceGrant, tokenizeUnderstandingSignal, updateUnderstandingSourceGrantCheckpoint, updateUnderstandingSourceGrantPolicies, updateUnderstandingSourceRun, updateUserFocus, upsertUnderstandingSourceGrant, upsertUserFocus };
@@ -54,7 +54,8 @@ export declare function updateUnderstandingSourceRun(id: string, patch: {
54
54
  nowMs?: number;
55
55
  }): UnderstandingSourceRun | null;
56
56
  export declare function upsertUserFocus(input: UserFocusInput): UserFocus;
57
- export declare function listUserFocuses(statuses?: UserFocus['status'][]): UserFocus[];
57
+ export declare function listUserFocuses(statuses?: UserFocus['status'][], limit?: number): UserFocus[];
58
+ export declare function getUserFocus(id: string): UserFocus | undefined;
58
59
  export declare function updateUserFocus(id: string, patch: Partial<Pick<UserFocus, 'title' | 'summary' | 'status' | 'validFrom' | 'validTo' | 'reviewAt'>>, nowMs?: number): UserFocus | null;
59
60
  export declare function deleteUserFocus(id: string): boolean;
60
61
  export {};