@rudderhq/server 0.3.6-canary.9 → 0.4.1

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 (346) hide show
  1. package/dist/bootstrap/register-api-routes.d.ts.map +1 -1
  2. package/dist/bootstrap/register-api-routes.js +2 -0
  3. package/dist/bootstrap/register-api-routes.js.map +1 -1
  4. package/dist/bundled-plugins/plugin-linear/dist/worker.js +37 -2
  5. package/dist/bundled-plugins/plugin-linear/dist/worker.js.map +2 -2
  6. package/dist/config.d.ts +1 -0
  7. package/dist/config.d.ts.map +1 -1
  8. package/dist/config.js +15 -1
  9. package/dist/config.js.map +1 -1
  10. package/dist/home-paths.d.ts +11 -0
  11. package/dist/home-paths.d.ts.map +1 -1
  12. package/dist/home-paths.js +151 -8
  13. package/dist/home-paths.js.map +1 -1
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.js +103 -26
  16. package/dist/index.js.map +1 -1
  17. package/dist/routes/activity.d.ts +1 -1
  18. package/dist/routes/activity.d.ts.map +1 -1
  19. package/dist/routes/activity.js +21 -5
  20. package/dist/routes/activity.js.map +1 -1
  21. package/dist/routes/agents.d.ts.map +1 -1
  22. package/dist/routes/agents.js +254 -4
  23. package/dist/routes/agents.js.map +1 -1
  24. package/dist/routes/agents.management-routes.d.ts.map +1 -1
  25. package/dist/routes/agents.management-routes.js +132 -40
  26. package/dist/routes/agents.management-routes.js.map +1 -1
  27. package/dist/routes/automations.d.ts +8 -0
  28. package/dist/routes/automations.d.ts.map +1 -1
  29. package/dist/routes/automations.js.map +1 -1
  30. package/dist/routes/chats.d.ts.map +1 -1
  31. package/dist/routes/chats.js +228 -115
  32. package/dist/routes/chats.js.map +1 -1
  33. package/dist/routes/chats.stream-routes.d.ts.map +1 -1
  34. package/dist/routes/chats.stream-routes.js +94 -5
  35. package/dist/routes/chats.stream-routes.js.map +1 -1
  36. package/dist/routes/instance-settings.d.ts.map +1 -1
  37. package/dist/routes/instance-settings.js +60 -9
  38. package/dist/routes/instance-settings.js.map +1 -1
  39. package/dist/routes/issues.comments-attachments.d.ts.map +1 -1
  40. package/dist/routes/issues.comments-attachments.js +72 -83
  41. package/dist/routes/issues.comments-attachments.js.map +1 -1
  42. package/dist/routes/issues.d.ts +8 -0
  43. package/dist/routes/issues.d.ts.map +1 -1
  44. package/dist/routes/issues.js +27 -4
  45. package/dist/routes/issues.js.map +1 -1
  46. package/dist/routes/issues.mutations.d.ts.map +1 -1
  47. package/dist/routes/issues.mutations.js +2 -26
  48. package/dist/routes/issues.mutations.js.map +1 -1
  49. package/dist/routes/messenger.d.ts.map +1 -1
  50. package/dist/routes/messenger.js +39 -1
  51. package/dist/routes/messenger.js.map +1 -1
  52. package/dist/routes/orgs.d.ts.map +1 -1
  53. package/dist/routes/orgs.js +16 -0
  54. package/dist/routes/orgs.js.map +1 -1
  55. package/dist/routes/plugin-ui-static.d.ts +4 -4
  56. package/dist/routes/plugin-ui-static.js +5 -5
  57. package/dist/routes/plugin-ui-static.js.map +1 -1
  58. package/dist/routes/plugins.d.ts +4 -4
  59. package/dist/routes/plugins.js +10 -10
  60. package/dist/routes/plugins.operations-routes.d.ts +1 -1
  61. package/dist/routes/plugins.operations-routes.js +2 -2
  62. package/dist/routes/plugins.operations-routes.js.map +1 -1
  63. package/dist/routes/run-intelligence.js +5 -5
  64. package/dist/routes/run-intelligence.js.map +1 -1
  65. package/dist/routes/sidebar-badges.d.ts.map +1 -1
  66. package/dist/routes/sidebar-badges.js +6 -10
  67. package/dist/routes/sidebar-badges.js.map +1 -1
  68. package/dist/routes/website-metadata.d.ts +8 -0
  69. package/dist/routes/website-metadata.d.ts.map +1 -0
  70. package/dist/routes/website-metadata.js +67 -0
  71. package/dist/routes/website-metadata.js.map +1 -0
  72. package/dist/services/activity.d.ts.map +1 -1
  73. package/dist/services/activity.js +1 -1
  74. package/dist/services/activity.js.map +1 -1
  75. package/dist/services/agent-instructions.d.ts +1 -0
  76. package/dist/services/agent-instructions.d.ts.map +1 -1
  77. package/dist/services/agent-instructions.js +57 -6
  78. package/dist/services/agent-instructions.js.map +1 -1
  79. package/dist/services/agent-run-context.d.ts +3 -1
  80. package/dist/services/agent-run-context.d.ts.map +1 -1
  81. package/dist/services/agent-run-context.js +7 -0
  82. package/dist/services/agent-run-context.js.map +1 -1
  83. package/dist/services/agent-startup-context.d.ts +2 -1
  84. package/dist/services/agent-startup-context.d.ts.map +1 -1
  85. package/dist/services/agent-startup-context.js +6 -26
  86. package/dist/services/agent-startup-context.js.map +1 -1
  87. package/dist/services/agents.d.ts +9 -1
  88. package/dist/services/agents.d.ts.map +1 -1
  89. package/dist/services/agents.js.map +1 -1
  90. package/dist/services/approvals.d.ts +8 -0
  91. package/dist/services/approvals.d.ts.map +1 -1
  92. package/dist/services/approvals.js.map +1 -1
  93. package/dist/services/automation-chat-output.d.ts +1 -1
  94. package/dist/services/automations.d.ts +4 -4
  95. package/dist/services/automations.d.ts.map +1 -1
  96. package/dist/services/automations.js +12 -0
  97. package/dist/services/automations.js.map +1 -1
  98. package/dist/services/budgets.d.ts +8 -0
  99. package/dist/services/budgets.d.ts.map +1 -1
  100. package/dist/services/budgets.js.map +1 -1
  101. package/dist/services/calendar.d.ts +2 -2
  102. package/dist/services/calendar.js +3 -3
  103. package/dist/services/calendar.js.map +1 -1
  104. package/dist/services/chat-agent-runs.d.ts +2 -0
  105. package/dist/services/chat-agent-runs.d.ts.map +1 -1
  106. package/dist/services/chat-agent-runs.js +6 -0
  107. package/dist/services/chat-agent-runs.js.map +1 -1
  108. package/dist/services/chat-assistant.d.ts.map +1 -1
  109. package/dist/services/chat-assistant.helpers.d.ts +6 -1
  110. package/dist/services/chat-assistant.helpers.d.ts.map +1 -1
  111. package/dist/services/chat-assistant.helpers.js +25 -11
  112. package/dist/services/chat-assistant.helpers.js.map +1 -1
  113. package/dist/services/chat-assistant.js +230 -95
  114. package/dist/services/chat-assistant.js.map +1 -1
  115. package/dist/services/chat-generation-locks.d.ts +6 -1
  116. package/dist/services/chat-generation-locks.d.ts.map +1 -1
  117. package/dist/services/chat-generation-locks.js +20 -2
  118. package/dist/services/chat-generation-locks.js.map +1 -1
  119. package/dist/services/chat-title-generation.d.ts +36 -0
  120. package/dist/services/chat-title-generation.d.ts.map +1 -0
  121. package/dist/services/chat-title-generation.js +107 -0
  122. package/dist/services/chat-title-generation.js.map +1 -0
  123. package/dist/services/chats.d.ts +471 -25
  124. package/dist/services/chats.d.ts.map +1 -1
  125. package/dist/services/chats.helpers.d.ts +2 -2
  126. package/dist/services/chats.js +681 -35
  127. package/dist/services/chats.js.map +1 -1
  128. package/dist/services/costs.d.ts +1 -1
  129. package/dist/services/finance.d.ts +2 -2
  130. package/dist/services/finance.js +1 -1
  131. package/dist/services/finance.js.map +1 -1
  132. package/dist/services/goals.d.ts +8 -0
  133. package/dist/services/goals.d.ts.map +1 -1
  134. package/dist/services/goals.js.map +1 -1
  135. package/dist/services/heartbeat-run-reference.d.ts +1 -0
  136. package/dist/services/heartbeat-run-reference.d.ts.map +1 -1
  137. package/dist/services/heartbeat-run-reference.js +3 -2
  138. package/dist/services/heartbeat-run-reference.js.map +1 -1
  139. package/dist/services/heartbeat-run-summary.js +1 -1
  140. package/dist/services/heartbeat-run-summary.js.map +1 -1
  141. package/dist/services/integrations/agent-integrations.d.ts +19 -0
  142. package/dist/services/integrations/agent-integrations.d.ts.map +1 -1
  143. package/dist/services/integrations/agent-integrations.js +30 -0
  144. package/dist/services/integrations/agent-integrations.js.map +1 -1
  145. package/dist/services/integrations/feishu/app-registration.d.ts +74 -0
  146. package/dist/services/integrations/feishu/app-registration.d.ts.map +1 -0
  147. package/dist/services/integrations/feishu/app-registration.js +236 -0
  148. package/dist/services/integrations/feishu/app-registration.js.map +1 -0
  149. package/dist/services/integrations/feishu/inbound-dispatcher-db.d.ts +5 -0
  150. package/dist/services/integrations/feishu/inbound-dispatcher-db.d.ts.map +1 -1
  151. package/dist/services/integrations/feishu/inbound-dispatcher-db.js +178 -7
  152. package/dist/services/integrations/feishu/inbound-dispatcher-db.js.map +1 -1
  153. package/dist/services/integrations/feishu/inbound-dispatcher.d.ts +23 -0
  154. package/dist/services/integrations/feishu/inbound-dispatcher.d.ts.map +1 -1
  155. package/dist/services/integrations/feishu/inbound-dispatcher.js +25 -0
  156. package/dist/services/integrations/feishu/inbound-dispatcher.js.map +1 -1
  157. package/dist/services/integrations/feishu/runtime-registry.d.ts +20 -0
  158. package/dist/services/integrations/feishu/runtime-registry.d.ts.map +1 -0
  159. package/dist/services/integrations/feishu/runtime-registry.js +41 -0
  160. package/dist/services/integrations/feishu/runtime-registry.js.map +1 -0
  161. package/dist/services/integrations/feishu/runtime.d.ts +39 -23
  162. package/dist/services/integrations/feishu/runtime.d.ts.map +1 -1
  163. package/dist/services/integrations/feishu/runtime.js +333 -95
  164. package/dist/services/integrations/feishu/runtime.js.map +1 -1
  165. package/dist/services/integrations/feishu/user-bindings.d.ts +22 -0
  166. package/dist/services/integrations/feishu/user-bindings.d.ts.map +1 -0
  167. package/dist/services/integrations/feishu/user-bindings.js +57 -0
  168. package/dist/services/integrations/feishu/user-bindings.js.map +1 -0
  169. package/dist/services/issue-approvals.d.ts +2 -2
  170. package/dist/services/issue-review-wakeup.js +1 -1
  171. package/dist/services/issue-review-wakeup.js.map +1 -1
  172. package/dist/services/issues.comments-attachments.d.ts +3 -3
  173. package/dist/services/issues.d.ts +14 -6
  174. package/dist/services/issues.d.ts.map +1 -1
  175. package/dist/services/issues.helpers.d.ts +12 -1
  176. package/dist/services/issues.helpers.d.ts.map +1 -1
  177. package/dist/services/issues.helpers.js +8 -0
  178. package/dist/services/issues.helpers.js.map +1 -1
  179. package/dist/services/issues.js +28 -2
  180. package/dist/services/issues.js.map +1 -1
  181. package/dist/services/knowledge-portability/organization-skills.catalog.d.ts +1 -1
  182. package/dist/services/library-entries.d.ts +8 -0
  183. package/dist/services/library-entries.d.ts.map +1 -1
  184. package/dist/services/library-entries.js +8 -0
  185. package/dist/services/library-entries.js.map +1 -1
  186. package/dist/services/managed-workspace-preflight.js +1 -1
  187. package/dist/services/managed-workspace-preflight.js.map +1 -1
  188. package/dist/services/messenger.d.ts +23 -4
  189. package/dist/services/messenger.d.ts.map +1 -1
  190. package/dist/services/messenger.js +187 -25
  191. package/dist/services/messenger.js.map +1 -1
  192. package/dist/services/plugin-capability-validator.d.ts +1 -1
  193. package/dist/services/plugin-capability-validator.js +2 -2
  194. package/dist/services/plugin-dev-watcher.js +1 -1
  195. package/dist/services/plugin-event-bus.d.ts +3 -3
  196. package/dist/services/plugin-event-bus.js +3 -3
  197. package/dist/services/plugin-job-coordinator.d.ts +1 -1
  198. package/dist/services/plugin-job-coordinator.js +1 -1
  199. package/dist/services/plugin-job-scheduler.d.ts +1 -1
  200. package/dist/services/plugin-job-scheduler.js +1 -1
  201. package/dist/services/plugin-job-store.d.ts +2 -2
  202. package/dist/services/plugin-job-store.js +2 -2
  203. package/dist/services/plugin-lifecycle.d.ts +4 -4
  204. package/dist/services/plugin-lifecycle.js +3 -3
  205. package/dist/services/plugin-loader.core.d.ts +4 -4
  206. package/dist/services/plugin-loader.core.js +2 -2
  207. package/dist/services/plugin-loader.core.js.map +1 -1
  208. package/dist/services/plugin-loader.d.ts +3 -3
  209. package/dist/services/plugin-loader.helpers.d.ts +26 -25
  210. package/dist/services/plugin-loader.helpers.d.ts.map +1 -1
  211. package/dist/services/plugin-loader.helpers.js +10 -9
  212. package/dist/services/plugin-loader.helpers.js.map +1 -1
  213. package/dist/services/plugin-loader.js +3 -3
  214. package/dist/services/plugin-loader.worker-paths.d.ts +3 -3
  215. package/dist/services/plugin-manifest-validator.d.ts +2 -2
  216. package/dist/services/plugin-registry.d.ts +9 -9
  217. package/dist/services/plugin-registry.js +1 -1
  218. package/dist/services/plugin-secrets-handler.d.ts +2 -2
  219. package/dist/services/plugin-secrets-handler.js +2 -2
  220. package/dist/services/plugin-state-store.d.ts +3 -3
  221. package/dist/services/plugin-state-store.js +3 -3
  222. package/dist/services/plugin-stream-bus.d.ts +1 -1
  223. package/dist/services/plugin-stream-bus.js +1 -1
  224. package/dist/services/plugin-tool-dispatcher.d.ts +2 -2
  225. package/dist/services/plugin-tool-dispatcher.js +2 -2
  226. package/dist/services/plugin-tool-registry.d.ts +2 -2
  227. package/dist/services/plugin-tool-registry.js +2 -2
  228. package/dist/services/plugin-worker-manager.d.ts +4 -4
  229. package/dist/services/plugin-worker-manager.d.ts.map +1 -1
  230. package/dist/services/plugin-worker-manager.js +8 -7
  231. package/dist/services/plugin-worker-manager.js.map +1 -1
  232. package/dist/services/run-intelligence.js +3 -3
  233. package/dist/services/run-intelligence.js.map +1 -1
  234. package/dist/services/runtime-kernel/heartbeat.core.d.ts +9 -1
  235. package/dist/services/runtime-kernel/heartbeat.core.d.ts.map +1 -1
  236. package/dist/services/runtime-kernel/heartbeat.core.js +16 -5
  237. package/dist/services/runtime-kernel/heartbeat.core.js.map +1 -1
  238. package/dist/services/runtime-kernel/heartbeat.d.ts +3 -3
  239. package/dist/services/runtime-kernel/heartbeat.execute.d.ts.map +1 -1
  240. package/dist/services/runtime-kernel/heartbeat.execute.js +17 -3
  241. package/dist/services/runtime-kernel/heartbeat.execute.js.map +1 -1
  242. package/dist/services/runtime-kernel/heartbeat.misc.js +1 -1
  243. package/dist/services/runtime-kernel/heartbeat.recovery.d.ts +1 -1
  244. package/dist/services/runtime-kernel/heartbeat.recovery.js +7 -7
  245. package/dist/services/runtime-kernel/heartbeat.recovery.js.map +1 -1
  246. package/dist/services/runtime-kernel/heartbeat.release.js +4 -4
  247. package/dist/services/runtime-kernel/heartbeat.release.js.map +1 -1
  248. package/dist/services/runtime-kernel/heartbeat.wakeup.js +1 -1
  249. package/dist/services/sidebar-badges.d.ts +3 -0
  250. package/dist/services/sidebar-badges.d.ts.map +1 -1
  251. package/dist/services/sidebar-badges.js +29 -1
  252. package/dist/services/sidebar-badges.js.map +1 -1
  253. package/dist/services/title-generation.d.ts +38 -0
  254. package/dist/services/title-generation.d.ts.map +1 -0
  255. package/dist/services/title-generation.js +119 -0
  256. package/dist/services/title-generation.js.map +1 -0
  257. package/dist/services/website-metadata.d.ts +17 -0
  258. package/dist/services/website-metadata.d.ts.map +1 -0
  259. package/dist/services/website-metadata.js +293 -0
  260. package/dist/services/website-metadata.js.map +1 -0
  261. package/dist/services/workspace-backups.d.ts +22 -0
  262. package/dist/services/workspace-backups.d.ts.map +1 -1
  263. package/dist/services/workspace-backups.js +161 -5
  264. package/dist/services/workspace-backups.js.map +1 -1
  265. package/dist/services/workspace-runtime.services.d.ts +1 -1
  266. package/package.json +15 -14
  267. package/resources/bundled-skills/rudder/SKILL.md +7 -6
  268. package/resources/bundled-skills/rudder/references/cli-reference.md +3 -3
  269. package/resources/bundled-skills/rudder-create-plugin/SKILL.md +2 -2
  270. package/skills/rudder/SKILL.md +7 -6
  271. package/skills/rudder/references/cli-reference.md +3 -3
  272. package/skills/rudder-create-plugin/SKILL.md +2 -2
  273. package/ui-dist/assets/{_basePickBy-CM0XatHw.js → _basePickBy-RX5N2cj2.js} +1 -1
  274. package/ui-dist/assets/{_baseUniq-CdBBmdoP.js → _baseUniq-Br4fg1iw.js} +1 -1
  275. package/ui-dist/assets/{arc-DSTtxyJ9.js → arc-B8svvCeo.js} +1 -1
  276. package/ui-dist/assets/{architectureDiagram-2XIMDMQ5-BkHMYb5I.js → architectureDiagram-2XIMDMQ5-C5dYOfG1.js} +1 -1
  277. package/ui-dist/assets/{blockDiagram-WCTKOSBZ-EYczZxwW.js → blockDiagram-WCTKOSBZ-B6XhVXfw.js} +1 -1
  278. package/ui-dist/assets/{c4Diagram-IC4MRINW-Xo9qijMi.js → c4Diagram-IC4MRINW-D31WV7FX.js} +1 -1
  279. package/ui-dist/assets/channel-BD332hbj.js +1 -0
  280. package/ui-dist/assets/{chunk-4BX2VUAB-CKzta1FF.js → chunk-4BX2VUAB-CxoBpj5-.js} +1 -1
  281. package/ui-dist/assets/{chunk-55IACEB6-BxxUB0ww.js → chunk-55IACEB6-kF3-cxbP.js} +1 -1
  282. package/ui-dist/assets/{chunk-FMBD7UC4-0F4oxVtY.js → chunk-FMBD7UC4-CmnJkmf-.js} +1 -1
  283. package/ui-dist/assets/{chunk-JSJVCQXG-CVMPMlVD.js → chunk-JSJVCQXG-U_rZ0R1l.js} +1 -1
  284. package/ui-dist/assets/{chunk-KX2RTZJC-lPrAWT94.js → chunk-KX2RTZJC-DB5h51jY.js} +1 -1
  285. package/ui-dist/assets/{chunk-NQ4KR5QH-Bufcm7Iv.js → chunk-NQ4KR5QH-D00Zb66Y.js} +1 -1
  286. package/ui-dist/assets/{chunk-QZHKN3VN-CucmdWnl.js → chunk-QZHKN3VN-CZOQzYse.js} +1 -1
  287. package/ui-dist/assets/{chunk-WL4C6EOR-Dz0oYQrJ.js → chunk-WL4C6EOR-CiFO_DRi.js} +1 -1
  288. package/ui-dist/assets/classDiagram-VBA2DB6C-BJA0edKB.js +1 -0
  289. package/ui-dist/assets/classDiagram-v2-RAHNMMFH-BJA0edKB.js +1 -0
  290. package/ui-dist/assets/clone-BXc7Yvje.js +1 -0
  291. package/ui-dist/assets/{cose-bilkent-S5V4N54A-DzyX-Er8.js → cose-bilkent-S5V4N54A-BvkdnfgN.js} +1 -1
  292. package/ui-dist/assets/{dagre-KLK3FWXG-BbZzCKuN.js → dagre-KLK3FWXG-DcTva6B8.js} +1 -1
  293. package/ui-dist/assets/{diagram-E7M64L7V-B5Rb7Bm4.js → diagram-E7M64L7V-sXDqPfE1.js} +1 -1
  294. package/ui-dist/assets/{diagram-IFDJBPK2-Cpu1Xc8G.js → diagram-IFDJBPK2-BVBaBBbz.js} +1 -1
  295. package/ui-dist/assets/{diagram-P4PSJMXO-kLfHqRlk.js → diagram-P4PSJMXO-cjQe9ndf.js} +1 -1
  296. package/ui-dist/assets/{erDiagram-INFDFZHY-rCnUyQUb.js → erDiagram-INFDFZHY-CFGKze0m.js} +1 -1
  297. package/ui-dist/assets/{flowDiagram-PKNHOUZH-BhOz8cvV.js → flowDiagram-PKNHOUZH-D7oV-h10.js} +1 -1
  298. package/ui-dist/assets/{ganttDiagram-A5KZAMGK-Csg9g3hz.js → ganttDiagram-A5KZAMGK-Rdv3FkwM.js} +1 -1
  299. package/ui-dist/assets/{gitGraphDiagram-K3NZZRJ6-DLPnSlRs.js → gitGraphDiagram-K3NZZRJ6-BejgDMgO.js} +1 -1
  300. package/ui-dist/assets/{graph-BrxYh68N.js → graph-FYmROErt.js} +1 -1
  301. package/ui-dist/assets/{index-BeZv_Z0b.js → index-4AkwW8qm.js} +1 -1
  302. package/ui-dist/assets/{index-Dj72ldIc.js → index-BArpEgpP.js} +1 -1
  303. package/ui-dist/assets/index-BPlr2F3e.css +1 -0
  304. package/ui-dist/assets/{index-Br07RRw1.js → index-BXKKdE9_.js} +1 -1
  305. package/ui-dist/assets/{index-mOyLwPeE.js → index-BeEzPu0t.js} +1 -1
  306. package/ui-dist/assets/{index-B6_gFYNj.js → index-BipRYXd-.js} +1 -1
  307. package/ui-dist/assets/{index-Bw8MgLaM.js → index-CEvBo8i0.js} +450 -445
  308. package/ui-dist/assets/{index-BkzdTp2b.js → index-CWj4VVKu.js} +1 -1
  309. package/ui-dist/assets/{index-D0rP99dj.js → index-CaLoiEJB.js} +1 -1
  310. package/ui-dist/assets/{index-DMkClCka.js → index-DDHYeuwy.js} +1 -1
  311. package/ui-dist/assets/{index-DiMeST8g.js → index-DSnSYKAK.js} +1 -1
  312. package/ui-dist/assets/{index-DpdsNIGb.js → index-DUeBWXLE.js} +1 -1
  313. package/ui-dist/assets/{index-G_y-oBne.js → index-DWxCltvd.js} +1 -1
  314. package/ui-dist/assets/{index-COBwmF-C.js → index-DYYXNc6j.js} +1 -1
  315. package/ui-dist/assets/{index-D_06pAuN.js → index-DaNviTjf.js} +1 -1
  316. package/ui-dist/assets/{index-BQW242nS.js → index-c9oJP_Zz.js} +1 -1
  317. package/ui-dist/assets/{index-Cb2qts0o.js → index-hUcZY0te.js} +1 -1
  318. package/ui-dist/assets/{index-D4FFno9t.js → index-ul4vjkem.js} +1 -1
  319. package/ui-dist/assets/{index-CsraICzz.js → index-uraSHmk-.js} +1 -1
  320. package/ui-dist/assets/{infoDiagram-LFFYTUFH-CRBKgiEf.js → infoDiagram-LFFYTUFH-D6ROD6kG.js} +1 -1
  321. package/ui-dist/assets/{ishikawaDiagram-PHBUUO56-DI3jquVE.js → ishikawaDiagram-PHBUUO56-DcVc0cdJ.js} +1 -1
  322. package/ui-dist/assets/{journeyDiagram-4ABVD52K-DDFZ2Q6D.js → journeyDiagram-4ABVD52K-BRufUm59.js} +1 -1
  323. package/ui-dist/assets/{kanban-definition-K7BYSVSG-yL5u3cXV.js → kanban-definition-K7BYSVSG-DEQ5w7B0.js} +1 -1
  324. package/ui-dist/assets/{layout-DDZaRkp7.js → layout-F5Axhkca.js} +1 -1
  325. package/ui-dist/assets/{linear-CWngWuQa.js → linear-BllnS5sO.js} +1 -1
  326. package/ui-dist/assets/{mermaid.core-CQuYoq9K.js → mermaid.core-CK8iLvY2.js} +4 -4
  327. package/ui-dist/assets/{mindmap-definition-YRQLILUH-BwSsHtTO.js → mindmap-definition-YRQLILUH-CXI6vt68.js} +1 -1
  328. package/ui-dist/assets/{pieDiagram-SKSYHLDU-BasUkvwH.js → pieDiagram-SKSYHLDU-DDUy_f_g.js} +1 -1
  329. package/ui-dist/assets/{quadrantDiagram-337W2JSQ-D0D2xp36.js → quadrantDiagram-337W2JSQ-Cpns5Yb1.js} +1 -1
  330. package/ui-dist/assets/{requirementDiagram-Z7DCOOCP-CztN9kDh.js → requirementDiagram-Z7DCOOCP-6p6V6XH6.js} +1 -1
  331. package/ui-dist/assets/{sankeyDiagram-WA2Y5GQK-2xDqN9ox.js → sankeyDiagram-WA2Y5GQK-C52tgQmQ.js} +1 -1
  332. package/ui-dist/assets/{sequenceDiagram-2WXFIKYE-CO3OUPIJ.js → sequenceDiagram-2WXFIKYE-CxlW_veo.js} +1 -1
  333. package/ui-dist/assets/{stateDiagram-RAJIS63D-DuQ1QZcT.js → stateDiagram-RAJIS63D-NFOjAzLj.js} +1 -1
  334. package/ui-dist/assets/stateDiagram-v2-FVOUBMTO-DblG-d9U.js +1 -0
  335. package/ui-dist/assets/{timeline-definition-YZTLITO2-CnOxbQeb.js → timeline-definition-YZTLITO2-DvENY4C6.js} +1 -1
  336. package/ui-dist/assets/{treemap-KZPCXAKY-DD77IFOl.js → treemap-KZPCXAKY-BJfIPF5s.js} +1 -1
  337. package/ui-dist/assets/{vennDiagram-LZ73GAT5-DOXTGJn1.js → vennDiagram-LZ73GAT5-DmGW-P4z.js} +1 -1
  338. package/ui-dist/assets/{xychartDiagram-JWTSCODW-DWkrcdri.js → xychartDiagram-JWTSCODW-bbLe3hqw.js} +1 -1
  339. package/ui-dist/brands/feishu-logo.svg +5 -0
  340. package/ui-dist/index.html +2 -2
  341. package/ui-dist/assets/channel-BRnz7pSY.js +0 -1
  342. package/ui-dist/assets/classDiagram-VBA2DB6C-Q3YuI9dv.js +0 -1
  343. package/ui-dist/assets/classDiagram-v2-RAHNMMFH-Q3YuI9dv.js +0 -1
  344. package/ui-dist/assets/clone-C1exIyAN.js +0 -1
  345. package/ui-dist/assets/index-Dz8xxyqB.css +0 -1
  346. package/ui-dist/assets/stateDiagram-v2-FVOUBMTO-DQbZqbl9.js +0 -1
@@ -1,8 +1,8 @@
1
- import { approvals, assets, chatAttachments, chatContextLinks, chatConversations, chatConversationUserStates, chatMessages } from "@rudderhq/db";
2
- import { sanitizeChatStructuredPayload } from "@rudderhq/shared";
3
- import { and, desc, eq, gt, gte, inArray, isNull, sql } from "drizzle-orm";
1
+ import { agentIntegrationChatBindings, agentIntegrations, approvals, assets, chatAttachments, chatContextLinks, chatConversations, chatConversationUserStates, chatGenerations, chatMessages, chatQueuedMessages, messengerCustomGroupEntries, messengerCustomGroups } from "@rudderhq/db";
2
+ import { MESSENGER_FORK_GROUP_DEFAULT_ICON, sanitizeChatStructuredPayload } from "@rudderhq/shared";
3
+ import { and, asc, desc, eq, gt, gte, inArray, isNull, lt, or, sql } from "drizzle-orm";
4
4
  import { randomUUID } from "node:crypto";
5
- import { notFound, unprocessable } from "../errors.js";
5
+ import { conflict, notFound, unprocessable } from "../errors.js";
6
6
  import { logActivity } from "./activity-log.js";
7
7
  import { agentService } from "./agents.js";
8
8
  import { approvalService } from "./approvals.js";
@@ -10,8 +10,18 @@ import { issueApprovalService } from "./issue-approvals.js";
10
10
  import { issueService } from "./issues.js";
11
11
  import { normalizeLocalLibraryPathMarkdown } from "./library-path-markdown.js";
12
12
  import { organizationService } from "./orgs.js";
13
+ function conversationMutability(row, sourceMetadata, sourceMetadataByConversationId) {
14
+ if (sourceMetadata)
15
+ return "external_bound_chat";
16
+ if ((row.forkedFromConversationId && sourceMetadataByConversationId.has(row.forkedFromConversationId)) ||
17
+ (row.forkRootConversationId && sourceMetadataByConversationId.has(row.forkRootConversationId))) {
18
+ return "native_fork_from_external";
19
+ }
20
+ return "native_chat";
21
+ }
13
22
  import { buildSearchSnippet, CHAT_TRANSCRIPT_KEY, chatTranscriptFromPayload, chatTranscriptSummaryFromEntries, contentPath, escapeLikePattern, incomingMessagePreviewSql, issueProposalFromPayload, isVisibleIncomingChatMessage, listContextLinksForConversationIds, listPrimaryIssues, operationProposalDecisionStatusFromPayload, operationProposalFromPayload, resolveContextEntities, safeTrim, stripChatMetadataFromPayload, textContains, truncatePreview, visibleIncomingMessageSql, withOperationProposalDecisionState, withPersistedTranscript, } from "./chats.helpers.js";
14
23
  export function chatService(db) {
24
+ const QUEUED_MESSAGE_CLAIM_LEASE_MS = 2 * 60 * 1000;
15
25
  const issuesSvc = issueService(db);
16
26
  const approvalsSvc = approvalService(db);
17
27
  const issueApprovalsSvc = issueApprovalService(db);
@@ -51,7 +61,12 @@ export function chatService(db) {
51
61
  })
52
62
  .from(chatMessages)
53
63
  .innerJoin(chatConversationUserStates, and(eq(chatConversationUserStates.orgId, orgId), eq(chatConversationUserStates.userId, userId), eq(chatConversationUserStates.conversationId, chatMessages.conversationId)))
54
- .where(and(eq(chatMessages.orgId, orgId), inArray(chatMessages.conversationId, conversationIds), isNull(chatMessages.supersededAt), visibleIncomingMessageSql(), gt(chatMessages.createdAt, chatConversationUserStates.lastReadAt)))
64
+ .where(and(eq(chatMessages.orgId, orgId), inArray(chatMessages.conversationId, conversationIds), isNull(chatMessages.supersededAt), visibleIncomingMessageSql(), gt(chatMessages.createdAt, chatConversationUserStates.lastReadAt), sql `not exists (
65
+ select 1
66
+ from ${agentIntegrationChatBindings}
67
+ where ${agentIntegrationChatBindings.orgId} = ${orgId}
68
+ and ${agentIntegrationChatBindings.conversationId} = ${chatMessages.conversationId}
69
+ )`))
55
70
  .groupBy(chatMessages.conversationId);
56
71
  return new Map(rows.map((row) => [row.conversationId, Number(row.count ?? 0)]));
57
72
  }
@@ -68,6 +83,63 @@ export function chatService(db) {
68
83
  .groupBy(chatMessages.conversationId);
69
84
  return new Set(rows.map((row) => row.conversationId));
70
85
  }
86
+ async function listConversationSourceMetadata(orgId, conversationIds) {
87
+ if (conversationIds.length === 0)
88
+ return new Map();
89
+ const rows = await db
90
+ .select({
91
+ conversationId: agentIntegrationChatBindings.conversationId,
92
+ integrationId: agentIntegrationChatBindings.integrationId,
93
+ provider: agentIntegrations.provider,
94
+ externalChatId: agentIntegrationChatBindings.externalChatId,
95
+ externalChatType: agentIntegrationChatBindings.externalChatType,
96
+ })
97
+ .from(agentIntegrationChatBindings)
98
+ .innerJoin(agentIntegrations, eq(agentIntegrations.id, agentIntegrationChatBindings.integrationId))
99
+ .where(and(eq(agentIntegrationChatBindings.orgId, orgId), inArray(agentIntegrationChatBindings.conversationId, conversationIds)))
100
+ .orderBy(agentIntegrationChatBindings.createdAt);
101
+ const map = new Map();
102
+ for (const row of rows) {
103
+ if (map.has(row.conversationId))
104
+ continue;
105
+ map.set(row.conversationId, {
106
+ source: "agent_integration",
107
+ provider: row.provider,
108
+ integrationId: row.integrationId,
109
+ externalChatId: row.externalChatId,
110
+ externalChatType: row.externalChatType,
111
+ });
112
+ }
113
+ const missingConversationIds = conversationIds.filter((id) => !map.has(id));
114
+ if (missingConversationIds.length === 0)
115
+ return map;
116
+ const historicalRows = await db
117
+ .select({
118
+ conversationId: chatMessages.conversationId,
119
+ payload: chatMessages.structuredPayload,
120
+ })
121
+ .from(chatMessages)
122
+ .where(and(eq(chatMessages.orgId, orgId), inArray(chatMessages.conversationId, missingConversationIds), sql `${chatMessages.structuredPayload}->>'source' = 'agent_integration'`, sql `${chatMessages.structuredPayload}->>'provider' = 'feishu'`))
123
+ .orderBy(chatMessages.createdAt);
124
+ for (const row of historicalRows) {
125
+ if (map.has(row.conversationId))
126
+ continue;
127
+ const payload = row.payload ?? {};
128
+ const integrationId = typeof payload.integrationId === "string" ? payload.integrationId : null;
129
+ const externalChatId = typeof payload.externalChatId === "string" ? payload.externalChatId : null;
130
+ const externalChatType = typeof payload.externalChatType === "string" ? payload.externalChatType : null;
131
+ if (!integrationId || !externalChatId || !externalChatType)
132
+ continue;
133
+ map.set(row.conversationId, {
134
+ source: "agent_integration",
135
+ provider: "feishu",
136
+ integrationId,
137
+ externalChatId,
138
+ externalChatType,
139
+ });
140
+ }
141
+ return map;
142
+ }
71
143
  async function listLatestReplyPreviews(orgId, conversationIds) {
72
144
  if (conversationIds.length === 0)
73
145
  return new Map();
@@ -175,8 +247,14 @@ export function chatService(db) {
175
247
  await ensureConversationUserStates(rows, userId);
176
248
  }
177
249
  const conversationIds = rows.map((row) => row.id);
250
+ const sourceLookupConversationIds = [
251
+ ...new Set([
252
+ ...conversationIds,
253
+ ...rows.flatMap((row) => [row.forkedFromConversationId, row.forkRootConversationId].filter((id) => Boolean(id))),
254
+ ]),
255
+ ];
178
256
  const orgId = rows[0]?.orgId ?? null;
179
- const [contextLinksByConversationId, primaryIssuesById, userStatesByConversationId, unreadCountsByConversationId, pendingProposalConversationIds, latestReplyPreviewsByConversationId, userMessageSummariesByConversationId,] = await Promise.all([
257
+ const [contextLinksByConversationId, primaryIssuesById, userStatesByConversationId, unreadCountsByConversationId, pendingProposalConversationIds, latestReplyPreviewsByConversationId, userMessageSummariesByConversationId, sourceMetadataByConversationId,] = await Promise.all([
180
258
  listContextLinksForConversationIds(db, rows.map((row) => row.id)),
181
259
  listPrimaryIssues(db, rows),
182
260
  userId && orgId
@@ -194,29 +272,45 @@ export function chatService(db) {
194
272
  orgId
195
273
  ? listUserMessageSummaries(orgId, conversationIds)
196
274
  : Promise.resolve(new Map()),
275
+ orgId
276
+ ? listConversationSourceMetadata(orgId, sourceLookupConversationIds)
277
+ : Promise.resolve(new Map()),
197
278
  ]);
198
- return rows.map((row) => ({
199
- ...row,
200
- primaryIssue: row.primaryIssueId ? (primaryIssuesById.get(row.primaryIssueId) ?? null) : null,
201
- latestReplyPreview: latestReplyPreviewsByConversationId.get(row.id) ?? null,
202
- latestUserMessagePreview: userMessageSummariesByConversationId.get(row.id)?.latestPreview ?? null,
203
- userMessageCount: userMessageSummariesByConversationId.get(row.id)?.count ?? 0,
204
- contextLinks: contextLinksByConversationId.get(row.id) ?? [],
205
- lastReadAt: userStatesByConversationId.get(row.id)?.lastReadAt ?? null,
206
- isPinned: Boolean(userStatesByConversationId.get(row.id)?.pinnedAt),
207
- unreadCount: unreadCountsByConversationId.get(row.id) ?? 0,
208
- isUnread: (unreadCountsByConversationId.get(row.id) ?? 0) > 0,
209
- needsAttention: (unreadCountsByConversationId.get(row.id) ?? 0) > 0 ||
210
- pendingProposalConversationIds.has(row.id),
211
- }));
279
+ return rows.map((row) => {
280
+ const sourceMetadata = sourceMetadataByConversationId.get(row.id) ?? null;
281
+ const isExternalBound = Boolean(sourceMetadata);
282
+ const unreadCount = isExternalBound ? 0 : (unreadCountsByConversationId.get(row.id) ?? 0);
283
+ return {
284
+ ...row,
285
+ primaryIssue: row.primaryIssueId ? (primaryIssuesById.get(row.primaryIssueId) ?? null) : null,
286
+ latestReplyPreview: latestReplyPreviewsByConversationId.get(row.id) ?? null,
287
+ latestUserMessagePreview: userMessageSummariesByConversationId.get(row.id)?.latestPreview ?? null,
288
+ userMessageCount: userMessageSummariesByConversationId.get(row.id)?.count ?? 0,
289
+ contextLinks: contextLinksByConversationId.get(row.id) ?? [],
290
+ sourceMetadata,
291
+ mutability: conversationMutability(row, sourceMetadata, sourceMetadataByConversationId),
292
+ lastReadAt: userStatesByConversationId.get(row.id)?.lastReadAt ?? null,
293
+ isPinned: Boolean(userStatesByConversationId.get(row.id)?.pinnedAt),
294
+ unreadCount,
295
+ isUnread: unreadCount > 0,
296
+ needsAttention: !isExternalBound && (unreadCount > 0 ||
297
+ pendingProposalConversationIds.has(row.id)),
298
+ };
299
+ });
212
300
  }
213
301
  async function hydrateConversationSummaries(rows, userId) {
214
302
  if (userId) {
215
303
  await ensureConversationUserStates(rows, userId);
216
304
  }
217
305
  const conversationIds = rows.map((row) => row.id);
306
+ const sourceLookupConversationIds = [
307
+ ...new Set([
308
+ ...conversationIds,
309
+ ...rows.flatMap((row) => [row.forkedFromConversationId, row.forkRootConversationId].filter((id) => Boolean(id))),
310
+ ]),
311
+ ];
218
312
  const orgId = rows[0]?.orgId ?? null;
219
- const [userStatesByConversationId, unreadCountsByConversationId, pendingProposalConversationIds, latestReplyPreviewsByConversationId, userMessageSummariesByConversationId,] = await Promise.all([
313
+ const [userStatesByConversationId, unreadCountsByConversationId, pendingProposalConversationIds, latestReplyPreviewsByConversationId, userMessageSummariesByConversationId, sourceMetadataByConversationId,] = await Promise.all([
220
314
  userId && orgId
221
315
  ? listConversationUserStates(orgId, userId, conversationIds)
222
316
  : Promise.resolve(new Map()),
@@ -232,19 +326,29 @@ export function chatService(db) {
232
326
  orgId
233
327
  ? listUserMessageSummaries(orgId, conversationIds)
234
328
  : Promise.resolve(new Map()),
329
+ orgId
330
+ ? listConversationSourceMetadata(orgId, sourceLookupConversationIds)
331
+ : Promise.resolve(new Map()),
235
332
  ]);
236
- return rows.map((row) => ({
237
- ...row,
238
- latestReplyPreview: latestReplyPreviewsByConversationId.get(row.id) ?? null,
239
- latestUserMessagePreview: userMessageSummariesByConversationId.get(row.id)?.latestPreview ?? null,
240
- userMessageCount: userMessageSummariesByConversationId.get(row.id)?.count ?? 0,
241
- lastReadAt: userStatesByConversationId.get(row.id)?.lastReadAt ?? null,
242
- isPinned: Boolean(userStatesByConversationId.get(row.id)?.pinnedAt),
243
- unreadCount: unreadCountsByConversationId.get(row.id) ?? 0,
244
- isUnread: (unreadCountsByConversationId.get(row.id) ?? 0) > 0,
245
- needsAttention: (unreadCountsByConversationId.get(row.id) ?? 0) > 0 ||
246
- pendingProposalConversationIds.has(row.id),
247
- }));
333
+ return rows.map((row) => {
334
+ const sourceMetadata = sourceMetadataByConversationId.get(row.id) ?? null;
335
+ const isExternalBound = Boolean(sourceMetadata);
336
+ const unreadCount = isExternalBound ? 0 : (unreadCountsByConversationId.get(row.id) ?? 0);
337
+ return {
338
+ ...row,
339
+ latestReplyPreview: latestReplyPreviewsByConversationId.get(row.id) ?? null,
340
+ latestUserMessagePreview: userMessageSummariesByConversationId.get(row.id)?.latestPreview ?? null,
341
+ userMessageCount: userMessageSummariesByConversationId.get(row.id)?.count ?? 0,
342
+ sourceMetadata,
343
+ mutability: conversationMutability(row, sourceMetadata, sourceMetadataByConversationId),
344
+ lastReadAt: userStatesByConversationId.get(row.id)?.lastReadAt ?? null,
345
+ isPinned: Boolean(userStatesByConversationId.get(row.id)?.pinnedAt),
346
+ unreadCount,
347
+ isUnread: unreadCount > 0,
348
+ needsAttention: !isExternalBound && (unreadCount > 0 ||
349
+ pendingProposalConversationIds.has(row.id)),
350
+ };
351
+ });
248
352
  }
249
353
  async function getConversationOrThrow(id) {
250
354
  const row = await db
@@ -305,6 +409,328 @@ export function chatService(db) {
305
409
  .where(inArray(approvals.id, approvalIds));
306
410
  return new Map(approvalRows.map((row) => [row.id, row]));
307
411
  }
412
+ function isQueuePositionConflict(error) {
413
+ return Boolean(error
414
+ && typeof error === "object"
415
+ && "code" in error
416
+ && error.code === "23505");
417
+ }
418
+ function normalizeQueuedPayload(payload) {
419
+ return {
420
+ body: String(payload.body ?? ""),
421
+ attachmentIds: Array.isArray(payload.attachmentIds)
422
+ ? payload.attachmentIds.filter((id) => typeof id === "string")
423
+ : [],
424
+ projectId: typeof payload.projectId === "string" ? payload.projectId : null,
425
+ skillRefs: Array.isArray(payload.skillRefs)
426
+ ? payload.skillRefs.filter((ref) => typeof ref === "string")
427
+ : [],
428
+ accessMode: typeof payload.accessMode === "string" ? payload.accessMode : null,
429
+ model: typeof payload.model === "string" ? payload.model : null,
430
+ effort: typeof payload.effort === "string" ? payload.effort : null,
431
+ metadata: payload.metadata && typeof payload.metadata === "object" && !Array.isArray(payload.metadata)
432
+ ? payload.metadata
433
+ : null,
434
+ };
435
+ }
436
+ function hydrateQueuedMessage(row) {
437
+ return {
438
+ ...row,
439
+ payload: normalizeQueuedPayload(row.payload),
440
+ };
441
+ }
442
+ async function createGeneration(orgId, conversationId) {
443
+ const [row] = await db
444
+ .insert(chatGenerations)
445
+ .values({
446
+ orgId,
447
+ conversationId,
448
+ status: "active",
449
+ })
450
+ .returning();
451
+ if (!row)
452
+ throw new Error("Failed to create chat generation");
453
+ return row;
454
+ }
455
+ async function markGenerationTerminal(generationId, status) {
456
+ if (!generationId)
457
+ return null;
458
+ const now = new Date();
459
+ const [row] = await db
460
+ .update(chatGenerations)
461
+ .set({
462
+ status,
463
+ terminalReason: status,
464
+ completedAt: now,
465
+ updatedAt: now,
466
+ })
467
+ .where(eq(chatGenerations.id, generationId))
468
+ .returning();
469
+ return row ?? null;
470
+ }
471
+ async function getLatestActiveGeneration(conversationId) {
472
+ return db
473
+ .select()
474
+ .from(chatGenerations)
475
+ .where(and(eq(chatGenerations.conversationId, conversationId), inArray(chatGenerations.status, ["active", "tool_busy", "closing"])))
476
+ .orderBy(desc(chatGenerations.startedAt), desc(chatGenerations.createdAt))
477
+ .limit(1)
478
+ .then((rows) => rows[0] ?? null);
479
+ }
480
+ async function getLatestGeneration(conversationId) {
481
+ return db
482
+ .select()
483
+ .from(chatGenerations)
484
+ .where(eq(chatGenerations.conversationId, conversationId))
485
+ .orderBy(desc(chatGenerations.startedAt), desc(chatGenerations.createdAt))
486
+ .limit(1)
487
+ .then((rows) => rows[0] ?? null);
488
+ }
489
+ async function listQueuedMessages(conversationId) {
490
+ await reclaimStaleQueuedMessageClaims(conversationId);
491
+ const rows = await db
492
+ .select()
493
+ .from(chatQueuedMessages)
494
+ .where(and(eq(chatQueuedMessages.conversationId, conversationId), inArray(chatQueuedMessages.status, ["queued", "steer_pending", "dequeue_claimed", "running"])))
495
+ .orderBy(asc(chatQueuedMessages.position), asc(chatQueuedMessages.createdAt));
496
+ return rows.map(hydrateQueuedMessage);
497
+ }
498
+ async function getQueueSnapshot(conversationId, activeGenerationId) {
499
+ const activeGeneration = activeGenerationId
500
+ ? { id: activeGenerationId }
501
+ : await getLatestActiveGeneration(conversationId);
502
+ return {
503
+ activeGenerationId: activeGeneration?.id ?? null,
504
+ items: await listQueuedMessages(conversationId),
505
+ };
506
+ }
507
+ async function createQueuedMessage(input) {
508
+ const payload = {
509
+ ...input.payload,
510
+ body: input.payload.body.trim(),
511
+ attachmentIds: input.payload.attachmentIds ?? [],
512
+ skillRefs: input.payload.skillRefs ?? [],
513
+ projectId: input.payload.projectId ?? null,
514
+ accessMode: input.payload.accessMode ?? null,
515
+ model: input.payload.model ?? null,
516
+ effort: input.payload.effort ?? null,
517
+ metadata: input.payload.metadata ?? null,
518
+ };
519
+ for (let attempt = 0; attempt < 3; attempt += 1) {
520
+ try {
521
+ return await db.transaction(async (tx) => {
522
+ const existing = await tx
523
+ .select()
524
+ .from(chatQueuedMessages)
525
+ .where(and(eq(chatQueuedMessages.conversationId, input.conversationId), eq(chatQueuedMessages.clientMutationId, input.clientMutationId)))
526
+ .limit(1)
527
+ .then((rows) => rows[0] ?? null);
528
+ if (existing) {
529
+ if (JSON.stringify(existing.payload) !== JSON.stringify(payload)) {
530
+ throw conflict("Queued message idempotency key reused with a different payload");
531
+ }
532
+ return hydrateQueuedMessage(existing);
533
+ }
534
+ const [positionRow] = await tx
535
+ .select({
536
+ nextPosition: sql `coalesce(max(${chatQueuedMessages.position}), 0) + 1`,
537
+ })
538
+ .from(chatQueuedMessages)
539
+ .where(eq(chatQueuedMessages.conversationId, input.conversationId));
540
+ const [row] = await tx
541
+ .insert(chatQueuedMessages)
542
+ .values({
543
+ orgId: input.orgId,
544
+ conversationId: input.conversationId,
545
+ clientMutationId: input.clientMutationId,
546
+ position: Number(positionRow?.nextPosition ?? 1),
547
+ payload,
548
+ expectedGenerationId: input.expectedGenerationId ?? null,
549
+ })
550
+ .returning();
551
+ if (!row)
552
+ throw new Error("Failed to create queued chat message");
553
+ return hydrateQueuedMessage(row);
554
+ });
555
+ }
556
+ catch (error) {
557
+ if (attempt < 2 && isQueuePositionConflict(error))
558
+ continue;
559
+ throw error;
560
+ }
561
+ }
562
+ throw new Error("Failed to create queued chat message");
563
+ }
564
+ async function updateQueuedMessage(input) {
565
+ const now = new Date();
566
+ const [row] = await db
567
+ .update(chatQueuedMessages)
568
+ .set({
569
+ payload: {
570
+ ...input.payload,
571
+ body: input.payload.body.trim(),
572
+ attachmentIds: input.payload.attachmentIds ?? [],
573
+ skillRefs: input.payload.skillRefs ?? [],
574
+ projectId: input.payload.projectId ?? null,
575
+ accessMode: input.payload.accessMode ?? null,
576
+ model: input.payload.model ?? null,
577
+ effort: input.payload.effort ?? null,
578
+ metadata: input.payload.metadata ?? null,
579
+ },
580
+ version: input.version + 1,
581
+ lastDeliveryReason: null,
582
+ updatedAt: now,
583
+ })
584
+ .where(and(eq(chatQueuedMessages.conversationId, input.conversationId), eq(chatQueuedMessages.id, input.itemId), eq(chatQueuedMessages.version, input.version), eq(chatQueuedMessages.status, "queued")))
585
+ .returning();
586
+ if (!row)
587
+ throw conflict("Queued message was changed or is no longer editable");
588
+ return hydrateQueuedMessage(row);
589
+ }
590
+ async function cancelQueuedMessage(input) {
591
+ const now = new Date();
592
+ const conditions = [
593
+ eq(chatQueuedMessages.conversationId, input.conversationId),
594
+ eq(chatQueuedMessages.id, input.itemId),
595
+ eq(chatQueuedMessages.status, "queued"),
596
+ ];
597
+ if (input.version)
598
+ conditions.push(eq(chatQueuedMessages.version, input.version));
599
+ const [row] = await db
600
+ .update(chatQueuedMessages)
601
+ .set({
602
+ status: "cancelled",
603
+ version: sql `${chatQueuedMessages.version} + 1`,
604
+ cancelledAt: now,
605
+ updatedAt: now,
606
+ })
607
+ .where(and(...conditions))
608
+ .returning();
609
+ if (!row)
610
+ throw conflict("Queued message was changed or is no longer cancellable");
611
+ return hydrateQueuedMessage(row);
612
+ }
613
+ async function markQueuedMessageSteerFallback(input) {
614
+ const now = new Date();
615
+ const [row] = await db
616
+ .update(chatQueuedMessages)
617
+ .set({
618
+ status: "queued",
619
+ activeGenerationId: input.activeGenerationId ?? null,
620
+ deliveryAttempts: sql `${chatQueuedMessages.deliveryAttempts} + 1`,
621
+ lastAttemptAt: now,
622
+ lastDeliveryReason: input.reason,
623
+ version: sql `${chatQueuedMessages.version} + 1`,
624
+ updatedAt: now,
625
+ })
626
+ .where(and(eq(chatQueuedMessages.conversationId, input.conversationId), eq(chatQueuedMessages.id, input.itemId), eq(chatQueuedMessages.status, "queued")))
627
+ .returning();
628
+ if (!row)
629
+ throw conflict("Queued message was changed or is no longer steerable");
630
+ return hydrateQueuedMessage(row);
631
+ }
632
+ async function claimNextQueuedMessage(conversationId) {
633
+ await reclaimStaleQueuedMessageClaims(conversationId);
634
+ const now = new Date();
635
+ return db.transaction(async (tx) => {
636
+ const [candidate] = await tx
637
+ .select()
638
+ .from(chatQueuedMessages)
639
+ .where(and(eq(chatQueuedMessages.conversationId, conversationId), eq(chatQueuedMessages.status, "queued")))
640
+ .orderBy(asc(chatQueuedMessages.position), asc(chatQueuedMessages.createdAt))
641
+ .limit(1);
642
+ if (!candidate)
643
+ return null;
644
+ const [row] = await tx
645
+ .update(chatQueuedMessages)
646
+ .set({
647
+ status: "dequeue_claimed",
648
+ dequeuedAt: now,
649
+ deliveryAttempts: sql `${chatQueuedMessages.deliveryAttempts} + 1`,
650
+ lastAttemptAt: now,
651
+ lastDeliveryReason: null,
652
+ version: sql `${chatQueuedMessages.version} + 1`,
653
+ updatedAt: now,
654
+ })
655
+ .where(and(eq(chatQueuedMessages.id, candidate.id), eq(chatQueuedMessages.conversationId, conversationId), eq(chatQueuedMessages.status, "queued"), eq(chatQueuedMessages.version, candidate.version)))
656
+ .returning();
657
+ return row ? hydrateQueuedMessage(row) : null;
658
+ });
659
+ }
660
+ async function releaseQueuedMessageClaim(input) {
661
+ const now = new Date();
662
+ const [row] = await db
663
+ .update(chatQueuedMessages)
664
+ .set({
665
+ status: "queued",
666
+ lastDeliveryReason: input.reason,
667
+ version: sql `${chatQueuedMessages.version} + 1`,
668
+ updatedAt: now,
669
+ })
670
+ .where(and(eq(chatQueuedMessages.conversationId, input.conversationId), eq(chatQueuedMessages.id, input.itemId), eq(chatQueuedMessages.status, "dequeue_claimed")))
671
+ .returning();
672
+ return row ? hydrateQueuedMessage(row) : null;
673
+ }
674
+ async function reclaimStaleQueuedMessageClaims(conversationId) {
675
+ const cutoff = new Date(Date.now() - QUEUED_MESSAGE_CLAIM_LEASE_MS);
676
+ await db
677
+ .update(chatQueuedMessages)
678
+ .set({
679
+ status: "queued",
680
+ lastDeliveryReason: "claim_expired",
681
+ version: sql `${chatQueuedMessages.version} + 1`,
682
+ updatedAt: new Date(),
683
+ })
684
+ .where(and(eq(chatQueuedMessages.conversationId, conversationId), eq(chatQueuedMessages.status, "dequeue_claimed"), lt(chatQueuedMessages.updatedAt, cutoff)));
685
+ }
686
+ async function assertQueuedMessageClaimedForDelivery(input) {
687
+ const row = await db
688
+ .select()
689
+ .from(chatQueuedMessages)
690
+ .where(and(eq(chatQueuedMessages.conversationId, input.conversationId), eq(chatQueuedMessages.id, input.itemId)))
691
+ .limit(1)
692
+ .then((rows) => rows[0] ?? null);
693
+ if (!row || row.status !== "dequeue_claimed") {
694
+ throw conflict("Queued message is not claimed for delivery");
695
+ }
696
+ const payload = normalizeQueuedPayload(row.payload);
697
+ if (payload.body.trim() !== input.body.trim()) {
698
+ throw conflict("Queued message body no longer matches claimed payload");
699
+ }
700
+ return hydrateQueuedMessage(row);
701
+ }
702
+ async function markQueuedMessageRunning(input) {
703
+ const now = new Date();
704
+ const [row] = await db
705
+ .update(chatQueuedMessages)
706
+ .set({
707
+ status: "running",
708
+ sourceMessageId: input.sourceMessageId,
709
+ deliveredMessageId: input.sourceMessageId,
710
+ version: sql `${chatQueuedMessages.version} + 1`,
711
+ updatedAt: now,
712
+ })
713
+ .where(and(eq(chatQueuedMessages.conversationId, input.conversationId), eq(chatQueuedMessages.id, input.itemId), eq(chatQueuedMessages.status, "dequeue_claimed")))
714
+ .returning();
715
+ if (!row)
716
+ throw conflict("Queued message is no longer deliverable");
717
+ return hydrateQueuedMessage(row);
718
+ }
719
+ async function markQueuedMessageDeliveryTerminal(input) {
720
+ const now = new Date();
721
+ const nextStatus = input.status === "completed" ? "completed" : "failed";
722
+ const [row] = await db
723
+ .update(chatQueuedMessages)
724
+ .set({
725
+ status: nextStatus,
726
+ lastDeliveryReason: input.status === "completed" ? null : input.status,
727
+ version: sql `${chatQueuedMessages.version} + 1`,
728
+ updatedAt: now,
729
+ })
730
+ .where(and(eq(chatQueuedMessages.conversationId, input.conversationId), eq(chatQueuedMessages.id, input.itemId), inArray(chatQueuedMessages.status, ["dequeue_claimed", "running"])))
731
+ .returning();
732
+ return row ? hydrateQueuedMessage(row) : null;
733
+ }
308
734
  async function hydrateMessages(rows, options = {}) {
309
735
  const includeTranscript = options.includeTranscript !== false;
310
736
  const [attachmentsByMessageId, approvalsById] = await Promise.all([
@@ -493,6 +919,210 @@ export function chatService(db) {
493
919
  });
494
920
  return getById(created.id);
495
921
  }
922
+ function forkSystemEventBody(sourceConversation, sourceMessageId) {
923
+ const messageSuffix = sourceMessageId ? " at message" : "";
924
+ return `Forked from [${sourceConversation.title}](chat://${sourceConversation.id})${messageSuffix}.`;
925
+ }
926
+ async function findForkFamilyGroup(client, orgId, userId, rootConversationId) {
927
+ const rootThreadKey = `chat:${rootConversationId}`;
928
+ return client
929
+ .select({ id: messengerCustomGroups.id })
930
+ .from(messengerCustomGroups)
931
+ .innerJoin(messengerCustomGroupEntries, eq(messengerCustomGroupEntries.groupId, messengerCustomGroups.id))
932
+ .where(and(eq(messengerCustomGroups.orgId, orgId), eq(messengerCustomGroups.userId, userId), eq(messengerCustomGroupEntries.orgId, orgId), eq(messengerCustomGroupEntries.userId, userId), eq(messengerCustomGroupEntries.threadKey, rootThreadKey)))
933
+ .orderBy(asc(messengerCustomGroups.sortOrder), asc(messengerCustomGroups.createdAt))
934
+ .limit(1)
935
+ .then((rows) => rows[0] ?? null);
936
+ }
937
+ async function createForkFamilyGroup(client, orgId, userId, name) {
938
+ const [lastGroup] = await client
939
+ .select({ sortOrder: messengerCustomGroups.sortOrder })
940
+ .from(messengerCustomGroups)
941
+ .where(and(eq(messengerCustomGroups.orgId, orgId), eq(messengerCustomGroups.userId, userId)))
942
+ .orderBy(desc(messengerCustomGroups.sortOrder))
943
+ .limit(1);
944
+ const now = new Date();
945
+ const [group] = await client
946
+ .insert(messengerCustomGroups)
947
+ .values({
948
+ orgId,
949
+ userId,
950
+ name: name.trim() || "Forked conversation",
951
+ icon: MESSENGER_FORK_GROUP_DEFAULT_ICON,
952
+ sortOrder: (lastGroup?.sortOrder ?? -1) + 1,
953
+ updatedAt: now,
954
+ })
955
+ .returning();
956
+ if (!group)
957
+ throw new Error("Failed to create Messenger fork group");
958
+ return group;
959
+ }
960
+ async function assignForkThreadToGroup(client, orgId, userId, groupId, threadKey) {
961
+ const [lastEntry] = await client
962
+ .select({ sortOrder: messengerCustomGroupEntries.sortOrder })
963
+ .from(messengerCustomGroupEntries)
964
+ .where(and(eq(messengerCustomGroupEntries.orgId, orgId), eq(messengerCustomGroupEntries.userId, userId), eq(messengerCustomGroupEntries.groupId, groupId)))
965
+ .orderBy(desc(messengerCustomGroupEntries.sortOrder))
966
+ .limit(1);
967
+ const now = new Date();
968
+ await client
969
+ .insert(messengerCustomGroupEntries)
970
+ .values({
971
+ orgId,
972
+ userId,
973
+ groupId,
974
+ threadKey,
975
+ sortOrder: (lastEntry?.sortOrder ?? -1) + 1,
976
+ updatedAt: now,
977
+ })
978
+ .onConflictDoNothing();
979
+ }
980
+ async function ensureForkFamilyGroup(client, orgId, userId, rootConversationId, sourceConversationId, childConversationId, groupName) {
981
+ const existing = await findForkFamilyGroup(client, orgId, userId, rootConversationId);
982
+ const group = existing ?? await createForkFamilyGroup(client, orgId, userId, groupName);
983
+ for (const threadKey of [
984
+ `chat:${rootConversationId}`,
985
+ `chat:${sourceConversationId}`,
986
+ `chat:${childConversationId}`,
987
+ ]) {
988
+ await assignForkThreadToGroup(client, orgId, userId, group.id, threadKey);
989
+ }
990
+ }
991
+ async function forkConversation(input) {
992
+ const created = await db.transaction(async (tx) => {
993
+ const source = await tx
994
+ .select()
995
+ .from(chatConversations)
996
+ .where(and(eq(chatConversations.id, input.sourceConversationId), eq(chatConversations.orgId, input.orgId)))
997
+ .then((rows) => rows[0] ?? null);
998
+ if (!source)
999
+ throw notFound("Chat conversation not found");
1000
+ const rootConversationId = source.forkRootConversationId ?? source.id;
1001
+ const messageConditions = [
1002
+ eq(chatMessages.conversationId, source.id),
1003
+ eq(chatMessages.orgId, input.orgId),
1004
+ isNull(chatMessages.supersededAt),
1005
+ ];
1006
+ let forkSourceCreatedAt = null;
1007
+ if (input.sourceMessageId) {
1008
+ const sourceMessage = await tx
1009
+ .select({
1010
+ id: chatMessages.id,
1011
+ kind: chatMessages.kind,
1012
+ role: chatMessages.role,
1013
+ createdAt: chatMessages.createdAt,
1014
+ })
1015
+ .from(chatMessages)
1016
+ .where(and(...messageConditions, eq(chatMessages.id, input.sourceMessageId)))
1017
+ .then((rows) => rows[0] ?? null);
1018
+ if (!sourceMessage)
1019
+ throw unprocessable("Fork source message must belong to the source conversation");
1020
+ if (sourceMessage.role !== "assistant" || sourceMessage.kind !== "message") {
1021
+ throw unprocessable("Fork source message must be an assistant response");
1022
+ }
1023
+ forkSourceCreatedAt = sourceMessage.createdAt;
1024
+ }
1025
+ const now = new Date();
1026
+ const [child] = await tx
1027
+ .insert(chatConversations)
1028
+ .values({
1029
+ orgId: input.orgId,
1030
+ status: "active",
1031
+ title: input.title?.trim() || source.title,
1032
+ summary: source.summary,
1033
+ preferredAgentId: source.preferredAgentId,
1034
+ routedAgentId: source.routedAgentId,
1035
+ primaryIssueId: source.primaryIssueId,
1036
+ forkedFromConversationId: source.id,
1037
+ forkedFromMessageId: input.sourceMessageId ?? null,
1038
+ forkRootConversationId: rootConversationId,
1039
+ issueCreationMode: source.issueCreationMode,
1040
+ planMode: source.planMode,
1041
+ createdByUserId: input.createdByUserId,
1042
+ createdAt: now,
1043
+ updatedAt: now,
1044
+ })
1045
+ .returning();
1046
+ if (!child)
1047
+ throw new Error("Failed to create forked chat conversation");
1048
+ const contextLinks = await tx
1049
+ .select()
1050
+ .from(chatContextLinks)
1051
+ .where(eq(chatContextLinks.conversationId, source.id))
1052
+ .orderBy(chatContextLinks.createdAt);
1053
+ if (contextLinks.length > 0) {
1054
+ await tx
1055
+ .insert(chatContextLinks)
1056
+ .values(contextLinks.map((link) => ({
1057
+ orgId: input.orgId,
1058
+ conversationId: child.id,
1059
+ entityType: link.entityType,
1060
+ entityId: link.entityId,
1061
+ metadata: link.metadata,
1062
+ })))
1063
+ .onConflictDoNothing();
1064
+ }
1065
+ const messagesToCopy = await tx
1066
+ .select()
1067
+ .from(chatMessages)
1068
+ .where(and(...messageConditions, ...(forkSourceCreatedAt && input.sourceMessageId
1069
+ ? [or(lt(chatMessages.createdAt, forkSourceCreatedAt), eq(chatMessages.id, input.sourceMessageId))]
1070
+ : [])))
1071
+ .orderBy(chatMessages.createdAt, chatMessages.id);
1072
+ const forkMessages = input.sourceMessageId
1073
+ ? messagesToCopy.slice(0, messagesToCopy.findIndex((message) => message.id === input.sourceMessageId) + 1)
1074
+ : messagesToCopy;
1075
+ if (forkMessages.length > 0) {
1076
+ await tx.insert(chatMessages).values(forkMessages.map((message) => ({
1077
+ orgId: input.orgId,
1078
+ conversationId: child.id,
1079
+ role: message.role,
1080
+ kind: message.kind,
1081
+ status: message.status === "streaming" ? "interrupted" : message.status,
1082
+ body: message.body,
1083
+ structuredPayload: null,
1084
+ approvalId: null,
1085
+ runId: null,
1086
+ replyingAgentId: message.replyingAgentId,
1087
+ chatTurnId: null,
1088
+ turnVariant: 0,
1089
+ createdAt: message.createdAt,
1090
+ updatedAt: message.updatedAt,
1091
+ })));
1092
+ }
1093
+ const [systemEvent] = await tx
1094
+ .insert(chatMessages)
1095
+ .values({
1096
+ orgId: input.orgId,
1097
+ conversationId: child.id,
1098
+ role: "system",
1099
+ kind: "system_event",
1100
+ status: "completed",
1101
+ body: forkSystemEventBody(source, input.sourceMessageId ?? null),
1102
+ structuredPayload: {
1103
+ eventType: "chat_fork",
1104
+ type: "chat_fork",
1105
+ sourceConversationId: source.id,
1106
+ sourceConversationTitle: source.title,
1107
+ sourceMessageId: input.sourceMessageId ?? null,
1108
+ forkRootConversationId: rootConversationId,
1109
+ },
1110
+ createdAt: now,
1111
+ updatedAt: now,
1112
+ })
1113
+ .returning();
1114
+ await tx
1115
+ .update(chatConversations)
1116
+ .set({
1117
+ lastMessageAt: systemEvent?.createdAt ?? now,
1118
+ updatedAt: now,
1119
+ })
1120
+ .where(eq(chatConversations.id, child.id));
1121
+ await ensureForkFamilyGroup(tx, input.orgId, input.userId, rootConversationId, source.id, child.id, source.title);
1122
+ return child;
1123
+ });
1124
+ return getById(created.id, input.userId);
1125
+ }
496
1126
  async function update(id, patch) {
497
1127
  const [updated] = await db
498
1128
  .update(chatConversations)
@@ -506,14 +1136,14 @@ export function chatService(db) {
506
1136
  return null;
507
1137
  return getById(id);
508
1138
  }
509
- async function updateDefaultTitle(id, title) {
1139
+ async function updateDefaultTitle(id, title, expectedCurrentTitle = "New chat") {
510
1140
  const [updated] = await db
511
1141
  .update(chatConversations)
512
1142
  .set({
513
1143
  title,
514
1144
  updatedAt: new Date(),
515
1145
  })
516
- .where(and(eq(chatConversations.id, id), eq(chatConversations.title, "New chat")))
1146
+ .where(and(eq(chatConversations.id, id), eq(chatConversations.title, expectedCurrentTitle)))
517
1147
  .returning();
518
1148
  if (!updated)
519
1149
  return null;
@@ -1462,10 +2092,26 @@ export function chatService(db) {
1462
2092
  replaceSystemGeneratedTitle,
1463
2093
  listAttachmentsForConversation,
1464
2094
  remove,
2095
+ forkConversation,
1465
2096
  resolve,
1466
2097
  markRead,
1467
2098
  markUnread,
1468
2099
  setPinned,
2100
+ createGeneration,
2101
+ markGenerationTerminal,
2102
+ getLatestActiveGeneration,
2103
+ getLatestGeneration,
2104
+ getQueueSnapshot,
2105
+ listQueuedMessages,
2106
+ createQueuedMessage,
2107
+ updateQueuedMessage,
2108
+ cancelQueuedMessage,
2109
+ markQueuedMessageSteerFallback,
2110
+ claimNextQueuedMessage,
2111
+ releaseQueuedMessageClaim,
2112
+ assertQueuedMessageClaimedForDelivery,
2113
+ markQueuedMessageRunning,
2114
+ markQueuedMessageDeliveryTerminal,
1469
2115
  listMessages,
1470
2116
  getMessageTranscript,
1471
2117
  addMessage,