@rudderhq/server 0.2.10-canary.8 → 0.2.10
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/plugin-host-runtime.d.ts +38 -38
- package/dist/bundled-plugins/plugin-linear/dist/worker.js +311 -159
- package/dist/bundled-plugins/plugin-linear/dist/worker.js.map +2 -2
- package/dist/config.d.ts +1 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +8 -0
- package/dist/config.js.map +1 -1
- package/dist/home-paths.d.ts +23 -4
- package/dist/home-paths.d.ts.map +1 -1
- package/dist/home-paths.js +46 -11
- package/dist/home-paths.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -2
- package/dist/index.js.map +1 -1
- package/dist/routes/access.helpers.d.ts +8 -8
- package/dist/routes/agents.d.ts.map +1 -1
- package/dist/routes/agents.js +15 -1
- package/dist/routes/agents.js.map +1 -1
- package/dist/routes/approvals.d.ts.map +1 -1
- package/dist/routes/approvals.js +34 -2
- package/dist/routes/approvals.js.map +1 -1
- package/dist/routes/chat-issue-assignment-wakeup.d.ts +28 -0
- package/dist/routes/chat-issue-assignment-wakeup.d.ts.map +1 -0
- package/dist/routes/chat-issue-assignment-wakeup.js +54 -0
- package/dist/routes/chat-issue-assignment-wakeup.js.map +1 -0
- package/dist/routes/chats.d.ts.map +1 -1
- package/dist/routes/chats.js +24 -6
- 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 +14 -3
- package/dist/routes/chats.stream-routes.js.map +1 -1
- package/dist/routes/issues.d.ts.map +1 -1
- package/dist/routes/issues.js +3 -0
- package/dist/routes/issues.js.map +1 -1
- package/dist/routes/issues.mutations.d.ts.map +1 -1
- package/dist/routes/issues.mutations.js +89 -32
- package/dist/routes/issues.mutations.js.map +1 -1
- package/dist/routes/orgs.d.ts.map +1 -1
- package/dist/routes/orgs.js +302 -3
- package/dist/routes/orgs.js.map +1 -1
- package/dist/routes/plugin-ui-static.d.ts +2 -1
- package/dist/routes/plugin-ui-static.d.ts.map +1 -1
- package/dist/routes/plugin-ui-static.js +8 -42
- package/dist/routes/plugin-ui-static.js.map +1 -1
- package/dist/routes/projects.d.ts.map +1 -1
- package/dist/routes/projects.js +6 -0
- package/dist/routes/projects.js.map +1 -1
- package/dist/services/access.d.ts +21 -21
- package/dist/services/activity.d.ts +19 -19
- package/dist/services/agent-run-context.d.ts +0 -2
- package/dist/services/agent-run-context.d.ts.map +1 -1
- package/dist/services/agent-run-context.js +6 -3
- package/dist/services/agent-run-context.js.map +1 -1
- package/dist/services/agents.d.ts +171 -171
- package/dist/services/approvals.d.ts +29 -29
- package/dist/services/assets.d.ts +8 -8
- package/dist/services/automation-chat-output.d.ts +3 -3
- package/dist/services/automations.d.ts +40 -32
- package/dist/services/automations.d.ts.map +1 -1
- package/dist/services/automations.js +467 -0
- package/dist/services/automations.js.map +1 -1
- package/dist/services/automations.scheduler.d.ts.map +1 -1
- package/dist/services/automations.scheduler.js +5 -3
- package/dist/services/automations.scheduler.js.map +1 -1
- package/dist/services/board-auth.d.ts +32 -32
- package/dist/services/calendar.d.ts +26 -26
- package/dist/services/chat-assistant.d.ts.map +1 -1
- package/dist/services/chat-assistant.helpers.d.ts +3 -2
- package/dist/services/chat-assistant.helpers.d.ts.map +1 -1
- package/dist/services/chat-assistant.helpers.js +3 -2
- package/dist/services/chat-assistant.helpers.js.map +1 -1
- package/dist/services/chat-assistant.js +11 -1
- package/dist/services/chat-assistant.js.map +1 -1
- package/dist/services/chat-generation-locks.d.ts +1 -0
- package/dist/services/chat-generation-locks.d.ts.map +1 -1
- package/dist/services/chat-generation-locks.js +10 -0
- package/dist/services/chat-generation-locks.js.map +1 -1
- package/dist/services/chats.d.ts +185 -161
- package/dist/services/chats.d.ts.map +1 -1
- package/dist/services/chats.helpers.d.ts +4 -4
- package/dist/services/chats.js +27 -0
- package/dist/services/chats.js.map +1 -1
- package/dist/services/costs.d.ts +8 -8
- package/dist/services/documents.d.ts +126 -0
- package/dist/services/documents.d.ts.map +1 -1
- package/dist/services/documents.js +323 -1
- package/dist/services/documents.js.map +1 -1
- package/dist/services/finance.d.ts +18 -18
- package/dist/services/goals.d.ts +30 -30
- package/dist/services/issue-approvals.d.ts +4 -4
- package/dist/services/issue-goal-fallback.d.ts.map +1 -1
- package/dist/services/issue-goal-fallback.js +9 -3
- package/dist/services/issue-goal-fallback.js.map +1 -1
- package/dist/services/issue-review-wakeup.d.ts +3 -3
- package/dist/services/issues.comments-attachments.d.ts +6 -6
- package/dist/services/issues.d.ts +26 -26
- package/dist/services/issues.d.ts.map +1 -1
- package/dist/services/issues.js +20 -0
- package/dist/services/issues.js.map +1 -1
- package/dist/services/knowledge-portability/organization-portability.core.d.ts +1 -1
- package/dist/services/knowledge-portability/organization-skills.catalog.d.ts +1 -1
- package/dist/services/messenger.d.ts +3 -2
- package/dist/services/messenger.d.ts.map +1 -1
- package/dist/services/messenger.js +98 -26
- package/dist/services/messenger.js.map +1 -1
- package/dist/services/organization-workspace-browser.d.ts +10 -1
- package/dist/services/organization-workspace-browser.d.ts.map +1 -1
- package/dist/services/organization-workspace-browser.js +286 -8
- package/dist/services/organization-workspace-browser.js.map +1 -1
- package/dist/services/orgs.d.ts +9 -9
- package/dist/services/plugin-loader.worker-paths.d.ts +5 -1
- package/dist/services/plugin-loader.worker-paths.d.ts.map +1 -1
- package/dist/services/plugin-loader.worker-paths.js +27 -24
- package/dist/services/plugin-loader.worker-paths.js.map +1 -1
- package/dist/services/plugin-registry.d.ts +137 -137
- package/dist/services/projects.d.ts +8 -8
- package/dist/services/projects.d.ts.map +1 -1
- package/dist/services/projects.js +52 -6
- package/dist/services/projects.js.map +1 -1
- package/dist/services/resource-catalog.d.ts.map +1 -1
- package/dist/services/resource-catalog.js +93 -27
- package/dist/services/resource-catalog.js.map +1 -1
- package/dist/services/runtime-kernel/heartbeat.d.ts +40 -33
- package/dist/services/runtime-kernel/heartbeat.d.ts.map +1 -1
- package/dist/services/runtime-kernel/heartbeat.execute.d.ts.map +1 -1
- package/dist/services/runtime-kernel/heartbeat.execute.js +19 -0
- package/dist/services/runtime-kernel/heartbeat.execute.js.map +1 -1
- package/dist/services/runtime-kernel/heartbeat.js +88 -1
- package/dist/services/runtime-kernel/heartbeat.js.map +1 -1
- package/dist/services/runtime-kernel/heartbeat.sessions.d.ts +1 -1
- package/dist/services/secrets.d.ts +25 -25
- package/dist/services/sidebar-badges.d.ts +0 -3
- package/dist/services/sidebar-badges.d.ts.map +1 -1
- package/dist/services/sidebar-badges.js +4 -54
- package/dist/services/sidebar-badges.js.map +1 -1
- package/dist/services/workspace-runtime.services.d.ts +13 -13
- package/package.json +13 -13
- package/resources/bundled-skills/para-memory-files/SKILL.md +4 -4
- package/resources/bundled-skills/rudder/SKILL.md +30 -13
- package/resources/bundled-skills/rudder/references/api-reference.md +16 -0
- package/resources/bundled-skills/rudder/references/cli-reference.md +9 -1
- package/resources/bundled-skills/rudder/references/organization-skills.md +1 -1
- package/skills/para-memory-files/SKILL.md +4 -4
- package/skills/rudder/SKILL.md +30 -13
- package/skills/rudder/references/api-reference.md +16 -0
- package/skills/rudder/references/cli-reference.md +9 -1
- package/skills/rudder/references/organization-skills.md +1 -1
- package/ui-dist/assets/_basePickBy-CSCT5uM-.js +1 -0
- package/ui-dist/assets/_baseUniq-6uzN-zvk.js +1 -0
- package/ui-dist/assets/{arc-DJicYGuR.js → arc-BwwnVVnu.js} +1 -1
- package/ui-dist/assets/{architectureDiagram-2XIMDMQ5-CNAjB0bS.js → architectureDiagram-2XIMDMQ5-DiP6mFDS.js} +1 -1
- package/ui-dist/assets/{blockDiagram-WCTKOSBZ-Cb2SN0O8.js → blockDiagram-WCTKOSBZ-DS7tlCEj.js} +1 -1
- package/ui-dist/assets/{c4Diagram-IC4MRINW-BUwidppn.js → c4Diagram-IC4MRINW-B2RNViSE.js} +1 -1
- package/ui-dist/assets/channel-D5xRBEMp.js +1 -0
- package/ui-dist/assets/{chunk-4BX2VUAB-DRq9D-c0.js → chunk-4BX2VUAB-Cg9RRkJ9.js} +1 -1
- package/ui-dist/assets/{chunk-55IACEB6-BU7fhJ5E.js → chunk-55IACEB6-C3OAh-Nm.js} +1 -1
- package/ui-dist/assets/{chunk-FMBD7UC4-B5KY7bkB.js → chunk-FMBD7UC4-BQ2yCpRL.js} +1 -1
- package/ui-dist/assets/{chunk-JSJVCQXG-CcU3d2u7.js → chunk-JSJVCQXG-D6lFBo3f.js} +1 -1
- package/ui-dist/assets/{chunk-KX2RTZJC-HQV7Thyw.js → chunk-KX2RTZJC-CUaDFynR.js} +1 -1
- package/ui-dist/assets/{chunk-NQ4KR5QH-CFZQUHUm.js → chunk-NQ4KR5QH-DOffnVy8.js} +1 -1
- package/ui-dist/assets/{chunk-QZHKN3VN-qWkcATvx.js → chunk-QZHKN3VN-C7Jx3r9m.js} +1 -1
- package/ui-dist/assets/{chunk-WL4C6EOR-rWD9bJYe.js → chunk-WL4C6EOR-DeATO8Iz.js} +1 -1
- package/ui-dist/assets/classDiagram-VBA2DB6C-CX2-VvTG.js +1 -0
- package/ui-dist/assets/classDiagram-v2-RAHNMMFH-CX2-VvTG.js +1 -0
- package/ui-dist/assets/clone-CAhALgsh.js +1 -0
- package/ui-dist/assets/{cose-bilkent-S5V4N54A-CsSjm2Co.js → cose-bilkent-S5V4N54A-x_82-QHb.js} +1 -1
- package/ui-dist/assets/{dagre-KLK3FWXG-mcPh1s1q.js → dagre-KLK3FWXG-B3xaAjXo.js} +1 -1
- package/ui-dist/assets/{diagram-E7M64L7V-BcWqAyuY.js → diagram-E7M64L7V-B7f9YQXK.js} +1 -1
- package/ui-dist/assets/{diagram-IFDJBPK2-B-5OERYu.js → diagram-IFDJBPK2-BdIywx8n.js} +1 -1
- package/ui-dist/assets/{diagram-P4PSJMXO-BPCuOOZ2.js → diagram-P4PSJMXO-B6Jz8GYG.js} +1 -1
- package/ui-dist/assets/{erDiagram-INFDFZHY-Cvau-JqB.js → erDiagram-INFDFZHY-CD_uFaUj.js} +1 -1
- package/ui-dist/assets/{flowDiagram-PKNHOUZH-BmTY4iN1.js → flowDiagram-PKNHOUZH-Btsi4bIC.js} +1 -1
- package/ui-dist/assets/{ganttDiagram-A5KZAMGK-Rx3_ciMY.js → ganttDiagram-A5KZAMGK-D9607_n7.js} +1 -1
- package/ui-dist/assets/{gitGraphDiagram-K3NZZRJ6-BSRwIrhI.js → gitGraphDiagram-K3NZZRJ6-DuJZbawi.js} +1 -1
- package/ui-dist/assets/{graph-C8ZACe2j.js → graph-CzzcMZjZ.js} +1 -1
- package/ui-dist/assets/{index-BZKsiCwA.js → index-6-mBOW4L.js} +1 -1
- package/ui-dist/assets/{index-z1an-zlr.js → index-BElMoOcl.js} +1 -1
- package/ui-dist/assets/{index-DP8nG4Ma.js → index-BHTArDmw.js} +1 -1
- package/ui-dist/assets/{index-jdhuEGPi.js → index-B_mXuEqJ.js} +1 -1
- package/ui-dist/assets/{index-B_wfe9Sq.js → index-Be1rLxo8.js} +1 -1
- package/ui-dist/assets/{index-B-SBJR-6.js → index-BlzWsRRW.js} +1 -1
- package/ui-dist/assets/{index-B8VxXSbS.js → index-C7eD9kLO.js} +1 -1
- package/ui-dist/assets/{index-ChHRnQjN.js → index-CB2kOtYK.js} +1 -1
- package/ui-dist/assets/{index-BWBQ0gJ1.js → index-CF3c2_3B.js} +1 -1
- package/ui-dist/assets/{index-BBtSnB9K.js → index-CIKUBddL.js} +1 -1
- package/ui-dist/assets/{index-DgPWaICy.js → index-CV51eG9V.js} +1 -1
- package/ui-dist/assets/index-Cl8ezghO.js +1575 -0
- package/ui-dist/assets/{index-B1jERrQP.js → index-CnKhnjg4.js} +1 -1
- package/ui-dist/assets/{index-oZ4uufqd.js → index-CxEId4kL.js} +1 -1
- package/ui-dist/assets/{index-Bc2KXsRy.js → index-CzoiRvOV.js} +1 -1
- package/ui-dist/assets/{index-BMaTBxHN.js → index-DFXiVVb9.js} +1 -1
- package/ui-dist/assets/{index-BZSbMc-V.js → index-DIM_TiMc.js} +1 -1
- package/ui-dist/assets/{index-B1lP_8Qm.js → index-DNHf2t08.js} +1 -1
- package/ui-dist/assets/{index-CIs6NOKk.js → index-DUi_nJkz.js} +1 -1
- package/ui-dist/assets/{index-CBTxOaVA.js → index-DZhxjaRV.js} +1 -1
- package/ui-dist/assets/{index-CCpTBOz2.js → index-De1w_DPK.js} +1 -1
- package/ui-dist/assets/index-DqSQXuKR.css +1 -0
- package/ui-dist/assets/{index-Av1vlrq_.js → index-DwK538a4.js} +1 -1
- package/ui-dist/assets/{index-jXMbbWhe.js → index-PLtyPrYV.js} +1 -1
- package/ui-dist/assets/{infoDiagram-LFFYTUFH-ZZkrWlCG.js → infoDiagram-LFFYTUFH-DiGITl2v.js} +1 -1
- package/ui-dist/assets/{ishikawaDiagram-PHBUUO56-C2kVJE3b.js → ishikawaDiagram-PHBUUO56-B0Wcc98L.js} +1 -1
- package/ui-dist/assets/{journeyDiagram-4ABVD52K-CUD8BfGC.js → journeyDiagram-4ABVD52K-CcwSx0Z4.js} +1 -1
- package/ui-dist/assets/{kanban-definition-K7BYSVSG-BSWhRDpQ.js → kanban-definition-K7BYSVSG-DeFt4kJ_.js} +1 -1
- package/ui-dist/assets/layout-BrGj-OnF.js +1 -0
- package/ui-dist/assets/{linear-B-yRz7s6.js → linear-DuFtuF_z.js} +1 -1
- package/ui-dist/assets/{mermaid.core-C-baF8bZ.js → mermaid.core-2Rx3AQaR.js} +57 -57
- package/ui-dist/assets/{mindmap-definition-YRQLILUH--gAgZZcl.js → mindmap-definition-YRQLILUH-B1Ng106P.js} +1 -1
- package/ui-dist/assets/{pieDiagram-SKSYHLDU-D98SS0Px.js → pieDiagram-SKSYHLDU-CHZc9iJf.js} +1 -1
- package/ui-dist/assets/{quadrantDiagram-337W2JSQ-BmE8vYkT.js → quadrantDiagram-337W2JSQ-vPyVOekT.js} +1 -1
- package/ui-dist/assets/{requirementDiagram-Z7DCOOCP-CBQB1rD1.js → requirementDiagram-Z7DCOOCP-OigqxZdS.js} +1 -1
- package/ui-dist/assets/{sankeyDiagram-WA2Y5GQK-B3YGzVwa.js → sankeyDiagram-WA2Y5GQK-BlqJUkbX.js} +1 -1
- package/ui-dist/assets/{sequenceDiagram-2WXFIKYE-B2MI2OVq.js → sequenceDiagram-2WXFIKYE-Dz0GHXK-.js} +1 -1
- package/ui-dist/assets/{stateDiagram-RAJIS63D-CnS8Uc6U.js → stateDiagram-RAJIS63D-BDp0frpT.js} +1 -1
- package/ui-dist/assets/stateDiagram-v2-FVOUBMTO-5yU2N9vK.js +1 -0
- package/ui-dist/assets/{timeline-definition-YZTLITO2-BSfReMsG.js → timeline-definition-YZTLITO2-Dluuvy7L.js} +1 -1
- package/ui-dist/assets/{treemap-KZPCXAKY-C4agj3NM.js → treemap-KZPCXAKY-CPpWyCyI.js} +4 -4
- package/ui-dist/assets/{vennDiagram-LZ73GAT5-tQ-QmgUr.js → vennDiagram-LZ73GAT5-CROeIBwe.js} +1 -1
- package/ui-dist/assets/{xychartDiagram-JWTSCODW-BcGHupvs.js → xychartDiagram-JWTSCODW-C3xQ6szH.js} +1 -1
- package/ui-dist/brands/claude-logo.svg +1 -0
- package/ui-dist/brands/cursor-logo.svg +1 -0
- package/ui-dist/brands/google-gemini-logo.svg +1 -0
- package/ui-dist/brands/openai-logo.svg +1 -0
- package/ui-dist/brands/pi-logo.svg +28 -0
- package/ui-dist/index.html +2 -2
- package/ui-dist/assets/_basePickBy-DHmAX-Ut.js +0 -1
- package/ui-dist/assets/_baseUniq-DpYhcode.js +0 -1
- package/ui-dist/assets/channel-L2R-jds5.js +0 -1
- package/ui-dist/assets/classDiagram-VBA2DB6C-CGKCZZyI.js +0 -1
- package/ui-dist/assets/classDiagram-v2-RAHNMMFH-CGKCZZyI.js +0 -1
- package/ui-dist/assets/clone-DxezikrM.js +0 -1
- package/ui-dist/assets/index-DB4yE_BH.js +0 -1537
- package/ui-dist/assets/index-bF3vOu6G.css +0 -1
- package/ui-dist/assets/layout-ChF-xA6S.js +0 -1
- package/ui-dist/assets/stateDiagram-v2-FVOUBMTO-DU4TN-D0.js +0 -1
|
@@ -1,15 +1,23 @@
|
|
|
1
1
|
import crypto from "node:crypto";
|
|
2
2
|
import { and, asc, desc, eq, inArray, isNotNull, isNull, lte, ne, sql } from "drizzle-orm";
|
|
3
3
|
import { agents, organizationSecrets, goals, heartbeatRuns, issues, projects, automationRuns, automations, automationTriggers, chatContextLinks, chatConversations, chatMessages, } from "@rudderhq/db";
|
|
4
|
+
import { chatIssueProposalFromStructuredPayload } from "@rudderhq/shared";
|
|
4
5
|
import { conflict, forbidden, notFound, unauthorized, unprocessable } from "../errors.js";
|
|
6
|
+
import { MAX_ATTACHMENT_BYTES } from "../attachment-types.js";
|
|
5
7
|
import { logger } from "../middleware/logger.js";
|
|
6
8
|
import { issueService } from "./issues.js";
|
|
9
|
+
import { chatService } from "./chats.js";
|
|
10
|
+
import { chatAssistantService, ChatAssistantStreamError } from "./chat-assistant.js";
|
|
11
|
+
import { claimChatGeneration, hasActiveChatGeneration } from "./chat-generation-locks.js";
|
|
7
12
|
import { secretService } from "./secrets.js";
|
|
13
|
+
import { getStorageService } from "../storage/index.js";
|
|
8
14
|
import { validateCron } from "./cron.js";
|
|
9
15
|
import { heartbeatService } from "./heartbeat.js";
|
|
10
16
|
import { queueIssueAssignmentWakeup } from "./issue-assignment-wakeup.js";
|
|
11
17
|
import { logActivity } from "./activity-log.js";
|
|
18
|
+
import { publishLiveEvent } from "./live-events.js";
|
|
12
19
|
import { assertTimeZone, LIVE_HEARTBEAT_RUN_STATUSES, MAX_CATCH_UP_RUNS, nextCronTickInTimeZone, nextResultText, normalizeWebhookTimestampMs, OPEN_ISSUE_STATUSES, } from "./automations.scheduler.js";
|
|
20
|
+
const CHAT_OUTPUT_STALE_RUN_MS = 30 * 60 * 1000;
|
|
13
21
|
function toAutomation(row) {
|
|
14
22
|
return {
|
|
15
23
|
...row,
|
|
@@ -18,8 +26,12 @@ function toAutomation(row) {
|
|
|
18
26
|
}
|
|
19
27
|
export function automationService(db, deps = {}) {
|
|
20
28
|
const issueSvc = issueService(db);
|
|
29
|
+
const chatSvc = chatService(db);
|
|
30
|
+
const storageSvc = deps.storage ?? (deps.chatAssistant ? null : getStorageService());
|
|
31
|
+
const assistantSvc = deps.chatAssistant ?? chatAssistantService(db, storageSvc ?? undefined);
|
|
21
32
|
const secretsSvc = secretService(db);
|
|
22
33
|
const heartbeat = deps.heartbeat ?? heartbeatService(db);
|
|
34
|
+
const autoStartChatOutputRuns = deps.autoStartChatOutputRuns ?? true;
|
|
23
35
|
async function getAutomationById(id) {
|
|
24
36
|
return db
|
|
25
37
|
.select()
|
|
@@ -142,6 +154,414 @@ export function automationService(db, deps = {}) {
|
|
|
142
154
|
.where(eq(automationRuns.id, input.runId));
|
|
143
155
|
return conversation.id;
|
|
144
156
|
}
|
|
157
|
+
function automationChatPrompt(input) {
|
|
158
|
+
const base = input.automation.description?.trim() || input.automation.title.trim();
|
|
159
|
+
const context = [
|
|
160
|
+
`Automation: ${input.automation.title}`,
|
|
161
|
+
`Trigger source: ${input.source}`,
|
|
162
|
+
];
|
|
163
|
+
if (input.payload && Object.keys(input.payload).length > 0) {
|
|
164
|
+
context.push(`Trigger payload: ${JSON.stringify(input.payload)}`);
|
|
165
|
+
}
|
|
166
|
+
return `${base}\n\n${context.join("\n")}`.trim();
|
|
167
|
+
}
|
|
168
|
+
function notifyChatChanged(orgId, conversationId, details) {
|
|
169
|
+
publishLiveEvent({
|
|
170
|
+
orgId,
|
|
171
|
+
type: "activity.logged",
|
|
172
|
+
payload: {
|
|
173
|
+
actorType: "system",
|
|
174
|
+
actorId: "automation-chat-output",
|
|
175
|
+
action: "chat.message_updated",
|
|
176
|
+
entityType: "chat",
|
|
177
|
+
entityId: conversationId,
|
|
178
|
+
agentId: null,
|
|
179
|
+
runId: null,
|
|
180
|
+
details: details ?? null,
|
|
181
|
+
},
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
async function logChatMessageAdded(input) {
|
|
185
|
+
await logActivity(db, {
|
|
186
|
+
orgId: input.orgId,
|
|
187
|
+
actorType: "system",
|
|
188
|
+
actorId: "automation-chat-output",
|
|
189
|
+
agentId: input.agentId ?? null,
|
|
190
|
+
action: "chat.message_added",
|
|
191
|
+
entityType: "chat",
|
|
192
|
+
entityId: input.conversationId,
|
|
193
|
+
details: {
|
|
194
|
+
messageId: input.message.id,
|
|
195
|
+
role: input.message.role,
|
|
196
|
+
kind: input.message.kind,
|
|
197
|
+
status: input.message.status,
|
|
198
|
+
source: "automation_chat_output",
|
|
199
|
+
},
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
function automationChatRunMetadata(automation, run, conversationId) {
|
|
203
|
+
return {
|
|
204
|
+
automationId: automation.id,
|
|
205
|
+
automationTitle: automation.title,
|
|
206
|
+
runId: run.id,
|
|
207
|
+
links: {
|
|
208
|
+
automation: `/automations/${automation.id}`,
|
|
209
|
+
chat: `/messenger/chat/${conversationId}`,
|
|
210
|
+
},
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
function proposedPlanDocumentPayload(structuredPayload) {
|
|
214
|
+
if (!structuredPayload)
|
|
215
|
+
return null;
|
|
216
|
+
const rawDocument = structuredPayload.planDocument
|
|
217
|
+
&& typeof structuredPayload.planDocument === "object"
|
|
218
|
+
&& !Array.isArray(structuredPayload.planDocument)
|
|
219
|
+
? structuredPayload.planDocument
|
|
220
|
+
: structuredPayload.plan && typeof structuredPayload.plan === "object" && !Array.isArray(structuredPayload.plan)
|
|
221
|
+
? structuredPayload.plan
|
|
222
|
+
: null;
|
|
223
|
+
return rawDocument ? rawDocument : null;
|
|
224
|
+
}
|
|
225
|
+
async function attachGeneratedFiles(input) {
|
|
226
|
+
if (!input.message || !input.generatedAttachments || input.generatedAttachments.length === 0) {
|
|
227
|
+
return input.message;
|
|
228
|
+
}
|
|
229
|
+
const attachments = [];
|
|
230
|
+
for (const generated of input.generatedAttachments) {
|
|
231
|
+
if (generated.body.length > MAX_ATTACHMENT_BYTES) {
|
|
232
|
+
throw new ChatAssistantStreamError(`Generated attachment exceeds ${MAX_ATTACHMENT_BYTES} bytes`, input.message.body, input.generatedAttachments);
|
|
233
|
+
}
|
|
234
|
+
const stored = await (storageSvc ?? getStorageService()).putFile({
|
|
235
|
+
orgId: input.conversation.orgId,
|
|
236
|
+
namespace: `chats/${input.conversation.id}/generated`,
|
|
237
|
+
originalFilename: generated.originalFilename,
|
|
238
|
+
contentType: generated.contentType,
|
|
239
|
+
body: generated.body,
|
|
240
|
+
});
|
|
241
|
+
const attachment = await chatSvc.createAttachment({
|
|
242
|
+
orgId: input.conversation.orgId,
|
|
243
|
+
conversationId: input.conversation.id,
|
|
244
|
+
messageId: input.message.id,
|
|
245
|
+
provider: stored.provider,
|
|
246
|
+
objectKey: stored.objectKey,
|
|
247
|
+
contentType: stored.contentType,
|
|
248
|
+
byteSize: stored.byteSize,
|
|
249
|
+
sha256: stored.sha256,
|
|
250
|
+
originalFilename: stored.originalFilename,
|
|
251
|
+
createdByAgentId: input.replyingAgentId ?? null,
|
|
252
|
+
createdByUserId: null,
|
|
253
|
+
});
|
|
254
|
+
attachments.push(attachment);
|
|
255
|
+
}
|
|
256
|
+
return {
|
|
257
|
+
...input.message,
|
|
258
|
+
attachments: [...(input.message.attachments ?? []), ...attachments],
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
async function automationAssistantReplyPersistence(input) {
|
|
262
|
+
if (input.reply.kind === "issue_proposal") {
|
|
263
|
+
const proposal = chatIssueProposalFromStructuredPayload(input.reply.structuredPayload);
|
|
264
|
+
const planDocument = proposedPlanDocumentPayload(input.reply.structuredPayload);
|
|
265
|
+
const approval = await chatSvc.createProposalApproval(input.conversation.orgId, {
|
|
266
|
+
type: "chat_issue_creation",
|
|
267
|
+
requestedByUserId: null,
|
|
268
|
+
payload: {
|
|
269
|
+
chatConversationId: input.conversation.id,
|
|
270
|
+
proposedByAgentId: input.reply.replyingAgentId ?? input.conversation.preferredAgentId ?? null,
|
|
271
|
+
proposedIssue: proposal,
|
|
272
|
+
...(planDocument ? { planDocument } : {}),
|
|
273
|
+
},
|
|
274
|
+
});
|
|
275
|
+
return {
|
|
276
|
+
kind: "issue_proposal",
|
|
277
|
+
approvalId: approval.id,
|
|
278
|
+
structuredPayload: input.reply.structuredPayload,
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
if (input.reply.kind === "operation_proposal") {
|
|
282
|
+
const approval = await chatSvc.createProposalApproval(input.conversation.orgId, {
|
|
283
|
+
type: "chat_operation",
|
|
284
|
+
requestedByUserId: null,
|
|
285
|
+
payload: {
|
|
286
|
+
chatConversationId: input.conversation.id,
|
|
287
|
+
operationProposal: input.reply.structuredPayload &&
|
|
288
|
+
typeof input.reply.structuredPayload.operationProposal === "object" &&
|
|
289
|
+
input.reply.structuredPayload.operationProposal !== null
|
|
290
|
+
? input.reply.structuredPayload.operationProposal
|
|
291
|
+
: input.reply.structuredPayload ?? {},
|
|
292
|
+
},
|
|
293
|
+
});
|
|
294
|
+
return {
|
|
295
|
+
kind: "operation_proposal",
|
|
296
|
+
approvalId: approval.id,
|
|
297
|
+
structuredPayload: {
|
|
298
|
+
...(input.reply.structuredPayload ?? {}),
|
|
299
|
+
operationProposalState: {
|
|
300
|
+
status: "pending",
|
|
301
|
+
decisionNote: null,
|
|
302
|
+
decidedByUserId: null,
|
|
303
|
+
decidedAt: null,
|
|
304
|
+
},
|
|
305
|
+
},
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
if (input.reply.kind === "ask_user") {
|
|
309
|
+
return {
|
|
310
|
+
kind: "ask_user",
|
|
311
|
+
approvalId: null,
|
|
312
|
+
structuredPayload: input.reply.structuredPayload,
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
return {
|
|
316
|
+
kind: "message",
|
|
317
|
+
approvalId: null,
|
|
318
|
+
structuredPayload: input.reply.structuredPayload,
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
async function expireStaleChatOutputRuns(automation, runId, executor = db) {
|
|
322
|
+
const staleBefore = new Date(Date.now() - CHAT_OUTPUT_STALE_RUN_MS);
|
|
323
|
+
const staleRuns = await executor
|
|
324
|
+
.select({
|
|
325
|
+
id: automationRuns.id,
|
|
326
|
+
linkedChatConversationId: automationRuns.linkedChatConversationId,
|
|
327
|
+
})
|
|
328
|
+
.from(automationRuns)
|
|
329
|
+
.where(and(eq(automationRuns.orgId, automation.orgId), eq(automationRuns.automationId, automation.id), ne(automationRuns.id, runId), inArray(automationRuns.status, ["received", "running"]), lte(automationRuns.updatedAt, staleBefore)));
|
|
330
|
+
for (const staleRun of staleRuns) {
|
|
331
|
+
if (staleRun.linkedChatConversationId && hasActiveChatGeneration(staleRun.linkedChatConversationId)) {
|
|
332
|
+
continue;
|
|
333
|
+
}
|
|
334
|
+
await executor
|
|
335
|
+
.update(automationRuns)
|
|
336
|
+
.set({
|
|
337
|
+
status: "failed",
|
|
338
|
+
failureReason: "Automation chat run was interrupted before completion",
|
|
339
|
+
completedAt: new Date(),
|
|
340
|
+
updatedAt: new Date(),
|
|
341
|
+
})
|
|
342
|
+
.where(eq(automationRuns.id, staleRun.id));
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
async function findLiveChatOutputRun(automation, runId, executor = db) {
|
|
346
|
+
await expireStaleChatOutputRuns(automation, runId, executor);
|
|
347
|
+
return executor
|
|
348
|
+
.select()
|
|
349
|
+
.from(automationRuns)
|
|
350
|
+
.where(and(eq(automationRuns.orgId, automation.orgId), eq(automationRuns.automationId, automation.id), ne(automationRuns.id, runId), inArray(automationRuns.status, ["received", "running"])))
|
|
351
|
+
.orderBy(desc(automationRuns.updatedAt), desc(automationRuns.createdAt))
|
|
352
|
+
.limit(1)
|
|
353
|
+
.then((rows) => rows[0] ?? null);
|
|
354
|
+
}
|
|
355
|
+
async function loadAutomationChatAssistantInput(conversationId) {
|
|
356
|
+
const conversation = await chatSvc.getById(conversationId);
|
|
357
|
+
if (!conversation)
|
|
358
|
+
throw notFound("Automation chat conversation not found");
|
|
359
|
+
const enriched = await assistantSvc.enrichConversation(conversation);
|
|
360
|
+
const messages = (await chatSvc.listMessages(conversationId)).filter((message) => !message.supersededAt);
|
|
361
|
+
const issueLabels = await issueSvc.listLabels(conversation.orgId);
|
|
362
|
+
return {
|
|
363
|
+
conversation: enriched,
|
|
364
|
+
messages,
|
|
365
|
+
contextLinks: (enriched.contextLinks ?? []),
|
|
366
|
+
issueLabels,
|
|
367
|
+
operatorProfile: null,
|
|
368
|
+
};
|
|
369
|
+
}
|
|
370
|
+
async function executeChatOutputAutomationRun(runId) {
|
|
371
|
+
const run = await getAutomationRunById(runId);
|
|
372
|
+
if (!run || run.status !== "running" || !run.linkedChatConversationId)
|
|
373
|
+
return;
|
|
374
|
+
const automation = await getAutomationById(run.automationId);
|
|
375
|
+
if (!automation || automation.outputMode !== "chat_output")
|
|
376
|
+
return;
|
|
377
|
+
const conversation = await chatSvc.getById(run.linkedChatConversationId);
|
|
378
|
+
if (!conversation) {
|
|
379
|
+
await finalizeRun(run.id, {
|
|
380
|
+
status: "failed",
|
|
381
|
+
failureReason: "Automation chat conversation not found",
|
|
382
|
+
completedAt: new Date(),
|
|
383
|
+
});
|
|
384
|
+
return;
|
|
385
|
+
}
|
|
386
|
+
const abortController = new AbortController();
|
|
387
|
+
const releaseGeneration = claimChatGeneration(conversation.id, abortController);
|
|
388
|
+
if (!releaseGeneration) {
|
|
389
|
+
await finalizeRun(run.id, {
|
|
390
|
+
status: "failed",
|
|
391
|
+
failureReason: "A chat reply is already being generated for this conversation",
|
|
392
|
+
completedAt: new Date(),
|
|
393
|
+
});
|
|
394
|
+
return;
|
|
395
|
+
}
|
|
396
|
+
const transcript = [];
|
|
397
|
+
let assistantDraftBody = "";
|
|
398
|
+
let assistantProgressMessage = null;
|
|
399
|
+
let assistantProgressMessageId = null;
|
|
400
|
+
let userMessage = null;
|
|
401
|
+
let lastRunProgressTouchMs = 0;
|
|
402
|
+
const touchRunChatProgress = async (messageId) => {
|
|
403
|
+
const nowMs = Date.now();
|
|
404
|
+
if (nowMs - lastRunProgressTouchMs < 15_000)
|
|
405
|
+
return;
|
|
406
|
+
lastRunProgressTouchMs = nowMs;
|
|
407
|
+
await db
|
|
408
|
+
.update(automationRuns)
|
|
409
|
+
.set({
|
|
410
|
+
lastChatMessageId: messageId,
|
|
411
|
+
updatedAt: new Date(nowMs),
|
|
412
|
+
})
|
|
413
|
+
.where(eq(automationRuns.id, run.id));
|
|
414
|
+
};
|
|
415
|
+
const persistProgress = async (progressConversation, status = "streaming", body = assistantDraftBody, replyingAgentId = progressConversation.chatRuntime?.runtimeAgentId ?? progressConversation.preferredAgentId ?? null, structuredPayload = null, kind = "message", approvalId = null) => {
|
|
416
|
+
if (!userMessage?.chatTurnId)
|
|
417
|
+
return null;
|
|
418
|
+
const input = {
|
|
419
|
+
kind,
|
|
420
|
+
status,
|
|
421
|
+
body,
|
|
422
|
+
transcript,
|
|
423
|
+
structuredPayload,
|
|
424
|
+
approvalId,
|
|
425
|
+
replyingAgentId,
|
|
426
|
+
};
|
|
427
|
+
if (assistantProgressMessage) {
|
|
428
|
+
const updated = await chatSvc.updateMessage(progressConversation.id, assistantProgressMessage.id, input);
|
|
429
|
+
if (updated) {
|
|
430
|
+
assistantProgressMessage = updated;
|
|
431
|
+
assistantProgressMessageId = assistantProgressMessage.id;
|
|
432
|
+
notifyChatChanged(progressConversation.orgId, progressConversation.id, {
|
|
433
|
+
messageId: assistantProgressMessage.id,
|
|
434
|
+
status,
|
|
435
|
+
});
|
|
436
|
+
await touchRunChatProgress(assistantProgressMessage.id);
|
|
437
|
+
return assistantProgressMessage;
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
assistantProgressMessage = await chatSvc.addMessage(progressConversation.id, {
|
|
441
|
+
orgId: progressConversation.orgId,
|
|
442
|
+
role: "assistant",
|
|
443
|
+
kind,
|
|
444
|
+
status,
|
|
445
|
+
body,
|
|
446
|
+
transcript,
|
|
447
|
+
structuredPayload,
|
|
448
|
+
approvalId,
|
|
449
|
+
replyingAgentId,
|
|
450
|
+
chatTurnId: userMessage.chatTurnId,
|
|
451
|
+
turnVariant: userMessage.turnVariant,
|
|
452
|
+
});
|
|
453
|
+
assistantProgressMessageId = assistantProgressMessage.id;
|
|
454
|
+
await logChatMessageAdded({
|
|
455
|
+
orgId: progressConversation.orgId,
|
|
456
|
+
conversationId: progressConversation.id,
|
|
457
|
+
message: assistantProgressMessage,
|
|
458
|
+
agentId: replyingAgentId,
|
|
459
|
+
});
|
|
460
|
+
await touchRunChatProgress(assistantProgressMessage.id);
|
|
461
|
+
return assistantProgressMessage;
|
|
462
|
+
};
|
|
463
|
+
try {
|
|
464
|
+
const prompt = automationChatPrompt({
|
|
465
|
+
automation,
|
|
466
|
+
source: run.source,
|
|
467
|
+
payload: run.triggerPayload,
|
|
468
|
+
});
|
|
469
|
+
userMessage = await chatSvc.addUserChatMessage(conversation.id, conversation.orgId, prompt);
|
|
470
|
+
await logChatMessageAdded({
|
|
471
|
+
orgId: conversation.orgId,
|
|
472
|
+
conversationId: conversation.id,
|
|
473
|
+
message: userMessage,
|
|
474
|
+
});
|
|
475
|
+
await finalizeRun(run.id, {
|
|
476
|
+
startedChatMessageId: userMessage.id,
|
|
477
|
+
lastChatMessageId: userMessage.id,
|
|
478
|
+
});
|
|
479
|
+
const assistantInput = await loadAutomationChatAssistantInput(conversation.id);
|
|
480
|
+
const streamed = await assistantSvc.streamChatAssistantReply({
|
|
481
|
+
...assistantInput,
|
|
482
|
+
abortSignal: abortController.signal,
|
|
483
|
+
onAssistantDelta: async (delta) => {
|
|
484
|
+
assistantDraftBody = `${assistantDraftBody}${delta}`;
|
|
485
|
+
await persistProgress(assistantInput.conversation);
|
|
486
|
+
},
|
|
487
|
+
onAssistantState: async () => {
|
|
488
|
+
await persistProgress(assistantInput.conversation);
|
|
489
|
+
},
|
|
490
|
+
onTranscriptEntry: async (entry) => {
|
|
491
|
+
transcript.push(entry);
|
|
492
|
+
await persistProgress(assistantInput.conversation);
|
|
493
|
+
},
|
|
494
|
+
});
|
|
495
|
+
const finalStatus = streamed.outcome === "stopped" ? "stopped" : "completed";
|
|
496
|
+
const finalBody = streamed.outcome === "stopped" ? streamed.partialBody : streamed.reply.body;
|
|
497
|
+
const finalReplyPersistence = streamed.outcome === "completed"
|
|
498
|
+
? await automationAssistantReplyPersistence({
|
|
499
|
+
conversation: assistantInput.conversation,
|
|
500
|
+
automation,
|
|
501
|
+
run,
|
|
502
|
+
reply: streamed.reply,
|
|
503
|
+
})
|
|
504
|
+
: {
|
|
505
|
+
kind: "message",
|
|
506
|
+
approvalId: null,
|
|
507
|
+
structuredPayload: null,
|
|
508
|
+
};
|
|
509
|
+
const finalMessage = await persistProgress(assistantInput.conversation, finalStatus, finalBody, streamed.replyingAgentId, {
|
|
510
|
+
...(finalReplyPersistence.structuredPayload ?? {}),
|
|
511
|
+
automationChatRun: {
|
|
512
|
+
...automationChatRunMetadata(automation, run, conversation.id),
|
|
513
|
+
status: streamed.outcome,
|
|
514
|
+
},
|
|
515
|
+
}, finalReplyPersistence.kind, finalReplyPersistence.approvalId);
|
|
516
|
+
const finalMessageWithAttachments = streamed.outcome === "completed"
|
|
517
|
+
? await attachGeneratedFiles({
|
|
518
|
+
conversation: assistantInput.conversation,
|
|
519
|
+
message: finalMessage,
|
|
520
|
+
generatedAttachments: streamed.reply.generatedAttachments,
|
|
521
|
+
replyingAgentId: streamed.replyingAgentId,
|
|
522
|
+
})
|
|
523
|
+
: finalMessage;
|
|
524
|
+
await finalizeRun(run.id, {
|
|
525
|
+
status: finalStatus === "completed" ? "completed" : "failed",
|
|
526
|
+
terminalChatMessageId: finalMessageWithAttachments?.id ?? assistantProgressMessageId,
|
|
527
|
+
lastChatMessageId: finalMessageWithAttachments?.id ?? assistantProgressMessageId ?? userMessage.id,
|
|
528
|
+
completedAt: new Date(),
|
|
529
|
+
});
|
|
530
|
+
}
|
|
531
|
+
catch (error) {
|
|
532
|
+
const partialBody = error instanceof ChatAssistantStreamError ? error.partialBody : "";
|
|
533
|
+
const failureReason = error instanceof Error ? error.message : String(error);
|
|
534
|
+
const fallbackBody = partialBody.trim() || "Automation chat run failed before it produced a final response.";
|
|
535
|
+
const latestConversation = await chatSvc.getById(conversation.id);
|
|
536
|
+
const failedMessage = await persistProgress((latestConversation ?? conversation), "failed", fallbackBody, automation.assigneeAgentId, {
|
|
537
|
+
eventType: "automation_chat_run_result",
|
|
538
|
+
automationId: automation.id,
|
|
539
|
+
automationTitle: automation.title,
|
|
540
|
+
runId: run.id,
|
|
541
|
+
status: "failed",
|
|
542
|
+
failureReason,
|
|
543
|
+
links: {
|
|
544
|
+
automation: `/automations/${automation.id}`,
|
|
545
|
+
chat: `/messenger/chat/${conversation.id}`,
|
|
546
|
+
},
|
|
547
|
+
});
|
|
548
|
+
await finalizeRun(run.id, {
|
|
549
|
+
status: "failed",
|
|
550
|
+
failureReason,
|
|
551
|
+
terminalChatMessageId: failedMessage?.id ?? assistantProgressMessageId,
|
|
552
|
+
lastChatMessageId: failedMessage?.id ?? assistantProgressMessageId ?? userMessage?.id ?? null,
|
|
553
|
+
completedAt: new Date(),
|
|
554
|
+
});
|
|
555
|
+
logger.warn({ err: error, automationId: automation.id, runId: run.id }, "automation chat output run failed");
|
|
556
|
+
}
|
|
557
|
+
finally {
|
|
558
|
+
releaseGeneration();
|
|
559
|
+
notifyChatChanged(conversation.orgId, conversation.id, {
|
|
560
|
+
automationId: automation.id,
|
|
561
|
+
runId: run.id,
|
|
562
|
+
});
|
|
563
|
+
}
|
|
564
|
+
}
|
|
145
565
|
async function listTriggersForAutomationIds(orgId, automationIds) {
|
|
146
566
|
if (automationIds.length === 0)
|
|
147
567
|
return new Map();
|
|
@@ -525,6 +945,46 @@ export function automationService(db, deps = {}) {
|
|
|
525
945
|
: undefined;
|
|
526
946
|
let createdIssue = null;
|
|
527
947
|
try {
|
|
948
|
+
if (input.automation.outputMode === "chat_output") {
|
|
949
|
+
const activeRun = await findLiveChatOutputRun(input.automation, createdRun.id, txDb);
|
|
950
|
+
if (activeRun && input.automation.concurrencyPolicy !== "always_enqueue") {
|
|
951
|
+
const status = input.automation.concurrencyPolicy === "skip_if_active" ? "skipped" : "coalesced";
|
|
952
|
+
const updated = await finalizeRun(createdRun.id, {
|
|
953
|
+
status,
|
|
954
|
+
linkedChatConversationId: activeRun.linkedChatConversationId,
|
|
955
|
+
coalescedIntoRunId: activeRun.id,
|
|
956
|
+
completedAt: triggeredAt,
|
|
957
|
+
}, txDb);
|
|
958
|
+
await updateAutomationTouchedState({
|
|
959
|
+
automationId: input.automation.id,
|
|
960
|
+
triggerId: input.trigger?.id ?? null,
|
|
961
|
+
triggeredAt,
|
|
962
|
+
status,
|
|
963
|
+
nextRunAt,
|
|
964
|
+
}, txDb);
|
|
965
|
+
return await getAutomationRunById(createdRun.id, txDb) ?? updated ?? createdRun;
|
|
966
|
+
}
|
|
967
|
+
const conversationId = await resolveAutomationRunChatConversationId({
|
|
968
|
+
automation: input.automation,
|
|
969
|
+
runId: createdRun.id,
|
|
970
|
+
executor: txDb,
|
|
971
|
+
});
|
|
972
|
+
if (!conversationId) {
|
|
973
|
+
throw new Error("Failed to create automation chat conversation");
|
|
974
|
+
}
|
|
975
|
+
const updated = await finalizeRun(createdRun.id, {
|
|
976
|
+
status: "running",
|
|
977
|
+
linkedChatConversationId: conversationId,
|
|
978
|
+
}, txDb);
|
|
979
|
+
await updateAutomationTouchedState({
|
|
980
|
+
automationId: input.automation.id,
|
|
981
|
+
triggerId: input.trigger?.id ?? null,
|
|
982
|
+
triggeredAt,
|
|
983
|
+
status: "running",
|
|
984
|
+
nextRunAt,
|
|
985
|
+
}, txDb);
|
|
986
|
+
return await getAutomationRunById(createdRun.id, txDb) ?? updated ?? createdRun;
|
|
987
|
+
}
|
|
528
988
|
const activeIssue = await findLiveExecutionIssue(input.automation, txDb);
|
|
529
989
|
if (activeIssue && input.automation.concurrencyPolicy !== "always_enqueue") {
|
|
530
990
|
const status = input.automation.concurrencyPolicy === "skip_if_active" ? "skipped" : "coalesced";
|
|
@@ -687,6 +1147,7 @@ export function automationService(db, deps = {}) {
|
|
|
687
1147
|
triggerId: input.trigger?.id ?? null,
|
|
688
1148
|
source: run.source,
|
|
689
1149
|
status: run.status,
|
|
1150
|
+
outputMode: input.automation.outputMode,
|
|
690
1151
|
},
|
|
691
1152
|
});
|
|
692
1153
|
}
|
|
@@ -694,11 +1155,17 @@ export function automationService(db, deps = {}) {
|
|
|
694
1155
|
logger.warn({ err, automationId: input.automation.id, runId: run.id }, "failed to log automated run");
|
|
695
1156
|
}
|
|
696
1157
|
}
|
|
1158
|
+
if (autoStartChatOutputRuns && input.automation.outputMode === "chat_output" && run.status === "running") {
|
|
1159
|
+
void executeChatOutputAutomationRun(run.id).catch((err) => {
|
|
1160
|
+
logger.warn({ err, automationId: input.automation.id, runId: run.id }, "automation chat output worker failed");
|
|
1161
|
+
});
|
|
1162
|
+
}
|
|
697
1163
|
return run;
|
|
698
1164
|
}
|
|
699
1165
|
return {
|
|
700
1166
|
get: getAutomationById,
|
|
701
1167
|
getTrigger: getTriggerById,
|
|
1168
|
+
executeChatOutputAutomationRun,
|
|
702
1169
|
list: async (orgId) => {
|
|
703
1170
|
const rows = await db
|
|
704
1171
|
.select()
|