memtap 3.2.0 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.ts +29 -186
- package/openclaw.plugin.json +16 -2
- package/package.json +1 -1
package/index.ts
CHANGED
|
@@ -38,6 +38,9 @@ interface MemTapConfig {
|
|
|
38
38
|
apiKey?: string;
|
|
39
39
|
agentId?: string;
|
|
40
40
|
autoCapture?: boolean;
|
|
41
|
+
captureEnabled?: boolean;
|
|
42
|
+
captureMinLength?: number;
|
|
43
|
+
debug?: boolean;
|
|
41
44
|
bulletinOnBoot?: boolean;
|
|
42
45
|
bulletinTopics?: string[];
|
|
43
46
|
llmUrl?: string;
|
|
@@ -2023,207 +2026,47 @@ ${memoryContext}
|
|
|
2023
2026
|
}
|
|
2024
2027
|
);
|
|
2025
2028
|
|
|
2026
|
-
// ── Hook:
|
|
2029
|
+
// ── Hook: Server-Side Capture (message_completed) ──────────────────────────
|
|
2030
|
+
// v4.0.0: Extraction moved to server. Plugin just POSTs conversation to /capture.
|
|
2027
2031
|
|
|
2028
2032
|
api.registerHook(
|
|
2029
2033
|
'message_completed',
|
|
2030
2034
|
async (event: any) => {
|
|
2031
2035
|
const cfg = getConfig(api);
|
|
2032
|
-
if (!cfg.autoCapture) return;
|
|
2036
|
+
if (!cfg.captureEnabled && !cfg.autoCapture) return;
|
|
2033
2037
|
|
|
2034
2038
|
const content = event.context?.content;
|
|
2035
2039
|
if (!content || content === 'NO_REPLY' || content === 'HEARTBEAT_OK') return;
|
|
2036
|
-
if (content.length < 80) return;
|
|
2040
|
+
if (content.length < (cfg.captureMinLength || 80)) return;
|
|
2037
2041
|
|
|
2038
|
-
const
|
|
2039
|
-
|
|
2040
|
-
(async () => {
|
|
2041
|
-
try {
|
|
2042
|
-
const context = conversationState.get(currentAgent);
|
|
2043
|
-
const workingMemory = workingMemoryState.get(currentAgent);
|
|
2044
|
-
|
|
2045
|
-
// Attention-gated encoding - only encode if attention allows
|
|
2046
|
-
if (context && !shouldEncodeMemory(
|
|
2047
|
-
content,
|
|
2048
|
-
context.attentionLevel,
|
|
2049
|
-
context.emotionalContext,
|
|
2050
|
-
workingMemory?.cognitiveLoad || 0
|
|
2051
|
-
)) {
|
|
2052
|
-
return; // Skip encoding due to low attention/high cognitive load
|
|
2053
|
-
}
|
|
2054
|
-
|
|
2055
|
-
const memories = await llmExtract(cfg, content);
|
|
2056
|
-
if (!memories.length) return;
|
|
2057
|
-
|
|
2058
|
-
let stored = 0;
|
|
2059
|
-
|
|
2060
|
-
for (const mem of memories) {
|
|
2061
|
-
if (!mem.content || mem.content.length < 10) continue;
|
|
2062
|
-
|
|
2063
|
-
try {
|
|
2064
|
-
// Calculate emotional weighting
|
|
2065
|
-
const memoryType = mem.type || 'fact';
|
|
2066
|
-
const emotionalWeight = EMOTIONAL_WEIGHTS[memoryType] || 1.0;
|
|
2067
|
-
const contextualWeight = context?.emotionalContext === 'excited' ? 1.2 :
|
|
2068
|
-
context?.emotionalContext === 'positive' ? 1.1 :
|
|
2069
|
-
context?.emotionalContext === 'negative' ? 1.15 : 1.0;
|
|
2070
|
-
|
|
2071
|
-
const finalImportance = (mem.importance ?? 5) * emotionalWeight * contextualWeight;
|
|
2072
|
-
|
|
2073
|
-
// Determine category (from LLM extraction or fallback)
|
|
2074
|
-
const memCategory = MEMORY_CATEGORIES.includes(mem.category as any)
|
|
2075
|
-
? mem.category
|
|
2076
|
-
: (memoryType === 'preference' ? 'preferences' :
|
|
2077
|
-
memoryType === 'decision' || memoryType === 'goal' || memoryType === 'task' ? 'project' :
|
|
2078
|
-
'technical');
|
|
2079
|
-
|
|
2080
|
-
// Enhanced memory with neuromimetic features
|
|
2081
|
-
const enhancedMem: Record<string, any> = {
|
|
2082
|
-
content: mem.content,
|
|
2083
|
-
type: memoryType,
|
|
2084
|
-
agent: currentAgent,
|
|
2085
|
-
importance: storeImportance(Math.min(10, finalImportance)),
|
|
2086
|
-
category: memCategory,
|
|
2087
|
-
tags: [
|
|
2088
|
-
...(mem.tags || []),
|
|
2089
|
-
'auto-captured',
|
|
2090
|
-
'neuromimetic',
|
|
2091
|
-
`category:${memCategory}`,
|
|
2092
|
-
...(context?.dominantTopic ? [`topic:${context.dominantTopic}`] : []),
|
|
2093
|
-
`engagement:${context?.userEngagement || 'unknown'}`,
|
|
2094
|
-
`attention:${context?.attentionLevel || 'unknown'}`,
|
|
2095
|
-
`emotion:${context?.emotionalContext || 'neutral'}`
|
|
2096
|
-
],
|
|
2097
|
-
source: 'plugin:neuromimetic-capture-v3.0',
|
|
2098
|
-
conversationContext: {
|
|
2099
|
-
dominantTopic: context?.dominantTopic,
|
|
2100
|
-
engagement: context?.userEngagement,
|
|
2101
|
-
queryCount: context?.memoryQueryCount || 0,
|
|
2102
|
-
attentionLevel: context?.attentionLevel,
|
|
2103
|
-
emotionalContext: context?.emotionalContext
|
|
2104
|
-
},
|
|
2105
|
-
neuromimeticData: {
|
|
2106
|
-
emotionalIntensity: contextualWeight,
|
|
2107
|
-
attentionStrength: context?.attentionLevel === 'flow' ? 1.0 :
|
|
2108
|
-
context?.attentionLevel === 'focused' ? 0.8 : 0.5,
|
|
2109
|
-
consolidationScore: 0.1, // Will increase with dream cycles
|
|
2110
|
-
retrievalCount: 0,
|
|
2111
|
-
lastAccess: Date.now()
|
|
2112
|
-
}
|
|
2113
|
-
};
|
|
2114
|
-
|
|
2115
|
-
// Create episodic memory entry
|
|
2116
|
-
if (context && memoryType === 'event') {
|
|
2117
|
-
const episodic = createEpisodicMemory(currentAgent, mem.content, context);
|
|
2118
|
-
const episodics = episodicMemories.get(currentAgent) || [];
|
|
2119
|
-
episodics.push(episodic);
|
|
2120
|
-
episodicMemories.set(currentAgent, episodics.slice(-100)); // Keep last 100
|
|
2121
|
-
}
|
|
2122
|
-
|
|
2123
|
-
await bbFetch(cfg, `${baseUrl(cfg)}/memories`, {
|
|
2124
|
-
method: 'POST',
|
|
2125
|
-
body: JSON.stringify(enhancedMem),
|
|
2126
|
-
});
|
|
2127
|
-
stored++;
|
|
2128
|
-
|
|
2129
|
-
// Cross-session memory sharing for MemTap agents
|
|
2130
|
-
if (currentAgent.includes('memtap') && mem.type === 'decision') {
|
|
2131
|
-
try {
|
|
2132
|
-
// Share important decisions across MemTap agent ecosystem
|
|
2133
|
-
const crossSessionMem = {
|
|
2134
|
-
...enhancedMem,
|
|
2135
|
-
agent: 'memtap-shared',
|
|
2136
|
-
tags: [...enhancedMem.tags, 'cross-session', `from:${currentAgent}`]
|
|
2137
|
-
};
|
|
2138
|
-
|
|
2139
|
-
await bbFetch(cfg, `${baseUrl(cfg)}/memories`, {
|
|
2140
|
-
method: 'POST',
|
|
2141
|
-
body: JSON.stringify(crossSessionMem)
|
|
2142
|
-
});
|
|
2143
|
-
} catch { /* cross-session sharing failed, not critical */ }
|
|
2144
|
-
}
|
|
2145
|
-
|
|
2146
|
-
} catch { /* skip individual failures */ }
|
|
2147
|
-
}
|
|
2042
|
+
const userMessage = event.context?.userMessage || event.context?.input;
|
|
2148
2043
|
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
// Check if the agent's response referenced any proactively surfaced memories
|
|
2161
|
-
try {
|
|
2162
|
-
const surfaced = proactiveSurfacedMemories.get(currentAgent);
|
|
2163
|
-
if (surfaced && (Date.now() - surfaced.timestamp) < 600000) { // within 10min
|
|
2164
|
-
const contentLower = content.toLowerCase();
|
|
2165
|
-
const usedIds: string[] = [];
|
|
2166
|
-
|
|
2167
|
-
for (const memId of surfaced.memoryIds) {
|
|
2168
|
-
// Check if the memory ID or content from proactive surfacing appears in the response
|
|
2169
|
-
if (contentLower.includes(memId.toLowerCase())) {
|
|
2170
|
-
usedIds.push(memId);
|
|
2171
|
-
}
|
|
2172
|
-
}
|
|
2173
|
-
|
|
2174
|
-
// Also do a fuzzy check: recall proactive memories and see if their content appears
|
|
2175
|
-
if (usedIds.length === 0 && surfaced.memoryIds.length > 0) {
|
|
2176
|
-
for (const memId of surfaced.memoryIds) {
|
|
2177
|
-
try {
|
|
2178
|
-
const memData = await bbFetch(cfg, `${baseUrl(cfg)}/memories/${encodeURIComponent(memId)}`);
|
|
2179
|
-
const memContent = (memData.content || '').toLowerCase();
|
|
2180
|
-
// Check if key phrases from the memory appear in the response
|
|
2181
|
-
const keyPhrases = memContent.split(/\s+/).filter((w: string) => w.length > 5).slice(0, 5);
|
|
2182
|
-
const matchCount = keyPhrases.filter((phrase: string) => contentLower.includes(phrase)).length;
|
|
2183
|
-
if (matchCount >= 2) {
|
|
2184
|
-
usedIds.push(memId);
|
|
2185
|
-
}
|
|
2186
|
-
} catch { /* skip */ }
|
|
2187
|
-
}
|
|
2188
|
-
}
|
|
2189
|
-
|
|
2190
|
-
// Importance reinforcement for used proactive memories
|
|
2191
|
-
if (usedIds.length > 0) {
|
|
2192
|
-
for (const memId of usedIds) {
|
|
2193
|
-
try {
|
|
2194
|
-
await bbFetch(cfg, `${baseUrl(cfg)}/memories/${encodeURIComponent(memId)}/access`, {
|
|
2195
|
-
method: 'POST',
|
|
2196
|
-
body: JSON.stringify({
|
|
2197
|
-
boost: FORGETTING_CURVE.retrievalStrengthening * 1.5, // Extra boost for proactive hit
|
|
2198
|
-
lastAccess: Date.now(),
|
|
2199
|
-
attentionLevel: 'proactive-hit',
|
|
2200
|
-
reinforcement: {
|
|
2201
|
-
proactiveHit: true,
|
|
2202
|
-
adaptiveDecayRate: Math.max(0.001, (cfg.decayRate || FORGETTING_CURVE.baseDecayRate) * 0.5)
|
|
2203
|
-
}
|
|
2204
|
-
})
|
|
2205
|
-
});
|
|
2206
|
-
} catch { /* reinforcement failed, not critical */ }
|
|
2207
|
-
}
|
|
2208
|
-
|
|
2209
|
-
logger.info?.(`[memtap] Proactive surfacing feedback: ${usedIds.length}/${surfaced.memoryIds.length} memories used by agent`) ??
|
|
2210
|
-
console.log(`[memtap] Proactive surfacing feedback: ${usedIds.length}/${surfaced.memoryIds.length} memories used by agent`);
|
|
2044
|
+
try {
|
|
2045
|
+
await bbFetch(cfg, `${baseUrl(cfg)}/capture`, {
|
|
2046
|
+
method: 'POST',
|
|
2047
|
+
body: JSON.stringify({
|
|
2048
|
+
agent: agentId(cfg, api),
|
|
2049
|
+
conversation: {
|
|
2050
|
+
userMessage,
|
|
2051
|
+
assistantMessage: content,
|
|
2052
|
+
context: {
|
|
2053
|
+
channel: event.context?.channel,
|
|
2054
|
+
timestamp: new Date().toISOString()
|
|
2211
2055
|
}
|
|
2212
|
-
|
|
2213
|
-
// Clear after processing
|
|
2214
|
-
proactiveSurfacedMemories.delete(currentAgent);
|
|
2215
2056
|
}
|
|
2216
|
-
}
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2057
|
+
})
|
|
2058
|
+
});
|
|
2059
|
+
} catch (err) {
|
|
2060
|
+
// Silent fail — capture is non-critical
|
|
2061
|
+
if (cfg.debug) {
|
|
2062
|
+
logger.warn?.(`[memtap] capture failed: ${err}`) ??
|
|
2063
|
+
console.error('[memtap] capture failed:', err);
|
|
2221
2064
|
}
|
|
2222
|
-
}
|
|
2065
|
+
}
|
|
2223
2066
|
},
|
|
2224
2067
|
{
|
|
2225
|
-
name: 'memtap.
|
|
2226
|
-
description: '
|
|
2068
|
+
name: 'memtap.server-capture',
|
|
2069
|
+
description: 'Server-side memory extraction via /v1/capture',
|
|
2227
2070
|
}
|
|
2228
2071
|
);
|
|
2229
2072
|
|
package/openclaw.plugin.json
CHANGED
|
@@ -2,11 +2,13 @@
|
|
|
2
2
|
"id": "memtap",
|
|
3
3
|
"name": "MemTap",
|
|
4
4
|
"kind": "memory",
|
|
5
|
-
"version": "
|
|
5
|
+
"version": "4.0.0",
|
|
6
6
|
"description": "Graph-based long-term memory for OpenClaw agents — semantic recall, GraphRAG, entity management, decision tracking, neural auto-capture, anomaly detection, consolidation, profiles, and adaptive decay.",
|
|
7
7
|
"defaultConfig": {
|
|
8
8
|
"serverUrl": "https://api.memtap.ai",
|
|
9
9
|
"autoCapture": true,
|
|
10
|
+
"captureEnabled": true,
|
|
11
|
+
"captureMinLength": 80,
|
|
10
12
|
"bulletinOnBoot": true
|
|
11
13
|
},
|
|
12
14
|
"configSchema": {
|
|
@@ -28,7 +30,19 @@
|
|
|
28
30
|
},
|
|
29
31
|
"autoCapture": {
|
|
30
32
|
"type": "boolean",
|
|
31
|
-
"description": "Automatically extract memories from conversations"
|
|
33
|
+
"description": "Automatically extract memories from conversations (alias for captureEnabled)"
|
|
34
|
+
},
|
|
35
|
+
"captureEnabled": {
|
|
36
|
+
"type": "boolean",
|
|
37
|
+
"description": "Enable server-side auto-capture of memories from conversations (default true)"
|
|
38
|
+
},
|
|
39
|
+
"captureMinLength": {
|
|
40
|
+
"type": "number",
|
|
41
|
+
"description": "Minimum message length to trigger capture (default 80 chars)"
|
|
42
|
+
},
|
|
43
|
+
"debug": {
|
|
44
|
+
"type": "boolean",
|
|
45
|
+
"description": "Enable debug logging for capture and other operations"
|
|
32
46
|
},
|
|
33
47
|
"bulletinOnBoot": {
|
|
34
48
|
"type": "boolean",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "memtap",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.0",
|
|
4
4
|
"description": "MemTap — Graph-based long-term memory plugin for OpenClaw agents. Knowledge graph with semantic recall, GraphRAG, entity management, decision tracking, and auto-capture.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"openclaw",
|