Files

1 line
13 KiB
JSON

{"repo": "aradotso/ai-agent-skills", "files": {"skills/tencentdb-agent-memory/SKILL.md": {"564b99e67bc8ce3074859d8180203038b13e891e": {"t": 1785846963.9470804, "n": 12611, "h": "88bda75fe5d1e013", "c": "---\nname: tencentdb-agent-memory\ndescription: Local-first long-term memory for AI agents with symbolic short-term memory and layered long-term recall via a 4-tier progressive pipeline\ntriggers:\n - add agent memory to my project\n - implement long-term memory for my AI agent\n - set up TencentDB Agent Memory\n - configure agent memory with symbolic compression\n - enable memory layering for my agent\n - integrate agent memory with OpenClaw\n - reduce token usage with memory offloading\n - add persona and scenario memory\n---\n\n# tencentdb-agent-memory\n\n> Skill by [ara.so](https://ara.so) — AI Agent Skills collection.\n\n## What It Does\n\nTencentDB Agent Memory provides **fully local** long-term memory for AI agents through a 4-tier progressive pipeline:\n\n- **L0 Conversation**: Raw dialogue logs\n- **L1 Atom**: Atomic facts extracted from conversations\n- **L2 Scenario**: Scene blocks aggregated from atoms\n- **L3 Persona**: User profile distilled from scenarios\n\nIt combines **symbolic short-term memory** (Mermaid canvas offloading) with **layered long-term memory** (persona/scenario pyramid) to:\n\n- Cut token usage by up to **61.38%** (WideSearch benchmark)\n- Improve task success by up to **51.52%** relative (WideSearch)\n- Boost PersonaMem accuracy from **48%** to **76%**\n\n**Zero external API dependencies** — runs entirely on local SQLite + sqlite-vec.\n\n## Installation\n\n### For OpenClaw\n\n```bash\n# Install the plugin\nopenclaw plugins install @tencentdb-agent-memory/memory-tencentdb\n\n# Restart the gateway\nopenclaw gateway restart\n```\n\n### For Hermes (Docker)\n\n```bash\n# Build the image\ndocker build -f Dockerfile.hermes -t hermes-memory .\n\n# Run with your LLM credentials\ndocker run -d \\\n --name hermes-memory \\\n --restart unless-stopped \\\n -p 8420:8420 \\\n -e MODEL_API_KEY=\"${YOUR_API_KEY}\" \\\n -e MODEL_BASE_URL=\"https://api.lkeap.cloud.tencent.com/v1\" \\\n -e MODEL_NAME=\"deepseek-v3.2\" \\\n -e MODEL_PROVIDER=\"custom\" \\\n -v hermes_data:/opt/data \\\n hermes-memory\n```\n\n### As a Standalone Library\n\n```bash\nnpm install @tencentdb-agent-memory/memory-tencentdb\n```\n\n```typescript\nimport { TencentDBMemory } from '@tencentdb-agent-memory/memory-tencentdb';\n\nconst memory = new TencentDBMemory({\n storage: {\n type: 'sqlite',\n dbPath: './data/memory.db'\n }\n});\n\nawait memory.initialize();\n```\n\n## Configuration\n\n### OpenClaw Zero-Config (Minimal)\n\n```jsonc\n// ~/.openclaw/openclaw.json\n{\n \"memory-tencentdb\": {\n \"enabled\": true\n }\n}\n```\n\n### Enable Short-Term Compression\n\n```jsonc\n{\n \"memory-tencentdb\": {\n \"enabled\": true,\n \"config\": {\n \"offload\": {\n \"enabled\": true\n }\n }\n },\n \"plugins\": {\n \"slots\": {\n \"contextEngine\": \"openclaw-context-offload\"\n }\n }\n}\n```\n\nThen apply the runtime patch:\n\n```bash\nbash scripts/openclaw-after-tool-call-messages.patch.sh\n```\n\n### Full Configuration Schema\n\n```jsonc\n{\n \"memory-tencentdb\": {\n \"enabled\": true,\n \"config\": {\n // Storage backend\n \"storage\": {\n \"type\": \"sqlite\", // or \"postgres\"\n \"dbPath\": \"./data/memory.db\",\n // For PostgreSQL:\n // \"host\": \"localhost\",\n // \"port\": 5432,\n // \"database\": \"agent_memory\",\n // \"user\": \"postgres\",\n // \"password\": \"${POSTGRES_PASSWORD}\"\n },\n \n // LLM for memory extraction\n \"llm\": {\n \"provider\": \"custom\",\n \"apiKey\": \"${LLM_API_KEY}\",\n \"baseURL\": \"https://api.lkeap.cloud.tencent.com/v1\",\n \"model\": \"deepseek-v3.2\"\n },\n \n // Embedding model (local by default)\n \"embedding\": {\n \"provider\": \"local\", // or \"openai\"\n \"model\": \"Xenova/all-MiniLM-L6-v2\",\n \"dimension\": 384\n },\n \n // Memory extraction control\n \"memory\": {\n \"autoExtract\": true,\n \"extractInterval\": 10, // Extract every 10 messages\n \"personaUpdateThreshold\": 50 // Update persona after 50 atoms\n },\n \n // Short-term offload\n \"offload\": {\n \"enabled\": true,\n \"maxContextTokens\": 100000,\n \"compressionRatio\": 0.3\n },\n \n // Recall settings\n \"recall\": {\n \"topK\": 5,\n \"similarityThreshold\": 0.6,\n \"includePersona\": true,\n \"includeScenarios\": true\n }\n }\n }\n}\n```\n\n## Core Concepts\n\n### Memory Layers\n\n```\nL3 Persona (user profile, preferences)\n ↑ aggregates from\nL2 Scenario (scene blocks, common patterns)\n ↑ extracts from\nL1 Atom (atomic facts)\n ↑ distills from\nL0 Conversation (raw dialogue)\n```\n\n### Symbolic Memory (Mermaid Canvas)\n\nLong tool outputs are:\n1. **Offloaded** to external files (`refs/*.md`)\n2. **Compressed** into Mermaid graph nodes with `node_id`\n3. **Recalled** via `node_id` lookup when needed\n\n```mermaid\ngraph LR\n A[\"Search Results (50k tokens)\"] -->|offload| B[(\"refs/search-001.md\")]\n A -->|symbolize| C[\"node_1234<br/>type: search<br/>summary: 3 key findings\"]\n C -.recall via node_id.-> B\n```\n\n## Usage Examples\n\n### Store a Conversation\n\n```typescript\nimport { TencentDBMemory } from '@tencentdb-agent-memory/memory-tencentdb';\n\nconst memory = new TencentDBMemory({\n storage: { type: 'sqlite', dbPath: './memory.db' }\n});\n\nawait memory.initialize();\n\n// Store conversation turn\nawait memory.storeConversation({\n sessionId: 'session-123',\n userId: 'user-456',\n messages: [\n { role: 'user', content: 'I prefer tabs over spaces' },\n { role: 'assistant', content: 'Got it, I'll use tabs in code.' }\n ],\n metadata: { topic: 'coding-preferences' }\n});\n```\n\n### Extract Atoms and Update Persona\n\n```typescript\n// Auto-extract runs every N messages (configurable)\n// Or trigger manually:\nawait memory.extractAtoms('session-123');\n\n// Check extracted atoms\nconst atoms = await memory.getAtoms('user-456', { limit: 10 });\nconsole.log(atoms);\n// [\n// { id: 'atom-1', content: 'User prefers tabs over spaces', category: 'preference' }\n// ]\n\n// Persona updates automatically after threshold\nconst persona = await memory.getPersona('user-456');\nconsole.log(persona);\n// {\n// userId: 'user-456',\n// profile: 'Prefers tabs, uses TypeScript, likes functional patterns',\n// preferences: { coding_style: 'tabs', language: 'TypeScript' }\n// }\n```\n\n### Recall Relevant Memories\n\n```typescript\n// Before agent turn, recall relevant context\nconst recalled = await memory.recall({\n userId: 'user-456',\n query: 'how should I format this code?',\n topK: 5,\n includePersona: true,\n includeScenarios: true\n});\n\nconsole.log(recalled);\n// {\n// persona: { profile: '...', preferences: {...} },\n// scenarios: [{ title: 'Code formatting', steps: [...] }],\n// atoms: [{ content: 'User prefers tabs', score: 0.89 }]\n// }\n```\n\n### Offload Tool Output (Short-Term Memory)\n\n```typescript\n// Large tool output\nconst toolOutput = {\n tool: 'search',\n result: '...(50,000 tokens of search results)...'\n};\n\n// Offload and get symbolic reference\nconst offloaded = await memory.offloadContext({\n sessionId: 'session-123',\n content: toolOutput.result,\n metadata: { tool: 'search', timestamp: Date.now() }\n});\n\nconsole.log(offloaded);\n// {\n// nodeId: 'node-1234',\n// mermaidNode: 'node-1234[\"🔍 Search: 3 findings\"]',\n// refPath: 'refs/search-001.md',\n// summary: 'Found 3 relevant papers on neural memory'\n// }\n\n// Later, recover if needed\nconst recovered = await memory.recoverContext('node-1234');\nconsole.log(recovered.content); // Full original text\n```\n\n### Query Scenarios\n\n```typescript\n// Get common solution patterns\nconst scenarios = await memory.getScenarios('user-456', {\n topic: 'debugging',\n limit: 3\n});\n\nconsole.log(scenarios);\n// [\n// {\n// id: 'scenario-1',\n// title: 'TypeScript type errors',\n// pattern: 'Check tsconfig, verify imports, run tsc --noEmit',\n// frequency: 12\n// }\n// ]\n```\n\n## Common Patterns\n\n### Agent Loop with Memory\n\n```typescript\nasync function agentLoop(userId: string, userMessage: string) {\n const sessionId = `session-${Date.now()}`;\n \n // 1. Recall relevant context\n const memory = await memorySystem.recall({\n userId,\n query: userMessage,\n topK: 5\n });\n \n // 2. Build prompt with persona + recalled facts\n const systemPrompt = `\nUser Profile: ${memory.persona?.profile || 'No profile yet'}\n\nRelevant memories:\n${memory.atoms.map(a => `- ${a.content}`).join('\\n')}\n\nRecent scenarios:\n${memory.scenarios.map(s => `- ${s.title}: ${s.pattern}`).join('\\n')}\n `.trim();\n \n // 3. Call LLM\n const response = await llm.chat({\n messages: [\n { role: 'system', content: systemPrompt },\n { role: 'user', content: userMessage }\n ]\n });\n \n // 4. Store conversation\n await memorySystem.storeConversation({\n sessionId,\n userId,\n messages: [\n { role: 'user', content: userMessage },\n { role: 'assistant', content: response }\n ]\n });\n \n return response;\n}\n```\n\n### Periodic Persona Refresh\n\n```typescript\n// Run nightly to update user personas\nasync function refreshPersonas() {\n const users = await memory.getAllUsers();\n \n for (const userId of users) {\n const atomCount = await memory.getAtomCount(userId);\n \n if (atomCount >= 50) { // Threshold\n await memory.updatePersona(userId);\n console.log(`Updated persona for ${userId}`);\n }\n }\n}\n\n// Schedule with cron\n// 0 2 * * * node refresh-personas.js\n```\n\n### Offload Long Tool Outputs\n\n```typescript\nasync function handleToolCall(tool: string, args: any) {\n const result = await executeTool(tool, args);\n \n // If result is large, offload\n const tokenCount = estimateTokens(result);\n \n if (tokenCount > 10000) {\n const offloaded = await memory.offloadContext({\n sessionId: currentSession,\n content: result,\n metadata: { tool, args }\n });\n \n return {\n summary: offloaded.summary,\n nodeId: offloaded.nodeId,\n // Agent sees only Mermaid node in context\n mermaid: offloaded.mermaidNode\n };\n }\n \n return result; // Small results stay inline\n}\n```\n\n## Troubleshooting\n\n### Memory not extracting\n\n**Check extraction interval:**\n```jsonc\n{\n \"memory\": {\n \"autoExtract\": true,\n \"extractInterval\": 10 // Extracts every 10 messages\n }\n}\n```\n\n**Manually trigger:**\n```typescript\nawait memory.extractAtoms('session-id');\n```\n\n### Persona not updating\n\n**Check threshold:**\n```jsonc\n{\n \"memory\": {\n \"personaUpdateThreshold\": 50 // Needs 50+ atoms\n }\n}\n```\n\n**Force update:**\n```typescript\nawait memory.updatePersona('user-id');\n```\n\n### Low recall quality\n\n**Tune similarity threshold:**\n```jsonc\n{\n \"recall\": {\n \"topK\": 10, // Return more results\n \"similarityThreshold\": 0.5 // Lower = more permissive\n }\n}\n```\n\n**Check embedding model:**\n```jsonc\n{\n \"embedding\": {\n \"provider\": \"openai\", // Try external embeddings\n \"model\": \"text-embedding-3-small\"\n }\n}\n```\n\n### Offload not compressing\n\n**Verify offload is enabled:**\n```jsonc\n{\n \"offload\": {\n \"enabled\": true,\n \"maxContextTokens\": 100000\n }\n}\n```\n\n**For OpenClaw, check slot registration:**\n```jsonc\n{\n \"plugins\": {\n \"slots\": {\n \"contextEngine\": \"openclaw-context-offload\"\n }\n }\n}\n```\n\n**Apply runtime patch:**\n```bash\nbash scripts/openclaw-after-tool-call-messages.patch.sh\n```\n\n### Database errors\n\n**SQLite locked:**\n- Ensure only one process accesses the DB\n- Check file permissions on `dbPath`\n\n**PostgreSQL connection failed:**\n- Verify credentials and network access\n- Check `storage.host`, `storage.port`, `storage.database`\n\n### High memory usage\n\n**Reduce embedding dimension:**\n```jsonc\n{\n \"embedding\": {\n \"model\": \"Xenova/all-MiniLM-L6-v2\", // 384 dims (lighter)\n \"dimension\": 384\n }\n}\n```\n\n**Limit recall scope:**\n```jsonc\n{\n \"recall\": {\n \"topK\": 3, // Fewer results\n \"includeScenarios\": false // Skip scenario recall\n }\n}\n```\n\n## Environment Variables\n\n```bash\n# LLM API Key (required if using external LLM)\nLLM_API_KEY=your-api-key-here\n\n# PostgreSQL password (if using postgres storage)\nPOSTGRES_PASSWORD=your-db-password\n\n# OpenAI API key (if using OpenAI embeddings)\nOPENAI_API_KEY=your-openai-key\n```\n\n## Learn More\n\n- **GitHub**: https://github.com/Tencent/TencentDB-Agent-Memory\n- **Discord**: https://discord.gg/kDtHb5RW2\n- **Benchmarks**: See README for WideSearch, SWE-bench, AA-LCR, PersonaMem results\n- **Architecture**: 4-tier pyramid (L0 Conversation → L1 Atom → L2 Scenario → L3 Persona)\n\n---\n\n**Key Takeaway**: TencentDB Agent Memory lets agents remember user preferences, task context, and solution patterns across sessions — without dumping everything into context. Use symbolic compression for short-term overload and layered memory for long-term knowledge.\n"}}}}