@rudderhq/server 0.3.6-canary.8 → 0.4.0
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.
- package/dist/bootstrap/register-api-routes.d.ts.map +1 -1
- package/dist/bootstrap/register-api-routes.js +2 -0
- package/dist/bootstrap/register-api-routes.js.map +1 -1
- package/dist/bundled-plugins/plugin-linear/dist/worker.js +35 -2
- package/dist/bundled-plugins/plugin-linear/dist/worker.js.map +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +103 -26
- package/dist/index.js.map +1 -1
- package/dist/routes/activity.d.ts +1 -1
- package/dist/routes/activity.d.ts.map +1 -1
- package/dist/routes/activity.js +21 -5
- package/dist/routes/activity.js.map +1 -1
- package/dist/routes/agents.d.ts.map +1 -1
- package/dist/routes/agents.js +254 -4
- package/dist/routes/agents.js.map +1 -1
- package/dist/routes/agents.management-routes.d.ts.map +1 -1
- package/dist/routes/agents.management-routes.js +132 -40
- package/dist/routes/agents.management-routes.js.map +1 -1
- package/dist/routes/automations.d.ts +8 -0
- package/dist/routes/automations.d.ts.map +1 -1
- package/dist/routes/automations.js.map +1 -1
- package/dist/routes/chats.d.ts.map +1 -1
- package/dist/routes/chats.js +228 -115
- package/dist/routes/chats.js.map +1 -1
- package/dist/routes/chats.stream-routes.d.ts.map +1 -1
- package/dist/routes/chats.stream-routes.js +94 -5
- package/dist/routes/chats.stream-routes.js.map +1 -1
- package/dist/routes/issues.comments-attachments.d.ts.map +1 -1
- package/dist/routes/issues.comments-attachments.js +72 -83
- package/dist/routes/issues.comments-attachments.js.map +1 -1
- package/dist/routes/issues.d.ts +8 -0
- package/dist/routes/issues.d.ts.map +1 -1
- package/dist/routes/issues.js +0 -4
- package/dist/routes/issues.js.map +1 -1
- package/dist/routes/issues.mutations.d.ts.map +1 -1
- package/dist/routes/issues.mutations.js +2 -26
- package/dist/routes/issues.mutations.js.map +1 -1
- package/dist/routes/messenger.d.ts.map +1 -1
- package/dist/routes/messenger.js +33 -1
- package/dist/routes/messenger.js.map +1 -1
- package/dist/routes/orgs.d.ts.map +1 -1
- package/dist/routes/orgs.js +16 -0
- package/dist/routes/orgs.js.map +1 -1
- package/dist/routes/plugin-ui-static.d.ts +4 -4
- package/dist/routes/plugin-ui-static.js +5 -5
- package/dist/routes/plugin-ui-static.js.map +1 -1
- package/dist/routes/plugins.d.ts +4 -4
- package/dist/routes/plugins.js +10 -10
- package/dist/routes/plugins.operations-routes.d.ts +1 -1
- package/dist/routes/plugins.operations-routes.js +2 -2
- package/dist/routes/plugins.operations-routes.js.map +1 -1
- package/dist/routes/run-intelligence.js +5 -5
- package/dist/routes/run-intelligence.js.map +1 -1
- package/dist/routes/website-metadata.d.ts +8 -0
- package/dist/routes/website-metadata.d.ts.map +1 -0
- package/dist/routes/website-metadata.js +67 -0
- package/dist/routes/website-metadata.js.map +1 -0
- package/dist/services/activity.d.ts.map +1 -1
- package/dist/services/activity.js +1 -1
- package/dist/services/activity.js.map +1 -1
- package/dist/services/agent-instructions.d.ts +1 -0
- package/dist/services/agent-instructions.d.ts.map +1 -1
- package/dist/services/agent-instructions.js +57 -6
- package/dist/services/agent-instructions.js.map +1 -1
- package/dist/services/agent-run-context.d.ts +3 -1
- package/dist/services/agent-run-context.d.ts.map +1 -1
- package/dist/services/agent-run-context.js +7 -0
- package/dist/services/agent-run-context.js.map +1 -1
- package/dist/services/agent-startup-context.d.ts +2 -1
- package/dist/services/agent-startup-context.d.ts.map +1 -1
- package/dist/services/agent-startup-context.js +6 -26
- package/dist/services/agent-startup-context.js.map +1 -1
- package/dist/services/agents.d.ts +9 -1
- package/dist/services/agents.d.ts.map +1 -1
- package/dist/services/agents.js.map +1 -1
- package/dist/services/approvals.d.ts +8 -0
- package/dist/services/approvals.d.ts.map +1 -1
- package/dist/services/approvals.js.map +1 -1
- package/dist/services/automation-chat-output.d.ts +1 -1
- package/dist/services/automations.d.ts +4 -4
- package/dist/services/automations.d.ts.map +1 -1
- package/dist/services/automations.js +12 -0
- package/dist/services/automations.js.map +1 -1
- package/dist/services/budgets.d.ts +8 -0
- package/dist/services/budgets.d.ts.map +1 -1
- package/dist/services/budgets.js.map +1 -1
- package/dist/services/calendar.d.ts +2 -2
- package/dist/services/calendar.js +3 -3
- package/dist/services/calendar.js.map +1 -1
- package/dist/services/chat-agent-runs.d.ts +2 -0
- package/dist/services/chat-agent-runs.d.ts.map +1 -1
- package/dist/services/chat-agent-runs.js +6 -0
- package/dist/services/chat-agent-runs.js.map +1 -1
- package/dist/services/chat-assistant.d.ts.map +1 -1
- package/dist/services/chat-assistant.helpers.d.ts +1 -0
- package/dist/services/chat-assistant.helpers.d.ts.map +1 -1
- package/dist/services/chat-assistant.helpers.js +7 -10
- package/dist/services/chat-assistant.helpers.js.map +1 -1
- package/dist/services/chat-assistant.js +23 -6
- package/dist/services/chat-assistant.js.map +1 -1
- package/dist/services/chat-generation-locks.d.ts +6 -1
- package/dist/services/chat-generation-locks.d.ts.map +1 -1
- package/dist/services/chat-generation-locks.js +20 -2
- package/dist/services/chat-generation-locks.js.map +1 -1
- package/dist/services/chat-title-generation.d.ts +36 -0
- package/dist/services/chat-title-generation.d.ts.map +1 -0
- package/dist/services/chat-title-generation.js +107 -0
- package/dist/services/chat-title-generation.js.map +1 -0
- package/dist/services/chats.d.ts +471 -25
- package/dist/services/chats.d.ts.map +1 -1
- package/dist/services/chats.helpers.d.ts +2 -2
- package/dist/services/chats.js +651 -35
- package/dist/services/chats.js.map +1 -1
- package/dist/services/costs.d.ts +1 -1
- package/dist/services/finance.d.ts +2 -2
- package/dist/services/finance.js +1 -1
- package/dist/services/finance.js.map +1 -1
- package/dist/services/goals.d.ts +8 -0
- package/dist/services/goals.d.ts.map +1 -1
- package/dist/services/goals.js.map +1 -1
- package/dist/services/heartbeat-run-reference.d.ts +1 -0
- package/dist/services/heartbeat-run-reference.d.ts.map +1 -1
- package/dist/services/heartbeat-run-reference.js +3 -2
- package/dist/services/heartbeat-run-reference.js.map +1 -1
- package/dist/services/integrations/agent-integrations.d.ts +19 -0
- package/dist/services/integrations/agent-integrations.d.ts.map +1 -1
- package/dist/services/integrations/agent-integrations.js +30 -0
- package/dist/services/integrations/agent-integrations.js.map +1 -1
- package/dist/services/integrations/feishu/app-registration.d.ts +74 -0
- package/dist/services/integrations/feishu/app-registration.d.ts.map +1 -0
- package/dist/services/integrations/feishu/app-registration.js +226 -0
- package/dist/services/integrations/feishu/app-registration.js.map +1 -0
- package/dist/services/integrations/feishu/inbound-dispatcher-db.d.ts +4 -0
- package/dist/services/integrations/feishu/inbound-dispatcher-db.d.ts.map +1 -1
- package/dist/services/integrations/feishu/inbound-dispatcher-db.js +35 -5
- package/dist/services/integrations/feishu/inbound-dispatcher-db.js.map +1 -1
- package/dist/services/integrations/feishu/inbound-dispatcher.d.ts +2 -0
- package/dist/services/integrations/feishu/inbound-dispatcher.d.ts.map +1 -1
- package/dist/services/integrations/feishu/inbound-dispatcher.js.map +1 -1
- package/dist/services/integrations/feishu/runtime-registry.d.ts +20 -0
- package/dist/services/integrations/feishu/runtime-registry.d.ts.map +1 -0
- package/dist/services/integrations/feishu/runtime-registry.js +41 -0
- package/dist/services/integrations/feishu/runtime-registry.js.map +1 -0
- package/dist/services/integrations/feishu/runtime.d.ts +21 -23
- package/dist/services/integrations/feishu/runtime.d.ts.map +1 -1
- package/dist/services/integrations/feishu/runtime.js +135 -45
- package/dist/services/integrations/feishu/runtime.js.map +1 -1
- package/dist/services/integrations/feishu/user-bindings.d.ts +22 -0
- package/dist/services/integrations/feishu/user-bindings.d.ts.map +1 -0
- package/dist/services/integrations/feishu/user-bindings.js +57 -0
- package/dist/services/integrations/feishu/user-bindings.js.map +1 -0
- package/dist/services/issue-approvals.d.ts +2 -2
- package/dist/services/issue-review-wakeup.js +1 -1
- package/dist/services/issue-review-wakeup.js.map +1 -1
- package/dist/services/issues.comments-attachments.d.ts +3 -3
- package/dist/services/issues.d.ts +14 -6
- package/dist/services/issues.d.ts.map +1 -1
- package/dist/services/issues.helpers.d.ts +9 -1
- package/dist/services/issues.helpers.d.ts.map +1 -1
- package/dist/services/issues.helpers.js +8 -0
- package/dist/services/issues.helpers.js.map +1 -1
- package/dist/services/issues.js +1 -1
- package/dist/services/issues.js.map +1 -1
- package/dist/services/knowledge-portability/organization-skills.catalog.d.ts +1 -1
- package/dist/services/library-entries.d.ts +8 -0
- package/dist/services/library-entries.d.ts.map +1 -1
- package/dist/services/library-entries.js +8 -0
- package/dist/services/library-entries.js.map +1 -1
- package/dist/services/messenger.d.ts +19 -4
- package/dist/services/messenger.d.ts.map +1 -1
- package/dist/services/messenger.js +136 -18
- package/dist/services/messenger.js.map +1 -1
- package/dist/services/plugin-capability-validator.d.ts +1 -1
- package/dist/services/plugin-capability-validator.js +2 -2
- package/dist/services/plugin-dev-watcher.js +1 -1
- package/dist/services/plugin-event-bus.d.ts +3 -3
- package/dist/services/plugin-event-bus.js +3 -3
- package/dist/services/plugin-job-coordinator.d.ts +1 -1
- package/dist/services/plugin-job-coordinator.js +1 -1
- package/dist/services/plugin-job-scheduler.d.ts +1 -1
- package/dist/services/plugin-job-scheduler.js +1 -1
- package/dist/services/plugin-job-store.d.ts +2 -2
- package/dist/services/plugin-job-store.js +2 -2
- package/dist/services/plugin-lifecycle.d.ts +4 -4
- package/dist/services/plugin-lifecycle.js +3 -3
- package/dist/services/plugin-loader.core.d.ts +4 -4
- package/dist/services/plugin-loader.core.js +2 -2
- package/dist/services/plugin-loader.core.js.map +1 -1
- package/dist/services/plugin-loader.d.ts +3 -3
- package/dist/services/plugin-loader.helpers.d.ts +26 -25
- package/dist/services/plugin-loader.helpers.d.ts.map +1 -1
- package/dist/services/plugin-loader.helpers.js +10 -9
- package/dist/services/plugin-loader.helpers.js.map +1 -1
- package/dist/services/plugin-loader.js +3 -3
- package/dist/services/plugin-loader.worker-paths.d.ts +3 -3
- package/dist/services/plugin-manifest-validator.d.ts +2 -2
- package/dist/services/plugin-registry.d.ts +9 -9
- package/dist/services/plugin-registry.js +1 -1
- package/dist/services/plugin-secrets-handler.d.ts +2 -2
- package/dist/services/plugin-secrets-handler.js +2 -2
- package/dist/services/plugin-state-store.d.ts +3 -3
- package/dist/services/plugin-state-store.js +3 -3
- package/dist/services/plugin-stream-bus.d.ts +1 -1
- package/dist/services/plugin-stream-bus.js +1 -1
- package/dist/services/plugin-tool-dispatcher.d.ts +2 -2
- package/dist/services/plugin-tool-dispatcher.js +2 -2
- package/dist/services/plugin-tool-registry.d.ts +2 -2
- package/dist/services/plugin-tool-registry.js +2 -2
- package/dist/services/plugin-worker-manager.d.ts +4 -4
- package/dist/services/plugin-worker-manager.d.ts.map +1 -1
- package/dist/services/plugin-worker-manager.js +8 -7
- package/dist/services/plugin-worker-manager.js.map +1 -1
- package/dist/services/run-intelligence.js +3 -3
- package/dist/services/run-intelligence.js.map +1 -1
- package/dist/services/runtime-kernel/heartbeat.core.d.ts +9 -1
- package/dist/services/runtime-kernel/heartbeat.core.d.ts.map +1 -1
- package/dist/services/runtime-kernel/heartbeat.core.js +16 -5
- package/dist/services/runtime-kernel/heartbeat.core.js.map +1 -1
- package/dist/services/runtime-kernel/heartbeat.d.ts +3 -3
- package/dist/services/runtime-kernel/heartbeat.execute.d.ts.map +1 -1
- package/dist/services/runtime-kernel/heartbeat.execute.js +17 -3
- package/dist/services/runtime-kernel/heartbeat.execute.js.map +1 -1
- package/dist/services/runtime-kernel/heartbeat.misc.js +1 -1
- package/dist/services/runtime-kernel/heartbeat.recovery.d.ts +1 -1
- package/dist/services/runtime-kernel/heartbeat.recovery.js +7 -7
- package/dist/services/runtime-kernel/heartbeat.recovery.js.map +1 -1
- package/dist/services/runtime-kernel/heartbeat.release.js +4 -4
- package/dist/services/runtime-kernel/heartbeat.release.js.map +1 -1
- package/dist/services/runtime-kernel/heartbeat.wakeup.js +1 -1
- package/dist/services/sidebar-badges.d.ts.map +1 -1
- package/dist/services/sidebar-badges.js +13 -1
- package/dist/services/sidebar-badges.js.map +1 -1
- package/dist/services/title-generation.d.ts +13 -0
- package/dist/services/title-generation.d.ts.map +1 -0
- package/dist/services/title-generation.js +77 -0
- package/dist/services/title-generation.js.map +1 -0
- package/dist/services/website-metadata.d.ts +17 -0
- package/dist/services/website-metadata.d.ts.map +1 -0
- package/dist/services/website-metadata.js +293 -0
- package/dist/services/website-metadata.js.map +1 -0
- package/dist/services/workspace-backups.d.ts +22 -0
- package/dist/services/workspace-backups.d.ts.map +1 -1
- package/dist/services/workspace-backups.js +161 -5
- package/dist/services/workspace-backups.js.map +1 -1
- package/dist/services/workspace-runtime.services.d.ts +1 -1
- package/package.json +14 -13
- package/resources/bundled-skills/rudder/SKILL.md +7 -6
- package/resources/bundled-skills/rudder/references/cli-reference.md +3 -3
- package/resources/bundled-skills/rudder-create-plugin/SKILL.md +2 -2
- package/skills/rudder/SKILL.md +7 -6
- package/skills/rudder/references/cli-reference.md +3 -3
- package/skills/rudder-create-plugin/SKILL.md +2 -2
- package/ui-dist/assets/{_basePickBy-CM0XatHw.js → _basePickBy-CyhMvFCw.js} +1 -1
- package/ui-dist/assets/{_baseUniq-CdBBmdoP.js → _baseUniq-k3x-egdv.js} +1 -1
- package/ui-dist/assets/{arc-DSTtxyJ9.js → arc-DVwZMGLR.js} +1 -1
- package/ui-dist/assets/{architectureDiagram-2XIMDMQ5-BkHMYb5I.js → architectureDiagram-2XIMDMQ5-BvKp7DHW.js} +1 -1
- package/ui-dist/assets/{blockDiagram-WCTKOSBZ-EYczZxwW.js → blockDiagram-WCTKOSBZ-CQ0KLoGd.js} +1 -1
- package/ui-dist/assets/{c4Diagram-IC4MRINW-Xo9qijMi.js → c4Diagram-IC4MRINW-BY44eeD7.js} +1 -1
- package/ui-dist/assets/channel-Cb8ybYSt.js +1 -0
- package/ui-dist/assets/{chunk-4BX2VUAB-CKzta1FF.js → chunk-4BX2VUAB-D7D6PuZU.js} +1 -1
- package/ui-dist/assets/{chunk-55IACEB6-BxxUB0ww.js → chunk-55IACEB6-CraDwywJ.js} +1 -1
- package/ui-dist/assets/{chunk-FMBD7UC4-0F4oxVtY.js → chunk-FMBD7UC4-BGYh4kbq.js} +1 -1
- package/ui-dist/assets/{chunk-JSJVCQXG-CVMPMlVD.js → chunk-JSJVCQXG-DndeOLp_.js} +1 -1
- package/ui-dist/assets/{chunk-KX2RTZJC-lPrAWT94.js → chunk-KX2RTZJC-Cx0eOadl.js} +1 -1
- package/ui-dist/assets/{chunk-NQ4KR5QH-Bufcm7Iv.js → chunk-NQ4KR5QH-PNVbQ_36.js} +1 -1
- package/ui-dist/assets/{chunk-QZHKN3VN-CucmdWnl.js → chunk-QZHKN3VN-DKsTZ1-C.js} +1 -1
- package/ui-dist/assets/{chunk-WL4C6EOR-Dz0oYQrJ.js → chunk-WL4C6EOR-B4aSDSws.js} +1 -1
- package/ui-dist/assets/classDiagram-VBA2DB6C-US2diuPm.js +1 -0
- package/ui-dist/assets/classDiagram-v2-RAHNMMFH-US2diuPm.js +1 -0
- package/ui-dist/assets/clone-CbFoFrhF.js +1 -0
- package/ui-dist/assets/{cose-bilkent-S5V4N54A-DzyX-Er8.js → cose-bilkent-S5V4N54A-DwgS7_iT.js} +1 -1
- package/ui-dist/assets/{dagre-KLK3FWXG-BbZzCKuN.js → dagre-KLK3FWXG-CGMeHr1L.js} +1 -1
- package/ui-dist/assets/{diagram-E7M64L7V-B5Rb7Bm4.js → diagram-E7M64L7V-1AVTOsRS.js} +1 -1
- package/ui-dist/assets/{diagram-IFDJBPK2-Cpu1Xc8G.js → diagram-IFDJBPK2-hfbRtuHq.js} +1 -1
- package/ui-dist/assets/{diagram-P4PSJMXO-kLfHqRlk.js → diagram-P4PSJMXO-BypSVEur.js} +1 -1
- package/ui-dist/assets/{erDiagram-INFDFZHY-rCnUyQUb.js → erDiagram-INFDFZHY-DWMZC8pq.js} +1 -1
- package/ui-dist/assets/{flowDiagram-PKNHOUZH-BhOz8cvV.js → flowDiagram-PKNHOUZH-C4ODl03j.js} +1 -1
- package/ui-dist/assets/{ganttDiagram-A5KZAMGK-Csg9g3hz.js → ganttDiagram-A5KZAMGK-K0UbcKpB.js} +1 -1
- package/ui-dist/assets/{gitGraphDiagram-K3NZZRJ6-DLPnSlRs.js → gitGraphDiagram-K3NZZRJ6-CEtw8QBQ.js} +1 -1
- package/ui-dist/assets/{graph-BrxYh68N.js → graph-D-YEM3eO.js} +1 -1
- package/ui-dist/assets/{index-DMkClCka.js → index--e_5aFtV.js} +1 -1
- package/ui-dist/assets/{index-G_y-oBne.js → index--wGHASfH.js} +1 -1
- package/ui-dist/assets/index-2sHXDbqQ.css +1 -0
- package/ui-dist/assets/{index-BQW242nS.js → index-8D4SrlCZ.js} +1 -1
- package/ui-dist/assets/{index-DpdsNIGb.js → index-B9FglFcf.js} +1 -1
- package/ui-dist/assets/{index-D4FFno9t.js → index-BOLNi_9C.js} +1 -1
- package/ui-dist/assets/{index-COBwmF-C.js → index-BVSwDm4x.js} +1 -1
- package/ui-dist/assets/{index-BkzdTp2b.js → index-C4vZZ0jB.js} +1 -1
- package/ui-dist/assets/{index-Br07RRw1.js → index-CMZ9kRE0.js} +1 -1
- package/ui-dist/assets/{index-mOyLwPeE.js → index-CZb2W71E.js} +1 -1
- package/ui-dist/assets/{index-DiMeST8g.js → index-Cfp9ooqM.js} +1 -1
- package/ui-dist/assets/{index-BeZv_Z0b.js → index-CyWWtF_x.js} +1 -1
- package/ui-dist/assets/{index-CsraICzz.js → index-CzQXnPD8.js} +1 -1
- package/ui-dist/assets/{index-Bw8MgLaM.js → index-D2uGk78l.js} +446 -446
- package/ui-dist/assets/{index-Cb2qts0o.js → index-DVl9xsgP.js} +1 -1
- package/ui-dist/assets/{index-D0rP99dj.js → index-T4jxRzoA.js} +1 -1
- package/ui-dist/assets/{index-B6_gFYNj.js → index-V0iKRmt7.js} +1 -1
- package/ui-dist/assets/{index-Dj72ldIc.js → index-byosaKUg.js} +1 -1
- package/ui-dist/assets/{index-D_06pAuN.js → index-nUtypsmU.js} +1 -1
- package/ui-dist/assets/{infoDiagram-LFFYTUFH-CRBKgiEf.js → infoDiagram-LFFYTUFH-C6TFdmXf.js} +1 -1
- package/ui-dist/assets/{ishikawaDiagram-PHBUUO56-DI3jquVE.js → ishikawaDiagram-PHBUUO56-DyiJqs9l.js} +1 -1
- package/ui-dist/assets/{journeyDiagram-4ABVD52K-DDFZ2Q6D.js → journeyDiagram-4ABVD52K-A-q8eZgk.js} +1 -1
- package/ui-dist/assets/{kanban-definition-K7BYSVSG-yL5u3cXV.js → kanban-definition-K7BYSVSG-B_1rE7-5.js} +1 -1
- package/ui-dist/assets/{layout-DDZaRkp7.js → layout-kMGiiRYg.js} +1 -1
- package/ui-dist/assets/{linear-CWngWuQa.js → linear-PdbwVMlL.js} +1 -1
- package/ui-dist/assets/{mermaid.core-CQuYoq9K.js → mermaid.core-Cev3K7jk.js} +4 -4
- package/ui-dist/assets/{mindmap-definition-YRQLILUH-BwSsHtTO.js → mindmap-definition-YRQLILUH-C8xkWcsS.js} +1 -1
- package/ui-dist/assets/{pieDiagram-SKSYHLDU-BasUkvwH.js → pieDiagram-SKSYHLDU-D2I_J-RQ.js} +1 -1
- package/ui-dist/assets/{quadrantDiagram-337W2JSQ-D0D2xp36.js → quadrantDiagram-337W2JSQ-B6BBePuG.js} +1 -1
- package/ui-dist/assets/{requirementDiagram-Z7DCOOCP-CztN9kDh.js → requirementDiagram-Z7DCOOCP-BUl7tTbs.js} +1 -1
- package/ui-dist/assets/{sankeyDiagram-WA2Y5GQK-2xDqN9ox.js → sankeyDiagram-WA2Y5GQK-Dus4b_vo.js} +1 -1
- package/ui-dist/assets/{sequenceDiagram-2WXFIKYE-CO3OUPIJ.js → sequenceDiagram-2WXFIKYE-DnwzyMvt.js} +1 -1
- package/ui-dist/assets/{stateDiagram-RAJIS63D-DuQ1QZcT.js → stateDiagram-RAJIS63D-CWYWUh48.js} +1 -1
- package/ui-dist/assets/stateDiagram-v2-FVOUBMTO-yRuBqnCA.js +1 -0
- package/ui-dist/assets/{timeline-definition-YZTLITO2-CnOxbQeb.js → timeline-definition-YZTLITO2-D7vwtWgR.js} +1 -1
- package/ui-dist/assets/{treemap-KZPCXAKY-DD77IFOl.js → treemap-KZPCXAKY-CGCh4N8D.js} +1 -1
- package/ui-dist/assets/{vennDiagram-LZ73GAT5-DOXTGJn1.js → vennDiagram-LZ73GAT5-Bq1y4idx.js} +1 -1
- package/ui-dist/assets/{xychartDiagram-JWTSCODW-DWkrcdri.js → xychartDiagram-JWTSCODW-CMFdYJaJ.js} +1 -1
- package/ui-dist/index.html +2 -2
- package/ui-dist/assets/channel-BRnz7pSY.js +0 -1
- package/ui-dist/assets/classDiagram-VBA2DB6C-Q3YuI9dv.js +0 -1
- package/ui-dist/assets/classDiagram-v2-RAHNMMFH-Q3YuI9dv.js +0 -1
- package/ui-dist/assets/clone-C1exIyAN.js +0 -1
- package/ui-dist/assets/index-Dz8xxyqB.css +0 -1
- package/ui-dist/assets/stateDiagram-v2-FVOUBMTO-DQbZqbl9.js +0 -1
package/dist/services/chats.js
CHANGED
|
@@ -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,35 @@ 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
|
+
return map;
|
|
114
|
+
}
|
|
71
115
|
async function listLatestReplyPreviews(orgId, conversationIds) {
|
|
72
116
|
if (conversationIds.length === 0)
|
|
73
117
|
return new Map();
|
|
@@ -175,8 +219,14 @@ export function chatService(db) {
|
|
|
175
219
|
await ensureConversationUserStates(rows, userId);
|
|
176
220
|
}
|
|
177
221
|
const conversationIds = rows.map((row) => row.id);
|
|
222
|
+
const sourceLookupConversationIds = [
|
|
223
|
+
...new Set([
|
|
224
|
+
...conversationIds,
|
|
225
|
+
...rows.flatMap((row) => [row.forkedFromConversationId, row.forkRootConversationId].filter((id) => Boolean(id))),
|
|
226
|
+
]),
|
|
227
|
+
];
|
|
178
228
|
const orgId = rows[0]?.orgId ?? null;
|
|
179
|
-
const [contextLinksByConversationId, primaryIssuesById, userStatesByConversationId, unreadCountsByConversationId, pendingProposalConversationIds, latestReplyPreviewsByConversationId, userMessageSummariesByConversationId,] = await Promise.all([
|
|
229
|
+
const [contextLinksByConversationId, primaryIssuesById, userStatesByConversationId, unreadCountsByConversationId, pendingProposalConversationIds, latestReplyPreviewsByConversationId, userMessageSummariesByConversationId, sourceMetadataByConversationId,] = await Promise.all([
|
|
180
230
|
listContextLinksForConversationIds(db, rows.map((row) => row.id)),
|
|
181
231
|
listPrimaryIssues(db, rows),
|
|
182
232
|
userId && orgId
|
|
@@ -194,29 +244,45 @@ export function chatService(db) {
|
|
|
194
244
|
orgId
|
|
195
245
|
? listUserMessageSummaries(orgId, conversationIds)
|
|
196
246
|
: Promise.resolve(new Map()),
|
|
247
|
+
orgId
|
|
248
|
+
? listConversationSourceMetadata(orgId, sourceLookupConversationIds)
|
|
249
|
+
: Promise.resolve(new Map()),
|
|
197
250
|
]);
|
|
198
|
-
return rows.map((row) =>
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
251
|
+
return rows.map((row) => {
|
|
252
|
+
const sourceMetadata = sourceMetadataByConversationId.get(row.id) ?? null;
|
|
253
|
+
const isExternalBound = Boolean(sourceMetadata);
|
|
254
|
+
const unreadCount = isExternalBound ? 0 : (unreadCountsByConversationId.get(row.id) ?? 0);
|
|
255
|
+
return {
|
|
256
|
+
...row,
|
|
257
|
+
primaryIssue: row.primaryIssueId ? (primaryIssuesById.get(row.primaryIssueId) ?? null) : null,
|
|
258
|
+
latestReplyPreview: latestReplyPreviewsByConversationId.get(row.id) ?? null,
|
|
259
|
+
latestUserMessagePreview: userMessageSummariesByConversationId.get(row.id)?.latestPreview ?? null,
|
|
260
|
+
userMessageCount: userMessageSummariesByConversationId.get(row.id)?.count ?? 0,
|
|
261
|
+
contextLinks: contextLinksByConversationId.get(row.id) ?? [],
|
|
262
|
+
sourceMetadata,
|
|
263
|
+
mutability: conversationMutability(row, sourceMetadata, sourceMetadataByConversationId),
|
|
264
|
+
lastReadAt: userStatesByConversationId.get(row.id)?.lastReadAt ?? null,
|
|
265
|
+
isPinned: Boolean(userStatesByConversationId.get(row.id)?.pinnedAt),
|
|
266
|
+
unreadCount,
|
|
267
|
+
isUnread: unreadCount > 0,
|
|
268
|
+
needsAttention: !isExternalBound && (unreadCount > 0 ||
|
|
269
|
+
pendingProposalConversationIds.has(row.id)),
|
|
270
|
+
};
|
|
271
|
+
});
|
|
212
272
|
}
|
|
213
273
|
async function hydrateConversationSummaries(rows, userId) {
|
|
214
274
|
if (userId) {
|
|
215
275
|
await ensureConversationUserStates(rows, userId);
|
|
216
276
|
}
|
|
217
277
|
const conversationIds = rows.map((row) => row.id);
|
|
278
|
+
const sourceLookupConversationIds = [
|
|
279
|
+
...new Set([
|
|
280
|
+
...conversationIds,
|
|
281
|
+
...rows.flatMap((row) => [row.forkedFromConversationId, row.forkRootConversationId].filter((id) => Boolean(id))),
|
|
282
|
+
]),
|
|
283
|
+
];
|
|
218
284
|
const orgId = rows[0]?.orgId ?? null;
|
|
219
|
-
const [userStatesByConversationId, unreadCountsByConversationId, pendingProposalConversationIds, latestReplyPreviewsByConversationId, userMessageSummariesByConversationId,] = await Promise.all([
|
|
285
|
+
const [userStatesByConversationId, unreadCountsByConversationId, pendingProposalConversationIds, latestReplyPreviewsByConversationId, userMessageSummariesByConversationId, sourceMetadataByConversationId,] = await Promise.all([
|
|
220
286
|
userId && orgId
|
|
221
287
|
? listConversationUserStates(orgId, userId, conversationIds)
|
|
222
288
|
: Promise.resolve(new Map()),
|
|
@@ -232,19 +298,29 @@ export function chatService(db) {
|
|
|
232
298
|
orgId
|
|
233
299
|
? listUserMessageSummaries(orgId, conversationIds)
|
|
234
300
|
: Promise.resolve(new Map()),
|
|
301
|
+
orgId
|
|
302
|
+
? listConversationSourceMetadata(orgId, sourceLookupConversationIds)
|
|
303
|
+
: Promise.resolve(new Map()),
|
|
235
304
|
]);
|
|
236
|
-
return rows.map((row) =>
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
305
|
+
return rows.map((row) => {
|
|
306
|
+
const sourceMetadata = sourceMetadataByConversationId.get(row.id) ?? null;
|
|
307
|
+
const isExternalBound = Boolean(sourceMetadata);
|
|
308
|
+
const unreadCount = isExternalBound ? 0 : (unreadCountsByConversationId.get(row.id) ?? 0);
|
|
309
|
+
return {
|
|
310
|
+
...row,
|
|
311
|
+
latestReplyPreview: latestReplyPreviewsByConversationId.get(row.id) ?? null,
|
|
312
|
+
latestUserMessagePreview: userMessageSummariesByConversationId.get(row.id)?.latestPreview ?? null,
|
|
313
|
+
userMessageCount: userMessageSummariesByConversationId.get(row.id)?.count ?? 0,
|
|
314
|
+
sourceMetadata,
|
|
315
|
+
mutability: conversationMutability(row, sourceMetadata, sourceMetadataByConversationId),
|
|
316
|
+
lastReadAt: userStatesByConversationId.get(row.id)?.lastReadAt ?? null,
|
|
317
|
+
isPinned: Boolean(userStatesByConversationId.get(row.id)?.pinnedAt),
|
|
318
|
+
unreadCount,
|
|
319
|
+
isUnread: unreadCount > 0,
|
|
320
|
+
needsAttention: !isExternalBound && (unreadCount > 0 ||
|
|
321
|
+
pendingProposalConversationIds.has(row.id)),
|
|
322
|
+
};
|
|
323
|
+
});
|
|
248
324
|
}
|
|
249
325
|
async function getConversationOrThrow(id) {
|
|
250
326
|
const row = await db
|
|
@@ -305,6 +381,328 @@ export function chatService(db) {
|
|
|
305
381
|
.where(inArray(approvals.id, approvalIds));
|
|
306
382
|
return new Map(approvalRows.map((row) => [row.id, row]));
|
|
307
383
|
}
|
|
384
|
+
function isQueuePositionConflict(error) {
|
|
385
|
+
return Boolean(error
|
|
386
|
+
&& typeof error === "object"
|
|
387
|
+
&& "code" in error
|
|
388
|
+
&& error.code === "23505");
|
|
389
|
+
}
|
|
390
|
+
function normalizeQueuedPayload(payload) {
|
|
391
|
+
return {
|
|
392
|
+
body: String(payload.body ?? ""),
|
|
393
|
+
attachmentIds: Array.isArray(payload.attachmentIds)
|
|
394
|
+
? payload.attachmentIds.filter((id) => typeof id === "string")
|
|
395
|
+
: [],
|
|
396
|
+
projectId: typeof payload.projectId === "string" ? payload.projectId : null,
|
|
397
|
+
skillRefs: Array.isArray(payload.skillRefs)
|
|
398
|
+
? payload.skillRefs.filter((ref) => typeof ref === "string")
|
|
399
|
+
: [],
|
|
400
|
+
accessMode: typeof payload.accessMode === "string" ? payload.accessMode : null,
|
|
401
|
+
model: typeof payload.model === "string" ? payload.model : null,
|
|
402
|
+
effort: typeof payload.effort === "string" ? payload.effort : null,
|
|
403
|
+
metadata: payload.metadata && typeof payload.metadata === "object" && !Array.isArray(payload.metadata)
|
|
404
|
+
? payload.metadata
|
|
405
|
+
: null,
|
|
406
|
+
};
|
|
407
|
+
}
|
|
408
|
+
function hydrateQueuedMessage(row) {
|
|
409
|
+
return {
|
|
410
|
+
...row,
|
|
411
|
+
payload: normalizeQueuedPayload(row.payload),
|
|
412
|
+
};
|
|
413
|
+
}
|
|
414
|
+
async function createGeneration(orgId, conversationId) {
|
|
415
|
+
const [row] = await db
|
|
416
|
+
.insert(chatGenerations)
|
|
417
|
+
.values({
|
|
418
|
+
orgId,
|
|
419
|
+
conversationId,
|
|
420
|
+
status: "active",
|
|
421
|
+
})
|
|
422
|
+
.returning();
|
|
423
|
+
if (!row)
|
|
424
|
+
throw new Error("Failed to create chat generation");
|
|
425
|
+
return row;
|
|
426
|
+
}
|
|
427
|
+
async function markGenerationTerminal(generationId, status) {
|
|
428
|
+
if (!generationId)
|
|
429
|
+
return null;
|
|
430
|
+
const now = new Date();
|
|
431
|
+
const [row] = await db
|
|
432
|
+
.update(chatGenerations)
|
|
433
|
+
.set({
|
|
434
|
+
status,
|
|
435
|
+
terminalReason: status,
|
|
436
|
+
completedAt: now,
|
|
437
|
+
updatedAt: now,
|
|
438
|
+
})
|
|
439
|
+
.where(eq(chatGenerations.id, generationId))
|
|
440
|
+
.returning();
|
|
441
|
+
return row ?? null;
|
|
442
|
+
}
|
|
443
|
+
async function getLatestActiveGeneration(conversationId) {
|
|
444
|
+
return db
|
|
445
|
+
.select()
|
|
446
|
+
.from(chatGenerations)
|
|
447
|
+
.where(and(eq(chatGenerations.conversationId, conversationId), inArray(chatGenerations.status, ["active", "tool_busy", "closing"])))
|
|
448
|
+
.orderBy(desc(chatGenerations.startedAt), desc(chatGenerations.createdAt))
|
|
449
|
+
.limit(1)
|
|
450
|
+
.then((rows) => rows[0] ?? null);
|
|
451
|
+
}
|
|
452
|
+
async function getLatestGeneration(conversationId) {
|
|
453
|
+
return db
|
|
454
|
+
.select()
|
|
455
|
+
.from(chatGenerations)
|
|
456
|
+
.where(eq(chatGenerations.conversationId, conversationId))
|
|
457
|
+
.orderBy(desc(chatGenerations.startedAt), desc(chatGenerations.createdAt))
|
|
458
|
+
.limit(1)
|
|
459
|
+
.then((rows) => rows[0] ?? null);
|
|
460
|
+
}
|
|
461
|
+
async function listQueuedMessages(conversationId) {
|
|
462
|
+
await reclaimStaleQueuedMessageClaims(conversationId);
|
|
463
|
+
const rows = await db
|
|
464
|
+
.select()
|
|
465
|
+
.from(chatQueuedMessages)
|
|
466
|
+
.where(and(eq(chatQueuedMessages.conversationId, conversationId), inArray(chatQueuedMessages.status, ["queued", "steer_pending", "dequeue_claimed", "running"])))
|
|
467
|
+
.orderBy(asc(chatQueuedMessages.position), asc(chatQueuedMessages.createdAt));
|
|
468
|
+
return rows.map(hydrateQueuedMessage);
|
|
469
|
+
}
|
|
470
|
+
async function getQueueSnapshot(conversationId, activeGenerationId) {
|
|
471
|
+
const activeGeneration = activeGenerationId
|
|
472
|
+
? { id: activeGenerationId }
|
|
473
|
+
: await getLatestActiveGeneration(conversationId);
|
|
474
|
+
return {
|
|
475
|
+
activeGenerationId: activeGeneration?.id ?? null,
|
|
476
|
+
items: await listQueuedMessages(conversationId),
|
|
477
|
+
};
|
|
478
|
+
}
|
|
479
|
+
async function createQueuedMessage(input) {
|
|
480
|
+
const payload = {
|
|
481
|
+
...input.payload,
|
|
482
|
+
body: input.payload.body.trim(),
|
|
483
|
+
attachmentIds: input.payload.attachmentIds ?? [],
|
|
484
|
+
skillRefs: input.payload.skillRefs ?? [],
|
|
485
|
+
projectId: input.payload.projectId ?? null,
|
|
486
|
+
accessMode: input.payload.accessMode ?? null,
|
|
487
|
+
model: input.payload.model ?? null,
|
|
488
|
+
effort: input.payload.effort ?? null,
|
|
489
|
+
metadata: input.payload.metadata ?? null,
|
|
490
|
+
};
|
|
491
|
+
for (let attempt = 0; attempt < 3; attempt += 1) {
|
|
492
|
+
try {
|
|
493
|
+
return await db.transaction(async (tx) => {
|
|
494
|
+
const existing = await tx
|
|
495
|
+
.select()
|
|
496
|
+
.from(chatQueuedMessages)
|
|
497
|
+
.where(and(eq(chatQueuedMessages.conversationId, input.conversationId), eq(chatQueuedMessages.clientMutationId, input.clientMutationId)))
|
|
498
|
+
.limit(1)
|
|
499
|
+
.then((rows) => rows[0] ?? null);
|
|
500
|
+
if (existing) {
|
|
501
|
+
if (JSON.stringify(existing.payload) !== JSON.stringify(payload)) {
|
|
502
|
+
throw conflict("Queued message idempotency key reused with a different payload");
|
|
503
|
+
}
|
|
504
|
+
return hydrateQueuedMessage(existing);
|
|
505
|
+
}
|
|
506
|
+
const [positionRow] = await tx
|
|
507
|
+
.select({
|
|
508
|
+
nextPosition: sql `coalesce(max(${chatQueuedMessages.position}), 0) + 1`,
|
|
509
|
+
})
|
|
510
|
+
.from(chatQueuedMessages)
|
|
511
|
+
.where(eq(chatQueuedMessages.conversationId, input.conversationId));
|
|
512
|
+
const [row] = await tx
|
|
513
|
+
.insert(chatQueuedMessages)
|
|
514
|
+
.values({
|
|
515
|
+
orgId: input.orgId,
|
|
516
|
+
conversationId: input.conversationId,
|
|
517
|
+
clientMutationId: input.clientMutationId,
|
|
518
|
+
position: Number(positionRow?.nextPosition ?? 1),
|
|
519
|
+
payload,
|
|
520
|
+
expectedGenerationId: input.expectedGenerationId ?? null,
|
|
521
|
+
})
|
|
522
|
+
.returning();
|
|
523
|
+
if (!row)
|
|
524
|
+
throw new Error("Failed to create queued chat message");
|
|
525
|
+
return hydrateQueuedMessage(row);
|
|
526
|
+
});
|
|
527
|
+
}
|
|
528
|
+
catch (error) {
|
|
529
|
+
if (attempt < 2 && isQueuePositionConflict(error))
|
|
530
|
+
continue;
|
|
531
|
+
throw error;
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
throw new Error("Failed to create queued chat message");
|
|
535
|
+
}
|
|
536
|
+
async function updateQueuedMessage(input) {
|
|
537
|
+
const now = new Date();
|
|
538
|
+
const [row] = await db
|
|
539
|
+
.update(chatQueuedMessages)
|
|
540
|
+
.set({
|
|
541
|
+
payload: {
|
|
542
|
+
...input.payload,
|
|
543
|
+
body: input.payload.body.trim(),
|
|
544
|
+
attachmentIds: input.payload.attachmentIds ?? [],
|
|
545
|
+
skillRefs: input.payload.skillRefs ?? [],
|
|
546
|
+
projectId: input.payload.projectId ?? null,
|
|
547
|
+
accessMode: input.payload.accessMode ?? null,
|
|
548
|
+
model: input.payload.model ?? null,
|
|
549
|
+
effort: input.payload.effort ?? null,
|
|
550
|
+
metadata: input.payload.metadata ?? null,
|
|
551
|
+
},
|
|
552
|
+
version: input.version + 1,
|
|
553
|
+
lastDeliveryReason: null,
|
|
554
|
+
updatedAt: now,
|
|
555
|
+
})
|
|
556
|
+
.where(and(eq(chatQueuedMessages.conversationId, input.conversationId), eq(chatQueuedMessages.id, input.itemId), eq(chatQueuedMessages.version, input.version), eq(chatQueuedMessages.status, "queued")))
|
|
557
|
+
.returning();
|
|
558
|
+
if (!row)
|
|
559
|
+
throw conflict("Queued message was changed or is no longer editable");
|
|
560
|
+
return hydrateQueuedMessage(row);
|
|
561
|
+
}
|
|
562
|
+
async function cancelQueuedMessage(input) {
|
|
563
|
+
const now = new Date();
|
|
564
|
+
const conditions = [
|
|
565
|
+
eq(chatQueuedMessages.conversationId, input.conversationId),
|
|
566
|
+
eq(chatQueuedMessages.id, input.itemId),
|
|
567
|
+
eq(chatQueuedMessages.status, "queued"),
|
|
568
|
+
];
|
|
569
|
+
if (input.version)
|
|
570
|
+
conditions.push(eq(chatQueuedMessages.version, input.version));
|
|
571
|
+
const [row] = await db
|
|
572
|
+
.update(chatQueuedMessages)
|
|
573
|
+
.set({
|
|
574
|
+
status: "cancelled",
|
|
575
|
+
version: sql `${chatQueuedMessages.version} + 1`,
|
|
576
|
+
cancelledAt: now,
|
|
577
|
+
updatedAt: now,
|
|
578
|
+
})
|
|
579
|
+
.where(and(...conditions))
|
|
580
|
+
.returning();
|
|
581
|
+
if (!row)
|
|
582
|
+
throw conflict("Queued message was changed or is no longer cancellable");
|
|
583
|
+
return hydrateQueuedMessage(row);
|
|
584
|
+
}
|
|
585
|
+
async function markQueuedMessageSteerFallback(input) {
|
|
586
|
+
const now = new Date();
|
|
587
|
+
const [row] = await db
|
|
588
|
+
.update(chatQueuedMessages)
|
|
589
|
+
.set({
|
|
590
|
+
status: "queued",
|
|
591
|
+
activeGenerationId: input.activeGenerationId ?? null,
|
|
592
|
+
deliveryAttempts: sql `${chatQueuedMessages.deliveryAttempts} + 1`,
|
|
593
|
+
lastAttemptAt: now,
|
|
594
|
+
lastDeliveryReason: input.reason,
|
|
595
|
+
version: sql `${chatQueuedMessages.version} + 1`,
|
|
596
|
+
updatedAt: now,
|
|
597
|
+
})
|
|
598
|
+
.where(and(eq(chatQueuedMessages.conversationId, input.conversationId), eq(chatQueuedMessages.id, input.itemId), eq(chatQueuedMessages.status, "queued")))
|
|
599
|
+
.returning();
|
|
600
|
+
if (!row)
|
|
601
|
+
throw conflict("Queued message was changed or is no longer steerable");
|
|
602
|
+
return hydrateQueuedMessage(row);
|
|
603
|
+
}
|
|
604
|
+
async function claimNextQueuedMessage(conversationId) {
|
|
605
|
+
await reclaimStaleQueuedMessageClaims(conversationId);
|
|
606
|
+
const now = new Date();
|
|
607
|
+
return db.transaction(async (tx) => {
|
|
608
|
+
const [candidate] = await tx
|
|
609
|
+
.select()
|
|
610
|
+
.from(chatQueuedMessages)
|
|
611
|
+
.where(and(eq(chatQueuedMessages.conversationId, conversationId), eq(chatQueuedMessages.status, "queued")))
|
|
612
|
+
.orderBy(asc(chatQueuedMessages.position), asc(chatQueuedMessages.createdAt))
|
|
613
|
+
.limit(1);
|
|
614
|
+
if (!candidate)
|
|
615
|
+
return null;
|
|
616
|
+
const [row] = await tx
|
|
617
|
+
.update(chatQueuedMessages)
|
|
618
|
+
.set({
|
|
619
|
+
status: "dequeue_claimed",
|
|
620
|
+
dequeuedAt: now,
|
|
621
|
+
deliveryAttempts: sql `${chatQueuedMessages.deliveryAttempts} + 1`,
|
|
622
|
+
lastAttemptAt: now,
|
|
623
|
+
lastDeliveryReason: null,
|
|
624
|
+
version: sql `${chatQueuedMessages.version} + 1`,
|
|
625
|
+
updatedAt: now,
|
|
626
|
+
})
|
|
627
|
+
.where(and(eq(chatQueuedMessages.id, candidate.id), eq(chatQueuedMessages.conversationId, conversationId), eq(chatQueuedMessages.status, "queued"), eq(chatQueuedMessages.version, candidate.version)))
|
|
628
|
+
.returning();
|
|
629
|
+
return row ? hydrateQueuedMessage(row) : null;
|
|
630
|
+
});
|
|
631
|
+
}
|
|
632
|
+
async function releaseQueuedMessageClaim(input) {
|
|
633
|
+
const now = new Date();
|
|
634
|
+
const [row] = await db
|
|
635
|
+
.update(chatQueuedMessages)
|
|
636
|
+
.set({
|
|
637
|
+
status: "queued",
|
|
638
|
+
lastDeliveryReason: input.reason,
|
|
639
|
+
version: sql `${chatQueuedMessages.version} + 1`,
|
|
640
|
+
updatedAt: now,
|
|
641
|
+
})
|
|
642
|
+
.where(and(eq(chatQueuedMessages.conversationId, input.conversationId), eq(chatQueuedMessages.id, input.itemId), eq(chatQueuedMessages.status, "dequeue_claimed")))
|
|
643
|
+
.returning();
|
|
644
|
+
return row ? hydrateQueuedMessage(row) : null;
|
|
645
|
+
}
|
|
646
|
+
async function reclaimStaleQueuedMessageClaims(conversationId) {
|
|
647
|
+
const cutoff = new Date(Date.now() - QUEUED_MESSAGE_CLAIM_LEASE_MS);
|
|
648
|
+
await db
|
|
649
|
+
.update(chatQueuedMessages)
|
|
650
|
+
.set({
|
|
651
|
+
status: "queued",
|
|
652
|
+
lastDeliveryReason: "claim_expired",
|
|
653
|
+
version: sql `${chatQueuedMessages.version} + 1`,
|
|
654
|
+
updatedAt: new Date(),
|
|
655
|
+
})
|
|
656
|
+
.where(and(eq(chatQueuedMessages.conversationId, conversationId), eq(chatQueuedMessages.status, "dequeue_claimed"), lt(chatQueuedMessages.updatedAt, cutoff)));
|
|
657
|
+
}
|
|
658
|
+
async function assertQueuedMessageClaimedForDelivery(input) {
|
|
659
|
+
const row = await db
|
|
660
|
+
.select()
|
|
661
|
+
.from(chatQueuedMessages)
|
|
662
|
+
.where(and(eq(chatQueuedMessages.conversationId, input.conversationId), eq(chatQueuedMessages.id, input.itemId)))
|
|
663
|
+
.limit(1)
|
|
664
|
+
.then((rows) => rows[0] ?? null);
|
|
665
|
+
if (!row || row.status !== "dequeue_claimed") {
|
|
666
|
+
throw conflict("Queued message is not claimed for delivery");
|
|
667
|
+
}
|
|
668
|
+
const payload = normalizeQueuedPayload(row.payload);
|
|
669
|
+
if (payload.body.trim() !== input.body.trim()) {
|
|
670
|
+
throw conflict("Queued message body no longer matches claimed payload");
|
|
671
|
+
}
|
|
672
|
+
return hydrateQueuedMessage(row);
|
|
673
|
+
}
|
|
674
|
+
async function markQueuedMessageRunning(input) {
|
|
675
|
+
const now = new Date();
|
|
676
|
+
const [row] = await db
|
|
677
|
+
.update(chatQueuedMessages)
|
|
678
|
+
.set({
|
|
679
|
+
status: "running",
|
|
680
|
+
sourceMessageId: input.sourceMessageId,
|
|
681
|
+
deliveredMessageId: input.sourceMessageId,
|
|
682
|
+
version: sql `${chatQueuedMessages.version} + 1`,
|
|
683
|
+
updatedAt: now,
|
|
684
|
+
})
|
|
685
|
+
.where(and(eq(chatQueuedMessages.conversationId, input.conversationId), eq(chatQueuedMessages.id, input.itemId), eq(chatQueuedMessages.status, "dequeue_claimed")))
|
|
686
|
+
.returning();
|
|
687
|
+
if (!row)
|
|
688
|
+
throw conflict("Queued message is no longer deliverable");
|
|
689
|
+
return hydrateQueuedMessage(row);
|
|
690
|
+
}
|
|
691
|
+
async function markQueuedMessageDeliveryTerminal(input) {
|
|
692
|
+
const now = new Date();
|
|
693
|
+
const nextStatus = input.status === "completed" ? "completed" : "failed";
|
|
694
|
+
const [row] = await db
|
|
695
|
+
.update(chatQueuedMessages)
|
|
696
|
+
.set({
|
|
697
|
+
status: nextStatus,
|
|
698
|
+
lastDeliveryReason: input.status === "completed" ? null : input.status,
|
|
699
|
+
version: sql `${chatQueuedMessages.version} + 1`,
|
|
700
|
+
updatedAt: now,
|
|
701
|
+
})
|
|
702
|
+
.where(and(eq(chatQueuedMessages.conversationId, input.conversationId), eq(chatQueuedMessages.id, input.itemId), inArray(chatQueuedMessages.status, ["dequeue_claimed", "running"])))
|
|
703
|
+
.returning();
|
|
704
|
+
return row ? hydrateQueuedMessage(row) : null;
|
|
705
|
+
}
|
|
308
706
|
async function hydrateMessages(rows, options = {}) {
|
|
309
707
|
const includeTranscript = options.includeTranscript !== false;
|
|
310
708
|
const [attachmentsByMessageId, approvalsById] = await Promise.all([
|
|
@@ -493,6 +891,208 @@ export function chatService(db) {
|
|
|
493
891
|
});
|
|
494
892
|
return getById(created.id);
|
|
495
893
|
}
|
|
894
|
+
function forkSystemEventBody(sourceConversation, sourceMessageId) {
|
|
895
|
+
const messageSuffix = sourceMessageId ? ` at message ${sourceMessageId}` : "";
|
|
896
|
+
return `Forked from [${sourceConversation.title}](chat://${sourceConversation.id})${messageSuffix}.`;
|
|
897
|
+
}
|
|
898
|
+
async function findForkFamilyGroup(client, orgId, userId, rootConversationId) {
|
|
899
|
+
const rootThreadKey = `chat:${rootConversationId}`;
|
|
900
|
+
return client
|
|
901
|
+
.select({ id: messengerCustomGroups.id })
|
|
902
|
+
.from(messengerCustomGroups)
|
|
903
|
+
.innerJoin(messengerCustomGroupEntries, eq(messengerCustomGroupEntries.groupId, messengerCustomGroups.id))
|
|
904
|
+
.where(and(eq(messengerCustomGroups.orgId, orgId), eq(messengerCustomGroups.userId, userId), eq(messengerCustomGroupEntries.orgId, orgId), eq(messengerCustomGroupEntries.userId, userId), eq(messengerCustomGroupEntries.threadKey, rootThreadKey)))
|
|
905
|
+
.orderBy(asc(messengerCustomGroups.sortOrder), asc(messengerCustomGroups.createdAt))
|
|
906
|
+
.limit(1)
|
|
907
|
+
.then((rows) => rows[0] ?? null);
|
|
908
|
+
}
|
|
909
|
+
async function createForkFamilyGroup(client, orgId, userId, name) {
|
|
910
|
+
const [lastGroup] = await client
|
|
911
|
+
.select({ sortOrder: messengerCustomGroups.sortOrder })
|
|
912
|
+
.from(messengerCustomGroups)
|
|
913
|
+
.where(and(eq(messengerCustomGroups.orgId, orgId), eq(messengerCustomGroups.userId, userId)))
|
|
914
|
+
.orderBy(desc(messengerCustomGroups.sortOrder))
|
|
915
|
+
.limit(1);
|
|
916
|
+
const now = new Date();
|
|
917
|
+
const [group] = await client
|
|
918
|
+
.insert(messengerCustomGroups)
|
|
919
|
+
.values({
|
|
920
|
+
orgId,
|
|
921
|
+
userId,
|
|
922
|
+
name: name.trim() || "Forked conversation",
|
|
923
|
+
icon: MESSENGER_FORK_GROUP_DEFAULT_ICON,
|
|
924
|
+
sortOrder: (lastGroup?.sortOrder ?? -1) + 1,
|
|
925
|
+
updatedAt: now,
|
|
926
|
+
})
|
|
927
|
+
.returning();
|
|
928
|
+
if (!group)
|
|
929
|
+
throw new Error("Failed to create Messenger fork group");
|
|
930
|
+
return group;
|
|
931
|
+
}
|
|
932
|
+
async function assignForkThreadToGroup(client, orgId, userId, groupId, threadKey) {
|
|
933
|
+
const [lastEntry] = await client
|
|
934
|
+
.select({ sortOrder: messengerCustomGroupEntries.sortOrder })
|
|
935
|
+
.from(messengerCustomGroupEntries)
|
|
936
|
+
.where(and(eq(messengerCustomGroupEntries.orgId, orgId), eq(messengerCustomGroupEntries.userId, userId), eq(messengerCustomGroupEntries.groupId, groupId)))
|
|
937
|
+
.orderBy(desc(messengerCustomGroupEntries.sortOrder))
|
|
938
|
+
.limit(1);
|
|
939
|
+
const now = new Date();
|
|
940
|
+
await client
|
|
941
|
+
.insert(messengerCustomGroupEntries)
|
|
942
|
+
.values({
|
|
943
|
+
orgId,
|
|
944
|
+
userId,
|
|
945
|
+
groupId,
|
|
946
|
+
threadKey,
|
|
947
|
+
sortOrder: (lastEntry?.sortOrder ?? -1) + 1,
|
|
948
|
+
updatedAt: now,
|
|
949
|
+
})
|
|
950
|
+
.onConflictDoNothing();
|
|
951
|
+
}
|
|
952
|
+
async function ensureForkFamilyGroup(client, orgId, userId, rootConversationId, sourceConversationId, childConversationId, groupName) {
|
|
953
|
+
const existing = await findForkFamilyGroup(client, orgId, userId, rootConversationId);
|
|
954
|
+
const group = existing ?? await createForkFamilyGroup(client, orgId, userId, groupName);
|
|
955
|
+
for (const threadKey of [
|
|
956
|
+
`chat:${rootConversationId}`,
|
|
957
|
+
`chat:${sourceConversationId}`,
|
|
958
|
+
`chat:${childConversationId}`,
|
|
959
|
+
]) {
|
|
960
|
+
await assignForkThreadToGroup(client, orgId, userId, group.id, threadKey);
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
async function forkConversation(input) {
|
|
964
|
+
const created = await db.transaction(async (tx) => {
|
|
965
|
+
const source = await tx
|
|
966
|
+
.select()
|
|
967
|
+
.from(chatConversations)
|
|
968
|
+
.where(and(eq(chatConversations.id, input.sourceConversationId), eq(chatConversations.orgId, input.orgId)))
|
|
969
|
+
.then((rows) => rows[0] ?? null);
|
|
970
|
+
if (!source)
|
|
971
|
+
throw notFound("Chat conversation not found");
|
|
972
|
+
const rootConversationId = source.forkRootConversationId ?? source.id;
|
|
973
|
+
const messageConditions = [
|
|
974
|
+
eq(chatMessages.conversationId, source.id),
|
|
975
|
+
eq(chatMessages.orgId, input.orgId),
|
|
976
|
+
isNull(chatMessages.supersededAt),
|
|
977
|
+
];
|
|
978
|
+
let forkSourceCreatedAt = null;
|
|
979
|
+
if (input.sourceMessageId) {
|
|
980
|
+
const sourceMessage = await tx
|
|
981
|
+
.select({
|
|
982
|
+
id: chatMessages.id,
|
|
983
|
+
kind: chatMessages.kind,
|
|
984
|
+
role: chatMessages.role,
|
|
985
|
+
createdAt: chatMessages.createdAt,
|
|
986
|
+
})
|
|
987
|
+
.from(chatMessages)
|
|
988
|
+
.where(and(...messageConditions, eq(chatMessages.id, input.sourceMessageId)))
|
|
989
|
+
.then((rows) => rows[0] ?? null);
|
|
990
|
+
if (!sourceMessage)
|
|
991
|
+
throw unprocessable("Fork source message must belong to the source conversation");
|
|
992
|
+
if (sourceMessage.role !== "assistant" || sourceMessage.kind !== "message") {
|
|
993
|
+
throw unprocessable("Fork source message must be an assistant response");
|
|
994
|
+
}
|
|
995
|
+
forkSourceCreatedAt = sourceMessage.createdAt;
|
|
996
|
+
}
|
|
997
|
+
const now = new Date();
|
|
998
|
+
const [child] = await tx
|
|
999
|
+
.insert(chatConversations)
|
|
1000
|
+
.values({
|
|
1001
|
+
orgId: input.orgId,
|
|
1002
|
+
status: "active",
|
|
1003
|
+
title: input.title?.trim() || source.title,
|
|
1004
|
+
summary: source.summary,
|
|
1005
|
+
preferredAgentId: source.preferredAgentId,
|
|
1006
|
+
routedAgentId: source.routedAgentId,
|
|
1007
|
+
primaryIssueId: source.primaryIssueId,
|
|
1008
|
+
forkedFromConversationId: source.id,
|
|
1009
|
+
forkedFromMessageId: input.sourceMessageId ?? null,
|
|
1010
|
+
forkRootConversationId: rootConversationId,
|
|
1011
|
+
issueCreationMode: source.issueCreationMode,
|
|
1012
|
+
planMode: source.planMode,
|
|
1013
|
+
createdByUserId: input.createdByUserId,
|
|
1014
|
+
createdAt: now,
|
|
1015
|
+
updatedAt: now,
|
|
1016
|
+
})
|
|
1017
|
+
.returning();
|
|
1018
|
+
if (!child)
|
|
1019
|
+
throw new Error("Failed to create forked chat conversation");
|
|
1020
|
+
const contextLinks = await tx
|
|
1021
|
+
.select()
|
|
1022
|
+
.from(chatContextLinks)
|
|
1023
|
+
.where(eq(chatContextLinks.conversationId, source.id))
|
|
1024
|
+
.orderBy(chatContextLinks.createdAt);
|
|
1025
|
+
if (contextLinks.length > 0) {
|
|
1026
|
+
await tx
|
|
1027
|
+
.insert(chatContextLinks)
|
|
1028
|
+
.values(contextLinks.map((link) => ({
|
|
1029
|
+
orgId: input.orgId,
|
|
1030
|
+
conversationId: child.id,
|
|
1031
|
+
entityType: link.entityType,
|
|
1032
|
+
entityId: link.entityId,
|
|
1033
|
+
metadata: link.metadata,
|
|
1034
|
+
})))
|
|
1035
|
+
.onConflictDoNothing();
|
|
1036
|
+
}
|
|
1037
|
+
const messagesToCopy = await tx
|
|
1038
|
+
.select()
|
|
1039
|
+
.from(chatMessages)
|
|
1040
|
+
.where(and(...messageConditions, ...(forkSourceCreatedAt && input.sourceMessageId
|
|
1041
|
+
? [or(lt(chatMessages.createdAt, forkSourceCreatedAt), eq(chatMessages.id, input.sourceMessageId))]
|
|
1042
|
+
: [])))
|
|
1043
|
+
.orderBy(chatMessages.createdAt, chatMessages.id);
|
|
1044
|
+
const forkMessages = input.sourceMessageId
|
|
1045
|
+
? messagesToCopy.slice(0, messagesToCopy.findIndex((message) => message.id === input.sourceMessageId) + 1)
|
|
1046
|
+
: messagesToCopy;
|
|
1047
|
+
if (forkMessages.length > 0) {
|
|
1048
|
+
await tx.insert(chatMessages).values(forkMessages.map((message) => ({
|
|
1049
|
+
orgId: input.orgId,
|
|
1050
|
+
conversationId: child.id,
|
|
1051
|
+
role: message.role,
|
|
1052
|
+
kind: message.kind,
|
|
1053
|
+
status: message.status === "streaming" ? "interrupted" : message.status,
|
|
1054
|
+
body: message.body,
|
|
1055
|
+
structuredPayload: null,
|
|
1056
|
+
approvalId: null,
|
|
1057
|
+
runId: null,
|
|
1058
|
+
replyingAgentId: message.replyingAgentId,
|
|
1059
|
+
chatTurnId: null,
|
|
1060
|
+
turnVariant: 0,
|
|
1061
|
+
createdAt: message.createdAt,
|
|
1062
|
+
updatedAt: message.updatedAt,
|
|
1063
|
+
})));
|
|
1064
|
+
}
|
|
1065
|
+
const [systemEvent] = await tx
|
|
1066
|
+
.insert(chatMessages)
|
|
1067
|
+
.values({
|
|
1068
|
+
orgId: input.orgId,
|
|
1069
|
+
conversationId: child.id,
|
|
1070
|
+
role: "system",
|
|
1071
|
+
kind: "system_event",
|
|
1072
|
+
status: "completed",
|
|
1073
|
+
body: forkSystemEventBody(source, input.sourceMessageId ?? null),
|
|
1074
|
+
structuredPayload: {
|
|
1075
|
+
type: "chat_fork",
|
|
1076
|
+
sourceConversationId: source.id,
|
|
1077
|
+
sourceMessageId: input.sourceMessageId ?? null,
|
|
1078
|
+
forkRootConversationId: rootConversationId,
|
|
1079
|
+
},
|
|
1080
|
+
createdAt: now,
|
|
1081
|
+
updatedAt: now,
|
|
1082
|
+
})
|
|
1083
|
+
.returning();
|
|
1084
|
+
await tx
|
|
1085
|
+
.update(chatConversations)
|
|
1086
|
+
.set({
|
|
1087
|
+
lastMessageAt: systemEvent?.createdAt ?? now,
|
|
1088
|
+
updatedAt: now,
|
|
1089
|
+
})
|
|
1090
|
+
.where(eq(chatConversations.id, child.id));
|
|
1091
|
+
await ensureForkFamilyGroup(tx, input.orgId, input.userId, rootConversationId, source.id, child.id, source.title);
|
|
1092
|
+
return child;
|
|
1093
|
+
});
|
|
1094
|
+
return getById(created.id, input.userId);
|
|
1095
|
+
}
|
|
496
1096
|
async function update(id, patch) {
|
|
497
1097
|
const [updated] = await db
|
|
498
1098
|
.update(chatConversations)
|
|
@@ -506,14 +1106,14 @@ export function chatService(db) {
|
|
|
506
1106
|
return null;
|
|
507
1107
|
return getById(id);
|
|
508
1108
|
}
|
|
509
|
-
async function updateDefaultTitle(id, title) {
|
|
1109
|
+
async function updateDefaultTitle(id, title, expectedCurrentTitle = "New chat") {
|
|
510
1110
|
const [updated] = await db
|
|
511
1111
|
.update(chatConversations)
|
|
512
1112
|
.set({
|
|
513
1113
|
title,
|
|
514
1114
|
updatedAt: new Date(),
|
|
515
1115
|
})
|
|
516
|
-
.where(and(eq(chatConversations.id, id), eq(chatConversations.title,
|
|
1116
|
+
.where(and(eq(chatConversations.id, id), eq(chatConversations.title, expectedCurrentTitle)))
|
|
517
1117
|
.returning();
|
|
518
1118
|
if (!updated)
|
|
519
1119
|
return null;
|
|
@@ -1462,10 +2062,26 @@ export function chatService(db) {
|
|
|
1462
2062
|
replaceSystemGeneratedTitle,
|
|
1463
2063
|
listAttachmentsForConversation,
|
|
1464
2064
|
remove,
|
|
2065
|
+
forkConversation,
|
|
1465
2066
|
resolve,
|
|
1466
2067
|
markRead,
|
|
1467
2068
|
markUnread,
|
|
1468
2069
|
setPinned,
|
|
2070
|
+
createGeneration,
|
|
2071
|
+
markGenerationTerminal,
|
|
2072
|
+
getLatestActiveGeneration,
|
|
2073
|
+
getLatestGeneration,
|
|
2074
|
+
getQueueSnapshot,
|
|
2075
|
+
listQueuedMessages,
|
|
2076
|
+
createQueuedMessage,
|
|
2077
|
+
updateQueuedMessage,
|
|
2078
|
+
cancelQueuedMessage,
|
|
2079
|
+
markQueuedMessageSteerFallback,
|
|
2080
|
+
claimNextQueuedMessage,
|
|
2081
|
+
releaseQueuedMessageClaim,
|
|
2082
|
+
assertQueuedMessageClaimedForDelivery,
|
|
2083
|
+
markQueuedMessageRunning,
|
|
2084
|
+
markQueuedMessageDeliveryTerminal,
|
|
1469
2085
|
listMessages,
|
|
1470
2086
|
getMessageTranscript,
|
|
1471
2087
|
addMessage,
|