@evermind-ai/openclaw-plugin 1.1.0
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 +400 -0
- package/README.zh.md +400 -0
- package/index.js +397 -0
- package/openclaw.plugin.json +50 -0
- package/package.json +40 -0
- package/src/assembler.js +96 -0
- package/src/compaction.js +85 -0
- package/src/config.js +14 -0
- package/src/context-engine.js +283 -0
- package/src/formatter.js +152 -0
- package/src/http-client.js +46 -0
- package/src/lifecycle.js +65 -0
- package/src/memory-api.js +77 -0
- package/src/message-utils.js +163 -0
- package/src/subagent.js +116 -0
- package/src/types.js +107 -0
package/README.md
ADDED
|
@@ -0,0 +1,400 @@
|
|
|
1
|
+
# EverMemOS ContextEngine Plugin for OpenClaw
|
|
2
|
+
|
|
3
|
+
Full-lifecycle memory management for **OpenClaw 3.8+** via [EverMemOS](https://github.com/EverMind-AI/EverMemOS).
|
|
4
|
+
|
|
5
|
+
> **Built for OpenClaw 3.8+ ContextEngine API** - Leverages the latest ContextEngine lifecycle hooks for intelligent memory management.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
- **Bootstrap**: Backend health check on plugin load
|
|
12
|
+
- **Assemble**: Query-aware context retrieval before each agent turn
|
|
13
|
+
- **AfterTurn**: Timely memory extraction after each turn (not just session end)
|
|
14
|
+
- **Compact**: Session compaction participation for context window optimization
|
|
15
|
+
- **Boundary Detection**: Smart memory extraction via EverMemOS's boundary detection algorithm
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Quick Start
|
|
20
|
+
|
|
21
|
+
### Prerequisites
|
|
22
|
+
|
|
23
|
+
| Requirement | Version | Notes |
|
|
24
|
+
|-------------|---------|-------|
|
|
25
|
+
| **Node.js** | 18+ | For the plugin |
|
|
26
|
+
| **Python** | 3.10+ | For EverMemOS backend |
|
|
27
|
+
| **Docker** | 20.10+ | For infrastructure services |
|
|
28
|
+
| **OpenClaw** | 3.8+ | With ContextEngine support |
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## Step 1: Install EverMemOS Backend
|
|
33
|
+
|
|
34
|
+
### Clone and Setup
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
# Clone EverMemOS repository
|
|
38
|
+
git clone https://github.com/EverMind-AI/EverMemOS.git
|
|
39
|
+
cd EverMemOS
|
|
40
|
+
|
|
41
|
+
# Start Docker services (MongoDB, Elasticsearch, Milvus, Redis)
|
|
42
|
+
docker compose up -d
|
|
43
|
+
|
|
44
|
+
# Install uv package manager
|
|
45
|
+
curl -LsSf https://astral.sh/uv/install.sh | sh
|
|
46
|
+
|
|
47
|
+
# Install Python dependencies
|
|
48
|
+
uv sync
|
|
49
|
+
|
|
50
|
+
# Configure API keys
|
|
51
|
+
cp env.template .env
|
|
52
|
+
# Edit .env and set your LLM_API_KEY and VECTORIZE_API_KEY
|
|
53
|
+
|
|
54
|
+
# Start the backend server (default: http://localhost:1995)
|
|
55
|
+
uv run python src/run.py
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Verify Backend
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
curl http://localhost:1995/health
|
|
62
|
+
# Expected response: {"status": "healthy", ...}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
> **For detailed EverMemOS setup**, see the [Official Setup Guide](https://github.com/EverMind-AI/EverMemOS/blob/main/docs/installation/SETUP.md)
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## Step 2: Install the Plugin
|
|
70
|
+
|
|
71
|
+
### Option A: Local Development (Recommended)
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
# Clone this repository
|
|
75
|
+
git clone https://github.com/EverMind-AI/evermemos-openclaw-plugin.git
|
|
76
|
+
cd evermemos-openclaw-plugin
|
|
77
|
+
|
|
78
|
+
# Install dependencies
|
|
79
|
+
npm install
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Option B: Via npm
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
npm install @evermind-ai/openclaw-plugin
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## Step 3: Configure OpenClaw
|
|
91
|
+
|
|
92
|
+
Edit `~/.openclaw/openclaw.json`:
|
|
93
|
+
|
|
94
|
+
### 3.1 Add Plugin Path
|
|
95
|
+
|
|
96
|
+
```json
|
|
97
|
+
{
|
|
98
|
+
"plugins": {
|
|
99
|
+
"load": {
|
|
100
|
+
"paths": [
|
|
101
|
+
"/path/to/openclaw/extensions/feishu",
|
|
102
|
+
"/path/to/openclaw/extensions/memory-openviking",
|
|
103
|
+
"/Users/admin/EverMind/evermemos-openclaw-plugin" // Add this line
|
|
104
|
+
]
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### 3.2 Enable the Plugin
|
|
111
|
+
|
|
112
|
+
```json
|
|
113
|
+
{
|
|
114
|
+
"plugins": {
|
|
115
|
+
"allow": [
|
|
116
|
+
"memory-openviking",
|
|
117
|
+
"feishu",
|
|
118
|
+
"mem9",
|
|
119
|
+
"evermemos-openclaw-plugin" // Add this line
|
|
120
|
+
]
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### 3.3 Set ContextEngine Slot (OpenClaw 3.8+)
|
|
126
|
+
|
|
127
|
+
```json
|
|
128
|
+
{
|
|
129
|
+
"plugins": {
|
|
130
|
+
"slots": {
|
|
131
|
+
"memory": "none",
|
|
132
|
+
"contextEngine": "evermemos-openclaw-plugin" // Use EverMemOS ContextEngine
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### 3.4 Add Plugin Configuration
|
|
139
|
+
|
|
140
|
+
```json
|
|
141
|
+
{
|
|
142
|
+
"plugins": {
|
|
143
|
+
"entries": {
|
|
144
|
+
"evermemos-openclaw-plugin": {
|
|
145
|
+
"enabled": true,
|
|
146
|
+
"config": {
|
|
147
|
+
"baseUrl": "http://localhost:1995",
|
|
148
|
+
"userId": "evermemos-user",
|
|
149
|
+
"groupId": "evermemos-group",
|
|
150
|
+
"topK": 5,
|
|
151
|
+
"memoryTypes": ["episodic_memory", "profile", "agent_skill", "agent_case"],
|
|
152
|
+
"retrieveMethod": "hybrid"
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
## Step 4: Restart OpenClaw
|
|
163
|
+
|
|
164
|
+
```bash
|
|
165
|
+
openclaw gateway restart
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## Step 5: Verify Installation
|
|
171
|
+
|
|
172
|
+
Check the OpenClaw logs for successful plugin loading:
|
|
173
|
+
|
|
174
|
+
```
|
|
175
|
+
[evermemos] Registering EverMemOS ContextEngine plugin
|
|
176
|
+
[evermemos] bootstrap: session=xxx, key=xxx
|
|
177
|
+
[evermemos] bootstrap: backend healthy, status=ok
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
## Testing
|
|
183
|
+
|
|
184
|
+
### Test Memory Storage
|
|
185
|
+
|
|
186
|
+
Send a message to your agent:
|
|
187
|
+
```
|
|
188
|
+
记住:我最喜欢的颜色是蓝色
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### Test Memory Retrieval
|
|
192
|
+
|
|
193
|
+
Later in the conversation, ask:
|
|
194
|
+
```
|
|
195
|
+
我最喜欢什么颜色?
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
The agent should recall the information from EverMemOS.
|
|
199
|
+
|
|
200
|
+
---
|
|
201
|
+
|
|
202
|
+
## Configuration
|
|
203
|
+
|
|
204
|
+
| Parameter | Type | Default | Description |
|
|
205
|
+
|-----------|------|---------|-------------|
|
|
206
|
+
| `baseUrl` | string | `http://localhost:1995` | EverMemOS server URL |
|
|
207
|
+
| `userId` | string | `evermemos-user` | User identity for memory ownership |
|
|
208
|
+
| `groupId` | string | `evermemos-group` | Group ID for shared memory |
|
|
209
|
+
| `topK` | integer | `5` | Max memory entries to retrieve |
|
|
210
|
+
| `memoryTypes` | string[] | See below | Memory types to search |
|
|
211
|
+
| `retrieveMethod` | string | `hybrid` | Retrieval strategy |
|
|
212
|
+
|
|
213
|
+
### Memory Types
|
|
214
|
+
|
|
215
|
+
| Value | Description |
|
|
216
|
+
|-------|-------------|
|
|
217
|
+
| `episodic_memory` | Past conversation episodes |
|
|
218
|
+
| `profile` | User profile and preferences |
|
|
219
|
+
| `agent_case` | Similar historical cases |
|
|
220
|
+
| `agent_skill` | Agent skill knowledge |
|
|
221
|
+
|
|
222
|
+
### Retrieval Strategies
|
|
223
|
+
|
|
224
|
+
| Value | Description |
|
|
225
|
+
|-------|-------------|
|
|
226
|
+
| `keyword` | Full-text keyword search |
|
|
227
|
+
| `vector` | Semantic vector search |
|
|
228
|
+
| `hybrid` | Keyword + vector fusion |
|
|
229
|
+
| `rrf` | Reciprocal Rank Fusion |
|
|
230
|
+
| `agentic` | Agent-driven adaptive retrieval |
|
|
231
|
+
|
|
232
|
+
---
|
|
233
|
+
|
|
234
|
+
## Architecture
|
|
235
|
+
|
|
236
|
+
```
|
|
237
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
238
|
+
│ OpenClaw Core │
|
|
239
|
+
│ ┌─────────────┐ ┌──────────────┐ ┌─────────────────────────┐ │
|
|
240
|
+
│ │ Message │ │ Session │ │ Token Budget Mgmt │ │
|
|
241
|
+
│ │ Flow │ │ Management │ │ (Compaction) │ │
|
|
242
|
+
│ └──────┬──────┘ └──────┬───────┘ └──────────┬──────────────┘ │
|
|
243
|
+
└─────────┼────────────────┼─────────────────────┼────────────────┘
|
|
244
|
+
│ │ │
|
|
245
|
+
▼ ▼ ▼
|
|
246
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
247
|
+
│ EverMemOS ContextEngine │
|
|
248
|
+
│ ┌─────────┐ ┌─────────┐ ┌──────────┐ ┌──────────────────┐ │
|
|
249
|
+
│ │bootstrap│ │ ingest │ │afterTurn │ │ assemble │ │
|
|
250
|
+
│ └────┬────┘ └────┬────┘ └────┬─────┘ └────────┬─────────┘ │
|
|
251
|
+
└───────┼─────────────┼─────────────┼─────────────────┼─────────────┘
|
|
252
|
+
│ │ │ │
|
|
253
|
+
▼ ▼ ▼ ▼
|
|
254
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
255
|
+
│ EverMemOS Backend │
|
|
256
|
+
│ http://localhost:1995 │
|
|
257
|
+
│ │
|
|
258
|
+
│ • Boundary Detection • Memory Extraction • Vector Search │
|
|
259
|
+
│ • Profile Building • Clustering • Foresight │
|
|
260
|
+
└─────────────────────────────────────────────────────────────────┘
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
---
|
|
264
|
+
|
|
265
|
+
## OpenClaw 3.8+ ContextEngine API
|
|
266
|
+
|
|
267
|
+
This plugin leverages OpenClaw 3.8's **ContextEngine API** for fine-grained lifecycle control:
|
|
268
|
+
|
|
269
|
+
| Lifecycle Hook | When Called | What Plugin Does |
|
|
270
|
+
|----------------|-------------|------------------|
|
|
271
|
+
| `bootstrap()` | Session starts | Health check, initialize state |
|
|
272
|
+
| `assemble()` | Before each agent turn | Retrieve relevant memories, inject as context |
|
|
273
|
+
| `afterTurn()` | After each agent turn | Save new messages to EverMemOS |
|
|
274
|
+
| `compact()` | When token budget exceeded | Evaluate compaction needs |
|
|
275
|
+
| `dispose()` | Session ends | Clean up session state |
|
|
276
|
+
|
|
277
|
+
### Difference from Legacy Memory Plugins
|
|
278
|
+
|
|
279
|
+
| Legacy Memory Hook | ContextEngine API |
|
|
280
|
+
|--------------------|-------------------|
|
|
281
|
+
| Simple storage/retrieval | Full lifecycle management |
|
|
282
|
+
| Automatic timing | Controlled timing |
|
|
283
|
+
| Limited context control | Query-aware assembly |
|
|
284
|
+
|
|
285
|
+
---
|
|
286
|
+
|
|
287
|
+
## Lifecycle Flow
|
|
288
|
+
|
|
289
|
+
```
|
|
290
|
+
┌──────────────┐
|
|
291
|
+
│ bootstrap() │ → Health check, initialize session state
|
|
292
|
+
└──────┬───────┘
|
|
293
|
+
│
|
|
294
|
+
▼
|
|
295
|
+
┌──────────────┐ ┌──────────────────┐
|
|
296
|
+
│ assemble() │ ── │ Memory Search │ → Inject context as system message
|
|
297
|
+
│ (each turn) │ │ GET /memories/ │
|
|
298
|
+
└──────┬───────┘ │ search │
|
|
299
|
+
│ └──────────────────┘
|
|
300
|
+
▼
|
|
301
|
+
┌──────────────────┐
|
|
302
|
+
│ [Agent Turn] │
|
|
303
|
+
└──────┬───────────┘
|
|
304
|
+
│
|
|
305
|
+
▼
|
|
306
|
+
┌──────────────┐ ┌──────────────────┐
|
|
307
|
+
│ afterTurn() │ ── │ Save Memories │ → POST /memories
|
|
308
|
+
│ (each turn) │ │ Boundary Detect │
|
|
309
|
+
└──────┬───────┘ └──────────────────┘
|
|
310
|
+
│
|
|
311
|
+
▼
|
|
312
|
+
┌──────────────┐
|
|
313
|
+
│ compact() │ → Evaluate if compaction needed
|
|
314
|
+
└──────────────┘
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
---
|
|
318
|
+
|
|
319
|
+
## Troubleshooting
|
|
320
|
+
|
|
321
|
+
### Plugin not loading
|
|
322
|
+
|
|
323
|
+
**Symptom**: Plugin not showing in OpenClaw logs
|
|
324
|
+
|
|
325
|
+
**Solution**:
|
|
326
|
+
1. Check `plugins.allow` contains `"evermemos-openclaw-plugin"`
|
|
327
|
+
2. Verify `plugins.load.paths` contains the correct plugin directory
|
|
328
|
+
3. Check `plugins.entries.evermemos-openclaw-plugin.enabled` is `true`
|
|
329
|
+
|
|
330
|
+
### Backend connection failed
|
|
331
|
+
|
|
332
|
+
**Symptom**: `bootstrap: backend unhealthy` or timeout errors
|
|
333
|
+
|
|
334
|
+
**Solution**:
|
|
335
|
+
1. Verify EverMemOS backend is running: `curl http://localhost:1995/health`
|
|
336
|
+
2. Check `baseUrl` configuration matches backend URL
|
|
337
|
+
3. Check firewall/network settings
|
|
338
|
+
|
|
339
|
+
### Memories not being saved
|
|
340
|
+
|
|
341
|
+
**Symptom**: No memory extraction in backend logs
|
|
342
|
+
|
|
343
|
+
**Solution**:
|
|
344
|
+
1. Verify `plugins.slots.contextEngine` is set to `"evermemos-openclaw-plugin"`
|
|
345
|
+
2. Send more messages - EverMemOS uses boundary detection and needs sufficient context
|
|
346
|
+
3. Check backend logs for `[Boundary Detection]` messages
|
|
347
|
+
|
|
348
|
+
### Memories not being retrieved
|
|
349
|
+
|
|
350
|
+
**Symptom**: Agent doesn't recall previous information
|
|
351
|
+
|
|
352
|
+
**Solution**:
|
|
353
|
+
1. Verify memories were extracted (check backend logs for "Successfully extracted MemCell")
|
|
354
|
+
2. Check query length is ≥ 3 characters
|
|
355
|
+
3. Increase `topK` value to retrieve more memories
|
|
356
|
+
4. Try different `retrieveMethod` (e.g., `hybrid` or `agentic`)
|
|
357
|
+
|
|
358
|
+
### Vector service errors
|
|
359
|
+
|
|
360
|
+
**Symptom**: `VllmVectorizeService API error: 502`
|
|
361
|
+
|
|
362
|
+
**Solution**: This is normal - EverMemOS automatically falls back to alternative embedding services. Memory extraction continues working.
|
|
363
|
+
|
|
364
|
+
---
|
|
365
|
+
|
|
366
|
+
## Project Structure
|
|
367
|
+
|
|
368
|
+
```
|
|
369
|
+
├── index.js # ContextEngine factory & main entry
|
|
370
|
+
├── package.json
|
|
371
|
+
├── openclaw.plugin.json # Plugin metadata (kind: context-engine)
|
|
372
|
+
├── README.md # English documentation
|
|
373
|
+
├── README.zh.md # Chinese documentation
|
|
374
|
+
└── src/
|
|
375
|
+
├── config.js # Configuration parsing
|
|
376
|
+
├── memory-api.js # EverMemOS REST API client
|
|
377
|
+
├── formatter.js # Memory response parsing & formatting
|
|
378
|
+
├── message-utils.js # Message collection & format conversion
|
|
379
|
+
├── http-client.js # HTTP client with timeout & retry
|
|
380
|
+
├── types.js # JSDoc type definitions
|
|
381
|
+
├── assembler.js # Query-aware context assembly
|
|
382
|
+
├── lifecycle.js # Turn-level ingestion hooks
|
|
383
|
+
├── compaction.js # Compaction evaluation logic
|
|
384
|
+
├── subagent.js # Subagent lifecycle tracking
|
|
385
|
+
└── context-engine.js # Core ContextEngine implementation
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
---
|
|
389
|
+
|
|
390
|
+
## Links
|
|
391
|
+
|
|
392
|
+
- [EverMemOS](https://github.com/EverMind-AI/EverMemOS) - Backend memory system
|
|
393
|
+
- [OpenClaw](https://github.com/openclaw-org/openclaw) - Agent framework
|
|
394
|
+
- [中文文档](README.zh.md) - Chinese documentation
|
|
395
|
+
|
|
396
|
+
---
|
|
397
|
+
|
|
398
|
+
## License
|
|
399
|
+
|
|
400
|
+
Apache-2.0
|