memories-lite 0.99.5 → 0.99.9

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/README.md CHANGED
@@ -1,196 +1,169 @@
1
- # 🧠 Memories-lite
1
+ # memories-lite
2
2
 
3
- > **A lightweight memory layer for AI agents, leveraging LLMs for fact extraction and vector embeddings for retrieval.**
3
+ > Lightweight memory layer for AI agents LLM-based extraction, vector embeddings for retrieval, per-user isolation.
4
4
 
5
- ## 📋 Table of Contents
6
- - [Quick Start](#-quick-start)
7
- - [Installation](#-installation)
8
- - [Basic Usage](#-basic-usage)
9
- - [Key Features](#-key-features)
10
- - [Memory Types](#-memory-types)
11
- - [Use Cases](#-use-cases)
12
- - [Advanced Configuration](#-advanced-configuration)
13
- - [Documentation](#-documentation)
14
- - [Acknowledgements](#-acknowledgements)
5
+ ## Quick Start
15
6
 
16
- ## 🚀 Quick Start
17
-
18
- ```bash
19
- # Install the package
20
- npm install memories-lite
21
-
22
- # Basic usage
7
+ ```typescript
23
8
  import { MemoriesLite } from 'memories-lite';
24
9
 
25
10
  const memory = new MemoriesLite({
26
- llm: {
27
- provider: 'openai',
28
- config: { apiKey: 'YOUR_API_KEY' }
29
- },
30
- embedder: {
31
- provider: 'openai',
32
- config: { apiKey: 'YOUR_API_KEY', model: 'text-embedding-3-small' }
33
- }
11
+ llm: { provider: 'openai', config: { apiKey: 'KEY', model: 'gpt-5-mini' } },
12
+ embedder: { provider: 'openai', config: { apiKey: 'KEY', model: 'text-embedding-3-small', dimension: 768 } },
13
+ vectorStore: { provider: 'lite', config: { dimension: 768, rootPath: './data' } }
34
14
  });
35
15
 
36
- // Add a memory for a user
37
- await memory.capture("I prefer dark chocolate over milk chocolate", "user123");
16
+ const userId = 'user-123';
17
+
18
+ // Capture a discussion → {title, summary}
19
+ await memory.capture(messages, userId, { metadata: { type: 'discussion' } });
38
20
 
39
- // Retrieve relevant memories
40
- const results = await memory.retrieve("What are my food preferences?", "user123");
21
+ // Capture or merge preferences into an existing memory (auto-load by ID)
22
+ await memory.captureOrUpdate(messages, userId, {
23
+ existingMemoryId: 'abc-123', // loads content + title from store
24
+ metadata: { type: 'discussion', applyMode: 'MEM_ALWAYS' }
25
+ });
26
+
27
+ // Retrieve by semantic search
28
+ const results = await memory.retrieve('réponses courtes', userId, { filters: { type: 'discussion' } });
29
+
30
+ // CRUD
31
+ await memory.update(memoryId, 'New content', userId, { title: 'New title' });
32
+ await memory.delete(memoryId, userId);
33
+ const all = await memory.getAll(userId, { type: 'discussion' });
41
34
  ```
42
35
 
43
- ## 🌟 Highlights
36
+ ## Architecture
44
37
 
45
- - **Higher Performance**: Optimized memory operations that run significantly faster than mem0
46
- - **Business-Centric Design**: Simplified API and workflows specifically tailored for business use cases
47
- - **Advanced Hybrid Scoring**: Improved relevance through a custom scoring algorithm that balances vector similarity, recency, and importance
48
- - **Enhanced Security**: One database per user architecture that provides stronger isolation and data protection
49
- - **Streamlined Implementation**: Focused on essential features with minimal dependencies
38
+ ### Instruction mémorisable
50
39
 
51
- ## 📥 Installation
40
+ Une instruction mémorisable est une règle de comportement durable liée à l'utilisateur courant, indiquant comment l'assistant doit se comporter au-delà du cas en cours.
52
41
 
53
- ```bash
54
- npm install memories-lite
55
- # or
56
- yarn add memories-lite
57
- ```
42
+ Exemples :
43
+ - `L'utilisateur souhaite qu'à l'avenir tu le tutoies et que tu répondes toujours en français.`
44
+ - `L'utilisateur utilise Windows 11 avec PowerShell (pas Linux).`
58
45
 
59
- ## 🔍 Basic Usage
46
+ Ce qui n'est **pas** mémorisable : actions ponctuelles ("envoie un email"), données métier, questions procédurales.
60
47
 
61
- ```typescript
62
- import { MemoriesLite } from 'memories-lite';
48
+ ### Two Capture Flows
63
49
 
64
- // Basic configuration
65
- const memory = new MemoriesLite({
66
- llm: {
67
- provider: 'openai',
68
- config: { apiKey: 'YOUR_OPENAI_API_KEY' }
69
- },
70
- embedder: {
71
- provider: 'openai',
72
- config: { apiKey: 'YOUR_OPENAI_API_KEY' }
73
- }
74
- // Vector store defaults to an in-memory store
75
- });
50
+ ```
51
+ Flow 1: capture() Discussion → New Memory
52
+ ─────────────────────────────────────────────
53
+ User clicks "Memorize" on a discussion
54
+ └─> capture(messages, userId, { capturePrompt?, metadata })
55
+ └─> LLM → { title, summary }
56
+ └─> createMemory(summary, embed(title))
57
+
58
+ Flow 2: captureOrUpdate() Discussion → Create or Merge
59
+ ──────────────────────────────────────────────────────────
60
+ Agent tool or explicit user action
61
+ └─> captureOrUpdate(messages, userId, {
62
+ existingMemoryId?, // if provided → auto-load + UPDATE (merge)
63
+ metadata
64
+ })
65
+ ├─ if existingMemoryId:
66
+ │ └─> get(existingMemoryId) → { memory, title }
67
+ │ └─> buildCapturePrompt(memory) → merge prompt
68
+ │ └─> LLM → complete merged set
69
+ │ └─> updateMemory() (preserves title + ID)
70
+ └─ else:
71
+ └─> buildCapturePrompt() → capture prompt
72
+ └─> LLM → { title, summary }
73
+ └─> createMemory()
74
+ ```
76
75
 
77
- // Unique ID for each user
78
- const userId = 'user-123';
76
+ `existingMemoryId` est prioritaire : le contenu et le titre sont toujours chargés depuis le store.
79
77
 
80
- // Add memories
81
- await memory.capture('I love Italian food', userId);
78
+ ### Memory Apply Modes
82
79
 
83
- // Retrieve relevant memories
84
- const results = await memory.retrieve('What foods do I like?', userId);
85
- console.log('Relevant memories:', results.results.map(m => m.memory));
80
+ | Mode | Injection | Use case |
81
+ |------|-----------|----------|
82
+ | `MEM_ALWAYS` | Automatic, every request | User preferences, permanent instructions |
83
+ | `MEM_SMART` | Semantic search match | Discussion syntheses, knowledge patterns |
84
+ | `MEM_MANUAL` | Explicit via `rules[]` | Session-specific rules |
86
85
 
87
- // Update a memory
88
- if (results.results.length > 0) {
89
- await memory.update(results.results[0].id, 'I love Italian and French cuisine', userId);
90
- }
86
+ ### Context Injection Flow
91
87
 
92
- // Delete a memory
93
- if (results.results.length > 0) {
94
- await memory.delete(results.results[0].id, userId);
95
- }
88
+ Memories are injected into the agent's system prompt via `enrichSystemWithMemory()`:
96
89
 
97
- // Get all memories for a user
98
- const allMemories = await memory.getAll(userId, {});
90
+ ```
91
+ enrichSystemWithMemory()
92
+ ├─> getAll(userId, {type: 'discussion'})
93
+ ├─> filter MEM_ALWAYS → globalInstructionsStr
94
+ ├─> filter rules[] → sessionInstructionsStr
95
+ └─> renderContextInjection(profile, global, session, history)
96
+
97
+ Produces:
98
+ <instructions>
99
+ GLOBAL:
100
+ L'utilisateur préfère les réponses courtes et structurées.
101
+ L'utilisateur utilise Windows 11 et souhaite des exemples en PowerShell.
102
+ </instructions>
99
103
  ```
100
104
 
101
- ## 🔑 Key Features
105
+ ### Merge Rules (captureOrUpdate)
102
106
 
103
- - **Memory Capture**: Extract and store relevant information from conversations
104
- - **Contextual Retrieval**: Find memories most relevant to the current query
105
- - **User Isolation**: Each user's memories are stored separately for privacy and security
106
- - **Memory Types**: Support for different types of memories (factual, episodic, etc.)
107
- - **Custom Scoring**: Hybrid scoring system balancing similarity, recency, and importance
107
+ When merging new instructions with existing preferences:
108
108
 
109
- ## 🧩 Memory Types
109
+ | Case | Existing | New discussion | Result |
110
+ |------|----------|---------------|--------|
111
+ | Duplicate | "préfère le français" | "parle-moi en français" | Keep existing |
112
+ | Refinement | "réponses courtes" | "courtes sauf pour les rapports" | Replace with refined |
113
+ | Contradiction | "tutoiement" | "vouvoie-moi" | Replace with new |
114
+ | New | _(nothing)_ | "j'utilise macOS" | Add with date |
110
115
 
111
- Memories-lite supports four main types of memory:
116
+ The LLM returns the **complete merged set** (not a diff). The title is preserved from the existing memory.
112
117
 
113
- 1. **Factual Memory**
114
- - User preferences, traits, and personal information
115
- - Example: "User likes Italian cuisine"
118
+ ### Memory Content Format
116
119
 
117
- 2. **Episodic Memory** ⏱️
118
- - Time-based events and interactions
119
- - Example: "User has a meeting tomorrow at 2pm"
120
+ 3rd person descriptive, grouped by date:
120
121
 
121
- 3. **Semantic Memory** 🧠
122
- - General knowledge and concepts
123
- - Example: "Yoga is beneficial for mental health"
122
+ ```
123
+ **2025-12-15**
124
+ L'utilisateur préfère les réponses courtes et structurées pour les résultats mfiles.
125
+ L'utilisateur souhaite que les formats "en gras" soient supprimés lors de la rédaction d'emails.
126
+ **2025-11-01**
127
+ L'utilisateur utilise Windows 11 et souhaite des exemples en shell.
128
+ ```
124
129
 
125
- 4. **Procedural Memory** 🔄
126
- - Step-by-step processes and workflows
127
- - Example: "Steps to configure the company VPN"
130
+ ## API
128
131
 
129
- ## 💼 Use Cases
132
+ ### `capture(messages, userId, config)`
133
+ Captures a discussion and generates a new memory with `{title, summary}`.
130
134
 
131
- - **Customer Support Bots**: Remember customer preferences and past interactions
132
- - **Personal Assistants**: Build context-aware AI assistants that learn about user preferences
133
- - **Business Applications**: Integrate with enterprise systems to maintain contextual awareness
134
- - **Educational Tools**: Create learning assistants that remember student progress
135
+ ### `captureOrUpdate(messages, userId, config)`
136
+ Captures and creates a new memory, or merges into an existing one if `existingMemoryId` is provided. The existing memory is auto-loaded from the store (content + title preserved).
135
137
 
136
- ## ⚙️ Advanced Configuration
138
+ ### `retrieve(query, userId, config)`
139
+ Semantic search. Returns only `MEM_SMART` memories.
137
140
 
138
- ```typescript
139
- // Custom scoring for different memory types
140
- const customMemory = new MemoriesLite({
141
- llm: {
142
- provider: 'openai',
143
- config: { apiKey: 'YOUR_API_KEY' }
144
- },
145
- embedder: {
146
- provider: 'openai',
147
- config: { apiKey: 'YOUR_API_KEY' }
148
- },
149
- vectorStore: {
150
- provider: 'lite',
151
- config: {
152
- dimension: 1536,
153
- scoring: {
154
- // Prioritize factual memories with long retention
155
- factual: { alpha: 0.7, beta: 0.2, gamma: 0.1, halfLifeDays: 365 },
156
- // Make preferences permanently available
157
- assistant_preference: { alpha: 0.6, beta: 0.0, gamma: 0.4, halfLifeDays: Infinity },
158
- }
159
- }
160
- }
161
- });
162
- ```
141
+ ### `getAll(userId, config)`
142
+ List all memories (all apply modes).
163
143
 
164
- ## 📚 Documentation
144
+ ### `get(memoryId, userId)`
145
+ Get a single memory by ID.
165
146
 
166
- For detailed technical information and implementation details, see:
147
+ ### `update(memoryId, data, userId, metadata?)`
148
+ Update memory content directly (no LLM).
167
149
 
168
- - [TECHNICAL.md](./TECHNICAL.md) - Technical implementation details
169
- - [MEMORIES.md](./MEMORIES.md) - Detailed memory models and concepts
150
+ ### `delete(memoryId, userId)`
151
+ Delete a memory.
170
152
 
171
- ## 🙏 Acknowledgements
153
+ ## Prompts
172
154
 
173
- Forked from the [Mem0](https://github.com/mem0ai/mem0) project ❤️.
155
+ Built-in prompts (customizable via `capturePrompt`):
174
156
 
175
- Inspired by research concepts from:
176
- - **A-MEM**: Agentic Memory for LLM Agents
177
- - **MemoryLLM**: Self-Updatable Large Language Models
178
- - **Reflexion**: Language Agents with Verbal Reinforcement Learning
157
+ - `DEFAULT_DISCUSSION_PROMPT` Synthesis of a discussion into title + summary
158
+ - `DEFAULT_CAPTURE_PROMPT` Extraction of memorizable user instructions (3rd person format)
159
+ - `DEFAULT_MERGE_RULES` Merge extension with `<existing-preferences>` injection
179
160
 
180
- ## 📝 Development Roadmap
161
+ Utilities:
162
+ - `buildCapturePrompt(existingContent?)` — Assembles capture or merge prompt
163
+ - `formatExistingPreferences(memories)` — Formats memories as date-grouped bullet points
181
164
 
182
- - [x] **Semantic Memory Typing & Structuring**: Explicitly tagging and utilizing memory types (factual, episodic, semantic, procedural)
183
- - [x] **Implicit Memory Updates**: Auto-merging memories based on context without explicit ID references
184
- - [x] **Virtual Sessions/Context Grouping**: Group memories related to specific conversation contexts
185
- - [x] **User Isolation**: Separate storage per user for enhanced security and data privacy
186
- - [x] **Memory Type Detection**: LLM-based automatic classification of memory types
187
- - [x] **Core Memory Operations**: Basic CRUD operations with user-specific isolation
188
- - [x] **Memory Decay & Scoring**: Hybrid scoring with recency decay and importance weights
189
- - [ ] **Reflexion Pattern Integration**: Self-correction loops for memory refinement
190
- - [x] **Memory Recency**: Prioritizing memories based on importance and time decay
191
- - [x] **Edge Case Tests**: Complete unit tests for episodic and factual memory edge cases
192
- - [ ] **Middleware Support**: Hooks and middleware for custom processing pipelines
165
+ ## Acknowledgements
193
166
 
194
- ## 📄 License
167
+ Forked from [Mem0](https://github.com/mem0ai/mem0).
195
168
 
196
- MIT
169
+ Inspired by: A-MEM, MemoryLLM, Reflexion.
package/ROADMAP.md ADDED
@@ -0,0 +1,75 @@
1
+ # memories-lite — Roadmap
2
+
3
+ ## Completed
4
+
5
+ - [x] Semantic Memory Typing & Structuring (factual, episodic, procedural)
6
+ - [x] Implicit Memory Updates via LLM
7
+ - [x] Virtual Sessions/Context Grouping
8
+ - [x] User Isolation (per-user vector store)
9
+ - [x] Memory Decay & Scoring (hybrid: cosine similarity + recency + importance)
10
+ - [x] Memory Recency (half-life per type)
11
+ - [x] Discussion Synthesis (`capture()` with title + summary)
12
+ - [x] ApplyMode system (MEM_ALWAYS / MEM_SMART / MEM_MANUAL)
13
+ - [x] `captureOrUpdate()` with merge support
14
+
15
+ ## In Progress
16
+
17
+ - [ ] Tool `saveUserPreference` integration in agentic-server
18
+
19
+ ## Planned
20
+
21
+ - [ ] Reflexion Pattern Integration — self-correction loops for memory refinement
22
+ - [ ] Middleware Support — hooks for custom processing pipelines
23
+
24
+ ## Deprecated (v1 → v2 migration)
25
+
26
+ ### Automatic 4-type extraction (deprecated)
27
+
28
+ The original system automatically classified memories into 4 types via LLM. This produced too many false positives in production. The v2 approach lets the user explicitly control what gets memorized.
29
+
30
+ #### Memory Types (historical reference)
31
+
32
+ 1. **Factual Memory** — User preferences, traits, personal information
33
+ - Example: "Aime la cuisine italienne", "Parle couramment l'espagnol"
34
+
35
+ 2. **Episodic Memory** — Events associated with time/place
36
+ - Example: "A assisté à un concert à Paris en 2023"
37
+
38
+ 3. **Semantic Memory** — Concepts, relations, general knowledge
39
+ - Example: "Le yoga est bénéfique pour la santé mentale"
40
+
41
+ 4. **Procedural Memory** — Processes, action sequences
42
+ - Example: "Sait comment préparer un café latte"
43
+
44
+ #### Why deprecated
45
+
46
+ - Too many false positives in type classification
47
+ - Automatic extraction stored irrelevant information
48
+ - Update/merge was fragile (LLM deciding ADD/UPDATE/DELETE)
49
+ - The v2 approach: user controls when to memorize, format is "L'utilisateur [verbe] [context]"
50
+
51
+ ### Scoring Coefficients (still active for compatibility)
52
+
53
+ | Type | α (similarity) | β (recency) | γ (importance) |
54
+ |------|---------------|-------------|----------------|
55
+ | procedural | 0.30 | 0.40 | 0.05 |
56
+ | episodic | 0.40 | 0.50 | 0.10 |
57
+ | assistant_preference | 0.60 | 0.05 | 0.35 |
58
+ | discussion | 1.00 | 0.00 | 0.00 |
59
+
60
+ ### Half-life per type
61
+
62
+ | Type | HL (days) | λ |
63
+ |------|-----------|---|
64
+ | procedural | 1 | 0.693 |
65
+ | episodic | 7 | 0.099 |
66
+ | assistant_preference | ∞ | 0 |
67
+ | discussion | ∞ | 0 |
68
+
69
+ ## Research References
70
+
71
+ - [Zep: Temporal Knowledge Graph for Agent Memory](https://arxiv.org/abs/2501.13956)
72
+ - [A-MEM: Agentic Memory for LLM Agents](https://arxiv.org/abs/2402.12110)
73
+ - [Reflexion: Language Agents with Verbal Reinforcement Learning](https://arxiv.org/abs/2303.11366)
74
+ - [MemoryLLM: Self-Updatable Large Language Models](https://arxiv.org/abs/2402.04624)
75
+ - [OpenAI Context Engineering for Personalization](https://cookbook.openai.com/examples/agents_sdk/context_personalization)
@@ -31,6 +31,20 @@ export declare class MemoriesLite {
31
31
  * @param config - Options incluant capturePrompt pour personnaliser la synthèse
32
32
  */
33
33
  capture(messages: string | Message[], userId: string, config: AddMemoryOptions): Promise<SearchResult>;
34
+ /**
35
+ * Capture une discussion et crée ou met à jour une mémoire existante (merge)
36
+ *
37
+ * - Sans existingMemoryId → CREATE : extraction d'instructions + nouvelle mémoire
38
+ * - Avec existingMemoryId → UPDATE : charge la mémoire depuis le store, merge les
39
+ * nouvelles instructions avec les existantes, met à jour en conservant le titre
40
+ *
41
+ * existingMemoryId est prioritaire sur existingContent (toujours chargé depuis le store).
42
+ *
43
+ * @param messages - Messages de la discussion ou texte brut
44
+ * @param userId - ID utilisateur
45
+ * @param config - Options (existingMemoryId pour le merge, metadata, capturePrompt override)
46
+ */
47
+ captureOrUpdate(messages: string | Message[], userId: string, config: AddMemoryOptions): Promise<SearchResult>;
34
48
  get(memoryId: string, userId: string): Promise<MemoryItem | null>;
35
49
  retrieve(query: string, userId: string, config: SearchMemoryOptions): Promise<SearchResult>;
36
50
  /**
@@ -193,6 +193,133 @@ class MemoriesLite {
193
193
  results: vectorStoreResult,
194
194
  };
195
195
  }
196
+ /**
197
+ * Capture une discussion et crée ou met à jour une mémoire existante (merge)
198
+ *
199
+ * - Sans existingMemoryId → CREATE : extraction d'instructions + nouvelle mémoire
200
+ * - Avec existingMemoryId → UPDATE : charge la mémoire depuis le store, merge les
201
+ * nouvelles instructions avec les existantes, met à jour en conservant le titre
202
+ *
203
+ * existingMemoryId est prioritaire sur existingContent (toujours chargé depuis le store).
204
+ *
205
+ * @param messages - Messages de la discussion ou texte brut
206
+ * @param userId - ID utilisateur
207
+ * @param config - Options (existingMemoryId pour le merge, metadata, capturePrompt override)
208
+ */
209
+ async captureOrUpdate(messages, userId, config) {
210
+ const { agentId, runId, metadata = {}, filters = {}, capturePrompt, existingMemoryId, existingContent, } = config;
211
+ if (agentId)
212
+ filters.agentId = metadata.agentId = agentId;
213
+ if (runId)
214
+ filters.runId = metadata.runId = runId;
215
+ if (!userId && !filters.agentId && !filters.runId) {
216
+ throw new Error("One of the filters: userId, agentId or runId is required!");
217
+ }
218
+ const parsedMessages = Array.isArray(messages)
219
+ ? messages
220
+ : [{ role: "user", content: messages }];
221
+ const final_parsedMessages = await (0, memory_1.parse_vision_messages)(parsedMessages);
222
+ //
223
+ // existingMemoryId est prioritaire : toujours charger depuis le store pour le contenu et le titre
224
+ let resolvedContent = existingContent;
225
+ let existingTitle;
226
+ if (existingMemoryId) {
227
+ const existing = await this.get(existingMemoryId, userId);
228
+ if (existing) {
229
+ resolvedContent = existing.memory;
230
+ existingTitle = existing.metadata?.title;
231
+ }
232
+ }
233
+ //
234
+ // Construire le prompt : merge si resolvedContent disponible, sinon capture simple
235
+ const effectivePrompt = capturePrompt || (0, prompts_1.buildCapturePrompt)(resolvedContent);
236
+ const $t = this.$t;
237
+ const vectorStore = await this.getVectorStore(userId);
238
+ //
239
+ // Formater les messages pour la synthèse
240
+ const formattedMessages = final_parsedMessages
241
+ .filter((m) => typeof m.content === 'string')
242
+ .map((m) => `**${m.role.toUpperCase()}**: ${$t(m.content)}`)
243
+ .join("\n\n");
244
+ //
245
+ // Générer la synthèse via LLM
246
+ const [systemPrompt, userPrompt] = (0, prompts_1.getDiscussionSynthesisMessages)(formattedMessages, effectivePrompt);
247
+ const response = await this.llm.generateResponse([
248
+ { role: "system", content: systemPrompt },
249
+ { role: "user", content: userPrompt },
250
+ ], { ...(0, zod_1.zodResponseFormat)(prompts_1.DiscussionSynthesisSchema, "DiscussionSynthesis") }, [], false);
251
+ //
252
+ // Parser la réponse
253
+ const parsedResponse = (res) => {
254
+ try {
255
+ if (typeof res === 'object')
256
+ return res;
257
+ const cleanResponse = (0, prompts_1.removeCodeBlocks)(res);
258
+ return JSON.parse(cleanResponse);
259
+ }
260
+ catch (e) {
261
+ console.error("Failed to parse synthesis from LLM response:", res, e);
262
+ return { title: "Sans titre", summary: "" };
263
+ }
264
+ };
265
+ const { title: llmTitle, summary } = parsedResponse(response);
266
+ //
267
+ // En mode merge, conserver le titre existant (chargé depuis le store ou fourni par metadata)
268
+ const title = (existingMemoryId && (existingTitle || metadata?.title))
269
+ ? (existingTitle || metadata.title)
270
+ : llmTitle;
271
+ //
272
+ // Nettoyage du summary : trim + lignes vides
273
+ // L'idempotence est assurée par le prompt (règles d'extraction + merge)
274
+ const filteredSummary = summary
275
+ .split("\n")
276
+ .map((l) => l.trim())
277
+ .filter((l) => l.length > 0)
278
+ .join("\n");
279
+ if (!filteredSummary) {
280
+ console.warn("-- ⚠️ Empty summary from LLM, skipping memory creation/update");
281
+ return { results: [] };
282
+ }
283
+ //
284
+ // Créer l'embedding sur le title
285
+ const embedding = await this.embedder.embed(title);
286
+ //
287
+ // Préparer les métadonnées
288
+ const memoryType = metadata.type || 'discussion';
289
+ const applyMode = metadata.applyMode || types_1.DEFAULT_MEMORY_APPLY_MODE;
290
+ const memoryMetadata = {
291
+ ...metadata,
292
+ title,
293
+ type: memoryType,
294
+ applyMode,
295
+ userId,
296
+ };
297
+ //
298
+ // UPDATE si existingMemoryId fourni, sinon CREATE
299
+ if (existingMemoryId) {
300
+ await this.updateMemory(existingMemoryId, filteredSummary, { [filteredSummary]: embedding }, memoryMetadata, userId);
301
+ return {
302
+ results: [{
303
+ id: existingMemoryId,
304
+ memory: filteredSummary,
305
+ type: memoryType,
306
+ metadata: { title, event: "UPDATE" },
307
+ }],
308
+ };
309
+ }
310
+ //
311
+ // CREATE nouvelle mémoire
312
+ const memoryId = await this.createMemory(filteredSummary, { [filteredSummary]: embedding }, memoryMetadata, userId);
313
+ console.log(`-- 🧠 Memory created: "${title}" (${memoryType})`);
314
+ return {
315
+ results: [{
316
+ id: memoryId,
317
+ memory: filteredSummary,
318
+ type: memoryType,
319
+ metadata: { title, event: "ADD" },
320
+ }],
321
+ };
322
+ }
196
323
  async get(memoryId, userId) {
197
324
  const vectorStore = await this.getVectorStore(userId);
198
325
  const memory = await vectorStore.get(memoryId);
@@ -9,6 +9,8 @@ export interface AddMemoryOptions extends Entity {
9
9
  metadata?: Record<string, any>;
10
10
  filters?: SearchFilters;
11
11
  capturePrompt?: string;
12
+ existingMemoryId?: string;
13
+ existingContent?: string;
12
14
  }
13
15
  export interface SearchMemoryOptions extends Entity {
14
16
  limit?: number;