Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 29 additions & 6 deletions client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,12 @@ export class SupermemoryClient {
log.warn(`container tag warning: ${tagCheck.reason}`)
}

this.client = new Supermemory({ apiKey })
// `x-sm-source` is read by mono's API to attribute searches and
// writes to the OpenClaw plugin in PostHog / `document.source`.
this.client = new Supermemory({
apiKey,
defaultHeaders: { "x-sm-source": "openclaw" },
})
this.containerTag = containerTag
log.info(`initialized (container: ${containerTag})`)
}
Expand All @@ -58,14 +63,23 @@ export class SupermemoryClient {
customId?: string,
containerTag?: string,
entityContext?: string,
): Promise<{ id: string }> {
): Promise<{ id: string; status: string }> {
const cleaned = sanitizeContent(content)
const tag = containerTag ?? this.containerTag

// Always stamp `sm_source` so mono's `document.source` column attributes
// these writes to the OpenClaw plugin. Existing callers can still pass
// extra metadata (e.g. `source: "openclaw_tool"`) and it is preserved
// underneath the canonical `sm_source` key.
const mergedMetadata: Record<string, string | number | boolean> = {
sm_source: "openclaw",
...(metadata ?? {}),
}

log.debugRequest("add", {
contentLength: cleaned.length,
customId,
metadata,
metadata: mergedMetadata,
containerTag: tag,
})

Expand All @@ -76,13 +90,22 @@ export class SupermemoryClient {
const result = await this.client.add({
content: cleaned,
containerTag: tag,
...(metadata && { metadata }),
metadata: mergedMetadata,
...(customId && { customId }),
...(clampedCtx && { entityContext: clampedCtx }),
})

log.debugResponse("add", { id: result.id })
return { id: result.id }
log.debugResponse("add", { id: result.id, status: result.status })

if (result.status === "failed") {
log.warn(
`add returned status="failed" for id=${result.id}` +
(customId ? ` customId=${customId}` : "") +
` (contentLength=${cleaned.length}, containerTag=${tag})`,
)
}

return { id: result.id, status: result.status }
}

async search(
Expand Down
7 changes: 6 additions & 1 deletion commands/slash.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ export function registerCommands(
try {
const category = detectCategory(text)
const sk = getSessionKey()
await client.addMemory(
const { status } = await client.addMemory(
text,
{ type: category, source: "openclaw_command" },
sk ? buildDocumentId(sk) : undefined,
Expand All @@ -95,6 +95,11 @@ export function registerCommands(
)

const preview = text.length > 60 ? `${text.slice(0, 60)}…` : text
if (status === "failed") {
return {
text: `Memory store failed (server returned status="failed") for: "${preview}"`,
}
}
return { text: `Remembered: "${preview}"` }
} catch (err) {
log.error("/remember failed", err)
Expand Down
4 changes: 4 additions & 0 deletions index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,10 @@ export default {
registerStoreTool(api, client, cfg, getSessionKey)
registerForgetTool(api, client, cfg)
registerProfileTool(api, client, cfg)
registerSearchTool(api, client, cfg, "supermemory-search")
registerStoreTool(api, client, cfg, getSessionKey, "supermemory-save")
registerForgetTool(api, client, cfg, "supermemory-forget")
registerProfileTool(api, client, cfg, "supermemory-profile")

if (cfg.autoRecall) {
api.on("before_prompt_build", buildRecallHandler(client, cfg))
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@supermemory/openclaw-supermemory",
"version": "2.1.12",
"version": "2.1.13",
"type": "module",
"description": "OpenClaw Supermemory memory plugin",
"license": "MIT",
Expand Down
5 changes: 3 additions & 2 deletions tools/forget.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@ export function registerForgetTool(
api: OpenClawPluginApi,
client: SupermemoryClient,
_cfg: SupermemoryConfig,
toolName = "supermemory_forget",
): void {
api.registerTool(
{
name: "supermemory_forget",
name: toolName,
label: "Memory Forget",
description:
"Forget/delete a specific memory. Searches for the closest match and removes it.",
Expand Down Expand Up @@ -66,6 +67,6 @@ export function registerForgetTool(
}
},
},
{ name: "supermemory_forget" },
{ name: toolName },
)
}
5 changes: 3 additions & 2 deletions tools/profile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@ export function registerProfileTool(
api: OpenClawPluginApi,
client: SupermemoryClient,
_cfg: SupermemoryConfig,
toolName = "supermemory_profile",
): void {
api.registerTool(
{
name: "supermemory_profile",
name: toolName,
label: "User Profile",
description:
"Get a summary of what is known about the user — stable preferences and recent context.",
Expand Down Expand Up @@ -77,6 +78,6 @@ export function registerProfileTool(
}
},
},
{ name: "supermemory_profile" },
{ name: toolName },
)
}
5 changes: 3 additions & 2 deletions tools/search.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@ export function registerSearchTool(
api: OpenClawPluginApi,
client: SupermemoryClient,
_cfg: SupermemoryConfig,
toolName = "supermemory_search",
): void {
api.registerTool(
{
name: "supermemory_search",
name: toolName,
label: "Memory Search",
description:
"Search through long-term memories for relevant information.",
Expand Down Expand Up @@ -77,6 +78,6 @@ export function registerSearchTool(
}
},
},
{ name: "supermemory_search" },
{ name: toolName },
)
}
20 changes: 16 additions & 4 deletions tools/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,11 @@ export function registerStoreTool(
client: SupermemoryClient,
cfg: SupermemoryConfig,
getSessionKey: () => string | undefined,
toolName = "supermemory_store",
): void {
api.registerTool(
{
name: "supermemory_store",
name: toolName,
label: "Memory Store",
description: "Save important information to long-term memory.",
parameters: Type.Object({
Expand All @@ -44,9 +45,9 @@ export function registerStoreTool(
`store tool: category="${category}" customId="${customId}" containerTag="${params.containerTag ?? "default"}"`,
)

await client.addMemory(
const { status } = await client.addMemory(
params.text,
{ type: category, source: "openclaw_tool" },
{ type: category, sm_capture_mode: "tool" },
customId,
params.containerTag,
cfg.entityContext,
Expand All @@ -55,11 +56,22 @@ export function registerStoreTool(
const preview =
params.text.length > 80 ? `${params.text.slice(0, 80)}…` : params.text

if (status === "failed") {
return {
content: [
{
type: "text" as const,
text: `Memory store failed (server returned status="failed") for: "${preview}"`,
},
],
}
}

return {
content: [{ type: "text" as const, text: `Stored: "${preview}"` }],
}
},
},
{ name: "supermemory_store" },
{ name: toolName },
)
}
Loading