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 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: Enhanced Auto-Capture with Learning (message_completed) ─────────
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 currentAgent = agentId(cfg, api);
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
- if (stored > 0) {
2150
- // Update user profile with successful capture
2151
- const profile = getUserProfile(currentAgent);
2152
- profile.successfulRecalls += stored; // Treat captures as successes
2153
- userProfiles.set(currentAgent, profile);
2154
-
2155
- logger.info?.(`[memtap] Auto-captured ${stored} enhanced memories with context`) ??
2156
- console.log(`[memtap] Auto-captured ${stored} enhanced memories with context`);
2157
- }
2158
-
2159
- // ── Proactive Surfacing Feedback Loop ──────────────────────
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
- } catch { /* proactive feedback loop failed, not critical */ }
2217
-
2218
- } catch (err: any) {
2219
- logger.warn?.(`[memtap] Auto-capture failed: ${err.message}`) ??
2220
- console.warn(`[memtap] Auto-capture failed: ${err.message}`);
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.auto-capture-enhanced',
2226
- description: 'Enhanced LLM-based memory extraction with context awareness and cross-session sharing',
2068
+ name: 'memtap.server-capture',
2069
+ description: 'Server-side memory extraction via /v1/capture',
2227
2070
  }
2228
2071
  );
2229
2072
 
@@ -2,11 +2,13 @@
2
2
  "id": "memtap",
3
3
  "name": "MemTap",
4
4
  "kind": "memory",
5
- "version": "3.2.0",
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.2.0",
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",