@multiplayer-app/ai-agent-node 0.1.0-beta.73 → 0.1.0-beta.75
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/helpers/AIHelper.cjs +5 -3
- package/dist/cjs/helpers/AIHelper.cjs.map +1 -1
- package/dist/cjs/helpers/AIHelper.d.ts +2 -1
- package/dist/cjs/helpers/AIHelper.d.ts.map +1 -1
- package/dist/cjs/processors/ActivityProcessor.cjs +16 -2
- package/dist/cjs/processors/ActivityProcessor.cjs.map +1 -1
- package/dist/cjs/processors/ActivityProcessor.d.ts +2 -0
- package/dist/cjs/processors/ActivityProcessor.d.ts.map +1 -1
- package/dist/cjs/processors/ActivityProcessor.test.cjs +63 -8
- package/dist/cjs/processors/ActivityProcessor.test.cjs.map +1 -1
- package/dist/cjs/processors/AgentProcessor.cjs +4 -3
- package/dist/cjs/processors/AgentProcessor.cjs.map +1 -1
- package/dist/cjs/processors/AgentProcessor.d.ts.map +1 -1
- package/dist/cjs/processors/ChatProcessor.cjs +330 -32
- package/dist/cjs/processors/ChatProcessor.cjs.map +1 -1
- package/dist/cjs/processors/ChatProcessor.d.ts +12 -2
- package/dist/cjs/processors/ChatProcessor.d.ts.map +1 -1
- package/dist/cjs/processors/ChatProcessor.test.cjs +41 -0
- package/dist/cjs/processors/ChatProcessor.test.cjs.map +1 -1
- package/dist/cjs/services/AIService.cjs +25 -20
- package/dist/cjs/services/AIService.cjs.map +1 -1
- package/dist/cjs/services/AIService.d.ts.map +1 -1
- package/dist/cjs/store/AgentStore.cjs +11 -0
- package/dist/cjs/store/AgentStore.cjs.map +1 -1
- package/dist/cjs/store/AgentStore.d.ts +1 -0
- package/dist/cjs/store/AgentStore.d.ts.map +1 -1
- package/dist/cjs/store/ConfigStore.cjs +7 -0
- 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/tsconfig.cjs.tsbuildinfo +1 -1
- package/dist/cjs/utils/utils.cjs +31 -0
- package/dist/cjs/utils/utils.cjs.map +1 -0
- package/dist/cjs/utils/utils.d.ts +5 -0
- package/dist/cjs/utils/utils.d.ts.map +1 -0
- package/dist/esm/helpers/AIHelper.d.ts +2 -1
- package/dist/esm/helpers/AIHelper.d.ts.map +1 -1
- package/dist/esm/helpers/AIHelper.js +5 -3
- package/dist/esm/helpers/AIHelper.js.map +1 -1
- package/dist/esm/processors/ActivityProcessor.d.ts +2 -0
- package/dist/esm/processors/ActivityProcessor.d.ts.map +1 -1
- package/dist/esm/processors/ActivityProcessor.js +16 -2
- package/dist/esm/processors/ActivityProcessor.js.map +1 -1
- package/dist/esm/processors/ActivityProcessor.test.js +63 -8
- package/dist/esm/processors/ActivityProcessor.test.js.map +1 -1
- package/dist/esm/processors/AgentProcessor.d.ts.map +1 -1
- package/dist/esm/processors/AgentProcessor.js +4 -3
- package/dist/esm/processors/AgentProcessor.js.map +1 -1
- package/dist/esm/processors/ChatProcessor.d.ts +12 -2
- package/dist/esm/processors/ChatProcessor.d.ts.map +1 -1
- package/dist/esm/processors/ChatProcessor.js +330 -32
- package/dist/esm/processors/ChatProcessor.js.map +1 -1
- package/dist/esm/processors/ChatProcessor.test.js +41 -0
- package/dist/esm/processors/ChatProcessor.test.js.map +1 -1
- package/dist/esm/services/AIService.d.ts.map +1 -1
- package/dist/esm/services/AIService.js +25 -20
- package/dist/esm/services/AIService.js.map +1 -1
- package/dist/esm/store/AgentStore.d.ts +1 -0
- package/dist/esm/store/AgentStore.d.ts.map +1 -1
- package/dist/esm/store/AgentStore.js +11 -0
- 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 -0
- package/dist/esm/store/ConfigStore.js.map +1 -1
- package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
- package/dist/esm/utils/utils.d.ts +5 -0
- package/dist/esm/utils/utils.d.ts.map +1 -0
- package/dist/esm/utils/utils.js +26 -0
- package/dist/esm/utils/utils.js.map +1 -0
- package/package.json +3 -3
|
@@ -3,12 +3,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.ChatProcessor = void 0;
|
|
4
4
|
const ai_agent_types_1 = require("@multiplayer-app/ai-agent-types");
|
|
5
5
|
const zod_1 = require("zod");
|
|
6
|
-
const helpers_1 = require("../helpers/index.cjs");
|
|
7
6
|
const store_1 = require("../store/index.cjs");
|
|
8
|
-
const
|
|
7
|
+
const helpers_1 = require("../helpers/index.cjs");
|
|
9
8
|
const stream_1 = require("stream");
|
|
10
9
|
const logger_1 = require("../libs/logger/index.cjs");
|
|
11
|
-
const
|
|
10
|
+
const ai_agent_types_2 = require("@multiplayer-app/ai-agent-types");
|
|
11
|
+
const utils_1 = require("../utils/utils.cjs");
|
|
12
12
|
class ChatProcessor {
|
|
13
13
|
constructor(params) {
|
|
14
14
|
this.chatRepository = params.chatRepository;
|
|
@@ -43,6 +43,117 @@ class ChatProcessor {
|
|
|
43
43
|
}
|
|
44
44
|
return payload.tenants ?? {};
|
|
45
45
|
}
|
|
46
|
+
async updateChatAndEmit(chat, update, excludeSocketId) {
|
|
47
|
+
await this.chatRepository.update(chat.id, update);
|
|
48
|
+
const updatedChat = await this.chatRepository.findById(chat.id);
|
|
49
|
+
const chatToEmit = updatedChat ?? { ...chat, ...update };
|
|
50
|
+
this.socketService.emitChatUpdate(chat.userId, chatToEmit, excludeSocketId);
|
|
51
|
+
return chatToEmit;
|
|
52
|
+
}
|
|
53
|
+
async startSubagentProcess(params) {
|
|
54
|
+
const childChat = await this.chatRepository.create({
|
|
55
|
+
title: `${params.subAgentConfig.name} subagent`,
|
|
56
|
+
type: ai_agent_types_1.ChatType.Agent,
|
|
57
|
+
status: ai_agent_types_1.AgentStatus.Streaming,
|
|
58
|
+
sessionKind: ai_agent_types_2.AgentSessionKind.SUBAGENT,
|
|
59
|
+
parentChatId: params.parentChat.id,
|
|
60
|
+
parentMessageId: params.parentMessage.id,
|
|
61
|
+
parentToolCallId: params.parentToolCallId,
|
|
62
|
+
contextKey: params.parentChat.contextKey,
|
|
63
|
+
userId: params.parentChat.userId,
|
|
64
|
+
model: params.subAgentConfig.defaultModel || params.parentChat.model,
|
|
65
|
+
});
|
|
66
|
+
try {
|
|
67
|
+
const parentToolCall = params.parentMessage.toolCalls?.find((toolCall) => toolCall.id === params.parentToolCallId);
|
|
68
|
+
if (parentToolCall) {
|
|
69
|
+
parentToolCall.input = {
|
|
70
|
+
...(parentToolCall.input ?? {}),
|
|
71
|
+
subagentChatId: childChat.id,
|
|
72
|
+
};
|
|
73
|
+
parentToolCall.subagentChatId = childChat.id;
|
|
74
|
+
const updatedParentMessage = await this.messageRepository.update(params.parentMessage.id, {
|
|
75
|
+
toolCalls: params.parentMessage.toolCalls,
|
|
76
|
+
});
|
|
77
|
+
if (updatedParentMessage) {
|
|
78
|
+
this.socketService.emitMessageUpdate(params.parentChat.userId, updatedParentMessage);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
this.socketService.emitChatUpdate(params.parentChat.userId, childChat);
|
|
82
|
+
const executionTenants = this.getExecutionTenants(params);
|
|
83
|
+
const abortController = this.agentStore.registerSubAgentProcess(childChat.id, params.parentChat.id);
|
|
84
|
+
const userMessage = await this.createMessage(childChat, ai_agent_types_1.MessageRole.User, {
|
|
85
|
+
content: JSON.stringify(params.input),
|
|
86
|
+
agentName: undefined
|
|
87
|
+
});
|
|
88
|
+
await this.agentStore.shareAgentProcessEvent(childChat.id, {
|
|
89
|
+
type: store_1.AgentProcessEventType.Update,
|
|
90
|
+
data: userMessage
|
|
91
|
+
});
|
|
92
|
+
let assistantMessage = await this.createMessage(childChat, ai_agent_types_1.MessageRole.Assistant, {
|
|
93
|
+
content: '',
|
|
94
|
+
agentName: params.subAgentConfig.name
|
|
95
|
+
});
|
|
96
|
+
const parentActivity = await this.activityRepository.create({
|
|
97
|
+
ownerId: params.parentChat.userId,
|
|
98
|
+
groupId: params.parentChat.id,
|
|
99
|
+
name: ai_agent_types_1.ActivityOperationName.SUBAGENT,
|
|
100
|
+
tenants: executionTenants,
|
|
101
|
+
sourceId: assistantMessage.id,
|
|
102
|
+
sourceType: 'AgentMessage',
|
|
103
|
+
metadata: {
|
|
104
|
+
modelId: this.aiHelper.getLanguageModelId(childChat.model),
|
|
105
|
+
agentOptions: {
|
|
106
|
+
name: params.subAgentConfig.name,
|
|
107
|
+
modelId: this.aiHelper.getLanguageModelId(params.subAgentConfig.defaultModel),
|
|
108
|
+
temperature: params.subAgentConfig.temperature,
|
|
109
|
+
maxOutputTokens: params.subAgentConfig.maxOutputTokens,
|
|
110
|
+
topP: params.subAgentConfig.topP,
|
|
111
|
+
topK: params.subAgentConfig.topK,
|
|
112
|
+
presencePenalty: params.subAgentConfig.presencePenalty,
|
|
113
|
+
frequencyPenalty: params.subAgentConfig.frequencyPenalty,
|
|
114
|
+
stopSequences: params.subAgentConfig.stopSequences,
|
|
115
|
+
seed: params.subAgentConfig.seed,
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
});
|
|
119
|
+
const updatedAssistantMessage = await this.messageRepository.update(assistantMessage.id, {
|
|
120
|
+
activity: parentActivity.id
|
|
121
|
+
});
|
|
122
|
+
const agentOptions = this.aiHelper.getAgentOptionsFromConfig(params.subAgentConfig, params.context);
|
|
123
|
+
agentOptions.onStepFinish = (stepResult) => {
|
|
124
|
+
return this.storeStepActivity({
|
|
125
|
+
chat: params.parentChat,
|
|
126
|
+
parentId: assistantMessage.activity,
|
|
127
|
+
stepResult,
|
|
128
|
+
name: ai_agent_types_1.ActivityOperationName.STEP_FINISHED,
|
|
129
|
+
sourceId: assistantMessage.id,
|
|
130
|
+
sourceType: 'AgentMessage',
|
|
131
|
+
tenants: executionTenants,
|
|
132
|
+
});
|
|
133
|
+
};
|
|
134
|
+
const userPreferences = await this.agentConfigRepository.findByUserIdAndAgentName(childChat.userId, agentOptions.name);
|
|
135
|
+
agentOptions.activeTools = this.getAvailableTools(agentOptions, userPreferences);
|
|
136
|
+
await this.streamMessageStep({
|
|
137
|
+
chat: childChat,
|
|
138
|
+
existingMessages: [userMessage, updatedAssistantMessage],
|
|
139
|
+
assistantMessage: updatedAssistantMessage,
|
|
140
|
+
agentOptions,
|
|
141
|
+
signal: abortController.signal,
|
|
142
|
+
tenants: executionTenants,
|
|
143
|
+
executionContext: params.executionContext,
|
|
144
|
+
context: params.context,
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
catch (error) {
|
|
148
|
+
await this.storeSubagentResponse({
|
|
149
|
+
subagentChat: childChat,
|
|
150
|
+
content: undefined,
|
|
151
|
+
error: error,
|
|
152
|
+
context: params.context,
|
|
153
|
+
executionContext: params.executionContext,
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
}
|
|
46
157
|
mergeMissingUsageFields(target, source) {
|
|
47
158
|
for (const [key, sourceValue] of Object.entries(source)) {
|
|
48
159
|
const targetValue = target[key];
|
|
@@ -114,8 +225,12 @@ class ChatProcessor {
|
|
|
114
225
|
}
|
|
115
226
|
}
|
|
116
227
|
async listChats(params) {
|
|
117
|
-
// Build filter object from params
|
|
118
|
-
|
|
228
|
+
// Build filter object from params. Always exclude subagent chats:
|
|
229
|
+
// the repository translates ROOT into `sessionKind !== SUBAGENT`, which
|
|
230
|
+
// also includes legacy chats where the field is unset.
|
|
231
|
+
const filter = {
|
|
232
|
+
sessionKind: ai_agent_types_2.AgentSessionKind.ROOT
|
|
233
|
+
};
|
|
119
234
|
if (params?.userId) {
|
|
120
235
|
filter.userId = params.userId;
|
|
121
236
|
}
|
|
@@ -164,15 +279,48 @@ class ChatProcessor {
|
|
|
164
279
|
return this.messageRepository.findByChatIdPaginated(chatId, options);
|
|
165
280
|
}
|
|
166
281
|
async deleteChat(chatId) {
|
|
282
|
+
// Collect all subagent descendants BEFORE removing the parent, otherwise the
|
|
283
|
+
// `parentChatId` link is severed and we'd orphan the subtree. Subagents can
|
|
284
|
+
// themselves spawn subagents, so traversal must be recursive.
|
|
285
|
+
const descendantIds = await this.collectDescendantChatIds(chatId);
|
|
167
286
|
const deleted = await this.chatRepository.delete(chatId);
|
|
168
287
|
if (!deleted) {
|
|
169
288
|
throw new Error('Chat not found');
|
|
170
289
|
}
|
|
290
|
+
// Delete descendant chat rows in parallel. Use `Promise.allSettled` so a
|
|
291
|
+
// missing/already-deleted descendant doesn't abort cleanup of the rest.
|
|
292
|
+
if (descendantIds.length > 0) {
|
|
293
|
+
await Promise.allSettled(descendantIds.map(id => this.chatRepository.delete(id)));
|
|
294
|
+
}
|
|
295
|
+
const allIds = [chatId, ...descendantIds];
|
|
171
296
|
await Promise.all([
|
|
172
|
-
this.messageRepository.deleteByChatId(
|
|
173
|
-
this.activityRepository.deleteByGroupId(
|
|
297
|
+
...allIds.map(id => this.messageRepository.deleteByChatId(id)),
|
|
298
|
+
...allIds.map(id => this.activityRepository.deleteByGroupId(id)),
|
|
174
299
|
]);
|
|
175
|
-
|
|
300
|
+
for (const id of allIds) {
|
|
301
|
+
this.artifactStore.deleteArtifacts(id);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* Walk the subagent tree rooted at `rootChatId` and return every descendant
|
|
306
|
+
* chat id (excluding the root itself). BFS, with parallel fan-out per level
|
|
307
|
+
* so deeply nested trees don't serialize one DB roundtrip per depth.
|
|
308
|
+
*/
|
|
309
|
+
async collectDescendantChatIds(rootChatId) {
|
|
310
|
+
const descendants = [];
|
|
311
|
+
let frontier = [rootChatId];
|
|
312
|
+
while (frontier.length > 0) {
|
|
313
|
+
const childLists = await Promise.all(frontier.map(id => this.chatRepository.find({ parentChatId: id })));
|
|
314
|
+
const nextFrontier = [];
|
|
315
|
+
for (const list of childLists) {
|
|
316
|
+
for (const child of list) {
|
|
317
|
+
descendants.push(child.id);
|
|
318
|
+
nextFrontier.push(child.id);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
frontier = nextFrontier;
|
|
322
|
+
}
|
|
323
|
+
return descendants;
|
|
176
324
|
}
|
|
177
325
|
async upsertAndGetChat(payload, excludeSocketId) {
|
|
178
326
|
const targetUserId = payload.userId ?? 'guest';
|
|
@@ -235,6 +383,7 @@ class ChatProcessor {
|
|
|
235
383
|
title: this.getTemporaryTitle(contextKey),
|
|
236
384
|
type: ai_agent_types_1.ChatType.Chat,
|
|
237
385
|
status: ai_agent_types_1.AgentStatus.Streaming,
|
|
386
|
+
sessionKind: ai_agent_types_2.AgentSessionKind.ROOT,
|
|
238
387
|
contextKey,
|
|
239
388
|
userId: targetUserId,
|
|
240
389
|
metadata,
|
|
@@ -306,8 +455,11 @@ class ChatProcessor {
|
|
|
306
455
|
* Update selected fields (input/output/status) on a specific tool call.
|
|
307
456
|
*/
|
|
308
457
|
async updateToolCall(params) {
|
|
309
|
-
if (params.input === undefined &&
|
|
310
|
-
|
|
458
|
+
if (params.input === undefined &&
|
|
459
|
+
params.output === undefined &&
|
|
460
|
+
params.status === undefined &&
|
|
461
|
+
params.subagentChatId === undefined) {
|
|
462
|
+
throw new Error('At least one tool call update field must be provided');
|
|
311
463
|
}
|
|
312
464
|
const chat = await this.chatRepository.findById(params.chatId);
|
|
313
465
|
if (!chat) {
|
|
@@ -335,6 +487,7 @@ class ChatProcessor {
|
|
|
335
487
|
...(params.input !== undefined ? { input: params.input } : {}),
|
|
336
488
|
...(params.output !== undefined ? { output: params.output } : {}),
|
|
337
489
|
...(params.status !== undefined ? { status: params.status } : {}),
|
|
490
|
+
...(params.subagentChatId !== undefined ? { subagentChatId: params.subagentChatId } : {}),
|
|
338
491
|
});
|
|
339
492
|
if (!updatedMessage) {
|
|
340
493
|
throw new Error('Tool call not found in message');
|
|
@@ -344,8 +497,80 @@ class ChatProcessor {
|
|
|
344
497
|
this.socketService.emitMessageUpdate(chat.userId, updatedMessage, params.excludeSocketId);
|
|
345
498
|
return updatedMessage;
|
|
346
499
|
}
|
|
500
|
+
async storeSubagentResponse(params) {
|
|
501
|
+
const { subagentChat, content, error, context, executionContext } = params;
|
|
502
|
+
if (!subagentChat.parentChatId || !subagentChat.parentMessageId) {
|
|
503
|
+
throw new Error(`Parent chat or message not found for subagent ${subagentChat.id}`);
|
|
504
|
+
}
|
|
505
|
+
const chat = await this.chatRepository.findById(subagentChat.parentChatId);
|
|
506
|
+
if (!chat) {
|
|
507
|
+
throw new Error(`Parent chat not found for subagent ${subagentChat.id}`);
|
|
508
|
+
}
|
|
509
|
+
const assistantMessage = await this.messageRepository.findById(subagentChat.parentMessageId);
|
|
510
|
+
if (!assistantMessage || assistantMessage.chat !== subagentChat.parentChatId) {
|
|
511
|
+
throw new Error(`Assistant message with id ${subagentChat.parentMessageId} not found`);
|
|
512
|
+
}
|
|
513
|
+
const toolCall = assistantMessage.toolCalls?.find(tc => tc.id === subagentChat.parentToolCallId);
|
|
514
|
+
if (!toolCall) {
|
|
515
|
+
throw new Error(`Tool call with id ${subagentChat.parentToolCallId} not found`);
|
|
516
|
+
}
|
|
517
|
+
if (error) {
|
|
518
|
+
toolCall.output = {
|
|
519
|
+
type: 'error',
|
|
520
|
+
message: error,
|
|
521
|
+
};
|
|
522
|
+
toolCall.status = ai_agent_types_1.AgentToolCallStatus.Failed;
|
|
523
|
+
}
|
|
524
|
+
else {
|
|
525
|
+
toolCall.output = content;
|
|
526
|
+
toolCall.status = ai_agent_types_1.AgentToolCallStatus.Succeeded;
|
|
527
|
+
}
|
|
528
|
+
await this.messageRepository.update(assistantMessage.id, assistantMessage);
|
|
529
|
+
const agentOptions = await this.aiHelper.getAgentOptions({
|
|
530
|
+
agentName: assistantMessage.agentName,
|
|
531
|
+
context: context,
|
|
532
|
+
executionContext: executionContext,
|
|
533
|
+
});
|
|
534
|
+
const executionTenants = this.getExecutionTenants(params);
|
|
535
|
+
const abortController = this.agentStore.registerAgentProcess(chat.id);
|
|
536
|
+
const existingMessages = await this.messageRepository.findByChatId(chat.id);
|
|
537
|
+
// Limit context to prevent exceeding token limits
|
|
538
|
+
const limitedMessages = helpers_1.ContextLimiter.limitContext(existingMessages, {
|
|
539
|
+
maxMessages: this.config.ai.maxContextMessages,
|
|
540
|
+
keepFirstUserMessage: true,
|
|
541
|
+
keepSystemMessages: true,
|
|
542
|
+
});
|
|
543
|
+
agentOptions.onStepFinish = (stepResult) => {
|
|
544
|
+
return this.storeStepActivity({
|
|
545
|
+
chat,
|
|
546
|
+
parentId: assistantMessage.activity,
|
|
547
|
+
stepResult,
|
|
548
|
+
name: ai_agent_types_1.ActivityOperationName.STEP_FINISHED,
|
|
549
|
+
sourceId: assistantMessage.id,
|
|
550
|
+
sourceType: 'AgentMessage',
|
|
551
|
+
tenants: executionTenants,
|
|
552
|
+
});
|
|
553
|
+
};
|
|
554
|
+
const userPreferences = await this.agentConfigRepository.findByUserIdAndAgentName(chat.userId, agentOptions.name);
|
|
555
|
+
agentOptions.activeTools = this.getAvailableTools(agentOptions, userPreferences);
|
|
556
|
+
await this.streamMessageStep({
|
|
557
|
+
chat,
|
|
558
|
+
existingMessages: limitedMessages,
|
|
559
|
+
assistantMessage,
|
|
560
|
+
agentOptions,
|
|
561
|
+
signal: abortController.signal,
|
|
562
|
+
tenants: executionTenants,
|
|
563
|
+
executionContext,
|
|
564
|
+
context,
|
|
565
|
+
});
|
|
566
|
+
}
|
|
347
567
|
async streamMessageStep(params) {
|
|
348
568
|
const { chat, assistantMessage, existingMessages, signal, excludeSocketId, agentOptions } = params;
|
|
569
|
+
const persistAndBroadcastToolCalls = async () => {
|
|
570
|
+
await this.messageRepository.update(assistantMessage.id, { toolCalls: assistantMessage.toolCalls ?? [] });
|
|
571
|
+
this.socketService.emitMessageUpdate(chat.userId, assistantMessage, excludeSocketId);
|
|
572
|
+
await this.agentStore.shareAgentProcessEvent(chat.id, { type: store_1.AgentProcessEventType.Update, data: assistantMessage });
|
|
573
|
+
};
|
|
349
574
|
if (signal.aborted) {
|
|
350
575
|
return;
|
|
351
576
|
}
|
|
@@ -359,12 +584,21 @@ class ChatProcessor {
|
|
|
359
584
|
await this.agentStore.shareAgentProcessEvent(chat.id, { type: store_1.AgentProcessEventType.Error, data: chunk.error });
|
|
360
585
|
assistantMessage.content = chunk.error.message || 'Sorry, I cannot process you request due to the error';
|
|
361
586
|
await this.messageRepository.update(assistantMessage.id, assistantMessage);
|
|
362
|
-
await this.
|
|
587
|
+
await this.updateChatAndEmit(chat, { status: ai_agent_types_1.AgentStatus.Error }, excludeSocketId);
|
|
588
|
+
if (chat.sessionKind === ai_agent_types_2.AgentSessionKind.SUBAGENT) {
|
|
589
|
+
await this.storeSubagentResponse({
|
|
590
|
+
subagentChat: chat,
|
|
591
|
+
content: undefined,
|
|
592
|
+
error: chunk.error,
|
|
593
|
+
context: params.context,
|
|
594
|
+
executionContext: params.executionContext,
|
|
595
|
+
});
|
|
596
|
+
}
|
|
363
597
|
continue;
|
|
364
598
|
}
|
|
365
599
|
if (chunk.type === 'abort') {
|
|
366
600
|
await this.agentStore.shareAgentProcessEvent(chat.id, { type: store_1.AgentProcessEventType.Aborted, data: undefined });
|
|
367
|
-
await this.
|
|
601
|
+
await this.updateChatAndEmit(chat, { status: ai_agent_types_1.AgentStatus.Aborted }, excludeSocketId);
|
|
368
602
|
await this.messageRepository.update(assistantMessage.id, assistantMessage);
|
|
369
603
|
this.socketService.emitMessageUpdate(chat.userId, assistantMessage, excludeSocketId);
|
|
370
604
|
continue;
|
|
@@ -383,8 +617,9 @@ class ChatProcessor {
|
|
|
383
617
|
((totalUsage.promptTokens ?? 0) + (totalUsage.completionTokens ?? 0));
|
|
384
618
|
}
|
|
385
619
|
await this.messageRepository.update(assistantMessage.id, { ...assistantMessage });
|
|
620
|
+
this.socketService.emitMessageUpdate(chat.userId, assistantMessage, excludeSocketId);
|
|
386
621
|
if (chunk.finishReason === 'stop') {
|
|
387
|
-
await this.
|
|
622
|
+
let nextChat = await this.updateChatAndEmit(chat, { status: ai_agent_types_1.AgentStatus.Finished }, excludeSocketId);
|
|
388
623
|
if (chat.title && this.isTemporaryTitle(chat.title)) {
|
|
389
624
|
const title = await this.aiHelper.generateTitleForMessage(chat.contextKey, existingMessages.filter(m => m.role === ai_agent_types_1.MessageRole.User), (stepResult) => {
|
|
390
625
|
return this.storeStepActivity({
|
|
@@ -396,16 +631,51 @@ class ChatProcessor {
|
|
|
396
631
|
tenants: params.tenants || {},
|
|
397
632
|
});
|
|
398
633
|
}, params.executionContext);
|
|
399
|
-
await this.
|
|
400
|
-
|
|
634
|
+
nextChat = await this.updateChatAndEmit(nextChat, { title }, excludeSocketId);
|
|
635
|
+
}
|
|
636
|
+
if (chat.sessionKind === ai_agent_types_2.AgentSessionKind.SUBAGENT) {
|
|
637
|
+
await this.storeSubagentResponse({
|
|
638
|
+
subagentChat: chat,
|
|
639
|
+
content: assistantMessage.content,
|
|
640
|
+
error: undefined,
|
|
641
|
+
context: params.context,
|
|
642
|
+
executionContext: params.executionContext,
|
|
643
|
+
});
|
|
401
644
|
}
|
|
402
645
|
}
|
|
403
646
|
if (chunk.finishReason === 'tool-calls') {
|
|
404
|
-
|
|
405
|
-
|
|
647
|
+
const toolCall = assistantMessage.toolCalls?.find(toolCall => toolCall.output === undefined && toolCall.status === ai_agent_types_1.AgentToolCallStatus.Running);
|
|
648
|
+
if (!toolCall) {
|
|
406
649
|
await this.agentStore.shareAgentProcessEvent(chat.id, { type: store_1.AgentProcessEventType.Finished, data: assistantMessage });
|
|
650
|
+
await this.storeSubagentResponse({
|
|
651
|
+
subagentChat: chat,
|
|
652
|
+
content: JSON.stringify(assistantMessage.toolCalls),
|
|
653
|
+
error: undefined,
|
|
654
|
+
context: params.context,
|
|
655
|
+
executionContext: params.executionContext,
|
|
656
|
+
});
|
|
407
657
|
continue;
|
|
408
658
|
}
|
|
659
|
+
const toolConfig = store_1.ConfigStore.getInstance().getToolConfig(assistantMessage.agentName || '', toolCall.name);
|
|
660
|
+
if (toolCall.requiresConfirmation && toolCall.approvalId) {
|
|
661
|
+
await this.updateChatAndEmit(chat, { status: ai_agent_types_1.AgentStatus.WaitingForUserAction }, excludeSocketId);
|
|
662
|
+
await this.agentStore.shareAgentProcessEvent(chat.id, { type: store_1.AgentProcessEventType.Finished, data: assistantMessage });
|
|
663
|
+
}
|
|
664
|
+
else if (toolConfig && toolConfig.type === ai_agent_types_1.AgentToolType.SUBAGENT) {
|
|
665
|
+
void this.startSubagentProcess({
|
|
666
|
+
parentChat: chat,
|
|
667
|
+
parentMessage: assistantMessage,
|
|
668
|
+
parentToolCallId: toolCall.id,
|
|
669
|
+
toolName: toolCall.name,
|
|
670
|
+
input: toolCall.input,
|
|
671
|
+
subAgentConfig: toolConfig.data.subAgent,
|
|
672
|
+
context: params.context,
|
|
673
|
+
executionContext: params.executionContext,
|
|
674
|
+
}).catch(error => {
|
|
675
|
+
logger_1.logger.error(error);
|
|
676
|
+
//todo: store error in response
|
|
677
|
+
});
|
|
678
|
+
}
|
|
409
679
|
}
|
|
410
680
|
//todo: Handle other finish reasons // length, content, error, other, undefined
|
|
411
681
|
await this.agentStore.shareAgentProcessEvent(chat.id, { type: store_1.AgentProcessEventType.Finished, data: assistantMessage });
|
|
@@ -433,20 +703,43 @@ class ChatProcessor {
|
|
|
433
703
|
if (chunk.type === 'tool-input-start') {
|
|
434
704
|
if (!assistantMessage.toolCalls)
|
|
435
705
|
assistantMessage.toolCalls = [];
|
|
436
|
-
assistantMessage.toolCalls.
|
|
437
|
-
|
|
438
|
-
name
|
|
439
|
-
status
|
|
440
|
-
|
|
441
|
-
|
|
706
|
+
const existingToolCall = assistantMessage.toolCalls.find((toolCall) => toolCall.id === chunk.id);
|
|
707
|
+
if (existingToolCall) {
|
|
708
|
+
existingToolCall.name = chunk.toolName;
|
|
709
|
+
if (!existingToolCall.status) {
|
|
710
|
+
existingToolCall.status = ai_agent_types_1.AgentToolCallStatus.Pending;
|
|
711
|
+
}
|
|
712
|
+
existingToolCall.input = existingToolCall.input ?? {};
|
|
713
|
+
}
|
|
714
|
+
else {
|
|
715
|
+
assistantMessage.toolCalls.push({
|
|
716
|
+
id: chunk.id,
|
|
717
|
+
name: chunk.toolName,
|
|
718
|
+
status: ai_agent_types_1.AgentToolCallStatus.Pending,
|
|
719
|
+
input: {},
|
|
720
|
+
});
|
|
721
|
+
}
|
|
722
|
+
await persistAndBroadcastToolCalls();
|
|
442
723
|
continue;
|
|
443
724
|
}
|
|
444
725
|
if (chunk.type === 'tool-call') {
|
|
445
|
-
|
|
446
|
-
|
|
726
|
+
if (!assistantMessage.toolCalls)
|
|
727
|
+
assistantMessage.toolCalls = [];
|
|
728
|
+
let toolCall = assistantMessage.toolCalls.find(toolCall => toolCall.id === chunk.toolCallId);
|
|
729
|
+
if (!toolCall) {
|
|
730
|
+
toolCall = {
|
|
731
|
+
id: chunk.toolCallId,
|
|
732
|
+
name: chunk.toolName,
|
|
733
|
+
status: ai_agent_types_1.AgentToolCallStatus.Running,
|
|
734
|
+
input: chunk.input,
|
|
735
|
+
};
|
|
736
|
+
assistantMessage.toolCalls.push(toolCall);
|
|
737
|
+
}
|
|
738
|
+
else {
|
|
447
739
|
toolCall.status = ai_agent_types_1.AgentToolCallStatus.Running;
|
|
448
740
|
toolCall.input = chunk.input;
|
|
449
741
|
}
|
|
742
|
+
await persistAndBroadcastToolCalls();
|
|
450
743
|
continue;
|
|
451
744
|
}
|
|
452
745
|
if (chunk.type === 'tool-error') {
|
|
@@ -454,29 +747,33 @@ class ChatProcessor {
|
|
|
454
747
|
if (toolCall) {
|
|
455
748
|
toolCall.status = ai_agent_types_1.AgentToolCallStatus.Failed;
|
|
456
749
|
toolCall.error = chunk.error.message || JSON.stringify(chunk.error);
|
|
750
|
+
await persistAndBroadcastToolCalls();
|
|
457
751
|
}
|
|
458
752
|
continue;
|
|
459
753
|
}
|
|
460
754
|
if (chunk.type === 'tool-approval-request') {
|
|
461
755
|
const toolCall = assistantMessage.toolCalls?.find(toolCall => toolCall.id === chunk.toolCall.toolCallId);
|
|
462
756
|
if (toolCall) {
|
|
757
|
+
const toolConfig = store_1.ConfigStore.getInstance().getToolConfig(assistantMessage.agentName || '', toolCall.name);
|
|
758
|
+
if (toolConfig && toolConfig.type === ai_agent_types_1.AgentToolType.SUBAGENT) {
|
|
759
|
+
// TODO: allow needsApproval flow for the subagents too
|
|
760
|
+
continue;
|
|
761
|
+
}
|
|
463
762
|
toolCall.requiresConfirmation = true;
|
|
464
763
|
toolCall.approvalId = chunk.approvalId;
|
|
465
764
|
if (toolCall.name === ai_agent_types_1.AgentToolType.REQUEST_CLARIFICATION) {
|
|
466
765
|
toolCall.requiresUserAction = true;
|
|
467
766
|
}
|
|
767
|
+
await persistAndBroadcastToolCalls();
|
|
468
768
|
}
|
|
469
769
|
continue;
|
|
470
770
|
}
|
|
471
771
|
if (chunk.type === 'tool-result') {
|
|
472
772
|
const toolCall = assistantMessage.toolCalls?.find(toolCall => toolCall.id === chunk.toolCallId);
|
|
473
773
|
if (toolCall) {
|
|
474
|
-
if (chunk.output?.requiresApproval) {
|
|
475
|
-
toolCall.requiresConfirmation = true;
|
|
476
|
-
continue;
|
|
477
|
-
}
|
|
478
774
|
toolCall.status = ai_agent_types_1.AgentToolCallStatus.Succeeded;
|
|
479
775
|
toolCall.output = chunk.output;
|
|
776
|
+
await persistAndBroadcastToolCalls();
|
|
480
777
|
}
|
|
481
778
|
continue;
|
|
482
779
|
}
|
|
@@ -667,7 +964,7 @@ class ChatProcessor {
|
|
|
667
964
|
let agentOptions;
|
|
668
965
|
const existingMessages = await this.messageRepository.findByChatId(chat.id);
|
|
669
966
|
// Limit context to prevent exceeding token limits
|
|
670
|
-
const limitedMessages =
|
|
967
|
+
const limitedMessages = helpers_1.ContextLimiter.limitContext(existingMessages, {
|
|
671
968
|
maxMessages: this.config.ai.maxContextMessages,
|
|
672
969
|
keepFirstUserMessage: true,
|
|
673
970
|
keepSystemMessages: true,
|
|
@@ -712,6 +1009,7 @@ class ChatProcessor {
|
|
|
712
1009
|
signal: abortController.signal,
|
|
713
1010
|
tenants: executionTenants,
|
|
714
1011
|
executionContext: payload.executionContext,
|
|
1012
|
+
context: payload.context,
|
|
715
1013
|
});
|
|
716
1014
|
}
|
|
717
1015
|
catch (error) {
|
|
@@ -721,9 +1019,9 @@ class ChatProcessor {
|
|
|
721
1019
|
getAvailableTools(agentOptions, userPreferences) {
|
|
722
1020
|
const toolNames = Object.keys(agentOptions.tools || {});
|
|
723
1021
|
const availableToolsMap = Object.fromEntries(toolNames.map(key => [key, true]));
|
|
724
|
-
const agentsConfiguration =
|
|
1022
|
+
const agentsConfiguration = store_1.ConfigStore.getInstance().getAgentConfigByName(agentOptions.name);
|
|
725
1023
|
agentsConfiguration.tools.forEach((tool) => {
|
|
726
|
-
const toolTitle =
|
|
1024
|
+
const toolTitle = (0, utils_1.getAgentToolName)(tool);
|
|
727
1025
|
if (tool.disabledByDefault) {
|
|
728
1026
|
availableToolsMap[toolTitle] = false;
|
|
729
1027
|
}
|