fix: update command on docs and logic (#4946)
This commit is contained in:
@@ -4,6 +4,30 @@ description: "Release notes for the OpenClaw plugin and agent harness."
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
<Update label="2026-04-23" description="v1.0.10">
|
||||
|
||||
**Security:**
|
||||
- Telemetry `distinct_id` now uses SHA-256 instead of MD5 — prevents rainbow-table reversal of API key hashes
|
||||
- User email is now SHA-256 hashed before sending as `distinct_id` — no PII in telemetry payloads
|
||||
- Declared PostHog telemetry endpoint (`us.i.posthog.com`) in `providerEndpoints`
|
||||
|
||||
**Fixes:**
|
||||
- Fixed version-pinned install records preventing plugin updates. `ensureInstallRecord()` now detects semver-pinned specs (e.g. `@mem0/openclaw-mem0@1.0.7`) and rewrites them to `@latest` or `clawhub:` prefix so `openclaw plugins update` resolves to the newest release
|
||||
- Fixed `searchThreshold` default inconsistency: standardized to `0.3` across docs, README, and manifest
|
||||
- `PLUGIN_VERSION` now injected at build time via tsup `define` from `package.json` — no more hardcoded version strings
|
||||
|
||||
**Manifest Compliance:**
|
||||
- Removed non-spec fields: `requiredEnvVars`, `dataLocations`, `privacy`, `setup` (with `externalEndpoints`, `providers`, `requiresRuntime`, `postInstallHint`)
|
||||
- Replaced `setup.externalEndpoints` with spec-compliant `providerEndpoints` using `endpointClass` + `hosts` format
|
||||
- Env var declarations now rely solely on `providerAuthEnvVars` (already spec-compliant)
|
||||
|
||||
**Docs:**
|
||||
- Fixed `openclaw plugins update` command: uses plugin ID (`openclaw-mem0`), not npm package name (`@mem0/openclaw-mem0`)
|
||||
- Added update section to README
|
||||
- Removed redundant "Key Features" and "Conclusion" sections from integration docs
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-04-22" description="v1.0.9">
|
||||
|
||||
**Security & Compliance:**
|
||||
|
||||
@@ -362,11 +362,9 @@ Everything inside `oss` is optional — defaults use OpenAI embeddings (`text-em
|
||||
### Updating the Plugin
|
||||
|
||||
```bash
|
||||
openclaw plugins update @mem0/openclaw-mem0
|
||||
openclaw plugins update openclaw-mem0
|
||||
```
|
||||
|
||||
<Note>Use the npm package name (`@mem0/openclaw-mem0`) for plugin management commands, not the plugin ID (`openclaw-mem0`).</Note>
|
||||
|
||||
### Checking Plugin Status
|
||||
|
||||
```bash
|
||||
@@ -411,8 +409,9 @@ If the plugin installs but doesn't work:
|
||||
|
||||
If `openclaw plugins update` fails:
|
||||
|
||||
1. Use the full npm package name: `openclaw plugins update @mem0/openclaw-mem0`
|
||||
2. If that fails, uninstall and reinstall:
|
||||
1. Use the plugin ID: `openclaw plugins update openclaw-mem0`
|
||||
2. Update all plugins at once: `openclaw plugins update --all`
|
||||
3. If that fails, uninstall and reinstall:
|
||||
```bash
|
||||
openclaw plugins uninstall openclaw-mem0
|
||||
openclaw plugins install @mem0/openclaw-mem0
|
||||
@@ -476,17 +475,6 @@ export MEM0_TELEMETRY=false
|
||||
|
||||
The plugin injects memory-related instructions into the agent's system context via OpenClaw's `prependSystemContext` mechanism. This includes the memory triage protocol and recalled memories. This is the standard OpenClaw plugin SDK pattern for memory backends — no user-facing prompts are modified.
|
||||
|
||||
## Key Features
|
||||
|
||||
1. **Zero Configuration** — Auto-recall and auto-capture work out of the box with no prompting required
|
||||
2. **Dual Memory Scopes** — Session-scoped short-term and user-scoped long-term memories
|
||||
3. **Flexible Backend** — Use Mem0 Cloud for managed service or self-host with open-source mode
|
||||
4. **Rich Tool Suite** — Eight agent tools for explicit memory operations when needed
|
||||
|
||||
## Conclusion
|
||||
|
||||
The `@mem0/openclaw-mem0` plugin gives OpenClaw agents persistent memory with minimal setup. Whether using Mem0 Cloud or self-hosting, your agents can now remember user preferences, facts, and context across sessions automatically.
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="OpenAI Agents SDK" icon="robot" href="/integrations/openai-agents-sdk">
|
||||
Build agents with OpenAI's SDK and Mem0
|
||||
|
||||
+7
-1
@@ -60,6 +60,12 @@ openclaw --version
|
||||
|
||||
> **Note:** OpenClaw memory plugins load through an exclusive slot, so install alone does not activate the plugin. You must set `plugins.slots.memory` as shown above.
|
||||
|
||||
### Updating the plugin to get the latest features and fixes:
|
||||
|
||||
```bash
|
||||
openclaw plugins update openclaw-mem0
|
||||
```
|
||||
|
||||
### Open-Source (Self-hosted)
|
||||
|
||||
No Mem0 key needed. Vectors are stored locally in SQLite at `~/.mem0/vector_store.db` — no external database required.
|
||||
@@ -257,7 +263,7 @@ openclaw mem0 help --json # discover all comma
|
||||
| `autoRecall` | `boolean` | `false` | Inject relevant memories before each turn |
|
||||
| `autoCapture` | `boolean` | `false` | Extract and store facts after each turn |
|
||||
| `topK` | `number` | `5` | Max memories returned per recall |
|
||||
| `searchThreshold` | `number` | `0.5` | Minimum similarity score (0-1) |
|
||||
| `searchThreshold` | `number` | `0.3` | Minimum similarity score (0-1) |
|
||||
|
||||
### Platform Mode
|
||||
|
||||
|
||||
@@ -141,10 +141,12 @@ export function ensureInstallRecord(): void {
|
||||
const entry = full?.plugins?.entries?.[PLUGIN_ID];
|
||||
const record = full?.plugins?.installs?.[PLUGIN_ID];
|
||||
const allow = full?.plugins?.allow;
|
||||
const specPinned = record?.spec && /\d+\.\d+\.\d+/.test(record.spec);
|
||||
if (
|
||||
entry?.enabled === true &&
|
||||
record?.source &&
|
||||
record?.spec &&
|
||||
!specPinned &&
|
||||
Array.isArray(allow) &&
|
||||
allow.includes(PLUGIN_ID)
|
||||
) {
|
||||
@@ -171,8 +173,10 @@ export function ensureInstallRecord(): void {
|
||||
record.source = "npm";
|
||||
changed = true;
|
||||
}
|
||||
if (!record.spec) {
|
||||
record.spec = `${NPM_PACKAGE}@latest`;
|
||||
if (!record.spec || /\d+\.\d+\.\d+/.test(record.spec)) {
|
||||
record.spec = record.source === "clawhub"
|
||||
? `clawhub:${NPM_PACKAGE}`
|
||||
: `${NPM_PACKAGE}@latest`;
|
||||
changed = true;
|
||||
}
|
||||
if (!record.resolvedName) {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"id": "openclaw-mem0",
|
||||
"name": "Memory (Mem0)",
|
||||
"description": "Mem0 memory backend for OpenClaw — platform (mem0.ai cloud) or self-hosted open-source. Auto-recall and auto-capture are opt-in (disabled by default). Supports OpenAI, Anthropic, Ollama (fully local), Qdrant, and PGVector providers.",
|
||||
"version": "1.0.9",
|
||||
"version": "1.0.10",
|
||||
"kind": "memory",
|
||||
"skills": ["skills"],
|
||||
"commandAliases": [
|
||||
@@ -103,8 +103,8 @@
|
||||
},
|
||||
"searchThreshold": {
|
||||
"label": "Search Threshold",
|
||||
"placeholder": "0.5",
|
||||
"help": "Minimum similarity score for search results (0-1). Default: 0.5"
|
||||
"placeholder": "0.3",
|
||||
"help": "Minimum similarity score for search results (0-1). Default: 0.3"
|
||||
},
|
||||
"topK": {
|
||||
"label": "Top K Results",
|
||||
@@ -295,34 +295,18 @@
|
||||
},
|
||||
"required": []
|
||||
},
|
||||
"setup": {
|
||||
"providers": [
|
||||
{
|
||||
"id": "mem0",
|
||||
"authMethods": ["api-key"],
|
||||
"envVars": ["MEM0_API_KEY"],
|
||||
"description": "Platform mode: hosted memory at mem0.ai"
|
||||
},
|
||||
{
|
||||
"id": "openclaw-mem0-oss",
|
||||
"authMethods": ["api-key", "config"],
|
||||
"envVars": ["OPENAI_API_KEY", "ANTHROPIC_API_KEY"],
|
||||
"description": "Open-source mode: self-hosted with chosen LLM/embedder providers. No env vars needed when using Ollama (local)."
|
||||
}
|
||||
],
|
||||
"requiresRuntime": false,
|
||||
"postInstallHint": "Run 'openclaw mem0 init' to configure mode and credentials",
|
||||
"externalEndpoints": [
|
||||
{
|
||||
"url": "https://api.mem0.ai",
|
||||
"purpose": "Platform mode API — memory storage and retrieval",
|
||||
"required": "platform mode only"
|
||||
},
|
||||
{
|
||||
"url": "https://app.mem0.ai",
|
||||
"purpose": "Account dashboard and API key management",
|
||||
"required": "platform mode only"
|
||||
}
|
||||
]
|
||||
}
|
||||
"providerEndpoints": [
|
||||
{
|
||||
"endpointClass": "api",
|
||||
"hosts": ["api.mem0.ai"]
|
||||
},
|
||||
{
|
||||
"endpointClass": "dashboard",
|
||||
"hosts": ["app.mem0.ai"]
|
||||
},
|
||||
{
|
||||
"endpointClass": "telemetry",
|
||||
"hosts": ["us.i.posthog.com"]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@mem0/openclaw-mem0",
|
||||
"version": "1.0.9",
|
||||
"version": "1.0.10",
|
||||
"type": "module",
|
||||
"description": "Mem0 memory backend for OpenClaw — platform or self-hosted open-source",
|
||||
"license": "Apache-2.0",
|
||||
|
||||
+12
-18
@@ -11,7 +11,8 @@
|
||||
import { createHash, randomUUID } from "node:crypto";
|
||||
import { readPluginAuth, writePluginAuth, getBaseUrl, clearAnonymousTelemetryId } from "./cli/config-file.ts";
|
||||
|
||||
export const PLUGIN_VERSION = "1.0.7";
|
||||
declare const __OPENCLAW_PLUGIN_VERSION__: string;
|
||||
export const PLUGIN_VERSION: string = __OPENCLAW_PLUGIN_VERSION__;
|
||||
|
||||
const POSTHOG_API_KEY = "phc_hgJkUVJFYtmaJqrvf6CYN67TIQ8yhXAkWzUn9AMU4yX";
|
||||
const POSTHOG_HOST = "https://us.i.posthog.com/i/v0/e/";
|
||||
@@ -129,18 +130,11 @@ function maybeResolveEmail(apiKey: string): void {
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
// Upgrade any already-queued events from md5(apiKey) to email
|
||||
const oldId = createHash("md5").update(apiKey).digest("hex");
|
||||
const oldId = createHash("sha256").update(apiKey).digest("hex");
|
||||
const newId = createHash("sha256").update(email).digest("hex");
|
||||
for (const ev of eventQueue) {
|
||||
if (ev.distinct_id === oldId) {
|
||||
ev.distinct_id = email;
|
||||
}
|
||||
// Also upgrade $identify's distinct_id if present
|
||||
if (
|
||||
ev.event === "$identify" &&
|
||||
ev.distinct_id === oldId
|
||||
) {
|
||||
ev.distinct_id = email;
|
||||
ev.distinct_id = newId;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -176,12 +170,14 @@ function isTelemetryEnabled(): boolean {
|
||||
function getDistinctId(apiKey?: string): string {
|
||||
try {
|
||||
const auth = readPluginAuth();
|
||||
if (auth.userEmail) return auth.userEmail;
|
||||
if (auth.userEmail) {
|
||||
return createHash("sha256").update(auth.userEmail).digest("hex");
|
||||
}
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
if (apiKey) {
|
||||
return createHash("md5").update(apiKey).digest("hex");
|
||||
return createHash("sha256").update(apiKey).digest("hex");
|
||||
}
|
||||
return getOrCreateAnonymousId();
|
||||
}
|
||||
@@ -262,11 +258,9 @@ export function captureEvent(
|
||||
try {
|
||||
const distinctId = getDistinctId(ctx?.apiKey);
|
||||
|
||||
// If we resolved to md5(apiKey) instead of email, kick off a background
|
||||
// /v1/ping/ to resolve and cache the email. The current event ships with
|
||||
// the hash, but the async resolution upgrades any still-queued events
|
||||
// (including this one) before the beforeExit flush fires.
|
||||
if (ctx?.apiKey && distinctId && !distinctId.includes("@") && !distinctId.startsWith("openclaw-anon-")) {
|
||||
let hasEmail = false;
|
||||
try { hasEmail = !!readPluginAuth().userEmail; } catch { /* ignore */ }
|
||||
if (ctx?.apiKey && !hasEmail && !distinctId.startsWith("openclaw-anon-")) {
|
||||
maybeResolveEmail(ctx.apiKey);
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ vi.mock("../cli/config-file.ts", () => ({
|
||||
readPluginAuth: vi.fn().mockReturnValue({}),
|
||||
}));
|
||||
|
||||
import { captureEvent, PLUGIN_VERSION } from "../telemetry.ts";
|
||||
import { captureEvent } from "../telemetry.ts";
|
||||
import { readPluginAuth } from "../cli/config-file.ts";
|
||||
|
||||
describe("telemetry", () => {
|
||||
@@ -23,10 +23,6 @@ describe("telemetry", () => {
|
||||
delete (globalThis as any).__mem0_telemetry_override;
|
||||
});
|
||||
|
||||
it("exports PLUGIN_VERSION", () => {
|
||||
expect(PLUGIN_VERSION).toBe("1.0.7");
|
||||
});
|
||||
|
||||
it("captureEvent does not throw", () => {
|
||||
expect(() => captureEvent("test_event")).not.toThrow();
|
||||
});
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { defineConfig } from "tsup";
|
||||
import pkg from "./package.json";
|
||||
|
||||
export default defineConfig({
|
||||
entry: ["index.ts", "fs-safe.ts"],
|
||||
@@ -8,4 +9,7 @@ export default defineConfig({
|
||||
sourcemap: true,
|
||||
clean: true,
|
||||
external: [/^node:/, /^openclaw\//, "fs", "os", "path", "url", "readline", "module"],
|
||||
define: {
|
||||
__OPENCLAW_PLUGIN_VERSION__: JSON.stringify(pkg.version),
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import { defineConfig } from "vitest/config";
|
||||
import pkg from "./package.json";
|
||||
|
||||
export default defineConfig({
|
||||
define: {
|
||||
__OPENCLAW_PLUGIN_VERSION__: JSON.stringify(pkg.version),
|
||||
},
|
||||
test: {
|
||||
alias: {
|
||||
// OpenClaw SDK modules are resolved from the gateway at runtime.
|
||||
|
||||
Reference in New Issue
Block a user