From 2549a84e5c37098de67c36768341d321c45b5f45 Mon Sep 17 00:00:00 2001 From: Kartik Date: Thu, 23 Apr 2026 19:42:28 +0530 Subject: [PATCH] fix: update command on docs and logic (#4946) --- docs/changelog/openclaw.mdx | 24 +++++++++++++++ docs/integrations/openclaw.mdx | 20 +++---------- openclaw/README.md | 8 ++++- openclaw/cli/config-file.ts | 8 +++-- openclaw/openclaw.plugin.json | 50 +++++++++++--------------------- openclaw/package.json | 2 +- openclaw/telemetry.ts | 30 ++++++++----------- openclaw/tests/telemetry.test.ts | 6 +--- openclaw/tsup.config.ts | 4 +++ openclaw/vitest.config.ts | 4 +++ 10 files changed, 80 insertions(+), 76 deletions(-) diff --git a/docs/changelog/openclaw.mdx b/docs/changelog/openclaw.mdx index b10ac249b..c5ff0f58b 100644 --- a/docs/changelog/openclaw.mdx +++ b/docs/changelog/openclaw.mdx @@ -4,6 +4,30 @@ description: "Release notes for the OpenClaw plugin and agent harness." mode: "wide" --- + + +**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 + + + **Security & Compliance:** diff --git a/docs/integrations/openclaw.mdx b/docs/integrations/openclaw.mdx index 06157e253..56e39fb70 100644 --- a/docs/integrations/openclaw.mdx +++ b/docs/integrations/openclaw.mdx @@ -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 ``` -Use the npm package name (`@mem0/openclaw-mem0`) for plugin management commands, not the plugin ID (`openclaw-mem0`). - ### 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. - Build agents with OpenAI's SDK and Mem0 diff --git a/openclaw/README.md b/openclaw/README.md index 7e63b318a..c18f50e8d 100644 --- a/openclaw/README.md +++ b/openclaw/README.md @@ -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 diff --git a/openclaw/cli/config-file.ts b/openclaw/cli/config-file.ts index 3f9aa2ffe..bba4a8dc3 100644 --- a/openclaw/cli/config-file.ts +++ b/openclaw/cli/config-file.ts @@ -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) { diff --git a/openclaw/openclaw.plugin.json b/openclaw/openclaw.plugin.json index e30e0e3ec..d0457fee3 100644 --- a/openclaw/openclaw.plugin.json +++ b/openclaw/openclaw.plugin.json @@ -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"] + } + ] } \ No newline at end of file diff --git a/openclaw/package.json b/openclaw/package.json index 65084b4ea..1ce60418b 100644 --- a/openclaw/package.json +++ b/openclaw/package.json @@ -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", diff --git a/openclaw/telemetry.ts b/openclaw/telemetry.ts index 93497f2a5..3e2b4c7a4 100644 --- a/openclaw/telemetry.ts +++ b/openclaw/telemetry.ts @@ -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); } diff --git a/openclaw/tests/telemetry.test.ts b/openclaw/tests/telemetry.test.ts index 20abcaaa2..9a7bee716 100644 --- a/openclaw/tests/telemetry.test.ts +++ b/openclaw/tests/telemetry.test.ts @@ -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(); }); diff --git a/openclaw/tsup.config.ts b/openclaw/tsup.config.ts index 397df11fe..95b5bdfa0 100644 --- a/openclaw/tsup.config.ts +++ b/openclaw/tsup.config.ts @@ -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), + }, }); diff --git a/openclaw/vitest.config.ts b/openclaw/vitest.config.ts index 94b1bab79..d9eb26694 100644 --- a/openclaw/vitest.config.ts +++ b/openclaw/vitest.config.ts @@ -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.