@jungjaehoon/mama-core 1.1.2 → 1.1.3
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/dist/config-loader.d.ts +61 -0
- package/dist/config-loader.js +187 -0
- package/dist/db-adapter/base-adapter.d.ts +76 -0
- package/dist/db-adapter/base-adapter.js +11 -0
- package/dist/db-adapter/index.d.ts +24 -0
- package/dist/db-adapter/index.js +29 -0
- package/dist/db-adapter/sqlite-adapter.d.ts +73 -0
- package/dist/db-adapter/sqlite-adapter.js +330 -0
- package/dist/db-adapter/statement.d.ts +119 -0
- package/dist/db-adapter/statement.js +113 -0
- package/dist/db-manager.d.ts +252 -0
- package/dist/db-manager.js +622 -0
- package/dist/debug-logger.d.ts +32 -0
- package/dist/debug-logger.js +83 -0
- package/dist/decision-formatter.d.ts +172 -0
- package/dist/decision-formatter.js +894 -0
- package/dist/decision-tracker.d.ts +218 -0
- package/dist/decision-tracker.js +531 -0
- package/dist/embedding-cache.d.ts +83 -0
- package/dist/embedding-cache.js +182 -0
- package/dist/embedding-client.d.ts +43 -0
- package/dist/embedding-client.js +132 -0
- package/dist/embedding-server/index.d.ts +65 -0
- package/dist/embedding-server/index.js +397 -0
- package/dist/embedding-server/mobile/auth.d.ts +53 -0
- package/dist/embedding-server/mobile/auth.js +140 -0
- package/dist/embedding-server/mobile/daemon.d.ts +128 -0
- package/dist/embedding-server/mobile/daemon.js +303 -0
- package/dist/embedding-server/mobile/output-parser.d.ts +115 -0
- package/dist/embedding-server/mobile/output-parser.js +241 -0
- package/dist/embedding-server/mobile/session-api.d.ts +57 -0
- package/dist/embedding-server/mobile/session-api.js +261 -0
- package/dist/embedding-server/mobile/session-manager.d.ts +135 -0
- package/dist/embedding-server/mobile/session-manager.js +333 -0
- package/dist/embedding-server/mobile/websocket-handler.d.ts +127 -0
- package/dist/embedding-server/mobile/websocket-handler.js +435 -0
- package/dist/embeddings.d.ts +75 -0
- package/dist/embeddings.js +262 -0
- package/dist/errors.d.ts +131 -0
- package/dist/errors.js +225 -0
- package/dist/index.d.ts +32 -0
- package/dist/index.js +193 -0
- package/dist/mama-api.d.ts +954 -0
- package/dist/mama-api.js +2210 -0
- package/dist/memory-inject.d.ts +24 -0
- package/dist/memory-inject.js +116 -0
- package/dist/memory-store.d.ts +103 -0
- package/dist/memory-store.js +129 -0
- package/dist/notification-manager.d.ts +7 -0
- package/dist/notification-manager.js +12 -0
- package/dist/ollama-client.d.ts +51 -0
- package/dist/ollama-client.js +308 -0
- package/dist/outcome-tracker.d.ts +165 -0
- package/dist/outcome-tracker.js +315 -0
- package/dist/progress-indicator.d.ts +48 -0
- package/dist/progress-indicator.js +82 -0
- package/dist/query-intent.d.ts +27 -0
- package/dist/query-intent.js +144 -0
- package/dist/relevance-scorer.d.ts +124 -0
- package/dist/relevance-scorer.js +243 -0
- package/dist/test-utils.d.ts +66 -0
- package/dist/test-utils.js +166 -0
- package/dist/tier-validator.d.ts +55 -0
- package/dist/tier-validator.js +216 -0
- package/dist/time-formatter.d.ts +25 -0
- package/dist/time-formatter.js +93 -0
- package/package.json +3 -2
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* MAMA (Memory-Augmented MCP Architecture) - Outcome Tracker
|
|
4
|
+
*
|
|
5
|
+
* Track decision outcomes from user feedback
|
|
6
|
+
* Tasks: 4.1-4.8 (Failure/success indicators, UserPromptSubmit analysis, outcome marking)
|
|
7
|
+
* AC #3: Failure tracking (user feedback → outcome marked, failure_reason extracted, duration calculated)
|
|
8
|
+
*
|
|
9
|
+
* @module outcome-tracker
|
|
10
|
+
* @version 1.0
|
|
11
|
+
* @date 2025-11-14
|
|
12
|
+
*/
|
|
13
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
+
exports.RECENT_WINDOW_MS = exports.PARTIAL_INDICATORS = exports.SUCCESS_INDICATORS = exports.FAILURE_INDICATORS = void 0;
|
|
15
|
+
exports.matchesFailureIndicators = matchesFailureIndicators;
|
|
16
|
+
exports.matchesSuccessIndicators = matchesSuccessIndicators;
|
|
17
|
+
exports.matchesPartialIndicators = matchesPartialIndicators;
|
|
18
|
+
exports.analyzeOutcome = analyzeOutcome;
|
|
19
|
+
exports.extractFailureReason = extractFailureReason;
|
|
20
|
+
exports.getRecentDecision = getRecentDecision;
|
|
21
|
+
exports.calculateDurationDays = calculateDurationDays;
|
|
22
|
+
exports.getEvidenceImpact = getEvidenceImpact;
|
|
23
|
+
exports.markOutcome = markOutcome;
|
|
24
|
+
exports.onUserPromptSubmit = onUserPromptSubmit;
|
|
25
|
+
const debug_logger_js_1 = require("./debug-logger.js");
|
|
26
|
+
const memory_store_js_1 = require("./memory-store.js");
|
|
27
|
+
const decision_tracker_js_1 = require("./decision-tracker.js");
|
|
28
|
+
/**
|
|
29
|
+
* Failure indicators
|
|
30
|
+
* Task 4.2: Define failure indicators
|
|
31
|
+
*/
|
|
32
|
+
exports.FAILURE_INDICATORS = [
|
|
33
|
+
/doesn't\s*work/i,
|
|
34
|
+
/failed/i,
|
|
35
|
+
/error/i,
|
|
36
|
+
/slow/i,
|
|
37
|
+
/broken/i,
|
|
38
|
+
/bug/i,
|
|
39
|
+
/wrong/i,
|
|
40
|
+
/not\s*working/i,
|
|
41
|
+
];
|
|
42
|
+
/**
|
|
43
|
+
* Success indicators
|
|
44
|
+
* Task 4.3: Define success indicators
|
|
45
|
+
*/
|
|
46
|
+
exports.SUCCESS_INDICATORS = [
|
|
47
|
+
/works/i,
|
|
48
|
+
/perfect/i,
|
|
49
|
+
/great/i,
|
|
50
|
+
/success/i,
|
|
51
|
+
/excellent/i,
|
|
52
|
+
/fast/i,
|
|
53
|
+
/good/i,
|
|
54
|
+
];
|
|
55
|
+
/**
|
|
56
|
+
* Partial success indicators
|
|
57
|
+
* Task 4.3: Define partial success indicators
|
|
58
|
+
*/
|
|
59
|
+
exports.PARTIAL_INDICATORS = [/okay/i, /acceptable/i, /improved/i, /better/i];
|
|
60
|
+
/**
|
|
61
|
+
* Recent decision time window (1 hour in milliseconds)
|
|
62
|
+
* Task 4.5: Only mark outcome if decision is recent (< 1 hour)
|
|
63
|
+
*/
|
|
64
|
+
exports.RECENT_WINDOW_MS = 60 * 60 * 1000; // 1 hour
|
|
65
|
+
/**
|
|
66
|
+
* Check if message matches failure indicators
|
|
67
|
+
*
|
|
68
|
+
* Task 4.2: Match failure patterns
|
|
69
|
+
*
|
|
70
|
+
* @param message - User message
|
|
71
|
+
* @returns True if failure detected
|
|
72
|
+
*/
|
|
73
|
+
function matchesFailureIndicators(message) {
|
|
74
|
+
return exports.FAILURE_INDICATORS.some((pattern) => pattern.test(message));
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Check if message matches success indicators
|
|
78
|
+
*
|
|
79
|
+
* Task 4.3: Match success patterns
|
|
80
|
+
*
|
|
81
|
+
* @param message - User message
|
|
82
|
+
* @returns True if success detected
|
|
83
|
+
*/
|
|
84
|
+
function matchesSuccessIndicators(message) {
|
|
85
|
+
return exports.SUCCESS_INDICATORS.some((pattern) => pattern.test(message));
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Check if message matches partial success indicators
|
|
89
|
+
*
|
|
90
|
+
* Task 4.3: Match partial success patterns
|
|
91
|
+
*
|
|
92
|
+
* @param message - User message
|
|
93
|
+
* @returns True if partial success detected
|
|
94
|
+
*/
|
|
95
|
+
function matchesPartialIndicators(message) {
|
|
96
|
+
return exports.PARTIAL_INDICATORS.some((pattern) => pattern.test(message));
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Determine outcome from user message
|
|
100
|
+
*
|
|
101
|
+
* Task 4.4, 4.5: Analyze user message for indicators
|
|
102
|
+
* AC #3: Failure tracking from user feedback
|
|
103
|
+
*
|
|
104
|
+
* @param message - User message
|
|
105
|
+
* @returns Outcome type ('FAILED', 'SUCCESS', 'PARTIAL') or null
|
|
106
|
+
*/
|
|
107
|
+
function analyzeOutcome(message) {
|
|
108
|
+
if (matchesFailureIndicators(message)) {
|
|
109
|
+
return 'FAILED';
|
|
110
|
+
}
|
|
111
|
+
if (matchesSuccessIndicators(message)) {
|
|
112
|
+
return 'SUCCESS';
|
|
113
|
+
}
|
|
114
|
+
if (matchesPartialIndicators(message)) {
|
|
115
|
+
return 'PARTIAL';
|
|
116
|
+
}
|
|
117
|
+
return null; // No clear outcome
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Extract failure reason from user message
|
|
121
|
+
*
|
|
122
|
+
* Task 4.6: Extract failure_reason from user message
|
|
123
|
+
* AC #3: failure_reason extracted
|
|
124
|
+
*
|
|
125
|
+
* Simple extraction: First sentence or first 200 characters
|
|
126
|
+
* Future: Use LLM for better extraction
|
|
127
|
+
*
|
|
128
|
+
* @param message - User message
|
|
129
|
+
* @param outcome - Outcome type
|
|
130
|
+
* @returns Failure reason
|
|
131
|
+
*/
|
|
132
|
+
function extractFailureReason(message, outcome) {
|
|
133
|
+
if (outcome !== 'FAILED') {
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
136
|
+
// Extract first sentence
|
|
137
|
+
const firstSentence = message.split(/[.!?]/)[0].trim();
|
|
138
|
+
// Limit to 200 characters
|
|
139
|
+
const reason = firstSentence.substring(0, 200);
|
|
140
|
+
return reason || 'User indicated failure';
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Get recent decision (within 1 hour)
|
|
144
|
+
*
|
|
145
|
+
* Task 4.5: Find recent decision (< 1 hour)
|
|
146
|
+
* AC #3: Recent decision (< 1 hour) marked
|
|
147
|
+
*
|
|
148
|
+
* @param sessionId - Session ID
|
|
149
|
+
* @returns Recent decision or null
|
|
150
|
+
*/
|
|
151
|
+
function getRecentDecision(sessionId) {
|
|
152
|
+
const db = (0, memory_store_js_1.getDB)();
|
|
153
|
+
try {
|
|
154
|
+
const now = Date.now();
|
|
155
|
+
const cutoffTime = now - exports.RECENT_WINDOW_MS;
|
|
156
|
+
const recent = db
|
|
157
|
+
.prepare(`
|
|
158
|
+
SELECT * FROM decisions
|
|
159
|
+
WHERE session_id = ?
|
|
160
|
+
AND outcome IS NULL
|
|
161
|
+
AND created_at > ?
|
|
162
|
+
ORDER BY created_at DESC
|
|
163
|
+
LIMIT 1
|
|
164
|
+
`)
|
|
165
|
+
.get(sessionId, cutoffTime);
|
|
166
|
+
return recent || null;
|
|
167
|
+
}
|
|
168
|
+
catch (error) {
|
|
169
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
170
|
+
throw new Error(`Failed to query recent decision: ${message}`);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Calculate duration in days
|
|
175
|
+
*
|
|
176
|
+
* Task 4.7: Calculate duration_days
|
|
177
|
+
* AC #3: duration_days calculated
|
|
178
|
+
*
|
|
179
|
+
* @param createdAt - Decision created timestamp
|
|
180
|
+
* @returns Duration in days
|
|
181
|
+
*/
|
|
182
|
+
function calculateDurationDays(createdAt) {
|
|
183
|
+
const now = Date.now();
|
|
184
|
+
const durationMs = now - createdAt;
|
|
185
|
+
const durationDays = durationMs / (1000 * 60 * 60 * 24);
|
|
186
|
+
// Round to 2 decimal places
|
|
187
|
+
return Math.round(durationDays * 100) / 100;
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Get evidence impact for outcome
|
|
191
|
+
*
|
|
192
|
+
* Task 6: Confidence evolution - Calculate impact based on outcome
|
|
193
|
+
* AC #5: Confidence score calculated based on history
|
|
194
|
+
*
|
|
195
|
+
* @param outcome - Outcome type ('FAILED', 'SUCCESS', 'PARTIAL')
|
|
196
|
+
* @param durationDays - Duration in days
|
|
197
|
+
* @returns Impact on confidence
|
|
198
|
+
*/
|
|
199
|
+
function getEvidenceImpact(outcome, durationDays) {
|
|
200
|
+
// Task 6.3: Define evidence impacts
|
|
201
|
+
let impact = 0;
|
|
202
|
+
switch (outcome) {
|
|
203
|
+
case 'SUCCESS':
|
|
204
|
+
impact = 0.2; // +0.2 for success
|
|
205
|
+
break;
|
|
206
|
+
case 'FAILED':
|
|
207
|
+
impact = -0.3; // -0.3 for failure
|
|
208
|
+
break;
|
|
209
|
+
case 'PARTIAL':
|
|
210
|
+
impact = 0.1; // +0.1 for partial success
|
|
211
|
+
break;
|
|
212
|
+
}
|
|
213
|
+
// Task 6.3: Temporal stability bonus (30+ days)
|
|
214
|
+
if (outcome === 'SUCCESS' && durationDays >= 30) {
|
|
215
|
+
impact += 0.1; // +0.1 for temporal stability
|
|
216
|
+
}
|
|
217
|
+
return impact;
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Mark decision outcome
|
|
221
|
+
*
|
|
222
|
+
* Task 4.8: Update decision row with outcome, failure_reason, duration_days
|
|
223
|
+
* Task 6.5: Update confidence when outcome is marked
|
|
224
|
+
* AC #3: Outcome marked with failure_reason and duration_days
|
|
225
|
+
* AC #5: Confidence evolution
|
|
226
|
+
*
|
|
227
|
+
* @param decisionId - Decision ID
|
|
228
|
+
* @param outcome - Outcome type ('FAILED', 'SUCCESS', 'PARTIAL')
|
|
229
|
+
* @param failureReason - Failure reason (if outcome=FAILED)
|
|
230
|
+
* @param durationDays - Duration in days
|
|
231
|
+
*/
|
|
232
|
+
async function markOutcome(decisionId, outcome, failureReason, durationDays) {
|
|
233
|
+
try {
|
|
234
|
+
// Get current decision to read confidence
|
|
235
|
+
const db = (0, memory_store_js_1.getDB)();
|
|
236
|
+
const decision = db.prepare('SELECT * FROM decisions WHERE id = ?').get(decisionId);
|
|
237
|
+
if (!decision) {
|
|
238
|
+
throw new Error(`Decision not found: ${decisionId}`);
|
|
239
|
+
}
|
|
240
|
+
// Guard against double-marking
|
|
241
|
+
if (decision.outcome) {
|
|
242
|
+
(0, debug_logger_js_1.info)(`[MAMA] Outcome already set for ${decisionId}: ${decision.outcome}`);
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
// Task 6.5: Calculate new confidence
|
|
246
|
+
const evidenceImpact = getEvidenceImpact(outcome, durationDays);
|
|
247
|
+
// Map OutcomeType to EvidenceItem.type (FAILED → failure, not 'failed')
|
|
248
|
+
const outcomeToEvidenceType = {
|
|
249
|
+
SUCCESS: 'success',
|
|
250
|
+
FAILED: 'failure',
|
|
251
|
+
PARTIAL: 'partial',
|
|
252
|
+
};
|
|
253
|
+
const evidence = [
|
|
254
|
+
{ type: outcomeToEvidenceType[outcome], impact: evidenceImpact },
|
|
255
|
+
];
|
|
256
|
+
const prevConfidence = Number(decision.confidence ?? 0);
|
|
257
|
+
const newConfidence = (0, decision_tracker_js_1.updateConfidence)(prevConfidence, evidence);
|
|
258
|
+
// Update decision with outcome and new confidence
|
|
259
|
+
await (0, memory_store_js_1.updateDecisionOutcome)(decisionId, {
|
|
260
|
+
outcome,
|
|
261
|
+
failure_reason: failureReason,
|
|
262
|
+
duration_days: durationDays,
|
|
263
|
+
confidence: newConfidence,
|
|
264
|
+
});
|
|
265
|
+
(0, debug_logger_js_1.info)(`[MAMA] Confidence updated: ${prevConfidence.toFixed(2)} → ${newConfidence.toFixed(2)} (${outcome})`);
|
|
266
|
+
}
|
|
267
|
+
catch (error) {
|
|
268
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
269
|
+
throw new Error(`Failed to mark outcome: ${message}`);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* UserPromptSubmit Handler
|
|
274
|
+
*
|
|
275
|
+
* Task 4.4: On UserPromptSubmit, analyze user message for indicators
|
|
276
|
+
* Task 4.5: If matches + recent decision (< 1 hour), mark outcome
|
|
277
|
+
* Task 4.6: Extract failure_reason from user message
|
|
278
|
+
* Task 4.7: Calculate duration_days
|
|
279
|
+
* Task 4.8: Update decision row
|
|
280
|
+
*
|
|
281
|
+
* AC #3: Failure tracking (user feedback → outcome marked)
|
|
282
|
+
*
|
|
283
|
+
* @param hookContext - Hook context from Claude Code
|
|
284
|
+
*/
|
|
285
|
+
async function onUserPromptSubmit(hookContext) {
|
|
286
|
+
try {
|
|
287
|
+
const userMessage = hookContext.user_message || '';
|
|
288
|
+
const sessionId = hookContext.session_id || '';
|
|
289
|
+
// Task 4.4: Analyze user message for outcome
|
|
290
|
+
const outcome = analyzeOutcome(userMessage);
|
|
291
|
+
if (!outcome) {
|
|
292
|
+
// No clear outcome detected
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
// Task 4.5: Find recent decision (< 1 hour)
|
|
296
|
+
const recentDecision = getRecentDecision(sessionId);
|
|
297
|
+
if (!recentDecision) {
|
|
298
|
+
// No recent decision to mark
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
// Task 4.6: Extract failure reason
|
|
302
|
+
const failureReason = extractFailureReason(userMessage, outcome);
|
|
303
|
+
// Task 4.7: Calculate duration
|
|
304
|
+
const durationDays = calculateDurationDays(recentDecision.created_at);
|
|
305
|
+
// Task 4.8: Mark outcome
|
|
306
|
+
await markOutcome(recentDecision.id, outcome, failureReason, durationDays);
|
|
307
|
+
(0, debug_logger_js_1.info)(`[MAMA] Outcome marked: ${recentDecision.id} → ${outcome} (${durationDays} days)`);
|
|
308
|
+
}
|
|
309
|
+
catch (error) {
|
|
310
|
+
// Log error but don't crash hook
|
|
311
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
312
|
+
(0, debug_logger_js_1.error)(`[MAMA] Outcome tracking failed: ${message}`);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
//# sourceMappingURL=outcome-tracker.js.map
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MAMA Progress Indicator
|
|
3
|
+
*
|
|
4
|
+
* Text-based progress feedback for long-running operations.
|
|
5
|
+
* Helps first-time users understand what's happening during initialization.
|
|
6
|
+
*
|
|
7
|
+
* Features:
|
|
8
|
+
* - Logs to stderr (no stdout pollution)
|
|
9
|
+
* - Emoji indicators: ⏳ (loading), ✅ (done), ❌ (error)
|
|
10
|
+
* - Concise messages (<50 chars)
|
|
11
|
+
*
|
|
12
|
+
* @module progress-indicator
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* Log progress message to stderr
|
|
16
|
+
*
|
|
17
|
+
* Format: [MAMA] emoji message
|
|
18
|
+
* Example: [MAMA] ⏳ Downloading embedding model (120MB)...
|
|
19
|
+
*
|
|
20
|
+
* @param message - Progress message (without emoji or prefix)
|
|
21
|
+
* @param emoji - Emoji indicator (⏳, ✅, ❌, 🔍, etc.)
|
|
22
|
+
*/
|
|
23
|
+
export declare function logProgress(message: string, emoji?: string): void;
|
|
24
|
+
/**
|
|
25
|
+
* Log completion message
|
|
26
|
+
*/
|
|
27
|
+
export declare function logComplete(message: string): void;
|
|
28
|
+
/**
|
|
29
|
+
* Log failure/error message (user-facing progress indicator)
|
|
30
|
+
*
|
|
31
|
+
* Note: Named logFailed to avoid confusion with debug-logger's logError
|
|
32
|
+
* which is used for internal debugging. This is for user-facing progress.
|
|
33
|
+
*/
|
|
34
|
+
export declare function logFailed(message: string): void;
|
|
35
|
+
export declare const logError: typeof logFailed;
|
|
36
|
+
/**
|
|
37
|
+
* Log info message
|
|
38
|
+
*/
|
|
39
|
+
export declare function logInfo(message: string): void;
|
|
40
|
+
/**
|
|
41
|
+
* Log loading message
|
|
42
|
+
*/
|
|
43
|
+
export declare function logLoading(message: string): void;
|
|
44
|
+
/**
|
|
45
|
+
* Log searching message
|
|
46
|
+
*/
|
|
47
|
+
export declare function logSearching(message: string): void;
|
|
48
|
+
//# sourceMappingURL=progress-indicator.d.ts.map
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* MAMA Progress Indicator
|
|
4
|
+
*
|
|
5
|
+
* Text-based progress feedback for long-running operations.
|
|
6
|
+
* Helps first-time users understand what's happening during initialization.
|
|
7
|
+
*
|
|
8
|
+
* Features:
|
|
9
|
+
* - Logs to stderr (no stdout pollution)
|
|
10
|
+
* - Emoji indicators: ⏳ (loading), ✅ (done), ❌ (error)
|
|
11
|
+
* - Concise messages (<50 chars)
|
|
12
|
+
*
|
|
13
|
+
* @module progress-indicator
|
|
14
|
+
*/
|
|
15
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
+
exports.logError = void 0;
|
|
17
|
+
exports.logProgress = logProgress;
|
|
18
|
+
exports.logComplete = logComplete;
|
|
19
|
+
exports.logFailed = logFailed;
|
|
20
|
+
exports.logInfo = logInfo;
|
|
21
|
+
exports.logLoading = logLoading;
|
|
22
|
+
exports.logSearching = logSearching;
|
|
23
|
+
/**
|
|
24
|
+
* Log progress message to stderr
|
|
25
|
+
*
|
|
26
|
+
* Format: [MAMA] emoji message
|
|
27
|
+
* Example: [MAMA] ⏳ Downloading embedding model (120MB)...
|
|
28
|
+
*
|
|
29
|
+
* @param message - Progress message (without emoji or prefix)
|
|
30
|
+
* @param emoji - Emoji indicator (⏳, ✅, ❌, 🔍, etc.)
|
|
31
|
+
*/
|
|
32
|
+
function logProgress(message, emoji = '⏳') {
|
|
33
|
+
// Ensure message is a string - warn in development if not
|
|
34
|
+
if (typeof message !== 'string') {
|
|
35
|
+
if (process.env.NODE_ENV === 'development' || process.env.MAMA_DEBUG) {
|
|
36
|
+
console.error(`[MAMA] ⚠️ logProgress expected string, got ${typeof message}`);
|
|
37
|
+
}
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
// Log to stderr to avoid stdout pollution
|
|
41
|
+
// stderr is used for progress/diagnostic output
|
|
42
|
+
console.error(`[MAMA] ${emoji} ${message}`);
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Log completion message
|
|
46
|
+
*/
|
|
47
|
+
function logComplete(message) {
|
|
48
|
+
logProgress(message, '✅');
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Log failure/error message (user-facing progress indicator)
|
|
52
|
+
*
|
|
53
|
+
* Note: Named logFailed to avoid confusion with debug-logger's logError
|
|
54
|
+
* which is used for internal debugging. This is for user-facing progress.
|
|
55
|
+
*/
|
|
56
|
+
function logFailed(message) {
|
|
57
|
+
logProgress(message, '❌');
|
|
58
|
+
}
|
|
59
|
+
// Alias for backward compatibility
|
|
60
|
+
exports.logError = logFailed;
|
|
61
|
+
/**
|
|
62
|
+
* Log info message
|
|
63
|
+
*/
|
|
64
|
+
function logInfo(message) {
|
|
65
|
+
logProgress(message, 'ℹ️');
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Log loading message
|
|
69
|
+
*/
|
|
70
|
+
function logLoading(message) {
|
|
71
|
+
logProgress(message, '⏳');
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Log searching message
|
|
75
|
+
*/
|
|
76
|
+
function logSearching(message) {
|
|
77
|
+
logProgress(message, '🔍');
|
|
78
|
+
}
|
|
79
|
+
// Note: Removed auto-registered SIGINT/SIGTERM handlers that called process.exit(0)
|
|
80
|
+
// This was causing issues with host cleanup in parent processes.
|
|
81
|
+
// If graceful shutdown is needed, the host application should handle it.
|
|
82
|
+
//# sourceMappingURL=progress-indicator.js.map
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MAMA (Memory-Augmented MCP Architecture) - Query Intent Analysis
|
|
3
|
+
*
|
|
4
|
+
* Analyzes user queries to detect decision-related intent using EXAONE 3.5
|
|
5
|
+
* Tasks: 2.1-2.8 (LLM intent analysis with fallback chain)
|
|
6
|
+
*
|
|
7
|
+
* @module query-intent
|
|
8
|
+
*/
|
|
9
|
+
export interface IntentResult {
|
|
10
|
+
involves_decision: boolean;
|
|
11
|
+
topic: string | null;
|
|
12
|
+
confidence: number;
|
|
13
|
+
reasoning: string;
|
|
14
|
+
}
|
|
15
|
+
export interface AnalyzeOptions {
|
|
16
|
+
timeout?: number;
|
|
17
|
+
threshold?: number;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Analyze user message for decision-related intent
|
|
21
|
+
*/
|
|
22
|
+
export declare function analyzeIntent(userMessage: string, options?: AnalyzeOptions): Promise<IntentResult>;
|
|
23
|
+
/**
|
|
24
|
+
* Extract topic keywords from user message (fallback method)
|
|
25
|
+
*/
|
|
26
|
+
export declare function extractTopicKeywords(userMessage: string): IntentResult;
|
|
27
|
+
//# sourceMappingURL=query-intent.d.ts.map
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* MAMA (Memory-Augmented MCP Architecture) - Query Intent Analysis
|
|
4
|
+
*
|
|
5
|
+
* Analyzes user queries to detect decision-related intent using EXAONE 3.5
|
|
6
|
+
* Tasks: 2.1-2.8 (LLM intent analysis with fallback chain)
|
|
7
|
+
*
|
|
8
|
+
* @module query-intent
|
|
9
|
+
*/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.analyzeIntent = analyzeIntent;
|
|
12
|
+
exports.extractTopicKeywords = extractTopicKeywords;
|
|
13
|
+
const debug_logger_js_1 = require("./debug-logger.js");
|
|
14
|
+
const ollama_client_js_1 = require("./ollama-client.js");
|
|
15
|
+
/**
|
|
16
|
+
* Analyze user message for decision-related intent
|
|
17
|
+
*/
|
|
18
|
+
async function analyzeIntent(userMessage, options = {}) {
|
|
19
|
+
const { timeout = 5000, // Increased: LLM needs time, user accepts longer thinking
|
|
20
|
+
threshold = 0.6, } = options;
|
|
21
|
+
try {
|
|
22
|
+
// Task 2.2: Build prompt for decision-making analysis
|
|
23
|
+
const prompt = `
|
|
24
|
+
Analyze if this query involves decision-making or past choices:
|
|
25
|
+
|
|
26
|
+
User Message: "${userMessage}"
|
|
27
|
+
|
|
28
|
+
Decision Indicators:
|
|
29
|
+
1. References to past decisions ("we chose X", "last time we did Y")
|
|
30
|
+
2. Questions about previous approaches ("why did we use X?")
|
|
31
|
+
3. Decision evolution queries ("should we change from X to Y?")
|
|
32
|
+
4. Architecture/strategy questions
|
|
33
|
+
5. Method/approach questions ("how do I...", "what's the way to...")
|
|
34
|
+
6. Best practice questions ("what should I use for...", "which one should I use...")
|
|
35
|
+
|
|
36
|
+
Return JSON with "topic" as a short snake_case identifier (e.g., "mesh_structure", "database_choice", "auth_strategy", "coding_style", "error_handling"):
|
|
37
|
+
{
|
|
38
|
+
"involves_decision": boolean,
|
|
39
|
+
"topic": string or null (extract main technical topic in snake_case),
|
|
40
|
+
"confidence": 0.0-1.0,
|
|
41
|
+
"reasoning": "brief explanation"
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
IMPORTANT: Generate "topic" freely based on the message content. Do NOT limit to predefined values.
|
|
45
|
+
|
|
46
|
+
Examples:
|
|
47
|
+
- "Why did we choose COMPLEX mesh structure?" → {"involves_decision": true, "topic": "mesh_structure", "confidence": 0.9}
|
|
48
|
+
- "Let's use PostgreSQL for database" → {"involves_decision": true, "topic": "database_choice", "confidence": 0.9}
|
|
49
|
+
- "How should we store workflow data?" → {"involves_decision": true, "topic": "workflow_storage", "confidence": 0.85}
|
|
50
|
+
- "Read the file please" → {"involves_decision": false, "topic": null, "confidence": 0.1}
|
|
51
|
+
`.trim();
|
|
52
|
+
// Task 2.3: Call EXAONE 3.5 with Tier 1 fallback
|
|
53
|
+
const result = await generateWithFallback(prompt, {
|
|
54
|
+
format: 'json',
|
|
55
|
+
temperature: 0.3,
|
|
56
|
+
max_tokens: 200,
|
|
57
|
+
timeout,
|
|
58
|
+
});
|
|
59
|
+
// Task 2.4: Parse response
|
|
60
|
+
const parsed = (typeof result === 'string' ? JSON.parse(result) : result);
|
|
61
|
+
// Task 2.5: Threshold check
|
|
62
|
+
const meetsThreshold = parsed.confidence >= threshold;
|
|
63
|
+
if (!meetsThreshold) {
|
|
64
|
+
(0, debug_logger_js_1.info)(`[MAMA] Intent confidence ${parsed.confidence} below threshold ${threshold}`);
|
|
65
|
+
return {
|
|
66
|
+
involves_decision: false,
|
|
67
|
+
topic: null,
|
|
68
|
+
confidence: parsed.confidence,
|
|
69
|
+
reasoning: 'Confidence below threshold',
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
return parsed;
|
|
73
|
+
}
|
|
74
|
+
catch (error) {
|
|
75
|
+
// CLAUDE.md Rule #1: NO FALLBACK
|
|
76
|
+
// Errors must be thrown for debugging
|
|
77
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
78
|
+
(0, debug_logger_js_1.error)(`[MAMA] Intent analysis FAILED: ${message}`);
|
|
79
|
+
throw new Error(`Intent analysis failed: ${message}`);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Generate with tiered fallback chain
|
|
84
|
+
*/
|
|
85
|
+
async function generateWithFallback(prompt, options = {}) {
|
|
86
|
+
const models = [
|
|
87
|
+
ollama_client_js_1.DEFAULT_MODEL, // Tier 1: EXAONE 3.5 (2.4B)
|
|
88
|
+
ollama_client_js_1.FALLBACK_MODEL, // Tier 2: Gemma 2B
|
|
89
|
+
'qwen:3b', // Tier 3: Qwen 3B
|
|
90
|
+
];
|
|
91
|
+
for (let i = 0; i < models.length; i++) {
|
|
92
|
+
const model = models[i];
|
|
93
|
+
try {
|
|
94
|
+
(0, debug_logger_js_1.info)(`[MAMA] Trying ${model}...`);
|
|
95
|
+
const result = await (0, ollama_client_js_1.generate)(prompt, {
|
|
96
|
+
...options,
|
|
97
|
+
model,
|
|
98
|
+
});
|
|
99
|
+
(0, debug_logger_js_1.info)(`[MAMA] ${model} succeeded`);
|
|
100
|
+
return result;
|
|
101
|
+
}
|
|
102
|
+
catch (error) {
|
|
103
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
104
|
+
(0, debug_logger_js_1.warn)(`[MAMA] ${model} failed: ${message}`);
|
|
105
|
+
// Continue to next tier
|
|
106
|
+
if (i === models.length - 1) {
|
|
107
|
+
// All tiers failed
|
|
108
|
+
throw new Error(`All LLM tiers failed. Last error: ${message}`);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
// Unreachable: loop always returns or throws
|
|
113
|
+
throw new Error('Unexpected: all LLM tiers exhausted without result');
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Extract topic keywords from user message (fallback method)
|
|
117
|
+
*/
|
|
118
|
+
function extractTopicKeywords(userMessage) {
|
|
119
|
+
const topicPatterns = {
|
|
120
|
+
workflow_storage: /workflow|save|persist/i,
|
|
121
|
+
mesh_structure: /mesh|structure/i,
|
|
122
|
+
authentication: /auth|jwt|oauth|login/i,
|
|
123
|
+
testing: /test|jest|spec/i,
|
|
124
|
+
architecture: /architecture|design/i,
|
|
125
|
+
coding_style: /style|format|coding/i,
|
|
126
|
+
};
|
|
127
|
+
for (const [topic, pattern] of Object.entries(topicPatterns)) {
|
|
128
|
+
if (pattern.test(userMessage)) {
|
|
129
|
+
return {
|
|
130
|
+
involves_decision: true,
|
|
131
|
+
topic,
|
|
132
|
+
confidence: 0.5, // Lower confidence for keyword matching
|
|
133
|
+
reasoning: 'Keyword-based detection (LLM fallback)',
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return {
|
|
138
|
+
involves_decision: false,
|
|
139
|
+
topic: null,
|
|
140
|
+
confidence: 0.0,
|
|
141
|
+
reasoning: 'No topic keywords found',
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
//# sourceMappingURL=query-intent.js.map
|