@ai.ntellect/core 0.6.17 → 0.6.20
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/.mocharc.json +1 -2
- package/README.md +123 -178
- package/dist/graph/controller.js +29 -6
- package/dist/graph/index.js +302 -62
- package/dist/index.js +21 -6
- package/dist/interfaces/index.js +15 -0
- package/dist/modules/agenda/adapters/node-cron/index.js +29 -0
- package/dist/modules/agenda/index.js +140 -0
- package/dist/{services/embedding.js → modules/embedding/adapters/ai/index.js} +24 -7
- package/dist/modules/embedding/index.js +59 -0
- package/dist/modules/memory/adapters/in-memory/index.js +210 -0
- package/dist/{memory → modules/memory}/adapters/meilisearch/index.js +97 -2
- package/dist/{memory → modules/memory}/adapters/redis/index.js +77 -15
- package/dist/modules/memory/index.js +103 -0
- package/dist/utils/{stringifiy-zod-schema.js → generate-action-schema.js} +5 -5
- package/graph/controller.ts +46 -35
- package/graph/index.ts +534 -102
- package/graph.ts +74 -0
- package/index.ts +25 -7
- package/interfaces/index.ts +353 -27
- package/modules/agenda/adapters/node-cron/index.ts +25 -0
- package/modules/agenda/index.ts +159 -0
- package/modules/embedding/adapters/ai/index.ts +42 -0
- package/modules/embedding/index.ts +45 -0
- package/modules/memory/adapters/in-memory/index.ts +203 -0
- package/{memory → modules/memory}/adapters/meilisearch/index.ts +114 -12
- package/modules/memory/adapters/redis/index.ts +164 -0
- package/modules/memory/index.ts +93 -0
- package/package.json +3 -1
- package/test/graph/index.test.ts +578 -0
- package/test/modules/agenda/node-cron.test.ts +286 -0
- package/test/modules/embedding/ai.test.ts +78 -0
- package/test/modules/memory/adapters/in-memory.test.ts +153 -0
- package/test/{memory → modules/memory}/adapters/meilisearch.test.ts +79 -75
- package/test/modules/memory/adapters/redis.test.ts +169 -0
- package/test/modules/memory/base.test.ts +230 -0
- package/test/services/agenda.test.ts +279 -280
- package/types/index.ts +93 -202
- package/utils/{stringifiy-zod-schema.ts → generate-action-schema.ts} +3 -3
- package/app/README.md +0 -36
- package/app/app/favicon.ico +0 -0
- package/app/app/globals.css +0 -21
- package/app/app/gun.ts +0 -0
- package/app/app/layout.tsx +0 -18
- package/app/app/page.tsx +0 -321
- package/app/eslint.config.mjs +0 -16
- package/app/next.config.ts +0 -7
- package/app/package-lock.json +0 -5912
- package/app/package.json +0 -31
- package/app/pnpm-lock.yaml +0 -4031
- package/app/postcss.config.mjs +0 -8
- package/app/public/file.svg +0 -1
- package/app/public/globe.svg +0 -1
- package/app/public/next.svg +0 -1
- package/app/public/vercel.svg +0 -1
- package/app/public/window.svg +0 -1
- package/app/tailwind.config.ts +0 -18
- package/app/tsconfig.json +0 -27
- package/dist/memory/index.js +0 -9
- package/dist/services/agenda.js +0 -115
- package/dist/services/queue.js +0 -142
- package/dist/utils/experimental-graph-rag.js +0 -152
- package/dist/utils/generate-object.js +0 -111
- package/dist/utils/inject-actions.js +0 -16
- package/dist/utils/queue-item-transformer.js +0 -24
- package/dist/utils/sanitize-results.js +0 -60
- package/memory/adapters/redis/index.ts +0 -103
- package/memory/index.ts +0 -22
- package/services/agenda.ts +0 -118
- package/services/embedding.ts +0 -26
- package/services/queue.ts +0 -145
- package/test/memory/adapters/redis.test.ts +0 -159
- package/test/memory/base.test.ts +0 -225
- package/test/services/queue.test.ts +0 -286
- package/utils/experimental-graph-rag.ts +0 -170
- package/utils/generate-object.ts +0 -117
- package/utils/inject-actions.ts +0 -19
- package/utils/queue-item-transformer.ts +0 -38
- package/utils/sanitize-results.ts +0 -66
@@ -0,0 +1,42 @@
|
|
1
|
+
import { embed, EmbeddingModel, embedMany } from "ai";
|
2
|
+
import { IEmbeddingModel } from "../../../../interfaces";
|
3
|
+
|
4
|
+
/**
|
5
|
+
* @module AIEmbeddingAdapter
|
6
|
+
* @description Adapter implementation for AI-based embedding service.
|
7
|
+
* Provides integration with AI models for text embedding generation.
|
8
|
+
* @implements {IEmbeddingModel}
|
9
|
+
*/
|
10
|
+
export class AIEmbeddingAdapter implements IEmbeddingModel {
|
11
|
+
/**
|
12
|
+
* Creates an instance of AIEmbeddingAdapter
|
13
|
+
* @param {EmbeddingModel<string>} model - The AI embedding model to use
|
14
|
+
*/
|
15
|
+
constructor(private readonly model: EmbeddingModel<string>) {}
|
16
|
+
|
17
|
+
/**
|
18
|
+
* Generates an embedding vector for a single text using the AI model
|
19
|
+
* @param {string} text - The text to embed
|
20
|
+
* @returns {Promise<number[]>} The generated embedding vector
|
21
|
+
*/
|
22
|
+
async embed(text: string): Promise<number[]> {
|
23
|
+
const { embedding } = await embed({
|
24
|
+
model: this.model,
|
25
|
+
value: text,
|
26
|
+
});
|
27
|
+
return embedding;
|
28
|
+
}
|
29
|
+
|
30
|
+
/**
|
31
|
+
* Generates embedding vectors for multiple texts using the AI model
|
32
|
+
* @param {string[]} texts - Array of texts to embed
|
33
|
+
* @returns {Promise<number[][]>} Array of generated embedding vectors
|
34
|
+
*/
|
35
|
+
async embedMany(texts: string[]): Promise<number[][]> {
|
36
|
+
const { embeddings } = await embedMany({
|
37
|
+
model: this.model,
|
38
|
+
values: texts,
|
39
|
+
});
|
40
|
+
return embeddings;
|
41
|
+
}
|
42
|
+
}
|
@@ -0,0 +1,45 @@
|
|
1
|
+
import { cosineSimilarity } from "ai";
|
2
|
+
import { IEmbeddingModel, IEmbeddingModule } from "../../interfaces";
|
3
|
+
|
4
|
+
/**
|
5
|
+
* @module Embedding
|
6
|
+
* @description A module for generating and managing text embeddings.
|
7
|
+
* Provides functionality for converting text into vector representations
|
8
|
+
* and calculating similarities between embeddings.
|
9
|
+
* @implements {IEmbeddingModule}
|
10
|
+
*/
|
11
|
+
export class Embedding implements IEmbeddingModule {
|
12
|
+
/**
|
13
|
+
* Creates an instance of Embedding
|
14
|
+
* @param {IEmbeddingModel} embeddingModel - The embedding model implementation to use
|
15
|
+
*/
|
16
|
+
constructor(private readonly embeddingModel: IEmbeddingModel) {}
|
17
|
+
|
18
|
+
/**
|
19
|
+
* Generates an embedding vector for a single text
|
20
|
+
* @param {string} text - The text to embed
|
21
|
+
* @returns {Promise<number[]>} The embedding vector
|
22
|
+
*/
|
23
|
+
async embedText(text: string): Promise<number[]> {
|
24
|
+
return this.embeddingModel.embed(text);
|
25
|
+
}
|
26
|
+
|
27
|
+
/**
|
28
|
+
* Generates embedding vectors for multiple texts
|
29
|
+
* @param {string[]} texts - Array of texts to embed
|
30
|
+
* @returns {Promise<number[][]>} Array of embedding vectors
|
31
|
+
*/
|
32
|
+
async embedMany(texts: string[]): Promise<number[][]> {
|
33
|
+
return this.embeddingModel.embedMany(texts);
|
34
|
+
}
|
35
|
+
|
36
|
+
/**
|
37
|
+
* Calculates the similarity score between two embeddings
|
38
|
+
* @param {number[]} embedding1 - First embedding vector
|
39
|
+
* @param {number[]} embedding2 - Second embedding vector
|
40
|
+
* @returns {number} Similarity score between 0 and 100
|
41
|
+
*/
|
42
|
+
calculateSimilarity(embedding1: number[], embedding2: number[]): number {
|
43
|
+
return (cosineSimilarity(embedding1, embedding2) + 1) * 50;
|
44
|
+
}
|
45
|
+
}
|
@@ -0,0 +1,203 @@
|
|
1
|
+
import { ICronJob, IMemoryAdapter } from "interfaces";
|
2
|
+
import { BaseMemoryType, CreateMemoryInput, ScheduledRequest } from "types";
|
3
|
+
|
4
|
+
/**
|
5
|
+
* @module InMemoryAdapter
|
6
|
+
* @description In-memory implementation of the memory storage adapter.
|
7
|
+
* Provides a simple Map-based storage solution
|
8
|
+
* @implements {IMemoryAdapter}
|
9
|
+
*/
|
10
|
+
export class InMemoryAdapter implements IMemoryAdapter {
|
11
|
+
/** Internal storage using Map structure for jobs and requests */
|
12
|
+
private jobs: Map<string, ICronJob>;
|
13
|
+
/** Internal storage using Map structure for requests */
|
14
|
+
private requests: Map<string, ScheduledRequest>;
|
15
|
+
/** Internal storage using Map structure */
|
16
|
+
private storage: Map<string, BaseMemoryType[]>;
|
17
|
+
|
18
|
+
/**
|
19
|
+
* Creates an instance of InMemoryAdapter
|
20
|
+
*/
|
21
|
+
constructor() {
|
22
|
+
this.storage = new Map();
|
23
|
+
this.jobs = new Map();
|
24
|
+
this.requests = new Map();
|
25
|
+
}
|
26
|
+
|
27
|
+
/**
|
28
|
+
* Initializes storage for a room
|
29
|
+
* @param {string} roomId - Room identifier
|
30
|
+
* @returns {Promise<void>}
|
31
|
+
*/
|
32
|
+
async init(roomId: string): Promise<void> {
|
33
|
+
if (!this.storage.has(roomId)) {
|
34
|
+
this.storage.set(roomId, []);
|
35
|
+
}
|
36
|
+
}
|
37
|
+
|
38
|
+
/**
|
39
|
+
* Creates a new memory entry
|
40
|
+
* @param {CreateMemoryInput & { embedding?: number[] }} input - Memory data with optional embedding
|
41
|
+
* @returns {Promise<BaseMemoryType | undefined>} Created memory or existing memory if duplicate
|
42
|
+
*/
|
43
|
+
async createMemory(
|
44
|
+
input: CreateMemoryInput & { embedding?: number[] }
|
45
|
+
): Promise<BaseMemoryType | undefined> {
|
46
|
+
await this.init(input.roomId);
|
47
|
+
|
48
|
+
// Check if memory already exists
|
49
|
+
const memories = this.storage.get(input.roomId) || [];
|
50
|
+
const existingMemory = memories.find((m) => m.data === input.data);
|
51
|
+
if (existingMemory) {
|
52
|
+
return existingMemory;
|
53
|
+
}
|
54
|
+
|
55
|
+
// Create new memory
|
56
|
+
const memory: BaseMemoryType = {
|
57
|
+
id: input.id || crypto.randomUUID(),
|
58
|
+
data: input.data,
|
59
|
+
embedding: input.embedding,
|
60
|
+
roomId: input.roomId,
|
61
|
+
createdAt: new Date(),
|
62
|
+
};
|
63
|
+
|
64
|
+
memories.push(memory);
|
65
|
+
this.storage.set(input.roomId, memories);
|
66
|
+
return memory;
|
67
|
+
}
|
68
|
+
|
69
|
+
/**
|
70
|
+
* Retrieves a memory by ID and room ID
|
71
|
+
* @param {string} id - Memory identifier
|
72
|
+
* @param {string} roomId - Room identifier
|
73
|
+
* @returns {Promise<BaseMemoryType | null>} Memory entry or null if not found
|
74
|
+
*/
|
75
|
+
async getMemoryById(
|
76
|
+
id: string,
|
77
|
+
roomId: string
|
78
|
+
): Promise<BaseMemoryType | null> {
|
79
|
+
const memories = this.storage.get(roomId) || [];
|
80
|
+
return memories.find((m) => m.id === id) || null;
|
81
|
+
}
|
82
|
+
|
83
|
+
/**
|
84
|
+
* Searches for memories based on query and options
|
85
|
+
* @param {string} query - Search query
|
86
|
+
* @param {Object} options - Search options
|
87
|
+
* @param {string} options.roomId - Room identifier
|
88
|
+
* @param {number} [options.limit] - Maximum number of results
|
89
|
+
* @returns {Promise<BaseMemoryType[]>} Array of matching memories
|
90
|
+
*/
|
91
|
+
async getMemoryByIndex(
|
92
|
+
query: string,
|
93
|
+
options: { roomId: string; limit?: number }
|
94
|
+
): Promise<BaseMemoryType[]> {
|
95
|
+
const memories = this.storage.get(options.roomId) || [];
|
96
|
+
const filtered = memories.filter((m) => m.data.includes(query));
|
97
|
+
return filtered.slice(0, options.limit || filtered.length);
|
98
|
+
}
|
99
|
+
|
100
|
+
/**
|
101
|
+
* Retrieves all memories for a room
|
102
|
+
* @param {string} roomId - Room identifier
|
103
|
+
* @returns {Promise<BaseMemoryType[]>} Array of all memories
|
104
|
+
*/
|
105
|
+
async getAllMemories(roomId: string): Promise<BaseMemoryType[]> {
|
106
|
+
return this.storage.get(roomId) || [];
|
107
|
+
}
|
108
|
+
|
109
|
+
/**
|
110
|
+
* Deletes a specific memory
|
111
|
+
* @param {string} id - Memory identifier
|
112
|
+
* @param {string} roomId - Room identifier
|
113
|
+
* @returns {Promise<void>}
|
114
|
+
*/
|
115
|
+
async clearMemoryById(id: string, roomId: string): Promise<void> {
|
116
|
+
const memories = this.storage.get(roomId) || [];
|
117
|
+
const filtered = memories.filter((m) => m.id !== id);
|
118
|
+
this.storage.set(roomId, filtered);
|
119
|
+
}
|
120
|
+
|
121
|
+
/**
|
122
|
+
* Clears all memories across all rooms
|
123
|
+
* @returns {Promise<void>}
|
124
|
+
*/
|
125
|
+
async clearAllMemories(): Promise<void> {
|
126
|
+
this.storage.clear();
|
127
|
+
this.jobs.clear();
|
128
|
+
this.requests.clear();
|
129
|
+
}
|
130
|
+
|
131
|
+
/**
|
132
|
+
* Saves a job to the internal storage
|
133
|
+
* @param {string} id - Job identifier
|
134
|
+
* @param {ICronJob} job - Job data
|
135
|
+
* @returns {Promise<void>}
|
136
|
+
*/
|
137
|
+
async saveJob(id: string, job: ICronJob): Promise<void> {
|
138
|
+
this.jobs.set(id, job);
|
139
|
+
}
|
140
|
+
|
141
|
+
/**
|
142
|
+
* Saves a request to the internal storage
|
143
|
+
* @param {string} id - Request identifier
|
144
|
+
* @param {ScheduledRequest} request - Request data
|
145
|
+
* @returns {Promise<void>}
|
146
|
+
*/
|
147
|
+
async saveRequest(id: string, request: ScheduledRequest): Promise<void> {
|
148
|
+
this.requests.set(id, request);
|
149
|
+
}
|
150
|
+
|
151
|
+
/**
|
152
|
+
* Retrieves a job by ID
|
153
|
+
* @param {string} id - Job identifier
|
154
|
+
* @returns {Promise<ICronJob | undefined>} Job data or undefined if not found
|
155
|
+
*/
|
156
|
+
async getJob(id: string): Promise<ICronJob | undefined> {
|
157
|
+
return this.jobs.get(id);
|
158
|
+
}
|
159
|
+
|
160
|
+
/**
|
161
|
+
* Retrieves a request by ID
|
162
|
+
* @param {string} id - Request identifier
|
163
|
+
* @returns {Promise<ScheduledRequest | undefined>} Request data or undefined if not found
|
164
|
+
*/
|
165
|
+
async getRequest(id: string): Promise<ScheduledRequest | undefined> {
|
166
|
+
return this.requests.get(id);
|
167
|
+
}
|
168
|
+
|
169
|
+
/**
|
170
|
+
* Deletes a job by ID
|
171
|
+
* @param {string} id - Job identifier
|
172
|
+
* @returns {Promise<void>}
|
173
|
+
*/
|
174
|
+
async deleteJob(id: string): Promise<void> {
|
175
|
+
this.jobs.delete(id);
|
176
|
+
}
|
177
|
+
|
178
|
+
/**
|
179
|
+
* Deletes a request by ID
|
180
|
+
* @param {string} id - Request identifier
|
181
|
+
* @returns {Promise<void>}
|
182
|
+
*/
|
183
|
+
async deleteRequest(id: string): Promise<void> {
|
184
|
+
this.requests.delete(id);
|
185
|
+
}
|
186
|
+
|
187
|
+
/**
|
188
|
+
* Retrieves all requests
|
189
|
+
* @returns {Promise<ScheduledRequest[]>} Array of all requests
|
190
|
+
*/
|
191
|
+
async getAllRequests(): Promise<ScheduledRequest[]> {
|
192
|
+
return Array.from(this.requests.values());
|
193
|
+
}
|
194
|
+
|
195
|
+
/**
|
196
|
+
* Clears all jobs and requests
|
197
|
+
* @returns {Promise<void>}
|
198
|
+
*/
|
199
|
+
async clear(): Promise<void> {
|
200
|
+
this.jobs.clear();
|
201
|
+
this.requests.clear();
|
202
|
+
}
|
203
|
+
}
|
@@ -1,12 +1,27 @@
|
|
1
|
-
import {
|
2
|
-
|
3
|
-
CreateMemoryInput,
|
4
|
-
MeilisearchConfig,
|
5
|
-
} from "../../../types";
|
1
|
+
import { IMemoryAdapter } from "interfaces";
|
2
|
+
import { BaseMemoryType, CreateMemoryInput, MeilisearchConfig } from "types";
|
6
3
|
|
7
|
-
|
4
|
+
/**
|
5
|
+
* @module MeilisearchAdapter
|
6
|
+
* @description Adapter implementation for Meilisearch as a memory storage solution.
|
7
|
+
* Provides integration with Meilisearch for storing and retrieving memory entries.
|
8
|
+
* @implements {IMemoryAdapter}
|
9
|
+
*/
|
10
|
+
export class MeilisearchAdapter implements IMemoryAdapter {
|
11
|
+
/**
|
12
|
+
* Creates an instance of MeilisearchAdapter
|
13
|
+
* @param {MeilisearchConfig} config - Configuration for Meilisearch connection
|
14
|
+
*/
|
8
15
|
constructor(private readonly config: MeilisearchConfig) {}
|
9
16
|
|
17
|
+
/**
|
18
|
+
* Makes an HTTP request to the Meilisearch API
|
19
|
+
* @private
|
20
|
+
* @param {string} path - API endpoint path
|
21
|
+
* @param {RequestInit} [options] - Fetch request options
|
22
|
+
* @returns {Promise<any>} Response data
|
23
|
+
* @throws {Error} If the request fails
|
24
|
+
*/
|
10
25
|
private async makeRequest(path: string, options?: RequestInit) {
|
11
26
|
try {
|
12
27
|
const url = `${this.config.host}${path}`;
|
@@ -37,7 +52,13 @@ export class MeilisearchAdapter {
|
|
37
52
|
}
|
38
53
|
}
|
39
54
|
|
40
|
-
|
55
|
+
/**
|
56
|
+
* Initializes a storage index for a room
|
57
|
+
* @private
|
58
|
+
* @param {string} roomId - Room identifier to create index for
|
59
|
+
* @returns {Promise<void>}
|
60
|
+
*/
|
61
|
+
private async initializeStorage(roomId: string): Promise<void> {
|
41
62
|
try {
|
42
63
|
let indexExists = false;
|
43
64
|
|
@@ -82,7 +103,14 @@ export class MeilisearchAdapter {
|
|
82
103
|
}
|
83
104
|
}
|
84
105
|
|
85
|
-
|
106
|
+
/**
|
107
|
+
* Adds documents to the Meilisearch index
|
108
|
+
* @private
|
109
|
+
* @param {BaseMemoryType[]} documents - Documents to add
|
110
|
+
* @param {string} roomId - Room identifier
|
111
|
+
* @returns {Promise<void>}
|
112
|
+
*/
|
113
|
+
private async addDocuments(
|
86
114
|
documents: BaseMemoryType[],
|
87
115
|
roomId: string
|
88
116
|
): Promise<void> {
|
@@ -91,13 +119,24 @@ export class MeilisearchAdapter {
|
|
91
119
|
body: JSON.stringify(documents),
|
92
120
|
});
|
93
121
|
}
|
94
|
-
|
122
|
+
|
123
|
+
/**
|
124
|
+
* Deletes a storage index for a room
|
125
|
+
* @private
|
126
|
+
* @param {string} roomId - Room identifier
|
127
|
+
* @returns {Promise<void>}
|
128
|
+
*/
|
129
|
+
private async deleteStorage(roomId: string): Promise<void> {
|
95
130
|
await this.makeRequest(`/indexes/${roomId}`, {
|
96
131
|
method: "DELETE",
|
97
132
|
});
|
98
133
|
}
|
99
134
|
|
100
|
-
|
135
|
+
/**
|
136
|
+
* Initializes the adapter for a specific room
|
137
|
+
* @param {string} roomId - Room identifier
|
138
|
+
* @returns {Promise<void>}
|
139
|
+
*/
|
101
140
|
async init(roomId: string): Promise<void> {
|
102
141
|
try {
|
103
142
|
// Initialize the default "memories" index
|
@@ -110,7 +149,17 @@ export class MeilisearchAdapter {
|
|
110
149
|
}
|
111
150
|
}
|
112
151
|
|
113
|
-
|
152
|
+
/**
|
153
|
+
* Performs a search in the Meilisearch index
|
154
|
+
* @private
|
155
|
+
* @param {string} query - Search query
|
156
|
+
* @param {string} roomId - Room identifier
|
157
|
+
* @param {Object} [options] - Search options
|
158
|
+
* @param {number} [options.limit] - Maximum number of results
|
159
|
+
* @param {number} [options.threshold] - Minimum score threshold
|
160
|
+
* @returns {Promise<SearchResult[]>} Search results
|
161
|
+
*/
|
162
|
+
private async search(
|
114
163
|
query: string,
|
115
164
|
roomId: string,
|
116
165
|
options?: { limit?: number; threshold?: number }
|
@@ -123,6 +172,10 @@ export class MeilisearchAdapter {
|
|
123
172
|
}),
|
124
173
|
});
|
125
174
|
|
175
|
+
if (!searchResults.hits) {
|
176
|
+
return [];
|
177
|
+
}
|
178
|
+
|
126
179
|
return searchResults.hits.map((hit: any) => ({
|
127
180
|
document: {
|
128
181
|
id: hit.id,
|
@@ -135,17 +188,30 @@ export class MeilisearchAdapter {
|
|
135
188
|
}));
|
136
189
|
}
|
137
190
|
|
191
|
+
/**
|
192
|
+
* Creates a new memory entry
|
193
|
+
* @param {CreateMemoryInput & { embedding?: number[] }} input - Memory data with optional embedding
|
194
|
+
* @returns {Promise<BaseMemoryType | undefined>} Created memory or undefined
|
195
|
+
*/
|
138
196
|
async createMemory(
|
139
197
|
input: CreateMemoryInput & { embedding?: number[] }
|
140
198
|
): Promise<BaseMemoryType | undefined> {
|
141
199
|
// Initialize storage for this roomId if needed
|
142
200
|
await this.initializeStorage(input.roomId);
|
143
201
|
|
202
|
+
// Check if the memory already exists
|
203
|
+
const existingMemory = await this.search(input.data, input.roomId, {
|
204
|
+
limit: 1,
|
205
|
+
});
|
206
|
+
if (existingMemory.length > 0) {
|
207
|
+
return existingMemory[0].document;
|
208
|
+
}
|
209
|
+
|
144
210
|
// If not found, create new memory
|
145
211
|
const memory: BaseMemoryType = {
|
146
212
|
id: input.id || crypto.randomUUID(),
|
147
213
|
data: input.data,
|
148
|
-
embedding: input.embedding
|
214
|
+
embedding: input.embedding,
|
149
215
|
roomId: input.roomId,
|
150
216
|
createdAt: new Date(),
|
151
217
|
};
|
@@ -154,6 +220,12 @@ export class MeilisearchAdapter {
|
|
154
220
|
return memory;
|
155
221
|
}
|
156
222
|
|
223
|
+
/**
|
224
|
+
* Retrieves a memory by ID and room ID
|
225
|
+
* @param {string} id - Memory identifier
|
226
|
+
* @param {string} roomId - Room identifier
|
227
|
+
* @returns {Promise<BaseMemoryType | null>} Memory entry or null if not found
|
228
|
+
*/
|
157
229
|
async getMemoryById(
|
158
230
|
id: string,
|
159
231
|
roomId: string
|
@@ -176,6 +248,14 @@ export class MeilisearchAdapter {
|
|
176
248
|
}
|
177
249
|
}
|
178
250
|
|
251
|
+
/**
|
252
|
+
* Searches for memories based on query and options
|
253
|
+
* @param {string} query - Search query
|
254
|
+
* @param {Object} options - Search options
|
255
|
+
* @param {string} options.roomId - Room identifier
|
256
|
+
* @param {number} [options.limit] - Maximum number of results
|
257
|
+
* @returns {Promise<BaseMemoryType[]>} Array of matching memories
|
258
|
+
*/
|
179
259
|
async getMemoryByIndex(
|
180
260
|
query: string,
|
181
261
|
options: { roomId: string; limit?: number }
|
@@ -194,6 +274,11 @@ export class MeilisearchAdapter {
|
|
194
274
|
}));
|
195
275
|
}
|
196
276
|
|
277
|
+
/**
|
278
|
+
* Retrieves all memories for a room
|
279
|
+
* @param {string} roomId - Room identifier
|
280
|
+
* @returns {Promise<BaseMemoryType[]>} Array of all memories
|
281
|
+
*/
|
197
282
|
async getAllMemories(roomId: string): Promise<BaseMemoryType[]> {
|
198
283
|
const results = await this.makeRequest(`/indexes/${roomId}/documents`);
|
199
284
|
if (results.total === 0) {
|
@@ -209,6 +294,12 @@ export class MeilisearchAdapter {
|
|
209
294
|
}));
|
210
295
|
}
|
211
296
|
|
297
|
+
/**
|
298
|
+
* Deletes a specific memory
|
299
|
+
* @param {string} id - Memory identifier
|
300
|
+
* @param {string} roomId - Room identifier
|
301
|
+
* @returns {Promise<void>}
|
302
|
+
*/
|
212
303
|
async clearMemoryById(id: string, roomId: string): Promise<void> {
|
213
304
|
try {
|
214
305
|
// Ensure the index exists before attempting to delete
|
@@ -230,6 +321,10 @@ export class MeilisearchAdapter {
|
|
230
321
|
}
|
231
322
|
}
|
232
323
|
|
324
|
+
/**
|
325
|
+
* Clears all memories across all rooms
|
326
|
+
* @returns {Promise<void>}
|
327
|
+
*/
|
233
328
|
async clearAllMemories(): Promise<void> {
|
234
329
|
try {
|
235
330
|
// Get all indexes
|
@@ -248,8 +343,15 @@ export class MeilisearchAdapter {
|
|
248
343
|
}
|
249
344
|
}
|
250
345
|
|
346
|
+
/**
|
347
|
+
* @interface SearchResult
|
348
|
+
* @description Interface for search results from Meilisearch
|
349
|
+
*/
|
251
350
|
interface SearchResult {
|
351
|
+
/** The matched document */
|
252
352
|
document?: any;
|
353
|
+
/** Relevance score of the match */
|
253
354
|
score?: number;
|
355
|
+
/** Array of additional results */
|
254
356
|
results?: any[];
|
255
357
|
}
|
@@ -0,0 +1,164 @@
|
|
1
|
+
import { IMemoryAdapter } from "interfaces";
|
2
|
+
import { createClient } from "redis";
|
3
|
+
import { BaseMemoryType, CreateMemoryInput } from "types";
|
4
|
+
|
5
|
+
/**
|
6
|
+
* @module RedisAdapter
|
7
|
+
* @description Adapter implementation for Redis as a memory storage solution.
|
8
|
+
* Provides integration with Redis for storing and retrieving memory entries with TTL support.
|
9
|
+
* @implements {IMemoryAdapter}
|
10
|
+
*/
|
11
|
+
export class RedisAdapter implements IMemoryAdapter {
|
12
|
+
private redis;
|
13
|
+
private readonly cachePrefix: string;
|
14
|
+
private readonly cacheTTL: number;
|
15
|
+
|
16
|
+
/**
|
17
|
+
* Creates an instance of RedisAdapter
|
18
|
+
* @param {string} redisUrl - Redis connection URL
|
19
|
+
* @param {Object} options - Configuration options
|
20
|
+
* @param {string} [options.cachePrefix="memory:"] - Prefix for Redis keys
|
21
|
+
* @param {number} [options.cacheTTL=3600] - Default TTL in seconds
|
22
|
+
*/
|
23
|
+
constructor(
|
24
|
+
private readonly redisUrl: string,
|
25
|
+
options: {
|
26
|
+
cachePrefix?: string;
|
27
|
+
cacheTTL?: number;
|
28
|
+
}
|
29
|
+
) {
|
30
|
+
this.cachePrefix = options.cachePrefix || "memory:";
|
31
|
+
this.cacheTTL = options.cacheTTL || 3600;
|
32
|
+
this.redis = createClient({
|
33
|
+
url: redisUrl,
|
34
|
+
socket: {
|
35
|
+
tls: true,
|
36
|
+
rejectUnauthorized: true,
|
37
|
+
},
|
38
|
+
});
|
39
|
+
}
|
40
|
+
|
41
|
+
/**
|
42
|
+
* Initializes the Redis connection
|
43
|
+
* @param {string} roomId - Room identifier
|
44
|
+
* @returns {Promise<void>}
|
45
|
+
*/
|
46
|
+
async init(roomId: string): Promise<void> {
|
47
|
+
this.redis.on("error", (err) => console.error("Redis Client Error:", err));
|
48
|
+
await this.redis.connect();
|
49
|
+
}
|
50
|
+
|
51
|
+
/**
|
52
|
+
* Creates a new memory entry in Redis
|
53
|
+
* @param {CreateMemoryInput & { embedding?: number[] }} input - Memory data with optional embedding
|
54
|
+
* @returns {Promise<BaseMemoryType | undefined>} Created memory or undefined
|
55
|
+
*/
|
56
|
+
async createMemory(
|
57
|
+
input: CreateMemoryInput & { embedding?: number[] }
|
58
|
+
): Promise<BaseMemoryType | undefined> {
|
59
|
+
const memory: BaseMemoryType = {
|
60
|
+
id: input.id || crypto.randomUUID(),
|
61
|
+
data: input.data,
|
62
|
+
embedding: input.embedding,
|
63
|
+
roomId: input.roomId,
|
64
|
+
createdAt: new Date(),
|
65
|
+
};
|
66
|
+
|
67
|
+
const key = memory.roomId
|
68
|
+
? `${this.cachePrefix}${memory.roomId}:${memory.id}`
|
69
|
+
: `${this.cachePrefix}${memory.id}`;
|
70
|
+
|
71
|
+
await this.redis.set(key, JSON.stringify(memory), {
|
72
|
+
EX: this.cacheTTL,
|
73
|
+
});
|
74
|
+
|
75
|
+
return memory;
|
76
|
+
}
|
77
|
+
|
78
|
+
/**
|
79
|
+
* Retrieves a memory by ID and room ID from Redis
|
80
|
+
* @param {string} id - Memory identifier
|
81
|
+
* @param {string} roomId - Room identifier
|
82
|
+
* @returns {Promise<BaseMemoryType | null>} Memory entry or null if not found
|
83
|
+
*/
|
84
|
+
async getMemoryById(
|
85
|
+
id: string,
|
86
|
+
roomId: string
|
87
|
+
): Promise<BaseMemoryType | null> {
|
88
|
+
const key = `${this.cachePrefix}${roomId}:${id}`;
|
89
|
+
const data = await this.redis.get(key);
|
90
|
+
return data ? JSON.parse(data) : null;
|
91
|
+
}
|
92
|
+
|
93
|
+
/**
|
94
|
+
* Searches for memories in Redis based on pattern matching
|
95
|
+
* @param {string} query - Search query
|
96
|
+
* @param {Object} options - Search options
|
97
|
+
* @param {string} options.roomId - Room identifier
|
98
|
+
* @param {number} [options.limit] - Maximum number of results
|
99
|
+
* @returns {Promise<BaseMemoryType[]>} Array of matching memories
|
100
|
+
*/
|
101
|
+
async getMemoryByIndex(
|
102
|
+
query: string,
|
103
|
+
options: { roomId: string; limit?: number }
|
104
|
+
): Promise<BaseMemoryType[]> {
|
105
|
+
const pattern = `${this.cachePrefix}${options.roomId}:*`;
|
106
|
+
const keys = await this.redis.keys(pattern);
|
107
|
+
const memories = await Promise.all(
|
108
|
+
keys.map(async (key) => {
|
109
|
+
const data = await this.redis.get(key);
|
110
|
+
return data ? JSON.parse(data) : null;
|
111
|
+
})
|
112
|
+
);
|
113
|
+
return memories.filter(Boolean).slice(0, options.limit || 10);
|
114
|
+
}
|
115
|
+
|
116
|
+
/**
|
117
|
+
* Retrieves all memories for a room from Redis
|
118
|
+
* @param {string} roomId - Room identifier
|
119
|
+
* @returns {Promise<BaseMemoryType[]>} Array of all memories
|
120
|
+
*/
|
121
|
+
async getAllMemories(roomId: string): Promise<BaseMemoryType[]> {
|
122
|
+
const pattern = `${this.cachePrefix}${roomId}:*`;
|
123
|
+
const keys = await this.redis.keys(pattern);
|
124
|
+
const memories = await Promise.all(
|
125
|
+
keys.map(async (key) => {
|
126
|
+
const data = await this.redis.get(key);
|
127
|
+
return data ? JSON.parse(data) : null;
|
128
|
+
})
|
129
|
+
);
|
130
|
+
return memories.filter(Boolean);
|
131
|
+
}
|
132
|
+
|
133
|
+
/**
|
134
|
+
* Deletes a specific memory from Redis
|
135
|
+
* @param {string} id - Memory identifier
|
136
|
+
* @param {string} roomId - Room identifier
|
137
|
+
* @returns {Promise<void>}
|
138
|
+
*/
|
139
|
+
async clearMemoryById(id: string, roomId: string): Promise<void> {
|
140
|
+
const key = `${this.cachePrefix}${roomId}:${id}`;
|
141
|
+
await this.redis.del(key);
|
142
|
+
}
|
143
|
+
|
144
|
+
/**
|
145
|
+
* Clears all memories across all rooms from Redis
|
146
|
+
* @returns {Promise<void>}
|
147
|
+
*/
|
148
|
+
async clearAllMemories(): Promise<void> {
|
149
|
+
const keys = await this.redis.keys(`${this.cachePrefix}*`);
|
150
|
+
if (keys.length > 0) {
|
151
|
+
await this.redis.del(keys);
|
152
|
+
}
|
153
|
+
}
|
154
|
+
|
155
|
+
/**
|
156
|
+
* Closes the Redis connection
|
157
|
+
* @returns {Promise<void>}
|
158
|
+
*/
|
159
|
+
async quit(): Promise<void> {
|
160
|
+
if (this.redis) {
|
161
|
+
await this.redis.quit();
|
162
|
+
}
|
163
|
+
}
|
164
|
+
}
|