@multiplayer-app/ai-agent-node 0.1.0-beta.8 → 0.1.0-beta.81
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/README.md +2 -2
- package/dist/cjs/config.cjs +88 -37
- package/dist/cjs/config.cjs.map +1 -1
- package/dist/cjs/config.d.ts +62 -23
- package/dist/cjs/config.d.ts.map +1 -1
- package/dist/cjs/helpers/AIHelper.cjs +134 -68
- package/dist/cjs/helpers/AIHelper.cjs.map +1 -1
- package/dist/cjs/helpers/AIHelper.d.ts +24 -16
- package/dist/cjs/helpers/AIHelper.d.ts.map +1 -1
- package/dist/cjs/helpers/AIHelper.test.cjs +22 -15
- package/dist/cjs/helpers/AIHelper.test.cjs.map +1 -1
- package/dist/cjs/helpers/ConfigHelper.cjs +15 -6
- package/dist/cjs/helpers/ConfigHelper.cjs.map +1 -1
- package/dist/cjs/helpers/ConfigHelper.d.ts.map +1 -1
- package/dist/cjs/helpers/FileHelper.cjs +131 -151
- package/dist/cjs/helpers/FileHelper.cjs.map +1 -1
- package/dist/cjs/helpers/FileHelper.d.ts +19 -25
- package/dist/cjs/helpers/FileHelper.d.ts.map +1 -1
- package/dist/cjs/helpers/index.cjs +0 -1
- package/dist/cjs/helpers/index.cjs.map +1 -1
- package/dist/cjs/helpers/index.d.ts +0 -1
- package/dist/cjs/helpers/index.d.ts.map +1 -1
- package/dist/cjs/index.cjs +125 -28
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.d.ts +47 -11
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/libs/index.cjs +0 -1
- package/dist/cjs/libs/index.cjs.map +1 -1
- package/dist/cjs/libs/index.d.ts +0 -1
- package/dist/cjs/libs/index.d.ts.map +1 -1
- package/dist/cjs/libs/s3/index.cjs +3 -39
- package/dist/cjs/libs/s3/index.cjs.map +1 -1
- package/dist/cjs/libs/s3/index.d.ts +1 -2
- package/dist/cjs/libs/s3/index.d.ts.map +1 -1
- package/dist/cjs/libs/s3/s3.lib.cjs +173 -186
- package/dist/cjs/libs/s3/s3.lib.cjs.map +1 -1
- package/dist/cjs/libs/s3/s3.lib.d.ts +29 -22
- package/dist/cjs/libs/s3/s3.lib.d.ts.map +1 -1
- package/dist/cjs/processors/ActivityProcessor.cjs +53 -0
- package/dist/cjs/processors/ActivityProcessor.cjs.map +1 -0
- package/dist/cjs/processors/ActivityProcessor.d.ts +34 -0
- package/dist/cjs/processors/ActivityProcessor.d.ts.map +1 -0
- package/dist/cjs/processors/ActivityProcessor.test.cjs +139 -0
- package/dist/cjs/processors/ActivityProcessor.test.cjs.map +1 -0
- package/dist/cjs/processors/ActivityProcessor.test.d.ts +2 -0
- package/dist/cjs/processors/ActivityProcessor.test.d.ts.map +1 -0
- package/dist/cjs/processors/AgentProcessor.cjs +47 -0
- package/dist/cjs/processors/AgentProcessor.cjs.map +1 -0
- package/dist/cjs/processors/AgentProcessor.d.ts +25 -0
- package/dist/cjs/processors/AgentProcessor.d.ts.map +1 -0
- package/dist/cjs/processors/AgentProcessor.test.cjs +103 -0
- package/dist/cjs/processors/AgentProcessor.test.cjs.map +1 -0
- package/dist/cjs/processors/AgentProcessor.test.d.ts +2 -0
- package/dist/cjs/processors/AgentProcessor.test.d.ts.map +1 -0
- package/dist/cjs/processors/ChatProcessor.cjs +1029 -148
- package/dist/cjs/processors/ChatProcessor.cjs.map +1 -1
- package/dist/cjs/processors/ChatProcessor.d.ts +108 -12
- package/dist/cjs/processors/ChatProcessor.d.ts.map +1 -1
- package/dist/cjs/processors/ChatProcessor.test.cjs +803 -0
- package/dist/cjs/processors/ChatProcessor.test.cjs.map +1 -0
- package/dist/cjs/processors/ChatProcessor.test.d.ts +2 -0
- package/dist/cjs/processors/ChatProcessor.test.d.ts.map +1 -0
- package/dist/cjs/processors/index.cjs +2 -0
- package/dist/cjs/processors/index.cjs.map +1 -1
- package/dist/cjs/processors/index.d.ts +2 -0
- package/dist/cjs/processors/index.d.ts.map +1 -1
- package/dist/cjs/services/AIService.cjs +114 -68
- package/dist/cjs/services/AIService.cjs.map +1 -1
- package/dist/cjs/services/AIService.d.ts +34 -13
- package/dist/cjs/services/AIService.d.ts.map +1 -1
- package/dist/cjs/services/CredentialProvider.cjs +62 -0
- package/dist/cjs/services/CredentialProvider.cjs.map +1 -0
- package/dist/cjs/services/CredentialProvider.d.ts +20 -0
- package/dist/cjs/services/CredentialProvider.d.ts.map +1 -0
- package/dist/cjs/services/CredentialProvider.test.cjs +71 -0
- package/dist/cjs/services/CredentialProvider.test.cjs.map +1 -0
- package/dist/cjs/services/CredentialProvider.test.d.ts +2 -0
- package/dist/cjs/services/CredentialProvider.test.d.ts.map +1 -0
- package/dist/cjs/services/ExecutionContext.cjs +3 -0
- package/dist/cjs/services/ExecutionContext.cjs.map +1 -0
- package/dist/cjs/services/ExecutionContext.d.ts +4 -0
- package/dist/cjs/services/ExecutionContext.d.ts.map +1 -0
- package/dist/cjs/services/InternalEventsHandler.cjs +3 -3
- package/dist/cjs/services/InternalEventsHandler.cjs.map +1 -1
- package/dist/cjs/services/InternalEventsHandler.d.ts +3 -1
- package/dist/cjs/services/InternalEventsHandler.d.ts.map +1 -1
- package/dist/cjs/services/ModelAccessPolicy.cjs +24 -0
- package/dist/cjs/services/ModelAccessPolicy.cjs.map +1 -0
- package/dist/cjs/services/ModelAccessPolicy.d.ts +7 -0
- package/dist/cjs/services/ModelAccessPolicy.d.ts.map +1 -0
- package/dist/cjs/services/ModelFetcher.cjs +2 -8
- package/dist/cjs/services/ModelFetcher.cjs.map +1 -1
- package/dist/cjs/services/ModelFetcher.d.ts +2 -7
- package/dist/cjs/services/ModelFetcher.d.ts.map +1 -1
- package/dist/cjs/services/ProviderClientFactory.cjs +29 -0
- package/dist/cjs/services/ProviderClientFactory.cjs.map +1 -0
- package/dist/cjs/services/ProviderClientFactory.d.ts +9 -0
- package/dist/cjs/services/ProviderClientFactory.d.ts.map +1 -0
- package/dist/cjs/services/RedisService.cjs +20 -16
- package/dist/cjs/services/RedisService.cjs.map +1 -1
- package/dist/cjs/services/RedisService.d.ts +5 -2
- package/dist/cjs/services/RedisService.d.ts.map +1 -1
- package/dist/cjs/services/SocketService.cjs +8 -8
- package/dist/cjs/services/SocketService.cjs.map +1 -1
- package/dist/cjs/services/SocketService.d.ts +9 -6
- package/dist/cjs/services/SocketService.d.ts.map +1 -1
- package/dist/cjs/services/TenantCredentialResolver.cjs +136 -0
- package/dist/cjs/services/TenantCredentialResolver.cjs.map +1 -0
- package/dist/cjs/services/TenantCredentialResolver.d.ts +32 -0
- package/dist/cjs/services/TenantCredentialResolver.d.ts.map +1 -0
- package/dist/cjs/services/TenantCredentialResolver.test.cjs +113 -0
- package/dist/cjs/services/TenantCredentialResolver.test.cjs.map +1 -0
- package/dist/cjs/services/TenantCredentialResolver.test.d.ts +2 -0
- package/dist/cjs/services/TenantCredentialResolver.test.d.ts.map +1 -0
- package/dist/cjs/services/index.cjs +5 -1
- package/dist/cjs/services/index.cjs.map +1 -1
- package/dist/cjs/services/index.d.ts +5 -1
- package/dist/cjs/services/index.d.ts.map +1 -1
- package/dist/cjs/store/AgentStore.cjs +14 -4
- package/dist/cjs/store/AgentStore.cjs.map +1 -1
- package/dist/cjs/store/AgentStore.d.ts +3 -1
- package/dist/cjs/store/AgentStore.d.ts.map +1 -1
- package/dist/cjs/store/ConfigStore.cjs +14 -3
- package/dist/cjs/store/ConfigStore.cjs.map +1 -1
- package/dist/cjs/store/ConfigStore.d.ts +2 -0
- package/dist/cjs/store/ConfigStore.d.ts.map +1 -1
- package/dist/cjs/tools/generateChartTool.d.ts +2 -2
- package/dist/cjs/tools/proposeFormValuesTool.d.ts +2 -2
- package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
- package/dist/cjs/utils/utils.cjs +31 -0
- package/dist/cjs/utils/utils.cjs.map +1 -0
- package/dist/cjs/utils/utils.d.ts +5 -0
- package/dist/cjs/utils/utils.d.ts.map +1 -0
- package/dist/esm/config.d.ts +62 -23
- package/dist/esm/config.d.ts.map +1 -1
- package/dist/esm/config.js +88 -35
- package/dist/esm/config.js.map +1 -1
- package/dist/esm/helpers/AIHelper.d.ts +24 -16
- package/dist/esm/helpers/AIHelper.d.ts.map +1 -1
- package/dist/esm/helpers/AIHelper.js +141 -73
- package/dist/esm/helpers/AIHelper.js.map +1 -1
- package/dist/esm/helpers/AIHelper.test.js +22 -15
- package/dist/esm/helpers/AIHelper.test.js.map +1 -1
- package/dist/esm/helpers/ConfigHelper.d.ts.map +1 -1
- package/dist/esm/helpers/ConfigHelper.js +15 -6
- package/dist/esm/helpers/ConfigHelper.js.map +1 -1
- package/dist/esm/helpers/FileHelper.d.ts +19 -25
- package/dist/esm/helpers/FileHelper.d.ts.map +1 -1
- package/dist/esm/helpers/FileHelper.js +131 -146
- package/dist/esm/helpers/FileHelper.js.map +1 -1
- package/dist/esm/helpers/index.d.ts +0 -1
- package/dist/esm/helpers/index.d.ts.map +1 -1
- package/dist/esm/helpers/index.js +0 -1
- package/dist/esm/helpers/index.js.map +1 -1
- package/dist/esm/index.d.ts +47 -11
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +98 -11
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/libs/index.d.ts +0 -1
- package/dist/esm/libs/index.d.ts.map +1 -1
- package/dist/esm/libs/index.js +0 -1
- package/dist/esm/libs/index.js.map +1 -1
- package/dist/esm/libs/s3/index.d.ts +1 -2
- package/dist/esm/libs/s3/index.d.ts.map +1 -1
- package/dist/esm/libs/s3/index.js +1 -2
- package/dist/esm/libs/s3/index.js.map +1 -1
- package/dist/esm/libs/s3/s3.lib.d.ts +29 -22
- package/dist/esm/libs/s3/s3.lib.d.ts.map +1 -1
- package/dist/esm/libs/s3/s3.lib.js +177 -172
- package/dist/esm/libs/s3/s3.lib.js.map +1 -1
- package/dist/esm/processors/ActivityProcessor.d.ts +34 -0
- package/dist/esm/processors/ActivityProcessor.d.ts.map +1 -0
- package/dist/esm/processors/ActivityProcessor.js +50 -0
- package/dist/esm/processors/ActivityProcessor.js.map +1 -0
- package/dist/esm/processors/ActivityProcessor.test.d.ts +2 -0
- package/dist/esm/processors/ActivityProcessor.test.d.ts.map +1 -0
- package/dist/esm/processors/ActivityProcessor.test.js +137 -0
- package/dist/esm/processors/ActivityProcessor.test.js.map +1 -0
- package/dist/esm/processors/AgentProcessor.d.ts +25 -0
- package/dist/esm/processors/AgentProcessor.d.ts.map +1 -0
- package/dist/esm/processors/AgentProcessor.js +44 -0
- package/dist/esm/processors/AgentProcessor.js.map +1 -0
- package/dist/esm/processors/AgentProcessor.test.d.ts +2 -0
- package/dist/esm/processors/AgentProcessor.test.d.ts.map +1 -0
- package/dist/esm/processors/AgentProcessor.test.js +101 -0
- package/dist/esm/processors/AgentProcessor.test.js.map +1 -0
- package/dist/esm/processors/ChatProcessor.d.ts +108 -12
- package/dist/esm/processors/ChatProcessor.d.ts.map +1 -1
- package/dist/esm/processors/ChatProcessor.js +1038 -150
- package/dist/esm/processors/ChatProcessor.js.map +1 -1
- package/dist/esm/processors/ChatProcessor.test.d.ts +2 -0
- package/dist/esm/processors/ChatProcessor.test.d.ts.map +1 -0
- package/dist/esm/processors/ChatProcessor.test.js +801 -0
- package/dist/esm/processors/ChatProcessor.test.js.map +1 -0
- package/dist/esm/processors/index.d.ts +2 -0
- package/dist/esm/processors/index.d.ts.map +1 -1
- package/dist/esm/processors/index.js +2 -0
- package/dist/esm/processors/index.js.map +1 -1
- package/dist/esm/services/AIService.d.ts +34 -13
- package/dist/esm/services/AIService.d.ts.map +1 -1
- package/dist/esm/services/AIService.js +118 -68
- package/dist/esm/services/AIService.js.map +1 -1
- package/dist/esm/services/CredentialProvider.d.ts +20 -0
- package/dist/esm/services/CredentialProvider.d.ts.map +1 -0
- package/dist/esm/services/CredentialProvider.js +60 -0
- package/dist/esm/services/CredentialProvider.js.map +1 -0
- package/dist/esm/services/CredentialProvider.test.d.ts +2 -0
- package/dist/esm/services/CredentialProvider.test.d.ts.map +1 -0
- package/dist/esm/services/CredentialProvider.test.js +69 -0
- package/dist/esm/services/CredentialProvider.test.js.map +1 -0
- package/dist/esm/services/ExecutionContext.d.ts +4 -0
- package/dist/esm/services/ExecutionContext.d.ts.map +1 -0
- package/dist/esm/services/ExecutionContext.js +2 -0
- package/dist/esm/services/ExecutionContext.js.map +1 -0
- package/dist/esm/services/InternalEventsHandler.d.ts +3 -1
- package/dist/esm/services/InternalEventsHandler.d.ts.map +1 -1
- package/dist/esm/services/InternalEventsHandler.js +4 -3
- package/dist/esm/services/InternalEventsHandler.js.map +1 -1
- package/dist/esm/services/ModelAccessPolicy.d.ts +7 -0
- package/dist/esm/services/ModelAccessPolicy.d.ts.map +1 -0
- package/dist/esm/services/ModelAccessPolicy.js +20 -0
- package/dist/esm/services/ModelAccessPolicy.js.map +1 -0
- package/dist/esm/services/ModelFetcher.d.ts +2 -7
- package/dist/esm/services/ModelFetcher.d.ts.map +1 -1
- package/dist/esm/services/ModelFetcher.js +2 -8
- package/dist/esm/services/ModelFetcher.js.map +1 -1
- package/dist/esm/services/ProviderClientFactory.d.ts +9 -0
- package/dist/esm/services/ProviderClientFactory.d.ts.map +1 -0
- package/dist/esm/services/ProviderClientFactory.js +25 -0
- package/dist/esm/services/ProviderClientFactory.js.map +1 -0
- package/dist/esm/services/RedisService.d.ts +5 -2
- package/dist/esm/services/RedisService.d.ts.map +1 -1
- package/dist/esm/services/RedisService.js +21 -14
- package/dist/esm/services/RedisService.js.map +1 -1
- package/dist/esm/services/SocketService.d.ts +9 -6
- package/dist/esm/services/SocketService.d.ts.map +1 -1
- package/dist/esm/services/SocketService.js +10 -6
- package/dist/esm/services/SocketService.js.map +1 -1
- package/dist/esm/services/TenantCredentialResolver.d.ts +32 -0
- package/dist/esm/services/TenantCredentialResolver.d.ts.map +1 -0
- package/dist/esm/services/TenantCredentialResolver.js +133 -0
- package/dist/esm/services/TenantCredentialResolver.js.map +1 -0
- package/dist/esm/services/TenantCredentialResolver.test.d.ts +2 -0
- package/dist/esm/services/TenantCredentialResolver.test.d.ts.map +1 -0
- package/dist/esm/services/TenantCredentialResolver.test.js +111 -0
- package/dist/esm/services/TenantCredentialResolver.test.js.map +1 -0
- package/dist/esm/services/index.d.ts +5 -1
- package/dist/esm/services/index.d.ts.map +1 -1
- package/dist/esm/services/index.js +5 -1
- package/dist/esm/services/index.js.map +1 -1
- package/dist/esm/store/AgentStore.d.ts +3 -1
- package/dist/esm/store/AgentStore.d.ts.map +1 -1
- package/dist/esm/store/AgentStore.js +15 -2
- package/dist/esm/store/AgentStore.js.map +1 -1
- package/dist/esm/store/ConfigStore.d.ts +2 -0
- package/dist/esm/store/ConfigStore.d.ts.map +1 -1
- package/dist/esm/store/ConfigStore.js +14 -3
- package/dist/esm/store/ConfigStore.js.map +1 -1
- package/dist/esm/tools/generateChartTool.d.ts +2 -2
- package/dist/esm/tools/proposeFormValuesTool.d.ts +2 -2
- package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
- package/dist/esm/utils/utils.d.ts +5 -0
- package/dist/esm/utils/utils.d.ts.map +1 -0
- package/dist/esm/utils/utils.js +26 -0
- package/dist/esm/utils/utils.js.map +1 -0
- package/package.json +7 -8
- package/dist/cjs/helpers/SetupHelper.cjs +0 -37
- package/dist/cjs/helpers/SetupHelper.cjs.map +0 -1
- package/dist/cjs/helpers/SetupHelper.d.ts +0 -5
- package/dist/cjs/helpers/SetupHelper.d.ts.map +0 -1
- package/dist/cjs/libs/kafka/config.cjs +0 -8
- package/dist/cjs/libs/kafka/config.cjs.map +0 -1
- package/dist/cjs/libs/kafka/config.d.ts +0 -5
- package/dist/cjs/libs/kafka/config.d.ts.map +0 -1
- package/dist/cjs/libs/kafka/consumer.cjs +0 -131
- package/dist/cjs/libs/kafka/consumer.cjs.map +0 -1
- package/dist/cjs/libs/kafka/consumer.d.ts +0 -16
- package/dist/cjs/libs/kafka/consumer.d.ts.map +0 -1
- package/dist/cjs/libs/kafka/index.cjs +0 -19
- package/dist/cjs/libs/kafka/index.cjs.map +0 -1
- package/dist/cjs/libs/kafka/index.d.ts +0 -3
- package/dist/cjs/libs/kafka/index.d.ts.map +0 -1
- package/dist/cjs/libs/kafka/kafka.cjs +0 -27
- package/dist/cjs/libs/kafka/kafka.cjs.map +0 -1
- package/dist/cjs/libs/kafka/kafka.d.ts +0 -3
- package/dist/cjs/libs/kafka/kafka.d.ts.map +0 -1
- package/dist/cjs/libs/kafka/producer.cjs +0 -48
- package/dist/cjs/libs/kafka/producer.cjs.map +0 -1
- package/dist/cjs/libs/kafka/producer.d.ts +0 -11
- package/dist/cjs/libs/kafka/producer.d.ts.map +0 -1
- package/dist/cjs/libs/logger/config.cjs +0 -8
- package/dist/cjs/libs/logger/config.cjs.map +0 -1
- package/dist/cjs/libs/logger/config.d.ts +0 -5
- package/dist/cjs/libs/logger/config.d.ts.map +0 -1
- package/dist/cjs/libs/s3/config.cjs +0 -10
- package/dist/cjs/libs/s3/config.cjs.map +0 -1
- package/dist/cjs/libs/s3/config.d.ts +0 -7
- package/dist/cjs/libs/s3/config.d.ts.map +0 -1
- package/dist/cjs/services/KafkaService.cjs +0 -122
- package/dist/cjs/services/KafkaService.cjs.map +0 -1
- package/dist/cjs/services/KafkaService.d.ts +0 -35
- package/dist/cjs/services/KafkaService.d.ts.map +0 -1
- package/dist/esm/helpers/SetupHelper.d.ts +0 -5
- package/dist/esm/helpers/SetupHelper.d.ts.map +0 -1
- package/dist/esm/helpers/SetupHelper.js +0 -32
- package/dist/esm/helpers/SetupHelper.js.map +0 -1
- package/dist/esm/libs/kafka/config.d.ts +0 -5
- package/dist/esm/libs/kafka/config.d.ts.map +0 -1
- package/dist/esm/libs/kafka/config.js +0 -5
- package/dist/esm/libs/kafka/config.js.map +0 -1
- package/dist/esm/libs/kafka/consumer.d.ts +0 -16
- package/dist/esm/libs/kafka/consumer.d.ts.map +0 -1
- package/dist/esm/libs/kafka/consumer.js +0 -125
- package/dist/esm/libs/kafka/consumer.js.map +0 -1
- package/dist/esm/libs/kafka/index.d.ts +0 -3
- package/dist/esm/libs/kafka/index.d.ts.map +0 -1
- package/dist/esm/libs/kafka/index.js +0 -3
- package/dist/esm/libs/kafka/index.js.map +0 -1
- package/dist/esm/libs/kafka/kafka.d.ts +0 -3
- package/dist/esm/libs/kafka/kafka.d.ts.map +0 -1
- package/dist/esm/libs/kafka/kafka.js +0 -24
- package/dist/esm/libs/kafka/kafka.js.map +0 -1
- package/dist/esm/libs/kafka/producer.d.ts +0 -11
- package/dist/esm/libs/kafka/producer.d.ts.map +0 -1
- package/dist/esm/libs/kafka/producer.js +0 -45
- package/dist/esm/libs/kafka/producer.js.map +0 -1
- package/dist/esm/libs/logger/config.d.ts +0 -5
- package/dist/esm/libs/logger/config.d.ts.map +0 -1
- package/dist/esm/libs/logger/config.js +0 -5
- package/dist/esm/libs/logger/config.js.map +0 -1
- package/dist/esm/libs/s3/config.d.ts +0 -7
- package/dist/esm/libs/s3/config.d.ts.map +0 -1
- package/dist/esm/libs/s3/config.js +0 -7
- package/dist/esm/libs/s3/config.js.map +0 -1
- package/dist/esm/services/KafkaService.d.ts +0 -35
- package/dist/esm/services/KafkaService.d.ts.map +0 -1
- package/dist/esm/services/KafkaService.js +0 -123
- package/dist/esm/services/KafkaService.js.map +0 -1
|
@@ -2,75 +2,361 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ChatProcessor = void 0;
|
|
4
4
|
const ai_agent_types_1 = require("@multiplayer-app/ai-agent-types");
|
|
5
|
-
const
|
|
6
|
-
const services_2 = require("../services/index.cjs");
|
|
7
|
-
const helpers_1 = require("../helpers/index.cjs");
|
|
5
|
+
const zod_1 = require("zod");
|
|
8
6
|
const store_1 = require("../store/index.cjs");
|
|
9
|
-
const
|
|
10
|
-
const config_1 = require("../config.cjs");
|
|
7
|
+
const helpers_1 = require("../helpers/index.cjs");
|
|
11
8
|
const stream_1 = require("stream");
|
|
12
|
-
const util_1 = require("util");
|
|
13
9
|
const logger_1 = require("../libs/logger/index.cjs");
|
|
14
|
-
const
|
|
10
|
+
const ai_agent_types_2 = require("@multiplayer-app/ai-agent-types");
|
|
11
|
+
const utils_1 = require("../utils/utils.cjs");
|
|
15
12
|
class ChatProcessor {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
13
|
+
getChatUserId(chat) {
|
|
14
|
+
return chat.tenants?.userId;
|
|
15
|
+
}
|
|
16
|
+
constructor(params) {
|
|
17
|
+
this.chatRepository = params.chatRepository;
|
|
18
|
+
this.messageRepository = params.messageRepository;
|
|
19
|
+
this.artifactStore = params.artifactStore;
|
|
20
|
+
this.config = params.config;
|
|
21
|
+
this.socketService = params.socketService;
|
|
22
|
+
this.agentStore = params.agentStore;
|
|
23
|
+
this.activityRepository = params.activityRepository;
|
|
24
|
+
this.agentConfigRepository = params.agentConfigRepository;
|
|
25
|
+
const fileHelper = new helpers_1.FileHelper(params.s3Lib, this.config);
|
|
26
|
+
this.aiHelper = new helpers_1.AIHelper(fileHelper, this.config, params.tenantCredentialResolver);
|
|
27
|
+
this.debug = this.config.debug;
|
|
20
28
|
}
|
|
21
29
|
getTemporaryTitle(contextKey) {
|
|
22
30
|
return `${contextKey} session ${new Date().toISOString()}`;
|
|
23
31
|
}
|
|
32
|
+
isTemporaryTitle(title) {
|
|
33
|
+
// Matches pattern: "{contextKey} session {ISO_DATE_STRING}"
|
|
34
|
+
// Example: "default session 2026-01-23T10:30:45.123Z"
|
|
35
|
+
// toISOString() always includes milliseconds, so we require them
|
|
36
|
+
const pattern = /^.+ session \d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/;
|
|
37
|
+
return pattern.test(title);
|
|
38
|
+
}
|
|
39
|
+
isPlainObject(value) {
|
|
40
|
+
return !!value && typeof value === 'object' && !Array.isArray(value);
|
|
41
|
+
}
|
|
42
|
+
getExecutionTenants(payload) {
|
|
43
|
+
const contextTenants = payload.executionContext?.tenants;
|
|
44
|
+
if (contextTenants && Object.keys(contextTenants).length > 0) {
|
|
45
|
+
return contextTenants;
|
|
46
|
+
}
|
|
47
|
+
return payload.tenants ?? {};
|
|
48
|
+
}
|
|
49
|
+
getParticipantIds(chat) {
|
|
50
|
+
const primary = chat.userId ?? this.getChatUserId(chat);
|
|
51
|
+
return Array.from(new Set([primary, ...(chat.participantIds ?? [])].filter(Boolean)));
|
|
52
|
+
}
|
|
53
|
+
hasChatAccess(chat, userId) {
|
|
54
|
+
if (!userId)
|
|
55
|
+
return true;
|
|
56
|
+
return this.getParticipantIds(chat).includes(userId);
|
|
57
|
+
}
|
|
58
|
+
emitChatToParticipants(chat, chatToEmit, excludeSocketId) {
|
|
59
|
+
for (const userId of this.getParticipantIds(chatToEmit.participantIds ? chatToEmit : chat)) {
|
|
60
|
+
this.socketService.emitChatUpdate(userId, chatToEmit, excludeSocketId);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
emitMessageToParticipants(chat, message, excludeSocketId) {
|
|
64
|
+
for (const userId of this.getParticipantIds(chat)) {
|
|
65
|
+
this.socketService.emitMessageUpdate(userId, message, excludeSocketId);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
async updateChatAndEmit(chat, update, excludeSocketId) {
|
|
69
|
+
await this.chatRepository.update(chat.id, update);
|
|
70
|
+
const updatedChat = await this.chatRepository.findById(chat.id);
|
|
71
|
+
const chatToEmit = updatedChat ?? { ...chat, ...update };
|
|
72
|
+
this.emitChatToParticipants(chat, chatToEmit, excludeSocketId);
|
|
73
|
+
return chatToEmit;
|
|
74
|
+
}
|
|
75
|
+
async startSubagentProcess(params) {
|
|
76
|
+
const parentUserId = params.parentChat.userId ?? this.getChatUserId(params.parentChat) ?? 'guest';
|
|
77
|
+
const childChat = await this.chatRepository.create({
|
|
78
|
+
title: `${params.subAgentConfig.name} subagent`,
|
|
79
|
+
type: ai_agent_types_1.ChatType.Agent,
|
|
80
|
+
status: ai_agent_types_1.AgentStatus.Streaming,
|
|
81
|
+
sessionKind: ai_agent_types_2.AgentSessionKind.SUBAGENT,
|
|
82
|
+
parentChatId: params.parentChat.id,
|
|
83
|
+
parentMessageId: params.parentMessage.id,
|
|
84
|
+
parentToolCallId: params.parentToolCallId,
|
|
85
|
+
contextKey: params.parentChat.contextKey,
|
|
86
|
+
userId: parentUserId,
|
|
87
|
+
tenants: { ...params.parentChat.tenants },
|
|
88
|
+
model: params.subAgentConfig.defaultModel || params.parentChat.model,
|
|
89
|
+
});
|
|
90
|
+
try {
|
|
91
|
+
const parentToolCall = params.parentMessage.toolCalls?.find((toolCall) => toolCall.id === params.parentToolCallId);
|
|
92
|
+
if (parentToolCall) {
|
|
93
|
+
parentToolCall.input = {
|
|
94
|
+
...(parentToolCall.input ?? {}),
|
|
95
|
+
subagentChatId: childChat.id,
|
|
96
|
+
};
|
|
97
|
+
parentToolCall.subagentChatId = childChat.id;
|
|
98
|
+
const updatedParentMessage = await this.messageRepository.update(params.parentMessage.id, {
|
|
99
|
+
toolCalls: params.parentMessage.toolCalls,
|
|
100
|
+
});
|
|
101
|
+
if (updatedParentMessage) {
|
|
102
|
+
this.emitMessageToParticipants(params.parentChat, updatedParentMessage);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
this.emitChatToParticipants(params.parentChat, childChat);
|
|
106
|
+
const executionTenants = this.getExecutionTenants(params);
|
|
107
|
+
const abortController = this.agentStore.registerSubAgentProcess(childChat.id, params.parentChat.id);
|
|
108
|
+
const userMessage = await this.createMessage(childChat, ai_agent_types_1.MessageRole.User, {
|
|
109
|
+
content: JSON.stringify(params.input),
|
|
110
|
+
agentName: undefined
|
|
111
|
+
});
|
|
112
|
+
await this.agentStore.shareAgentProcessEvent(childChat.id, {
|
|
113
|
+
type: store_1.AgentProcessEventType.Update,
|
|
114
|
+
data: userMessage
|
|
115
|
+
});
|
|
116
|
+
let assistantMessage = await this.createMessage(childChat, ai_agent_types_1.MessageRole.Assistant, {
|
|
117
|
+
content: '',
|
|
118
|
+
agentName: params.subAgentConfig.name
|
|
119
|
+
});
|
|
120
|
+
const parentActivity = await this.activityRepository.create({
|
|
121
|
+
ownerId: parentUserId,
|
|
122
|
+
groupId: params.parentChat.id,
|
|
123
|
+
name: ai_agent_types_1.ActivityOperationName.SUBAGENT,
|
|
124
|
+
tenants: executionTenants,
|
|
125
|
+
sourceId: assistantMessage.id,
|
|
126
|
+
sourceType: 'AgentMessage',
|
|
127
|
+
metadata: {
|
|
128
|
+
modelId: this.aiHelper.getLanguageModelId(childChat.model),
|
|
129
|
+
agentOptions: {
|
|
130
|
+
name: params.subAgentConfig.name,
|
|
131
|
+
modelId: this.aiHelper.getLanguageModelId(params.subAgentConfig.defaultModel),
|
|
132
|
+
temperature: params.subAgentConfig.temperature,
|
|
133
|
+
maxOutputTokens: params.subAgentConfig.maxOutputTokens,
|
|
134
|
+
topP: params.subAgentConfig.topP,
|
|
135
|
+
topK: params.subAgentConfig.topK,
|
|
136
|
+
presencePenalty: params.subAgentConfig.presencePenalty,
|
|
137
|
+
frequencyPenalty: params.subAgentConfig.frequencyPenalty,
|
|
138
|
+
stopSequences: params.subAgentConfig.stopSequences,
|
|
139
|
+
seed: params.subAgentConfig.seed,
|
|
140
|
+
},
|
|
141
|
+
},
|
|
142
|
+
});
|
|
143
|
+
const updatedAssistantMessage = await this.messageRepository.update(assistantMessage.id, {
|
|
144
|
+
activity: parentActivity.id
|
|
145
|
+
});
|
|
146
|
+
const agentOptions = this.aiHelper.getAgentOptionsFromConfig(params.subAgentConfig, params.context);
|
|
147
|
+
agentOptions.onStepFinish = (stepResult) => {
|
|
148
|
+
return this.storeStepActivity({
|
|
149
|
+
chat: params.parentChat,
|
|
150
|
+
parentId: assistantMessage.activity,
|
|
151
|
+
stepResult,
|
|
152
|
+
name: ai_agent_types_1.ActivityOperationName.STEP_FINISHED,
|
|
153
|
+
sourceId: assistantMessage.id,
|
|
154
|
+
sourceType: 'AgentMessage',
|
|
155
|
+
tenants: executionTenants,
|
|
156
|
+
});
|
|
157
|
+
};
|
|
158
|
+
const userPreferences = await this.agentConfigRepository.findByUserIdAndAgentName(parentUserId, agentOptions.name);
|
|
159
|
+
agentOptions.activeTools = this.getAvailableTools(agentOptions, userPreferences);
|
|
160
|
+
await this.streamMessageStep({
|
|
161
|
+
chat: childChat,
|
|
162
|
+
existingMessages: [userMessage, updatedAssistantMessage],
|
|
163
|
+
assistantMessage: updatedAssistantMessage,
|
|
164
|
+
agentOptions,
|
|
165
|
+
signal: abortController.signal,
|
|
166
|
+
tenants: executionTenants,
|
|
167
|
+
executionContext: params.executionContext,
|
|
168
|
+
context: params.context,
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
catch (error) {
|
|
172
|
+
await this.storeSubagentResponse({
|
|
173
|
+
subagentChat: childChat,
|
|
174
|
+
content: undefined,
|
|
175
|
+
error: error,
|
|
176
|
+
context: params.context,
|
|
177
|
+
executionContext: params.executionContext,
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
mergeMissingUsageFields(target, source) {
|
|
182
|
+
for (const [key, sourceValue] of Object.entries(source)) {
|
|
183
|
+
const targetValue = target[key];
|
|
184
|
+
if (targetValue === undefined) {
|
|
185
|
+
target[key] = sourceValue;
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
if (this.isPlainObject(targetValue) && this.isPlainObject(sourceValue)) {
|
|
189
|
+
this.mergeMissingUsageFields(targetValue, sourceValue);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
extractCostUsageFields(source) {
|
|
194
|
+
const extracted = {};
|
|
195
|
+
for (const [key, value] of Object.entries(source)) {
|
|
196
|
+
const normalizedKey = key.toLowerCase();
|
|
197
|
+
if (normalizedKey.includes('cost')) {
|
|
198
|
+
extracted[key] = value;
|
|
199
|
+
continue;
|
|
200
|
+
}
|
|
201
|
+
if (this.isPlainObject(value)) {
|
|
202
|
+
const nestedCostFields = this.extractCostUsageFields(value);
|
|
203
|
+
if (Object.keys(nestedCostFields).length > 0) {
|
|
204
|
+
extracted[key] = nestedCostFields;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
return extracted;
|
|
209
|
+
}
|
|
210
|
+
mergeUsageWithProviderMetadata(stepUsage, providerMetadata) {
|
|
211
|
+
const mergedUsage = this.isPlainObject(stepUsage) ? { ...stepUsage } : {};
|
|
212
|
+
let hasProviderUsage = false;
|
|
213
|
+
if (this.isPlainObject(providerMetadata)) {
|
|
214
|
+
for (const providerEntry of Object.values(providerMetadata)) {
|
|
215
|
+
if (!this.isPlainObject(providerEntry) || !this.isPlainObject(providerEntry.usage)) {
|
|
216
|
+
continue;
|
|
217
|
+
}
|
|
218
|
+
const providerCostUsage = this.extractCostUsageFields(providerEntry.usage);
|
|
219
|
+
if (Object.keys(providerCostUsage).length === 0) {
|
|
220
|
+
continue;
|
|
221
|
+
}
|
|
222
|
+
hasProviderUsage = true;
|
|
223
|
+
this.mergeMissingUsageFields(mergedUsage, providerCostUsage);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
if (this.isPlainObject(stepUsage)) {
|
|
227
|
+
return mergedUsage;
|
|
228
|
+
}
|
|
229
|
+
if (hasProviderUsage) {
|
|
230
|
+
return mergedUsage;
|
|
231
|
+
}
|
|
232
|
+
return stepUsage;
|
|
233
|
+
}
|
|
234
|
+
async validateToolCallInput(params) {
|
|
235
|
+
const agentOptions = await this.aiHelper.getAgentOptions({
|
|
236
|
+
agentName: params.agentName,
|
|
237
|
+
});
|
|
238
|
+
const tool = agentOptions.tools?.[params.toolName] ?? undefined;
|
|
239
|
+
const schema = tool?.inputSchema;
|
|
240
|
+
if (!schema) {
|
|
241
|
+
throw new Error(`Tool "${params.toolName}" schema not found`);
|
|
242
|
+
}
|
|
243
|
+
if (!(schema instanceof zod_1.z.ZodType)) {
|
|
244
|
+
throw new Error(`Tool "${params.toolName}" inputSchema must be a Zod schema`);
|
|
245
|
+
}
|
|
246
|
+
const result = schema.safeParse(params.input);
|
|
247
|
+
if (!result.success) {
|
|
248
|
+
throw new Error(`Invalid tool input for "${params.toolName}": ${result.error.message}`);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
24
251
|
async listChats(params) {
|
|
25
|
-
// Build filter object from params
|
|
26
|
-
|
|
252
|
+
// Build filter object from params. Always exclude subagent chats:
|
|
253
|
+
// the repository translates ROOT into `sessionKind !== SUBAGENT`, which
|
|
254
|
+
// also includes legacy chats where the field is unset.
|
|
255
|
+
const filter = {
|
|
256
|
+
sessionKind: ai_agent_types_2.AgentSessionKind.ROOT
|
|
257
|
+
};
|
|
27
258
|
if (params?.userId) {
|
|
259
|
+
// Chats visible to this user: owner, tenant owner, or participant (multi-user).
|
|
28
260
|
filter.userId = params.userId;
|
|
29
261
|
}
|
|
30
262
|
if (params?.contextKey) {
|
|
31
263
|
filter.contextKey = params.contextKey;
|
|
32
264
|
}
|
|
33
|
-
|
|
265
|
+
if (params?.multiUser !== undefined) {
|
|
266
|
+
filter.multiUser = params.multiUser;
|
|
267
|
+
}
|
|
268
|
+
// Build query options for sort and limit with defaults.
|
|
34
269
|
const options = {
|
|
35
270
|
sort: {
|
|
36
271
|
field: params?.sortField ?? 'updatedAt',
|
|
37
272
|
order: params?.sortOrder ?? ai_agent_types_1.SortOrder.Desc
|
|
38
273
|
},
|
|
274
|
+
skip: params?.skip,
|
|
39
275
|
limit: params?.limit
|
|
40
276
|
};
|
|
41
|
-
|
|
42
|
-
|
|
277
|
+
const [total, data] = await Promise.all([
|
|
278
|
+
this.chatRepository.count(filter),
|
|
279
|
+
this.chatRepository.find(filter, options)
|
|
280
|
+
]);
|
|
281
|
+
return {
|
|
282
|
+
cursor: {
|
|
283
|
+
...(params?.skip != null ? { skip: params.skip } : {}),
|
|
284
|
+
...(params?.limit != null ? { limit: params.limit } : {}),
|
|
285
|
+
total
|
|
286
|
+
},
|
|
287
|
+
data
|
|
288
|
+
};
|
|
43
289
|
}
|
|
44
290
|
async getChat(chatId) {
|
|
45
291
|
const chat = await this.chatRepository.findById(chatId);
|
|
46
292
|
if (!chat) {
|
|
47
293
|
throw new Error('Chat not found');
|
|
48
294
|
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
295
|
+
return chat;
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* Get messages for a chat with optional cursor pagination.
|
|
299
|
+
* When limit is omitted, returns all messages (backward compatible).
|
|
300
|
+
* Messages are returned in chronological order (oldest → newest).
|
|
301
|
+
*/
|
|
302
|
+
async getMessages(chatId, options) {
|
|
303
|
+
const chat = await this.chatRepository.findById(chatId);
|
|
304
|
+
if (!chat) {
|
|
305
|
+
throw new Error('Chat not found');
|
|
306
|
+
}
|
|
307
|
+
return this.messageRepository.findByChatIdPaginated(chatId, options);
|
|
54
308
|
}
|
|
55
309
|
async deleteChat(chatId) {
|
|
310
|
+
// Collect all subagent descendants BEFORE removing the parent, otherwise the
|
|
311
|
+
// `parentChatId` link is severed and we'd orphan the subtree. Subagents can
|
|
312
|
+
// themselves spawn subagents, so traversal must be recursive.
|
|
313
|
+
const descendantIds = await this.collectDescendantChatIds(chatId);
|
|
56
314
|
const deleted = await this.chatRepository.delete(chatId);
|
|
57
315
|
if (!deleted) {
|
|
58
316
|
throw new Error('Chat not found');
|
|
59
317
|
}
|
|
60
|
-
|
|
318
|
+
// Delete descendant chat rows in parallel. Use `Promise.allSettled` so a
|
|
319
|
+
// missing/already-deleted descendant doesn't abort cleanup of the rest.
|
|
320
|
+
if (descendantIds.length > 0) {
|
|
321
|
+
await Promise.allSettled(descendantIds.map(id => this.chatRepository.delete(id)));
|
|
322
|
+
}
|
|
323
|
+
const allIds = [chatId, ...descendantIds];
|
|
324
|
+
await Promise.all([
|
|
325
|
+
...allIds.map(id => this.messageRepository.deleteByChatId(id)),
|
|
326
|
+
...allIds.map(id => this.activityRepository.deleteByGroupId(id)),
|
|
327
|
+
]);
|
|
328
|
+
for (const id of allIds) {
|
|
329
|
+
this.artifactStore.deleteArtifacts(id);
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Walk the subagent tree rooted at `rootChatId` and return every descendant
|
|
334
|
+
* chat id (excluding the root itself). BFS, with parallel fan-out per level
|
|
335
|
+
* so deeply nested trees don't serialize one DB roundtrip per depth.
|
|
336
|
+
*/
|
|
337
|
+
async collectDescendantChatIds(rootChatId) {
|
|
338
|
+
const descendants = [];
|
|
339
|
+
let frontier = [rootChatId];
|
|
340
|
+
while (frontier.length > 0) {
|
|
341
|
+
const childLists = await Promise.all(frontier.map(id => this.chatRepository.find({ parentChatId: id })));
|
|
342
|
+
const nextFrontier = [];
|
|
343
|
+
for (const list of childLists) {
|
|
344
|
+
for (const child of list) {
|
|
345
|
+
descendants.push(child.id);
|
|
346
|
+
nextFrontier.push(child.id);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
frontier = nextFrontier;
|
|
350
|
+
}
|
|
351
|
+
return descendants;
|
|
61
352
|
}
|
|
62
353
|
async upsertAndGetChat(payload, excludeSocketId) {
|
|
63
|
-
const targetUserId = payload.userId ?? 'guest';
|
|
64
354
|
let chat = null;
|
|
65
355
|
if (payload.chatId) {
|
|
66
356
|
chat = await this.chatRepository.findById(payload.chatId);
|
|
67
357
|
if (!chat) {
|
|
68
358
|
throw new Error('Chat not found');
|
|
69
359
|
}
|
|
70
|
-
// Ensure chat is associated with the caller's userId
|
|
71
|
-
if (chat.userId && chat.userId !== targetUserId) {
|
|
72
|
-
throw new Error('Chat does not belong to this user');
|
|
73
|
-
}
|
|
74
360
|
}
|
|
75
361
|
if (!chat) {
|
|
76
362
|
chat = await this.createChat(payload, excludeSocketId);
|
|
@@ -92,7 +378,7 @@ class ChatProcessor {
|
|
|
92
378
|
if (!content) {
|
|
93
379
|
return this.getTemporaryTitle(payload.contextKey);
|
|
94
380
|
}
|
|
95
|
-
return
|
|
381
|
+
return this.aiHelper.generateTitleForMessage(payload.contextKey, [{
|
|
96
382
|
role: ai_agent_types_1.MessageRole.User,
|
|
97
383
|
content: content
|
|
98
384
|
}]);
|
|
@@ -103,34 +389,38 @@ class ChatProcessor {
|
|
|
103
389
|
role,
|
|
104
390
|
content: messageData.content,
|
|
105
391
|
agentName: messageData.agentName,
|
|
392
|
+
sender: messageData.sender,
|
|
393
|
+
mentions: messageData.mentions ?? [],
|
|
394
|
+
annotations: messageData.annotations,
|
|
106
395
|
attachments: attachments ?? [],
|
|
107
396
|
reasoning: "",
|
|
108
397
|
toolCalls: []
|
|
109
398
|
});
|
|
110
|
-
|
|
111
|
-
services_1.socketService.emitMessageUpdate(chat.userId, message, excludeSocketId);
|
|
112
|
-
}
|
|
399
|
+
this.emitMessageToParticipants(chat, message, excludeSocketId);
|
|
113
400
|
return message;
|
|
114
401
|
}
|
|
115
402
|
async createChat(payload, excludeSocketId) {
|
|
116
|
-
const targetUserId = payload.userId ?? 'guest';
|
|
403
|
+
const targetUserId = payload.userId ?? payload.tenants?.userId ?? 'guest';
|
|
117
404
|
const contextKey = 'contextKey' in payload ? payload.contextKey : 'default';
|
|
118
405
|
const metadata = 'metadata' in payload ? payload.metadata : {};
|
|
406
|
+
const requestedParticipantIds = 'participantIds' in payload && Array.isArray(payload.participantIds) ? payload.participantIds : [];
|
|
407
|
+
const participantIds = Array.from(new Set([targetUserId, ...requestedParticipantIds].filter(Boolean)));
|
|
119
408
|
const chat = await this.chatRepository.create({
|
|
120
409
|
title: this.getTemporaryTitle(contextKey),
|
|
121
410
|
type: ai_agent_types_1.ChatType.Chat,
|
|
122
411
|
status: ai_agent_types_1.AgentStatus.Streaming,
|
|
412
|
+
sessionKind: ai_agent_types_2.AgentSessionKind.ROOT,
|
|
123
413
|
contextKey,
|
|
124
414
|
userId: targetUserId,
|
|
415
|
+
tenants: {
|
|
416
|
+
...(payload.tenants ?? {}),
|
|
417
|
+
userId: targetUserId,
|
|
418
|
+
},
|
|
419
|
+
participantIds,
|
|
125
420
|
metadata,
|
|
126
421
|
...(payload.model ? { model: payload.model } : {})
|
|
127
422
|
});
|
|
128
|
-
|
|
129
|
-
const initialChatResponse = {
|
|
130
|
-
...chat,
|
|
131
|
-
messages: []
|
|
132
|
-
};
|
|
133
|
-
services_1.socketService.emitChatUpdate(targetUserId, initialChatResponse, excludeSocketId);
|
|
423
|
+
this.emitChatToParticipants(chat, chat, excludeSocketId);
|
|
134
424
|
return chat;
|
|
135
425
|
}
|
|
136
426
|
/**
|
|
@@ -185,33 +475,163 @@ class ChatProcessor {
|
|
|
185
475
|
await this.messageRepository.update(message.id, { toolCalls });
|
|
186
476
|
// Bump chat updatedAt so listChats ordering reflects the action.
|
|
187
477
|
await this.chatRepository.update(chat.id, { updatedAt: now });
|
|
188
|
-
|
|
478
|
+
this.emitMessageToParticipants(chat, updatedMessage, params.excludeSocketId);
|
|
189
479
|
if (params.systemMessage) {
|
|
190
480
|
//todo discuss support for system messages
|
|
191
481
|
//await this.createMessage(chat, MessageRole.System, params.systemMessage, undefined, params.excludeSocketId);
|
|
192
482
|
}
|
|
193
483
|
return { ok: true };
|
|
194
484
|
}
|
|
485
|
+
/**
|
|
486
|
+
* Update selected fields (input/output/status) on a specific tool call.
|
|
487
|
+
*/
|
|
488
|
+
async updateToolCall(params) {
|
|
489
|
+
if (params.input === undefined &&
|
|
490
|
+
params.output === undefined &&
|
|
491
|
+
params.status === undefined &&
|
|
492
|
+
params.subagentChatId === undefined) {
|
|
493
|
+
throw new Error('At least one tool call update field must be provided');
|
|
494
|
+
}
|
|
495
|
+
const chat = await this.chatRepository.findById(params.chatId);
|
|
496
|
+
if (!chat) {
|
|
497
|
+
throw new Error('Chat not found');
|
|
498
|
+
}
|
|
499
|
+
if (params.userId && !this.hasChatAccess(chat, params.userId)) {
|
|
500
|
+
throw new Error('Chat does not belong to this user');
|
|
501
|
+
}
|
|
502
|
+
const message = await this.messageRepository.findById(params.messageId);
|
|
503
|
+
if (!message || message.chat !== params.chatId) {
|
|
504
|
+
throw new Error('Message not found or does not belong to this chat');
|
|
505
|
+
}
|
|
506
|
+
const targetToolCall = (message.toolCalls ?? []).find((tc) => tc.id === params.toolCallId);
|
|
507
|
+
if (!targetToolCall) {
|
|
508
|
+
throw new Error('Tool call not found in message');
|
|
509
|
+
}
|
|
510
|
+
if (params.input !== undefined) {
|
|
511
|
+
await this.validateToolCallInput({
|
|
512
|
+
agentName: message.agentName,
|
|
513
|
+
toolName: targetToolCall.name,
|
|
514
|
+
input: params.input,
|
|
515
|
+
});
|
|
516
|
+
}
|
|
517
|
+
const updatedMessage = await this.messageRepository.updateToolCall(params.messageId, params.toolCallId, {
|
|
518
|
+
...(params.input !== undefined ? { input: params.input } : {}),
|
|
519
|
+
...(params.output !== undefined ? { output: params.output } : {}),
|
|
520
|
+
...(params.status !== undefined ? { status: params.status } : {}),
|
|
521
|
+
...(params.subagentChatId !== undefined ? { subagentChatId: params.subagentChatId } : {}),
|
|
522
|
+
});
|
|
523
|
+
if (!updatedMessage) {
|
|
524
|
+
throw new Error('Tool call not found in message');
|
|
525
|
+
}
|
|
526
|
+
const now = new Date().toISOString();
|
|
527
|
+
await this.chatRepository.update(chat.id, { updatedAt: now });
|
|
528
|
+
this.emitMessageToParticipants(chat, updatedMessage, params.excludeSocketId);
|
|
529
|
+
return updatedMessage;
|
|
530
|
+
}
|
|
531
|
+
async storeSubagentResponse(params) {
|
|
532
|
+
const { subagentChat, content, error, context, executionContext } = params;
|
|
533
|
+
if (!subagentChat.parentChatId || !subagentChat.parentMessageId) {
|
|
534
|
+
throw new Error(`Parent chat or message not found for subagent ${subagentChat.id}`);
|
|
535
|
+
}
|
|
536
|
+
const chat = await this.chatRepository.findById(subagentChat.parentChatId);
|
|
537
|
+
if (!chat) {
|
|
538
|
+
throw new Error(`Parent chat not found for subagent ${subagentChat.id}`);
|
|
539
|
+
}
|
|
540
|
+
const assistantMessage = await this.messageRepository.findById(subagentChat.parentMessageId);
|
|
541
|
+
if (!assistantMessage || assistantMessage.chat !== subagentChat.parentChatId) {
|
|
542
|
+
throw new Error(`Assistant message with id ${subagentChat.parentMessageId} not found`);
|
|
543
|
+
}
|
|
544
|
+
const toolCall = assistantMessage.toolCalls?.find(tc => tc.id === subagentChat.parentToolCallId);
|
|
545
|
+
if (!toolCall) {
|
|
546
|
+
throw new Error(`Tool call with id ${subagentChat.parentToolCallId} not found`);
|
|
547
|
+
}
|
|
548
|
+
if (error) {
|
|
549
|
+
toolCall.output = {
|
|
550
|
+
type: 'error',
|
|
551
|
+
message: error,
|
|
552
|
+
};
|
|
553
|
+
toolCall.status = ai_agent_types_1.AgentToolCallStatus.Failed;
|
|
554
|
+
}
|
|
555
|
+
else {
|
|
556
|
+
toolCall.output = content;
|
|
557
|
+
toolCall.status = ai_agent_types_1.AgentToolCallStatus.Succeeded;
|
|
558
|
+
}
|
|
559
|
+
await this.messageRepository.update(assistantMessage.id, assistantMessage);
|
|
560
|
+
const agentOptions = await this.aiHelper.getAgentOptions({
|
|
561
|
+
agentName: assistantMessage.agentName,
|
|
562
|
+
context: context,
|
|
563
|
+
executionContext: executionContext,
|
|
564
|
+
});
|
|
565
|
+
const executionTenants = this.getExecutionTenants(params);
|
|
566
|
+
const abortController = this.agentStore.registerAgentProcess(chat.id);
|
|
567
|
+
const existingMessages = await this.messageRepository.findByChatId(chat.id);
|
|
568
|
+
// Limit context to prevent exceeding token limits
|
|
569
|
+
const limitedMessages = helpers_1.ContextLimiter.limitContext(existingMessages, {
|
|
570
|
+
maxMessages: this.config.ai.maxContextMessages,
|
|
571
|
+
keepFirstUserMessage: true,
|
|
572
|
+
keepSystemMessages: true,
|
|
573
|
+
});
|
|
574
|
+
agentOptions.onStepFinish = (stepResult) => {
|
|
575
|
+
return this.storeStepActivity({
|
|
576
|
+
chat,
|
|
577
|
+
parentId: assistantMessage.activity,
|
|
578
|
+
stepResult,
|
|
579
|
+
name: ai_agent_types_1.ActivityOperationName.STEP_FINISHED,
|
|
580
|
+
sourceId: assistantMessage.id,
|
|
581
|
+
sourceType: 'AgentMessage',
|
|
582
|
+
tenants: executionTenants,
|
|
583
|
+
});
|
|
584
|
+
};
|
|
585
|
+
const userPreferences = await this.agentConfigRepository.findByUserIdAndAgentName(this.getChatUserId(chat) ?? chat.userId ?? 'guest', agentOptions.name);
|
|
586
|
+
agentOptions.activeTools = this.getAvailableTools(agentOptions, userPreferences);
|
|
587
|
+
await this.streamMessageStep({
|
|
588
|
+
chat,
|
|
589
|
+
existingMessages: limitedMessages,
|
|
590
|
+
assistantMessage,
|
|
591
|
+
agentOptions,
|
|
592
|
+
signal: abortController.signal,
|
|
593
|
+
tenants: executionTenants,
|
|
594
|
+
executionContext,
|
|
595
|
+
context,
|
|
596
|
+
});
|
|
597
|
+
}
|
|
195
598
|
async streamMessageStep(params) {
|
|
196
599
|
const { chat, assistantMessage, existingMessages, signal, excludeSocketId, agentOptions } = params;
|
|
600
|
+
const persistAndBroadcastToolCalls = async () => {
|
|
601
|
+
await this.messageRepository.update(assistantMessage.id, { toolCalls: assistantMessage.toolCalls ?? [] });
|
|
602
|
+
this.emitMessageToParticipants(chat, assistantMessage, excludeSocketId);
|
|
603
|
+
await this.agentStore.shareAgentProcessEvent(chat.id, { type: store_1.AgentProcessEventType.Update, data: assistantMessage });
|
|
604
|
+
};
|
|
197
605
|
if (signal.aborted) {
|
|
198
606
|
return;
|
|
199
607
|
}
|
|
200
|
-
const result = await
|
|
608
|
+
const result = await this.aiHelper.streamAssistantResponse(existingMessages, signal, {
|
|
609
|
+
...agentOptions,
|
|
610
|
+
executionContext: params.executionContext,
|
|
611
|
+
});
|
|
201
612
|
try {
|
|
202
613
|
for await (const chunk of result.fullStream) {
|
|
203
614
|
if (chunk.type === 'error') {
|
|
204
|
-
await
|
|
615
|
+
await this.agentStore.shareAgentProcessEvent(chat.id, { type: store_1.AgentProcessEventType.Error, data: chunk.error });
|
|
205
616
|
assistantMessage.content = chunk.error.message || 'Sorry, I cannot process you request due to the error';
|
|
206
617
|
await this.messageRepository.update(assistantMessage.id, assistantMessage);
|
|
207
|
-
await this.
|
|
618
|
+
await this.updateChatAndEmit(chat, { status: ai_agent_types_1.AgentStatus.Error }, excludeSocketId);
|
|
619
|
+
if (chat.sessionKind === ai_agent_types_2.AgentSessionKind.SUBAGENT) {
|
|
620
|
+
await this.storeSubagentResponse({
|
|
621
|
+
subagentChat: chat,
|
|
622
|
+
content: undefined,
|
|
623
|
+
error: chunk.error,
|
|
624
|
+
context: params.context,
|
|
625
|
+
executionContext: params.executionContext,
|
|
626
|
+
});
|
|
627
|
+
}
|
|
208
628
|
continue;
|
|
209
629
|
}
|
|
210
630
|
if (chunk.type === 'abort') {
|
|
211
|
-
await
|
|
212
|
-
await this.
|
|
631
|
+
await this.agentStore.shareAgentProcessEvent(chat.id, { type: store_1.AgentProcessEventType.Aborted, data: undefined });
|
|
632
|
+
await this.updateChatAndEmit(chat, { status: ai_agent_types_1.AgentStatus.Aborted }, excludeSocketId);
|
|
213
633
|
await this.messageRepository.update(assistantMessage.id, assistantMessage);
|
|
214
|
-
|
|
634
|
+
this.emitMessageToParticipants(chat, assistantMessage, excludeSocketId);
|
|
215
635
|
continue;
|
|
216
636
|
}
|
|
217
637
|
if (chunk.type === 'finish') {
|
|
@@ -228,38 +648,76 @@ class ChatProcessor {
|
|
|
228
648
|
((totalUsage.promptTokens ?? 0) + (totalUsage.completionTokens ?? 0));
|
|
229
649
|
}
|
|
230
650
|
await this.messageRepository.update(assistantMessage.id, { ...assistantMessage });
|
|
651
|
+
this.emitMessageToParticipants(chat, assistantMessage, excludeSocketId);
|
|
231
652
|
if (chunk.finishReason === 'stop') {
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
653
|
+
let nextChat = await this.updateChatAndEmit(chat, { status: ai_agent_types_1.AgentStatus.Finished }, excludeSocketId);
|
|
654
|
+
if (chat.title && this.isTemporaryTitle(chat.title)) {
|
|
655
|
+
const title = await this.aiHelper.generateTitleForMessage(chat.contextKey, existingMessages.filter(m => m.role === ai_agent_types_1.MessageRole.User), (stepResult) => {
|
|
656
|
+
return this.storeStepActivity({
|
|
657
|
+
chat,
|
|
658
|
+
stepResult,
|
|
659
|
+
name: ai_agent_types_1.ActivityOperationName.TITLE_GENERATION,
|
|
660
|
+
sourceId: chat.id,
|
|
661
|
+
sourceType: 'Chat',
|
|
662
|
+
tenants: params.tenants || {},
|
|
663
|
+
});
|
|
664
|
+
}, params.executionContext);
|
|
665
|
+
nextChat = await this.updateChatAndEmit(nextChat, { title }, excludeSocketId);
|
|
240
666
|
}
|
|
241
|
-
|
|
242
|
-
await this.
|
|
667
|
+
if (chat.sessionKind === ai_agent_types_2.AgentSessionKind.SUBAGENT) {
|
|
668
|
+
await this.storeSubagentResponse({
|
|
669
|
+
subagentChat: chat,
|
|
670
|
+
content: assistantMessage.content,
|
|
671
|
+
error: undefined,
|
|
672
|
+
context: params.context,
|
|
673
|
+
executionContext: params.executionContext,
|
|
674
|
+
});
|
|
243
675
|
}
|
|
244
|
-
await store_1.agentStore.shareAgentProcessEvent(chat.id, { type: store_1.AgentProcessEventType.Finished, data: assistantMessage });
|
|
245
|
-
continue;
|
|
246
676
|
}
|
|
247
677
|
if (chunk.finishReason === 'tool-calls') {
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
await
|
|
678
|
+
const toolCall = assistantMessage.toolCalls?.find(toolCall => toolCall.output === undefined && toolCall.status === ai_agent_types_1.AgentToolCallStatus.Running);
|
|
679
|
+
if (!toolCall) {
|
|
680
|
+
await this.agentStore.shareAgentProcessEvent(chat.id, { type: store_1.AgentProcessEventType.Finished, data: assistantMessage });
|
|
681
|
+
await this.storeSubagentResponse({
|
|
682
|
+
subagentChat: chat,
|
|
683
|
+
content: JSON.stringify(assistantMessage.toolCalls),
|
|
684
|
+
error: undefined,
|
|
685
|
+
context: params.context,
|
|
686
|
+
executionContext: params.executionContext,
|
|
687
|
+
});
|
|
688
|
+
continue;
|
|
689
|
+
}
|
|
690
|
+
const toolConfig = store_1.ConfigStore.getInstance().getToolConfig(assistantMessage.agentName || '', toolCall.name);
|
|
691
|
+
if (toolCall.requiresConfirmation && toolCall.approvalId) {
|
|
692
|
+
await this.updateChatAndEmit(chat, { status: ai_agent_types_1.AgentStatus.WaitingForUserAction }, excludeSocketId);
|
|
693
|
+
await this.agentStore.shareAgentProcessEvent(chat.id, { type: store_1.AgentProcessEventType.Finished, data: assistantMessage });
|
|
251
694
|
}
|
|
252
|
-
else {
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
695
|
+
else if (toolConfig && toolConfig.type === ai_agent_types_1.AgentToolType.SUBAGENT) {
|
|
696
|
+
void this.startSubagentProcess({
|
|
697
|
+
parentChat: chat,
|
|
698
|
+
parentMessage: assistantMessage,
|
|
699
|
+
parentToolCallId: toolCall.id,
|
|
700
|
+
toolName: toolCall.name,
|
|
701
|
+
input: toolCall.input,
|
|
702
|
+
subAgentConfig: toolConfig.data.subAgent,
|
|
703
|
+
context: params.context,
|
|
704
|
+
executionContext: params.executionContext,
|
|
705
|
+
}).catch(error => {
|
|
706
|
+
logger_1.logger.error(error);
|
|
707
|
+
//todo: store error in response
|
|
256
708
|
});
|
|
257
|
-
await this.streamMessageStep(params);
|
|
258
709
|
}
|
|
259
|
-
continue;
|
|
260
710
|
}
|
|
261
711
|
//todo: Handle other finish reasons // length, content, error, other, undefined
|
|
262
|
-
await
|
|
712
|
+
await this.agentStore.shareAgentProcessEvent(chat.id, { type: store_1.AgentProcessEventType.Finished, data: assistantMessage });
|
|
713
|
+
if (assistantMessage.activity) {
|
|
714
|
+
const groupedMeta = await this.activityRepository.getGroupedMetadataByParentId(assistantMessage.activity);
|
|
715
|
+
await this.activityRepository.updateMetadata(assistantMessage.activity, {
|
|
716
|
+
usage: groupedMeta,
|
|
717
|
+
finishReason: chunk.finishReason,
|
|
718
|
+
responseTimestamp: new Date().toISOString(),
|
|
719
|
+
});
|
|
720
|
+
}
|
|
263
721
|
continue;
|
|
264
722
|
}
|
|
265
723
|
if (chunk.type === 'text-delta') {
|
|
@@ -268,55 +726,85 @@ class ChatProcessor {
|
|
|
268
726
|
...assistantMessage,
|
|
269
727
|
content: assistantMessage.content
|
|
270
728
|
};
|
|
271
|
-
|
|
272
|
-
await
|
|
729
|
+
this.emitMessageToParticipants(chat, updatedMessage, excludeSocketId);
|
|
730
|
+
await this.agentStore.shareAgentProcessEvent(chat.id, { type: store_1.AgentProcessEventType.Update, data: updatedMessage });
|
|
273
731
|
await this.messageRepository.update(assistantMessage.id, { content: assistantMessage.content });
|
|
274
732
|
continue;
|
|
275
733
|
}
|
|
276
734
|
if (chunk.type === 'tool-input-start') {
|
|
277
735
|
if (!assistantMessage.toolCalls)
|
|
278
736
|
assistantMessage.toolCalls = [];
|
|
279
|
-
assistantMessage.toolCalls.
|
|
280
|
-
|
|
281
|
-
name
|
|
282
|
-
status
|
|
283
|
-
|
|
284
|
-
|
|
737
|
+
const existingToolCall = assistantMessage.toolCalls.find((toolCall) => toolCall.id === chunk.id);
|
|
738
|
+
if (existingToolCall) {
|
|
739
|
+
existingToolCall.name = chunk.toolName;
|
|
740
|
+
if (!existingToolCall.status) {
|
|
741
|
+
existingToolCall.status = ai_agent_types_1.AgentToolCallStatus.Pending;
|
|
742
|
+
}
|
|
743
|
+
existingToolCall.input = existingToolCall.input ?? {};
|
|
744
|
+
}
|
|
745
|
+
else {
|
|
746
|
+
assistantMessage.toolCalls.push({
|
|
747
|
+
id: chunk.id,
|
|
748
|
+
name: chunk.toolName,
|
|
749
|
+
status: ai_agent_types_1.AgentToolCallStatus.Pending,
|
|
750
|
+
input: {},
|
|
751
|
+
});
|
|
752
|
+
}
|
|
753
|
+
await persistAndBroadcastToolCalls();
|
|
285
754
|
continue;
|
|
286
755
|
}
|
|
287
|
-
if (chunk.type === 'tool-call') {
|
|
288
|
-
|
|
289
|
-
|
|
756
|
+
if (chunk.type === 'tool-call') {
|
|
757
|
+
if (!assistantMessage.toolCalls)
|
|
758
|
+
assistantMessage.toolCalls = [];
|
|
759
|
+
let toolCall = assistantMessage.toolCalls.find(toolCall => toolCall.id === chunk.toolCallId);
|
|
760
|
+
if (!toolCall) {
|
|
761
|
+
toolCall = {
|
|
762
|
+
id: chunk.toolCallId,
|
|
763
|
+
name: chunk.toolName,
|
|
764
|
+
status: ai_agent_types_1.AgentToolCallStatus.Running,
|
|
765
|
+
input: chunk.input,
|
|
766
|
+
};
|
|
767
|
+
assistantMessage.toolCalls.push(toolCall);
|
|
768
|
+
}
|
|
769
|
+
else {
|
|
290
770
|
toolCall.status = ai_agent_types_1.AgentToolCallStatus.Running;
|
|
291
771
|
toolCall.input = chunk.input;
|
|
292
772
|
}
|
|
773
|
+
await persistAndBroadcastToolCalls();
|
|
293
774
|
continue;
|
|
294
775
|
}
|
|
295
776
|
if (chunk.type === 'tool-error') {
|
|
296
777
|
const toolCall = assistantMessage.toolCalls?.find(toolCall => toolCall.id === chunk.toolCallId);
|
|
297
778
|
if (toolCall) {
|
|
298
779
|
toolCall.status = ai_agent_types_1.AgentToolCallStatus.Failed;
|
|
299
|
-
toolCall.error = JSON.stringify(chunk.error);
|
|
780
|
+
toolCall.error = chunk.error.message || JSON.stringify(chunk.error);
|
|
781
|
+
await persistAndBroadcastToolCalls();
|
|
300
782
|
}
|
|
301
783
|
continue;
|
|
302
784
|
}
|
|
303
785
|
if (chunk.type === 'tool-approval-request') {
|
|
304
786
|
const toolCall = assistantMessage.toolCalls?.find(toolCall => toolCall.id === chunk.toolCall.toolCallId);
|
|
305
787
|
if (toolCall) {
|
|
788
|
+
const toolConfig = store_1.ConfigStore.getInstance().getToolConfig(assistantMessage.agentName || '', toolCall.name);
|
|
789
|
+
if (toolConfig && toolConfig.type === ai_agent_types_1.AgentToolType.SUBAGENT) {
|
|
790
|
+
// TODO: allow needsApproval flow for the subagents too
|
|
791
|
+
continue;
|
|
792
|
+
}
|
|
306
793
|
toolCall.requiresConfirmation = true;
|
|
307
794
|
toolCall.approvalId = chunk.approvalId;
|
|
795
|
+
if (toolCall.name === ai_agent_types_1.AgentToolType.REQUEST_CLARIFICATION) {
|
|
796
|
+
toolCall.requiresUserAction = true;
|
|
797
|
+
}
|
|
798
|
+
await persistAndBroadcastToolCalls();
|
|
308
799
|
}
|
|
309
800
|
continue;
|
|
310
801
|
}
|
|
311
802
|
if (chunk.type === 'tool-result') {
|
|
312
803
|
const toolCall = assistantMessage.toolCalls?.find(toolCall => toolCall.id === chunk.toolCallId);
|
|
313
804
|
if (toolCall) {
|
|
314
|
-
if (chunk.output.requiresApproval) {
|
|
315
|
-
toolCall.requiresConfirmation = true;
|
|
316
|
-
continue;
|
|
317
|
-
}
|
|
318
805
|
toolCall.status = ai_agent_types_1.AgentToolCallStatus.Succeeded;
|
|
319
806
|
toolCall.output = chunk.output;
|
|
807
|
+
await persistAndBroadcastToolCalls();
|
|
320
808
|
}
|
|
321
809
|
continue;
|
|
322
810
|
}
|
|
@@ -324,9 +812,9 @@ class ChatProcessor {
|
|
|
324
812
|
if (!assistantMessage.reasoning)
|
|
325
813
|
assistantMessage.reasoning = '';
|
|
326
814
|
assistantMessage.reasoning += chunk.text;
|
|
327
|
-
|
|
815
|
+
this.emitMessageToParticipants(chat, assistantMessage, excludeSocketId);
|
|
328
816
|
await this.messageRepository.update(assistantMessage.id, { reasoning: assistantMessage.reasoning });
|
|
329
|
-
await
|
|
817
|
+
await this.agentStore.shareAgentProcessEvent(chat.id, { type: store_1.AgentProcessEventType.Update, data: assistantMessage });
|
|
330
818
|
continue;
|
|
331
819
|
}
|
|
332
820
|
}
|
|
@@ -335,7 +823,7 @@ class ChatProcessor {
|
|
|
335
823
|
if (streamError instanceof Error && streamError.name === 'AbortError') {
|
|
336
824
|
return;
|
|
337
825
|
}
|
|
338
|
-
await
|
|
826
|
+
await this.agentStore.shareAgentProcessEvent(chat.id, { type: store_1.AgentProcessEventType.Error, data: streamError });
|
|
339
827
|
throw streamError;
|
|
340
828
|
}
|
|
341
829
|
}
|
|
@@ -347,9 +835,10 @@ class ChatProcessor {
|
|
|
347
835
|
if (!assistantMessage || assistantMessage.chat !== chat.id) {
|
|
348
836
|
throw new Error(`Assistant message with id ${payload.messageId} not found`);
|
|
349
837
|
}
|
|
350
|
-
const agentOptions = await
|
|
838
|
+
const agentOptions = await this.aiHelper.getAgentOptions({
|
|
351
839
|
agentName: assistantMessage.agentName,
|
|
352
|
-
context: payload.context
|
|
840
|
+
context: payload.context,
|
|
841
|
+
executionContext: payload.executionContext,
|
|
353
842
|
});
|
|
354
843
|
const toolCall = assistantMessage.toolCalls?.find(tc => tc.approvalId === payload.approvalId);
|
|
355
844
|
if (!toolCall) {
|
|
@@ -360,14 +849,20 @@ class ChatProcessor {
|
|
|
360
849
|
};
|
|
361
850
|
}
|
|
362
851
|
toolCall.approved = payload.approved;
|
|
363
|
-
toolCall.
|
|
852
|
+
toolCall.userResponse = payload.userResponse;
|
|
364
853
|
if (!toolCall.approved) {
|
|
365
854
|
toolCall.output = {
|
|
366
855
|
type: 'execution-denied',
|
|
367
|
-
reason: toolCall.
|
|
856
|
+
reason: toolCall.userResponse
|
|
368
857
|
};
|
|
369
858
|
toolCall.status = ai_agent_types_1.AgentToolCallStatus.Failed;
|
|
370
859
|
}
|
|
860
|
+
else if (toolCall.requiresUserAction) {
|
|
861
|
+
toolCall.output = {
|
|
862
|
+
userResponse: toolCall.userResponse
|
|
863
|
+
};
|
|
864
|
+
toolCall.status = ai_agent_types_1.AgentToolCallStatus.Succeeded;
|
|
865
|
+
}
|
|
371
866
|
else {
|
|
372
867
|
const executeFunction = agentOptions.tools?.[toolCall.name]?.execute;
|
|
373
868
|
if (executeFunction) {
|
|
@@ -399,33 +894,333 @@ class ChatProcessor {
|
|
|
399
894
|
};
|
|
400
895
|
}
|
|
401
896
|
async processNewUserMessage(chat, payload, prevMessages, excludeSocketId) {
|
|
897
|
+
const executionTenants = this.getExecutionTenants(payload);
|
|
898
|
+
const chatUserId = this.getChatUserId(chat) ?? 'guest';
|
|
402
899
|
const userMessage = await this.createMessage(chat, ai_agent_types_1.MessageRole.User, { content: payload.content, agentName: undefined }, payload.attachments);
|
|
403
|
-
await
|
|
404
|
-
|
|
900
|
+
await this.agentStore.shareAgentProcessEvent(chat.id, { type: store_1.AgentProcessEventType.Update, data: userMessage });
|
|
901
|
+
let assistantMessage = await this.createMessage(chat, ai_agent_types_1.MessageRole.Assistant, { content: '', agentName: undefined }, undefined, excludeSocketId);
|
|
902
|
+
const parentActivity = await this.activityRepository.create({
|
|
903
|
+
ownerId: chatUserId,
|
|
904
|
+
groupId: chat.id,
|
|
905
|
+
name: ai_agent_types_1.ActivityOperationName.MESSAGE_PROCESSING,
|
|
906
|
+
tenants: executionTenants,
|
|
907
|
+
sourceId: userMessage.id,
|
|
908
|
+
sourceType: 'AgentMessage',
|
|
909
|
+
metadata: {
|
|
910
|
+
contextKey: chat.contextKey,
|
|
911
|
+
modelId: this.aiHelper.getLanguageModelId(chat.model),
|
|
912
|
+
},
|
|
913
|
+
});
|
|
914
|
+
const agentOptions = await this.aiHelper.getAgentOptions({
|
|
405
915
|
contextKey: chat.contextKey,
|
|
406
|
-
messages:
|
|
916
|
+
messages: [...prevMessages, userMessage],
|
|
407
917
|
context: payload.context,
|
|
408
918
|
agentName: undefined,
|
|
409
919
|
modelId: chat.model,
|
|
920
|
+
executionContext: payload.executionContext,
|
|
921
|
+
}, {
|
|
922
|
+
onStepFinish: async (stepResult) => {
|
|
923
|
+
await this.storeStepActivity({
|
|
924
|
+
chat,
|
|
925
|
+
parentId: parentActivity.id,
|
|
926
|
+
stepResult,
|
|
927
|
+
name: ai_agent_types_1.ActivityOperationName.AGENT_SELECTION,
|
|
928
|
+
sourceId: userMessage.id,
|
|
929
|
+
sourceType: 'AgentMessage',
|
|
930
|
+
tenants: executionTenants,
|
|
931
|
+
});
|
|
932
|
+
}
|
|
933
|
+
});
|
|
934
|
+
const updatedAssistantMessage = await this.messageRepository.update(assistantMessage.id, {
|
|
935
|
+
agentName: agentOptions.name,
|
|
936
|
+
activity: parentActivity.id
|
|
937
|
+
});
|
|
938
|
+
await this.activityRepository.update(parentActivity.id, {
|
|
939
|
+
metadata: {
|
|
940
|
+
...parentActivity.metadata,
|
|
941
|
+
agentOptions: {
|
|
942
|
+
name: agentOptions.name,
|
|
943
|
+
modelId: this.aiHelper.getLanguageModelId(agentOptions.model),
|
|
944
|
+
temperature: agentOptions.temperature,
|
|
945
|
+
maxOutputTokens: agentOptions.maxOutputTokens,
|
|
946
|
+
topP: agentOptions.topP,
|
|
947
|
+
topK: agentOptions.topK,
|
|
948
|
+
presencePenalty: agentOptions.presencePenalty,
|
|
949
|
+
frequencyPenalty: agentOptions.frequencyPenalty,
|
|
950
|
+
stopSequences: agentOptions.stopSequences,
|
|
951
|
+
seed: agentOptions.seed,
|
|
952
|
+
},
|
|
953
|
+
},
|
|
410
954
|
});
|
|
411
|
-
|
|
412
|
-
|
|
955
|
+
if (!updatedAssistantMessage) {
|
|
956
|
+
throw new Error(`Assistant message with id ${assistantMessage.id} not found after update`);
|
|
957
|
+
}
|
|
958
|
+
assistantMessage = updatedAssistantMessage;
|
|
413
959
|
return {
|
|
414
960
|
userMessage,
|
|
415
961
|
assistantMessage,
|
|
416
962
|
agentOptions,
|
|
417
963
|
};
|
|
418
964
|
}
|
|
965
|
+
getAgentNamesForContext(contextKey) {
|
|
966
|
+
try {
|
|
967
|
+
return store_1.ConfigStore.getInstance().getAgentsForContext(contextKey).map((config) => config.name);
|
|
968
|
+
}
|
|
969
|
+
catch {
|
|
970
|
+
return [];
|
|
971
|
+
}
|
|
972
|
+
}
|
|
973
|
+
normalizeMentionName(value) {
|
|
974
|
+
return value.trim().replace(/^@/, '').toLowerCase();
|
|
975
|
+
}
|
|
976
|
+
extractMentionNames(content) {
|
|
977
|
+
const mentions = content.matchAll(/(^|[\s([{])@([a-zA-Z0-9_.-]+)/g);
|
|
978
|
+
return Array.from(mentions, (match) => match[2]).filter(Boolean);
|
|
979
|
+
}
|
|
980
|
+
getExplicitAgentMention(params) {
|
|
981
|
+
const agentNames = this.getAgentNamesForContext(params.contextKey);
|
|
982
|
+
const normalizedAgentNames = new Map(agentNames.map((name) => [this.normalizeMentionName(name), name]));
|
|
983
|
+
for (const mention of params.mentions ?? []) {
|
|
984
|
+
if (mention.type !== 'agent')
|
|
985
|
+
continue;
|
|
986
|
+
const normalized = this.normalizeMentionName(mention.name);
|
|
987
|
+
return { mentioned: true, agentName: normalizedAgentNames.get(normalized) };
|
|
988
|
+
}
|
|
989
|
+
for (const name of this.extractMentionNames(params.content)) {
|
|
990
|
+
const normalized = this.normalizeMentionName(name);
|
|
991
|
+
if (normalized === 'agent') {
|
|
992
|
+
return { mentioned: true };
|
|
993
|
+
}
|
|
994
|
+
const agentName = normalizedAgentNames.get(normalized);
|
|
995
|
+
if (agentName) {
|
|
996
|
+
return { mentioned: true, agentName };
|
|
997
|
+
}
|
|
998
|
+
}
|
|
999
|
+
return { mentioned: false };
|
|
1000
|
+
}
|
|
1001
|
+
hasNonAgentMention(params) {
|
|
1002
|
+
const agentNames = this.getAgentNamesForContext(params.contextKey);
|
|
1003
|
+
const normalizedAgentNames = new Set(['agent', ...agentNames.map((name) => this.normalizeMentionName(name))]);
|
|
1004
|
+
if ((params.mentions ?? []).some((mention) => mention.type === 'user')) {
|
|
1005
|
+
return true;
|
|
1006
|
+
}
|
|
1007
|
+
return this.extractMentionNames(params.content).some((name) => {
|
|
1008
|
+
const normalized = this.normalizeMentionName(name);
|
|
1009
|
+
return !normalizedAgentNames.has(normalized);
|
|
1010
|
+
});
|
|
1011
|
+
}
|
|
1012
|
+
renderMessageForDecision(message) {
|
|
1013
|
+
const sender = message.sender?.displayName || message.sender?.id || message.agentName || message.role;
|
|
1014
|
+
return `${sender}: ${message.content}`;
|
|
1015
|
+
}
|
|
1016
|
+
async analyzeAgentShouldRespond(params) {
|
|
1017
|
+
try {
|
|
1018
|
+
const recentMessages = [...params.previousMessages.slice(-8), params.userMessage]
|
|
1019
|
+
.map((message) => this.renderMessageForDecision(message))
|
|
1020
|
+
.join('\n');
|
|
1021
|
+
const response = await this.aiHelper.getAssistantResponse([
|
|
1022
|
+
{
|
|
1023
|
+
role: ai_agent_types_1.MessageRole.User,
|
|
1024
|
+
content: `Conversation:\n${recentMessages}\n\nShould the AI agent respond to the latest message?`
|
|
1025
|
+
}
|
|
1026
|
+
], {
|
|
1027
|
+
system: [
|
|
1028
|
+
'You decide whether an AI agent should reply in a multi-user chat.',
|
|
1029
|
+
'Reply with exactly YES or NO.',
|
|
1030
|
+
'YES only when the latest message asks for help, requests agent action, or is clearly addressed to the AI.',
|
|
1031
|
+
'NO when the latest message is human-to-human chatter, status, acknowledgement, or otherwise does not need the AI.'
|
|
1032
|
+
].join('\n'),
|
|
1033
|
+
temperature: 0,
|
|
1034
|
+
maxOutputTokens: 5,
|
|
1035
|
+
model: params.chat.model,
|
|
1036
|
+
executionContext: params.executionContext
|
|
1037
|
+
});
|
|
1038
|
+
return /^yes\b/i.test(response.trim());
|
|
1039
|
+
}
|
|
1040
|
+
catch (error) {
|
|
1041
|
+
logger_1.logger.warn({ error, chatId: params.chat.id }, 'Agent response decision failed');
|
|
1042
|
+
return false;
|
|
1043
|
+
}
|
|
1044
|
+
}
|
|
1045
|
+
async shouldRunAgentForMultiUserMessage(params) {
|
|
1046
|
+
const firstUserMessage = !params.previousMessages.some((message) => message.role === ai_agent_types_1.MessageRole.User);
|
|
1047
|
+
if (firstUserMessage) {
|
|
1048
|
+
return { shouldRun: true };
|
|
1049
|
+
}
|
|
1050
|
+
const explicitAgent = this.getExplicitAgentMention({
|
|
1051
|
+
content: params.payload.content,
|
|
1052
|
+
mentions: params.payload.mentions,
|
|
1053
|
+
contextKey: params.chat.contextKey,
|
|
1054
|
+
});
|
|
1055
|
+
if (explicitAgent.mentioned) {
|
|
1056
|
+
return { shouldRun: true, agentName: explicitAgent.agentName };
|
|
1057
|
+
}
|
|
1058
|
+
if (this.hasNonAgentMention({
|
|
1059
|
+
content: params.payload.content,
|
|
1060
|
+
mentions: params.payload.mentions,
|
|
1061
|
+
contextKey: params.chat.contextKey,
|
|
1062
|
+
})) {
|
|
1063
|
+
return { shouldRun: false };
|
|
1064
|
+
}
|
|
1065
|
+
const shouldRun = await this.analyzeAgentShouldRespond({
|
|
1066
|
+
chat: params.chat,
|
|
1067
|
+
previousMessages: params.previousMessages,
|
|
1068
|
+
userMessage: params.userMessage,
|
|
1069
|
+
executionContext: params.payload.executionContext,
|
|
1070
|
+
});
|
|
1071
|
+
return { shouldRun };
|
|
1072
|
+
}
|
|
1073
|
+
async prepareAgentResponseForUserMessage(chat, payload, prevMessages, userMessage, excludeSocketId, agentName) {
|
|
1074
|
+
const executionTenants = this.getExecutionTenants(payload);
|
|
1075
|
+
let assistantMessage = await this.createMessage(chat, ai_agent_types_1.MessageRole.Assistant, {
|
|
1076
|
+
content: '',
|
|
1077
|
+
agentName: agentName,
|
|
1078
|
+
sender: {
|
|
1079
|
+
id: agentName ?? 'agent',
|
|
1080
|
+
type: 'agent',
|
|
1081
|
+
displayName: agentName ?? 'Agent',
|
|
1082
|
+
}
|
|
1083
|
+
}, undefined, excludeSocketId);
|
|
1084
|
+
const ownerId = payload.userId ?? chat.userId ?? this.getChatUserId(chat) ?? 'guest';
|
|
1085
|
+
const parentActivity = await this.activityRepository.create({
|
|
1086
|
+
ownerId,
|
|
1087
|
+
groupId: chat.id,
|
|
1088
|
+
name: ai_agent_types_1.ActivityOperationName.MESSAGE_PROCESSING,
|
|
1089
|
+
tenants: executionTenants,
|
|
1090
|
+
sourceId: userMessage.id,
|
|
1091
|
+
sourceType: 'AgentMessage',
|
|
1092
|
+
metadata: {
|
|
1093
|
+
contextKey: chat.contextKey,
|
|
1094
|
+
modelId: this.aiHelper.getLanguageModelId(chat.model),
|
|
1095
|
+
},
|
|
1096
|
+
});
|
|
1097
|
+
const agentOptions = await this.aiHelper.getAgentOptions(agentName
|
|
1098
|
+
? {
|
|
1099
|
+
agentName,
|
|
1100
|
+
modelId: chat.model,
|
|
1101
|
+
context: payload.context,
|
|
1102
|
+
executionContext: payload.executionContext,
|
|
1103
|
+
}
|
|
1104
|
+
: {
|
|
1105
|
+
contextKey: chat.contextKey,
|
|
1106
|
+
messages: [...prevMessages, userMessage],
|
|
1107
|
+
context: payload.context,
|
|
1108
|
+
agentName: undefined,
|
|
1109
|
+
modelId: chat.model,
|
|
1110
|
+
executionContext: payload.executionContext,
|
|
1111
|
+
}, {
|
|
1112
|
+
onStepFinish: async (stepResult) => {
|
|
1113
|
+
await this.storeStepActivity({
|
|
1114
|
+
chat,
|
|
1115
|
+
parentId: parentActivity.id,
|
|
1116
|
+
stepResult,
|
|
1117
|
+
name: ai_agent_types_1.ActivityOperationName.AGENT_SELECTION,
|
|
1118
|
+
sourceId: userMessage.id,
|
|
1119
|
+
sourceType: 'AgentMessage',
|
|
1120
|
+
tenants: executionTenants,
|
|
1121
|
+
});
|
|
1122
|
+
}
|
|
1123
|
+
});
|
|
1124
|
+
const updatedAssistantMessage = await this.messageRepository.update(assistantMessage.id, {
|
|
1125
|
+
agentName: agentOptions.name,
|
|
1126
|
+
activity: parentActivity.id,
|
|
1127
|
+
sender: {
|
|
1128
|
+
id: agentOptions.name,
|
|
1129
|
+
type: 'agent',
|
|
1130
|
+
displayName: agentOptions.name,
|
|
1131
|
+
}
|
|
1132
|
+
});
|
|
1133
|
+
await this.activityRepository.update(parentActivity.id, {
|
|
1134
|
+
metadata: {
|
|
1135
|
+
...parentActivity.metadata,
|
|
1136
|
+
agentOptions: {
|
|
1137
|
+
name: agentOptions.name,
|
|
1138
|
+
modelId: this.aiHelper.getLanguageModelId(agentOptions.model),
|
|
1139
|
+
temperature: agentOptions.temperature,
|
|
1140
|
+
maxOutputTokens: agentOptions.maxOutputTokens,
|
|
1141
|
+
topP: agentOptions.topP,
|
|
1142
|
+
topK: agentOptions.topK,
|
|
1143
|
+
presencePenalty: agentOptions.presencePenalty,
|
|
1144
|
+
frequencyPenalty: agentOptions.frequencyPenalty,
|
|
1145
|
+
stopSequences: agentOptions.stopSequences,
|
|
1146
|
+
seed: agentOptions.seed,
|
|
1147
|
+
},
|
|
1148
|
+
},
|
|
1149
|
+
});
|
|
1150
|
+
if (!updatedAssistantMessage) {
|
|
1151
|
+
throw new Error(`Assistant message with id ${assistantMessage.id} not found after update`);
|
|
1152
|
+
}
|
|
1153
|
+
assistantMessage = updatedAssistantMessage;
|
|
1154
|
+
return {
|
|
1155
|
+
assistantMessage,
|
|
1156
|
+
agentOptions,
|
|
1157
|
+
executionTenants,
|
|
1158
|
+
};
|
|
1159
|
+
}
|
|
1160
|
+
async streamAgentResponseForUserMessage(params) {
|
|
1161
|
+
const { assistantMessage, agentOptions, executionTenants } = await this.prepareAgentResponseForUserMessage(params.chat, params.payload, params.previousMessages, params.userMessage, params.excludeSocketId, params.agentName);
|
|
1162
|
+
const messagesForAgent = [...params.previousMessages, params.userMessage];
|
|
1163
|
+
agentOptions.onStepFinish = (stepResult) => {
|
|
1164
|
+
return this.storeStepActivity({
|
|
1165
|
+
chat: params.chat,
|
|
1166
|
+
parentId: assistantMessage.activity,
|
|
1167
|
+
stepResult,
|
|
1168
|
+
name: ai_agent_types_1.ActivityOperationName.STEP_FINISHED,
|
|
1169
|
+
sourceId: assistantMessage.id,
|
|
1170
|
+
sourceType: 'AgentMessage',
|
|
1171
|
+
tenants: executionTenants,
|
|
1172
|
+
});
|
|
1173
|
+
};
|
|
1174
|
+
const userPreferences = await this.agentConfigRepository.findByUserIdAndAgentName(params.payload.userId ?? params.chat.userId ?? this.getChatUserId(params.chat) ?? 'guest', agentOptions.name);
|
|
1175
|
+
agentOptions.activeTools = this.getAvailableTools(agentOptions, userPreferences);
|
|
1176
|
+
await this.streamMessageStep({
|
|
1177
|
+
chat: params.chat,
|
|
1178
|
+
existingMessages: messagesForAgent,
|
|
1179
|
+
assistantMessage,
|
|
1180
|
+
agentOptions,
|
|
1181
|
+
excludeSocketId: params.excludeSocketId,
|
|
1182
|
+
signal: params.signal,
|
|
1183
|
+
tenants: executionTenants,
|
|
1184
|
+
executionContext: params.payload.executionContext,
|
|
1185
|
+
context: params.payload.context,
|
|
1186
|
+
});
|
|
1187
|
+
}
|
|
1188
|
+
async storeStepActivity(params) {
|
|
1189
|
+
try {
|
|
1190
|
+
const stepResult = params.stepResult;
|
|
1191
|
+
const mergedUsage = this.mergeUsageWithProviderMetadata(stepResult.usage, stepResult.providerMetadata);
|
|
1192
|
+
const activity = await this.activityRepository.create({
|
|
1193
|
+
ownerId: this.getChatUserId(params.chat) ?? 'guest',
|
|
1194
|
+
groupId: params.chat.id,
|
|
1195
|
+
name: params.name,
|
|
1196
|
+
tenants: params.tenants || {},
|
|
1197
|
+
sourceId: params.sourceId,
|
|
1198
|
+
sourceType: params.sourceType,
|
|
1199
|
+
metadata: {
|
|
1200
|
+
finishReason: stepResult.finishReason,
|
|
1201
|
+
usage: mergedUsage,
|
|
1202
|
+
responseTimestamp: stepResult.response.timestamp,
|
|
1203
|
+
modelId: stepResult.response.modelId,
|
|
1204
|
+
messages: this.debug ? stepResult.request?.body?.messages : undefined,
|
|
1205
|
+
},
|
|
1206
|
+
parentId: params.parentId,
|
|
1207
|
+
});
|
|
1208
|
+
}
|
|
1209
|
+
catch (error) {
|
|
1210
|
+
logger_1.logger.error({ error, chatId: params.chat.id, parentId: params.parentId }, 'Failed to store step activity');
|
|
1211
|
+
}
|
|
1212
|
+
}
|
|
419
1213
|
async streamMessage(chat, payload, excludeSocketId, onAgentStart) {
|
|
420
1214
|
try {
|
|
421
|
-
const
|
|
1215
|
+
const executionTenants = this.getExecutionTenants(payload);
|
|
1216
|
+
const abortController = this.agentStore.registerAgentProcess(chat.id);
|
|
422
1217
|
onAgentStart?.();
|
|
423
1218
|
let assistantMessage;
|
|
424
1219
|
let agentOptions;
|
|
425
1220
|
const existingMessages = await this.messageRepository.findByChatId(chat.id);
|
|
426
1221
|
// Limit context to prevent exceeding token limits
|
|
427
|
-
const limitedMessages =
|
|
428
|
-
maxMessages:
|
|
1222
|
+
const limitedMessages = helpers_1.ContextLimiter.limitContext(existingMessages, {
|
|
1223
|
+
maxMessages: this.config.ai.maxContextMessages,
|
|
429
1224
|
keepFirstUserMessage: true,
|
|
430
1225
|
keepSystemMessages: true,
|
|
431
1226
|
});
|
|
@@ -447,6 +1242,19 @@ class ChatProcessor {
|
|
|
447
1242
|
agentOptions = result.agentOptions;
|
|
448
1243
|
limitedMessages.push(result.userMessage);
|
|
449
1244
|
}
|
|
1245
|
+
agentOptions.onStepFinish = (stepResult) => {
|
|
1246
|
+
return this.storeStepActivity({
|
|
1247
|
+
chat,
|
|
1248
|
+
parentId: assistantMessage.activity,
|
|
1249
|
+
stepResult,
|
|
1250
|
+
name: ai_agent_types_1.ActivityOperationName.STEP_FINISHED,
|
|
1251
|
+
sourceId: assistantMessage.id,
|
|
1252
|
+
sourceType: 'AgentMessage',
|
|
1253
|
+
tenants: executionTenants,
|
|
1254
|
+
});
|
|
1255
|
+
};
|
|
1256
|
+
const userPreferences = await this.agentConfigRepository.findByUserIdAndAgentName(this.getChatUserId(chat) ?? 'guest', agentOptions.name);
|
|
1257
|
+
agentOptions.activeTools = this.getAvailableTools(agentOptions, userPreferences);
|
|
450
1258
|
await this.streamMessageStep({
|
|
451
1259
|
chat,
|
|
452
1260
|
existingMessages: limitedMessages,
|
|
@@ -454,12 +1262,30 @@ class ChatProcessor {
|
|
|
454
1262
|
agentOptions,
|
|
455
1263
|
excludeSocketId: excludeSocketId,
|
|
456
1264
|
signal: abortController.signal,
|
|
1265
|
+
tenants: executionTenants,
|
|
1266
|
+
executionContext: payload.executionContext,
|
|
1267
|
+
context: payload.context,
|
|
457
1268
|
});
|
|
458
1269
|
}
|
|
459
1270
|
catch (error) {
|
|
460
1271
|
throw error;
|
|
461
1272
|
}
|
|
462
1273
|
}
|
|
1274
|
+
getAvailableTools(agentOptions, userPreferences) {
|
|
1275
|
+
const toolNames = Object.keys(agentOptions.tools || {});
|
|
1276
|
+
const availableToolsMap = Object.fromEntries(toolNames.map(key => [key, true]));
|
|
1277
|
+
const agentsConfiguration = store_1.ConfigStore.getInstance().getAgentConfigByName(agentOptions.name);
|
|
1278
|
+
agentsConfiguration.tools.forEach((tool) => {
|
|
1279
|
+
const toolTitle = (0, utils_1.getAgentToolName)(tool);
|
|
1280
|
+
if (tool.disabledByDefault) {
|
|
1281
|
+
availableToolsMap[toolTitle] = false;
|
|
1282
|
+
}
|
|
1283
|
+
if (tool.userConfigurable && userPreferences?.tools?.[toolTitle] !== undefined) {
|
|
1284
|
+
availableToolsMap[toolTitle] = userPreferences.tools[toolTitle];
|
|
1285
|
+
}
|
|
1286
|
+
});
|
|
1287
|
+
return Object.keys(availableToolsMap).filter(key => availableToolsMap[key]);
|
|
1288
|
+
}
|
|
463
1289
|
listArtifacts(chatId) {
|
|
464
1290
|
return this.artifactStore.listArtifacts(chatId);
|
|
465
1291
|
}
|
|
@@ -490,7 +1316,7 @@ class ChatProcessor {
|
|
|
490
1316
|
return null;
|
|
491
1317
|
}
|
|
492
1318
|
}
|
|
493
|
-
getMessageStream(chatId) {
|
|
1319
|
+
getMessageStream(chatId, signal) {
|
|
494
1320
|
const stream = new stream_1.PassThrough();
|
|
495
1321
|
let ended = false;
|
|
496
1322
|
const endStream = (error) => {
|
|
@@ -511,13 +1337,15 @@ class ChatProcessor {
|
|
|
511
1337
|
}
|
|
512
1338
|
};
|
|
513
1339
|
const pushChunk = (chunk) => {
|
|
514
|
-
if (ended || stream.destroyed || stream.writableEnded)
|
|
1340
|
+
if (ended || stream.destroyed || stream.writableEnded || signal?.aborted)
|
|
515
1341
|
return;
|
|
516
1342
|
stream.write(`data: ${JSON.stringify(chunk)}\n\n`);
|
|
517
1343
|
};
|
|
518
1344
|
const listener = (event) => {
|
|
519
|
-
if (
|
|
1345
|
+
if (signal?.aborted) {
|
|
1346
|
+
endStream();
|
|
520
1347
|
return;
|
|
1348
|
+
}
|
|
521
1349
|
try {
|
|
522
1350
|
const chunk = this.eventToChunk(event);
|
|
523
1351
|
if (chunk) {
|
|
@@ -527,7 +1355,6 @@ class ChatProcessor {
|
|
|
527
1355
|
event.type === store_1.AgentProcessEventType.Error ||
|
|
528
1356
|
event.type === store_1.AgentProcessEventType.Aborted) {
|
|
529
1357
|
endStream();
|
|
530
|
-
store_1.agentStore.removeListener(chatId, listener);
|
|
531
1358
|
}
|
|
532
1359
|
}
|
|
533
1360
|
catch (err) {
|
|
@@ -536,21 +1363,18 @@ class ChatProcessor {
|
|
|
536
1363
|
error: err instanceof Error ? err.message : 'Unknown error occurred',
|
|
537
1364
|
});
|
|
538
1365
|
endStream(err);
|
|
539
|
-
store_1.agentStore.removeListener(chatId, listener);
|
|
540
1366
|
}
|
|
541
1367
|
};
|
|
542
|
-
// Cleanup on consumer side closing
|
|
543
1368
|
const closeHandler = () => {
|
|
544
|
-
|
|
1369
|
+
this.agentStore.removeListener(chatId, listener);
|
|
545
1370
|
};
|
|
546
1371
|
const errorHandler = (err) => {
|
|
547
|
-
|
|
548
|
-
store_1.agentStore.removeListener(chatId, listener);
|
|
1372
|
+
signal?.removeEventListener('abort', endStream);
|
|
549
1373
|
endStream(err);
|
|
550
1374
|
};
|
|
551
1375
|
stream.on('close', closeHandler);
|
|
552
1376
|
stream.on('error', errorHandler);
|
|
553
|
-
const listenerAttached =
|
|
1377
|
+
const listenerAttached = this.agentStore.addListener(chatId, listener);
|
|
554
1378
|
if (!listenerAttached) {
|
|
555
1379
|
// Remove stream listeners if listener attachment failed to prevent memory leak
|
|
556
1380
|
stream.removeListener('close', closeHandler);
|
|
@@ -559,51 +1383,108 @@ class ChatProcessor {
|
|
|
559
1383
|
}
|
|
560
1384
|
return stream;
|
|
561
1385
|
}
|
|
562
|
-
async
|
|
563
|
-
const
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
type: ai_agent_types_1.StreamChunkType.Chat,
|
|
571
|
-
chatId: chat.id,
|
|
572
|
-
chat,
|
|
573
|
-
})}\n\n`);
|
|
574
|
-
}
|
|
575
|
-
await this.streamMessage(chat, payload, excludeSocketId, async () => {
|
|
576
|
-
if (stream.destroyed || stream.writableEnded) {
|
|
577
|
-
return;
|
|
578
|
-
}
|
|
579
|
-
const messageStream = this.getMessageStream(chat.id);
|
|
580
|
-
// If client disconnects, destroy inner stream
|
|
581
|
-
stream.on('close', () => {
|
|
582
|
-
if (!messageStream.destroyed) {
|
|
583
|
-
messageStream.destroy();
|
|
584
|
-
}
|
|
585
|
-
});
|
|
586
|
-
await pipelineAsync(messageStream, stream);
|
|
587
|
-
});
|
|
1386
|
+
async upsertAndGetMultiUserChat(payload, excludeSocketId) {
|
|
1387
|
+
const targetUserId = payload.userId ?? 'guest';
|
|
1388
|
+
let chat = null;
|
|
1389
|
+
let isNewChat = false;
|
|
1390
|
+
if (payload.chatId) {
|
|
1391
|
+
chat = await this.chatRepository.findById(payload.chatId);
|
|
1392
|
+
if (!chat) {
|
|
1393
|
+
throw new Error('Chat not found');
|
|
588
1394
|
}
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
1395
|
+
if (!this.hasChatAccess(chat, targetUserId)) {
|
|
1396
|
+
throw new Error('Chat does not belong to this user');
|
|
1397
|
+
}
|
|
1398
|
+
const participantIds = Array.from(new Set([
|
|
1399
|
+
...this.getParticipantIds(chat),
|
|
1400
|
+
...(payload.participantIds ?? []),
|
|
1401
|
+
targetUserId,
|
|
1402
|
+
].filter(Boolean)));
|
|
1403
|
+
const updates = {};
|
|
1404
|
+
if (participantIds.length !== this.getParticipantIds(chat).length) {
|
|
1405
|
+
updates.participantIds = participantIds;
|
|
1406
|
+
}
|
|
1407
|
+
if ('model' in payload) {
|
|
1408
|
+
updates.model = payload.model || undefined;
|
|
599
1409
|
}
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
1410
|
+
if (Object.keys(updates).length > 0) {
|
|
1411
|
+
chat = await this.updateChatAndEmit(chat, updates, excludeSocketId);
|
|
1412
|
+
}
|
|
1413
|
+
}
|
|
1414
|
+
if (!chat) {
|
|
1415
|
+
chat = await this.createChat(payload, excludeSocketId);
|
|
1416
|
+
isNewChat = true;
|
|
1417
|
+
}
|
|
1418
|
+
return { chat, isNewChat };
|
|
1419
|
+
}
|
|
1420
|
+
async postMultiUserMessage(payload, excludeSocketId) {
|
|
1421
|
+
const { chat } = await this.upsertAndGetMultiUserChat(payload, excludeSocketId);
|
|
1422
|
+
const existingMessages = await this.messageRepository.findByChatId(chat.id);
|
|
1423
|
+
const sender = {
|
|
1424
|
+
id: payload.userId ?? 'guest',
|
|
1425
|
+
type: 'user',
|
|
1426
|
+
...(payload.senderDisplayName ? { displayName: payload.senderDisplayName } : {}),
|
|
1427
|
+
...(payload.senderAvatarUrl ? { avatarUrl: payload.senderAvatarUrl } : {}),
|
|
1428
|
+
};
|
|
1429
|
+
const userMessage = await this.createMessage(chat, ai_agent_types_1.MessageRole.User, {
|
|
1430
|
+
content: payload.content,
|
|
1431
|
+
agentName: undefined,
|
|
1432
|
+
sender,
|
|
1433
|
+
mentions: payload.mentions ?? [],
|
|
1434
|
+
}, payload.attachments, excludeSocketId);
|
|
1435
|
+
const decision = await this.shouldRunAgentForMultiUserMessage({
|
|
1436
|
+
chat,
|
|
1437
|
+
previousMessages: existingMessages,
|
|
1438
|
+
userMessage,
|
|
1439
|
+
payload,
|
|
1440
|
+
});
|
|
1441
|
+
if (!decision.shouldRun) {
|
|
1442
|
+
const updatedChat = await this.updateChatAndEmit(chat, { status: ai_agent_types_1.AgentStatus.Finished }, excludeSocketId);
|
|
1443
|
+
return { chat: updatedChat, message: userMessage, agentTriggered: false };
|
|
1444
|
+
}
|
|
1445
|
+
const updatedChat = await this.updateChatAndEmit(chat, { status: ai_agent_types_1.AgentStatus.Streaming }, undefined);
|
|
1446
|
+
const abortController = this.agentStore.registerAgentProcess(chat.id);
|
|
1447
|
+
const limitedMessages = helpers_1.ContextLimiter.limitContext(existingMessages, {
|
|
1448
|
+
maxMessages: this.config.ai.maxContextMessages,
|
|
1449
|
+
keepFirstUserMessage: true,
|
|
1450
|
+
keepSystemMessages: true,
|
|
1451
|
+
});
|
|
1452
|
+
void this.streamAgentResponseForUserMessage({
|
|
1453
|
+
chat,
|
|
1454
|
+
payload,
|
|
1455
|
+
previousMessages: limitedMessages,
|
|
1456
|
+
userMessage,
|
|
1457
|
+
excludeSocketId: undefined,
|
|
1458
|
+
signal: abortController.signal,
|
|
1459
|
+
agentName: decision.agentName,
|
|
1460
|
+
}).catch(async (error) => {
|
|
1461
|
+
logger_1.logger.error({ error, chatId: chat.id }, 'Multi-user background agent flow failed');
|
|
1462
|
+
await this.updateChatAndEmit(chat, { status: ai_agent_types_1.AgentStatus.Error }, undefined);
|
|
1463
|
+
});
|
|
1464
|
+
return { chat: updatedChat, message: userMessage, agentTriggered: true };
|
|
1465
|
+
}
|
|
1466
|
+
async createMessageStream(payload, excludeSocketId, signal) {
|
|
1467
|
+
const stream = new stream_1.PassThrough();
|
|
1468
|
+
this.runMessageStream(stream, payload, excludeSocketId, signal)
|
|
1469
|
+
.catch(err => {
|
|
1470
|
+
logger_1.logger.error({ err }, 'Stream task failed');
|
|
604
1471
|
});
|
|
605
1472
|
return stream;
|
|
606
1473
|
}
|
|
1474
|
+
async runMessageStream(stream, payload, excludeSocketId, signal) {
|
|
1475
|
+
const chat = await this.upsertAndGetChat(payload, excludeSocketId);
|
|
1476
|
+
if (!('chatId' in payload) && !('messageId' in payload) && chat) {
|
|
1477
|
+
stream.write(`data: ${JSON.stringify({
|
|
1478
|
+
type: ai_agent_types_1.StreamChunkType.Chat,
|
|
1479
|
+
chatId: chat.id,
|
|
1480
|
+
chat,
|
|
1481
|
+
})}\n\n`);
|
|
1482
|
+
}
|
|
1483
|
+
await this.streamMessage(chat, payload, excludeSocketId, () => {
|
|
1484
|
+
const messageStream = this.getMessageStream(chat.id, signal);
|
|
1485
|
+
messageStream.pipe(stream);
|
|
1486
|
+
});
|
|
1487
|
+
}
|
|
607
1488
|
}
|
|
608
1489
|
exports.ChatProcessor = ChatProcessor;
|
|
609
1490
|
//# sourceMappingURL=ChatProcessor.js.map
|