@xopcai/xopc 0.0.197 → 0.0.200

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 (244) 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-BwmdJ5pv.js → activity-store-DYVN1hRp.js} +1 -1
  4. package/dist/gateway/static/root/assets/{agent-avatar-dicebear-C5st7lt5.js → agent-avatar-dicebear-eMarz29u.js} +1 -1
  5. package/dist/gateway/static/root/assets/agents-DeLW-454.js +68 -0
  6. package/dist/gateway/static/root/assets/{api-BM1hNzjw.js → api-B8mzbAle.js} +1 -1
  7. package/dist/gateway/static/root/assets/app-management-settings-panel-yfb68wq9.js +1 -0
  8. package/dist/gateway/static/root/assets/appearance-settings-B8SPknFM.js +1 -0
  9. package/dist/gateway/static/root/assets/apps-page-Bmor22Ny.js +1 -0
  10. package/dist/gateway/static/root/assets/{archive-plugin-qL07mwnY.js → archive-plugin-DmYRiOP3.js} +1 -1
  11. package/dist/gateway/static/root/assets/{attachment-load-CqSobpdi.js → attachment-load-D66JvcPi.js} +1 -1
  12. package/dist/gateway/static/root/assets/automations-page-Q4e8m11h.js +6 -0
  13. package/dist/gateway/static/root/assets/{binary-plugins-DBRPyLYE.js → binary-plugins-ChIsZArT.js} +1 -1
  14. package/dist/gateway/static/root/assets/{block-editor-6wG1LU7t.js → block-editor-Ck-k_d0Z.js} +4 -4
  15. package/dist/gateway/static/root/assets/browser-settings-page--uVL73Sb.js +8 -0
  16. package/dist/gateway/static/root/assets/browser-workflow-inputs-_ndaecsf.js +1 -0
  17. package/dist/gateway/static/root/assets/{browser-workflows-page-BEu3E0et.js → browser-workflows-page-BC5jm1zL.js} +2 -2
  18. package/dist/gateway/static/root/assets/button-CSEbl4zT.js +1 -0
  19. package/dist/gateway/static/root/assets/capabilities-settings-panel-DXpf3QYN.js +7 -0
  20. package/dist/gateway/static/root/assets/{capability-presets-api-BoOzFotX.js → capability-presets-api-Dy1jZJKs.js} +1 -1
  21. package/dist/gateway/static/root/assets/capability-presets-settings-panel-NAjCsrTi.js +3 -0
  22. package/dist/gateway/static/root/assets/{channel-recipient-api-_8IiTxRB.js → channel-recipient-api-D-9qiuio.js} +1 -1
  23. package/dist/gateway/static/root/assets/channels-settings-CiWUo7jW.js +1 -0
  24. package/dist/gateway/static/root/assets/channels-status-swr-B4Rbh3bM.js +1 -0
  25. package/dist/gateway/static/root/assets/connectors-api-5xiCRVUS.js +1 -0
  26. package/dist/gateway/static/root/assets/connectors-page-DOwlMseU.js +2 -0
  27. package/dist/gateway/static/root/assets/copy-Dv6d4Dvw.js +1 -0
  28. package/dist/gateway/static/root/assets/cron-expression-B3PebXKZ.js +2 -0
  29. package/dist/gateway/static/root/assets/date-picker-C1Vke7Xn.js +1 -0
  30. package/dist/gateway/static/root/assets/dependency-picker-FrQ0tsBC.js +1 -0
  31. package/dist/gateway/static/root/assets/{desktop-pet-CsLR4pWB.js → desktop-pet-CPBAzNJi.js} +1 -1
  32. package/dist/gateway/static/root/assets/desktop-pet-settings-D6s3glDP.js +1 -0
  33. package/dist/gateway/static/root/assets/directory-picker-path-field-CbNQ7QQS.js +1 -0
  34. package/dist/gateway/static/root/assets/dist-BPoKqzeH.js +1 -0
  35. package/dist/gateway/static/root/assets/dist-DY4Af0fY.js +1 -0
  36. package/dist/gateway/static/root/assets/{extension-debug-page-CD73euAM.js → extension-debug-page-dTK14hUv.js} +1 -1
  37. package/dist/gateway/static/root/assets/{extension-page-DAKjpNwd.js → extension-page-Cpdj1Kip.js} +1 -1
  38. package/dist/gateway/static/root/assets/extension-settings-page-iNHUZGd5.js +1 -0
  39. package/dist/gateway/static/root/assets/external-link-DjqjBmc3.js +1 -0
  40. package/dist/gateway/static/root/assets/form-field-width-DJw_jULe.js +1 -0
  41. package/dist/gateway/static/root/assets/gateway-config-api-SvMvWqMM.js +1 -0
  42. package/dist/gateway/static/root/assets/gateway-config-swr-jB0hAhWO.js +1 -0
  43. package/dist/gateway/static/root/assets/gateway-settings-BilR3dGZ.js +1 -0
  44. package/dist/gateway/static/root/assets/{gateway-startup-retry--2njcDpC.js → gateway-startup-retry-C-fRlHCL.js} +1 -1
  45. package/dist/gateway/static/root/assets/globe-DSSGFWFn.js +1 -0
  46. package/dist/gateway/static/root/assets/heartbeat-settings-zK40dcQ5.js +1 -0
  47. package/dist/gateway/static/root/assets/home-page-NyXy5MLr.js +3 -0
  48. package/dist/gateway/static/root/assets/index-Bp8I_eX4.css +1 -0
  49. package/dist/gateway/static/root/assets/index-CCK8zdlS.js +152 -0
  50. package/dist/gateway/static/root/assets/interaction-BmQogeqz.js +1 -0
  51. package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-HMhxgOuD.js → keyboard-shortcuts-settings-nKzsroud.js} +1 -1
  52. package/dist/gateway/static/root/assets/loader-circle-CifKLtgG.js +1 -0
  53. package/dist/gateway/static/root/assets/local-app-workbench-page-Ds3sPXTh.js +2 -0
  54. package/dist/gateway/static/root/assets/local-apps-page-DV1s_FYh.js +1 -0
  55. package/dist/gateway/static/root/assets/{locale-store-Bjvw7jtg.js → locale-store-xULEcFVs.js} +1 -1
  56. package/dist/gateway/static/root/assets/logs-page-Biz4eA02.js +2 -0
  57. package/dist/gateway/static/root/assets/management-settings-D7KjYgHu.js +1 -0
  58. package/dist/gateway/static/root/assets/{markdown-split-DvVBewS4.js → markdown-split-CTYbpkrd.js} +1 -1
  59. package/dist/gateway/static/root/assets/{media-plugins-YVj7NVzD.js → media-plugins-BXYnaiZ6.js} +1 -1
  60. package/dist/gateway/static/root/assets/messages-3qRsLZuX.js +3 -0
  61. package/dist/gateway/static/root/assets/{notes-page-BDzuL2I9.js → notes-page-CWWVXpw5.js} +1 -1
  62. package/dist/gateway/static/root/assets/notes-workbench-DnBkQihH.js +4 -0
  63. package/dist/gateway/static/root/assets/page-tabs-BaEQMYm_.js +1 -0
  64. package/dist/gateway/static/root/assets/popover-select-BzdnTy3h.js +1 -0
  65. package/dist/gateway/static/root/assets/preview-open-alternatives-pimQAkeI.js +1 -0
  66. package/dist/gateway/static/root/assets/{product-open-page-Bwx_CQht.js → product-open-page-BoYSS_YR.js} +1 -1
  67. package/dist/gateway/static/root/assets/project-detail-page-ZO7t1UkB.js +1 -0
  68. package/dist/gateway/static/root/assets/projects-page-By-vq41g.js +1 -0
  69. package/dist/gateway/static/root/assets/remote-access-hub-C0C_Y9d0.js +1 -0
  70. package/dist/gateway/static/root/assets/{runtime-tools-settings-panel-Fe05Nus6.js → runtime-tools-settings-panel-DT8flaX1.js} +4 -4
  71. package/dist/gateway/static/root/assets/schema-form-DabEP-UI.js +1 -0
  72. package/dist/gateway/static/root/assets/sessions-page-BNlVwUzV.js +1 -0
  73. package/dist/gateway/static/root/assets/settings-advanced-gate-CxYBQDaM.js +1 -0
  74. package/dist/gateway/static/root/assets/settings-form-draft-Dy10ldo8.js +1 -0
  75. package/dist/gateway/static/root/assets/settings-form-section-DCsfZAtC.js +1 -0
  76. package/dist/gateway/static/root/assets/{settings-loading-skeleton-BRE_-7Da.js → settings-loading-skeleton-Dac6Yd0T.js} +1 -1
  77. package/dist/gateway/static/root/assets/{settings-page-C1zxCpqB.js → settings-page-BDoYoEar.js} +1 -1
  78. package/dist/gateway/static/root/assets/settings-page-layout-BRQNel6r.js +1 -0
  79. package/dist/gateway/static/root/assets/settings-shell-dialog-layer-BU3UuiJr.js +1 -0
  80. package/dist/gateway/static/root/assets/setup-status-panel-DWijJ1rw.js +1 -0
  81. package/dist/gateway/static/root/assets/share-preview-page-ie9I2_7h.js +2 -0
  82. package/dist/gateway/static/root/assets/shares-settings-DU9VrJLf.js +1 -0
  83. package/dist/gateway/static/root/assets/skill-reload-api-C5RaIvoE.js +1 -0
  84. package/dist/gateway/static/root/assets/skills-page-N0YhaR5S.js +2 -0
  85. package/dist/gateway/static/root/assets/{skills-page.utils-CYwFWTso.js → skills-page.utils-C639DLXr.js} +1 -1
  86. package/dist/gateway/static/root/assets/system-settings-panel-CpshpQtC.js +1 -0
  87. package/dist/gateway/static/root/assets/task-detail-page-DsTocYkK.js +1 -0
  88. package/dist/gateway/static/root/assets/{theme-store-DtxpMC5S.js → theme-store-CHQRiuCF.js} +1 -1
  89. package/dist/gateway/static/root/assets/tool-activity-R8V9l6nk.js +1 -0
  90. package/dist/gateway/static/root/assets/typed-models-lib-q5-Vfqd8.js +1 -0
  91. package/dist/gateway/static/root/assets/use-autosave-ms6rDy59.js +1 -0
  92. package/dist/gateway/static/root/assets/user-context-page-BUxIemwy.js +1 -0
  93. package/dist/gateway/static/root/assets/voice-api-key-field-CObrQWh2.js +1 -0
  94. package/dist/gateway/static/root/assets/work-discovery-overlay-BBxrnEFt.js +1 -0
  95. package/dist/gateway/static/root/assets/work-discovery-page-DN3l-HW3.js +1 -0
  96. package/dist/gateway/static/root/assets/{workflow-run-setup-panel-DqIb1oBB.js → workflow-run-setup-panel-BxXhe3IV.js} +2 -2
  97. package/dist/gateway/static/root/assets/workflows-page-BCHkjd1i.js +5 -0
  98. package/dist/gateway/static/root/assets/working-directory-picker-modal-D-IgcHPp.js +1 -0
  99. package/dist/gateway/static/root/index.html +23 -8
  100. package/dist/package.js +1 -1
  101. package/dist/packages/gateway-contract/src/tasks.js +103 -9
  102. package/dist/src/agent/agent-manager.d.ts +1 -0
  103. package/dist/src/agent/agent-manager.js +1 -0
  104. package/dist/src/agent/context/execution-scope.js +3 -1
  105. package/dist/src/agent/service.js +1 -0
  106. package/dist/src/agent/service.types.d.ts +1 -0
  107. package/dist/src/agent/tasks/task-judge-service.d.ts +1 -1
  108. package/dist/src/agent/tasks/task-judge-service.js +3 -2
  109. package/dist/src/agent/tools/factory.d.ts +2 -0
  110. package/dist/src/agent/tools/factory.js +2 -1
  111. package/dist/src/agent/tools/xopc-use-tool.d.ts +1 -0
  112. package/dist/src/agent/tools/xopc-use-tool.js +69 -9
  113. package/dist/src/automations/domain/validation.d.ts +40 -12
  114. package/dist/src/automations/draft/automation-draft-validator.d.ts +4 -4
  115. package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
  116. package/dist/src/config/rules.js +2 -2
  117. package/dist/src/gateway/hono/app.d.ts +2 -0
  118. package/dist/src/gateway/hono/app.js +10 -3
  119. package/dist/src/gateway/hono/middleware/strict-rate-limit.d.ts +4 -0
  120. package/dist/src/gateway/hono/middleware/strict-rate-limit.js +8 -1
  121. package/dist/src/gateway/hono/routes/agent-stream.js +2 -74
  122. package/dist/src/gateway/hono/routes/config-patch/misc.js +2 -1
  123. package/dist/src/gateway/hono/routes/config.js +9 -0
  124. package/dist/src/gateway/hono/routes/deps.d.ts +1 -0
  125. package/dist/src/gateway/hono/routes/projects.js +55 -0
  126. package/dist/src/gateway/hono/routes/session-input-handler.d.ts +62 -0
  127. package/dist/src/gateway/hono/routes/session-input-handler.js +82 -0
  128. package/dist/src/gateway/hono/routes/tasks.js +272 -20
  129. package/dist/src/gateway/host.d.ts +9 -1
  130. package/dist/src/gateway/host.js +22 -5
  131. package/dist/src/gateway/rate-limit/buckets.d.ts +3 -0
  132. package/dist/src/gateway/rate-limit/buckets.js +12 -0
  133. package/dist/src/gateway/runtime-config.js +6 -5
  134. package/dist/src/gateway/security/audit.js +0 -7
  135. package/dist/src/gateway/server.js +4 -1
  136. package/dist/src/gateway/service/task-conversation-query-service.d.ts +58 -0
  137. package/dist/src/gateway/service/task-conversation-query-service.js +84 -0
  138. package/dist/src/gateway/service.d.ts +11 -0
  139. package/dist/src/gateway/service.js +75 -38
  140. package/dist/src/proactive/actions/service.d.ts +2 -0
  141. package/dist/src/proactive/actions/service.js +80 -0
  142. package/dist/src/proactive/execution/insight.js +20 -0
  143. package/dist/src/proactive/execution/repository.js +8 -2
  144. package/dist/src/proactive/execution/types.d.ts +14 -0
  145. package/dist/src/proactive/inbox/repository.js +59 -9
  146. package/dist/src/proactive/inbox/service.d.ts +2 -2
  147. package/dist/src/proactive/inbox/service.js +7 -2
  148. package/dist/src/proactive/inbox/types.d.ts +14 -0
  149. package/dist/src/proactive/inbox/worker.js +2 -0
  150. package/dist/src/proactive/scenarios/prompt-composer.js +2 -2
  151. package/dist/src/projects/project-agent.js +1 -1
  152. package/dist/src/storage/sqlite/migrations/118_task_board_rank.sql +6 -0
  153. package/dist/src/storage/sqlite/migrations/119_proactive_disposition.sql +13 -0
  154. package/dist/src/storage/sqlite/migrations/120_task_conversation.sql +112 -0
  155. package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
  156. package/dist/src/storage/sqlite/migrations/runner.js +3 -3
  157. package/dist/src/storage/sqlite/migrations/runner.ts +1 -1
  158. package/dist/src/storage/sqlite/schema.js +1 -1
  159. package/dist/src/tasks/execution-context.js +8 -4
  160. package/dist/src/tasks/home-query-service.d.ts +5 -0
  161. package/dist/src/tasks/home-query-service.js +7 -2
  162. package/dist/src/tasks/index.d.ts +3 -0
  163. package/dist/src/tasks/index.js +6 -3
  164. package/dist/src/tasks/project-monitoring-service.d.ts +9 -0
  165. package/dist/src/tasks/project-monitoring-service.js +41 -3
  166. package/dist/src/tasks/project-operating-view-service.d.ts +1 -2
  167. package/dist/src/tasks/project-operating-view-service.js +26 -23
  168. package/dist/src/tasks/task-application-service.js +107 -21
  169. package/dist/src/tasks/task-change-events.d.ts +13 -0
  170. package/dist/src/tasks/task-change-events.js +29 -0
  171. package/dist/src/tasks/task-context-assembler.js +9 -4
  172. package/dist/src/tasks/task-context-repository.d.ts +0 -6
  173. package/dist/src/tasks/task-context-repository.js +0 -4
  174. package/dist/src/tasks/task-conversation-repository.d.ts +71 -0
  175. package/dist/src/tasks/task-conversation-repository.js +194 -0
  176. package/dist/src/tasks/task-handoff-service.d.ts +31 -0
  177. package/dist/src/tasks/task-handoff-service.js +143 -0
  178. package/dist/src/tasks/task-read-model-projector.js +3 -6
  179. package/dist/src/tasks/task-repository.d.ts +7 -2
  180. package/dist/src/tasks/task-repository.js +31 -15
  181. package/dist/src/tasks/task-run-coordinator.js +3 -1
  182. package/dist/src/tunnel/enable-lan-pairing.js +15 -26
  183. package/dist/src/tunnel/pair-context.js +1 -1
  184. package/dist/src/tunnel/pair-url.js +1 -1
  185. package/dist/src/tunnel/tunnel-qr.d.ts +0 -7
  186. package/dist/src/tunnel/tunnel-qr.js +2 -19
  187. package/dist/src/workflows/service/workflow-run-service.js +4 -2
  188. package/package.json +5 -3
  189. package/dist/gateway/static/root/assets/agents-Baxfj44y.js +0 -68
  190. package/dist/gateway/static/root/assets/app-management-settings-panel-S8LhoD6G.js +0 -1
  191. package/dist/gateway/static/root/assets/appearance-settings-D8Cd5vDP.js +0 -1
  192. package/dist/gateway/static/root/assets/apps-page-0uCxKyE5.js +0 -1
  193. package/dist/gateway/static/root/assets/automations-page-XyDat125.js +0 -6
  194. package/dist/gateway/static/root/assets/browser-settings-page-CrYNMR4w.js +0 -8
  195. package/dist/gateway/static/root/assets/browser-workflow-inputs-Abil4puY.js +0 -1
  196. package/dist/gateway/static/root/assets/capabilities-settings-panel-CvMcDhGf.js +0 -7
  197. package/dist/gateway/static/root/assets/capability-presets-settings-panel-CHJDY-Ih.js +0 -3
  198. package/dist/gateway/static/root/assets/channels-settings-Ds9BJbcY.js +0 -1
  199. package/dist/gateway/static/root/assets/channels-status-swr-DPaJSYX_.js +0 -1
  200. package/dist/gateway/static/root/assets/connectors-api-CgWjgPSI.js +0 -1
  201. package/dist/gateway/static/root/assets/connectors-page-NUs-Zf7F.js +0 -2
  202. package/dist/gateway/static/root/assets/cron-expression-ZdDBAoqA.js +0 -2
  203. package/dist/gateway/static/root/assets/dependency-picker-BGeB1jpn.js +0 -1
  204. package/dist/gateway/static/root/assets/desktop-pet-settings-CCjT1bdo.js +0 -1
  205. package/dist/gateway/static/root/assets/directory-picker-path-field-C-Te1QN3.js +0 -1
  206. package/dist/gateway/static/root/assets/extension-settings-page-BLSNdlgd.js +0 -1
  207. package/dist/gateway/static/root/assets/gateway-config-api-CQrf0k3D.js +0 -1
  208. package/dist/gateway/static/root/assets/gateway-settings-CvgH8IJI.js +0 -1
  209. package/dist/gateway/static/root/assets/heartbeat-settings-SPpnqbjl.js +0 -1
  210. package/dist/gateway/static/root/assets/home-page-BFoD6047.js +0 -3
  211. package/dist/gateway/static/root/assets/index-84ys9u-K.js +0 -152
  212. package/dist/gateway/static/root/assets/index-D-srnucP.css +0 -1
  213. package/dist/gateway/static/root/assets/local-app-workbench-page-D5uL2_Fd.js +0 -2
  214. package/dist/gateway/static/root/assets/local-apps-page-DIWkFa3g.js +0 -1
  215. package/dist/gateway/static/root/assets/logs-page--6v8qq6y.js +0 -2
  216. package/dist/gateway/static/root/assets/management-settings-DtEuS-kR.js +0 -1
  217. package/dist/gateway/static/root/assets/messages-DQ5X6cXp.js +0 -3
  218. package/dist/gateway/static/root/assets/notes-workbench-IdjuNXvH.js +0 -4
  219. package/dist/gateway/static/root/assets/page-tabs-7bSEWfSX.js +0 -1
  220. package/dist/gateway/static/root/assets/preview-open-alternatives-tgLbHgcV.js +0 -1
  221. package/dist/gateway/static/root/assets/project-detail-page-DnJXSuM4.js +0 -1
  222. package/dist/gateway/static/root/assets/projects-page-DckZKlBI.js +0 -1
  223. package/dist/gateway/static/root/assets/remote-access-hub-CfbUHBUH.js +0 -1
  224. package/dist/gateway/static/root/assets/schema-form-CFfyC4CB.js +0 -1
  225. package/dist/gateway/static/root/assets/sessions-page-BCfCh4My.js +0 -1
  226. package/dist/gateway/static/root/assets/settings-advanced-gate-Cbi4FvzO.js +0 -1
  227. package/dist/gateway/static/root/assets/settings-form-section-gEnEYT_3.js +0 -1
  228. package/dist/gateway/static/root/assets/settings-page-layout-CRpXF_05.js +0 -1
  229. package/dist/gateway/static/root/assets/setup-status-panel-BcHdpmFf.js +0 -1
  230. package/dist/gateway/static/root/assets/share-preview-page-DU8L68A5.js +0 -2
  231. package/dist/gateway/static/root/assets/shares-settings-kjTqH9yY.js +0 -1
  232. package/dist/gateway/static/root/assets/skill-reload-api-QAGpwzIM.js +0 -1
  233. package/dist/gateway/static/root/assets/skills-page-lE1-YRdK.js +0 -2
  234. package/dist/gateway/static/root/assets/system-settings-panel-CVDsiPKn.js +0 -1
  235. package/dist/gateway/static/root/assets/task-detail-page-DsM13-cy.js +0 -1
  236. package/dist/gateway/static/root/assets/typed-models-lib-DelyYgoc.js +0 -1
  237. package/dist/gateway/static/root/assets/use-autosave-C50Mq5yQ.js +0 -1
  238. package/dist/gateway/static/root/assets/user-context-page-D-VEOt2A.js +0 -1
  239. package/dist/gateway/static/root/assets/voice-api-key-field-DYfgTe3Y.js +0 -1
  240. package/dist/gateway/static/root/assets/work-discovery-overlay-DPbujsp3.js +0 -1
  241. package/dist/gateway/static/root/assets/work-discovery-page-D77opady.js +0 -1
  242. package/dist/gateway/static/root/assets/workflows-page-B9-PLmlX.js +0 -5
  243. package/dist/src/gateway/ensure-network-cors.d.ts +0 -3
  244. package/dist/src/gateway/ensure-network-cors.js +0 -23
@@ -0,0 +1,58 @@
1
+ import type { SessionTimelineItem } from '../../session/transcript-outline.js';
2
+ import { TaskConversationRepository } from '../../tasks/task-conversation-repository.js';
3
+ import type { GatewaySessionsApi } from './sessions-api.js';
4
+ export declare class TaskConversationQueryService {
5
+ #private;
6
+ private readonly sessions;
7
+ private readonly conversations;
8
+ constructor(sessions: Pick<GatewaySessionsApi, 'getMessagePage' | 'getTimeline'>, conversations?: Pick<TaskConversationRepository, 'listSessions'>);
9
+ getMessagePage(taskId: string, options: {
10
+ limit: number;
11
+ offset: number;
12
+ before?: number;
13
+ }): Promise<{
14
+ session: {
15
+ messages: import("../../session/types.js").Message[];
16
+ transcriptSummary?: import("../../session/types.js").SessionTranscriptSummary;
17
+ transcriptRows?: import("../../session/session-context-for-llm.js").TranscriptStoredRow[];
18
+ key: string;
19
+ name?: string;
20
+ status: import("../../session/types.js").SessionStatus;
21
+ tags: string[];
22
+ createdAt: string;
23
+ updatedAt: string;
24
+ lastAccessedAt: string;
25
+ messageCount: number;
26
+ estimatedTokens: number;
27
+ compactedCount: number;
28
+ lastFlushedAt?: string;
29
+ flushCount?: number;
30
+ sourceChannel: string;
31
+ sourceChatId: string;
32
+ customData?: Record<string, unknown>;
33
+ projectId?: string;
34
+ routing?: import("../../session/types.js").SessionRoutingMeta;
35
+ stats?: import("../../session/types.js").SessionStats;
36
+ sessionType: import("../../session/types.js").SessionType;
37
+ hiddenFromSessionList?: boolean;
38
+ parentSessionKey?: string;
39
+ workflowRunId?: string;
40
+ workflowDefinitionId?: string;
41
+ workflowAgentId?: string;
42
+ workflowAgentLabel?: string;
43
+ sessionId?: string;
44
+ cwd?: string;
45
+ sessionStartedAt?: string;
46
+ lastInteractionAt?: string;
47
+ };
48
+ pagination: {
49
+ nextBeforeCursor?: string;
50
+ before?: string;
51
+ total: number;
52
+ limit: number;
53
+ offset: number;
54
+ hasMore: boolean;
55
+ };
56
+ }>;
57
+ getTimeline(taskId: string): Promise<SessionTimelineItem[] | null>;
58
+ }
@@ -0,0 +1,84 @@
1
+ import { TaskConversationRepository } from "../../tasks/task-conversation-repository.js";
2
+ //#region src/gateway/service/task-conversation-query-service.ts
3
+ var TaskConversationQueryService = class {
4
+ constructor(sessions, conversations = new TaskConversationRepository()) {
5
+ this.sessions = sessions;
6
+ this.conversations = conversations;
7
+ }
8
+ async getMessagePage(taskId, options) {
9
+ const links = this.#executionSessions(taskId);
10
+ if (links.length === 0) return null;
11
+ const probes = await Promise.all(links.map((link) => this.sessions.getMessagePage(link.sessionKey, { limit: 1 })));
12
+ if (probes.some((page) => !page)) return null;
13
+ const pages = probes;
14
+ const total = pages.reduce((sum, page) => sum + page.pagination.total, 0);
15
+ const end = Math.min(total, Math.max(0, options.before ?? total - options.offset));
16
+ const start = Math.max(0, end - options.limit);
17
+ const messages = [];
18
+ let cursor = 0;
19
+ for (let index = 0; index < links.length; index += 1) {
20
+ const sessionTotal = pages[index].pagination.total;
21
+ const localStart = Math.max(0, start - cursor);
22
+ const localEnd = Math.min(sessionTotal, end - cursor);
23
+ if (localStart < localEnd) {
24
+ const page = await this.sessions.getMessagePage(links[index].sessionKey, {
25
+ offset: sessionTotal - localEnd,
26
+ limit: localEnd - localStart
27
+ });
28
+ if (!page) return null;
29
+ messages.push(...page.session.messages);
30
+ }
31
+ cursor += sessionTotal;
32
+ }
33
+ const activeIndex = links.findIndex((link) => link.status === "active");
34
+ return {
35
+ session: {
36
+ ...pages[activeIndex >= 0 ? activeIndex : pages.length - 1].session,
37
+ messages
38
+ },
39
+ pagination: {
40
+ total,
41
+ limit: options.limit,
42
+ offset: options.offset,
43
+ hasMore: start > 0,
44
+ ...options.before === void 0 ? {} : { before: String(end) },
45
+ ...start > 0 ? { nextBeforeCursor: String(start) } : {}
46
+ }
47
+ };
48
+ }
49
+ async getTimeline(taskId) {
50
+ const links = this.#executionSessions(taskId);
51
+ if (links.length === 0) return null;
52
+ const output = [];
53
+ let displayOffset = 0;
54
+ let turnOffset = 0;
55
+ for (const [index, link] of links.entries()) {
56
+ const [items, page] = await Promise.all([this.sessions.getTimeline(link.sessionKey), this.sessions.getMessagePage(link.sessionKey, { limit: 1 })]);
57
+ if (!items || !page) return null;
58
+ if (index > 0) output.push({
59
+ id: `assignment:${link.id}`,
60
+ kind: "branch",
61
+ title: link.agentId ? `Execution continued by ${link.agentId}` : "Execution continued",
62
+ timestamp: link.startedAt,
63
+ depth: 0,
64
+ turn: turnOffset,
65
+ displayIndex: displayOffset
66
+ });
67
+ output.push(...items.map((item) => ({
68
+ ...item,
69
+ id: `${link.id}:${item.id}`,
70
+ turn: item.turn + turnOffset,
71
+ ...item.displayIndex === void 0 ? {} : { displayIndex: item.displayIndex + displayOffset }
72
+ })));
73
+ displayOffset += page.pagination.total;
74
+ const highestTurn = items.reduce((max, item) => Math.max(max, item.turn), -1);
75
+ turnOffset += highestTurn + 1;
76
+ }
77
+ return output;
78
+ }
79
+ #executionSessions(taskId) {
80
+ return this.conversations.listSessions(taskId).filter((link) => link.role === "execution").sort((a, b) => a.assignmentEpoch - b.assignmentEpoch || a.startedAt - b.startedAt);
81
+ }
82
+ };
83
+ //#endregion
84
+ export { TaskConversationQueryService };
@@ -12,6 +12,7 @@ import { type ResolvedGatewayAuth } from './auth.js';
12
12
  import { ModelCatalogSyncService } from '../providers/model-catalog-sync-service.js';
13
13
  import { ProjectService } from '../projects/index.js';
14
14
  import { LocalAppService } from '../local-apps/index.js';
15
+ import { TaskConversationRepository } from '../tasks/task-conversation-repository.js';
15
16
  import { type BrowserRecipeService } from '../browser/recipes/index.js';
16
17
  import { listInsights, ProactiveEventService, ProactiveInboxService, ProactiveInboxWorker, ProactiveScenarioService, ProactiveTemporalWorker, ProactiveWorker } from '../proactive/index.js';
17
18
  import { GatewaySessionsApi } from './service/sessions-api.js';
@@ -120,6 +121,16 @@ export declare class GatewayService {
120
121
  private createTaskRunDispatcher;
121
122
  private createMobileNotificationService;
122
123
  dispatchTaskRuns(): void;
124
+ ensureTaskConversation(taskId: string, options?: {
125
+ runId?: string;
126
+ requestedAgentId?: string;
127
+ }): Promise<{
128
+ sessionKey: string;
129
+ agentId: string;
130
+ created: boolean;
131
+ conversation: ReturnType<TaskConversationRepository['requireState']>;
132
+ }>;
133
+ dispatchTaskEvents(): void;
123
134
  runAgent(...args: Parameters<GatewayAgentRunner['runAgent']>): ReturnType<GatewayAgentRunner['runAgent']>;
124
135
  submitSessionInput(...args: Parameters<GatewayAgentRunner['submitSessionInput']>): Promise<{
125
136
  ok: true;
@@ -19,19 +19,20 @@ import { loadConfig, saveConfig } from "../config/loader.js";
19
19
  import { prewarmModelRegistry } from "../providers/model-registry.js";
20
20
  import { init_providers, providers_exports } from "../providers/index.js";
21
21
  import { TaskRepository } from "../tasks/task-repository.js";
22
+ import { TaskConversationRepository } from "../tasks/task-conversation-repository.js";
22
23
  import { disposeAllSessionMcpRuntimes } from "../agent/mcp/bundle-mcp-runtime.js";
23
24
  import { resolveEffectiveGatewayPort } from "./host.js";
24
25
  import { AutomationService } from "../automations/service/automation-service.js";
25
26
  import { onAutomationProductEvent, publishAutomationProductEvent } from "../automations/product-events.js";
26
27
  import "../automations/index.js";
27
28
  import { ProjectService } from "../projects/project-service.js";
29
+ import { resolveProjectAgentId } from "../projects/project-agent.js";
28
30
  import "../projects/index.js";
29
31
  import { sanitizeTunnelConfig } from "../tunnel/tunnel-config.js";
30
32
  import { wireTunnelEventsToGateway } from "../tunnel/gateway-lifecycle.js";
31
33
  import { buckets } from "./rate-limit/buckets.js";
32
34
  import { isGatewayStrictSecurityEnabled } from "./rate-limit/env-flags.js";
33
35
  import "./rate-limit/index.js";
34
- import { TaskContextRepository } from "../tasks/task-context-repository.js";
35
36
  import { TaskApplicationService } from "../tasks/task-application-service.js";
36
37
  import { ProactiveScenarioService } from "../proactive/scenarios/service.js";
37
38
  import { TaskOutboxDispatcher } from "../tasks/task-outbox-dispatcher.js";
@@ -460,6 +461,7 @@ var GatewayService = class {
460
461
  getNotesService: () => this.notesService,
461
462
  getProjectService: () => this.projects,
462
463
  getLocalAppService: () => this.localApps,
464
+ dispatchTaskEvents: () => this.dispatchTaskEvents(),
463
465
  dispatchTaskRuns: () => this.dispatchTaskRuns(),
464
466
  getWorkflowRunService: () => this.createWorkflowRunService(),
465
467
  sourceContextResolver: async (binding) => {
@@ -540,42 +542,10 @@ var GatewayService = class {
540
542
  if (!this.taskRunDispatcher) this.taskRunDispatcher = new TaskRunDispatcher({
541
543
  workerId: "gateway-agent",
542
544
  ensureSession: async (taskId, runId, requestedAgentId) => {
543
- const task = new TaskRepository().require(taskId);
544
- const agentId = requestedAgentId || task.delegateAgentId || getDefaultAgentId(this.config);
545
- const peerId = `task-${sanitizeSegment(taskId) || Date.now()}`;
546
- const sessionKey = buildSessionKey({
547
- agentId,
548
- source: "webchat",
549
- accountId: "default",
550
- peerKind: "direct",
551
- peerId
552
- });
553
- if (!await this.sessionIndex.getSessionMetadata(sessionKey)) await this.sessionIndex.saveMessages(sessionKey, [], { metadata: {
554
- sourceChannel: "webchat",
555
- sourceChatId: `default:direct:${peerId}`,
556
- sessionType: "chat",
557
- routing: {
558
- agentId,
559
- source: "webchat",
560
- accountId: "default",
561
- peerKind: "direct",
562
- peerId
563
- },
564
- projectId: task.projectId,
565
- customData: {
566
- taskId,
567
- origin: "task",
568
- triggerKind: "user",
569
- taskRunId: runId
570
- }
571
- } });
572
- if (task.projectId) this.projects.attachSession(sessionKey, task.projectId);
573
- new TaskContextRepository().linkSession({
574
- taskId,
575
- sessionKey,
576
- role: "execution"
577
- });
578
- return sessionKey;
545
+ return (await this.ensureTaskConversation(taskId, {
546
+ runId,
547
+ requestedAgentId
548
+ })).sessionKey;
579
549
  },
580
550
  runAgent: async (runId, sessionKey, message) => {
581
551
  const stream = this.agentRunner.runAgent(message, "webchat", sessionKey, {
@@ -593,10 +563,77 @@ var GatewayService = class {
593
563
  }
594
564
  dispatchTaskRuns() {
595
565
  new TaskSignalService().tick();
596
- new TaskOutboxDispatcher(publishAutomationProductEvent).drain();
566
+ this.dispatchTaskEvents();
597
567
  this.createTaskRunDispatcher().dispatch();
598
568
  this.createWorkflowRunService().dispatchTaskRuns();
599
569
  }
570
+ async ensureTaskConversation(taskId, options = {}) {
571
+ const task = new TaskRepository().require(taskId);
572
+ const agentId = resolveProjectAgentId({
573
+ config: this.config,
574
+ projects: this.projects,
575
+ explicitAgentId: options.requestedAgentId ?? task.delegateAgentId,
576
+ projectId: task.projectId
577
+ });
578
+ const conversations = new TaskConversationRepository();
579
+ const active = conversations.getActiveSession(task.id);
580
+ if (active) {
581
+ if (active.agentId && active.agentId !== agentId) throw new Error("Task executor differs from the active conversation");
582
+ const conversation = conversations.activateExecutionSession({
583
+ taskId: task.id,
584
+ sessionKey: active.sessionKey,
585
+ agentId,
586
+ runId: options.runId
587
+ });
588
+ return {
589
+ sessionKey: active.sessionKey,
590
+ agentId,
591
+ created: false,
592
+ conversation
593
+ };
594
+ }
595
+ const peerId = `task-${sanitizeSegment(task.id) || Date.now()}`;
596
+ const sessionKey = buildSessionKey({
597
+ agentId,
598
+ source: "webchat",
599
+ accountId: "default",
600
+ peerKind: "direct",
601
+ peerId
602
+ });
603
+ if (!await this.sessionIndex.getSessionMetadata(sessionKey)) await this.sessionIndex.saveMessages(sessionKey, [], { metadata: {
604
+ sourceChannel: "webchat",
605
+ sourceChatId: `default:direct:${peerId}`,
606
+ sessionType: "chat",
607
+ routing: {
608
+ agentId,
609
+ source: "webchat",
610
+ accountId: "default",
611
+ peerKind: "direct",
612
+ peerId
613
+ },
614
+ projectId: task.projectId,
615
+ customData: {
616
+ origin: "task",
617
+ triggerKind: "user",
618
+ ...options.runId ? { taskRunId: options.runId } : {}
619
+ }
620
+ } });
621
+ if (task.projectId) this.projects.attachSession(sessionKey, task.projectId);
622
+ return {
623
+ sessionKey,
624
+ agentId,
625
+ created: true,
626
+ conversation: conversations.activateExecutionSession({
627
+ taskId: task.id,
628
+ sessionKey,
629
+ agentId,
630
+ runId: options.runId
631
+ })
632
+ };
633
+ }
634
+ dispatchTaskEvents() {
635
+ new TaskOutboxDispatcher(publishAutomationProductEvent).drain();
636
+ }
600
637
  runAgent(...args) {
601
638
  return this.agentRunner.runAgent(...args);
602
639
  }
@@ -0,0 +1,2 @@
1
+ export declare function executePendingProactiveActions(now?: Date): number;
2
+ export declare function resolveProactiveActionDecision(inboxItemId: string, choice: string, now?: Date): void;
@@ -0,0 +1,80 @@
1
+ import { getSqliteDatabase, runSqliteWriteTransaction } from "../../storage/sqlite/transaction.js";
2
+ import { TaskApplicationService } from "../../tasks/task-application-service.js";
3
+ //#region src/proactive/actions/service.ts
4
+ function projectIdFromAggregationKey(value) {
5
+ if (!value.startsWith("project:") || value.length === 8) throw new Error("Proactive action has no project scope");
6
+ return value.slice(8);
7
+ }
8
+ function executeClaimedAction(row, now = /* @__PURE__ */ new Date()) {
9
+ const action = JSON.parse(row.proposed_action_json);
10
+ try {
11
+ if (action.id !== "create_project_task") throw new Error(`Unsupported proactive action: ${action.id}`);
12
+ const result = new TaskApplicationService().create({
13
+ idempotencyKey: `proactive:${row.insight_id}:${action.id}`,
14
+ title: action.input.title,
15
+ projectId: projectIdFromAggregationKey(row.aggregation_key),
16
+ priority: "normal",
17
+ contract: {
18
+ objective: action.input.objective,
19
+ expectedOutputs: [],
20
+ acceptanceCriteria: [],
21
+ constraints: [],
22
+ approvalRequired: [],
23
+ assumptions: [],
24
+ risks: [],
25
+ acceptancePolicy: "manual",
26
+ outputDestinations: []
27
+ },
28
+ dependencies: [],
29
+ context: [],
30
+ authorityGrants: [],
31
+ activation: {
32
+ mode: "capture",
33
+ phase: "backlog"
34
+ }
35
+ }, {
36
+ kind: "system",
37
+ id: "proactive"
38
+ });
39
+ if (!result.ok) throw new Error(`Task creation failed: ${"reason" in result ? result.reason : "unknown"}`);
40
+ getSqliteDatabase().prepare(`UPDATE proactive_insights
41
+ SET action_status = 'completed', action_result_json = ?, action_error = NULL, action_updated_at = ?
42
+ WHERE insight_id = ? AND action_status = 'executing'`).run(JSON.stringify({ taskId: result.model.task.id }), now.toISOString(), row.insight_id);
43
+ } catch (error) {
44
+ getSqliteDatabase().prepare(`UPDATE proactive_insights
45
+ SET action_status = 'failed', action_error = ?, action_updated_at = ?
46
+ WHERE insight_id = ? AND action_status = 'executing'`).run(String(error instanceof Error ? error.message : error).slice(0, 2e3), now.toISOString(), row.insight_id);
47
+ }
48
+ }
49
+ function executePendingProactiveActions(now = /* @__PURE__ */ new Date()) {
50
+ const expired = (/* @__PURE__ */ new Date(now.getTime() - 5 * 6e4)).toISOString();
51
+ getSqliteDatabase().prepare(`UPDATE proactive_insights SET action_status = 'pending', action_updated_at = ?
52
+ WHERE action_status = 'executing' AND action_updated_at <= ?`).run(now.toISOString(), expired);
53
+ let executed = 0;
54
+ while (true) {
55
+ const row = runSqliteWriteTransaction((db) => {
56
+ const candidate = db.prepare(`SELECT x.insight_id, b.aggregation_key, x.proposed_action_json
57
+ FROM proactive_insights x
58
+ JOIN proactive_runs r ON r.run_id = x.run_id
59
+ JOIN proactive_signal_batches b ON b.batch_id = r.batch_id
60
+ WHERE x.action_status = 'pending' ORDER BY x.created_at LIMIT 1`).get();
61
+ if (!candidate) return void 0;
62
+ return db.prepare(`UPDATE proactive_insights SET action_status = 'executing', action_updated_at = ?
63
+ WHERE insight_id = ? AND action_status = 'pending'`).run(now.toISOString(), candidate.insight_id).changes === 1 ? candidate : void 0;
64
+ });
65
+ if (!row) return executed;
66
+ executeClaimedAction(row, now);
67
+ executed += 1;
68
+ }
69
+ }
70
+ function resolveProactiveActionDecision(inboxItemId, choice, now = /* @__PURE__ */ new Date()) {
71
+ const row = getSqliteDatabase().prepare(`SELECT x.insight_id, x.action_status
72
+ FROM proactive_inbox_items i JOIN proactive_insights x ON x.insight_id = i.insight_id
73
+ WHERE i.inbox_item_id = ?`).get(inboxItemId);
74
+ if (!row || row.action_status !== "approval_required") return;
75
+ getSqliteDatabase().prepare(`UPDATE proactive_insights SET action_status = ?, action_updated_at = ?
76
+ WHERE insight_id = ? AND action_status = 'approval_required'`).run(choice === "approve" ? "pending" : "rejected", now.toISOString(), row.insight_id);
77
+ if (choice === "approve") executePendingProactiveActions(now);
78
+ }
79
+ //#endregion
80
+ export { executePendingProactiveActions, resolveProactiveActionDecision };
@@ -30,6 +30,23 @@ function parseDecision(value) {
30
30
  options
31
31
  };
32
32
  }
33
+ function parseProposedAction(value) {
34
+ if (value == null) return void 0;
35
+ if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error("Insight proposedAction is invalid");
36
+ const row = value;
37
+ if (row.id !== "create_project_task" || row.risk !== "low") throw new Error("Insight proposedAction is not supported");
38
+ if (!row.input || typeof row.input !== "object" || Array.isArray(row.input)) throw new Error("Insight proposedAction input is invalid");
39
+ const input = row.input;
40
+ return {
41
+ id: "create_project_task",
42
+ risk: "low",
43
+ rationale: boundedText(row.rationale, "proposedAction rationale", 600),
44
+ input: {
45
+ title: boundedText(input.title, "proposedAction title", 160),
46
+ objective: boundedText(input.objective, "proposedAction objective", 1200)
47
+ }
48
+ };
49
+ }
33
50
  function parseInsightCandidate(raw, allowedEvidenceIds) {
34
51
  let value;
35
52
  try {
@@ -45,6 +62,8 @@ function parseInsightCandidate(raw, allowedEvidenceIds) {
45
62
  const evidenceIds = [...new Set(row.evidenceIds.map(String))];
46
63
  if (evidenceIds.some((id) => !allowedEvidenceIds.has(id))) throw new Error("Insight cites unknown evidence");
47
64
  const decision = parseDecision(row.decision);
65
+ const proposedAction = parseProposedAction(row.proposedAction);
66
+ if (proposedAction && (!decision || decision.options.length !== 2 || decision.options[0]?.id !== "approve" || decision.options[1]?.id !== "reject")) throw new Error("Insight proposedAction requires approve and reject decision options");
48
67
  return {
49
68
  title: boundedText(row.title, "title", 160),
50
69
  summary: boundedText(row.summary, "summary", 1200),
@@ -53,6 +72,7 @@ function parseInsightCandidate(raw, allowedEvidenceIds) {
53
72
  recommendation: boundedText(row.recommendation, "recommendation", 800),
54
73
  workDone: boundedText(row.workDone, "workDone", 800),
55
74
  ...decision ? { decision } : {},
75
+ ...proposedAction ? { proposedAction } : {},
56
76
  urgency: String(row.urgency),
57
77
  confidence: row.confidence,
58
78
  evidenceIds
@@ -96,9 +96,9 @@ function finishRun(input, now = /* @__PURE__ */ new Date()) {
96
96
  createdAt: nowIso
97
97
  };
98
98
  db.prepare(`INSERT INTO proactive_insights (insight_id, run_id, subscription_id, scenario_key, title, summary,
99
- why_now, impact, recommendation, work_done, decision_json, urgency, confidence, value_score,
99
+ why_now, impact, recommendation, work_done, decision_json, proposed_action_json, urgency, confidence, value_score,
100
100
  evidence_ids_json, content_fingerprint, created_at)
101
- 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), fingerprint, insight.createdAt);
101
+ 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.proposedAction ? JSON.stringify(insight.proposedAction) : null, insight.urgency, insight.confidence, insight.valueScore, JSON.stringify(insight.evidenceIds), fingerprint, insight.createdAt);
102
102
  return insight;
103
103
  });
104
104
  }
@@ -124,9 +124,15 @@ function listInsights(limit = 50) {
124
124
  recommendation: str(row, "recommendation"),
125
125
  workDone: str(row, "work_done"),
126
126
  ...row.decision_json ? { decision: JSON.parse(str(row, "decision_json")) } : {},
127
+ ...row.proposed_action_json ? { proposedAction: JSON.parse(str(row, "proposed_action_json")) } : {},
127
128
  urgency: str(row, "urgency"),
128
129
  confidence: Number(row.confidence),
129
130
  valueScore: Number(row.value_score),
131
+ ...row.disposition ? { disposition: str(row, "disposition") } : {},
132
+ ...row.disposition_reason ? { dispositionReason: str(row, "disposition_reason") } : {},
133
+ ...row.action_status ? { actionStatus: str(row, "action_status") } : {},
134
+ ...row.action_result_json ? { actionResult: JSON.parse(str(row, "action_result_json")) } : {},
135
+ ...row.action_error ? { actionError: str(row, "action_error") } : {},
130
136
  evidenceIds: JSON.parse(str(row, "evidence_ids_json")),
131
137
  createdAt: str(row, "created_at")
132
138
  }));
@@ -20,6 +20,15 @@ export interface InsightCandidate {
20
20
  consequence: string;
21
21
  }>;
22
22
  };
23
+ proposedAction?: {
24
+ id: 'create_project_task';
25
+ risk: 'low';
26
+ rationale: string;
27
+ input: {
28
+ title: string;
29
+ objective: string;
30
+ };
31
+ };
23
32
  urgency: 'low' | 'medium' | 'high' | 'critical';
24
33
  confidence: number;
25
34
  evidenceIds: string[];
@@ -30,6 +39,11 @@ export interface ProactiveInsight extends InsightCandidate {
30
39
  subscriptionId: string;
31
40
  scenarioKey: string;
32
41
  valueScore: number;
42
+ disposition?: 'record_silently' | 'show_in_work' | 'request_approval' | 'auto_execute';
43
+ dispositionReason?: string;
44
+ actionStatus?: 'not_authorized' | 'approval_required' | 'pending' | 'executing' | 'completed' | 'rejected' | 'failed';
45
+ actionResult?: Record<string, unknown>;
46
+ actionError?: string;
33
47
  createdAt: string;
34
48
  }
35
49
  export interface ProactiveAgentExecutor {
@@ -1,4 +1,5 @@
1
1
  import { getSqliteDatabase, runSqliteWriteTransaction } from "../../storage/sqlite/transaction.js";
2
+ import { decideProactiveDisposition, nextQuietHoursEnd, proactiveDispositionReason } from "../../tasks/project-monitoring-service.js";
2
3
  import { randomUUID } from "node:crypto";
3
4
  //#region src/proactive/inbox/repository.ts
4
5
  const s = (row, key) => String(row[key]);
@@ -20,6 +21,12 @@ function itemFromRow(row) {
20
21
  recommendation: s(row, "recommendation"),
21
22
  workDone: s(row, "work_done"),
22
23
  ...row.decision_json ? { decision: JSON.parse(s(row, "decision_json")) } : {},
24
+ ...row.proposed_action_json ? { proposedAction: JSON.parse(s(row, "proposed_action_json")) } : {},
25
+ disposition: s(row, "disposition"),
26
+ dispositionReason: s(row, "disposition_reason"),
27
+ ...row.action_status ? { actionStatus: s(row, "action_status") } : {},
28
+ ...row.action_result_json ? { actionResult: JSON.parse(s(row, "action_result_json")) } : {},
29
+ ...row.action_error ? { actionError: s(row, "action_error") } : {},
23
30
  urgency: s(row, "urgency"),
24
31
  confidence: Number(row.confidence),
25
32
  valueScore: Number(row.value_score),
@@ -28,27 +35,70 @@ function itemFromRow(row) {
28
35
  };
29
36
  }
30
37
  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
38
+ x.work_done, x.decision_json, x.proposed_action_json, x.disposition, x.disposition_reason,
39
+ x.action_status, x.action_result_json, x.action_error, x.urgency, x.confidence, x.value_score, x.evidence_ids_json FROM proactive_inbox_items i
32
40
  JOIN proactive_insights x ON x.insight_id = i.insight_id`;
33
41
  function projectInsightsToInbox(now = /* @__PURE__ */ new Date()) {
34
42
  return runSqliteWriteTransaction((db) => {
35
- const missing = db.prepare(`SELECT x.insight_id FROM proactive_insights x
43
+ const missing = db.prepare(`SELECT x.insight_id, x.confidence, x.value_score, x.decision_json,
44
+ x.proposed_action_json, b.aggregation_key, p.project_id, p.mode, p.quiet_hours_json,
45
+ p.allowed_actions_json, p.confidence_threshold FROM proactive_insights x
36
46
  JOIN proactive_runs r ON r.run_id = x.run_id
37
47
  JOIN proactive_signal_batches b ON b.batch_id = r.batch_id
38
48
  LEFT JOIN project_monitoring_policies p
39
49
  ON b.aggregation_key = 'project:' || p.project_id
40
- WHERE x.insight_id NOT IN (SELECT insight_id FROM proactive_inbox_items)
41
- AND (p.project_id IS NULL OR (p.mode != 'observe' AND x.confidence >= p.confidence_threshold))
42
- ORDER BY x.created_at`).all();
50
+ WHERE x.disposition IS NULL ORDER BY x.created_at`).all();
51
+ let projected = 0;
43
52
  for (const row of missing) {
44
- const id = randomUUID();
53
+ const aggregationKey = String(row.aggregation_key);
54
+ const projectId = aggregationKey.startsWith("project:") ? aggregationKey.slice(8) : void 0;
55
+ const policy = projectId ? row.project_id ? {
56
+ projectId,
57
+ mode: String(row.mode),
58
+ ...row.quiet_hours_json ? { quietHours: JSON.parse(String(row.quiet_hours_json)) } : {},
59
+ allowedActions: JSON.parse(String(row.allowed_actions_json)),
60
+ confidenceThreshold: Number(row.confidence_threshold),
61
+ scenarios: [],
62
+ configured: true
63
+ } : {
64
+ projectId,
65
+ mode: "observe",
66
+ allowedActions: [],
67
+ confidenceThreshold: .75,
68
+ scenarios: [],
69
+ configured: false
70
+ } : {
71
+ projectId: "",
72
+ mode: "ask_before_action",
73
+ allowedActions: [],
74
+ confidenceThreshold: 0,
75
+ scenarios: [],
76
+ configured: false
77
+ };
78
+ const action = row.proposed_action_json ? JSON.parse(String(row.proposed_action_json)) : void 0;
79
+ const dispositionInput = {
80
+ confidence: Number(row.confidence),
81
+ valueScore: Number(row.value_score),
82
+ risk: action?.risk ?? "low",
83
+ ...action ? { actionId: action.id } : {},
84
+ requiresApproval: !action && Boolean(row.decision_json)
85
+ };
86
+ const disposition = action && !projectId ? "show_in_work" : decideProactiveDisposition(policy, dispositionInput);
87
+ const reason = action && !projectId ? "Proposed project action cannot run outside a project scope" : proactiveDispositionReason(policy, dispositionInput, disposition);
88
+ const actionStatus = action ? disposition === "auto_execute" ? "pending" : disposition === "request_approval" ? "approval_required" : disposition === "show_in_work" ? "not_authorized" : null : null;
45
89
  const nowIso = now.toISOString();
90
+ db.prepare(`UPDATE proactive_insights SET disposition = ?, disposition_reason = ?, action_status = ?,
91
+ disposition_at = ?, action_updated_at = ? WHERE insight_id = ? AND disposition IS NULL`).run(disposition, reason, actionStatus, nowIso, actionStatus ? nowIso : null, String(row.insight_id));
92
+ if (disposition === "record_silently") continue;
93
+ const id = randomUUID();
46
94
  db.prepare(`INSERT INTO proactive_inbox_items (inbox_item_id, insight_id, status, created_at, updated_at)
47
- VALUES (?, ?, 'unread', ?, ?)`).run(id, row.insight_id, nowIso, nowIso);
95
+ VALUES (?, ?, 'unread', ?, ?)`).run(id, String(row.insight_id), nowIso, nowIso);
96
+ const nextAttemptAt = nextQuietHoursEnd(policy.quietHours, now)?.toISOString() ?? nowIso;
48
97
  db.prepare(`INSERT INTO proactive_delivery_outbox (delivery_id, inbox_item_id, status, attempt, next_attempt_at, created_at, updated_at)
49
- VALUES (?, ?, 'pending', 0, ?, ?, ?)`).run(randomUUID(), id, nowIso, nowIso, nowIso);
98
+ VALUES (?, ?, 'pending', 0, ?, ?, ?)`).run(randomUUID(), id, nextAttemptAt, nowIso, nowIso);
99
+ projected += 1;
50
100
  }
51
- return missing.length;
101
+ return projected;
52
102
  });
53
103
  }
54
104
  function wakeSnoozedItems(now = /* @__PURE__ */ new Date()) {
@@ -1,11 +1,11 @@
1
- import { listInbox, projectInsightsToInbox, recordDecision, recordFeedback, wakeSnoozedItems } from './repository.js';
1
+ import { listInbox, projectInsightsToInbox, recordFeedback, wakeSnoozedItems } from './repository.js';
2
2
  import type { InboxStatus } from './types.js';
3
3
  export declare class ProactiveInboxService {
4
4
  list: typeof listInbox;
5
5
  project: typeof projectInsightsToInbox;
6
6
  wakeSnoozed: typeof wakeSnoozedItems;
7
- decide: typeof recordDecision;
8
7
  feedback: typeof recordFeedback;
8
+ decide(id: string, choice: string, note?: string): import("./types.js").InboxItem;
9
9
  instruct(id: string, instruction: string): {
10
10
  revisionId: string;
11
11
  };
@@ -1,12 +1,17 @@
1
1
  import { publishInstructionFeedback } from "../scenarios/repository.js";
2
- import { getInboxSubscriptionId, listInbox, projectInsightsToInbox, recordDecision, recordFeedback, transitionInboxItem, wakeSnoozedItems } from "./repository.js";
2
+ import { resolveProactiveActionDecision } from "../actions/service.js";
3
+ import { getInboxItem, getInboxSubscriptionId, listInbox, projectInsightsToInbox, recordDecision, recordFeedback, transitionInboxItem, wakeSnoozedItems } from "./repository.js";
3
4
  //#region src/proactive/inbox/service.ts
4
5
  var ProactiveInboxService = class {
5
6
  list = listInbox;
6
7
  project = projectInsightsToInbox;
7
8
  wakeSnoozed = wakeSnoozedItems;
8
- decide = recordDecision;
9
9
  feedback = recordFeedback;
10
+ decide(id, choice, note = "") {
11
+ const item = recordDecision(id, choice, note);
12
+ resolveProactiveActionDecision(id, choice);
13
+ return getInboxItem(id) ?? item;
14
+ }
10
15
  instruct(id, instruction) {
11
16
  return { revisionId: publishInstructionFeedback({
12
17
  subscriptionId: getInboxSubscriptionId(id),
@@ -23,6 +23,20 @@ export interface InboxItem {
23
23
  consequence: string;
24
24
  }>;
25
25
  };
26
+ proposedAction?: {
27
+ id: 'create_project_task';
28
+ risk: 'low';
29
+ rationale: string;
30
+ input: {
31
+ title: string;
32
+ objective: string;
33
+ };
34
+ };
35
+ disposition: 'show_in_work' | 'request_approval' | 'auto_execute';
36
+ dispositionReason: string;
37
+ actionStatus?: 'not_authorized' | 'approval_required' | 'pending' | 'executing' | 'completed' | 'rejected' | 'failed';
38
+ actionResult?: Record<string, unknown>;
39
+ actionError?: string;
26
40
  urgency: 'low' | 'medium' | 'high' | 'critical';
27
41
  confidence: number;
28
42
  valueScore: number;