extensions: add memory-powermem plugin for long-term memory
This commit is contained in:
parent
6e09492a37
commit
fd7999cefa
@ -21,25 +21,33 @@ Moltbot long-term memory plugin backed by [PowerMem](https://github.com/oceanbas
|
||||
|
||||
## Moltbot configuration
|
||||
|
||||
1. Set the memory slot to this plugin:
|
||||
1. Enable the plugin and set the memory slot to this plugin. Edit your Moltbot config (e.g. `~/.clawdbot/config.json` or `moltbot.json` in your state dir):
|
||||
|
||||
```yaml
|
||||
plugins:
|
||||
slots:
|
||||
memory: memory-powermem
|
||||
config:
|
||||
memory-powermem:
|
||||
baseUrl: "http://localhost:8000"
|
||||
# apiKey: "optional-if-auth-enabled"
|
||||
autoCapture: true
|
||||
autoRecall: true
|
||||
inferOnAdd: true
|
||||
# userId: "optional-override"
|
||||
# agentId: "optional-override"
|
||||
```json
|
||||
{
|
||||
"plugins": {
|
||||
"slots": { "memory": "memory-powermem" },
|
||||
"entries": {
|
||||
"memory-powermem": {
|
||||
"enabled": true,
|
||||
"config": {
|
||||
"baseUrl": "http://localhost:8000",
|
||||
"autoCapture": true,
|
||||
"autoRecall": true,
|
||||
"inferOnAdd": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Optional: `apiKey` (if PowerMem server has auth), `userId`, `agentId` — see Options below.
|
||||
|
||||
2. Ensure PowerMem server is running before starting the gateway.
|
||||
|
||||
**Auto-capture:** When a conversation ends, the full user/assistant text is sent to PowerMem with `infer: true`; PowerMem extracts and stores memories (no trigger phrases) (e.g. “remember …”, “I like …”, “important”, or Chinese “记得/记住/我喜欢/重要/偏好”). At most 3 chunks per session (each up to 6000 chars). To test: run `moltbot ltm health`, then `moltbot ltm add "User prefers dark mode"` and `moltbot ltm search "dark mode"`. In chat, ask the agent to “remember that I prefer tea” or say “我喜欢用 Python” so a message is auto-captured.
|
||||
|
||||
## Options
|
||||
|
||||
| Option | Required | Description |
|
||||
@ -62,6 +70,7 @@ Moltbot long-term memory plugin backed by [PowerMem](https://github.com/oceanbas
|
||||
|
||||
- `moltbot ltm search <query> [--limit n]` — Search memories.
|
||||
- `moltbot ltm health` — Check PowerMem server health.
|
||||
- `moltbot ltm add "<text>"` — Manually store one memory (for testing or one-off storage).
|
||||
|
||||
## Running tests
|
||||
|
||||
|
||||
@ -17,32 +17,6 @@ import {
|
||||
} from "./config.js";
|
||||
import { PowerMemClient } from "./client.js";
|
||||
|
||||
// ============================================================================
|
||||
// Rule-based capture filter (same idea as memory-lancedb)
|
||||
// ============================================================================
|
||||
|
||||
const MEMORY_TRIGGERS = [
|
||||
/zapamatuj si|pamatuj|remember/i,
|
||||
/preferuji|radši|nechci|prefer/i,
|
||||
/rozhodli jsme|budeme používat/i,
|
||||
/\+\d{10,}/,
|
||||
/[\w.-]+@[\w.-]+\.\w+/,
|
||||
/můj\s+\w+\s+je|je\s+můj/i,
|
||||
/my\s+\w+\s+is|is\s+my/i,
|
||||
/i (like|prefer|hate|love|want|need)/i,
|
||||
/always|never|important/i,
|
||||
];
|
||||
|
||||
function shouldCapture(text: string): boolean {
|
||||
if (text.length < 10 || text.length > 500) return false;
|
||||
if (text.includes("<relevant-memories>")) return false;
|
||||
if (text.startsWith("<") && text.includes("</")) return false;
|
||||
if (text.includes("**") && text.includes("\n-")) return false;
|
||||
const emojiCount = (text.match(/[\u{1F300}-\u{1F9FF}]/gu) || []).length;
|
||||
if (emojiCount > 3) return false;
|
||||
return MEMORY_TRIGGERS.some((r) => r.test(text));
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Plugin Definition
|
||||
// ============================================================================
|
||||
@ -309,6 +283,24 @@ const memoryPlugin = {
|
||||
process.exitCode = 1;
|
||||
}
|
||||
});
|
||||
|
||||
ltm
|
||||
.command("add")
|
||||
.description("Manually add a memory (for testing or one-off storage)")
|
||||
.argument("<text>", "Content to store")
|
||||
.action(async (text: string) => {
|
||||
try {
|
||||
const created = await client.add(text.trim(), { infer: cfg.inferOnAdd });
|
||||
if (created.length === 0) {
|
||||
console.log("Stored (no inferred items).");
|
||||
} else {
|
||||
console.log(`Stored ${created.length} item(s):`, created.map((c) => c.memory_id));
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("PowerMem add failed:", err);
|
||||
process.exitCode = 1;
|
||||
}
|
||||
});
|
||||
},
|
||||
{ commands: ["ltm"] },
|
||||
);
|
||||
@ -372,16 +364,34 @@ const memoryPlugin = {
|
||||
}
|
||||
}
|
||||
|
||||
const toCapture = texts.filter((t) => t && shouldCapture(t));
|
||||
if (toCapture.length === 0) return;
|
||||
// Use all conversation content; PowerMem infers memories (no trigger-phrase filter)
|
||||
const MIN_LEN = 10;
|
||||
const MAX_CHUNK_LEN = 6000;
|
||||
const MAX_CHUNKS_PER_SESSION = 3;
|
||||
const sanitized = texts
|
||||
.filter((t): t is string => typeof t === "string" && t.trim().length >= MIN_LEN)
|
||||
.map((t) => t.trim())
|
||||
.filter(
|
||||
(t) =>
|
||||
!t.includes("<relevant-memories>") &&
|
||||
!(t.startsWith("<") && t.includes("</")),
|
||||
);
|
||||
if (sanitized.length === 0) return;
|
||||
|
||||
const combined = sanitized.join("\n\n");
|
||||
const chunks: string[] = [];
|
||||
for (let i = 0; i < combined.length; i += MAX_CHUNK_LEN) {
|
||||
if (chunks.length >= MAX_CHUNKS_PER_SESSION) break;
|
||||
chunks.push(combined.slice(i, i + MAX_CHUNK_LEN));
|
||||
}
|
||||
|
||||
let stored = 0;
|
||||
for (const text of toCapture.slice(0, 3)) {
|
||||
const created = await client.add(text, { infer: cfg.inferOnAdd });
|
||||
for (const chunk of chunks) {
|
||||
const created = await client.add(chunk, { infer: cfg.inferOnAdd });
|
||||
stored += created.length;
|
||||
}
|
||||
if (stored > 0) {
|
||||
api.logger.info?.(`memory-powermem: auto-captured ${stored} memories`);
|
||||
api.logger.info?.(`memory-powermem: auto-captured ${stored} memories from conversation`);
|
||||
}
|
||||
} catch (err) {
|
||||
api.logger.warn?.(`memory-powermem: capture failed: ${String(err)}`);
|
||||
|
||||
1
extensions/memory-powermem/node_modules/@sinclair/typebox
generated
vendored
1
extensions/memory-powermem/node_modules/@sinclair/typebox
generated
vendored
@ -1 +0,0 @@
|
||||
../../../../node_modules/.pnpm/@sinclair+typebox@0.34.47/node_modules/@sinclair/typebox
|
||||
Loading…
Reference in New Issue
Block a user