memories-lite 0.9.5 → 0.99.1

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.
@@ -72,11 +72,8 @@ export interface MemoryTypeConfig {
72
72
  }
73
73
 
74
74
  export interface MemoryScoringConfig {
75
- todo: MemoryTypeConfig;
76
- procedural: MemoryTypeConfig;
77
- episodic: MemoryTypeConfig;
78
- factual: MemoryTypeConfig;
79
75
  assistant_preference: MemoryTypeConfig;
76
+ discussion: MemoryTypeConfig;
80
77
  default: MemoryTypeConfig; // Fallback if type is missing or unknown
81
78
  }
82
79
 
@@ -103,7 +100,7 @@ export interface MemoryConfig {
103
100
  enableGraph?: boolean;
104
101
  }
105
102
 
106
- export type MemoryType = 'procedural' | 'todo' | 'episodic' | 'factual' | 'assistant_preference';
103
+ export type MemoryType = 'assistant_preference' | 'discussion';
107
104
 
108
105
  export interface MemoryItem {
109
106
  id: string;
@@ -164,31 +161,13 @@ export const MemoryConfigSchema = z.object({
164
161
  dimension: z.number().optional(),
165
162
  client: z.any().optional(),
166
163
  scoring: z.object({
167
- todo: z.object({
168
- alpha: z.number(),
169
- beta: z.number(),
170
- gamma: z.number(),
171
- halfLifeDays: z.number(),
172
- }),
173
- procedural: z.object({
174
- alpha: z.number(),
175
- beta: z.number(),
176
- gamma: z.number(),
177
- halfLifeDays: z.number(),
178
- }),
179
- episodic: z.object({
180
- alpha: z.number(),
181
- beta: z.number(),
182
- gamma: z.number(),
183
- halfLifeDays: z.number(),
184
- }),
185
- factual: z.object({
164
+ assistant_preference: z.object({
186
165
  alpha: z.number(),
187
166
  beta: z.number(),
188
167
  gamma: z.number(),
189
168
  halfLifeDays: z.number(),
190
169
  }),
191
- assistant_preference: z.object({
170
+ discussion: z.object({
192
171
  alpha: z.number(),
193
172
  beta: z.number(),
194
173
  gamma: z.number(),
@@ -25,6 +25,10 @@ jest.mock('sqlite3', () => {
25
25
  });
26
26
 
27
27
 
28
+ /**
29
+ * Tests for LiteVectorStore private methods
30
+ * Updated to use new memory types: assistant_preference and discussion
31
+ */
28
32
  describe('LiteVectorStore Private Methods', () => {
29
33
  let store: LiteVectorStore;
30
34
  const userId = 'test-user';
@@ -98,59 +102,65 @@ describe('LiteVectorStore Private Methods', () => {
98
102
  const veryOldDate = new Date(now.getTime() - 400 * 24 * 60 * 60 * 1000).toISOString();
99
103
  const scoring = DEFAULT_MEMORY_CONFIG.vectorStore.config.scoring!;
100
104
 
101
- it('should prioritize cosine similarity for factual memory (high alpha)', () => {
102
- const payload: MemoryPayload = { memoryId: 'mem-f1', userId: userId, type: 'factual', createdAt: twoDaysAgo };
105
+ it('should prioritize cosine similarity for assistant_preference (high alpha)', () => {
106
+ //
107
+ // assistant_preference: { alpha: 0.60, beta: 0.05, gamma: 0.35, halfLifeDays: Infinity }
108
+ const payload: MemoryPayload = { memoryId: 'mem-ap1', userId: userId, type: 'assistant_preference', createdAt: twoDaysAgo };
103
109
  const cosineScore = 0.9;
104
- const expectedRecency = (store as any).calculateRecencyScore(twoDaysAgo, scoring.factual.halfLifeDays);
105
- const expectedScore = scoring.factual.alpha * cosineScore + scoring.factual.beta * expectedRecency + scoring.factual.gamma;
110
+ const expectedRecency = 1.0; // Infinity halfLife → recency = 1
111
+ const expectedScore = scoring.assistant_preference.alpha * cosineScore + scoring.assistant_preference.beta * expectedRecency + scoring.assistant_preference.gamma;
106
112
  const hybridScore = (store as any).calculateHybridScore(cosineScore, payload);
107
113
  expect(hybridScore).toBeCloseTo(expectedScore, 5);
108
- expect(scoring.factual.alpha * cosineScore).toBeGreaterThan(scoring.factual.beta * expectedRecency);
114
+ // alpha * cosine (0.54) > beta * recency (0.05)
115
+ expect(scoring.assistant_preference.alpha * cosineScore).toBeGreaterThan(scoring.assistant_preference.beta * expectedRecency);
109
116
  });
110
117
 
111
- it('should prioritize recency for episodic memory (high beta, short half-life)', () => {
112
- const payload: MemoryPayload = { memoryId: 'mem-e1', userId: userId, type: 'episodic', createdAt: twoDaysAgo };
118
+ it('should return constant score for discussion (beta=1, alpha=0, gamma=0)', () => {
119
+ //
120
+ // discussion: { alpha: 0, beta: 1, gamma: 0, halfLifeDays: Infinity }
121
+ // Score = 0 * cosine + 1 * recency + 0 = 1 (constant)
122
+ const payload: MemoryPayload = { memoryId: 'mem-d1', userId: userId, type: 'discussion', createdAt: twoDaysAgo };
113
123
  const cosineScore = 0.5;
114
- const expectedRecency = (store as any).calculateRecencyScore(twoDaysAgo, scoring.episodic.halfLifeDays);
115
- const expectedScore = scoring.episodic.alpha * cosineScore + scoring.episodic.beta * expectedRecency + scoring.episodic.gamma;
124
+ const expectedRecency = 1.0; // Infinity halfLife → recency = 1
125
+ const expectedScore = scoring.discussion.alpha * cosineScore + scoring.discussion.beta * expectedRecency + scoring.discussion.gamma;
116
126
  const hybridScore = (store as any).calculateHybridScore(cosineScore, payload);
117
127
  expect(hybridScore).toBeCloseTo(expectedScore, 5);
118
- expect(scoring.episodic.beta * expectedRecency).toBeGreaterThan(0.2);
128
+ expect(hybridScore).toBe(1); // Score constant = 1
119
129
  });
120
130
 
121
- it('should have low score for old episodic memory', () => {
122
- const payload: MemoryPayload = { memoryId: 'mem-e2', userId: userId, type: 'episodic', createdAt: veryOldDate };
123
- const cosineScore = 0.9;
124
- const expectedRecency = (store as any).calculateRecencyScore(veryOldDate, scoring.episodic.halfLifeDays);
125
- const expectedScore = scoring.episodic.alpha * cosineScore + scoring.episodic.beta * expectedRecency + scoring.episodic.gamma;
126
- const hybridScore = (store as any).calculateHybridScore(cosineScore, payload);
127
- expect(expectedRecency).toBeLessThan(0.01);
128
- expect(hybridScore).toBeCloseTo(scoring.episodic.alpha * cosineScore + scoring.episodic.gamma, 5);
131
+ it('should have constant score for old discussion memory (no decay)', () => {
132
+ //
133
+ // discussion with Infinity halfLife → old memories have same score as new
134
+ const payload: MemoryPayload = { memoryId: 'mem-d2', userId: userId, type: 'discussion', createdAt: veryOldDate };
135
+ const cosineScore = 0.9;
136
+ const expectedRecency = 1.0; // Infinity halfLife → recency = 1 even for old dates
137
+ const hybridScore = (store as any).calculateHybridScore(cosineScore, payload);
138
+ expect(hybridScore).toBe(1); // Score constant = 1
129
139
  });
130
140
 
131
141
  it('should handle assistant_preference with no decay (Infinity half-life)', () => {
132
- const payload: MemoryPayload = { memoryId: 'mem-a1', userId: userId, type: 'assistant_preference', createdAt: veryOldDate };
133
- const cosineScore = 0.7;
134
- const expectedRecency = 1.0;
135
- const expectedScore = scoring.assistant_preference.alpha * cosineScore + scoring.assistant_preference.beta * expectedRecency + scoring.assistant_preference.gamma;
136
- const hybridScore = (store as any).calculateHybridScore(cosineScore, payload);
137
- expect(hybridScore).toBeCloseTo(expectedScore, 5);
142
+ const payload: MemoryPayload = { memoryId: 'mem-a1', userId: userId, type: 'assistant_preference', createdAt: veryOldDate };
143
+ const cosineScore = 0.7;
144
+ const expectedRecency = 1.0;
145
+ const expectedScore = scoring.assistant_preference.alpha * cosineScore + scoring.assistant_preference.beta * expectedRecency + scoring.assistant_preference.gamma;
146
+ const hybridScore = (store as any).calculateHybridScore(cosineScore, payload);
147
+ expect(hybridScore).toBeCloseTo(expectedScore, 5);
138
148
  });
139
149
 
140
150
  it('should use default scoring if type is missing', () => {
141
- const payload: MemoryPayload = { memoryId: 'mem-d1', userId: userId, createdAt: sevenDaysAgo }; // No type specified
142
- const cosineScore = 0.8;
143
- const expectedRecency = (store as any).calculateRecencyScore(sevenDaysAgo, scoring.default.halfLifeDays);
144
- const expectedScore = scoring.default.alpha * cosineScore + scoring.default.beta * expectedRecency + scoring.default.gamma;
145
- const hybridScore = (store as any).calculateHybridScore(cosineScore, payload);
146
- expect(hybridScore).toBeCloseTo(expectedScore, 5);
151
+ const payload: MemoryPayload = { memoryId: 'mem-def1', userId: userId, createdAt: sevenDaysAgo }; // No type specified
152
+ const cosineScore = 0.8;
153
+ const expectedRecency = (store as any).calculateRecencyScore(sevenDaysAgo, scoring.default.halfLifeDays);
154
+ const expectedScore = scoring.default.alpha * cosineScore + scoring.default.beta * expectedRecency + scoring.default.gamma;
155
+ const hybridScore = (store as any).calculateHybridScore(cosineScore, payload);
156
+ expect(hybridScore).toBeCloseTo(expectedScore, 5);
147
157
  });
148
158
 
149
159
  it('should return score >= 0 even with negative cosine similarity', () => {
150
- const payload: MemoryPayload = { memoryId: 'mem-s1', userId: userId, type: 'factual', createdAt: twoDaysAgo };
151
- const cosineScore = -0.5;
152
- const hybridScore = (store as any).calculateHybridScore(cosineScore, payload);
153
- expect(hybridScore).toBeGreaterThanOrEqual(0);
160
+ const payload: MemoryPayload = { memoryId: 'mem-neg1', userId: userId, type: 'assistant_preference', createdAt: twoDaysAgo };
161
+ const cosineScore = -0.5;
162
+ const hybridScore = (store as any).calculateHybridScore(cosineScore, payload);
163
+ expect(hybridScore).toBeGreaterThanOrEqual(0);
154
164
  });
155
165
 
156
166
  });
@@ -0,0 +1,279 @@
1
+ /// <reference types="jest" />
2
+ import { MemoriesLite } from "../src";
3
+ import { SearchResult } from "../src/types";
4
+ import dotenv from "dotenv";
5
+ import { createTestMemory } from "./init.mem";
6
+
7
+ dotenv.config();
8
+
9
+ jest.setTimeout(60000); // 60s pour les tests avec LLM
10
+
11
+ /**
12
+ * Tests pour le nouveau type de mémoire 'discussion'
13
+ * Permet de mémoriser une discussion avec synthèse (title + summary)
14
+ */
15
+ describe("Memory Discussion - Synthèse de discussions", () => {
16
+ let memory: MemoriesLite;
17
+ let userId: string;
18
+
19
+ //
20
+ // Exemple de discussion à synthétiser
21
+ const discussionMessages = [
22
+ {
23
+ role: "user",
24
+ content: "Tu dois vérifier les autorisations (ou APA) de la FAO de Genève, et ensuite tu dois extraire toutes les adresses et chercher nos immeubles. Merci de me mettre les liens des FAO que tu jugeras utiles."
25
+ },
26
+ {
27
+ role: "assistant",
28
+ content: `Voici un premier lot traité. Dites-moi si vous voulez que je continue sur plus d'avis.
29
+
30
+ Adresses extraites et recherche de nos immeubles
31
+ - Chemin Émile-Bressler 19, 1226 Thônex
32
+ - Immeubles PRSA à proximité (200 m) : aucun trouvé.
33
+ - FAO: Requête M/341685/1 — Démolition d'une villa
34
+ - Chemin du Port 9, 1246 Corsier
35
+ - À vérifier (souhaitez-vous que je cherche nos immeubles autour de cette adresse ?)
36
+ - FAO: Requête M/341714/1 — Démolition
37
+ - Boulevard de Saint‑Georges 46, 1205 Genève (Plainpalais)
38
+ - À vérifier (je peux lancer la recherche de nos immeubles).
39
+ - FAO: Autorisation DD 330818 — Transformation`
40
+ },
41
+ {
42
+ role: "user",
43
+ content: "oui merci pour le premier"
44
+ },
45
+ {
46
+ role: "assistant",
47
+ content: `Parfait. Je poursuis avec ces trois adresses et vous reviens avec:
48
+ - adresses exactes confirmées
49
+ - présence/absence de nos immeubles à 200 m
50
+ - liens FAO utiles
51
+
52
+ Cibles:
53
+ - Chemin du Port 9, 1246 Corsier
54
+ - Boulevard de Saint‑Georges 46, 1205 Genève
55
+ - Chemin du Champ‑des‑Bois 8, 1255 Veyrier`
56
+ },
57
+ {
58
+ role: "user",
59
+ content: "oui"
60
+ },
61
+ {
62
+ role: "assistant",
63
+ content: `Voici la suite.
64
+
65
+ Résultats par adresse (rayon 200 m)
66
+ - Chemin du Port 9, 1246 Corsier — aucun immeuble PRSA trouvé.
67
+ - Boulevard de Saint‑Georges 46, 1205 Genève — aucun immeuble PRSA trouvé.
68
+ - Chemin du Champ‑des‑Bois 8, 1255 Veyrier — aucun immeuble PRSA trouvé.
69
+
70
+ Souhaitez-vous que je:
71
+ - élargisse à 300–500 m,
72
+ - continue l'extraction sur d'autres avis FAO récents (démolitions/transformations/APA),
73
+ - ou cible des communes/quartiers spécifiques ?`
74
+ }
75
+ ];
76
+
77
+ beforeEach(async () => {
78
+ ({ memory, userId } = createTestMemory({}));
79
+ await memory.reset(userId);
80
+ });
81
+
82
+ afterEach(async () => {
83
+ await memory.reset(userId);
84
+ });
85
+
86
+ describe("Capture de discussion", () => {
87
+
88
+ it("should capture a discussion and generate exactly ONE memory with title + summary", async () => {
89
+ //
90
+ // Capturer la discussion avec type 'discussion'
91
+ const result = await memory.capture(discussionMessages, userId, {
92
+ metadata: {
93
+ type: 'discussion',
94
+ discussionId: '7c3e43ac-7621-470d-a22e-82713c3a113e'
95
+ }
96
+ }) as SearchResult;
97
+
98
+ expect(result).toBeDefined();
99
+ expect(result.results).toBeDefined();
100
+ expect(Array.isArray(result.results)).toBe(true);
101
+
102
+ //
103
+ // ✅ Vérifier qu'UNE SEULE mémoire est créée par capture
104
+ expect(result.results.length).toBe(1);
105
+
106
+ //
107
+ // Vérifier que la mémoire contient title et type
108
+ const mem = result.results[0];
109
+ expect(mem.id).toBeDefined();
110
+ expect(mem.type).toBe('discussion');
111
+ expect(mem.memory).toBeDefined(); // summary
112
+ expect(mem.metadata?.title).toBeDefined();
113
+
114
+ console.log('--- Title:', mem.metadata?.title);
115
+ console.log('--- Summary:', mem.memory);
116
+
117
+ //
118
+ // ✅ Vérifier qu'il n'y a bien qu'une seule mémoire stockée
119
+ const allMemories = await memory.getAll(userId, { type: 'discussion' });
120
+ expect(allMemories.results.length).toBe(1);
121
+ });
122
+
123
+ it("should use custom capturePrompt when provided", async () => {
124
+ const customPrompt = `Tu es un expert en synthèse. Génère:
125
+ 1. TITRE: Un titre technique en français (max 8 mots)
126
+ 2. SUMMARY: Résumé technique des actions effectuées (max 50 mots)
127
+
128
+ Discussion:
129
+ `;
130
+
131
+ const result = await memory.capture(discussionMessages, userId, {
132
+ capturePrompt: customPrompt,
133
+ metadata: {
134
+ type: 'discussion',
135
+ discussionId: 'custom-test-id'
136
+ }
137
+ }) as SearchResult;
138
+
139
+ expect(result).toBeDefined();
140
+ expect(result.results.length).toBeGreaterThan(0);
141
+ expect(result.results[0].type).toBe('discussion');
142
+ });
143
+
144
+ it("should retrieve discussion memories by semantic search with title in metadata", async () => {
145
+ //
146
+ // D'abord capturer la discussion
147
+ const captureResult = await memory.capture(discussionMessages, userId, {
148
+ metadata: {
149
+ type: 'discussion',
150
+ discussionId: 'search-test-id'
151
+ }
152
+ }) as SearchResult;
153
+
154
+ const originalTitle = captureResult.results[0].metadata?.title;
155
+ expect(originalTitle).toBeDefined();
156
+
157
+ //
158
+ // Recherche sémantique avec retrieve()
159
+ const searchResult = await memory.retrieve(
160
+ "recherche FAO autorisation immeuble Genève",
161
+ userId,
162
+ { filters: { type: 'discussion' } }
163
+ ) as SearchResult;
164
+
165
+ expect(searchResult).toBeDefined();
166
+ expect(searchResult.results).toBeDefined();
167
+ expect(searchResult.results.length).toBeGreaterThan(0);
168
+
169
+ //
170
+ // ✅ Vérifier que le title est dans metadata
171
+ expect(searchResult.results[0].metadata?.title).toBeDefined();
172
+ expect(searchResult.results[0].metadata?.title).toBe(originalTitle);
173
+ expect(searchResult.results[0].score).toBeDefined();
174
+ expect(searchResult.results[0].type).toBe('discussion');
175
+
176
+ console.log('--- retrieve() title:', searchResult.results[0].metadata?.title);
177
+ });
178
+
179
+ it("should list all discussion memories with title in metadata (getAll)", async () => {
180
+ //
181
+ // Capturer plusieurs discussions
182
+ const capture1 = await memory.capture(discussionMessages, userId, {
183
+ metadata: { type: 'discussion', discussionId: 'disc-1' }
184
+ }) as SearchResult;
185
+
186
+ const capture2 = await memory.capture([
187
+ { role: "user", content: "Comment résilier un bail ?" },
188
+ { role: "assistant", content: "Voici la procédure de résiliation..." }
189
+ ], userId, {
190
+ metadata: { type: 'discussion', discussionId: 'disc-2' }
191
+ }) as SearchResult;
192
+
193
+ //
194
+ // Lister toutes les mémoires discussion avec getAll()
195
+ const allResult = await memory.getAll(userId, { type: 'discussion' }) as SearchResult;
196
+
197
+ expect(allResult).toBeDefined();
198
+ expect(allResult.results.length).toBe(2);
199
+ expect(allResult.results.every(r => r.type === 'discussion')).toBe(true);
200
+
201
+ //
202
+ // ✅ Vérifier que chaque mémoire a un title dans metadata
203
+ expect(allResult.results.every(r => r.metadata?.title !== undefined)).toBe(true);
204
+
205
+ console.log('--- getAll() titles:', allResult.results.map(r => r.metadata?.title));
206
+ });
207
+
208
+ it("should get a single discussion memory with title in metadata (get)", async () => {
209
+ //
210
+ // Capturer
211
+ const captureResult = await memory.capture(discussionMessages, userId, {
212
+ metadata: { type: 'discussion', discussionId: 'get-test' }
213
+ }) as SearchResult;
214
+
215
+ const memoryId = captureResult.results[0].id;
216
+ const originalTitle = captureResult.results[0].metadata?.title;
217
+
218
+ //
219
+ // Récupérer avec get()
220
+ const getResult = await memory.get(memoryId, userId);
221
+
222
+ expect(getResult).not.toBeNull();
223
+ expect(getResult?.type).toBe('discussion');
224
+ expect(getResult?.memory).toBeDefined();
225
+
226
+ //
227
+ // ✅ Vérifier que le title est dans metadata
228
+ expect(getResult?.metadata?.title).toBeDefined();
229
+ expect(getResult?.metadata?.title).toBe(originalTitle);
230
+
231
+ console.log('--- get() title:', getResult?.metadata?.title);
232
+ });
233
+
234
+ it("should delete a discussion memory", async () => {
235
+ //
236
+ // Capturer
237
+ const result = await memory.capture(discussionMessages, userId, {
238
+ metadata: { type: 'discussion', discussionId: 'delete-test' }
239
+ }) as SearchResult;
240
+
241
+ const memoryId = result.results[0].id;
242
+
243
+ //
244
+ // Supprimer
245
+ await memory.delete(memoryId, userId);
246
+
247
+ //
248
+ // Vérifier suppression
249
+ const deleted = await memory.get(memoryId, userId);
250
+ expect(deleted).toBeNull();
251
+ });
252
+ });
253
+
254
+ describe("Scoring discussion", () => {
255
+
256
+ it("should have constant score (beta=1, halfLife=Infinity)", async () => {
257
+ //
258
+ // Capturer une discussion
259
+ await memory.capture(discussionMessages, userId, {
260
+ metadata: { type: 'discussion', discussionId: 'score-test' }
261
+ });
262
+
263
+ //
264
+ // Rechercher immédiatement
265
+ const result1 = await memory.retrieve("FAO Genève", userId, {
266
+ filters: { type: 'discussion' }
267
+ }) as SearchResult;
268
+
269
+ //
270
+ // Le score ne devrait pas dépendre du temps (halfLife=Infinity)
271
+ // Avec alpha=0, beta=1, gamma=0, le score = recency = 1 (constant)
272
+ expect(result1.results.length).toBeGreaterThan(0);
273
+ expect(result1.results[0].score).toBeDefined();
274
+
275
+ console.log('--- Score:', result1.results[0].score);
276
+ });
277
+ });
278
+ });
279
+
@@ -8,7 +8,11 @@ dotenv.config();
8
8
 
9
9
  jest.setTimeout(30000); // Increase timeout to 30 seconds
10
10
 
11
- describe("Memory Updates - Type Preservation", () => {
11
+ /**
12
+ * @deprecated Tests use factual/episodic types that have been removed
13
+ * These tests are skipped - see migration to discussion memory type
14
+ */
15
+ describe.skip("Memory Updates - Type Preservation (DEPRECATED)", () => {
12
16
  let memory: MemoriesLite;
13
17
  let userId: string;
14
18
 
@@ -1,168 +0,0 @@
1
- /// <reference types="jest" />
2
- import { MemoriesLite } from "../src";
3
- import { MemoryItem, SearchResult } from "../src/types";
4
- import dotenv from "dotenv";
5
- import { createTestMemory } from "./init.mem";
6
-
7
- dotenv.config();
8
-
9
- jest.setTimeout(30000); // Increase timeout to 30 seconds
10
-
11
- describe("Memory Class facts regression tests", () => {
12
- let memory: MemoriesLite;
13
- let userId: string;
14
-
15
- beforeEach(async () => {
16
- // Initialize memory via helper
17
- ({ memory, userId } = createTestMemory({customPrompt:"L'utilisateur travail pour une régie immobilière!"}));
18
- // Reset all memories before each test
19
- await memory.reset(userId);
20
- });
21
-
22
- afterEach(async () => {
23
- // Clean up after each test
24
- await memory.reset(userId);
25
- });
26
-
27
- describe("Edge cases for Facts", () => {
28
-
29
-
30
- it("should not add memory: Qui suis-je ?", async () => {
31
- const customFacts = "Je suis Olivier Poulain\nIT et je travaille chez Immeuble SA";
32
- const result = (await memory.capture([
33
- {role:"user", content:"Qui suis-je ?"},
34
- {role:"assistant", content:"Vous êtes Olivier Poulain, Chef de Projets au département IT & Gestion de projet, dans l'équipe IT de Immeuble SA"}],
35
- userId,
36
- {customFacts},
37
- )) as SearchResult;
38
- expect(result).toBeDefined();
39
- expect(result.results).toBeDefined();
40
- expect(result.results.length).toBe(0);
41
- // expect(result.results[0]?.type).toBe("factual");
42
- });
43
- it("episodic: Je veux manger des sushis pour ma pause de midi.", async () => {
44
- const customFacts = "Je suis Olivier Poulain\nIT et je travaille chez Immeuble SA";
45
- const result = (await memory.capture([
46
- {role:"user", content:"J'ai faim, je veux manger des sushis pour ma pause de midi."},
47
- {role:"user", content:"Cherche un restaurant de sushis près de chez moi."}],
48
- userId,
49
- {customFacts},
50
- )) as SearchResult;
51
-
52
- expect(result).toBeDefined();
53
- expect(result.results).toBeDefined();
54
- expect(result.results.length).toBeGreaterThan(1);
55
- expect(result.results[0]?.type).toBe("episodic");
56
- expect(result.results[1]?.type).toBe("episodic");
57
- });
58
-
59
-
60
- it("should add assistant_preference memory", async () => {
61
- const result = (await memory.capture(
62
- "tu dois répondre de manière concise et précise",
63
- userId,
64
- {},
65
- )) as SearchResult;
66
-
67
- expect(result).toBeDefined();
68
- expect(result.results).toBeDefined();
69
- expect(Array.isArray(result.results)).toBe(true);
70
- expect(result.results.length).toBeGreaterThan(0);
71
- expect(result.results[0]?.id).toBeDefined();
72
- expect(result.results[0]?.type).toBe("assistant_preference");
73
- });
74
-
75
- it("business:je cherche le téléphone de mon client Alphonse MAGLOIRE", async () => {
76
- // type?: "factual" | "episodic" | "todo"|"procedural" | "assistant_preference";
77
- // Capture a query that contains a name but is asking for contact information
78
- const result = (await memory.capture(
79
- "je cherche le téléphone de mon client Alphonse MAGLOIRE",
80
- userId,
81
- {},
82
- )) as SearchResult;
83
-
84
- // Verify no memory was created (business query)
85
- expect(result).toBeDefined();
86
- expect(result.results).toBeDefined();
87
- expect(Array.isArray(result.results)).toBe(true);
88
- expect(result.results.length).toBe(1);
89
- const type = result.results[0]?.type;
90
- expect(["procedural","episodic"].includes(type)).toBe(true);
91
- });
92
-
93
- it("business:Le logement de Alphonse MAGLOIRE au 5ème étage est de combien pièces", async () => {
94
- const result = (await memory.capture([
95
- {role:"user", content:"Le logement de Alphonse MAGLOIRE au 5ème étage est de combien pièces.",},
96
- {role:"assitant", content:"Alphonse MAGLOIRE a un logement de 4 pièces au 5ème étage",}],
97
- userId,
98
- {customFacts:"Je suis Olivier Poulain, Je m'occupe de la gérance locataire chez Immeuble SA"},
99
- )) as SearchResult;
100
- expect(result).toBeDefined();
101
- expect(result.results).toBeDefined();
102
- expect(Array.isArray(result.results)).toBe(true);
103
- //
104
- // result can also be empty
105
- if(result.results.length > 0) {
106
- expect(result.results.length).toBe(1);
107
- expect(result.results[0]?.type).toBe("procedural");
108
- }
109
- });
110
-
111
-
112
- it("business task are not factual (2)", async () => {
113
- const result = (await memory.capture([
114
- {role:"user", content:"Quelle est la procédure pour résilier un bail chez Pouet & Compagnie SA ?"}],
115
- userId,
116
- {customFacts:"Je suis Olivier Poulain, Je m'occupe de la gérance locataire chez Immeuble SA"},
117
- )) as SearchResult;
118
-
119
-
120
- expect(result).toBeDefined();
121
- expect(result.results).toBeDefined();
122
- expect(Array.isArray(result.results)).toBe(true);
123
- //
124
- // result can also be empty
125
- if(result.results.length > 0) {
126
- expect(result.results.length).toBe(1);
127
- expect(result.results[0]?.type).toBe("procedural");
128
- }
129
- });
130
-
131
- it("business:Est-ce que Claude RIBUR est à jour avec son loyer ?", async () => {
132
- const result = (await memory.capture([
133
- {role:"user", content:"Est-ce que Claude RIBUR est à jour avec son loyer ?"}],
134
- userId,
135
- {customFacts:"Je suis Olivier Poulain, Je m'occupe de la gérance locataire chez Immeuble SA"},
136
- )) as SearchResult;
137
- expect(result).toBeDefined();
138
- expect(result.results).toBeDefined();
139
- expect(Array.isArray(result.results)).toBe(true);
140
- expect(result.results.length).toBe(1);
141
- expect(result.results[0]?.type).toBe("procedural");
142
-
143
-
144
- });
145
-
146
-
147
- it("should add and remove a single memory", async () => {
148
- const result = (await memory.capture(
149
- "je veux que tu répondes en italien",
150
- userId,
151
- {},
152
- )) as SearchResult;
153
- expect(result.results?.[0]?.id).toBeDefined();
154
- const memoryId = result.results[0]?.id;
155
- await memory.capture(
156
- "je ne veux plus que tu répondes en italien",
157
- userId,
158
- {},
159
- ) as SearchResult;
160
-
161
- const id = await memory.get(memoryId, userId);
162
- expect(id).toBeNull();
163
-
164
- });
165
-
166
-
167
- });
168
- });