@multiplayer-app/ai-agent-node 0.1.0-beta.5 → 0.1.0-beta.50
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 +57 -23
- package/dist/cjs/config.d.ts.map +1 -1
- package/dist/cjs/helpers/AIHelper.cjs +127 -65
- package/dist/cjs/helpers/AIHelper.cjs.map +1 -1
- package/dist/cjs/helpers/AIHelper.d.ts +22 -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 +120 -28
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.d.ts +43 -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 +39 -0
- package/dist/cjs/processors/ActivityProcessor.cjs.map +1 -0
- package/dist/cjs/processors/ActivityProcessor.d.ts +32 -0
- package/dist/cjs/processors/ActivityProcessor.d.ts.map +1 -0
- package/dist/cjs/processors/ActivityProcessor.test.cjs +84 -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 +46 -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 +355 -122
- package/dist/cjs/processors/ChatProcessor.cjs.map +1 -1
- package/dist/cjs/processors/ChatProcessor.d.ts +71 -11
- package/dist/cjs/processors/ChatProcessor.d.ts.map +1 -1
- package/dist/cjs/processors/ChatProcessor.test.cjs +762 -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 +87 -21
- package/dist/cjs/services/AIService.cjs.map +1 -1
- package/dist/cjs/services/AIService.d.ts +19 -7
- package/dist/cjs/services/AIService.d.ts.map +1 -1
- 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/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/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/index.cjs +0 -1
- package/dist/cjs/services/index.cjs.map +1 -1
- package/dist/cjs/services/index.d.ts +0 -1
- package/dist/cjs/services/index.d.ts.map +1 -1
- package/dist/cjs/store/AgentStore.cjs +3 -4
- package/dist/cjs/store/AgentStore.cjs.map +1 -1
- package/dist/cjs/store/AgentStore.d.ts +2 -1
- package/dist/cjs/store/AgentStore.d.ts.map +1 -1
- package/dist/cjs/store/ConfigStore.cjs +7 -3
- package/dist/cjs/store/ConfigStore.cjs.map +1 -1
- package/dist/cjs/store/ConfigStore.d.ts +1 -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/esm/config.d.ts +57 -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 +22 -16
- package/dist/esm/helpers/AIHelper.d.ts.map +1 -1
- package/dist/esm/helpers/AIHelper.js +134 -70
- 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 +43 -11
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +92 -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 +32 -0
- package/dist/esm/processors/ActivityProcessor.d.ts.map +1 -0
- package/dist/esm/processors/ActivityProcessor.js +36 -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 +82 -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 +43 -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 +71 -11
- package/dist/esm/processors/ChatProcessor.d.ts.map +1 -1
- package/dist/esm/processors/ChatProcessor.js +366 -126
- 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 +760 -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 +19 -7
- package/dist/esm/services/AIService.d.ts.map +1 -1
- package/dist/esm/services/AIService.js +91 -24
- package/dist/esm/services/AIService.js.map +1 -1
- 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/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/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/index.d.ts +0 -1
- package/dist/esm/services/index.d.ts.map +1 -1
- package/dist/esm/services/index.js +0 -1
- package/dist/esm/services/index.js.map +1 -1
- package/dist/esm/store/AgentStore.d.ts +2 -1
- package/dist/esm/store/AgentStore.d.ts.map +1 -1
- package/dist/esm/store/AgentStore.js +4 -2
- package/dist/esm/store/AgentStore.js.map +1 -1
- package/dist/esm/store/ConfigStore.d.ts +1 -0
- package/dist/esm/store/ConfigStore.d.ts.map +1 -1
- package/dist/esm/store/ConfigStore.js +7 -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/package.json +12 -12
- 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
|
@@ -1,26 +1,118 @@
|
|
|
1
|
-
import { AgentStatus, AgentToolCallStatus, ChatType, MessageRole, SortOrder, StreamChunkType } from '@multiplayer-app/ai-agent-types';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { AgentProcessEventType, agentStore } from '../store';
|
|
1
|
+
import { AgentStatus, AgentToolCallStatus, ChatType, MessageRole, SortOrder, StreamChunkType, ActivityOperationName, AgentToolType } from '@multiplayer-app/ai-agent-types';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { AIHelper, FileHelper } from '../helpers';
|
|
4
|
+
import { AgentProcessEventType } from '../store';
|
|
6
5
|
import { ContextLimiter } from '../helpers';
|
|
7
|
-
import {
|
|
8
|
-
import { PassThrough, pipeline } from 'stream';
|
|
9
|
-
import { promisify } from 'util';
|
|
6
|
+
import { PassThrough } from 'stream';
|
|
10
7
|
import { logger } from '../libs/logger';
|
|
11
|
-
|
|
8
|
+
import { ConfigStore } from '../store';
|
|
12
9
|
export class ChatProcessor {
|
|
10
|
+
aiHelper;
|
|
13
11
|
chatRepository;
|
|
14
12
|
messageRepository;
|
|
15
13
|
artifactStore;
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
14
|
+
activityRepository;
|
|
15
|
+
agentConfigRepository;
|
|
16
|
+
config;
|
|
17
|
+
socketService;
|
|
18
|
+
agentStore;
|
|
19
|
+
debug;
|
|
20
|
+
constructor(params) {
|
|
21
|
+
this.chatRepository = params.chatRepository;
|
|
22
|
+
this.messageRepository = params.messageRepository;
|
|
23
|
+
this.artifactStore = params.artifactStore;
|
|
24
|
+
this.config = params.config;
|
|
25
|
+
this.socketService = params.socketService;
|
|
26
|
+
this.agentStore = params.agentStore;
|
|
27
|
+
this.activityRepository = params.activityRepository;
|
|
28
|
+
this.agentConfigRepository = params.agentConfigRepository;
|
|
29
|
+
const fileHelper = new FileHelper(params.s3Lib, this.config);
|
|
30
|
+
this.aiHelper = new AIHelper(fileHelper, this.config);
|
|
31
|
+
this.debug = this.config.debug;
|
|
20
32
|
}
|
|
21
33
|
getTemporaryTitle(contextKey) {
|
|
22
34
|
return `${contextKey} session ${new Date().toISOString()}`;
|
|
23
35
|
}
|
|
36
|
+
isTemporaryTitle(title) {
|
|
37
|
+
// Matches pattern: "{contextKey} session {ISO_DATE_STRING}"
|
|
38
|
+
// Example: "default session 2026-01-23T10:30:45.123Z"
|
|
39
|
+
// toISOString() always includes milliseconds, so we require them
|
|
40
|
+
const pattern = /^.+ session \d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/;
|
|
41
|
+
return pattern.test(title);
|
|
42
|
+
}
|
|
43
|
+
isPlainObject(value) {
|
|
44
|
+
return !!value && typeof value === 'object' && !Array.isArray(value);
|
|
45
|
+
}
|
|
46
|
+
mergeMissingUsageFields(target, source) {
|
|
47
|
+
for (const [key, sourceValue] of Object.entries(source)) {
|
|
48
|
+
const targetValue = target[key];
|
|
49
|
+
if (targetValue === undefined) {
|
|
50
|
+
target[key] = sourceValue;
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
if (this.isPlainObject(targetValue) && this.isPlainObject(sourceValue)) {
|
|
54
|
+
this.mergeMissingUsageFields(targetValue, sourceValue);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
extractCostUsageFields(source) {
|
|
59
|
+
const extracted = {};
|
|
60
|
+
for (const [key, value] of Object.entries(source)) {
|
|
61
|
+
const normalizedKey = key.toLowerCase();
|
|
62
|
+
if (normalizedKey.includes('cost')) {
|
|
63
|
+
extracted[key] = value;
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
if (this.isPlainObject(value)) {
|
|
67
|
+
const nestedCostFields = this.extractCostUsageFields(value);
|
|
68
|
+
if (Object.keys(nestedCostFields).length > 0) {
|
|
69
|
+
extracted[key] = nestedCostFields;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return extracted;
|
|
74
|
+
}
|
|
75
|
+
mergeUsageWithProviderMetadata(stepUsage, providerMetadata) {
|
|
76
|
+
const mergedUsage = this.isPlainObject(stepUsage) ? { ...stepUsage } : {};
|
|
77
|
+
let hasProviderUsage = false;
|
|
78
|
+
if (this.isPlainObject(providerMetadata)) {
|
|
79
|
+
for (const providerEntry of Object.values(providerMetadata)) {
|
|
80
|
+
if (!this.isPlainObject(providerEntry) || !this.isPlainObject(providerEntry.usage)) {
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
const providerCostUsage = this.extractCostUsageFields(providerEntry.usage);
|
|
84
|
+
if (Object.keys(providerCostUsage).length === 0) {
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
hasProviderUsage = true;
|
|
88
|
+
this.mergeMissingUsageFields(mergedUsage, providerCostUsage);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
if (this.isPlainObject(stepUsage)) {
|
|
92
|
+
return mergedUsage;
|
|
93
|
+
}
|
|
94
|
+
if (hasProviderUsage) {
|
|
95
|
+
return mergedUsage;
|
|
96
|
+
}
|
|
97
|
+
return stepUsage;
|
|
98
|
+
}
|
|
99
|
+
async validateToolCallInput(params) {
|
|
100
|
+
const agentOptions = await this.aiHelper.getAgentOptions({
|
|
101
|
+
agentName: params.agentName,
|
|
102
|
+
});
|
|
103
|
+
const tool = agentOptions.tools?.[params.toolName] ?? undefined;
|
|
104
|
+
const schema = tool?.inputSchema;
|
|
105
|
+
if (!schema) {
|
|
106
|
+
throw new Error(`Tool "${params.toolName}" schema not found`);
|
|
107
|
+
}
|
|
108
|
+
if (!(schema instanceof z.ZodType)) {
|
|
109
|
+
throw new Error(`Tool "${params.toolName}" inputSchema must be a Zod schema`);
|
|
110
|
+
}
|
|
111
|
+
const result = schema.safeParse(params.input);
|
|
112
|
+
if (!result.success) {
|
|
113
|
+
throw new Error(`Invalid tool input for "${params.toolName}": ${result.error.message}`);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
24
116
|
async listChats(params) {
|
|
25
117
|
// Build filter object from params
|
|
26
118
|
const filter = {};
|
|
@@ -30,33 +122,56 @@ export class ChatProcessor {
|
|
|
30
122
|
if (params?.contextKey) {
|
|
31
123
|
filter.contextKey = params.contextKey;
|
|
32
124
|
}
|
|
33
|
-
// Build query options for sort and limit with defaults
|
|
125
|
+
// Build query options for sort and limit with defaults.
|
|
34
126
|
const options = {
|
|
35
127
|
sort: {
|
|
36
128
|
field: params?.sortField ?? 'updatedAt',
|
|
37
129
|
order: params?.sortOrder ?? SortOrder.Desc
|
|
38
130
|
},
|
|
131
|
+
skip: params?.skip,
|
|
39
132
|
limit: params?.limit
|
|
40
133
|
};
|
|
41
|
-
|
|
42
|
-
|
|
134
|
+
const [total, data] = await Promise.all([
|
|
135
|
+
this.chatRepository.count(filter),
|
|
136
|
+
this.chatRepository.find(filter, options)
|
|
137
|
+
]);
|
|
138
|
+
return {
|
|
139
|
+
cursor: {
|
|
140
|
+
...(params?.skip != null ? { skip: params.skip } : {}),
|
|
141
|
+
...(params?.limit != null ? { limit: params.limit } : {}),
|
|
142
|
+
total
|
|
143
|
+
},
|
|
144
|
+
data
|
|
145
|
+
};
|
|
43
146
|
}
|
|
44
147
|
async getChat(chatId) {
|
|
45
148
|
const chat = await this.chatRepository.findById(chatId);
|
|
46
149
|
if (!chat) {
|
|
47
150
|
throw new Error('Chat not found');
|
|
48
151
|
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
152
|
+
return chat;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Get messages for a chat with optional cursor pagination.
|
|
156
|
+
* When limit is omitted, returns all messages (backward compatible).
|
|
157
|
+
* Messages are returned in chronological order (oldest → newest).
|
|
158
|
+
*/
|
|
159
|
+
async getMessages(chatId, options) {
|
|
160
|
+
const chat = await this.chatRepository.findById(chatId);
|
|
161
|
+
if (!chat) {
|
|
162
|
+
throw new Error('Chat not found');
|
|
163
|
+
}
|
|
164
|
+
return this.messageRepository.findByChatIdPaginated(chatId, options);
|
|
54
165
|
}
|
|
55
166
|
async deleteChat(chatId) {
|
|
56
167
|
const deleted = await this.chatRepository.delete(chatId);
|
|
57
168
|
if (!deleted) {
|
|
58
169
|
throw new Error('Chat not found');
|
|
59
170
|
}
|
|
171
|
+
await Promise.all([
|
|
172
|
+
this.messageRepository.deleteByChatId(chatId),
|
|
173
|
+
this.activityRepository.deleteByGroupId(chatId), // todo: discuss if this is needed
|
|
174
|
+
]);
|
|
60
175
|
this.artifactStore.deleteArtifacts(chatId);
|
|
61
176
|
}
|
|
62
177
|
async upsertAndGetChat(payload, excludeSocketId) {
|
|
@@ -92,7 +207,7 @@ export class ChatProcessor {
|
|
|
92
207
|
if (!content) {
|
|
93
208
|
return this.getTemporaryTitle(payload.contextKey);
|
|
94
209
|
}
|
|
95
|
-
return
|
|
210
|
+
return this.aiHelper.generateTitleForMessage(payload.contextKey, [{
|
|
96
211
|
role: MessageRole.User,
|
|
97
212
|
content: content
|
|
98
213
|
}]);
|
|
@@ -108,7 +223,7 @@ export class ChatProcessor {
|
|
|
108
223
|
toolCalls: []
|
|
109
224
|
});
|
|
110
225
|
if (chat.userId) {
|
|
111
|
-
socketService.emitMessageUpdate(chat.userId, message, excludeSocketId);
|
|
226
|
+
this.socketService.emitMessageUpdate(chat.userId, message, excludeSocketId);
|
|
112
227
|
}
|
|
113
228
|
return message;
|
|
114
229
|
}
|
|
@@ -125,12 +240,7 @@ export class ChatProcessor {
|
|
|
125
240
|
metadata,
|
|
126
241
|
...(payload.model ? { model: payload.model } : {})
|
|
127
242
|
});
|
|
128
|
-
|
|
129
|
-
const initialChatResponse = {
|
|
130
|
-
...chat,
|
|
131
|
-
messages: []
|
|
132
|
-
};
|
|
133
|
-
socketService.emitChatUpdate(targetUserId, initialChatResponse, excludeSocketId);
|
|
243
|
+
this.socketService.emitChatUpdate(targetUserId, chat, excludeSocketId);
|
|
134
244
|
return chat;
|
|
135
245
|
}
|
|
136
246
|
/**
|
|
@@ -185,33 +295,75 @@ export class ChatProcessor {
|
|
|
185
295
|
await this.messageRepository.update(message.id, { toolCalls });
|
|
186
296
|
// Bump chat updatedAt so listChats ordering reflects the action.
|
|
187
297
|
await this.chatRepository.update(chat.id, { updatedAt: now });
|
|
188
|
-
socketService.emitMessageUpdate(chat.userId, updatedMessage, params.excludeSocketId);
|
|
298
|
+
this.socketService.emitMessageUpdate(chat.userId, updatedMessage, params.excludeSocketId);
|
|
189
299
|
if (params.systemMessage) {
|
|
190
300
|
//todo discuss support for system messages
|
|
191
301
|
//await this.createMessage(chat, MessageRole.System, params.systemMessage, undefined, params.excludeSocketId);
|
|
192
302
|
}
|
|
193
303
|
return { ok: true };
|
|
194
304
|
}
|
|
305
|
+
/**
|
|
306
|
+
* Update selected fields (input/output/status) on a specific tool call.
|
|
307
|
+
*/
|
|
308
|
+
async updateToolCall(params) {
|
|
309
|
+
if (params.input === undefined && params.output === undefined && params.status === undefined) {
|
|
310
|
+
throw new Error('At least one of input, output, or status must be provided');
|
|
311
|
+
}
|
|
312
|
+
const chat = await this.chatRepository.findById(params.chatId);
|
|
313
|
+
if (!chat) {
|
|
314
|
+
throw new Error('Chat not found');
|
|
315
|
+
}
|
|
316
|
+
if (params.userId && chat.userId !== params.userId) {
|
|
317
|
+
throw new Error('Chat does not belong to this user');
|
|
318
|
+
}
|
|
319
|
+
const message = await this.messageRepository.findById(params.messageId);
|
|
320
|
+
if (!message || message.chat !== params.chatId) {
|
|
321
|
+
throw new Error('Message not found or does not belong to this chat');
|
|
322
|
+
}
|
|
323
|
+
const targetToolCall = (message.toolCalls ?? []).find((tc) => tc.id === params.toolCallId);
|
|
324
|
+
if (!targetToolCall) {
|
|
325
|
+
throw new Error('Tool call not found in message');
|
|
326
|
+
}
|
|
327
|
+
if (params.input !== undefined) {
|
|
328
|
+
await this.validateToolCallInput({
|
|
329
|
+
agentName: message.agentName,
|
|
330
|
+
toolName: targetToolCall.name,
|
|
331
|
+
input: params.input,
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
const updatedMessage = await this.messageRepository.updateToolCall(params.messageId, params.toolCallId, {
|
|
335
|
+
...(params.input !== undefined ? { input: params.input } : {}),
|
|
336
|
+
...(params.output !== undefined ? { output: params.output } : {}),
|
|
337
|
+
...(params.status !== undefined ? { status: params.status } : {}),
|
|
338
|
+
});
|
|
339
|
+
if (!updatedMessage) {
|
|
340
|
+
throw new Error('Tool call not found in message');
|
|
341
|
+
}
|
|
342
|
+
const now = new Date().toISOString();
|
|
343
|
+
await this.chatRepository.update(chat.id, { updatedAt: now });
|
|
344
|
+
this.socketService.emitMessageUpdate(chat.userId, updatedMessage, params.excludeSocketId);
|
|
345
|
+
return updatedMessage;
|
|
346
|
+
}
|
|
195
347
|
async streamMessageStep(params) {
|
|
196
348
|
const { chat, assistantMessage, existingMessages, signal, excludeSocketId, agentOptions } = params;
|
|
197
349
|
if (signal.aborted) {
|
|
198
350
|
return;
|
|
199
351
|
}
|
|
200
|
-
const result = await
|
|
352
|
+
const result = await this.aiHelper.streamAssistantResponse(existingMessages, signal, agentOptions);
|
|
201
353
|
try {
|
|
202
354
|
for await (const chunk of result.fullStream) {
|
|
203
355
|
if (chunk.type === 'error') {
|
|
204
|
-
await agentStore.shareAgentProcessEvent(chat.id, { type: AgentProcessEventType.Error, data: chunk.error });
|
|
356
|
+
await this.agentStore.shareAgentProcessEvent(chat.id, { type: AgentProcessEventType.Error, data: chunk.error });
|
|
205
357
|
assistantMessage.content = chunk.error.message || 'Sorry, I cannot process you request due to the error';
|
|
206
358
|
await this.messageRepository.update(assistantMessage.id, assistantMessage);
|
|
207
359
|
await this.chatRepository.update(chat.id, { status: AgentStatus.Error });
|
|
208
360
|
continue;
|
|
209
361
|
}
|
|
210
362
|
if (chunk.type === 'abort') {
|
|
211
|
-
await agentStore.shareAgentProcessEvent(chat.id, { type: AgentProcessEventType.Aborted, data: undefined });
|
|
363
|
+
await this.agentStore.shareAgentProcessEvent(chat.id, { type: AgentProcessEventType.Aborted, data: undefined });
|
|
212
364
|
await this.chatRepository.update(chat.id, { status: AgentStatus.Aborted });
|
|
213
365
|
await this.messageRepository.update(assistantMessage.id, assistantMessage);
|
|
214
|
-
socketService.emitMessageUpdate(chat.userId, assistantMessage, excludeSocketId);
|
|
366
|
+
this.socketService.emitMessageUpdate(chat.userId, assistantMessage, excludeSocketId);
|
|
215
367
|
continue;
|
|
216
368
|
}
|
|
217
369
|
if (chunk.type === 'finish') {
|
|
@@ -229,37 +381,39 @@ export class ChatProcessor {
|
|
|
229
381
|
}
|
|
230
382
|
await this.messageRepository.update(assistantMessage.id, { ...assistantMessage });
|
|
231
383
|
if (chunk.finishReason === 'stop') {
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
384
|
+
await this.chatRepository.update(chat.id, { status: AgentStatus.Finished });
|
|
385
|
+
if (chat.title && this.isTemporaryTitle(chat.title)) {
|
|
386
|
+
const title = await this.aiHelper.generateTitleForMessage(chat.contextKey, existingMessages.filter(m => m.role === MessageRole.User), (stepResult) => {
|
|
387
|
+
return this.storeStepActivity({
|
|
388
|
+
chat,
|
|
389
|
+
stepResult,
|
|
390
|
+
name: ActivityOperationName.TITLE_GENERATION,
|
|
391
|
+
sourceId: chat.id,
|
|
392
|
+
sourceType: 'Chat',
|
|
393
|
+
tenants: params.tenants || {},
|
|
394
|
+
});
|
|
395
|
+
});
|
|
396
|
+
await this.chatRepository.update(chat.id, { title });
|
|
397
|
+
this.socketService.emitChatUpdate(chat.userId, { ...chat, title });
|
|
243
398
|
}
|
|
244
|
-
await agentStore.shareAgentProcessEvent(chat.id, { type: AgentProcessEventType.Finished, data: assistantMessage });
|
|
245
|
-
continue;
|
|
246
399
|
}
|
|
247
400
|
if (chunk.finishReason === 'tool-calls') {
|
|
248
401
|
if (assistantMessage.toolCalls?.some(toolCall => toolCall.requiresConfirmation && toolCall.approvalId && !toolCall.output)) {
|
|
249
402
|
await this.chatRepository.update(chat.id, { status: AgentStatus.WaitingForUserAction });
|
|
250
|
-
await agentStore.shareAgentProcessEvent(chat.id, { type: AgentProcessEventType.Finished, data: assistantMessage });
|
|
251
|
-
|
|
252
|
-
else {
|
|
253
|
-
await agentStore.shareAgentProcessEvent(chat.id, {
|
|
254
|
-
type: AgentProcessEventType.Update,
|
|
255
|
-
data: assistantMessage
|
|
256
|
-
});
|
|
257
|
-
await this.streamMessageStep(params);
|
|
403
|
+
await this.agentStore.shareAgentProcessEvent(chat.id, { type: AgentProcessEventType.Finished, data: assistantMessage });
|
|
404
|
+
continue;
|
|
258
405
|
}
|
|
259
|
-
continue;
|
|
260
406
|
}
|
|
261
407
|
//todo: Handle other finish reasons // length, content, error, other, undefined
|
|
262
|
-
await agentStore.shareAgentProcessEvent(chat.id, { type: AgentProcessEventType.Finished, data: assistantMessage });
|
|
408
|
+
await this.agentStore.shareAgentProcessEvent(chat.id, { type: AgentProcessEventType.Finished, data: assistantMessage });
|
|
409
|
+
if (assistantMessage.activity) {
|
|
410
|
+
const groupedMeta = await this.activityRepository.getGroupedMetadataByParentId(assistantMessage.activity);
|
|
411
|
+
await this.activityRepository.updateMetadata(assistantMessage.activity, {
|
|
412
|
+
usage: groupedMeta,
|
|
413
|
+
finishReason: chunk.finishReason,
|
|
414
|
+
responseTimestamp: new Date().toISOString(),
|
|
415
|
+
});
|
|
416
|
+
}
|
|
263
417
|
continue;
|
|
264
418
|
}
|
|
265
419
|
if (chunk.type === 'text-delta') {
|
|
@@ -268,8 +422,8 @@ export class ChatProcessor {
|
|
|
268
422
|
...assistantMessage,
|
|
269
423
|
content: assistantMessage.content
|
|
270
424
|
};
|
|
271
|
-
socketService.emitMessageUpdate(chat.userId, updatedMessage, excludeSocketId);
|
|
272
|
-
await agentStore.shareAgentProcessEvent(chat.id, { type: AgentProcessEventType.Update, data: updatedMessage });
|
|
425
|
+
this.socketService.emitMessageUpdate(chat.userId, updatedMessage, excludeSocketId);
|
|
426
|
+
await this.agentStore.shareAgentProcessEvent(chat.id, { type: AgentProcessEventType.Update, data: updatedMessage });
|
|
273
427
|
await this.messageRepository.update(assistantMessage.id, { content: assistantMessage.content });
|
|
274
428
|
continue;
|
|
275
429
|
}
|
|
@@ -284,7 +438,7 @@ export class ChatProcessor {
|
|
|
284
438
|
});
|
|
285
439
|
continue;
|
|
286
440
|
}
|
|
287
|
-
if (chunk.type === 'tool-call') {
|
|
441
|
+
if (chunk.type === 'tool-call') {
|
|
288
442
|
const toolCall = assistantMessage.toolCalls?.find(toolCall => toolCall.id === chunk.toolCallId);
|
|
289
443
|
if (toolCall) {
|
|
290
444
|
toolCall.status = AgentToolCallStatus.Running;
|
|
@@ -296,7 +450,7 @@ export class ChatProcessor {
|
|
|
296
450
|
const toolCall = assistantMessage.toolCalls?.find(toolCall => toolCall.id === chunk.toolCallId);
|
|
297
451
|
if (toolCall) {
|
|
298
452
|
toolCall.status = AgentToolCallStatus.Failed;
|
|
299
|
-
toolCall.error = JSON.stringify(chunk.error);
|
|
453
|
+
toolCall.error = chunk.error.message || JSON.stringify(chunk.error);
|
|
300
454
|
}
|
|
301
455
|
continue;
|
|
302
456
|
}
|
|
@@ -305,13 +459,16 @@ export class ChatProcessor {
|
|
|
305
459
|
if (toolCall) {
|
|
306
460
|
toolCall.requiresConfirmation = true;
|
|
307
461
|
toolCall.approvalId = chunk.approvalId;
|
|
462
|
+
if (toolCall.name === AgentToolType.REQUEST_CLARIFICATION) {
|
|
463
|
+
toolCall.requiresUserAction = true;
|
|
464
|
+
}
|
|
308
465
|
}
|
|
309
466
|
continue;
|
|
310
467
|
}
|
|
311
468
|
if (chunk.type === 'tool-result') {
|
|
312
469
|
const toolCall = assistantMessage.toolCalls?.find(toolCall => toolCall.id === chunk.toolCallId);
|
|
313
470
|
if (toolCall) {
|
|
314
|
-
if (chunk.output
|
|
471
|
+
if (chunk.output?.requiresApproval) {
|
|
315
472
|
toolCall.requiresConfirmation = true;
|
|
316
473
|
continue;
|
|
317
474
|
}
|
|
@@ -324,9 +481,9 @@ export class ChatProcessor {
|
|
|
324
481
|
if (!assistantMessage.reasoning)
|
|
325
482
|
assistantMessage.reasoning = '';
|
|
326
483
|
assistantMessage.reasoning += chunk.text;
|
|
327
|
-
socketService.emitMessageUpdate(chat.userId, assistantMessage, excludeSocketId);
|
|
484
|
+
this.socketService.emitMessageUpdate(chat.userId, assistantMessage, excludeSocketId);
|
|
328
485
|
await this.messageRepository.update(assistantMessage.id, { reasoning: assistantMessage.reasoning });
|
|
329
|
-
await agentStore.shareAgentProcessEvent(chat.id, { type: AgentProcessEventType.Update, data: assistantMessage });
|
|
486
|
+
await this.agentStore.shareAgentProcessEvent(chat.id, { type: AgentProcessEventType.Update, data: assistantMessage });
|
|
330
487
|
continue;
|
|
331
488
|
}
|
|
332
489
|
}
|
|
@@ -335,7 +492,7 @@ export class ChatProcessor {
|
|
|
335
492
|
if (streamError instanceof Error && streamError.name === 'AbortError') {
|
|
336
493
|
return;
|
|
337
494
|
}
|
|
338
|
-
await agentStore.shareAgentProcessEvent(chat.id, { type: AgentProcessEventType.Error, data: streamError });
|
|
495
|
+
await this.agentStore.shareAgentProcessEvent(chat.id, { type: AgentProcessEventType.Error, data: streamError });
|
|
339
496
|
throw streamError;
|
|
340
497
|
}
|
|
341
498
|
}
|
|
@@ -347,7 +504,7 @@ export class ChatProcessor {
|
|
|
347
504
|
if (!assistantMessage || assistantMessage.chat !== chat.id) {
|
|
348
505
|
throw new Error(`Assistant message with id ${payload.messageId} not found`);
|
|
349
506
|
}
|
|
350
|
-
const agentOptions = await
|
|
507
|
+
const agentOptions = await this.aiHelper.getAgentOptions({
|
|
351
508
|
agentName: assistantMessage.agentName,
|
|
352
509
|
context: payload.context
|
|
353
510
|
});
|
|
@@ -360,14 +517,20 @@ export class ChatProcessor {
|
|
|
360
517
|
};
|
|
361
518
|
}
|
|
362
519
|
toolCall.approved = payload.approved;
|
|
363
|
-
toolCall.
|
|
520
|
+
toolCall.userResponse = payload.userResponse;
|
|
364
521
|
if (!toolCall.approved) {
|
|
365
522
|
toolCall.output = {
|
|
366
523
|
type: 'execution-denied',
|
|
367
|
-
reason: toolCall.
|
|
524
|
+
reason: toolCall.userResponse
|
|
368
525
|
};
|
|
369
526
|
toolCall.status = AgentToolCallStatus.Failed;
|
|
370
527
|
}
|
|
528
|
+
else if (toolCall.requiresUserAction) {
|
|
529
|
+
toolCall.output = {
|
|
530
|
+
userResponse: toolCall.userResponse
|
|
531
|
+
};
|
|
532
|
+
toolCall.status = AgentToolCallStatus.Succeeded;
|
|
533
|
+
}
|
|
371
534
|
else {
|
|
372
535
|
const executeFunction = agentOptions.tools?.[toolCall.name]?.execute;
|
|
373
536
|
if (executeFunction) {
|
|
@@ -400,32 +563,105 @@ export class ChatProcessor {
|
|
|
400
563
|
}
|
|
401
564
|
async processNewUserMessage(chat, payload, prevMessages, excludeSocketId) {
|
|
402
565
|
const userMessage = await this.createMessage(chat, MessageRole.User, { content: payload.content, agentName: undefined }, payload.attachments);
|
|
403
|
-
await agentStore.shareAgentProcessEvent(chat.id, { type: AgentProcessEventType.Update, data: userMessage });
|
|
404
|
-
|
|
566
|
+
await this.agentStore.shareAgentProcessEvent(chat.id, { type: AgentProcessEventType.Update, data: userMessage });
|
|
567
|
+
let assistantMessage = await this.createMessage(chat, MessageRole.Assistant, { content: '', agentName: undefined }, undefined, excludeSocketId);
|
|
568
|
+
const parentActivity = await this.activityRepository.create({
|
|
569
|
+
ownerId: chat.userId,
|
|
570
|
+
groupId: chat.id,
|
|
571
|
+
name: ActivityOperationName.MESSAGE_PROCESSING,
|
|
572
|
+
tenants: payload.tenants ?? {},
|
|
573
|
+
sourceId: userMessage.id,
|
|
574
|
+
sourceType: 'AgentMessage',
|
|
575
|
+
metadata: {
|
|
576
|
+
contextKey: chat.contextKey,
|
|
577
|
+
modelId: this.aiHelper.getLanguageModelId(chat.model),
|
|
578
|
+
},
|
|
579
|
+
});
|
|
580
|
+
const agentOptions = await this.aiHelper.getAgentOptions({
|
|
405
581
|
contextKey: chat.contextKey,
|
|
406
|
-
messages:
|
|
582
|
+
messages: [...prevMessages, userMessage],
|
|
407
583
|
context: payload.context,
|
|
408
584
|
agentName: undefined,
|
|
409
585
|
modelId: chat.model,
|
|
586
|
+
}, {
|
|
587
|
+
onStepFinish: async (stepResult) => {
|
|
588
|
+
await this.storeStepActivity({
|
|
589
|
+
chat,
|
|
590
|
+
parentId: parentActivity.id,
|
|
591
|
+
stepResult,
|
|
592
|
+
name: ActivityOperationName.AGENT_SELECTION,
|
|
593
|
+
sourceId: userMessage.id,
|
|
594
|
+
sourceType: 'AgentMessage',
|
|
595
|
+
tenants: payload.tenants || {},
|
|
596
|
+
});
|
|
597
|
+
}
|
|
598
|
+
});
|
|
599
|
+
const updatedAssistantMessage = await this.messageRepository.update(assistantMessage.id, {
|
|
600
|
+
agentName: agentOptions.name,
|
|
601
|
+
activity: parentActivity.id
|
|
410
602
|
});
|
|
411
|
-
|
|
412
|
-
|
|
603
|
+
await this.activityRepository.update(parentActivity.id, {
|
|
604
|
+
metadata: {
|
|
605
|
+
...parentActivity.metadata,
|
|
606
|
+
agentOptions: {
|
|
607
|
+
name: agentOptions.name,
|
|
608
|
+
modelId: this.aiHelper.getLanguageModelId(agentOptions.model),
|
|
609
|
+
temperature: agentOptions.temperature,
|
|
610
|
+
maxOutputTokens: agentOptions.maxOutputTokens,
|
|
611
|
+
topP: agentOptions.topP,
|
|
612
|
+
topK: agentOptions.topK,
|
|
613
|
+
presencePenalty: agentOptions.presencePenalty,
|
|
614
|
+
frequencyPenalty: agentOptions.frequencyPenalty,
|
|
615
|
+
stopSequences: agentOptions.stopSequences,
|
|
616
|
+
seed: agentOptions.seed,
|
|
617
|
+
},
|
|
618
|
+
},
|
|
619
|
+
});
|
|
620
|
+
if (!updatedAssistantMessage) {
|
|
621
|
+
throw new Error(`Assistant message with id ${assistantMessage.id} not found after update`);
|
|
622
|
+
}
|
|
623
|
+
assistantMessage = updatedAssistantMessage;
|
|
413
624
|
return {
|
|
414
625
|
userMessage,
|
|
415
626
|
assistantMessage,
|
|
416
627
|
agentOptions,
|
|
417
628
|
};
|
|
418
629
|
}
|
|
630
|
+
async storeStepActivity(params) {
|
|
631
|
+
try {
|
|
632
|
+
const stepResult = params.stepResult;
|
|
633
|
+
const mergedUsage = this.mergeUsageWithProviderMetadata(stepResult.usage, stepResult.providerMetadata);
|
|
634
|
+
const activity = await this.activityRepository.create({
|
|
635
|
+
ownerId: params.chat.userId,
|
|
636
|
+
groupId: params.chat.id,
|
|
637
|
+
name: params.name,
|
|
638
|
+
tenants: params.tenants || {},
|
|
639
|
+
sourceId: params.sourceId,
|
|
640
|
+
sourceType: params.sourceType,
|
|
641
|
+
metadata: {
|
|
642
|
+
finishReason: stepResult.finishReason,
|
|
643
|
+
usage: mergedUsage,
|
|
644
|
+
responseTimestamp: stepResult.response.timestamp,
|
|
645
|
+
modelId: stepResult.response.modelId,
|
|
646
|
+
messages: this.debug ? stepResult.request?.body?.messages : undefined,
|
|
647
|
+
},
|
|
648
|
+
parentId: params.parentId,
|
|
649
|
+
});
|
|
650
|
+
}
|
|
651
|
+
catch (error) {
|
|
652
|
+
logger.error({ error, chatId: params.chat.id, parentId: params.parentId }, 'Failed to store step activity');
|
|
653
|
+
}
|
|
654
|
+
}
|
|
419
655
|
async streamMessage(chat, payload, excludeSocketId, onAgentStart) {
|
|
420
656
|
try {
|
|
421
|
-
const abortController = agentStore.registerAgentProcess(chat.id);
|
|
657
|
+
const abortController = this.agentStore.registerAgentProcess(chat.id);
|
|
422
658
|
onAgentStart?.();
|
|
423
659
|
let assistantMessage;
|
|
424
660
|
let agentOptions;
|
|
425
661
|
const existingMessages = await this.messageRepository.findByChatId(chat.id);
|
|
426
662
|
// Limit context to prevent exceeding token limits
|
|
427
663
|
const limitedMessages = ContextLimiter.limitContext(existingMessages, {
|
|
428
|
-
maxMessages: config.ai.maxContextMessages,
|
|
664
|
+
maxMessages: this.config.ai.maxContextMessages,
|
|
429
665
|
keepFirstUserMessage: true,
|
|
430
666
|
keepSystemMessages: true,
|
|
431
667
|
});
|
|
@@ -447,6 +683,19 @@ export class ChatProcessor {
|
|
|
447
683
|
agentOptions = result.agentOptions;
|
|
448
684
|
limitedMessages.push(result.userMessage);
|
|
449
685
|
}
|
|
686
|
+
agentOptions.onStepFinish = (stepResult) => {
|
|
687
|
+
return this.storeStepActivity({
|
|
688
|
+
chat,
|
|
689
|
+
parentId: assistantMessage.activity,
|
|
690
|
+
stepResult,
|
|
691
|
+
name: ActivityOperationName.STEP_FINISHED,
|
|
692
|
+
sourceId: assistantMessage.id,
|
|
693
|
+
sourceType: 'AgentMessage',
|
|
694
|
+
tenants: payload.tenants || {},
|
|
695
|
+
});
|
|
696
|
+
};
|
|
697
|
+
const userPreferences = await this.agentConfigRepository.findByUserIdAndAgentName(chat.userId, agentOptions.name);
|
|
698
|
+
agentOptions.activeTools = this.getAvailableTools(agentOptions, userPreferences);
|
|
450
699
|
await this.streamMessageStep({
|
|
451
700
|
chat,
|
|
452
701
|
existingMessages: limitedMessages,
|
|
@@ -454,12 +703,28 @@ export class ChatProcessor {
|
|
|
454
703
|
agentOptions,
|
|
455
704
|
excludeSocketId: excludeSocketId,
|
|
456
705
|
signal: abortController.signal,
|
|
706
|
+
tenants: payload.tenants || {},
|
|
457
707
|
});
|
|
458
708
|
}
|
|
459
709
|
catch (error) {
|
|
460
710
|
throw error;
|
|
461
711
|
}
|
|
462
712
|
}
|
|
713
|
+
getAvailableTools(agentOptions, userPreferences) {
|
|
714
|
+
const toolNames = Object.keys(agentOptions.tools || {});
|
|
715
|
+
const availableToolsMap = Object.fromEntries(toolNames.map(key => [key, true]));
|
|
716
|
+
const agentsConfiguration = ConfigStore.getInstance().getAgentConfigByName(agentOptions.name);
|
|
717
|
+
agentsConfiguration.tools.forEach((tool) => {
|
|
718
|
+
const toolTitle = tool.data?.title || tool.type;
|
|
719
|
+
if (tool.disabledByDefault) {
|
|
720
|
+
availableToolsMap[toolTitle] = false;
|
|
721
|
+
}
|
|
722
|
+
if (tool.userConfigurable && userPreferences?.tools?.[toolTitle] !== undefined) {
|
|
723
|
+
availableToolsMap[toolTitle] = userPreferences.tools[toolTitle];
|
|
724
|
+
}
|
|
725
|
+
});
|
|
726
|
+
return Object.keys(availableToolsMap).filter(key => availableToolsMap[key]);
|
|
727
|
+
}
|
|
463
728
|
listArtifacts(chatId) {
|
|
464
729
|
return this.artifactStore.listArtifacts(chatId);
|
|
465
730
|
}
|
|
@@ -490,7 +755,7 @@ export class ChatProcessor {
|
|
|
490
755
|
return null;
|
|
491
756
|
}
|
|
492
757
|
}
|
|
493
|
-
getMessageStream(chatId) {
|
|
758
|
+
getMessageStream(chatId, signal) {
|
|
494
759
|
const stream = new PassThrough();
|
|
495
760
|
let ended = false;
|
|
496
761
|
const endStream = (error) => {
|
|
@@ -511,13 +776,15 @@ export class ChatProcessor {
|
|
|
511
776
|
}
|
|
512
777
|
};
|
|
513
778
|
const pushChunk = (chunk) => {
|
|
514
|
-
if (ended || stream.destroyed || stream.writableEnded)
|
|
779
|
+
if (ended || stream.destroyed || stream.writableEnded || signal?.aborted)
|
|
515
780
|
return;
|
|
516
781
|
stream.write(`data: ${JSON.stringify(chunk)}\n\n`);
|
|
517
782
|
};
|
|
518
783
|
const listener = (event) => {
|
|
519
|
-
if (
|
|
784
|
+
if (signal?.aborted) {
|
|
785
|
+
endStream();
|
|
520
786
|
return;
|
|
787
|
+
}
|
|
521
788
|
try {
|
|
522
789
|
const chunk = this.eventToChunk(event);
|
|
523
790
|
if (chunk) {
|
|
@@ -527,7 +794,6 @@ export class ChatProcessor {
|
|
|
527
794
|
event.type === AgentProcessEventType.Error ||
|
|
528
795
|
event.type === AgentProcessEventType.Aborted) {
|
|
529
796
|
endStream();
|
|
530
|
-
agentStore.removeListener(chatId, listener);
|
|
531
797
|
}
|
|
532
798
|
}
|
|
533
799
|
catch (err) {
|
|
@@ -536,21 +802,18 @@ export class ChatProcessor {
|
|
|
536
802
|
error: err instanceof Error ? err.message : 'Unknown error occurred',
|
|
537
803
|
});
|
|
538
804
|
endStream(err);
|
|
539
|
-
agentStore.removeListener(chatId, listener);
|
|
540
805
|
}
|
|
541
806
|
};
|
|
542
|
-
// Cleanup on consumer side closing
|
|
543
807
|
const closeHandler = () => {
|
|
544
|
-
agentStore.removeListener(chatId, listener);
|
|
808
|
+
this.agentStore.removeListener(chatId, listener);
|
|
545
809
|
};
|
|
546
810
|
const errorHandler = (err) => {
|
|
547
|
-
|
|
548
|
-
agentStore.removeListener(chatId, listener);
|
|
811
|
+
signal?.removeEventListener('abort', endStream);
|
|
549
812
|
endStream(err);
|
|
550
813
|
};
|
|
551
814
|
stream.on('close', closeHandler);
|
|
552
815
|
stream.on('error', errorHandler);
|
|
553
|
-
const listenerAttached = agentStore.addListener(chatId, listener);
|
|
816
|
+
const listenerAttached = this.agentStore.addListener(chatId, listener);
|
|
554
817
|
if (!listenerAttached) {
|
|
555
818
|
// Remove stream listeners if listener attachment failed to prevent memory leak
|
|
556
819
|
stream.removeListener('close', closeHandler);
|
|
@@ -559,50 +822,27 @@ export class ChatProcessor {
|
|
|
559
822
|
}
|
|
560
823
|
return stream;
|
|
561
824
|
}
|
|
562
|
-
async createMessageStream(payload, excludeSocketId) {
|
|
825
|
+
async createMessageStream(payload, excludeSocketId, signal) {
|
|
563
826
|
const stream = new PassThrough();
|
|
564
|
-
(
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
// Send chat metadata first
|
|
568
|
-
if (!('chatId' in payload) && !('messageId' in payload) && chat) {
|
|
569
|
-
stream.write(`data: ${JSON.stringify({
|
|
570
|
-
type: 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
|
-
});
|
|
588
|
-
}
|
|
589
|
-
catch (error) {
|
|
590
|
-
logger.error({ error }, 'createMessageStream failed');
|
|
591
|
-
if (!stream.destroyed && !stream.writableEnded) {
|
|
592
|
-
stream.write(`data: ${JSON.stringify({
|
|
593
|
-
type: StreamChunkType.Error,
|
|
594
|
-
error: error instanceof Error ? error.message : 'Unknown error occurred',
|
|
595
|
-
})}\n\n`);
|
|
596
|
-
stream.write('data: [DONE]\n\n');
|
|
597
|
-
stream.end();
|
|
598
|
-
}
|
|
599
|
-
}
|
|
600
|
-
})().catch((err) => {
|
|
601
|
-
logger.error({ err }, 'Unhandled stream task error');
|
|
602
|
-
if (!stream.destroyed)
|
|
603
|
-
stream.destroy(err);
|
|
827
|
+
this.runMessageStream(stream, payload, excludeSocketId, signal)
|
|
828
|
+
.catch(err => {
|
|
829
|
+
logger.error({ err }, 'Stream task failed');
|
|
604
830
|
});
|
|
605
831
|
return stream;
|
|
606
832
|
}
|
|
833
|
+
async runMessageStream(stream, payload, excludeSocketId, signal) {
|
|
834
|
+
const chat = await this.upsertAndGetChat(payload, excludeSocketId);
|
|
835
|
+
if (!('chatId' in payload) && !('messageId' in payload) && chat) {
|
|
836
|
+
stream.write(`data: ${JSON.stringify({
|
|
837
|
+
type: StreamChunkType.Chat,
|
|
838
|
+
chatId: chat.id,
|
|
839
|
+
chat,
|
|
840
|
+
})}\n\n`);
|
|
841
|
+
}
|
|
842
|
+
await this.streamMessage(chat, payload, excludeSocketId, () => {
|
|
843
|
+
const messageStream = this.getMessageStream(chat.id, signal);
|
|
844
|
+
messageStream.pipe(stream);
|
|
845
|
+
});
|
|
846
|
+
}
|
|
607
847
|
}
|
|
608
848
|
//# sourceMappingURL=ChatProcessor.js.map
|