@xopcai/xopc 0.0.196 → 0.0.199

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 (258) 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-B1oxPli_.js → agent-avatar-dicebear-Bt70bZjv.js} +1 -1
  5. package/dist/gateway/static/root/assets/agents-D19uNmJf.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-B4x7JfL8.js +1 -0
  8. package/dist/gateway/static/root/assets/appearance-settings-Dwdagf-Q.js +1 -0
  9. package/dist/gateway/static/root/assets/apps-page-DkTiesxe.js +1 -0
  10. package/dist/gateway/static/root/assets/{archive-plugin-BdE4Mati.js → archive-plugin-Cv0VXKLm.js} +1 -1
  11. package/dist/gateway/static/root/assets/{attachment-load-CTzaQcLV.js → attachment-load-CgidKrXn.js} +1 -1
  12. package/dist/gateway/static/root/assets/automations-page-BR6qMOVr.js +6 -0
  13. package/dist/gateway/static/root/assets/{binary-plugins-B25zTNxl.js → binary-plugins-DN3CQgIq.js} +1 -1
  14. package/dist/gateway/static/root/assets/{block-editor-Cdrf2awF.js → block-editor-BwkSl1F_.js} +46 -46
  15. package/dist/gateway/static/root/assets/browser-settings-page-CDFQWAxI.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-Wx9FrbK-.js → browser-workflows-page-C_I31wLm.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-D41mssOq.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-BXgCyuu2.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-DV5BhAeu.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-5FEBYguL.js +1 -0
  26. package/dist/gateway/static/root/assets/connectors-page-C_qkEN0T.js +2 -0
  27. package/dist/gateway/static/root/assets/copy-Dv6d4Dvw.js +1 -0
  28. package/dist/gateway/static/root/assets/cron-expression-SEFx5rnr.js +2 -0
  29. package/dist/gateway/static/root/assets/date-picker-D4zCUQJL.js +1 -0
  30. package/dist/gateway/static/root/assets/dependency-picker-DpQAxS2k.js +1 -0
  31. package/dist/gateway/static/root/assets/{desktop-pet-BOb8sEhN.js → desktop-pet-B_5G3lQl.js} +1 -1
  32. package/dist/gateway/static/root/assets/desktop-pet-settings-ClEyoUJe.js +1 -0
  33. package/dist/gateway/static/root/assets/directory-picker-path-field-AsFWmOjG.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-p83TmZFd.js → extension-debug-page-C22Y2o5l.js} +1 -1
  37. package/dist/gateway/static/root/assets/{extension-page-DMQ3ovxA.js → extension-page-C61Ikawk.js} +1 -1
  38. package/dist/gateway/static/root/assets/extension-settings-page-WlWWcDFr.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-ByIOMQdc.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-CzzS9A17.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-B4A_CXUL.js +1 -0
  47. package/dist/gateway/static/root/assets/home-page-FVGYYPWo.js +3 -0
  48. package/dist/gateway/static/root/assets/index-CGbKTCST.js +152 -0
  49. package/dist/gateway/static/root/assets/index-CR233S0Q.css +1 -0
  50. package/dist/gateway/static/root/assets/interaction-BmQogeqz.js +1 -0
  51. package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-BQb06_jl.js → keyboard-shortcuts-settings-BD_TFz0_.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-BNpkigNb.js +2 -0
  54. package/dist/gateway/static/root/assets/local-apps-page-BwbUeLfm.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-DXP9OQQt.js +2 -0
  57. package/dist/gateway/static/root/assets/management-settings-CW2VpqtT.js +1 -0
  58. package/dist/gateway/static/root/assets/{markdown-split-Db-KrpOQ.js → markdown-split-B1M9KO16.js} +1 -1
  59. package/dist/gateway/static/root/assets/{media-plugins-CHN66qs0.js → media-plugins-B_QlNdqZ.js} +1 -1
  60. package/dist/gateway/static/root/assets/messages-3qRsLZuX.js +3 -0
  61. package/dist/gateway/static/root/assets/{notes-page-CJtKZM0P.js → notes-page-BTbD4GmH.js} +1 -1
  62. package/dist/gateway/static/root/assets/notes-workbench-JRiq7QDW.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-CeqtArlZ.js +1 -0
  66. package/dist/gateway/static/root/assets/{product-open-page--RnCc9bb.js → product-open-page-DnalBZZs.js} +1 -1
  67. package/dist/gateway/static/root/assets/project-detail-page-CjWA13aE.js +1 -0
  68. package/dist/gateway/static/root/assets/projects-page-jsCkScbG.js +1 -0
  69. package/dist/gateway/static/root/assets/remote-access-hub-CGPJTEkM.js +1 -0
  70. package/dist/gateway/static/root/assets/{runtime-tools-settings-panel-Bg1W2__k.js → runtime-tools-settings-panel-cGkBEfg4.js} +4 -4
  71. package/dist/gateway/static/root/assets/schema-form-CmsrLlxu.js +1 -0
  72. package/dist/gateway/static/root/assets/sessions-page-BBHzziMd.js +1 -0
  73. package/dist/gateway/static/root/assets/settings-advanced-gate-2cGg8-9h.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-DUWCbaMJ.js +1 -0
  76. package/dist/gateway/static/root/assets/{settings-loading-skeleton-BS36Mjzz.js → settings-loading-skeleton-Bvy5rdMY.js} +1 -1
  77. package/dist/gateway/static/root/assets/{settings-page-BDSd7F9Y.js → settings-page-cZSAwsRR.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-Cf06b66-.js +1 -0
  81. package/dist/gateway/static/root/assets/share-preview-page-BzA2NCAH.js +2 -0
  82. package/dist/gateway/static/root/assets/shares-settings-xlNKydYY.js +1 -0
  83. package/dist/gateway/static/root/assets/skill-reload-api-C5Xu93c_.js +1 -0
  84. package/dist/gateway/static/root/assets/skills-page-Bvde7_i5.js +2 -0
  85. package/dist/gateway/static/root/assets/{skills-page.utils-CnbJncdL.js → skills-page.utils-vXSqHR7g.js} +1 -1
  86. package/dist/gateway/static/root/assets/system-settings-panel-9cQGOGCK.js +1 -0
  87. package/dist/gateway/static/root/assets/task-detail-page-Bkno4tTe.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-7XfKULPI.js +1 -0
  92. package/dist/gateway/static/root/assets/user-context-page-CZ9m9aC_.js +1 -0
  93. package/dist/gateway/static/root/assets/voice-api-key-field-DXr21v-3.js +1 -0
  94. package/dist/gateway/static/root/assets/work-discovery-overlay-CeG7g_DZ.js +1 -0
  95. package/dist/gateway/static/root/assets/work-discovery-page-CQWZD03N.js +1 -0
  96. package/dist/gateway/static/root/assets/{workflow-run-setup-panel-BEmugHfL.js → workflow-run-setup-panel-DSQQZP9T.js} +2 -2
  97. package/dist/gateway/static/root/assets/workflows-page-Cs-MXFJ1.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 +54 -2
  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/embedded/execution-context.d.ts +2 -0
  105. package/dist/src/agent/embedded/execution-context.js +11 -0
  106. package/dist/src/agent/embedded/index.d.ts +3 -1
  107. package/dist/src/agent/embedded/index.js +5 -3
  108. package/dist/src/agent/embedded/run-turn.js +15 -9
  109. package/dist/src/agent/embedded/session-runner.d.ts +6 -11
  110. package/dist/src/agent/embedded/session-runner.js +25 -36
  111. package/dist/src/agent/embedded/transcript-runtime.d.ts +35 -0
  112. package/dist/src/agent/embedded/transcript-runtime.js +66 -0
  113. package/dist/src/agent/embedded/types.d.ts +3 -1
  114. package/dist/src/agent/service.d.ts +15 -0
  115. package/dist/src/agent/service.js +31 -0
  116. package/dist/src/agent/service.types.d.ts +1 -0
  117. package/dist/src/agent/tools/factory.d.ts +2 -0
  118. package/dist/src/agent/tools/factory.js +2 -1
  119. package/dist/src/agent/tools/xopc-use-tool.d.ts +1 -0
  120. package/dist/src/agent/tools/xopc-use-tool.js +56 -6
  121. package/dist/src/automations/domain/validation.d.ts +40 -0
  122. package/dist/src/automations/draft/automation-draft-validator.d.ts +4 -1
  123. package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
  124. package/dist/src/config/agent-profile.js +1 -1
  125. package/dist/src/config/rules.js +2 -2
  126. package/dist/src/gateway/agents-admin.js +1 -1
  127. package/dist/src/gateway/hono/app.d.ts +2 -0
  128. package/dist/src/gateway/hono/app.js +10 -3
  129. package/dist/src/gateway/hono/middleware/strict-rate-limit.d.ts +4 -0
  130. package/dist/src/gateway/hono/middleware/strict-rate-limit.js +8 -1
  131. package/dist/src/gateway/hono/routes/config-patch/misc.js +2 -1
  132. package/dist/src/gateway/hono/routes/config.js +9 -0
  133. package/dist/src/gateway/hono/routes/deps.d.ts +1 -0
  134. package/dist/src/gateway/hono/routes/home.d.ts +1 -1
  135. package/dist/src/gateway/hono/routes/home.js +2 -2
  136. package/dist/src/gateway/hono/routes/index.js +2 -0
  137. package/dist/src/gateway/hono/routes/projects.js +67 -1
  138. package/dist/src/gateway/hono/routes/side-chats.d.ts +3 -0
  139. package/dist/src/gateway/hono/routes/side-chats.js +173 -0
  140. package/dist/src/gateway/hono/routes/tasks.js +112 -19
  141. package/dist/src/gateway/host.d.ts +9 -1
  142. package/dist/src/gateway/host.js +22 -5
  143. package/dist/src/gateway/rate-limit/buckets.d.ts +3 -0
  144. package/dist/src/gateway/rate-limit/buckets.js +12 -0
  145. package/dist/src/gateway/runtime-config.js +6 -5
  146. package/dist/src/gateway/security/audit.js +0 -7
  147. package/dist/src/gateway/server.js +4 -1
  148. package/dist/src/gateway/service/agent-runner.d.ts +4 -0
  149. package/dist/src/gateway/service/agent-runner.js +15 -1
  150. package/dist/src/gateway/service/run-gateway-agent.js +1 -1
  151. package/dist/src/gateway/service.d.ts +5 -0
  152. package/dist/src/gateway/service.js +38 -8
  153. package/dist/src/gateway/side-chat/context-snapshot.d.ts +11 -0
  154. package/dist/src/gateway/side-chat/context-snapshot.js +108 -0
  155. package/dist/src/gateway/side-chat/index.d.ts +5 -0
  156. package/dist/src/gateway/side-chat/index.js +4 -0
  157. package/dist/src/gateway/side-chat/manager.d.ts +45 -0
  158. package/dist/src/gateway/side-chat/manager.js +198 -0
  159. package/dist/src/gateway/side-chat/run-service.d.ts +22 -0
  160. package/dist/src/gateway/side-chat/run-service.js +110 -0
  161. package/dist/src/gateway/side-chat/types.d.ts +61 -0
  162. package/dist/src/gateway/side-chat/types.js +1 -0
  163. package/dist/src/proactive/actions/service.d.ts +2 -0
  164. package/dist/src/proactive/actions/service.js +80 -0
  165. package/dist/src/proactive/execution/insight.js +20 -0
  166. package/dist/src/proactive/execution/repository.js +8 -2
  167. package/dist/src/proactive/execution/types.d.ts +14 -0
  168. package/dist/src/proactive/inbox/repository.js +59 -9
  169. package/dist/src/proactive/inbox/service.d.ts +2 -2
  170. package/dist/src/proactive/inbox/service.js +7 -2
  171. package/dist/src/proactive/inbox/types.d.ts +14 -0
  172. package/dist/src/proactive/inbox/worker.js +2 -0
  173. package/dist/src/proactive/scenarios/prompt-composer.js +2 -2
  174. package/dist/src/routing/session-key-utils.d.ts +0 -1
  175. package/dist/src/routing/session-key-utils.js +1 -6
  176. package/dist/src/routing/session-key.js +2 -2
  177. package/dist/src/storage/sqlite/migrations/118_task_board_rank.sql +6 -0
  178. package/dist/src/storage/sqlite/migrations/119_proactive_disposition.sql +13 -0
  179. package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
  180. package/dist/src/storage/sqlite/migrations/runner.js +3 -3
  181. package/dist/src/storage/sqlite/migrations/runner.ts +1 -1
  182. package/dist/src/storage/sqlite/schema.js +1 -1
  183. package/dist/src/tasks/home-query-service.d.ts +29 -0
  184. package/dist/src/tasks/home-query-service.js +291 -7
  185. package/dist/src/tasks/index.d.ts +1 -0
  186. package/dist/src/tasks/index.js +5 -4
  187. package/dist/src/tasks/project-monitoring-service.d.ts +9 -0
  188. package/dist/src/tasks/project-monitoring-service.js +41 -3
  189. package/dist/src/tasks/project-operating-view-service.d.ts +2 -2
  190. package/dist/src/tasks/project-operating-view-service.js +47 -21
  191. package/dist/src/tasks/task-application-service.js +99 -6
  192. package/dist/src/tasks/task-change-events.d.ts +13 -0
  193. package/dist/src/tasks/task-change-events.js +29 -0
  194. package/dist/src/tasks/task-read-model-projector.js +2 -1
  195. package/dist/src/tasks/task-repository.d.ts +7 -0
  196. package/dist/src/tasks/task-repository.js +29 -6
  197. package/dist/src/tunnel/enable-lan-pairing.js +15 -26
  198. package/dist/src/tunnel/pair-context.js +1 -1
  199. package/dist/src/tunnel/pair-url.js +1 -1
  200. package/dist/src/tunnel/tunnel-qr.d.ts +0 -7
  201. package/dist/src/tunnel/tunnel-qr.js +2 -19
  202. package/package.json +4 -2
  203. package/dist/gateway/static/root/assets/agents-VoFNMGL3.js +0 -68
  204. package/dist/gateway/static/root/assets/app-management-settings-panel-vmuJ_Z6i.js +0 -1
  205. package/dist/gateway/static/root/assets/appearance-settings-BMlEoe-G.js +0 -1
  206. package/dist/gateway/static/root/assets/apps-page-CsNB6mv_.js +0 -1
  207. package/dist/gateway/static/root/assets/automations-page-CW1YWgiX.js +0 -6
  208. package/dist/gateway/static/root/assets/browser-settings-page-BMTmGMM6.js +0 -8
  209. package/dist/gateway/static/root/assets/browser-workflow-inputs-BsmHy0ks.js +0 -1
  210. package/dist/gateway/static/root/assets/capabilities-settings-panel-C5l85__e.js +0 -7
  211. package/dist/gateway/static/root/assets/capability-presets-settings-panel-9T2KXAs1.js +0 -3
  212. package/dist/gateway/static/root/assets/channels-settings-DquD4BPQ.js +0 -1
  213. package/dist/gateway/static/root/assets/channels-status-swr-DPaJSYX_.js +0 -1
  214. package/dist/gateway/static/root/assets/connectors-api-BC-4ftOM.js +0 -1
  215. package/dist/gateway/static/root/assets/connectors-page-7zUxVHQg.js +0 -2
  216. package/dist/gateway/static/root/assets/cron-expression-BycQlU8Q.js +0 -2
  217. package/dist/gateway/static/root/assets/dependency-picker-BvYqHRz0.js +0 -1
  218. package/dist/gateway/static/root/assets/desktop-pet-settings-DStgPb82.js +0 -1
  219. package/dist/gateway/static/root/assets/directory-picker-path-field-DUUr9sq0.js +0 -1
  220. package/dist/gateway/static/root/assets/extension-settings-page-BcSKEU8s.js +0 -1
  221. package/dist/gateway/static/root/assets/gateway-config-api-C-MmtCc7.js +0 -1
  222. package/dist/gateway/static/root/assets/gateway-settings-CuaRDWbg.js +0 -1
  223. package/dist/gateway/static/root/assets/heartbeat-settings-Dm8TrfGa.js +0 -1
  224. package/dist/gateway/static/root/assets/home-page-BYhDbUvI.js +0 -3
  225. package/dist/gateway/static/root/assets/index-BzPwnXho.js +0 -150
  226. package/dist/gateway/static/root/assets/index-CFFYvilx.css +0 -1
  227. package/dist/gateway/static/root/assets/local-app-workbench-page-CHk4x0kR.js +0 -2
  228. package/dist/gateway/static/root/assets/local-apps-page-DQtsxjGs.js +0 -1
  229. package/dist/gateway/static/root/assets/logs-page-CDqIY72S.js +0 -2
  230. package/dist/gateway/static/root/assets/management-settings-D7itDEHl.js +0 -1
  231. package/dist/gateway/static/root/assets/messages-DQ5X6cXp.js +0 -3
  232. package/dist/gateway/static/root/assets/notes-workbench-epHGeKd5.js +0 -4
  233. package/dist/gateway/static/root/assets/page-tabs-HXweXqYE.js +0 -1
  234. package/dist/gateway/static/root/assets/preview-open-alternatives-Dob6Oe2l.js +0 -1
  235. package/dist/gateway/static/root/assets/project-detail-page-BxOD5-zj.js +0 -1
  236. package/dist/gateway/static/root/assets/projects-page-D-9AhrH5.js +0 -1
  237. package/dist/gateway/static/root/assets/remote-access-hub-CSUNXLKM.js +0 -1
  238. package/dist/gateway/static/root/assets/schema-form-BI4rVt3u.js +0 -1
  239. package/dist/gateway/static/root/assets/sessions-page-BxOUBMca.js +0 -1
  240. package/dist/gateway/static/root/assets/settings-advanced-gate-DAvTIbgw.js +0 -1
  241. package/dist/gateway/static/root/assets/settings-form-section-C7rzhi7x.js +0 -1
  242. package/dist/gateway/static/root/assets/settings-page-layout-CTMmZcwj.js +0 -1
  243. package/dist/gateway/static/root/assets/setup-status-panel-D1v-2Ci-.js +0 -1
  244. package/dist/gateway/static/root/assets/share-preview-page-BeCxg6eb.js +0 -2
  245. package/dist/gateway/static/root/assets/shares-settings-CXL1EldF.js +0 -1
  246. package/dist/gateway/static/root/assets/skill-reload-api-BxwkKgVw.js +0 -1
  247. package/dist/gateway/static/root/assets/skills-page-CyfjEM4D.js +0 -2
  248. package/dist/gateway/static/root/assets/system-settings-panel-CAv0Yk0Y.js +0 -1
  249. package/dist/gateway/static/root/assets/task-detail-page-DGTVJs_N.js +0 -1
  250. package/dist/gateway/static/root/assets/typed-models-lib-DomX3Szl.js +0 -1
  251. package/dist/gateway/static/root/assets/use-autosave-BLc4gfG0.js +0 -1
  252. package/dist/gateway/static/root/assets/user-context-page-C2kQENTK.js +0 -1
  253. package/dist/gateway/static/root/assets/voice-api-key-field-BijmpPjb.js +0 -1
  254. package/dist/gateway/static/root/assets/work-discovery-overlay-D7w2JFFq.js +0 -1
  255. package/dist/gateway/static/root/assets/work-discovery-page-XtoPgPUS.js +0 -1
  256. package/dist/gateway/static/root/assets/workflows-page-D_K2xOWq.js +0 -5
  257. package/dist/src/gateway/ensure-network-cors.d.ts +0 -3
  258. package/dist/src/gateway/ensure-network-cors.js +0 -23
@@ -16,6 +16,7 @@ var GatewayAgentRunner = class {
16
16
  clarifyBridge = new ClarifyBridge();
17
17
  /** Maps webchat session key → active `runId` for `clarify` tool routing. */
18
18
  activeWebchatRunBySession = /* @__PURE__ */ new Map();
19
+ externalStreamBySession = /* @__PURE__ */ new Map();
19
20
  inputs;
20
21
  constructor(opts) {
21
22
  this.opts = opts;
@@ -63,6 +64,19 @@ var GatewayAgentRunner = class {
63
64
  disposeClarifyBridge() {
64
65
  this.clarifyBridge.dispose();
65
66
  }
67
+ registerExternalWebchatRun(sessionKey, runId, publish) {
68
+ this.activeWebchatRunBySession.set(sessionKey, runId);
69
+ this.externalStreamBySession.set(sessionKey, publish);
70
+ }
71
+ unregisterExternalWebchatRun(sessionKey, runId) {
72
+ if (this.activeWebchatRunBySession.get(sessionKey) === runId) {
73
+ this.activeWebchatRunBySession.delete(sessionKey);
74
+ this.externalStreamBySession.delete(sessionKey);
75
+ }
76
+ }
77
+ cancelClarificationForRun(runId) {
78
+ this.clarifyBridge.cancelForRun(runId);
79
+ }
66
80
  async *runAgent(message, channel, chatId, origin, attachments, thinking, runOptions) {
67
81
  const trackedRunId = runOptions?.runId;
68
82
  if (trackedRunId) {
@@ -184,7 +198,7 @@ var GatewayAgentRunner = class {
184
198
  async requestClarification(opts) {
185
199
  const { sessionKey, request, publishStreamFor } = opts;
186
200
  const runId = this.activeWebchatRunBySession.get(sessionKey);
187
- const publishStream = runId ? publishStreamFor(runId) : void 0;
201
+ const publishStream = this.externalStreamBySession.get(sessionKey) ?? (runId ? publishStreamFor(runId) : void 0);
188
202
  const deliver = ((await this.opts.sessionIndex.getSessionMetadata(sessionKey).catch(() => null))?.routing)?.source === "telegram" ? async (ctx) => {
189
203
  await this.deliverTelegramClarify(ctx);
190
204
  } : void 0;
@@ -9,9 +9,9 @@ import { TaskRunCoordinator } from "../../tasks/task-run-coordinator.js";
9
9
  import { formatAgentRunErrorForClient } from "../../agent/client-error-format.js";
10
10
  import { prependEnvelopeTimestamp } from "../../channels/envelope-timestamp.js";
11
11
  import "../chat-limits.js";
12
+ import { ChatStreamMapper } from "../chat-stream/mapper.js";
12
13
  import { resolveWebchatSessionKey } from "../resolve-webchat-session-key.js";
13
14
  import { recordExplicitRelationshipFollowUp } from "../../user-context/relationship-continuity.js";
14
- import { ChatStreamMapper } from "../chat-stream/mapper.js";
15
15
  import { coalesceThinkingDeltas } from "../chat-stream/thinking-delta-coalescer.js";
16
16
  import crypto from "crypto";
17
17
  //#region src/gateway/service/run-gateway-agent.ts
@@ -6,6 +6,7 @@ import { NotesService } from '../notes/index.js';
6
6
  import { WorkflowRunService } from '../workflows/service/workflow-run-service.js';
7
7
  import { ExtensionLoader } from '../extensions/index.js';
8
8
  import { SessionIndex } from '../session/index.js';
9
+ import { EphemeralSideChatManager, SideChatRunService } from './side-chat/index.js';
9
10
  import type { Config } from '../config/schema.js';
10
11
  import { type ResolvedGatewayAuth } from './auth.js';
11
12
  import { ModelCatalogSyncService } from '../providers/model-catalog-sync-service.js';
@@ -79,6 +80,9 @@ export declare class GatewayService {
79
80
  * `activeWebchatRunBySession` + `runAbortControllers` maps.
80
81
  */
81
82
  readonly agentRunner: GatewayAgentRunner;
83
+ /** Process-local, non-persistent side conversations forked from durable sessions. */
84
+ readonly sideChats: EphemeralSideChatManager;
85
+ readonly sideChatRuns: SideChatRunService;
82
86
  /**
83
87
  * Session CRUD / search / compaction / tag-archive-pin / stats — the gateway
84
88
  * REST surface for sessions. Routes should depend on this narrow service
@@ -116,6 +120,7 @@ export declare class GatewayService {
116
120
  private createTaskRunDispatcher;
117
121
  private createMobileNotificationService;
118
122
  dispatchTaskRuns(): void;
123
+ dispatchTaskEvents(): void;
119
124
  runAgent(...args: Parameters<GatewayAgentRunner['runAgent']>): ReturnType<GatewayAgentRunner['runAgent']>;
120
125
  submitSessionInput(...args: Parameters<GatewayAgentRunner['submitSessionInput']>): Promise<{
121
126
  ok: true;
@@ -44,6 +44,7 @@ import { SessionIndex } from "../session/manager.js";
44
44
  import "../session/index.js";
45
45
  import { ExtensionLoader } from "../extensions/loader.js";
46
46
  import "../extensions/index.js";
47
+ import { getEmbeddedExecutionSession } from "../agent/embedded/execution-context.js";
47
48
  import { MessageBus, MessageBusShutdownError } from "../infra/bus/queue.js";
48
49
  import "../infra/bus/index.js";
49
50
  import { AgentService } from "../agent/service.js";
@@ -77,6 +78,9 @@ import { WorkflowRunService } from "../workflows/service/workflow-run-service.js
77
78
  import { WorkflowSessionBridge } from "../workflows/service/workflow-session-bridge.js";
78
79
  import { HeartbeatService, heartbeatRunnerConfigFromConfig } from "./heartbeat/service.js";
79
80
  import "./heartbeat/index.js";
81
+ import { EphemeralSideChatManager } from "./side-chat/manager.js";
82
+ import { SideChatRunService } from "./side-chat/run-service.js";
83
+ import "./side-chat/index.js";
80
84
  import { stopTailscaleExposure } from "./tailscale-lifecycle.js";
81
85
  import { getExposureManager } from "../remote-access/exposure-manager.js";
82
86
  import { assertGatewayAuthNotKnownWeak } from "./security/known-weak-secrets.js";
@@ -190,6 +194,9 @@ var GatewayService = class {
190
194
  * `activeWebchatRunBySession` + `runAbortControllers` maps.
191
195
  */
192
196
  agentRunner;
197
+ /** Process-local, non-persistent side conversations forked from durable sessions. */
198
+ sideChats;
199
+ sideChatRuns;
193
200
  /**
194
201
  * Session CRUD / search / compaction / tag-archive-pin / stats — the gateway
195
202
  * REST surface for sessions. Routes should depend on this narrow service
@@ -363,6 +370,21 @@ var GatewayService = class {
363
370
  },
364
371
  completeRealtimeTopic: (topic) => this.realtime.completeTopic(topic)
365
372
  });
373
+ let sideChatRuns;
374
+ this.sideChats = new EphemeralSideChatManager({
375
+ getParentMetadata: (sessionKey) => this.sessionIndex.getSessionMetadata(sessionKey),
376
+ loadParentMessages: (sessionKey) => this.sessionIndex.getStore().load(sessionKey),
377
+ getDefaultModelRef: (sessionKey) => this.ensureAgentService().getModelForSession(sessionKey),
378
+ getWorkspacePath: (metadata) => metadata.cwd || this.currentWorkspacePath,
379
+ onBeforeDispose: (sideChatId, clientInstanceId) => sideChatRuns?.abort(sideChatId, clientInstanceId).then(() => void 0)
380
+ });
381
+ this.sideChatRuns = sideChatRuns = new SideChatRunService({
382
+ manager: this.sideChats,
383
+ getAgentService: () => this.ensureAgentService(),
384
+ agentRunner: this.agentRunner,
385
+ publishRealtime: (topic, event, data) => this.realtime.broker.publish(topic, event, data),
386
+ completeRealtimeTopic: (topic) => this.realtime.completeTopic(topic)
387
+ });
366
388
  this.sessions = new GatewaySessionsApi({
367
389
  sessionIndex: this.sessionIndex,
368
390
  getAgentService: () => this.ensureAgentService(),
@@ -438,6 +460,7 @@ var GatewayService = class {
438
460
  getNotesService: () => this.notesService,
439
461
  getProjectService: () => this.projects,
440
462
  getLocalAppService: () => this.localApps,
463
+ dispatchTaskEvents: () => this.dispatchTaskEvents(),
441
464
  dispatchTaskRuns: () => this.dispatchTaskRuns(),
442
465
  getWorkflowRunService: () => this.createWorkflowRunService(),
443
466
  sourceContextResolver: async (binding) => {
@@ -452,13 +475,16 @@ var GatewayService = class {
452
475
  }
453
476
  return null;
454
477
  },
455
- gatewayClarify: { requestClarification: (sessionKey, request) => this.agentRunner.requestClarification({
456
- sessionKey,
457
- request,
458
- publishStreamFor: (_runId) => (event) => {
459
- this._agentService.turnDispatcher.enqueueWebchatStreamEvent(sessionKey, event);
460
- }
461
- }) }
478
+ gatewayClarify: { requestClarification: (sessionKey, request) => {
479
+ const executionSessionKey = getEmbeddedExecutionSession() ?? sessionKey;
480
+ return this.agentRunner.requestClarification({
481
+ sessionKey: executionSessionKey,
482
+ request,
483
+ publishStreamFor: (_runId) => (event) => {
484
+ this._agentService.turnDispatcher.enqueueWebchatStreamEvent(executionSessionKey, event);
485
+ }
486
+ });
487
+ } }
462
488
  });
463
489
  this._agentService.setChannelManager(this.channelManager);
464
490
  this.channelManager.setSessionModelHooks({
@@ -568,10 +594,13 @@ var GatewayService = class {
568
594
  }
569
595
  dispatchTaskRuns() {
570
596
  new TaskSignalService().tick();
571
- new TaskOutboxDispatcher(publishAutomationProductEvent).drain();
597
+ this.dispatchTaskEvents();
572
598
  this.createTaskRunDispatcher().dispatch();
573
599
  this.createWorkflowRunService().dispatchTaskRuns();
574
600
  }
601
+ dispatchTaskEvents() {
602
+ new TaskOutboxDispatcher(publishAutomationProductEvent).drain();
603
+ }
575
604
  runAgent(...args) {
576
605
  return this.agentRunner.runAgent(...args);
577
606
  }
@@ -988,6 +1017,7 @@ var GatewayService = class {
988
1017
  log.debug("Stopping gateway service...");
989
1018
  this.readiness.markStarting();
990
1019
  this.endpointTools.close();
1020
+ await this.sideChats.disposeAll();
991
1021
  this.realtime.close();
992
1022
  await this.proactiveWorker.stop();
993
1023
  await this.discussionWorker.stop();
@@ -0,0 +1,11 @@
1
+ import type { AgentMessage } from '@earendil-works/pi-agent-core';
2
+ import type { SideChatContextSnapshot, SideChatSelection } from './types.js';
3
+ export declare function validateSideChatSelections(value: unknown): SideChatSelection[];
4
+ export declare function createSideChatContextSnapshot(params: {
5
+ parentSessionKey: string;
6
+ parentSessionId: string;
7
+ parentMessages: readonly AgentMessage[];
8
+ selections: readonly SideChatSelection[];
9
+ createdAt: string;
10
+ }): SideChatContextSnapshot;
11
+ export declare function formatSideChatSelections(selections: readonly SideChatSelection[]): string | null;
@@ -0,0 +1,108 @@
1
+ import { createHash } from "node:crypto";
2
+ //#region src/gateway/side-chat/context-snapshot.ts
3
+ const MAX_SELECTIONS = 20;
4
+ const MAX_SELECTION_CHARS = 32e3;
5
+ const MAX_TOTAL_SELECTION_CHARS = 128e3;
6
+ function selectionText(selection) {
7
+ switch (selection.type) {
8
+ case "message": return selection.content;
9
+ case "text": return selection.text;
10
+ case "file-range": return selection.text;
11
+ case "diff": return selection.diff;
12
+ }
13
+ }
14
+ function validateSideChatSelections(value) {
15
+ if (value === void 0) return [];
16
+ if (!Array.isArray(value)) throw new Error("selections must be an array");
17
+ if (value.length > MAX_SELECTIONS) throw new Error(`selections cannot exceed ${MAX_SELECTIONS} items`);
18
+ let totalChars = 0;
19
+ const selections = value.map((candidate, index) => {
20
+ if (!candidate || typeof candidate !== "object") throw new Error(`selection ${index} must be an object`);
21
+ const selection = candidate;
22
+ const id = typeof selection.id === "string" ? selection.id.trim() : "";
23
+ const type = selection.type;
24
+ if (!id) throw new Error(`selection ${index} requires id`);
25
+ let normalized;
26
+ if (type === "message") normalized = {
27
+ id,
28
+ type,
29
+ messageId: requiredString(selection.messageId, `selection ${index} messageId`),
30
+ role: requiredString(selection.role, `selection ${index} role`),
31
+ content: requiredString(selection.content, `selection ${index} content`),
32
+ label: optionalString(selection.label)
33
+ };
34
+ else if (type === "text") normalized = {
35
+ id,
36
+ type,
37
+ text: requiredString(selection.text, `selection ${index} text`),
38
+ sourceMessageId: optionalString(selection.sourceMessageId),
39
+ label: optionalString(selection.label)
40
+ };
41
+ else if (type === "file-range") {
42
+ const startLine = positiveInteger(selection.startLine, `selection ${index} startLine`);
43
+ const endLine = positiveInteger(selection.endLine, `selection ${index} endLine`);
44
+ if (endLine < startLine) throw new Error(`selection ${index} endLine must be >= startLine`);
45
+ normalized = {
46
+ id,
47
+ type,
48
+ path: requiredString(selection.path, `selection ${index} path`),
49
+ startLine,
50
+ endLine,
51
+ text: requiredString(selection.text, `selection ${index} text`),
52
+ contentHash: optionalString(selection.contentHash),
53
+ label: optionalString(selection.label)
54
+ };
55
+ } else if (type === "diff") normalized = {
56
+ id,
57
+ type,
58
+ diff: requiredString(selection.diff, `selection ${index} diff`),
59
+ path: optionalString(selection.path),
60
+ label: optionalString(selection.label)
61
+ };
62
+ else throw new Error(`selection ${index} has unsupported type`);
63
+ const chars = selectionText(normalized).length;
64
+ if (chars > MAX_SELECTION_CHARS) throw new Error(`selection ${index} exceeds ${MAX_SELECTION_CHARS} characters`);
65
+ totalChars += chars;
66
+ return normalized;
67
+ });
68
+ if (totalChars > MAX_TOTAL_SELECTION_CHARS) throw new Error(`selection content exceeds ${MAX_TOTAL_SELECTION_CHARS} characters`);
69
+ return selections;
70
+ }
71
+ function createSideChatContextSnapshot(params) {
72
+ const selections = structuredClone(params.selections);
73
+ const digest = createHash("sha256").update(JSON.stringify({
74
+ messages: params.parentMessages,
75
+ selections
76
+ })).digest("hex");
77
+ return {
78
+ parentSessionKey: params.parentSessionKey,
79
+ parentSessionId: params.parentSessionId,
80
+ parentMessageCount: params.parentMessages.length,
81
+ createdAt: params.createdAt,
82
+ selections,
83
+ contentHash: digest
84
+ };
85
+ }
86
+ function formatSideChatSelections(selections) {
87
+ if (selections.length === 0) return null;
88
+ return `The user attached the following immutable context snapshot to this side chat:\n\n${selections.map((selection, index) => {
89
+ const title = selection.label || `${selection.type} ${index + 1}`;
90
+ if (selection.type === "file-range") return `### ${title}\nSource: ${selection.path}:${selection.startLine}-${selection.endLine}\n\n${selection.text}`;
91
+ if (selection.type === "message") return `### ${title}\nSource message: ${selection.messageId} (${selection.role})\n\n${selection.content}`;
92
+ if (selection.type === "diff") return `### ${title}${selection.path ? `\nSource: ${selection.path}` : ""}\n\n${selection.diff}`;
93
+ return `### ${title}${selection.sourceMessageId ? `\nSource message: ${selection.sourceMessageId}` : ""}\n\n${selection.text}`;
94
+ }).join("\n\n")}`;
95
+ }
96
+ function requiredString(value, label) {
97
+ if (typeof value !== "string" || !value.trim()) throw new Error(`${label} is required`);
98
+ return value;
99
+ }
100
+ function optionalString(value) {
101
+ return typeof value === "string" && value.trim() ? value : void 0;
102
+ }
103
+ function positiveInteger(value, label) {
104
+ if (!Number.isInteger(value) || Number(value) < 1) throw new Error(`${label} must be a positive integer`);
105
+ return Number(value);
106
+ }
107
+ //#endregion
108
+ export { createSideChatContextSnapshot, formatSideChatSelections, validateSideChatSelections };
@@ -0,0 +1,5 @@
1
+ export { EphemeralSideChatManager, SideChatError, parseThinkingLevel } from './manager.js';
2
+ export type { EphemeralSideChatManagerOptions } from './manager.js';
3
+ export { validateSideChatSelections } from './context-snapshot.js';
4
+ export { SideChatRunService } from './run-service.js';
5
+ export type { CreateSideChatInput, SideChatConfig, SideChatContextSnapshot, SideChatSelection, SideChatStatus, SideChatView, } from './types.js';
@@ -0,0 +1,4 @@
1
+ import { validateSideChatSelections } from "./context-snapshot.js";
2
+ import { EphemeralSideChatManager, SideChatError, parseThinkingLevel } from "./manager.js";
3
+ import { SideChatRunService } from "./run-service.js";
4
+ export { EphemeralSideChatManager, SideChatError, SideChatRunService, parseThinkingLevel, validateSideChatSelections };
@@ -0,0 +1,45 @@
1
+ import type { AgentMessage, ThinkingLevel } from '@earendil-works/pi-agent-core';
2
+ import { InMemoryTranscriptRuntime } from '../../agent/embedded/transcript-runtime.js';
3
+ import type { SessionMetadata } from '../../session/types.js';
4
+ import type { CreateSideChatInput, SideChatConfig, SideChatStatus, SideChatView } from './types.js';
5
+ export declare class SideChatError extends Error {
6
+ readonly code: 'INVALID_REQUEST' | 'NOT_FOUND' | 'LIMIT_REACHED' | 'CONFLICT';
7
+ constructor(message: string, code: 'INVALID_REQUEST' | 'NOT_FOUND' | 'LIMIT_REACHED' | 'CONFLICT');
8
+ }
9
+ export interface EphemeralSideChatManagerOptions {
10
+ getParentMetadata: (sessionKey: string) => Promise<SessionMetadata | null>;
11
+ loadParentMessages: (sessionKey: string) => Promise<AgentMessage[]>;
12
+ getDefaultModelRef: (sessionKey: string) => string;
13
+ getWorkspacePath: (metadata: SessionMetadata) => string;
14
+ idleTtlMs?: number;
15
+ maxPerClient?: number;
16
+ maxTotal?: number;
17
+ now?: () => number;
18
+ startSweepTimer?: boolean;
19
+ onBeforeDispose?: (sideChatId: string, clientInstanceId: string) => void | Promise<void>;
20
+ }
21
+ export declare class EphemeralSideChatManager {
22
+ private readonly options;
23
+ private readonly entries;
24
+ private readonly now;
25
+ private readonly idleTtlMs;
26
+ private readonly maxPerClient;
27
+ private readonly maxTotal;
28
+ private readonly sweepTimer;
29
+ constructor(options: EphemeralSideChatManagerOptions);
30
+ create(input: CreateSideChatInput): Promise<SideChatView>;
31
+ get(id: string, clientInstanceId: string): SideChatView;
32
+ getRuntime(id: string, clientInstanceId: string): InMemoryTranscriptRuntime;
33
+ getMessages(id: string, clientInstanceId: string): AgentMessage[];
34
+ updateConfig(id: string, clientInstanceId: string, patch: Partial<SideChatConfig>): SideChatView;
35
+ heartbeat(id: string, clientInstanceId: string): SideChatView;
36
+ setStatus(id: string, clientInstanceId: string, status: SideChatStatus): SideChatView;
37
+ dispose(id: string, clientInstanceId: string): Promise<boolean>;
38
+ disposeClient(clientInstanceId: string): Promise<number>;
39
+ sweepExpired(at?: number): Promise<number>;
40
+ disposeAll(): Promise<void>;
41
+ private requireEntry;
42
+ private touchEntry;
43
+ private runBeforeDispose;
44
+ }
45
+ export declare function parseThinkingLevel(value: unknown): ThinkingLevel | undefined;
@@ -0,0 +1,198 @@
1
+ import { createLogger } from "../../utils/logger/index.js";
2
+ import { init_logger } from "../../utils/logger.js";
3
+ import { evictEmbeddedSessionRunner } from "../../agent/embedded/session-runner.js";
4
+ import { InMemoryTranscriptRuntime } from "../../agent/embedded/transcript-runtime.js";
5
+ import { createSideChatContextSnapshot, formatSideChatSelections, validateSideChatSelections } from "./context-snapshot.js";
6
+ import { randomUUID } from "node:crypto";
7
+ //#region src/gateway/side-chat/manager.ts
8
+ init_logger();
9
+ const DEFAULT_IDLE_TTL_MS = 1800 * 1e3;
10
+ const DEFAULT_MAX_PER_CLIENT = 5;
11
+ const DEFAULT_MAX_TOTAL = 50;
12
+ const log = createLogger("Gateway:SideChat");
13
+ var SideChatError = class extends Error {
14
+ constructor(message, code) {
15
+ super(message);
16
+ this.code = code;
17
+ }
18
+ };
19
+ var EphemeralSideChatManager = class {
20
+ entries = /* @__PURE__ */ new Map();
21
+ now;
22
+ idleTtlMs;
23
+ maxPerClient;
24
+ maxTotal;
25
+ sweepTimer;
26
+ constructor(options) {
27
+ this.options = options;
28
+ this.now = options.now ?? Date.now;
29
+ this.idleTtlMs = options.idleTtlMs ?? DEFAULT_IDLE_TTL_MS;
30
+ this.maxPerClient = options.maxPerClient ?? DEFAULT_MAX_PER_CLIENT;
31
+ this.maxTotal = options.maxTotal ?? DEFAULT_MAX_TOTAL;
32
+ this.sweepTimer = options.startSweepTimer === false ? null : setInterval(() => {
33
+ this.sweepExpired().catch((err) => {
34
+ log.warn({
35
+ err,
36
+ phase: "side_chat_sweep"
37
+ }, "Side chat expiry sweep failed");
38
+ });
39
+ }, Math.min(this.idleTtlMs, 6e4));
40
+ this.sweepTimer?.unref();
41
+ }
42
+ async create(input) {
43
+ const parentSessionKey = input.parentSessionKey.trim();
44
+ const clientInstanceId = input.clientInstanceId.trim();
45
+ if (!parentSessionKey || !clientInstanceId) throw new SideChatError("parentSessionKey and clientInstanceId are required", "INVALID_REQUEST");
46
+ if (this.entries.size >= this.maxTotal) throw new SideChatError("The side chat capacity has been reached", "LIMIT_REACHED");
47
+ if ([...this.entries.values()].filter((entry) => entry.clientInstanceId === clientInstanceId).length >= this.maxPerClient) throw new SideChatError(`A client can have at most ${this.maxPerClient} side chats`, "LIMIT_REACHED");
48
+ const metadata = await this.options.getParentMetadata(parentSessionKey);
49
+ if (!metadata || !metadata.sessionId) throw new SideChatError("Parent session not found", "NOT_FOUND");
50
+ const parentMessages = await this.options.loadParentMessages(parentSessionKey);
51
+ let selections;
52
+ try {
53
+ selections = validateSideChatSelections(input.selections);
54
+ } catch (error) {
55
+ throw new SideChatError(error instanceof Error ? error.message : "Invalid selections", "INVALID_REQUEST");
56
+ }
57
+ const now = this.now();
58
+ const createdAt = new Date(now).toISOString();
59
+ const id = randomUUID();
60
+ const runtime = new InMemoryTranscriptRuntime({
61
+ runtimeId: `${parentSessionKey}:side-chat:${id}`,
62
+ cwd: this.options.getWorkspacePath(metadata),
63
+ initialMessages: structuredClone(parentMessages)
64
+ });
65
+ const selectionContext = formatSideChatSelections(selections);
66
+ if (selectionContext) runtime.openSessionManager(this.options.getWorkspacePath(metadata)).appendCustomMessageEntry("side-chat-selection", selectionContext, false);
67
+ runtime.captureBaseline();
68
+ const config = {
69
+ modelRef: normalizeOptionalString(input.config?.modelRef) || this.options.getDefaultModelRef(parentSessionKey),
70
+ thinkingLevel: input.config?.thinkingLevel
71
+ };
72
+ const entry = {
73
+ id,
74
+ parentSessionKey,
75
+ clientInstanceId,
76
+ status: "idle",
77
+ createdAt,
78
+ lastActiveAt: createdAt,
79
+ expiresAt: new Date(now + this.idleTtlMs).toISOString(),
80
+ messageCount: 0,
81
+ context: createSideChatContextSnapshot({
82
+ parentSessionKey,
83
+ parentSessionId: metadata.sessionId,
84
+ parentMessages,
85
+ selections,
86
+ createdAt
87
+ }),
88
+ config,
89
+ runtime
90
+ };
91
+ this.entries.set(id, entry);
92
+ return toView(entry);
93
+ }
94
+ get(id, clientInstanceId) {
95
+ return toView(this.requireEntry(id, clientInstanceId));
96
+ }
97
+ getRuntime(id, clientInstanceId) {
98
+ return this.requireEntry(id, clientInstanceId).runtime;
99
+ }
100
+ getMessages(id, clientInstanceId) {
101
+ const entry = this.requireEntry(id, clientInstanceId);
102
+ const messages = entry.runtime.loadConversationMessages();
103
+ entry.messageCount = messages.length;
104
+ return structuredClone(messages);
105
+ }
106
+ updateConfig(id, clientInstanceId, patch) {
107
+ const entry = this.requireEntry(id, clientInstanceId);
108
+ if (entry.status === "running") throw new SideChatError("Cannot change config while a run is active", "CONFLICT");
109
+ const modelRef = patch.modelRef === void 0 ? entry.config.modelRef : normalizeOptionalString(patch.modelRef);
110
+ if (!modelRef) throw new SideChatError("modelRef cannot be empty", "INVALID_REQUEST");
111
+ entry.config = {
112
+ modelRef,
113
+ thinkingLevel: patch.thinkingLevel === void 0 ? entry.config.thinkingLevel : patch.thinkingLevel
114
+ };
115
+ this.touchEntry(entry);
116
+ return toView(entry);
117
+ }
118
+ heartbeat(id, clientInstanceId) {
119
+ const entry = this.requireEntry(id, clientInstanceId);
120
+ this.touchEntry(entry);
121
+ return toView(entry);
122
+ }
123
+ setStatus(id, clientInstanceId, status) {
124
+ const entry = this.requireEntry(id, clientInstanceId);
125
+ entry.status = status;
126
+ this.touchEntry(entry);
127
+ return toView(entry);
128
+ }
129
+ async dispose(id, clientInstanceId) {
130
+ const entry = this.entries.get(id);
131
+ if (!entry || entry.clientInstanceId !== clientInstanceId) return false;
132
+ entry.status = "closing";
133
+ await this.runBeforeDispose(id, clientInstanceId);
134
+ this.entries.delete(id);
135
+ await evictEmbeddedSessionRunner(entry.runtime.runtimeId, "side_chat_dispose");
136
+ return true;
137
+ }
138
+ async disposeClient(clientInstanceId) {
139
+ const ids = [...this.entries.values()].filter((entry) => entry.clientInstanceId === clientInstanceId).map((entry) => entry.id);
140
+ await Promise.all(ids.map((id) => this.dispose(id, clientInstanceId)));
141
+ return ids.length;
142
+ }
143
+ async sweepExpired(at = this.now()) {
144
+ const expired = [...this.entries.values()].filter((entry) => Date.parse(entry.expiresAt) <= at);
145
+ await Promise.all(expired.map((entry) => this.dispose(entry.id, entry.clientInstanceId)));
146
+ return expired.length;
147
+ }
148
+ async disposeAll() {
149
+ if (this.sweepTimer) clearInterval(this.sweepTimer);
150
+ const entries = [...this.entries.values()];
151
+ await Promise.all(entries.map((entry) => this.runBeforeDispose(entry.id, entry.clientInstanceId)));
152
+ this.entries.clear();
153
+ await Promise.all(entries.map((entry) => evictEmbeddedSessionRunner(entry.runtime.runtimeId, "side_chat_shutdown")));
154
+ }
155
+ requireEntry(id, clientInstanceId) {
156
+ const entry = this.entries.get(id);
157
+ if (!entry || entry.clientInstanceId !== clientInstanceId) throw new SideChatError("Side chat not found", "NOT_FOUND");
158
+ return entry;
159
+ }
160
+ touchEntry(entry) {
161
+ const now = this.now();
162
+ entry.lastActiveAt = new Date(now).toISOString();
163
+ entry.expiresAt = new Date(now + this.idleTtlMs).toISOString();
164
+ }
165
+ async runBeforeDispose(id, clientInstanceId) {
166
+ try {
167
+ await this.options.onBeforeDispose?.(id, clientInstanceId);
168
+ } catch (err) {
169
+ log.warn({
170
+ err,
171
+ sideChatId: id,
172
+ phase: "side_chat_abort"
173
+ }, "Side chat run cleanup failed");
174
+ }
175
+ }
176
+ };
177
+ function toView(entry) {
178
+ const { runtime: _runtime, ...view } = entry;
179
+ return structuredClone(view);
180
+ }
181
+ function normalizeOptionalString(value) {
182
+ return typeof value === "string" && value.trim() ? value.trim() : void 0;
183
+ }
184
+ function parseThinkingLevel(value) {
185
+ if (value === void 0 || value === null || value === "") return void 0;
186
+ if (typeof value !== "string" || !new Set([
187
+ "off",
188
+ "minimal",
189
+ "low",
190
+ "medium",
191
+ "high",
192
+ "xhigh",
193
+ "max"
194
+ ]).has(value)) throw new SideChatError("Invalid thinkingLevel", "INVALID_REQUEST");
195
+ return value;
196
+ }
197
+ //#endregion
198
+ export { EphemeralSideChatManager, SideChatError, parseThinkingLevel };
@@ -0,0 +1,22 @@
1
+ import type { AgentService } from '../../agent/service.js';
2
+ import type { GatewayAgentRunner } from '../service/agent-runner.js';
3
+ import { type EphemeralSideChatManager } from './manager.js';
4
+ export interface SideChatRunServiceOptions {
5
+ manager: EphemeralSideChatManager;
6
+ getAgentService: () => AgentService;
7
+ agentRunner: GatewayAgentRunner;
8
+ publishRealtime: (topic: string, event: string, data: unknown) => void;
9
+ completeRealtimeTopic: (topic: string) => void;
10
+ }
11
+ export declare class SideChatRunService {
12
+ private readonly options;
13
+ private readonly activeBySideChat;
14
+ constructor(options: SideChatRunServiceOptions);
15
+ submit(sideChatId: string, clientInstanceId: string, content: string): {
16
+ runId: string;
17
+ };
18
+ abort(sideChatId: string, clientInstanceId: string, runId?: string): Promise<boolean>;
19
+ dispose(sideChatId: string, clientInstanceId: string): Promise<boolean>;
20
+ submitClarification(sideChatId: string, clientInstanceId: string, requestId: string, answer: string): boolean;
21
+ private execute;
22
+ }