@ai.ntellect/core 0.3.0 → 0.3.3

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/types.d.ts CHANGED
@@ -154,8 +154,7 @@ export interface Memory {
154
154
  query: string;
155
155
  purpose: string;
156
156
  data: any;
157
- scope: MemoryScopeType;
158
- userId?: string;
157
+ roomId: string;
159
158
  createdAt: Date;
160
159
  chunks?: MemoryChunk[];
161
160
  }
@@ -205,3 +204,24 @@ export interface TransformedQueueItem {
205
204
  name: string;
206
205
  parameters: QueueItemParameter[];
207
206
  }
207
+ export interface ScheduledAction {
208
+ id: string;
209
+ action: {
210
+ name: string;
211
+ parameters: QueueItemParameter[];
212
+ };
213
+ scheduledTime: Date;
214
+ userId: string;
215
+ status: "pending" | "completed" | "failed";
216
+ recurrence?: {
217
+ type: "daily" | "weekly" | "monthly";
218
+ interval: number;
219
+ };
220
+ }
221
+ export interface ScheduledActionEvents {
222
+ onActionStart?: (action: ScheduledAction) => void;
223
+ onActionComplete?: (action: ScheduledAction, result: any) => void;
224
+ onActionFailed?: (action: ScheduledAction, error: Error) => void;
225
+ onActionScheduled?: (action: ScheduledAction) => void;
226
+ onActionCancelled?: (actionId: string) => void;
227
+ }
@@ -1,13 +1,15 @@
1
1
  export const evaluatorContext = {
2
2
  behavior: {
3
- language: "user_language",
4
- role: "Your role is to verify if the goal has been achieved and make a response or suggest next actions.",
3
+ language: "same_as_user",
4
+ role: "Your role is to ensure the goal will be achieved and make a response or suggest next actions.",
5
5
  guidelines: {
6
6
  important: [
7
- "Verify if all required actions were executed successfully.",
8
- "Check if the results align with the initial goal.",
7
+ "Verify if all actions were executed successfully (actionsAlreadyDone).",
8
+ "Check if the results align with the initial goal (explain in 'why' field).",
9
+ "Suggest next actions in 'nextActionsNeeded' if the goal is not achieved and if actions in 'actionsAlreadyDone' are not enough.",
9
10
  "If you retrieved the informations from your internal knowledge base, no need to store them in 'extraInformationsToStore'.",
10
- "Store ONLY extra new needed informations in 'extraInformationsToStore' (choose the most relevant informations and memory type: episodic, semantic, or procedural).",
11
+ "Store ONLY new needed informations in 'extraInformationsToStore'.",
12
+ "Choose the most relevant informations and memory type: episodic, semantic, or procedural.",
11
13
  ],
12
14
  warnings: [
13
15
  "NEVER store an old data you retrieve from your internal knowledge base.",
@@ -3,7 +3,7 @@ import { generateObject } from "ai";
3
3
  import { z } from "zod";
4
4
  import { CacheMemory } from "../../memory/cache";
5
5
  import { PersistentMemory } from "../../memory/persistent";
6
- import { ActionSchema, MemoryScope, MemoryType, State } from "../../types";
6
+ import { ActionSchema, MemoryType, State } from "../../types";
7
7
  import { injectActions } from "../../utils/inject-actions";
8
8
  import { Interpreter } from "../interpreter";
9
9
  import { evaluatorContext } from "./context";
@@ -62,8 +62,8 @@ export class Evaluator {
62
62
  const response = await generateObject({
63
63
  model: this.model,
64
64
  schema: z.object({
65
- actionsCompleted: z.array(z.string()),
66
- actionsFailed: z.array(z.string()),
65
+ requestLanguage: z.string(),
66
+ actionsAlreadyDone: z.array(z.string()),
67
67
  extraInformationsToStore: z.array(
68
68
  z.object({
69
69
  memoryType: z.enum(["episodic", "semantic", "procedural"]),
@@ -111,7 +111,7 @@ export class Evaluator {
111
111
  console.log("Type:", item.memoryType);
112
112
  console.log("Content:", item.queryForData);
113
113
 
114
- const memories = await this.memory.persistent.searchSimilarQueries(
114
+ const memories = await this.memory.persistent.findRelevantDocuments(
115
115
  item.queryForData,
116
116
  {
117
117
  similarityThreshold: 70,
@@ -129,7 +129,7 @@ export class Evaluator {
129
129
  purpose: item.memoryType,
130
130
  query: item.queryForData,
131
131
  data: item.data,
132
- scope: MemoryScope.GLOBAL,
132
+ roomId: "global",
133
133
  createdAt: new Date(),
134
134
  });
135
135
  }
@@ -141,13 +141,12 @@ export class Evaluator {
141
141
  cacheMemory.createMemory({
142
142
  content: prompt,
143
143
  type: MemoryType.ACTION,
144
- data: validatedResponse.actionsCompleted,
145
- scope: MemoryScope.GLOBAL,
144
+ data: validatedResponse.actionsAlreadyDone,
146
145
  });
147
146
  console.log(
148
147
  "✅ Workflow actions completed stored in cache",
149
148
  prompt,
150
- validatedResponse.actionsCompleted
149
+ validatedResponse.actionsAlreadyDone
151
150
  );
152
151
  }
153
152
  console.log("\n✅ Evaluation completed");
@@ -164,7 +163,7 @@ export class Evaluator {
164
163
  if (error.value.extraInformationsToStore.length > 0) {
165
164
  for (const item of error.value.extraInformationsToStore) {
166
165
  // Check if the item is already in the memory
167
- const memories = await this.memory.persistent.searchSimilarQueries(
166
+ const memories = await this.memory.persistent.findRelevantDocuments(
168
167
  item.content
169
168
  );
170
169
  if (memories.length === 0) {
@@ -177,7 +176,7 @@ export class Evaluator {
177
176
  purpose: "importantToRemember",
178
177
  query: item.content,
179
178
  data: item.data,
180
- scope: MemoryScope.USER,
179
+ roomId: "global",
181
180
  createdAt: new Date(),
182
181
  });
183
182
  }
@@ -1,6 +1,6 @@
1
1
  export const generalInterpreterContext = {
2
2
  role: "You are the general assistant. Your role is to provide a clear and factual analysis of the results.",
3
- language: "user_language",
3
+ language: "same_as_user",
4
4
  guidelines: {
5
5
  important: [],
6
6
  warnings: [],
@@ -1,17 +1,15 @@
1
1
  export const orchestratorContext = {
2
2
  behavior: {
3
- language: "user_language",
4
- role: "You are the orchestrator agent. Your role is to determine what actions are needed to achieve the user goal.",
3
+ language: "same_as_user",
4
+ role: "Your role is to determine what actions are needed to achieve the user goal.",
5
5
  guidelines: {
6
6
  important: [
7
7
  "If there is no action to do, you must answer in the 'answer' field.",
8
8
  "If some parameters are not clear or missing, don't add the action, YOU MUST ask the user for them.",
9
- "ALWAYS use the same language as user request. (If it's English, use English, if it's French, use French, etc.)",
9
+ "For QUESTIONS or ANALYSIS, search first in your internal knowledge base before using actions.",
10
10
  "For ON-CHAIN actions, just use the useful actions.",
11
- "For QUESTIONS or ANALYSIS, you MUST search in your cache memory or/and internal knowledge base.",
12
- "NEVER repeat same actions if the user doesn't ask for it.",
13
11
  ],
14
- warnings: [],
12
+ warnings: ["NEVER repeat same actions if the user doesn't ask for it."],
15
13
  },
16
14
  },
17
15
  };
@@ -41,7 +41,7 @@ export class Orchestrator {
41
41
  }),
42
42
  execute: async ({ query }: { query: string }) => {
43
43
  const persistentMemories =
44
- await this.memory.persistent.searchSimilarQueries(query, {
44
+ await this.memory.persistent.findRelevantDocuments(query, {
45
45
  similarityThreshold: 70,
46
46
  });
47
47
  return `# LONG_TERM_MEMORY: ${JSON.stringify(persistentMemories)}`;
package/memory/cache.ts CHANGED
@@ -44,15 +44,8 @@ export class CacheMemory {
44
44
  }
45
45
  }
46
46
 
47
- private getMemoryKey(scope: MemoryScope, userId?: string): string {
48
- if (scope === MemoryScope.GLOBAL) {
49
- return `${this.CACHE_PREFIX}global:`;
50
- }
51
- return `${this.CACHE_PREFIX}user:${userId}:`;
52
- }
53
-
54
47
  private async storeMemory(memory: CacheMemoryType) {
55
- const prefix = this.getMemoryKey(memory.scope, memory.userId);
48
+ const prefix = this.CACHE_PREFIX;
56
49
  const key = `${prefix}${memory.id}`;
57
50
  const result = await this.redis.set(key, JSON.stringify(memory), {
58
51
  EX: this.CACHE_TTL,
@@ -124,23 +117,10 @@ export class CacheMemory {
124
117
  scope?: MemoryScope,
125
118
  userId?: string
126
119
  ): Promise<CacheMemoryType[]> {
127
- let patterns: CacheMemoryType[] = [];
128
-
129
- if (!scope || scope === MemoryScope.GLOBAL) {
130
- const globalPrefix = this.getMemoryKey(MemoryScope.GLOBAL);
131
- const globalKeys = await this.redis.keys(`${globalPrefix}*`);
132
- const globalPatterns = await this.getMemoriesFromKeys(globalKeys);
133
- patterns = patterns.concat(globalPatterns);
134
- }
135
-
136
- if (userId && (!scope || scope === MemoryScope.USER)) {
137
- const userPrefix = this.getMemoryKey(MemoryScope.USER, userId);
138
- const userKeys = await this.redis.keys(`${userPrefix}*`);
139
- const userPatterns = await this.getMemoriesFromKeys(userKeys);
140
- patterns = patterns.concat(userPatterns);
141
- }
120
+ const keys = await this.redis.keys(`${this.CACHE_PREFIX}*`);
121
+ const memories = await this.getMemoriesFromKeys(keys);
142
122
 
143
- return patterns;
123
+ return memories;
144
124
  }
145
125
 
146
126
  private async getMemoriesFromKeys(
@@ -28,18 +28,6 @@ interface MeilisearchResponse {
28
28
  }>;
29
29
  }
30
30
 
31
- interface SearchParams {
32
- q?: string;
33
- offset?: number;
34
- limit?: number;
35
- filter?: string | string[];
36
- facets?: string[];
37
- attributesToRetrieve?: string[];
38
- attributesToSearchOn?: string[];
39
- sort?: string[];
40
- matchingStrategy?: "last" | "all" | "frequency";
41
- }
42
-
43
31
  interface ProcessedChunk {
44
32
  content: string;
45
33
  embedding: number[];
@@ -56,7 +44,7 @@ export class PersistentMemory {
56
44
  constructor(options: { host: string; apiKey: string; indexPrefix?: string }) {
57
45
  this.host = options.host;
58
46
  this.apiKey = options.apiKey;
59
- this.INDEX_PREFIX = options.indexPrefix || "memory_";
47
+ this.INDEX_PREFIX = options.indexPrefix || "memory";
60
48
  }
61
49
 
62
50
  /**
@@ -64,10 +52,7 @@ export class PersistentMemory {
64
52
  */
65
53
  async init() {
66
54
  // Create global index
67
- await this._getOrCreateIndex(this._getIndexName(MemoryScope.GLOBAL));
68
-
69
- // Create user index
70
- await this._getOrCreateIndex(this._getIndexName(MemoryScope.USER));
55
+ await this._getOrCreateIndex(this.INDEX_PREFIX);
71
56
  }
72
57
 
73
58
  /**
@@ -94,17 +79,6 @@ export class PersistentMemory {
94
79
 
95
80
  return response.json() as Promise<T>;
96
81
  }
97
-
98
- /**
99
- * Get index name based on scope and userId
100
- */
101
- private _getIndexName(scope: MemoryScope, userId?: string): string {
102
- if (scope === "global") {
103
- return `${this.INDEX_PREFIX}global`;
104
- }
105
- return `${this.INDEX_PREFIX}user_${userId}`;
106
- }
107
-
108
82
  /**
109
83
  * Get or create an index with proper settings
110
84
  */
@@ -161,8 +135,7 @@ export class PersistentMemory {
161
135
  * Store a memory in the database
162
136
  */
163
137
  async createMemory(memory: Memory) {
164
- const indexName = this._getIndexName(memory.scope, memory.userId);
165
- await this._getOrCreateIndex(indexName);
138
+ await this._getOrCreateIndex(memory.roomId);
166
139
 
167
140
  const chunks = await this.processContent(memory.data);
168
141
 
@@ -173,7 +146,7 @@ export class PersistentMemory {
173
146
  };
174
147
 
175
148
  const response = await this._makeRequest(
176
- `/indexes/${indexName}/documents`,
149
+ `/indexes/${this.INDEX_PREFIX}/documents`,
177
150
  {
178
151
  method: "POST",
179
152
  body: JSON.stringify([document]),
@@ -186,7 +159,7 @@ export class PersistentMemory {
186
159
  /**
187
160
  * Find best matching memories
188
161
  */
189
- async searchSimilarQueries(query: string, options: SearchOptions = {}) {
162
+ async findRelevantDocuments(query: string, options: SearchOptions = {}) {
190
163
  console.log("\n🔍 Searching in persistent memory");
191
164
  console.log("Query:", query);
192
165
  console.log("Options:", JSON.stringify(options, null, 2));
@@ -199,42 +172,20 @@ export class PersistentMemory {
199
172
 
200
173
  const searchResults = [];
201
174
 
202
- // Search in global memories
203
- if (!options.scope || options.scope === "global") {
204
- const globalIndex = this._getIndexName(MemoryScope.GLOBAL);
205
- console.log("\n📚 Searching in global index:", globalIndex);
206
- try {
207
- const globalResults = await this._makeRequest<MeilisearchResponse>(
208
- `/indexes/${globalIndex}/search`,
209
- {
210
- method: "POST",
211
- body: JSON.stringify({ q: query }),
212
- }
213
- );
214
- if (globalResults?.hits) {
215
- searchResults.push(...globalResults.hits);
216
- }
217
- } catch (error) {
218
- console.error("❌ Error searching global index:", error);
219
- }
220
- }
221
-
222
- // Search in user memories
223
- if (
224
- options.userId &&
225
- (!options.scope || options.scope === MemoryScope.USER)
226
- ) {
227
- const userIndex = this._getIndexName(MemoryScope.USER, options.userId);
228
- const userResults = await this._makeRequest<MeilisearchResponse>(
229
- `/indexes/${userIndex}/search`,
175
+ console.log("\n📚 Searching in global index:", this.INDEX_PREFIX);
176
+ try {
177
+ const globalResults = await this._makeRequest<MeilisearchResponse>(
178
+ `/indexes/${this.INDEX_PREFIX}/search`,
230
179
  {
231
180
  method: "POST",
232
181
  body: JSON.stringify({ q: query }),
233
182
  }
234
183
  );
235
- if (userResults.hits) {
236
- searchResults.push(...userResults.hits);
184
+ if (globalResults?.hits) {
185
+ searchResults.push(...globalResults.hits);
237
186
  }
187
+ } catch (error) {
188
+ console.error("❌ Error searching global index:", error);
238
189
  }
239
190
 
240
191
  const totalResults = searchResults.length;
@@ -244,13 +195,11 @@ export class PersistentMemory {
244
195
  const results = searchResults
245
196
  .flatMap((hit) => {
246
197
  const chunkSimilarities = hit.chunks.map((chunk) => ({
247
- createdAt: hit.createdAt,
248
- data: hit.data,
249
- purpose: hit.purpose,
250
198
  query: hit.query,
251
- chunk: chunk.content,
199
+ data: hit.data,
252
200
  similarityPercentage:
253
201
  (cosineSimilarity(queryEmbedding, chunk.embedding) + 1) * 50,
202
+ createdAt: hit.createdAt,
254
203
  }));
255
204
 
256
205
  return chunkSimilarities.reduce(
@@ -275,10 +224,6 @@ export class PersistentMemory {
275
224
  results.forEach((match, index) => {
276
225
  console.log(`\n${index + 1}. Match Details:`);
277
226
  console.log(` Query: ${match.query}`);
278
- console.log(` Purpose: ${match.purpose}`);
279
- console.log(` Similarity: ${match.similarityPercentage.toFixed(2)}%`);
280
- console.log(` Content: "${match.chunk}"`);
281
- console.log("─".repeat(50));
282
227
  });
283
228
  } else {
284
229
  console.log("\n❌ No relevant matches found");
@@ -290,9 +235,8 @@ export class PersistentMemory {
290
235
  /**
291
236
  * Delete memories for a given scope and user
292
237
  */
293
- async deleteMemories(scope: MemoryScope, userId?: string) {
294
- const indexName = this._getIndexName(scope, userId);
295
- return this._makeRequest(`/indexes/${indexName}`, {
238
+ async deleteMemories() {
239
+ return this._makeRequest(`/indexes/${this.INDEX_PREFIX}`, {
296
240
  method: "DELETE",
297
241
  });
298
242
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai.ntellect/core",
3
- "version": "0.3.0",
3
+ "version": "0.3.3",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {
@@ -0,0 +1,167 @@
1
+ import { Orchestrator } from "../llm/orchestrator";
2
+ import { ActionSchema, ScheduledAction, ScheduledActionEvents } from "../types";
3
+ import { ActionQueueManager } from "./queue";
4
+
5
+ export class ActionScheduler {
6
+ private scheduledActions: Map<string, NodeJS.Timeout> = new Map();
7
+ private storage: ScheduledActionStorage;
8
+ private events: ScheduledActionEvents;
9
+
10
+ constructor(
11
+ private actionQueueManager: ActionQueueManager,
12
+ private orchestrator: Orchestrator,
13
+ events: ScheduledActionEvents = {}
14
+ ) {
15
+ this.storage = new ScheduledActionStorage();
16
+ this.events = events;
17
+ this.initializeScheduledActions();
18
+ }
19
+
20
+ async scheduleAction(
21
+ action: ActionSchema,
22
+ scheduledTime: Date,
23
+ userId: string,
24
+ recurrence?: ScheduledAction["recurrence"]
25
+ ): Promise<string> {
26
+ const scheduledAction: ScheduledAction = {
27
+ id: crypto.randomUUID(),
28
+ action: {
29
+ name: action.name,
30
+ parameters: [],
31
+ },
32
+ scheduledTime,
33
+ userId,
34
+ status: "pending",
35
+ recurrence,
36
+ };
37
+
38
+ await this.storage.saveScheduledAction(scheduledAction);
39
+ this.scheduleExecution(scheduledAction);
40
+ this.events.onActionScheduled?.(scheduledAction);
41
+
42
+ return scheduledAction.id;
43
+ }
44
+
45
+ private async initializeScheduledActions() {
46
+ const pendingActions = await this.storage.getPendingActions();
47
+ pendingActions.forEach((action) => this.scheduleExecution(action));
48
+ }
49
+
50
+ private scheduleExecution(scheduledAction: ScheduledAction) {
51
+ const now = new Date();
52
+ const delay = scheduledAction.scheduledTime.getTime() - now.getTime();
53
+
54
+ if (delay < 0) return;
55
+
56
+ const timeout = setTimeout(async () => {
57
+ try {
58
+ await this.executeScheduledAction(scheduledAction);
59
+
60
+ if (scheduledAction.recurrence) {
61
+ const nextExecutionTime = this.calculateNextExecutionTime(
62
+ scheduledAction.scheduledTime,
63
+ scheduledAction.recurrence
64
+ );
65
+ const actionSchema = this.orchestrator.tools.find(
66
+ (tool: ActionSchema) => tool.name === scheduledAction.action.name
67
+ );
68
+ if (actionSchema) {
69
+ await this.scheduleAction(
70
+ actionSchema,
71
+ nextExecutionTime,
72
+ scheduledAction.userId,
73
+ scheduledAction.recurrence
74
+ );
75
+ }
76
+ }
77
+ } catch (error) {
78
+ console.error(
79
+ `Failed to execute scheduled action ${scheduledAction.id}:`,
80
+ error
81
+ );
82
+ await this.storage.updateActionStatus(scheduledAction.id, "failed");
83
+ }
84
+ }, delay);
85
+
86
+ this.scheduledActions.set(scheduledAction.id, timeout);
87
+ }
88
+
89
+ private async executeScheduledAction(scheduledAction: ScheduledAction) {
90
+ try {
91
+ this.events.onActionStart?.(scheduledAction);
92
+
93
+ this.actionQueueManager.addToQueue({
94
+ name: scheduledAction.action.name,
95
+ parameters: scheduledAction.action.parameters,
96
+ });
97
+
98
+ const result = await this.actionQueueManager.processQueue();
99
+ await this.storage.updateActionStatus(scheduledAction.id, "completed");
100
+
101
+ this.events.onActionComplete?.(scheduledAction, result);
102
+ } catch (error) {
103
+ await this.storage.updateActionStatus(scheduledAction.id, "failed");
104
+ this.events.onActionFailed?.(scheduledAction, error as Error);
105
+ throw error;
106
+ }
107
+ }
108
+
109
+ private calculateNextExecutionTime(
110
+ currentTime: Date,
111
+ recurrence: NonNullable<ScheduledAction["recurrence"]>
112
+ ): Date {
113
+ const nextTime = new Date(currentTime);
114
+
115
+ switch (recurrence.type) {
116
+ case "daily":
117
+ nextTime.setDate(nextTime.getDate() + recurrence.interval);
118
+ break;
119
+ case "weekly":
120
+ nextTime.setDate(nextTime.getDate() + 7 * recurrence.interval);
121
+ break;
122
+ case "monthly":
123
+ nextTime.setMonth(nextTime.getMonth() + recurrence.interval);
124
+ break;
125
+ }
126
+
127
+ return nextTime;
128
+ }
129
+
130
+ async cancelScheduledAction(actionId: string): Promise<boolean> {
131
+ const timeout = this.scheduledActions.get(actionId);
132
+ if (timeout) {
133
+ clearTimeout(timeout);
134
+ this.scheduledActions.delete(actionId);
135
+ await this.storage.deleteScheduledAction(actionId);
136
+ this.events.onActionCancelled?.(actionId);
137
+ return true;
138
+ }
139
+ return false;
140
+ }
141
+ }
142
+
143
+ class ScheduledActionStorage {
144
+ private actions: ScheduledAction[] = [];
145
+
146
+ async saveScheduledAction(action: ScheduledAction): Promise<void> {
147
+ this.actions.push(action);
148
+ }
149
+
150
+ async getPendingActions(): Promise<ScheduledAction[]> {
151
+ return this.actions.filter((action) => action.status === "pending");
152
+ }
153
+
154
+ async updateActionStatus(
155
+ actionId: string,
156
+ status: ScheduledAction["status"]
157
+ ): Promise<void> {
158
+ const action = this.actions.find((a) => a.id === actionId);
159
+ if (action) {
160
+ action.status = status;
161
+ }
162
+ }
163
+
164
+ async deleteScheduledAction(actionId: string): Promise<void> {
165
+ this.actions = this.actions.filter((a) => a.id !== actionId);
166
+ }
167
+ }