memento-mcp 0.3.10 → 0.3.11

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/CHANGELOG.md CHANGED
@@ -15,6 +15,9 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). Version
15
15
  ### Changed
16
16
  - `source:distill` tag renamed to `source:distill:llama-3.1-8b` to encode model provenance. The `claude-code` path tags memories `source:distill:claude-code`.
17
17
 
18
+ ### Removed
19
+ - **Passive memory extraction (auto_extract)** — removed conversation buffer, auto-extraction from `/v1/context`, and buffer fallback from `/v1/extract`. Smart models know when to store via `memento_store`; passive extraction produced noisy, low-signal memories. The `memento_extract` tool and `/v1/extract` route still work with explicit transcripts. The `conversation_buffer` table is no longer created for new workspaces.
20
+
18
21
  ---
19
22
 
20
23
  ## [0.2.3] - 2026-02-24
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "memento-mcp",
3
- "version": "0.3.10",
3
+ "version": "0.3.11",
4
4
  "mcpName": "io.github.myrakrusemark/memento-protocol",
5
5
  "description": "The Memento Protocol — persistent memory for AI agents",
6
6
  "type": "module",
@@ -78,13 +78,13 @@ QUERY="${ASSISTANT_MSG:0:500}"
78
78
  # Toast: start retrieving
79
79
  "$TOAST" memento "⏳ Autonomous recall..." &>/dev/null
80
80
 
81
- # Call Memento /v1/context (with auto_extract for passive memory formation)
81
+ # Call Memento /v1/context
82
82
  RESULT=$(curl -s --max-time 8 \
83
83
  -X POST \
84
84
  -H "Authorization: Bearer $MEMENTO_KEY" \
85
85
  -H "X-Memento-Workspace: $MEMENTO_WS" \
86
86
  -H "Content-Type: application/json" \
87
- -d "{\"message\": $(echo "$QUERY" | python3 -c 'import json,sys; print(json.dumps(sys.stdin.read()))'), \"include\": [\"memories\", \"skip_list\"], \"auto_extract\": true, \"extract_role\": \"assistant\", \"extract_content\": $(echo "$ASSISTANT_MSG" | python3 -c 'import json,sys; print(json.dumps(sys.stdin.read()))')}" \
87
+ -d "{\"message\": $(echo "$QUERY" | python3 -c 'import json,sys; print(json.dumps(sys.stdin.read()))'), \"include\": [\"memories\", \"skip_list\"]}" \
88
88
  "$MEMENTO_API/v1/context" 2>/dev/null \
89
89
  | python3 -c "
90
90
  import json, sys
@@ -107,55 +107,35 @@ try:
107
107
  for s in skip_matches:
108
108
  lines.append(f' Skip: {s[\"item\"]} — {s[\"reason\"]} (expires {s[\"expires\"]})')
109
109
 
110
- extracted = data.get('extracted', [])
111
- if extracted:
112
- lines.append(f' Stored: {len(extracted)} new memories')
113
-
114
- # Output: recall_count \t extracted_count \t detail
115
- extracted_count = len(extracted)
116
110
  detail = '\n'.join(lines)
117
- print(f'{count}\t{extracted_count}\t{detail}')
111
+ print(f'{count}\t{detail}')
118
112
  except Exception:
119
- print('0\t0\t')
113
+ print('0\t')
120
114
  " 2>/dev/null)
121
115
 
122
- # Parse count, extracted count, and detail
116
+ # Parse count and detail
123
117
  SAAS_COUNT=$(echo "$RESULT" | head -1 | cut -f1)
124
- EXTRACTED_COUNT=$(echo "$RESULT" | head -1 | cut -f2)
125
- SAAS_DETAIL=$(echo "$RESULT" | head -1 | cut -f3-)
118
+ SAAS_DETAIL=$(echo "$RESULT" | head -1 | cut -f2-)
126
119
  REMAINING=$(echo "$RESULT" | tail -n +2)
127
120
  if [ -n "$REMAINING" ]; then
128
121
  SAAS_DETAIL="$SAAS_DETAIL"$'\n'"$REMAINING"
129
122
  fi
130
123
 
131
124
  if [ -z "$SAAS_COUNT" ] || [ "$SAAS_COUNT" = "0" ]; then
132
- if [ -n "$EXTRACTED_COUNT" ] && [ "$EXTRACTED_COUNT" != "0" ]; then
133
- "$TOAST" memento "✓ ${EXTRACTED_COUNT} memories stored" &>/dev/null
134
- else
135
- "$TOAST" memento "✓ No memories matched" &>/dev/null
136
- fi
125
+ "$TOAST" memento "✓ No memories matched" &>/dev/null
137
126
  exit 0
138
127
  fi
139
128
 
140
- if [ "$SAAS_COUNT" != "0" ]; then
141
- if [ -n "$EXTRACTED_COUNT" ] && [ "$EXTRACTED_COUNT" != "0" ]; then
142
- "$TOAST" memento "✓ ${SAAS_COUNT} recalled, ${EXTRACTED_COUNT} stored" &>/dev/null
143
- else
144
- "$TOAST" memento "✓ ${SAAS_COUNT} memories recalled" &>/dev/null
145
- fi
146
- fi
129
+ "$TOAST" memento "${SAAS_COUNT} memories recalled" &>/dev/null
147
130
 
148
131
  # Build summary line
149
- SUMMARY="Recall (${SAAS_COUNT})"
150
- if [ -n "$EXTRACTED_COUNT" ] && [ "$EXTRACTED_COUNT" != "0" ]; then
151
- SUMMARY="Recall (${SAAS_COUNT}), stored ${EXTRACTED_COUNT}"
152
- fi
132
+ SUMMARY="Memento Recall (${SAAS_COUNT})"
153
133
 
154
134
  # Block the Stop so recalled memories are injected into context.
155
135
  # If no memories are relevant, respond with <...> to signal active silence.
156
136
  REASON="${SUMMARY}:
157
137
  ${SAAS_DETAIL}
158
- Stale or wrong? Update or consolidate. Otherwise <...>."
138
+ Stale or wrong? memento_memory_delete · memento_consolidate · memento_store. Otherwise <...>."
159
139
 
160
140
  python3 -c "
161
141
  import json, sys
@@ -43,7 +43,7 @@ print('true' if hook.get('enabled', True) else 'false')
43
43
  MEMENTO_WORKSPACE="${MEMENTO_WORKSPACE:-$(echo "$CONFIG_JSON" | python3 -c "import json,sys; print(json.load(sys.stdin).get('workspace',''))" 2>/dev/null)}"
44
44
 
45
45
  RECALL_LIMIT=$(echo "$CONFIG_JSON" | python3 -c "import json,sys; print(json.load(sys.stdin).get('hooks',{}).get('$HOOK_NAME',{}).get('limit',5))" 2>/dev/null)
46
- RECALL_MAX_LENGTH=$(echo "$CONFIG_JSON" | python3 -c "import json,sys; print(json.load(sys.stdin).get('hooks',{}).get('$HOOK_NAME',{}).get('maxLength',200))" 2>/dev/null)
46
+ RECALL_MAX_LENGTH=$(echo "$CONFIG_JSON" | python3 -c "import json,sys; print(json.load(sys.stdin).get('hooks',{}).get('$HOOK_NAME',{}).get('maxLength',120))" 2>/dev/null)
47
47
  fi
48
48
  # --- End config block ---
49
49
 
@@ -70,13 +70,13 @@ QUERY="${USER_MESSAGE:0:500}"
70
70
  # Toast: start retrieving
71
71
  "$TOAST" memento "⏳ Retrieving memories..." &>/dev/null
72
72
 
73
- # Call Memento SaaS /v1/context (with auto_extract for passive memory formation)
73
+ # Call Memento SaaS /v1/context
74
74
  SAAS_OUTPUT=$(curl -s --max-time 8 \
75
75
  -X POST \
76
76
  -H "Authorization: Bearer $MEMENTO_KEY" \
77
77
  -H "X-Memento-Workspace: $MEMENTO_WS" \
78
78
  -H "Content-Type: application/json" \
79
- -d "{\"message\": $(echo "$QUERY" | python3 -c 'import json,sys; print(json.dumps(sys.stdin.read()))'), \"include\": [\"memories\", \"skip_list\"], \"auto_extract\": true, \"extract_role\": \"user\", \"extract_content\": $(echo "$USER_MESSAGE" | python3 -c 'import json,sys; print(json.dumps(sys.stdin.read()))')}" \
79
+ -d "{\"message\": $(echo "$QUERY" | python3 -c 'import json,sys; print(json.dumps(sys.stdin.read()))'), \"include\": [\"memories\", \"skip_list\"]}" \
80
80
  "$MEMENTO_API/v1/context" 2>/dev/null \
81
81
  | python3 -c "
82
82
  import json, sys
@@ -84,75 +84,44 @@ try:
84
84
  data = json.load(sys.stdin)
85
85
  lines = []
86
86
  count = 0
87
+ abbrev = {'instruction':'instr','observation':'obs','decision':'dec','preference':'pref'}
87
88
 
88
- # Memory matches
89
89
  memories = data.get('memories', {}).get('matches', [])
90
90
  if memories:
91
91
  for m in memories[:${RECALL_LIMIT:-5}]:
92
- tags = m.get('tags', [])
93
- tag_str = f' [{\", \".join(tags)}]' if tags else ''
94
- content = m['content'][:${RECALL_MAX_LENGTH:-200}]
95
- score = m.get('score', '?')
96
- date_str = f' {m[\"created_at\"][:10]}' if m.get('created_at') else ''
97
- lines.append(f' {m[\"id\"]} ({m[\"type\"]}, {score}{date_str}){tag_str} — {content}')
92
+ content = m['content'][:${RECALL_MAX_LENGTH:-120}]
93
+ t = abbrev.get(m['type'], m['type'])
94
+ lines.append(f' 🔹 {content} [{m[\"id\"]} {t}]')
98
95
  count += 1
99
96
 
100
- # Skip matches (WARNING format)
101
97
  skip_matches = data.get('skip_matches', [])
102
98
  if skip_matches:
103
- lines.append('')
104
- lines.append('SKIP LIST WARNINGS:')
105
99
  for s in skip_matches:
106
- lines.append(f' ⚠ SKIP: {s[\"item\"]} — {s[\"reason\"]} (expires: {s[\"expires\"]})')
107
-
108
- # Auto-extracted memories
109
- extracted = data.get('extracted', [])
110
- if extracted:
111
- lines.append('')
112
- lines.append('MEMORIES STORED:')
113
- for e in extracted:
114
- etags = [t for t in e.get('tags', []) if t != 'source:auto-extract']
115
- etag_str = f' [{\", \".join(etags)}]' if etags else ''
116
- lines.append(f' {e[\"id\"]} ({e.get(\"type\", \"observation\")}){etag_str} — {e[\"content\"]}')
117
-
118
- # Output: recall_count \t extracted_count \t detail
119
- extracted_count = len(extracted)
100
+ lines.append(f' Skip: {s[\"item\"]} — {s[\"reason\"]} (expires {s[\"expires\"]})')
101
+
120
102
  detail = '\n'.join(lines)
121
- print(f'{count}\t{extracted_count}\t{detail}')
103
+ print(f'{count}\t{detail}')
122
104
  except Exception:
123
- print('0\t0\t')
105
+ print('0\t')
124
106
  " 2>/dev/null)
125
107
 
126
- # Parse count, extracted count, and detail
108
+ # Parse count and detail
127
109
  SAAS_COUNT=$(echo "$SAAS_OUTPUT" | head -1 | cut -f1)
128
- EXTRACTED_COUNT=$(echo "$SAAS_OUTPUT" | head -1 | cut -f2)
129
- SAAS_DETAIL=$(echo "$SAAS_OUTPUT" | head -1 | cut -f3-)
130
- # Append any remaining lines (skip warnings etc.)
110
+ SAAS_DETAIL=$(echo "$SAAS_OUTPUT" | head -1 | cut -f2-)
131
111
  REMAINING=$(echo "$SAAS_OUTPUT" | tail -n +2)
132
112
  if [ -n "$REMAINING" ]; then
133
113
  SAAS_DETAIL="$SAAS_DETAIL"$'\n'"$REMAINING"
134
114
  fi
135
115
 
136
116
  if [ -z "$SAAS_COUNT" ] || [ "$SAAS_COUNT" = "0" ]; then
137
- if [ -n "$EXTRACTED_COUNT" ] && [ "$EXTRACTED_COUNT" != "0" ]; then
138
- "$TOAST" memento "✓ ${EXTRACTED_COUNT} memories stored" &>/dev/null
139
- else
140
- "$TOAST" memento "✓ No memories matched" &>/dev/null
141
- exit 0
142
- fi
143
- else
144
- if [ -n "$EXTRACTED_COUNT" ] && [ "$EXTRACTED_COUNT" != "0" ]; then
145
- "$TOAST" memento "✓ ${SAAS_COUNT} recalled, ${EXTRACTED_COUNT} stored" &>/dev/null
146
- else
147
- "$TOAST" memento "✓ ${SAAS_COUNT} memories recalled" &>/dev/null
148
- fi
117
+ "$TOAST" memento "✓ No memories matched" &>/dev/null
118
+ exit 0
149
119
  fi
150
120
 
121
+ "$TOAST" memento "✓ ${SAAS_COUNT} memories recalled" &>/dev/null
122
+
151
123
  # Build summary line
152
- SUMMARY="Memento Recall: ${SAAS_COUNT} memories"
153
- if [ -n "$EXTRACTED_COUNT" ] && [ "$EXTRACTED_COUNT" != "0" ]; then
154
- SUMMARY="${SUMMARY}, ${EXTRACTED_COUNT} memories stored"
155
- fi
124
+ SUMMARY="Memento Recall (${SAAS_COUNT})"
156
125
 
157
126
  DETAIL_TEXT="$SUMMARY"
158
127
  DETAIL_TEXT="$DETAIL_TEXT"$'\n'"$SAAS_DETAIL"
package/src/index.js CHANGED
@@ -439,25 +439,23 @@ This is reconsolidation — like how the brain rebuilds memories on recall. Freq
439
439
 
440
440
  server.tool(
441
441
  "memento_extract",
442
- `Extract memories from a conversation transcript or the conversation buffer using LLM. Use this to manually trigger memory extraction — e.g., to flush the buffer before ending a session, or to extract from a pasted transcript.
442
+ `Extract memories from a conversation transcript using LLM. Use this to extract memories from a pasted transcript.
443
443
 
444
444
  Two modes:
445
445
  - "distill" (default): Full extraction — facts, decisions, instructions, observations. Up to 20 memories.
446
446
  - "seeds": Relational/experiential texture — preferences, emotions, sensory details. Up to 3 memories.
447
447
 
448
- If no transcript is provided, reads from the conversation buffer (auto-populated by the context hook). Buffer is cleared after extraction unless keep_buffer is true.`,
448
+ A transcript is required.`,
449
449
  {
450
- transcript: z.string().optional().describe("Raw conversation text. If omitted, reads from the conversation buffer."),
450
+ transcript: z.string().describe("Raw conversation text to extract memories from."),
451
451
  mode: z.enum(["distill", "seeds"]).optional().describe("Extraction mode (default: distill)"),
452
452
  max_memories: z.number().optional().describe("Override max memories to extract"),
453
- keep_buffer: z.boolean().optional().describe("If true, don't clear the buffer after reading it"),
454
453
  },
455
- async ({ transcript, mode, max_memories, keep_buffer }) => {
454
+ async ({ transcript, mode, max_memories }) => {
456
455
  const result = await storage.extractMemories(null, {
457
456
  transcript,
458
457
  mode,
459
458
  max_memories,
460
- keep_buffer,
461
459
  });
462
460
 
463
461
  if (result.error && !result.stored) {
@@ -261,13 +261,12 @@ export class HostedStorageAdapter extends StorageInterface {
261
261
  return res;
262
262
  }
263
263
 
264
- async extractMemories(_wsPath, { transcript, mode, max_memories, source_tag, keep_buffer }) {
264
+ async extractMemories(_wsPath, { transcript, mode, max_memories, source_tag }) {
265
265
  const body = {};
266
266
  if (transcript) body.transcript = transcript;
267
267
  if (mode) body.mode = mode;
268
268
  if (max_memories) body.max_memories = max_memories;
269
269
  if (source_tag) body.source_tag = source_tag;
270
- if (keep_buffer !== undefined) body.keep_buffer = keep_buffer;
271
270
 
272
271
  const res = await this._fetchJson("POST", "/v1/extract", body);
273
272
  if (res.error && !res.stored) return { error: res.error };