@ai.ntellect/core 0.1.81 → 0.1.83

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,9 +1,8 @@
1
1
  import { openai } from "@ai-sdk/openai";
2
2
  import { generateObject } from "ai";
3
3
  import { z } from "zod";
4
- import { CacheMemory } from "../../memory/cache";
5
4
  import { PersistentMemory } from "../../memory/persistent";
6
- import { ActionSchema, BaseLLM } from "../../types";
5
+ import { ActionSchema, BaseLLM, MemoryScopeType } from "../../types";
7
6
  import { orchestratorContext } from "./context";
8
7
 
9
8
  export class Orchestrator implements BaseLLM {
@@ -21,8 +20,44 @@ export class Orchestrator implements BaseLLM {
21
20
  parameters: z.object({
22
21
  query: z.string(),
23
22
  }),
24
- execute: async (params) => {
25
- const memories = await this.memory.searchSimilarQueries(params.value);
23
+ execute: async ({ query }: { query: string }) => {
24
+ const memories = await this.memory.searchSimilarQueries(query);
25
+ return memories;
26
+ },
27
+ },
28
+ {
29
+ name: "save_memory",
30
+ description: "Save a query in the internal knowledge base",
31
+ parameters: z.object({
32
+ query: z.string(),
33
+ purpose: z.string(),
34
+ data: z.any(),
35
+ scope: z.enum(["GLOBAL", "USER"]),
36
+ userId: z.string().optional(),
37
+ whyStored: z.string(),
38
+ }),
39
+ execute: async ({
40
+ query,
41
+ purpose,
42
+ data,
43
+ scope,
44
+ userId,
45
+ }: {
46
+ query: string;
47
+ purpose: string;
48
+ data: any;
49
+ scope: MemoryScopeType;
50
+ userId?: string;
51
+ }) => {
52
+ const memories = await this.memory.storeMemory({
53
+ query,
54
+ purpose,
55
+ data,
56
+ scope,
57
+ userId,
58
+ createdAt: new Date(),
59
+ id: crypto.randomUUID(),
60
+ });
26
61
  return memories;
27
62
  },
28
63
  },
@@ -37,10 +72,12 @@ export class Orchestrator implements BaseLLM {
37
72
  actions: z.array(
38
73
  z.object({
39
74
  name: z.string(),
40
- parameters: z.object({
41
- name: z.string(),
42
- value: z.string(),
43
- }),
75
+ parameters: z.array(
76
+ z.object({
77
+ name: z.string(),
78
+ value: z.string(),
79
+ })
80
+ ),
44
81
  })
45
82
  ),
46
83
  answer: z.string(),
package/memory/cache.ts CHANGED
@@ -56,22 +56,23 @@ export class CacheMemory {
56
56
  private async storeMemory(memory: CacheMemoryType) {
57
57
  const prefix = this.getMemoryKey(memory.scope, memory.userId);
58
58
  const key = `${prefix}${memory.id}`;
59
- await this.redis.set(key, JSON.stringify(memory), {
59
+ const result = await this.redis.set(key, JSON.stringify(memory), {
60
60
  EX: this.CACHE_TTL,
61
61
  });
62
+ console.log("Cache memory created: ", result);
62
63
  }
63
64
 
64
- async findBestMatches(
65
+ async findSimilarQueries(
65
66
  query: string,
66
67
  options: MatchOptions & { userId?: string; scope?: MemoryScope } = {}
67
68
  ): Promise<
68
69
  {
69
70
  data: any;
70
71
  similarityPercentage: number;
71
- purpose: string;
72
+ query: string;
72
73
  }[]
73
74
  > {
74
- console.log("\n🔍 Searching in cache for query:", query);
75
+ console.log("\nSearching in cache for query:", query);
75
76
 
76
77
  const { embedding } = await embed({
77
78
  model: openai.embedding("text-embedding-3-small"),
@@ -79,21 +80,20 @@ export class CacheMemory {
79
80
  });
80
81
 
81
82
  const memories = await this.getAllMemories(options.scope, options.userId);
82
- console.log("\n📚 Found", memories.length, "memories to compare with");
83
+ console.log("\n📚 Found", memories.length, "queries to compare with");
83
84
 
84
85
  const matches = memories
85
86
  .map((memory) => {
86
87
  const similarity = cosineSimilarity(embedding, memory.embedding);
87
88
  const similarityPercentage = (similarity + 1) * 50; // Conversion en pourcentage
88
89
 
89
- console.log(`\n📊 Memory "${memory.purpose}":
90
- - Similarity: ${similarityPercentage.toFixed(2)}%
91
- - Query: ${memory.query}`);
90
+ console.log(`\n📊 Query "${memory.query}":
91
+ - Similarity: ${similarityPercentage.toFixed(2)}%`);
92
92
 
93
93
  return {
94
94
  data: memory.data,
95
+ query: memory.query,
95
96
  similarityPercentage,
96
- purpose: memory.purpose,
97
97
  // Optionnel : ajouter des métadonnées utiles
98
98
  memoryId: memory.id,
99
99
  };
@@ -109,10 +109,10 @@ export class CacheMemory {
109
109
  : matches;
110
110
 
111
111
  if (results.length > 0) {
112
- console.log("\n✨ Best matches found:");
112
+ console.log("\n✨ Similar queries found:");
113
113
  results.forEach((match) => {
114
114
  console.log(
115
- `- ${match.purpose} (${match.similarityPercentage.toFixed(2)}%)`
115
+ `- ${match.query} (${match.similarityPercentage.toFixed(2)}%)`
116
116
  );
117
117
  });
118
118
  } else {
@@ -123,7 +123,7 @@ export class CacheMemory {
123
123
  return results;
124
124
  }
125
125
 
126
- private async getAllMemories(
126
+ async getAllMemories(
127
127
  scope?: MemoryScope,
128
128
  userId?: string
129
129
  ): Promise<CacheMemoryType[]> {
@@ -162,23 +162,28 @@ export class CacheMemory {
162
162
  public async createMemory(
163
163
  input: CreateMemoryInput
164
164
  ): Promise<string | undefined> {
165
- const existingPattern = await this.findBestMatches(input.content, {
165
+ console.log("Searching for similar memory", input);
166
+ const existingPattern = await this.findSimilarQueries(input.content, {
166
167
  similarityThreshold: 95,
167
168
  userId: input.userId,
168
169
  scope: input.scope,
169
170
  });
170
171
 
171
172
  if (existingPattern.length > 0) {
172
- console.log("\n🔍 Similar memory found:");
173
+ console.log("\nSimilar cache memory found:");
173
174
  existingPattern.forEach((match) => {
174
175
  console.log(
175
- `- ${match.purpose} (${match.similarityPercentage.toFixed(2)}%)`
176
+ `- ${match.query} (${match.similarityPercentage.toFixed(2)}%)`
176
177
  );
177
178
  });
179
+ console.log("Cache memory already exists. No need to create new one..");
178
180
  return;
179
181
  }
180
182
 
183
+ console.log("No similar memory found");
184
+
181
185
  // Générer les variations via GPT-4
186
+ console.log("Generating variations...");
182
187
  const variations = await generateObject({
183
188
  model: openai("gpt-4"),
184
189
  schema: z.object({
@@ -186,20 +191,17 @@ export class CacheMemory {
186
191
  queries: z.array(z.object({ text: z.string() })),
187
192
  }),
188
193
  prompt: `For this input: "${input.content}"
189
- Generate similar variations that should match the same context.
190
- Context type: ${input.type}
191
- Data: ${JSON.stringify(input.data)}
194
+ Generate similar way to ask the same question.
195
+ Action results: ${JSON.stringify(input.data)}
192
196
  - Keep variations natural and human-like
193
- - Include the original input
194
197
  - Add 3-5 variations`,
195
198
  });
196
-
199
+ console.log("Variations generated:", variations.object.queries);
197
200
  await this.createSingleMemory({
198
201
  id: crypto.randomUUID(),
199
202
  content: input.content,
200
203
  type: input.type,
201
204
  data: input.data,
202
- purpose: variations.object.request,
203
205
  userId: input.userId,
204
206
  scope: input.scope,
205
207
  });
@@ -212,7 +214,6 @@ export class CacheMemory {
212
214
  content: variation.text,
213
215
  type: input.type,
214
216
  data: input.data,
215
- purpose: variations.object.request,
216
217
  userId: input.userId,
217
218
  scope: input.scope,
218
219
  });
@@ -229,20 +230,20 @@ export class CacheMemory {
229
230
  content: string;
230
231
  type: MemoryType;
231
232
  data: any;
232
- purpose: string;
233
233
  userId?: string;
234
234
  scope?: MemoryScope;
235
235
  }): Promise<CacheMemoryType> {
236
+ console.log("Creating new cache memory...", params.content);
237
+ console.log("Creating embedding...");
236
238
  const { embedding } = await embed({
237
239
  model: openai.embedding("text-embedding-3-small"),
238
240
  value: params.content,
239
241
  });
240
-
242
+ console.log("Embedding created");
241
243
  const memory: CacheMemoryType = {
242
244
  id: params.id,
243
245
  type: params.type,
244
246
  data: params.data,
245
- purpose: params.purpose,
246
247
  query: params.content,
247
248
  embedding,
248
249
  userId: params.userId,
@@ -250,7 +251,6 @@ export class CacheMemory {
250
251
  params.scope || (params.userId ? MemoryScope.USER : MemoryScope.GLOBAL),
251
252
  createdAt: new Date(),
252
253
  };
253
-
254
254
  await this.storeMemory(memory);
255
255
  return memory;
256
256
  }
@@ -77,7 +77,6 @@ export class PersistentMemory {
77
77
  options: RequestInit = {}
78
78
  ): Promise<T> {
79
79
  const url = `${this.host}${path}`;
80
- console.log("Making request to:", url);
81
80
  const response = await fetch(url, {
82
81
  ...options,
83
82
  headers: {
@@ -187,7 +186,7 @@ export class PersistentMemory {
187
186
  * Find best matching memories
188
187
  */
189
188
  async searchSimilarQueries(query: string, options: SearchOptions = {}) {
190
- console.log("\n🔍 Searching in persistent memory:", query);
189
+ console.log("\nSearching in persistent memory:", query);
191
190
 
192
191
  // Generate embedding for the query
193
192
  const { embedding: queryEmbedding } = await embed({
@@ -240,7 +239,9 @@ export class PersistentMemory {
240
239
  }
241
240
  }
242
241
 
243
- console.log("Found in persistent memory:", searchResults);
242
+ console.log(
243
+ `📚 Found ${searchResults.length} queries in persistent memory`
244
+ );
244
245
 
245
246
  // Process and filter results using cosine similarity
246
247
  const results = searchResults
@@ -272,7 +273,7 @@ export class PersistentMemory {
272
273
 
273
274
  // Log results
274
275
  if (results.length > 0) {
275
- console.log("\n✨ Best matches found:");
276
+ console.log("\n✨ Similar queries found:");
276
277
  results.forEach((match) => {
277
278
  console.log(
278
279
  `- ${match.query} : ${match.similarityPercentage.toFixed(2)}% (${
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai.ntellect/core",
3
- "version": "0.1.81",
3
+ "version": "0.1.83",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {
@@ -14,8 +14,10 @@
14
14
  "dependencies": {
15
15
  "@ai-sdk/openai": "1.0.6",
16
16
  "ai": "^3.0.0",
17
+ "ethers": "^6.13.5",
17
18
  "langchain": "^0.3.11",
18
19
  "redis": "^4.7.0",
20
+ "rss-parser": "^3.13.0",
19
21
  "zod": "^3.24.1"
20
22
  },
21
23
  "devDependencies": {
package/services/queue.ts CHANGED
@@ -42,7 +42,6 @@ export class ActionQueueManager {
42
42
 
43
43
  for (const action of this.queue) {
44
44
  const actionConfig = this.actions.find((a) => a.name === action.name);
45
-
46
45
  if (actionConfig?.confirmation?.requireConfirmation) {
47
46
  // Wait for user confirmation before executing this action
48
47
  const shouldProceed = await this.callbacks.onConfirmationRequired?.(
@@ -62,6 +61,7 @@ export class ActionQueueManager {
62
61
  continue;
63
62
  }
64
63
  }
64
+ const parameters = this.formatArguments(action.parameters);
65
65
 
66
66
  actionPromises.push(
67
67
  this.executeAction(action)
@@ -72,7 +72,7 @@ export class ActionQueueManager {
72
72
  .catch((error) => {
73
73
  const result = {
74
74
  name: action.name,
75
- parameters: this.formatArguments(action.parameters),
75
+ parameters,
76
76
  result: null,
77
77
  error: error.message || "Unknown error occurred",
78
78
  };
@@ -98,7 +98,23 @@ export class ActionQueueManager {
98
98
 
99
99
  private formatArguments(args: QueueItemParameter[]): Record<string, string> {
100
100
  return args.reduce<Record<string, string>>((acc, arg) => {
101
- acc[arg.name] = arg.value;
101
+ try {
102
+ // Parse the JSON string if the value is a stringified JSON object
103
+ const parsedValue = JSON.parse(arg.value);
104
+ if (
105
+ parsedValue &&
106
+ typeof parsedValue === "object" &&
107
+ "value" in parsedValue
108
+ ) {
109
+ acc[parsedValue.name] = parsedValue.value;
110
+ } else {
111
+ // Fallback to original value if not in expected format
112
+ acc[arg.name] = arg.value;
113
+ }
114
+ } catch {
115
+ // If JSON parsing fails, use the original value
116
+ acc[arg.name] = arg.value;
117
+ }
102
118
  return acc;
103
119
  }, {});
104
120
  }
@@ -115,13 +131,7 @@ export class ActionQueueManager {
115
131
  error: `Action '${action.name}' not found in actions list`,
116
132
  };
117
133
  }
118
- const actionArgs = action.parameters.reduce<Record<string, string>>(
119
- (acc: Record<string, string>, arg: QueueItemParameter) => {
120
- acc[arg.name] = arg.value;
121
- return acc;
122
- },
123
- {}
124
- );
134
+ const actionArgs = this.formatArguments(action.parameters);
125
135
  try {
126
136
  const result = await actionConfig.execute(actionArgs);
127
137
  const actionResult = {
@@ -130,8 +140,7 @@ export class ActionQueueManager {
130
140
  result,
131
141
  error: null,
132
142
  };
133
- console.log("Action executed successfully: ", action.name);
134
- console.dir(actionResult, { depth: null });
143
+ console.log("Action executed successfully: ", action.name, "🎉");
135
144
  return actionResult;
136
145
  } catch (error) {
137
146
  const actionResult = {
package/t.ts ADDED
@@ -0,0 +1,133 @@
1
+ export interface NetworkConfig {
2
+ name: string;
3
+ id?: number;
4
+ rpc: string;
5
+ explorerUrl: string;
6
+ nativeToken: string; // WETH
7
+ }
8
+ export const networkConfigs: Record<string, NetworkConfig> = {
9
+ ethereum: {
10
+ name: "Ethereum Mainnet",
11
+ id: 1,
12
+ rpc: "https://eth.llamarpc.com",
13
+ explorerUrl: "https://etherscan.io",
14
+ nativeToken: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
15
+ },
16
+ polygon: {
17
+ name: "Polygon Mainnet",
18
+ id: 137,
19
+ rpc: "https://polygon.llamarpc.com",
20
+ explorerUrl: "https://polygonscan.com",
21
+ nativeToken: "0x0000000000000000000000000000000000001010",
22
+ },
23
+ arbitrum: {
24
+ name: "Arbitrum Mainnet",
25
+ id: 42161,
26
+ rpc: "https://arbitrum.llamarpc.com",
27
+ explorerUrl: "https://arbiscan.io",
28
+ nativeToken: "0x82af49447d8a07e3bd95bd0d56f35241523fbab1",
29
+ },
30
+ base: {
31
+ name: "Base Mainnet",
32
+ id: 8453,
33
+ rpc: "https://base.llamarpc.com",
34
+ explorerUrl: "https://basescan.org",
35
+ nativeToken: "0x4200000000000000000000000000000000000006",
36
+ },
37
+ solana: {
38
+ name: "Solana Mainnet",
39
+ rpc: "https://api.mainnet-beta.solana.com",
40
+ explorerUrl: "https://solscan.io",
41
+ nativeToken: "So11111111111111111111111111111111111111112",
42
+ },
43
+ sepolia: {
44
+ name: "Sepolia Testnet",
45
+ id: 11155111,
46
+ rpc: "https://sepolia.llamarpc.com",
47
+ explorerUrl: "https://sepolia.etherscan.io",
48
+ nativeToken: "0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14",
49
+ },
50
+ baseSepolia: {
51
+ name: "Base Sepolia Testnet",
52
+ id: 84532,
53
+ rpc: "https://base-sepolia-rpc.publicnode.com",
54
+ explorerUrl: "https://sepolia.basescan.org",
55
+ nativeToken: "0x4200000000000000000000000000000000000006",
56
+ },
57
+ };
58
+
59
+ export const getNetworkProvider = (networkName: string) => {
60
+ const config = networkConfigs[networkName.toLowerCase()];
61
+ if (!config) {
62
+ throw new Error(`Network ${networkName} not supported`);
63
+ }
64
+ return { config };
65
+ };
66
+
67
+ import { parseEther } from "ethers";
68
+ import { z } from "zod";
69
+
70
+ export type TransactionPrepared = {
71
+ to: string;
72
+ value: string;
73
+ data?: string;
74
+ chain: {
75
+ id: number;
76
+ rpc: string;
77
+ };
78
+ type: "transfer" | "approve" | "swap";
79
+ method?: string;
80
+ params?: any[];
81
+ };
82
+
83
+ export const prepareEvmTransaction = {
84
+ name: "prepare-evm-transaction",
85
+ description: "Prepare a transaction for the user to sign.",
86
+ parameters: z.object({
87
+ walletAddress: z.string(),
88
+ amount: z
89
+ .string()
90
+ .describe("Ask the user for the amount to send, if not specified"),
91
+ network: z
92
+ .string()
93
+ .describe(
94
+ "Examples networks: ethereum, arbitrum, base. IMPORTANT: You must respect the network name."
95
+ ),
96
+ }),
97
+ execute: async ({
98
+ walletAddress,
99
+ amount,
100
+ network,
101
+ }: {
102
+ walletAddress: string;
103
+ amount: string;
104
+ network: string;
105
+ }): Promise<TransactionPrepared> => {
106
+ try {
107
+ console.log("💰 Preparing transaction", {
108
+ to: walletAddress,
109
+ amount,
110
+ network,
111
+ });
112
+
113
+ const networkConfig = networkConfigs[network.toLowerCase()];
114
+
115
+ if (!networkConfig) {
116
+ throw new Error(`Network ${network} not found`);
117
+ }
118
+
119
+ return {
120
+ to: walletAddress,
121
+ value: parseEther(amount).toString(),
122
+ chain: {
123
+ id: networkConfig.id || 0,
124
+ rpc: networkConfig.rpc,
125
+ },
126
+ type: "transfer",
127
+ };
128
+ } catch (error) {
129
+ console.error("💰 Error sending transaction:", error);
130
+ throw new Error("An error occurred while sending the transaction");
131
+ }
132
+ },
133
+ };
package/types.ts CHANGED
@@ -126,9 +126,9 @@ export interface CacheMemoryOptions {
126
126
  }
127
127
 
128
128
  export interface CreateMemoryInput {
129
- content: string;
129
+ content: any;
130
130
  type: MemoryType;
131
- data: any;
131
+ data: ActionSchema[];
132
132
  userId?: string;
133
133
  scope?: MemoryScope;
134
134
  }
@@ -137,7 +137,6 @@ export interface CacheMemoryType {
137
137
  id: string;
138
138
  type: MemoryType;
139
139
  data: any;
140
- purpose: string;
141
140
  query: string;
142
141
  embedding: Embedding;
143
142
  userId?: string;
@@ -5,7 +5,7 @@ export const injectActions = (actions: ActionSchema[]) => {
5
5
  return actions.map((action) => {
6
6
  const parameters = action.parameters as z.ZodObject<any>;
7
7
  const schemaShape = Object.keys(parameters._def.shape()).join(", ");
8
- const actionString = `Name: ${action.name}, Description: ${action.description}, Arguments: { ${schemaShape} }`;
8
+ const actionString = `Name: ${action.name}, Description: ${action.description}, Arguments (STRICTLY REQUIRED): { ${schemaShape} }`;
9
9
  return actionString;
10
10
  });
11
11
  };