claude-brain 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +157 -0
- package/VERSION +1 -0
- package/assets/CLAUDE.md +307 -0
- package/bunfig.toml +8 -0
- package/package.json +74 -0
- package/src/automation/auto-context.ts +240 -0
- package/src/automation/decision-detector.ts +452 -0
- package/src/automation/index.ts +11 -0
- package/src/automation/proactive-recall.ts +373 -0
- package/src/automation/project-detector.ts +297 -0
- package/src/cli/auto-setup.ts +74 -0
- package/src/cli/bin.ts +110 -0
- package/src/cli/commands/install-mcp.ts +50 -0
- package/src/cli/commands/serve.ts +129 -0
- package/src/cli/diagnose.ts +4 -0
- package/src/cli/health-check.ts +4 -0
- package/src/cli/migrate-chroma.ts +106 -0
- package/src/cli/setup.ts +4 -0
- package/src/config/defaults.ts +47 -0
- package/src/config/home.ts +55 -0
- package/src/config/index.ts +7 -0
- package/src/config/loader.ts +166 -0
- package/src/config/migration.ts +76 -0
- package/src/config/schema.ts +257 -0
- package/src/config/validator.ts +184 -0
- package/src/config/watcher.ts +86 -0
- package/src/context/assembler.ts +398 -0
- package/src/context/cache-manager.ts +101 -0
- package/src/context/formatter.ts +84 -0
- package/src/context/hierarchy.ts +85 -0
- package/src/context/index.ts +83 -0
- package/src/context/progress-tracker.ts +174 -0
- package/src/context/standards-manager.ts +267 -0
- package/src/context/types.ts +252 -0
- package/src/context/validator.ts +58 -0
- package/src/cross-project/affinity.ts +162 -0
- package/src/cross-project/generalizer.ts +283 -0
- package/src/cross-project/index.ts +13 -0
- package/src/cross-project/transfer.ts +201 -0
- package/src/diagnostics/index.ts +123 -0
- package/src/health/index.ts +229 -0
- package/src/index.ts +7 -0
- package/src/knowledge/entity-extractor.ts +416 -0
- package/src/knowledge/graph/builder.ts +159 -0
- package/src/knowledge/graph/linker.ts +201 -0
- package/src/knowledge/graph/memory-graph.ts +359 -0
- package/src/knowledge/graph/schema.ts +99 -0
- package/src/knowledge/graph/search.ts +168 -0
- package/src/knowledge/relationship-extractor.ts +108 -0
- package/src/memory/chroma/client.ts +169 -0
- package/src/memory/chroma/collection-manager.ts +94 -0
- package/src/memory/chroma/config.ts +46 -0
- package/src/memory/chroma/embeddings.ts +153 -0
- package/src/memory/chroma/index.ts +82 -0
- package/src/memory/chroma/migration.ts +270 -0
- package/src/memory/chroma/schemas.ts +69 -0
- package/src/memory/chroma/search.ts +315 -0
- package/src/memory/chroma/store.ts +694 -0
- package/src/memory/consolidation/archiver.ts +164 -0
- package/src/memory/consolidation/merger.ts +186 -0
- package/src/memory/consolidation/scorer.ts +138 -0
- package/src/memory/context-builder.ts +236 -0
- package/src/memory/database.ts +169 -0
- package/src/memory/embedding-utils.ts +156 -0
- package/src/memory/embeddings.ts +226 -0
- package/src/memory/episodic/detector.ts +108 -0
- package/src/memory/episodic/manager.ts +334 -0
- package/src/memory/episodic/summarizer.ts +179 -0
- package/src/memory/episodic/types.ts +52 -0
- package/src/memory/index.ts +395 -0
- package/src/memory/knowledge-extractor.ts +455 -0
- package/src/memory/learning.ts +378 -0
- package/src/memory/patterns.ts +396 -0
- package/src/memory/schema.ts +56 -0
- package/src/memory/search.ts +309 -0
- package/src/memory/store.ts +344 -0
- package/src/memory/types.ts +121 -0
- package/src/optimization/index.ts +10 -0
- package/src/optimization/precompute.ts +202 -0
- package/src/optimization/semantic-cache.ts +207 -0
- package/src/orchestrator/coordinator.ts +272 -0
- package/src/orchestrator/decision-logger.ts +228 -0
- package/src/orchestrator/event-emitter.ts +198 -0
- package/src/orchestrator/event-queue.ts +184 -0
- package/src/orchestrator/handlers/base-handler.ts +70 -0
- package/src/orchestrator/handlers/context-handler.ts +73 -0
- package/src/orchestrator/handlers/decision-handler.ts +204 -0
- package/src/orchestrator/handlers/index.ts +10 -0
- package/src/orchestrator/handlers/status-handler.ts +131 -0
- package/src/orchestrator/handlers/task-handler.ts +171 -0
- package/src/orchestrator/index.ts +275 -0
- package/src/orchestrator/task-parser.ts +284 -0
- package/src/orchestrator/types.ts +98 -0
- package/src/phase12/index.ts +456 -0
- package/src/prediction/context-anticipator.ts +198 -0
- package/src/prediction/decision-predictor.ts +184 -0
- package/src/prediction/index.ts +13 -0
- package/src/prediction/recommender.ts +268 -0
- package/src/reasoning/chain-retrieval.ts +247 -0
- package/src/reasoning/counterfactual.ts +248 -0
- package/src/reasoning/index.ts +13 -0
- package/src/reasoning/synthesizer.ts +169 -0
- package/src/retrieval/bm25/index.ts +300 -0
- package/src/retrieval/bm25/tokenizer.ts +184 -0
- package/src/retrieval/feedback/adaptive.ts +223 -0
- package/src/retrieval/feedback/index.ts +16 -0
- package/src/retrieval/feedback/metrics.ts +223 -0
- package/src/retrieval/feedback/store.ts +283 -0
- package/src/retrieval/fusion/index.ts +194 -0
- package/src/retrieval/fusion/rrf.ts +163 -0
- package/src/retrieval/index.ts +12 -0
- package/src/retrieval/pipeline.ts +375 -0
- package/src/retrieval/query/expander.ts +198 -0
- package/src/retrieval/query/index.ts +27 -0
- package/src/retrieval/query/intent-classifier.ts +236 -0
- package/src/retrieval/query/temporal-parser.ts +295 -0
- package/src/retrieval/reranker/index.ts +188 -0
- package/src/retrieval/reranker/model.ts +95 -0
- package/src/retrieval/service.ts +125 -0
- package/src/retrieval/types.ts +162 -0
- package/src/scripts/health-check.ts +118 -0
- package/src/scripts/setup.ts +122 -0
- package/src/server/handlers/call-tool.ts +194 -0
- package/src/server/handlers/index.ts +9 -0
- package/src/server/handlers/list-tools.ts +18 -0
- package/src/server/handlers/tools/analyze-decision-evolution.ts +71 -0
- package/src/server/handlers/tools/auto-remember.ts +200 -0
- package/src/server/handlers/tools/create-project.ts +135 -0
- package/src/server/handlers/tools/detect-trends.ts +80 -0
- package/src/server/handlers/tools/find-cross-project-patterns.ts +73 -0
- package/src/server/handlers/tools/get-activity-log.ts +194 -0
- package/src/server/handlers/tools/get-code-standards.ts +124 -0
- package/src/server/handlers/tools/get-corrections.ts +154 -0
- package/src/server/handlers/tools/get-decision-timeline.ts +86 -0
- package/src/server/handlers/tools/get-episode.ts +93 -0
- package/src/server/handlers/tools/get-patterns.ts +158 -0
- package/src/server/handlers/tools/get-phase12-status.ts +63 -0
- package/src/server/handlers/tools/get-project-context.ts +75 -0
- package/src/server/handlers/tools/get-recommendations.ts +65 -0
- package/src/server/handlers/tools/index.ts +33 -0
- package/src/server/handlers/tools/init-project.ts +710 -0
- package/src/server/handlers/tools/list-episodes.ts +80 -0
- package/src/server/handlers/tools/list-projects.ts +125 -0
- package/src/server/handlers/tools/rate-memory.ts +95 -0
- package/src/server/handlers/tools/recall-similar.ts +87 -0
- package/src/server/handlers/tools/recognize-pattern.ts +126 -0
- package/src/server/handlers/tools/record-correction.ts +125 -0
- package/src/server/handlers/tools/remember-decision.ts +153 -0
- package/src/server/handlers/tools/schemas.ts +241 -0
- package/src/server/handlers/tools/search-knowledge-graph.ts +89 -0
- package/src/server/handlers/tools/smart-context.ts +124 -0
- package/src/server/handlers/tools/update-progress.ts +114 -0
- package/src/server/handlers/tools/what-if-analysis.ts +73 -0
- package/src/server/http-api.ts +474 -0
- package/src/server/index.ts +40 -0
- package/src/server/mcp-server.ts +283 -0
- package/src/server/providers/index.ts +7 -0
- package/src/server/providers/prompts.ts +327 -0
- package/src/server/providers/resources.ts +427 -0
- package/src/server/services.ts +388 -0
- package/src/server/types.ts +39 -0
- package/src/server/utils/error-handler.ts +155 -0
- package/src/server/utils/index.ts +13 -0
- package/src/server/utils/memory-indicator.ts +83 -0
- package/src/server/utils/request-context.ts +122 -0
- package/src/server/utils/response-formatter.ts +124 -0
- package/src/server/utils/validators.ts +210 -0
- package/src/setup/index.ts +22 -0
- package/src/setup/wizard.ts +321 -0
- package/src/temporal/evolution.ts +197 -0
- package/src/temporal/index.ts +16 -0
- package/src/temporal/query-processor.ts +190 -0
- package/src/temporal/timeline.ts +259 -0
- package/src/temporal/trends.ts +263 -0
- package/src/tools/index.ts +24 -0
- package/src/tools/registry.ts +106 -0
- package/src/tools/schemas.test.ts +30 -0
- package/src/tools/schemas.ts +907 -0
- package/src/tools/types.ts +412 -0
- package/src/utils/circuit-breaker.ts +130 -0
- package/src/utils/cleanup.ts +34 -0
- package/src/utils/error-handler.ts +132 -0
- package/src/utils/error-messages.ts +60 -0
- package/src/utils/fallback.ts +45 -0
- package/src/utils/index.ts +54 -0
- package/src/utils/logger-utils.ts +80 -0
- package/src/utils/logger.ts +88 -0
- package/src/utils/phase12-helper.ts +56 -0
- package/src/utils/retry.ts +94 -0
- package/src/utils/transaction.ts +63 -0
- package/src/vault/frontmatter.ts +264 -0
- package/src/vault/index.ts +318 -0
- package/src/vault/paths.ts +106 -0
- package/src/vault/query.ts +422 -0
- package/src/vault/reader.ts +264 -0
- package/src/vault/templates.ts +186 -0
- package/src/vault/types.ts +73 -0
- package/src/vault/watcher.ts +277 -0
- package/src/vault/writer.ts +393 -0
- package/tsconfig.json +30 -0
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extractive Summarizer
|
|
3
|
+
* Generates summaries by scoring and selecting key sentences
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { Episode, EpisodeSummary } from './types'
|
|
7
|
+
|
|
8
|
+
interface ScoredSentence {
|
|
9
|
+
text: string
|
|
10
|
+
score: number
|
|
11
|
+
position: number
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export class ExtractiveSummarizer {
|
|
15
|
+
private briefSize: number
|
|
16
|
+
private detailedSize: number
|
|
17
|
+
|
|
18
|
+
constructor(briefSize: number = 2, detailedSize: number = 8) {
|
|
19
|
+
this.briefSize = briefSize
|
|
20
|
+
this.detailedSize = detailedSize
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
summarize(episode: Episode): EpisodeSummary {
|
|
24
|
+
const allText = episode.messages.map(m => m.content).join('\n')
|
|
25
|
+
const sentences = this.splitSentences(allText)
|
|
26
|
+
|
|
27
|
+
if (sentences.length === 0) {
|
|
28
|
+
return {
|
|
29
|
+
brief: 'Empty episode',
|
|
30
|
+
detailed: 'No messages in this episode.',
|
|
31
|
+
key_topics: [],
|
|
32
|
+
decisions_made: [],
|
|
33
|
+
unresolved_questions: [],
|
|
34
|
+
entity_count: 0
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Calculate word frequencies for TF scoring
|
|
39
|
+
const wordFreqs = this.calculateWordFrequencies(allText)
|
|
40
|
+
const totalSentences = sentences.length
|
|
41
|
+
|
|
42
|
+
// Score each sentence
|
|
43
|
+
const scored: ScoredSentence[] = sentences.map((text, position) => ({
|
|
44
|
+
text,
|
|
45
|
+
position,
|
|
46
|
+
score: this.scoreSentence(text, position, totalSentences, wordFreqs)
|
|
47
|
+
}))
|
|
48
|
+
|
|
49
|
+
// Sort by score descending
|
|
50
|
+
const ranked = [...scored].sort((a, b) => b.score - a.score)
|
|
51
|
+
|
|
52
|
+
// Select top sentences for brief and detailed, then re-order by position
|
|
53
|
+
const briefSentences = ranked
|
|
54
|
+
.slice(0, this.briefSize)
|
|
55
|
+
.sort((a, b) => a.position - b.position)
|
|
56
|
+
.map(s => s.text)
|
|
57
|
+
|
|
58
|
+
const detailedSentences = ranked
|
|
59
|
+
.slice(0, this.detailedSize)
|
|
60
|
+
.sort((a, b) => a.position - b.position)
|
|
61
|
+
.map(s => s.text)
|
|
62
|
+
|
|
63
|
+
// Extract key topics from high-frequency words
|
|
64
|
+
const keyTopics = this.extractKeyTopics(wordFreqs)
|
|
65
|
+
|
|
66
|
+
// Find decisions (sentences with decision keywords)
|
|
67
|
+
const decisionKeywords = ['decided', 'chose', 'selected', 'will use', 'going with', 'recommend', 'should use']
|
|
68
|
+
const decisions = sentences.filter(s =>
|
|
69
|
+
decisionKeywords.some(k => s.toLowerCase().includes(k))
|
|
70
|
+
).slice(0, 5)
|
|
71
|
+
|
|
72
|
+
// Find unresolved questions (last messages with ? that aren't answered)
|
|
73
|
+
const lastMessages = episode.messages.slice(-Math.ceil(episode.messages.length / 2))
|
|
74
|
+
const questions = lastMessages
|
|
75
|
+
.filter(m => m.role === 'user' && m.content.includes('?'))
|
|
76
|
+
.map(m => {
|
|
77
|
+
const qSentences = this.splitSentences(m.content)
|
|
78
|
+
return qSentences.filter(s => s.includes('?'))
|
|
79
|
+
})
|
|
80
|
+
.flat()
|
|
81
|
+
.slice(0, 3)
|
|
82
|
+
|
|
83
|
+
return {
|
|
84
|
+
brief: briefSentences.join(' '),
|
|
85
|
+
detailed: detailedSentences.join(' '),
|
|
86
|
+
key_topics: keyTopics,
|
|
87
|
+
decisions_made: decisions,
|
|
88
|
+
unresolved_questions: questions,
|
|
89
|
+
entity_count: keyTopics.length
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
private splitSentences(text: string): string[] {
|
|
94
|
+
// Split on sentence boundaries
|
|
95
|
+
const raw = text
|
|
96
|
+
.replace(/\n+/g, '. ')
|
|
97
|
+
.split(/(?<=[.!?])\s+/)
|
|
98
|
+
.map(s => s.trim())
|
|
99
|
+
.filter(s => s.length > 10)
|
|
100
|
+
|
|
101
|
+
return raw
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
private calculateWordFrequencies(text: string): Map<string, number> {
|
|
105
|
+
const stopWords = new Set([
|
|
106
|
+
'the', 'a', 'an', 'is', 'are', 'was', 'were', 'be', 'been', 'being',
|
|
107
|
+
'have', 'has', 'had', 'do', 'does', 'did', 'will', 'would', 'could',
|
|
108
|
+
'should', 'can', 'may', 'might', 'to', 'of', 'in', 'for', 'on',
|
|
109
|
+
'with', 'at', 'by', 'from', 'as', 'and', 'but', 'or', 'not', 'so',
|
|
110
|
+
'if', 'that', 'this', 'it', 'its', 'i', 'me', 'my', 'we', 'our',
|
|
111
|
+
'you', 'your', 'he', 'she', 'they', 'them', 'their', 'what', 'which',
|
|
112
|
+
'who', 'when', 'where', 'how', 'all', 'each', 'both', 'few', 'more',
|
|
113
|
+
'most', 'other', 'some', 'no', 'only', 'own', 'same', 'than', 'too',
|
|
114
|
+
'very', 'just', 'about', 'up', 'out', 'off'
|
|
115
|
+
])
|
|
116
|
+
|
|
117
|
+
const freqs = new Map<string, number>()
|
|
118
|
+
const words = text.toLowerCase()
|
|
119
|
+
.replace(/[^a-z0-9\s-]/g, ' ')
|
|
120
|
+
.split(/\s+/)
|
|
121
|
+
.filter(w => w.length > 2 && !stopWords.has(w))
|
|
122
|
+
|
|
123
|
+
for (const word of words) {
|
|
124
|
+
freqs.set(word, (freqs.get(word) || 0) + 1)
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return freqs
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
private scoreSentence(
|
|
131
|
+
sentence: string,
|
|
132
|
+
position: number,
|
|
133
|
+
totalSentences: number,
|
|
134
|
+
wordFreqs: Map<string, number>
|
|
135
|
+
): number {
|
|
136
|
+
let score = 0
|
|
137
|
+
|
|
138
|
+
// 1. TF-based keyword score
|
|
139
|
+
const words = sentence.toLowerCase()
|
|
140
|
+
.replace(/[^a-z0-9\s-]/g, ' ')
|
|
141
|
+
.split(/\s+/)
|
|
142
|
+
.filter(w => w.length > 2)
|
|
143
|
+
|
|
144
|
+
if (words.length === 0) return 0
|
|
145
|
+
|
|
146
|
+
let keywordScore = 0
|
|
147
|
+
for (const word of words) {
|
|
148
|
+
keywordScore += wordFreqs.get(word) || 0
|
|
149
|
+
}
|
|
150
|
+
keywordScore /= words.length // normalize by sentence length
|
|
151
|
+
score += keywordScore * 0.4
|
|
152
|
+
|
|
153
|
+
// 2. Position bonus (first and last sentences score higher)
|
|
154
|
+
const posRatio = position / Math.max(totalSentences - 1, 1)
|
|
155
|
+
const positionScore = posRatio < 0.15 ? 1.0 : posRatio > 0.85 ? 0.8 : 0.3
|
|
156
|
+
score += positionScore * 0.25
|
|
157
|
+
|
|
158
|
+
// 3. Decision keyword boost
|
|
159
|
+
const decisionKeywords = ['decided', 'chose', 'selected', 'recommend', 'should', 'must', 'will use', 'going with', 'use', 'implement', 'adopt']
|
|
160
|
+
const lowerSentence = sentence.toLowerCase()
|
|
161
|
+
const hasDecision = decisionKeywords.some(k => lowerSentence.includes(k))
|
|
162
|
+
if (hasDecision) score += 0.2
|
|
163
|
+
|
|
164
|
+
// 4. Length penalty for very short or very long sentences
|
|
165
|
+
const optimalLength = 20 // words
|
|
166
|
+
const lengthRatio = Math.min(words.length, optimalLength * 2) / optimalLength
|
|
167
|
+
const lengthScore = lengthRatio <= 1 ? lengthRatio : 2 - lengthRatio
|
|
168
|
+
score += Math.max(0, lengthScore) * 0.15
|
|
169
|
+
|
|
170
|
+
return score
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
private extractKeyTopics(wordFreqs: Map<string, number>): string[] {
|
|
174
|
+
return Array.from(wordFreqs.entries())
|
|
175
|
+
.sort(([, a], [, b]) => b - a)
|
|
176
|
+
.slice(0, 10)
|
|
177
|
+
.map(([word]) => word)
|
|
178
|
+
}
|
|
179
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Episodic Memory Types
|
|
3
|
+
* Type definitions for the episodic memory system
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export interface EpisodeMessage {
|
|
7
|
+
role: 'user' | 'assistant' | 'system'
|
|
8
|
+
content: string
|
|
9
|
+
timestamp: string
|
|
10
|
+
token_estimate?: number
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface EpisodeSummary {
|
|
14
|
+
brief: string
|
|
15
|
+
detailed: string
|
|
16
|
+
key_topics: string[]
|
|
17
|
+
decisions_made: string[]
|
|
18
|
+
unresolved_questions: string[]
|
|
19
|
+
entity_count: number
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export type SessionClassification = 'new_session' | 'continuation' | 'topic_shift'
|
|
23
|
+
|
|
24
|
+
export interface Episode {
|
|
25
|
+
id: string
|
|
26
|
+
project?: string
|
|
27
|
+
status: 'active' | 'completed'
|
|
28
|
+
started_at: string
|
|
29
|
+
ended_at?: string
|
|
30
|
+
messages: EpisodeMessage[]
|
|
31
|
+
summary?: EpisodeSummary
|
|
32
|
+
related_decisions: string[]
|
|
33
|
+
related_patterns: string[]
|
|
34
|
+
related_corrections: string[]
|
|
35
|
+
token_count: number
|
|
36
|
+
message_count: number
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface EpisodeMetadata {
|
|
40
|
+
episode_id: string
|
|
41
|
+
project: string
|
|
42
|
+
status: 'active' | 'completed'
|
|
43
|
+
started_at: string
|
|
44
|
+
ended_at: string
|
|
45
|
+
message_count: number
|
|
46
|
+
token_count: number
|
|
47
|
+
key_topics: string
|
|
48
|
+
brief_summary: string
|
|
49
|
+
related_decisions: string
|
|
50
|
+
related_patterns: string
|
|
51
|
+
related_corrections: string
|
|
52
|
+
}
|
|
@@ -0,0 +1,395 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memory System - Main Module
|
|
3
|
+
* Phase 3: Memory and Embedding System
|
|
4
|
+
*
|
|
5
|
+
* Unified memory system manager that combines all components
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { Logger } from 'pino'
|
|
9
|
+
import { MemoryDatabase } from './database'
|
|
10
|
+
import { EmbeddingService } from './embeddings'
|
|
11
|
+
import { MemoryStore } from './store'
|
|
12
|
+
import { SemanticSearch } from './search'
|
|
13
|
+
import { MemoryContextBuilder } from './context-builder'
|
|
14
|
+
import type { MemorySystemStats } from './types'
|
|
15
|
+
import { ChromaManager, DEFAULT_CHROMA_CONFIG, getChromaConfigFromEnv, ChromaMigration, type MigrationOptions } from './chroma'
|
|
16
|
+
|
|
17
|
+
// Re-export all types and classes for external use
|
|
18
|
+
export * from './types'
|
|
19
|
+
export { MemoryDatabase } from './database'
|
|
20
|
+
export { EmbeddingService } from './embeddings'
|
|
21
|
+
export { MemoryStore } from './store'
|
|
22
|
+
export { SemanticSearch } from './search'
|
|
23
|
+
export { MemoryContextBuilder, type ContextOptions } from './context-builder'
|
|
24
|
+
export {
|
|
25
|
+
embeddingToBuffer,
|
|
26
|
+
bufferToEmbedding,
|
|
27
|
+
normalizeEmbedding,
|
|
28
|
+
euclideanDistance,
|
|
29
|
+
cosineSimilarity,
|
|
30
|
+
dotProduct,
|
|
31
|
+
magnitude,
|
|
32
|
+
averageEmbeddings,
|
|
33
|
+
topKSimilar
|
|
34
|
+
} from './embedding-utils'
|
|
35
|
+
|
|
36
|
+
// Phase 12: Advanced Memory Features
|
|
37
|
+
export { PatternRecognizer, type Pattern } from './patterns'
|
|
38
|
+
export { LearningSystem, type Correction, type Preference, type LearningInsights } from './learning'
|
|
39
|
+
export { KnowledgeExtractor, type ExtractedKnowledge, type ExtractionResult } from './knowledge-extractor'
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Unified memory system manager
|
|
43
|
+
* Combines database, embeddings, store, search, and context building
|
|
44
|
+
*/
|
|
45
|
+
export class MemoryManager {
|
|
46
|
+
readonly database: MemoryDatabase
|
|
47
|
+
readonly embeddings: EmbeddingService
|
|
48
|
+
readonly contextBuilder: MemoryContextBuilder
|
|
49
|
+
readonly chroma: ChromaManager
|
|
50
|
+
|
|
51
|
+
// Store and search are initialized after database is ready
|
|
52
|
+
private _store: MemoryStore | null = null
|
|
53
|
+
private _search: SemanticSearch | null = null
|
|
54
|
+
|
|
55
|
+
private logger: Logger
|
|
56
|
+
private initialized: boolean = false
|
|
57
|
+
private useChromaDB: boolean = true
|
|
58
|
+
|
|
59
|
+
constructor(
|
|
60
|
+
dbPath: string,
|
|
61
|
+
logger: Logger,
|
|
62
|
+
useChromaDB: boolean = true,
|
|
63
|
+
chromaConfig?: any,
|
|
64
|
+
customEmbeddings?: EmbeddingService
|
|
65
|
+
) {
|
|
66
|
+
this.logger = logger.child({ component: 'memory-manager' })
|
|
67
|
+
this.useChromaDB = useChromaDB
|
|
68
|
+
|
|
69
|
+
this.database = new MemoryDatabase(dbPath, logger)
|
|
70
|
+
this.embeddings = customEmbeddings || new EmbeddingService(logger)
|
|
71
|
+
this.contextBuilder = new MemoryContextBuilder(logger)
|
|
72
|
+
|
|
73
|
+
const envConfig = getChromaConfigFromEnv()
|
|
74
|
+
const config = { ...DEFAULT_CHROMA_CONFIG, ...envConfig, ...chromaConfig }
|
|
75
|
+
this.chroma = new ChromaManager(logger, config)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Initialize memory system
|
|
80
|
+
* Must be called before using store or search
|
|
81
|
+
*/
|
|
82
|
+
async initialize(): Promise<void> {
|
|
83
|
+
if (this.initialized) {
|
|
84
|
+
this.logger.warn('Memory system already initialized')
|
|
85
|
+
return
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
try {
|
|
89
|
+
this.logger.info('Initializing memory system...')
|
|
90
|
+
|
|
91
|
+
await this.database.initialize()
|
|
92
|
+
|
|
93
|
+
await this.embeddings.initialize()
|
|
94
|
+
|
|
95
|
+
const db = this.database.getDb()
|
|
96
|
+
this._store = new MemoryStore(db, this.embeddings, this.logger)
|
|
97
|
+
this._search = new SemanticSearch(db, this.embeddings, this.logger)
|
|
98
|
+
|
|
99
|
+
if (this.useChromaDB) {
|
|
100
|
+
try {
|
|
101
|
+
await this.chroma.initialize()
|
|
102
|
+
this.logger.info('ChromaDB backend initialized successfully')
|
|
103
|
+
} catch (error) {
|
|
104
|
+
this.logger.warn({ error }, 'Failed to initialize ChromaDB, falling back to SQLite backend')
|
|
105
|
+
this.useChromaDB = false
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
this.initialized = true
|
|
110
|
+
this.logger.info('Memory system initialized successfully')
|
|
111
|
+
} catch (error) {
|
|
112
|
+
this.logger.error({ error }, 'Failed to initialize memory system')
|
|
113
|
+
throw error
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Get the memory store (throws if not initialized)
|
|
119
|
+
*/
|
|
120
|
+
get store(): MemoryStore {
|
|
121
|
+
if (!this._store) {
|
|
122
|
+
throw new Error('Memory system not initialized. Call initialize() first.')
|
|
123
|
+
}
|
|
124
|
+
return this._store
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Get the semantic search engine (throws if not initialized)
|
|
129
|
+
*/
|
|
130
|
+
get search(): SemanticSearch {
|
|
131
|
+
if (!this._search) {
|
|
132
|
+
throw new Error('Memory system not initialized. Call initialize() first.')
|
|
133
|
+
}
|
|
134
|
+
return this._search
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Check if memory system is initialized
|
|
139
|
+
*/
|
|
140
|
+
isInitialized(): boolean {
|
|
141
|
+
return this.initialized
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
close(): void {
|
|
145
|
+
if (this.useChromaDB) {
|
|
146
|
+
this.chroma.close()
|
|
147
|
+
}
|
|
148
|
+
this.database.close()
|
|
149
|
+
this._store = null
|
|
150
|
+
this._search = null
|
|
151
|
+
this.initialized = false
|
|
152
|
+
this.logger.info('Memory system closed')
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Get system statistics
|
|
157
|
+
*/
|
|
158
|
+
getStats(): MemorySystemStats {
|
|
159
|
+
if (!this.initialized) {
|
|
160
|
+
throw new Error('Memory system not initialized')
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return {
|
|
164
|
+
database: this.database.getStats(),
|
|
165
|
+
embeddings: this.embeddings.getCacheStats()
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Health check
|
|
171
|
+
*/
|
|
172
|
+
async healthCheck(): Promise<boolean> {
|
|
173
|
+
if (!this.initialized) {
|
|
174
|
+
return false
|
|
175
|
+
}
|
|
176
|
+
return this.database.healthCheck()
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
async rememberDecision(
|
|
180
|
+
project: string,
|
|
181
|
+
context: string,
|
|
182
|
+
decision: string,
|
|
183
|
+
reasoning: string,
|
|
184
|
+
options?: { alternatives?: string; tags?: string[] }
|
|
185
|
+
): Promise<string> {
|
|
186
|
+
if (this.useChromaDB) {
|
|
187
|
+
return this.chroma.store.storeDecision({
|
|
188
|
+
project,
|
|
189
|
+
context,
|
|
190
|
+
decision,
|
|
191
|
+
reasoning,
|
|
192
|
+
alternatives: options?.alternatives,
|
|
193
|
+
tags: options?.tags
|
|
194
|
+
})
|
|
195
|
+
}
|
|
196
|
+
return this.store.storeDecision({
|
|
197
|
+
project,
|
|
198
|
+
context,
|
|
199
|
+
decision,
|
|
200
|
+
reasoning,
|
|
201
|
+
alternatives: options?.alternatives,
|
|
202
|
+
tags: options?.tags
|
|
203
|
+
})
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Get raw search results - routes to ChromaDB when enabled
|
|
208
|
+
* Use this for internal operations that need raw results
|
|
209
|
+
*/
|
|
210
|
+
async searchRaw(
|
|
211
|
+
query: string,
|
|
212
|
+
options?: { project?: string; limit?: number; minSimilarity?: number }
|
|
213
|
+
): Promise<any[]> {
|
|
214
|
+
if (this.useChromaDB) {
|
|
215
|
+
const chromaResults = await this.chroma.search.searchDecisions(query, {
|
|
216
|
+
project: options?.project,
|
|
217
|
+
limit: options?.limit || 5,
|
|
218
|
+
minSimilarity: options?.minSimilarity || 0.5
|
|
219
|
+
})
|
|
220
|
+
// Transform ChromaDB results to match MemorySearchResult structure
|
|
221
|
+
return chromaResults.map(r => ({
|
|
222
|
+
memory: {
|
|
223
|
+
id: r.id,
|
|
224
|
+
project: r.metadata.project || options?.project || 'unknown',
|
|
225
|
+
content: typeof r.content === 'string' ? r.content : JSON.stringify(r.content),
|
|
226
|
+
createdAt: r.metadata.created_at ? new Date(r.metadata.created_at) : new Date(),
|
|
227
|
+
metadata: r.metadata
|
|
228
|
+
},
|
|
229
|
+
similarity: r.similarity,
|
|
230
|
+
decision: r.metadata.decision ? {
|
|
231
|
+
id: r.id,
|
|
232
|
+
project: r.metadata.project || options?.project || 'unknown',
|
|
233
|
+
context: r.metadata.context || '',
|
|
234
|
+
decision: r.metadata.decision || (typeof r.content === 'string' ? r.content : ''),
|
|
235
|
+
reasoning: r.metadata.reasoning || '',
|
|
236
|
+
alternatives: r.metadata.alternatives_considered || '',
|
|
237
|
+
tags: r.metadata.tags || [],
|
|
238
|
+
outcome: r.metadata.outcome,
|
|
239
|
+
createdAt: r.metadata.created_at ? new Date(r.metadata.created_at) : new Date()
|
|
240
|
+
} : undefined
|
|
241
|
+
}))
|
|
242
|
+
} else {
|
|
243
|
+
return await this.search.search(query, {
|
|
244
|
+
project: options?.project,
|
|
245
|
+
limit: options?.limit || 5,
|
|
246
|
+
minSimilarity: options?.minSimilarity || 0.5
|
|
247
|
+
})
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
async recallSimilar(
|
|
252
|
+
query: string,
|
|
253
|
+
options?: { project?: string; limit?: number; minSimilarity?: number }
|
|
254
|
+
): Promise<string> {
|
|
255
|
+
const results = await this.searchRaw(query, options)
|
|
256
|
+
return this.contextBuilder.buildDecisionContext(results)
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
async getRecommendations(
|
|
260
|
+
currentContext: string,
|
|
261
|
+
project: string,
|
|
262
|
+
limit: number = 3
|
|
263
|
+
): Promise<string> {
|
|
264
|
+
const results = await this.search.getRecommendations(currentContext, project, limit)
|
|
265
|
+
return this.contextBuilder.buildRecommendationContext(results)
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
async migrateToChromaDB(options: MigrationOptions = {}): Promise<any> {
|
|
269
|
+
if (!this.useChromaDB) {
|
|
270
|
+
throw new Error('ChromaDB is not enabled')
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
const migration = new ChromaMigration(
|
|
274
|
+
this.logger,
|
|
275
|
+
this.database.getDb(),
|
|
276
|
+
this.chroma.store,
|
|
277
|
+
this.chroma.collections
|
|
278
|
+
)
|
|
279
|
+
|
|
280
|
+
return migration.migrate(options)
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Store a pattern in memory
|
|
285
|
+
*/
|
|
286
|
+
async storePattern(input: {
|
|
287
|
+
project: string
|
|
288
|
+
pattern_type: 'solution' | 'anti-pattern' | 'best-practice' | 'common-issue'
|
|
289
|
+
description: string
|
|
290
|
+
example?: string
|
|
291
|
+
confidence: number
|
|
292
|
+
context?: string
|
|
293
|
+
}): Promise<string> {
|
|
294
|
+
if (!this.useChromaDB) {
|
|
295
|
+
throw new Error('Pattern storage requires ChromaDB backend')
|
|
296
|
+
}
|
|
297
|
+
return this.chroma.store.storePattern(input)
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* Store a correction/lesson learned in memory
|
|
302
|
+
*/
|
|
303
|
+
async storeCorrection(input: {
|
|
304
|
+
project: string
|
|
305
|
+
original: string
|
|
306
|
+
correction: string
|
|
307
|
+
reasoning: string
|
|
308
|
+
context?: string
|
|
309
|
+
confidence: number
|
|
310
|
+
}): Promise<string> {
|
|
311
|
+
if (!this.useChromaDB) {
|
|
312
|
+
throw new Error('Correction storage requires ChromaDB backend')
|
|
313
|
+
}
|
|
314
|
+
return this.chroma.store.storeCorrection(input)
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* Get patterns for a project
|
|
319
|
+
*/
|
|
320
|
+
async getPatterns(
|
|
321
|
+
project?: string,
|
|
322
|
+
options?: {
|
|
323
|
+
pattern_type?: 'solution' | 'anti-pattern' | 'best-practice' | 'common-issue'
|
|
324
|
+
limit?: number
|
|
325
|
+
}
|
|
326
|
+
): Promise<any[]> {
|
|
327
|
+
if (!this.useChromaDB) {
|
|
328
|
+
throw new Error('Pattern retrieval requires ChromaDB backend')
|
|
329
|
+
}
|
|
330
|
+
if (project) {
|
|
331
|
+
return this.chroma.store.getPatternsByProject(project, options)
|
|
332
|
+
}
|
|
333
|
+
// If no project specified, search all patterns
|
|
334
|
+
return this.chroma.store.searchPatterns('', { limit: options?.limit || 10 })
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* Get corrections for a project
|
|
339
|
+
*/
|
|
340
|
+
async getCorrections(
|
|
341
|
+
project?: string,
|
|
342
|
+
options?: { limit?: number }
|
|
343
|
+
): Promise<any[]> {
|
|
344
|
+
if (!this.useChromaDB) {
|
|
345
|
+
throw new Error('Correction retrieval requires ChromaDB backend')
|
|
346
|
+
}
|
|
347
|
+
if (project) {
|
|
348
|
+
return this.chroma.store.getCorrectionsByProject(project, options?.limit || 10)
|
|
349
|
+
}
|
|
350
|
+
// If no project specified, search all corrections
|
|
351
|
+
return this.chroma.store.searchCorrections('', { limit: options?.limit || 10 })
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
/**
|
|
355
|
+
* Search patterns by query
|
|
356
|
+
*/
|
|
357
|
+
async searchPatterns(
|
|
358
|
+
query: string,
|
|
359
|
+
options?: {
|
|
360
|
+
project?: string
|
|
361
|
+
pattern_type?: 'solution' | 'anti-pattern' | 'best-practice' | 'common-issue'
|
|
362
|
+
limit?: number
|
|
363
|
+
minSimilarity?: number
|
|
364
|
+
}
|
|
365
|
+
): Promise<any[]> {
|
|
366
|
+
if (!this.useChromaDB) {
|
|
367
|
+
throw new Error('Pattern search requires ChromaDB backend')
|
|
368
|
+
}
|
|
369
|
+
return this.chroma.store.searchPatterns(query, options)
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/**
|
|
373
|
+
* Search corrections by query
|
|
374
|
+
*/
|
|
375
|
+
async searchCorrections(
|
|
376
|
+
query: string,
|
|
377
|
+
options?: {
|
|
378
|
+
project?: string
|
|
379
|
+
limit?: number
|
|
380
|
+
minSimilarity?: number
|
|
381
|
+
}
|
|
382
|
+
): Promise<any[]> {
|
|
383
|
+
if (!this.useChromaDB) {
|
|
384
|
+
throw new Error('Correction search requires ChromaDB backend')
|
|
385
|
+
}
|
|
386
|
+
return this.chroma.store.searchCorrections(query, options)
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
/**
|
|
391
|
+
* Create a memory manager instance
|
|
392
|
+
*/
|
|
393
|
+
export function createMemoryManager(dbPath: string, logger: Logger): MemoryManager {
|
|
394
|
+
return new MemoryManager(dbPath, logger)
|
|
395
|
+
}
|