claude-brain 0.30.2 → 0.30.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +241 -191
- package/VERSION +1 -1
- package/assets/CLAUDE-unified.md +11 -11
- package/assets/CLAUDE.md +29 -29
- package/package.json +7 -3
- 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/scripts/postinstall.mjs +531 -531
- package/src/automation/decision-detector.ts +452 -452
- 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 +210 -205
- package/src/cli/auto-setup.ts +75 -75
- package/src/cli/auto-start.ts +266 -266
- package/src/cli/bin.ts +264 -264
- package/src/cli/commands/autostart.ts +90 -90
- package/src/cli/commands/chroma.ts +578 -577
- package/src/cli/commands/export-training.ts +70 -70
- package/src/cli/commands/export.ts +130 -130
- package/src/cli/commands/git-hook.ts +183 -183
- package/src/cli/commands/hooks.ts +217 -217
- package/src/cli/commands/init.ts +123 -123
- package/src/cli/commands/install-mcp.ts +122 -111
- package/src/cli/commands/models.ts +979 -979
- package/src/cli/commands/pack.ts +200 -200
- package/src/cli/commands/refresh.ts +344 -339
- package/src/cli/commands/reindex.ts +120 -120
- package/src/cli/commands/serve.ts +466 -463
- package/src/cli/commands/start.ts +44 -44
- package/src/cli/commands/status.ts +220 -203
- package/src/cli/commands/uninstall-mcp.ts +45 -41
- package/src/cli/commands/update.ts +130 -124
- package/src/cli/migrate-chroma.ts +106 -106
- 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/code-intelligence/indexer.ts +352 -352
- package/src/code-intelligence/linker.ts +178 -178
- package/src/code-intelligence/parser.ts +484 -484
- package/src/code-intelligence/query.ts +291 -291
- package/src/code-intelligence/schema.ts +83 -83
- package/src/code-intelligence/types.ts +95 -95
- package/src/config/defaults.ts +52 -52
- package/src/config/home.ts +56 -56
- package/src/config/index.ts +5 -5
- package/src/config/loader.ts +192 -192
- package/src/config/schema.ts +446 -415
- package/src/config/validator.ts +182 -182
- package/src/context/assembler.ts +407 -400
- package/src/context/index.ts +79 -79
- package/src/context/progress-tracker.ts +174 -174
- package/src/context/standards-manager.ts +287 -287
- package/src/context/validator.ts +58 -58
- package/src/diagnostics/index.ts +122 -121
- package/src/health/index.ts +233 -232
- package/src/hooks/brain-hook.ts +134 -131
- package/src/hooks/capture.ts +168 -168
- package/src/hooks/claude-code-mastery.md +112 -112
- package/src/hooks/context-hook.ts +260 -245
- package/src/hooks/deduplicator.ts +72 -72
- package/src/hooks/git-capture.ts +109 -109
- package/src/hooks/git-hook-installer.ts +211 -207
- package/src/hooks/index.ts +20 -20
- package/src/hooks/installer.ts +306 -288
- package/src/hooks/interceptor-hook.ts +204 -201
- package/src/hooks/passive-classifier.ts +397 -397
- package/src/hooks/queue.ts +160 -129
- package/src/hooks/session-tracker.ts +312 -312
- package/src/hooks/types.ts +52 -52
- package/src/index.ts +7 -7
- package/src/intelligence/cross-project/generalizer.ts +283 -283
- package/src/intelligence/cross-project/index.ts +7 -7
- package/src/intelligence/hf-downloader.ts +222 -222
- package/src/intelligence/hf-manifest.json +78 -78
- package/src/intelligence/index.ts +24 -24
- package/src/intelligence/inference-router.ts +762 -762
- package/src/intelligence/model-manager.ts +263 -245
- package/src/intelligence/optimization/index.ts +10 -10
- package/src/intelligence/optimization/precompute.ts +202 -202
- package/src/intelligence/optimization/semantic-cache.ts +213 -207
- package/src/intelligence/prediction/index.ts +7 -7
- package/src/intelligence/prediction/recommender.ts +276 -268
- package/src/intelligence/reasoning/chain-retrieval.ts +243 -247
- package/src/intelligence/reasoning/index.ts +7 -7
- package/src/intelligence/temporal/evolution.ts +193 -197
- package/src/intelligence/temporal/index.ts +16 -16
- package/src/intelligence/temporal/query-processor.ts +190 -190
- package/src/intelligence/temporal/timeline.ts +272 -259
- package/src/intelligence/temporal/trends.ts +263 -263
- package/src/intelligence/tokenizer.ts +118 -118
- package/src/knowledge/entity-extractor.ts +447 -443
- 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 +166 -166
- package/src/knowledge/relationship-extractor.ts +108 -108
- package/src/memory/chroma/client.ts +211 -192
- package/src/memory/chroma/collection-manager.ts +92 -92
- package/src/memory/chroma/config.ts +57 -57
- package/src/memory/chroma/embeddings.ts +177 -175
- 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 +319 -315
- package/src/memory/chroma/store.ts +755 -747
- package/src/memory/compression.ts +121 -121
- package/src/memory/consolidation/archiver.ts +162 -165
- package/src/memory/consolidation/merger.ts +182 -186
- package/src/memory/consolidation/scorer.ts +136 -136
- package/src/memory/database.ts +9 -0
- package/src/memory/dual-write.ts +145 -0
- package/src/memory/embeddings.ts +226 -226
- package/src/memory/episodic/detector.ts +108 -108
- package/src/memory/episodic/manager.ts +347 -351
- package/src/memory/episodic/summarizer.ts +179 -179
- package/src/memory/episodic/types.ts +52 -52
- package/src/memory/fts5-search.ts +692 -633
- package/src/memory/index.ts +943 -1060
- package/src/memory/migrations/add-fts5.ts +118 -108
- package/src/memory/patterns.ts +438 -438
- package/src/memory/pruning.ts +60 -60
- package/src/memory/schema.ts +88 -88
- package/src/memory/store.ts +911 -787
- package/src/orchestrator/handlers/decision-handler.ts +204 -204
- 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 -297
- package/src/retrieval/bm25/tokenizer.ts +184 -184
- package/src/retrieval/feedback/adaptive.ts +221 -221
- package/src/retrieval/feedback/index.ts +16 -16
- package/src/retrieval/feedback/metrics.ts +221 -221
- package/src/retrieval/feedback/store.ts +283 -283
- package/src/retrieval/fusion/index.ts +194 -194
- package/src/retrieval/fusion/rrf.ts +165 -165
- package/src/retrieval/index.ts +12 -12
- package/src/retrieval/pipeline.ts +375 -375
- package/src/retrieval/query/expander.ts +203 -203
- package/src/retrieval/query/index.ts +27 -27
- package/src/retrieval/query/intent-classifier.ts +252 -252
- package/src/retrieval/query/temporal-parser.ts +295 -295
- package/src/retrieval/reranker/index.ts +189 -188
- package/src/retrieval/reranker/model.ts +99 -95
- package/src/retrieval/service.ts +125 -125
- package/src/retrieval/types.ts +162 -162
- package/src/routing/entity-extractor.ts +454 -454
- package/src/routing/handlers/exploration-handler.ts +369 -0
- package/src/routing/handlers/index.ts +19 -0
- package/src/routing/handlers/memory-handler.ts +273 -0
- package/src/routing/handlers/mutation-handler.ts +241 -0
- package/src/routing/handlers/recall-handler.ts +642 -0
- package/src/routing/handlers/shared.ts +515 -0
- package/src/routing/handlers/types.ts +48 -0
- package/src/routing/intent-classifier.ts +552 -552
- package/src/routing/response-filter.ts +399 -391
- package/src/routing/router.ts +245 -2193
- package/src/routing/search-engine.ts +521 -514
- package/src/routing/types.ts +104 -94
- package/src/scripts/health-check.ts +118 -118
- package/src/scripts/setup.ts +122 -122
- package/src/server/auto-updater.ts +283 -276
- package/src/server/handlers/call-tool.ts +159 -159
- package/src/server/handlers/list-tools.ts +35 -35
- package/src/server/handlers/tools/auto-remember.ts +165 -165
- package/src/server/handlers/tools/brain.ts +86 -86
- package/src/server/handlers/tools/create-project.ts +135 -135
- package/src/server/handlers/tools/get-code-standards.ts +123 -123
- package/src/server/handlers/tools/get-corrections.ts +152 -152
- package/src/server/handlers/tools/get-patterns.ts +156 -156
- package/src/server/handlers/tools/get-project-context.ts +75 -75
- package/src/server/handlers/tools/index.ts +30 -30
- package/src/server/handlers/tools/init-project.ts +756 -756
- package/src/server/handlers/tools/list-projects.ts +126 -126
- package/src/server/handlers/tools/recall-similar.ts +87 -87
- package/src/server/handlers/tools/recognize-pattern.ts +132 -132
- package/src/server/handlers/tools/record-correction.ts +131 -131
- package/src/server/handlers/tools/remember-decision.ts +168 -168
- package/src/server/handlers/tools/schemas.ts +179 -179
- package/src/server/handlers/tools/search-code.ts +122 -122
- package/src/server/handlers/tools/smart-context.ts +146 -146
- package/src/server/handlers/tools/update-progress.ts +131 -131
- package/src/server/http-api.ts +215 -1229
- package/src/server/mcp-proxy.ts +85 -84
- package/src/server/mcp-server.ts +285 -284
- package/src/server/middleware/auth.ts +39 -0
- package/src/server/middleware/error-handler.ts +37 -0
- package/src/server/middleware/rate-limit.ts +53 -0
- package/src/server/middleware/validate.ts +42 -0
- package/src/server/pid-manager.ts +137 -136
- package/src/server/providers/resources.ts +581 -581
- package/src/server/routes/code.ts +228 -0
- package/src/server/routes/context.ts +26 -0
- package/src/server/routes/health.ts +19 -0
- package/src/server/routes/helpers.ts +100 -0
- package/src/server/routes/hooks.ts +197 -0
- package/src/server/routes/mcp.ts +47 -0
- package/src/server/routes/memory.ts +397 -0
- package/src/server/routes/models.ts +96 -0
- package/src/server/routes/projects.ts +89 -0
- package/src/server/routes/types.ts +21 -0
- package/src/server/schemas/api-schemas.ts +202 -0
- package/src/server/services.ts +720 -720
- package/src/server/utils/memory-indicator.ts +84 -84
- package/src/server/utils/response-formatter.ts +129 -129
- package/src/server/web-viewer.ts +1145 -1115
- package/src/setup/index.ts +38 -38
- package/src/tools/registry.ts +115 -115
- package/src/tools/schemas.ts +666 -666
- package/src/tools/types.ts +412 -412
- package/src/training/data-store.ts +320 -298
- package/src/training/retrain-pipeline.ts +399 -394
- package/src/utils/error-handler.ts +136 -136
- package/src/utils/index.ts +58 -58
- package/src/utils/kill-port.ts +55 -53
- package/src/utils/phase12-helper.ts +56 -56
- package/src/utils/safe-path.ts +43 -0
- package/src/utils/timing.ts +47 -47
- package/src/utils/transaction.ts +63 -63
- package/src/vault/index.ts +4 -3
- package/src/vault/paths.ts +106 -106
- package/src/vault/query.ts +4 -1
- package/src/vault/reader.ts +44 -1
- package/src/vault/watcher.ts +24 -1
- package/src/vault/writer.ts +487 -413
- package/skills/persistent-memory/SKILL.md +0 -148
- package/skills/persistent-memory/references/tool-reference.md +0 -90
|
@@ -1,186 +1,182 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Memory Merger
|
|
3
|
-
* Finds and merges highly similar memories
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import type { Logger } from 'pino'
|
|
7
|
-
import type { CollectionManager } from '../chroma/collection-manager'
|
|
8
|
-
import type { EmbeddingProvider } from '../chroma/embeddings'
|
|
9
|
-
|
|
10
|
-
export interface MergeCandidate {
|
|
11
|
-
idA: string
|
|
12
|
-
idB: string
|
|
13
|
-
similarity: number
|
|
14
|
-
contentA: string
|
|
15
|
-
contentB: string
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export interface MergeResult {
|
|
19
|
-
mergedId: string
|
|
20
|
-
sourceIds: string[]
|
|
21
|
-
mergedContent: string
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export class MemoryMerger {
|
|
25
|
-
private logger: Logger
|
|
26
|
-
private collections: CollectionManager
|
|
27
|
-
private embeddings?: EmbeddingProvider
|
|
28
|
-
|
|
29
|
-
constructor(logger: Logger, collections: CollectionManager, embeddings?: EmbeddingProvider) {
|
|
30
|
-
this.logger = logger.child({ component: 'memory-merger' })
|
|
31
|
-
this.collections = collections
|
|
32
|
-
this.embeddings = embeddings
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
async findMergeCandidates(project: string, threshold: number = 0.85): Promise<MergeCandidate[]> {
|
|
36
|
-
const candidates: MergeCandidate[] = []
|
|
37
|
-
|
|
38
|
-
try {
|
|
39
|
-
const collection = await this.collections.getDecisions()
|
|
40
|
-
const results = await collection.get({
|
|
41
|
-
where: { project: { $eq: project } },
|
|
42
|
-
include: ['documents', 'metadatas', 'embeddings']
|
|
43
|
-
})
|
|
44
|
-
|
|
45
|
-
if (results.ids.length < 2) return candidates
|
|
46
|
-
|
|
47
|
-
// Pairwise comparison using embeddings
|
|
48
|
-
for (let i = 0; i < results.ids.length; i++) {
|
|
49
|
-
const docI = results.documents?.[i] as string
|
|
50
|
-
if (!docI) continue
|
|
51
|
-
|
|
52
|
-
// Query for similar items to this document
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
const
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
(
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
//
|
|
121
|
-
const
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
metadata
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
const
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
return null
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Memory Merger
|
|
3
|
+
* Finds and merges highly similar memories
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { Logger } from 'pino'
|
|
7
|
+
import type { CollectionManager } from '../chroma/collection-manager'
|
|
8
|
+
import type { EmbeddingProvider } from '../chroma/embeddings'
|
|
9
|
+
|
|
10
|
+
export interface MergeCandidate {
|
|
11
|
+
idA: string
|
|
12
|
+
idB: string
|
|
13
|
+
similarity: number
|
|
14
|
+
contentA: string
|
|
15
|
+
contentB: string
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface MergeResult {
|
|
19
|
+
mergedId: string
|
|
20
|
+
sourceIds: string[]
|
|
21
|
+
mergedContent: string
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export class MemoryMerger {
|
|
25
|
+
private logger: Logger
|
|
26
|
+
private collections: CollectionManager
|
|
27
|
+
private embeddings?: EmbeddingProvider
|
|
28
|
+
|
|
29
|
+
constructor(logger: Logger, collections: CollectionManager, embeddings?: EmbeddingProvider) {
|
|
30
|
+
this.logger = logger.child({ component: 'memory-merger' })
|
|
31
|
+
this.collections = collections
|
|
32
|
+
this.embeddings = embeddings
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async findMergeCandidates(project: string, threshold: number = 0.85): Promise<MergeCandidate[]> {
|
|
36
|
+
const candidates: MergeCandidate[] = []
|
|
37
|
+
|
|
38
|
+
try {
|
|
39
|
+
const collection = await this.collections.getDecisions()
|
|
40
|
+
const results = await collection.get({
|
|
41
|
+
where: { project: { $eq: project } },
|
|
42
|
+
include: ['documents', 'metadatas', 'embeddings']
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
if (results.ids.length < 2) return candidates
|
|
46
|
+
|
|
47
|
+
// Pairwise comparison using embeddings
|
|
48
|
+
for (let i = 0; i < results.ids.length; i++) {
|
|
49
|
+
const docI = results.documents?.[i] as string
|
|
50
|
+
if (!docI) continue
|
|
51
|
+
|
|
52
|
+
// Query for similar items to this document
|
|
53
|
+
const similar = (this.embeddings && results.embeddings?.[i])
|
|
54
|
+
? await collection.query({
|
|
55
|
+
queryEmbeddings: [results.embeddings[i] as number[]],
|
|
56
|
+
nResults: 5,
|
|
57
|
+
where: { project: { $eq: project } },
|
|
58
|
+
include: ['documents', 'distances']
|
|
59
|
+
})
|
|
60
|
+
: await collection.query({
|
|
61
|
+
queryTexts: [docI],
|
|
62
|
+
nResults: 5,
|
|
63
|
+
where: { project: { $eq: project } },
|
|
64
|
+
include: ['documents', 'distances']
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
if (!similar.ids?.[0]) continue
|
|
68
|
+
|
|
69
|
+
for (let j = 0; j < similar.ids[0].length; j++) {
|
|
70
|
+
const otherId = similar.ids[0][j]
|
|
71
|
+
if (otherId === results.ids[i]) continue
|
|
72
|
+
|
|
73
|
+
const distance = similar.distances?.[0]?.[j] || 1
|
|
74
|
+
const similarity = 1 - distance
|
|
75
|
+
|
|
76
|
+
if (similarity >= threshold) {
|
|
77
|
+
// Avoid duplicate pairs
|
|
78
|
+
const exists = candidates.some(c =>
|
|
79
|
+
(c.idA === results.ids[i] && c.idB === otherId) ||
|
|
80
|
+
(c.idA === otherId && c.idB === results.ids[i])
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
if (!exists) {
|
|
84
|
+
candidates.push({
|
|
85
|
+
idA: results.ids[i]!,
|
|
86
|
+
idB: otherId!,
|
|
87
|
+
similarity,
|
|
88
|
+
contentA: docI,
|
|
89
|
+
contentB: similar.documents?.[0]?.[j] || ''
|
|
90
|
+
})
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
this.logger.debug({ project, candidateCount: candidates.length }, 'Found merge candidates')
|
|
97
|
+
} catch (error) {
|
|
98
|
+
this.logger.error({ error, project }, 'Failed to find merge candidates')
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return candidates.sort((a, b) => b.similarity - a.similarity)
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
async merge(memoryIds: string[]): Promise<MergeResult | null> {
|
|
105
|
+
if (memoryIds.length < 2) return null
|
|
106
|
+
|
|
107
|
+
try {
|
|
108
|
+
const collection = await this.collections.getDecisions()
|
|
109
|
+
const results = await collection.get({
|
|
110
|
+
ids: memoryIds,
|
|
111
|
+
include: ['documents', 'metadatas']
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
if (results.ids.length < 2) return null
|
|
115
|
+
|
|
116
|
+
// Keep the newest document as the base
|
|
117
|
+
const documents = results.documents as string[]
|
|
118
|
+
const metadatas = results.metadatas as Record<string, any>[]
|
|
119
|
+
|
|
120
|
+
// Sort by created_at descending (newest first)
|
|
121
|
+
const indexed = results.ids.map((id, i) => ({
|
|
122
|
+
id,
|
|
123
|
+
document: documents[i],
|
|
124
|
+
metadata: metadatas[i]
|
|
125
|
+
}))
|
|
126
|
+
|
|
127
|
+
indexed.sort((a, b) => {
|
|
128
|
+
const dateA = a.metadata?.created_at || ''
|
|
129
|
+
const dateB = b.metadata?.created_at || ''
|
|
130
|
+
return dateB.localeCompare(dateA)
|
|
131
|
+
})
|
|
132
|
+
|
|
133
|
+
const newest = indexed[0]!
|
|
134
|
+
const mergedContent = newest.document ?? ''
|
|
135
|
+
|
|
136
|
+
// Update the newest with merged metadata
|
|
137
|
+
const mergedMetadata: Record<string, any> = {
|
|
138
|
+
...newest.metadata,
|
|
139
|
+
updated_at: new Date().toISOString(),
|
|
140
|
+
merged_from: memoryIds.filter(id => id !== newest.id).join(',')
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Combine tags from all sources
|
|
144
|
+
const allTags = new Set<string>()
|
|
145
|
+
for (const item of indexed) {
|
|
146
|
+
const tags = item.metadata?.tags?.split(',') || []
|
|
147
|
+
for (const tag of tags) {
|
|
148
|
+
if (tag.trim()) allTags.add(tag.trim())
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
mergedMetadata.tags = Array.from(allTags).join(',')
|
|
152
|
+
|
|
153
|
+
// Update the surviving memory
|
|
154
|
+
await collection.update({
|
|
155
|
+
ids: [newest.id],
|
|
156
|
+
documents: [mergedContent],
|
|
157
|
+
metadatas: [mergedMetadata]
|
|
158
|
+
})
|
|
159
|
+
|
|
160
|
+
// Delete the other memories
|
|
161
|
+
const toDelete = memoryIds.filter(id => id !== newest.id)
|
|
162
|
+
if (toDelete.length > 0) {
|
|
163
|
+
await collection.delete({ ids: toDelete })
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
this.logger.info({
|
|
167
|
+
mergedId: newest.id,
|
|
168
|
+
sourceIds: memoryIds,
|
|
169
|
+
deletedCount: toDelete.length
|
|
170
|
+
}, 'Memories merged')
|
|
171
|
+
|
|
172
|
+
return {
|
|
173
|
+
mergedId: newest.id,
|
|
174
|
+
sourceIds: memoryIds,
|
|
175
|
+
mergedContent
|
|
176
|
+
}
|
|
177
|
+
} catch (error) {
|
|
178
|
+
this.logger.error({ error, memoryIds }, 'Failed to merge memories')
|
|
179
|
+
return null
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
@@ -1,136 +1,136 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Importance Scorer
|
|
3
|
-
* Multi-factor importance scoring for memories
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import type { Logger } from 'pino'
|
|
7
|
-
import type { InMemoryKnowledgeGraph } from '../../knowledge/graph/memory-graph'
|
|
8
|
-
|
|
9
|
-
export interface ImportanceWeights {
|
|
10
|
-
recency: number
|
|
11
|
-
frequency: number
|
|
12
|
-
references: number
|
|
13
|
-
feedback: number
|
|
14
|
-
uniqueness: number
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export interface ImportanceScore {
|
|
18
|
-
total: number
|
|
19
|
-
components: {
|
|
20
|
-
recency: number
|
|
21
|
-
frequency: number
|
|
22
|
-
references: number
|
|
23
|
-
feedback: number
|
|
24
|
-
uniqueness: number
|
|
25
|
-
}
|
|
26
|
-
memoryId: string
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
const DEFAULT_WEIGHTS: ImportanceWeights = {
|
|
30
|
-
recency: 0.2,
|
|
31
|
-
frequency: 0.2,
|
|
32
|
-
references: 0.2,
|
|
33
|
-
feedback: 0.2,
|
|
34
|
-
uniqueness: 0.2
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export class ImportanceScorer {
|
|
38
|
-
private weights: ImportanceWeights
|
|
39
|
-
private graph?: InMemoryKnowledgeGraph
|
|
40
|
-
|
|
41
|
-
constructor(_logger: Logger, weights?: Partial<ImportanceWeights>, graph?: InMemoryKnowledgeGraph) {
|
|
42
|
-
this.weights = { ...DEFAULT_WEIGHTS, ...weights }
|
|
43
|
-
this.graph = graph
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
score(memory: {
|
|
47
|
-
id: string
|
|
48
|
-
created_at: string
|
|
49
|
-
recall_count?: number
|
|
50
|
-
average_rating?: number
|
|
51
|
-
max_similarity?: number
|
|
52
|
-
project?: string
|
|
53
|
-
}): ImportanceScore {
|
|
54
|
-
const recencyScore = this.calculateRecency(memory.created_at)
|
|
55
|
-
const frequencyScore = this.calculateFrequency(memory.recall_count || 0)
|
|
56
|
-
const referencesScore = this.calculateReferences(memory.id)
|
|
57
|
-
const feedbackScore = this.calculateFeedback(memory.average_rating)
|
|
58
|
-
const uniquenessScore = this.calculateUniqueness(memory.max_similarity)
|
|
59
|
-
|
|
60
|
-
const total =
|
|
61
|
-
this.weights.recency * recencyScore +
|
|
62
|
-
this.weights.frequency * frequencyScore +
|
|
63
|
-
this.weights.references * referencesScore +
|
|
64
|
-
this.weights.feedback * feedbackScore +
|
|
65
|
-
this.weights.uniqueness * uniquenessScore
|
|
66
|
-
|
|
67
|
-
return {
|
|
68
|
-
total,
|
|
69
|
-
components: {
|
|
70
|
-
recency: recencyScore,
|
|
71
|
-
frequency: frequencyScore,
|
|
72
|
-
references: referencesScore,
|
|
73
|
-
feedback: feedbackScore,
|
|
74
|
-
uniqueness: uniquenessScore
|
|
75
|
-
},
|
|
76
|
-
memoryId: memory.id
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
scoreBatch(memories: Array<{
|
|
81
|
-
id: string
|
|
82
|
-
created_at: string
|
|
83
|
-
recall_count?: number
|
|
84
|
-
average_rating?: number
|
|
85
|
-
max_similarity?: number
|
|
86
|
-
project?: string
|
|
87
|
-
}>): ImportanceScore[] {
|
|
88
|
-
return memories
|
|
89
|
-
.map(m => this.score(m))
|
|
90
|
-
.sort((a, b) => b.total - a.total)
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
private calculateRecency(createdAt: string): number {
|
|
94
|
-
const now = Date.now()
|
|
95
|
-
const created = new Date(createdAt).getTime()
|
|
96
|
-
const ageMs = now - created
|
|
97
|
-
|
|
98
|
-
// Exponential decay: half-life of 30 days
|
|
99
|
-
const halfLifeMs = 30 * 24 * 60 * 60 * 1000
|
|
100
|
-
return Math.exp(-0.693 * (ageMs / halfLifeMs))
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
private calculateFrequency(recallCount: number): number {
|
|
104
|
-
// Logarithmic scaling: diminishing returns for very high recall
|
|
105
|
-
if (recallCount === 0) return 0
|
|
106
|
-
return Math.min(1.0, Math.log10(recallCount + 1) / 2)
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
private calculateReferences(memoryId: string): number {
|
|
110
|
-
if (!this.graph) return 0.5 // neutral if no graph
|
|
111
|
-
|
|
112
|
-
// Count edges pointing to nodes related to this memory
|
|
113
|
-
const nodes = this.graph.findNodes({ properties: { decision_id: memoryId } })
|
|
114
|
-
if (nodes.length === 0) return 0.3
|
|
115
|
-
|
|
116
|
-
let edgeCount = 0
|
|
117
|
-
for (const node of nodes) {
|
|
118
|
-
edgeCount += this.graph.getEdges(node.id).length
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
// Normalize: 10+ references → score of 1.0
|
|
122
|
-
return Math.min(1.0, edgeCount / 10)
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
private calculateFeedback(averageRating?: number): number {
|
|
126
|
-
if (averageRating === undefined) return 0.5 // neutral if no feedback
|
|
127
|
-
// Scale 1-5 rating to 0-1
|
|
128
|
-
return (averageRating - 1) / 4
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
private calculateUniqueness(maxSimilarity?: number): number {
|
|
132
|
-
if (maxSimilarity === undefined) return 0.5 // neutral if unknown
|
|
133
|
-
// Inverse of max similarity: unique memories score higher
|
|
134
|
-
return 1 - maxSimilarity
|
|
135
|
-
}
|
|
136
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Importance Scorer
|
|
3
|
+
* Multi-factor importance scoring for memories
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { Logger } from 'pino'
|
|
7
|
+
import type { InMemoryKnowledgeGraph } from '../../knowledge/graph/memory-graph'
|
|
8
|
+
|
|
9
|
+
export interface ImportanceWeights {
|
|
10
|
+
recency: number
|
|
11
|
+
frequency: number
|
|
12
|
+
references: number
|
|
13
|
+
feedback: number
|
|
14
|
+
uniqueness: number
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface ImportanceScore {
|
|
18
|
+
total: number
|
|
19
|
+
components: {
|
|
20
|
+
recency: number
|
|
21
|
+
frequency: number
|
|
22
|
+
references: number
|
|
23
|
+
feedback: number
|
|
24
|
+
uniqueness: number
|
|
25
|
+
}
|
|
26
|
+
memoryId: string
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const DEFAULT_WEIGHTS: ImportanceWeights = {
|
|
30
|
+
recency: 0.2,
|
|
31
|
+
frequency: 0.2,
|
|
32
|
+
references: 0.2,
|
|
33
|
+
feedback: 0.2,
|
|
34
|
+
uniqueness: 0.2
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export class ImportanceScorer {
|
|
38
|
+
private weights: ImportanceWeights
|
|
39
|
+
private graph?: InMemoryKnowledgeGraph
|
|
40
|
+
|
|
41
|
+
constructor(_logger: Logger, weights?: Partial<ImportanceWeights>, graph?: InMemoryKnowledgeGraph) {
|
|
42
|
+
this.weights = { ...DEFAULT_WEIGHTS, ...weights }
|
|
43
|
+
this.graph = graph
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
score(memory: {
|
|
47
|
+
id: string
|
|
48
|
+
created_at: string
|
|
49
|
+
recall_count?: number
|
|
50
|
+
average_rating?: number
|
|
51
|
+
max_similarity?: number
|
|
52
|
+
project?: string
|
|
53
|
+
}): ImportanceScore {
|
|
54
|
+
const recencyScore = this.calculateRecency(memory.created_at)
|
|
55
|
+
const frequencyScore = this.calculateFrequency(memory.recall_count || 0)
|
|
56
|
+
const referencesScore = this.calculateReferences(memory.id)
|
|
57
|
+
const feedbackScore = this.calculateFeedback(memory.average_rating)
|
|
58
|
+
const uniquenessScore = this.calculateUniqueness(memory.max_similarity)
|
|
59
|
+
|
|
60
|
+
const total =
|
|
61
|
+
this.weights.recency * recencyScore +
|
|
62
|
+
this.weights.frequency * frequencyScore +
|
|
63
|
+
this.weights.references * referencesScore +
|
|
64
|
+
this.weights.feedback * feedbackScore +
|
|
65
|
+
this.weights.uniqueness * uniquenessScore
|
|
66
|
+
|
|
67
|
+
return {
|
|
68
|
+
total,
|
|
69
|
+
components: {
|
|
70
|
+
recency: recencyScore,
|
|
71
|
+
frequency: frequencyScore,
|
|
72
|
+
references: referencesScore,
|
|
73
|
+
feedback: feedbackScore,
|
|
74
|
+
uniqueness: uniquenessScore
|
|
75
|
+
},
|
|
76
|
+
memoryId: memory.id
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
scoreBatch(memories: Array<{
|
|
81
|
+
id: string
|
|
82
|
+
created_at: string
|
|
83
|
+
recall_count?: number
|
|
84
|
+
average_rating?: number
|
|
85
|
+
max_similarity?: number
|
|
86
|
+
project?: string
|
|
87
|
+
}>): ImportanceScore[] {
|
|
88
|
+
return memories
|
|
89
|
+
.map(m => this.score(m))
|
|
90
|
+
.sort((a, b) => b.total - a.total)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
private calculateRecency(createdAt: string): number {
|
|
94
|
+
const now = Date.now()
|
|
95
|
+
const created = new Date(createdAt).getTime()
|
|
96
|
+
const ageMs = now - created
|
|
97
|
+
|
|
98
|
+
// Exponential decay: half-life of 30 days
|
|
99
|
+
const halfLifeMs = 30 * 24 * 60 * 60 * 1000
|
|
100
|
+
return Math.exp(-0.693 * (ageMs / halfLifeMs))
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
private calculateFrequency(recallCount: number): number {
|
|
104
|
+
// Logarithmic scaling: diminishing returns for very high recall
|
|
105
|
+
if (recallCount === 0) return 0
|
|
106
|
+
return Math.min(1.0, Math.log10(recallCount + 1) / 2)
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
private calculateReferences(memoryId: string): number {
|
|
110
|
+
if (!this.graph) return 0.5 // neutral if no graph
|
|
111
|
+
|
|
112
|
+
// Count edges pointing to nodes related to this memory
|
|
113
|
+
const nodes = this.graph.findNodes({ properties: { decision_id: memoryId } })
|
|
114
|
+
if (nodes.length === 0) return 0.3
|
|
115
|
+
|
|
116
|
+
let edgeCount = 0
|
|
117
|
+
for (const node of nodes) {
|
|
118
|
+
edgeCount += this.graph.getEdges(node.id).length
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Normalize: 10+ references → score of 1.0
|
|
122
|
+
return Math.min(1.0, edgeCount / 10)
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
private calculateFeedback(averageRating?: number): number {
|
|
126
|
+
if (averageRating === undefined) return 0.5 // neutral if no feedback
|
|
127
|
+
// Scale 1-5 rating to 0-1
|
|
128
|
+
return (averageRating - 1) / 4
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
private calculateUniqueness(maxSimilarity?: number): number {
|
|
132
|
+
if (maxSimilarity === undefined) return 0.5 // neutral if unknown
|
|
133
|
+
// Inverse of max similarity: unique memories score higher
|
|
134
|
+
return 1 - maxSimilarity
|
|
135
|
+
}
|
|
136
|
+
}
|
package/src/memory/database.ts
CHANGED
|
@@ -39,6 +39,15 @@ export class MemoryDatabase {
|
|
|
39
39
|
// Enable foreign keys
|
|
40
40
|
this.db.run('PRAGMA foreign_keys = ON')
|
|
41
41
|
|
|
42
|
+
// Performance optimizations
|
|
43
|
+
this.db.run('PRAGMA synchronous = NORMAL')
|
|
44
|
+
this.db.run('PRAGMA cache_size = -64000')
|
|
45
|
+
this.db.run('PRAGMA mmap_size = 268435456')
|
|
46
|
+
this.db.run('PRAGMA temp_store = MEMORY')
|
|
47
|
+
this.db.run('PRAGMA journal_size_limit = 67108864')
|
|
48
|
+
this.db.run('PRAGMA wal_autocheckpoint = 1000')
|
|
49
|
+
this.db.run('PRAGMA busy_timeout = 5000')
|
|
50
|
+
|
|
42
51
|
// Create schema
|
|
43
52
|
this.db.exec(MEMORY_SCHEMA)
|
|
44
53
|
|