@xopcai/xopc 0.0.160 → 0.0.162

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 (248) 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-hpcNv9MZ.js +1 -0
  4. package/dist/gateway/static/root/assets/{agent-avatar-dicebear-B_27aaZQ.js → agent-avatar-dicebear-Zf9UQEmQ.js} +1 -1
  5. package/dist/gateway/static/root/assets/agents-DfVkZlHc.js +2 -0
  6. package/dist/gateway/static/root/assets/{api-BbzB57CJ.js → api-Dnatri09.js} +1 -1
  7. package/dist/gateway/static/root/assets/{app-management-settings-panel-DfmyWcyh.js → app-management-settings-panel-BBTR9wJP.js} +1 -1
  8. package/dist/gateway/static/root/assets/{appearance-settings-B2v0c-K-.js → appearance-settings-C2zpLCHD.js} +1 -1
  9. package/dist/gateway/static/root/assets/apps-page-BMtAa4Ra.js +1 -0
  10. package/dist/gateway/static/root/assets/{archive-plugin-DL5Lnx0C.js → archive-plugin-9eR_ODY1.js} +1 -1
  11. package/dist/gateway/static/root/assets/{attachment-load-InuP-ZjQ.js → attachment-load-DPuWYUeX.js} +1 -1
  12. package/dist/gateway/static/root/assets/{automation-suggestion-card-CahGuh7B.js → automation-suggestion-card-Dw49OJRl.js} +1 -1
  13. package/dist/gateway/static/root/assets/automations-page-BiSAMYTr.js +6 -0
  14. package/dist/gateway/static/root/assets/{binary-plugins-CdOTGYVu.js → binary-plugins-BdkJpDFm.js} +1 -1
  15. package/dist/gateway/static/root/assets/{block-editor-D6ShK1S-.js → block-editor-CAi7SXYU.js} +47 -47
  16. package/dist/gateway/static/root/assets/browser-settings-page-DHmaEJS2.js +8 -0
  17. package/dist/gateway/static/root/assets/browser-workflow-inputs-Dx6wkGz1.js +1 -0
  18. package/dist/gateway/static/root/assets/browser-workflows-page-Skertc-A.js +3 -0
  19. package/dist/gateway/static/root/assets/capabilities-settings-panel-B5wSgf4f.js +2 -0
  20. package/dist/gateway/static/root/assets/{capability-presets-api-BzoLm52Z.js → capability-presets-api-CNFl7dM3.js} +1 -1
  21. package/dist/gateway/static/root/assets/capability-presets-settings-panel-DyvFZwBj.js +2 -0
  22. package/dist/gateway/static/root/assets/{channel-recipient-api-DbgydMjl.js → channel-recipient-api-DYQyGDw4.js} +1 -1
  23. package/dist/gateway/static/root/assets/channels-settings-BBKEqDZn.js +1 -0
  24. package/dist/gateway/static/root/assets/channels-status-swr-Drk110ve.js +1 -0
  25. package/dist/gateway/static/root/assets/check-DUBLcKHA.js +1 -0
  26. package/dist/gateway/static/root/assets/circle-alert-BEjgurr2.js +1 -0
  27. package/dist/gateway/static/root/assets/cn-JdwAhgNB.js +1 -0
  28. package/dist/gateway/static/root/assets/{connector-logo-C3bJC9nt.js → connector-logo-Bng6kxYF.js} +1 -1
  29. package/dist/gateway/static/root/assets/connectors-page-HpgaUDQ1.js +2 -0
  30. package/dist/gateway/static/root/assets/createLucideIcon-DPHK1VkS.js +1 -0
  31. package/dist/gateway/static/root/assets/desktop-pet-Bpf6oegd.js +1 -0
  32. package/dist/gateway/static/root/assets/{desktop-pet-settings-BrHVvbBw.js → desktop-pet-settings-BVUyefSd.js} +1 -1
  33. package/dist/gateway/static/root/assets/{desktop-pet-sprite-CFd1jGLJ.js → desktop-pet-sprite-DTqXSpqf.js} +1 -1
  34. package/dist/gateway/static/root/assets/{directory-picker-path-field-BPI969w-.js → directory-picker-path-field-DjSZAPz_.js} +1 -1
  35. package/dist/gateway/static/root/assets/{dreaming-settings-iw6QXD45.js → dreaming-settings-CAZk2AM4.js} +3 -3
  36. package/dist/gateway/static/root/assets/{extension-debug-page-rCHyhEr6.js → extension-debug-page-C2F6vTTd.js} +1 -1
  37. package/dist/gateway/static/root/assets/{extension-page-C4gQsAPt.js → extension-page-AnIt4bn4.js} +1 -1
  38. package/dist/gateway/static/root/assets/{extension-settings-page-DB_3eik7.js → extension-settings-page-CLSc6682.js} +1 -1
  39. package/dist/gateway/static/root/assets/{gateway-config-api-Cdt38iF2.js → gateway-config-api-DLFyZv33.js} +1 -1
  40. package/dist/gateway/static/root/assets/{gateway-settings-DM4BgyGw.js → gateway-settings-DnQAA-qq.js} +1 -1
  41. package/dist/gateway/static/root/assets/{gateway-startup-retry-ChRFNjj_.js → gateway-startup-retry-DbzLyJ3R.js} +1 -1
  42. package/dist/gateway/static/root/assets/goal-create-dialog-DrnKFC6M.js +1 -0
  43. package/dist/gateway/static/root/assets/goal-detail-page-Cw1hpJkZ.js +4 -0
  44. package/dist/gateway/static/root/assets/{goals-config-api-RvljeEm6.js → goals-config-api-REmr3QCr.js} +1 -1
  45. package/dist/gateway/static/root/assets/goals-page-BDGkTVma.js +2 -0
  46. package/dist/gateway/static/root/assets/{goals-settings-DMGV4S4L.js → goals-settings-Dz0F3uRO.js} +1 -1
  47. package/dist/gateway/static/root/assets/{heartbeat-settings-B8r5EXc5.js → heartbeat-settings-CQFY5gYs.js} +1 -1
  48. package/dist/gateway/static/root/assets/index-C8JkTS6d.js +199 -0
  49. package/dist/gateway/static/root/assets/index-hmrG55qg.css +1 -0
  50. package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-1-LYibQ4.js → keyboard-shortcuts-settings-BnOQXU5k.js} +1 -1
  51. package/dist/gateway/static/root/assets/local-app-workbench-page-Bdef1b7F.js +2 -0
  52. package/dist/gateway/static/root/assets/{local-apps-page-CC4vtUUI.js → local-apps-page-KsOtWOyM.js} +1 -1
  53. package/dist/gateway/static/root/assets/{locale-store-CPbGB_6l.js → locale-store-0lpYdNDr.js} +1 -1
  54. package/dist/gateway/static/root/assets/{logs-page-Bn_taxBV.js → logs-page-CwLPgrWh.js} +3 -3
  55. package/dist/gateway/static/root/assets/{markdown-split-CprEIf8A.js → markdown-split-D5GRg10r.js} +1 -1
  56. package/dist/gateway/static/root/assets/{media-plugins-BXt_Sj2O.js → media-plugins-C1ryULGs.js} +1 -1
  57. package/dist/gateway/static/root/assets/messages-BwQ3WssU.js +5 -0
  58. package/dist/gateway/static/root/assets/{notes-page-Wf5-eyyM.js → notes-page-CIeZ1_DT.js} +1 -1
  59. package/dist/gateway/static/root/assets/notes-workbench-Cf06q19x.js +4 -0
  60. package/dist/gateway/static/root/assets/{page-tabs-dtpK_4Fs.js → page-tabs-Caj1-E_X.js} +1 -1
  61. package/dist/gateway/static/root/assets/{preview-open-alternatives-DijtEVxG.js → preview-open-alternatives-DKwEce-9.js} +1 -1
  62. package/dist/gateway/static/root/assets/product-delivery-BTRT9kCS.js +1 -0
  63. package/dist/gateway/static/root/assets/product-open-page-B90ZskkN.js +1 -0
  64. package/dist/gateway/static/root/assets/project-detail-page-SHTurM4t.js +1 -0
  65. package/dist/gateway/static/root/assets/projects-page-BcC2qUAw.js +1 -0
  66. package/dist/gateway/static/root/assets/remote-access-hub-6vGefBHv.js +1 -0
  67. package/dist/gateway/static/root/assets/save-bar-controls-BDYt53uQ.js +1 -0
  68. package/dist/gateway/static/root/assets/{schedule-field-AhJ50NoT.js → schedule-field-Bcdni4Pj.js} +1 -1
  69. package/dist/gateway/static/root/assets/{schema-form-AuJg2CXU.js → schema-form-D7oCARF7.js} +1 -1
  70. package/dist/gateway/static/root/assets/sessions-page-C5014a53.js +1 -0
  71. package/dist/gateway/static/root/assets/settings-advanced-gate-CDY3ZI1K.js +1 -0
  72. package/dist/gateway/static/root/assets/{settings-collapsible-section-D5ganr_X.js → settings-collapsible-section-6eNF8Jey.js} +1 -1
  73. package/dist/gateway/static/root/assets/{settings-form-section-Db3cKRsg.js → settings-form-section-CARTHCxH.js} +1 -1
  74. package/dist/gateway/static/root/assets/{settings-loading-skeleton-D05YKT2x.js → settings-loading-skeleton-DEwYqESe.js} +1 -1
  75. package/dist/gateway/static/root/assets/settings-page-B6vVdHeQ.js +1 -0
  76. package/dist/gateway/static/root/assets/{settings-page-layout-Cv_Cu4I5.js → settings-page-layout-D3srt5Bi.js} +1 -1
  77. package/dist/gateway/static/root/assets/setup-status-panel-z-rF0Hdg.js +1 -0
  78. package/dist/gateway/static/root/assets/{share-preview-page-CYkZVuse.js → share-preview-page-Ck9SxiXw.js} +1 -1
  79. package/dist/gateway/static/root/assets/shares-settings-CHZFXE_d.js +1 -0
  80. package/dist/gateway/static/root/assets/skill-reload-api-B7p2QNXt.js +1 -0
  81. package/dist/gateway/static/root/assets/skills-page-ncw3tX9P.js +2 -0
  82. package/dist/gateway/static/root/assets/{system-settings-panel-C1Ng5bXh.js → system-settings-panel-DLBUQSk2.js} +1 -1
  83. package/dist/gateway/static/root/assets/{theme-store-LMHIDR9n.js → theme-store-C1oaqeD2.js} +1 -1
  84. package/dist/gateway/static/root/assets/{typed-models-lib-Ch2Bdm_5.js → typed-models-lib-Divbg_C4.js} +1 -1
  85. package/dist/gateway/static/root/assets/{use-channel-catalog-CZnaMOeL.js → use-channel-catalog-CP9a_rAf.js} +1 -1
  86. package/dist/gateway/static/root/assets/user-context-page-iYfeSLKI.js +1 -0
  87. package/dist/gateway/static/root/assets/voice-api-key-field-CrwkicvT.js +1 -0
  88. package/dist/gateway/static/root/assets/work-discovery-page-BQWxyPg8.js +1 -0
  89. package/dist/gateway/static/root/assets/work-item-detail-page-50ZzGay5.js +1 -0
  90. package/dist/gateway/static/root/assets/work-page-DPqEahx7.js +1 -0
  91. package/dist/gateway/static/root/assets/{workflow-run-setup-panel-BFk8TvTw.js → workflow-run-setup-panel-DbDPYQwB.js} +2 -2
  92. package/dist/gateway/static/root/assets/workflows-page-C3eIC5HZ.js +11 -0
  93. package/dist/gateway/static/root/index.html +12 -10
  94. package/dist/package.js +1 -1
  95. package/dist/src/agent/agent-manager.d.ts +1 -0
  96. package/dist/src/agent/agent-manager.js +1 -0
  97. package/dist/src/agent/client-error-format.js +3 -3
  98. package/dist/src/agent/outcomes/task-evaluation.d.ts +20 -0
  99. package/dist/src/agent/outcomes/task-evaluation.js +48 -0
  100. package/dist/src/agent/outcomes/task-verifier.d.ts +29 -0
  101. package/dist/src/agent/outcomes/task-verifier.js +71 -0
  102. package/dist/src/agent/prompt/memory/index.js +1 -1
  103. package/dist/src/agent/prompt/service-prompt-builder.js +32 -1
  104. package/dist/src/agent/service.js +1 -0
  105. package/dist/src/agent/service.types.d.ts +1 -0
  106. package/dist/src/agent/tools/browser/tool/browser-use-tool.d.ts +1 -7
  107. package/dist/src/agent/tools/browser/tool/browser-use-tool.js +2 -73
  108. package/dist/src/agent/tools/browser/tool/schemas.d.ts +1 -13
  109. package/dist/src/agent/tools/browser/tool/schemas.js +1 -9
  110. package/dist/src/agent/tools/browser-recipe-tool.d.ts +12 -0
  111. package/dist/src/agent/tools/browser-recipe-tool.js +113 -0
  112. package/dist/src/agent/tools/factory.d.ts +2 -0
  113. package/dist/src/agent/tools/factory.js +2 -0
  114. package/dist/src/agent/tools/index.d.ts +1 -0
  115. package/dist/src/agent/tools/index.js +2 -1
  116. package/dist/src/automations/domain/types.d.ts +13 -0
  117. package/dist/src/automations/domain/validation.d.ts +44 -24
  118. package/dist/src/automations/domain/validation.js +27 -18
  119. package/dist/src/automations/draft/automation-draft-validator.d.ts +6 -1
  120. package/dist/src/automations/draft/automation-draft-validator.js +1 -0
  121. package/dist/src/automations/service/action-executor.d.ts +1 -0
  122. package/dist/src/automations/service/action-executor.js +22 -0
  123. package/dist/src/browser/index.d.ts +0 -1
  124. package/dist/src/browser/index.js +1 -2
  125. package/dist/src/browser/pipeline/runner.d.ts +9 -2
  126. package/dist/src/browser/pipeline/runner.js +151 -105
  127. package/dist/src/browser/pipeline/schema.d.ts +21 -15
  128. package/dist/src/browser/pipeline/schema.js +93 -99
  129. package/dist/src/browser/recipes/index.d.ts +3 -0
  130. package/dist/src/browser/recipes/index.js +3 -0
  131. package/dist/src/browser/recipes/repository.d.ts +13 -0
  132. package/dist/src/browser/recipes/repository.js +81 -0
  133. package/dist/src/browser/recipes/runtime-service.d.ts +6 -0
  134. package/dist/src/browser/recipes/runtime-service.js +30 -0
  135. package/dist/src/browser/recipes/service.d.ts +36 -0
  136. package/dist/src/browser/recipes/service.js +186 -0
  137. package/dist/src/browser/recipes/types.d.ts +36 -0
  138. package/dist/src/browser/recipes/types.js +1 -0
  139. package/dist/src/cli/commands/browser-cli-helpers.js +6 -12
  140. package/dist/src/cli/commands/browser.js +4 -3
  141. package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
  142. package/dist/src/config/schema.d.ts +3 -3
  143. package/dist/src/config/schema.js +21 -21
  144. package/dist/src/gateway/hono/lib/config-payload.d.ts +1 -1
  145. package/dist/src/gateway/hono/routes/browser-workflows.d.ts +3 -0
  146. package/dist/src/gateway/hono/routes/browser-workflows.js +78 -0
  147. package/dist/src/gateway/hono/routes/home.js +1 -0
  148. package/dist/src/gateway/hono/routes/index.js +4 -0
  149. package/dist/src/gateway/hono/routes/interaction-state.d.ts +3 -0
  150. package/dist/src/gateway/hono/routes/interaction-state.js +45 -0
  151. package/dist/src/gateway/hono/routes/lazy-bundles.js +8 -0
  152. package/dist/src/gateway/hono/routes/memory.js +33 -4
  153. package/dist/src/gateway/hono/routes/task-outcomes.d.ts +3 -0
  154. package/dist/src/gateway/hono/routes/task-outcomes.js +109 -0
  155. package/dist/src/gateway/hono/routes/you.d.ts +10 -2
  156. package/dist/src/gateway/hono/routes/you.js +184 -28
  157. package/dist/src/gateway/hono/sse.d.ts +2 -0
  158. package/dist/src/gateway/hono/sse.js +10 -3
  159. package/dist/src/gateway/run-loop.js +17 -7
  160. package/dist/src/gateway/server.d.ts +1 -0
  161. package/dist/src/gateway/server.js +9 -0
  162. package/dist/src/gateway/service/run-gateway-agent.js +84 -0
  163. package/dist/src/gateway/service.d.ts +3 -0
  164. package/dist/src/gateway/service.js +14 -0
  165. package/dist/src/local-apps/preview-runtime-bridge.d.ts +1 -1
  166. package/dist/src/local-apps/preview-runtime-bridge.js +14 -11
  167. package/dist/src/proactive/insight-repository.d.ts +2 -0
  168. package/dist/src/proactive/insight-repository.js +5 -2
  169. package/dist/src/proactive/run-processor.js +22 -1
  170. package/dist/src/proactive/types.d.ts +2 -0
  171. package/dist/src/proactive/value-score.d.ts +13 -0
  172. package/dist/src/proactive/value-score.js +30 -0
  173. package/dist/src/share/share-types.js +5 -5
  174. package/dist/src/share/site-share-types.d.ts +1 -1
  175. package/dist/src/share/site-share-types.js +5 -5
  176. package/dist/src/storage/sqlite/index.d.ts +3 -0
  177. package/dist/src/storage/sqlite/index.js +4 -1
  178. package/dist/src/storage/sqlite/interaction-state-repository.d.ts +17 -0
  179. package/dist/src/storage/sqlite/interaction-state-repository.js +60 -0
  180. package/dist/src/storage/sqlite/memory-records-repository.js +1 -1
  181. package/dist/src/storage/sqlite/migrations/053_browser_recipes.sql +45 -0
  182. package/dist/src/storage/sqlite/migrations/054_task_outcomes.sql +24 -0
  183. package/dist/src/storage/sqlite/migrations/055_relationship_settings.sql +14 -0
  184. package/dist/src/storage/sqlite/migrations/056_task_verification.sql +6 -0
  185. package/dist/src/storage/sqlite/migrations/057_interaction_states.sql +11 -0
  186. package/dist/src/storage/sqlite/migrations/058_proactive_value.sql +3 -0
  187. package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
  188. package/dist/src/storage/sqlite/migrations/runner.js +3 -3
  189. package/dist/src/storage/sqlite/migrations/runner.ts +1 -1
  190. package/dist/src/storage/sqlite/relationship-settings-repository.d.ts +17 -0
  191. package/dist/src/storage/sqlite/relationship-settings-repository.js +64 -0
  192. package/dist/src/storage/sqlite/schema.js +1 -1
  193. package/dist/src/storage/sqlite/schema.sql +46 -0
  194. package/dist/src/storage/sqlite/task-outcome-repository.d.ts +90 -0
  195. package/dist/src/storage/sqlite/task-outcome-repository.js +138 -0
  196. package/dist/src/user-context/interaction-state.d.ts +13 -0
  197. package/dist/src/user-context/interaction-state.js +69 -0
  198. package/dist/src/user-context/memory-use-audit.d.ts +10 -0
  199. package/dist/src/user-context/memory-use-audit.js +25 -0
  200. package/dist/src/user-context/personal-playbook.d.ts +11 -0
  201. package/dist/src/user-context/personal-playbook.js +41 -0
  202. package/dist/src/user-context/projection.d.ts +4 -0
  203. package/dist/src/user-context/projection.js +5 -1
  204. package/dist/src/user-context/relationship-continuity.d.ts +14 -0
  205. package/dist/src/user-context/relationship-continuity.js +51 -0
  206. package/package.json +1 -1
  207. package/dist/gateway/static/root/assets/action-boundary-settings-panel-CY3sizqC.js +0 -1
  208. package/dist/gateway/static/root/assets/activity-store-3Cso_2qm.js +0 -1
  209. package/dist/gateway/static/root/assets/agents-B1l3iii6.js +0 -2
  210. package/dist/gateway/static/root/assets/apps-page-DaNFLsp0.js +0 -1
  211. package/dist/gateway/static/root/assets/automations-page-Cd0gMx6p.js +0 -6
  212. package/dist/gateway/static/root/assets/browser-settings-page-BmUYDL2Z.js +0 -8
  213. package/dist/gateway/static/root/assets/capability-presets-settings-panel-CE7mrWtS.js +0 -2
  214. package/dist/gateway/static/root/assets/channels-settings-D1_gcAHK.js +0 -1
  215. package/dist/gateway/static/root/assets/channels-status-swr-Cqfqv59m.js +0 -1
  216. package/dist/gateway/static/root/assets/check-BODqo66o.js +0 -1
  217. package/dist/gateway/static/root/assets/circle-alert-RzVebuX2.js +0 -1
  218. package/dist/gateway/static/root/assets/cn-BQ_8x0bT.js +0 -1
  219. package/dist/gateway/static/root/assets/connectors-page-CaLBi6Na.js +0 -2
  220. package/dist/gateway/static/root/assets/desktop-pet-wacrnJJ1.js +0 -1
  221. package/dist/gateway/static/root/assets/goal-create-dialog-BQamcEmF.js +0 -1
  222. package/dist/gateway/static/root/assets/goal-detail-page-DZUQ0Lf1.js +0 -4
  223. package/dist/gateway/static/root/assets/goals-page-BtxVD27C.js +0 -2
  224. package/dist/gateway/static/root/assets/index-CHKe7nwC.js +0 -197
  225. package/dist/gateway/static/root/assets/index-CXhfUIjh.css +0 -1
  226. package/dist/gateway/static/root/assets/local-app-workbench-page-CTTfyFe3.js +0 -2
  227. package/dist/gateway/static/root/assets/messages-DDsiqdJS.js +0 -5
  228. package/dist/gateway/static/root/assets/models-hub-panel-DJReXRP9.js +0 -2
  229. package/dist/gateway/static/root/assets/notes-workbench-BbdjzYzs.js +0 -4
  230. package/dist/gateway/static/root/assets/project-detail-page-BwG8SOzI.js +0 -1
  231. package/dist/gateway/static/root/assets/projects-page-nUlyUtxh.js +0 -1
  232. package/dist/gateway/static/root/assets/remote-access-hub-rf7bjije.js +0 -1
  233. package/dist/gateway/static/root/assets/save-bar-controls-qhDisdqY.js +0 -1
  234. package/dist/gateway/static/root/assets/sessions-page-CSoHUe38.js +0 -1
  235. package/dist/gateway/static/root/assets/settings-advanced-gate-Db976IEa.js +0 -1
  236. package/dist/gateway/static/root/assets/settings-page-DYfXmfTx.js +0 -1
  237. package/dist/gateway/static/root/assets/setup-status-panel-wBWOFpvw.js +0 -1
  238. package/dist/gateway/static/root/assets/shares-settings-BAMma1-P.js +0 -1
  239. package/dist/gateway/static/root/assets/skill-reload-api-TWxFFWxM.js +0 -1
  240. package/dist/gateway/static/root/assets/skills-page-Ca2RA29R.js +0 -2
  241. package/dist/gateway/static/root/assets/user-context-page-CTumZa0y.js +0 -1
  242. package/dist/gateway/static/root/assets/voice-api-key-field-DdlMxeqO.js +0 -1
  243. package/dist/gateway/static/root/assets/work-discovery-page-CcfZhdBi.js +0 -1
  244. package/dist/gateway/static/root/assets/work-item-detail-page--wxLw1p_.js +0 -1
  245. package/dist/gateway/static/root/assets/work-page-DyS0XBpV.js +0 -1
  246. package/dist/gateway/static/root/assets/workflows-page-CVVJd4gy.js +0 -11
  247. package/dist/src/browser/pipeline/source.d.ts +0 -9
  248. package/dist/src/browser/pipeline/source.js +0 -77
@@ -1,4 +1,5 @@
1
1
  import { runSqliteWriteTransaction } from "../../../storage/sqlite/transaction.js";
2
+ import { getRelationshipSettings, updateRelationshipSettings } from "../../../storage/sqlite/relationship-settings-repository.js";
2
3
  import { deleteMemoryRecord, getMemoryRecord, listMemoryRecords, upsertMemoryRecord } from "../../../storage/sqlite/memory-records-repository.js";
3
4
  import { listKnowledgeSourceItems, listKnowledgeSyncRuns } from "../../../storage/sqlite/knowledge-repository.js";
4
5
  import { getConnectorConnection, listConnectorConnections } from "../../../storage/sqlite/connector-repository.js";
@@ -15,6 +16,7 @@ import "../../../goals/index.js";
15
16
  import { revokeComposioConnection } from "../../../connectors/composio.js";
16
17
  import { listConnectorCatalog } from "../../../connectors/catalog.js";
17
18
  import { nextMemoryReviewAt, resolveMemoryStability } from "../../../agent/memory/lifecycle.js";
19
+ import { PERSONAL_PLAYBOOK_DISABLED_TAG, PERSONAL_PLAYBOOK_ORDER_PREFIX, PERSONAL_PLAYBOOK_RULE_TAG, patchPersonalPlaybookContextTags, personalPlaybookContext } from "../../../user-context/personal-playbook.js";
18
20
  import { listConnectorInstances } from "../../../connectors/instances.js";
19
21
  import { uninstallConnector } from "../../../connectors/install.js";
20
22
  import { readUserProfileFile, writeUserProfileFile } from "../../agents-admin.js";
@@ -44,8 +46,13 @@ const PLAYBOOK_IDS = [
44
46
  "execution",
45
47
  "routines"
46
48
  ];
47
- const PLAYBOOK_DISABLED_TAG = "playbook:disabled";
48
- const PLAYBOOK_ORDER_PREFIX = "playbook:order:";
49
+ const PLAYBOOK_SUPPORT_NEEDS = new Set([
50
+ "listen",
51
+ "clarify",
52
+ "advise",
53
+ "act",
54
+ "unknown"
55
+ ]);
49
56
  const PROFILE_FIELD_LIMITS = {
50
57
  callName: 80,
51
58
  pronouns: 80,
@@ -154,34 +161,57 @@ function parseProfilePatch(body) {
154
161
  return Object.keys(patch).length > 0 ? { patch } : { error: "No profile fields provided" };
155
162
  }
156
163
  function playbookForRecord(record) {
164
+ if (!record.tags?.includes("playbook:rule")) return void 0;
157
165
  if (record.kind === "preference" || record.kind === "boundary" || record.kind === "tool_preference") return "communication";
158
166
  if (record.kind === "task_lesson" || record.kind === "derived_insight") return "execution";
159
167
  if (record.kind === "routine") return "routines";
160
168
  }
161
169
  function playbookRuleOrder(record) {
162
- const tag = record.tags?.find((value) => value.startsWith(PLAYBOOK_ORDER_PREFIX));
163
- const parsed = tag ? Number.parseInt(tag.slice(15), 10) : NaN;
170
+ const tag = record.tags?.find((value) => value.startsWith(PERSONAL_PLAYBOOK_ORDER_PREFIX));
171
+ const parsed = tag ? Number.parseInt(tag.slice(PERSONAL_PLAYBOOK_ORDER_PREFIX.length), 10) : NaN;
164
172
  return Number.isFinite(parsed) ? parsed : 1e3;
165
173
  }
166
174
  function patchPlaybookRuleTags(record, patch) {
167
- let tags = (record.tags ?? []).filter((tag) => !tag.startsWith(PLAYBOOK_ORDER_PREFIX));
168
- if (patch.enabled === true) tags = tags.filter((tag) => tag !== PLAYBOOK_DISABLED_TAG);
169
- if (patch.enabled === false) tags.push(PLAYBOOK_DISABLED_TAG);
170
- if (patch.order !== void 0) tags.push(`${PLAYBOOK_ORDER_PREFIX}${patch.order}`);
175
+ let tags = (record.tags ?? []).filter((tag) => !tag.startsWith(PERSONAL_PLAYBOOK_ORDER_PREFIX));
176
+ if (patch.enabled === true) tags = tags.filter((tag) => tag !== PERSONAL_PLAYBOOK_DISABLED_TAG);
177
+ if (patch.enabled === false) tags.push(PERSONAL_PLAYBOOK_DISABLED_TAG);
178
+ if (patch.order !== void 0) tags.push(`${PERSONAL_PLAYBOOK_ORDER_PREFIX}${patch.order}`);
171
179
  return [...new Set(tags)];
172
180
  }
181
+ function parsePlaybookContext(value) {
182
+ if (value === void 0) return { context: {} };
183
+ if (!value || typeof value !== "object" || Array.isArray(value)) return { error: "context must be an object" };
184
+ const input = value;
185
+ const context = {};
186
+ if ("channel" in input) {
187
+ if (input.channel !== null && (typeof input.channel !== "string" || !/^[a-z0-9_-]{1,40}$/i.test(input.channel))) return { error: "context.channel is invalid" };
188
+ context.channel = input.channel === null ? void 0 : String(input.channel);
189
+ }
190
+ if ("supportNeed" in input) {
191
+ if (input.supportNeed !== null && !PLAYBOOK_SUPPORT_NEEDS.has(String(input.supportNeed))) return { error: "context.supportNeed is invalid" };
192
+ context.supportNeed = input.supportNeed === null ? void 0 : input.supportNeed;
193
+ }
194
+ return { context };
195
+ }
173
196
  function buildPersonalPlaybooks(records) {
174
197
  return PLAYBOOK_IDS.map((id) => {
175
- const rules = records.filter((record) => playbookForRecord(record) === id).sort((left, right) => playbookRuleOrder(left) - playbookRuleOrder(right) || left.updatedAt.localeCompare(right.updatedAt));
198
+ const rules = records.filter((record) => record.status === "active" && playbookForRecord(record) === id).sort((left, right) => playbookRuleOrder(left) - playbookRuleOrder(right) || left.updatedAt.localeCompare(right.updatedAt));
176
199
  return {
177
200
  id,
178
- enabled: rules.some((record) => !record.tags?.includes(PLAYBOOK_DISABLED_TAG)),
201
+ enabled: rules.some((record) => !record.tags?.includes(PERSONAL_PLAYBOOK_DISABLED_TAG)),
179
202
  rules: rules.map((record) => ({
180
203
  id: record.id,
181
204
  statement: record.content,
182
205
  origin: record.explicitness,
183
- enabled: !record.tags?.includes(PLAYBOOK_DISABLED_TAG),
184
- order: playbookRuleOrder(record)
206
+ enabled: !record.tags?.includes(PERSONAL_PLAYBOOK_DISABLED_TAG),
207
+ order: playbookRuleOrder(record),
208
+ context: personalPlaybookContext(record),
209
+ versions: playbookVersionChain(records, record.id).map((version) => ({
210
+ id: version.id,
211
+ statement: version.content,
212
+ updatedAt: version.updatedAt,
213
+ current: version.id === record.id
214
+ }))
185
215
  })),
186
216
  updatedAt: rules.map((record) => record.updatedAt).sort().at(-1)
187
217
  };
@@ -195,7 +225,7 @@ function buildInsightSuggestions(records) {
195
225
  id: record.id,
196
226
  insight: record.content,
197
227
  kind: record.kind,
198
- action: record.kind === "routine" ? "make_repeatable" : "start_progress",
228
+ action: record.kind === "routine" ? "make_repeatable" : record.kind === "task_lesson" || record.kind === "derived_insight" ? "add_playbook" : "start_progress",
199
229
  evidenceCount: record.evidence?.length ?? 0,
200
230
  confidence: record.confidence,
201
231
  sourceName: record.source.provider ?? "local"
@@ -216,11 +246,11 @@ function editableRecord(recordId) {
216
246
  if (!record || !VISIBLE_STATUSES.has(record.status) || !isUserContextRecord(record)) return null;
217
247
  return record;
218
248
  }
219
- function preserveRecord(record, patch) {
220
- return upsertMemoryRecord({
221
- id: record.id,
249
+ function memoryRecordInput(record) {
250
+ return {
222
251
  providerId: record.source.provider ?? "local",
223
252
  kind: record.kind,
253
+ userId: record.scope.userId,
224
254
  sourceAgentId: record.provenance.sourceAgentId,
225
255
  workspaceId: record.scope.workspaceId,
226
256
  sessionKey: record.scope.sessionKey,
@@ -242,8 +272,41 @@ function preserveRecord(record, patch) {
242
272
  validFrom: record.validFrom,
243
273
  validTo: record.validTo,
244
274
  supersedesRecordId: record.supersedesRecordId,
245
- conflictGroupId: record.conflictGroupId,
246
- ...patch
275
+ conflictGroupId: record.conflictGroupId
276
+ };
277
+ }
278
+ function preserveRecord(record, patch) {
279
+ return upsertMemoryRecord({
280
+ ...memoryRecordInput(record),
281
+ ...patch,
282
+ id: record.id
283
+ });
284
+ }
285
+ function playbookVersionChain(records, recordId) {
286
+ const relatedIds = new Set([recordId]);
287
+ let previousSize = 0;
288
+ while (previousSize !== relatedIds.size) {
289
+ previousSize = relatedIds.size;
290
+ for (const record of records) {
291
+ if (!record.supersedesRecordId) continue;
292
+ if (relatedIds.has(record.id) || relatedIds.has(record.supersedesRecordId)) {
293
+ relatedIds.add(record.id);
294
+ relatedIds.add(record.supersedesRecordId);
295
+ }
296
+ }
297
+ }
298
+ return records.filter((record) => relatedIds.has(record.id) && playbookForRecord(record) !== void 0).sort((left, right) => Date.parse(right.updatedAt) - Date.parse(left.updatedAt));
299
+ }
300
+ function versionPlaybookRule(record, patch) {
301
+ return upsertMemoryRecord({
302
+ ...memoryRecordInput(record),
303
+ ...patch,
304
+ status: "active",
305
+ supersedesRecordId: record.id,
306
+ source: {
307
+ provider: "local",
308
+ path: "you://playbook/version"
309
+ }
247
310
  });
248
311
  }
249
312
  function registerYouRoutes(authenticated, deps) {
@@ -291,13 +354,14 @@ function registerYouRoutes(authenticated, deps) {
291
354
  }),
292
355
  conflictGroups: buildConflictGroups(allUserContextRecords),
293
356
  insights: buildInsightSuggestions(records),
294
- playbooks: buildPersonalPlaybooks(records.filter((record) => record.status === "active")),
357
+ playbooks: buildPersonalPlaybooks(allUserContextRecords),
295
358
  sources,
296
359
  sourceRecommendations: buildGoalSourceRecommendations(sourceDefinitions.filter((definition) => definition.capabilities.includes("context") || definition.capabilities.includes("memory_source")), new Set(sourceInstances.map((instance) => instance.connectorId)), activeGoals),
297
360
  controls: {
298
361
  mode: config.userContext.memory.mode,
299
362
  sensitiveWritePolicy: config.userContext.privacy.sensitiveWritePolicy
300
363
  },
364
+ relationship: getRelationshipSettings(),
301
365
  trust: {
302
366
  defaultActionLevel: trustPolicy.defaultActionLevel,
303
367
  levels: USER_TRUST_LEVELS,
@@ -305,6 +369,41 @@ function registerYouRoutes(authenticated, deps) {
305
369
  }
306
370
  });
307
371
  });
372
+ authenticated.patch("/api/you/relationship", deps.strictRateLimitMiddleware, async (c) => {
373
+ const body = await c.req.json().catch(() => null);
374
+ if (!body || typeof body !== "object" || Array.isArray(body)) return c.json({ error: "Invalid relationship settings" }, 400);
375
+ const input = body;
376
+ const patch = {};
377
+ if ("supportMode" in input) {
378
+ if (![
379
+ "efficient",
380
+ "coach",
381
+ "companion",
382
+ "auto"
383
+ ].includes(String(input.supportMode))) return c.json({ error: "Invalid supportMode" }, 400);
384
+ patch.supportMode = input.supportMode;
385
+ }
386
+ if ("proactiveEnabled" in input) {
387
+ if (typeof input.proactiveEnabled !== "boolean") return c.json({ error: "proactiveEnabled must be boolean" }, 400);
388
+ patch.proactiveEnabled = input.proactiveEnabled;
389
+ }
390
+ for (const field of ["quietStart", "quietEnd"]) {
391
+ if (!(field in input)) continue;
392
+ const value = input[field];
393
+ if (value !== null && (typeof value !== "string" || !/^([01]\d|2[0-3]):[0-5]\d$/.test(value))) return c.json({ error: `${field} must use HH:mm` }, 400);
394
+ patch[field] = value === null ? void 0 : String(value);
395
+ }
396
+ for (const field of ["allowedTopics", "blockedTopics"]) {
397
+ if (!(field in input)) continue;
398
+ if (!Array.isArray(input[field]) || input[field].length > 20 || input[field].some((value) => typeof value !== "string" || !value.trim() || value.length > 80)) return c.json({ error: `${field} must contain up to 20 short topics` }, 400);
399
+ patch[field] = [...new Set(input[field].map((value) => value.trim()))];
400
+ }
401
+ if (Object.keys(patch).length === 0) return c.json({ error: "No relationship settings provided" }, 400);
402
+ return c.json({
403
+ ok: true,
404
+ relationship: updateRelationshipSettings(patch)
405
+ });
406
+ });
308
407
  authenticated.get("/api/you/profile", async (c) => {
309
408
  return c.json(await readProfileBundle(deps.service.currentConfig));
310
409
  });
@@ -523,7 +622,7 @@ function registerYouRoutes(authenticated, deps) {
523
622
  limit: 500
524
623
  }).filter(isUserContextRecord).filter((record) => playbookForRecord(record) === id);
525
624
  runSqliteWriteTransaction(() => {
526
- for (const record of active) preserveRecord(record, { tags: patchPlaybookRuleTags(record, { enabled }) });
625
+ for (const record of active) versionPlaybookRule(record, { tags: patchPlaybookRuleTags(record, { enabled }) });
527
626
  });
528
627
  const current = active.map((record) => ({
529
628
  ...record,
@@ -540,6 +639,8 @@ function registerYouRoutes(authenticated, deps) {
540
639
  const body = await c.req.json().catch(() => ({}));
541
640
  const statement = typeof body.statement === "string" ? body.statement.trim() : "";
542
641
  if (!statement || statement.length > 5e3) return c.json({ error: "Rule statement is required" }, 400);
642
+ const parsedContext = parsePlaybookContext(body.context);
643
+ if ("error" in parsedContext) return c.json({ error: parsedContext.error }, 400);
543
644
  const record = upsertMemoryRecord({
544
645
  providerId: "local",
545
646
  kind: id === "communication" ? "preference" : id === "execution" ? "task_lesson" : "routine",
@@ -550,11 +651,11 @@ function registerYouRoutes(authenticated, deps) {
550
651
  path: "you://playbook"
551
652
  },
552
653
  confidence: 1,
553
- tags: [
654
+ tags: patchPersonalPlaybookContextTags([
554
655
  "user-understanding",
555
- "playbook:explicit",
556
- `${PLAYBOOK_ORDER_PREFIX}${Number.isInteger(body.order) ? body.order : 1e3}`
557
- ],
656
+ PERSONAL_PLAYBOOK_RULE_TAG,
657
+ `${PERSONAL_PLAYBOOK_ORDER_PREFIX}${Number.isInteger(body.order) ? body.order : 1e3}`
658
+ ], parsedContext.context),
558
659
  status: "active",
559
660
  sensitivity: "normal",
560
661
  explicitness: "explicit",
@@ -576,12 +677,14 @@ function registerYouRoutes(authenticated, deps) {
576
677
  if (!content || content.length > 5e3) return c.json({ error: "Rule statement is required" }, 400);
577
678
  if (body.enabled !== void 0 && typeof body.enabled !== "boolean") return c.json({ error: "enabled must be boolean" }, 400);
578
679
  if (body.order !== void 0 && (!Number.isInteger(body.order) || body.order < 0 || body.order > 1e4)) return c.json({ error: "order must be an integer between 0 and 10000" }, 400);
579
- const updated = preserveRecord(record, {
680
+ const parsedContext = parsePlaybookContext(body.context);
681
+ if ("error" in parsedContext) return c.json({ error: parsedContext.error }, 400);
682
+ const updated = versionPlaybookRule(record, {
580
683
  content,
581
- tags: patchPlaybookRuleTags(record, {
684
+ tags: patchPersonalPlaybookContextTags(patchPlaybookRuleTags(record, {
582
685
  enabled: body.enabled,
583
686
  order: body.order
584
- }),
687
+ }), parsedContext.context),
585
688
  explicitness: body.statement === void 0 ? record.explicitness : "explicit"
586
689
  });
587
690
  return c.json({
@@ -593,9 +696,32 @@ function registerYouRoutes(authenticated, deps) {
593
696
  const id = c.req.param("id");
594
697
  const record = editableRecord(c.req.param("recordId"));
595
698
  if (!PLAYBOOK_IDS.includes(id) || !record || playbookForRecord(record) !== id) return c.json({ error: "Playbook rule not found" }, 404);
596
- deleteMemoryRecord(record.id);
699
+ preserveRecord(record, {
700
+ status: "archived",
701
+ validTo: (/* @__PURE__ */ new Date()).toISOString()
702
+ });
597
703
  return c.json({ ok: true });
598
704
  });
705
+ authenticated.post("/api/you/playbooks/:id/rules/:recordId/rollback", deps.strictRateLimitMiddleware, async (c) => {
706
+ const id = c.req.param("id");
707
+ const current = editableRecord(c.req.param("recordId"));
708
+ if (!PLAYBOOK_IDS.includes(id) || !current || playbookForRecord(current) !== id) return c.json({ error: "Playbook rule not found" }, 404);
709
+ const body = await c.req.json().catch(() => ({}));
710
+ const versionId = typeof body.versionId === "string" ? body.versionId : "";
711
+ const all = listAllUserContextRecords(ALL_MEMORY_STATUSES);
712
+ const target = playbookVersionChain(all, current.id).find((record) => record.id === versionId);
713
+ if (!target || target.id === current.id) return c.json({ error: "Previous version not found" }, 404);
714
+ const rolledBack = versionPlaybookRule(current, {
715
+ content: target.content,
716
+ tags: target.tags,
717
+ evidence: target.evidence,
718
+ explicitness: "explicit"
719
+ });
720
+ return c.json({
721
+ ok: true,
722
+ rule: buildPersonalPlaybooks([...all, rolledBack]).find((playbook) => playbook.id === id)?.rules.find((rule) => rule.id === rolledBack.id)
723
+ });
724
+ });
599
725
  authenticated.patch("/api/you/insights/:id", deps.strictRateLimitMiddleware, async (c) => {
600
726
  const config = deps.service.currentConfig;
601
727
  const existing = editableRecord(c.req.param("id"));
@@ -622,6 +748,36 @@ function registerYouRoutes(authenticated, deps) {
622
748
  status: "drafting",
623
749
  href: buildRoutineAutomationDraftHref(existing)
624
750
  });
751
+ if (existing.kind === "task_lesson" || existing.kind === "derived_insight") {
752
+ upsertMemoryRecord({
753
+ providerId: "local",
754
+ kind: "task_lesson",
755
+ sourceAgentId: selectedAgentId(config),
756
+ content: existing.content,
757
+ source: {
758
+ provider: "local",
759
+ path: "you://insight-proposal"
760
+ },
761
+ confidence: 1,
762
+ tags: [
763
+ "user-understanding",
764
+ PERSONAL_PLAYBOOK_RULE_TAG,
765
+ `${PERSONAL_PLAYBOOK_ORDER_PREFIX}1000`
766
+ ],
767
+ status: "active",
768
+ sensitivity: existing.sensitivity,
769
+ explicitness: "explicit",
770
+ durability: "durable",
771
+ importance: existing.importance,
772
+ disclosurePolicy: existing.disclosurePolicy,
773
+ evidence: existing.evidence
774
+ });
775
+ preserveRecord(existing, { tags: [...new Set([...existing.tags ?? [], INSIGHT_ACCEPTED_TAG])] });
776
+ return c.json({
777
+ ok: true,
778
+ status: "saved"
779
+ });
780
+ }
625
781
  const title = existing.content.trim().split(/\r?\n/)[0].slice(0, 72);
626
782
  const uiLocale = body.uiLocale === "zh" ? "zh" : "en";
627
783
  const contractDraft = await draftGoalContract({
@@ -1,5 +1,7 @@
1
1
  import type { Context } from 'hono';
2
2
  import type { GatewayService } from '../service.js';
3
+ /** Close long-lived gateway event streams before the HTTP server starts draining. */
4
+ export declare function closeAllEventStreams(): void;
3
5
  export interface SSEHandlerConfig {
4
6
  service: GatewayService;
5
7
  maxSseConnections?: number;
@@ -9,6 +9,10 @@ import { streamSSE } from "hono/streaming";
9
9
  init_logger();
10
10
  const log = createLogger("Gateway:SSE");
11
11
  const activeConnections = /* @__PURE__ */ new Map();
12
+ /** Close long-lived gateway event streams before the HTTP server starts draining. */
13
+ function closeAllEventStreams() {
14
+ for (const controller of activeConnections.values()) controller.abort();
15
+ }
12
16
  function isValidAgentRequest(body) {
13
17
  if (!body || typeof body !== "object") return false;
14
18
  const b = body;
@@ -341,17 +345,20 @@ function createEventsSSEHandler(config) {
341
345
  }
342
346
  }, 3e4);
343
347
  await new Promise((resolve) => {
344
- stream.onAbort(() => {
348
+ const finish = () => {
345
349
  aborted = true;
346
350
  clearInterval(keepAlive);
347
351
  cleanup();
348
352
  activeConnections.delete(sessionId);
349
353
  log.debug({ sessionId }, "Event stream disconnected");
350
354
  resolve();
351
- });
355
+ };
356
+ stream.onAbort(finish);
357
+ abortController.signal.addEventListener("abort", () => stream.abort(), { once: true });
358
+ if (abortController.signal.aborted) stream.abort();
352
359
  });
353
360
  });
354
361
  };
355
362
  }
356
363
  //#endregion
357
- export { createAgentResumeHandler, createAgentSSEHandler, createEventsSSEHandler, createSendHandler };
364
+ export { closeAllEventStreams, createAgentResumeHandler, createAgentSSEHandler, createEventsSSEHandler, createSendHandler };
@@ -15,7 +15,8 @@ async function runGatewayLoop(opts) {
15
15
  let lock = await acquireGatewayLock(opts.configPath, { port: opts.port });
16
16
  let server = null;
17
17
  let shuttingDown = false;
18
- let restartResolver = null;
18
+ let forceCloseRequested = false;
19
+ let loopResolver = null;
19
20
  const cleanupSignals = () => {
20
21
  process.removeListener("SIGTERM", onSigterm);
21
22
  process.removeListener("SIGINT", onSigint);
@@ -51,20 +52,27 @@ async function runGatewayLoop(opts) {
51
52
  return;
52
53
  }
53
54
  shuttingDown = false;
54
- restartResolver?.();
55
+ forceCloseRequested = false;
56
+ loopResolver?.("restart");
55
57
  };
56
58
  const handleStopAfterClose = async () => {
57
59
  await releaseLock();
58
- exitProcess(0);
60
+ loopResolver?.("stop");
59
61
  };
60
62
  const DRAIN_TIMEOUT_MS = 3e4;
61
63
  const SHUTDOWN_TIMEOUT_MS = 15e3;
62
64
  const requestShutdown = (action, signal) => {
63
- if (shuttingDown) return;
65
+ if (shuttingDown) {
66
+ if (!forceCloseRequested && (signal === "SIGINT" || signal === "SIGTERM")) {
67
+ forceCloseRequested = true;
68
+ console.warn(`[GatewayRunLoop] Received ${signal} again; force closing connections`);
69
+ server?.forceCloseConnections();
70
+ }
71
+ return;
72
+ }
64
73
  shuttingDown = true;
65
74
  const isRestart = action === "restart";
66
75
  console.log(`[GatewayRunLoop] Received ${signal}; ${isRestart ? "restarting" : "shutting down"}`);
67
- cleanupSignals();
68
76
  const forceExitMs = isRestart ? DRAIN_TIMEOUT_MS + SHUTDOWN_TIMEOUT_MS : SHUTDOWN_TIMEOUT_MS;
69
77
  const forceExitTimer = setTimeout(() => {
70
78
  console.error("[GatewayRunLoop] Shutdown timed out; force exiting");
@@ -129,9 +137,11 @@ async function runGatewayLoop(opts) {
129
137
  exitProcess(1);
130
138
  return;
131
139
  }
132
- await new Promise((resolve) => {
133
- restartResolver = resolve;
140
+ const action = await new Promise((resolve) => {
141
+ loopResolver = resolve;
134
142
  });
143
+ loopResolver = null;
144
+ if (action === "stop") return;
135
145
  console.log("[GatewayRunLoop] Restart signal received, restarting gateway...");
136
146
  }
137
147
  } finally {
@@ -23,6 +23,7 @@ export declare class GatewayServer {
23
23
  restartExpectedMs?: number | null;
24
24
  }): Promise<void>;
25
25
  stop(): Promise<void>;
26
+ forceCloseConnections(): void;
26
27
  get isRunning(): boolean;
27
28
  get serviceInstance(): GatewayService;
28
29
  }
@@ -2,6 +2,7 @@ import { resolveGatewayBindHost, resolveGatewayListenHosts } from "../config/gat
2
2
  import { ensureXopcCliOnPath } from "../infra/path-env.js";
3
3
  import { resolveGatewayListenPlan } from "./listen.js";
4
4
  import { GatewayService } from "./service.js";
5
+ import { closeAllEventStreams } from "./hono/sse.js";
5
6
  import { handleSiteShareUpgrade } from "../share/site-share-router.js";
6
7
  import { createHonoApp } from "./hono/app.js";
7
8
  import { serve } from "@hono/node-server";
@@ -94,6 +95,7 @@ var GatewayServer = class {
94
95
  }
95
96
  async stop() {
96
97
  console.log("[GatewayServer] Stopping gateway server...");
98
+ closeAllEventStreams();
97
99
  const closeServer = async (server) => {
98
100
  if (!server) return;
99
101
  const forceClose = setTimeout(() => {
@@ -113,6 +115,13 @@ var GatewayServer = class {
113
115
  await this.service.stop();
114
116
  console.log("[GatewayServer] Gateway server stopped");
115
117
  }
118
+ forceCloseConnections() {
119
+ const close = (server) => {
120
+ server?.closeAllConnections?.();
121
+ };
122
+ close(this.server);
123
+ for (const extra of this.extraServers) close(extra);
124
+ }
116
125
  get isRunning() {
117
126
  return this.server !== void 0;
118
127
  }
@@ -1,6 +1,11 @@
1
1
  import { inboundCorrelationMetadataFromAsyncLogContext, updateAsyncLogContext } from "../../utils/logger/context.js";
2
2
  import { createLogger } from "../../utils/logger/index.js";
3
3
  import { init_logger } from "../../utils/logger.js";
4
+ import { updateInteractionStateFromMessage } from "../../storage/sqlite/interaction-state-repository.js";
5
+ import { completeTaskOutcome, startTaskOutcome, updateTaskOutcome } from "../../storage/sqlite/task-outcome-repository.js";
6
+ import "../../storage/sqlite/index.js";
7
+ import { init_session_key, parseSessionKey } from "../../routing/session-key.js";
8
+ import { recordExplicitRelationshipFollowUp } from "../../user-context/relationship-continuity.js";
4
9
  import { formatAgentRunErrorForClient } from "../../agent/client-error-format.js";
5
10
  import { prependEnvelopeTimestamp } from "../../channels/envelope-timestamp.js";
6
11
  import { shouldSkipWebchatInboundByAbortCutoff } from "../../session/abort-cutoff.js";
@@ -11,6 +16,7 @@ import { coalesceThinkingDeltas } from "../chat-stream/thinking-delta-coalescer.
11
16
  import crypto from "crypto";
12
17
  //#region src/gateway/service/run-gateway-agent.ts
13
18
  init_logger();
19
+ init_session_key();
14
20
  const log = createLogger("Gateway:Service");
15
21
  /**
16
22
  * @param runOptions.signal — When set (e.g. client disconnect), aborts in-flight generation and persists partial output.
@@ -24,6 +30,11 @@ async function* runGatewayAgent(deps, message, channel, chatId, attachments, thi
24
30
  const runId = crypto.randomUUID();
25
31
  const { agentService, bus, runRelay, runAbortControllers, activeWebchatRunBySession, sessionIndex: sessionIndexFromDeps, emit } = deps;
26
32
  const sessionIndex = sessionIndexFromDeps;
33
+ let taskOutcomeStarted = false;
34
+ let taskOutcomeStatus = "failed";
35
+ let taskOutcomeSummary = "Agent run ended unexpectedly";
36
+ let taskContract;
37
+ const taskEvidence = [];
27
38
  let webchatSessionKey;
28
39
  let webchatSessionId;
29
40
  let webchatStaleSkip = false;
@@ -40,15 +51,65 @@ async function* runGatewayAgent(deps, message, channel, chatId, attachments, thi
40
51
  runAbortControllers.set(runId, new AbortController());
41
52
  }
42
53
  const streamSessionKey = webchatSessionKey ?? chatId;
54
+ if (webchatSessionKey) {
55
+ const parsedSession = parseSessionKey(webchatSessionKey);
56
+ if (!parsedSession) throw new Error("Resolved webchat session key is invalid");
57
+ updateInteractionStateFromMessage({
58
+ sessionKey: webchatSessionKey,
59
+ message
60
+ });
61
+ recordExplicitRelationshipFollowUp({
62
+ sessionKey: webchatSessionKey,
63
+ sourceAgentId: parsedSession.agentId,
64
+ message
65
+ });
66
+ startTaskOutcome({
67
+ runId,
68
+ sessionKey: webchatSessionKey,
69
+ channel,
70
+ objective: message.trim()
71
+ });
72
+ taskOutcomeStarted = true;
73
+ }
43
74
  const mapper = new ChatStreamMapper({
44
75
  runId,
45
76
  sessionKey: streamSessionKey,
46
77
  channel
47
78
  });
48
79
  let registeredActiveWebchatRun = false;
80
+ const addTaskEvidence = (evidence) => {
81
+ if (taskEvidence.some((item) => item.kind === evidence.kind && item.title === evidence.title)) return;
82
+ taskEvidence.push(evidence);
83
+ };
84
+ const captureTaskEvent = (event) => {
85
+ if (event.type === "turn_plan") {
86
+ taskContract = {
87
+ objective: message.trim(),
88
+ deliverables: [],
89
+ acceptanceCriteria: event.payload.plan.map((item) => item.step),
90
+ constraints: [],
91
+ approvalRequired: []
92
+ };
93
+ return;
94
+ }
95
+ if (event.type === "patch_applied") {
96
+ addTaskEvidence({
97
+ kind: "state",
98
+ title: "Changes applied",
99
+ summary: `${event.payload.added} additions and ${event.payload.removed} removals`
100
+ });
101
+ return;
102
+ }
103
+ if (event.type === "command_completed" && event.payload.exitCode === 0 && /(^|\s)(test|vitest|jest|pytest|lint|typecheck|build)(\s|$|:)/i.test(event.payload.command)) addTaskEvidence({
104
+ kind: "test",
105
+ title: event.payload.command.slice(0, 120),
106
+ summary: event.payload.durationMs === void 0 ? "Command completed successfully" : `Command completed successfully in ${event.payload.durationMs} ms`
107
+ });
108
+ };
49
109
  const publishStreamEvent = (event) => channel === "webchat" ? runRelay.publish(runId, event) ?? event : event;
50
110
  const emitAndYield = function* (events) {
51
111
  for (const event of events) {
112
+ if (taskOutcomeStarted) captureTaskEvent(event);
52
113
  const relayedEvent = publishStreamEvent(event);
53
114
  if (channel === "webchat") emit("agent.stream", {
54
115
  sessionKey: streamSessionKey,
@@ -61,6 +122,8 @@ async function* runGatewayAgent(deps, message, channel, chatId, attachments, thi
61
122
  try {
62
123
  if (channel === "webchat" && webchatSessionKey) {
63
124
  if (webchatStaleSkip) {
125
+ taskOutcomeStatus = "cancelled";
126
+ taskOutcomeSummary = "Stale inbound message skipped";
64
127
  yield* emitAndYield(mapper.end("cancelled", "Stale inbound after abort (clientCreatedAtMs before cutoff)"));
65
128
  runRelay.complete(runId);
66
129
  runAbortControllers.delete(runId);
@@ -97,6 +160,8 @@ async function* runGatewayAgent(deps, message, channel, chatId, attachments, thi
97
160
  for await (const event of coalesceThinkingDeltas(mappedEvents)) yield* emitAndYield([event]);
98
161
  const endStatus = mergedSignal.aborted ? "cancelled" : "success";
99
162
  const endSummary = mergedSignal.aborted ? "Interrupted" : "Message processed successfully";
163
+ taskOutcomeStatus = mergedSignal.aborted ? "cancelled" : "succeeded";
164
+ taskOutcomeSummary = endSummary;
100
165
  yield* emitAndYield(mapper.end(endStatus, endSummary));
101
166
  runRelay.complete(runId);
102
167
  try {
@@ -121,6 +186,8 @@ async function* runGatewayAgent(deps, message, channel, chatId, attachments, thi
121
186
  channel: "webchat"
122
187
  }, `Agent processing failed: ${em}`);
123
188
  streamError = em;
189
+ taskOutcomeStatus = "failed";
190
+ taskOutcomeSummary = em;
124
191
  const errorContent = formatAgentRunErrorForClient(streamError);
125
192
  yield* emitAndYield(mapper.error(errorContent));
126
193
  yield* emitAndYield(mapper.end("error", streamError));
@@ -198,12 +265,16 @@ async function* runGatewayAgent(deps, message, channel, chatId, attachments, thi
198
265
  payload: { messageId }
199
266
  }]);
200
267
  yield* emitAndYield(mapper.end("success", "Message processed"));
268
+ taskOutcomeStatus = "succeeded";
269
+ taskOutcomeSummary = "Message processed";
201
270
  return {
202
271
  status: "ok",
203
272
  summary: "Message processed"
204
273
  };
205
274
  } catch (error) {
206
275
  const em = error instanceof Error ? error.message : String(error);
276
+ taskOutcomeStatus = "failed";
277
+ taskOutcomeSummary = em;
207
278
  log.error({
208
279
  err: error,
209
280
  errorMessage: em,
@@ -213,6 +284,19 @@ async function* runGatewayAgent(deps, message, channel, chatId, attachments, thi
213
284
  chatId
214
285
  }, `Agent run failed: ${em}`);
215
286
  throw error;
287
+ } finally {
288
+ if (taskOutcomeStarted) {
289
+ updateTaskOutcome({
290
+ runId,
291
+ ...taskContract ? { contract: taskContract } : {},
292
+ evidence: taskEvidence
293
+ });
294
+ completeTaskOutcome({
295
+ runId,
296
+ status: taskOutcomeStatus,
297
+ summary: taskOutcomeSummary
298
+ });
299
+ }
216
300
  }
217
301
  }
218
302
  //#endregion
@@ -11,6 +11,7 @@ import { AgentRunRelay } from './agent-run-relay.js';
11
11
  import { type EnqueueGoalRunOptions } from '../goals/index.js';
12
12
  import { ProjectService } from '../projects/index.js';
13
13
  import { LocalAppService } from '../local-apps/index.js';
14
+ import { type BrowserRecipeService } from '../browser/recipes/index.js';
14
15
  import { GatewaySessionsApi } from './service/sessions-api.js';
15
16
  import { GatewayMarketplaceService } from './service/marketplace-service.js';
16
17
  import { GatewayAgentRunner } from './service/agent-runner.js';
@@ -26,6 +27,7 @@ export declare class GatewayService {
26
27
  private _agentService;
27
28
  private channelManager;
28
29
  private automationService;
30
+ private browserRecipeService;
29
31
  private notesService;
30
32
  private extensionLoader;
31
33
  private extensionMetadataSnapshot;
@@ -42,6 +44,7 @@ export declare class GatewayService {
42
44
  private auth;
43
45
  private readonly sse;
44
46
  getConfig(): Config;
47
+ get browserRecipes(): BrowserRecipeService;
45
48
  private stopGatewayUpdateCheck;
46
49
  /** When set (e.g. by `GatewayServer`), `triggerGatewayProcessRestart` can stop HTTP then exit. */
47
50
  private gatewayShutdownForRestart;