@xopcai/xopc 0.0.176 → 0.0.178

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 (238) 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-DsFM1upC.js → activity-store-BzGX__8I.js} +1 -1
  4. package/dist/gateway/static/root/assets/{agent-avatar-dicebear-DvdMLOga.js → agent-avatar-dicebear-BzxntcaZ.js} +1 -1
  5. package/dist/gateway/static/root/assets/agents-DC9F12Kw.js +2 -0
  6. package/dist/gateway/static/root/assets/{api-BdPLCCBm.js → api-hi6f2Xtp.js} +1 -1
  7. package/dist/gateway/static/root/assets/{app-management-settings-panel-DMLDOHul.js → app-management-settings-panel-fTY1F7ac.js} +1 -1
  8. package/dist/gateway/static/root/assets/{appearance-settings-DbI9foFR.js → appearance-settings-BZ-IxQfB.js} +1 -1
  9. package/dist/gateway/static/root/assets/apps-page-5bKr05Fa.js +1 -0
  10. package/dist/gateway/static/root/assets/{archive-plugin-Dfdxuwvb.js → archive-plugin-ZSLLG8wB.js} +1 -1
  11. package/dist/gateway/static/root/assets/{attachment-load-Dn3RlnYD.js → attachment-load-D4YktqIF.js} +1 -1
  12. package/dist/gateway/static/root/assets/{automation-suggestion-card-Bc0Y7A9u.js → automation-suggestion-card-B7mxFRtf.js} +1 -1
  13. package/dist/gateway/static/root/assets/automations-page-Dg6dmt5g.js +6 -0
  14. package/dist/gateway/static/root/assets/{binary-plugins-0XtB-xC0.js → binary-plugins-BIkPxfxj.js} +1 -1
  15. package/dist/gateway/static/root/assets/{block-editor-C4fXWbEE.js → block-editor-Q3v_YQom.js} +6 -6
  16. package/dist/gateway/static/root/assets/{browser-settings-page-lC86-drr.js → browser-settings-page-BHoo6Rpq.js} +4 -4
  17. package/dist/gateway/static/root/assets/{browser-workflow-inputs-CZmzNymN.js → browser-workflow-inputs-M5lTEW1I.js} +1 -1
  18. package/dist/gateway/static/root/assets/{browser-workflows-page-CBYM9HqG.js → browser-workflows-page-B3T1KYk4.js} +2 -2
  19. package/dist/gateway/static/root/assets/capabilities-settings-panel-BlsqN8Fu.js +7 -0
  20. package/dist/gateway/static/root/assets/{capability-presets-api-BiJxmmhW.js → capability-presets-api-DE09c0VB.js} +1 -1
  21. package/dist/gateway/static/root/assets/capability-presets-settings-panel-DJeT8_B4.js +1 -0
  22. package/dist/gateway/static/root/assets/{channel-recipient-api-BKTUZDp-.js → channel-recipient-api-CFR5FBfS.js} +1 -1
  23. package/dist/gateway/static/root/assets/channels-settings-C4VVjYEm.js +1 -0
  24. package/dist/gateway/static/root/assets/channels-status-swr-vdf8kB16.js +1 -0
  25. package/dist/gateway/static/root/assets/{connector-logo-Pr4RIKjj.js → connector-logo-B1mD-3pM.js} +1 -1
  26. package/dist/gateway/static/root/assets/connectors-page-DNcrDThX.js +2 -0
  27. package/dist/gateway/static/root/assets/desktop-pet-B1urphOZ.js +1 -0
  28. package/dist/gateway/static/root/assets/{desktop-pet-settings-CEQacUDF.js → desktop-pet-settings-DTL6J3EP.js} +1 -1
  29. package/dist/gateway/static/root/assets/{directory-picker-path-field-DWnxdZtc.js → directory-picker-path-field-BYQJ2XUS.js} +1 -1
  30. package/dist/gateway/static/root/assets/{dreaming-settings-D2e2w2Ho.js → dreaming-settings-BXcb8fwx.js} +3 -3
  31. package/dist/gateway/static/root/assets/{extension-debug-page-BLjTGbv3.js → extension-debug-page-O1Xu1r4Q.js} +1 -1
  32. package/dist/gateway/static/root/assets/{extension-page-D2_UC6hy.js → extension-page-C2Jraq8l.js} +1 -1
  33. package/dist/gateway/static/root/assets/{extension-settings-page-BsH6o_PX.js → extension-settings-page-DcXQDTpG.js} +1 -1
  34. package/dist/gateway/static/root/assets/{gateway-config-api-C-DkC6UJ.js → gateway-config-api-DmPIZrvg.js} +1 -1
  35. package/dist/gateway/static/root/assets/{gateway-settings-DEOGiimF.js → gateway-settings-DmObBx9b.js} +1 -1
  36. package/dist/gateway/static/root/assets/{gateway-startup-retry-BlSLh1TF.js → gateway-startup-retry-BZEkOdPm.js} +1 -1
  37. package/dist/gateway/static/root/assets/{goal-create-dialog-CSFcRE_N.js → goal-create-dialog-BRhmmBe9.js} +1 -1
  38. package/dist/gateway/static/root/assets/goal-detail-page-C1k7_s_O.js +4 -0
  39. package/dist/gateway/static/root/assets/{goals-config-api-CcdS9qek.js → goals-config-api-Fwu1wjEP.js} +1 -1
  40. package/dist/gateway/static/root/assets/{goals-page-BAcErdch.js → goals-page-hOu9uA3q.js} +2 -2
  41. package/dist/gateway/static/root/assets/{goals-settings-BY7crl0z.js → goals-settings-DY-JjvHz.js} +1 -1
  42. package/dist/gateway/static/root/assets/{heartbeat-settings-DtTkS0gs.js → heartbeat-settings-BtKu2NWT.js} +1 -1
  43. package/dist/gateway/static/root/assets/{image-generation-api-WGgkbwDZ.js → image-generation-api-05Gg8wsU.js} +1 -1
  44. package/dist/gateway/static/root/assets/{index-2UImfRDC.js → index-C0CGebQ1.js} +65 -65
  45. package/dist/gateway/static/root/assets/index-eqq25gvV.css +1 -0
  46. package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-C5lpWQ3f.js → keyboard-shortcuts-settings-CfmDR9Sc.js} +1 -1
  47. package/dist/gateway/static/root/assets/local-app-workbench-page-EjsNT7nJ.js +2 -0
  48. package/dist/gateway/static/root/assets/{local-apps-page-b05wWvXG.js → local-apps-page-Df8BW1A_.js} +1 -1
  49. package/dist/gateway/static/root/assets/{locale-store-sToMfHX_.js → locale-store-CTwSy7yW.js} +1 -1
  50. package/dist/gateway/static/root/assets/{logs-page-cDE1jLJv.js → logs-page-Dswjlraa.js} +3 -3
  51. package/dist/gateway/static/root/assets/{markdown-split-0gPVst5y.js → markdown-split-B3FvKbaP.js} +1 -1
  52. package/dist/gateway/static/root/assets/{media-plugins-Rxyq_KTm.js → media-plugins-DsjrvvB6.js} +1 -1
  53. package/dist/gateway/static/root/assets/messages-DP6tPKk-.js +3 -0
  54. package/dist/gateway/static/root/assets/{notes-page-DRhNDl_Q.js → notes-page-tuzIwy3c.js} +1 -1
  55. package/dist/gateway/static/root/assets/notes-workbench-DSh3-hMY.js +4 -0
  56. package/dist/gateway/static/root/assets/{page-tabs-cOEOQqHh.js → page-tabs-ke9s4nYi.js} +1 -1
  57. package/dist/gateway/static/root/assets/{preview-open-alternatives-BopOLFvu.js → preview-open-alternatives-Cp1eI4S9.js} +1 -1
  58. package/dist/gateway/static/root/assets/{product-open-page-DWVPmmOq.js → product-open-page-dXQCMAtH.js} +1 -1
  59. package/dist/gateway/static/root/assets/project-detail-page-D0QPRHR_.js +1 -0
  60. package/dist/gateway/static/root/assets/projects-page-CI5Vz62F.js +1 -0
  61. package/dist/gateway/static/root/assets/remote-access-hub-S1jpzBS5.js +1 -0
  62. package/dist/gateway/static/root/assets/{save-bar-controls-BfZmKe1t.js → save-bar-controls-Bl30zjHc.js} +1 -1
  63. package/dist/gateway/static/root/assets/{schedule-field-Cpi4jCRV.js → schedule-field-DqhmXQKo.js} +1 -1
  64. package/dist/gateway/static/root/assets/{schema-form-OXFkcZQe.js → schema-form-DkUCy6vf.js} +1 -1
  65. package/dist/gateway/static/root/assets/sessions-page-CTm66k7h.js +1 -0
  66. package/dist/gateway/static/root/assets/settings-advanced-gate-CU52AUVD.js +1 -0
  67. package/dist/gateway/static/root/assets/{settings-form-section-BwqkZCHJ.js → settings-form-section-C6ZbNpdy.js} +1 -1
  68. package/dist/gateway/static/root/assets/{settings-loading-skeleton-BbqH_S3Y.js → settings-loading-skeleton-Bk58_cr7.js} +1 -1
  69. package/dist/gateway/static/root/assets/{settings-page-BoxC-JSa.js → settings-page-k8iE_NdX.js} +1 -1
  70. package/dist/gateway/static/root/assets/{settings-page-layout-Ddu2iGaW.js → settings-page-layout-DgFSya2e.js} +1 -1
  71. package/dist/gateway/static/root/assets/{setup-status-panel-z1Lwv0js.js → setup-status-panel-B_KDlyZA.js} +1 -1
  72. package/dist/gateway/static/root/assets/{share-preview-page-CVazOFjy.js → share-preview-page-CV7nL_J9.js} +1 -1
  73. package/dist/gateway/static/root/assets/shares-settings-DK6XK95e.js +1 -0
  74. package/dist/gateway/static/root/assets/skill-reload-api-Bvv_u4ii.js +1 -0
  75. package/dist/gateway/static/root/assets/skills-page-BGHvVbay.js +2 -0
  76. package/dist/gateway/static/root/assets/{skills-page.utils-DgyB1tSo.js → skills-page.utils-kahBIHg0.js} +1 -1
  77. package/dist/gateway/static/root/assets/{system-settings-panel-BoLSQL65.js → system-settings-panel-JV3-MG5F.js} +1 -1
  78. package/dist/gateway/static/root/assets/{theme-store-CBNcGOfj.js → theme-store-DFLyzoLO.js} +1 -1
  79. package/dist/gateway/static/root/assets/{time-picker-gochWrny.js → time-picker-XwpxdZFr.js} +1 -1
  80. package/dist/gateway/static/root/assets/{typed-models-lib-DvRnr7YB.js → typed-models-lib-60Aqo-UJ.js} +1 -1
  81. package/dist/gateway/static/root/assets/{use-channel-catalog-CA9BFVB7.js → use-channel-catalog-CnTkHDnw.js} +1 -1
  82. package/dist/gateway/static/root/assets/user-context-page-DBCMk-Vn.js +1 -0
  83. package/dist/gateway/static/root/assets/{voice-api-key-field-v8tgylEZ.js → voice-api-key-field-CNa8qUgS.js} +1 -1
  84. package/dist/gateway/static/root/assets/work-discovery-page-C1UIdsCl.js +1 -0
  85. package/dist/gateway/static/root/assets/work-item-detail-page-DEAQepB8.js +1 -0
  86. package/dist/gateway/static/root/assets/work-page-D5qYmCTq.js +3 -0
  87. package/dist/gateway/static/root/assets/{workflow-run-setup-panel-CC3cJn5k.js → workflow-run-setup-panel-yV_x595t.js} +2 -2
  88. package/dist/gateway/static/root/assets/workflows-page-yrK17ZZ5.js +11 -0
  89. package/dist/gateway/static/root/index.html +7 -7
  90. package/dist/package.js +1 -1
  91. package/dist/src/agent/embedded/model-runtime.js +3 -0
  92. package/dist/src/agent/embedded/run-for-session.js +18 -5
  93. package/dist/src/agent/embedded/run-turn.js +6 -3
  94. package/dist/src/agent/embedded/types.d.ts +2 -0
  95. package/dist/src/automations/service/automation-service.d.ts +3 -0
  96. package/dist/src/automations/service/automation-service.js +37 -7
  97. package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
  98. package/dist/src/cli/commands/gateway/lifecycle.js +1 -1
  99. package/dist/src/cli/commands/update.js +1 -1
  100. package/dist/src/connectors/composio-sessions.js +1 -1
  101. package/dist/src/gateway/hono/routes/home.d.ts +18 -2
  102. package/dist/src/gateway/hono/routes/home.js +19 -0
  103. package/dist/src/gateway/hono/routes/index.js +2 -2
  104. package/dist/src/gateway/hono/routes/local-apps.js +1 -1
  105. package/dist/src/gateway/hono/routes/proactive.d.ts +4 -0
  106. package/dist/src/gateway/hono/routes/proactive.js +157 -0
  107. package/dist/src/gateway/hono/routes/projects.js +2 -2
  108. package/dist/src/gateway/hono/routes/update.js +2 -2
  109. package/dist/src/gateway/index.js +1 -1
  110. package/dist/src/gateway/run-loop.js +1 -1
  111. package/dist/src/gateway/service.d.ts +10 -1
  112. package/dist/src/gateway/service.js +36 -36
  113. package/dist/src/infra/gateway-processes.js +1 -1
  114. package/dist/src/infra/update-restart.js +1 -1
  115. package/dist/src/infra/update-runner.js +2 -2
  116. package/dist/src/infra/update-startup.js +1 -1
  117. package/dist/src/mcp/channel-bridge.js +1 -1
  118. package/dist/src/mobile/notification-service.d.ts +1 -0
  119. package/dist/src/mobile/notification-service.js +38 -18
  120. package/dist/src/mobile/notification-types.d.ts +2 -2
  121. package/dist/src/proactive/events/envelope.d.ts +2 -0
  122. package/dist/src/proactive/events/envelope.js +54 -0
  123. package/dist/src/proactive/events/publisher.d.ts +4 -0
  124. package/dist/src/proactive/events/repository.d.ts +9 -0
  125. package/dist/src/proactive/events/repository.js +62 -0
  126. package/dist/src/proactive/events/types.d.ts +44 -0
  127. package/dist/src/proactive/events/types.js +15 -0
  128. package/dist/src/proactive/execution/agent-executor.d.ts +16 -0
  129. package/dist/src/proactive/execution/agent-executor.js +104 -0
  130. package/dist/src/proactive/execution/context.d.ts +31 -0
  131. package/dist/src/proactive/execution/context.js +72 -0
  132. package/dist/src/proactive/execution/insight.d.ts +4 -0
  133. package/dist/src/proactive/execution/insight.js +74 -0
  134. package/dist/src/proactive/execution/repository.d.ts +23 -0
  135. package/dist/src/proactive/execution/repository.js +122 -0
  136. package/dist/src/proactive/execution/types.d.ts +54 -0
  137. package/dist/src/proactive/execution/types.js +1 -0
  138. package/dist/src/proactive/execution/worker.d.ts +15 -0
  139. package/dist/src/proactive/execution/worker.js +96 -0
  140. package/dist/src/proactive/inbox/repository.d.ts +24 -0
  141. package/dist/src/proactive/inbox/repository.js +117 -0
  142. package/dist/src/proactive/inbox/service.d.ts +17 -0
  143. package/dist/src/proactive/inbox/service.js +22 -0
  144. package/dist/src/proactive/inbox/types.d.ts +38 -0
  145. package/dist/src/proactive/inbox/types.js +1 -0
  146. package/dist/src/proactive/inbox/worker.d.ts +12 -0
  147. package/dist/src/proactive/inbox/worker.js +56 -0
  148. package/dist/src/proactive/index.d.ts +17 -0
  149. package/dist/src/proactive/index.js +11 -0
  150. package/dist/src/proactive/routing/batch-repository.d.ts +27 -0
  151. package/dist/src/proactive/routing/batch-repository.js +56 -0
  152. package/dist/src/proactive/routing/matcher.d.ts +5 -0
  153. package/dist/src/proactive/routing/matcher.js +56 -0
  154. package/dist/src/proactive/routing/types.d.ts +44 -0
  155. package/dist/src/proactive/routing/types.js +1 -0
  156. package/dist/src/proactive/scenarios/prompt-composer.d.ts +14 -0
  157. package/dist/src/proactive/scenarios/prompt-composer.js +24 -0
  158. package/dist/src/proactive/scenarios/repository.d.ts +23 -0
  159. package/dist/src/proactive/scenarios/repository.js +162 -0
  160. package/dist/src/proactive/scenarios/service.d.ts +15 -0
  161. package/dist/src/proactive/scenarios/service.js +26 -0
  162. package/dist/src/proactive/scenarios/types.d.ts +36 -0
  163. package/dist/src/proactive/scenarios/types.js +1 -0
  164. package/dist/src/proactive/service.d.ts +18 -0
  165. package/dist/src/proactive/service.js +61 -0
  166. package/dist/src/projects/project-service.d.ts +3 -1
  167. package/dist/src/projects/project-service.js +62 -32
  168. package/dist/src/providers/provider-auth-service.js +3 -0
  169. package/dist/src/providers/register-bundled-oauth-flows.d.ts +2 -0
  170. package/dist/src/providers/register-bundled-oauth-flows.js +16 -0
  171. package/dist/src/session/store.d.ts +2 -0
  172. package/dist/src/session/store.js +30 -0
  173. package/dist/src/storage/sqlite/migrations/068_proactive_event_spine.sql +71 -0
  174. package/dist/src/storage/sqlite/migrations/069_proactive_scenario_control.sql +69 -0
  175. package/dist/src/storage/sqlite/migrations/070_proactive_execution.sql +55 -0
  176. package/dist/src/storage/sqlite/migrations/071_proactive_inbox.sql +45 -0
  177. package/dist/src/storage/sqlite/migrations/072_proactive_judgments.sql +14 -0
  178. package/dist/src/storage/sqlite/migrations/073_enable_default_proactive_scenarios.sql +13 -0
  179. package/dist/src/storage/sqlite/migrations/074_deduplicate_blocked_work_routing.sql +5 -0
  180. package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
  181. package/dist/src/storage/sqlite/migrations/runner.js +3 -3
  182. package/dist/src/storage/sqlite/migrations/runner.ts +1 -1
  183. package/dist/src/storage/sqlite/schema.js +1 -1
  184. package/dist/src/work-discovery/thread-service.d.ts +1 -3
  185. package/dist/src/work-discovery/thread-service.js +13 -25
  186. package/dist/src/work-items/work-item-service.d.ts +3 -1
  187. package/dist/src/work-items/work-item-service.js +67 -36
  188. package/package.json +3 -11
  189. package/dist/gateway/static/root/assets/agents-BVjlpbeZ.js +0 -2
  190. package/dist/gateway/static/root/assets/api-Bop4IQRW.js +0 -1
  191. package/dist/gateway/static/root/assets/apps-page-njqxLWYD.js +0 -1
  192. package/dist/gateway/static/root/assets/automations-page-D-eweHZJ.js +0 -6
  193. package/dist/gateway/static/root/assets/capabilities-settings-panel-6tYNfHqJ.js +0 -7
  194. package/dist/gateway/static/root/assets/capability-presets-settings-panel-Co-ymbd9.js +0 -1
  195. package/dist/gateway/static/root/assets/channels-settings-D46eVjaQ.js +0 -1
  196. package/dist/gateway/static/root/assets/channels-status-swr-BMRAO4zZ.js +0 -1
  197. package/dist/gateway/static/root/assets/connectors-page-Dw1eYbRi.js +0 -2
  198. package/dist/gateway/static/root/assets/copy-VueTIC2x.js +0 -1
  199. package/dist/gateway/static/root/assets/desktop-pet-B8cZuQUt.js +0 -1
  200. package/dist/gateway/static/root/assets/focus-detail-page-BBXUtxRB.js +0 -1
  201. package/dist/gateway/static/root/assets/goal-detail-page-VjRArfAJ.js +0 -4
  202. package/dist/gateway/static/root/assets/index-CS9sVShT.css +0 -1
  203. package/dist/gateway/static/root/assets/local-app-workbench-page-Cl0fcPL4.js +0 -2
  204. package/dist/gateway/static/root/assets/messages-CarlxqXV.js +0 -3
  205. package/dist/gateway/static/root/assets/notes-workbench-BKNBk0Uf.js +0 -4
  206. package/dist/gateway/static/root/assets/project-detail-page-BhjEXNQW.js +0 -1
  207. package/dist/gateway/static/root/assets/projects-page-B80e69PH.js +0 -1
  208. package/dist/gateway/static/root/assets/remote-access-hub-CwdVob6H.js +0 -1
  209. package/dist/gateway/static/root/assets/sessions-page-BGt3Asj6.js +0 -1
  210. package/dist/gateway/static/root/assets/settings-advanced-gate-BnTdM9Nn.js +0 -1
  211. package/dist/gateway/static/root/assets/shares-settings-C4lXuyQj.js +0 -1
  212. package/dist/gateway/static/root/assets/skill-reload-api-DSuIDkeI.js +0 -1
  213. package/dist/gateway/static/root/assets/skills-page-xgZczqVe.js +0 -2
  214. package/dist/gateway/static/root/assets/user-context-page-CEfIy4WZ.js +0 -1
  215. package/dist/gateway/static/root/assets/work-discovery-page-B-3MClaf.js +0 -1
  216. package/dist/gateway/static/root/assets/work-item-detail-page-CEsFEdax.js +0 -1
  217. package/dist/gateway/static/root/assets/work-page-CT9AHnq6.js +0 -3
  218. package/dist/gateway/static/root/assets/workflows-page-C-1-_Zp1.js +0 -11
  219. package/dist/src/focuses/candidate-repository.d.ts +0 -15
  220. package/dist/src/focuses/candidate-repository.js +0 -91
  221. package/dist/src/focuses/index.d.ts +0 -7
  222. package/dist/src/focuses/index.js +0 -7
  223. package/dist/src/focuses/insight-repository.d.ts +0 -22
  224. package/dist/src/focuses/insight-repository.js +0 -77
  225. package/dist/src/focuses/prompts.d.ts +0 -2
  226. package/dist/src/focuses/prompts.js +0 -18
  227. package/dist/src/focuses/reconciler.d.ts +0 -5
  228. package/dist/src/focuses/reconciler.js +0 -26
  229. package/dist/src/focuses/repository.d.ts +0 -61
  230. package/dist/src/focuses/repository.js +0 -214
  231. package/dist/src/focuses/run-processor.d.ts +0 -18
  232. package/dist/src/focuses/run-processor.js +0 -162
  233. package/dist/src/focuses/service.d.ts +0 -42
  234. package/dist/src/focuses/service.js +0 -241
  235. package/dist/src/focuses/types.d.ts +0 -89
  236. package/dist/src/gateway/hono/routes/focuses.d.ts +0 -3
  237. package/dist/src/gateway/hono/routes/focuses.js +0 -319
  238. /package/dist/src/{focuses/types.js → proactive/events/publisher.js} +0 -0
@@ -0,0 +1,31 @@
1
+ import type { ContextProvider } from './types.js';
2
+ export declare class EventBatchContextProvider implements ContextProvider {
3
+ readonly id = "event_batch";
4
+ supports(): boolean;
5
+ collect(input: {
6
+ eventIds: string[];
7
+ }): Promise<Record<string, unknown>>;
8
+ }
9
+ export declare class ProjectStateContextProvider implements ContextProvider {
10
+ readonly id = "project_state";
11
+ supports(scenarioKey: string): boolean;
12
+ collect(input: {
13
+ eventIds: string[];
14
+ }): Promise<Record<string, unknown>>;
15
+ }
16
+ export declare class AutomationStateContextProvider implements ContextProvider {
17
+ readonly id = "automation_state";
18
+ supports(scenarioKey: string): boolean;
19
+ collect(input: {
20
+ eventIds: string[];
21
+ }): Promise<Record<string, unknown>>;
22
+ }
23
+ export declare class ContextProviderRegistry {
24
+ private readonly providers;
25
+ constructor(providers?: ContextProvider[]);
26
+ collect(scenarioKey: string, input: {
27
+ batchId: string;
28
+ eventIds: string[];
29
+ subscriptionId: string;
30
+ }): Promise<Record<string, unknown>>;
31
+ }
@@ -0,0 +1,72 @@
1
+ import { getSqliteDatabase } from "../../storage/sqlite/transaction.js";
2
+ //#region src/proactive/execution/context.ts
3
+ var EventBatchContextProvider = class {
4
+ id = "event_batch";
5
+ supports() {
6
+ return true;
7
+ }
8
+ async collect(input) {
9
+ if (input.eventIds.length === 0) return { events: [] };
10
+ return { events: getSqliteDatabase().prepare(`SELECT event_id, type, subject_kind, subject_id, payload_json, occurred_at
11
+ FROM proactive_events WHERE event_id IN (${input.eventIds.map(() => "?").join(",")}) ORDER BY occurred_at`).all(...input.eventIds).map((row) => ({
12
+ evidenceId: row.event_id,
13
+ type: row.type,
14
+ subject: {
15
+ kind: row.subject_kind,
16
+ id: row.subject_id
17
+ },
18
+ payload: JSON.parse(row.payload_json),
19
+ occurredAt: row.occurred_at
20
+ })) };
21
+ }
22
+ };
23
+ var ProjectStateContextProvider = class {
24
+ id = "project_state";
25
+ supports(scenarioKey) {
26
+ return scenarioKey === "project_delivery_risk" || scenarioKey === "blocked_work";
27
+ }
28
+ async collect(input) {
29
+ if (!input.eventIds.length) return {};
30
+ const project = getSqliteDatabase().prepare(`SELECT p.* FROM proactive_events e JOIN projects p ON p.project_id = e.project_id
31
+ WHERE e.event_id IN (${input.eventIds.map(() => "?").join(",")}) AND e.project_id IS NOT NULL ORDER BY e.occurred_at DESC LIMIT 1`).get(...input.eventIds);
32
+ if (!project) return {};
33
+ return {
34
+ project,
35
+ workItems: getSqliteDatabase().prepare(`SELECT id, title, status, priority, owner_agent_id, next_action,
36
+ blocked_reason, due_at, updated_at FROM work_items WHERE project_id = ? AND archived_at IS NULL
37
+ ORDER BY CASE status WHEN 'blocked' THEN 0 ELSE 1 END, updated_at DESC LIMIT 100`).all(String(project.project_id))
38
+ };
39
+ }
40
+ };
41
+ var AutomationStateContextProvider = class {
42
+ id = "automation_state";
43
+ supports(scenarioKey) {
44
+ return scenarioKey === "automation_failure_impact";
45
+ }
46
+ async collect(input) {
47
+ if (!input.eventIds.length) return {};
48
+ const run = getSqliteDatabase().prepare(`SELECT r.* FROM proactive_events e JOIN automation_runs r ON r.run_id = e.subject_id
49
+ WHERE e.event_id IN (${input.eventIds.map(() => "?").join(",")}) ORDER BY e.occurred_at DESC LIMIT 1`).get(...input.eventIds);
50
+ if (!run) return {};
51
+ return {
52
+ automation: getSqliteDatabase().prepare(`SELECT automation_id, name, description, enabled, reliability_json, state_json, project_id
53
+ FROM automations WHERE automation_id = ?`).get(String(run.automation_id)),
54
+ failedRun: run
55
+ };
56
+ }
57
+ };
58
+ var ContextProviderRegistry = class {
59
+ constructor(providers = [
60
+ new EventBatchContextProvider(),
61
+ new ProjectStateContextProvider(),
62
+ new AutomationStateContextProvider()
63
+ ]) {
64
+ this.providers = providers;
65
+ }
66
+ async collect(scenarioKey, input) {
67
+ const entries = await Promise.all(this.providers.filter((provider) => provider.supports(scenarioKey)).map(async (provider) => [provider.id, await provider.collect(input)]));
68
+ return Object.fromEntries(entries);
69
+ }
70
+ };
71
+ //#endregion
72
+ export { AutomationStateContextProvider, ContextProviderRegistry, EventBatchContextProvider, ProjectStateContextProvider };
@@ -0,0 +1,4 @@
1
+ import type { InsightCandidate } from './types.js';
2
+ export declare function parseInsightCandidate(raw: string, allowedEvidenceIds: Set<string>): InsightCandidate;
3
+ export declare function scoreInsight(candidate: InsightCandidate): number;
4
+ export declare function isValuableInsight(candidate: InsightCandidate): boolean;
@@ -0,0 +1,74 @@
1
+ import { stripCodeFences } from "../../agent/goals/judge.js";
2
+ //#region src/proactive/execution/insight.ts
3
+ const URGENCY = new Set([
4
+ "low",
5
+ "medium",
6
+ "high",
7
+ "critical"
8
+ ]);
9
+ const boundedText = (value, field, max) => {
10
+ if (typeof value !== "string" || !value.trim()) throw new Error(`Insight ${field} is required`);
11
+ return value.trim().slice(0, max);
12
+ };
13
+ function parseDecision(value) {
14
+ if (value == null) return void 0;
15
+ if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error("Insight decision is invalid");
16
+ const row = value;
17
+ if (!Array.isArray(row.options) || row.options.length < 2 || row.options.length > 3) throw new Error("Insight decision options are invalid");
18
+ const options = row.options.map((option) => {
19
+ if (!option || typeof option !== "object" || Array.isArray(option)) throw new Error("Insight decision option is invalid");
20
+ const item = option;
21
+ return {
22
+ id: boundedText(item.id, "decision option id", 80),
23
+ label: boundedText(item.label, "decision option label", 120),
24
+ consequence: boundedText(item.consequence, "decision option consequence", 400)
25
+ };
26
+ });
27
+ if (new Set(options.map((option) => option.id)).size !== options.length) throw new Error("Insight decision option ids must be unique");
28
+ return {
29
+ question: boundedText(row.question, "decision question", 400),
30
+ options
31
+ };
32
+ }
33
+ function parseInsightCandidate(raw, allowedEvidenceIds) {
34
+ let value;
35
+ try {
36
+ value = JSON.parse(stripCodeFences(raw));
37
+ } catch {
38
+ throw new Error("Model output is not valid JSON");
39
+ }
40
+ if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error("Insight must be a JSON object");
41
+ const row = value;
42
+ if (!URGENCY.has(String(row.urgency))) throw new Error("Insight urgency is invalid");
43
+ if (typeof row.confidence !== "number" || row.confidence < 0 || row.confidence > 1) throw new Error("Insight confidence is invalid");
44
+ if (!Array.isArray(row.evidenceIds) || row.evidenceIds.length === 0 || row.evidenceIds.length > 20) throw new Error("Insight evidenceIds are invalid");
45
+ const evidenceIds = [...new Set(row.evidenceIds.map(String))];
46
+ if (evidenceIds.some((id) => !allowedEvidenceIds.has(id))) throw new Error("Insight cites unknown evidence");
47
+ const decision = parseDecision(row.decision);
48
+ return {
49
+ title: boundedText(row.title, "title", 160),
50
+ summary: boundedText(row.summary, "summary", 1200),
51
+ whyNow: boundedText(row.whyNow, "whyNow", 800),
52
+ impact: boundedText(row.impact, "impact", 800),
53
+ recommendation: boundedText(row.recommendation, "recommendation", 800),
54
+ workDone: boundedText(row.workDone, "workDone", 800),
55
+ ...decision ? { decision } : {},
56
+ urgency: String(row.urgency),
57
+ confidence: row.confidence,
58
+ evidenceIds
59
+ };
60
+ }
61
+ function scoreInsight(candidate) {
62
+ const urgencyWeight = {
63
+ low: .15,
64
+ medium: .45,
65
+ high: .75,
66
+ critical: 1
67
+ }[candidate.urgency];
68
+ return Math.round((candidate.confidence * .7 + urgencyWeight * .3) * 1e3) / 1e3;
69
+ }
70
+ function isValuableInsight(candidate) {
71
+ return candidate.confidence >= .65 && candidate.urgency !== "low" && scoreInsight(candidate) >= .6;
72
+ }
73
+ //#endregion
74
+ export { isValuableInsight, parseInsightCandidate, scoreInsight };
@@ -0,0 +1,23 @@
1
+ import type { ContextSnapshot, InsightCandidate, ProactiveInsight } from './types.js';
2
+ export interface ClaimedRun {
3
+ id: string;
4
+ batchId: string;
5
+ subscriptionId: string;
6
+ scenarioKey: string;
7
+ scenarioVersion: number;
8
+ promptRevisionId?: string;
9
+ attempt: number;
10
+ }
11
+ export declare function claimNextRun(owner: string, now?: Date, leaseSeconds?: number): ClaimedRun | null;
12
+ export declare function eventIdsForBatch(batchId: string): string[];
13
+ export declare function saveSnapshot(batchId: string, content: Record<string, unknown>, evidenceIds: string[], now?: Date): ContextSnapshot;
14
+ export declare function attachSnapshot(runId: string, snapshotId: string): void;
15
+ export declare function finishRun(input: {
16
+ run: ClaimedRun;
17
+ candidate?: InsightCandidate;
18
+ valueScore?: number;
19
+ rawOutput: string;
20
+ modelRef?: string;
21
+ }, now?: Date): ProactiveInsight | null;
22
+ export declare function failRun(run: ClaimedRun, error: unknown, retryable: boolean, now?: Date): void;
23
+ export declare function listInsights(limit?: number): ProactiveInsight[];
@@ -0,0 +1,122 @@
1
+ import { getSqliteDatabase, runSqliteWriteTransaction } from "../../storage/sqlite/transaction.js";
2
+ import { randomUUID } from "node:crypto";
3
+ //#region src/proactive/execution/repository.ts
4
+ const str = (row, key) => String(row[key]);
5
+ function claimNextRun(owner, now = /* @__PURE__ */ new Date(), leaseSeconds = 120) {
6
+ return runSqliteWriteTransaction((db) => {
7
+ const nowIso = now.toISOString();
8
+ db.prepare(`UPDATE proactive_signal_batches SET status = 'ignored', updated_at = ? WHERE status = 'ready'
9
+ AND subscription_id IN (SELECT subscription_id FROM proactive_scenario_subscriptions WHERE enabled = 0)`).run(nowIso);
10
+ db.prepare(`UPDATE proactive_signal_batches SET status = 'failed_permanent', updated_at = ?
11
+ WHERE status = 'processing' AND batch_id IN (
12
+ SELECT batch_id FROM proactive_runs WHERE status = 'running' AND lease_expires_at <= ? AND attempt >= 3
13
+ )`).run(nowIso, nowIso);
14
+ db.prepare(`UPDATE proactive_runs SET status = 'failed', error_message = 'Lease expired after maximum attempts',
15
+ lease_owner = NULL, lease_expires_at = NULL, updated_at = ?
16
+ WHERE status = 'running' AND lease_expires_at <= ? AND attempt >= 3`).run(nowIso, nowIso);
17
+ const retry = db.prepare(`SELECT * FROM proactive_runs WHERE status = 'retryable' AND next_attempt_at <= ? ORDER BY next_attempt_at LIMIT 1`).get(nowIso);
18
+ if (retry) {
19
+ db.prepare(`UPDATE proactive_runs SET status = 'running', attempt = attempt + 1, lease_owner = ?, lease_expires_at = ?, next_attempt_at = NULL, updated_at = ? WHERE run_id = ?`).run(owner, new Date(now.getTime() + leaseSeconds * 1e3).toISOString(), nowIso, str(retry, "run_id"));
20
+ db.prepare("UPDATE proactive_signal_batches SET status = 'processing', updated_at = ? WHERE batch_id = ?").run(nowIso, str(retry, "batch_id"));
21
+ return runFromRow(db.prepare("SELECT * FROM proactive_runs WHERE run_id = ?").get(str(retry, "run_id")));
22
+ }
23
+ const expired = db.prepare(`SELECT * FROM proactive_runs WHERE status = 'running' AND lease_expires_at <= ? AND attempt < 3 ORDER BY updated_at LIMIT 1`).get(nowIso);
24
+ if (expired) {
25
+ db.prepare(`UPDATE proactive_runs SET attempt = attempt + 1, lease_owner = ?, lease_expires_at = ?, updated_at = ? WHERE run_id = ?`).run(owner, new Date(now.getTime() + leaseSeconds * 1e3).toISOString(), nowIso, str(expired, "run_id"));
26
+ return runFromRow(db.prepare("SELECT * FROM proactive_runs WHERE run_id = ?").get(str(expired, "run_id")));
27
+ }
28
+ const batch = db.prepare(`SELECT b.*, s.active_prompt_revision_id FROM proactive_signal_batches b
29
+ JOIN proactive_scenario_subscriptions s ON s.subscription_id = b.subscription_id
30
+ WHERE b.status = 'ready' ORDER BY b.ready_at LIMIT 1`).get();
31
+ if (!batch) return null;
32
+ const id = randomUUID();
33
+ db.prepare(`INSERT INTO proactive_runs (run_id, batch_id, subscription_id, scenario_key, scenario_version,
34
+ prompt_revision_id, status, attempt, lease_owner, lease_expires_at, started_at, updated_at)
35
+ VALUES (?, ?, ?, ?, ?, ?, 'running', 1, ?, ?, ?, ?)`).run(id, str(batch, "batch_id"), str(batch, "subscription_id"), str(batch, "scenario_key"), Number(batch.scenario_version), batch.active_prompt_revision_id ? String(batch.active_prompt_revision_id) : null, owner, new Date(now.getTime() + leaseSeconds * 1e3).toISOString(), nowIso, nowIso);
36
+ db.prepare("UPDATE proactive_signal_batches SET status = 'processing', updated_at = ? WHERE batch_id = ?").run(nowIso, str(batch, "batch_id"));
37
+ return runFromRow(db.prepare("SELECT * FROM proactive_runs WHERE run_id = ?").get(id));
38
+ });
39
+ }
40
+ function runFromRow(row) {
41
+ return {
42
+ id: str(row, "run_id"),
43
+ batchId: str(row, "batch_id"),
44
+ subscriptionId: str(row, "subscription_id"),
45
+ scenarioKey: str(row, "scenario_key"),
46
+ scenarioVersion: Number(row.scenario_version),
47
+ attempt: Number(row.attempt),
48
+ ...row.prompt_revision_id ? { promptRevisionId: str(row, "prompt_revision_id") } : {}
49
+ };
50
+ }
51
+ function eventIdsForBatch(batchId) {
52
+ return getSqliteDatabase().prepare("SELECT event_id FROM proactive_batch_events WHERE batch_id = ? ORDER BY added_at DESC LIMIT 100").all(batchId).map((row) => row.event_id);
53
+ }
54
+ function saveSnapshot(batchId, content, evidenceIds, now = /* @__PURE__ */ new Date()) {
55
+ const snapshot = {
56
+ id: randomUUID(),
57
+ batchId,
58
+ content,
59
+ evidenceIds,
60
+ createdAt: now.toISOString()
61
+ };
62
+ runSqliteWriteTransaction((db) => db.prepare(`INSERT INTO proactive_context_snapshots
63
+ (snapshot_id, batch_id, content_json, evidence_ids_json, created_at) VALUES (?, ?, ?, ?, ?)`).run(snapshot.id, batchId, JSON.stringify(content), JSON.stringify(evidenceIds), snapshot.createdAt));
64
+ return snapshot;
65
+ }
66
+ function attachSnapshot(runId, snapshotId) {
67
+ runSqliteWriteTransaction((db) => db.prepare("UPDATE proactive_runs SET context_snapshot_id = ?, updated_at = ? WHERE run_id = ?").run(snapshotId, (/* @__PURE__ */ new Date()).toISOString(), runId));
68
+ }
69
+ function finishRun(input, now = /* @__PURE__ */ new Date()) {
70
+ return runSqliteWriteTransaction((db) => {
71
+ const nowIso = now.toISOString();
72
+ const valuable = Boolean(input.candidate);
73
+ db.prepare(`UPDATE proactive_runs SET status = ?, raw_output = ?, model_ref = ?, lease_owner = NULL,
74
+ lease_expires_at = NULL, completed_at = ?, updated_at = ? WHERE run_id = ?`).run(valuable ? "completed" : "discarded", input.rawOutput.slice(0, 2e4), input.modelRef ?? null, nowIso, nowIso, input.run.id);
75
+ db.prepare(`UPDATE proactive_signal_batches SET status = ?, updated_at = ? WHERE batch_id = ?`).run(valuable ? "processed" : "ignored", nowIso, input.run.batchId);
76
+ if (!input.candidate) return null;
77
+ const insight = {
78
+ ...input.candidate,
79
+ id: randomUUID(),
80
+ runId: input.run.id,
81
+ subscriptionId: input.run.subscriptionId,
82
+ scenarioKey: input.run.scenarioKey,
83
+ valueScore: input.valueScore ?? 0,
84
+ createdAt: nowIso
85
+ };
86
+ db.prepare(`INSERT INTO proactive_insights (insight_id, run_id, subscription_id, scenario_key, title, summary,
87
+ why_now, impact, recommendation, work_done, decision_json, urgency, confidence, value_score, evidence_ids_json, created_at)
88
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(insight.id, insight.runId, insight.subscriptionId, insight.scenarioKey, insight.title, insight.summary, insight.whyNow, insight.impact, insight.recommendation, insight.workDone, insight.decision ? JSON.stringify(insight.decision) : null, insight.urgency, insight.confidence, insight.valueScore, JSON.stringify(insight.evidenceIds), insight.createdAt);
89
+ return insight;
90
+ });
91
+ }
92
+ function failRun(run, error, retryable, now = /* @__PURE__ */ new Date()) {
93
+ runSqliteWriteTransaction((db) => {
94
+ const finalRetryable = retryable && run.attempt < 3;
95
+ const nowIso = now.toISOString();
96
+ const nextAttemptAt = finalRetryable ? new Date(now.getTime() + 15e3 * run.attempt).toISOString() : null;
97
+ db.prepare(`UPDATE proactive_runs SET status = ?, error_message = ?, lease_owner = NULL, lease_expires_at = NULL, next_attempt_at = ?, updated_at = ? WHERE run_id = ?`).run(finalRetryable ? "retryable" : "failed", String(error instanceof Error ? error.message : error).slice(0, 2e3), nextAttemptAt, nowIso, run.id);
98
+ db.prepare(`UPDATE proactive_signal_batches SET status = ?, updated_at = ? WHERE batch_id = ?`).run(finalRetryable ? "failed_retryable" : "failed_permanent", nowIso, run.batchId);
99
+ });
100
+ }
101
+ function listInsights(limit = 50) {
102
+ return getSqliteDatabase().prepare("SELECT * FROM proactive_insights ORDER BY created_at DESC LIMIT ?").all(Math.min(200, Math.max(1, limit))).map((row) => ({
103
+ id: str(row, "insight_id"),
104
+ runId: str(row, "run_id"),
105
+ subscriptionId: str(row, "subscription_id"),
106
+ scenarioKey: str(row, "scenario_key"),
107
+ title: str(row, "title"),
108
+ summary: str(row, "summary"),
109
+ whyNow: str(row, "why_now"),
110
+ impact: str(row, "impact"),
111
+ recommendation: str(row, "recommendation"),
112
+ workDone: str(row, "work_done"),
113
+ ...row.decision_json ? { decision: JSON.parse(str(row, "decision_json")) } : {},
114
+ urgency: str(row, "urgency"),
115
+ confidence: Number(row.confidence),
116
+ valueScore: Number(row.value_score),
117
+ evidenceIds: JSON.parse(str(row, "evidence_ids_json")),
118
+ createdAt: str(row, "created_at")
119
+ }));
120
+ }
121
+ //#endregion
122
+ export { attachSnapshot, claimNextRun, eventIdsForBatch, failRun, finishRun, listInsights, saveSnapshot };
@@ -0,0 +1,54 @@
1
+ export interface ContextSnapshot {
2
+ id: string;
3
+ batchId: string;
4
+ content: Record<string, unknown>;
5
+ evidenceIds: string[];
6
+ createdAt: string;
7
+ }
8
+ export interface InsightCandidate {
9
+ title: string;
10
+ summary: string;
11
+ whyNow: string;
12
+ impact: string;
13
+ recommendation: string;
14
+ workDone: string;
15
+ decision?: {
16
+ question: string;
17
+ options: Array<{
18
+ id: string;
19
+ label: string;
20
+ consequence: string;
21
+ }>;
22
+ };
23
+ urgency: 'low' | 'medium' | 'high' | 'critical';
24
+ confidence: number;
25
+ evidenceIds: string[];
26
+ }
27
+ export interface ProactiveInsight extends InsightCandidate {
28
+ id: string;
29
+ runId: string;
30
+ subscriptionId: string;
31
+ scenarioKey: string;
32
+ valueScore: number;
33
+ createdAt: string;
34
+ }
35
+ export interface ProactiveAgentExecutor {
36
+ execute(input: {
37
+ systemPrompt: string;
38
+ userPrompt: string;
39
+ authorizedContext: Record<string, unknown>;
40
+ signal?: AbortSignal;
41
+ }): Promise<{
42
+ text: string;
43
+ modelRef?: string;
44
+ }>;
45
+ }
46
+ export interface ContextProvider {
47
+ id: string;
48
+ supports(scenarioKey: string): boolean;
49
+ collect(input: {
50
+ batchId: string;
51
+ eventIds: string[];
52
+ subscriptionId: string;
53
+ }): Promise<Record<string, unknown>>;
54
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,15 @@
1
+ import { ContextProviderRegistry } from './context.js';
2
+ import type { ProactiveAgentExecutor } from './types.js';
3
+ export declare class ProactiveWorker {
4
+ private readonly executor;
5
+ private readonly contexts;
6
+ private readonly intervalMs;
7
+ private readonly owner;
8
+ private timer?;
9
+ private running;
10
+ private stoppedWaiters;
11
+ constructor(executor: ProactiveAgentExecutor, contexts?: ContextProviderRegistry, intervalMs?: number);
12
+ start(): void;
13
+ stop(): Promise<void>;
14
+ tick(): Promise<void>;
15
+ }
@@ -0,0 +1,96 @@
1
+ import { createLogger } from "../../utils/logger/index.js";
2
+ import { init_logger } from "../../utils/logger.js";
3
+ import { markReadyBatches } from "../routing/batch-repository.js";
4
+ import { getPromptRevision, getScenario } from "../scenarios/repository.js";
5
+ import { composeScenarioPrompt } from "../scenarios/prompt-composer.js";
6
+ import { ContextProviderRegistry } from "./context.js";
7
+ import { attachSnapshot, claimNextRun, eventIdsForBatch, failRun, finishRun, saveSnapshot } from "./repository.js";
8
+ import { isValuableInsight, parseInsightCandidate, scoreInsight } from "./insight.js";
9
+ import { randomUUID } from "node:crypto";
10
+ //#region src/proactive/execution/worker.ts
11
+ init_logger();
12
+ const log = createLogger("ProactiveWorker");
13
+ var ProactiveWorker = class {
14
+ owner = randomUUID();
15
+ timer;
16
+ running = false;
17
+ stoppedWaiters = [];
18
+ constructor(executor, contexts = new ContextProviderRegistry(), intervalMs = 5e3) {
19
+ this.executor = executor;
20
+ this.contexts = contexts;
21
+ this.intervalMs = intervalMs;
22
+ }
23
+ start() {
24
+ if (this.timer) return;
25
+ this.timer = setInterval(() => void this.tick(), this.intervalMs);
26
+ this.timer.unref();
27
+ this.tick();
28
+ }
29
+ async stop() {
30
+ if (this.timer) clearInterval(this.timer);
31
+ this.timer = void 0;
32
+ if (!this.running) return;
33
+ await new Promise((resolve) => this.stoppedWaiters.push(resolve));
34
+ }
35
+ async tick() {
36
+ if (this.running) return;
37
+ this.running = true;
38
+ try {
39
+ markReadyBatches();
40
+ const run = claimNextRun(this.owner);
41
+ if (!run) return;
42
+ try {
43
+ const scenario = getScenario(run.scenarioKey);
44
+ if (!scenario || scenario.version !== run.scenarioVersion) throw new Error("Pinned scenario version is unavailable");
45
+ const revision = run.promptRevisionId ? getPromptRevision(run.promptRevisionId) ?? void 0 : void 0;
46
+ const eventIds = eventIdsForBatch(run.batchId);
47
+ const context = await this.contexts.collect(run.scenarioKey, {
48
+ batchId: run.batchId,
49
+ eventIds,
50
+ subscriptionId: run.subscriptionId
51
+ });
52
+ const snapshot = saveSnapshot(run.batchId, context, eventIds);
53
+ attachSnapshot(run.id, snapshot.id);
54
+ const prompt = composeScenarioPrompt({
55
+ scenario,
56
+ ...revision ? { revision } : {},
57
+ runtimeContext: "Use the read-only inspection tool to examine the authorized evidence."
58
+ });
59
+ const output = await this.executor.execute({
60
+ systemPrompt: prompt.platformSafety,
61
+ userPrompt: prompt.text,
62
+ authorizedContext: context
63
+ });
64
+ const candidate = parseInsightCandidate(output.text, new Set(eventIds));
65
+ const valuable = isValuableInsight(candidate);
66
+ const insight = finishRun({
67
+ run,
68
+ ...valuable ? {
69
+ candidate,
70
+ valueScore: scoreInsight(candidate)
71
+ } : {},
72
+ rawOutput: output.text,
73
+ modelRef: output.modelRef
74
+ });
75
+ log.info({
76
+ runId: run.id,
77
+ scenarioKey: run.scenarioKey,
78
+ valuable,
79
+ insightId: insight?.id
80
+ }, valuable ? "Proactive insight created" : "Proactive output discarded by value gate");
81
+ } catch (error) {
82
+ failRun(run, error, !(error instanceof Error && /Pinned scenario/.test(error.message)));
83
+ log.warn({
84
+ err: error,
85
+ runId: run.id,
86
+ scenarioKey: run.scenarioKey
87
+ }, "Proactive run failed");
88
+ }
89
+ } finally {
90
+ this.running = false;
91
+ for (const resolve of this.stoppedWaiters.splice(0)) resolve();
92
+ }
93
+ }
94
+ };
95
+ //#endregion
96
+ export { ProactiveWorker };
@@ -0,0 +1,24 @@
1
+ import type { InboxItem, InboxStatus } from './types.js';
2
+ export declare function projectInsightsToInbox(now?: Date): number;
3
+ export declare function wakeSnoozedItems(now?: Date): number;
4
+ export declare function listInbox(input?: {
5
+ status?: InboxStatus;
6
+ limit?: number;
7
+ }): InboxItem[];
8
+ export declare function getInboxItem(id: string): InboxItem | null;
9
+ export declare function transitionInboxItem(id: string, input: {
10
+ status: InboxStatus;
11
+ snoozedUntil?: string;
12
+ resolution?: string;
13
+ }, now?: Date): InboxItem;
14
+ export declare function recordDecision(id: string, choice: string, note?: string, now?: Date): InboxItem;
15
+ export declare function recordFeedback(id: string, rating: 'useful' | 'not_useful', note?: string, now?: Date): void;
16
+ export declare function getInboxSubscriptionId(id: string): string;
17
+ export interface OutboxClaim {
18
+ id: string;
19
+ item: InboxItem;
20
+ attempt: number;
21
+ }
22
+ export declare function claimDelivery(now?: Date): OutboxClaim | null;
23
+ export declare function finishDelivery(id: string, error?: unknown, attempt?: number, now?: Date): void;
24
+ export declare function recoverExpiredDeliveries(now?: Date): number;
@@ -0,0 +1,117 @@
1
+ import { getSqliteDatabase, runSqliteWriteTransaction } from "../../storage/sqlite/transaction.js";
2
+ import { randomUUID } from "node:crypto";
3
+ //#region src/proactive/inbox/repository.ts
4
+ const s = (row, key) => String(row[key]);
5
+ function itemFromRow(row) {
6
+ return {
7
+ id: s(row, "inbox_item_id"),
8
+ insightId: s(row, "insight_id"),
9
+ status: s(row, "status"),
10
+ ...row.snoozed_until ? { snoozedUntil: s(row, "snoozed_until") } : {},
11
+ ...row.resolution ? { resolution: s(row, "resolution") } : {},
12
+ createdAt: s(row, "created_at"),
13
+ updatedAt: s(row, "updated_at"),
14
+ insight: {
15
+ scenarioKey: s(row, "scenario_key"),
16
+ title: s(row, "title"),
17
+ summary: s(row, "summary"),
18
+ whyNow: s(row, "why_now"),
19
+ impact: s(row, "impact"),
20
+ recommendation: s(row, "recommendation"),
21
+ workDone: s(row, "work_done"),
22
+ ...row.decision_json ? { decision: JSON.parse(s(row, "decision_json")) } : {},
23
+ urgency: s(row, "urgency"),
24
+ confidence: Number(row.confidence),
25
+ valueScore: Number(row.value_score),
26
+ evidenceIds: JSON.parse(s(row, "evidence_ids_json"))
27
+ }
28
+ };
29
+ }
30
+ const SELECT_ITEM = `SELECT i.*, x.subscription_id, x.scenario_key, x.title, x.summary, x.why_now, x.impact, x.recommendation,
31
+ x.work_done, x.decision_json, x.urgency, x.confidence, x.value_score, x.evidence_ids_json FROM proactive_inbox_items i
32
+ JOIN proactive_insights x ON x.insight_id = i.insight_id`;
33
+ function projectInsightsToInbox(now = /* @__PURE__ */ new Date()) {
34
+ return runSqliteWriteTransaction((db) => {
35
+ const missing = db.prepare(`SELECT insight_id FROM proactive_insights WHERE insight_id NOT IN
36
+ (SELECT insight_id FROM proactive_inbox_items) ORDER BY created_at`).all();
37
+ for (const row of missing) {
38
+ const id = randomUUID();
39
+ const nowIso = now.toISOString();
40
+ db.prepare(`INSERT INTO proactive_inbox_items (inbox_item_id, insight_id, status, created_at, updated_at)
41
+ VALUES (?, ?, 'unread', ?, ?)`).run(id, row.insight_id, nowIso, nowIso);
42
+ db.prepare(`INSERT INTO proactive_delivery_outbox (delivery_id, inbox_item_id, status, attempt, next_attempt_at, created_at, updated_at)
43
+ VALUES (?, ?, 'pending', 0, ?, ?, ?)`).run(randomUUID(), id, nowIso, nowIso, nowIso);
44
+ }
45
+ return missing.length;
46
+ });
47
+ }
48
+ function wakeSnoozedItems(now = /* @__PURE__ */ new Date()) {
49
+ return Number(runSqliteWriteTransaction((db) => db.prepare(`UPDATE proactive_inbox_items SET status = 'unread', snoozed_until = NULL, updated_at = ?
50
+ WHERE status = 'snoozed' AND snoozed_until <= ?`).run(now.toISOString(), now.toISOString()).changes));
51
+ }
52
+ function listInbox(input = {}) {
53
+ const limit = Math.min(200, Math.max(1, input.limit ?? 50));
54
+ return (input.status ? getSqliteDatabase().prepare(`${SELECT_ITEM} WHERE i.status = ? ORDER BY i.updated_at DESC LIMIT ?`).all(input.status, limit) : getSqliteDatabase().prepare(`${SELECT_ITEM} ORDER BY i.updated_at DESC LIMIT ?`).all(limit)).map(itemFromRow);
55
+ }
56
+ function getInboxItem(id) {
57
+ const row = getSqliteDatabase().prepare(`${SELECT_ITEM} WHERE i.inbox_item_id = ?`).get(id);
58
+ return row ? itemFromRow(row) : null;
59
+ }
60
+ function transitionInboxItem(id, input, now = /* @__PURE__ */ new Date()) {
61
+ if (input.status === "snoozed" && (!input.snoozedUntil || Date.parse(input.snoozedUntil) <= now.getTime())) throw new Error("snoozedUntil must be in the future");
62
+ if (input.status === "resolved" && !input.resolution?.trim()) throw new Error("resolution is required");
63
+ runSqliteWriteTransaction((db) => {
64
+ if (db.prepare(`UPDATE proactive_inbox_items SET status = ?, snoozed_until = ?, resolution = ?, updated_at = ? WHERE inbox_item_id = ?`).run(input.status, input.status === "snoozed" ? input.snoozedUntil : null, input.status === "resolved" ? input.resolution.trim() : null, now.toISOString(), id).changes !== 1) throw new Error("Inbox item not found");
65
+ });
66
+ return getInboxItem(id);
67
+ }
68
+ function recordDecision(id, choice, note = "", now = /* @__PURE__ */ new Date()) {
69
+ if (!choice.trim()) throw new Error("choice is required");
70
+ runSqliteWriteTransaction((db) => {
71
+ const row = db.prepare(`SELECT x.decision_json FROM proactive_inbox_items i
72
+ JOIN proactive_insights x ON x.insight_id = i.insight_id WHERE i.inbox_item_id = ?`).get(id);
73
+ if (!row) throw new Error("Inbox item not found");
74
+ if (!row.decision_json) throw new Error("Inbox item does not require a decision");
75
+ if (!JSON.parse(row.decision_json).options.some((option) => option.id === choice.trim())) throw new Error("choice is not a valid decision option");
76
+ db.prepare("INSERT INTO proactive_decisions (decision_id, inbox_item_id, choice, note, created_at) VALUES (?, ?, ?, ?, ?)").run(randomUUID(), id, choice.trim().slice(0, 200), note.trim().slice(0, 2e3), now.toISOString());
77
+ db.prepare("UPDATE proactive_inbox_items SET status = 'resolved', resolution = ?, updated_at = ? WHERE inbox_item_id = ?").run(choice.trim().slice(0, 200), now.toISOString(), id);
78
+ });
79
+ return getInboxItem(id);
80
+ }
81
+ function recordFeedback(id, rating, note = "", now = /* @__PURE__ */ new Date()) {
82
+ runSqliteWriteTransaction((db) => {
83
+ if (!db.prepare("SELECT 1 FROM proactive_inbox_items WHERE inbox_item_id = ?").get(id)) throw new Error("Inbox item not found");
84
+ db.prepare("INSERT INTO proactive_feedback (feedback_id, inbox_item_id, rating, note, created_at) VALUES (?, ?, ?, ?, ?)").run(randomUUID(), id, rating, note.trim().slice(0, 2e3), now.toISOString());
85
+ });
86
+ }
87
+ function getInboxSubscriptionId(id) {
88
+ const item = getSqliteDatabase().prepare(`${SELECT_ITEM} WHERE i.inbox_item_id = ?`).get(id);
89
+ if (!item) throw new Error("Inbox item not found");
90
+ return s(item, "subscription_id");
91
+ }
92
+ function claimDelivery(now = /* @__PURE__ */ new Date()) {
93
+ return runSqliteWriteTransaction((db) => {
94
+ const row = db.prepare(`SELECT delivery_id, inbox_item_id, attempt FROM proactive_delivery_outbox
95
+ WHERE status IN ('pending', 'retryable') AND next_attempt_at <= ? ORDER BY created_at LIMIT 1`).get(now.toISOString());
96
+ if (!row) return null;
97
+ db.prepare(`UPDATE proactive_delivery_outbox SET status = 'delivering', attempt = attempt + 1, lease_expires_at = ?, updated_at = ? WHERE delivery_id = ?`).run(new Date(now.getTime() + 6e4).toISOString(), now.toISOString(), s(row, "delivery_id"));
98
+ return {
99
+ id: s(row, "delivery_id"),
100
+ item: getInboxItem(s(row, "inbox_item_id")),
101
+ attempt: Number(row.attempt) + 1
102
+ };
103
+ });
104
+ }
105
+ function finishDelivery(id, error, attempt = 1, now = /* @__PURE__ */ new Date()) {
106
+ runSqliteWriteTransaction((db) => {
107
+ const retry = Boolean(error) && attempt < 5;
108
+ db.prepare(`UPDATE proactive_delivery_outbox SET status = ?, next_attempt_at = ?, lease_expires_at = NULL,
109
+ error_message = ?, delivered_at = ?, updated_at = ? WHERE delivery_id = ?`).run(error ? retry ? "retryable" : "failed" : "delivered", retry ? new Date(now.getTime() + attempt * 3e4).toISOString() : now.toISOString(), error ? String(error instanceof Error ? error.message : error).slice(0, 1e3) : null, error ? null : now.toISOString(), now.toISOString(), id);
110
+ });
111
+ }
112
+ function recoverExpiredDeliveries(now = /* @__PURE__ */ new Date()) {
113
+ return Number(runSqliteWriteTransaction((db) => db.prepare(`UPDATE proactive_delivery_outbox SET status = 'retryable', next_attempt_at = ?, lease_expires_at = NULL, updated_at = ?
114
+ WHERE status = 'delivering' AND lease_expires_at <= ?`).run(now.toISOString(), now.toISOString(), now.toISOString()).changes));
115
+ }
116
+ //#endregion
117
+ export { claimDelivery, finishDelivery, getInboxItem, getInboxSubscriptionId, listInbox, projectInsightsToInbox, recordDecision, recordFeedback, recoverExpiredDeliveries, transitionInboxItem, wakeSnoozedItems };
@@ -0,0 +1,17 @@
1
+ import { listInbox, projectInsightsToInbox, recordDecision, recordFeedback, wakeSnoozedItems } from './repository.js';
2
+ import type { InboxStatus } from './types.js';
3
+ export declare class ProactiveInboxService {
4
+ list: typeof listInbox;
5
+ project: typeof projectInsightsToInbox;
6
+ wakeSnoozed: typeof wakeSnoozedItems;
7
+ decide: typeof recordDecision;
8
+ feedback: typeof recordFeedback;
9
+ instruct(id: string, instruction: string): {
10
+ revisionId: string;
11
+ };
12
+ transition(id: string, input: {
13
+ status: InboxStatus;
14
+ snoozedUntil?: string;
15
+ resolution?: string;
16
+ }): import("./types.js").InboxItem;
17
+ }