@xopcai/xopc 0.0.227 → 0.0.229

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 (249) 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-BevwE16n.js → activity-store-M0nAY5XB.js} +1 -1
  4. package/dist/gateway/static/root/assets/{agent-avatar-dicebear-BggVQrEZ.js → agent-avatar-dicebear-CsFAJTIN.js} +1 -1
  5. package/dist/gateway/static/root/assets/agents-DA4b6_0C.js +68 -0
  6. package/dist/gateway/static/root/assets/{api-Bx_BpIt8.js → api-BywYxpaS.js} +1 -1
  7. package/dist/gateway/static/root/assets/{app-management-settings-panel-BtKP9n2r.js → app-management-settings-panel-7KcMWuah.js} +1 -1
  8. package/dist/gateway/static/root/assets/{appearance-settings-BoH2NAUX.js → appearance-settings-Cqlw7Fif.js} +1 -1
  9. package/dist/gateway/static/root/assets/apps-page-CsnhdGZ2.js +1 -0
  10. package/dist/gateway/static/root/assets/{archive-plugin-DnceUyxm.js → archive-plugin-7_DXaMTP.js} +1 -1
  11. package/dist/gateway/static/root/assets/{attachment-load-Bh8_9gkr.js → attachment-load-q4pDpqkF.js} +1 -1
  12. package/dist/gateway/static/root/assets/{automations-page-ZKeAAVxD.js → automations-page-BuTqjKGX.js} +1 -1
  13. package/dist/gateway/static/root/assets/automations-workspace-CD0E2ThS.js +6 -0
  14. package/dist/gateway/static/root/assets/{binary-plugins-Cy9er6w-.js → binary-plugins-DUce1Bsc.js} +1 -1
  15. package/dist/gateway/static/root/assets/{block-editor-Cc0wWvNX.js → block-editor-D8Ejp-QR.js} +3 -3
  16. package/dist/gateway/static/root/assets/browser-settings-page-CY1k3MMd.js +8 -0
  17. package/dist/gateway/static/root/assets/{browser-workflow-inputs-BS7rpLLl.js → browser-workflow-inputs-8NC2qDRF.js} +1 -1
  18. package/dist/gateway/static/root/assets/{browser-workflows-page-BdBVUZXm.js → browser-workflows-page-BDvZbR9v.js} +2 -2
  19. package/dist/gateway/static/root/assets/capabilities-settings-panel-D1VfotHQ.js +7 -0
  20. package/dist/gateway/static/root/assets/{capability-presets-api-D1Lqz0Tt.js → capability-presets-api-o0y9WgAI.js} +1 -1
  21. package/dist/gateway/static/root/assets/capability-presets-settings-panel-DXHqRLpU.js +3 -0
  22. package/dist/gateway/static/root/assets/{channel-recipient-api-CGuEl-l2.js → channel-recipient-api-C5ABr73b.js} +1 -1
  23. package/dist/gateway/static/root/assets/channels-settings-DrFL57M_.js +1 -0
  24. package/dist/gateway/static/root/assets/channels-status-swr-38FsOnR0.js +1 -0
  25. package/dist/gateway/static/root/assets/{chat-terminal-dock-CdX_7aQh.js → chat-terminal-dock-h1CKexNz.js} +2 -2
  26. package/dist/gateway/static/root/assets/connectors-page-DUAyfFCF.js +2 -0
  27. package/dist/gateway/static/root/assets/{cron-expression-BnSQc4Ek.js → cron-expression-DlaQQOId.js} +1 -1
  28. package/dist/gateway/static/root/assets/{date-picker-BbuG7zQ_.js → date-picker-8R1sXJKb.js} +1 -1
  29. package/dist/gateway/static/root/assets/{dependency-picker-snZeqOmG.js → dependency-picker-CWur0821.js} +1 -1
  30. package/dist/gateway/static/root/assets/{desktop-pet-DJQ8JoR1.js → desktop-pet-Knl-zNDU.js} +1 -1
  31. package/dist/gateway/static/root/assets/{desktop-pet-settings-B9txsRtv.js → desktop-pet-settings-CAQMLVtd.js} +1 -1
  32. package/dist/gateway/static/root/assets/{directory-picker-path-field-D7WKWkNB.js → directory-picker-path-field-Caaz4Rw5.js} +1 -1
  33. package/dist/gateway/static/root/assets/{extension-debug-page-D_7cOCj2.js → extension-debug-page-B965Mc15.js} +1 -1
  34. package/dist/gateway/static/root/assets/{extension-page-Bwu47iUb.js → extension-page-C0UnkBi5.js} +1 -1
  35. package/dist/gateway/static/root/assets/{extension-settings-page-Dwg4dSZM.js → extension-settings-page-BUSIAZCR.js} +1 -1
  36. package/dist/gateway/static/root/assets/{gateway-config-api-jURUSte_.js → gateway-config-api-DkH0eEgy.js} +1 -1
  37. package/dist/gateway/static/root/assets/{gateway-config-swr-6SQXF1yR.js → gateway-config-swr-BWGjnmDl.js} +1 -1
  38. package/dist/gateway/static/root/assets/{gateway-settings-UklJOMLX.js → gateway-settings-BBgLDm6I.js} +1 -1
  39. package/dist/gateway/static/root/assets/{gateway-startup-retry-DqWaxyvZ.js → gateway-startup-retry-B_zrtccP.js} +1 -1
  40. package/dist/gateway/static/root/assets/{heartbeat-settings-Djs_nduD.js → heartbeat-settings-BtEHVXWD.js} +1 -1
  41. package/dist/gateway/static/root/assets/home-page-5SU2TNJj.js +1 -0
  42. package/dist/gateway/static/root/assets/{image-generation-api-Bxmt6LEr.js → image-generation-api-YKP2me5Z.js} +1 -1
  43. package/dist/gateway/static/root/assets/index-BNWhgmjs.js +70 -0
  44. package/dist/gateway/static/root/assets/index-D_hrEKXM.css +2 -0
  45. package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-ByVsCH3d.js → keyboard-shortcuts-settings-CsRz8NrS.js} +1 -1
  46. package/dist/gateway/static/root/assets/local-app-workbench-page-DYPEUgpP.js +2 -0
  47. package/dist/gateway/static/root/assets/{local-apps-page-D19R-xsz.js → local-apps-page-CTBNUG4a.js} +1 -1
  48. package/dist/gateway/static/root/assets/{locale-store-Ci1Qi0Q-.js → locale-store-CXhjfe4q.js} +1 -1
  49. package/dist/gateway/static/root/assets/logs-page-B0P7rG2B.js +2 -0
  50. package/dist/gateway/static/root/assets/{management-settings-G0y7zmfY.js → management-settings-YqUAEwQo.js} +1 -1
  51. package/dist/gateway/static/root/assets/{markdown-split-B69d2HWt.js → markdown-split-dxpSCXb8.js} +1 -1
  52. package/dist/gateway/static/root/assets/{markdown-view-DD_PgVue.css → markdown-view-CLzTdVLW.css} +1 -1
  53. package/dist/gateway/static/root/assets/markdown-view-DvM5PWEH.js +201 -0
  54. package/dist/gateway/static/root/assets/{media-plugins-6TWEQgN_.js → media-plugins-CJ00i1Lg.js} +1 -1
  55. package/dist/gateway/static/root/assets/messages-BMdD0LWk.js +3 -0
  56. package/dist/gateway/static/root/assets/{notes-api-DLsnnZCS.js → notes-api-BFsOGYkd.js} +1 -1
  57. package/dist/gateway/static/root/assets/{notes-page-CkRJJKDm.js → notes-page-DEnbnkIt.js} +1 -1
  58. package/dist/gateway/static/root/assets/notes-workbench-DmVYu_Oc.js +4 -0
  59. package/dist/gateway/static/root/assets/{product-open-page-HxArIvoN.js → product-open-page-BHxo9U95.js} +1 -1
  60. package/dist/gateway/static/root/assets/project-detail-page-DV2nGmsq.js +1 -0
  61. package/dist/gateway/static/root/assets/projects-page-BNIFwFfc.js +1 -0
  62. package/dist/gateway/static/root/assets/{registry-api-lEar5FOV.js → registry-api-BFZrVYfy.js} +1 -1
  63. package/dist/gateway/static/root/assets/remote-access-hub-DLXqKiA_.js +1 -0
  64. package/dist/gateway/static/root/assets/{runtime-tools-settings-panel-Bf03UNGD.js → runtime-tools-settings-panel-BpQ2GI-0.js} +1 -1
  65. package/dist/gateway/static/root/assets/{schema-form-CIXMBgx5.js → schema-form-HE1G26Lx.js} +1 -1
  66. package/dist/gateway/static/root/assets/sessions-page-DWaXf_25.js +1 -0
  67. package/dist/gateway/static/root/assets/settings-advanced-gate-JFCbnCL2.js +1 -0
  68. package/dist/gateway/static/root/assets/{settings-form-section-DgdB26mE.js → settings-form-section-CXAn0Xhy.js} +1 -1
  69. package/dist/gateway/static/root/assets/{settings-loading-skeleton-efk5W6lG.js → settings-loading-skeleton-DsFu7Bcv.js} +1 -1
  70. package/dist/gateway/static/root/assets/{settings-page-BHVf4gEP.js → settings-page-C4iib9nO.js} +1 -1
  71. package/dist/gateway/static/root/assets/{setup-status-panel-WK0dGNMv.js → setup-status-panel-BA83Wr1d.js} +1 -1
  72. package/dist/gateway/static/root/assets/{share-preview-page-Cod-w2qm.js → share-preview-page-BOGl3s6M.js} +1 -1
  73. package/dist/gateway/static/root/assets/{shares-settings-CUqQ31gt.js → shares-settings-Q2MdGaBi.js} +1 -1
  74. package/dist/gateway/static/root/assets/skill-reload-api-cFtfVeFU.js +1 -0
  75. package/dist/gateway/static/root/assets/{skills-page-DwCcipqK.js → skills-page-CdaFtNw9.js} +1 -1
  76. package/dist/gateway/static/root/assets/{skills-page.utils-3WSbtl3S.js → skills-page.utils-DYaAddUL.js} +1 -1
  77. package/dist/gateway/static/root/assets/{system-settings-panel-C5VxqC_s.js → system-settings-panel-Co7gilRd.js} +1 -1
  78. package/dist/gateway/static/root/assets/task-detail-page-5B1pswu8.js +1 -0
  79. package/dist/gateway/static/root/assets/{theme-store-Dd89g_ki.js → theme-store-DOdCjyuw.js} +1 -1
  80. package/dist/gateway/static/root/assets/{use-autosave-CeV8VJh2.js → use-autosave-DnnZtMpA.js} +1 -1
  81. package/dist/gateway/static/root/assets/user-context-page-Dr1FKjXv.js +1 -0
  82. package/dist/gateway/static/root/assets/{voice-api-key-field-EmJ-8aZu.js → voice-api-key-field-wetUpi3i.js} +1 -1
  83. package/dist/gateway/static/root/assets/{work-discovery-overlay-zsk6E3Mi.js → work-discovery-overlay-tbTWASJJ.js} +1 -1
  84. package/dist/gateway/static/root/assets/workflow-run-setup-panel-Dy0fDs8w.js +3 -0
  85. package/dist/gateway/static/root/assets/workflows-page-IVP3GSkI.js +5 -0
  86. package/dist/gateway/static/root/index.html +12 -12
  87. package/dist/gateway/static/root/notification-sw.js +1 -1
  88. package/dist/package.js +1 -1
  89. package/dist/packages/gateway-contract/src/notifications.js +56 -0
  90. package/dist/packages/gateway-contract/src/turn-outcome.js +114 -0
  91. package/dist/src/agent/agent-instance-gateway.d.ts +1 -1
  92. package/dist/src/agent/agent-manager.d.ts +1 -1
  93. package/dist/src/agent/agent-manager.js +18 -3
  94. package/dist/src/agent/background-review/prompts.d.ts +8 -2
  95. package/dist/src/agent/background-review/prompts.js +25 -12
  96. package/dist/src/agent/background-review/run-background-review.d.ts +7 -2
  97. package/dist/src/agent/background-review/run-background-review.js +175 -160
  98. package/dist/src/agent/lifecycle/timeout-wrapper.d.ts +1 -0
  99. package/dist/src/agent/lifecycle/timeout-wrapper.js +7 -6
  100. package/dist/src/agent/mcp/mcp-transport-config.d.ts +1 -1
  101. package/dist/src/agent/mcp/mcp-transport-config.js +1 -1
  102. package/dist/src/agent/memory/index.d.ts +1 -1
  103. package/dist/src/agent/memory/index.js +2 -2
  104. package/dist/src/agent/memory/manager.d.ts +1 -11
  105. package/dist/src/agent/memory/manager.js +0 -16
  106. package/dist/src/agent/memory/understanding/service.d.ts +0 -11
  107. package/dist/src/agent/memory/understanding/service.js +7 -173
  108. package/dist/src/agent/memory/user-context-coordinator.d.ts +1 -3
  109. package/dist/src/agent/memory/user-context-coordinator.js +3 -66
  110. package/dist/src/agent/orchestration/agent-orchestrator.js +1 -1
  111. package/dist/src/agent/orchestration/run-agent-turn-with-timeout.d.ts +2 -2
  112. package/dist/src/agent/orchestration/run-agent-turn-with-timeout.js +4 -4
  113. package/dist/src/agent/service/direct-turn-helpers.js +1 -1
  114. package/dist/src/agent/tools/create-share-tool.js +14 -1
  115. package/dist/src/agent/tools/exec-command.js +3 -3
  116. package/dist/src/agent/tools/execute-code-tool.js +1 -1
  117. package/dist/src/agent/tools/executor.js +2 -2
  118. package/dist/src/agent/tools/image-generate-tool.js +12 -0
  119. package/dist/src/agent/tools/send-media.js +11 -0
  120. package/dist/src/agent/tools/xopc-use-tool.js +1 -1
  121. package/dist/src/cli/command-loaders.js +1 -0
  122. package/dist/src/cli/command-manifest.js +4 -0
  123. package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
  124. package/dist/src/cli/commands/history.d.ts +1 -0
  125. package/dist/src/cli/commands/history.js +50 -0
  126. package/dist/src/config/agent-profile.js +1 -1
  127. package/dist/src/config/schema.d.ts +4 -0
  128. package/dist/src/config/schema.js +1 -0
  129. package/dist/src/connectors/connected-source-understanding.js +35 -21
  130. package/dist/src/connectors/learning-coordinator.js +1 -42
  131. package/dist/src/gateway/agents-admin.js +1 -1
  132. package/dist/src/gateway/chat-stream/mapper.d.ts +2 -0
  133. package/dist/src/gateway/chat-stream/mapper.js +5 -0
  134. package/dist/src/gateway/chat-stream/protocol.d.ts +3 -2
  135. package/dist/src/gateway/chat-stream/turn-outcome-collector.d.ts +16 -0
  136. package/dist/src/gateway/chat-stream/turn-outcome-collector.js +111 -0
  137. package/dist/src/gateway/hono/lib/static-ui.js +7 -5
  138. package/dist/src/gateway/hono/routes/index.js +2 -0
  139. package/dist/src/gateway/hono/routes/mobile.js +18 -40
  140. package/dist/src/gateway/hono/routes/notifications.d.ts +3 -0
  141. package/dist/src/gateway/hono/routes/notifications.js +45 -0
  142. package/dist/src/gateway/hono/routes/sessions.js +31 -0
  143. package/dist/src/gateway/hono/routes/tasks.js +1 -1
  144. package/dist/src/gateway/hono/routes/understanding-sources.js +4 -1
  145. package/dist/src/gateway/hono/routes/you.js +29 -11
  146. package/dist/src/gateway/service/agent-runner.js +6 -2
  147. package/dist/src/gateway/service/run-gateway-agent.js +58 -2
  148. package/dist/src/gateway/service/sessions-api.d.ts +6 -0
  149. package/dist/src/gateway/service/sessions-api.js +60 -3
  150. package/dist/src/gateway/service.d.ts +2 -2
  151. package/dist/src/gateway/service.js +8 -7
  152. package/dist/src/history/ctx/exporter.d.ts +14 -0
  153. package/dist/src/history/ctx/exporter.js +99 -0
  154. package/dist/src/history/ctx/format.d.ts +25 -0
  155. package/dist/src/history/ctx/format.js +282 -0
  156. package/dist/src/knowledge/index.d.ts +0 -1
  157. package/dist/src/knowledge/index.js +1 -2
  158. package/dist/src/media/session-references.d.ts +6 -0
  159. package/dist/src/media/session-references.js +24 -3
  160. package/dist/src/notifications/device-store.d.ts +16 -0
  161. package/dist/src/notifications/device-store.js +96 -0
  162. package/dist/src/notifications/planner.d.ts +6 -0
  163. package/dist/src/notifications/planner.js +160 -0
  164. package/dist/src/notifications/service.d.ts +18 -0
  165. package/dist/src/notifications/service.js +184 -0
  166. package/dist/src/notifications/store.d.ts +53 -0
  167. package/dist/src/notifications/store.js +184 -0
  168. package/dist/src/notifications/types.d.ts +29 -0
  169. package/dist/src/notifications/types.js +14 -0
  170. package/dist/src/session/client-history.d.ts +3 -1
  171. package/dist/src/session/client-history.js +13 -0
  172. package/dist/src/session/index.d.ts +1 -1
  173. package/dist/src/session/manager.d.ts +1 -0
  174. package/dist/src/session/manager.js +6 -0
  175. package/dist/src/session/store.d.ts +15 -0
  176. package/dist/src/session/store.js +58 -0
  177. package/dist/src/storage/sqlite/index.d.ts +2 -2
  178. package/dist/src/storage/sqlite/index.js +3 -3
  179. package/dist/src/storage/sqlite/migrations/136_product_notifications.sql +79 -0
  180. package/dist/src/storage/sqlite/migrations/137_understanding_status_audit.sql +71 -0
  181. package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
  182. package/dist/src/storage/sqlite/migrations/runner.js +3 -3
  183. package/dist/src/storage/sqlite/migrations/runner.ts +1 -1
  184. package/dist/src/storage/sqlite/schema.js +1 -1
  185. package/dist/src/storage/sqlite/session-input-repository.d.ts +5 -0
  186. package/dist/src/storage/sqlite/session-input-repository.js +9 -1
  187. package/dist/src/storage/sqlite/user-context-repository.d.ts +16 -4
  188. package/dist/src/storage/sqlite/user-context-repository.js +56 -12
  189. package/dist/src/tasks/index.js +2 -2
  190. package/dist/src/tasks/task-application-service.js +42 -6
  191. package/dist/src/tasks/task-change-events.d.ts +9 -0
  192. package/dist/src/tasks/task-change-events.js +17 -1
  193. package/dist/src/tasks/task-outbox-dispatcher.js +5 -1
  194. package/dist/src/tasks/task-run-dispatcher.js +4 -2
  195. package/dist/src/tasks/task-run-repository.js +13 -0
  196. package/dist/src/user-context/config.d.ts +8 -0
  197. package/dist/src/user-context/config.js +3 -0
  198. package/dist/src/user-context/consolidation.js +16 -4
  199. package/dist/src/user-context/extraction/executor.d.ts +22 -0
  200. package/dist/src/user-context/extraction/executor.js +142 -0
  201. package/dist/src/user-context/extraction/registry.d.ts +1 -1
  202. package/dist/src/user-context/extraction/registry.js +5 -34
  203. package/dist/src/user-context/extraction/repair.js +4 -1
  204. package/dist/src/user-context/extraction/semantic.d.ts +18 -0
  205. package/dist/src/user-context/extraction/semantic.js +148 -0
  206. package/dist/src/user-context/understandingQuality.js +4 -0
  207. package/dist/src/work-discovery/analyzer.js +9 -4
  208. package/dist/src/work-discovery/service.d.ts +1 -0
  209. package/dist/src/work-discovery/service.js +5 -4
  210. package/dist/src/work-discovery/types.d.ts +1 -0
  211. package/package.json +14 -8
  212. package/dist/gateway/static/root/assets/agents-TJpjRHnr.js +0 -68
  213. package/dist/gateway/static/root/assets/apps-page-CZ4Da51l.js +0 -1
  214. package/dist/gateway/static/root/assets/automations-workspace-2Y00PvJU.js +0 -6
  215. package/dist/gateway/static/root/assets/browser-settings-page-CbJD27_j.js +0 -8
  216. package/dist/gateway/static/root/assets/capabilities-settings-panel-Dv8y6OuP.js +0 -7
  217. package/dist/gateway/static/root/assets/capability-presets-settings-panel-TZmjzWzt.js +0 -3
  218. package/dist/gateway/static/root/assets/channels-settings-g-68dutA.js +0 -1
  219. package/dist/gateway/static/root/assets/channels-status-swr-D7KsAeWh.js +0 -1
  220. package/dist/gateway/static/root/assets/connectors-page-DXA0rAvQ.js +0 -2
  221. package/dist/gateway/static/root/assets/home-page-i6bXCHdo.js +0 -1
  222. package/dist/gateway/static/root/assets/index-BBBE89vm.css +0 -2
  223. package/dist/gateway/static/root/assets/index-BsD5wygl.js +0 -74
  224. package/dist/gateway/static/root/assets/local-app-workbench-page-BCKEDMlP.js +0 -2
  225. package/dist/gateway/static/root/assets/logs-page-Cy9YQK7j.js +0 -2
  226. package/dist/gateway/static/root/assets/markdown-view-CBM-v2ph.js +0 -69
  227. package/dist/gateway/static/root/assets/mermaid-render-BbqDc_LQ.js +0 -134
  228. package/dist/gateway/static/root/assets/messages-CtOJwGW3.js +0 -3
  229. package/dist/gateway/static/root/assets/notes-workbench-B10T3hGX.js +0 -4
  230. package/dist/gateway/static/root/assets/project-detail-page-DsqRlgsy.js +0 -1
  231. package/dist/gateway/static/root/assets/projects-page-Bu2PN8OK.js +0 -1
  232. package/dist/gateway/static/root/assets/remote-access-hub-CXACdJ2f.js +0 -1
  233. package/dist/gateway/static/root/assets/sessions-page-CS2knWDT.js +0 -1
  234. package/dist/gateway/static/root/assets/settings-advanced-gate-ByFGk0q_.js +0 -1
  235. package/dist/gateway/static/root/assets/skill-reload-api-DweAPjI8.js +0 -1
  236. package/dist/gateway/static/root/assets/task-detail-page-DEj-BFMP.js +0 -1
  237. package/dist/gateway/static/root/assets/user-context-page-f7yh7aD5.js +0 -1
  238. package/dist/gateway/static/root/assets/workflow-run-setup-panel-CBAYvm3G.js +0 -3
  239. package/dist/gateway/static/root/assets/workflows-page-BN0JmHrG.js +0 -5
  240. package/dist/src/agent/memory/understanding/correction.d.ts +0 -3
  241. package/dist/src/agent/memory/understanding/correction.js +0 -39
  242. package/dist/src/knowledge/connected-understanding-pipeline.d.ts +0 -17
  243. package/dist/src/knowledge/connected-understanding-pipeline.js +0 -278
  244. package/dist/src/mobile/notification-service.d.ts +0 -9
  245. package/dist/src/mobile/notification-service.js +0 -156
  246. package/dist/src/mobile/notification-store.d.ts +0 -28
  247. package/dist/src/mobile/notification-store.js +0 -132
  248. package/dist/src/mobile/notification-types.d.ts +0 -37
  249. package/dist/src/mobile/notification-types.js +0 -9
@@ -0,0 +1,282 @@
1
+ import { createHash } from "node:crypto";
2
+ //#region src/history/ctx/format.ts
3
+ const CTX_HISTORY_SCHEMA_VERSION = "ctx-history-jsonl-v2";
4
+ const CTX_PROVIDER_KEY = "xopc";
5
+ const CTX_SOURCE_ID = "default";
6
+ const CTX_SOURCE_FORMAT = "xopc-session-history-v1";
7
+ const EVENT_INDEX_STRIDE = 65536;
8
+ const MAX_TEXT_CHUNK_BYTES = 1024 * 1024;
9
+ const MAX_JSONL_LINE_BYTES = 16 * 1024 * 1024;
10
+ function asRecord(value) {
11
+ return value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
12
+ }
13
+ function stringValue(value) {
14
+ return typeof value === "string" ? value : void 0;
15
+ }
16
+ function timestamp(value, label) {
17
+ const date = new Date(value);
18
+ if (!Number.isFinite(value) || Number.isNaN(date.getTime())) throw new Error(`Invalid ${label}: ${String(value)}`);
19
+ return date.toISOString();
20
+ }
21
+ function stringifyValue(value) {
22
+ if (typeof value === "string") return value;
23
+ if (value === void 0) return "";
24
+ return JSON.stringify(value) ?? "";
25
+ }
26
+ function textParts(content) {
27
+ if (typeof content === "string") return content.length > 0 ? [content] : [];
28
+ if (!Array.isArray(content)) return [];
29
+ return content.flatMap((block) => {
30
+ const record = asRecord(block);
31
+ return record?.type === "text" && typeof record.text === "string" && record.text.length > 0 ? [record.text] : [];
32
+ });
33
+ }
34
+ function outputText(output) {
35
+ if (typeof output === "string") return output;
36
+ return textParts(output).join("");
37
+ }
38
+ function toolCallDetails(block) {
39
+ const toolName = stringValue(block.name);
40
+ if (!toolName) return null;
41
+ const toolCallId = stringValue(block.id);
42
+ const argumentsText = stringifyValue(block.arguments);
43
+ return {
44
+ eventType: "tool_call",
45
+ role: "assistant",
46
+ text: argumentsText ? `${toolName} ${argumentsText}` : toolName,
47
+ details: {
48
+ tool_name: toolName,
49
+ ...toolCallId ? { tool_call_id: toolCallId } : {}
50
+ }
51
+ };
52
+ }
53
+ function normalizeAssistant(row) {
54
+ if (typeof row.content === "string") return row.content.length > 0 ? [{
55
+ eventType: "message",
56
+ role: "assistant",
57
+ text: row.content
58
+ }] : [];
59
+ if (!Array.isArray(row.content)) return [];
60
+ const events = [];
61
+ for (const block of row.content) {
62
+ const record = asRecord(block);
63
+ if (!record) continue;
64
+ if (record.type === "text" && typeof record.text === "string" && record.text.length > 0) {
65
+ events.push({
66
+ eventType: "message",
67
+ role: "assistant",
68
+ text: record.text
69
+ });
70
+ continue;
71
+ }
72
+ if (record.type === "toolCall") {
73
+ const event = toolCallDetails(record);
74
+ if (event) events.push(event);
75
+ }
76
+ }
77
+ return events;
78
+ }
79
+ function normalizeToolResult(row) {
80
+ const text = textParts(row.content).join("");
81
+ if (!text) return [];
82
+ const toolName = stringValue(row.toolName);
83
+ const toolCallId = stringValue(row.toolCallId);
84
+ return [{
85
+ eventType: "tool_output",
86
+ role: "tool",
87
+ text,
88
+ details: {
89
+ ...toolName ? { tool_name: toolName } : {},
90
+ ...toolCallId ? { tool_call_id: toolCallId } : {},
91
+ ...typeof row.isError === "boolean" ? { is_error: row.isError } : {}
92
+ }
93
+ }];
94
+ }
95
+ function normalizeBashExecution(row) {
96
+ const command = stringValue(row.command);
97
+ if (!command) return [];
98
+ const events = [{
99
+ eventType: "command_started",
100
+ role: "user",
101
+ text: command
102
+ }];
103
+ const output = outputText(row.output);
104
+ if (output) events.push({
105
+ eventType: "command_output",
106
+ role: "tool",
107
+ text: output
108
+ });
109
+ events.push({
110
+ eventType: "command_finished",
111
+ role: "tool",
112
+ text: row.exitCode == null ? "Command finished" : `Command exited with code ${String(row.exitCode)}`,
113
+ details: {
114
+ ...typeof row.exitCode === "number" ? { exit_code: row.exitCode } : {},
115
+ ...typeof row.signal === "string" ? { signal: row.signal } : {},
116
+ ...typeof row.truncated === "boolean" ? { truncated: row.truncated } : {}
117
+ }
118
+ });
119
+ return events;
120
+ }
121
+ function normalizeStoredRow(row) {
122
+ if (row.kind === "context" || row.role === "system") return [];
123
+ if (row.type === "compaction" && typeof row.summary === "string" && row.summary.length > 0) return [{
124
+ eventType: "summary",
125
+ role: "assistant",
126
+ text: row.summary
127
+ }];
128
+ if ((row.role === "branchSummary" || row.role === "compactionSummary") && typeof row.summary === "string" && row.summary.length > 0) return [{
129
+ eventType: "summary",
130
+ role: "assistant",
131
+ text: row.summary
132
+ }];
133
+ if (row.role === "bashExecution") return normalizeBashExecution(row);
134
+ if (row.role === "custom" || row.type === "custom_message") {
135
+ if (row.display === false) return [];
136
+ return textParts(row.content).map((text) => ({
137
+ eventType: "message",
138
+ role: "user",
139
+ text
140
+ }));
141
+ }
142
+ if (row.role === "user") return textParts(row.content).map((text) => ({
143
+ eventType: "message",
144
+ role: "user",
145
+ text
146
+ }));
147
+ if (row.role === "assistant") return normalizeAssistant(row);
148
+ if (row.role === "toolResult" || row.role === "tool") return normalizeToolResult(row);
149
+ return [];
150
+ }
151
+ function splitTextByUtf8Bytes(text) {
152
+ if (Buffer.byteLength(text, "utf8") <= MAX_TEXT_CHUNK_BYTES) return [text];
153
+ const chunks = [];
154
+ let start = 0;
155
+ while (start < text.length) {
156
+ let low = start + 1;
157
+ let high = text.length;
158
+ let end = low;
159
+ while (low <= high) {
160
+ const middle = Math.floor((low + high) / 2);
161
+ if (Buffer.byteLength(text.slice(start, middle), "utf8") <= MAX_TEXT_CHUNK_BYTES) {
162
+ end = middle;
163
+ low = middle + 1;
164
+ } else high = middle - 1;
165
+ }
166
+ const previous = text.charCodeAt(end - 1);
167
+ const next = text.charCodeAt(end);
168
+ if (previous >= 55296 && previous <= 56319 && next >= 56320 && next <= 57343) end -= 1;
169
+ chunks.push(text.slice(start, end));
170
+ start = end;
171
+ }
172
+ return chunks;
173
+ }
174
+ function stableEventId(sessionId, entryId, eventOffset) {
175
+ return `xopc:${createHash("sha256").update(sessionId).update("\0").update(entryId).update("\0").update(String(eventOffset)).digest("hex")}`;
176
+ }
177
+ function serializeRecord(record) {
178
+ const line = JSON.stringify(record);
179
+ const size = Buffer.byteLength(line, "utf8");
180
+ if (size > MAX_JSONL_LINE_BYTES) throw new Error(`ctx history record exceeds 16 MiB (${size} bytes)`);
181
+ return line;
182
+ }
183
+ function sessionRecord(session) {
184
+ const active = session.status === "active";
185
+ return {
186
+ record_type: "session",
187
+ source_id: CTX_SOURCE_ID,
188
+ provider_session_id: session.sessionId,
189
+ started_at: timestamp(session.createdAt, `session timestamp for ${session.sessionId}`),
190
+ external_agent_id: session.agentId,
191
+ cwd: session.cwd,
192
+ ...session.archivedAt === null ? {} : { ended_at: timestamp(session.archivedAt, `session end timestamp for ${session.sessionId}`) },
193
+ status: active ? "active" : "completed",
194
+ agent_scope: session.sessionType === "workflow-subagent" ? "subagent" : "primary"
195
+ };
196
+ }
197
+ function entryRecords(session, entry) {
198
+ let parsed;
199
+ try {
200
+ parsed = JSON.parse(entry.payloadJson);
201
+ } catch (error) {
202
+ const message = error instanceof Error ? error.message : String(error);
203
+ throw new Error(`Invalid transcript payload for entry ${entry.entryId}: ${message}`);
204
+ }
205
+ const row = asRecord(parsed);
206
+ if (!row) throw new Error(`Transcript payload for entry ${entry.entryId} is not an object`);
207
+ const occurredAt = timestamp(entry.createdAt, `entry timestamp for ${entry.entryId}`);
208
+ const records = [];
209
+ let offset = 0;
210
+ for (const event of normalizeStoredRow(row)) {
211
+ const chunks = splitTextByUtf8Bytes(event.text);
212
+ for (let chunkIndex = 0; chunkIndex < chunks.length; chunkIndex += 1) {
213
+ if (offset >= EVENT_INDEX_STRIDE) throw new Error(`Transcript entry ${entry.entryId} expands to too many ctx events`);
214
+ const eventIndex = entry.seq * EVENT_INDEX_STRIDE + offset;
215
+ if (!Number.isSafeInteger(eventIndex) || eventIndex < 0) throw new Error(`Transcript sequence is outside the supported range: ${entry.seq}`);
216
+ records.push({
217
+ record_type: "event",
218
+ source_id: CTX_SOURCE_ID,
219
+ provider_session_id: session.sessionId,
220
+ event_index: eventIndex,
221
+ event_id: stableEventId(session.sessionId, entry.entryId, offset),
222
+ occurred_at: occurredAt,
223
+ event_type: event.eventType,
224
+ ...event.role ? { role: event.role } : {},
225
+ payload: {
226
+ text: chunks[chunkIndex],
227
+ ...event.details,
228
+ ...chunks.length > 1 ? {
229
+ chunk_index: chunkIndex,
230
+ chunk_count: chunks.length
231
+ } : {}
232
+ }
233
+ });
234
+ offset += 1;
235
+ }
236
+ }
237
+ return records;
238
+ }
239
+ function buildCtxHistoryJsonl(sessions) {
240
+ const lines = [serializeRecord({
241
+ record_type: "manifest",
242
+ schema_version: CTX_HISTORY_SCHEMA_VERSION,
243
+ producer: "xopc"
244
+ }), serializeRecord({
245
+ record_type: "source",
246
+ source_id: CTX_SOURCE_ID,
247
+ provider_key: CTX_PROVIDER_KEY,
248
+ source_format: CTX_SOURCE_FORMAT
249
+ })];
250
+ let eventCount = 0;
251
+ for (const session of sessions) {
252
+ lines.push(serializeRecord(sessionRecord(session)));
253
+ for (const entry of session.entries) {
254
+ const records = entryRecords(session, entry);
255
+ eventCount += records.length;
256
+ lines.push(...records.map(serializeRecord));
257
+ }
258
+ }
259
+ return {
260
+ contents: `${lines.join("\n")}\n`,
261
+ eventCount
262
+ };
263
+ }
264
+ function buildCtxPluginManifest() {
265
+ return `${JSON.stringify({
266
+ schema_version: 1,
267
+ name: "xopc",
268
+ display_name: "XOPC history",
269
+ version: "1.0.0",
270
+ history_sources: [{
271
+ id: CTX_SOURCE_ID,
272
+ provider_key: CTX_PROVIDER_KEY,
273
+ source_id: CTX_SOURCE_ID,
274
+ source_format: CTX_SOURCE_FORMAT,
275
+ path: "history.jsonl",
276
+ enabled: true,
277
+ refresh: "manual"
278
+ }]
279
+ }, null, 2)}\n`;
280
+ }
281
+ //#endregion
282
+ export { CTX_HISTORY_SCHEMA_VERSION, CTX_PROVIDER_KEY, CTX_SOURCE_FORMAT, CTX_SOURCE_ID, buildCtxHistoryJsonl, buildCtxPluginManifest };
@@ -1,6 +1,5 @@
1
1
  export * from './types.js';
2
2
  export * from './ingestion-service.js';
3
3
  export * from './connected-knowledge-pipeline.js';
4
- export * from './connected-understanding-pipeline.js';
5
4
  export * from './coordinator.js';
6
5
  export * from './local-folder-adapter.js';
@@ -1,6 +1,5 @@
1
1
  import { KnowledgeIngestionService, SqliteKnowledgeSourceStateStore } from "./ingestion-service.js";
2
2
  import { ConnectedKnowledgePipeline } from "./connected-knowledge-pipeline.js";
3
- import { ConnectedUnderstandingPipeline, deriveConnectedClaimObservations, renderConnectedObservation } from "./connected-understanding-pipeline.js";
4
3
  import { startConnectedKnowledgeCoordinator } from "./coordinator.js";
5
4
  import { LocalFolderKnowledgeSourceAdapter } from "./local-folder-adapter.js";
6
- export { ConnectedKnowledgePipeline, ConnectedUnderstandingPipeline, KnowledgeIngestionService, LocalFolderKnowledgeSourceAdapter, SqliteKnowledgeSourceStateStore, deriveConnectedClaimObservations, renderConnectedObservation, startConnectedKnowledgeCoordinator };
5
+ export { ConnectedKnowledgePipeline, KnowledgeIngestionService, LocalFolderKnowledgeSourceAdapter, SqliteKnowledgeSourceStateStore, startConnectedKnowledgeCoordinator };
@@ -1,6 +1,12 @@
1
1
  import type { AgentMessage } from '@earendil-works/pi-agent-core';
2
+ export declare function collectMediaUrisFromValues(values: readonly unknown[]): Set<string>;
2
3
  export declare function collectMediaUrisFromMessages(messages: readonly AgentMessage[]): Set<string>;
3
4
  export declare function messagesReferenceMediaUri(messages: readonly AgentMessage[], uri: string): boolean;
5
+ /**
6
+ * A media object remains live while any non-deleted session references it,
7
+ * including archived transcripts retained by a reset of that session key.
8
+ */
9
+ export declare function isMediaUriReferencedByLiveSession(uri: string): boolean;
4
10
  export declare function deleteMediaUris(uris: Iterable<string>): Promise<void>;
5
11
  export declare function deleteMediaUrisNoLongerReferenced(params: {
6
12
  removed: readonly AgentMessage[];
@@ -1,3 +1,5 @@
1
+ import { getSqliteDatabase } from "../storage/sqlite/transaction.js";
2
+ import "../storage/sqlite/index.js";
1
3
  import { tryParseMediaUri } from "./uri.js";
2
4
  import { deleteMediaBuffer } from "./store.js";
3
5
  //#region src/media/session-references.ts
@@ -19,19 +21,38 @@ function collectFromValue(value, out, seen) {
19
21
  const record = value;
20
22
  for (const nested of Object.values(record)) collectFromValue(nested, out, seen);
21
23
  }
22
- function collectMediaUrisFromMessages(messages) {
24
+ function collectMediaUrisFromValues(values) {
23
25
  const out = /* @__PURE__ */ new Set();
24
26
  const seen = /* @__PURE__ */ new WeakSet();
25
- for (const message of messages) collectFromValue(message, out, seen);
27
+ for (const value of values) collectFromValue(value, out, seen);
26
28
  return out;
27
29
  }
30
+ function collectMediaUrisFromMessages(messages) {
31
+ return collectMediaUrisFromValues(messages);
32
+ }
28
33
  function messagesReferenceMediaUri(messages, uri) {
29
34
  return collectMediaUrisFromMessages(messages).has(uri.trim());
30
35
  }
36
+ /**
37
+ * A media object remains live while any non-deleted session references it,
38
+ * including archived transcripts retained by a reset of that session key.
39
+ */
40
+ function isMediaUriReferencedByLiveSession(uri) {
41
+ const normalized = uri.trim();
42
+ if (!normalized) return false;
43
+ const escaped = JSON.stringify(normalized).replaceAll("\\", "\\\\").replaceAll("%", "\\%").replaceAll("_", "\\_");
44
+ return getSqliteDatabase().prepare(`SELECT 1 AS referenced
45
+ FROM transcript_entries e
46
+ JOIN transcripts t ON t.session_id = e.session_id
47
+ JOIN sessions s ON s.session_key = t.session_key
48
+ WHERE e.payload_json LIKE ? ESCAPE '\\'
49
+ LIMIT 1`).get(`%${escaped}%`)?.referenced === 1;
50
+ }
31
51
  async function deleteMediaUris(uris) {
32
52
  for (const uri of new Set(uris)) {
33
53
  const parsed = tryParseMediaUri(uri);
34
54
  if (!parsed) continue;
55
+ if (isMediaUriReferencedByLiveSession(uri)) continue;
35
56
  await deleteMediaBuffer(parsed.id, parsed.bucket).catch(() => {});
36
57
  }
37
58
  }
@@ -43,4 +64,4 @@ async function deleteMediaUrisNoLongerReferenced(params) {
43
64
  await deleteMediaUris(removedUris);
44
65
  }
45
66
  //#endregion
46
- export { collectMediaUrisFromMessages, deleteMediaUris, deleteMediaUrisNoLongerReferenced, messagesReferenceMediaUri };
67
+ export { collectMediaUrisFromMessages, collectMediaUrisFromValues, deleteMediaUris, deleteMediaUrisNoLongerReferenced, isMediaUriReferencedByLiveSession, messagesReferenceMediaUri };
@@ -0,0 +1,16 @@
1
+ import { type NotificationDevice, type NotificationDevicePlatform, type NotificationLanguage, type NotificationPermission, type NotificationPreferences } from './types.js';
2
+ export type RegisterNotificationDeviceInput = {
3
+ id: string;
4
+ platform: NotificationDevicePlatform;
5
+ pushToken: string;
6
+ permissions: NotificationPermission;
7
+ preferences?: Partial<NotificationPreferences>;
8
+ locale: NotificationLanguage;
9
+ appVersion?: string;
10
+ };
11
+ export declare function registerNotificationDevice(input: RegisterNotificationDeviceInput): NotificationDevice;
12
+ export declare function getNotificationDevice(deviceId: string): NotificationDevice | null;
13
+ export declare function listDeliverableNotificationDevices(now?: number): NotificationDevice[];
14
+ export declare function updateNotificationDevicePreferences(deviceId: string, patch: Partial<NotificationPreferences>): NotificationDevice | null;
15
+ export declare function removeNotificationDevice(deviceId: string): boolean;
16
+ export declare function disableNotificationDeviceForPushToken(pushToken: string): void;
@@ -0,0 +1,96 @@
1
+ import { getSqliteDatabase, runSqliteWriteTransaction } from "../storage/sqlite/transaction.js";
2
+ import { DEFAULT_NOTIFICATION_PREFERENCES } from "./types.js";
3
+ //#region src/notifications/device-store.ts
4
+ const DEVICE_LEASE_MS = 10080 * 60 * 1e3;
5
+ function parsePreferences(raw) {
6
+ try {
7
+ const value = JSON.parse(raw);
8
+ return value && typeof value === "object" && !Array.isArray(value) ? value : {};
9
+ } catch {
10
+ return {};
11
+ }
12
+ }
13
+ function normalizePreferences(input) {
14
+ return {
15
+ chatCompleted: input?.chatCompleted ?? DEFAULT_NOTIFICATION_PREFERENCES.chatCompleted,
16
+ chatFailed: input?.chatFailed ?? DEFAULT_NOTIFICATION_PREFERENCES.chatFailed,
17
+ taskNeedsInput: input?.taskNeedsInput ?? DEFAULT_NOTIFICATION_PREFERENCES.taskNeedsInput,
18
+ taskBlocked: input?.taskBlocked ?? DEFAULT_NOTIFICATION_PREFERENCES.taskBlocked,
19
+ taskFailed: input?.taskFailed ?? DEFAULT_NOTIFICATION_PREFERENCES.taskFailed,
20
+ taskCompleted: input?.taskCompleted ?? DEFAULT_NOTIFICATION_PREFERENCES.taskCompleted,
21
+ automationCompleted: input?.automationCompleted ?? DEFAULT_NOTIFICATION_PREFERENCES.automationCompleted,
22
+ automationFailed: input?.automationFailed ?? DEFAULT_NOTIFICATION_PREFERENCES.automationFailed,
23
+ proactiveInsight: input?.proactiveInsight ?? DEFAULT_NOTIFICATION_PREFERENCES.proactiveInsight
24
+ };
25
+ }
26
+ function deviceFromRow(row) {
27
+ return {
28
+ id: row.device_id,
29
+ platform: row.platform === "android" ? "android" : "ios",
30
+ pushToken: row.push_token,
31
+ enabled: row.enabled !== 0,
32
+ permissions: row.permissions === "granted" || row.permissions === "denied" ? row.permissions : "unknown",
33
+ preferences: normalizePreferences(parsePreferences(row.preferences_json)),
34
+ locale: row.locale === "zh" ? "zh" : "en",
35
+ appVersion: row.app_version ?? void 0,
36
+ leaseExpiresAt: row.lease_expires_at,
37
+ lastSeenAt: row.last_seen_at,
38
+ createdAt: row.created_at,
39
+ updatedAt: row.updated_at
40
+ };
41
+ }
42
+ function registerNotificationDevice(input) {
43
+ const now = Date.now();
44
+ const preferences = input.preferences ? normalizePreferences(input.preferences) : getNotificationDevice(input.id)?.preferences ?? normalizePreferences();
45
+ runSqliteWriteTransaction((db) => {
46
+ db.prepare(`DELETE FROM notification_devices
47
+ WHERE push_provider = 'expo' AND push_token = ? AND device_id <> ?`).run(input.pushToken, input.id);
48
+ db.prepare(`INSERT INTO notification_devices (
49
+ device_id, platform, push_token, enabled, permissions, preferences_json,
50
+ locale, app_version, lease_expires_at, last_seen_at, created_at, updated_at
51
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
52
+ ON CONFLICT(device_id) DO UPDATE SET
53
+ platform = excluded.platform,
54
+ push_token = excluded.push_token,
55
+ enabled = excluded.enabled,
56
+ permissions = excluded.permissions,
57
+ preferences_json = excluded.preferences_json,
58
+ locale = excluded.locale,
59
+ app_version = excluded.app_version,
60
+ lease_expires_at = excluded.lease_expires_at,
61
+ last_seen_at = excluded.last_seen_at,
62
+ updated_at = excluded.updated_at`).run(input.id, input.platform, input.pushToken, input.permissions === "granted" ? 1 : 0, input.permissions, JSON.stringify(preferences), input.locale, input.appVersion?.trim() || null, now + DEVICE_LEASE_MS, now, now, now);
63
+ });
64
+ return getNotificationDevice(input.id);
65
+ }
66
+ function getNotificationDevice(deviceId) {
67
+ const row = getSqliteDatabase().prepare("SELECT * FROM notification_devices WHERE device_id = ?").get(deviceId);
68
+ return row ? deviceFromRow(row) : null;
69
+ }
70
+ function listDeliverableNotificationDevices(now = Date.now()) {
71
+ return getSqliteDatabase().prepare(`SELECT * FROM notification_devices
72
+ WHERE enabled = 1 AND permissions = 'granted' AND lease_expires_at > ?
73
+ ORDER BY updated_at DESC`).all(now).map(deviceFromRow);
74
+ }
75
+ function updateNotificationDevicePreferences(deviceId, patch) {
76
+ const current = getNotificationDevice(deviceId);
77
+ if (!current) return null;
78
+ const preferences = normalizePreferences({
79
+ ...current.preferences,
80
+ ...patch
81
+ });
82
+ runSqliteWriteTransaction((db) => {
83
+ db.prepare("UPDATE notification_devices SET preferences_json = ?, updated_at = ? WHERE device_id = ?").run(JSON.stringify(preferences), Date.now(), deviceId);
84
+ });
85
+ return getNotificationDevice(deviceId);
86
+ }
87
+ function removeNotificationDevice(deviceId) {
88
+ return runSqliteWriteTransaction((db) => db.prepare("DELETE FROM notification_devices WHERE device_id = ?").run(deviceId).changes > 0);
89
+ }
90
+ function disableNotificationDeviceForPushToken(pushToken) {
91
+ runSqliteWriteTransaction((db) => {
92
+ db.prepare("UPDATE notification_devices SET enabled = 0, updated_at = ? WHERE push_token = ?").run(Date.now(), pushToken);
93
+ });
94
+ }
95
+ //#endregion
96
+ export { disableNotificationDeviceForPushToken, getNotificationDevice, listDeliverableNotificationDevices, registerNotificationDevice, removeNotificationDevice, updateNotificationDevicePreferences };
@@ -0,0 +1,6 @@
1
+ import { type ProductNotification } from '@xopcai/gateway-contract';
2
+ export type NotificationPlan = {
3
+ dedupeKey: string;
4
+ notification: Omit<ProductNotification, 'schemaVersion' | 'id' | 'createdAt'>;
5
+ };
6
+ export declare function notificationPlanFromGatewayEvent(type: string, payload: unknown): NotificationPlan | null;
@@ -0,0 +1,160 @@
1
+ import { NotificationTargetSchema } from "../../packages/gateway-contract/src/notifications.js";
2
+ //#region src/notifications/planner.ts
3
+ function chatPlan(payload) {
4
+ if (!payload || typeof payload !== "object") return null;
5
+ const event = payload;
6
+ if (event.status !== "success" && event.status !== "error") return null;
7
+ if (typeof event.runId !== "string" || !event.runId) return null;
8
+ const target = NotificationTargetSchema.safeParse(event.target);
9
+ if (!target.success || target.data.kind !== "chat" || target.data.sessionKey !== event.sessionKey) return null;
10
+ const completed = event.status === "success";
11
+ const type = completed ? "chat.completed" : "chat.failed";
12
+ const fallback = {
13
+ en: "Open the conversation to review the result.",
14
+ zh: "打开对话查看结果。"
15
+ };
16
+ const sessionTitle = typeof event.sessionTitle === "string" ? event.sessionTitle.trim().slice(0, 120) : "";
17
+ const responsePreview = completed && typeof event.responsePreview === "string" ? Array.from(event.responsePreview.trim()).slice(0, 180).join("") : "";
18
+ return {
19
+ dedupeKey: `${type}:${event.runId}`,
20
+ notification: {
21
+ type,
22
+ target: target.data,
23
+ priority: completed ? "normal" : "high",
24
+ title: completed ? {
25
+ en: "Response ready",
26
+ zh: "回答已就绪"
27
+ } : {
28
+ en: "Response needs attention",
29
+ zh: "回答需要处理"
30
+ },
31
+ body: responsePreview ? {
32
+ en: responsePreview,
33
+ zh: responsePreview
34
+ } : sessionTitle ? {
35
+ en: sessionTitle,
36
+ zh: sessionTitle
37
+ } : fallback,
38
+ payload: { runId: event.runId }
39
+ }
40
+ };
41
+ }
42
+ function taskPlan(payload) {
43
+ if (!payload || typeof payload !== "object") return null;
44
+ const data = payload;
45
+ const taskId = typeof data.task?.id === "string" ? data.task.id : typeof data.taskId === "string" ? data.taskId : "";
46
+ const sourceEventId = typeof data.sourceEventId === "string" ? data.sourceEventId : "";
47
+ if (!taskId || !sourceEventId) return null;
48
+ const type = data.reason === "blocked" ? "task.blocked" : data.reason === "failed" ? "task.failed" : data.reason === "user_input" || data.reason === "approval" ? "task.needs_input" : data.to === "closed" && data.resolution === "done" ? "task.completed" : void 0;
49
+ if (!type) return null;
50
+ const taskTitle = typeof data.task?.title === "string" ? data.task.title.trim().slice(0, 120) : "";
51
+ const title = type === "task.needs_input" ? {
52
+ en: "Action needed",
53
+ zh: "需要你的操作"
54
+ } : type === "task.blocked" ? {
55
+ en: "Task blocked",
56
+ zh: "任务受阻"
57
+ } : type === "task.failed" ? {
58
+ en: "Task failed",
59
+ zh: "任务失败"
60
+ } : {
61
+ en: "Task completed",
62
+ zh: "任务已完成"
63
+ };
64
+ return {
65
+ dedupeKey: `${type}:${sourceEventId}`,
66
+ notification: {
67
+ type,
68
+ target: {
69
+ kind: "task",
70
+ taskId
71
+ },
72
+ priority: type === "task.completed" ? "normal" : "high",
73
+ title,
74
+ ...taskTitle ? { body: {
75
+ en: taskTitle,
76
+ zh: taskTitle
77
+ } } : {},
78
+ payload: {
79
+ taskId,
80
+ sourceEventId
81
+ }
82
+ }
83
+ };
84
+ }
85
+ function automationPlan(payload) {
86
+ if (!payload || typeof payload !== "object") return null;
87
+ const event = payload;
88
+ if (event.notificationPolicy === "none") return null;
89
+ if (event.notificationPolicy === "attention" && event.requiresAttention !== true) return null;
90
+ const run = event.run;
91
+ if (!run || run.status !== "failed" && run.status !== "timeout" && run.status !== "succeeded") return null;
92
+ const completed = run.status === "succeeded";
93
+ const type = completed ? "automation.completed" : "automation.failed";
94
+ return {
95
+ dedupeKey: `${type}:${run.id}`,
96
+ notification: {
97
+ type,
98
+ target: {
99
+ kind: "automation_run",
100
+ automationId: run.automationId,
101
+ runId: run.id
102
+ },
103
+ priority: completed ? "normal" : "high",
104
+ title: completed ? {
105
+ en: "Automation completed",
106
+ zh: "自动化已完成"
107
+ } : {
108
+ en: "Automation needs attention",
109
+ zh: "自动化需要处理"
110
+ },
111
+ body: {
112
+ en: (run.error || run.summary || run.automationName).slice(0, 180),
113
+ zh: (run.error || run.summary || run.automationName).slice(0, 180)
114
+ },
115
+ payload: {
116
+ automationId: run.automationId,
117
+ runId: run.id
118
+ }
119
+ }
120
+ };
121
+ }
122
+ function proactivePlan(payload) {
123
+ if (!payload || typeof payload !== "object") return null;
124
+ const item = payload;
125
+ if (typeof item.id !== "string" || typeof item.insight?.id !== "string" || typeof item.insight.title !== "string") return null;
126
+ const title = item.insight.title.trim().slice(0, 120);
127
+ const summary = typeof item.insight.summary === "string" ? item.insight.summary.trim().slice(0, 180) : "";
128
+ return {
129
+ dedupeKey: `proactive.insight:${item.id}`,
130
+ notification: {
131
+ type: "proactive.insight",
132
+ target: {
133
+ kind: "insight",
134
+ inboxItemId: item.id
135
+ },
136
+ priority: item.insight.urgency === "high" || item.insight.urgency === "critical" ? "high" : "normal",
137
+ title: {
138
+ en: title,
139
+ zh: title
140
+ },
141
+ ...summary ? { body: {
142
+ en: summary,
143
+ zh: summary
144
+ } } : {},
145
+ payload: {
146
+ inboxItemId: item.id,
147
+ insightId: item.insight.id
148
+ }
149
+ }
150
+ };
151
+ }
152
+ function notificationPlanFromGatewayEvent(type, payload) {
153
+ if (type === "agent.run.ended") return chatPlan(payload);
154
+ if (type === "task.attention_required.v2" || type === "task.phase_changed.v2") return taskPlan(payload);
155
+ if (type === "automation.run.completed") return automationPlan(payload);
156
+ if (type === "proactive.inbox.created") return proactivePlan(payload);
157
+ return null;
158
+ }
159
+ //#endregion
160
+ export { notificationPlanFromGatewayEvent };
@@ -0,0 +1,18 @@
1
+ export declare class NotificationService {
2
+ private readonly options;
3
+ private timer;
4
+ private draining;
5
+ private lastMaintenanceAt;
6
+ constructor(options: {
7
+ publish: (type: string, payload: unknown) => void;
8
+ fetch?: typeof fetch;
9
+ });
10
+ start(): void;
11
+ stop(): void;
12
+ handleGatewayEvent(type: string, payload: unknown): void;
13
+ drain(): Promise<void>;
14
+ private deliverPending;
15
+ private send;
16
+ private checkReceipts;
17
+ private retryOrFail;
18
+ }