@multiplayer-app/ai-agent-node 0.1.0-beta.7 → 0.1.0-beta.70
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 +87 -45
- package/dist/cjs/config.cjs.map +1 -1
- package/dist/cjs/config.d.ts +60 -29
- 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 -26
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.d.ts +43 -10
- package/dist/cjs/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 +348 -126
- package/dist/cjs/processors/ChatProcessor.cjs.map +1 -1
- package/dist/cjs/processors/ChatProcessor.d.ts +70 -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 +7 -7
- 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/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 +60 -29
- package/dist/esm/config.d.ts.map +1 -1
- package/dist/esm/config.js +87 -43
- 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 -10
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +92 -10
- package/dist/esm/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 +70 -11
- package/dist/esm/processors/ChatProcessor.d.ts.map +1 -1
- package/dist/esm/processors/ChatProcessor.js +359 -130
- 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 +9 -5
- package/dist/esm/services/SocketService.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 -11
- package/dist/cjs/helpers/SetupHelper.cjs +0 -34
- package/dist/cjs/helpers/SetupHelper.cjs.map +0 -1
- package/dist/cjs/helpers/SetupHelper.d.ts +0 -4
- package/dist/cjs/helpers/SetupHelper.d.ts.map +0 -1
- package/dist/cjs/libs/logger/config.cjs +0 -9
- 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 -8
- package/dist/cjs/libs/s3/config.cjs.map +0 -1
- package/dist/cjs/libs/s3/config.d.ts +0 -4
- package/dist/cjs/libs/s3/config.d.ts.map +0 -1
- package/dist/esm/helpers/SetupHelper.d.ts +0 -4
- package/dist/esm/helpers/SetupHelper.d.ts.map +0 -1
- package/dist/esm/helpers/SetupHelper.js +0 -29
- package/dist/esm/helpers/SetupHelper.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 -6
- package/dist/esm/libs/logger/config.js.map +0 -1
- package/dist/esm/libs/s3/config.d.ts +0 -4
- package/dist/esm/libs/s3/config.d.ts.map +0 -1
- package/dist/esm/libs/s3/config.js +0 -5
- package/dist/esm/libs/s3/config.js.map +0 -1
|
@@ -1,21 +1,34 @@
|
|
|
1
|
-
import { AgentStatus, AgentToolCallStatus, ChatType, MessageRole, SortOrder, StreamChunkType } from '@multiplayer-app/ai-agent-types';
|
|
2
|
-
import {
|
|
3
|
-
import { AIHelper } from '../helpers';
|
|
4
|
-
import { AgentProcessEventType
|
|
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';
|
|
5
5
|
import { ContextLimiter } from '../helpers';
|
|
6
|
-
import {
|
|
7
|
-
import { PassThrough, pipeline } from 'stream';
|
|
8
|
-
import { promisify } from 'util';
|
|
6
|
+
import { PassThrough } from 'stream';
|
|
9
7
|
import { logger } from '../libs/logger';
|
|
10
|
-
|
|
8
|
+
import { ConfigStore } from '../store';
|
|
11
9
|
export class ChatProcessor {
|
|
10
|
+
aiHelper;
|
|
12
11
|
chatRepository;
|
|
13
12
|
messageRepository;
|
|
14
13
|
artifactStore;
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
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;
|
|
19
32
|
}
|
|
20
33
|
getTemporaryTitle(contextKey) {
|
|
21
34
|
return `${contextKey} session ${new Date().toISOString()}`;
|
|
@@ -27,6 +40,79 @@ export class ChatProcessor {
|
|
|
27
40
|
const pattern = /^.+ session \d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/;
|
|
28
41
|
return pattern.test(title);
|
|
29
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
|
+
}
|
|
30
116
|
async listChats(params) {
|
|
31
117
|
// Build filter object from params
|
|
32
118
|
const filter = {};
|
|
@@ -36,33 +122,56 @@ export class ChatProcessor {
|
|
|
36
122
|
if (params?.contextKey) {
|
|
37
123
|
filter.contextKey = params.contextKey;
|
|
38
124
|
}
|
|
39
|
-
// Build query options for sort and limit with defaults
|
|
125
|
+
// Build query options for sort and limit with defaults.
|
|
40
126
|
const options = {
|
|
41
127
|
sort: {
|
|
42
128
|
field: params?.sortField ?? 'updatedAt',
|
|
43
129
|
order: params?.sortOrder ?? SortOrder.Desc
|
|
44
130
|
},
|
|
131
|
+
skip: params?.skip,
|
|
45
132
|
limit: params?.limit
|
|
46
133
|
};
|
|
47
|
-
|
|
48
|
-
|
|
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
|
+
};
|
|
49
146
|
}
|
|
50
147
|
async getChat(chatId) {
|
|
51
148
|
const chat = await this.chatRepository.findById(chatId);
|
|
52
149
|
if (!chat) {
|
|
53
150
|
throw new Error('Chat not found');
|
|
54
151
|
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
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);
|
|
60
165
|
}
|
|
61
166
|
async deleteChat(chatId) {
|
|
62
167
|
const deleted = await this.chatRepository.delete(chatId);
|
|
63
168
|
if (!deleted) {
|
|
64
169
|
throw new Error('Chat not found');
|
|
65
170
|
}
|
|
171
|
+
await Promise.all([
|
|
172
|
+
this.messageRepository.deleteByChatId(chatId),
|
|
173
|
+
this.activityRepository.deleteByGroupId(chatId), // todo: discuss if this is needed
|
|
174
|
+
]);
|
|
66
175
|
this.artifactStore.deleteArtifacts(chatId);
|
|
67
176
|
}
|
|
68
177
|
async upsertAndGetChat(payload, excludeSocketId) {
|
|
@@ -98,7 +207,7 @@ export class ChatProcessor {
|
|
|
98
207
|
if (!content) {
|
|
99
208
|
return this.getTemporaryTitle(payload.contextKey);
|
|
100
209
|
}
|
|
101
|
-
return
|
|
210
|
+
return this.aiHelper.generateTitleForMessage(payload.contextKey, [{
|
|
102
211
|
role: MessageRole.User,
|
|
103
212
|
content: content
|
|
104
213
|
}]);
|
|
@@ -114,7 +223,7 @@ export class ChatProcessor {
|
|
|
114
223
|
toolCalls: []
|
|
115
224
|
});
|
|
116
225
|
if (chat.userId) {
|
|
117
|
-
socketService.emitMessageUpdate(chat.userId, message, excludeSocketId);
|
|
226
|
+
this.socketService.emitMessageUpdate(chat.userId, message, excludeSocketId);
|
|
118
227
|
}
|
|
119
228
|
return message;
|
|
120
229
|
}
|
|
@@ -131,12 +240,7 @@ export class ChatProcessor {
|
|
|
131
240
|
metadata,
|
|
132
241
|
...(payload.model ? { model: payload.model } : {})
|
|
133
242
|
});
|
|
134
|
-
|
|
135
|
-
const initialChatResponse = {
|
|
136
|
-
...chat,
|
|
137
|
-
messages: []
|
|
138
|
-
};
|
|
139
|
-
socketService.emitChatUpdate(targetUserId, initialChatResponse, excludeSocketId);
|
|
243
|
+
this.socketService.emitChatUpdate(targetUserId, chat, excludeSocketId);
|
|
140
244
|
return chat;
|
|
141
245
|
}
|
|
142
246
|
/**
|
|
@@ -191,33 +295,75 @@ export class ChatProcessor {
|
|
|
191
295
|
await this.messageRepository.update(message.id, { toolCalls });
|
|
192
296
|
// Bump chat updatedAt so listChats ordering reflects the action.
|
|
193
297
|
await this.chatRepository.update(chat.id, { updatedAt: now });
|
|
194
|
-
socketService.emitMessageUpdate(chat.userId, updatedMessage, params.excludeSocketId);
|
|
298
|
+
this.socketService.emitMessageUpdate(chat.userId, updatedMessage, params.excludeSocketId);
|
|
195
299
|
if (params.systemMessage) {
|
|
196
300
|
//todo discuss support for system messages
|
|
197
301
|
//await this.createMessage(chat, MessageRole.System, params.systemMessage, undefined, params.excludeSocketId);
|
|
198
302
|
}
|
|
199
303
|
return { ok: true };
|
|
200
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
|
+
}
|
|
201
347
|
async streamMessageStep(params) {
|
|
202
348
|
const { chat, assistantMessage, existingMessages, signal, excludeSocketId, agentOptions } = params;
|
|
203
349
|
if (signal.aborted) {
|
|
204
350
|
return;
|
|
205
351
|
}
|
|
206
|
-
const result = await
|
|
352
|
+
const result = await this.aiHelper.streamAssistantResponse(existingMessages, signal, agentOptions);
|
|
207
353
|
try {
|
|
208
354
|
for await (const chunk of result.fullStream) {
|
|
209
355
|
if (chunk.type === 'error') {
|
|
210
|
-
await agentStore.shareAgentProcessEvent(chat.id, { type: AgentProcessEventType.Error, data: chunk.error });
|
|
356
|
+
await this.agentStore.shareAgentProcessEvent(chat.id, { type: AgentProcessEventType.Error, data: chunk.error });
|
|
211
357
|
assistantMessage.content = chunk.error.message || 'Sorry, I cannot process you request due to the error';
|
|
212
358
|
await this.messageRepository.update(assistantMessage.id, assistantMessage);
|
|
213
359
|
await this.chatRepository.update(chat.id, { status: AgentStatus.Error });
|
|
214
360
|
continue;
|
|
215
361
|
}
|
|
216
362
|
if (chunk.type === 'abort') {
|
|
217
|
-
await agentStore.shareAgentProcessEvent(chat.id, { type: AgentProcessEventType.Aborted, data: undefined });
|
|
363
|
+
await this.agentStore.shareAgentProcessEvent(chat.id, { type: AgentProcessEventType.Aborted, data: undefined });
|
|
218
364
|
await this.chatRepository.update(chat.id, { status: AgentStatus.Aborted });
|
|
219
365
|
await this.messageRepository.update(assistantMessage.id, assistantMessage);
|
|
220
|
-
socketService.emitMessageUpdate(chat.userId, assistantMessage, excludeSocketId);
|
|
366
|
+
this.socketService.emitMessageUpdate(chat.userId, assistantMessage, excludeSocketId);
|
|
221
367
|
continue;
|
|
222
368
|
}
|
|
223
369
|
if (chunk.type === 'finish') {
|
|
@@ -235,42 +381,39 @@ export class ChatProcessor {
|
|
|
235
381
|
}
|
|
236
382
|
await this.messageRepository.update(assistantMessage.id, { ...assistantMessage });
|
|
237
383
|
if (chunk.finishReason === 'stop') {
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
socketService.emitChatUpdate(chat.userId, { ...chat, title, messages: [] });
|
|
253
|
-
}
|
|
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 });
|
|
254
398
|
}
|
|
255
|
-
await agentStore.shareAgentProcessEvent(chat.id, { type: AgentProcessEventType.Finished, data: assistantMessage });
|
|
256
|
-
continue;
|
|
257
399
|
}
|
|
258
400
|
if (chunk.finishReason === 'tool-calls') {
|
|
259
401
|
if (assistantMessage.toolCalls?.some(toolCall => toolCall.requiresConfirmation && toolCall.approvalId && !toolCall.output)) {
|
|
260
402
|
await this.chatRepository.update(chat.id, { status: AgentStatus.WaitingForUserAction });
|
|
261
|
-
await agentStore.shareAgentProcessEvent(chat.id, { type: AgentProcessEventType.Finished, data: assistantMessage });
|
|
262
|
-
|
|
263
|
-
else {
|
|
264
|
-
await agentStore.shareAgentProcessEvent(chat.id, {
|
|
265
|
-
type: AgentProcessEventType.Update,
|
|
266
|
-
data: assistantMessage
|
|
267
|
-
});
|
|
268
|
-
await this.streamMessageStep(params);
|
|
403
|
+
await this.agentStore.shareAgentProcessEvent(chat.id, { type: AgentProcessEventType.Finished, data: assistantMessage });
|
|
404
|
+
continue;
|
|
269
405
|
}
|
|
270
|
-
continue;
|
|
271
406
|
}
|
|
272
407
|
//todo: Handle other finish reasons // length, content, error, other, undefined
|
|
273
|
-
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
|
+
}
|
|
274
417
|
continue;
|
|
275
418
|
}
|
|
276
419
|
if (chunk.type === 'text-delta') {
|
|
@@ -279,8 +422,8 @@ export class ChatProcessor {
|
|
|
279
422
|
...assistantMessage,
|
|
280
423
|
content: assistantMessage.content
|
|
281
424
|
};
|
|
282
|
-
socketService.emitMessageUpdate(chat.userId, updatedMessage, excludeSocketId);
|
|
283
|
-
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 });
|
|
284
427
|
await this.messageRepository.update(assistantMessage.id, { content: assistantMessage.content });
|
|
285
428
|
continue;
|
|
286
429
|
}
|
|
@@ -295,7 +438,7 @@ export class ChatProcessor {
|
|
|
295
438
|
});
|
|
296
439
|
continue;
|
|
297
440
|
}
|
|
298
|
-
if (chunk.type === 'tool-call') {
|
|
441
|
+
if (chunk.type === 'tool-call') {
|
|
299
442
|
const toolCall = assistantMessage.toolCalls?.find(toolCall => toolCall.id === chunk.toolCallId);
|
|
300
443
|
if (toolCall) {
|
|
301
444
|
toolCall.status = AgentToolCallStatus.Running;
|
|
@@ -307,7 +450,7 @@ export class ChatProcessor {
|
|
|
307
450
|
const toolCall = assistantMessage.toolCalls?.find(toolCall => toolCall.id === chunk.toolCallId);
|
|
308
451
|
if (toolCall) {
|
|
309
452
|
toolCall.status = AgentToolCallStatus.Failed;
|
|
310
|
-
toolCall.error = JSON.stringify(chunk.error);
|
|
453
|
+
toolCall.error = chunk.error.message || JSON.stringify(chunk.error);
|
|
311
454
|
}
|
|
312
455
|
continue;
|
|
313
456
|
}
|
|
@@ -316,13 +459,16 @@ export class ChatProcessor {
|
|
|
316
459
|
if (toolCall) {
|
|
317
460
|
toolCall.requiresConfirmation = true;
|
|
318
461
|
toolCall.approvalId = chunk.approvalId;
|
|
462
|
+
if (toolCall.name === AgentToolType.REQUEST_CLARIFICATION) {
|
|
463
|
+
toolCall.requiresUserAction = true;
|
|
464
|
+
}
|
|
319
465
|
}
|
|
320
466
|
continue;
|
|
321
467
|
}
|
|
322
468
|
if (chunk.type === 'tool-result') {
|
|
323
469
|
const toolCall = assistantMessage.toolCalls?.find(toolCall => toolCall.id === chunk.toolCallId);
|
|
324
470
|
if (toolCall) {
|
|
325
|
-
if (chunk.output
|
|
471
|
+
if (chunk.output?.requiresApproval) {
|
|
326
472
|
toolCall.requiresConfirmation = true;
|
|
327
473
|
continue;
|
|
328
474
|
}
|
|
@@ -335,9 +481,9 @@ export class ChatProcessor {
|
|
|
335
481
|
if (!assistantMessage.reasoning)
|
|
336
482
|
assistantMessage.reasoning = '';
|
|
337
483
|
assistantMessage.reasoning += chunk.text;
|
|
338
|
-
socketService.emitMessageUpdate(chat.userId, assistantMessage, excludeSocketId);
|
|
484
|
+
this.socketService.emitMessageUpdate(chat.userId, assistantMessage, excludeSocketId);
|
|
339
485
|
await this.messageRepository.update(assistantMessage.id, { reasoning: assistantMessage.reasoning });
|
|
340
|
-
await agentStore.shareAgentProcessEvent(chat.id, { type: AgentProcessEventType.Update, data: assistantMessage });
|
|
486
|
+
await this.agentStore.shareAgentProcessEvent(chat.id, { type: AgentProcessEventType.Update, data: assistantMessage });
|
|
341
487
|
continue;
|
|
342
488
|
}
|
|
343
489
|
}
|
|
@@ -346,7 +492,7 @@ export class ChatProcessor {
|
|
|
346
492
|
if (streamError instanceof Error && streamError.name === 'AbortError') {
|
|
347
493
|
return;
|
|
348
494
|
}
|
|
349
|
-
await agentStore.shareAgentProcessEvent(chat.id, { type: AgentProcessEventType.Error, data: streamError });
|
|
495
|
+
await this.agentStore.shareAgentProcessEvent(chat.id, { type: AgentProcessEventType.Error, data: streamError });
|
|
350
496
|
throw streamError;
|
|
351
497
|
}
|
|
352
498
|
}
|
|
@@ -358,7 +504,7 @@ export class ChatProcessor {
|
|
|
358
504
|
if (!assistantMessage || assistantMessage.chat !== chat.id) {
|
|
359
505
|
throw new Error(`Assistant message with id ${payload.messageId} not found`);
|
|
360
506
|
}
|
|
361
|
-
const agentOptions = await
|
|
507
|
+
const agentOptions = await this.aiHelper.getAgentOptions({
|
|
362
508
|
agentName: assistantMessage.agentName,
|
|
363
509
|
context: payload.context
|
|
364
510
|
});
|
|
@@ -371,14 +517,20 @@ export class ChatProcessor {
|
|
|
371
517
|
};
|
|
372
518
|
}
|
|
373
519
|
toolCall.approved = payload.approved;
|
|
374
|
-
toolCall.
|
|
520
|
+
toolCall.userResponse = payload.userResponse;
|
|
375
521
|
if (!toolCall.approved) {
|
|
376
522
|
toolCall.output = {
|
|
377
523
|
type: 'execution-denied',
|
|
378
|
-
reason: toolCall.
|
|
524
|
+
reason: toolCall.userResponse
|
|
379
525
|
};
|
|
380
526
|
toolCall.status = AgentToolCallStatus.Failed;
|
|
381
527
|
}
|
|
528
|
+
else if (toolCall.requiresUserAction) {
|
|
529
|
+
toolCall.output = {
|
|
530
|
+
userResponse: toolCall.userResponse
|
|
531
|
+
};
|
|
532
|
+
toolCall.status = AgentToolCallStatus.Succeeded;
|
|
533
|
+
}
|
|
382
534
|
else {
|
|
383
535
|
const executeFunction = agentOptions.tools?.[toolCall.name]?.execute;
|
|
384
536
|
if (executeFunction) {
|
|
@@ -411,32 +563,105 @@ export class ChatProcessor {
|
|
|
411
563
|
}
|
|
412
564
|
async processNewUserMessage(chat, payload, prevMessages, excludeSocketId) {
|
|
413
565
|
const userMessage = await this.createMessage(chat, MessageRole.User, { content: payload.content, agentName: undefined }, payload.attachments);
|
|
414
|
-
await agentStore.shareAgentProcessEvent(chat.id, { type: AgentProcessEventType.Update, data: userMessage });
|
|
415
|
-
|
|
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({
|
|
416
581
|
contextKey: chat.contextKey,
|
|
417
|
-
messages:
|
|
582
|
+
messages: [...prevMessages, userMessage],
|
|
418
583
|
context: payload.context,
|
|
419
584
|
agentName: undefined,
|
|
420
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
|
|
421
602
|
});
|
|
422
|
-
|
|
423
|
-
|
|
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;
|
|
424
624
|
return {
|
|
425
625
|
userMessage,
|
|
426
626
|
assistantMessage,
|
|
427
627
|
agentOptions,
|
|
428
628
|
};
|
|
429
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
|
+
}
|
|
430
655
|
async streamMessage(chat, payload, excludeSocketId, onAgentStart) {
|
|
431
656
|
try {
|
|
432
|
-
const abortController = agentStore.registerAgentProcess(chat.id);
|
|
657
|
+
const abortController = this.agentStore.registerAgentProcess(chat.id);
|
|
433
658
|
onAgentStart?.();
|
|
434
659
|
let assistantMessage;
|
|
435
660
|
let agentOptions;
|
|
436
661
|
const existingMessages = await this.messageRepository.findByChatId(chat.id);
|
|
437
662
|
// Limit context to prevent exceeding token limits
|
|
438
663
|
const limitedMessages = ContextLimiter.limitContext(existingMessages, {
|
|
439
|
-
maxMessages: config.ai.maxContextMessages,
|
|
664
|
+
maxMessages: this.config.ai.maxContextMessages,
|
|
440
665
|
keepFirstUserMessage: true,
|
|
441
666
|
keepSystemMessages: true,
|
|
442
667
|
});
|
|
@@ -458,6 +683,19 @@ export class ChatProcessor {
|
|
|
458
683
|
agentOptions = result.agentOptions;
|
|
459
684
|
limitedMessages.push(result.userMessage);
|
|
460
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);
|
|
461
699
|
await this.streamMessageStep({
|
|
462
700
|
chat,
|
|
463
701
|
existingMessages: limitedMessages,
|
|
@@ -465,12 +703,28 @@ export class ChatProcessor {
|
|
|
465
703
|
agentOptions,
|
|
466
704
|
excludeSocketId: excludeSocketId,
|
|
467
705
|
signal: abortController.signal,
|
|
706
|
+
tenants: payload.tenants || {},
|
|
468
707
|
});
|
|
469
708
|
}
|
|
470
709
|
catch (error) {
|
|
471
710
|
throw error;
|
|
472
711
|
}
|
|
473
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
|
+
}
|
|
474
728
|
listArtifacts(chatId) {
|
|
475
729
|
return this.artifactStore.listArtifacts(chatId);
|
|
476
730
|
}
|
|
@@ -501,7 +755,7 @@ export class ChatProcessor {
|
|
|
501
755
|
return null;
|
|
502
756
|
}
|
|
503
757
|
}
|
|
504
|
-
getMessageStream(chatId) {
|
|
758
|
+
getMessageStream(chatId, signal) {
|
|
505
759
|
const stream = new PassThrough();
|
|
506
760
|
let ended = false;
|
|
507
761
|
const endStream = (error) => {
|
|
@@ -522,13 +776,15 @@ export class ChatProcessor {
|
|
|
522
776
|
}
|
|
523
777
|
};
|
|
524
778
|
const pushChunk = (chunk) => {
|
|
525
|
-
if (ended || stream.destroyed || stream.writableEnded)
|
|
779
|
+
if (ended || stream.destroyed || stream.writableEnded || signal?.aborted)
|
|
526
780
|
return;
|
|
527
781
|
stream.write(`data: ${JSON.stringify(chunk)}\n\n`);
|
|
528
782
|
};
|
|
529
783
|
const listener = (event) => {
|
|
530
|
-
if (
|
|
784
|
+
if (signal?.aborted) {
|
|
785
|
+
endStream();
|
|
531
786
|
return;
|
|
787
|
+
}
|
|
532
788
|
try {
|
|
533
789
|
const chunk = this.eventToChunk(event);
|
|
534
790
|
if (chunk) {
|
|
@@ -538,7 +794,6 @@ export class ChatProcessor {
|
|
|
538
794
|
event.type === AgentProcessEventType.Error ||
|
|
539
795
|
event.type === AgentProcessEventType.Aborted) {
|
|
540
796
|
endStream();
|
|
541
|
-
agentStore.removeListener(chatId, listener);
|
|
542
797
|
}
|
|
543
798
|
}
|
|
544
799
|
catch (err) {
|
|
@@ -547,21 +802,18 @@ export class ChatProcessor {
|
|
|
547
802
|
error: err instanceof Error ? err.message : 'Unknown error occurred',
|
|
548
803
|
});
|
|
549
804
|
endStream(err);
|
|
550
|
-
agentStore.removeListener(chatId, listener);
|
|
551
805
|
}
|
|
552
806
|
};
|
|
553
|
-
// Cleanup on consumer side closing
|
|
554
807
|
const closeHandler = () => {
|
|
555
|
-
agentStore.removeListener(chatId, listener);
|
|
808
|
+
this.agentStore.removeListener(chatId, listener);
|
|
556
809
|
};
|
|
557
810
|
const errorHandler = (err) => {
|
|
558
|
-
|
|
559
|
-
agentStore.removeListener(chatId, listener);
|
|
811
|
+
signal?.removeEventListener('abort', endStream);
|
|
560
812
|
endStream(err);
|
|
561
813
|
};
|
|
562
814
|
stream.on('close', closeHandler);
|
|
563
815
|
stream.on('error', errorHandler);
|
|
564
|
-
const listenerAttached = agentStore.addListener(chatId, listener);
|
|
816
|
+
const listenerAttached = this.agentStore.addListener(chatId, listener);
|
|
565
817
|
if (!listenerAttached) {
|
|
566
818
|
// Remove stream listeners if listener attachment failed to prevent memory leak
|
|
567
819
|
stream.removeListener('close', closeHandler);
|
|
@@ -570,50 +822,27 @@ export class ChatProcessor {
|
|
|
570
822
|
}
|
|
571
823
|
return stream;
|
|
572
824
|
}
|
|
573
|
-
async createMessageStream(payload, excludeSocketId) {
|
|
825
|
+
async createMessageStream(payload, excludeSocketId, signal) {
|
|
574
826
|
const stream = new PassThrough();
|
|
575
|
-
(
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
// Send chat metadata first
|
|
579
|
-
if (!('chatId' in payload) && !('messageId' in payload) && chat) {
|
|
580
|
-
stream.write(`data: ${JSON.stringify({
|
|
581
|
-
type: StreamChunkType.Chat,
|
|
582
|
-
chatId: chat.id,
|
|
583
|
-
chat,
|
|
584
|
-
})}\n\n`);
|
|
585
|
-
}
|
|
586
|
-
await this.streamMessage(chat, payload, excludeSocketId, async () => {
|
|
587
|
-
if (stream.destroyed || stream.writableEnded) {
|
|
588
|
-
return;
|
|
589
|
-
}
|
|
590
|
-
const messageStream = this.getMessageStream(chat.id);
|
|
591
|
-
// If client disconnects, destroy inner stream
|
|
592
|
-
stream.on('close', () => {
|
|
593
|
-
if (!messageStream.destroyed) {
|
|
594
|
-
messageStream.destroy();
|
|
595
|
-
}
|
|
596
|
-
});
|
|
597
|
-
await pipelineAsync(messageStream, stream);
|
|
598
|
-
});
|
|
599
|
-
}
|
|
600
|
-
catch (error) {
|
|
601
|
-
logger.error({ error }, 'createMessageStream failed');
|
|
602
|
-
if (!stream.destroyed && !stream.writableEnded) {
|
|
603
|
-
stream.write(`data: ${JSON.stringify({
|
|
604
|
-
type: StreamChunkType.Error,
|
|
605
|
-
error: error instanceof Error ? error.message : 'Unknown error occurred',
|
|
606
|
-
})}\n\n`);
|
|
607
|
-
stream.write('data: [DONE]\n\n');
|
|
608
|
-
stream.end();
|
|
609
|
-
}
|
|
610
|
-
}
|
|
611
|
-
})().catch((err) => {
|
|
612
|
-
logger.error({ err }, 'Unhandled stream task error');
|
|
613
|
-
if (!stream.destroyed)
|
|
614
|
-
stream.destroy(err);
|
|
827
|
+
this.runMessageStream(stream, payload, excludeSocketId, signal)
|
|
828
|
+
.catch(err => {
|
|
829
|
+
logger.error({ err }, 'Stream task failed');
|
|
615
830
|
});
|
|
616
831
|
return stream;
|
|
617
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
|
+
}
|
|
618
847
|
}
|
|
619
848
|
//# sourceMappingURL=ChatProcessor.js.map
|