File size: 7,898 Bytes
e706de2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
# Code Explanation: simple-agent-with-memory.js

This example extends the simple agent with **persistent memory**, enabling it to remember information across sessions while intelligently avoiding duplicate saves.

## Key Components

### 1. MemoryManager Import
```javascript

import {MemoryManager} from "./memory-manager.js";

```
Custom class for persisting agent memories to JSON files with unified memory storage.

### 2. Initialize Memory Manager
```javascript

const memoryManager = new MemoryManager('./agent-memory.json');

const memorySummary = await memoryManager.getMemorySummary();

```
- Loads existing memories from file
- Generates formatted summary for system prompt
- Handles migration from old memory schemas

### 3. Memory-Aware System Prompt with Reasoning
```javascript

const systemPrompt = `

You are a helpful assistant with long-term memory.



Before calling any function, always follow this reasoning process:



1. **Compare** new user statements against existing memories below.

2. **If the same key and value already exist**, do NOT call saveMemory again.

   - Instead, simply acknowledge the known information.

   - Example: if the user says "My name is Malua" and memory already says "user_name: Malua", reply "Yes, I remember your name is Malua."

3. **If the user provides an updated value** (e.g., "I actually prefer sushi now"), 

   then call saveMemory once to update the value.

4. **Only call saveMemory for genuinely new information.**



When saving new data, call saveMemory with structured fields:

- type: "fact" or "preference"

- key: short descriptive identifier (e.g., "user_name", "favorite_food")

- value: the specific information (e.g., "Malua", "chinua")



Examples:

saveMemory({ type: "fact", key: "user_name", value: "Malua" })

saveMemory({ type: "preference", key: "favorite_food", value: "chinua" })



${memorySummary}

`;

```

**What this does:**
- Includes existing memories in the prompt
- Provides explicit reasoning guidelines to prevent duplicate saves
- Teaches the agent to compare before saving
- Instructs when to update vs. acknowledge existing data

### 4. saveMemory Function
```javascript

const saveMemory = defineChatSessionFunction({

    description: "Save important information to long-term memory (user preferences, facts, personal details)",

    params: {

        type: "object",

        properties: {

            type: {

                type: "string",

                enum: ["fact", "preference"]

            },

            key: { type: "string" },

            value: { type: "string" }

        },

        required: ["type", "key", "value"]

    },

    async handler({ type, key, value }) {

        await memoryManager.addMemory({ type, key, value });

        return `Memory saved: ${key} = ${value}`;

    }

});

```

**What it does:**
- Uses structured key-value format for all memories
- Saves both facts and preferences with the same method
- Automatically handles duplicates (updates if value changes)
- Persists to JSON file
- Returns confirmation message

**Parameter Structure:**
- `type`: Either "fact" or "preference"
- `key`: Short identifier (e.g., "user_name", "favorite_food")
- `value`: The actual information (e.g., "Alex", "pizza")

### 5. Example Conversation
```javascript

const prompt1 = "Hi! My name is Alex and I love pizza.";

const response1 = await session.prompt(prompt1, {functions});

// Agent calls saveMemory twice:

// - saveMemory({ type: "fact", key: "user_name", value: "Alex" })

// - saveMemory({ type: "preference", key: "favorite_food", value: "pizza" })



const prompt2 = "What's my favorite food?";

const response2 = await session.prompt(prompt2, {functions});

// Agent recalls from memory: "Pizza"

```

## How Memory Works

### Flow Diagram
```

Session 1:

User: "My name is Alex and I love pizza"

  ↓

Agent calls: saveMemory({ type: "fact", key: "user_name", value: "Alex" })

Agent calls: saveMemory({ type: "preference", key: "favorite_food", value: "pizza" })

  ↓

Saved to: agent-memory.json



Session 2 (after restart):

1. Load memories from agent-memory.json

2. Add to system prompt

3. Agent sees: "user_name: Alex" and "favorite_food: pizza"

4. Can use this information in responses



Session 3:

User: "My name is Alex"

  ↓

Agent compares: user_name already = "Alex"

  ↓

No function call! Just acknowledges: "Yes, I remember your name is Alex."

```

## The MemoryManager Class

Located in `memory-manager.js`:
```javascript

class MemoryManager {

  async loadMemories()           // Load from JSON (handles schema migration)

  async saveMemories()           // Write to JSON

  async addMemory()              // Unified method for all memory types

  async getMemorySummary()       // Format memories for system prompt

  extractKey()                   // Helper for migration

  extractValue()                 // Helper for migration

}

```

**Benefits:**
- Single unified method for all memory types
- Automatic duplicate detection and prevention
- Automatic value updates when information changes

## Key Concepts

### 1. Structured Memory Format
All memories now use a consistent structure:
```javascript

{

  type: "fact" | "preference",

  key: "user_name",           // Identifier

  value: "Alex",              // The actual data

  source: "user",             // Where it came from

  timestamp: "2025-10-29..."  // When it was saved/updated

}

```

### 2. Intelligent Duplicate Prevention
The agent is trained to:
- **Compare** before saving
- **Skip** if data is identical
- **Update** if value changed
- **Acknowledge** existing memories instead of re-saving

### 3. Persistent State
- Memories survive script restarts
- Stored in JSON file with metadata
- Loaded at startup and injected into prompt

### 4. Memory Integration in System Prompt
Memories are automatically formatted and injected:
```

=== LONG-TERM MEMORY ===



Known Facts:

- user_name: Alex

- location: Paris



User Preferences:

- favorite_food: pizza

- preferred_language: French

```

## Why This Matters

**Without memory:** Agent starts fresh every time, asks same questions repeatedly

**With basic memory:** Agent remembers, but may save duplicates wastefully

**With smart memory:** Agent remembers AND avoids redundant saves by reasoning first

This enables:
- **Personalized responses** based on user history
- **Efficient memory usage** (no duplicate entries)
- **Natural conversations** that feel continuous
- **Stateful agents** that maintain context
- **Automatic updates** when information changes

## Expected Output

**First run:**
```

User: "Hi! My name is Alex and I love pizza."

AI: "Nice to meet you, Alex! I've noted that you love pizza."

[Calls saveMemory twice - new information saved]

```

**Second run (after restart):**
```

User: "What's my favorite food?"

AI: "Your favorite food is pizza! You mentioned that you love it."

[No function calls - recalls from loaded memory]

```

**Third run (duplicate statement):**
```

User: "My name is Alex."

AI: "Yes, I remember your name is Alex!"

[No function call - recognizes duplicate, just acknowledges]

```

**Fourth run (updated information):**
```

User: "I actually prefer sushi now."

AI: "Got it! I've updated your favorite food to sushi."

[Calls saveMemory once - updates existing value]

```

## Reasoning Process

The system prompt explicitly guides the agent through this decision tree:
```

New user statement

    ↓

Compare to existing memories

    ↓

    β”œβ”€β†’ Exact match? β†’ Acknowledge only (no save)

    β”œβ”€β†’ Updated value? β†’ Save to update

    └─→ New information? β†’ Save as new

```

This reasoning-first approach makes the agent more intelligent and efficient with memory operations!