claude-brain 0.30.2 → 0.31.1
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 +59 -56
- package/src/config/index.ts +5 -5
- package/src/config/loader.ts +195 -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,194 +1,194 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Fusion Strategies
|
|
3
|
-
* Different methods for combining dense and sparse search results
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import type { HybridSearchResult } from '../types'
|
|
7
|
-
import { fuseWithRRF, fuseMultipleWithRRF } from './rrf'
|
|
8
|
-
|
|
9
|
-
export interface FusionConfig {
|
|
10
|
-
/** Fusion method to use */
|
|
11
|
-
method: 'rrf' | 'linear' | 'max'
|
|
12
|
-
/** RRF k parameter (for RRF method) */
|
|
13
|
-
rrfK?: number
|
|
14
|
-
/** Dense weight (for linear method) */
|
|
15
|
-
denseWeight?: number
|
|
16
|
-
/** Sparse weight (for linear method) */
|
|
17
|
-
sparseWeight?: number
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const DEFAULT_CONFIG: FusionConfig = {
|
|
21
|
-
method: 'rrf',
|
|
22
|
-
rrfK: 60,
|
|
23
|
-
denseWeight: 0.7,
|
|
24
|
-
sparseWeight: 0.3
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* RRF Fusion - Reciprocal Rank Fusion
|
|
29
|
-
*/
|
|
30
|
-
export class RRFFusion {
|
|
31
|
-
private k: number
|
|
32
|
-
|
|
33
|
-
constructor(k: number = 60) {
|
|
34
|
-
this.k = k
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
fuse(
|
|
38
|
-
denseResults: HybridSearchResult[],
|
|
39
|
-
sparseResults: HybridSearchResult[]
|
|
40
|
-
): HybridSearchResult[] {
|
|
41
|
-
return fuseWithRRF(denseResults, sparseResults, { k: this.k })
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
fuseMultiple(rankedLists: HybridSearchResult[][]): HybridSearchResult[] {
|
|
45
|
-
return fuseMultipleWithRRF(rankedLists, { k: this.k })
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Linear Fusion - Weighted combination of scores
|
|
51
|
-
*/
|
|
52
|
-
export class LinearFusion {
|
|
53
|
-
private denseWeight: number
|
|
54
|
-
private sparseWeight: number
|
|
55
|
-
|
|
56
|
-
constructor(denseWeight: number = 0.7, sparseWeight: number = 0.3) {
|
|
57
|
-
this.denseWeight = denseWeight
|
|
58
|
-
this.sparseWeight = sparseWeight
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
fuse(
|
|
62
|
-
denseResults: HybridSearchResult[],
|
|
63
|
-
sparseResults: HybridSearchResult[]
|
|
64
|
-
): HybridSearchResult[] {
|
|
65
|
-
// Create map for merging
|
|
66
|
-
const merged = new Map<string, HybridSearchResult>()
|
|
67
|
-
|
|
68
|
-
// Add dense results
|
|
69
|
-
for (const result of denseResults) {
|
|
70
|
-
merged.set(result.id, {
|
|
71
|
-
...result,
|
|
72
|
-
scores: {
|
|
73
|
-
...result.scores,
|
|
74
|
-
fusion: result.scores.dense * this.denseWeight,
|
|
75
|
-
final: result.scores.dense * this.denseWeight
|
|
76
|
-
},
|
|
77
|
-
provenance: 'dense'
|
|
78
|
-
})
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// Add/merge sparse results
|
|
82
|
-
for (const result of sparseResults) {
|
|
83
|
-
const existing = merged.get(result.id)
|
|
84
|
-
if (existing) {
|
|
85
|
-
const combinedScore =
|
|
86
|
-
existing.scores.fusion + result.scores.sparse * this.sparseWeight
|
|
87
|
-
merged.set(result.id, {
|
|
88
|
-
...existing,
|
|
89
|
-
scores: {
|
|
90
|
-
...existing.scores,
|
|
91
|
-
sparse: result.scores.sparse,
|
|
92
|
-
fusion: combinedScore,
|
|
93
|
-
final: combinedScore
|
|
94
|
-
},
|
|
95
|
-
provenance: 'both'
|
|
96
|
-
})
|
|
97
|
-
} else {
|
|
98
|
-
merged.set(result.id, {
|
|
99
|
-
...result,
|
|
100
|
-
scores: {
|
|
101
|
-
...result.scores,
|
|
102
|
-
fusion: result.scores.sparse * this.sparseWeight,
|
|
103
|
-
final: result.scores.sparse * this.sparseWeight
|
|
104
|
-
},
|
|
105
|
-
provenance: 'sparse'
|
|
106
|
-
})
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
// Sort by fusion score
|
|
111
|
-
const results = Array.from(merged.values())
|
|
112
|
-
results.sort((a, b) => b.scores.fusion - a.scores.fusion)
|
|
113
|
-
|
|
114
|
-
return results
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
/**
|
|
119
|
-
* Max Fusion - Take maximum score from either list
|
|
120
|
-
*/
|
|
121
|
-
export class MaxFusion {
|
|
122
|
-
fuse(
|
|
123
|
-
denseResults: HybridSearchResult[],
|
|
124
|
-
sparseResults: HybridSearchResult[]
|
|
125
|
-
): HybridSearchResult[] {
|
|
126
|
-
// Create map for merging
|
|
127
|
-
const merged = new Map<string, HybridSearchResult>()
|
|
128
|
-
|
|
129
|
-
// Add dense results
|
|
130
|
-
for (const result of denseResults) {
|
|
131
|
-
merged.set(result.id, {
|
|
132
|
-
...result,
|
|
133
|
-
scores: {
|
|
134
|
-
...result.scores,
|
|
135
|
-
fusion: result.scores.dense,
|
|
136
|
-
final: result.scores.dense
|
|
137
|
-
},
|
|
138
|
-
provenance: 'dense'
|
|
139
|
-
})
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
// Add/merge sparse results
|
|
143
|
-
for (const result of sparseResults) {
|
|
144
|
-
const existing = merged.get(result.id)
|
|
145
|
-
if (existing) {
|
|
146
|
-
const maxScore = Math.max(existing.scores.dense || 0, result.scores.sparse)
|
|
147
|
-
merged.set(result.id, {
|
|
148
|
-
...existing,
|
|
149
|
-
scores: {
|
|
150
|
-
...existing.scores,
|
|
151
|
-
sparse: result.scores.sparse,
|
|
152
|
-
fusion: maxScore,
|
|
153
|
-
final: maxScore
|
|
154
|
-
},
|
|
155
|
-
provenance: 'both'
|
|
156
|
-
})
|
|
157
|
-
} else {
|
|
158
|
-
merged.set(result.id, {
|
|
159
|
-
...result,
|
|
160
|
-
scores: {
|
|
161
|
-
...result.scores,
|
|
162
|
-
fusion: result.scores.sparse,
|
|
163
|
-
final: result.scores.sparse
|
|
164
|
-
},
|
|
165
|
-
provenance: 'sparse'
|
|
166
|
-
})
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
// Sort by fusion score
|
|
171
|
-
const results = Array.from(merged.values())
|
|
172
|
-
results.sort((a, b) => b.scores.fusion - a.scores.fusion)
|
|
173
|
-
|
|
174
|
-
return results
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
/**
|
|
179
|
-
* Create a fusion strategy based on config
|
|
180
|
-
*/
|
|
181
|
-
export function createFusionStrategy(config: FusionConfig = DEFAULT_CONFIG) {
|
|
182
|
-
switch (config.method) {
|
|
183
|
-
case 'rrf':
|
|
184
|
-
return new RRFFusion(config.rrfK)
|
|
185
|
-
case 'linear':
|
|
186
|
-
return new LinearFusion(config.denseWeight, config.sparseWeight)
|
|
187
|
-
case 'max':
|
|
188
|
-
return new MaxFusion()
|
|
189
|
-
default:
|
|
190
|
-
return new RRFFusion(config.rrfK)
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
export { fuseWithRRF, fuseMultipleWithRRF, calculateRRFScore } from './rrf'
|
|
1
|
+
/**
|
|
2
|
+
* Fusion Strategies
|
|
3
|
+
* Different methods for combining dense and sparse search results
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { HybridSearchResult } from '../types'
|
|
7
|
+
import { fuseWithRRF, fuseMultipleWithRRF } from './rrf'
|
|
8
|
+
|
|
9
|
+
export interface FusionConfig {
|
|
10
|
+
/** Fusion method to use */
|
|
11
|
+
method: 'rrf' | 'linear' | 'max'
|
|
12
|
+
/** RRF k parameter (for RRF method) */
|
|
13
|
+
rrfK?: number
|
|
14
|
+
/** Dense weight (for linear method) */
|
|
15
|
+
denseWeight?: number
|
|
16
|
+
/** Sparse weight (for linear method) */
|
|
17
|
+
sparseWeight?: number
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const DEFAULT_CONFIG: FusionConfig = {
|
|
21
|
+
method: 'rrf',
|
|
22
|
+
rrfK: 60,
|
|
23
|
+
denseWeight: 0.7,
|
|
24
|
+
sparseWeight: 0.3
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* RRF Fusion - Reciprocal Rank Fusion
|
|
29
|
+
*/
|
|
30
|
+
export class RRFFusion {
|
|
31
|
+
private k: number
|
|
32
|
+
|
|
33
|
+
constructor(k: number = 60) {
|
|
34
|
+
this.k = k
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
fuse(
|
|
38
|
+
denseResults: HybridSearchResult[],
|
|
39
|
+
sparseResults: HybridSearchResult[]
|
|
40
|
+
): HybridSearchResult[] {
|
|
41
|
+
return fuseWithRRF(denseResults, sparseResults, { k: this.k })
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
fuseMultiple(rankedLists: HybridSearchResult[][]): HybridSearchResult[] {
|
|
45
|
+
return fuseMultipleWithRRF(rankedLists, { k: this.k })
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Linear Fusion - Weighted combination of scores
|
|
51
|
+
*/
|
|
52
|
+
export class LinearFusion {
|
|
53
|
+
private denseWeight: number
|
|
54
|
+
private sparseWeight: number
|
|
55
|
+
|
|
56
|
+
constructor(denseWeight: number = 0.7, sparseWeight: number = 0.3) {
|
|
57
|
+
this.denseWeight = denseWeight
|
|
58
|
+
this.sparseWeight = sparseWeight
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
fuse(
|
|
62
|
+
denseResults: HybridSearchResult[],
|
|
63
|
+
sparseResults: HybridSearchResult[]
|
|
64
|
+
): HybridSearchResult[] {
|
|
65
|
+
// Create map for merging
|
|
66
|
+
const merged = new Map<string, HybridSearchResult>()
|
|
67
|
+
|
|
68
|
+
// Add dense results
|
|
69
|
+
for (const result of denseResults) {
|
|
70
|
+
merged.set(result.id, {
|
|
71
|
+
...result,
|
|
72
|
+
scores: {
|
|
73
|
+
...result.scores,
|
|
74
|
+
fusion: result.scores.dense * this.denseWeight,
|
|
75
|
+
final: result.scores.dense * this.denseWeight
|
|
76
|
+
},
|
|
77
|
+
provenance: 'dense'
|
|
78
|
+
})
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Add/merge sparse results
|
|
82
|
+
for (const result of sparseResults) {
|
|
83
|
+
const existing = merged.get(result.id)
|
|
84
|
+
if (existing) {
|
|
85
|
+
const combinedScore =
|
|
86
|
+
existing.scores.fusion + result.scores.sparse * this.sparseWeight
|
|
87
|
+
merged.set(result.id, {
|
|
88
|
+
...existing,
|
|
89
|
+
scores: {
|
|
90
|
+
...existing.scores,
|
|
91
|
+
sparse: result.scores.sparse,
|
|
92
|
+
fusion: combinedScore,
|
|
93
|
+
final: combinedScore
|
|
94
|
+
},
|
|
95
|
+
provenance: 'both'
|
|
96
|
+
})
|
|
97
|
+
} else {
|
|
98
|
+
merged.set(result.id, {
|
|
99
|
+
...result,
|
|
100
|
+
scores: {
|
|
101
|
+
...result.scores,
|
|
102
|
+
fusion: result.scores.sparse * this.sparseWeight,
|
|
103
|
+
final: result.scores.sparse * this.sparseWeight
|
|
104
|
+
},
|
|
105
|
+
provenance: 'sparse'
|
|
106
|
+
})
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Sort by fusion score
|
|
111
|
+
const results = Array.from(merged.values())
|
|
112
|
+
results.sort((a, b) => b.scores.fusion - a.scores.fusion)
|
|
113
|
+
|
|
114
|
+
return results
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Max Fusion - Take maximum score from either list
|
|
120
|
+
*/
|
|
121
|
+
export class MaxFusion {
|
|
122
|
+
fuse(
|
|
123
|
+
denseResults: HybridSearchResult[],
|
|
124
|
+
sparseResults: HybridSearchResult[]
|
|
125
|
+
): HybridSearchResult[] {
|
|
126
|
+
// Create map for merging
|
|
127
|
+
const merged = new Map<string, HybridSearchResult>()
|
|
128
|
+
|
|
129
|
+
// Add dense results
|
|
130
|
+
for (const result of denseResults) {
|
|
131
|
+
merged.set(result.id, {
|
|
132
|
+
...result,
|
|
133
|
+
scores: {
|
|
134
|
+
...result.scores,
|
|
135
|
+
fusion: result.scores.dense,
|
|
136
|
+
final: result.scores.dense
|
|
137
|
+
},
|
|
138
|
+
provenance: 'dense'
|
|
139
|
+
})
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Add/merge sparse results
|
|
143
|
+
for (const result of sparseResults) {
|
|
144
|
+
const existing = merged.get(result.id)
|
|
145
|
+
if (existing) {
|
|
146
|
+
const maxScore = Math.max(existing.scores.dense || 0, result.scores.sparse)
|
|
147
|
+
merged.set(result.id, {
|
|
148
|
+
...existing,
|
|
149
|
+
scores: {
|
|
150
|
+
...existing.scores,
|
|
151
|
+
sparse: result.scores.sparse,
|
|
152
|
+
fusion: maxScore,
|
|
153
|
+
final: maxScore
|
|
154
|
+
},
|
|
155
|
+
provenance: 'both'
|
|
156
|
+
})
|
|
157
|
+
} else {
|
|
158
|
+
merged.set(result.id, {
|
|
159
|
+
...result,
|
|
160
|
+
scores: {
|
|
161
|
+
...result.scores,
|
|
162
|
+
fusion: result.scores.sparse,
|
|
163
|
+
final: result.scores.sparse
|
|
164
|
+
},
|
|
165
|
+
provenance: 'sparse'
|
|
166
|
+
})
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Sort by fusion score
|
|
171
|
+
const results = Array.from(merged.values())
|
|
172
|
+
results.sort((a, b) => b.scores.fusion - a.scores.fusion)
|
|
173
|
+
|
|
174
|
+
return results
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Create a fusion strategy based on config
|
|
180
|
+
*/
|
|
181
|
+
export function createFusionStrategy(config: FusionConfig = DEFAULT_CONFIG) {
|
|
182
|
+
switch (config.method) {
|
|
183
|
+
case 'rrf':
|
|
184
|
+
return new RRFFusion(config.rrfK)
|
|
185
|
+
case 'linear':
|
|
186
|
+
return new LinearFusion(config.denseWeight, config.sparseWeight)
|
|
187
|
+
case 'max':
|
|
188
|
+
return new MaxFusion()
|
|
189
|
+
default:
|
|
190
|
+
return new RRFFusion(config.rrfK)
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
export { fuseWithRRF, fuseMultipleWithRRF, calculateRRFScore } from './rrf'
|