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,221 +1,221 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Retrieval Metrics
|
|
3
|
-
* Evaluation metrics for retrieval quality: MRR, Precision@K, NDCG
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import type { MemoryFeedback, RetrievalMetrics } from '../types'
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Calculate Mean Reciprocal Rank (MRR)
|
|
10
|
-
*
|
|
11
|
-
* MRR measures where the first relevant result appears in the ranking.
|
|
12
|
-
* MRR = (1/|Q|) * sum(1/rank_i) for each query
|
|
13
|
-
*
|
|
14
|
-
* @param feedbackByQuery - Feedback grouped by query
|
|
15
|
-
* @param relevanceThreshold - Minimum rating to consider relevant (default: 4)
|
|
16
|
-
*/
|
|
17
|
-
export function calculateMRR(
|
|
18
|
-
feedbackByQuery: Map<string, MemoryFeedback[]>,
|
|
19
|
-
relevanceThreshold: number = 4
|
|
20
|
-
): number {
|
|
21
|
-
if (feedbackByQuery.size === 0) return 0
|
|
22
|
-
|
|
23
|
-
let sumReciprocal = 0
|
|
24
|
-
let queryCount = 0
|
|
25
|
-
|
|
26
|
-
for (const [, feedbacks] of feedbackByQuery) {
|
|
27
|
-
// Sort by implicit rank (assuming feedback order matches retrieval order)
|
|
28
|
-
const sorted = [...feedbacks]
|
|
29
|
-
|
|
30
|
-
// Find first relevant result
|
|
31
|
-
for (let rank = 0; rank < sorted.length; rank++) {
|
|
32
|
-
if (sorted[rank]!.rating >= relevanceThreshold) {
|
|
33
|
-
sumReciprocal += 1 / (rank + 1)
|
|
34
|
-
break
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
if (sorted.length > 0) {
|
|
39
|
-
queryCount++
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
return queryCount > 0 ? sumReciprocal / queryCount : 0
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Calculate Precision at K
|
|
48
|
-
*
|
|
49
|
-
* Precision@K = (# relevant in top K) / K
|
|
50
|
-
*
|
|
51
|
-
* @param feedbackByQuery - Feedback grouped by query
|
|
52
|
-
* @param k - Number of top results to consider
|
|
53
|
-
* @param relevanceThreshold - Minimum rating to consider relevant
|
|
54
|
-
*/
|
|
55
|
-
export function calculatePrecisionAtK(
|
|
56
|
-
feedbackByQuery: Map<string, MemoryFeedback[]>,
|
|
57
|
-
k: number,
|
|
58
|
-
relevanceThreshold: number = 4
|
|
59
|
-
): number {
|
|
60
|
-
if (feedbackByQuery.size === 0) return 0
|
|
61
|
-
|
|
62
|
-
let sumPrecision = 0
|
|
63
|
-
let queryCount = 0
|
|
64
|
-
|
|
65
|
-
for (const [, feedbacks] of feedbackByQuery) {
|
|
66
|
-
const topK = feedbacks.slice(0, k)
|
|
67
|
-
if (topK.length === 0) continue
|
|
68
|
-
|
|
69
|
-
const relevantCount = topK.filter(f => f.rating >= relevanceThreshold).length
|
|
70
|
-
sumPrecision += relevantCount / k
|
|
71
|
-
|
|
72
|
-
queryCount++
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
return queryCount > 0 ? sumPrecision / queryCount : 0
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Calculate Normalized Discounted Cumulative Gain (NDCG)
|
|
80
|
-
*
|
|
81
|
-
* NDCG measures ranking quality, giving higher weight to relevant results at the top.
|
|
82
|
-
* DCG = sum(rating_i / log2(i + 1))
|
|
83
|
-
* NDCG = DCG / IDCG (ideal DCG)
|
|
84
|
-
*
|
|
85
|
-
* @param feedbackByQuery - Feedback grouped by query
|
|
86
|
-
* @param k - Number of top results to consider (optional, default all)
|
|
87
|
-
*/
|
|
88
|
-
export function calculateNDCG(
|
|
89
|
-
feedbackByQuery: Map<string, MemoryFeedback[]>,
|
|
90
|
-
k?: number
|
|
91
|
-
): number {
|
|
92
|
-
if (feedbackByQuery.size === 0) return 0
|
|
93
|
-
|
|
94
|
-
let sumNDCG = 0
|
|
95
|
-
let queryCount = 0
|
|
96
|
-
|
|
97
|
-
for (const [, feedbacks] of feedbackByQuery) {
|
|
98
|
-
if (feedbacks.length === 0) continue
|
|
99
|
-
|
|
100
|
-
const results = k ? feedbacks.slice(0, k) : feedbacks
|
|
101
|
-
|
|
102
|
-
// Calculate DCG
|
|
103
|
-
let dcg = 0
|
|
104
|
-
for (let i = 0; i < results.length; i++) {
|
|
105
|
-
// Use rating as relevance score (1-5)
|
|
106
|
-
const relevance = results[i]!.rating
|
|
107
|
-
dcg += relevance / Math.log2(i + 2) // +2 because log2(1) = 0
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
// Calculate ideal DCG (sort by rating descending)
|
|
111
|
-
const idealResults = [...results].sort((a, b) => b.rating - a.rating)
|
|
112
|
-
let idcg = 0
|
|
113
|
-
for (let i = 0; i < idealResults.length; i++) {
|
|
114
|
-
const relevance = idealResults[i]!.rating
|
|
115
|
-
idcg += relevance / Math.log2(i + 2)
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
// Normalize
|
|
119
|
-
if (idcg > 0) {
|
|
120
|
-
sumNDCG += dcg / idcg
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
queryCount++
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
return queryCount > 0 ? sumNDCG / queryCount : 0
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
/**
|
|
130
|
-
* Calculate all retrieval metrics from feedback
|
|
131
|
-
*/
|
|
132
|
-
export function calculateAllMetrics(
|
|
133
|
-
feedback: MemoryFeedback[],
|
|
134
|
-
kValues: number[] = [3, 5, 10]
|
|
135
|
-
): RetrievalMetrics {
|
|
136
|
-
// Group feedback by query
|
|
137
|
-
const feedbackByQuery = new Map<string, MemoryFeedback[]>()
|
|
138
|
-
|
|
139
|
-
for (const f of feedback) {
|
|
140
|
-
const existing = feedbackByQuery.get(f.queryId) || []
|
|
141
|
-
existing.push(f)
|
|
142
|
-
feedbackByQuery.set(f.queryId, existing)
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
// Calculate precision at each K
|
|
146
|
-
const precisionAtK: Record<number, number> = {}
|
|
147
|
-
for (const k of kValues) {
|
|
148
|
-
precisionAtK[k] = calculatePrecisionAtK(feedbackByQuery, k)
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
return {
|
|
152
|
-
mrr: calculateMRR(feedbackByQuery),
|
|
153
|
-
precisionAtK,
|
|
154
|
-
ndcg: calculateNDCG(feedbackByQuery),
|
|
155
|
-
queryCount: feedbackByQuery.size,
|
|
156
|
-
avgLatencyMs: 0 // Not tracked in feedback
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
/**
|
|
161
|
-
* Calculate average rating from feedback
|
|
162
|
-
*/
|
|
163
|
-
export function calculateAverageRating(feedback: MemoryFeedback[]): number {
|
|
164
|
-
if (feedback.length === 0) return 0
|
|
165
|
-
const sum = feedback.reduce((acc, f) => acc + f.rating, 0)
|
|
166
|
-
return sum / feedback.length
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
/**
|
|
170
|
-
* Calculate positive feedback rate (rating >= 4)
|
|
171
|
-
*/
|
|
172
|
-
export function calculatePositiveRate(
|
|
173
|
-
feedback: MemoryFeedback[],
|
|
174
|
-
threshold: number = 4
|
|
175
|
-
): number {
|
|
176
|
-
if (feedback.length === 0) return 0
|
|
177
|
-
const positive = feedback.filter(f => f.rating >= threshold).length
|
|
178
|
-
return positive / feedback.length
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
/**
|
|
182
|
-
* Calculate usage rate (was_used = true)
|
|
183
|
-
*/
|
|
184
|
-
export function calculateUsageRate(feedback: MemoryFeedback[]): number {
|
|
185
|
-
if (feedback.length === 0) return 0
|
|
186
|
-
const used = feedback.filter(f => f.wasUsed).length
|
|
187
|
-
return used / feedback.length
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
export class FeedbackMetrics {
|
|
191
|
-
calculateMRR(feedback: Map<string, MemoryFeedback[]>): number {
|
|
192
|
-
return calculateMRR(feedback)
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
calculatePrecisionAtK(
|
|
196
|
-
feedback: Map<string, MemoryFeedback[]>,
|
|
197
|
-
k: number
|
|
198
|
-
): number {
|
|
199
|
-
return calculatePrecisionAtK(feedback, k)
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
calculateNDCG(feedback: Map<string, MemoryFeedback[]>): number {
|
|
203
|
-
return calculateNDCG(feedback)
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
calculateAll(feedback: MemoryFeedback[]): RetrievalMetrics {
|
|
207
|
-
return calculateAllMetrics(feedback)
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
calculateAverageRating(feedback: MemoryFeedback[]): number {
|
|
211
|
-
return calculateAverageRating(feedback)
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
calculatePositiveRate(feedback: MemoryFeedback[]): number {
|
|
215
|
-
return calculatePositiveRate(feedback)
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
calculateUsageRate(feedback: MemoryFeedback[]): number {
|
|
219
|
-
return calculateUsageRate(feedback)
|
|
220
|
-
}
|
|
221
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Retrieval Metrics
|
|
3
|
+
* Evaluation metrics for retrieval quality: MRR, Precision@K, NDCG
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { MemoryFeedback, RetrievalMetrics } from '../types'
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Calculate Mean Reciprocal Rank (MRR)
|
|
10
|
+
*
|
|
11
|
+
* MRR measures where the first relevant result appears in the ranking.
|
|
12
|
+
* MRR = (1/|Q|) * sum(1/rank_i) for each query
|
|
13
|
+
*
|
|
14
|
+
* @param feedbackByQuery - Feedback grouped by query
|
|
15
|
+
* @param relevanceThreshold - Minimum rating to consider relevant (default: 4)
|
|
16
|
+
*/
|
|
17
|
+
export function calculateMRR(
|
|
18
|
+
feedbackByQuery: Map<string, MemoryFeedback[]>,
|
|
19
|
+
relevanceThreshold: number = 4
|
|
20
|
+
): number {
|
|
21
|
+
if (feedbackByQuery.size === 0) return 0
|
|
22
|
+
|
|
23
|
+
let sumReciprocal = 0
|
|
24
|
+
let queryCount = 0
|
|
25
|
+
|
|
26
|
+
for (const [, feedbacks] of feedbackByQuery) {
|
|
27
|
+
// Sort by implicit rank (assuming feedback order matches retrieval order)
|
|
28
|
+
const sorted = [...feedbacks]
|
|
29
|
+
|
|
30
|
+
// Find first relevant result
|
|
31
|
+
for (let rank = 0; rank < sorted.length; rank++) {
|
|
32
|
+
if (sorted[rank]!.rating >= relevanceThreshold) {
|
|
33
|
+
sumReciprocal += 1 / (rank + 1)
|
|
34
|
+
break
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (sorted.length > 0) {
|
|
39
|
+
queryCount++
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return queryCount > 0 ? sumReciprocal / queryCount : 0
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Calculate Precision at K
|
|
48
|
+
*
|
|
49
|
+
* Precision@K = (# relevant in top K) / K
|
|
50
|
+
*
|
|
51
|
+
* @param feedbackByQuery - Feedback grouped by query
|
|
52
|
+
* @param k - Number of top results to consider
|
|
53
|
+
* @param relevanceThreshold - Minimum rating to consider relevant
|
|
54
|
+
*/
|
|
55
|
+
export function calculatePrecisionAtK(
|
|
56
|
+
feedbackByQuery: Map<string, MemoryFeedback[]>,
|
|
57
|
+
k: number,
|
|
58
|
+
relevanceThreshold: number = 4
|
|
59
|
+
): number {
|
|
60
|
+
if (feedbackByQuery.size === 0) return 0
|
|
61
|
+
|
|
62
|
+
let sumPrecision = 0
|
|
63
|
+
let queryCount = 0
|
|
64
|
+
|
|
65
|
+
for (const [, feedbacks] of feedbackByQuery) {
|
|
66
|
+
const topK = feedbacks.slice(0, k)
|
|
67
|
+
if (topK.length === 0) continue
|
|
68
|
+
|
|
69
|
+
const relevantCount = topK.filter(f => f.rating >= relevanceThreshold).length
|
|
70
|
+
sumPrecision += relevantCount / k
|
|
71
|
+
|
|
72
|
+
queryCount++
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return queryCount > 0 ? sumPrecision / queryCount : 0
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Calculate Normalized Discounted Cumulative Gain (NDCG)
|
|
80
|
+
*
|
|
81
|
+
* NDCG measures ranking quality, giving higher weight to relevant results at the top.
|
|
82
|
+
* DCG = sum(rating_i / log2(i + 1))
|
|
83
|
+
* NDCG = DCG / IDCG (ideal DCG)
|
|
84
|
+
*
|
|
85
|
+
* @param feedbackByQuery - Feedback grouped by query
|
|
86
|
+
* @param k - Number of top results to consider (optional, default all)
|
|
87
|
+
*/
|
|
88
|
+
export function calculateNDCG(
|
|
89
|
+
feedbackByQuery: Map<string, MemoryFeedback[]>,
|
|
90
|
+
k?: number
|
|
91
|
+
): number {
|
|
92
|
+
if (feedbackByQuery.size === 0) return 0
|
|
93
|
+
|
|
94
|
+
let sumNDCG = 0
|
|
95
|
+
let queryCount = 0
|
|
96
|
+
|
|
97
|
+
for (const [, feedbacks] of feedbackByQuery) {
|
|
98
|
+
if (feedbacks.length === 0) continue
|
|
99
|
+
|
|
100
|
+
const results = k ? feedbacks.slice(0, k) : feedbacks
|
|
101
|
+
|
|
102
|
+
// Calculate DCG
|
|
103
|
+
let dcg = 0
|
|
104
|
+
for (let i = 0; i < results.length; i++) {
|
|
105
|
+
// Use rating as relevance score (1-5)
|
|
106
|
+
const relevance = results[i]!.rating
|
|
107
|
+
dcg += relevance / Math.log2(i + 2) // +2 because log2(1) = 0
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Calculate ideal DCG (sort by rating descending)
|
|
111
|
+
const idealResults = [...results].sort((a, b) => b.rating - a.rating)
|
|
112
|
+
let idcg = 0
|
|
113
|
+
for (let i = 0; i < idealResults.length; i++) {
|
|
114
|
+
const relevance = idealResults[i]!.rating
|
|
115
|
+
idcg += relevance / Math.log2(i + 2)
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Normalize
|
|
119
|
+
if (idcg > 0) {
|
|
120
|
+
sumNDCG += dcg / idcg
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
queryCount++
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return queryCount > 0 ? sumNDCG / queryCount : 0
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Calculate all retrieval metrics from feedback
|
|
131
|
+
*/
|
|
132
|
+
export function calculateAllMetrics(
|
|
133
|
+
feedback: MemoryFeedback[],
|
|
134
|
+
kValues: number[] = [3, 5, 10]
|
|
135
|
+
): RetrievalMetrics {
|
|
136
|
+
// Group feedback by query
|
|
137
|
+
const feedbackByQuery = new Map<string, MemoryFeedback[]>()
|
|
138
|
+
|
|
139
|
+
for (const f of feedback) {
|
|
140
|
+
const existing = feedbackByQuery.get(f.queryId) || []
|
|
141
|
+
existing.push(f)
|
|
142
|
+
feedbackByQuery.set(f.queryId, existing)
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Calculate precision at each K
|
|
146
|
+
const precisionAtK: Record<number, number> = {}
|
|
147
|
+
for (const k of kValues) {
|
|
148
|
+
precisionAtK[k] = calculatePrecisionAtK(feedbackByQuery, k)
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
return {
|
|
152
|
+
mrr: calculateMRR(feedbackByQuery),
|
|
153
|
+
precisionAtK,
|
|
154
|
+
ndcg: calculateNDCG(feedbackByQuery),
|
|
155
|
+
queryCount: feedbackByQuery.size,
|
|
156
|
+
avgLatencyMs: 0 // Not tracked in feedback
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Calculate average rating from feedback
|
|
162
|
+
*/
|
|
163
|
+
export function calculateAverageRating(feedback: MemoryFeedback[]): number {
|
|
164
|
+
if (feedback.length === 0) return 0
|
|
165
|
+
const sum = feedback.reduce((acc, f) => acc + f.rating, 0)
|
|
166
|
+
return sum / feedback.length
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Calculate positive feedback rate (rating >= 4)
|
|
171
|
+
*/
|
|
172
|
+
export function calculatePositiveRate(
|
|
173
|
+
feedback: MemoryFeedback[],
|
|
174
|
+
threshold: number = 4
|
|
175
|
+
): number {
|
|
176
|
+
if (feedback.length === 0) return 0
|
|
177
|
+
const positive = feedback.filter(f => f.rating >= threshold).length
|
|
178
|
+
return positive / feedback.length
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Calculate usage rate (was_used = true)
|
|
183
|
+
*/
|
|
184
|
+
export function calculateUsageRate(feedback: MemoryFeedback[]): number {
|
|
185
|
+
if (feedback.length === 0) return 0
|
|
186
|
+
const used = feedback.filter(f => f.wasUsed).length
|
|
187
|
+
return used / feedback.length
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
export class FeedbackMetrics {
|
|
191
|
+
calculateMRR(feedback: Map<string, MemoryFeedback[]>): number {
|
|
192
|
+
return calculateMRR(feedback)
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
calculatePrecisionAtK(
|
|
196
|
+
feedback: Map<string, MemoryFeedback[]>,
|
|
197
|
+
k: number
|
|
198
|
+
): number {
|
|
199
|
+
return calculatePrecisionAtK(feedback, k)
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
calculateNDCG(feedback: Map<string, MemoryFeedback[]>): number {
|
|
203
|
+
return calculateNDCG(feedback)
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
calculateAll(feedback: MemoryFeedback[]): RetrievalMetrics {
|
|
207
|
+
return calculateAllMetrics(feedback)
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
calculateAverageRating(feedback: MemoryFeedback[]): number {
|
|
211
|
+
return calculateAverageRating(feedback)
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
calculatePositiveRate(feedback: MemoryFeedback[]): number {
|
|
215
|
+
return calculatePositiveRate(feedback)
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
calculateUsageRate(feedback: MemoryFeedback[]): number {
|
|
219
|
+
return calculateUsageRate(feedback)
|
|
220
|
+
}
|
|
221
|
+
}
|