@rudderhq/server 0.5.0 → 0.5.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 (352) hide show
  1. package/dist/agent-runtimes/http/execute.d.ts.map +1 -1
  2. package/dist/agent-runtimes/http/execute.js +56 -1
  3. package/dist/agent-runtimes/http/execute.js.map +1 -1
  4. package/dist/agent-runtimes/http/index.d.ts.map +1 -1
  5. package/dist/agent-runtimes/http/index.js +10 -0
  6. package/dist/agent-runtimes/http/index.js.map +1 -1
  7. package/dist/agent-runtimes/process/execute.d.ts.map +1 -1
  8. package/dist/agent-runtimes/process/execute.js +9 -1
  9. package/dist/agent-runtimes/process/execute.js.map +1 -1
  10. package/dist/agent-runtimes/process/index.d.ts.map +1 -1
  11. package/dist/agent-runtimes/process/index.js +7 -0
  12. package/dist/agent-runtimes/process/index.js.map +1 -1
  13. package/dist/agent-runtimes/registry.d.ts.map +1 -1
  14. package/dist/agent-runtimes/registry.js +21 -1
  15. package/dist/agent-runtimes/registry.js.map +1 -1
  16. package/dist/agent-runtimes/utils.d.ts +1 -0
  17. package/dist/agent-runtimes/utils.d.ts.map +1 -1
  18. package/dist/agent-runtimes/utils.js.map +1 -1
  19. package/dist/bundled-plugins/plugin-linear/dist/worker.js +183 -10
  20. package/dist/bundled-plugins/plugin-linear/dist/worker.js.map +3 -3
  21. package/dist/home-paths.d.ts +7 -0
  22. package/dist/home-paths.d.ts.map +1 -1
  23. package/dist/home-paths.js +46 -2
  24. package/dist/home-paths.js.map +1 -1
  25. package/dist/index.js +23 -4
  26. package/dist/index.js.map +1 -1
  27. package/dist/routes/access.d.ts.map +1 -1
  28. package/dist/routes/access.helpers.d.ts +1 -1
  29. package/dist/routes/access.helpers.d.ts.map +1 -1
  30. package/dist/routes/access.helpers.js +0 -3
  31. package/dist/routes/access.helpers.js.map +1 -1
  32. package/dist/routes/access.js +0 -4
  33. package/dist/routes/access.js.map +1 -1
  34. package/dist/routes/agents.js +2 -2
  35. package/dist/routes/agents.js.map +1 -1
  36. package/dist/routes/chats.d.ts.map +1 -1
  37. package/dist/routes/chats.generated-attachments.d.ts +16 -0
  38. package/dist/routes/chats.generated-attachments.d.ts.map +1 -0
  39. package/dist/routes/chats.generated-attachments.js +157 -0
  40. package/dist/routes/chats.generated-attachments.js.map +1 -0
  41. package/dist/routes/chats.helpers.d.ts +27 -0
  42. package/dist/routes/chats.helpers.d.ts.map +1 -0
  43. package/dist/routes/chats.helpers.js +52 -0
  44. package/dist/routes/chats.helpers.js.map +1 -0
  45. package/dist/routes/chats.js +126 -188
  46. package/dist/routes/chats.js.map +1 -1
  47. package/dist/routes/chats.stream-routes.d.ts.map +1 -1
  48. package/dist/routes/chats.stream-routes.js +185 -16
  49. package/dist/routes/chats.stream-routes.js.map +1 -1
  50. package/dist/routes/llms.js +3 -3
  51. package/dist/routes/llms.js.map +1 -1
  52. package/dist/routes/messenger.d.ts.map +1 -1
  53. package/dist/routes/messenger.js +48 -6
  54. package/dist/routes/messenger.js.map +1 -1
  55. package/dist/services/activity.d.ts.map +1 -1
  56. package/dist/services/activity.js +7 -2
  57. package/dist/services/activity.js.map +1 -1
  58. package/dist/services/agents.d.ts +65 -65
  59. package/dist/services/agents.d.ts.map +1 -1
  60. package/dist/services/agents.js +5 -4
  61. package/dist/services/agents.js.map +1 -1
  62. package/dist/services/approvals.d.ts +1 -1
  63. package/dist/services/assets.d.ts +2 -2
  64. package/dist/services/automation-chat-output.d.ts +1 -1
  65. package/dist/services/automation-chat-output.d.ts.map +1 -1
  66. package/dist/services/automation-chat-output.js +38 -23
  67. package/dist/services/automation-chat-output.js.map +1 -1
  68. package/dist/services/automations.d.ts.map +1 -1
  69. package/dist/services/automations.js +39 -41
  70. package/dist/services/automations.js.map +1 -1
  71. package/dist/services/budgets.d.ts +1 -1
  72. package/dist/services/chat-assistant.d.ts +23 -1
  73. package/dist/services/chat-assistant.d.ts.map +1 -1
  74. package/dist/services/chat-assistant.helpers.d.ts +21 -0
  75. package/dist/services/chat-assistant.helpers.d.ts.map +1 -1
  76. package/dist/services/chat-assistant.helpers.js +29 -10
  77. package/dist/services/chat-assistant.helpers.js.map +1 -1
  78. package/dist/services/chat-assistant.inline-visuals.d.ts +23 -0
  79. package/dist/services/chat-assistant.inline-visuals.d.ts.map +1 -0
  80. package/dist/services/chat-assistant.inline-visuals.js +129 -0
  81. package/dist/services/chat-assistant.inline-visuals.js.map +1 -0
  82. package/dist/services/chat-assistant.inline-visuals.test.js +85 -1
  83. package/dist/services/chat-assistant.inline-visuals.test.js.map +1 -1
  84. package/dist/services/chat-assistant.js +262 -38
  85. package/dist/services/chat-assistant.js.map +1 -1
  86. package/dist/services/chat-family-groups.d.ts +14 -0
  87. package/dist/services/chat-family-groups.d.ts.map +1 -0
  88. package/dist/services/chat-family-groups.js +96 -0
  89. package/dist/services/chat-family-groups.js.map +1 -0
  90. package/dist/services/chat-generation-protocol.d.ts +17 -31
  91. package/dist/services/chat-generation-protocol.d.ts.map +1 -1
  92. package/dist/services/chat-generation-protocol.helpers.d.ts +36 -0
  93. package/dist/services/chat-generation-protocol.helpers.d.ts.map +1 -0
  94. package/dist/services/chat-generation-protocol.helpers.js +53 -0
  95. package/dist/services/chat-generation-protocol.helpers.js.map +1 -0
  96. package/dist/services/chat-generation-protocol.js +86 -55
  97. package/dist/services/chat-generation-protocol.js.map +1 -1
  98. package/dist/services/chat-generation-protocol.test.js +31 -3
  99. package/dist/services/chat-generation-protocol.test.js.map +1 -1
  100. package/dist/services/chat-steer-messages.d.ts +117 -0
  101. package/dist/services/chat-steer-messages.d.ts.map +1 -0
  102. package/dist/services/chat-steer-messages.js +410 -0
  103. package/dist/services/chat-steer-messages.js.map +1 -0
  104. package/dist/services/chat-title-generation.d.ts +1 -0
  105. package/dist/services/chat-title-generation.d.ts.map +1 -1
  106. package/dist/services/chat-title-generation.js +12 -9
  107. package/dist/services/chat-title-generation.js.map +1 -1
  108. package/dist/services/chat-work-manifest.d.ts.map +1 -1
  109. package/dist/services/chat-work-manifest.js +39 -2
  110. package/dist/services/chat-work-manifest.js.map +1 -1
  111. package/dist/services/chats.constants.d.ts +5 -0
  112. package/dist/services/chats.constants.d.ts.map +1 -0
  113. package/dist/services/chats.constants.js +13 -0
  114. package/dist/services/chats.constants.js.map +1 -0
  115. package/dist/services/chats.create.d.ts +75 -0
  116. package/dist/services/chats.create.d.ts.map +1 -0
  117. package/dist/services/chats.create.js +159 -0
  118. package/dist/services/chats.create.js.map +1 -0
  119. package/dist/services/chats.d.ts +85 -76
  120. package/dist/services/chats.d.ts.map +1 -1
  121. package/dist/services/chats.fork-helpers.d.ts +8 -0
  122. package/dist/services/chats.fork-helpers.d.ts.map +1 -0
  123. package/dist/services/chats.fork-helpers.js +45 -0
  124. package/dist/services/chats.fork-helpers.js.map +1 -0
  125. package/dist/services/chats.inline-visual-persistence.d.ts +30 -0
  126. package/dist/services/chats.inline-visual-persistence.d.ts.map +1 -0
  127. package/dist/services/chats.inline-visual-persistence.js +209 -0
  128. package/dist/services/chats.inline-visual-persistence.js.map +1 -0
  129. package/dist/services/chats.js +288 -273
  130. package/dist/services/chats.js.map +1 -1
  131. package/dist/services/chats.types.d.ts +31 -0
  132. package/dist/services/chats.types.d.ts.map +1 -0
  133. package/dist/services/chats.types.js +2 -0
  134. package/dist/services/chats.types.js.map +1 -0
  135. package/dist/services/integrations/feishu/inbound-dispatcher-db.d.ts.map +1 -1
  136. package/dist/services/integrations/feishu/inbound-dispatcher-db.js +81 -53
  137. package/dist/services/integrations/feishu/inbound-dispatcher-db.js.map +1 -1
  138. package/dist/services/integrations/feishu/inbound-dispatcher.d.ts +1 -0
  139. package/dist/services/integrations/feishu/inbound-dispatcher.d.ts.map +1 -1
  140. package/dist/services/integrations/feishu/inbound-dispatcher.js.map +1 -1
  141. package/dist/services/issues.comments-attachments.d.ts.map +1 -1
  142. package/dist/services/issues.comments-attachments.js +11 -2
  143. package/dist/services/issues.comments-attachments.js.map +1 -1
  144. package/dist/services/issues.d.ts.map +1 -1
  145. package/dist/services/knowledge-portability/organization-skills.catalog.d.ts.map +1 -1
  146. package/dist/services/knowledge-portability/organization-skills.catalog.js +7 -1
  147. package/dist/services/knowledge-portability/organization-skills.catalog.js.map +1 -1
  148. package/dist/services/knowledge-portability/organization-skills.d.ts.map +1 -1
  149. package/dist/services/knowledge-portability/organization-skills.js +13 -1
  150. package/dist/services/knowledge-portability/organization-skills.js.map +1 -1
  151. package/dist/services/messenger-run-origin.d.ts +18 -0
  152. package/dist/services/messenger-run-origin.d.ts.map +1 -0
  153. package/dist/services/messenger-run-origin.js +248 -0
  154. package/dist/services/messenger-run-origin.js.map +1 -0
  155. package/dist/services/messenger-run-summary.d.ts +4 -0
  156. package/dist/services/messenger-run-summary.d.ts.map +1 -0
  157. package/dist/services/messenger-run-summary.js +6 -0
  158. package/dist/services/messenger-run-summary.js.map +1 -0
  159. package/dist/services/messenger-saved-views.d.ts +133 -0
  160. package/dist/services/messenger-saved-views.d.ts.map +1 -0
  161. package/dist/services/messenger-saved-views.js +275 -0
  162. package/dist/services/messenger-saved-views.js.map +1 -0
  163. package/dist/services/messenger.d.ts +17 -3
  164. package/dist/services/messenger.d.ts.map +1 -1
  165. package/dist/services/messenger.js +276 -56
  166. package/dist/services/messenger.js.map +1 -1
  167. package/dist/services/operator-event-visibility.d.ts +3 -0
  168. package/dist/services/operator-event-visibility.d.ts.map +1 -0
  169. package/dist/services/operator-event-visibility.js +5 -0
  170. package/dist/services/operator-event-visibility.js.map +1 -0
  171. package/dist/services/orgs.d.ts +5 -5
  172. package/dist/services/plugin-registry.d.ts +4 -4
  173. package/dist/services/projects.d.ts +2 -2
  174. package/dist/services/run-intelligence.d.ts.map +1 -1
  175. package/dist/services/run-intelligence.js +7 -3
  176. package/dist/services/run-intelligence.js.map +1 -1
  177. package/dist/services/runtime-kernel/heartbeat.core.d.ts.map +1 -1
  178. package/dist/services/runtime-kernel/heartbeat.core.js +9 -8
  179. package/dist/services/runtime-kernel/heartbeat.core.js.map +1 -1
  180. package/dist/services/runtime-kernel/heartbeat.d.ts +2 -2
  181. package/dist/services/runtime-kernel/heartbeat.d.ts.map +1 -1
  182. package/dist/services/runtime-kernel/heartbeat.js +3 -2
  183. package/dist/services/runtime-kernel/heartbeat.js.map +1 -1
  184. package/dist/services/runtime-kernel/heartbeat.misc.js +1 -1
  185. package/dist/services/runtime-kernel/heartbeat.misc.js.map +1 -1
  186. package/dist/services/runtime-kernel/heartbeat.recovery.js +1 -1
  187. package/dist/services/runtime-kernel/heartbeat.recovery.js.map +1 -1
  188. package/dist/services/side-chats.d.ts +1 -46
  189. package/dist/services/side-chats.d.ts.map +1 -1
  190. package/dist/services/side-chats.js +58 -65
  191. package/dist/services/side-chats.js.map +1 -1
  192. package/dist/services/title-generation.d.ts +3 -0
  193. package/dist/services/title-generation.d.ts.map +1 -1
  194. package/dist/services/title-generation.js +178 -6
  195. package/dist/services/title-generation.js.map +1 -1
  196. package/dist/services/workspace-backups.d.ts +19 -8
  197. package/dist/services/workspace-backups.d.ts.map +1 -1
  198. package/dist/services/workspace-backups.js +335 -127
  199. package/dist/services/workspace-backups.js.map +1 -1
  200. package/package.json +14 -13
  201. package/resources/bundled-skills/browser/references/tool-contract.md +2 -2
  202. package/resources/bundled-skills/rudder-docs/SKILL.md +20 -4
  203. package/resources/bundled-skills/rudder-docs/evals/retrieval-authority-evals.json +262 -0
  204. package/resources/bundled-skills/rudder-docs/evals/trigger-evals.json +11 -11
  205. package/resources/bundled-skills/rudder-docs/references/agent-creation.md +153 -0
  206. package/resources/bundled-skills/rudder-docs/references/api-reference.md +9 -2
  207. package/resources/bundled-skills/rudder-docs/references/cli-reference.md +12 -12
  208. package/{skills/rudder-docs/references/control-plane-practices.md → resources/bundled-skills/rudder-docs/references/operating-practices.md} +4 -4
  209. package/resources/bundled-skills/rudder-docs/references/organization-skills.md +3 -3
  210. package/resources/bundled-skills/rudder-docs/references/plugin-authoring.md +116 -0
  211. package/resources/bundled-skills/rudder-docs/references/source-map.md +26 -2
  212. package/resources/bundled-skills/visualize/SKILL.md +29 -27
  213. package/resources/bundled-skills/visualize/references/runtime-contract.md +18 -8
  214. package/skills/browser/references/tool-contract.md +2 -2
  215. package/skills/rudder-docs/SKILL.md +20 -4
  216. package/skills/rudder-docs/evals/retrieval-authority-evals.json +262 -0
  217. package/skills/rudder-docs/evals/trigger-evals.json +11 -11
  218. package/skills/rudder-docs/references/agent-creation.md +153 -0
  219. package/skills/rudder-docs/references/api-reference.md +9 -2
  220. package/skills/rudder-docs/references/cli-reference.md +12 -12
  221. package/{resources/bundled-skills/rudder-docs/references/control-plane-practices.md → skills/rudder-docs/references/operating-practices.md} +4 -4
  222. package/skills/rudder-docs/references/organization-skills.md +3 -3
  223. package/skills/rudder-docs/references/plugin-authoring.md +116 -0
  224. package/skills/rudder-docs/references/source-map.md +26 -2
  225. package/skills/visualize/SKILL.md +29 -27
  226. package/skills/visualize/references/runtime-contract.md +18 -8
  227. package/ui-dist/assets/{abnfDiagram-VRR7QNED-Dpnx79fp.js → abnfDiagram-VRR7QNED-CAAPm9Nj.js} +1 -1
  228. package/ui-dist/assets/{arc-Cpvh_rCf.js → arc-DOFoNr3M.js} +1 -1
  229. package/ui-dist/assets/{architectureDiagram-ZJ3FMSHR-sDD_mBAI.js → architectureDiagram-ZJ3FMSHR-DRg6yhG8.js} +1 -1
  230. package/ui-dist/assets/{blockDiagram-677ZJIJ3-4O4wWti1.js → blockDiagram-677ZJIJ3-e3ShzsXT.js} +1 -1
  231. package/ui-dist/assets/{c4Diagram-LMCZKHZV-BkGODE4P.js → c4Diagram-LMCZKHZV-Csd_18O2.js} +1 -1
  232. package/ui-dist/assets/channel-BFLsBJOK.js +1 -0
  233. package/ui-dist/assets/{chunk-2Q5K7J3B-DsDQQpID.js → chunk-2Q5K7J3B-eF77FV1C.js} +1 -1
  234. package/ui-dist/assets/{chunk-32BRIVSS-Bzx_VnIw.js → chunk-32BRIVSS-CpMx72B5.js} +1 -1
  235. package/ui-dist/assets/{chunk-5VM5RSS4-D4LoPCni.js → chunk-5VM5RSS4-Be6WylCu.js} +1 -1
  236. package/ui-dist/assets/{chunk-EX3LRPZG-BO0R-mS4.js → chunk-EX3LRPZG-D-A_TfL-.js} +1 -1
  237. package/ui-dist/assets/{chunk-JWPE2WC7-B4Nr8KRL.js → chunk-JWPE2WC7-CdBLDqvo.js} +1 -1
  238. package/ui-dist/assets/{chunk-MOJQB5TN--uaDDrYM.js → chunk-MOJQB5TN-DkLjRENV.js} +1 -1
  239. package/ui-dist/assets/{chunk-RYQCIY6F-CyBY2w_j.js → chunk-RYQCIY6F-57VqTsE9.js} +1 -1
  240. package/ui-dist/assets/{chunk-V7JOEXUC-BMid_x8S.js → chunk-V7JOEXUC-DI_m8pt6.js} +1 -1
  241. package/ui-dist/assets/{chunk-VR4S4FIN-DVqdPKuG.js → chunk-VR4S4FIN-CM_944j4.js} +1 -1
  242. package/ui-dist/assets/{chunk-XXDRQBXY-vy03lLSS.js → chunk-XXDRQBXY--WTAlt82.js} +1 -1
  243. package/ui-dist/assets/classDiagram-OUVF2IWQ-Dah6C4Dl.js +1 -0
  244. package/ui-dist/assets/classDiagram-v2-EOCWNBFH-Dah6C4Dl.js +1 -0
  245. package/ui-dist/assets/{cose-bilkent-JH36ORCC-jQDZmrG3.js → cose-bilkent-JH36ORCC-CR0qu31s.js} +1 -1
  246. package/ui-dist/assets/{cynefin-VYW2F7L2-BxBj6aea.js → cynefin-VYW2F7L2-f41lF5RD.js} +1 -1
  247. package/ui-dist/assets/{cynefinDiagram-TSTJHNR4-BuUubF5I.js → cynefinDiagram-TSTJHNR4-88wJ2LA8.js} +1 -1
  248. package/ui-dist/assets/{dagre-VKFMJZFB-B8HipJ3a.js → dagre-VKFMJZFB-B1yJCIRh.js} +1 -1
  249. package/ui-dist/assets/{diagram-FQU43EPY-r7gkbKSt.js → diagram-FQU43EPY-C0iYYFUe.js} +1 -1
  250. package/ui-dist/assets/{diagram-G47NLZAW-CxClRsxD.js → diagram-G47NLZAW-Cp6S0siK.js} +1 -1
  251. package/ui-dist/assets/{diagram-NH7WQ7WH-C8HYTLlq.js → diagram-NH7WQ7WH-CmZb5OSk.js} +1 -1
  252. package/ui-dist/assets/{diagram-OA4YK3LP-CjwqqLKz.js → diagram-OA4YK3LP-9rFYGY7H.js} +1 -1
  253. package/ui-dist/assets/{diagram-WEI45ONY-2IWfCqZb.js → diagram-WEI45ONY-Og8vyDQh.js} +1 -1
  254. package/ui-dist/assets/{ebnfDiagram-CCIWWBDH-DVGZkgjy.js → ebnfDiagram-CCIWWBDH--5sMape2.js} +1 -1
  255. package/ui-dist/assets/{erDiagram-Q63AITRT-C_-u3Gmw.js → erDiagram-Q63AITRT-DG10Bza-.js} +1 -1
  256. package/ui-dist/assets/{flowDiagram-23GEKE2U-BvGg0NCq.js → flowDiagram-23GEKE2U-BW-aZfEk.js} +1 -1
  257. package/ui-dist/assets/{ganttDiagram-NO4QXBWP-U3CZUUUR.js → ganttDiagram-NO4QXBWP-DcA7on8t.js} +1 -1
  258. package/ui-dist/assets/{gitGraphDiagram-IHSO6WYX-CIWuEBIo.js → gitGraphDiagram-IHSO6WYX-ygGufg32.js} +1 -1
  259. package/ui-dist/assets/{graph-D3P5q-7m.js → graph-BXl6uBoM.js} +1 -1
  260. package/ui-dist/assets/{index-DOPIV8vd.js → index-9bXlV2sq.js} +1 -1
  261. package/ui-dist/assets/{index-CjztBLJi.js → index-B58ems-F.js} +1 -1
  262. package/ui-dist/assets/{index-mnl55Stn.js → index-BM-SJNCx.js} +1 -1
  263. package/ui-dist/assets/index-BcdA9dZc.css +1 -0
  264. package/ui-dist/assets/{index-BAgtKYR1.js → index-BmTNDbzy.js} +1 -1
  265. package/ui-dist/assets/{index-DidCCw78.js → index-CCDynlok.js} +1 -1
  266. package/ui-dist/assets/{index-CbHqnWUe.js → index-CRLl2Ck7.js} +1 -1
  267. package/ui-dist/assets/{index-D7ycf1qU.js → index-CqmU1PxY.js} +1 -1
  268. package/ui-dist/assets/{index-B1rLBtZ1.js → index-CssgLJwf.js} +605 -493
  269. package/ui-dist/assets/{index-DRxLJD40.js → index-DOVMMhyj.js} +1 -1
  270. package/ui-dist/assets/{index-Ds_qma4-.js → index-DTlR8bJV.js} +1 -1
  271. package/ui-dist/assets/{index-DCFf9dps.js → index-Dl6nXXNc.js} +1 -1
  272. package/ui-dist/assets/{index-DAYlwxsg.js → index-DoiNhQrY.js} +1 -1
  273. package/ui-dist/assets/{index-CBOr9F6w.js → index-Dug5GX1J.js} +1 -1
  274. package/ui-dist/assets/{index-HkQRx1D6.js → index-DxXOCTVe.js} +1 -1
  275. package/ui-dist/assets/{index-BAMXpiI5.js → index-GdN-7KLt.js} +1 -1
  276. package/ui-dist/assets/{index-ikpL--zj.js → index-ZA8lPH2n.js} +1 -1
  277. package/ui-dist/assets/{index-Cu1iMhjl.js → index-fkDP349f.js} +1 -1
  278. package/ui-dist/assets/{index-DYMtCDKT.js → index-uKIvv9n9.js} +1 -1
  279. package/ui-dist/assets/{infoDiagram-FWYZ7A6U-Cx8Fa-I4.js → infoDiagram-FWYZ7A6U-27INMkBm.js} +1 -1
  280. package/ui-dist/assets/{ishikawaDiagram-FXEZZL3T-Cmuz1QUN.js → ishikawaDiagram-FXEZZL3T-Bp6XQ1_r.js} +1 -1
  281. package/ui-dist/assets/{journeyDiagram-5HDEW3XC-CJgkiVXG.js → journeyDiagram-5HDEW3XC-9vaIwdZ3.js} +1 -1
  282. package/ui-dist/assets/{kanban-definition-HUTT4EX6-RAWpefOB.js → kanban-definition-HUTT4EX6-DjsMaR6l.js} +1 -1
  283. package/ui-dist/assets/{layout-DyWQv0Rr.js → layout-C0oWcIiC.js} +1 -1
  284. package/ui-dist/assets/{linear-D5pdgIf9.js → linear-DNbmenmQ.js} +1 -1
  285. package/ui-dist/assets/{map-bVSzNLl2.js → map-B1s9kpcR.js} +1 -1
  286. package/ui-dist/assets/{mermaid.core-CeaXGD6B.js → mermaid.core-DsYT9DxL.js} +4 -4
  287. package/ui-dist/assets/{mindmap-definition-LN4V7U3C-B8B8AX5C.js → mindmap-definition-LN4V7U3C-vVHeRI83.js} +1 -1
  288. package/ui-dist/assets/{pegDiagram-2B236MQR-C4Sv-ua6.js → pegDiagram-2B236MQR-ohrgWLo_.js} +1 -1
  289. package/ui-dist/assets/{pieDiagram-ENE6RG2P-CLARlOHx.js → pieDiagram-ENE6RG2P-B0EqPrjn.js} +1 -1
  290. package/ui-dist/assets/{quadrantDiagram-ABIIQ3AL-DPCXQmeT.js → quadrantDiagram-ABIIQ3AL-D44iYm0o.js} +1 -1
  291. package/ui-dist/assets/{railroadDiagram-RFXS5EU6-BpqRuKUQ.js → railroadDiagram-RFXS5EU6-BQU5bpbU.js} +1 -1
  292. package/ui-dist/assets/{requirementDiagram-TGXJPOKE-Dd-h62HZ.js → requirementDiagram-TGXJPOKE-DGJciRxB.js} +1 -1
  293. package/ui-dist/assets/{sankeyDiagram-HTMAVEWB-DylT_pqq.js → sankeyDiagram-HTMAVEWB-NMXZW_Qb.js} +1 -1
  294. package/ui-dist/assets/{sequenceDiagram-DBY2YBRQ-RiCF1REj.js → sequenceDiagram-DBY2YBRQ-8uWY67Bb.js} +1 -1
  295. package/ui-dist/assets/{sizeCapture-X5ZJPWSS-DXW4JQz2.js → sizeCapture-X5ZJPWSS-BnUUR-On.js} +1 -1
  296. package/ui-dist/assets/{stateDiagram-2N3HPSRC-6U3ESIGT.js → stateDiagram-2N3HPSRC-B37bcKMy.js} +1 -1
  297. package/ui-dist/assets/stateDiagram-v2-6OUMAXLB-p6H0vL7N.js +1 -0
  298. package/ui-dist/assets/{swimlanes-5IMT3BWC-CeNHVNCi.js → swimlanes-5IMT3BWC-Bi2ZzUMi.js} +2 -2
  299. package/ui-dist/assets/swimlanesDiagram-G3AALYLV-BX6FiLF9.js +8 -0
  300. package/ui-dist/assets/{timeline-definition-FHXFAJF6-Vlwoe_1b.js → timeline-definition-FHXFAJF6-CkWauU5D.js} +1 -1
  301. package/ui-dist/assets/{vennDiagram-L72KCM5P-DBP7D3HE.js → vennDiagram-L72KCM5P-BrmBXmnk.js} +1 -1
  302. package/ui-dist/assets/{wardleyDiagram-EHGQE667-DG-wzqpy.js → wardleyDiagram-EHGQE667-kO5cojc6.js} +1 -1
  303. package/ui-dist/assets/{xychartDiagram-FW5EYKEG-BAq3mbha.js → xychartDiagram-FW5EYKEG-CUBDaCDm.js} +1 -1
  304. package/ui-dist/index.html +5 -4
  305. package/resources/bundled-skills/rudder-create-agent/SKILL.md +0 -185
  306. package/resources/bundled-skills/rudder-create-agent/references/api-reference.md +0 -179
  307. package/resources/bundled-skills/rudder-create-agent/references/cli-reference.md +0 -132
  308. package/resources/bundled-skills/rudder-create-plugin/SKILL.md +0 -103
  309. package/resources/bundled-skills/skill-optimizer/CHANGELOG.md +0 -29
  310. package/resources/bundled-skills/skill-optimizer/SKILL.md +0 -205
  311. package/resources/bundled-skills/skill-optimizer/references/adapters/creative-brand-content.md +0 -30
  312. package/resources/bundled-skills/skill-optimizer/references/adapters/customer-support-sales.md +0 -30
  313. package/resources/bundled-skills/skill-optimizer/references/adapters/document-data-processing.md +0 -31
  314. package/resources/bundled-skills/skill-optimizer/references/adapters/education-training.md +0 -31
  315. package/resources/bundled-skills/skill-optimizer/references/adapters/finance-accounting.md +0 -31
  316. package/resources/bundled-skills/skill-optimizer/references/adapters/healthcare-operations.md +0 -30
  317. package/resources/bundled-skills/skill-optimizer/references/adapters/hr-people-ops.md +0 -31
  318. package/resources/bundled-skills/skill-optimizer/references/adapters/legal-compliance.md +0 -31
  319. package/resources/bundled-skills/skill-optimizer/references/adapters/operations-supply-chain.md +0 -31
  320. package/resources/bundled-skills/skill-optimizer/references/adapters/personal-productivity.md +0 -29
  321. package/resources/bundled-skills/skill-optimizer/references/adapters/research-knowledge.md +0 -31
  322. package/resources/bundled-skills/skill-optimizer/references/adapters/software-ai.md +0 -31
  323. package/resources/bundled-skills/skill-optimizer/references/domain-adapter-patterns.md +0 -66
  324. package/resources/bundled-skills/skill-optimizer/references/eval-method.md +0 -17
  325. package/resources/bundled-skills/skill-optimizer/references/universal-optimization-lens.md +0 -73
  326. package/skills/rudder-create-agent/SKILL.md +0 -185
  327. package/skills/rudder-create-agent/references/api-reference.md +0 -179
  328. package/skills/rudder-create-agent/references/cli-reference.md +0 -132
  329. package/skills/rudder-create-plugin/SKILL.md +0 -103
  330. package/skills/skill-optimizer/CHANGELOG.md +0 -29
  331. package/skills/skill-optimizer/SKILL.md +0 -205
  332. package/skills/skill-optimizer/references/adapters/creative-brand-content.md +0 -30
  333. package/skills/skill-optimizer/references/adapters/customer-support-sales.md +0 -30
  334. package/skills/skill-optimizer/references/adapters/document-data-processing.md +0 -31
  335. package/skills/skill-optimizer/references/adapters/education-training.md +0 -31
  336. package/skills/skill-optimizer/references/adapters/finance-accounting.md +0 -31
  337. package/skills/skill-optimizer/references/adapters/healthcare-operations.md +0 -30
  338. package/skills/skill-optimizer/references/adapters/hr-people-ops.md +0 -31
  339. package/skills/skill-optimizer/references/adapters/legal-compliance.md +0 -31
  340. package/skills/skill-optimizer/references/adapters/operations-supply-chain.md +0 -31
  341. package/skills/skill-optimizer/references/adapters/personal-productivity.md +0 -29
  342. package/skills/skill-optimizer/references/adapters/research-knowledge.md +0 -31
  343. package/skills/skill-optimizer/references/adapters/software-ai.md +0 -31
  344. package/skills/skill-optimizer/references/domain-adapter-patterns.md +0 -66
  345. package/skills/skill-optimizer/references/eval-method.md +0 -17
  346. package/skills/skill-optimizer/references/universal-optimization-lens.md +0 -73
  347. package/ui-dist/assets/channel-CM4Myg_6.js +0 -1
  348. package/ui-dist/assets/classDiagram-OUVF2IWQ-CtlIEzTt.js +0 -1
  349. package/ui-dist/assets/classDiagram-v2-EOCWNBFH-CtlIEzTt.js +0 -1
  350. package/ui-dist/assets/index-DekHKOsL.css +0 -1
  351. package/ui-dist/assets/stateDiagram-v2-6OUMAXLB-KQTrcZvp.js +0 -1
  352. package/ui-dist/assets/swimlanesDiagram-G3AALYLV-CcxS1c6r.js +0 -8
@@ -1,75 +1,24 @@
1
- import { agentIntegrationChatBindings, agentIntegrations, approvals, assets, chatAttachments, chatContextLinks, chatControlActions, chatConversations, chatConversationUserStates, chatGenerationEvents, chatGenerations, chatMessages, chatQueuedMessages, messengerCustomGroupEntries, messengerCustomGroups } from "@rudderhq/db";
2
- import { chatInlineVisualMappingsFromStructuredPayload, 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";
1
+ import { agentIntegrationChatBindings, agentIntegrations, approvals, assets, chatAttachments, chatContextLinks, chatControlActions, chatConversations, chatConversationUserStates, chatGenerationEvents, chatGenerations, chatMessages, chatQueuedMessages } from "@rudderhq/db";
2
+ import { sanitizeChatStructuredPayload } from "@rudderhq/shared";
3
+ import { and, asc, desc, eq, gt, gte, inArray, isNotNull, isNull, lt, or, sql } from "drizzle-orm";
4
4
  import { randomUUID } from "node:crypto";
5
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";
9
+ import { ensureChatFamilyGroup } from "./chat-family-groups.js";
9
10
  import { chatGenerationProtocolService } from "./chat-generation-protocol.js";
11
+ import { ACTIVE_CHAT_GENERATION_STATUSES, CHAT_GENERATION_CONTROL_LEASE_MS, NATIVE_STEER_GENERATION_STATUSES, SERVER_QUEUE_RUNNING_STATUSES, } from "./chats.constants.js";
12
+ import { createChatConversation, createChatWithInitialMessage } from "./chats.create.js";
13
+ import { conversationMutability, nextForkTitle } from "./chats.fork-helpers.js";
14
+ 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";
15
+ import { copyForkInlineVisualMessages, listRecentUserChatMessages, updateTrustedInlineVisualMappings, } from "./chats.inline-visual-persistence.js";
10
16
  import { issueApprovalService } from "./issue-approvals.js";
11
17
  import { issueService } from "./issues.js";
12
18
  import { normalizeLocalLibraryPathMarkdown } from "./library-path-markdown.js";
13
19
  import { organizationService } from "./orgs.js";
14
20
  import { isPostgresError } from "./postgres-errors.js";
15
21
  const CHAT_TITLE_MAX_LENGTH = 200;
16
- const FORK_TITLE_SUFFIX_PATTERN = / \(([1-9]\d*)\)$/;
17
- const ACTIVE_CHAT_GENERATION_STATUSES = [
18
- "starting",
19
- "active",
20
- "running",
21
- "tool_busy",
22
- "closing",
23
- "stop_requested",
24
- "stopping",
25
- ];
26
- const NATIVE_STEER_GENERATION_STATUSES = ["starting", "active", "running", "tool_busy"];
27
- const SERVER_QUEUE_RUNNING_STATUSES = ["dequeue_claimed", "running_next"];
28
- const CHAT_GENERATION_CONTROL_LEASE_MS = 30_000;
29
- function baseForkTitle(title, sourceIsFork, familyTitles) {
30
- const trimmed = title.trim() || "Forked conversation";
31
- if (!sourceIsFork)
32
- return trimmed;
33
- const match = trimmed.match(FORK_TITLE_SUFFIX_PATTERN);
34
- const index = Number(match?.[1]);
35
- if (!match || index < 2)
36
- return trimmed;
37
- for (const familyTitle of familyTitles) {
38
- const candidateBase = familyTitle.trim();
39
- if (!candidateBase || candidateBase === trimmed)
40
- continue;
41
- if (numberedForkTitle(candidateBase, index) !== trimmed)
42
- continue;
43
- if (index === 2 || familyTitles.has(numberedForkTitle(candidateBase, index - 1))) {
44
- return candidateBase;
45
- }
46
- }
47
- return trimmed;
48
- }
49
- function numberedForkTitle(baseTitle, index) {
50
- const suffix = ` (${index})`;
51
- const availableBaseLength = CHAT_TITLE_MAX_LENGTH - suffix.length;
52
- const truncatedBase = baseTitle.slice(0, availableBaseLength).trimEnd() || "Forked conversation";
53
- return `${truncatedBase}${suffix}`;
54
- }
55
- function nextForkTitle(source, familyTitles) {
56
- const existingTitles = new Set(familyTitles);
57
- const baseTitle = baseForkTitle(source.title, Boolean(source.forkedFromConversationId), existingTitles);
58
- let index = 2;
59
- while (existingTitles.has(numberedForkTitle(baseTitle, index)))
60
- index += 1;
61
- return numberedForkTitle(baseTitle, index);
62
- }
63
- function conversationMutability(row, sourceMetadata, sourceMetadataByConversationId) {
64
- if (sourceMetadata)
65
- return "external_bound_chat";
66
- if ((row.forkedFromConversationId && sourceMetadataByConversationId.has(row.forkedFromConversationId)) ||
67
- (row.forkRootConversationId && sourceMetadataByConversationId.has(row.forkRootConversationId))) {
68
- return "native_fork_from_external";
69
- }
70
- return "native_chat";
71
- }
72
- 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";
73
22
  export function chatService(db) {
74
23
  const generationProtocol = chatGenerationProtocolService(db);
75
24
  const QUEUED_MESSAGE_CLAIM_LEASE_MS = 2 * 60 * 1000;
@@ -606,7 +555,7 @@ export function chatService(db) {
606
555
  const rows = await db
607
556
  .select()
608
557
  .from(chatQueuedMessages)
609
- .where(and(eq(chatQueuedMessages.conversationId, conversationId), inArray(chatQueuedMessages.status, [
558
+ .where(and(eq(chatQueuedMessages.conversationId, conversationId), isNull(chatQueuedMessages.cancelledAt), inArray(chatQueuedMessages.status, [
610
559
  "queued",
611
560
  "steer_pending",
612
561
  "acceptance_unknown",
@@ -1121,6 +1070,28 @@ export function chatService(db) {
1121
1070
  .returning();
1122
1071
  if (!item)
1123
1072
  throw conflict("Queued Steer feedback changed while provider evidence was resolving");
1073
+ const linkedSteerMessageId = item.continuationMessageId ?? item.sourceMessageId;
1074
+ if (linkedSteerMessageId) {
1075
+ const linkedSteerMessage = await tx
1076
+ .select({ structuredPayload: chatMessages.structuredPayload })
1077
+ .from(chatMessages)
1078
+ .where(and(eq(chatMessages.id, linkedSteerMessageId), eq(chatMessages.orgId, input.orgId), eq(chatMessages.conversationId, input.conversationId), eq(chatMessages.role, "user")))
1079
+ .limit(1)
1080
+ .then((rows) => rows[0] ?? null);
1081
+ const steerPayload = linkedSteerMessage?.structuredPayload;
1082
+ if (steerPayload && steerPayload.source === "steer") {
1083
+ await tx
1084
+ .update(chatMessages)
1085
+ .set({
1086
+ structuredPayload: {
1087
+ ...steerPayload,
1088
+ deliveryDisposition: input.disposition,
1089
+ },
1090
+ updatedAt: now,
1091
+ })
1092
+ .where(eq(chatMessages.id, linkedSteerMessageId));
1093
+ }
1094
+ }
1124
1095
  return { action, item: hydrateQueuedMessage(item), applied: true };
1125
1096
  });
1126
1097
  }
@@ -1425,7 +1396,7 @@ export function chatService(db) {
1425
1396
  const item = await tx
1426
1397
  .select()
1427
1398
  .from(chatQueuedMessages)
1428
- .where(and(eq(chatQueuedMessages.id, input.itemId), eq(chatQueuedMessages.orgId, input.orgId), eq(chatQueuedMessages.conversationId, input.conversationId), inArray(chatQueuedMessages.status, ["queued", "steer_pending", "continuation_pending"])))
1399
+ .where(and(eq(chatQueuedMessages.id, input.itemId), eq(chatQueuedMessages.orgId, input.orgId), eq(chatQueuedMessages.conversationId, input.conversationId), isNull(chatQueuedMessages.cancelledAt), inArray(chatQueuedMessages.status, ["queued", "steer_pending", "continuation_pending"])))
1429
1400
  .limit(1)
1430
1401
  .then((rows) => rows[0] ?? null);
1431
1402
  if (!item)
@@ -1479,7 +1450,7 @@ export function chatService(db) {
1479
1450
  version: sql `${chatQueuedMessages.version} + 1`,
1480
1451
  updatedAt: now,
1481
1452
  })
1482
- .where(and(eq(chatQueuedMessages.id, item.id), eq(chatQueuedMessages.version, item.version)))
1453
+ .where(and(eq(chatQueuedMessages.id, item.id), eq(chatQueuedMessages.version, item.version), isNull(chatQueuedMessages.cancelledAt)))
1483
1454
  .returning();
1484
1455
  if (!updatedItem)
1485
1456
  throw conflict("Queued feedback changed while continuation was being scheduled");
@@ -1503,7 +1474,7 @@ export function chatService(db) {
1503
1474
  version: sql `${chatQueuedMessages.version} + 1`,
1504
1475
  updatedAt: now,
1505
1476
  })
1506
- .where(and(eq(chatQueuedMessages.conversationId, input.conversationId), eq(chatQueuedMessages.id, input.itemId), eq(chatQueuedMessages.status, "queued")))
1477
+ .where(and(eq(chatQueuedMessages.conversationId, input.conversationId), eq(chatQueuedMessages.id, input.itemId), eq(chatQueuedMessages.status, "queued"), isNull(chatQueuedMessages.cancelledAt)))
1507
1478
  .returning();
1508
1479
  if (!row)
1509
1480
  throw conflict("Queued message was changed or is no longer steerable");
@@ -1519,12 +1490,12 @@ export function chatService(db) {
1519
1490
  const candidates = await tx
1520
1491
  .select()
1521
1492
  .from(chatQueuedMessages)
1522
- .where(and(inArray(chatQueuedMessages.status, ["continuation_pending", "steer_pending", "queued"]), sql `jsonb_typeof(${chatQueuedMessages.requestActor}) = 'object'`, or(isNull(chatQueuedMessages.deliveryLeaseExpiresAt), lt(chatQueuedMessages.deliveryLeaseExpiresAt, now)), sql `${chatQueuedMessages.status} <> 'steer_pending' or coalesce((
1493
+ .where(and(inArray(chatQueuedMessages.status, ["continuation_pending", "steer_pending", "queued"]), isNull(chatQueuedMessages.cancelledAt), sql `jsonb_typeof(${chatQueuedMessages.requestActor}) = 'object'`, or(isNull(chatQueuedMessages.deliveryLeaseExpiresAt), lt(chatQueuedMessages.deliveryLeaseExpiresAt, now)), sql `(${chatQueuedMessages.status} <> 'steer_pending' or coalesce((
1523
1494
  select steer_action.provider_disposition
1524
1495
  from ${chatControlActions} as steer_action
1525
1496
  where steer_action.id = ${chatQueuedMessages.controlActionId}
1526
1497
  limit 1
1527
- ), 'not_sent') in ('not_sent', 'rejected')`))
1498
+ ), 'not_sent') in ('not_sent', 'rejected'))`))
1528
1499
  .orderBy(sql `case
1529
1500
  when ${chatQueuedMessages.status} = 'continuation_pending' then 0
1530
1501
  when ${chatQueuedMessages.status} = 'steer_pending' then 1
@@ -1653,7 +1624,7 @@ export function chatService(db) {
1653
1624
  version: sql `${chatQueuedMessages.version} + 1`,
1654
1625
  updatedAt: now,
1655
1626
  })
1656
- .where(and(eq(chatQueuedMessages.id, candidate.id), eq(chatQueuedMessages.version, candidate.version)))
1627
+ .where(and(eq(chatQueuedMessages.id, candidate.id), eq(chatQueuedMessages.version, candidate.version), isNull(chatQueuedMessages.cancelledAt)))
1657
1628
  .returning();
1658
1629
  if (!claimed)
1659
1630
  throw conflict("Queued continuation changed while being claimed");
@@ -1689,7 +1660,7 @@ export function chatService(db) {
1689
1660
  deliveryLeaseExpiresAt: new Date(now.getTime() + input.leaseMs),
1690
1661
  updatedAt: now,
1691
1662
  })
1692
- .where(and(eq(chatQueuedMessages.id, input.itemId), eq(chatQueuedMessages.continuationGenerationId, input.generationId), eq(chatQueuedMessages.deliveryLeaseToken, input.leaseToken), eq(chatQueuedMessages.deliveryLeaseEpoch, input.leaseEpoch), inArray(chatQueuedMessages.status, SERVER_QUEUE_RUNNING_STATUSES)))
1663
+ .where(and(eq(chatQueuedMessages.id, input.itemId), eq(chatQueuedMessages.continuationGenerationId, input.generationId), eq(chatQueuedMessages.deliveryLeaseToken, input.leaseToken), eq(chatQueuedMessages.deliveryLeaseEpoch, input.leaseEpoch), isNull(chatQueuedMessages.cancelledAt), inArray(chatQueuedMessages.status, SERVER_QUEUE_RUNNING_STATUSES)))
1693
1664
  .returning({ id: chatQueuedMessages.id });
1694
1665
  return Boolean(row);
1695
1666
  }
@@ -1705,13 +1676,19 @@ export function chatService(db) {
1705
1676
  if (!item)
1706
1677
  return null;
1707
1678
  const isSteer = item.deliveryIntent === "steer" || item.status === "running_next";
1708
- const succeeded = input.status === "completed";
1709
- const nextStatus = succeeded
1710
- ? (isSteer ? "delivered" : "completed")
1711
- : "failed_actionable";
1712
- const nextDisposition = succeeded
1713
- ? (isSteer ? "delivered" : null)
1714
- : "failed_actionable";
1679
+ const cancelled = Boolean(item.cancelledAt);
1680
+ const succeeded = !cancelled && input.status === "completed";
1681
+ const nextStatus = cancelled
1682
+ ? "cancelled"
1683
+ : succeeded
1684
+ ? (isSteer ? "delivered" : "completed")
1685
+ : "failed_actionable";
1686
+ const nextDisposition = cancelled
1687
+ ? "cancelled"
1688
+ : succeeded
1689
+ ? (isSteer ? "delivered" : null)
1690
+ : "failed_actionable";
1691
+ const terminalReason = cancelled ? "operator_cancelled" : (input.reason ?? input.status);
1715
1692
  const [updated] = await tx
1716
1693
  .update(chatQueuedMessages)
1717
1694
  .set({
@@ -1720,25 +1697,27 @@ export function chatService(db) {
1720
1697
  deliveryLeaseToken: null,
1721
1698
  deliveryLeaseOwner: null,
1722
1699
  deliveryLeaseExpiresAt: null,
1723
- lastDeliveryReason: succeeded ? null : (input.reason ?? input.status),
1724
- reconciliationReason: succeeded ? null : (input.reason ?? input.status),
1700
+ lastDeliveryReason: succeeded ? null : terminalReason,
1701
+ reconciliationReason: succeeded ? null : terminalReason,
1725
1702
  version: sql `${chatQueuedMessages.version} + 1`,
1726
1703
  updatedAt: now,
1727
1704
  })
1728
1705
  .where(and(eq(chatQueuedMessages.id, item.id), eq(chatQueuedMessages.version, item.version)))
1729
1706
  .returning();
1707
+ if (!updated)
1708
+ return null;
1730
1709
  if (item.controlActionId) {
1731
1710
  await tx
1732
1711
  .update(chatControlActions)
1733
1712
  .set({
1734
1713
  localDisposition: nextDisposition ?? (succeeded ? "delivered" : "failed_actionable"),
1735
- lastError: succeeded ? null : (input.reason ?? input.status),
1714
+ lastError: succeeded ? null : terminalReason,
1736
1715
  resolvedAt: now,
1737
1716
  updatedAt: now,
1738
1717
  })
1739
1718
  .where(eq(chatControlActions.id, item.controlActionId));
1740
1719
  }
1741
- return updated ? hydrateQueuedMessage(updated) : null;
1720
+ return hydrateQueuedMessage(updated);
1742
1721
  });
1743
1722
  }
1744
1723
  async function releaseServerQueuedMessageClaim(input) {
@@ -1764,12 +1743,18 @@ export function chatService(db) {
1764
1743
  || generation.status === "tool_busy"
1765
1744
  || generation.status === "closing"));
1766
1745
  const isSteer = item.deliveryIntent === "steer" || item.status === "running_next";
1767
- const nextStatus = providerMayHaveStarted
1768
- ? (isSteer ? "acceptance_unknown" : "failed_actionable")
1769
- : (isSteer ? "continuation_pending" : "queued");
1770
- const nextDisposition = providerMayHaveStarted
1771
- ? (isSteer ? "acceptance_unknown" : "failed_actionable")
1772
- : (isSteer ? "continuation_pending" : null);
1746
+ const cancelled = Boolean(item.cancelledAt);
1747
+ const nextStatus = cancelled
1748
+ ? "cancelled"
1749
+ : providerMayHaveStarted
1750
+ ? (isSteer ? "acceptance_unknown" : "failed_actionable")
1751
+ : (isSteer ? "continuation_pending" : "queued");
1752
+ const nextDisposition = cancelled
1753
+ ? "cancelled"
1754
+ : providerMayHaveStarted
1755
+ ? (isSteer ? "acceptance_unknown" : "failed_actionable")
1756
+ : (isSteer ? "continuation_pending" : null);
1757
+ const releaseReason = cancelled ? "operator_cancelled" : input.reason;
1773
1758
  const [updated] = await tx
1774
1759
  .update(chatQueuedMessages)
1775
1760
  .set({
@@ -1779,25 +1764,27 @@ export function chatService(db) {
1779
1764
  deliveryLeaseToken: null,
1780
1765
  deliveryLeaseOwner: null,
1781
1766
  deliveryLeaseExpiresAt: null,
1782
- lastDeliveryReason: input.reason,
1783
- reconciliationReason: input.reason,
1767
+ lastDeliveryReason: releaseReason,
1768
+ reconciliationReason: releaseReason,
1784
1769
  version: sql `${chatQueuedMessages.version} + 1`,
1785
1770
  updatedAt: now,
1786
1771
  })
1787
1772
  .where(and(eq(chatQueuedMessages.id, item.id), eq(chatQueuedMessages.version, item.version)))
1788
1773
  .returning();
1774
+ if (!updated)
1775
+ return null;
1789
1776
  if (generation) {
1790
1777
  await tx
1791
1778
  .update(chatGenerations)
1792
1779
  .set({
1793
1780
  status: "aborted",
1794
- terminalReason: input.reason,
1781
+ terminalReason: releaseReason,
1795
1782
  controlState: providerMayHaveStarted ? "control_lost" : "terminal",
1796
1783
  runtimeTerminalAt: now,
1797
1784
  completedAt: now,
1798
1785
  updatedAt: now,
1799
1786
  })
1800
- .where(eq(chatGenerations.id, generation.id));
1787
+ .where(and(eq(chatGenerations.id, generation.id), inArray(chatGenerations.status, ACTIVE_CHAT_GENERATION_STATUSES)));
1801
1788
  }
1802
1789
  if (item.controlActionId) {
1803
1790
  await tx
@@ -1805,13 +1792,13 @@ export function chatService(db) {
1805
1792
  .set({
1806
1793
  localDisposition: nextDisposition ?? "pending",
1807
1794
  providerDisposition: providerMayHaveStarted ? "unverified" : "not_sent",
1808
- lastError: input.reason,
1795
+ lastError: releaseReason,
1809
1796
  resolvedAt: providerMayHaveStarted ? now : null,
1810
1797
  updatedAt: now,
1811
1798
  })
1812
1799
  .where(eq(chatControlActions.id, item.controlActionId));
1813
1800
  }
1814
- return updated ? hydrateQueuedMessage(updated) : null;
1801
+ return hydrateQueuedMessage(updated);
1815
1802
  });
1816
1803
  }
1817
1804
  async function recoverExpiredServerQueueClaims(now = new Date()) {
@@ -1852,7 +1839,7 @@ export function chatService(db) {
1852
1839
  const [candidate] = await tx
1853
1840
  .select()
1854
1841
  .from(chatQueuedMessages)
1855
- .where(and(eq(chatQueuedMessages.conversationId, conversationId), eq(chatQueuedMessages.status, "queued")))
1842
+ .where(and(eq(chatQueuedMessages.conversationId, conversationId), eq(chatQueuedMessages.status, "queued"), isNull(chatQueuedMessages.cancelledAt)))
1856
1843
  .orderBy(asc(chatQueuedMessages.position), asc(chatQueuedMessages.createdAt))
1857
1844
  .limit(1);
1858
1845
  if (!candidate)
@@ -1868,13 +1855,26 @@ export function chatService(db) {
1868
1855
  version: sql `${chatQueuedMessages.version} + 1`,
1869
1856
  updatedAt: now,
1870
1857
  })
1871
- .where(and(eq(chatQueuedMessages.id, candidate.id), eq(chatQueuedMessages.conversationId, conversationId), eq(chatQueuedMessages.status, "queued"), eq(chatQueuedMessages.version, candidate.version)))
1858
+ .where(and(eq(chatQueuedMessages.id, candidate.id), eq(chatQueuedMessages.conversationId, conversationId), eq(chatQueuedMessages.status, "queued"), eq(chatQueuedMessages.version, candidate.version), isNull(chatQueuedMessages.cancelledAt)))
1872
1859
  .returning();
1873
1860
  return row ? hydrateQueuedMessage(row) : null;
1874
1861
  });
1875
1862
  }
1876
1863
  async function releaseQueuedMessageClaim(input) {
1877
1864
  const now = new Date();
1865
+ const [cancelledRow] = await db
1866
+ .update(chatQueuedMessages)
1867
+ .set({
1868
+ status: "cancelled",
1869
+ deliveryDisposition: "cancelled",
1870
+ lastDeliveryReason: "operator_cancelled",
1871
+ version: sql `${chatQueuedMessages.version} + 1`,
1872
+ updatedAt: now,
1873
+ })
1874
+ .where(and(eq(chatQueuedMessages.conversationId, input.conversationId), eq(chatQueuedMessages.id, input.itemId), eq(chatQueuedMessages.status, "dequeue_claimed"), isNotNull(chatQueuedMessages.cancelledAt), isNull(chatQueuedMessages.deliveryLeaseToken), isNull(chatQueuedMessages.continuationGenerationId)))
1875
+ .returning();
1876
+ if (cancelledRow)
1877
+ return hydrateQueuedMessage(cancelledRow);
1878
1878
  const [row] = await db
1879
1879
  .update(chatQueuedMessages)
1880
1880
  .set({
@@ -1883,27 +1883,38 @@ export function chatService(db) {
1883
1883
  version: sql `${chatQueuedMessages.version} + 1`,
1884
1884
  updatedAt: now,
1885
1885
  })
1886
- .where(and(eq(chatQueuedMessages.conversationId, input.conversationId), eq(chatQueuedMessages.id, input.itemId), eq(chatQueuedMessages.status, "dequeue_claimed")))
1886
+ .where(and(eq(chatQueuedMessages.conversationId, input.conversationId), eq(chatQueuedMessages.id, input.itemId), eq(chatQueuedMessages.status, "dequeue_claimed"), isNull(chatQueuedMessages.cancelledAt), isNull(chatQueuedMessages.deliveryLeaseToken), isNull(chatQueuedMessages.continuationGenerationId)))
1887
1887
  .returning();
1888
1888
  return row ? hydrateQueuedMessage(row) : null;
1889
1889
  }
1890
1890
  async function reclaimStaleQueuedMessageClaims(conversationId) {
1891
1891
  const cutoff = new Date(Date.now() - QUEUED_MESSAGE_CLAIM_LEASE_MS);
1892
+ const now = new Date();
1893
+ await db
1894
+ .update(chatQueuedMessages)
1895
+ .set({
1896
+ status: "cancelled",
1897
+ deliveryDisposition: "cancelled",
1898
+ lastDeliveryReason: "operator_cancelled",
1899
+ version: sql `${chatQueuedMessages.version} + 1`,
1900
+ updatedAt: now,
1901
+ })
1902
+ .where(and(eq(chatQueuedMessages.conversationId, conversationId), eq(chatQueuedMessages.status, "dequeue_claimed"), isNotNull(chatQueuedMessages.cancelledAt), isNull(chatQueuedMessages.deliveryLeaseToken), isNull(chatQueuedMessages.continuationGenerationId), lt(chatQueuedMessages.updatedAt, cutoff)));
1892
1903
  await db
1893
1904
  .update(chatQueuedMessages)
1894
1905
  .set({
1895
1906
  status: "queued",
1896
1907
  lastDeliveryReason: "claim_expired",
1897
1908
  version: sql `${chatQueuedMessages.version} + 1`,
1898
- updatedAt: new Date(),
1909
+ updatedAt: now,
1899
1910
  })
1900
- .where(and(eq(chatQueuedMessages.conversationId, conversationId), eq(chatQueuedMessages.status, "dequeue_claimed"), lt(chatQueuedMessages.updatedAt, cutoff)));
1911
+ .where(and(eq(chatQueuedMessages.conversationId, conversationId), eq(chatQueuedMessages.status, "dequeue_claimed"), isNull(chatQueuedMessages.cancelledAt), isNull(chatQueuedMessages.deliveryLeaseToken), isNull(chatQueuedMessages.continuationGenerationId), lt(chatQueuedMessages.updatedAt, cutoff)));
1901
1912
  }
1902
1913
  async function assertQueuedMessageClaimedForDelivery(input) {
1903
1914
  const row = await db
1904
1915
  .select()
1905
1916
  .from(chatQueuedMessages)
1906
- .where(and(eq(chatQueuedMessages.conversationId, input.conversationId), eq(chatQueuedMessages.id, input.itemId)))
1917
+ .where(and(eq(chatQueuedMessages.conversationId, input.conversationId), eq(chatQueuedMessages.id, input.itemId), isNull(chatQueuedMessages.cancelledAt)))
1907
1918
  .limit(1)
1908
1919
  .then((rows) => rows[0] ?? null);
1909
1920
  if (!row || row.status !== "dequeue_claimed") {
@@ -1949,19 +1960,120 @@ export function chatService(db) {
1949
1960
  }
1950
1961
  async function hydrateMessages(rows, options = {}) {
1951
1962
  const includeTranscript = options.includeTranscript !== false;
1952
- const [attachmentsByMessageId, approvalsById] = await Promise.all([
1963
+ const assistantMessageIds = rows
1964
+ .filter((row) => row.role === "assistant")
1965
+ .map((row) => row.id);
1966
+ const nativeSteerMessageIds = rows
1967
+ .filter((row) => row.role === "user" && row.structuredPayload?.source === "steer")
1968
+ .map((row) => row.id);
1969
+ const [attachmentsByMessageId, approvalsById, generationMessageRows, linkedSteerQueueRows] = await Promise.all([
1953
1970
  listAttachmentsForMessageIds(rows.map((row) => row.id)),
1954
1971
  listApprovalsForMessages(rows),
1972
+ assistantMessageIds.length > 0
1973
+ ? db
1974
+ .select({
1975
+ assistantMessageId: chatGenerationEvents.assistantMessageId,
1976
+ generationId: chatGenerationEvents.generationId,
1977
+ })
1978
+ .from(chatGenerationEvents)
1979
+ .where(inArray(chatGenerationEvents.assistantMessageId, assistantMessageIds))
1980
+ .orderBy(desc(chatGenerationEvents.generationSeq))
1981
+ : Promise.resolve([]),
1982
+ nativeSteerMessageIds.length > 0
1983
+ ? db
1984
+ .select({
1985
+ sourceMessageId: chatQueuedMessages.sourceMessageId,
1986
+ continuationMessageId: chatQueuedMessages.continuationMessageId,
1987
+ deliveryDisposition: chatQueuedMessages.deliveryDisposition,
1988
+ continuationGenerationId: chatQueuedMessages.continuationGenerationId,
1989
+ dequeuedAt: chatQueuedMessages.dequeuedAt,
1990
+ })
1991
+ .from(chatQueuedMessages)
1992
+ .where(or(inArray(chatQueuedMessages.sourceMessageId, nativeSteerMessageIds), inArray(chatQueuedMessages.continuationMessageId, nativeSteerMessageIds)))
1993
+ : Promise.resolve([]),
1955
1994
  ]);
1995
+ const generationIdByAssistantMessageId = new Map();
1996
+ for (const generationMessageRow of generationMessageRows) {
1997
+ if (!generationMessageRow.assistantMessageId)
1998
+ continue;
1999
+ if (generationIdByAssistantMessageId.has(generationMessageRow.assistantMessageId))
2000
+ continue;
2001
+ generationIdByAssistantMessageId.set(generationMessageRow.assistantMessageId, generationMessageRow.generationId);
2002
+ }
2003
+ const steerDispositionByMessageId = new Map();
2004
+ for (const queueRow of linkedSteerQueueRows) {
2005
+ const messageIds = new Set([
2006
+ queueRow.sourceMessageId,
2007
+ queueRow.continuationMessageId,
2008
+ ].filter((messageId) => Boolean(messageId)));
2009
+ // `dequeuedAt` is durable provenance that this feedback left the native turn.
2010
+ // A failed continuation claim clears continuationGenerationId and may become
2011
+ // acceptance_unknown, but it must never be projected back into the old transcript.
2012
+ const projectedDisposition = queueRow.continuationGenerationId || queueRow.dequeuedAt
2013
+ ? "continuation_pending"
2014
+ : queueRow.deliveryDisposition === "delivered"
2015
+ ? "accepted_current"
2016
+ : queueRow.deliveryDisposition;
2017
+ if (!projectedDisposition)
2018
+ continue;
2019
+ for (const messageId of messageIds) {
2020
+ steerDispositionByMessageId.set(messageId, projectedDisposition);
2021
+ }
2022
+ }
2023
+ const effectiveStructuredPayload = (row) => {
2024
+ const payload = row.structuredPayload;
2025
+ if (!payload || payload.source !== "steer")
2026
+ return payload;
2027
+ const projectedDisposition = steerDispositionByMessageId.get(row.id);
2028
+ return projectedDisposition
2029
+ ? { ...payload, deliveryDisposition: projectedDisposition }
2030
+ : payload;
2031
+ };
2032
+ const nativeSteerTargetGenerationIds = new Set();
2033
+ for (const row of rows) {
2034
+ const payload = effectiveStructuredPayload(row);
2035
+ const targetGenerationId = payload?.source === "steer"
2036
+ && ["pending", "acceptance_unknown", "accepted_current"].includes(typeof payload.deliveryDisposition === "string" ? payload.deliveryDisposition : "")
2037
+ && typeof payload.targetGenerationId === "string"
2038
+ ? payload.targetGenerationId
2039
+ : null;
2040
+ if (targetGenerationId)
2041
+ nativeSteerTargetGenerationIds.add(targetGenerationId);
2042
+ }
2043
+ const nativeSteerAssistantMessageIds = includeTranscript
2044
+ ? []
2045
+ : assistantMessageIds.filter((messageId) => {
2046
+ const generationId = generationIdByAssistantMessageId.get(messageId);
2047
+ return Boolean(generationId && nativeSteerTargetGenerationIds.has(generationId));
2048
+ });
2049
+ const nativeSteerTranscriptPayloadByMessageId = new Map();
2050
+ if (nativeSteerAssistantMessageIds.length > 0) {
2051
+ const transcriptPayloadRows = await db
2052
+ .select({
2053
+ id: chatMessages.id,
2054
+ structuredPayload: chatMessages.structuredPayload,
2055
+ })
2056
+ .from(chatMessages)
2057
+ .where(inArray(chatMessages.id, nativeSteerAssistantMessageIds));
2058
+ for (const transcriptPayloadRow of transcriptPayloadRows) {
2059
+ nativeSteerTranscriptPayloadByMessageId.set(transcriptPayloadRow.id, transcriptPayloadRow.structuredPayload);
2060
+ }
2061
+ }
1956
2062
  return rows.map((row) => {
1957
- const transcript = includeTranscript ? chatTranscriptFromPayload(row.structuredPayload) : [];
1958
- const transcriptSummary = includeTranscript
2063
+ const generationId = generationIdByAssistantMessageId.get(row.id) ?? null;
2064
+ const includeRowTranscript = includeTranscript
2065
+ || Boolean(generationId && nativeSteerTargetGenerationIds.has(generationId));
2066
+ const transcriptPayload = nativeSteerTranscriptPayloadByMessageId.get(row.id) ?? row.structuredPayload;
2067
+ const transcript = includeRowTranscript ? chatTranscriptFromPayload(transcriptPayload) : [];
2068
+ const transcriptSummary = includeRowTranscript
1959
2069
  ? chatTranscriptSummaryFromEntries(transcript)
1960
2070
  : row.transcriptSummary ?? null;
2071
+ const structuredPayload = effectiveStructuredPayload(row);
1961
2072
  return {
1962
2073
  ...row,
1963
- structuredPayload: stripChatMetadataFromPayload(row.structuredPayload),
1964
- transcript: includeTranscript ? transcript : undefined,
2074
+ generationId,
2075
+ structuredPayload: stripChatMetadataFromPayload(structuredPayload),
2076
+ transcript: includeRowTranscript ? transcript : undefined,
1965
2077
  transcriptSummary,
1966
2078
  approval: row.approvalId ? (approvalsById.get(row.approvalId) ?? null) : null,
1967
2079
  attachments: attachmentsByMessageId.get(row.id) ?? [],
@@ -2113,107 +2225,16 @@ export function chatService(db) {
2113
2225
  return conversation ?? null;
2114
2226
  }
2115
2227
  async function create(orgId, data) {
2116
- const created = await db.transaction(async (tx) => {
2117
- const [conversation] = await tx
2118
- .insert(chatConversations)
2119
- .values({
2120
- orgId,
2121
- title: data.title?.trim() || "New chat",
2122
- summary: data.summary ?? null,
2123
- preferredAgentId: data.preferredAgentId ?? null,
2124
- issueCreationMode: data.issueCreationMode,
2125
- planMode: data.planMode,
2126
- createdByUserId: data.createdByUserId,
2127
- })
2128
- .returning();
2129
- if (!conversation)
2130
- throw new Error("Failed to create chat conversation");
2131
- const contextLinks = data.contextLinks ?? [];
2132
- if (contextLinks.length > 0) {
2133
- await tx
2134
- .insert(chatContextLinks)
2135
- .values(contextLinks.map((link) => ({
2136
- orgId,
2137
- conversationId: conversation.id,
2138
- entityType: link.entityType,
2139
- entityId: link.entityId,
2140
- metadata: link.metadata ?? null,
2141
- })))
2142
- .onConflictDoNothing();
2143
- }
2144
- return conversation;
2145
- });
2228
+ const created = await createChatConversation(db, orgId, data);
2146
2229
  return getById(created.id);
2147
2230
  }
2231
+ async function createWithInitialMessage(orgId, data, executor) {
2232
+ return createChatWithInitialMessage(db, orgId, data, executor);
2233
+ }
2148
2234
  function forkSystemEventBody(sourceConversation, sourceMessageId) {
2149
2235
  const messageSuffix = sourceMessageId ? " at message" : "";
2150
2236
  return `Forked from [${sourceConversation.title}](chat://${sourceConversation.id})${messageSuffix}.`;
2151
2237
  }
2152
- async function findForkFamilyGroup(client, orgId, userId, rootConversationId) {
2153
- const rootThreadKey = `chat:${rootConversationId}`;
2154
- return client
2155
- .select({ id: messengerCustomGroups.id })
2156
- .from(messengerCustomGroups)
2157
- .innerJoin(messengerCustomGroupEntries, eq(messengerCustomGroupEntries.groupId, messengerCustomGroups.id))
2158
- .where(and(eq(messengerCustomGroups.orgId, orgId), eq(messengerCustomGroups.userId, userId), eq(messengerCustomGroupEntries.orgId, orgId), eq(messengerCustomGroupEntries.userId, userId), eq(messengerCustomGroupEntries.threadKey, rootThreadKey)))
2159
- .orderBy(asc(messengerCustomGroups.sortOrder), asc(messengerCustomGroups.createdAt))
2160
- .limit(1)
2161
- .then((rows) => rows[0] ?? null);
2162
- }
2163
- async function createForkFamilyGroup(client, orgId, userId, name) {
2164
- const [lastGroup] = await client
2165
- .select({ sortOrder: messengerCustomGroups.sortOrder })
2166
- .from(messengerCustomGroups)
2167
- .where(and(eq(messengerCustomGroups.orgId, orgId), eq(messengerCustomGroups.userId, userId)))
2168
- .orderBy(desc(messengerCustomGroups.sortOrder))
2169
- .limit(1);
2170
- const now = new Date();
2171
- const [group] = await client
2172
- .insert(messengerCustomGroups)
2173
- .values({
2174
- orgId,
2175
- userId,
2176
- name: name.trim() || "Forked conversation",
2177
- icon: MESSENGER_FORK_GROUP_DEFAULT_ICON,
2178
- sortOrder: (lastGroup?.sortOrder ?? -1) + 1,
2179
- updatedAt: now,
2180
- })
2181
- .returning();
2182
- if (!group)
2183
- throw new Error("Failed to create Messenger fork group");
2184
- return group;
2185
- }
2186
- async function assignForkThreadToGroup(client, orgId, userId, groupId, threadKey) {
2187
- const [lastEntry] = await client
2188
- .select({ sortOrder: messengerCustomGroupEntries.sortOrder })
2189
- .from(messengerCustomGroupEntries)
2190
- .where(and(eq(messengerCustomGroupEntries.orgId, orgId), eq(messengerCustomGroupEntries.userId, userId), eq(messengerCustomGroupEntries.groupId, groupId)))
2191
- .orderBy(desc(messengerCustomGroupEntries.sortOrder))
2192
- .limit(1);
2193
- const now = new Date();
2194
- await client
2195
- .insert(messengerCustomGroupEntries)
2196
- .values({
2197
- orgId,
2198
- userId,
2199
- groupId,
2200
- threadKey,
2201
- sortOrder: (lastEntry?.sortOrder ?? -1) + 1,
2202
- updatedAt: now,
2203
- })
2204
- .onConflictDoNothing();
2205
- }
2206
- async function ensureForkFamilyGroup(client, orgId, userId, rootConversationId, sourceConversationId, childConversationId, groupName) {
2207
- const existing = await findForkFamilyGroup(client, orgId, userId, rootConversationId);
2208
- const group = existing ?? await createForkFamilyGroup(client, orgId, userId, groupName);
2209
- for (const threadKey of [
2210
- `chat:${rootConversationId}`,
2211
- `chat:${sourceConversationId}`,
2212
- `chat:${childConversationId}`,
2213
- ]) {
2214
- await assignForkThreadToGroup(client, orgId, userId, group.id, threadKey);
2215
- }
2216
- }
2217
2238
  async function forkConversation(input) {
2218
2239
  const created = await db.transaction(async (tx) => {
2219
2240
  const initialSource = await tx
@@ -2326,79 +2347,13 @@ export function chatService(db) {
2326
2347
  const forkMessages = input.sourceMessageId
2327
2348
  ? messagesToCopy.slice(0, messagesToCopy.findIndex((message) => message.id === input.sourceMessageId) + 1)
2328
2349
  : messagesToCopy;
2329
- if (forkMessages.length > 0) {
2330
- for (const message of forkMessages) {
2331
- const copiedMessageId = randomUUID();
2332
- const visualMappings = chatInlineVisualMappingsFromStructuredPayload(message.structuredPayload);
2333
- const readyAttachmentIds = visualMappings
2334
- .filter((mapping) => mapping.status === "ready")
2335
- .map((mapping) => mapping.attachmentId);
2336
- const copiedAttachmentIdBySourceId = new Map();
2337
- const pendingVisualAttachments = [];
2338
- if (readyAttachmentIds.length > 0) {
2339
- const sourceVisualAttachments = await tx
2340
- .select({
2341
- id: chatAttachments.id,
2342
- assetId: chatAttachments.assetId,
2343
- contentType: assets.contentType,
2344
- createdByAgentId: assets.createdByAgentId,
2345
- createdByUserId: assets.createdByUserId,
2346
- })
2347
- .from(chatAttachments)
2348
- .innerJoin(assets, eq(chatAttachments.assetId, assets.id))
2349
- .where(and(eq(chatAttachments.conversationId, source.id), eq(chatAttachments.messageId, message.id), inArray(chatAttachments.id, readyAttachmentIds)));
2350
- const safeVisualAttachments = sourceVisualAttachments.filter((attachment) => attachment.contentType === "text/html"
2351
- && Boolean(attachment.createdByAgentId)
2352
- && !attachment.createdByUserId);
2353
- if (safeVisualAttachments.length > 0) {
2354
- pendingVisualAttachments.push(...safeVisualAttachments.map((attachment) => {
2355
- const copiedAttachmentId = randomUUID();
2356
- copiedAttachmentIdBySourceId.set(attachment.id, copiedAttachmentId);
2357
- return {
2358
- id: copiedAttachmentId,
2359
- orgId: input.orgId,
2360
- conversationId: child.id,
2361
- messageId: copiedMessageId,
2362
- assetId: attachment.assetId,
2363
- };
2364
- }));
2365
- }
2366
- }
2367
- const copiedVisualMappings = visualMappings.map((mapping) => {
2368
- if (mapping.status === "unavailable")
2369
- return mapping;
2370
- const copiedAttachmentId = copiedAttachmentIdBySourceId.get(mapping.attachmentId);
2371
- return copiedAttachmentId
2372
- ? { ...mapping, attachmentId: copiedAttachmentId }
2373
- : {
2374
- directiveIndex: mapping.directiveIndex,
2375
- file: mapping.file,
2376
- status: "unavailable",
2377
- reason: "fork_source_missing",
2378
- };
2379
- });
2380
- await tx.insert(chatMessages).values({
2381
- id: copiedMessageId,
2382
- orgId: input.orgId,
2383
- conversationId: child.id,
2384
- role: message.role,
2385
- kind: message.kind,
2386
- status: message.status === "streaming" ? "interrupted" : message.status,
2387
- body: message.body,
2388
- structuredPayload: copiedVisualMappings.length > 0 ? { inlineVisuals: copiedVisualMappings } : null,
2389
- approvalId: null,
2390
- runId: null,
2391
- replyingAgentId: message.replyingAgentId,
2392
- chatTurnId: null,
2393
- turnVariant: 0,
2394
- createdAt: message.createdAt,
2395
- updatedAt: message.updatedAt,
2396
- });
2397
- if (pendingVisualAttachments.length > 0) {
2398
- await tx.insert(chatAttachments).values(pendingVisualAttachments);
2399
- }
2400
- }
2401
- }
2350
+ await copyForkInlineVisualMessages({
2351
+ tx,
2352
+ messages: forkMessages,
2353
+ sourceConversationId: source.id,
2354
+ targetConversationId: child.id,
2355
+ orgId: input.orgId,
2356
+ });
2402
2357
  const [systemEvent] = await tx
2403
2358
  .insert(chatMessages)
2404
2359
  .values({
@@ -2427,7 +2382,14 @@ export function chatService(db) {
2427
2382
  updatedAt: now,
2428
2383
  })
2429
2384
  .where(eq(chatConversations.id, child.id));
2430
- await ensureForkFamilyGroup(tx, input.orgId, input.userId, rootConversationId, source.id, child.id, source.title);
2385
+ await ensureChatFamilyGroup(tx, {
2386
+ orgId: input.orgId,
2387
+ userId: input.userId,
2388
+ rootConversationId,
2389
+ sourceConversationId: source.id,
2390
+ childConversationId: child.id,
2391
+ groupName: source.title,
2392
+ });
2431
2393
  return child;
2432
2394
  });
2433
2395
  return getById(created.id, input.userId);
@@ -2626,13 +2588,21 @@ export function chatService(db) {
2626
2588
  end
2627
2589
  `;
2628
2590
  }
2591
+ async function listRecentUserMessages(conversationId, limit) {
2592
+ return listRecentUserChatMessages(db, conversationId, limit);
2593
+ }
2629
2594
  async function listMessages(conversationId, options = {}) {
2630
2595
  const includeTranscript = options.includeTranscript !== false;
2596
+ const conversationOrgIds = db
2597
+ .select({ orgId: chatConversations.orgId })
2598
+ .from(chatConversations)
2599
+ .where(eq(chatConversations.id, conversationId));
2600
+ const messageConditions = and(eq(chatMessages.conversationId, conversationId), inArray(chatMessages.orgId, conversationOrgIds));
2631
2601
  const rows = includeTranscript
2632
2602
  ? await db
2633
2603
  .select()
2634
2604
  .from(chatMessages)
2635
- .where(eq(chatMessages.conversationId, conversationId))
2605
+ .where(messageConditions)
2636
2606
  .orderBy(chatMessages.createdAt, chatMessages.id)
2637
2607
  : await db
2638
2608
  .select({
@@ -2655,7 +2625,7 @@ export function chatService(db) {
2655
2625
  transcriptSummary: transcriptSummarySql(),
2656
2626
  })
2657
2627
  .from(chatMessages)
2658
- .where(eq(chatMessages.conversationId, conversationId))
2628
+ .where(messageConditions)
2659
2629
  .orderBy(chatMessages.createdAt, chatMessages.id);
2660
2630
  return hydrateMessages(rows, { includeTranscript });
2661
2631
  }
@@ -2868,6 +2838,15 @@ export function chatService(db) {
2868
2838
  const [hydrated] = await hydrateMessages([updated]);
2869
2839
  return hydrated ?? null;
2870
2840
  }
2841
+ async function updateMessageInternalInlineVisuals(conversationId, messageId, input) {
2842
+ return updateTrustedInlineVisualMappings({
2843
+ db,
2844
+ hydrateMessages,
2845
+ conversationId,
2846
+ messageId,
2847
+ ...input,
2848
+ });
2849
+ }
2871
2850
  async function markInterruptedStreamingMessages(conversationId) {
2872
2851
  const rows = await db
2873
2852
  .select()
@@ -3000,6 +2979,38 @@ export function chatService(db) {
3000
2979
  };
3001
2980
  });
3002
2981
  }
2982
+ async function removeAttachment(attachmentId) {
2983
+ return db.transaction(async (tx) => {
2984
+ const existing = await tx
2985
+ .select({
2986
+ id: chatAttachments.id,
2987
+ orgId: chatAttachments.orgId,
2988
+ assetId: chatAttachments.assetId,
2989
+ objectKey: assets.objectKey,
2990
+ })
2991
+ .from(chatAttachments)
2992
+ .innerJoin(assets, eq(chatAttachments.assetId, assets.id))
2993
+ .where(eq(chatAttachments.id, attachmentId))
2994
+ .then((rows) => rows[0] ?? null);
2995
+ if (!existing)
2996
+ return null;
2997
+ await tx.delete(chatAttachments).where(eq(chatAttachments.id, attachmentId));
2998
+ const hasRemainingAttachment = await tx
2999
+ .select({ id: chatAttachments.id })
3000
+ .from(chatAttachments)
3001
+ .where(eq(chatAttachments.assetId, existing.assetId))
3002
+ .limit(1)
3003
+ .then((rows) => rows.length > 0);
3004
+ if (!hasRemainingAttachment) {
3005
+ await tx.delete(assets).where(eq(assets.id, existing.assetId));
3006
+ }
3007
+ return {
3008
+ orgId: existing.orgId,
3009
+ objectKey: existing.objectKey,
3010
+ assetDeleted: !hasRemainingAttachment,
3011
+ };
3012
+ });
3013
+ }
3003
3014
  function assertIssueProposalOwnerDecision(issueProposal) {
3004
3015
  const hasAssignee = Boolean(safeTrim(issueProposal.assigneeAgentId) || safeTrim(issueProposal.assigneeUserId));
3005
3016
  const hasUnassignedReason = Boolean(safeTrim(issueProposal.assigneeUnassignedReason));
@@ -3408,9 +3419,11 @@ export function chatService(db) {
3408
3419
  listSummariesByIds,
3409
3420
  getById,
3410
3421
  create,
3422
+ createWithInitialMessage,
3411
3423
  update,
3412
3424
  updateDefaultTitle,
3413
3425
  replaceSystemGeneratedTitle,
3426
+ listRecentUserMessages,
3414
3427
  listAttachmentsForConversation,
3415
3428
  assetHasAttachments,
3416
3429
  remove,
@@ -3453,11 +3466,13 @@ export function chatService(db) {
3453
3466
  getMessageTranscript,
3454
3467
  addMessage,
3455
3468
  updateMessage,
3469
+ updateMessageInternalInlineVisuals,
3456
3470
  markInterruptedStreamingMessages,
3457
3471
  addUserChatMessage,
3458
3472
  addContextLink,
3459
3473
  setProjectContextLink,
3460
3474
  createAttachment,
3475
+ removeAttachment,
3461
3476
  convertToIssue,
3462
3477
  getMessage,
3463
3478
  applyApprovedApproval,