Skip to content

Commit 51b60c7

Browse files
committed
chore: update OpenClaw Plugin to version 1.5.1 and rename references from EverMemOS to EverOS
1 parent 3739a2c commit 51b60c7

15 files changed

Lines changed: 124 additions & 517 deletions

examples/openclaw-plugin/README.md

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
Persistent memory for **OpenClaw** through normal conversation.
44

5-
This plugin keeps the current OpenClaw `context-engine` architecture and connects it to a self-hosted EverOS backend powered by [EverMemOS](https://github.com/EverMind-AI/EverMemOS).
5+
This plugin keeps the current OpenClaw `context-engine` architecture and connects it to a self-hosted EverOS backend powered by [EverOS](https://github.com/EverMind-AI/EverOS).
66

77
## What it does
88

@@ -64,8 +64,8 @@ curl http://localhost:1995/health
6464
If you have not started the EverOS backend yet:
6565

6666
```bash
67-
git clone https://github.com/EverMind-AI/EverMemOS.git
68-
cd EverMemOS
67+
git clone https://github.com/EverMind-AI/EverOS.git
68+
cd EverOS
6969
docker compose up -d
7070
curl -LsSf https://astral.sh/uv/install.sh | sh
7171
uv sync
@@ -111,7 +111,7 @@ Expected config shape:
111111
"userId": "everos-user",
112112
"groupId": "everos-group",
113113
"topK": 5,
114-
"memoryTypes": ["episodic_memory", "profile", "agent_skill", "agent_case"],
114+
"memoryTypes": ["episodic_memory"],
115115
"retrieveMethod": "hybrid"
116116
}
117117
}
@@ -128,7 +128,7 @@ Expected config shape:
128128
| `userId` | `everos-user` | Memory owner identity |
129129
| `groupId` | `everos-group` | Shared memory namespace |
130130
| `topK` | `5` | Max retrieved entries |
131-
| `memoryTypes` | `["episodic_memory", "profile", "agent_skill", "agent_case"]` | Memory types to search |
131+
| `memoryTypes` | `["episodic_memory"]` | Memory types to search |
132132
| `retrieveMethod` | `hybrid` | Retrieval mode |
133133

134134
## Manual install
@@ -152,12 +152,11 @@ everos-install
152152

153153
- `index.js`: plugin entry point (register)
154154
- `src/engine.js`: ContextEngine lifecycle hooks
155-
- `src/convert.js`: OpenClaw message to EverMemOS format conversion
155+
- `src/convert.js`: OpenClaw message to EverOS format conversion
156156
- `src/api.js`: EverOS backend REST client
157157
- `src/messages.js`: message normalization and turn collection
158158
- `src/prompt.js`: memory search response parsing and prompt building
159-
- `src/subagent-assembler.js`: subagent context assembly
160-
- `src/subagent-tracker.js`: subagent lifecycle tracking
159+
- `src/subagent-assembler.js`: memory context assembly
161160
- `bin/install.js`: installer and config bootstrap
162161
- `openclaw.plugin.json`: plugin metadata and config schema
163162

examples/openclaw-plugin/README.zh.md

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
通过自然语言对话为 **OpenClaw / 龙虾** 提供持久记忆能力。
44

5-
这个插件保留当前 OpenClaw 的 `context-engine` 架构,并连接到自托管的 EverOS backend。其后端能力由 [EverMemOS](https://github.com/EverMind-AI/EverMemOS) 提供。
5+
这个插件保留当前 OpenClaw 的 `context-engine` 架构,并连接到自托管的 EverOS backend。其后端能力由 [EverOS](https://github.com/EverMind-AI/EverOS) 提供。
66

77
## 它能做什么
88

@@ -64,8 +64,8 @@ curl http://localhost:1995/health
6464
如果你还没有启动 EverOS backend:
6565

6666
```bash
67-
git clone https://github.com/EverMind-AI/EverMemOS.git
68-
cd EverMemOS
67+
git clone https://github.com/EverMind-AI/EverOS.git
68+
cd EverOS
6969
docker compose up -d
7070
curl -LsSf https://astral.sh/uv/install.sh | sh
7171
uv sync
@@ -111,7 +111,7 @@ uv run python src/run.py
111111
"userId": "everos-user",
112112
"groupId": "everos-group",
113113
"topK": 5,
114-
"memoryTypes": ["episodic_memory", "profile", "agent_skill", "agent_case"],
114+
"memoryTypes": ["episodic_memory"],
115115
"retrieveMethod": "hybrid"
116116
}
117117
}
@@ -129,7 +129,7 @@ uv run python src/run.py
129129
| `userId` | `everos-user` | 记忆归属的用户标识 |
130130
| `groupId` | `everos-group` | 共享记忆命名空间 |
131131
| `topK` | `5` | 最多检索条目数 |
132-
| `memoryTypes` | `["episodic_memory", "profile", "agent_skill", "agent_case"]` | 要搜索的记忆类型 |
132+
| `memoryTypes` | `["episodic_memory"]` | 要搜索的记忆类型 |
133133
| `retrieveMethod` | `hybrid` | 检索模式 |
134134

135135

@@ -156,12 +156,11 @@ everos-install
156156

157157
- `index.js`:插件入口(注册)
158158
- `src/engine.js`:ContextEngine 生命周期实现
159-
- `src/convert.js`:OpenClaw 消息转 EverMemOS 格式
159+
- `src/convert.js`:OpenClaw 消息转 EverOS 格式
160160
- `src/api.js`:EverOS backend REST API 客户端
161161
- `src/messages.js`:消息归一化与轮次收集
162162
- `src/prompt.js`:记忆搜索结果解析与 prompt 构建
163-
- `src/subagent-assembler.js`:子 agent 上下文组装
164-
- `src/subagent-tracker.js`:子 agent 生命周期追踪
163+
- `src/subagent-assembler.js`:记忆上下文组装
165164
- `bin/install.js`:安装器与配置引导
166165
- `openclaw.plugin.json`:插件元数据与配置结构
167166

examples/openclaw-plugin/SKILL.md

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
name: evermind-ai-everos
3-
version: 1.4.0
3+
version: 1.5.1
44
description: |
55
Install and configure EverOS for OpenClaw natural-language memory.
66
@@ -13,7 +13,6 @@ description: |
1313
author: EverMind
1414
keywords:
1515
- everos
16-
- evermemos
1716
- context engine
1817
- persistent memory
1918
- openclaw
@@ -127,8 +126,8 @@ If it is not healthy, tell the user plainly:
127126
If the user asks how to start the backend, give the shortest useful path:
128127

129128
```bash
130-
git clone https://github.com/EverMind-AI/EverMemOS.git
131-
cd EverMemOS
129+
git clone https://github.com/EverMind-AI/EverOS.git
130+
cd EverOS
132131
docker compose up -d
133132
curl -LsSf https://astral.sh/uv/install.sh | sh
134133
uv sync
@@ -182,7 +181,7 @@ Expected config shape:
182181
"userId": "everos-user",
183182
"groupId": "everos-group",
184183
"topK": 5,
185-
"memoryTypes": ["episodic_memory", "profile", "agent_skill", "agent_case"],
184+
"memoryTypes": ["episodic_memory"],
186185
"retrieveMethod": "hybrid"
187186
}
188187
}
@@ -197,7 +196,7 @@ Merge-safe patch:
197196
jq '
198197
.plugins = (.plugins // {}) |
199198
.plugins.load = (.plugins.load // {}) |
200-
.plugins.load.paths = ((.plugins.load.paths // []) + ["/path/to/evermemos-openclaw-plugin"] | unique) |
199+
.plugins.load.paths = ((.plugins.load.paths // []) + ["/path/to/everos-openclaw-plugin"] | unique) |
201200
.plugins.allow = ((.plugins.allow // []) + ["evermind-ai-everos"] | unique) |
202201
.plugins.slots = (.plugins.slots // {}) |
203202
.plugins.slots.memory = "none" |
@@ -210,7 +209,7 @@ jq '
210209
"userId": "everos-user",
211210
"groupId": "everos-group",
212211
"topK": 5,
213-
"memoryTypes": ["episodic_memory", "profile", "agent_skill", "agent_case"],
212+
"memoryTypes": ["episodic_memory"],
214213
"retrieveMethod": "hybrid"
215214
}
216215
)
@@ -290,7 +289,7 @@ OpenClaw config file:
290289
291290
- Back up `~/.openclaw/openclaw.json`
292291
- Back up the EverOS backend data directory or database
293-
- Back up the EverMemOS `.env` and deployment configuration
292+
- Back up the EverOS `.env` and deployment configuration
294293
```
295294

296295
---

examples/openclaw-plugin/bin/install.js

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ const DEFAULT_CONFIG = {
2424
userId: "everos-user",
2525
groupId: "everos-group",
2626
topK: 5,
27-
memoryTypes: ["episodic_memory", "profile", "agent_skill", "agent_case"],
27+
memoryTypes: ["episodic_memory"],
2828
retrieveMethod: "hybrid",
2929
};
3030

@@ -130,14 +130,14 @@ function ensureStablePluginPath() {
130130
return { pluginDir: STABLE_PLUGIN_DIR, loadPath: STABLE_PLUGIN_DIR };
131131
}
132132

133-
function isLegacyPluginPath(entry, currentLoadPath) {
133+
function isDuplicatePluginPath(entry, currentLoadPath) {
134134
if (typeof entry !== "string") return false;
135135
if (path.resolve(entry) === path.resolve(currentLoadPath)) return false;
136136

137137
const normalized = entry.replace(/\\/g, "/");
138138
return normalized.includes("evermemos-openclaw-plugin") ||
139-
normalized.includes("evermind-ai-openclaw-plugin") ||
140-
normalized.includes("@evermind-ai/openclaw-plugin");
139+
normalized.includes("@evermind-ai/openclaw-plugin") ||
140+
normalized.includes(PLUGIN_ID);
141141
}
142142

143143
function loadConfig() {
@@ -258,8 +258,8 @@ async function install() {
258258
const { pluginDir, loadPath } = ensureStablePluginPath();
259259
config.plugins.load.paths = config.plugins.load.paths.filter((entry) => {
260260
if (path.resolve(entry) === path.resolve(loadPath)) return true;
261-
if (isLegacyPluginPath(entry, loadPath)) {
262-
warn(`Removing old plugin path: ${entry}`);
261+
if (isDuplicatePluginPath(entry, loadPath)) {
262+
warn(`Removing duplicate plugin path: ${entry}`);
263263
return false;
264264
}
265265
return true;
@@ -329,7 +329,7 @@ async function install() {
329329
} else {
330330
warn(`EverOS backend is not reachable yet (${health.reason || "unknown reason"}).`);
331331
warn("You can continue, but memory recall/save will not work until the backend is running.");
332-
info("Typical start command: cd EverMemOS && uv run python src/run.py");
332+
info("Typical start command: cd EverOS && uv run python src/run.py");
333333
}
334334

335335
const userId = await promptWithDefault("User ID", DEFAULT_CONFIG.userId);

examples/openclaw-plugin/openclaw.plugin.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
{
22
"id": "evermind-ai-everos",
33
"name": "EverOS OpenClaw Plugin",
4-
"description": "Full-lifecycle memory management for OpenClaw through the EverOS backend, powered by EverMemOS",
5-
"version": "1.4.0",
4+
"description": "Full-lifecycle memory management for OpenClaw through the EverOS backend, powered by EverOS",
5+
"version": "1.5.1",
66
"kind": "context-engine",
77
"contextEngine": true,
88
"main": "./index.js",
@@ -35,9 +35,9 @@
3535
"description": "EverOS memory types to search",
3636
"items": {
3737
"type": "string",
38-
"enum": ["episodic_memory", "profile", "agent_skill", "agent_case"]
38+
"enum": ["episodic_memory"]
3939
},
40-
"default": ["episodic_memory", "profile", "agent_skill", "agent_case"]
40+
"default": ["episodic_memory"]
4141
},
4242
"retrieveMethod": {
4343
"type": "string",

examples/openclaw-plugin/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@evermind-ai/openclaw-plugin",
3-
"version": "1.4.0",
4-
"description": "EverOS OpenClaw Plugin for OpenClaw 3.8+",
3+
"version": "1.5.1",
4+
"description": "EverOS OpenClaw Plugin — persistent memory through natural conversation",
55
"type": "module",
66
"main": "./index.js",
77
"bin": {

examples/openclaw-plugin/src/api.js

Lines changed: 18 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -16,75 +16,45 @@ function messageId(idSeed, role, content) {
1616
export async function searchMemories(cfg, params, log = noop) {
1717
const { memory_types, ...baseParams } = params;
1818

19-
// Backend only supports these types in hybrid/vector search.
20-
// "profile" is handled separately by the backend (fetched from MongoDB, not ES/Milvus).
21-
// "agent_case" / "agent_skill" do not exist in the backend MemoryType enum.
22-
const SEARCHABLE_TYPES = new Set(["episodic_memory", "foresight", "event_log"]);
19+
const SEARCHABLE = new Set(["episodic_memory"]);
20+
const searchTypes = (memory_types ?? []).filter((t) => SEARCHABLE.has(t));
2321

24-
const searchTypes = (memory_types ?? []).filter((t) => SEARCHABLE_TYPES.has(t));
25-
// profile is passed alongside a searchable type so the backend can attach it via its own path
26-
const wantProfile = (memory_types ?? []).includes("profile");
27-
28-
if (!searchTypes.length && !wantProfile) {
29-
return { status: "ok", result: { profiles: [], memories: [], pending_messages: [] } };
22+
if (!searchTypes.length) {
23+
return { status: "ok", result: { memories: [], pending_messages: [] } };
3024
}
3125

32-
// Single search request with only valid searchable types.
33-
// The backend's retrieve_mem always fetches pending_messages and (when profile is requested)
34-
// attaches profile data automatically based on user_id/group_id.
35-
const types = searchTypes.length ? searchTypes : ["episodic_memory"];
36-
const p = { ...baseParams, memory_types: types };
37-
log.info(`${TAG} GET /api/v1/memories/search`, JSON.stringify(p));
38-
const searchResult = await request(cfg, "GET", "/api/v1/memories/search", p);
39-
log.info(`${TAG} GET response`, JSON.stringify(searchResult));
40-
41-
// If profile was requested, fetch it separately via the fetch endpoint
42-
let profiles = [];
43-
if (wantProfile) {
44-
try {
45-
const profileParams = {
46-
user_id: baseParams.user_id,
47-
group_id: baseParams.group_id,
48-
memory_type: "profile",
49-
limit: 1,
50-
};
51-
log.info(`${TAG} GET /api/v1/memories (profile)`, JSON.stringify(profileParams));
52-
const profileResult = await request(cfg, "GET", "/api/v1/memories", profileParams);
53-
log.info(`${TAG} GET response (profile)`, JSON.stringify(profileResult));
54-
if (profileResult?.result?.memories?.length) {
55-
profiles = profileResult.result.memories;
56-
}
57-
} catch (err) {
58-
log.warn(`${TAG} profile fetch failed: ${err.message}`);
59-
}
60-
}
26+
const p = { ...baseParams, memory_types: searchTypes };
27+
log.info(`${TAG} GET /api/v1/memories/search`);
28+
const r = await request(cfg, "GET", "/api/v1/memories/search", p);
29+
log.info(`${TAG} GET response`);
6130

62-
const merged = {
31+
return {
6332
status: "ok",
6433
result: {
65-
profiles,
66-
memories: searchResult?.result?.memories ?? [],
67-
pending_messages: searchResult?.result?.pending_messages ?? [],
34+
memories: r?.result?.memories ?? [],
35+
pending_messages: r?.result?.pending_messages ?? [],
6836
},
6937
};
70-
return merged;
7138
}
7239

73-
export async function saveMemories(cfg, { userId, groupId, messages = [], flush = false, idSeed = "" }, log = noop) {
40+
export async function saveMemories(cfg, { userId, groupId, messages = [], flush = false, idSeed = "" }) {
7441
if (!messages.length) return;
7542
const stamp = Date.now();
7643

7744
const payloads = messages.map((msg, i) => {
7845
const { role = "user", content = "" } = msg;
79-
const sender = role === "assistant" ? role : userId;
46+
// Always use userId as sender so the backend stores a consistent user_id
47+
// for both user and assistant messages. The `role` field distinguishes who spoke.
48+
const sender = userId;
49+
const senderName = role === "assistant" ? "assistant" : userId;
8050
const isLast = i === messages.length - 1;
8151

8252
return {
8353
message_id: messageId(idSeed, role, content),
8454
create_time: new Date(stamp + i).toISOString(),
8555
role,
8656
sender,
87-
sender_name: sender,
57+
sender_name: senderName,
8858
content,
8959
group_id: groupId,
9060
group_name: groupId,
@@ -94,10 +64,7 @@ export async function saveMemories(cfg, { userId, groupId, messages = [], flush
9464
};
9565
});
9666

97-
// Send sequentially to preserve message order on the backend
9867
for (const payload of payloads) {
99-
log.info(`${TAG} POST /api/v1/memories`, JSON.stringify(payload));
100-
const result = await request(cfg, "POST", "/api/v1/memories", payload);
101-
log.info(`${TAG} POST response`, JSON.stringify(result));
68+
await request(cfg, "POST", "/api/v1/memories", payload);
10269
}
10370
}

examples/openclaw-plugin/src/config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ export function resolveConfig(pc = {}) {
88
userId: pc.userId || "everos-user",
99
groupId: pc.groupId || "everos-group",
1010
topK: pc.topK ?? 5,
11-
memoryTypes: pc.memoryTypes ?? ["episodic_memory", "profile"],
11+
memoryTypes: pc.memoryTypes ?? ["episodic_memory"],
1212
retrieveMethod: pc.retrieveMethod ?? "hybrid",
1313
};
1414
}

0 commit comments

Comments
 (0)