@jungjaehoon/clawdbot-mama 0.1.3 → 0.2.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.
Files changed (2) hide show
  1. package/index.ts +154 -6
  2. package/package.json +1 -1
package/index.ts CHANGED
@@ -3,6 +3,11 @@
3
3
  *
4
4
  * NO HTTP/REST - MAMA 로직을 Gateway에 직접 임베드
5
5
  * better-sqlite3 + sqlite-vec로 벡터 검색
6
+ *
7
+ * Features:
8
+ * - 4 native tools: mama_search, mama_save, mama_load_checkpoint, mama_update
9
+ * - Auto-recall: 에이전트 시작 시 유저 프롬프트 기반 시맨틱 검색
10
+ * - Auto-capture: 에이전트 종료 시 중요 결정 자동 저장
6
11
  */
7
12
 
8
13
  import { Type } from "@sinclair/typebox";
@@ -53,6 +58,142 @@ const mamaPlugin = {
53
58
 
54
59
  register(api: ClawdbotPluginApi) {
55
60
 
61
+ // =====================================================
62
+ // Auto-recall: 유저 프롬프트 기반 시맨틱 검색
63
+ // =====================================================
64
+ api.on("before_agent_start", async (event: any) => {
65
+ try {
66
+ await initMAMA();
67
+
68
+ const userPrompt = event.prompt || "";
69
+
70
+ // 1. 유저 프롬프트가 있으면 시맨틱 검색 수행
71
+ let semanticResults: any[] = [];
72
+ if (userPrompt && userPrompt.length >= 5) {
73
+ try {
74
+ const searchResult = await mama.suggest(userPrompt, { limit: 3, threshold: 0.5 });
75
+ semanticResults = searchResult?.results || [];
76
+ } catch (searchErr: any) {
77
+ console.error("[MAMA] Semantic search error:", searchErr.message);
78
+ }
79
+ }
80
+
81
+ // 2. 최근 체크포인트 로드
82
+ const checkpoint = await mama.loadCheckpoint();
83
+
84
+ // 3. 최근 결정들 로드 (시맨틱 검색 결과가 없을 때만)
85
+ let recentDecisions: any[] = [];
86
+ if (semanticResults.length === 0) {
87
+ const recentResult = await mama.list({ limit: 3 });
88
+ recentDecisions = recentResult?.decisions || [];
89
+ }
90
+
91
+ // 4. 컨텍스트가 있으면 주입
92
+ if (checkpoint || semanticResults.length > 0 || recentDecisions.length > 0) {
93
+ let content = "<relevant-memories>\n";
94
+ content += "# MAMA Memory Context\n\n";
95
+
96
+ if (semanticResults.length > 0) {
97
+ content += "## Relevant Decisions (semantic match)\n\n";
98
+ semanticResults.forEach((r: any) => {
99
+ const pct = Math.round((r.similarity || 0) * 100);
100
+ content += `- **${r.topic}** [${pct}%]: ${r.decision}`;
101
+ if (r.outcome) content += ` (${r.outcome})`;
102
+ content += `\n _${(r.reasoning || "").substring(0, 100)}..._\n`;
103
+ content += ` ID: \`${r.id}\`\n`;
104
+ });
105
+ content += "\n";
106
+ }
107
+
108
+ if (checkpoint) {
109
+ content += `## Last Checkpoint (${new Date(checkpoint.timestamp).toLocaleString()})\n\n`;
110
+ content += `**Summary:** ${checkpoint.summary}\n\n`;
111
+ if (checkpoint.next_steps) {
112
+ content += `**Next Steps:** ${checkpoint.next_steps}\n\n`;
113
+ }
114
+ }
115
+
116
+ if (recentDecisions.length > 0) {
117
+ content += "## Recent Decisions\n\n";
118
+ recentDecisions.forEach((d: any) => {
119
+ content += `- **${d.topic}**: ${d.decision}`;
120
+ if (d.outcome) content += ` (${d.outcome})`;
121
+ content += "\n";
122
+ });
123
+ content += "\n";
124
+ }
125
+
126
+ content += "</relevant-memories>";
127
+
128
+ console.log(`[MAMA] Auto-recall: ${semanticResults.length} semantic matches, ${recentDecisions.length} recent, checkpoint: ${!!checkpoint}`);
129
+
130
+ return {
131
+ prependContext: content,
132
+ };
133
+ }
134
+ } catch (err: any) {
135
+ console.error("[MAMA] Auto-recall error:", err.message);
136
+ }
137
+ });
138
+
139
+ // =====================================================
140
+ // Auto-capture: 에이전트 종료 시 결정 자동 저장
141
+ // =====================================================
142
+ api.on("agent_end", async (event: any) => {
143
+ if (!event.success || !event.messages || event.messages.length === 0) {
144
+ return;
145
+ }
146
+
147
+ try {
148
+ await initMAMA();
149
+
150
+ // 메시지에서 텍스트 추출
151
+ const texts: string[] = [];
152
+ for (const msg of event.messages) {
153
+ if (!msg || typeof msg !== "object") continue;
154
+
155
+ const role = msg.role;
156
+ if (role !== "user" && role !== "assistant") continue;
157
+
158
+ const content = msg.content;
159
+ if (typeof content === "string") {
160
+ texts.push(content);
161
+ } else if (Array.isArray(content)) {
162
+ for (const block of content) {
163
+ if (block?.type === "text" && typeof block.text === "string") {
164
+ texts.push(block.text);
165
+ }
166
+ }
167
+ }
168
+ }
169
+
170
+ // 결정 패턴 감지
171
+ const decisionPatterns = [
172
+ /decided|결정|선택|chose|use.*instead|going with/i,
173
+ /will use|사용할|approach|방식|strategy/i,
174
+ /remember|기억|learned|배웠|lesson/i,
175
+ ];
176
+
177
+ for (const text of texts) {
178
+ // Skip short or injected content
179
+ if (text.length < 20 || text.length > 500) continue;
180
+ if (text.includes("<relevant-memories>")) continue;
181
+ if (text.startsWith("<") && text.includes("</")) continue;
182
+
183
+ // Check if it matches decision patterns
184
+ const isDecision = decisionPatterns.some(p => p.test(text));
185
+ if (!isDecision) continue;
186
+
187
+ // Auto-save detected decision (logged only, not actually saved without explicit topic)
188
+ console.log(`[MAMA] Auto-capture candidate: ${text.substring(0, 50)}...`);
189
+ // Note: 실제 저장은 명시적 topic이 필요하므로 로그만 남김
190
+ // 향후 LLM을 통한 topic 추출 기능 추가 가능
191
+ }
192
+ } catch (err: any) {
193
+ console.error("[MAMA] Auto-capture error:", err.message);
194
+ }
195
+ });
196
+
56
197
  // =====================================================
57
198
  // mama_search - 시맨틱 메모리 검색
58
199
  // =====================================================
@@ -60,17 +201,19 @@ const mamaPlugin = {
60
201
  name: "mama_search",
61
202
  description: `Search semantic memory for relevant past decisions.
62
203
 
63
- **ALWAYS use BEFORE making architectural decisions:**
64
- - Find if this problem was solved before
65
- - Recall reasoning and lessons learned
66
- - Avoid repeating past mistakes
67
- - Check for related decisions to link
204
+ ⚠️ **TRIGGERS - Call this BEFORE:**
205
+ Making architectural choices (check prior art)
206
+ Calling mama_save (find links first!)
207
+ Debugging (find past failures on similar issues)
208
+ Starting work on a topic (load context)
68
209
 
69
210
  **Returns:** Decisions ranked by semantic similarity with:
70
211
  - Topic, decision, reasoning
71
212
  - Similarity score (0-100%)
72
213
  - Decision ID (for linking/updating)
73
214
 
215
+ **High similarity (>80%) = MUST link with builds_on/debates/synthesizes**
216
+
74
217
  **Example queries:** "authentication", "database choice", "error handling"`,
75
218
 
76
219
  parameters: Type.Object({
@@ -126,6 +269,11 @@ const mamaPlugin = {
126
269
  name: "mama_save",
127
270
  description: `Save a decision or checkpoint to semantic memory.
128
271
 
272
+ ⚠️ **REQUIRED WORKFLOW (Don't create orphans!):**
273
+ 1. Call mama_search FIRST to find related decisions
274
+ 2. Check if same topic exists (yours will supersede it)
275
+ 3. MUST include link in reasoning/summary field
276
+
129
277
  **DECISION - Use when:**
130
278
  - Making architectural choices
131
279
  - Learning a lesson (success or failure)
@@ -137,7 +285,7 @@ const mamaPlugin = {
137
285
  - Reaching a milestone
138
286
  - Before switching tasks
139
287
 
140
- **Link decisions:** Add "builds_on: decision_xxx" in reasoning to create graph edges.`,
288
+ **Link decisions:** End reasoning with 'builds_on: <id>' or 'debates: <id>' or 'synthesizes: [id1, id2]'`,
141
289
 
142
290
  parameters: Type.Object({
143
291
  type: Type.Union([
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jungjaehoon/clawdbot-mama",
3
- "version": "0.1.3",
3
+ "version": "0.2.0",
4
4
  "description": "MAMA Memory Plugin for Clawdbot - Semantic decision memory with reasoning graph",
5
5
  "type": "module",
6
6
  "main": "index.ts",