@memberjunction/ai-agents 3.4.0 → 4.0.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.
Files changed (97) hide show
  1. package/dist/AgentDataPreloader.d.ts +117 -1
  2. package/dist/AgentDataPreloader.d.ts.map +1 -1
  3. package/dist/AgentDataPreloader.js +156 -58
  4. package/dist/AgentDataPreloader.js.map +1 -1
  5. package/dist/AgentRunner.d.ts +212 -0
  6. package/dist/AgentRunner.d.ts.map +1 -1
  7. package/dist/AgentRunner.js +354 -103
  8. package/dist/AgentRunner.js.map +1 -1
  9. package/dist/PayloadChangeAnalyzer.d.ts +68 -0
  10. package/dist/PayloadChangeAnalyzer.d.ts.map +1 -1
  11. package/dist/PayloadChangeAnalyzer.js +68 -32
  12. package/dist/PayloadChangeAnalyzer.js.map +1 -1
  13. package/dist/PayloadFeedbackManager.d.ts +57 -1
  14. package/dist/PayloadFeedbackManager.d.ts.map +1 -1
  15. package/dist/PayloadFeedbackManager.js +66 -21
  16. package/dist/PayloadFeedbackManager.js.map +1 -1
  17. package/dist/PayloadManager.d.ts +286 -1
  18. package/dist/PayloadManager.d.ts.map +1 -1
  19. package/dist/PayloadManager.js +423 -50
  20. package/dist/PayloadManager.js.map +1 -1
  21. package/dist/__tests__/action-changes.test.d.ts +13 -0
  22. package/dist/__tests__/action-changes.test.d.ts.map +1 -1
  23. package/dist/__tests__/action-changes.test.js +57 -4
  24. package/dist/__tests__/action-changes.test.js.map +1 -1
  25. package/dist/__tests__/agent-memory-features.test.d.ts +52 -0
  26. package/dist/__tests__/agent-memory-features.test.d.ts.map +1 -1
  27. package/dist/__tests__/agent-memory-features.test.js +96 -13
  28. package/dist/__tests__/agent-memory-features.test.js.map +1 -1
  29. package/dist/__tests__/agent-type-prompt-params.test.d.ts +12 -0
  30. package/dist/__tests__/agent-type-prompt-params.test.d.ts.map +1 -1
  31. package/dist/__tests__/agent-type-prompt-params.test.js +112 -20
  32. package/dist/__tests__/agent-type-prompt-params.test.js.map +1 -1
  33. package/dist/__tests__/chat-handling-option.test.d.ts +26 -0
  34. package/dist/__tests__/chat-handling-option.test.d.ts.map +1 -1
  35. package/dist/__tests__/chat-handling-option.test.js +41 -2
  36. package/dist/__tests__/chat-handling-option.test.js.map +1 -1
  37. package/dist/agent-context-injector.d.ts +114 -0
  38. package/dist/agent-context-injector.d.ts.map +1 -1
  39. package/dist/agent-context-injector.js +138 -19
  40. package/dist/agent-context-injector.js.map +1 -1
  41. package/dist/agent-types/base-agent-type.d.ts +354 -0
  42. package/dist/agent-types/base-agent-type.d.ts.map +1 -1
  43. package/dist/agent-types/base-agent-type.js +288 -17
  44. package/dist/agent-types/base-agent-type.js.map +1 -1
  45. package/dist/agent-types/flow-agent-type.d.ts +328 -2
  46. package/dist/agent-types/flow-agent-type.d.ts.map +1 -1
  47. package/dist/agent-types/flow-agent-type.js +503 -63
  48. package/dist/agent-types/flow-agent-type.js.map +1 -1
  49. package/dist/agent-types/index.d.ts +14 -3
  50. package/dist/agent-types/index.d.ts.map +1 -1
  51. package/dist/agent-types/index.js +14 -23
  52. package/dist/agent-types/index.js.map +1 -1
  53. package/dist/agent-types/loop-agent-prompt-params.d.ts +190 -0
  54. package/dist/agent-types/loop-agent-prompt-params.d.ts.map +1 -1
  55. package/dist/agent-types/loop-agent-prompt-params.js +23 -6
  56. package/dist/agent-types/loop-agent-prompt-params.js.map +1 -1
  57. package/dist/agent-types/loop-agent-response-type.d.ts +62 -0
  58. package/dist/agent-types/loop-agent-response-type.d.ts.map +1 -1
  59. package/dist/agent-types/loop-agent-response-type.js +3 -2
  60. package/dist/agent-types/loop-agent-response-type.js.map +1 -1
  61. package/dist/agent-types/loop-agent-type.d.ts +139 -2
  62. package/dist/agent-types/loop-agent-type.d.ts.map +1 -1
  63. package/dist/agent-types/loop-agent-type.js +207 -35
  64. package/dist/agent-types/loop-agent-type.js.map +1 -1
  65. package/dist/base-agent.d.ts +1344 -1
  66. package/dist/base-agent.d.ts.map +1 -1
  67. package/dist/base-agent.js +2282 -211
  68. package/dist/base-agent.js.map +1 -1
  69. package/dist/index.d.ts +24 -14
  70. package/dist/index.d.ts.map +1 -1
  71. package/dist/index.js +25 -35
  72. package/dist/index.js.map +1 -1
  73. package/dist/memory-cleanup-agent.d.ts +53 -1
  74. package/dist/memory-cleanup-agent.d.ts.map +1 -1
  75. package/dist/memory-cleanup-agent.js +89 -21
  76. package/dist/memory-cleanup-agent.js.map +1 -1
  77. package/dist/memory-manager-agent.d.ts +61 -1
  78. package/dist/memory-manager-agent.d.ts.map +1 -1
  79. package/dist/memory-manager-agent.js +260 -116
  80. package/dist/memory-manager-agent.js.map +1 -1
  81. package/dist/services/AgentEmbeddingService.d.ts +16 -0
  82. package/dist/services/AgentEmbeddingService.d.ts.map +1 -0
  83. package/dist/services/AgentEmbeddingService.js +158 -0
  84. package/dist/services/AgentEmbeddingService.js.map +1 -0
  85. package/dist/types/AgentMatchResult.d.ts +18 -0
  86. package/dist/types/AgentMatchResult.d.ts.map +1 -0
  87. package/dist/types/AgentMatchResult.js +3 -0
  88. package/dist/types/AgentMatchResult.js.map +1 -0
  89. package/dist/types/payload-operations.d.ts +51 -0
  90. package/dist/types/payload-operations.d.ts.map +1 -1
  91. package/dist/types/payload-operations.js +54 -15
  92. package/dist/types/payload-operations.js.map +1 -1
  93. package/dist/utils/ConversationMessageResolver.d.ts +79 -1
  94. package/dist/utils/ConversationMessageResolver.d.ts.map +1 -1
  95. package/dist/utils/ConversationMessageResolver.js +99 -9
  96. package/dist/utils/ConversationMessageResolver.js.map +1 -1
  97. package/package.json +20 -19
@@ -1,40 +1,53 @@
1
- "use strict";
2
1
  var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
2
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
3
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
4
  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
5
  return c > 3 && r && Object.defineProperty(target, key, r), r;
7
6
  };
8
- Object.defineProperty(exports, "__esModule", { value: true });
9
- exports.MemoryManagerAgent = void 0;
10
- const base_agent_1 = require("./base-agent");
11
- const global_1 = require("@memberjunction/global");
12
- const core_1 = require("@memberjunction/core");
13
- const ai_prompts_1 = require("@memberjunction/ai-prompts");
14
- const ai_core_plus_1 = require("@memberjunction/ai-core-plus");
15
- const aiengine_1 = require("@memberjunction/aiengine");
7
+ import { BaseAgent } from './base-agent.js';
8
+ import { RegisterClass } from '@memberjunction/global';
9
+ import { Metadata, RunView, RunQuery, LogError, LogStatus } from '@memberjunction/core';
10
+ import { AIPromptRunner } from '@memberjunction/ai-prompts';
11
+ import { AIPromptParams } from '@memberjunction/ai-core-plus';
12
+ import { AIEngine } from '@memberjunction/aiengine';
13
+ /**
14
+ * Configuration for extraction limits to ensure sparsity
15
+ */
16
16
  const EXTRACTION_CONFIG = {
17
- maxNotesPerRun: 1000,
18
- maxNotesPerConversation: 1000,
19
- maxNotesPerMessage: 1000,
20
- minConfidenceThreshold: 80,
21
- minContentLength: 10,
22
- cooldownHours: 24
17
+ maxNotesPerRun: 1000, // Max new notes per agent run
18
+ maxNotesPerConversation: 1000, // Max notes from a single conversation
19
+ maxNotesPerMessage: 1000, // Max notes from a single message
20
+ minConfidenceThreshold: 80, // Minimum confidence to extract a note
21
+ minContentLength: 10, // Minimum note content length (lowered from 20 to allow short names)
22
+ cooldownHours: 24 // Don't re-extract from same conversation within 24h
23
23
  };
24
- let MemoryManagerAgent = class MemoryManagerAgent extends base_agent_1.BaseAgent {
24
+ /**
25
+ * Memory Manager Agent - automatically extracts notes and examples from conversations.
26
+ * This agent runs on a schedule (every 15 minutes) and analyzes high-quality conversations
27
+ * and agent runs to extract learnings and example interactions.
28
+ */
29
+ let MemoryManagerAgent = class MemoryManagerAgent extends BaseAgent {
25
30
  constructor() {
26
31
  super(...arguments);
32
+ /** Verbose logging flag from params.verbose */
27
33
  this._verbose = false;
34
+ /** Agent run ID for creating run steps */
28
35
  this._agentRunID = null;
36
+ /** Step counter for sequential step numbering */
29
37
  this._stepCounter = 0;
38
+ /** Context user for step operations */
30
39
  this._contextUser = null;
31
40
  }
41
+ /**
42
+ * Create an agent run step record for observability.
43
+ * Returns null if agentRunID is not set (defensive check).
44
+ */
32
45
  async CreateRunStep(stepType, stepName, inputData, targetId) {
33
46
  if (!this._agentRunID || !this._contextUser) {
34
47
  return null;
35
48
  }
36
49
  try {
37
- const md = new core_1.Metadata();
50
+ const md = new Metadata();
38
51
  const step = await md.GetEntityObject('MJ: AI Agent Run Steps', this._contextUser);
39
52
  step.AgentRunID = this._agentRunID;
40
53
  step.StepNumber = ++this._stepCounter;
@@ -52,15 +65,18 @@ let MemoryManagerAgent = class MemoryManagerAgent extends base_agent_1.BaseAgent
52
65
  return step;
53
66
  }
54
67
  else {
55
- (0, core_1.LogError)(`Memory Manager: Failed to create run step: ${JSON.stringify(step.LatestResult)}`);
68
+ LogError(`Memory Manager: Failed to create run step: ${JSON.stringify(step.LatestResult)}`);
56
69
  return null;
57
70
  }
58
71
  }
59
72
  catch (error) {
60
- (0, core_1.LogError)('Memory Manager: Exception creating run step:', error);
73
+ LogError('Memory Manager: Exception creating run step:', error);
61
74
  return null;
62
75
  }
63
76
  }
77
+ /**
78
+ * Finalize an agent run step with success/failure status and output data.
79
+ */
64
80
  async FinalizeRunStep(step, success, outputData, targetLogId, errorMessage) {
65
81
  if (!step) {
66
82
  return;
@@ -79,15 +95,19 @@ let MemoryManagerAgent = class MemoryManagerAgent extends base_agent_1.BaseAgent
79
95
  step.OutputData = JSON.stringify(outputData);
80
96
  }
81
97
  if (!await step.Save()) {
82
- (0, core_1.LogError)(`Memory Manager: Failed to finalize run step: ${JSON.stringify(step.LatestResult)}`);
98
+ LogError(`Memory Manager: Failed to finalize run step: ${JSON.stringify(step.LatestResult)}`);
83
99
  }
84
100
  }
85
101
  catch (error) {
86
- (0, core_1.LogError)('Memory Manager: Exception finalizing run step:', error);
102
+ LogError('Memory Manager: Exception finalizing run step:', error);
87
103
  }
88
104
  }
105
+ /**
106
+ * Get the last run timestamp for this agent to determine what to process.
107
+ * For first run, returns null to process all history (limited by MaxRows).
108
+ */
89
109
  async GetLastRunTime(agentId, contextUser) {
90
- const rv = new core_1.RunView();
110
+ const rv = new RunView();
91
111
  const result = await rv.RunView({
92
112
  EntityName: 'MJ: AI Agent Runs',
93
113
  ExtraFilter: `AgentID='${agentId}' AND Status='Completed'`,
@@ -96,38 +116,52 @@ let MemoryManagerAgent = class MemoryManagerAgent extends base_agent_1.BaseAgent
96
116
  ResultType: 'entity_object'
97
117
  }, contextUser);
98
118
  if (result.Success && result.Results && result.Results.length > 0) {
119
+ // Ensure we return a proper Date object
99
120
  const startedAt = result.Results[0].StartedAt;
100
121
  return startedAt instanceof Date ? startedAt : new Date(startedAt);
101
122
  }
123
+ // First run - return null to process all history (with MaxRows limit)
102
124
  return null;
103
125
  }
126
+ /**
127
+ * Load agents that have note or example injection enabled.
128
+ * Only extract notes/examples for agents that actually use these features.
129
+ */
104
130
  async LoadAgentsUsingMemory(contextUser) {
105
- const allAgents = aiengine_1.AIEngine.Instance.Agents;
131
+ const allAgents = AIEngine.Instance.Agents;
106
132
  const filteredAgents = allAgents.filter(a => a.Status === 'Active' && (a.InjectNotes || a.InjectExamples));
133
+ // Debug logging only in verbose mode
107
134
  if (this._verbose) {
108
- (0, core_1.LogStatus)(`Memory Manager: AIEngine has ${allAgents.length} total agents cached`);
135
+ LogStatus(`Memory Manager: AIEngine has ${allAgents.length} total agents cached`);
109
136
  if (filteredAgents.length > 0) {
110
137
  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}`);
138
+ LogStatus(`Memory Manager: Agents with memory enabled: ${agentNames}`);
112
139
  }
113
140
  const sage = allAgents.find(a => a.Name === 'Sage');
114
141
  if (sage) {
115
- (0, core_1.LogStatus)(`Memory Manager: Sage agent - ID=${sage.ID}, InjectNotes=${sage.InjectNotes}, InjectExamples=${sage.InjectExamples}, Status=${sage.Status}`);
142
+ LogStatus(`Memory Manager: Sage agent - ID=${sage.ID}, InjectNotes=${sage.InjectNotes}, InjectExamples=${sage.InjectExamples}, Status=${sage.Status}`);
116
143
  }
117
144
  }
145
+ // Warning: Always log if Sage is missing
118
146
  const sage = allAgents.find(a => a.Name === 'Sage');
119
147
  if (!sage) {
120
- (0, core_1.LogStatus)(`Memory Manager: WARNING - Sage agent not found in AIEngine cache!`);
148
+ LogStatus(`Memory Manager: WARNING - Sage agent not found in AIEngine cache!`);
121
149
  }
122
150
  return filteredAgents;
123
151
  }
152
+ /**
153
+ * Load conversations with new activity since last run, including rating data.
154
+ * Uses a single optimized RunQuery that replaces 4 separate database queries.
155
+ * Returns conversations with their details, ratings, and agent run IDs for scope inheritance.
156
+ */
124
157
  async LoadConversationsWithNewActivity(since, agentsUsingMemory, contextUser) {
125
158
  if (agentsUsingMemory.length === 0) {
126
- (0, core_1.LogStatus)('Memory Manager: No agents have memory injection enabled - skipping');
159
+ LogStatus('Memory Manager: No agents have memory injection enabled - skipping');
127
160
  return [];
128
161
  }
129
162
  const agentIds = agentsUsingMemory.map(a => `'${a.ID}'`).join(',');
130
- const rq = new core_1.RunQuery();
163
+ // Use RunQuery to fetch all data in a single optimized query
164
+ const rq = new RunQuery();
131
165
  const result = await rq.RunQuery({
132
166
  QueryName: 'GetConversationsForMemoryManager',
133
167
  CategoryPath: '/MJ/AI/Agents/',
@@ -135,14 +169,16 @@ let MemoryManagerAgent = class MemoryManagerAgent extends base_agent_1.BaseAgent
135
169
  since: since?.toISOString() || null,
136
170
  agentIds: agentIds
137
171
  },
138
- MaxRows: 1000
172
+ MaxRows: 1000 // Limit to 1000 conversations per run
139
173
  }, contextUser);
140
174
  if (!result.Success || !result.Results || result.Results.length === 0) {
141
- (0, core_1.LogStatus)('Memory Manager: No conversations with new activity found');
175
+ LogStatus('Memory Manager: No conversations with new activity found');
142
176
  return [];
143
177
  }
178
+ // Parse the query results into ConversationWithRatings objects
144
179
  const conversations = [];
145
180
  for (const row of result.Results) {
181
+ // Parse the MessagesJSON from the query result
146
182
  let messages = [];
147
183
  if (row.MessagesJSON) {
148
184
  try {
@@ -157,7 +193,7 @@ let MemoryManagerAgent = class MemoryManagerAgent extends base_agent_1.BaseAgent
157
193
  }));
158
194
  }
159
195
  catch (e) {
160
- (0, core_1.LogError)(`Memory Manager: Failed to parse MessagesJSON for conversation ${row.ConversationID}:`, e);
196
+ LogError(`Memory Manager: Failed to parse MessagesJSON for conversation ${row.ConversationID}:`, e);
161
197
  continue;
162
198
  }
163
199
  }
@@ -173,12 +209,17 @@ let MemoryManagerAgent = class MemoryManagerAgent extends base_agent_1.BaseAgent
173
209
  }
174
210
  const totalMessages = conversations.reduce((sum, c) => sum + c.messages.length, 0);
175
211
  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})`);
212
+ 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
213
  }
178
214
  return conversations;
179
215
  }
216
+ /**
217
+ * Load agent runs with high-usage artifacts since last run.
218
+ * Links through: ArtifactUse -> ArtifactVersion -> ConversationDetailArtifact -> ConversationDetail -> Conversation -> AIAgentRun
219
+ */
180
220
  async LoadHighValueAgentRuns(since, contextUser) {
181
- const rv = new core_1.RunView();
221
+ const rv = new RunView();
222
+ // Use subquery to find agent runs with high-usage artifacts
182
223
  const sinceFilter = since ? `AND au.__mj_CreatedAt >= '${since.toISOString()}'` : '';
183
224
  const filter = `
184
225
  ID IN (
@@ -205,21 +246,27 @@ let MemoryManagerAgent = class MemoryManagerAgent extends base_agent_1.BaseAgent
205
246
  EntityName: 'MJ: AI Agent Runs',
206
247
  ExtraFilter: filter,
207
248
  OrderBy: '__mj_CreatedAt DESC',
208
- MaxRows: 50,
249
+ MaxRows: 50, // Limit to most recent 50 high-value runs
209
250
  ResultType: 'entity_object'
210
251
  }, contextUser);
211
252
  return result.Success ? (result.Results || []) : [];
212
253
  }
254
+ /**
255
+ * Extract notes from conversations with rating data using AI analysis.
256
+ * This is the primary method that handles rated, unrated, positive, and negative feedback.
257
+ * Uses LLM-based deduplication and applies sparsity controls.
258
+ */
213
259
  async ExtractNotesFromConversations(conversations, contextUser) {
214
260
  if (conversations.length === 0) {
215
261
  return [];
216
262
  }
217
- const allNotes = aiengine_1.AIEngine.Instance.AgentNotes;
263
+ const allNotes = AIEngine.Instance.AgentNotes;
218
264
  const existingNotes = allNotes.filter(n => n.Status === 'Active');
265
+ // Prepare conversation threads with rating data and user context
219
266
  const conversationThreads = conversations.map(conv => ({
220
267
  conversationId: conv.conversationId,
221
- userId: conv.userId,
222
- agentRunId: conv.agentRunId,
268
+ userId: conv.userId, // User who owns the conversation - for scoping
269
+ agentRunId: conv.agentRunId, // Linked agent run - for scope inheritance
223
270
  hasPositiveRating: conv.hasPositiveRating,
224
271
  hasNegativeRating: conv.hasNegativeRating,
225
272
  isUnrated: conv.isUnrated,
@@ -245,88 +292,100 @@ let MemoryManagerAgent = class MemoryManagerAgent extends base_agent_1.BaseAgent
245
292
  };
246
293
  return this.executeNoteExtraction(promptData, existingNotes, contextUser);
247
294
  }
295
+ /**
296
+ * Common extraction logic for note extraction.
297
+ * Applies sparsity controls and deduplication.
298
+ */
248
299
  async executeNoteExtraction(promptData, existingNotes, contextUser) {
249
300
  const conversationThreads = promptData.conversationThreads;
250
- const prompt = aiengine_1.AIEngine.Instance.Prompts.find(p => p.Name === 'Memory Manager - Extract Notes' && p.Category === 'MJ: System');
301
+ // Find extraction prompt
302
+ const prompt = AIEngine.Instance.Prompts.find(p => p.Name === 'Memory Manager - Extract Notes' && p.Category === 'MJ: System');
251
303
  if (!prompt) {
252
- (0, core_1.LogError)('Memory Manager note extraction prompt not found');
304
+ LogError('Memory Manager note extraction prompt not found');
253
305
  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(', ')}`);
306
+ LogStatus(`Memory Manager: Available prompts in MJ: System category: ${AIEngine.Instance.Prompts.filter(p => p.Category === 'MJ: System').map(p => p.Name).join(', ')}`);
255
307
  }
256
308
  return [];
257
309
  }
258
310
  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`);
311
+ LogStatus(`Memory Manager: Found extraction prompt "${prompt.Name}" (ID: ${prompt.ID})`);
312
+ LogStatus(`Memory Manager: Sending ${conversationThreads.length} conversation threads with ${conversationThreads.reduce((sum, t) => sum + t.messages.length, 0)} total messages for note extraction`);
261
313
  if (conversationThreads.length > 0) {
262
314
  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(' | ')}`);
315
+ LogStatus(`Memory Manager: Sample thread (conv ${firstThread.conversationId}): ${firstThread.messages.map(m => `[${m.role}] ${m.message?.substring(0, 80)}...`).join(' | ')}`);
264
316
  }
265
317
  }
318
+ // Step 3: Execute AI extraction
266
319
  const step3 = await this.CreateRunStep('Prompt', 'Extract Notes from Conversations', {
267
320
  conversationCount: conversationThreads.length,
268
321
  messageCount: conversationThreads.reduce((sum, t) => sum + t.messages.length, 0),
269
322
  existingNoteCount: existingNotes.length
270
323
  }, prompt.ID);
271
- const runner = new ai_prompts_1.AIPromptRunner();
272
- const params = new ai_core_plus_1.AIPromptParams();
324
+ const runner = new AIPromptRunner();
325
+ const params = new AIPromptParams();
273
326
  params.prompt = prompt;
274
327
  params.data = promptData;
275
328
  params.contextUser = contextUser;
276
329
  const result = await runner.ExecutePrompt(params);
330
+ // Finalize Step 3 after extraction
277
331
  await this.FinalizeRunStep(step3, result.success, {
278
332
  success: result.success,
279
333
  rawNoteCount: result.result && typeof result.result !== 'string' ? (result.result.notes?.length || 0) : 0
280
334
  }, result.promptRun?.ID, result.errorMessage || undefined);
281
335
  if (this._verbose) {
282
- (0, core_1.LogStatus)(`Memory Manager: Extraction prompt result - success: ${result.success}, hasResult: ${!!result.result}`);
336
+ LogStatus(`Memory Manager: Extraction prompt result - success: ${result.success}, hasResult: ${!!result.result}`);
283
337
  if (result.errorMessage) {
284
- (0, core_1.LogStatus)(`Memory Manager: Extraction error: ${result.errorMessage}`);
338
+ LogStatus(`Memory Manager: Extraction error: ${result.errorMessage}`);
285
339
  }
286
340
  if (result.result) {
287
- (0, core_1.LogStatus)(`Memory Manager: Raw extraction result: ${JSON.stringify(result.result)}`);
341
+ LogStatus(`Memory Manager: Raw extraction result: ${JSON.stringify(result.result)}`);
288
342
  }
289
343
  }
290
344
  if (!result.success || !result.result) {
291
- (0, core_1.LogError)('Failed to extract notes:', result.errorMessage);
345
+ LogError('Failed to extract notes:', result.errorMessage);
292
346
  return [];
293
347
  }
348
+ // Parse result if it's a string (AI sometimes returns JSON as string)
294
349
  let parsedResult;
295
350
  if (typeof result.result === 'string') {
296
351
  try {
297
352
  parsedResult = JSON.parse(result.result);
298
353
  if (this._verbose) {
299
- (0, core_1.LogStatus)(`Memory Manager: Parsed string result into object with ${parsedResult.notes?.length || 0} notes`);
354
+ LogStatus(`Memory Manager: Parsed string result into object with ${parsedResult.notes?.length || 0} notes`);
300
355
  }
301
356
  }
302
357
  catch (e) {
303
- (0, core_1.LogError)('Failed to parse extraction result as JSON:', e);
358
+ LogError('Failed to parse extraction result as JSON:', e);
304
359
  return [];
305
360
  }
306
361
  }
307
362
  else {
308
363
  parsedResult = result.result;
309
364
  }
365
+ // Log raw notes before filtering (for debugging)
310
366
  if (this._verbose && parsedResult.notes) {
311
- (0, core_1.LogStatus)(`Memory Manager: LLM returned ${parsedResult.notes.length} raw notes before filtering`);
367
+ LogStatus(`Memory Manager: LLM returned ${parsedResult.notes.length} raw notes before filtering`);
312
368
  for (const note of parsedResult.notes) {
313
- (0, core_1.LogStatus)(`Memory Manager: Raw note: [${note.type}] "${note.content}" (confidence: ${note.confidence})`);
369
+ LogStatus(`Memory Manager: Raw note: [${note.type}] "${note.content}" (confidence: ${note.confidence})`);
314
370
  }
315
371
  }
372
+ // Filter by confidence threshold (use EXTRACTION_CONFIG)
316
373
  const candidateNotes = (parsedResult.notes || []).filter(n => n.confidence >= EXTRACTION_CONFIG.minConfidenceThreshold &&
317
374
  n.content && n.content.length >= EXTRACTION_CONFIG.minContentLength);
318
375
  if (candidateNotes.length === 0) {
319
376
  if (this._verbose) {
320
- (0, core_1.LogStatus)('Memory Manager: No candidates passed confidence/length thresholds');
377
+ LogStatus('Memory Manager: No candidates passed confidence/length thresholds');
321
378
  }
322
379
  return [];
323
380
  }
324
381
  if (this._verbose) {
325
- (0, core_1.LogStatus)(`Memory Manager: ${candidateNotes.length} candidates passed confidence threshold (>=${EXTRACTION_CONFIG.minConfidenceThreshold})`);
382
+ LogStatus(`Memory Manager: ${candidateNotes.length} candidates passed confidence threshold (>=${EXTRACTION_CONFIG.minConfidenceThreshold})`);
383
+ // Log each extracted note for debugging
326
384
  for (const note of candidateNotes) {
327
- (0, core_1.LogStatus)(`Memory Manager: Extracted note: [${note.type}] "${note.content}" (confidence: ${note.confidence})`);
385
+ LogStatus(`Memory Manager: Extracted note: [${note.type}] "${note.content}" (confidence: ${note.confidence})`);
328
386
  }
329
387
  }
388
+ // Apply sparsity: limit notes per message AND per conversation
330
389
  const notesByMessage = new Map();
331
390
  const noteCountByConversation = new Map();
332
391
  for (const note of candidateNotes) {
@@ -334,14 +393,15 @@ let MemoryManagerAgent = class MemoryManagerAgent extends base_agent_1.BaseAgent
334
393
  const convId = note.sourceConversationId || 'unknown';
335
394
  const existingForMsg = notesByMessage.get(msgId) || [];
336
395
  const convCount = noteCountByConversation.get(convId) || 0;
396
+ // Check both per-message and per-conversation limits
337
397
  if (existingForMsg.length >= EXTRACTION_CONFIG.maxNotesPerMessage) {
338
398
  if (this._verbose) {
339
- (0, core_1.LogStatus)(`Memory Manager: Skipping note (max ${EXTRACTION_CONFIG.maxNotesPerMessage} per message reached)`);
399
+ LogStatus(`Memory Manager: Skipping note (max ${EXTRACTION_CONFIG.maxNotesPerMessage} per message reached)`);
340
400
  }
341
401
  }
342
402
  else if (convCount >= EXTRACTION_CONFIG.maxNotesPerConversation) {
343
403
  if (this._verbose) {
344
- (0, core_1.LogStatus)(`Memory Manager: Skipping note (max ${EXTRACTION_CONFIG.maxNotesPerConversation} per conversation reached)`);
404
+ LogStatus(`Memory Manager: Skipping note (max ${EXTRACTION_CONFIG.maxNotesPerConversation} per conversation reached)`);
345
405
  }
346
406
  }
347
407
  else {
@@ -352,8 +412,9 @@ let MemoryManagerAgent = class MemoryManagerAgent extends base_agent_1.BaseAgent
352
412
  }
353
413
  const sparseCandidates = Array.from(notesByMessage.values()).flat();
354
414
  if (this._verbose) {
355
- (0, core_1.LogStatus)(`Memory Manager: ${sparseCandidates.length} candidates after sparsity filter`);
415
+ LogStatus(`Memory Manager: ${sparseCandidates.length} candidates after sparsity filter`);
356
416
  }
417
+ // Step 4: Apply deduplication (summary step)
357
418
  const step4 = await this.CreateRunStep('Decision', 'Deduplicate Note Candidates', {
358
419
  candidateCount: sparseCandidates.length,
359
420
  existingNoteCount: existingNotes.length
@@ -361,26 +422,33 @@ let MemoryManagerAgent = class MemoryManagerAgent extends base_agent_1.BaseAgent
361
422
  const approvedNotes = [];
362
423
  let dedupeRejectedCount = 0;
363
424
  let dedupeLlmCallCount = 0;
364
- const dedupePrompt = aiengine_1.AIEngine.Instance.Prompts.find(p => p.Name === 'Memory Manager - Deduplicate Note' && p.Category === 'MJ: System');
425
+ // Find deduplication prompt
426
+ const dedupePrompt = AIEngine.Instance.Prompts.find(p => p.Name === 'Memory Manager - Deduplicate Note' && p.Category === 'MJ: System');
365
427
  for (const candidate of sparseCandidates) {
428
+ // Check global max notes per run
366
429
  if (approvedNotes.length >= EXTRACTION_CONFIG.maxNotesPerRun) {
367
430
  if (this._verbose) {
368
- (0, core_1.LogStatus)(`Memory Manager: Stopping - max notes per run (${EXTRACTION_CONFIG.maxNotesPerRun}) reached`);
431
+ LogStatus(`Memory Manager: Stopping - max notes per run (${EXTRACTION_CONFIG.maxNotesPerRun}) reached`);
369
432
  }
370
433
  break;
371
434
  }
435
+ // Step 1: Check for exact content match FIRST (case-insensitive, trimmed)
372
436
  const normalizedContent = candidate.content.toLowerCase().trim();
373
437
  const exactMatch = existingNotes.find(n => n.Note && n.Note.toLowerCase().trim() === normalizedContent);
374
438
  if (exactMatch) {
375
439
  dedupeRejectedCount++;
376
440
  if (this._verbose) {
377
- (0, core_1.LogStatus)(`Memory Manager: Skipping exact duplicate: "${candidate.content.substring(0, 50)}..."`);
441
+ LogStatus(`Memory Manager: Skipping exact duplicate: "${candidate.content.substring(0, 50)}..."`);
378
442
  }
379
443
  continue;
380
444
  }
381
- const similarNotes = await aiengine_1.AIEngine.Instance.FindSimilarAgentNotes(candidate.content, candidate.agentId, candidate.userId, candidate.companyId, 10, 0.85);
445
+ // Step 2: Find similar existing notes using semantic search with tighter threshold
446
+ const similarNotes = await AIEngine.Instance.FindSimilarAgentNotes(candidate.content, candidate.agentId, candidate.userId, candidate.companyId, 10, // Top 10 similar (increased from 5)
447
+ 0.85 // 85% similarity threshold (increased from 70%)
448
+ );
449
+ // Step 3: If deduplication prompt exists and similar notes found, ask LLM
382
450
  if (dedupePrompt && similarNotes.length > 0) {
383
- const dedupeParams = new ai_core_plus_1.AIPromptParams();
451
+ const dedupeParams = new AIPromptParams();
384
452
  dedupeParams.prompt = dedupePrompt;
385
453
  dedupeParams.data = {
386
454
  candidateNote: candidate,
@@ -399,31 +467,35 @@ let MemoryManagerAgent = class MemoryManagerAgent extends base_agent_1.BaseAgent
399
467
  if (dedupeResult.success && dedupeResult.result && dedupeResult.result.shouldAdd) {
400
468
  approvedNotes.push(candidate);
401
469
  if (this._verbose) {
402
- (0, core_1.LogStatus)(`Memory Manager: Approved note - ${dedupeResult.result.reason}`);
470
+ LogStatus(`Memory Manager: Approved note - ${dedupeResult.result.reason}`);
403
471
  }
404
472
  }
405
473
  else {
406
474
  dedupeRejectedCount++;
407
475
  if (this._verbose) {
408
- (0, core_1.LogStatus)(`Memory Manager: Skipped duplicate note - ${dedupeResult.result?.reason || 'too similar to existing notes'}`);
476
+ LogStatus(`Memory Manager: Skipped duplicate note - ${dedupeResult.result?.reason || 'too similar to existing notes'}`);
409
477
  }
410
478
  }
411
479
  }
412
480
  else {
481
+ // No similar notes found or no deduplication prompt, add the note
413
482
  approvedNotes.push(candidate);
414
483
  if (this._verbose) {
415
- (0, core_1.LogStatus)(`Memory Manager: Approved note (no similar notes found): "${candidate.content.substring(0, 50)}..."`);
484
+ LogStatus(`Memory Manager: Approved note (no similar notes found): "${candidate.content.substring(0, 50)}..."`);
416
485
  }
417
486
  }
418
487
  }
488
+ // Finalize Step 4 after deduplication loop
419
489
  await this.FinalizeRunStep(step4, true, {
420
490
  approvedCount: approvedNotes.length,
421
491
  rejectedCount: dedupeRejectedCount,
422
492
  llmCallCount: dedupeLlmCallCount
423
493
  });
424
494
  if (this._verbose) {
425
- (0, core_1.LogStatus)(`Memory Manager: Final approved notes: ${approvedNotes.length}`);
495
+ LogStatus(`Memory Manager: Final approved notes: ${approvedNotes.length}`);
426
496
  }
497
+ // Enrich notes with userId and agentRunId from conversation context
498
+ // Build a map of conversationId -> context for quick lookup
427
499
  const conversationContext = new Map();
428
500
  for (const thread of conversationThreads) {
429
501
  conversationContext.set(thread.conversationId, {
@@ -431,13 +503,16 @@ let MemoryManagerAgent = class MemoryManagerAgent extends base_agent_1.BaseAgent
431
503
  agentRunId: thread.agentRunId || null
432
504
  });
433
505
  }
506
+ // Enrich each note with conversation context
434
507
  for (const note of approvedNotes) {
435
508
  if (note.sourceConversationId) {
436
509
  const ctx = conversationContext.get(note.sourceConversationId);
437
510
  if (ctx) {
511
+ // Set userId from conversation if not already set
438
512
  if (!note.userId && ctx.userId) {
439
513
  note.userId = ctx.userId;
440
514
  }
515
+ // Set sourceAgentRunId from conversation if not already set
441
516
  if (!note.sourceAgentRunId && ctx.agentRunId) {
442
517
  note.sourceAgentRunId = ctx.agentRunId;
443
518
  }
@@ -446,10 +521,15 @@ let MemoryManagerAgent = class MemoryManagerAgent extends base_agent_1.BaseAgent
446
521
  }
447
522
  return approvedNotes;
448
523
  }
524
+ /**
525
+ * Extract examples from conversation details with high ratings.
526
+ * Uses LLM-based deduplication to avoid adding redundant examples.
527
+ */
449
528
  async ExtractExamples(conversationDetails, contextUser) {
450
529
  if (conversationDetails.length === 0) {
451
530
  return [];
452
531
  }
532
+ // Prepare Q&A pairs from conversation details
453
533
  const qaPairs = conversationDetails.map(detail => ({
454
534
  id: detail.ID,
455
535
  conversationId: detail.ConversationID,
@@ -457,16 +537,18 @@ let MemoryManagerAgent = class MemoryManagerAgent extends base_agent_1.BaseAgent
457
537
  message: detail.Message,
458
538
  createdAt: detail.__mj_CreatedAt
459
539
  }));
460
- const extractPrompt = aiengine_1.AIEngine.Instance.Prompts.find(p => p.Name === 'Memory Manager - Extract Examples' && p.Category === 'MJ: System');
540
+ // Find extraction prompt
541
+ const extractPrompt = AIEngine.Instance.Prompts.find(p => p.Name === 'Memory Manager - Extract Examples' && p.Category === 'MJ: System');
461
542
  if (!extractPrompt) {
462
- (0, core_1.LogError)('Memory Manager example extraction prompt not found');
543
+ LogError('Memory Manager example extraction prompt not found');
463
544
  return [];
464
545
  }
546
+ // Step 5: Execute AI extraction
465
547
  const step5 = await this.CreateRunStep('Prompt', 'Extract Examples from Conversations', {
466
548
  qaPairCount: qaPairs.length
467
549
  }, extractPrompt.ID);
468
- const runner = new ai_prompts_1.AIPromptRunner();
469
- const extractParams = new ai_core_plus_1.AIPromptParams();
550
+ const runner = new AIPromptRunner();
551
+ const extractParams = new AIPromptParams();
470
552
  extractParams.prompt = extractPrompt;
471
553
  extractParams.data = { qaPairs };
472
554
  extractParams.contextUser = contextUser;
@@ -475,16 +557,17 @@ let MemoryManagerAgent = class MemoryManagerAgent extends base_agent_1.BaseAgent
475
557
  await this.FinalizeRunStep(step5, false, {
476
558
  success: false
477
559
  }, extractResult.promptRun?.ID, extractResult.errorMessage || undefined);
478
- (0, core_1.LogError)('Failed to extract examples:', extractResult.errorMessage);
560
+ LogError('Failed to extract examples:', extractResult.errorMessage);
479
561
  return [];
480
562
  }
563
+ // Parse result if it's a string (AI sometimes returns JSON as string)
481
564
  let parsedResult;
482
565
  if (typeof extractResult.result === 'string') {
483
566
  try {
484
567
  parsedResult = JSON.parse(extractResult.result);
485
568
  }
486
569
  catch (e) {
487
- (0, core_1.LogError)('Failed to parse example extraction result as JSON:', e);
570
+ LogError('Failed to parse example extraction result as JSON:', e);
488
571
  return [];
489
572
  }
490
573
  }
@@ -493,6 +576,7 @@ let MemoryManagerAgent = class MemoryManagerAgent extends base_agent_1.BaseAgent
493
576
  }
494
577
  const candidateExamples = (parsedResult.examples || [])
495
578
  .filter(e => e.successScore >= 70 && e.confidence >= 70);
579
+ // Finalize Step 5 after extraction parsing
496
580
  await this.FinalizeRunStep(step5, true, {
497
581
  rawExampleCount: parsedResult.examples?.length || 0,
498
582
  candidateCount: candidateExamples.length
@@ -500,17 +584,23 @@ let MemoryManagerAgent = class MemoryManagerAgent extends base_agent_1.BaseAgent
500
584
  if (candidateExamples.length === 0) {
501
585
  return [];
502
586
  }
587
+ // Step 6: Deduplicate example candidates (summary step)
503
588
  const step6 = await this.CreateRunStep('Decision', 'Deduplicate Example Candidates', {
504
589
  candidateCount: candidateExamples.length
505
590
  });
506
591
  const approvedExamples = [];
507
592
  let exampleDedupeRejectedCount = 0;
508
593
  let exampleDedupeLlmCallCount = 0;
594
+ // Process each candidate example with LLM-based deduplication
509
595
  for (const candidate of candidateExamples) {
510
- const similarExamples = await aiengine_1.AIEngine.Instance.FindSimilarAgentExamples(candidate.exampleInput, candidate.agentId, candidate.userId, candidate.companyId, 5, 0.7);
511
- const dedupePrompt = aiengine_1.AIEngine.Instance.Prompts.find(p => p.Name === 'Memory Manager - Deduplicate Example' && p.Category === 'MJ: System');
596
+ // Find similar existing examples using semantic search
597
+ const similarExamples = await AIEngine.Instance.FindSimilarAgentExamples(candidate.exampleInput, candidate.agentId, candidate.userId, candidate.companyId, 5, // Top 5 similar
598
+ 0.7 // 70% similarity threshold
599
+ );
600
+ // Ask LLM if this candidate adds value given existing similar examples
601
+ const dedupePrompt = AIEngine.Instance.Prompts.find(p => p.Name === 'Memory Manager - Deduplicate Example' && p.Category === 'MJ: System');
512
602
  if (dedupePrompt && similarExamples.length > 0) {
513
- const dedupeParams = new ai_core_plus_1.AIPromptParams();
603
+ const dedupeParams = new AIPromptParams();
514
604
  dedupeParams.prompt = dedupePrompt;
515
605
  dedupeParams.data = {
516
606
  candidateExample: candidate,
@@ -527,20 +617,22 @@ let MemoryManagerAgent = class MemoryManagerAgent extends base_agent_1.BaseAgent
527
617
  if (dedupeResult.success && dedupeResult.result && dedupeResult.result.shouldAdd) {
528
618
  approvedExamples.push(candidate);
529
619
  if (this._verbose) {
530
- (0, core_1.LogStatus)(`Memory Manager: Approved example - ${dedupeResult.result.reason}`);
620
+ LogStatus(`Memory Manager: Approved example - ${dedupeResult.result.reason}`);
531
621
  }
532
622
  }
533
623
  else {
534
624
  exampleDedupeRejectedCount++;
535
625
  if (this._verbose) {
536
- (0, core_1.LogStatus)(`Memory Manager: Skipped duplicate example - ${dedupeResult.result?.reason || 'too similar'}`);
626
+ LogStatus(`Memory Manager: Skipped duplicate example - ${dedupeResult.result?.reason || 'too similar'}`);
537
627
  }
538
628
  }
539
629
  }
540
630
  else {
631
+ // No similar examples found, add it
541
632
  approvedExamples.push(candidate);
542
633
  }
543
634
  }
635
+ // Finalize Step 6 after deduplication loop
544
636
  await this.FinalizeRunStep(step6, true, {
545
637
  approvedCount: approvedExamples.length,
546
638
  rejectedCount: exampleDedupeRejectedCount,
@@ -548,23 +640,33 @@ let MemoryManagerAgent = class MemoryManagerAgent extends base_agent_1.BaseAgent
548
640
  });
549
641
  return approvedExamples;
550
642
  }
643
+ /**
644
+ * Check if a string is a valid UUID format.
645
+ */
551
646
  isValidUUID(str) {
552
647
  const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
553
648
  return uuidRegex.test(str);
554
649
  }
650
+ /**
651
+ * Create note records from extracted data.
652
+ * Inherits scope from source agent run and applies scopeLevel to determine scope specificity.
653
+ */
555
654
  async CreateNoteRecords(extractedNotes, contextUser) {
655
+ // Step 7: Create Note Records
556
656
  const step7 = await this.CreateRunStep('Decision', 'Create Note Records', {
557
657
  noteCount: extractedNotes.length
558
658
  });
559
659
  let created = 0;
560
660
  let merged = 0;
561
661
  let failed = 0;
562
- const md = new core_1.Metadata();
563
- const rv = new core_1.RunView();
662
+ const md = new Metadata();
663
+ const rv = new RunView();
664
+ // Cache source agent runs to avoid repeated lookups
564
665
  const runCache = new Map();
565
- const aiNoteTypeId = aiengine_1.AIEngine.Instance.AgenteNoteTypeIDByName('AI');
666
+ // Get the "AI" note type ID for AI-generated notes
667
+ const aiNoteTypeId = AIEngine.Instance.AgenteNoteTypeIDByName('AI');
566
668
  if (!aiNoteTypeId) {
567
- (0, core_1.LogError)('Memory Manager: Could not find "AI" note type - cannot create notes');
669
+ LogError('Memory Manager: Could not find "AI" note type - cannot create notes');
568
670
  await this.FinalizeRunStep(step7, false, {
569
671
  created: 0,
570
672
  merged: 0,
@@ -574,6 +676,7 @@ let MemoryManagerAgent = class MemoryManagerAgent extends base_agent_1.BaseAgent
574
676
  }
575
677
  for (const extracted of extractedNotes) {
576
678
  try {
679
+ // Load source agent run for scope inheritance (if available)
577
680
  let sourceRun = null;
578
681
  if (extracted.sourceAgentRunId) {
579
682
  if (!runCache.has(extracted.sourceAgentRunId)) {
@@ -587,9 +690,11 @@ let MemoryManagerAgent = class MemoryManagerAgent extends base_agent_1.BaseAgent
587
690
  }
588
691
  sourceRun = runCache.get(extracted.sourceAgentRunId) || null;
589
692
  }
693
+ // Check if we should merge with existing
590
694
  if (extracted.mergeWithExistingId) {
591
695
  const existingNote = await md.GetEntityObject('AI Agent Notes', contextUser);
592
696
  if (await existingNote.Load(extracted.mergeWithExistingId)) {
697
+ // Update existing note
593
698
  existingNote.Note = extracted.content;
594
699
  existingNote.Type = extracted.type;
595
700
  existingNote.AgentNoteTypeID = aiNoteTypeId;
@@ -605,12 +710,15 @@ let MemoryManagerAgent = class MemoryManagerAgent extends base_agent_1.BaseAgent
605
710
  }
606
711
  }
607
712
  else {
713
+ // Create new note
608
714
  const note = await md.GetEntityObject('AI Agent Notes', contextUser);
715
+ // Only use valid UUIDs, filter out placeholders like "user-uuid-here"
609
716
  const isValidUUID = (id) => {
610
717
  if (!id)
611
718
  return false;
612
719
  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
720
  };
721
+ // Determine AgentID - prefer extracted, then inherit from source run
614
722
  let agentId = isValidUUID(extracted.agentId) ? extracted.agentId : null;
615
723
  if (!agentId && sourceRun?.AgentID) {
616
724
  agentId = sourceRun.AgentID;
@@ -618,15 +726,17 @@ let MemoryManagerAgent = class MemoryManagerAgent extends base_agent_1.BaseAgent
618
726
  note.AgentID = agentId;
619
727
  note.UserID = isValidUUID(extracted.userId) ? extracted.userId : null;
620
728
  note.CompanyID = isValidUUID(extracted.companyId) ? extracted.companyId : null;
621
- note.AgentNoteTypeID = aiNoteTypeId;
622
- note.Type = extracted.type;
729
+ note.AgentNoteTypeID = aiNoteTypeId; // "AI" type for AI-generated notes
730
+ note.Type = extracted.type; // Category: Preference, Constraint, Context, Issue, Example
623
731
  note.Note = extracted.content;
624
732
  note.IsAutoGenerated = true;
625
- note.Status = 'Active';
626
- note.AccessCount = 1;
733
+ note.Status = 'Active'; // Auto-approve high-confidence notes
734
+ note.AccessCount = 1; // Required field
627
735
  note.SourceConversationID = extracted.sourceConversationId || null;
736
+ // Only use if it's a valid UUID (LLM now sees message IDs in the prompt)
628
737
  note.SourceConversationDetailID = isValidUUID(extracted.sourceConversationDetailId) ? extracted.sourceConversationDetailId : null;
629
738
  note.SourceAIAgentRunID = extracted.sourceAgentRunId || null;
739
+ // Apply scope: Lean towards USER-specific memories by default
630
740
  const scopeLevel = extracted.scopeLevel || 'contact';
631
741
  if (scopeLevel === 'global') {
632
742
  note.PrimaryScopeEntityID = null;
@@ -649,15 +759,16 @@ let MemoryManagerAgent = class MemoryManagerAgent extends base_agent_1.BaseAgent
649
759
  }
650
760
  else {
651
761
  failed++;
652
- (0, core_1.LogError)(`Memory Manager: Failed to save note - Validation errors: ${JSON.stringify(note.LatestResult)}`);
762
+ LogError(`Memory Manager: Failed to save note - Validation errors: ${JSON.stringify(note.LatestResult)}`);
653
763
  }
654
764
  }
655
765
  }
656
766
  catch (error) {
657
767
  failed++;
658
- (0, core_1.LogError)('Memory Manager: Exception creating note:', error);
768
+ LogError('Memory Manager: Exception creating note:', error);
659
769
  }
660
770
  }
771
+ // Finalize Step 7
661
772
  await this.FinalizeRunStep(step7, failed === 0 || created > 0 || merged > 0, {
662
773
  created,
663
774
  merged,
@@ -665,18 +776,25 @@ let MemoryManagerAgent = class MemoryManagerAgent extends base_agent_1.BaseAgent
665
776
  });
666
777
  return created + merged;
667
778
  }
779
+ /**
780
+ * Create example records from extracted data.
781
+ * Inherits scope from source agent run and applies scopeLevel to determine scope specificity.
782
+ */
668
783
  async CreateExampleRecords(extractedExamples, contextUser) {
784
+ // Step 8: Create Example Records
669
785
  const step8 = await this.CreateRunStep('Decision', 'Create Example Records', {
670
786
  exampleCount: extractedExamples.length
671
787
  });
672
788
  let created = 0;
673
789
  let skipped = 0;
674
790
  let failed = 0;
675
- const md = new core_1.Metadata();
676
- const rv = new core_1.RunView();
791
+ const md = new Metadata();
792
+ const rv = new RunView();
793
+ // Cache source agent runs to avoid repeated lookups
677
794
  const runCache = new Map();
678
795
  for (const extracted of extractedExamples) {
679
796
  try {
797
+ // Load source agent run for scope inheritance (if available)
680
798
  let sourceRun = null;
681
799
  if (extracted.sourceAgentRunId) {
682
800
  if (!runCache.has(extracted.sourceAgentRunId)) {
@@ -691,10 +809,11 @@ let MemoryManagerAgent = class MemoryManagerAgent extends base_agent_1.BaseAgent
691
809
  sourceRun = runCache.get(extracted.sourceAgentRunId) || null;
692
810
  }
693
811
  const example = await md.GetEntityObject('MJ: AI Agent Examples', contextUser);
812
+ // AgentID must come from source run - LLM doesn't know real agent IDs
694
813
  if (!sourceRun?.AgentID) {
695
814
  skipped++;
696
815
  if (this._verbose) {
697
- (0, core_1.LogStatus)(`Memory Manager: Skipping example - no source run to inherit AgentID from`);
816
+ LogStatus(`Memory Manager: Skipping example - no source run to inherit AgentID from`);
698
817
  }
699
818
  continue;
700
819
  }
@@ -706,23 +825,28 @@ let MemoryManagerAgent = class MemoryManagerAgent extends base_agent_1.BaseAgent
706
825
  example.ExampleOutput = extracted.exampleOutput;
707
826
  example.IsAutoGenerated = true;
708
827
  example.SuccessScore = extracted.successScore;
709
- example.Status = 'Active';
828
+ example.Status = 'Active'; // Auto-approve high-confidence examples
710
829
  example.SourceConversationID = extracted.sourceConversationId || null;
830
+ // Only use if it's a valid UUID
711
831
  example.SourceConversationDetailID = this.isValidUUID(extracted.sourceConversationDetailId) ? extracted.sourceConversationDetailId : null;
712
832
  example.SourceAIAgentRunID = extracted.sourceAgentRunId || null;
833
+ // Apply scope from source agent run based on scopeLevel hint
713
834
  if (sourceRun && sourceRun.PrimaryScopeEntityID) {
714
- const scopeLevel = extracted.scopeLevel || 'contact';
835
+ const scopeLevel = extracted.scopeLevel || 'contact'; // Default to most specific
715
836
  if (scopeLevel === 'global') {
837
+ // Global example - no scope fields set
716
838
  example.PrimaryScopeEntityID = null;
717
839
  example.PrimaryScopeRecordID = null;
718
840
  example.SecondaryScopes = null;
719
841
  }
720
842
  else if (scopeLevel === 'organization') {
843
+ // Org-level example - primary scope only, no secondary
721
844
  example.PrimaryScopeEntityID = sourceRun.PrimaryScopeEntityID;
722
845
  example.PrimaryScopeRecordID = sourceRun.PrimaryScopeRecordID;
723
846
  example.SecondaryScopes = null;
724
847
  }
725
848
  else {
849
+ // Fully-scoped example (contact level) - inherit full scope
726
850
  example.PrimaryScopeEntityID = sourceRun.PrimaryScopeEntityID;
727
851
  example.PrimaryScopeRecordID = sourceRun.PrimaryScopeRecordID;
728
852
  example.SecondaryScopes = sourceRun.SecondaryScopes;
@@ -733,14 +857,15 @@ let MemoryManagerAgent = class MemoryManagerAgent extends base_agent_1.BaseAgent
733
857
  }
734
858
  else {
735
859
  failed++;
736
- (0, core_1.LogError)(`Memory Manager: Failed to save example - Validation errors: ${JSON.stringify(example.LatestResult)}`);
860
+ LogError(`Memory Manager: Failed to save example - Validation errors: ${JSON.stringify(example.LatestResult)}`);
737
861
  }
738
862
  }
739
863
  catch (error) {
740
864
  failed++;
741
- (0, core_1.LogError)('Memory Manager: Exception creating example:', error);
865
+ LogError('Memory Manager: Exception creating example:', error);
742
866
  }
743
867
  }
868
+ // Finalize Step 8
744
869
  await this.FinalizeRunStep(step8, failed === 0 || created > 0, {
745
870
  created,
746
871
  skipped,
@@ -748,19 +873,25 @@ let MemoryManagerAgent = class MemoryManagerAgent extends base_agent_1.BaseAgent
748
873
  });
749
874
  return created;
750
875
  }
876
+ /**
877
+ * Main execution method called by scheduler
878
+ */
751
879
  async executeAgentInternal(params, config) {
752
880
  try {
881
+ // Use verbose flag from agent execution params
753
882
  this._verbose = params.verbose ?? false;
883
+ // Initialize observability state for this run
754
884
  this._agentRunID = this.AgentRun?.ID || null;
755
885
  this._stepCounter = 0;
756
886
  this._contextUser = params.contextUser || null;
757
- (0, core_1.LogStatus)('Memory Manager: Starting analysis cycle');
887
+ LogStatus('Memory Manager: Starting analysis cycle');
758
888
  const lastRunTime = await this.GetLastRunTime(params.agent.ID, params.contextUser);
889
+ // Load agents that have memory injection enabled
759
890
  const agentsUsingMemory = await this.LoadAgentsUsingMemory(params.contextUser);
760
891
  if (this._verbose) {
761
892
  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`);
893
+ LogStatus(`Memory Manager: Processing ${sinceMessage}`);
894
+ LogStatus(`Memory Manager: Found ${agentsUsingMemory.length} agents with memory injection enabled`);
764
895
  }
765
896
  if (agentsUsingMemory.length === 0) {
766
897
  const finalStep = {
@@ -770,6 +901,7 @@ let MemoryManagerAgent = class MemoryManagerAgent extends base_agent_1.BaseAgent
770
901
  };
771
902
  return { finalStep, stepCount: 1 };
772
903
  }
904
+ // Step 1: Load conversations with new activity (includes rating data)
773
905
  const step1 = await this.CreateRunStep('Decision', 'Load Conversations With New Activity', {
774
906
  since: lastRunTime?.toISOString() || null,
775
907
  agentCount: agentsUsingMemory.length,
@@ -785,8 +917,9 @@ let MemoryManagerAgent = class MemoryManagerAgent extends base_agent_1.BaseAgent
785
917
  unratedCount: conversations.filter(c => c.isUnrated).length
786
918
  });
787
919
  if (this._verbose) {
788
- (0, core_1.LogStatus)(`Memory Manager: Found ${conversations.length} conversations with new activity`);
920
+ LogStatus(`Memory Manager: Found ${conversations.length} conversations with new activity`);
789
921
  }
922
+ // Step 2: Load high-value agent runs
790
923
  const step2 = await this.CreateRunStep('Decision', 'Load High-Value Agent Runs', {
791
924
  since: lastRunTime?.toISOString() || null
792
925
  });
@@ -795,11 +928,11 @@ let MemoryManagerAgent = class MemoryManagerAgent extends base_agent_1.BaseAgent
795
928
  runCount: agentRuns.length
796
929
  });
797
930
  if (this._verbose) {
798
- (0, core_1.LogStatus)(`Memory Manager: Found ${agentRuns.length} high-value agent runs`);
931
+ LogStatus(`Memory Manager: Found ${agentRuns.length} high-value agent runs`);
799
932
  }
800
933
  if (conversations.length === 0 && agentRuns.length === 0) {
801
934
  if (this._verbose) {
802
- (0, core_1.LogStatus)('Memory Manager: No data to process');
935
+ LogStatus('Memory Manager: No data to process');
803
936
  }
804
937
  const finalStep = {
805
938
  terminate: true,
@@ -808,10 +941,13 @@ let MemoryManagerAgent = class MemoryManagerAgent extends base_agent_1.BaseAgent
808
941
  };
809
942
  return { finalStep, stepCount: 1 };
810
943
  }
944
+ // Extract notes from conversations (with rating context)
811
945
  const extractedNotes = await this.ExtractNotesFromConversations(conversations, params.contextUser);
812
946
  if (this._verbose) {
813
- (0, core_1.LogStatus)(`Memory Manager: Extracted ${extractedNotes.length} potential notes`);
947
+ LogStatus(`Memory Manager: Extracted ${extractedNotes.length} potential notes`);
814
948
  }
949
+ // Extract examples from conversation details (legacy method for now)
950
+ // Convert conversations back to flat details for example extraction
815
951
  const conversationDetails = conversations.flatMap(conv => conv.messages.map(msg => ({
816
952
  ID: msg.id,
817
953
  ConversationID: conv.conversationId,
@@ -822,8 +958,10 @@ let MemoryManagerAgent = class MemoryManagerAgent extends base_agent_1.BaseAgent
822
958
  })));
823
959
  const extractedExamples = await this.ExtractExamples(conversationDetails, params.contextUser);
824
960
  if (this._verbose) {
825
- (0, core_1.LogStatus)(`Memory Manager: Extracted ${extractedExamples.length} potential examples`);
961
+ LogStatus(`Memory Manager: Extracted ${extractedExamples.length} potential examples`);
826
962
  }
963
+ // Enrich examples with userId and agentRunId from conversation context
964
+ // Build a map from conversationId to context (same as notes enrichment)
827
965
  const conversationContextForExamples = new Map();
828
966
  for (const conv of conversations) {
829
967
  conversationContextForExamples.set(conv.conversationId, {
@@ -835,34 +973,40 @@ let MemoryManagerAgent = class MemoryManagerAgent extends base_agent_1.BaseAgent
835
973
  if (example.sourceConversationId) {
836
974
  const ctx = conversationContextForExamples.get(example.sourceConversationId);
837
975
  if (ctx) {
976
+ // Enrich userId if not set
838
977
  if (!example.userId && ctx.userId) {
839
978
  example.userId = ctx.userId;
840
979
  if (this._verbose) {
841
- (0, core_1.LogStatus)(`Memory Manager: Enriched example with userId from conversation: ${ctx.userId}`);
980
+ LogStatus(`Memory Manager: Enriched example with userId from conversation: ${ctx.userId}`);
842
981
  }
843
982
  }
983
+ // Enrich agentRunId if not set
844
984
  if (!example.sourceAgentRunId && ctx.agentRunId) {
845
985
  example.sourceAgentRunId = ctx.agentRunId;
846
986
  if (this._verbose) {
847
- (0, core_1.LogStatus)(`Memory Manager: Enriched example with agentRunId from conversation: ${ctx.agentRunId}`);
987
+ LogStatus(`Memory Manager: Enriched example with agentRunId from conversation: ${ctx.agentRunId}`);
848
988
  }
849
989
  }
850
990
  }
851
991
  }
992
+ // Clear invalid agentId (LLM sometimes returns placeholder values like "agent-12345")
852
993
  if (example.agentId && !this.isValidUUID(example.agentId)) {
853
994
  if (this._verbose) {
854
- (0, core_1.LogStatus)(`Memory Manager: Clearing invalid agentId "${example.agentId}" from example`);
995
+ LogStatus(`Memory Manager: Clearing invalid agentId "${example.agentId}" from example`);
855
996
  }
856
997
  example.agentId = '';
857
998
  }
858
999
  }
1000
+ // Create records
859
1001
  const notesCreated = await this.CreateNoteRecords(extractedNotes, params.contextUser);
860
1002
  const examplesCreated = await this.CreateExampleRecords(extractedExamples, params.contextUser);
861
- (0, core_1.LogStatus)(`Memory Manager: Created ${notesCreated} notes and ${examplesCreated} examples`);
1003
+ LogStatus(`Memory Manager: Created ${notesCreated} notes and ${examplesCreated} examples`);
1004
+ // Refresh AIEngine memory cache if any new memories were created
1005
+ // This ensures subsequent agent runs can find the new notes/examples via semantic search
862
1006
  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`);
1007
+ LogStatus(`Memory Manager: Refreshing AIEngine memory cache...`);
1008
+ await AIEngine.Instance.Config(true, params.contextUser);
1009
+ LogStatus(`Memory Manager: Memory cache refreshed`);
866
1010
  }
867
1011
  const finalStep = {
868
1012
  terminate: true,
@@ -879,7 +1023,7 @@ let MemoryManagerAgent = class MemoryManagerAgent extends base_agent_1.BaseAgent
879
1023
  return { finalStep, stepCount: 1 };
880
1024
  }
881
1025
  catch (error) {
882
- (0, core_1.LogError)('Memory Manager execution failed:', error);
1026
+ LogError('Memory Manager execution failed:', error);
883
1027
  const finalStep = {
884
1028
  terminate: true,
885
1029
  step: 'Failed',
@@ -889,8 +1033,8 @@ let MemoryManagerAgent = class MemoryManagerAgent extends base_agent_1.BaseAgent
889
1033
  }
890
1034
  }
891
1035
  };
892
- exports.MemoryManagerAgent = MemoryManagerAgent;
893
- exports.MemoryManagerAgent = MemoryManagerAgent = __decorate([
894
- (0, global_1.RegisterClass)(base_agent_1.BaseAgent, 'MemoryManagerAgent')
1036
+ MemoryManagerAgent = __decorate([
1037
+ RegisterClass(BaseAgent, 'MemoryManagerAgent')
895
1038
  ], MemoryManagerAgent);
1039
+ export { MemoryManagerAgent };
896
1040
  //# sourceMappingURL=memory-manager-agent.js.map