@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.
Files changed (67) hide show
  1. package/dist/config-loader.d.ts +61 -0
  2. package/dist/config-loader.js +187 -0
  3. package/dist/db-adapter/base-adapter.d.ts +76 -0
  4. package/dist/db-adapter/base-adapter.js +11 -0
  5. package/dist/db-adapter/index.d.ts +24 -0
  6. package/dist/db-adapter/index.js +29 -0
  7. package/dist/db-adapter/sqlite-adapter.d.ts +73 -0
  8. package/dist/db-adapter/sqlite-adapter.js +330 -0
  9. package/dist/db-adapter/statement.d.ts +119 -0
  10. package/dist/db-adapter/statement.js +113 -0
  11. package/dist/db-manager.d.ts +252 -0
  12. package/dist/db-manager.js +622 -0
  13. package/dist/debug-logger.d.ts +32 -0
  14. package/dist/debug-logger.js +83 -0
  15. package/dist/decision-formatter.d.ts +172 -0
  16. package/dist/decision-formatter.js +894 -0
  17. package/dist/decision-tracker.d.ts +218 -0
  18. package/dist/decision-tracker.js +531 -0
  19. package/dist/embedding-cache.d.ts +83 -0
  20. package/dist/embedding-cache.js +182 -0
  21. package/dist/embedding-client.d.ts +43 -0
  22. package/dist/embedding-client.js +132 -0
  23. package/dist/embedding-server/index.d.ts +65 -0
  24. package/dist/embedding-server/index.js +397 -0
  25. package/dist/embedding-server/mobile/auth.d.ts +53 -0
  26. package/dist/embedding-server/mobile/auth.js +140 -0
  27. package/dist/embedding-server/mobile/daemon.d.ts +128 -0
  28. package/dist/embedding-server/mobile/daemon.js +303 -0
  29. package/dist/embedding-server/mobile/output-parser.d.ts +115 -0
  30. package/dist/embedding-server/mobile/output-parser.js +241 -0
  31. package/dist/embedding-server/mobile/session-api.d.ts +57 -0
  32. package/dist/embedding-server/mobile/session-api.js +261 -0
  33. package/dist/embedding-server/mobile/session-manager.d.ts +135 -0
  34. package/dist/embedding-server/mobile/session-manager.js +333 -0
  35. package/dist/embedding-server/mobile/websocket-handler.d.ts +127 -0
  36. package/dist/embedding-server/mobile/websocket-handler.js +435 -0
  37. package/dist/embeddings.d.ts +75 -0
  38. package/dist/embeddings.js +262 -0
  39. package/dist/errors.d.ts +131 -0
  40. package/dist/errors.js +225 -0
  41. package/dist/index.d.ts +32 -0
  42. package/dist/index.js +193 -0
  43. package/dist/mama-api.d.ts +954 -0
  44. package/dist/mama-api.js +2210 -0
  45. package/dist/memory-inject.d.ts +24 -0
  46. package/dist/memory-inject.js +116 -0
  47. package/dist/memory-store.d.ts +103 -0
  48. package/dist/memory-store.js +129 -0
  49. package/dist/notification-manager.d.ts +7 -0
  50. package/dist/notification-manager.js +12 -0
  51. package/dist/ollama-client.d.ts +51 -0
  52. package/dist/ollama-client.js +308 -0
  53. package/dist/outcome-tracker.d.ts +165 -0
  54. package/dist/outcome-tracker.js +315 -0
  55. package/dist/progress-indicator.d.ts +48 -0
  56. package/dist/progress-indicator.js +82 -0
  57. package/dist/query-intent.d.ts +27 -0
  58. package/dist/query-intent.js +144 -0
  59. package/dist/relevance-scorer.d.ts +124 -0
  60. package/dist/relevance-scorer.js +243 -0
  61. package/dist/test-utils.d.ts +66 -0
  62. package/dist/test-utils.js +166 -0
  63. package/dist/tier-validator.d.ts +55 -0
  64. package/dist/tier-validator.js +216 -0
  65. package/dist/time-formatter.d.ts +25 -0
  66. package/dist/time-formatter.js +93 -0
  67. 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