From f7f19fa8a1bd0597c046cb25ada98afc87b7e757 Mon Sep 17 00:00:00 2001 From: Prasanna721 Date: Wed, 4 Mar 2026 21:51:30 -0800 Subject: [PATCH 1/3] migrate console.supermemory.ai to app.supermemory.ai --- README.md | 5 ++--- commands/cli.ts | 4 ++-- openclaw.plugin.json | 2 +- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index dd419cf..1ea38e6 100644 --- a/README.md +++ b/README.md @@ -2,10 +2,9 @@ Untitled_Artwork 3 - Long-term memory for OpenClaw. Automatically remembers conversations, recalls relevant context, and builds a persistent user profile — all powered by [Supermemory](https://supermemory.ai) cloud. No local infrastructure required. -> **Requires [Supermemory Pro or above](https://console.supermemory.ai/billing)** - Unlock the state of the art memory for your OpenClaw bot. +> **Requires [Supermemory Pro or above](https://app.supermemory.ai/?view=integrations)** - Unlock the state of the art memory for your OpenClaw bot. ## Install @@ -21,7 +20,7 @@ Restart OpenClaw after installing. openclaw supermemory setup ``` -Enter your API key from [console.supermemory.ai](https://console.supermemory.ai). That's it. +Enter your API key from [app.supermemory.ai](https://app.supermemory.ai/?view=integrations). That's it. ### Advanced Setup diff --git a/commands/cli.ts b/commands/cli.ts index 7cfef62..9ac2459 100644 --- a/commands/cli.ts +++ b/commands/cli.ts @@ -23,7 +23,7 @@ export function registerCliSetup(api: OpenClawPluginApi): void { const configPath = path.join(configDir, "openclaw.json") console.log("\n🧠 Supermemory Setup\n") - console.log("Get your API key from: https://console.supermemory.ai\n") + console.log("Get your API key from: https://app.supermemory.ai\n") const rl = readline.createInterface({ input: process.stdin, @@ -87,7 +87,7 @@ export function registerCliSetup(api: OpenClawPluginApi): void { console.log("\n🧠 Supermemory Advanced Setup\n") console.log("Press Enter to use default values shown in [brackets]\n") - console.log("Get your API key from: https://console.supermemory.ai\n") + console.log("Get your API key from: https://app.supermemory.ai\n") const rl = readline.createInterface({ input: process.stdin, diff --git a/openclaw.plugin.json b/openclaw.plugin.json index df11b93..a14af41 100644 --- a/openclaw.plugin.json +++ b/openclaw.plugin.json @@ -6,7 +6,7 @@ "label": "Supermemory API Key", "sensitive": true, "placeholder": "sm_...", - "help": "Your API key from console.supermemory.ai (or use ${SUPERMEMORY_OPENCLAW_API_KEY})" + "help": "Your API key from app.supermemory.ai (or use ${SUPERMEMORY_OPENCLAW_API_KEY})" }, "containerTag": { "label": "Container Tag", From 8b2e0071e501d5a2af1ebebfd5b495c9f8a0dfca Mon Sep 17 00:00:00 2001 From: Prasanna721 Date: Thu, 5 Mar 2026 19:04:44 -0800 Subject: [PATCH 2/3] updates entity context --- commands/cli.ts | 43 +++++++++++++++++++++++++++++++++++++++---- commands/slash.ts | 6 ++++-- config.ts | 8 ++++++++ hooks/capture.ts | 10 ++++++---- memory.ts | 32 ++++++++++++++++++++++++++++++-- openclaw.plugin.json | 7 +++++++ tools/store.ts | 3 ++- 7 files changed, 96 insertions(+), 13 deletions(-) diff --git a/commands/cli.ts b/commands/cli.ts index 9ac2459..5a55ede 100644 --- a/commands/cli.ts +++ b/commands/cli.ts @@ -190,6 +190,17 @@ export function registerCliSetup(api: OpenClawPluginApi): void { console.log(" Invalid value, using default: all") } + console.log("\nEntity context:") + console.log( + " Instructions that guide what memories are extracted from conversations.", + ) + console.log( + " Leave blank to use the built-in default (recommended for most users).", + ) + const entityContextInput = await ask( + "Entity context (optional, press Enter for default): ", + ) + console.log("\n--- Custom Container Tags (Advanced) ---") console.log("Define custom containers for AI-driven memory routing.") const enableCustomContainerTagsInput = await ask( @@ -264,6 +275,8 @@ export function registerCliSetup(api: OpenClawPluginApi): void { if (profileFrequency !== 50) pluginConfig.profileFrequency = profileFrequency if (captureMode !== "all") pluginConfig.captureMode = captureMode + if (entityContextInput.trim()) + pluginConfig.entityContext = entityContextInput.trim() if (enableCustomContainerTags) pluginConfig.enableCustomContainerTags = true if (customContainerInstructions.trim()) { @@ -298,10 +311,20 @@ export function registerCliSetup(api: OpenClawPluginApi): void { console.log(` Max results: ${maxRecallResults}`) console.log(` Profile freq: ${profileFrequency}`) console.log(` Capture mode: ${captureMode}`) + const entityPreview = entityContextInput.trim() + if (entityPreview) { + const truncated = + entityPreview.length > 50 + ? `${entityPreview.slice(0, 50)}...` + : entityPreview + console.log(` Entity context: "${truncated}"`) + } else { + console.log(" Entity context: (default)") + } console.log( - ` Custom containers: ${enableCustomContainerTags ? "enabled" : "disabled"}`, + ` Container tags: ${enableCustomContainerTags ? "enabled" : "disabled"}`, ) - console.log(` Custom containers: ${customContainers.length}`) + console.log(` Container count: ${customContainers.length}`) if (customContainerInstructions.trim()) { console.log( ` Routing instructions: "${customContainerInstructions.trim().slice(0, 50)}${customContainerInstructions.length > 50 ? "..." : ""}"`, @@ -381,10 +404,22 @@ export function registerCliSetup(api: OpenClawPluginApi): void { console.log( ` Capture mode: ${pluginConfig.captureMode ?? "all"}`, ) + const entityCtx = pluginConfig.entityContext as + | string + | undefined + if (entityCtx) { + const truncated = + entityCtx.length > 50 + ? `${entityCtx.slice(0, 50)}...` + : entityCtx + console.log(` Entity context: "${truncated}"`) + } else { + console.log(" Entity context: (default)") + } console.log( - ` Custom containers: ${pluginConfig.enableCustomContainerTags ? "enabled" : "disabled"}`, + ` Container tags: ${pluginConfig.enableCustomContainerTags ? "enabled" : "disabled"}`, ) - console.log(` Custom containers: ${customContainers.length}`) + console.log(` Container count: ${customContainers.length}`) console.log("") }) }, diff --git a/commands/slash.ts b/commands/slash.ts index 48f437a..ff7e74f 100644 --- a/commands/slash.ts +++ b/commands/slash.ts @@ -33,7 +33,7 @@ export function registerStubCommands(api: OpenClawPluginApi): void { export function registerCommands( api: OpenClawPluginApi, client: SupermemoryClient, - _cfg: SupermemoryConfig, + cfg: SupermemoryConfig, getSessionKey: () => string | undefined, ): void { api.registerCommand({ @@ -56,6 +56,8 @@ export function registerCommands( text, { type: category, source: "openclaw_command" }, sk ? buildDocumentId(sk) : undefined, + undefined, + cfg.entityContext, ) const preview = text.length > 60 ? `${text.slice(0, 60)}…` : text @@ -81,7 +83,7 @@ export function registerCommands( log.debug(`/recall command: "${query}"`) try { - const results = await client.search(query, _cfg.maxRecallResults) + const results = await client.search(query, cfg.maxRecallResults) if (results.length === 0) { return { text: `No memories found for: "${query}"` } diff --git a/config.ts b/config.ts index f592ecb..e9d917e 100644 --- a/config.ts +++ b/config.ts @@ -1,4 +1,5 @@ import { hostname } from "node:os" +import { DEFAULT_ENTITY_CONTEXT } from "./memory.ts" export type CaptureMode = "everything" | "all" @@ -15,6 +16,7 @@ export type SupermemoryConfig = { maxRecallResults: number profileFrequency: number captureMode: CaptureMode + entityContext: string debug: boolean enableCustomContainerTags: boolean customContainers: CustomContainer[] @@ -29,6 +31,7 @@ const ALLOWED_KEYS = [ "maxRecallResults", "profileFrequency", "captureMode", + "entityContext", "debug", "enableCustomContainerTags", "customContainers", @@ -117,6 +120,10 @@ export function parseConfig(raw: unknown): SupermemoryConfig { cfg.captureMode === "everything" ? ("everything" as const) : ("all" as const), + entityContext: + typeof cfg.entityContext === "string" && cfg.entityContext.trim() + ? cfg.entityContext.trim() + : DEFAULT_ENTITY_CONTEXT, debug: (cfg.debug as boolean) ?? false, enableCustomContainerTags: (cfg.enableCustomContainerTags as boolean) ?? false, @@ -140,6 +147,7 @@ export const supermemoryConfigSchema = { maxRecallResults: { type: "number" }, profileFrequency: { type: "number" }, captureMode: { type: "string", enum: ["all", "everything"] }, + entityContext: { type: "string" }, debug: { type: "boolean" }, enableCustomContainerTags: { type: "boolean" }, customContainers: { diff --git a/hooks/capture.ts b/hooks/capture.ts index 4b73979..9bfd930 100644 --- a/hooks/capture.ts +++ b/hooks/capture.ts @@ -1,7 +1,9 @@ import type { SupermemoryClient } from "../client.ts" import type { SupermemoryConfig } from "../config.ts" import { log } from "../logger.ts" -import { buildDocumentId, ENTITY_CONTEXT } from "../memory.ts" +import { buildDocumentId } from "../memory.ts" + +const SKIPPED_PROVIDERS = ["exec-event", "cron-event", "heartbeat"] function getLastTurn(messages: unknown[]): unknown[] { let lastUserIdx = -1 @@ -31,8 +33,8 @@ export function buildCaptureHandler( log.info( `agent_end fired: provider="${ctx.messageProvider}" success=${event.success}`, ) - const provider = ctx.messageProvider - if (provider === "exec-event" || provider === "cron-event") { + const provider = ctx.messageProvider as string + if (SKIPPED_PROVIDERS.includes(provider)) { return } @@ -107,7 +109,7 @@ export function buildCaptureHandler( { source: "openclaw", timestamp: new Date().toISOString() }, customId, undefined, - ENTITY_CONTEXT, + cfg.entityContext, ) } catch (err) { log.error("capture failed", err) diff --git a/memory.ts b/memory.ts index a65c51c..2e56dd4 100644 --- a/memory.ts +++ b/memory.ts @@ -16,8 +16,36 @@ export function detectCategory(text: string): MemoryCategory { return "other" } -export const ENTITY_CONTEXT = - "Messages are tagged with [role: user] and [role: assistant]. Only create memories from what the user actually said — their preferences, decisions, and important personal details. Agent (assistant) responses are just context, not facts to remember. Only remember things that will be useful later. Ignore noise like greetings or status updates." +export const DEFAULT_ENTITY_CONTEXT = `Conversation between a user and an AI assistant. Format: [role: user] ... [user:end] and [role: assistant] ... [assistant:end]. + +You do NOT need to generate memories for every message. Most messages are not worth remembering. Only extract things that will be useful in FUTURE conversations. + +REMEMBER (lasting personal facts): +- "doesn't eat pork or beef" ← dietary restriction, useful forever +- "prefers TypeScript over JavaScript" ← preference +- "works at Acme Corp as a backend engineer" ← personal detail +- "lives in San Francisco" ← personal detail +- "uses Neovim, prefers dark themes" ← preference +- "building a recipe app in Next.js" ← ongoing project +- "weekly standup on Mondays at 10am EST" ← routine +- "remember my server IP is 192.168.1.100" ← user explicitly asked to remember + +DO NOT REMEMBER (session-specific, ephemeral, or assistant-generated): +- "looking for food recommendations" ← temporary intent, not a lasting fact +- "wants a list of YC companies" ← one-time task, not a preference +- "found 193 YC companies from the directory" ← the ASSISTANT did this, not the user +- "saved a JSON file at /path/to/file" ← the ASSISTANT did this +- "is using Algolia API to search" ← implementation detail of current task +- "wants chicken pho, ramen, udon..." ← assistant's suggestions, not user's preference +- Any action the assistant performed (searching, writing files, generating code) +- Any recommendation or list the assistant provided +- Any in-progress task status or intermediate step + +KEY RULES: +- The assistant's output is CONTEXT ONLY — never attribute assistant actions to the user +- If the user asks "find X" or "do Y", that is a one-time request, NOT a memory +- Only store preferences if the user explicitly states them ("I like...", "I prefer...", "I always...") +- When in doubt, do NOT create a memory. Less is more.` export function buildDocumentId(sessionKey: string): string { const sanitized = sessionKey diff --git a/openclaw.plugin.json b/openclaw.plugin.json index a14af41..40d7a49 100644 --- a/openclaw.plugin.json +++ b/openclaw.plugin.json @@ -39,6 +39,12 @@ "help": "'all' (default) = filter out short texts and injected context, 'everything' = capture all messages", "advanced": true }, + "entityContext": { + "label": "Entity Context", + "placeholder": "Custom instructions for memory extraction...", + "help": "Instructions that guide what memories are extracted from conversations. Leave blank to use the built-in default.", + "advanced": true + }, "debug": { "label": "Debug Logging", "help": "Enable verbose debug logs for API calls and responses", @@ -71,6 +77,7 @@ "maxRecallResults": { "type": "number", "minimum": 1, "maximum": 20 }, "profileFrequency": { "type": "number", "minimum": 1, "maximum": 500 }, "captureMode": { "type": "string", "enum": ["everything", "all"] }, + "entityContext": { "type": "string" }, "debug": { "type": "boolean" }, "enableCustomContainerTags": { "type": "boolean" }, "customContainers": { diff --git a/tools/store.ts b/tools/store.ts index 5cfaf02..0d1b93b 100644 --- a/tools/store.ts +++ b/tools/store.ts @@ -13,7 +13,7 @@ import { export function registerStoreTool( api: OpenClawPluginApi, client: SupermemoryClient, - _cfg: SupermemoryConfig, + cfg: SupermemoryConfig, getSessionKey: () => string | undefined, ): void { api.registerTool( @@ -48,6 +48,7 @@ export function registerStoreTool( { type: category, source: "openclaw_tool" }, customId, params.containerTag, + cfg.entityContext, ) const preview = From 017eeedcca9a51676ac2f23168699220c0cd63ec Mon Sep 17 00:00:00 2001 From: Prasanna721 Date: Thu, 5 Mar 2026 19:14:02 -0800 Subject: [PATCH 3/3] biome --- commands/cli.ts | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/commands/cli.ts b/commands/cli.ts index 5a55ede..c38e552 100644 --- a/commands/cli.ts +++ b/commands/cli.ts @@ -404,14 +404,10 @@ export function registerCliSetup(api: OpenClawPluginApi): void { console.log( ` Capture mode: ${pluginConfig.captureMode ?? "all"}`, ) - const entityCtx = pluginConfig.entityContext as - | string - | undefined + const entityCtx = pluginConfig.entityContext as string | undefined if (entityCtx) { const truncated = - entityCtx.length > 50 - ? `${entityCtx.slice(0, 50)}...` - : entityCtx + entityCtx.length > 50 ? `${entityCtx.slice(0, 50)}...` : entityCtx console.log(` Entity context: "${truncated}"`) } else { console.log(" Entity context: (default)")