claude-brain 0.14.2 → 0.14.4
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/README.md +191 -191
- package/VERSION +1 -1
- package/assets/CLAUDE-unified.md +11 -11
- package/assets/CLAUDE.md +11 -11
- package/bunfig.toml +8 -8
- package/package.json +80 -80
- package/packs/backend/node.json +173 -173
- package/packs/core/javascript.json +176 -176
- package/packs/core/typescript.json +222 -222
- package/packs/frontend/react.json +254 -254
- package/packs/meta/testing.json +172 -172
- package/src/automation/auto-context.ts +240 -240
- package/src/automation/decision-detector.ts +452 -452
- package/src/automation/index.ts +11 -11
- package/src/automation/phase12-manager.ts +456 -456
- package/src/automation/proactive-recall.ts +373 -373
- package/src/automation/project-detector.ts +310 -310
- package/src/automation/repo-scanner.ts +205 -205
- package/src/cli/auto-setup.ts +82 -82
- package/src/cli/bin.ts +202 -202
- package/src/cli/commands/chroma.ts +573 -573
- package/src/cli/commands/git-hook.ts +189 -189
- package/src/cli/commands/hooks.ts +213 -213
- package/src/cli/commands/init.ts +122 -122
- package/src/cli/commands/install-mcp.ts +92 -92
- package/src/cli/commands/pack.ts +197 -197
- package/src/cli/commands/serve.ts +167 -167
- package/src/cli/commands/start.ts +42 -42
- package/src/cli/commands/uninstall-mcp.ts +41 -41
- package/src/cli/commands/update.ts +121 -121
- package/src/cli/diagnose.ts +4 -4
- package/src/cli/health-check.ts +4 -4
- package/src/cli/migrate-chroma.ts +106 -106
- package/src/cli/setup.ts +4 -4
- package/src/cli/ui/animations.ts +80 -80
- package/src/cli/ui/components.ts +82 -82
- package/src/cli/ui/index.ts +4 -4
- package/src/cli/ui/logo.ts +36 -36
- package/src/cli/ui/theme.ts +55 -55
- package/src/config/defaults.ts +50 -50
- package/src/config/home.ts +55 -55
- package/src/config/index.ts +7 -7
- package/src/config/loader.ts +166 -166
- package/src/config/migration.ts +76 -76
- package/src/config/schema.ts +360 -360
- package/src/config/validator.ts +184 -184
- package/src/config/watcher.ts +86 -86
- package/src/context/assembler.ts +398 -398
- package/src/context/cache-manager.ts +101 -101
- package/src/context/formatter.ts +84 -84
- package/src/context/hierarchy.ts +85 -85
- package/src/context/index.ts +83 -83
- package/src/context/progress-tracker.ts +174 -174
- package/src/context/standards-manager.ts +287 -287
- package/src/context/types.ts +252 -252
- package/src/context/validator.ts +58 -58
- package/src/diagnostics/index.ts +123 -123
- package/src/health/index.ts +229 -229
- package/src/hooks/brain-hook.ts +112 -112
- package/src/hooks/capture.ts +168 -168
- package/src/hooks/deduplicator.ts +72 -72
- package/src/hooks/git-capture.ts +109 -109
- package/src/hooks/git-hook-installer.ts +207 -207
- package/src/hooks/index.ts +20 -20
- package/src/hooks/installer.ts +191 -194
- package/src/hooks/passive-classifier.ts +366 -366
- package/src/hooks/queue.ts +129 -129
- package/src/hooks/session-tracker.ts +275 -275
- package/src/hooks/types.ts +47 -47
- package/src/index.ts +7 -7
- package/src/intelligence/cross-project/affinity.ts +162 -162
- package/src/intelligence/cross-project/generalizer.ts +283 -283
- package/src/intelligence/cross-project/index.ts +13 -13
- package/src/intelligence/cross-project/transfer.ts +201 -201
- package/src/intelligence/index.ts +24 -24
- package/src/intelligence/optimization/index.ts +10 -10
- package/src/intelligence/optimization/precompute.ts +202 -202
- package/src/intelligence/optimization/semantic-cache.ts +207 -207
- package/src/intelligence/prediction/context-anticipator.ts +198 -198
- package/src/intelligence/prediction/decision-predictor.ts +184 -184
- package/src/intelligence/prediction/index.ts +13 -13
- package/src/intelligence/prediction/recommender.ts +268 -268
- package/src/intelligence/reasoning/chain-retrieval.ts +247 -247
- package/src/intelligence/reasoning/counterfactual.ts +248 -248
- package/src/intelligence/reasoning/index.ts +13 -13
- package/src/intelligence/reasoning/synthesizer.ts +169 -169
- package/src/intelligence/temporal/evolution.ts +197 -197
- package/src/intelligence/temporal/index.ts +16 -16
- package/src/intelligence/temporal/query-processor.ts +190 -190
- package/src/intelligence/temporal/timeline.ts +259 -259
- package/src/intelligence/temporal/trends.ts +263 -263
- package/src/knowledge/entity-extractor.ts +416 -416
- package/src/knowledge/graph/builder.ts +185 -185
- package/src/knowledge/graph/linker.ts +201 -201
- package/src/knowledge/graph/memory-graph.ts +359 -359
- package/src/knowledge/graph/schema.ts +99 -99
- package/src/knowledge/graph/search.ts +168 -168
- package/src/knowledge/relationship-extractor.ts +108 -108
- package/src/memory/chroma/client.ts +174 -174
- package/src/memory/chroma/collection-manager.ts +94 -94
- package/src/memory/chroma/config.ts +57 -57
- package/src/memory/chroma/embeddings.ts +153 -153
- package/src/memory/chroma/index.ts +82 -82
- package/src/memory/chroma/migration.ts +270 -270
- package/src/memory/chroma/schemas.ts +69 -69
- package/src/memory/chroma/search.ts +315 -315
- package/src/memory/chroma/store.ts +741 -741
- package/src/memory/consolidation/archiver.ts +164 -164
- package/src/memory/consolidation/merger.ts +186 -186
- package/src/memory/consolidation/scorer.ts +138 -138
- package/src/memory/context-builder.ts +236 -236
- package/src/memory/database.ts +169 -169
- package/src/memory/embedding-utils.ts +156 -156
- package/src/memory/embeddings.ts +226 -226
- package/src/memory/episodic/detector.ts +108 -108
- package/src/memory/episodic/manager.ts +351 -351
- package/src/memory/episodic/summarizer.ts +179 -179
- package/src/memory/episodic/types.ts +52 -52
- package/src/memory/index.ts +582 -582
- package/src/memory/knowledge-extractor.ts +455 -455
- package/src/memory/learning.ts +378 -378
- package/src/memory/patterns.ts +396 -396
- package/src/memory/schema.ts +88 -88
- package/src/memory/search.ts +309 -309
- package/src/memory/store.ts +787 -787
- package/src/memory/types.ts +121 -121
- package/src/orchestrator/coordinator.ts +272 -272
- package/src/orchestrator/decision-logger.ts +228 -228
- package/src/orchestrator/event-emitter.ts +198 -198
- package/src/orchestrator/event-queue.ts +184 -184
- package/src/orchestrator/handlers/base-handler.ts +70 -70
- package/src/orchestrator/handlers/context-handler.ts +73 -73
- package/src/orchestrator/handlers/decision-handler.ts +204 -204
- package/src/orchestrator/handlers/index.ts +10 -10
- package/src/orchestrator/handlers/status-handler.ts +131 -131
- package/src/orchestrator/handlers/task-handler.ts +171 -171
- package/src/orchestrator/index.ts +275 -275
- package/src/orchestrator/task-parser.ts +284 -284
- package/src/orchestrator/types.ts +98 -98
- package/src/packs/index.ts +9 -9
- package/src/packs/loader.ts +134 -134
- package/src/packs/manager.ts +204 -204
- package/src/packs/ranker.ts +78 -78
- package/src/packs/types.ts +81 -81
- package/src/phase12/index.ts +5 -5
- package/src/retrieval/bm25/index.ts +300 -300
- package/src/retrieval/bm25/tokenizer.ts +184 -184
- package/src/retrieval/feedback/adaptive.ts +223 -223
- package/src/retrieval/feedback/index.ts +16 -16
- package/src/retrieval/feedback/metrics.ts +223 -223
- package/src/retrieval/feedback/store.ts +283 -283
- package/src/retrieval/fusion/index.ts +194 -194
- package/src/retrieval/fusion/rrf.ts +163 -163
- package/src/retrieval/index.ts +12 -12
- package/src/retrieval/pipeline.ts +375 -375
- package/src/retrieval/query/expander.ts +198 -198
- package/src/retrieval/query/index.ts +27 -27
- package/src/retrieval/query/intent-classifier.ts +236 -236
- package/src/retrieval/query/temporal-parser.ts +295 -295
- package/src/retrieval/reranker/index.ts +188 -188
- package/src/retrieval/reranker/model.ts +95 -95
- package/src/retrieval/service.ts +125 -125
- package/src/retrieval/types.ts +162 -162
- package/src/routing/entity-extractor.ts +428 -428
- package/src/routing/intent-classifier.ts +436 -436
- package/src/routing/response-filter.ts +258 -254
- package/src/routing/router.ts +1322 -1314
- package/src/routing/search-engine.ts +475 -475
- package/src/routing/types.ts +94 -84
- package/src/scripts/health-check.ts +118 -118
- package/src/scripts/setup.ts +122 -122
- package/src/server/handlers/call-tool.ts +156 -156
- package/src/server/handlers/index.ts +9 -9
- package/src/server/handlers/list-tools.ts +35 -35
- package/src/server/handlers/tools/analyze-decision-evolution.ts +151 -151
- package/src/server/handlers/tools/auto-remember.ts +200 -200
- package/src/server/handlers/tools/brain.ts +85 -85
- package/src/server/handlers/tools/create-project.ts +135 -135
- package/src/server/handlers/tools/detect-trends.ts +144 -144
- package/src/server/handlers/tools/find-cross-project-patterns.ts +168 -168
- package/src/server/handlers/tools/get-activity-log.ts +194 -194
- package/src/server/handlers/tools/get-code-standards.ts +124 -124
- package/src/server/handlers/tools/get-corrections.ts +154 -154
- package/src/server/handlers/tools/get-decision-timeline.ts +172 -172
- package/src/server/handlers/tools/get-episode.ts +103 -103
- package/src/server/handlers/tools/get-patterns.ts +158 -158
- package/src/server/handlers/tools/get-phase12-status.ts +63 -63
- package/src/server/handlers/tools/get-project-context.ts +75 -75
- package/src/server/handlers/tools/get-recommendations.ts +145 -145
- package/src/server/handlers/tools/index.ts +31 -31
- package/src/server/handlers/tools/init-project.ts +757 -757
- package/src/server/handlers/tools/list-episodes.ts +90 -90
- package/src/server/handlers/tools/list-projects.ts +125 -125
- package/src/server/handlers/tools/rate-memory.ts +101 -101
- package/src/server/handlers/tools/recall-similar.ts +87 -87
- package/src/server/handlers/tools/recognize-pattern.ts +126 -126
- package/src/server/handlers/tools/record-correction.ts +125 -125
- package/src/server/handlers/tools/remember-decision.ts +153 -153
- package/src/server/handlers/tools/schemas.ts +253 -253
- package/src/server/handlers/tools/search-knowledge-graph.ts +102 -102
- package/src/server/handlers/tools/smart-context.ts +146 -146
- package/src/server/handlers/tools/update-progress.ts +131 -131
- package/src/server/handlers/tools/what-if-analysis.ts +135 -135
- package/src/server/http-api.ts +693 -693
- package/src/server/index.ts +40 -40
- package/src/server/mcp-server.ts +283 -283
- package/src/server/providers/index.ts +7 -7
- package/src/server/providers/prompts.ts +327 -327
- package/src/server/providers/resources.ts +622 -622
- package/src/server/services.ts +468 -468
- package/src/server/types.ts +39 -39
- package/src/server/utils/error-handler.ts +155 -155
- package/src/server/utils/index.ts +13 -13
- package/src/server/utils/memory-indicator.ts +83 -83
- package/src/server/utils/request-context.ts +122 -122
- package/src/server/utils/response-formatter.ts +129 -124
- package/src/server/utils/validators.ts +210 -210
- package/src/setup/index.ts +48 -48
- package/src/setup/wizard.ts +461 -461
- package/src/tools/index.ts +24 -24
- package/src/tools/registry.ts +115 -115
- package/src/tools/schemas.test.ts +30 -30
- package/src/tools/schemas.ts +617 -617
- package/src/tools/types.ts +412 -412
- package/src/utils/circuit-breaker.ts +130 -130
- package/src/utils/cleanup.ts +34 -34
- package/src/utils/error-handler.ts +132 -132
- package/src/utils/error-messages.ts +60 -60
- package/src/utils/fallback.ts +45 -45
- package/src/utils/index.ts +54 -54
- package/src/utils/logger-utils.ts +80 -80
- package/src/utils/logger.ts +88 -88
- package/src/utils/phase12-helper.ts +56 -56
- package/src/utils/retry.ts +94 -94
- package/src/utils/timing.ts +47 -47
- package/src/utils/transaction.ts +63 -63
- package/src/vault/frontmatter.ts +264 -264
- package/src/vault/index.ts +318 -318
- package/src/vault/paths.ts +106 -106
- package/src/vault/query.ts +422 -422
- package/src/vault/reader.ts +264 -264
- package/src/vault/templates.ts +186 -186
- package/src/vault/types.ts +73 -73
- package/src/vault/watcher.ts +277 -277
- package/src/vault/writer.ts +413 -413
- package/tsconfig.json +30 -30
package/src/memory/learning.ts
CHANGED
|
@@ -1,378 +1,378 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Learning System
|
|
3
|
-
* Phase 12: Advanced Memory & Intelligent Automation
|
|
4
|
-
*
|
|
5
|
-
* Learns from corrections and user preferences over time
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import type { Logger } from 'pino'
|
|
9
|
-
import type { MemoryManager } from './index'
|
|
10
|
-
|
|
11
|
-
export interface Correction {
|
|
12
|
-
id: string
|
|
13
|
-
originalDecision: string
|
|
14
|
-
correctedDecision: string
|
|
15
|
-
reasoning: string
|
|
16
|
-
project: string
|
|
17
|
-
timestamp: Date
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export interface Preference {
|
|
21
|
-
category: string
|
|
22
|
-
preference: string
|
|
23
|
-
strength: number // 0-1
|
|
24
|
-
examples: string[]
|
|
25
|
-
lastUpdated: Date
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export interface LearningInsights {
|
|
29
|
-
preferences: Preference[]
|
|
30
|
-
correctionCount: number
|
|
31
|
-
categoriesImproved: string[]
|
|
32
|
-
recentCorrections: Correction[]
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export class LearningSystem {
|
|
36
|
-
private logger: Logger
|
|
37
|
-
private memory: MemoryManager
|
|
38
|
-
private corrections: Correction[] = []
|
|
39
|
-
private preferences: Map<string, Preference> = new Map()
|
|
40
|
-
|
|
41
|
-
constructor(logger: Logger, memory: MemoryManager) {
|
|
42
|
-
this.logger = logger.child({ component: 'learning-system' })
|
|
43
|
-
this.memory = memory
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Record a correction
|
|
48
|
-
*/
|
|
49
|
-
async recordCorrection(
|
|
50
|
-
originalDecision: string,
|
|
51
|
-
correctedDecision: string,
|
|
52
|
-
reasoning: string,
|
|
53
|
-
project: string
|
|
54
|
-
): Promise<string> {
|
|
55
|
-
const correction: Correction = {
|
|
56
|
-
id: this.generateId(),
|
|
57
|
-
originalDecision,
|
|
58
|
-
correctedDecision,
|
|
59
|
-
reasoning,
|
|
60
|
-
project,
|
|
61
|
-
timestamp: new Date()
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
this.corrections.push(correction)
|
|
65
|
-
|
|
66
|
-
// Store in memory system
|
|
67
|
-
try {
|
|
68
|
-
await this.memory.store.storeMemory({
|
|
69
|
-
project,
|
|
70
|
-
content: `Correction: Changed "${originalDecision}" to "${correctedDecision}". Reason: ${reasoning}`,
|
|
71
|
-
metadata: {
|
|
72
|
-
type: 'correction',
|
|
73
|
-
original: originalDecision,
|
|
74
|
-
corrected: correctedDecision
|
|
75
|
-
}
|
|
76
|
-
})
|
|
77
|
-
} catch (error) {
|
|
78
|
-
this.logger.warn({ error }, 'Failed to store correction in memory')
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// Extract preferences from correction
|
|
82
|
-
await this.extractPreferences(correction)
|
|
83
|
-
|
|
84
|
-
this.logger.info(
|
|
85
|
-
{ correctionId: correction.id, project },
|
|
86
|
-
'Correction recorded and preferences updated'
|
|
87
|
-
)
|
|
88
|
-
|
|
89
|
-
return correction.id
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* Extract preferences from correction
|
|
94
|
-
*/
|
|
95
|
-
private async extractPreferences(correction: Correction): Promise<void> {
|
|
96
|
-
// Analyze what changed
|
|
97
|
-
const category = this.categorizeCorrection(correction)
|
|
98
|
-
const preference = this.extractPreference(correction)
|
|
99
|
-
|
|
100
|
-
// Update or create preference
|
|
101
|
-
const existing = this.preferences.get(category)
|
|
102
|
-
|
|
103
|
-
if (existing) {
|
|
104
|
-
// Strengthen existing preference
|
|
105
|
-
existing.strength = Math.min(existing.strength + 0.1, 1.0)
|
|
106
|
-
existing.examples.push(correction.correctedDecision)
|
|
107
|
-
existing.lastUpdated = new Date()
|
|
108
|
-
|
|
109
|
-
// Keep only recent examples
|
|
110
|
-
if (existing.examples.length > 10) {
|
|
111
|
-
existing.examples = existing.examples.slice(-10)
|
|
112
|
-
}
|
|
113
|
-
} else {
|
|
114
|
-
// Create new preference
|
|
115
|
-
this.preferences.set(category, {
|
|
116
|
-
category,
|
|
117
|
-
preference,
|
|
118
|
-
strength: 0.5,
|
|
119
|
-
examples: [correction.correctedDecision],
|
|
120
|
-
lastUpdated: new Date()
|
|
121
|
-
})
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
/**
|
|
126
|
-
* Categorize correction to extract learning
|
|
127
|
-
*/
|
|
128
|
-
private categorizeCorrection(correction: Correction): string {
|
|
129
|
-
const reasoning = correction.reasoning.toLowerCase()
|
|
130
|
-
const original = correction.originalDecision.toLowerCase()
|
|
131
|
-
const corrected = correction.correctedDecision.toLowerCase()
|
|
132
|
-
|
|
133
|
-
// Check various categories
|
|
134
|
-
if (reasoning.includes('naming') || reasoning.includes('convention') ||
|
|
135
|
-
reasoning.includes('name')) {
|
|
136
|
-
return 'naming-conventions'
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
if (reasoning.includes('architecture') || reasoning.includes('structure') ||
|
|
140
|
-
reasoning.includes('pattern')) {
|
|
141
|
-
return 'architecture-preferences'
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
if (reasoning.includes('library') || reasoning.includes('framework') ||
|
|
145
|
-
reasoning.includes('dependency') || reasoning.includes('package')) {
|
|
146
|
-
return 'technology-preferences'
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
if (reasoning.includes('testing') || reasoning.includes('test') ||
|
|
150
|
-
reasoning.includes('spec')) {
|
|
151
|
-
return 'testing-preferences'
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
if (reasoning.includes('style') || reasoning.includes('format') ||
|
|
155
|
-
reasoning.includes('lint')) {
|
|
156
|
-
return 'code-style'
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
if (reasoning.includes('performance') || reasoning.includes('speed') ||
|
|
160
|
-
reasoning.includes('optimization')) {
|
|
161
|
-
return 'performance-preferences'
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
if (reasoning.includes('security') || reasoning.includes('auth') ||
|
|
165
|
-
reasoning.includes('access')) {
|
|
166
|
-
return 'security-preferences'
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
// Try to detect from content
|
|
170
|
-
if (original.includes('use') || corrected.includes('use')) {
|
|
171
|
-
return 'technology-preferences'
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
return 'general'
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
/**
|
|
178
|
-
* Extract preference from correction
|
|
179
|
-
*/
|
|
180
|
-
private extractPreference(correction: Correction): string {
|
|
181
|
-
// Use the corrected decision as the preference
|
|
182
|
-
return correction.correctedDecision
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
/**
|
|
186
|
-
* Get applicable preferences for context
|
|
187
|
-
*/
|
|
188
|
-
getRelevantPreferences(context: string): Preference[] {
|
|
189
|
-
const contextLower = context.toLowerCase()
|
|
190
|
-
|
|
191
|
-
return Array.from(this.preferences.values())
|
|
192
|
-
.filter(pref => {
|
|
193
|
-
// Check if preference category matches context
|
|
194
|
-
const categoryWords = pref.category.split('-')
|
|
195
|
-
const contextMatches = categoryWords.some(word =>
|
|
196
|
-
contextLower.includes(word)
|
|
197
|
-
)
|
|
198
|
-
|
|
199
|
-
// Check if examples match context
|
|
200
|
-
const exampleMatches = pref.examples.some(ex =>
|
|
201
|
-
contextLower.includes(ex.toLowerCase().slice(0, 20))
|
|
202
|
-
)
|
|
203
|
-
|
|
204
|
-
return contextMatches || exampleMatches
|
|
205
|
-
})
|
|
206
|
-
.sort((a, b) => b.strength - a.strength)
|
|
207
|
-
.slice(0, 5)
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
/**
|
|
211
|
-
* Get all preferences
|
|
212
|
-
*/
|
|
213
|
-
getAllPreferences(): Preference[] {
|
|
214
|
-
return Array.from(this.preferences.values())
|
|
215
|
-
.sort((a, b) => b.strength - a.strength)
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
/**
|
|
219
|
-
* Get preferences by category
|
|
220
|
-
*/
|
|
221
|
-
getPreferencesByCategory(category: string): Preference | undefined {
|
|
222
|
-
return this.preferences.get(category)
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
/**
|
|
226
|
-
* Decay preference strength over time
|
|
227
|
-
* Call this periodically to prevent stale preferences from dominating
|
|
228
|
-
*/
|
|
229
|
-
decayPreferences(decayFactor: number = 0.95): void {
|
|
230
|
-
const now = Date.now()
|
|
231
|
-
const dayInMs = 24 * 60 * 60 * 1000
|
|
232
|
-
|
|
233
|
-
for (const [key, pref] of this.preferences.entries()) {
|
|
234
|
-
const ageInDays = (now - pref.lastUpdated.getTime()) / dayInMs
|
|
235
|
-
|
|
236
|
-
// Decay more for older preferences
|
|
237
|
-
if (ageInDays > 30) {
|
|
238
|
-
pref.strength *= decayFactor
|
|
239
|
-
|
|
240
|
-
// Remove very weak preferences
|
|
241
|
-
if (pref.strength < 0.1) {
|
|
242
|
-
this.preferences.delete(key)
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
/**
|
|
249
|
-
* Get learning insights
|
|
250
|
-
*/
|
|
251
|
-
getLearningInsights(): LearningInsights {
|
|
252
|
-
const topPrefs = Array.from(this.preferences.values())
|
|
253
|
-
.sort((a, b) => b.strength - a.strength)
|
|
254
|
-
.slice(0, 10)
|
|
255
|
-
|
|
256
|
-
const categories = new Set(this.corrections.map(c => this.categorizeCorrection(c)))
|
|
257
|
-
|
|
258
|
-
const recentCorrections = this.corrections
|
|
259
|
-
.sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime())
|
|
260
|
-
.slice(0, 5)
|
|
261
|
-
|
|
262
|
-
return {
|
|
263
|
-
preferences: topPrefs,
|
|
264
|
-
correctionCount: this.corrections.length,
|
|
265
|
-
categoriesImproved: Array.from(categories),
|
|
266
|
-
recentCorrections
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
/**
|
|
271
|
-
* Format learning insights as markdown
|
|
272
|
-
*/
|
|
273
|
-
formatLearningInsights(): string {
|
|
274
|
-
const insights = this.getLearningInsights()
|
|
275
|
-
const parts: string[] = []
|
|
276
|
-
|
|
277
|
-
if (insights.preferences.length > 0) {
|
|
278
|
-
parts.push('## Learned Preferences\n')
|
|
279
|
-
for (const pref of insights.preferences) {
|
|
280
|
-
const confidence = Math.round(pref.strength * 100)
|
|
281
|
-
parts.push(`- **${pref.category}**: ${pref.preference} (${confidence}% confidence)\n`)
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
if (insights.correctionCount > 0) {
|
|
286
|
-
parts.push('\n## Correction Statistics\n')
|
|
287
|
-
parts.push(`- Total corrections: ${insights.correctionCount}\n`)
|
|
288
|
-
parts.push(`- Categories improved: ${insights.categoriesImproved.join(', ')}\n`)
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
if (insights.recentCorrections.length > 0) {
|
|
292
|
-
parts.push('\n## Recent Corrections\n')
|
|
293
|
-
for (const correction of insights.recentCorrections) {
|
|
294
|
-
parts.push(`- ${correction.project}: "${correction.correctedDecision}"\n`)
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
return parts.join('') || 'No learning data yet.'
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
/**
|
|
302
|
-
* Apply learned preferences to a decision
|
|
303
|
-
* Returns suggestions based on past corrections
|
|
304
|
-
*/
|
|
305
|
-
async applySuggestions(
|
|
306
|
-
decision: string,
|
|
307
|
-
project: string
|
|
308
|
-
): Promise<string[]> {
|
|
309
|
-
const suggestions: string[] = []
|
|
310
|
-
const decisionLower = decision.toLowerCase()
|
|
311
|
-
|
|
312
|
-
// Get relevant preferences
|
|
313
|
-
const relevantPrefs = this.getRelevantPreferences(decision)
|
|
314
|
-
|
|
315
|
-
for (const pref of relevantPrefs) {
|
|
316
|
-
if (pref.strength >= 0.5) {
|
|
317
|
-
// Check if the decision might conflict with preference
|
|
318
|
-
const exampleKeywords = pref.examples
|
|
319
|
-
.flatMap(ex => ex.toLowerCase().split(/\W+/))
|
|
320
|
-
.filter(w => w.length > 4)
|
|
321
|
-
|
|
322
|
-
const hasRelevantKeyword = exampleKeywords.some(keyword =>
|
|
323
|
-
decisionLower.includes(keyword)
|
|
324
|
-
)
|
|
325
|
-
|
|
326
|
-
if (hasRelevantKeyword) {
|
|
327
|
-
suggestions.push(
|
|
328
|
-
`Consider ${pref.category}: Previous preference was "${pref.preference}"`
|
|
329
|
-
)
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
// Check against past corrections
|
|
335
|
-
for (const correction of this.corrections) {
|
|
336
|
-
if (correction.project === project) {
|
|
337
|
-
const originalKeywords = correction.originalDecision
|
|
338
|
-
.toLowerCase()
|
|
339
|
-
.split(/\W+/)
|
|
340
|
-
.filter(w => w.length > 4)
|
|
341
|
-
|
|
342
|
-
const matchesOriginal = originalKeywords.some(keyword =>
|
|
343
|
-
decisionLower.includes(keyword)
|
|
344
|
-
)
|
|
345
|
-
|
|
346
|
-
if (matchesOriginal) {
|
|
347
|
-
suggestions.push(
|
|
348
|
-
`Note: Previously corrected similar decision. Consider: "${correction.correctedDecision}"`
|
|
349
|
-
)
|
|
350
|
-
}
|
|
351
|
-
}
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
return suggestions.slice(0, 3) // Return top 3 suggestions
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
/**
|
|
358
|
-
* Get correction history for a project
|
|
359
|
-
*/
|
|
360
|
-
getProjectCorrections(project: string): Correction[] {
|
|
361
|
-
return this.corrections
|
|
362
|
-
.filter(c => c.project === project)
|
|
363
|
-
.sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime())
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
/**
|
|
367
|
-
* Clear all learning data
|
|
368
|
-
*/
|
|
369
|
-
clearLearning(): void {
|
|
370
|
-
this.corrections = []
|
|
371
|
-
this.preferences.clear()
|
|
372
|
-
this.logger.info('Learning data cleared')
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
private generateId(): string {
|
|
376
|
-
return `correction-${Date.now()}-${Math.random().toString(36).substring(2, 11)}`
|
|
377
|
-
}
|
|
378
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Learning System
|
|
3
|
+
* Phase 12: Advanced Memory & Intelligent Automation
|
|
4
|
+
*
|
|
5
|
+
* Learns from corrections and user preferences over time
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { Logger } from 'pino'
|
|
9
|
+
import type { MemoryManager } from './index'
|
|
10
|
+
|
|
11
|
+
export interface Correction {
|
|
12
|
+
id: string
|
|
13
|
+
originalDecision: string
|
|
14
|
+
correctedDecision: string
|
|
15
|
+
reasoning: string
|
|
16
|
+
project: string
|
|
17
|
+
timestamp: Date
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface Preference {
|
|
21
|
+
category: string
|
|
22
|
+
preference: string
|
|
23
|
+
strength: number // 0-1
|
|
24
|
+
examples: string[]
|
|
25
|
+
lastUpdated: Date
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface LearningInsights {
|
|
29
|
+
preferences: Preference[]
|
|
30
|
+
correctionCount: number
|
|
31
|
+
categoriesImproved: string[]
|
|
32
|
+
recentCorrections: Correction[]
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export class LearningSystem {
|
|
36
|
+
private logger: Logger
|
|
37
|
+
private memory: MemoryManager
|
|
38
|
+
private corrections: Correction[] = []
|
|
39
|
+
private preferences: Map<string, Preference> = new Map()
|
|
40
|
+
|
|
41
|
+
constructor(logger: Logger, memory: MemoryManager) {
|
|
42
|
+
this.logger = logger.child({ component: 'learning-system' })
|
|
43
|
+
this.memory = memory
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Record a correction
|
|
48
|
+
*/
|
|
49
|
+
async recordCorrection(
|
|
50
|
+
originalDecision: string,
|
|
51
|
+
correctedDecision: string,
|
|
52
|
+
reasoning: string,
|
|
53
|
+
project: string
|
|
54
|
+
): Promise<string> {
|
|
55
|
+
const correction: Correction = {
|
|
56
|
+
id: this.generateId(),
|
|
57
|
+
originalDecision,
|
|
58
|
+
correctedDecision,
|
|
59
|
+
reasoning,
|
|
60
|
+
project,
|
|
61
|
+
timestamp: new Date()
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
this.corrections.push(correction)
|
|
65
|
+
|
|
66
|
+
// Store in memory system
|
|
67
|
+
try {
|
|
68
|
+
await this.memory.store.storeMemory({
|
|
69
|
+
project,
|
|
70
|
+
content: `Correction: Changed "${originalDecision}" to "${correctedDecision}". Reason: ${reasoning}`,
|
|
71
|
+
metadata: {
|
|
72
|
+
type: 'correction',
|
|
73
|
+
original: originalDecision,
|
|
74
|
+
corrected: correctedDecision
|
|
75
|
+
}
|
|
76
|
+
})
|
|
77
|
+
} catch (error) {
|
|
78
|
+
this.logger.warn({ error }, 'Failed to store correction in memory')
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Extract preferences from correction
|
|
82
|
+
await this.extractPreferences(correction)
|
|
83
|
+
|
|
84
|
+
this.logger.info(
|
|
85
|
+
{ correctionId: correction.id, project },
|
|
86
|
+
'Correction recorded and preferences updated'
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
return correction.id
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Extract preferences from correction
|
|
94
|
+
*/
|
|
95
|
+
private async extractPreferences(correction: Correction): Promise<void> {
|
|
96
|
+
// Analyze what changed
|
|
97
|
+
const category = this.categorizeCorrection(correction)
|
|
98
|
+
const preference = this.extractPreference(correction)
|
|
99
|
+
|
|
100
|
+
// Update or create preference
|
|
101
|
+
const existing = this.preferences.get(category)
|
|
102
|
+
|
|
103
|
+
if (existing) {
|
|
104
|
+
// Strengthen existing preference
|
|
105
|
+
existing.strength = Math.min(existing.strength + 0.1, 1.0)
|
|
106
|
+
existing.examples.push(correction.correctedDecision)
|
|
107
|
+
existing.lastUpdated = new Date()
|
|
108
|
+
|
|
109
|
+
// Keep only recent examples
|
|
110
|
+
if (existing.examples.length > 10) {
|
|
111
|
+
existing.examples = existing.examples.slice(-10)
|
|
112
|
+
}
|
|
113
|
+
} else {
|
|
114
|
+
// Create new preference
|
|
115
|
+
this.preferences.set(category, {
|
|
116
|
+
category,
|
|
117
|
+
preference,
|
|
118
|
+
strength: 0.5,
|
|
119
|
+
examples: [correction.correctedDecision],
|
|
120
|
+
lastUpdated: new Date()
|
|
121
|
+
})
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Categorize correction to extract learning
|
|
127
|
+
*/
|
|
128
|
+
private categorizeCorrection(correction: Correction): string {
|
|
129
|
+
const reasoning = correction.reasoning.toLowerCase()
|
|
130
|
+
const original = correction.originalDecision.toLowerCase()
|
|
131
|
+
const corrected = correction.correctedDecision.toLowerCase()
|
|
132
|
+
|
|
133
|
+
// Check various categories
|
|
134
|
+
if (reasoning.includes('naming') || reasoning.includes('convention') ||
|
|
135
|
+
reasoning.includes('name')) {
|
|
136
|
+
return 'naming-conventions'
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (reasoning.includes('architecture') || reasoning.includes('structure') ||
|
|
140
|
+
reasoning.includes('pattern')) {
|
|
141
|
+
return 'architecture-preferences'
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (reasoning.includes('library') || reasoning.includes('framework') ||
|
|
145
|
+
reasoning.includes('dependency') || reasoning.includes('package')) {
|
|
146
|
+
return 'technology-preferences'
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (reasoning.includes('testing') || reasoning.includes('test') ||
|
|
150
|
+
reasoning.includes('spec')) {
|
|
151
|
+
return 'testing-preferences'
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (reasoning.includes('style') || reasoning.includes('format') ||
|
|
155
|
+
reasoning.includes('lint')) {
|
|
156
|
+
return 'code-style'
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if (reasoning.includes('performance') || reasoning.includes('speed') ||
|
|
160
|
+
reasoning.includes('optimization')) {
|
|
161
|
+
return 'performance-preferences'
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (reasoning.includes('security') || reasoning.includes('auth') ||
|
|
165
|
+
reasoning.includes('access')) {
|
|
166
|
+
return 'security-preferences'
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Try to detect from content
|
|
170
|
+
if (original.includes('use') || corrected.includes('use')) {
|
|
171
|
+
return 'technology-preferences'
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
return 'general'
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Extract preference from correction
|
|
179
|
+
*/
|
|
180
|
+
private extractPreference(correction: Correction): string {
|
|
181
|
+
// Use the corrected decision as the preference
|
|
182
|
+
return correction.correctedDecision
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Get applicable preferences for context
|
|
187
|
+
*/
|
|
188
|
+
getRelevantPreferences(context: string): Preference[] {
|
|
189
|
+
const contextLower = context.toLowerCase()
|
|
190
|
+
|
|
191
|
+
return Array.from(this.preferences.values())
|
|
192
|
+
.filter(pref => {
|
|
193
|
+
// Check if preference category matches context
|
|
194
|
+
const categoryWords = pref.category.split('-')
|
|
195
|
+
const contextMatches = categoryWords.some(word =>
|
|
196
|
+
contextLower.includes(word)
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
// Check if examples match context
|
|
200
|
+
const exampleMatches = pref.examples.some(ex =>
|
|
201
|
+
contextLower.includes(ex.toLowerCase().slice(0, 20))
|
|
202
|
+
)
|
|
203
|
+
|
|
204
|
+
return contextMatches || exampleMatches
|
|
205
|
+
})
|
|
206
|
+
.sort((a, b) => b.strength - a.strength)
|
|
207
|
+
.slice(0, 5)
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Get all preferences
|
|
212
|
+
*/
|
|
213
|
+
getAllPreferences(): Preference[] {
|
|
214
|
+
return Array.from(this.preferences.values())
|
|
215
|
+
.sort((a, b) => b.strength - a.strength)
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Get preferences by category
|
|
220
|
+
*/
|
|
221
|
+
getPreferencesByCategory(category: string): Preference | undefined {
|
|
222
|
+
return this.preferences.get(category)
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Decay preference strength over time
|
|
227
|
+
* Call this periodically to prevent stale preferences from dominating
|
|
228
|
+
*/
|
|
229
|
+
decayPreferences(decayFactor: number = 0.95): void {
|
|
230
|
+
const now = Date.now()
|
|
231
|
+
const dayInMs = 24 * 60 * 60 * 1000
|
|
232
|
+
|
|
233
|
+
for (const [key, pref] of this.preferences.entries()) {
|
|
234
|
+
const ageInDays = (now - pref.lastUpdated.getTime()) / dayInMs
|
|
235
|
+
|
|
236
|
+
// Decay more for older preferences
|
|
237
|
+
if (ageInDays > 30) {
|
|
238
|
+
pref.strength *= decayFactor
|
|
239
|
+
|
|
240
|
+
// Remove very weak preferences
|
|
241
|
+
if (pref.strength < 0.1) {
|
|
242
|
+
this.preferences.delete(key)
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Get learning insights
|
|
250
|
+
*/
|
|
251
|
+
getLearningInsights(): LearningInsights {
|
|
252
|
+
const topPrefs = Array.from(this.preferences.values())
|
|
253
|
+
.sort((a, b) => b.strength - a.strength)
|
|
254
|
+
.slice(0, 10)
|
|
255
|
+
|
|
256
|
+
const categories = new Set(this.corrections.map(c => this.categorizeCorrection(c)))
|
|
257
|
+
|
|
258
|
+
const recentCorrections = this.corrections
|
|
259
|
+
.sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime())
|
|
260
|
+
.slice(0, 5)
|
|
261
|
+
|
|
262
|
+
return {
|
|
263
|
+
preferences: topPrefs,
|
|
264
|
+
correctionCount: this.corrections.length,
|
|
265
|
+
categoriesImproved: Array.from(categories),
|
|
266
|
+
recentCorrections
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Format learning insights as markdown
|
|
272
|
+
*/
|
|
273
|
+
formatLearningInsights(): string {
|
|
274
|
+
const insights = this.getLearningInsights()
|
|
275
|
+
const parts: string[] = []
|
|
276
|
+
|
|
277
|
+
if (insights.preferences.length > 0) {
|
|
278
|
+
parts.push('## Learned Preferences\n')
|
|
279
|
+
for (const pref of insights.preferences) {
|
|
280
|
+
const confidence = Math.round(pref.strength * 100)
|
|
281
|
+
parts.push(`- **${pref.category}**: ${pref.preference} (${confidence}% confidence)\n`)
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
if (insights.correctionCount > 0) {
|
|
286
|
+
parts.push('\n## Correction Statistics\n')
|
|
287
|
+
parts.push(`- Total corrections: ${insights.correctionCount}\n`)
|
|
288
|
+
parts.push(`- Categories improved: ${insights.categoriesImproved.join(', ')}\n`)
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
if (insights.recentCorrections.length > 0) {
|
|
292
|
+
parts.push('\n## Recent Corrections\n')
|
|
293
|
+
for (const correction of insights.recentCorrections) {
|
|
294
|
+
parts.push(`- ${correction.project}: "${correction.correctedDecision}"\n`)
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
return parts.join('') || 'No learning data yet.'
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* Apply learned preferences to a decision
|
|
303
|
+
* Returns suggestions based on past corrections
|
|
304
|
+
*/
|
|
305
|
+
async applySuggestions(
|
|
306
|
+
decision: string,
|
|
307
|
+
project: string
|
|
308
|
+
): Promise<string[]> {
|
|
309
|
+
const suggestions: string[] = []
|
|
310
|
+
const decisionLower = decision.toLowerCase()
|
|
311
|
+
|
|
312
|
+
// Get relevant preferences
|
|
313
|
+
const relevantPrefs = this.getRelevantPreferences(decision)
|
|
314
|
+
|
|
315
|
+
for (const pref of relevantPrefs) {
|
|
316
|
+
if (pref.strength >= 0.5) {
|
|
317
|
+
// Check if the decision might conflict with preference
|
|
318
|
+
const exampleKeywords = pref.examples
|
|
319
|
+
.flatMap(ex => ex.toLowerCase().split(/\W+/))
|
|
320
|
+
.filter(w => w.length > 4)
|
|
321
|
+
|
|
322
|
+
const hasRelevantKeyword = exampleKeywords.some(keyword =>
|
|
323
|
+
decisionLower.includes(keyword)
|
|
324
|
+
)
|
|
325
|
+
|
|
326
|
+
if (hasRelevantKeyword) {
|
|
327
|
+
suggestions.push(
|
|
328
|
+
`Consider ${pref.category}: Previous preference was "${pref.preference}"`
|
|
329
|
+
)
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// Check against past corrections
|
|
335
|
+
for (const correction of this.corrections) {
|
|
336
|
+
if (correction.project === project) {
|
|
337
|
+
const originalKeywords = correction.originalDecision
|
|
338
|
+
.toLowerCase()
|
|
339
|
+
.split(/\W+/)
|
|
340
|
+
.filter(w => w.length > 4)
|
|
341
|
+
|
|
342
|
+
const matchesOriginal = originalKeywords.some(keyword =>
|
|
343
|
+
decisionLower.includes(keyword)
|
|
344
|
+
)
|
|
345
|
+
|
|
346
|
+
if (matchesOriginal) {
|
|
347
|
+
suggestions.push(
|
|
348
|
+
`Note: Previously corrected similar decision. Consider: "${correction.correctedDecision}"`
|
|
349
|
+
)
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
return suggestions.slice(0, 3) // Return top 3 suggestions
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* Get correction history for a project
|
|
359
|
+
*/
|
|
360
|
+
getProjectCorrections(project: string): Correction[] {
|
|
361
|
+
return this.corrections
|
|
362
|
+
.filter(c => c.project === project)
|
|
363
|
+
.sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime())
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
/**
|
|
367
|
+
* Clear all learning data
|
|
368
|
+
*/
|
|
369
|
+
clearLearning(): void {
|
|
370
|
+
this.corrections = []
|
|
371
|
+
this.preferences.clear()
|
|
372
|
+
this.logger.info('Learning data cleared')
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
private generateId(): string {
|
|
376
|
+
return `correction-${Date.now()}-${Math.random().toString(36).substring(2, 11)}`
|
|
377
|
+
}
|
|
378
|
+
}
|