@memberjunction/ai-agents 3.2.0 → 3.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/PayloadFeedbackManager.d.ts +3 -1
- package/dist/PayloadFeedbackManager.d.ts.map +1 -1
- package/dist/PayloadFeedbackManager.js +61 -7
- package/dist/PayloadFeedbackManager.js.map +1 -1
- package/dist/__tests__/agent-memory-features.test.d.ts +71 -0
- package/dist/__tests__/agent-memory-features.test.d.ts.map +1 -0
- package/dist/__tests__/agent-memory-features.test.js +513 -0
- package/dist/__tests__/agent-memory-features.test.js.map +1 -0
- package/dist/agent-context-injector.d.ts +16 -1
- package/dist/agent-context-injector.d.ts.map +1 -1
- package/dist/agent-context-injector.js +162 -11
- package/dist/agent-context-injector.js.map +1 -1
- package/dist/base-agent.d.ts.map +1 -1
- package/dist/base-agent.js +27 -1
- package/dist/base-agent.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/memory-cleanup-agent.d.ts +25 -0
- package/dist/memory-cleanup-agent.d.ts.map +1 -0
- package/dist/memory-cleanup-agent.js +237 -0
- package/dist/memory-cleanup-agent.js.map +1 -0
- package/dist/memory-manager-agent.d.ts +10 -2
- package/dist/memory-manager-agent.d.ts.map +1 -1
- package/dist/memory-manager-agent.js +647 -83
- package/dist/memory-manager-agent.js.map +1 -1
- package/package.json +12 -11
|
@@ -1,61 +1,181 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
2
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
9
|
exports.MemoryManagerAgent = void 0;
|
|
4
10
|
const base_agent_1 = require("./base-agent");
|
|
11
|
+
const global_1 = require("@memberjunction/global");
|
|
5
12
|
const core_1 = require("@memberjunction/core");
|
|
6
13
|
const ai_prompts_1 = require("@memberjunction/ai-prompts");
|
|
7
14
|
const ai_core_plus_1 = require("@memberjunction/ai-core-plus");
|
|
8
15
|
const aiengine_1 = require("@memberjunction/aiengine");
|
|
9
|
-
|
|
16
|
+
const EXTRACTION_CONFIG = {
|
|
17
|
+
maxNotesPerRun: 1000,
|
|
18
|
+
maxNotesPerConversation: 1000,
|
|
19
|
+
maxNotesPerMessage: 1000,
|
|
20
|
+
minConfidenceThreshold: 80,
|
|
21
|
+
minContentLength: 10,
|
|
22
|
+
cooldownHours: 24
|
|
23
|
+
};
|
|
24
|
+
let MemoryManagerAgent = class MemoryManagerAgent extends base_agent_1.BaseAgent {
|
|
25
|
+
constructor() {
|
|
26
|
+
super(...arguments);
|
|
27
|
+
this._verbose = false;
|
|
28
|
+
this._agentRunID = null;
|
|
29
|
+
this._stepCounter = 0;
|
|
30
|
+
this._contextUser = null;
|
|
31
|
+
}
|
|
32
|
+
async CreateRunStep(stepType, stepName, inputData, targetId) {
|
|
33
|
+
if (!this._agentRunID || !this._contextUser) {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
try {
|
|
37
|
+
const md = new core_1.Metadata();
|
|
38
|
+
const step = await md.GetEntityObject('MJ: AI Agent Run Steps', this._contextUser);
|
|
39
|
+
step.AgentRunID = this._agentRunID;
|
|
40
|
+
step.StepNumber = ++this._stepCounter;
|
|
41
|
+
step.StepType = stepType;
|
|
42
|
+
step.StepName = stepName;
|
|
43
|
+
step.Status = 'Running';
|
|
44
|
+
step.StartedAt = new Date();
|
|
45
|
+
if (targetId) {
|
|
46
|
+
step.TargetID = targetId;
|
|
47
|
+
}
|
|
48
|
+
if (inputData) {
|
|
49
|
+
step.InputData = JSON.stringify(inputData);
|
|
50
|
+
}
|
|
51
|
+
if (await step.Save()) {
|
|
52
|
+
return step;
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
(0, core_1.LogError)(`Memory Manager: Failed to create run step: ${JSON.stringify(step.LatestResult)}`);
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
(0, core_1.LogError)('Memory Manager: Exception creating run step:', error);
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
async FinalizeRunStep(step, success, outputData, targetLogId, errorMessage) {
|
|
65
|
+
if (!step) {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
try {
|
|
69
|
+
step.Status = success ? 'Completed' : 'Failed';
|
|
70
|
+
step.CompletedAt = new Date();
|
|
71
|
+
step.Success = success;
|
|
72
|
+
if (errorMessage) {
|
|
73
|
+
step.ErrorMessage = errorMessage;
|
|
74
|
+
}
|
|
75
|
+
if (targetLogId) {
|
|
76
|
+
step.TargetLogID = targetLogId;
|
|
77
|
+
}
|
|
78
|
+
if (outputData) {
|
|
79
|
+
step.OutputData = JSON.stringify(outputData);
|
|
80
|
+
}
|
|
81
|
+
if (!await step.Save()) {
|
|
82
|
+
(0, core_1.LogError)(`Memory Manager: Failed to finalize run step: ${JSON.stringify(step.LatestResult)}`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
catch (error) {
|
|
86
|
+
(0, core_1.LogError)('Memory Manager: Exception finalizing run step:', error);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
10
89
|
async GetLastRunTime(agentId, contextUser) {
|
|
11
90
|
const rv = new core_1.RunView();
|
|
12
91
|
const result = await rv.RunView({
|
|
13
92
|
EntityName: 'MJ: AI Agent Runs',
|
|
14
|
-
ExtraFilter: `AgentID='${agentId}' AND Status='
|
|
93
|
+
ExtraFilter: `AgentID='${agentId}' AND Status='Completed'`,
|
|
15
94
|
OrderBy: 'StartedAt DESC',
|
|
16
95
|
MaxRows: 1,
|
|
17
96
|
ResultType: 'entity_object'
|
|
18
97
|
}, contextUser);
|
|
19
98
|
if (result.Success && result.Results && result.Results.length > 0) {
|
|
20
|
-
|
|
99
|
+
const startedAt = result.Results[0].StartedAt;
|
|
100
|
+
return startedAt instanceof Date ? startedAt : new Date(startedAt);
|
|
21
101
|
}
|
|
22
102
|
return null;
|
|
23
103
|
}
|
|
24
104
|
async LoadAgentsUsingMemory(contextUser) {
|
|
25
|
-
const
|
|
105
|
+
const allAgents = aiengine_1.AIEngine.Instance.Agents;
|
|
106
|
+
const filteredAgents = allAgents.filter(a => a.Status === 'Active' && (a.InjectNotes || a.InjectExamples));
|
|
107
|
+
if (this._verbose) {
|
|
108
|
+
(0, core_1.LogStatus)(`Memory Manager: AIEngine has ${allAgents.length} total agents cached`);
|
|
109
|
+
if (filteredAgents.length > 0) {
|
|
110
|
+
const agentNames = filteredAgents.map(a => `${a.Name} (InjectNotes=${a.InjectNotes}, InjectExamples=${a.InjectExamples})`).join(', ');
|
|
111
|
+
(0, core_1.LogStatus)(`Memory Manager: Agents with memory enabled: ${agentNames}`);
|
|
112
|
+
}
|
|
113
|
+
const sage = allAgents.find(a => a.Name === 'Sage');
|
|
114
|
+
if (sage) {
|
|
115
|
+
(0, core_1.LogStatus)(`Memory Manager: Sage agent - ID=${sage.ID}, InjectNotes=${sage.InjectNotes}, InjectExamples=${sage.InjectExamples}, Status=${sage.Status}`);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
const sage = allAgents.find(a => a.Name === 'Sage');
|
|
119
|
+
if (!sage) {
|
|
120
|
+
(0, core_1.LogStatus)(`Memory Manager: WARNING - Sage agent not found in AIEngine cache!`);
|
|
121
|
+
}
|
|
26
122
|
return filteredAgents;
|
|
27
123
|
}
|
|
28
|
-
async
|
|
124
|
+
async LoadConversationsWithNewActivity(since, agentsUsingMemory, contextUser) {
|
|
29
125
|
if (agentsUsingMemory.length === 0) {
|
|
30
126
|
(0, core_1.LogStatus)('Memory Manager: No agents have memory injection enabled - skipping');
|
|
31
127
|
return [];
|
|
32
128
|
}
|
|
33
|
-
const
|
|
34
|
-
const
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
AND cdr.Rating >= 8
|
|
44
|
-
)
|
|
45
|
-
AND EXISTS (
|
|
46
|
-
SELECT 1 FROM AIAgentRun ar
|
|
47
|
-
WHERE ar.ConversationID = cd.ConversationID
|
|
48
|
-
AND ar.AgentID IN (${agentIdFilter})
|
|
49
|
-
)
|
|
50
|
-
`.trim().replace(/\s+/g, ' ');
|
|
51
|
-
const result = await rv.RunView({
|
|
52
|
-
EntityName: 'Conversation Details',
|
|
53
|
-
ExtraFilter: filter,
|
|
54
|
-
OrderBy: '__mj_CreatedAt DESC',
|
|
55
|
-
MaxRows: 100,
|
|
56
|
-
ResultType: 'entity_object'
|
|
129
|
+
const agentIds = agentsUsingMemory.map(a => `'${a.ID}'`).join(',');
|
|
130
|
+
const rq = new core_1.RunQuery();
|
|
131
|
+
const result = await rq.RunQuery({
|
|
132
|
+
QueryName: 'GetConversationsForMemoryManager',
|
|
133
|
+
CategoryPath: '/MJ/AI/Agents/',
|
|
134
|
+
Parameters: {
|
|
135
|
+
since: since?.toISOString() || null,
|
|
136
|
+
agentIds: agentIds
|
|
137
|
+
},
|
|
138
|
+
MaxRows: 1000
|
|
57
139
|
}, contextUser);
|
|
58
|
-
|
|
140
|
+
if (!result.Success || !result.Results || result.Results.length === 0) {
|
|
141
|
+
(0, core_1.LogStatus)('Memory Manager: No conversations with new activity found');
|
|
142
|
+
return [];
|
|
143
|
+
}
|
|
144
|
+
const conversations = [];
|
|
145
|
+
for (const row of result.Results) {
|
|
146
|
+
let messages = [];
|
|
147
|
+
if (row.MessagesJSON) {
|
|
148
|
+
try {
|
|
149
|
+
const parsedMessages = JSON.parse(row.MessagesJSON);
|
|
150
|
+
messages = parsedMessages.map(m => ({
|
|
151
|
+
id: m.id,
|
|
152
|
+
role: m.role,
|
|
153
|
+
message: m.message,
|
|
154
|
+
createdAt: new Date(m.createdAt),
|
|
155
|
+
rating: m.rating,
|
|
156
|
+
ratingComment: m.ratingComment
|
|
157
|
+
}));
|
|
158
|
+
}
|
|
159
|
+
catch (e) {
|
|
160
|
+
(0, core_1.LogError)(`Memory Manager: Failed to parse MessagesJSON for conversation ${row.ConversationID}:`, e);
|
|
161
|
+
continue;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
conversations.push({
|
|
165
|
+
conversationId: row.ConversationID,
|
|
166
|
+
userId: row.UserID,
|
|
167
|
+
agentRunId: row.AgentRunID,
|
|
168
|
+
messages: messages,
|
|
169
|
+
hasPositiveRating: row.HasPositiveRating === 1,
|
|
170
|
+
hasNegativeRating: row.HasNegativeRating === 1,
|
|
171
|
+
isUnrated: row.IsUnrated === 1
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
const totalMessages = conversations.reduce((sum, c) => sum + c.messages.length, 0);
|
|
175
|
+
if (this._verbose) {
|
|
176
|
+
(0, core_1.LogStatus)(`Memory Manager: Loaded ${conversations.length} conversations with ${totalMessages} total messages (positive: ${conversations.filter(c => c.hasPositiveRating).length}, negative: ${conversations.filter(c => c.hasNegativeRating).length}, unrated: ${conversations.filter(c => c.isUnrated).length})`);
|
|
177
|
+
}
|
|
178
|
+
return conversations;
|
|
59
179
|
}
|
|
60
180
|
async LoadHighValueAgentRuns(since, contextUser) {
|
|
61
181
|
const rv = new core_1.RunView();
|
|
@@ -63,14 +183,14 @@ class MemoryManagerAgent extends base_agent_1.BaseAgent {
|
|
|
63
183
|
const filter = `
|
|
64
184
|
ID IN (
|
|
65
185
|
SELECT DISTINCT ar.ID
|
|
66
|
-
FROM AIAgentRun ar
|
|
67
|
-
INNER JOIN Conversation c ON ar.ConversationID = c.ID
|
|
68
|
-
INNER JOIN ConversationDetail cd ON cd.ConversationID = c.ID
|
|
69
|
-
INNER JOIN ConversationDetailArtifact cda ON cda.ConversationDetailID = cd.ID
|
|
70
|
-
INNER JOIN ArtifactVersion av ON av.ID = cda.ArtifactVersionID
|
|
186
|
+
FROM __mj.AIAgentRun ar
|
|
187
|
+
INNER JOIN __mj.Conversation c ON ar.ConversationID = c.ID
|
|
188
|
+
INNER JOIN __mj.ConversationDetail cd ON cd.ConversationID = c.ID
|
|
189
|
+
INNER JOIN __mj.ConversationDetailArtifact cda ON cda.ConversationDetailID = cd.ID
|
|
190
|
+
INNER JOIN __mj.ArtifactVersion av ON av.ID = cda.ArtifactVersionID
|
|
71
191
|
WHERE EXISTS (
|
|
72
192
|
SELECT 1
|
|
73
|
-
FROM ArtifactUse au
|
|
193
|
+
FROM __mj.ArtifactUse au
|
|
74
194
|
WHERE au.ArtifactVersionID = av.ID
|
|
75
195
|
${sinceFilter}
|
|
76
196
|
GROUP BY au.ArtifactVersionID
|
|
@@ -90,25 +210,26 @@ class MemoryManagerAgent extends base_agent_1.BaseAgent {
|
|
|
90
210
|
}, contextUser);
|
|
91
211
|
return result.Success ? (result.Results || []) : [];
|
|
92
212
|
}
|
|
93
|
-
async
|
|
94
|
-
if (
|
|
213
|
+
async ExtractNotesFromConversations(conversations, contextUser) {
|
|
214
|
+
if (conversations.length === 0) {
|
|
95
215
|
return [];
|
|
96
216
|
}
|
|
97
217
|
const allNotes = aiengine_1.AIEngine.Instance.AgentNotes;
|
|
98
218
|
const existingNotes = allNotes.filter(n => n.Status === 'Active');
|
|
99
|
-
const
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
219
|
+
const conversationThreads = conversations.map(conv => ({
|
|
220
|
+
conversationId: conv.conversationId,
|
|
221
|
+
userId: conv.userId,
|
|
222
|
+
agentRunId: conv.agentRunId,
|
|
223
|
+
hasPositiveRating: conv.hasPositiveRating,
|
|
224
|
+
hasNegativeRating: conv.hasNegativeRating,
|
|
225
|
+
isUnrated: conv.isUnrated,
|
|
226
|
+
messages: conv.messages.map(msg => ({
|
|
227
|
+
id: msg.id,
|
|
228
|
+
role: msg.role,
|
|
229
|
+
message: msg.message,
|
|
230
|
+
createdAt: msg.createdAt,
|
|
231
|
+
rating: msg.rating,
|
|
232
|
+
ratingComment: msg.ratingComment
|
|
112
233
|
}))
|
|
113
234
|
}));
|
|
114
235
|
const promptData = {
|
|
@@ -122,22 +243,208 @@ class MemoryManagerAgent extends base_agent_1.BaseAgent {
|
|
|
122
243
|
companyId: n.CompanyID
|
|
123
244
|
}))
|
|
124
245
|
};
|
|
246
|
+
return this.executeNoteExtraction(promptData, existingNotes, contextUser);
|
|
247
|
+
}
|
|
248
|
+
async executeNoteExtraction(promptData, existingNotes, contextUser) {
|
|
249
|
+
const conversationThreads = promptData.conversationThreads;
|
|
125
250
|
const prompt = aiengine_1.AIEngine.Instance.Prompts.find(p => p.Name === 'Memory Manager - Extract Notes' && p.Category === 'MJ: System');
|
|
126
251
|
if (!prompt) {
|
|
127
252
|
(0, core_1.LogError)('Memory Manager note extraction prompt not found');
|
|
253
|
+
if (this._verbose) {
|
|
254
|
+
(0, core_1.LogStatus)(`Memory Manager: Available prompts in MJ: System category: ${aiengine_1.AIEngine.Instance.Prompts.filter(p => p.Category === 'MJ: System').map(p => p.Name).join(', ')}`);
|
|
255
|
+
}
|
|
128
256
|
return [];
|
|
129
257
|
}
|
|
258
|
+
if (this._verbose) {
|
|
259
|
+
(0, core_1.LogStatus)(`Memory Manager: Found extraction prompt "${prompt.Name}" (ID: ${prompt.ID})`);
|
|
260
|
+
(0, core_1.LogStatus)(`Memory Manager: Sending ${conversationThreads.length} conversation threads with ${conversationThreads.reduce((sum, t) => sum + t.messages.length, 0)} total messages for note extraction`);
|
|
261
|
+
if (conversationThreads.length > 0) {
|
|
262
|
+
const firstThread = conversationThreads[0];
|
|
263
|
+
(0, core_1.LogStatus)(`Memory Manager: Sample thread (conv ${firstThread.conversationId}): ${firstThread.messages.map(m => `[${m.role}] ${m.message?.substring(0, 80)}...`).join(' | ')}`);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
const step3 = await this.CreateRunStep('Prompt', 'Extract Notes from Conversations', {
|
|
267
|
+
conversationCount: conversationThreads.length,
|
|
268
|
+
messageCount: conversationThreads.reduce((sum, t) => sum + t.messages.length, 0),
|
|
269
|
+
existingNoteCount: existingNotes.length
|
|
270
|
+
}, prompt.ID);
|
|
130
271
|
const runner = new ai_prompts_1.AIPromptRunner();
|
|
131
272
|
const params = new ai_core_plus_1.AIPromptParams();
|
|
132
273
|
params.prompt = prompt;
|
|
133
274
|
params.data = promptData;
|
|
134
275
|
params.contextUser = contextUser;
|
|
135
276
|
const result = await runner.ExecutePrompt(params);
|
|
277
|
+
await this.FinalizeRunStep(step3, result.success, {
|
|
278
|
+
success: result.success,
|
|
279
|
+
rawNoteCount: result.result && typeof result.result !== 'string' ? (result.result.notes?.length || 0) : 0
|
|
280
|
+
}, result.promptRun?.ID, result.errorMessage || undefined);
|
|
281
|
+
if (this._verbose) {
|
|
282
|
+
(0, core_1.LogStatus)(`Memory Manager: Extraction prompt result - success: ${result.success}, hasResult: ${!!result.result}`);
|
|
283
|
+
if (result.errorMessage) {
|
|
284
|
+
(0, core_1.LogStatus)(`Memory Manager: Extraction error: ${result.errorMessage}`);
|
|
285
|
+
}
|
|
286
|
+
if (result.result) {
|
|
287
|
+
(0, core_1.LogStatus)(`Memory Manager: Raw extraction result: ${JSON.stringify(result.result)}`);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
136
290
|
if (!result.success || !result.result) {
|
|
137
291
|
(0, core_1.LogError)('Failed to extract notes:', result.errorMessage);
|
|
138
292
|
return [];
|
|
139
293
|
}
|
|
140
|
-
|
|
294
|
+
let parsedResult;
|
|
295
|
+
if (typeof result.result === 'string') {
|
|
296
|
+
try {
|
|
297
|
+
parsedResult = JSON.parse(result.result);
|
|
298
|
+
if (this._verbose) {
|
|
299
|
+
(0, core_1.LogStatus)(`Memory Manager: Parsed string result into object with ${parsedResult.notes?.length || 0} notes`);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
catch (e) {
|
|
303
|
+
(0, core_1.LogError)('Failed to parse extraction result as JSON:', e);
|
|
304
|
+
return [];
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
else {
|
|
308
|
+
parsedResult = result.result;
|
|
309
|
+
}
|
|
310
|
+
if (this._verbose && parsedResult.notes) {
|
|
311
|
+
(0, core_1.LogStatus)(`Memory Manager: LLM returned ${parsedResult.notes.length} raw notes before filtering`);
|
|
312
|
+
for (const note of parsedResult.notes) {
|
|
313
|
+
(0, core_1.LogStatus)(`Memory Manager: Raw note: [${note.type}] "${note.content}" (confidence: ${note.confidence})`);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
const candidateNotes = (parsedResult.notes || []).filter(n => n.confidence >= EXTRACTION_CONFIG.minConfidenceThreshold &&
|
|
317
|
+
n.content && n.content.length >= EXTRACTION_CONFIG.minContentLength);
|
|
318
|
+
if (candidateNotes.length === 0) {
|
|
319
|
+
if (this._verbose) {
|
|
320
|
+
(0, core_1.LogStatus)('Memory Manager: No candidates passed confidence/length thresholds');
|
|
321
|
+
}
|
|
322
|
+
return [];
|
|
323
|
+
}
|
|
324
|
+
if (this._verbose) {
|
|
325
|
+
(0, core_1.LogStatus)(`Memory Manager: ${candidateNotes.length} candidates passed confidence threshold (>=${EXTRACTION_CONFIG.minConfidenceThreshold})`);
|
|
326
|
+
for (const note of candidateNotes) {
|
|
327
|
+
(0, core_1.LogStatus)(`Memory Manager: Extracted note: [${note.type}] "${note.content}" (confidence: ${note.confidence})`);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
const notesByMessage = new Map();
|
|
331
|
+
const noteCountByConversation = new Map();
|
|
332
|
+
for (const note of candidateNotes) {
|
|
333
|
+
const msgId = note.sourceConversationDetailId || 'unknown';
|
|
334
|
+
const convId = note.sourceConversationId || 'unknown';
|
|
335
|
+
const existingForMsg = notesByMessage.get(msgId) || [];
|
|
336
|
+
const convCount = noteCountByConversation.get(convId) || 0;
|
|
337
|
+
if (existingForMsg.length >= EXTRACTION_CONFIG.maxNotesPerMessage) {
|
|
338
|
+
if (this._verbose) {
|
|
339
|
+
(0, core_1.LogStatus)(`Memory Manager: Skipping note (max ${EXTRACTION_CONFIG.maxNotesPerMessage} per message reached)`);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
else if (convCount >= EXTRACTION_CONFIG.maxNotesPerConversation) {
|
|
343
|
+
if (this._verbose) {
|
|
344
|
+
(0, core_1.LogStatus)(`Memory Manager: Skipping note (max ${EXTRACTION_CONFIG.maxNotesPerConversation} per conversation reached)`);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
else {
|
|
348
|
+
existingForMsg.push(note);
|
|
349
|
+
notesByMessage.set(msgId, existingForMsg);
|
|
350
|
+
noteCountByConversation.set(convId, convCount + 1);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
const sparseCandidates = Array.from(notesByMessage.values()).flat();
|
|
354
|
+
if (this._verbose) {
|
|
355
|
+
(0, core_1.LogStatus)(`Memory Manager: ${sparseCandidates.length} candidates after sparsity filter`);
|
|
356
|
+
}
|
|
357
|
+
const step4 = await this.CreateRunStep('Decision', 'Deduplicate Note Candidates', {
|
|
358
|
+
candidateCount: sparseCandidates.length,
|
|
359
|
+
existingNoteCount: existingNotes.length
|
|
360
|
+
});
|
|
361
|
+
const approvedNotes = [];
|
|
362
|
+
let dedupeRejectedCount = 0;
|
|
363
|
+
let dedupeLlmCallCount = 0;
|
|
364
|
+
const dedupePrompt = aiengine_1.AIEngine.Instance.Prompts.find(p => p.Name === 'Memory Manager - Deduplicate Note' && p.Category === 'MJ: System');
|
|
365
|
+
for (const candidate of sparseCandidates) {
|
|
366
|
+
if (approvedNotes.length >= EXTRACTION_CONFIG.maxNotesPerRun) {
|
|
367
|
+
if (this._verbose) {
|
|
368
|
+
(0, core_1.LogStatus)(`Memory Manager: Stopping - max notes per run (${EXTRACTION_CONFIG.maxNotesPerRun}) reached`);
|
|
369
|
+
}
|
|
370
|
+
break;
|
|
371
|
+
}
|
|
372
|
+
const normalizedContent = candidate.content.toLowerCase().trim();
|
|
373
|
+
const exactMatch = existingNotes.find(n => n.Note && n.Note.toLowerCase().trim() === normalizedContent);
|
|
374
|
+
if (exactMatch) {
|
|
375
|
+
dedupeRejectedCount++;
|
|
376
|
+
if (this._verbose) {
|
|
377
|
+
(0, core_1.LogStatus)(`Memory Manager: Skipping exact duplicate: "${candidate.content.substring(0, 50)}..."`);
|
|
378
|
+
}
|
|
379
|
+
continue;
|
|
380
|
+
}
|
|
381
|
+
const similarNotes = await aiengine_1.AIEngine.Instance.FindSimilarAgentNotes(candidate.content, candidate.agentId, candidate.userId, candidate.companyId, 10, 0.85);
|
|
382
|
+
if (dedupePrompt && similarNotes.length > 0) {
|
|
383
|
+
const dedupeParams = new ai_core_plus_1.AIPromptParams();
|
|
384
|
+
dedupeParams.prompt = dedupePrompt;
|
|
385
|
+
dedupeParams.data = {
|
|
386
|
+
candidateNote: candidate,
|
|
387
|
+
similarNotes: similarNotes.map(s => ({
|
|
388
|
+
type: s.note.Type,
|
|
389
|
+
content: s.note.Note,
|
|
390
|
+
agentId: s.note.AgentID,
|
|
391
|
+
userId: s.note.UserID,
|
|
392
|
+
companyId: s.note.CompanyID,
|
|
393
|
+
similarity: s.similarity
|
|
394
|
+
}))
|
|
395
|
+
};
|
|
396
|
+
dedupeParams.contextUser = contextUser;
|
|
397
|
+
const dedupeResult = await runner.ExecutePrompt(dedupeParams);
|
|
398
|
+
dedupeLlmCallCount++;
|
|
399
|
+
if (dedupeResult.success && dedupeResult.result && dedupeResult.result.shouldAdd) {
|
|
400
|
+
approvedNotes.push(candidate);
|
|
401
|
+
if (this._verbose) {
|
|
402
|
+
(0, core_1.LogStatus)(`Memory Manager: Approved note - ${dedupeResult.result.reason}`);
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
else {
|
|
406
|
+
dedupeRejectedCount++;
|
|
407
|
+
if (this._verbose) {
|
|
408
|
+
(0, core_1.LogStatus)(`Memory Manager: Skipped duplicate note - ${dedupeResult.result?.reason || 'too similar to existing notes'}`);
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
else {
|
|
413
|
+
approvedNotes.push(candidate);
|
|
414
|
+
if (this._verbose) {
|
|
415
|
+
(0, core_1.LogStatus)(`Memory Manager: Approved note (no similar notes found): "${candidate.content.substring(0, 50)}..."`);
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
await this.FinalizeRunStep(step4, true, {
|
|
420
|
+
approvedCount: approvedNotes.length,
|
|
421
|
+
rejectedCount: dedupeRejectedCount,
|
|
422
|
+
llmCallCount: dedupeLlmCallCount
|
|
423
|
+
});
|
|
424
|
+
if (this._verbose) {
|
|
425
|
+
(0, core_1.LogStatus)(`Memory Manager: Final approved notes: ${approvedNotes.length}`);
|
|
426
|
+
}
|
|
427
|
+
const conversationContext = new Map();
|
|
428
|
+
for (const thread of conversationThreads) {
|
|
429
|
+
conversationContext.set(thread.conversationId, {
|
|
430
|
+
userId: thread.userId || null,
|
|
431
|
+
agentRunId: thread.agentRunId || null
|
|
432
|
+
});
|
|
433
|
+
}
|
|
434
|
+
for (const note of approvedNotes) {
|
|
435
|
+
if (note.sourceConversationId) {
|
|
436
|
+
const ctx = conversationContext.get(note.sourceConversationId);
|
|
437
|
+
if (ctx) {
|
|
438
|
+
if (!note.userId && ctx.userId) {
|
|
439
|
+
note.userId = ctx.userId;
|
|
440
|
+
}
|
|
441
|
+
if (!note.sourceAgentRunId && ctx.agentRunId) {
|
|
442
|
+
note.sourceAgentRunId = ctx.agentRunId;
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
return approvedNotes;
|
|
141
448
|
}
|
|
142
449
|
async ExtractExamples(conversationDetails, contextUser) {
|
|
143
450
|
if (conversationDetails.length === 0) {
|
|
@@ -155,6 +462,9 @@ class MemoryManagerAgent extends base_agent_1.BaseAgent {
|
|
|
155
462
|
(0, core_1.LogError)('Memory Manager example extraction prompt not found');
|
|
156
463
|
return [];
|
|
157
464
|
}
|
|
465
|
+
const step5 = await this.CreateRunStep('Prompt', 'Extract Examples from Conversations', {
|
|
466
|
+
qaPairCount: qaPairs.length
|
|
467
|
+
}, extractPrompt.ID);
|
|
158
468
|
const runner = new ai_prompts_1.AIPromptRunner();
|
|
159
469
|
const extractParams = new ai_core_plus_1.AIPromptParams();
|
|
160
470
|
extractParams.prompt = extractPrompt;
|
|
@@ -162,15 +472,40 @@ class MemoryManagerAgent extends base_agent_1.BaseAgent {
|
|
|
162
472
|
extractParams.contextUser = contextUser;
|
|
163
473
|
const extractResult = await runner.ExecutePrompt(extractParams);
|
|
164
474
|
if (!extractResult.success || !extractResult.result) {
|
|
475
|
+
await this.FinalizeRunStep(step5, false, {
|
|
476
|
+
success: false
|
|
477
|
+
}, extractResult.promptRun?.ID, extractResult.errorMessage || undefined);
|
|
165
478
|
(0, core_1.LogError)('Failed to extract examples:', extractResult.errorMessage);
|
|
166
479
|
return [];
|
|
167
480
|
}
|
|
168
|
-
|
|
481
|
+
let parsedResult;
|
|
482
|
+
if (typeof extractResult.result === 'string') {
|
|
483
|
+
try {
|
|
484
|
+
parsedResult = JSON.parse(extractResult.result);
|
|
485
|
+
}
|
|
486
|
+
catch (e) {
|
|
487
|
+
(0, core_1.LogError)('Failed to parse example extraction result as JSON:', e);
|
|
488
|
+
return [];
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
else {
|
|
492
|
+
parsedResult = extractResult.result;
|
|
493
|
+
}
|
|
494
|
+
const candidateExamples = (parsedResult.examples || [])
|
|
169
495
|
.filter(e => e.successScore >= 70 && e.confidence >= 70);
|
|
496
|
+
await this.FinalizeRunStep(step5, true, {
|
|
497
|
+
rawExampleCount: parsedResult.examples?.length || 0,
|
|
498
|
+
candidateCount: candidateExamples.length
|
|
499
|
+
}, extractResult.promptRun?.ID);
|
|
170
500
|
if (candidateExamples.length === 0) {
|
|
171
501
|
return [];
|
|
172
502
|
}
|
|
503
|
+
const step6 = await this.CreateRunStep('Decision', 'Deduplicate Example Candidates', {
|
|
504
|
+
candidateCount: candidateExamples.length
|
|
505
|
+
});
|
|
173
506
|
const approvedExamples = [];
|
|
507
|
+
let exampleDedupeRejectedCount = 0;
|
|
508
|
+
let exampleDedupeLlmCallCount = 0;
|
|
174
509
|
for (const candidate of candidateExamples) {
|
|
175
510
|
const similarExamples = await aiengine_1.AIEngine.Instance.FindSimilarAgentExamples(candidate.exampleInput, candidate.agentId, candidate.userId, candidate.companyId, 5, 0.7);
|
|
176
511
|
const dedupePrompt = aiengine_1.AIEngine.Instance.Prompts.find(p => p.Name === 'Memory Manager - Deduplicate Example' && p.Category === 'MJ: System');
|
|
@@ -188,65 +523,182 @@ class MemoryManagerAgent extends base_agent_1.BaseAgent {
|
|
|
188
523
|
};
|
|
189
524
|
dedupeParams.contextUser = contextUser;
|
|
190
525
|
const dedupeResult = await runner.ExecutePrompt(dedupeParams);
|
|
526
|
+
exampleDedupeLlmCallCount++;
|
|
191
527
|
if (dedupeResult.success && dedupeResult.result && dedupeResult.result.shouldAdd) {
|
|
192
528
|
approvedExamples.push(candidate);
|
|
193
|
-
(
|
|
529
|
+
if (this._verbose) {
|
|
530
|
+
(0, core_1.LogStatus)(`Memory Manager: Approved example - ${dedupeResult.result.reason}`);
|
|
531
|
+
}
|
|
194
532
|
}
|
|
195
533
|
else {
|
|
196
|
-
|
|
534
|
+
exampleDedupeRejectedCount++;
|
|
535
|
+
if (this._verbose) {
|
|
536
|
+
(0, core_1.LogStatus)(`Memory Manager: Skipped duplicate example - ${dedupeResult.result?.reason || 'too similar'}`);
|
|
537
|
+
}
|
|
197
538
|
}
|
|
198
539
|
}
|
|
199
540
|
else {
|
|
200
541
|
approvedExamples.push(candidate);
|
|
201
542
|
}
|
|
202
543
|
}
|
|
544
|
+
await this.FinalizeRunStep(step6, true, {
|
|
545
|
+
approvedCount: approvedExamples.length,
|
|
546
|
+
rejectedCount: exampleDedupeRejectedCount,
|
|
547
|
+
llmCallCount: exampleDedupeLlmCallCount
|
|
548
|
+
});
|
|
203
549
|
return approvedExamples;
|
|
204
550
|
}
|
|
551
|
+
isValidUUID(str) {
|
|
552
|
+
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
553
|
+
return uuidRegex.test(str);
|
|
554
|
+
}
|
|
205
555
|
async CreateNoteRecords(extractedNotes, contextUser) {
|
|
556
|
+
const step7 = await this.CreateRunStep('Decision', 'Create Note Records', {
|
|
557
|
+
noteCount: extractedNotes.length
|
|
558
|
+
});
|
|
206
559
|
let created = 0;
|
|
560
|
+
let merged = 0;
|
|
561
|
+
let failed = 0;
|
|
207
562
|
const md = new core_1.Metadata();
|
|
563
|
+
const rv = new core_1.RunView();
|
|
564
|
+
const runCache = new Map();
|
|
565
|
+
const aiNoteTypeId = aiengine_1.AIEngine.Instance.AgenteNoteTypeIDByName('AI');
|
|
566
|
+
if (!aiNoteTypeId) {
|
|
567
|
+
(0, core_1.LogError)('Memory Manager: Could not find "AI" note type - cannot create notes');
|
|
568
|
+
await this.FinalizeRunStep(step7, false, {
|
|
569
|
+
created: 0,
|
|
570
|
+
merged: 0,
|
|
571
|
+
failed: extractedNotes.length
|
|
572
|
+
}, undefined, 'Could not find "AI" note type');
|
|
573
|
+
return 0;
|
|
574
|
+
}
|
|
208
575
|
for (const extracted of extractedNotes) {
|
|
209
576
|
try {
|
|
577
|
+
let sourceRun = null;
|
|
578
|
+
if (extracted.sourceAgentRunId) {
|
|
579
|
+
if (!runCache.has(extracted.sourceAgentRunId)) {
|
|
580
|
+
const runResult = await rv.RunView({
|
|
581
|
+
EntityName: 'MJ: AI Agent Runs',
|
|
582
|
+
ExtraFilter: `ID='${extracted.sourceAgentRunId}'`,
|
|
583
|
+
MaxRows: 1,
|
|
584
|
+
ResultType: 'entity_object'
|
|
585
|
+
}, contextUser);
|
|
586
|
+
runCache.set(extracted.sourceAgentRunId, runResult.Success && runResult.Results?.length > 0 ? runResult.Results[0] : null);
|
|
587
|
+
}
|
|
588
|
+
sourceRun = runCache.get(extracted.sourceAgentRunId) || null;
|
|
589
|
+
}
|
|
210
590
|
if (extracted.mergeWithExistingId) {
|
|
211
591
|
const existingNote = await md.GetEntityObject('AI Agent Notes', contextUser);
|
|
212
592
|
if (await existingNote.Load(extracted.mergeWithExistingId)) {
|
|
213
593
|
existingNote.Note = extracted.content;
|
|
214
594
|
existingNote.Type = extracted.type;
|
|
215
|
-
|
|
216
|
-
|
|
595
|
+
existingNote.AgentNoteTypeID = aiNoteTypeId;
|
|
596
|
+
if (await existingNote.Save()) {
|
|
597
|
+
merged++;
|
|
598
|
+
}
|
|
599
|
+
else {
|
|
600
|
+
failed++;
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
else {
|
|
604
|
+
failed++;
|
|
217
605
|
}
|
|
218
606
|
}
|
|
219
607
|
else {
|
|
220
608
|
const note = await md.GetEntityObject('AI Agent Notes', contextUser);
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
609
|
+
const isValidUUID = (id) => {
|
|
610
|
+
if (!id)
|
|
611
|
+
return false;
|
|
612
|
+
return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(id);
|
|
613
|
+
};
|
|
614
|
+
let agentId = isValidUUID(extracted.agentId) ? extracted.agentId : null;
|
|
615
|
+
if (!agentId && sourceRun?.AgentID) {
|
|
616
|
+
agentId = sourceRun.AgentID;
|
|
617
|
+
}
|
|
618
|
+
note.AgentID = agentId;
|
|
619
|
+
note.UserID = isValidUUID(extracted.userId) ? extracted.userId : null;
|
|
620
|
+
note.CompanyID = isValidUUID(extracted.companyId) ? extracted.companyId : null;
|
|
621
|
+
note.AgentNoteTypeID = aiNoteTypeId;
|
|
225
622
|
note.Type = extracted.type;
|
|
226
623
|
note.Note = extracted.content;
|
|
227
624
|
note.IsAutoGenerated = true;
|
|
228
625
|
note.Status = 'Active';
|
|
626
|
+
note.AccessCount = 1;
|
|
229
627
|
note.SourceConversationID = extracted.sourceConversationId || null;
|
|
230
|
-
note.SourceConversationDetailID = extracted.sourceConversationDetailId
|
|
628
|
+
note.SourceConversationDetailID = isValidUUID(extracted.sourceConversationDetailId) ? extracted.sourceConversationDetailId : null;
|
|
231
629
|
note.SourceAIAgentRunID = extracted.sourceAgentRunId || null;
|
|
232
|
-
|
|
630
|
+
const scopeLevel = extracted.scopeLevel || 'contact';
|
|
631
|
+
if (scopeLevel === 'global') {
|
|
632
|
+
note.PrimaryScopeEntityID = null;
|
|
633
|
+
note.PrimaryScopeRecordID = null;
|
|
634
|
+
note.SecondaryScopes = null;
|
|
635
|
+
}
|
|
636
|
+
else if (scopeLevel === 'organization' && sourceRun?.PrimaryScopeEntityID) {
|
|
637
|
+
note.PrimaryScopeEntityID = sourceRun.PrimaryScopeEntityID;
|
|
638
|
+
note.PrimaryScopeRecordID = sourceRun.PrimaryScopeRecordID;
|
|
639
|
+
note.SecondaryScopes = null;
|
|
640
|
+
}
|
|
641
|
+
else if (sourceRun) {
|
|
642
|
+
note.PrimaryScopeEntityID = sourceRun.PrimaryScopeEntityID;
|
|
643
|
+
note.PrimaryScopeRecordID = sourceRun.PrimaryScopeRecordID;
|
|
644
|
+
note.SecondaryScopes = sourceRun.SecondaryScopes;
|
|
645
|
+
}
|
|
646
|
+
const saveResult = await note.Save();
|
|
647
|
+
if (saveResult) {
|
|
233
648
|
created++;
|
|
234
649
|
}
|
|
650
|
+
else {
|
|
651
|
+
failed++;
|
|
652
|
+
(0, core_1.LogError)(`Memory Manager: Failed to save note - Validation errors: ${JSON.stringify(note.LatestResult)}`);
|
|
653
|
+
}
|
|
235
654
|
}
|
|
236
655
|
}
|
|
237
656
|
catch (error) {
|
|
238
|
-
|
|
657
|
+
failed++;
|
|
658
|
+
(0, core_1.LogError)('Memory Manager: Exception creating note:', error);
|
|
239
659
|
}
|
|
240
660
|
}
|
|
241
|
-
|
|
661
|
+
await this.FinalizeRunStep(step7, failed === 0 || created > 0 || merged > 0, {
|
|
662
|
+
created,
|
|
663
|
+
merged,
|
|
664
|
+
failed
|
|
665
|
+
});
|
|
666
|
+
return created + merged;
|
|
242
667
|
}
|
|
243
668
|
async CreateExampleRecords(extractedExamples, contextUser) {
|
|
669
|
+
const step8 = await this.CreateRunStep('Decision', 'Create Example Records', {
|
|
670
|
+
exampleCount: extractedExamples.length
|
|
671
|
+
});
|
|
244
672
|
let created = 0;
|
|
673
|
+
let skipped = 0;
|
|
674
|
+
let failed = 0;
|
|
245
675
|
const md = new core_1.Metadata();
|
|
676
|
+
const rv = new core_1.RunView();
|
|
677
|
+
const runCache = new Map();
|
|
246
678
|
for (const extracted of extractedExamples) {
|
|
247
679
|
try {
|
|
680
|
+
let sourceRun = null;
|
|
681
|
+
if (extracted.sourceAgentRunId) {
|
|
682
|
+
if (!runCache.has(extracted.sourceAgentRunId)) {
|
|
683
|
+
const runResult = await rv.RunView({
|
|
684
|
+
EntityName: 'MJ: AI Agent Runs',
|
|
685
|
+
ExtraFilter: `ID='${extracted.sourceAgentRunId}'`,
|
|
686
|
+
MaxRows: 1,
|
|
687
|
+
ResultType: 'entity_object'
|
|
688
|
+
}, contextUser);
|
|
689
|
+
runCache.set(extracted.sourceAgentRunId, runResult.Success && runResult.Results?.length > 0 ? runResult.Results[0] : null);
|
|
690
|
+
}
|
|
691
|
+
sourceRun = runCache.get(extracted.sourceAgentRunId) || null;
|
|
692
|
+
}
|
|
248
693
|
const example = await md.GetEntityObject('MJ: AI Agent Examples', contextUser);
|
|
249
|
-
|
|
694
|
+
if (!sourceRun?.AgentID) {
|
|
695
|
+
skipped++;
|
|
696
|
+
if (this._verbose) {
|
|
697
|
+
(0, core_1.LogStatus)(`Memory Manager: Skipping example - no source run to inherit AgentID from`);
|
|
698
|
+
}
|
|
699
|
+
continue;
|
|
700
|
+
}
|
|
701
|
+
example.AgentID = sourceRun.AgentID;
|
|
250
702
|
example.UserID = extracted.userId || null;
|
|
251
703
|
example.CompanyID = extracted.companyId || null;
|
|
252
704
|
example.Type = extracted.type;
|
|
@@ -256,26 +708,60 @@ class MemoryManagerAgent extends base_agent_1.BaseAgent {
|
|
|
256
708
|
example.SuccessScore = extracted.successScore;
|
|
257
709
|
example.Status = 'Active';
|
|
258
710
|
example.SourceConversationID = extracted.sourceConversationId || null;
|
|
259
|
-
example.SourceConversationDetailID = extracted.sourceConversationDetailId
|
|
711
|
+
example.SourceConversationDetailID = this.isValidUUID(extracted.sourceConversationDetailId) ? extracted.sourceConversationDetailId : null;
|
|
260
712
|
example.SourceAIAgentRunID = extracted.sourceAgentRunId || null;
|
|
713
|
+
if (sourceRun && sourceRun.PrimaryScopeEntityID) {
|
|
714
|
+
const scopeLevel = extracted.scopeLevel || 'contact';
|
|
715
|
+
if (scopeLevel === 'global') {
|
|
716
|
+
example.PrimaryScopeEntityID = null;
|
|
717
|
+
example.PrimaryScopeRecordID = null;
|
|
718
|
+
example.SecondaryScopes = null;
|
|
719
|
+
}
|
|
720
|
+
else if (scopeLevel === 'organization') {
|
|
721
|
+
example.PrimaryScopeEntityID = sourceRun.PrimaryScopeEntityID;
|
|
722
|
+
example.PrimaryScopeRecordID = sourceRun.PrimaryScopeRecordID;
|
|
723
|
+
example.SecondaryScopes = null;
|
|
724
|
+
}
|
|
725
|
+
else {
|
|
726
|
+
example.PrimaryScopeEntityID = sourceRun.PrimaryScopeEntityID;
|
|
727
|
+
example.PrimaryScopeRecordID = sourceRun.PrimaryScopeRecordID;
|
|
728
|
+
example.SecondaryScopes = sourceRun.SecondaryScopes;
|
|
729
|
+
}
|
|
730
|
+
}
|
|
261
731
|
if (await example.Save()) {
|
|
262
732
|
created++;
|
|
263
733
|
}
|
|
734
|
+
else {
|
|
735
|
+
failed++;
|
|
736
|
+
(0, core_1.LogError)(`Memory Manager: Failed to save example - Validation errors: ${JSON.stringify(example.LatestResult)}`);
|
|
737
|
+
}
|
|
264
738
|
}
|
|
265
739
|
catch (error) {
|
|
266
|
-
|
|
740
|
+
failed++;
|
|
741
|
+
(0, core_1.LogError)('Memory Manager: Exception creating example:', error);
|
|
267
742
|
}
|
|
268
743
|
}
|
|
744
|
+
await this.FinalizeRunStep(step8, failed === 0 || created > 0, {
|
|
745
|
+
created,
|
|
746
|
+
skipped,
|
|
747
|
+
failed
|
|
748
|
+
});
|
|
269
749
|
return created;
|
|
270
750
|
}
|
|
271
751
|
async executeAgentInternal(params, config) {
|
|
272
752
|
try {
|
|
753
|
+
this._verbose = params.verbose ?? false;
|
|
754
|
+
this._agentRunID = this.AgentRun?.ID || null;
|
|
755
|
+
this._stepCounter = 0;
|
|
756
|
+
this._contextUser = params.contextUser || null;
|
|
273
757
|
(0, core_1.LogStatus)('Memory Manager: Starting analysis cycle');
|
|
274
758
|
const lastRunTime = await this.GetLastRunTime(params.agent.ID, params.contextUser);
|
|
275
|
-
const sinceMessage = lastRunTime ? `since ${lastRunTime.toISOString()}` : 'all history';
|
|
276
|
-
(0, core_1.LogStatus)(`Memory Manager: Processing ${sinceMessage}`);
|
|
277
759
|
const agentsUsingMemory = await this.LoadAgentsUsingMemory(params.contextUser);
|
|
278
|
-
(
|
|
760
|
+
if (this._verbose) {
|
|
761
|
+
const sinceMessage = lastRunTime ? `since ${lastRunTime.toISOString()}` : 'all history';
|
|
762
|
+
(0, core_1.LogStatus)(`Memory Manager: Processing ${sinceMessage}`);
|
|
763
|
+
(0, core_1.LogStatus)(`Memory Manager: Found ${agentsUsingMemory.length} agents with memory injection enabled`);
|
|
764
|
+
}
|
|
279
765
|
if (agentsUsingMemory.length === 0) {
|
|
280
766
|
const finalStep = {
|
|
281
767
|
terminate: true,
|
|
@@ -284,34 +770,109 @@ class MemoryManagerAgent extends base_agent_1.BaseAgent {
|
|
|
284
770
|
};
|
|
285
771
|
return { finalStep, stepCount: 1 };
|
|
286
772
|
}
|
|
287
|
-
const
|
|
288
|
-
|
|
773
|
+
const step1 = await this.CreateRunStep('Decision', 'Load Conversations With New Activity', {
|
|
774
|
+
since: lastRunTime?.toISOString() || null,
|
|
775
|
+
agentCount: agentsUsingMemory.length,
|
|
776
|
+
agentIds: agentsUsingMemory.map(a => a.ID)
|
|
777
|
+
});
|
|
778
|
+
const conversations = await this.LoadConversationsWithNewActivity(lastRunTime, agentsUsingMemory, params.contextUser);
|
|
779
|
+
const totalMessages = conversations.reduce((sum, c) => sum + c.messages.length, 0);
|
|
780
|
+
await this.FinalizeRunStep(step1, true, {
|
|
781
|
+
conversationCount: conversations.length,
|
|
782
|
+
totalMessages,
|
|
783
|
+
positiveCount: conversations.filter(c => c.hasPositiveRating).length,
|
|
784
|
+
negativeCount: conversations.filter(c => c.hasNegativeRating).length,
|
|
785
|
+
unratedCount: conversations.filter(c => c.isUnrated).length
|
|
786
|
+
});
|
|
787
|
+
if (this._verbose) {
|
|
788
|
+
(0, core_1.LogStatus)(`Memory Manager: Found ${conversations.length} conversations with new activity`);
|
|
789
|
+
}
|
|
790
|
+
const step2 = await this.CreateRunStep('Decision', 'Load High-Value Agent Runs', {
|
|
791
|
+
since: lastRunTime?.toISOString() || null
|
|
792
|
+
});
|
|
289
793
|
const agentRuns = await this.LoadHighValueAgentRuns(lastRunTime, params.contextUser);
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
794
|
+
await this.FinalizeRunStep(step2, true, {
|
|
795
|
+
runCount: agentRuns.length
|
|
796
|
+
});
|
|
797
|
+
if (this._verbose) {
|
|
798
|
+
(0, core_1.LogStatus)(`Memory Manager: Found ${agentRuns.length} high-value agent runs`);
|
|
799
|
+
}
|
|
800
|
+
if (conversations.length === 0 && agentRuns.length === 0) {
|
|
801
|
+
if (this._verbose) {
|
|
802
|
+
(0, core_1.LogStatus)('Memory Manager: No data to process');
|
|
803
|
+
}
|
|
293
804
|
const finalStep = {
|
|
294
805
|
terminate: true,
|
|
295
806
|
step: 'Success',
|
|
296
|
-
message: 'No
|
|
807
|
+
message: 'No conversations with new activity or agent runs to process'
|
|
297
808
|
};
|
|
298
809
|
return { finalStep, stepCount: 1 };
|
|
299
810
|
}
|
|
300
|
-
const extractedNotes = await this.
|
|
301
|
-
(
|
|
811
|
+
const extractedNotes = await this.ExtractNotesFromConversations(conversations, params.contextUser);
|
|
812
|
+
if (this._verbose) {
|
|
813
|
+
(0, core_1.LogStatus)(`Memory Manager: Extracted ${extractedNotes.length} potential notes`);
|
|
814
|
+
}
|
|
815
|
+
const conversationDetails = conversations.flatMap(conv => conv.messages.map(msg => ({
|
|
816
|
+
ID: msg.id,
|
|
817
|
+
ConversationID: conv.conversationId,
|
|
818
|
+
Role: msg.role,
|
|
819
|
+
Message: msg.message,
|
|
820
|
+
Status: 'Complete',
|
|
821
|
+
__mj_CreatedAt: msg.createdAt
|
|
822
|
+
})));
|
|
302
823
|
const extractedExamples = await this.ExtractExamples(conversationDetails, params.contextUser);
|
|
303
|
-
(
|
|
824
|
+
if (this._verbose) {
|
|
825
|
+
(0, core_1.LogStatus)(`Memory Manager: Extracted ${extractedExamples.length} potential examples`);
|
|
826
|
+
}
|
|
827
|
+
const conversationContextForExamples = new Map();
|
|
828
|
+
for (const conv of conversations) {
|
|
829
|
+
conversationContextForExamples.set(conv.conversationId, {
|
|
830
|
+
userId: conv.userId || null,
|
|
831
|
+
agentRunId: conv.agentRunId || null
|
|
832
|
+
});
|
|
833
|
+
}
|
|
834
|
+
for (const example of extractedExamples) {
|
|
835
|
+
if (example.sourceConversationId) {
|
|
836
|
+
const ctx = conversationContextForExamples.get(example.sourceConversationId);
|
|
837
|
+
if (ctx) {
|
|
838
|
+
if (!example.userId && ctx.userId) {
|
|
839
|
+
example.userId = ctx.userId;
|
|
840
|
+
if (this._verbose) {
|
|
841
|
+
(0, core_1.LogStatus)(`Memory Manager: Enriched example with userId from conversation: ${ctx.userId}`);
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
if (!example.sourceAgentRunId && ctx.agentRunId) {
|
|
845
|
+
example.sourceAgentRunId = ctx.agentRunId;
|
|
846
|
+
if (this._verbose) {
|
|
847
|
+
(0, core_1.LogStatus)(`Memory Manager: Enriched example with agentRunId from conversation: ${ctx.agentRunId}`);
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
if (example.agentId && !this.isValidUUID(example.agentId)) {
|
|
853
|
+
if (this._verbose) {
|
|
854
|
+
(0, core_1.LogStatus)(`Memory Manager: Clearing invalid agentId "${example.agentId}" from example`);
|
|
855
|
+
}
|
|
856
|
+
example.agentId = '';
|
|
857
|
+
}
|
|
858
|
+
}
|
|
304
859
|
const notesCreated = await this.CreateNoteRecords(extractedNotes, params.contextUser);
|
|
305
860
|
const examplesCreated = await this.CreateExampleRecords(extractedExamples, params.contextUser);
|
|
306
861
|
(0, core_1.LogStatus)(`Memory Manager: Created ${notesCreated} notes and ${examplesCreated} examples`);
|
|
862
|
+
if (notesCreated > 0 || examplesCreated > 0) {
|
|
863
|
+
(0, core_1.LogStatus)(`Memory Manager: Refreshing AIEngine memory cache...`);
|
|
864
|
+
await aiengine_1.AIEngine.Instance.Config(true, params.contextUser);
|
|
865
|
+
(0, core_1.LogStatus)(`Memory Manager: Memory cache refreshed`);
|
|
866
|
+
}
|
|
307
867
|
const finalStep = {
|
|
308
868
|
terminate: true,
|
|
309
869
|
step: 'Success',
|
|
310
|
-
message: `Processed ${
|
|
870
|
+
message: `Processed ${conversations.length} conversations (${totalMessages} messages) and ${agentRuns.length} agent runs. Created ${notesCreated} notes and ${examplesCreated} examples.`,
|
|
311
871
|
newPayload: {
|
|
312
872
|
notesCreated,
|
|
313
873
|
examplesCreated,
|
|
314
|
-
|
|
874
|
+
conversationsProcessed: conversations.length,
|
|
875
|
+
messagesProcessed: totalMessages,
|
|
315
876
|
agentRunsProcessed: agentRuns.length
|
|
316
877
|
}
|
|
317
878
|
};
|
|
@@ -327,6 +888,9 @@ class MemoryManagerAgent extends base_agent_1.BaseAgent {
|
|
|
327
888
|
return { finalStep, stepCount: 1 };
|
|
328
889
|
}
|
|
329
890
|
}
|
|
330
|
-
}
|
|
891
|
+
};
|
|
331
892
|
exports.MemoryManagerAgent = MemoryManagerAgent;
|
|
893
|
+
exports.MemoryManagerAgent = MemoryManagerAgent = __decorate([
|
|
894
|
+
(0, global_1.RegisterClass)(base_agent_1.BaseAgent, 'MemoryManagerAgent')
|
|
895
|
+
], MemoryManagerAgent);
|
|
332
896
|
//# sourceMappingURL=memory-manager-agent.js.map
|