@rudderhq/server 0.5.2-canary.2 → 0.6.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 +15 -0
- package/dist/bootstrap/register-api-routes.js.map +1 -1
- package/dist/bootstrap/types.d.ts +11 -0
- package/dist/bootstrap/types.d.ts.map +1 -1
- package/dist/bundled-plugins/plugin-linear/dist/worker.js +741 -7
- package/dist/bundled-plugins/plugin-linear/dist/worker.js.map +3 -3
- package/dist/config.d.ts +2 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +3 -0
- package/dist/config.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +28 -1
- package/dist/index.js.map +1 -1
- package/dist/local-runtime.d.ts +7 -0
- package/dist/local-runtime.d.ts.map +1 -1
- package/dist/local-runtime.js +15 -1
- package/dist/local-runtime.js.map +1 -1
- package/dist/middleware/auth.js +2 -2
- package/dist/middleware/auth.js.map +1 -1
- package/dist/middleware/error-handler.d.ts.map +1 -1
- package/dist/middleware/error-handler.js +3 -2
- package/dist/middleware/error-handler.js.map +1 -1
- package/dist/middleware/logger.d.ts +4 -0
- package/dist/middleware/logger.d.ts.map +1 -1
- package/dist/middleware/logger.js +82 -7
- package/dist/middleware/logger.js.map +1 -1
- package/dist/middleware/logger.test.js +94 -1
- package/dist/middleware/logger.test.js.map +1 -1
- package/dist/routes/chats.annotation-routes.d.ts +47 -0
- package/dist/routes/chats.annotation-routes.d.ts.map +1 -0
- package/dist/routes/chats.annotation-routes.js +164 -0
- package/dist/routes/chats.annotation-routes.js.map +1 -0
- package/dist/routes/chats.d.ts.map +1 -1
- package/dist/routes/chats.js +467 -165
- package/dist/routes/chats.js.map +1 -1
- package/dist/routes/chats.stream-routes.d.ts +1 -10
- package/dist/routes/chats.stream-routes.d.ts.map +1 -1
- package/dist/routes/chats.stream-routes.js +168 -110
- package/dist/routes/chats.stream-routes.js.map +1 -1
- package/dist/routes/chats.stream-support.d.ts +79 -0
- package/dist/routes/chats.stream-support.d.ts.map +1 -0
- package/dist/routes/chats.stream-support.js +121 -0
- package/dist/routes/chats.stream-support.js.map +1 -0
- package/dist/routes/issues.comments-attachments.d.ts.map +1 -1
- package/dist/routes/issues.comments-attachments.js +16 -2
- package/dist/routes/issues.comments-attachments.js.map +1 -1
- package/dist/routes/issues.d.ts.map +1 -1
- package/dist/routes/issues.js +21 -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 +20 -33
- package/dist/routes/issues.mutations.js.map +1 -1
- package/dist/routes/managed-mcp-agent-bindings.d.ts +15 -0
- package/dist/routes/managed-mcp-agent-bindings.d.ts.map +1 -0
- package/dist/routes/managed-mcp-agent-bindings.js +66 -0
- package/dist/routes/managed-mcp-agent-bindings.js.map +1 -0
- package/dist/routes/managed-mcp-connections.d.ts +8 -0
- package/dist/routes/managed-mcp-connections.d.ts.map +1 -0
- package/dist/routes/managed-mcp-connections.js +189 -0
- package/dist/routes/managed-mcp-connections.js.map +1 -0
- package/dist/routes/managed-mcp-runtime.d.ts +5 -0
- package/dist/routes/managed-mcp-runtime.d.ts.map +1 -0
- package/dist/routes/managed-mcp-runtime.js +148 -0
- package/dist/routes/managed-mcp-runtime.js.map +1 -0
- package/dist/routes/messenger.d.ts.map +1 -1
- package/dist/routes/messenger.js +1 -1
- package/dist/routes/messenger.js.map +1 -1
- package/dist/services/access.d.ts.map +1 -1
- package/dist/services/access.js +91 -12
- package/dist/services/access.js.map +1 -1
- package/dist/services/agent-run-context.d.ts +1 -0
- package/dist/services/agent-run-context.d.ts.map +1 -1
- package/dist/services/agent-run-context.js +5 -1
- package/dist/services/agent-run-context.js.map +1 -1
- package/dist/services/board-auth.d.ts +2 -2
- package/dist/services/chat-annotation-copy-lineage.d.ts +32 -0
- package/dist/services/chat-annotation-copy-lineage.d.ts.map +1 -0
- package/dist/services/chat-annotation-copy-lineage.js +110 -0
- package/dist/services/chat-annotation-copy-lineage.js.map +1 -0
- package/dist/services/chat-assistant.annotations.d.ts +16 -0
- package/dist/services/chat-assistant.annotations.d.ts.map +1 -0
- package/dist/services/chat-assistant.annotations.js +108 -0
- package/dist/services/chat-assistant.annotations.js.map +1 -0
- package/dist/services/chat-assistant.annotations.test.d.ts +2 -0
- package/dist/services/chat-assistant.annotations.test.d.ts.map +1 -0
- package/dist/services/chat-assistant.annotations.test.js +257 -0
- package/dist/services/chat-assistant.annotations.test.js.map +1 -0
- package/dist/services/chat-assistant.d.ts.map +1 -1
- package/dist/services/chat-assistant.helpers.d.ts +2 -3
- package/dist/services/chat-assistant.helpers.d.ts.map +1 -1
- package/dist/services/chat-assistant.helpers.js +37 -53
- package/dist/services/chat-assistant.helpers.js.map +1 -1
- package/dist/services/chat-assistant.js +61 -5
- package/dist/services/chat-assistant.js.map +1 -1
- package/dist/services/chat-generation-protocol.d.ts +8 -15
- package/dist/services/chat-generation-protocol.d.ts.map +1 -1
- package/dist/services/chat-generation-protocol.js +19 -59
- package/dist/services/chat-generation-protocol.js.map +1 -1
- package/dist/services/chat-generation-protocol.test.js +168 -6
- package/dist/services/chat-generation-protocol.test.js.map +1 -1
- package/dist/services/chat-generation-provenance.d.ts +14 -0
- package/dist/services/chat-generation-provenance.d.ts.map +1 -0
- package/dist/services/chat-generation-provenance.js +71 -0
- package/dist/services/chat-generation-provenance.js.map +1 -0
- package/dist/services/chat-inline-annotation-rendering.d.ts +2 -0
- package/dist/services/chat-inline-annotation-rendering.d.ts.map +1 -0
- package/dist/services/chat-inline-annotation-rendering.js +265 -0
- package/dist/services/chat-inline-annotation-rendering.js.map +1 -0
- package/dist/services/chat-inline-annotation-resolved-labels.d.ts +11 -0
- package/dist/services/chat-inline-annotation-resolved-labels.d.ts.map +1 -0
- package/dist/services/chat-inline-annotation-resolved-labels.js +490 -0
- package/dist/services/chat-inline-annotation-resolved-labels.js.map +1 -0
- package/dist/services/chat-inline-annotation-validation.d.ts +15 -0
- package/dist/services/chat-inline-annotation-validation.d.ts.map +1 -0
- package/dist/services/chat-inline-annotation-validation.js +430 -0
- package/dist/services/chat-inline-annotation-validation.js.map +1 -0
- package/dist/services/chat-inline-annotations.d.ts +18 -0
- package/dist/services/chat-inline-annotations.d.ts.map +1 -0
- package/dist/services/chat-inline-annotations.js +52 -0
- package/dist/services/chat-inline-annotations.js.map +1 -0
- package/dist/services/chat-inline-annotations.test.d.ts +2 -0
- package/dist/services/chat-inline-annotations.test.d.ts.map +1 -0
- package/dist/services/chat-inline-annotations.test.js +1306 -0
- package/dist/services/chat-inline-annotations.test.js.map +1 -0
- package/dist/services/chat-queued-message-materialization.d.ts +126 -0
- package/dist/services/chat-queued-message-materialization.d.ts.map +1 -0
- package/dist/services/chat-queued-message-materialization.js +327 -0
- package/dist/services/chat-queued-message-materialization.js.map +1 -0
- package/dist/services/chat-steer-messages.d.ts +3 -3
- package/dist/services/chat-steer-messages.d.ts.map +1 -1
- package/dist/services/chat-steer-messages.js +50 -80
- package/dist/services/chat-steer-messages.js.map +1 -1
- package/dist/services/chat-work-manifest.d.ts.map +1 -1
- package/dist/services/chat-work-manifest.js +5 -1
- package/dist/services/chat-work-manifest.js.map +1 -1
- package/dist/services/chats.annotation-persistence.d.ts +20 -0
- package/dist/services/chats.annotation-persistence.d.ts.map +1 -0
- package/dist/services/chats.annotation-persistence.js +206 -0
- package/dist/services/chats.annotation-persistence.js.map +1 -0
- package/dist/services/chats.d.ts +129 -96
- package/dist/services/chats.d.ts.map +1 -1
- package/dist/services/chats.helpers.d.ts +2 -2
- package/dist/services/chats.inline-visual-persistence.d.ts +3 -3
- package/dist/services/chats.inline-visual-persistence.d.ts.map +1 -1
- package/dist/services/chats.inline-visual-persistence.js +114 -54
- package/dist/services/chats.inline-visual-persistence.js.map +1 -1
- package/dist/services/chats.js +743 -252
- package/dist/services/chats.js.map +1 -1
- package/dist/services/finance.d.ts +1 -1
- package/dist/services/index.d.ts +8 -0
- package/dist/services/index.d.ts.map +1 -1
- package/dist/services/index.js +8 -0
- package/dist/services/index.js.map +1 -1
- package/dist/services/integrations/agent-integrations.d.ts +2 -2
- package/dist/services/integrations/custom-integrations.d.ts +3 -1
- package/dist/services/integrations/custom-integrations.d.ts.map +1 -1
- package/dist/services/integrations/custom-integrations.js +13 -2
- package/dist/services/integrations/custom-integrations.js.map +1 -1
- package/dist/services/issues.comments-attachments.d.ts +7 -1
- package/dist/services/issues.comments-attachments.d.ts.map +1 -1
- package/dist/services/issues.comments-attachments.js +13 -1
- package/dist/services/issues.comments-attachments.js.map +1 -1
- package/dist/services/issues.d.ts +6 -0
- package/dist/services/issues.d.ts.map +1 -1
- package/dist/services/issues.js +22 -3
- package/dist/services/issues.js.map +1 -1
- package/dist/services/knowledge-portability/organization-portability.core.d.ts +4 -1
- package/dist/services/knowledge-portability/organization-portability.core.d.ts.map +1 -1
- package/dist/services/knowledge-portability/organization-portability.core.js +17 -3
- package/dist/services/knowledge-portability/organization-portability.core.js.map +1 -1
- package/dist/services/knowledge-portability/organization-portability.export.d.ts.map +1 -1
- package/dist/services/knowledge-portability/organization-portability.export.js +2 -2
- package/dist/services/knowledge-portability/organization-portability.export.js.map +1 -1
- package/dist/services/knowledge-portability/organization-portability.import.d.ts.map +1 -1
- package/dist/services/knowledge-portability/organization-portability.import.js +13 -3
- package/dist/services/knowledge-portability/organization-portability.import.js.map +1 -1
- package/dist/services/knowledge-portability/organization-skills.catalog.d.ts +3 -0
- package/dist/services/knowledge-portability/organization-skills.catalog.d.ts.map +1 -1
- package/dist/services/knowledge-portability/organization-skills.catalog.js +54 -23
- package/dist/services/knowledge-portability/organization-skills.catalog.js.map +1 -1
- package/dist/services/knowledge-portability/organization-skills.d.ts.map +1 -1
- package/dist/services/knowledge-portability/organization-skills.js +627 -124
- package/dist/services/knowledge-portability/organization-skills.js.map +1 -1
- package/dist/services/knowledge-portability/organization-skills.sources.d.ts +1 -0
- package/dist/services/knowledge-portability/organization-skills.sources.d.ts.map +1 -1
- package/dist/services/knowledge-portability/organization-skills.sources.js +53 -10
- package/dist/services/knowledge-portability/organization-skills.sources.js.map +1 -1
- package/dist/services/mcp/authorizer-lock.d.ts +9 -0
- package/dist/services/mcp/authorizer-lock.d.ts.map +1 -0
- package/dist/services/mcp/authorizer-lock.js +15 -0
- package/dist/services/mcp/authorizer-lock.js.map +1 -0
- package/dist/services/mcp/managed-bindings.d.ts +17 -0
- package/dist/services/mcp/managed-bindings.d.ts.map +1 -0
- package/dist/services/mcp/managed-bindings.js +332 -0
- package/dist/services/mcp/managed-bindings.js.map +1 -0
- package/dist/services/mcp/managed-client.d.ts +64 -0
- package/dist/services/mcp/managed-client.d.ts.map +1 -0
- package/dist/services/mcp/managed-client.js +238 -0
- package/dist/services/mcp/managed-client.js.map +1 -0
- package/dist/services/mcp/managed-client.test.d.ts +2 -0
- package/dist/services/mcp/managed-client.test.d.ts.map +1 -0
- package/dist/services/mcp/managed-client.test.js +398 -0
- package/dist/services/mcp/managed-client.test.js.map +1 -0
- package/dist/services/mcp/managed-connections.d.ts +81 -0
- package/dist/services/mcp/managed-connections.d.ts.map +1 -0
- package/dist/services/mcp/managed-connections.js +920 -0
- package/dist/services/mcp/managed-connections.js.map +1 -0
- package/dist/services/mcp/managed-runtime.d.ts +134 -0
- package/dist/services/mcp/managed-runtime.d.ts.map +1 -0
- package/dist/services/mcp/managed-runtime.js +282 -0
- package/dist/services/mcp/managed-runtime.js.map +1 -0
- package/dist/services/mcp/oauth-provider.d.ts +48 -0
- package/dist/services/mcp/oauth-provider.d.ts.map +1 -0
- package/dist/services/mcp/oauth-provider.js +120 -0
- package/dist/services/mcp/oauth-provider.js.map +1 -0
- package/dist/services/mcp/oauth-scope.test.d.ts +2 -0
- package/dist/services/mcp/oauth-scope.test.d.ts.map +1 -0
- package/dist/services/mcp/oauth-scope.test.js +69 -0
- package/dist/services/mcp/oauth-scope.test.js.map +1 -0
- package/dist/services/mcp/oauth-session-gc.d.ts +14 -0
- package/dist/services/mcp/oauth-session-gc.d.ts.map +1 -0
- package/dist/services/mcp/oauth-session-gc.js +34 -0
- package/dist/services/mcp/oauth-session-gc.js.map +1 -0
- package/dist/services/mcp/oauth-session-gc.test.d.ts +2 -0
- package/dist/services/mcp/oauth-session-gc.test.d.ts.map +1 -0
- package/dist/services/mcp/oauth-session-gc.test.js +66 -0
- package/dist/services/mcp/oauth-session-gc.test.js.map +1 -0
- package/dist/services/mcp/oauth.d.ts +61 -0
- package/dist/services/mcp/oauth.d.ts.map +1 -0
- package/dist/services/mcp/oauth.js +1690 -0
- package/dist/services/mcp/oauth.js.map +1 -0
- package/dist/services/mcp/pinned-fetch.d.ts +15 -0
- package/dist/services/mcp/pinned-fetch.d.ts.map +1 -0
- package/dist/services/mcp/pinned-fetch.js +400 -0
- package/dist/services/mcp/pinned-fetch.js.map +1 -0
- package/dist/services/mcp/pinned-fetch.test.d.ts +2 -0
- package/dist/services/mcp/pinned-fetch.test.d.ts.map +1 -0
- package/dist/services/mcp/pinned-fetch.test.js +190 -0
- package/dist/services/mcp/pinned-fetch.test.js.map +1 -0
- package/dist/services/mcp/provider-registry.d.ts +77 -0
- package/dist/services/mcp/provider-registry.d.ts.map +1 -0
- package/dist/services/mcp/provider-registry.js +80 -0
- package/dist/services/mcp/provider-registry.js.map +1 -0
- package/dist/services/mcp/provider-registry.test.d.ts +2 -0
- package/dist/services/mcp/provider-registry.test.d.ts.map +1 -0
- package/dist/services/mcp/provider-registry.test.js +80 -0
- package/dist/services/mcp/provider-registry.test.js.map +1 -0
- package/dist/services/mcp/security-policy.d.ts +48 -0
- package/dist/services/mcp/security-policy.d.ts.map +1 -0
- package/dist/services/mcp/security-policy.js +344 -0
- package/dist/services/mcp/security-policy.js.map +1 -0
- package/dist/services/mcp/security-policy.test.d.ts +2 -0
- package/dist/services/mcp/security-policy.test.d.ts.map +1 -0
- package/dist/services/mcp/security-policy.test.js +226 -0
- package/dist/services/mcp/security-policy.test.js.map +1 -0
- package/dist/services/mcp/tool-discovery.d.ts +49 -0
- package/dist/services/mcp/tool-discovery.d.ts.map +1 -0
- package/dist/services/mcp/tool-discovery.js +198 -0
- package/dist/services/mcp/tool-discovery.js.map +1 -0
- package/dist/services/mcp/tool-discovery.test.d.ts +2 -0
- package/dist/services/mcp/tool-discovery.test.d.ts.map +1 -0
- package/dist/services/mcp/tool-discovery.test.js +168 -0
- package/dist/services/mcp/tool-discovery.test.js.map +1 -0
- package/dist/services/messenger.d.ts +1 -1
- package/dist/services/messenger.d.ts.map +1 -1
- package/dist/services/messenger.js +21 -3
- package/dist/services/messenger.js.map +1 -1
- package/dist/services/plugin-registry.d.ts +3 -3
- package/dist/services/runtime-kernel/heartbeat.core.d.ts +1 -1
- package/dist/services/runtime-kernel/heartbeat.core.d.ts.map +1 -1
- package/dist/services/runtime-kernel/heartbeat.core.js +30 -4
- package/dist/services/runtime-kernel/heartbeat.core.js.map +1 -1
- package/dist/services/runtime-kernel/heartbeat.wakeup.d.ts.map +1 -1
- package/dist/services/runtime-kernel/heartbeat.wakeup.js +38 -23
- package/dist/services/runtime-kernel/heartbeat.wakeup.js.map +1 -1
- package/dist/services/secrets.d.ts +64 -6
- package/dist/services/secrets.d.ts.map +1 -1
- package/dist/services/secrets.js +38 -15
- package/dist/services/secrets.js.map +1 -1
- package/dist/services/side-chats.d.ts +1 -1
- package/dist/services/side-chats.d.ts.map +1 -1
- package/dist/services/side-chats.js +56 -14
- package/dist/services/side-chats.js.map +1 -1
- package/dist/services/workspace-runtime.services.d.ts +2 -2
- package/dist/services/workspace-web-preview.js +1 -1
- package/package.json +16 -13
- package/resources/bundled-skills/rudder-docs/references/operating-practices.md +12 -5
- package/skills/rudder-docs/references/operating-practices.md +12 -5
- package/ui-dist/assets/LibraryLiveSurface-CKOthw54.js +1 -0
- package/ui-dist/assets/{abnfDiagram-VRR7QNED-KGtP7zoC.js → abnfDiagram-VRR7QNED-C6a_wMho.js} +1 -1
- package/ui-dist/assets/{arc-JjnKyiOb.js → arc-CP0En6KA.js} +1 -1
- package/ui-dist/assets/architectureDiagram-ZJ3FMSHR-AHfOdcaZ.js +36 -0
- package/ui-dist/assets/{blockDiagram-677ZJIJ3-D7YzMYrz.js → blockDiagram-677ZJIJ3-Bkl9lp63.js} +1 -1
- package/ui-dist/assets/{c4Diagram-LMCZKHZV-Dpf7UQxl.js → c4Diagram-LMCZKHZV-BpZareVt.js} +1 -1
- package/ui-dist/assets/channel-DqxL_Zcy.js +1 -0
- package/ui-dist/assets/{chunk-2Q5K7J3B-UJ3gsGlQ.js → chunk-2Q5K7J3B-BQAwVuXc.js} +1 -1
- package/ui-dist/assets/{chunk-32BRIVSS-BeHl2j2l.js → chunk-32BRIVSS-YkmfA08F.js} +1 -1
- package/ui-dist/assets/{chunk-5VM5RSS4-STE9fJd0.js → chunk-5VM5RSS4-DvvjwTnG.js} +1 -1
- package/ui-dist/assets/{chunk-EX3LRPZG-Bj8g8j4B.js → chunk-EX3LRPZG-TXD_Yhg5.js} +1 -1
- package/ui-dist/assets/{chunk-JWPE2WC7-0V4Pwta-.js → chunk-JWPE2WC7-CgMlj6XI.js} +1 -1
- package/ui-dist/assets/{chunk-MOJQB5TN-DNPn50gm.js → chunk-MOJQB5TN-BnJjU8Rc.js} +1 -1
- package/ui-dist/assets/{chunk-RYQCIY6F-Befmnv8r.js → chunk-RYQCIY6F-D9B64JKM.js} +1 -1
- package/ui-dist/assets/{chunk-V7JOEXUC-Boh8TjHj.js → chunk-V7JOEXUC-PS09QVpl.js} +1 -1
- package/ui-dist/assets/{chunk-VR4S4FIN-B_yEQSo3.js → chunk-VR4S4FIN-DQXb7pRS.js} +1 -1
- package/ui-dist/assets/{chunk-XXDRQBXY-Cf1GnUFx.js → chunk-XXDRQBXY-B1UdLiF2.js} +1 -1
- package/ui-dist/assets/classDiagram-OUVF2IWQ-DMwjzuJE.js +1 -0
- package/ui-dist/assets/classDiagram-v2-EOCWNBFH-DMwjzuJE.js +1 -0
- package/ui-dist/assets/cose-bilkent-JH36ORCC-lqqmMB3m.js +1 -0
- package/ui-dist/assets/{cynefin-VYW2F7L2-Dv1yELYC.js → cynefin-VYW2F7L2-C9hu0XqZ.js} +1 -1
- package/ui-dist/assets/{cynefinDiagram-TSTJHNR4-CeFwjFoZ.js → cynefinDiagram-TSTJHNR4-Uuhz4c-1.js} +1 -1
- package/ui-dist/assets/{dagre-VKFMJZFB-8idd_4sX.js → dagre-VKFMJZFB-ChDrQYse.js} +1 -1
- package/ui-dist/assets/{diagram-FQU43EPY-BBVua6hM.js → diagram-FQU43EPY-DLtjkVSN.js} +1 -1
- package/ui-dist/assets/{diagram-G47NLZAW-D1zLQZlp.js → diagram-G47NLZAW-DCvEm4D0.js} +1 -1
- package/ui-dist/assets/{diagram-NH7WQ7WH-DE_FTSNv.js → diagram-NH7WQ7WH-Dz5jlsPG.js} +1 -1
- package/ui-dist/assets/{diagram-OA4YK3LP-61VSKBEn.js → diagram-OA4YK3LP-BXmQLO-Q.js} +1 -1
- package/ui-dist/assets/{diagram-WEI45ONY-C-tED6BJ.js → diagram-WEI45ONY-JnMU3xrx.js} +1 -1
- package/ui-dist/assets/{ebnfDiagram-CCIWWBDH-BEB8WGt0.js → ebnfDiagram-CCIWWBDH-Kryuqj4r.js} +1 -1
- package/ui-dist/assets/{erDiagram-Q63AITRT-AN_jm1TZ.js → erDiagram-Q63AITRT-Bn7g2mSW.js} +1 -1
- package/ui-dist/assets/{flowDiagram-23GEKE2U-BwLC6tI7.js → flowDiagram-23GEKE2U-DcjqTK91.js} +4 -4
- package/ui-dist/assets/ganttDiagram-NO4QXBWP-BRkw9-GE.js +292 -0
- package/ui-dist/assets/{gitGraphDiagram-IHSO6WYX-D9HCL9rY.js → gitGraphDiagram-IHSO6WYX-Cexcp6kR.js} +1 -1
- package/ui-dist/assets/graph-Cu7OV4Oi.js +1 -0
- package/ui-dist/assets/{index-BQXnpwke.js → index-ASZMPBYm.js} +5 -5
- package/ui-dist/assets/{index-5OM32_rf.js → index-B17BqCTj.js} +1 -1
- package/ui-dist/assets/{index-Cf0gLy6a.js → index-B9MccU1g.js} +1 -1
- package/ui-dist/assets/{index-BoSJ4Rx1.js → index-BPqbtW_X.js} +1 -1
- package/ui-dist/assets/{index-CpIdZ4-7.js → index-C2HjDa98.js} +1 -1
- package/ui-dist/assets/index-CMPtpj0A.js +1 -0
- package/ui-dist/assets/{index-p0ZGU1_7.js → index-CZXgOYtk.js} +1 -1
- package/ui-dist/assets/{index-74cx3ESJ.js → index-CknAauOP.js} +1 -1
- package/ui-dist/assets/index-Cu1GuH0a.js +1 -0
- package/ui-dist/assets/index-D8PdEImm.css +1 -0
- package/ui-dist/assets/{index-DrVDiJhe.js → index-DB1YX9-p.js} +1 -1
- package/ui-dist/assets/{index-vHMnAQSb.js → index-DBxLZXK7.js} +624 -610
- package/ui-dist/assets/{index-CpEfk5zb.js → index-DOCVOD97.js} +1 -1
- package/ui-dist/assets/{index-DMuWG0YN.js → index-DUbakRAC.js} +1 -1
- package/ui-dist/assets/{index-AT8juaIi.js → index-Dbg1ZwO2.js} +1 -1
- package/ui-dist/assets/index-DwbLsoLt.js +1 -0
- package/ui-dist/assets/index-hCLSotmS.js +1 -0
- package/ui-dist/assets/index-jrhEFc-j.js +1 -0
- package/ui-dist/assets/index-kz8ueXgo.js +1 -0
- package/ui-dist/assets/{infoDiagram-FWYZ7A6U-CyO3CAA1.js → infoDiagram-FWYZ7A6U-DugVGI3K.js} +1 -1
- package/ui-dist/assets/{ishikawaDiagram-FXEZZL3T-BLLZuF1_.js → ishikawaDiagram-FXEZZL3T-CHy06Oev.js} +1 -1
- package/ui-dist/assets/{journeyDiagram-5HDEW3XC-CWzQocvE.js → journeyDiagram-5HDEW3XC-BI0w53rb.js} +1 -1
- package/ui-dist/assets/{kanban-definition-HUTT4EX6-Dz4SFU-I.js → kanban-definition-HUTT4EX6-v_bLwx7B.js} +1 -1
- package/ui-dist/assets/layout-Dwp1s_bo.js +1 -0
- package/ui-dist/assets/{linear-BlzDlAaL.js → linear-DAV4STLZ.js} +1 -1
- package/ui-dist/assets/map-Bs6QpaaQ.js +1 -0
- package/ui-dist/assets/{mermaid.core-BtCydd-w.js → mermaid.core-fVmaL47V.js} +4 -4
- package/ui-dist/assets/{mindmap-definition-LN4V7U3C-BeIkKRBx.js → mindmap-definition-LN4V7U3C-5dWD4dxm.js} +1 -1
- package/ui-dist/assets/{pegDiagram-2B236MQR-BZgpT4TN.js → pegDiagram-2B236MQR-DB2XsDPN.js} +1 -1
- package/ui-dist/assets/{pieDiagram-ENE6RG2P-BRFggcg2.js → pieDiagram-ENE6RG2P-Bc5teLCS.js} +1 -1
- package/ui-dist/assets/{quadrantDiagram-ABIIQ3AL-CibUo3gT.js → quadrantDiagram-ABIIQ3AL-BlfNdETt.js} +1 -1
- package/ui-dist/assets/{railroadDiagram-RFXS5EU6-DINJqhgn.js → railroadDiagram-RFXS5EU6-BbXywkq3.js} +1 -1
- package/ui-dist/assets/{requirementDiagram-TGXJPOKE-NegluQIe.js → requirementDiagram-TGXJPOKE-DU-CapdF.js} +1 -1
- package/ui-dist/assets/{sankeyDiagram-HTMAVEWB-Kq41yHAd.js → sankeyDiagram-HTMAVEWB-Ftvh3MqA.js} +1 -1
- package/ui-dist/assets/{sequenceDiagram-DBY2YBRQ-CngfEI4f.js → sequenceDiagram-DBY2YBRQ-CCtHt9V4.js} +1 -1
- package/ui-dist/assets/{sizeCapture-X5ZJPWSS-DUWRNlme.js → sizeCapture-X5ZJPWSS-x0jnIKHx.js} +1 -1
- package/ui-dist/assets/{stateDiagram-2N3HPSRC-BwHC_Fz4.js → stateDiagram-2N3HPSRC-2qCrydE7.js} +1 -1
- package/ui-dist/assets/stateDiagram-v2-6OUMAXLB-CvGRUgRf.js +1 -0
- package/ui-dist/assets/{swimlanes-5IMT3BWC-Cqp2rT1K.js → swimlanes-5IMT3BWC-6kqJq5Xf.js} +2 -2
- package/ui-dist/assets/swimlanesDiagram-G3AALYLV-EBa7-qSc.js +8 -0
- package/ui-dist/assets/{timeline-definition-FHXFAJF6-BG3GYPCu.js → timeline-definition-FHXFAJF6-BuRz8KHZ.js} +1 -1
- package/ui-dist/assets/{vennDiagram-L72KCM5P-D1IFU27N.js → vennDiagram-L72KCM5P-BKzMZ_Rv.js} +1 -1
- package/ui-dist/assets/{wardleyDiagram-EHGQE667-DboO2kYu.js → wardleyDiagram-EHGQE667-8uXlFtBV.js} +1 -1
- package/ui-dist/assets/{xychartDiagram-FW5EYKEG-vI2BGrXP.js → xychartDiagram-FW5EYKEG-CWKGlpF9.js} +1 -1
- package/ui-dist/index.html +2 -2
- package/ui-dist/assets/architectureDiagram-ZJ3FMSHR-DHyfFgK0.js +0 -36
- package/ui-dist/assets/channel-TMGI9Qt9.js +0 -1
- package/ui-dist/assets/classDiagram-OUVF2IWQ-r5zIpY6G.js +0 -1
- package/ui-dist/assets/classDiagram-v2-EOCWNBFH-r5zIpY6G.js +0 -1
- package/ui-dist/assets/cose-bilkent-JH36ORCC-fSNs9447.js +0 -1
- package/ui-dist/assets/ganttDiagram-NO4QXBWP-CJYhBF1C.js +0 -292
- package/ui-dist/assets/graph-DdBT9W3J.js +0 -1
- package/ui-dist/assets/index-6UIO-gg7.js +0 -1
- package/ui-dist/assets/index-BVkQVMFn.js +0 -1
- package/ui-dist/assets/index-BaAPxkqh.css +0 -1
- package/ui-dist/assets/index-CmCERTmS.js +0 -1
- package/ui-dist/assets/index-Cr4lUIaJ.js +0 -1
- package/ui-dist/assets/index-D0fAqlES.js +0 -1
- package/ui-dist/assets/index-DfNcAyZq.js +0 -1
- package/ui-dist/assets/layout-D3tY9q4Q.js +0 -1
- package/ui-dist/assets/map-Ctg1-a9N.js +0 -1
- package/ui-dist/assets/stateDiagram-v2-6OUMAXLB-C6P3NY96.js +0 -1
- package/ui-dist/assets/swimlanesDiagram-G3AALYLV-BNdDt62J.js +0 -8
package/dist/routes/chats.js
CHANGED
|
@@ -8,9 +8,11 @@ import { logger } from "../middleware/logger.js";
|
|
|
8
8
|
import { validate } from "../middleware/validate.js";
|
|
9
9
|
import { assertTimeZone } from "../services/automations.scheduler.js";
|
|
10
10
|
import { chatAgentRunService } from "../services/chat-agent-runs.js";
|
|
11
|
-
import {
|
|
11
|
+
import { buildChatNativeSteerFeedback } from "../services/chat-assistant.annotations.js";
|
|
12
|
+
import { CHAT_ASSISTANT_USER_ERROR_MESSAGE, chatAssistantErrorForLog, chatAssistantService, ChatAssistantStreamError, prepareChatAttachmentReferences, userVisiblePartialBodyFromError, } from "../services/chat-assistant.js";
|
|
12
13
|
import { cancelAndReleaseActiveChatGeneration, claimChatGeneration, createChatRuntimeControlCoordinator, getActiveChatGeneration, hasActiveChatGeneration, interruptActiveChatGeneration, steerActiveChatGeneration } from "../services/chat-generation-locks.js";
|
|
13
14
|
import { hashChatGenerationBody } from "../services/chat-generation-protocol.js";
|
|
15
|
+
import { chatInlineAnnotationService } from "../services/chat-inline-annotations.js";
|
|
14
16
|
import { chatSteerMessageService } from "../services/chat-steer-messages.js";
|
|
15
17
|
import { buildChatTitlePromptFromMessages, chatTitleGenerationService, } from "../services/chat-title-generation.js";
|
|
16
18
|
import { chatWorkManifestService } from "../services/chat-work-manifest.js";
|
|
@@ -20,6 +22,7 @@ import { runtimeResultText, sanitizeGeneratedTitle, } from "../services/title-ge
|
|
|
20
22
|
import { assertBoard, assertCompanyAccess, getActorInfo } from "./authz.js";
|
|
21
23
|
import { createChatBackgroundRuntime, } from "./chat-background-runtime.js";
|
|
22
24
|
import { wakeIssueAssigneeAfterChatConversion } from "./chat-issue-assignment-wakeup.js";
|
|
25
|
+
import { createChatAnnotationRouteHelpers, turnContextFromUserMessage, } from "./chats.annotation-routes.js";
|
|
23
26
|
import { attachGeneratedChatFiles } from "./chats.generated-attachments.js";
|
|
24
27
|
import { isMultipartRequest, paginateChatMessages, positiveIntegerQuery, uploadedMessageFiles, validateUploadedMessageFiles, } from "./chats.helpers.js";
|
|
25
28
|
import { registerChatStreamRoutes } from "./chats.stream-routes.js";
|
|
@@ -47,6 +50,14 @@ export function chatRoutes(db, storage, backgroundRuntime = createChatBackground
|
|
|
47
50
|
const chatTitles = chatTitleGenerationService({ chats: svc, productIntelligence });
|
|
48
51
|
const steerMessages = chatSteerMessageService(db);
|
|
49
52
|
const sideChats = sideChatService(db);
|
|
53
|
+
const inlineAnnotations = chatInlineAnnotationService(db);
|
|
54
|
+
const { addAgentAuthoredMessage, addUserMessage, cleanupStoredUserMessageFiles, storeUserMessageFiles, } = createChatAnnotationRouteHelpers({
|
|
55
|
+
db,
|
|
56
|
+
storage,
|
|
57
|
+
chats: svc,
|
|
58
|
+
logActivity,
|
|
59
|
+
assertLocalMutationAllowed: assertChatLocalMutationAllowed,
|
|
60
|
+
});
|
|
50
61
|
const CHAT_ASSISTANT_RECOVERABLE_FAILURE_FALLBACK_MESSAGE = "The assistant reply could not be completed. Rudder saved this attempt for diagnostics; retry when ready.";
|
|
51
62
|
const upload = multer({
|
|
52
63
|
storage: multer.memoryStorage(),
|
|
@@ -76,9 +87,112 @@ export function chatRoutes(db, storage, backgroundRuntime = createChatBackground
|
|
|
76
87
|
});
|
|
77
88
|
});
|
|
78
89
|
}
|
|
79
|
-
|
|
90
|
+
function parseQueuedMultipartBody(body, mode) {
|
|
91
|
+
const raw = { ...(body ?? {}) };
|
|
92
|
+
let payload = {};
|
|
93
|
+
if (typeof raw.payload === "string") {
|
|
94
|
+
try {
|
|
95
|
+
const parsed = JSON.parse(raw.payload);
|
|
96
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
97
|
+
payload = parsed;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
catch {
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
else if (raw.payload && typeof raw.payload === "object" && !Array.isArray(raw.payload)) {
|
|
105
|
+
payload = raw.payload;
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
const payloadKeys = [
|
|
109
|
+
"body",
|
|
110
|
+
"inlineAnnotations",
|
|
111
|
+
"projectId",
|
|
112
|
+
"skillRefs",
|
|
113
|
+
"accessMode",
|
|
114
|
+
"model",
|
|
115
|
+
"effort",
|
|
116
|
+
"metadata",
|
|
117
|
+
];
|
|
118
|
+
for (const key of payloadKeys) {
|
|
119
|
+
if (Object.hasOwn(raw, key))
|
|
120
|
+
payload[key] = raw[key];
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
if (typeof payload.inlineAnnotations === "string") {
|
|
124
|
+
try {
|
|
125
|
+
payload.inlineAnnotations = JSON.parse(payload.inlineAnnotations);
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
for (const key of ["skillRefs", "metadata"]) {
|
|
132
|
+
if (typeof payload[key] !== "string")
|
|
133
|
+
continue;
|
|
134
|
+
try {
|
|
135
|
+
payload[key] = JSON.parse(payload[key]);
|
|
136
|
+
}
|
|
137
|
+
catch {
|
|
138
|
+
return null;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
if (mode === "create") {
|
|
142
|
+
return {
|
|
143
|
+
clientMutationId: raw.clientMutationId,
|
|
144
|
+
expectedGenerationId: typeof raw.expectedGenerationId === "string" && raw.expectedGenerationId.trim()
|
|
145
|
+
? raw.expectedGenerationId
|
|
146
|
+
: null,
|
|
147
|
+
payload,
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
const version = typeof raw.version === "string" ? Number(raw.version) : raw.version;
|
|
151
|
+
return { version, payload };
|
|
152
|
+
}
|
|
153
|
+
async function storeQueuedAnnotationFiles(conversation, files) {
|
|
154
|
+
const storedFiles = [];
|
|
155
|
+
try {
|
|
156
|
+
for (const file of files) {
|
|
157
|
+
storedFiles.push(await storage.putFile({
|
|
158
|
+
orgId: conversation.orgId,
|
|
159
|
+
namespace: `chat-queue-annotations/${conversation.id}`,
|
|
160
|
+
originalFilename: file.originalname || null,
|
|
161
|
+
contentType: (file.mimetype || "").toLowerCase(),
|
|
162
|
+
body: file.buffer,
|
|
163
|
+
}));
|
|
164
|
+
}
|
|
165
|
+
return storedFiles;
|
|
166
|
+
}
|
|
167
|
+
catch (error) {
|
|
168
|
+
await Promise.all(storedFiles.map((stored) => storage.deleteObject(conversation.orgId, stored.objectKey).catch(() => undefined)));
|
|
169
|
+
throw error;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
async function cleanupCommittedQueuedAnnotationAssets(orgId, queueItemId, cleanupAttachments) {
|
|
173
|
+
const deletedAssetIds = [];
|
|
174
|
+
for (const attachment of cleanupAttachments) {
|
|
175
|
+
try {
|
|
176
|
+
await storage.deleteObject(orgId, attachment.objectKey);
|
|
177
|
+
deletedAssetIds.push(attachment.assetId);
|
|
178
|
+
}
|
|
179
|
+
catch (error) {
|
|
180
|
+
logger.warn({ err: error, queuedMessageId: queueItemId, assetId: attachment.assetId }, "failed to delete orphaned queued annotation asset");
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
if (deletedAssetIds.length > 0) {
|
|
184
|
+
await svc.finalizeQueuedAnnotationAssetCleanup({ orgId, assetIds: deletedAssetIds });
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
async function cleanupUncommittedQueuedAnnotationFiles(orgId, queueMutationId, attachments) {
|
|
188
|
+
await Promise.all(attachments.map((attachment) => storage.deleteObject(orgId, attachment.objectKey).catch((error) => {
|
|
189
|
+
logger.warn({ err: error, queueMutationId }, "failed to compensate an uncommitted queued annotation object");
|
|
190
|
+
})));
|
|
191
|
+
}
|
|
192
|
+
async function assertConversationAccess(req, conversationId, expectedOrgId) {
|
|
80
193
|
const conversation = await svc.getById(conversationId);
|
|
81
|
-
if (!conversation
|
|
194
|
+
if (!conversation
|
|
195
|
+
|| (expectedOrgId !== undefined && conversation.orgId !== expectedOrgId))
|
|
82
196
|
return null;
|
|
83
197
|
assertCompanyAccess(req, conversation.orgId);
|
|
84
198
|
await sideChats.assertAccessible(conversation, req.actor.type === "board" ? (req.actor.userId ?? "local-board") : null);
|
|
@@ -283,64 +397,6 @@ export function chatRoutes(db, storage, backgroundRuntime = createChatBackground
|
|
|
283
397
|
},
|
|
284
398
|
};
|
|
285
399
|
}
|
|
286
|
-
function turnContextFromUserMessage(userMessage) {
|
|
287
|
-
if (!userMessage.chatTurnId) {
|
|
288
|
-
throw new Error("User message missing chat turn id");
|
|
289
|
-
}
|
|
290
|
-
return { chatTurnId: userMessage.chatTurnId, turnVariant: userMessage.turnVariant };
|
|
291
|
-
}
|
|
292
|
-
async function addUserMessage(conversation, body, actor, editUserMessageId) {
|
|
293
|
-
assertChatLocalMutationAllowed(conversation);
|
|
294
|
-
const userMessage = await svc.addUserChatMessage(conversation.id, conversation.orgId, body, editUserMessageId ?? null);
|
|
295
|
-
await logActivity(db, {
|
|
296
|
-
orgId: conversation.orgId,
|
|
297
|
-
actorType: actor.actorType,
|
|
298
|
-
actorId: actor.actorId,
|
|
299
|
-
agentId: actor.agentId,
|
|
300
|
-
runId: actor.runId,
|
|
301
|
-
action: "chat.message_added",
|
|
302
|
-
entityType: "chat",
|
|
303
|
-
entityId: conversation.id,
|
|
304
|
-
details: {
|
|
305
|
-
messageId: userMessage.id,
|
|
306
|
-
role: "user",
|
|
307
|
-
kind: "message",
|
|
308
|
-
editUserMessageId: editUserMessageId ?? null,
|
|
309
|
-
},
|
|
310
|
-
});
|
|
311
|
-
return userMessage;
|
|
312
|
-
}
|
|
313
|
-
async function addAgentAuthoredMessage(conversation, body, actor) {
|
|
314
|
-
assertChatLocalMutationAllowed(conversation);
|
|
315
|
-
if (!actor.agentId) {
|
|
316
|
-
throw forbidden("Agent authentication required");
|
|
317
|
-
}
|
|
318
|
-
const message = await svc.addMessage(conversation.id, {
|
|
319
|
-
orgId: conversation.orgId,
|
|
320
|
-
role: "assistant",
|
|
321
|
-
kind: "message",
|
|
322
|
-
body,
|
|
323
|
-
replyingAgentId: actor.agentId,
|
|
324
|
-
});
|
|
325
|
-
await logActivity(db, {
|
|
326
|
-
orgId: conversation.orgId,
|
|
327
|
-
actorType: "agent",
|
|
328
|
-
actorId: actor.agentId,
|
|
329
|
-
agentId: actor.agentId,
|
|
330
|
-
runId: actor.runId,
|
|
331
|
-
action: "chat.message_added",
|
|
332
|
-
entityType: "chat",
|
|
333
|
-
entityId: conversation.id,
|
|
334
|
-
details: {
|
|
335
|
-
messageId: message.id,
|
|
336
|
-
role: "assistant",
|
|
337
|
-
kind: "message",
|
|
338
|
-
replyingAgentId: actor.agentId,
|
|
339
|
-
source: "agent_direct_message",
|
|
340
|
-
},
|
|
341
|
-
});
|
|
342
|
-
return message;
|
|
343
|
-
}
|
|
344
400
|
async function attachFilesToUserMessage(conversation, messageId, files, actor) {
|
|
345
401
|
assertChatLocalMutationAllowed(conversation);
|
|
346
402
|
const attachments = [];
|
|
@@ -458,7 +514,7 @@ export function chatRoutes(db, storage, backgroundRuntime = createChatBackground
|
|
|
458
514
|
const labels = await issuesSvc.listLabels(orgId);
|
|
459
515
|
return labels.length >= 5;
|
|
460
516
|
}
|
|
461
|
-
async function persistAssistantReply(req, conversation, actor, assistantReply, turnContext, transcript = [], replyingAgentId = assistantReply.replyingAgentId ?? chatReplyingAgentId(conversation), existingMessageId, runId) {
|
|
517
|
+
async function persistAssistantReply(req, conversation, actor, assistantReply, turnContext, transcript = [], replyingAgentId = assistantReply.replyingAgentId ?? chatReplyingAgentId(conversation), existingMessageId, runId, persistTranscript = true) {
|
|
462
518
|
const createdMessages = [];
|
|
463
519
|
const { chatTurnId, turnVariant } = turnContext;
|
|
464
520
|
const attachGeneratedFiles = (message, generatedAttachments) => attachGeneratedChatFiles({
|
|
@@ -477,7 +533,7 @@ export function chatRoutes(db, storage, backgroundRuntime = createChatBackground
|
|
|
477
533
|
status: "completed",
|
|
478
534
|
body: input.body,
|
|
479
535
|
structuredPayload: input.structuredPayload ?? null,
|
|
480
|
-
transcript,
|
|
536
|
+
...(persistTranscript ? { transcript } : {}),
|
|
481
537
|
approvalId: input.approvalId ?? null,
|
|
482
538
|
runId: runId ?? undefined,
|
|
483
539
|
replyingAgentId,
|
|
@@ -491,7 +547,7 @@ export function chatRoutes(db, storage, backgroundRuntime = createChatBackground
|
|
|
491
547
|
kind: input.kind,
|
|
492
548
|
body: input.body,
|
|
493
549
|
structuredPayload: input.structuredPayload ?? null,
|
|
494
|
-
transcript,
|
|
550
|
+
...(persistTranscript ? { transcript } : {}),
|
|
495
551
|
approvalId: input.approvalId ?? null,
|
|
496
552
|
runId: runId ?? null,
|
|
497
553
|
replyingAgentId,
|
|
@@ -783,13 +839,13 @@ export function chatRoutes(db, storage, backgroundRuntime = createChatBackground
|
|
|
783
839
|
attachments: [...(message.attachments ?? []), ...attachments],
|
|
784
840
|
};
|
|
785
841
|
}
|
|
786
|
-
async function persistPartialAssistantMessage(conversation, body, status, turnContext, transcript = [], replyingAgentId = chatReplyingAgentId(conversation), existingMessageId, runId, structuredPayload) {
|
|
842
|
+
async function persistPartialAssistantMessage(conversation, body, status, turnContext, transcript = [], replyingAgentId = chatReplyingAgentId(conversation), existingMessageId, runId, structuredPayload, persistTranscript = true) {
|
|
787
843
|
const trimmed = body.trim();
|
|
788
844
|
const fallbackBody = status === "stopped"
|
|
789
845
|
? "Chat run stopped before a final reply. Continue the conversation to resume from the preserved context."
|
|
790
846
|
: CHAT_ASSISTANT_USER_ERROR_MESSAGE;
|
|
791
847
|
const durableBody = trimmed || (transcript.length > 0 ? fallbackBody : "");
|
|
792
|
-
if (!durableBody)
|
|
848
|
+
if (!durableBody && status !== "stopped")
|
|
793
849
|
return null;
|
|
794
850
|
const chatTurnId = turnContext?.chatTurnId ?? randomUUID();
|
|
795
851
|
const turnVariant = turnContext?.turnVariant ?? 0;
|
|
@@ -799,7 +855,7 @@ export function chatRoutes(db, storage, backgroundRuntime = createChatBackground
|
|
|
799
855
|
status,
|
|
800
856
|
body: durableBody,
|
|
801
857
|
structuredPayload: structuredPayload ?? null,
|
|
802
|
-
transcript,
|
|
858
|
+
...(persistTranscript ? { transcript } : {}),
|
|
803
859
|
runId: runId ?? undefined,
|
|
804
860
|
replyingAgentId,
|
|
805
861
|
});
|
|
@@ -813,7 +869,7 @@ export function chatRoutes(db, storage, backgroundRuntime = createChatBackground
|
|
|
813
869
|
status,
|
|
814
870
|
body: durableBody,
|
|
815
871
|
structuredPayload: structuredPayload ?? null,
|
|
816
|
-
transcript,
|
|
872
|
+
...(persistTranscript ? { transcript } : {}),
|
|
817
873
|
runId: runId ?? null,
|
|
818
874
|
replyingAgentId,
|
|
819
875
|
chatTurnId,
|
|
@@ -999,8 +1055,10 @@ export function chatRoutes(db, storage, backgroundRuntime = createChatBackground
|
|
|
999
1055
|
}
|
|
1000
1056
|
let leaseRenewing = false;
|
|
1001
1057
|
let leaseLost = false;
|
|
1058
|
+
let deliveryAcknowledged = false;
|
|
1059
|
+
let deliveryAcknowledging = false;
|
|
1002
1060
|
const renewLease = async () => {
|
|
1003
|
-
if (leaseRenewing || leaseLost)
|
|
1061
|
+
if (leaseRenewing || leaseLost || deliveryAcknowledged || deliveryAcknowledging)
|
|
1004
1062
|
return;
|
|
1005
1063
|
leaseRenewing = true;
|
|
1006
1064
|
try {
|
|
@@ -1011,7 +1069,7 @@ export function chatRoutes(db, storage, backgroundRuntime = createChatBackground
|
|
|
1011
1069
|
leaseEpoch: claim.leaseEpoch,
|
|
1012
1070
|
leaseMs: queueLeaseMs,
|
|
1013
1071
|
});
|
|
1014
|
-
if (!renewed) {
|
|
1072
|
+
if (!renewed && !deliveryAcknowledged && !deliveryAcknowledging) {
|
|
1015
1073
|
leaseLost = true;
|
|
1016
1074
|
abortController.abort(new Error("Queued chat continuation lost its delivery lease"));
|
|
1017
1075
|
}
|
|
@@ -1022,17 +1080,20 @@ export function chatRoutes(db, storage, backgroundRuntime = createChatBackground
|
|
|
1022
1080
|
};
|
|
1023
1081
|
const leaseTimer = backgroundRuntime.setInterval(() => {
|
|
1024
1082
|
return renewLease().catch((error) => {
|
|
1083
|
+
if (deliveryAcknowledged || deliveryAcknowledging)
|
|
1084
|
+
return;
|
|
1025
1085
|
leaseLost = true;
|
|
1026
1086
|
abortController.abort(error);
|
|
1027
1087
|
});
|
|
1028
1088
|
}, Math.floor(queueLeaseMs / 3));
|
|
1029
1089
|
let terminalStatus = "failed";
|
|
1030
1090
|
let terminalReason = null;
|
|
1031
|
-
let completionRecorded = false;
|
|
1032
1091
|
let assistantConversation = conversation;
|
|
1033
1092
|
let activeChatRunId = null;
|
|
1034
1093
|
const transcript = [];
|
|
1035
1094
|
let partialBody = "";
|
|
1095
|
+
let assistantProjectionMessageId = null;
|
|
1096
|
+
let activeAttemptEpoch = Math.max(1, getActiveChatGeneration(conversation.id)?.attemptEpoch ?? 1);
|
|
1036
1097
|
try {
|
|
1037
1098
|
const userMessage = await svc.getMessage(conversation.id, claim.userMessageId);
|
|
1038
1099
|
if (!userMessage)
|
|
@@ -1040,6 +1101,17 @@ export function chatRoutes(db, storage, backgroundRuntime = createChatBackground
|
|
|
1040
1101
|
const turnContext = turnContextFromUserMessage(userMessage);
|
|
1041
1102
|
const assistantInput = await loadAssistantInput(conversation, actor);
|
|
1042
1103
|
assistantConversation = assistantInput.conversation;
|
|
1104
|
+
const persistStoppedQueuedMessage = async (replyingAgentId) => {
|
|
1105
|
+
const frozen = await svc.generationProtocol.getFrozenVisibleProjection({
|
|
1106
|
+
orgId: conversation.orgId,
|
|
1107
|
+
conversationId: conversation.id,
|
|
1108
|
+
generationId: claim.generationId,
|
|
1109
|
+
}).catch(() => null);
|
|
1110
|
+
const frozenAtCutoff = frozen && frozen.generation.acceptedThroughSeq !== null
|
|
1111
|
+
? frozen
|
|
1112
|
+
: null;
|
|
1113
|
+
return persistPartialAssistantMessage(assistantConversation, frozenAtCutoff?.projection.body ?? partialBody, "stopped", turnContext, frozenAtCutoff?.projection.transcript ?? transcript, replyingAgentId, assistantProjectionMessageId, activeChatRunId, undefined, false);
|
|
1114
|
+
};
|
|
1043
1115
|
const streamed = await assistantSvc.streamChatAssistantReply({
|
|
1044
1116
|
...assistantInput,
|
|
1045
1117
|
userMessageId: userMessage.id,
|
|
@@ -1049,6 +1121,7 @@ export function chatRoutes(db, storage, backgroundRuntime = createChatBackground
|
|
|
1049
1121
|
abortSignal: abortController.signal,
|
|
1050
1122
|
controlCoordinator: createChatRuntimeControlCoordinator(conversation.id, claim.generationId, {
|
|
1051
1123
|
onAttemptStarted: async ({ generationId, attemptEpoch, ownerToken, attempt }) => {
|
|
1124
|
+
activeAttemptEpoch = attemptEpoch;
|
|
1052
1125
|
await svc.beginGenerationControlAttempt({
|
|
1053
1126
|
orgId: conversation.orgId,
|
|
1054
1127
|
conversationId: conversation.id,
|
|
@@ -1067,6 +1140,25 @@ export function chatRoutes(db, storage, backgroundRuntime = createChatBackground
|
|
|
1067
1140
|
providerThreadId: handle.providerThreadId ?? null,
|
|
1068
1141
|
providerTurnId: handle.providerTurnId ?? null,
|
|
1069
1142
|
});
|
|
1143
|
+
if (!deliveryAcknowledged) {
|
|
1144
|
+
deliveryAcknowledging = true;
|
|
1145
|
+
try {
|
|
1146
|
+
const acknowledged = await svc.acknowledgeServerQueuedMessageDelivery({
|
|
1147
|
+
itemId: claim.item.id,
|
|
1148
|
+
generationId: claim.generationId,
|
|
1149
|
+
leaseToken: claim.leaseToken,
|
|
1150
|
+
leaseEpoch: claim.leaseEpoch,
|
|
1151
|
+
});
|
|
1152
|
+
if (!acknowledged) {
|
|
1153
|
+
throw new Error("Queued chat continuation delivery acknowledgement was not recorded");
|
|
1154
|
+
}
|
|
1155
|
+
deliveryAcknowledged = true;
|
|
1156
|
+
backgroundRuntime.clearTimer(leaseTimer);
|
|
1157
|
+
}
|
|
1158
|
+
finally {
|
|
1159
|
+
deliveryAcknowledging = false;
|
|
1160
|
+
}
|
|
1161
|
+
}
|
|
1070
1162
|
},
|
|
1071
1163
|
onAttemptLeaseRenewed: async ({ generationId, attemptEpoch, ownerToken }) => {
|
|
1072
1164
|
await svc.renewGenerationControlLease({ generationId, attemptEpoch, ownerToken });
|
|
@@ -1087,15 +1179,38 @@ export function chatRoutes(db, storage, backgroundRuntime = createChatBackground
|
|
|
1087
1179
|
partialBody = `${partialBody}${delta}`;
|
|
1088
1180
|
},
|
|
1089
1181
|
onTranscriptEntry: async (entry) => {
|
|
1090
|
-
if (
|
|
1091
|
-
|
|
1182
|
+
if (abortController.signal.aborted)
|
|
1183
|
+
return;
|
|
1184
|
+
transcript.push(entry);
|
|
1185
|
+
try {
|
|
1186
|
+
const projection = await svc.generationProtocol.appendVisibleEventAndProject({
|
|
1187
|
+
orgId: conversation.orgId,
|
|
1188
|
+
conversationId: conversation.id,
|
|
1189
|
+
generationId: claim.generationId,
|
|
1190
|
+
expectedAttemptEpoch: activeAttemptEpoch,
|
|
1191
|
+
eventKind: "transcript",
|
|
1192
|
+
payload: { entry },
|
|
1193
|
+
messageId: assistantProjectionMessageId,
|
|
1194
|
+
runId: activeChatRunId,
|
|
1195
|
+
bodyHash: hashChatGenerationBody(partialBody),
|
|
1196
|
+
body: partialBody,
|
|
1197
|
+
chatTurnId: turnContext.chatTurnId,
|
|
1198
|
+
turnVariant: turnContext.turnVariant,
|
|
1199
|
+
});
|
|
1200
|
+
assistantProjectionMessageId = projection.message.id;
|
|
1201
|
+
}
|
|
1202
|
+
catch (error) {
|
|
1203
|
+
if (chatVisibleOutputAdmissionClosed(error))
|
|
1204
|
+
return;
|
|
1205
|
+
throw error;
|
|
1206
|
+
}
|
|
1092
1207
|
},
|
|
1093
1208
|
});
|
|
1094
1209
|
partialBody = streamed.partialBody || partialBody;
|
|
1095
1210
|
if (abortController.signal.aborted || streamed.outcome === "stopped") {
|
|
1096
1211
|
terminalStatus = "stopped";
|
|
1097
1212
|
terminalReason = "operator_stop";
|
|
1098
|
-
const stoppedMessage = await
|
|
1213
|
+
const stoppedMessage = await persistStoppedQueuedMessage(streamed.replyingAgentId);
|
|
1099
1214
|
const stoppedMessages = stoppedMessage ? [stoppedMessage] : [];
|
|
1100
1215
|
await linkChatRunMessages(assistantConversation, activeChatRunId, stoppedMessages);
|
|
1101
1216
|
if (stoppedMessages.length > 0) {
|
|
@@ -1109,12 +1224,11 @@ export function chatRoutes(db, storage, backgroundRuntime = createChatBackground
|
|
|
1109
1224
|
else {
|
|
1110
1225
|
let completionMessageId = null;
|
|
1111
1226
|
try {
|
|
1112
|
-
const attemptEpoch = Math.max(1, getActiveChatGeneration(conversation.id)?.attemptEpoch ?? 1);
|
|
1113
1227
|
const completion = await svc.generationProtocol.appendVisibleEventAndProject({
|
|
1114
1228
|
orgId: conversation.orgId,
|
|
1115
1229
|
conversationId: conversation.id,
|
|
1116
1230
|
generationId: claim.generationId,
|
|
1117
|
-
expectedAttemptEpoch:
|
|
1231
|
+
expectedAttemptEpoch: activeAttemptEpoch,
|
|
1118
1232
|
eventKind: "runtime_output",
|
|
1119
1233
|
payload: {
|
|
1120
1234
|
resultKind: streamed.reply.kind,
|
|
@@ -1122,10 +1236,10 @@ export function chatRoutes(db, storage, backgroundRuntime = createChatBackground
|
|
|
1122
1236
|
},
|
|
1123
1237
|
bodyOffset: 0,
|
|
1124
1238
|
bodyLength: streamed.reply.body.length,
|
|
1239
|
+
messageId: assistantProjectionMessageId,
|
|
1125
1240
|
runId: activeChatRunId,
|
|
1126
1241
|
bodyHash: hashChatGenerationBody(streamed.reply.body),
|
|
1127
1242
|
body: streamed.reply.body,
|
|
1128
|
-
transcript,
|
|
1129
1243
|
replyingAgentId: streamed.replyingAgentId,
|
|
1130
1244
|
chatTurnId: turnContext.chatTurnId,
|
|
1131
1245
|
turnVariant: turnContext.turnVariant,
|
|
@@ -1137,7 +1251,7 @@ export function chatRoutes(db, storage, backgroundRuntime = createChatBackground
|
|
|
1137
1251
|
throw error;
|
|
1138
1252
|
terminalStatus = "stopped";
|
|
1139
1253
|
terminalReason = "operator_stop";
|
|
1140
|
-
const stoppedMessage = await
|
|
1254
|
+
const stoppedMessage = await persistStoppedQueuedMessage(streamed.replyingAgentId);
|
|
1141
1255
|
const stoppedMessages = stoppedMessage ? [stoppedMessage] : [];
|
|
1142
1256
|
await linkChatRunMessages(assistantConversation, activeChatRunId, stoppedMessages);
|
|
1143
1257
|
if (stoppedMessages.length > 0) {
|
|
@@ -1149,7 +1263,7 @@ export function chatRoutes(db, storage, backgroundRuntime = createChatBackground
|
|
|
1149
1263
|
}
|
|
1150
1264
|
return;
|
|
1151
1265
|
}
|
|
1152
|
-
const createdMessages = await persistAssistantReply(request, assistantConversation, actor, streamed.reply, turnContext, transcript, streamed.replyingAgentId, completionMessageId, activeChatRunId);
|
|
1266
|
+
const createdMessages = await persistAssistantReply(request, assistantConversation, actor, streamed.reply, turnContext, transcript, streamed.replyingAgentId, completionMessageId, activeChatRunId, false);
|
|
1153
1267
|
await linkChatRunMessages(assistantConversation, activeChatRunId, createdMessages);
|
|
1154
1268
|
await logChatMessagesAdded(assistantConversation, createdMessages, {
|
|
1155
1269
|
actorType: "system",
|
|
@@ -1172,7 +1286,7 @@ export function chatRoutes(db, storage, backgroundRuntime = createChatBackground
|
|
|
1172
1286
|
const failureBody = userVisiblePartialBodyFromError(error)
|
|
1173
1287
|
|| recoverableFailureBody(failurePayload)
|
|
1174
1288
|
|| CHAT_ASSISTANT_USER_ERROR_MESSAGE;
|
|
1175
|
-
const failedMessage = await persistPartialAssistantMessage(assistantConversation, failureBody, "failed", null, transcript, chatReplyingAgentId(assistantConversation),
|
|
1289
|
+
const failedMessage = await persistPartialAssistantMessage(assistantConversation, failureBody, "failed", null, transcript, chatReplyingAgentId(assistantConversation), assistantProjectionMessageId, activeChatRunId, failurePayload, false).catch(() => null);
|
|
1176
1290
|
const failedMessages = failedMessage ? [failedMessage] : [];
|
|
1177
1291
|
await linkChatRunMessages(assistantConversation, activeChatRunId, failedMessages).catch(() => undefined);
|
|
1178
1292
|
if (failedMessages.length > 0) {
|
|
@@ -1202,23 +1316,10 @@ export function chatRoutes(db, storage, backgroundRuntime = createChatBackground
|
|
|
1202
1316
|
return null;
|
|
1203
1317
|
})
|
|
1204
1318
|
: null;
|
|
1205
|
-
if (terminalEvidence)
|
|
1319
|
+
if (terminalEvidence)
|
|
1206
1320
|
wakeTerminalProjector();
|
|
1207
|
-
const completed = await svc.completeServerQueuedMessageDelivery({
|
|
1208
|
-
itemId: claim.item.id,
|
|
1209
|
-
generationId: claim.generationId,
|
|
1210
|
-
leaseToken: claim.leaseToken,
|
|
1211
|
-
leaseEpoch: claim.leaseEpoch,
|
|
1212
|
-
status: terminalStatus,
|
|
1213
|
-
reason: terminalReason,
|
|
1214
|
-
}).catch((error) => {
|
|
1215
|
-
logger.warn({ err: error, queuedMessageId: claim.item.id }, "failed to complete queued chat continuation");
|
|
1216
|
-
return null;
|
|
1217
|
-
});
|
|
1218
|
-
completionRecorded = Boolean(completed);
|
|
1219
|
-
}
|
|
1220
1321
|
}
|
|
1221
|
-
if (!
|
|
1322
|
+
if (!deliveryAcknowledged && !leaseLost) {
|
|
1222
1323
|
await svc.releaseServerQueuedMessageClaim({
|
|
1223
1324
|
itemId: claim.item.id,
|
|
1224
1325
|
generationId: claim.generationId,
|
|
@@ -1654,7 +1755,7 @@ export function chatRoutes(db, storage, backgroundRuntime = createChatBackground
|
|
|
1654
1755
|
const active = getActiveChatGeneration(conversation.id);
|
|
1655
1756
|
res.json(await svc.getQueueSnapshot(conversation.id, active?.generationId ?? null));
|
|
1656
1757
|
});
|
|
1657
|
-
router.post("/chats/:id/queue",
|
|
1758
|
+
router.post("/chats/:id/queue", async (req, res) => {
|
|
1658
1759
|
const conversation = await assertConversationAccess(req, req.params.id);
|
|
1659
1760
|
if (!conversation) {
|
|
1660
1761
|
res.status(404).json({ error: "Chat conversation not found" });
|
|
@@ -1662,15 +1763,71 @@ export function chatRoutes(db, storage, backgroundRuntime = createChatBackground
|
|
|
1662
1763
|
}
|
|
1663
1764
|
assertChatLocalMutationAllowed(conversation);
|
|
1664
1765
|
await assertSideChatMutationAllowed(req, conversation);
|
|
1665
|
-
const
|
|
1666
|
-
|
|
1766
|
+
const multipart = isMultipartRequest(req);
|
|
1767
|
+
if (multipart)
|
|
1768
|
+
await runMessageFileUpload(req, res);
|
|
1769
|
+
const files = multipart ? uploadedMessageFiles(req) : [];
|
|
1770
|
+
const fileValidationError = validateUploadedMessageFiles(files);
|
|
1771
|
+
if (fileValidationError) {
|
|
1772
|
+
res.status(400).json({ error: fileValidationError });
|
|
1773
|
+
return;
|
|
1774
|
+
}
|
|
1775
|
+
const requestBody = multipart
|
|
1776
|
+
? parseQueuedMultipartBody(req.body, "create")
|
|
1777
|
+
: req.body;
|
|
1778
|
+
const inlineAnnotationsProvided = Boolean(requestBody
|
|
1779
|
+
&& typeof requestBody === "object"
|
|
1780
|
+
&& "payload" in requestBody
|
|
1781
|
+
&& requestBody.payload
|
|
1782
|
+
&& typeof requestBody.payload === "object"
|
|
1783
|
+
&& Object.hasOwn(requestBody.payload, "inlineAnnotations"));
|
|
1784
|
+
if ((inlineAnnotationsProvided || files.length > 0) && req.actor.type !== "board") {
|
|
1785
|
+
assertBoard(req);
|
|
1786
|
+
}
|
|
1787
|
+
const parsed = createChatQueuedMessageSchema.safeParse(requestBody);
|
|
1788
|
+
if (!parsed.success) {
|
|
1789
|
+
res.status(400).json({
|
|
1790
|
+
error: "Invalid queued message request",
|
|
1791
|
+
details: parsed.error.issues,
|
|
1792
|
+
});
|
|
1793
|
+
return;
|
|
1794
|
+
}
|
|
1795
|
+
const preparedAnnotations = await inlineAnnotations.prepare({
|
|
1667
1796
|
orgId: conversation.orgId,
|
|
1668
1797
|
conversationId: conversation.id,
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
payload: req.body.payload,
|
|
1672
|
-
requestActor,
|
|
1798
|
+
annotations: parsed.data.payload.inlineAnnotations,
|
|
1799
|
+
uploadedFileCount: files.length,
|
|
1673
1800
|
});
|
|
1801
|
+
const storedFiles = await storeQueuedAnnotationFiles(conversation, files);
|
|
1802
|
+
const requestActor = queueRequestActor(req);
|
|
1803
|
+
let result;
|
|
1804
|
+
try {
|
|
1805
|
+
result = await svc.createQueuedMessageWithStagedAttachments({
|
|
1806
|
+
orgId: conversation.orgId,
|
|
1807
|
+
conversationId: conversation.id,
|
|
1808
|
+
clientMutationId: parsed.data.clientMutationId,
|
|
1809
|
+
expectedGenerationId: parsed.data.expectedGenerationId
|
|
1810
|
+
?? getActiveChatGeneration(conversation.id)?.generationId
|
|
1811
|
+
?? null,
|
|
1812
|
+
payload: {
|
|
1813
|
+
...parsed.data.payload,
|
|
1814
|
+
inlineAnnotations: preparedAnnotations.annotations,
|
|
1815
|
+
},
|
|
1816
|
+
requestActor,
|
|
1817
|
+
stagedAttachments: storedFiles.map((attachment) => ({
|
|
1818
|
+
...attachment,
|
|
1819
|
+
createdByAgentId: req.actor.type === "agent" ? (req.actor.agentId ?? null) : null,
|
|
1820
|
+
createdByUserId: req.actor.type === "board" ? (req.actor.userId ?? null) : null,
|
|
1821
|
+
})),
|
|
1822
|
+
attachmentFileIndexesByAnnotationId: preparedAnnotations.attachmentFileIndexesByAnnotationId,
|
|
1823
|
+
});
|
|
1824
|
+
}
|
|
1825
|
+
catch (error) {
|
|
1826
|
+
await cleanupUncommittedQueuedAnnotationFiles(conversation.orgId, parsed.data.clientMutationId, storedFiles);
|
|
1827
|
+
throw error;
|
|
1828
|
+
}
|
|
1829
|
+
await cleanupUncommittedQueuedAnnotationFiles(conversation.orgId, parsed.data.clientMutationId, result.cleanupAttachments);
|
|
1830
|
+
const item = result.item;
|
|
1674
1831
|
const actor = getActorInfo(req);
|
|
1675
1832
|
await logActivity(db, {
|
|
1676
1833
|
orgId: conversation.orgId,
|
|
@@ -1684,6 +1841,10 @@ export function chatRoutes(db, storage, backgroundRuntime = createChatBackground
|
|
|
1684
1841
|
details: {
|
|
1685
1842
|
queuedMessageId: item.id,
|
|
1686
1843
|
position: item.position,
|
|
1844
|
+
annotationCount: item.annotationCount ?? 0,
|
|
1845
|
+
annotationSourceMessageIds: [
|
|
1846
|
+
...new Set((item.payload.inlineAnnotations ?? []).map((annotation) => annotation.sourceMessageId)),
|
|
1847
|
+
],
|
|
1687
1848
|
},
|
|
1688
1849
|
});
|
|
1689
1850
|
wakeServerQueue();
|
|
@@ -1701,8 +1862,11 @@ export function chatRoutes(db, storage, backgroundRuntime = createChatBackground
|
|
|
1701
1862
|
throw conflict("Cannot dequeue the next message while a reply is in progress");
|
|
1702
1863
|
}
|
|
1703
1864
|
const latestGeneration = await svc.getLatestGeneration(conversation.id);
|
|
1704
|
-
if (latestGeneration
|
|
1705
|
-
|
|
1865
|
+
if (latestGeneration
|
|
1866
|
+
&& latestGeneration.status !== "completed"
|
|
1867
|
+
&& !(latestGeneration.status === "stopped"
|
|
1868
|
+
&& latestGeneration.terminalReason === "operator_stop")) {
|
|
1869
|
+
throw conflict("Queue remains parked after a failed or unverified reply");
|
|
1706
1870
|
}
|
|
1707
1871
|
const item = await svc.claimNextQueuedMessage(conversation.id);
|
|
1708
1872
|
if (item) {
|
|
@@ -1739,7 +1903,7 @@ export function chatRoutes(db, storage, backgroundRuntime = createChatBackground
|
|
|
1739
1903
|
});
|
|
1740
1904
|
res.json({ item });
|
|
1741
1905
|
});
|
|
1742
|
-
router.patch("/chats/:id/queue/:itemId",
|
|
1906
|
+
router.patch("/chats/:id/queue/:itemId", async (req, res) => {
|
|
1743
1907
|
const conversation = await assertConversationAccess(req, req.params.id);
|
|
1744
1908
|
if (!conversation) {
|
|
1745
1909
|
res.status(404).json({ error: "Chat conversation not found" });
|
|
@@ -1747,13 +1911,71 @@ export function chatRoutes(db, storage, backgroundRuntime = createChatBackground
|
|
|
1747
1911
|
}
|
|
1748
1912
|
assertChatLocalMutationAllowed(conversation);
|
|
1749
1913
|
await assertSideChatMutationAllowed(req, conversation);
|
|
1750
|
-
const
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1914
|
+
const multipart = isMultipartRequest(req);
|
|
1915
|
+
if (multipart)
|
|
1916
|
+
await runMessageFileUpload(req, res);
|
|
1917
|
+
const files = multipart ? uploadedMessageFiles(req) : [];
|
|
1918
|
+
const fileValidationError = validateUploadedMessageFiles(files);
|
|
1919
|
+
if (fileValidationError) {
|
|
1920
|
+
res.status(400).json({ error: fileValidationError });
|
|
1921
|
+
return;
|
|
1922
|
+
}
|
|
1923
|
+
const requestBody = multipart
|
|
1924
|
+
? parseQueuedMultipartBody(req.body, "update")
|
|
1925
|
+
: req.body;
|
|
1926
|
+
const inlineAnnotationsProvided = Boolean(requestBody
|
|
1927
|
+
&& typeof requestBody === "object"
|
|
1928
|
+
&& "payload" in requestBody
|
|
1929
|
+
&& requestBody.payload
|
|
1930
|
+
&& typeof requestBody.payload === "object"
|
|
1931
|
+
&& Object.hasOwn(requestBody.payload, "inlineAnnotations"));
|
|
1932
|
+
if ((inlineAnnotationsProvided || files.length > 0) && req.actor.type !== "board") {
|
|
1933
|
+
assertBoard(req);
|
|
1934
|
+
}
|
|
1935
|
+
const parsed = updateChatQueuedMessageSchema.safeParse(requestBody);
|
|
1936
|
+
if (!parsed.success) {
|
|
1937
|
+
res.status(400).json({
|
|
1938
|
+
error: "Invalid queued message update",
|
|
1939
|
+
details: parsed.error.issues,
|
|
1940
|
+
});
|
|
1941
|
+
return;
|
|
1942
|
+
}
|
|
1943
|
+
const preparedAnnotations = inlineAnnotationsProvided
|
|
1944
|
+
? await inlineAnnotations.prepare({
|
|
1945
|
+
orgId: conversation.orgId,
|
|
1946
|
+
conversationId: conversation.id,
|
|
1947
|
+
annotations: parsed.data.payload.inlineAnnotations ?? [],
|
|
1948
|
+
uploadedFileCount: files.length,
|
|
1949
|
+
})
|
|
1950
|
+
: null;
|
|
1951
|
+
const storedFiles = await storeQueuedAnnotationFiles(conversation, files);
|
|
1952
|
+
let result;
|
|
1953
|
+
try {
|
|
1954
|
+
result = await svc.updateQueuedMessageWithStagedAttachments({
|
|
1955
|
+
orgId: conversation.orgId,
|
|
1956
|
+
conversationId: conversation.id,
|
|
1957
|
+
itemId: req.params.itemId,
|
|
1958
|
+
version: parsed.data.version,
|
|
1959
|
+
payload: {
|
|
1960
|
+
...parsed.data.payload,
|
|
1961
|
+
...(inlineAnnotationsProvided
|
|
1962
|
+
? { inlineAnnotations: preparedAnnotations?.annotations ?? [] }
|
|
1963
|
+
: {}),
|
|
1964
|
+
},
|
|
1965
|
+
stagedAttachments: storedFiles.map((attachment) => ({
|
|
1966
|
+
...attachment,
|
|
1967
|
+
createdByAgentId: req.actor.type === "agent" ? (req.actor.agentId ?? null) : null,
|
|
1968
|
+
createdByUserId: req.actor.type === "board" ? (req.actor.userId ?? null) : null,
|
|
1969
|
+
})),
|
|
1970
|
+
attachmentFileIndexesByAnnotationId: preparedAnnotations?.attachmentFileIndexesByAnnotationId ?? new Map(),
|
|
1971
|
+
});
|
|
1972
|
+
}
|
|
1973
|
+
catch (error) {
|
|
1974
|
+
await cleanupUncommittedQueuedAnnotationFiles(conversation.orgId, req.params.itemId, storedFiles);
|
|
1975
|
+
throw error;
|
|
1976
|
+
}
|
|
1977
|
+
await cleanupCommittedQueuedAnnotationAssets(conversation.orgId, result.item.id, result.cleanupAttachments);
|
|
1978
|
+
res.json(result.item);
|
|
1757
1979
|
});
|
|
1758
1980
|
router.delete("/chats/:id/queue/:itemId", async (req, res) => {
|
|
1759
1981
|
const conversation = await assertConversationAccess(req, req.params.id);
|
|
@@ -1768,12 +1990,14 @@ export function chatRoutes(db, storage, backgroundRuntime = createChatBackground
|
|
|
1768
1990
|
res.status(400).json({ error: "Invalid queued message cancel request", details: parsed.error.issues });
|
|
1769
1991
|
return;
|
|
1770
1992
|
}
|
|
1771
|
-
const
|
|
1993
|
+
const result = await svc.cancelQueuedMessageWithStagedAttachments({
|
|
1994
|
+
orgId: conversation.orgId,
|
|
1772
1995
|
conversationId: conversation.id,
|
|
1773
1996
|
itemId: req.params.itemId,
|
|
1774
1997
|
version: parsed.data.version ?? null,
|
|
1775
1998
|
});
|
|
1776
|
-
|
|
1999
|
+
await cleanupCommittedQueuedAnnotationAssets(conversation.orgId, result.item.id, result.cleanupAttachments);
|
|
2000
|
+
res.json(result.item);
|
|
1777
2001
|
});
|
|
1778
2002
|
router.post("/chats/:id/queue/:itemId/steer", validate(steerChatQueuedMessageSchema), async (req, res) => {
|
|
1779
2003
|
const conversation = await assertConversationAccess(req, req.params.id);
|
|
@@ -1863,62 +2087,101 @@ export function chatRoutes(db, storage, backgroundRuntime = createChatBackground
|
|
|
1863
2087
|
return;
|
|
1864
2088
|
}
|
|
1865
2089
|
const providerSendState = { denied: null };
|
|
1866
|
-
const
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
2090
|
+
const nativeSteerMessageId = started.item.continuationMessageId
|
|
2091
|
+
?? started.item.sourceMessageId;
|
|
2092
|
+
const nativeSteerMessage = nativeSteerMessageId
|
|
2093
|
+
? await svc.getMessage(conversation.id, nativeSteerMessageId)
|
|
2094
|
+
: null;
|
|
2095
|
+
if ((started.item.payload.inlineAnnotations?.length ?? 0) > 0
|
|
2096
|
+
&& !nativeSteerMessage) {
|
|
2097
|
+
throw conflict("Materialized Steer annotation message could not be loaded");
|
|
2098
|
+
}
|
|
2099
|
+
const nativeSteerRuntimeType = (started.generation?.controlRuntimeType
|
|
2100
|
+
?? getActiveChatGeneration(conversation.id)?.runtimeType
|
|
2101
|
+
?? active?.runtimeType
|
|
2102
|
+
?? null);
|
|
2103
|
+
const preparedSteerAttachments = nativeSteerMessage && nativeSteerRuntimeType
|
|
2104
|
+
? await prepareChatAttachmentReferences({
|
|
2105
|
+
runtimeType: nativeSteerRuntimeType,
|
|
2106
|
+
messages: [nativeSteerMessage],
|
|
2107
|
+
storage,
|
|
2108
|
+
runId: durableControlActionId,
|
|
2109
|
+
})
|
|
2110
|
+
: {
|
|
2111
|
+
references: new Map(),
|
|
2112
|
+
media: [],
|
|
2113
|
+
cleanup: async () => undefined,
|
|
2114
|
+
};
|
|
2115
|
+
const nativeSteerFeedback = nativeSteerMessage
|
|
2116
|
+
? buildChatNativeSteerFeedback({
|
|
2117
|
+
message: nativeSteerMessage,
|
|
2118
|
+
clientMessageId: started.action.providerClientMessageId ?? durableControlActionId,
|
|
2119
|
+
attachmentReferences: preparedSteerAttachments.references,
|
|
2120
|
+
media: preparedSteerAttachments.media,
|
|
2121
|
+
})
|
|
2122
|
+
: {
|
|
1871
2123
|
text: started.item.payload.body,
|
|
1872
2124
|
clientMessageId: started.action.providerClientMessageId ?? durableControlActionId,
|
|
1873
|
-
}
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
return {
|
|
1884
|
-
sendDenied: true,
|
|
1885
|
-
reason: "generation_fence_changed",
|
|
1886
|
-
};
|
|
1887
|
-
}
|
|
1888
|
-
try {
|
|
1889
|
-
await svc.appendGenerationEvent({
|
|
2125
|
+
};
|
|
2126
|
+
let runtimeResult;
|
|
2127
|
+
try {
|
|
2128
|
+
runtimeResult = await steerActiveChatGeneration({
|
|
2129
|
+
conversationId: conversation.id,
|
|
2130
|
+
expectedGenerationId: durableGenerationId,
|
|
2131
|
+
expectedAttemptEpoch: durableAttemptEpoch,
|
|
2132
|
+
feedback: nativeSteerFeedback,
|
|
2133
|
+
claimProviderSend: async () => {
|
|
2134
|
+
const sendClaim = await svc.claimSteerProviderSend({
|
|
1890
2135
|
orgId: conversation.orgId,
|
|
1891
|
-
generationId: durableGenerationId,
|
|
1892
|
-
attemptEpoch: durableAttemptEpoch,
|
|
1893
|
-
eventKind: "steer_requested",
|
|
1894
|
-
payload: { controlActionId: durableControlActionId, queueItemId: started.item.id },
|
|
1895
2136
|
controlActionId: durableControlActionId,
|
|
1896
|
-
queueItemId: started.item.id,
|
|
1897
2137
|
});
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
release: async () => {
|
|
1910
|
-
const released = await svc.releaseSteerProviderSendClaim({
|
|
2138
|
+
if (!sendClaim)
|
|
2139
|
+
return null;
|
|
2140
|
+
if ("sendDenied" in sendClaim) {
|
|
2141
|
+
providerSendState.denied = sendClaim;
|
|
2142
|
+
return {
|
|
2143
|
+
sendDenied: true,
|
|
2144
|
+
reason: "generation_fence_changed",
|
|
2145
|
+
};
|
|
2146
|
+
}
|
|
2147
|
+
try {
|
|
2148
|
+
await svc.appendGenerationEvent({
|
|
1911
2149
|
orgId: conversation.orgId,
|
|
2150
|
+
generationId: durableGenerationId,
|
|
2151
|
+
attemptEpoch: durableAttemptEpoch,
|
|
2152
|
+
eventKind: "steer_requested",
|
|
2153
|
+
payload: { controlActionId: durableControlActionId, queueItemId: started.item.id },
|
|
1912
2154
|
controlActionId: durableControlActionId,
|
|
1913
|
-
|
|
2155
|
+
queueItemId: started.item.id,
|
|
1914
2156
|
});
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
2157
|
+
}
|
|
2158
|
+
catch (error) {
|
|
2159
|
+
await svc.releaseSteerProviderSendClaim({
|
|
2160
|
+
orgId: conversation.orgId,
|
|
2161
|
+
controlActionId: durableControlActionId,
|
|
2162
|
+
reason: "steer_requested_event_failed",
|
|
2163
|
+
}).catch(() => null);
|
|
2164
|
+
throw error;
|
|
2165
|
+
}
|
|
2166
|
+
return {
|
|
2167
|
+
clientMessageId: sendClaim.providerClientMessageId ?? durableControlActionId,
|
|
2168
|
+
release: async () => {
|
|
2169
|
+
const released = await svc.releaseSteerProviderSendClaim({
|
|
2170
|
+
orgId: conversation.orgId,
|
|
2171
|
+
controlActionId: durableControlActionId,
|
|
2172
|
+
reason: "runtime_owner_changed_before_provider_send",
|
|
2173
|
+
});
|
|
2174
|
+
if (!released) {
|
|
2175
|
+
throw new Error("Steer provider send claim could not be safely released before send");
|
|
2176
|
+
}
|
|
2177
|
+
},
|
|
2178
|
+
};
|
|
2179
|
+
},
|
|
2180
|
+
});
|
|
2181
|
+
}
|
|
2182
|
+
finally {
|
|
2183
|
+
await preparedSteerAttachments.cleanup().catch(() => undefined);
|
|
2184
|
+
}
|
|
1922
2185
|
if (runtimeResult.status === "provider_send_in_flight") {
|
|
1923
2186
|
res.json(responseForDurableDisposition(started.item, started.action.localDisposition));
|
|
1924
2187
|
return;
|
|
@@ -2065,7 +2328,14 @@ export function chatRoutes(db, storage, backgroundRuntime = createChatBackground
|
|
|
2065
2328
|
});
|
|
2066
2329
|
});
|
|
2067
2330
|
router.get("/chats/:id/messages", async (req, res) => {
|
|
2068
|
-
const
|
|
2331
|
+
const requestedOrgId = typeof req.query.orgId === "string"
|
|
2332
|
+
? req.query.orgId.trim()
|
|
2333
|
+
: undefined;
|
|
2334
|
+
if (req.query.orgId !== undefined && requestedOrgId === undefined) {
|
|
2335
|
+
res.status(404).json({ error: "Chat conversation not found" });
|
|
2336
|
+
return;
|
|
2337
|
+
}
|
|
2338
|
+
const conversation = await assertConversationAccess(req, req.params.id, requestedOrgId);
|
|
2069
2339
|
if (!conversation) {
|
|
2070
2340
|
res.status(404).json({ error: "Chat conversation not found" });
|
|
2071
2341
|
return;
|
|
@@ -2094,7 +2364,10 @@ export function chatRoutes(db, storage, backgroundRuntime = createChatBackground
|
|
|
2094
2364
|
}
|
|
2095
2365
|
res.json(transcript);
|
|
2096
2366
|
});
|
|
2097
|
-
router.post("/chats/:id/messages",
|
|
2367
|
+
router.post("/chats/:id/messages", (req, res, next) => {
|
|
2368
|
+
res.locals.inlineAnnotationsProvided = Object.hasOwn(req.body ?? {}, "inlineAnnotations");
|
|
2369
|
+
next();
|
|
2370
|
+
}, validate(addChatMessageSchema), async (req, res) => {
|
|
2098
2371
|
const conversation = await assertConversationAccess(req, req.params.id);
|
|
2099
2372
|
if (!conversation) {
|
|
2100
2373
|
res.status(404).json({ error: "Chat conversation not found" });
|
|
@@ -2104,6 +2377,14 @@ export function chatRoutes(db, storage, backgroundRuntime = createChatBackground
|
|
|
2104
2377
|
assertChatLocalMutationAllowed(conversation);
|
|
2105
2378
|
await assertSideChatMutationAllowed(req, conversation);
|
|
2106
2379
|
if (actor.actorType === "agent") {
|
|
2380
|
+
if (!req.body.body.trim()) {
|
|
2381
|
+
res.status(422).json({ error: "Agent-authored chat messages require a nonempty body" });
|
|
2382
|
+
return;
|
|
2383
|
+
}
|
|
2384
|
+
if (res.locals.inlineAnnotationsProvided === true) {
|
|
2385
|
+
res.status(422).json({ error: "Agent-authored chat messages cannot include response annotations" });
|
|
2386
|
+
return;
|
|
2387
|
+
}
|
|
2107
2388
|
if (req.body.editUserMessageId) {
|
|
2108
2389
|
res.status(422).json({ error: "Agent-authored chat messages cannot edit operator messages" });
|
|
2109
2390
|
return;
|
|
@@ -2112,6 +2393,16 @@ export function chatRoutes(db, storage, backgroundRuntime = createChatBackground
|
|
|
2112
2393
|
res.status(201).json({ messages: [message] });
|
|
2113
2394
|
return;
|
|
2114
2395
|
}
|
|
2396
|
+
const inlineAnnotationsProvided = res.locals.inlineAnnotationsProvided === true;
|
|
2397
|
+
const preparedAnnotations = inlineAnnotationsProvided
|
|
2398
|
+
? await inlineAnnotations.prepare({
|
|
2399
|
+
orgId: conversation.orgId,
|
|
2400
|
+
conversationId: conversation.id,
|
|
2401
|
+
annotations: req.body.inlineAnnotations ?? [],
|
|
2402
|
+
uploadedFileCount: 0,
|
|
2403
|
+
editUserMessageId: req.body.editUserMessageId ?? null,
|
|
2404
|
+
})
|
|
2405
|
+
: null;
|
|
2115
2406
|
const assistantAvailability = await assistantSvc.getChatAssistantAvailability(conversation);
|
|
2116
2407
|
if (!assistantAvailability.available) {
|
|
2117
2408
|
res.status(503).json({ error: assistantAvailability.error });
|
|
@@ -2132,6 +2423,9 @@ export function chatRoutes(db, storage, backgroundRuntime = createChatBackground
|
|
|
2132
2423
|
payload: {
|
|
2133
2424
|
body: req.body.body,
|
|
2134
2425
|
attachmentIds: [],
|
|
2426
|
+
...(inlineAnnotationsProvided
|
|
2427
|
+
? { inlineAnnotations: preparedAnnotations?.annotations ?? [] }
|
|
2428
|
+
: {}),
|
|
2135
2429
|
skillRefs: [],
|
|
2136
2430
|
projectId: null,
|
|
2137
2431
|
accessMode: null,
|
|
@@ -2147,7 +2441,10 @@ export function chatRoutes(db, storage, backgroundRuntime = createChatBackground
|
|
|
2147
2441
|
return;
|
|
2148
2442
|
}
|
|
2149
2443
|
try {
|
|
2150
|
-
const userMessage = await addUserMessage(conversation, req.body.body, actor, req.body.editUserMessageId ?? null
|
|
2444
|
+
const userMessage = await addUserMessage(conversation, req.body.body, actor, req.body.editUserMessageId ?? null, {
|
|
2445
|
+
provided: inlineAnnotationsProvided,
|
|
2446
|
+
prepared: preparedAnnotations,
|
|
2447
|
+
});
|
|
2151
2448
|
await touchSideChat(req, conversation);
|
|
2152
2449
|
if (!req.body.editUserMessageId) {
|
|
2153
2450
|
startChatTitleGeneration(conversation, userMessage);
|
|
@@ -2254,6 +2551,11 @@ export function chatRoutes(db, storage, backgroundRuntime = createChatBackground
|
|
|
2254
2551
|
assertContextLinksBelongToCompany,
|
|
2255
2552
|
turnContextFromUserMessage,
|
|
2256
2553
|
addUserMessage,
|
|
2554
|
+
inlineAnnotations,
|
|
2555
|
+
storeUserMessageFiles,
|
|
2556
|
+
cleanupStoredUserMessageFiles,
|
|
2557
|
+
storeQueuedAnnotationFiles,
|
|
2558
|
+
cleanupUncommittedQueuedAnnotationFiles,
|
|
2257
2559
|
startChatTitleGeneration,
|
|
2258
2560
|
attachFilesToUserMessage,
|
|
2259
2561
|
loadAssistantInput,
|