claude-brain 0.14.2 → 0.14.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +191 -191
- package/VERSION +1 -1
- package/assets/CLAUDE-unified.md +11 -11
- package/assets/CLAUDE.md +11 -11
- package/bunfig.toml +8 -8
- package/package.json +80 -80
- package/packs/backend/node.json +173 -173
- package/packs/core/javascript.json +176 -176
- package/packs/core/typescript.json +222 -222
- package/packs/frontend/react.json +254 -254
- package/packs/meta/testing.json +172 -172
- package/src/automation/auto-context.ts +240 -240
- package/src/automation/decision-detector.ts +452 -452
- package/src/automation/index.ts +11 -11
- package/src/automation/phase12-manager.ts +456 -456
- package/src/automation/proactive-recall.ts +373 -373
- package/src/automation/project-detector.ts +310 -310
- package/src/automation/repo-scanner.ts +205 -205
- package/src/cli/auto-setup.ts +82 -82
- package/src/cli/bin.ts +202 -202
- package/src/cli/commands/chroma.ts +573 -573
- package/src/cli/commands/git-hook.ts +189 -189
- package/src/cli/commands/hooks.ts +213 -213
- package/src/cli/commands/init.ts +122 -122
- package/src/cli/commands/install-mcp.ts +92 -92
- package/src/cli/commands/pack.ts +197 -197
- package/src/cli/commands/serve.ts +167 -167
- package/src/cli/commands/start.ts +42 -42
- package/src/cli/commands/uninstall-mcp.ts +41 -41
- package/src/cli/commands/update.ts +121 -121
- package/src/cli/diagnose.ts +4 -4
- package/src/cli/health-check.ts +4 -4
- package/src/cli/migrate-chroma.ts +106 -106
- package/src/cli/setup.ts +4 -4
- package/src/cli/ui/animations.ts +80 -80
- package/src/cli/ui/components.ts +82 -82
- package/src/cli/ui/index.ts +4 -4
- package/src/cli/ui/logo.ts +36 -36
- package/src/cli/ui/theme.ts +55 -55
- package/src/config/defaults.ts +50 -50
- package/src/config/home.ts +55 -55
- package/src/config/index.ts +7 -7
- package/src/config/loader.ts +166 -166
- package/src/config/migration.ts +76 -76
- package/src/config/schema.ts +360 -360
- package/src/config/validator.ts +184 -184
- package/src/config/watcher.ts +86 -86
- package/src/context/assembler.ts +398 -398
- package/src/context/cache-manager.ts +101 -101
- package/src/context/formatter.ts +84 -84
- package/src/context/hierarchy.ts +85 -85
- package/src/context/index.ts +83 -83
- package/src/context/progress-tracker.ts +174 -174
- package/src/context/standards-manager.ts +287 -287
- package/src/context/types.ts +252 -252
- package/src/context/validator.ts +58 -58
- package/src/diagnostics/index.ts +123 -123
- package/src/health/index.ts +229 -229
- package/src/hooks/brain-hook.ts +112 -112
- package/src/hooks/capture.ts +168 -168
- package/src/hooks/deduplicator.ts +72 -72
- package/src/hooks/git-capture.ts +109 -109
- package/src/hooks/git-hook-installer.ts +207 -207
- package/src/hooks/index.ts +20 -20
- package/src/hooks/installer.ts +191 -194
- package/src/hooks/passive-classifier.ts +366 -366
- package/src/hooks/queue.ts +129 -129
- package/src/hooks/session-tracker.ts +275 -275
- package/src/hooks/types.ts +47 -47
- package/src/index.ts +7 -7
- package/src/intelligence/cross-project/affinity.ts +162 -162
- package/src/intelligence/cross-project/generalizer.ts +283 -283
- package/src/intelligence/cross-project/index.ts +13 -13
- package/src/intelligence/cross-project/transfer.ts +201 -201
- package/src/intelligence/index.ts +24 -24
- package/src/intelligence/optimization/index.ts +10 -10
- package/src/intelligence/optimization/precompute.ts +202 -202
- package/src/intelligence/optimization/semantic-cache.ts +207 -207
- package/src/intelligence/prediction/context-anticipator.ts +198 -198
- package/src/intelligence/prediction/decision-predictor.ts +184 -184
- package/src/intelligence/prediction/index.ts +13 -13
- package/src/intelligence/prediction/recommender.ts +268 -268
- package/src/intelligence/reasoning/chain-retrieval.ts +247 -247
- package/src/intelligence/reasoning/counterfactual.ts +248 -248
- package/src/intelligence/reasoning/index.ts +13 -13
- package/src/intelligence/reasoning/synthesizer.ts +169 -169
- package/src/intelligence/temporal/evolution.ts +197 -197
- package/src/intelligence/temporal/index.ts +16 -16
- package/src/intelligence/temporal/query-processor.ts +190 -190
- package/src/intelligence/temporal/timeline.ts +259 -259
- package/src/intelligence/temporal/trends.ts +263 -263
- package/src/knowledge/entity-extractor.ts +416 -416
- package/src/knowledge/graph/builder.ts +185 -185
- package/src/knowledge/graph/linker.ts +201 -201
- package/src/knowledge/graph/memory-graph.ts +359 -359
- package/src/knowledge/graph/schema.ts +99 -99
- package/src/knowledge/graph/search.ts +168 -168
- package/src/knowledge/relationship-extractor.ts +108 -108
- package/src/memory/chroma/client.ts +174 -174
- package/src/memory/chroma/collection-manager.ts +94 -94
- package/src/memory/chroma/config.ts +57 -57
- package/src/memory/chroma/embeddings.ts +153 -153
- package/src/memory/chroma/index.ts +82 -82
- package/src/memory/chroma/migration.ts +270 -270
- package/src/memory/chroma/schemas.ts +69 -69
- package/src/memory/chroma/search.ts +315 -315
- package/src/memory/chroma/store.ts +741 -741
- package/src/memory/consolidation/archiver.ts +164 -164
- package/src/memory/consolidation/merger.ts +186 -186
- package/src/memory/consolidation/scorer.ts +138 -138
- package/src/memory/context-builder.ts +236 -236
- package/src/memory/database.ts +169 -169
- package/src/memory/embedding-utils.ts +156 -156
- package/src/memory/embeddings.ts +226 -226
- package/src/memory/episodic/detector.ts +108 -108
- package/src/memory/episodic/manager.ts +351 -351
- package/src/memory/episodic/summarizer.ts +179 -179
- package/src/memory/episodic/types.ts +52 -52
- package/src/memory/index.ts +582 -582
- package/src/memory/knowledge-extractor.ts +455 -455
- package/src/memory/learning.ts +378 -378
- package/src/memory/patterns.ts +396 -396
- package/src/memory/schema.ts +88 -88
- package/src/memory/search.ts +309 -309
- package/src/memory/store.ts +787 -787
- package/src/memory/types.ts +121 -121
- package/src/orchestrator/coordinator.ts +272 -272
- package/src/orchestrator/decision-logger.ts +228 -228
- package/src/orchestrator/event-emitter.ts +198 -198
- package/src/orchestrator/event-queue.ts +184 -184
- package/src/orchestrator/handlers/base-handler.ts +70 -70
- package/src/orchestrator/handlers/context-handler.ts +73 -73
- package/src/orchestrator/handlers/decision-handler.ts +204 -204
- package/src/orchestrator/handlers/index.ts +10 -10
- package/src/orchestrator/handlers/status-handler.ts +131 -131
- package/src/orchestrator/handlers/task-handler.ts +171 -171
- package/src/orchestrator/index.ts +275 -275
- package/src/orchestrator/task-parser.ts +284 -284
- package/src/orchestrator/types.ts +98 -98
- package/src/packs/index.ts +9 -9
- package/src/packs/loader.ts +134 -134
- package/src/packs/manager.ts +204 -204
- package/src/packs/ranker.ts +78 -78
- package/src/packs/types.ts +81 -81
- package/src/phase12/index.ts +5 -5
- package/src/retrieval/bm25/index.ts +300 -300
- package/src/retrieval/bm25/tokenizer.ts +184 -184
- package/src/retrieval/feedback/adaptive.ts +223 -223
- package/src/retrieval/feedback/index.ts +16 -16
- package/src/retrieval/feedback/metrics.ts +223 -223
- package/src/retrieval/feedback/store.ts +283 -283
- package/src/retrieval/fusion/index.ts +194 -194
- package/src/retrieval/fusion/rrf.ts +163 -163
- package/src/retrieval/index.ts +12 -12
- package/src/retrieval/pipeline.ts +375 -375
- package/src/retrieval/query/expander.ts +198 -198
- package/src/retrieval/query/index.ts +27 -27
- package/src/retrieval/query/intent-classifier.ts +236 -236
- package/src/retrieval/query/temporal-parser.ts +295 -295
- package/src/retrieval/reranker/index.ts +188 -188
- package/src/retrieval/reranker/model.ts +95 -95
- package/src/retrieval/service.ts +125 -125
- package/src/retrieval/types.ts +162 -162
- package/src/routing/entity-extractor.ts +428 -428
- package/src/routing/intent-classifier.ts +436 -436
- package/src/routing/response-filter.ts +258 -254
- package/src/routing/router.ts +1322 -1314
- package/src/routing/search-engine.ts +475 -475
- package/src/routing/types.ts +94 -84
- package/src/scripts/health-check.ts +118 -118
- package/src/scripts/setup.ts +122 -122
- package/src/server/handlers/call-tool.ts +156 -156
- package/src/server/handlers/index.ts +9 -9
- package/src/server/handlers/list-tools.ts +35 -35
- package/src/server/handlers/tools/analyze-decision-evolution.ts +151 -151
- package/src/server/handlers/tools/auto-remember.ts +200 -200
- package/src/server/handlers/tools/brain.ts +85 -85
- package/src/server/handlers/tools/create-project.ts +135 -135
- package/src/server/handlers/tools/detect-trends.ts +144 -144
- package/src/server/handlers/tools/find-cross-project-patterns.ts +168 -168
- package/src/server/handlers/tools/get-activity-log.ts +194 -194
- package/src/server/handlers/tools/get-code-standards.ts +124 -124
- package/src/server/handlers/tools/get-corrections.ts +154 -154
- package/src/server/handlers/tools/get-decision-timeline.ts +172 -172
- package/src/server/handlers/tools/get-episode.ts +103 -103
- package/src/server/handlers/tools/get-patterns.ts +158 -158
- package/src/server/handlers/tools/get-phase12-status.ts +63 -63
- package/src/server/handlers/tools/get-project-context.ts +75 -75
- package/src/server/handlers/tools/get-recommendations.ts +145 -145
- package/src/server/handlers/tools/index.ts +31 -31
- package/src/server/handlers/tools/init-project.ts +757 -757
- package/src/server/handlers/tools/list-episodes.ts +90 -90
- package/src/server/handlers/tools/list-projects.ts +125 -125
- package/src/server/handlers/tools/rate-memory.ts +101 -101
- package/src/server/handlers/tools/recall-similar.ts +87 -87
- package/src/server/handlers/tools/recognize-pattern.ts +126 -126
- package/src/server/handlers/tools/record-correction.ts +125 -125
- package/src/server/handlers/tools/remember-decision.ts +153 -153
- package/src/server/handlers/tools/schemas.ts +253 -253
- package/src/server/handlers/tools/search-knowledge-graph.ts +102 -102
- package/src/server/handlers/tools/smart-context.ts +146 -146
- package/src/server/handlers/tools/update-progress.ts +131 -131
- package/src/server/handlers/tools/what-if-analysis.ts +135 -135
- package/src/server/http-api.ts +693 -693
- package/src/server/index.ts +40 -40
- package/src/server/mcp-server.ts +283 -283
- package/src/server/providers/index.ts +7 -7
- package/src/server/providers/prompts.ts +327 -327
- package/src/server/providers/resources.ts +622 -622
- package/src/server/services.ts +468 -468
- package/src/server/types.ts +39 -39
- package/src/server/utils/error-handler.ts +155 -155
- package/src/server/utils/index.ts +13 -13
- package/src/server/utils/memory-indicator.ts +83 -83
- package/src/server/utils/request-context.ts +122 -122
- package/src/server/utils/response-formatter.ts +129 -124
- package/src/server/utils/validators.ts +210 -210
- package/src/setup/index.ts +48 -48
- package/src/setup/wizard.ts +461 -461
- package/src/tools/index.ts +24 -24
- package/src/tools/registry.ts +115 -115
- package/src/tools/schemas.test.ts +30 -30
- package/src/tools/schemas.ts +617 -617
- package/src/tools/types.ts +412 -412
- package/src/utils/circuit-breaker.ts +130 -130
- package/src/utils/cleanup.ts +34 -34
- package/src/utils/error-handler.ts +132 -132
- package/src/utils/error-messages.ts +60 -60
- package/src/utils/fallback.ts +45 -45
- package/src/utils/index.ts +54 -54
- package/src/utils/logger-utils.ts +80 -80
- package/src/utils/logger.ts +88 -88
- package/src/utils/phase12-helper.ts +56 -56
- package/src/utils/retry.ts +94 -94
- package/src/utils/timing.ts +47 -47
- package/src/utils/transaction.ts +63 -63
- package/src/vault/frontmatter.ts +264 -264
- package/src/vault/index.ts +318 -318
- package/src/vault/paths.ts +106 -106
- package/src/vault/query.ts +422 -422
- package/src/vault/reader.ts +264 -264
- package/src/vault/templates.ts +186 -186
- package/src/vault/types.ts +73 -73
- package/src/vault/watcher.ts +277 -277
- package/src/vault/writer.ts +413 -413
- package/tsconfig.json +30 -30
|
@@ -1,268 +1,268 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Recommender
|
|
3
|
-
* Provides recommendations based on project history, patterns, and corrections
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import type { Logger } from 'pino'
|
|
7
|
-
import type { CollectionManager } from '@/memory/chroma/collection-manager'
|
|
8
|
-
import type { EmbeddingProvider } from '@/memory/chroma/embeddings'
|
|
9
|
-
|
|
10
|
-
export interface Recommendation {
|
|
11
|
-
type: 'pattern' | 'correction' | 'decision' | 'best-practice'
|
|
12
|
-
content: string
|
|
13
|
-
confidence: number
|
|
14
|
-
source: string
|
|
15
|
-
sourceId: string
|
|
16
|
-
reasoning: string
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export interface RecommendationResult {
|
|
20
|
-
query: string
|
|
21
|
-
project?: string
|
|
22
|
-
recommendations: Recommendation[]
|
|
23
|
-
totalConsidered: number
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export class Recommender {
|
|
27
|
-
private logger: Logger
|
|
28
|
-
private collections: CollectionManager
|
|
29
|
-
private embeddings?: EmbeddingProvider
|
|
30
|
-
|
|
31
|
-
constructor(logger: Logger, collections: CollectionManager, embeddings?: EmbeddingProvider) {
|
|
32
|
-
this.logger = logger.child({ component: 'recommender' })
|
|
33
|
-
this.collections = collections
|
|
34
|
-
this.embeddings = embeddings
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Get recommendations for a given context
|
|
39
|
-
*/
|
|
40
|
-
async getRecommendations(query: string, options: {
|
|
41
|
-
project?: string
|
|
42
|
-
limit?: number
|
|
43
|
-
types?: Array<'pattern' | 'correction' | 'decision'>
|
|
44
|
-
} = {}): Promise<RecommendationResult> {
|
|
45
|
-
const {
|
|
46
|
-
project,
|
|
47
|
-
limit = 10,
|
|
48
|
-
types = ['pattern', 'correction', 'decision']
|
|
49
|
-
} = options
|
|
50
|
-
|
|
51
|
-
const allRecommendations: Recommendation[] = []
|
|
52
|
-
let totalConsidered = 0
|
|
53
|
-
|
|
54
|
-
// Fetch from patterns
|
|
55
|
-
if (types.includes('pattern')) {
|
|
56
|
-
const patterns = await this.fetchPatternRecommendations(query, project, limit)
|
|
57
|
-
allRecommendations.push(...patterns.recommendations)
|
|
58
|
-
totalConsidered += patterns.considered
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// Fetch from corrections (things to avoid)
|
|
62
|
-
if (types.includes('correction')) {
|
|
63
|
-
const corrections = await this.fetchCorrectionRecommendations(query, project, limit)
|
|
64
|
-
allRecommendations.push(...corrections.recommendations)
|
|
65
|
-
totalConsidered += corrections.considered
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
// Fetch from past decisions
|
|
69
|
-
if (types.includes('decision')) {
|
|
70
|
-
const decisions = await this.fetchDecisionRecommendations(query, project, limit)
|
|
71
|
-
allRecommendations.push(...decisions.recommendations)
|
|
72
|
-
totalConsidered += decisions.considered
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
// Sort by confidence and deduplicate
|
|
76
|
-
const sorted = allRecommendations
|
|
77
|
-
.sort((a, b) => b.confidence - a.confidence)
|
|
78
|
-
.slice(0, limit)
|
|
79
|
-
|
|
80
|
-
return {
|
|
81
|
-
query,
|
|
82
|
-
project,
|
|
83
|
-
recommendations: sorted,
|
|
84
|
-
totalConsidered
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
private async fetchPatternRecommendations(
|
|
89
|
-
query: string,
|
|
90
|
-
project?: string,
|
|
91
|
-
limit: number = 5
|
|
92
|
-
): Promise<{ recommendations: Recommendation[]; considered: number }> {
|
|
93
|
-
try {
|
|
94
|
-
const collection = await this.collections.getPatterns()
|
|
95
|
-
|
|
96
|
-
const where: any = project ? { project: { $eq: project } } : undefined
|
|
97
|
-
|
|
98
|
-
let results: any
|
|
99
|
-
|
|
100
|
-
if (this.embeddings) {
|
|
101
|
-
const embedding = await this.embeddings.generate(query)
|
|
102
|
-
results = await collection.query({
|
|
103
|
-
queryEmbeddings: [embedding],
|
|
104
|
-
nResults: limit,
|
|
105
|
-
where,
|
|
106
|
-
include: ['documents', 'metadatas', 'distances']
|
|
107
|
-
})
|
|
108
|
-
} else {
|
|
109
|
-
results = await collection.query({
|
|
110
|
-
queryTexts: [query],
|
|
111
|
-
nResults: limit,
|
|
112
|
-
where,
|
|
113
|
-
include: ['documents', 'metadatas', 'distances']
|
|
114
|
-
})
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
if (!results.ids || !results.ids[0]) return { recommendations: [], considered: 0 }
|
|
118
|
-
|
|
119
|
-
const recommendations: Recommendation[] = []
|
|
120
|
-
const ids = results.ids[0]
|
|
121
|
-
const documents = results.documents?.[0] || []
|
|
122
|
-
const metadatas = results.metadatas?.[0] || []
|
|
123
|
-
const distances = results.distances?.[0] || []
|
|
124
|
-
|
|
125
|
-
for (let i = 0; i < ids.length; i++) {
|
|
126
|
-
const similarity = 1 - (distances[i] || 0)
|
|
127
|
-
if (similarity < 0.3) continue
|
|
128
|
-
|
|
129
|
-
const meta = metadatas[i] as any
|
|
130
|
-
const patternType = meta?.pattern_type || 'pattern'
|
|
131
|
-
|
|
132
|
-
recommendations.push({
|
|
133
|
-
type: patternType === 'best-practice' ? 'best-practice' : 'pattern',
|
|
134
|
-
content: documents[i] || '',
|
|
135
|
-
confidence: similarity * (meta?.confidence || 0.8),
|
|
136
|
-
source: `Pattern (${patternType})`,
|
|
137
|
-
sourceId: ids[i],
|
|
138
|
-
reasoning: meta?.context || `Relevant ${patternType} pattern found`
|
|
139
|
-
})
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
return { recommendations, considered: ids.length }
|
|
143
|
-
} catch (error) {
|
|
144
|
-
this.logger.debug({ error }, 'Failed to fetch pattern recommendations')
|
|
145
|
-
return { recommendations: [], considered: 0 }
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
private async fetchCorrectionRecommendations(
|
|
150
|
-
query: string,
|
|
151
|
-
project?: string,
|
|
152
|
-
limit: number = 5
|
|
153
|
-
): Promise<{ recommendations: Recommendation[]; considered: number }> {
|
|
154
|
-
try {
|
|
155
|
-
const collection = await this.collections.getCorrections()
|
|
156
|
-
|
|
157
|
-
const where: any = project ? { project: { $eq: project } } : undefined
|
|
158
|
-
|
|
159
|
-
let results: any
|
|
160
|
-
|
|
161
|
-
if (this.embeddings) {
|
|
162
|
-
const embedding = await this.embeddings.generate(query)
|
|
163
|
-
results = await collection.query({
|
|
164
|
-
queryEmbeddings: [embedding],
|
|
165
|
-
nResults: limit,
|
|
166
|
-
where,
|
|
167
|
-
include: ['documents', 'metadatas', 'distances']
|
|
168
|
-
})
|
|
169
|
-
} else {
|
|
170
|
-
results = await collection.query({
|
|
171
|
-
queryTexts: [query],
|
|
172
|
-
nResults: limit,
|
|
173
|
-
where,
|
|
174
|
-
include: ['documents', 'metadatas', 'distances']
|
|
175
|
-
})
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
if (!results.ids || !results.ids[0]) return { recommendations: [], considered: 0 }
|
|
179
|
-
|
|
180
|
-
const recommendations: Recommendation[] = []
|
|
181
|
-
const ids = results.ids[0]
|
|
182
|
-
const documents = results.documents?.[0] || []
|
|
183
|
-
const metadatas = results.metadatas?.[0] || []
|
|
184
|
-
const distances = results.distances?.[0] || []
|
|
185
|
-
|
|
186
|
-
for (let i = 0; i < ids.length; i++) {
|
|
187
|
-
const similarity = 1 - (distances[i] || 0)
|
|
188
|
-
if (similarity < 0.3) continue
|
|
189
|
-
|
|
190
|
-
const meta = metadatas[i] as any
|
|
191
|
-
|
|
192
|
-
recommendations.push({
|
|
193
|
-
type: 'correction',
|
|
194
|
-
content: `Avoid: ${meta?.original || ''}\nDo instead: ${documents[i] || ''}`,
|
|
195
|
-
confidence: similarity * (meta?.confidence || 0.9),
|
|
196
|
-
source: 'Lesson Learned',
|
|
197
|
-
sourceId: ids[i],
|
|
198
|
-
reasoning: meta?.reasoning || 'Based on a past correction'
|
|
199
|
-
})
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
return { recommendations, considered: ids.length }
|
|
203
|
-
} catch (error) {
|
|
204
|
-
this.logger.debug({ error }, 'Failed to fetch correction recommendations')
|
|
205
|
-
return { recommendations: [], considered: 0 }
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
private async fetchDecisionRecommendations(
|
|
210
|
-
query: string,
|
|
211
|
-
project?: string,
|
|
212
|
-
limit: number = 5
|
|
213
|
-
): Promise<{ recommendations: Recommendation[]; considered: number }> {
|
|
214
|
-
try {
|
|
215
|
-
const collection = await this.collections.getDecisions()
|
|
216
|
-
|
|
217
|
-
const where: any = project ? { project: { $eq: project } } : undefined
|
|
218
|
-
|
|
219
|
-
let results: any
|
|
220
|
-
|
|
221
|
-
if (this.embeddings) {
|
|
222
|
-
const embedding = await this.embeddings.generate(query)
|
|
223
|
-
results = await collection.query({
|
|
224
|
-
queryEmbeddings: [embedding],
|
|
225
|
-
nResults: limit,
|
|
226
|
-
where,
|
|
227
|
-
include: ['documents', 'metadatas', 'distances']
|
|
228
|
-
})
|
|
229
|
-
} else {
|
|
230
|
-
results = await collection.query({
|
|
231
|
-
queryTexts: [query],
|
|
232
|
-
nResults: limit,
|
|
233
|
-
where,
|
|
234
|
-
include: ['documents', 'metadatas', 'distances']
|
|
235
|
-
})
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
if (!results.ids || !results.ids[0]) return { recommendations: [], considered: 0 }
|
|
239
|
-
|
|
240
|
-
const recommendations: Recommendation[] = []
|
|
241
|
-
const ids = results.ids[0]
|
|
242
|
-
const documents = results.documents?.[0] || []
|
|
243
|
-
const metadatas = results.metadatas?.[0] || []
|
|
244
|
-
const distances = results.distances?.[0] || []
|
|
245
|
-
|
|
246
|
-
for (let i = 0; i < ids.length; i++) {
|
|
247
|
-
const similarity = 1 - (distances[i] || 0)
|
|
248
|
-
if (similarity < 0.5) continue // Higher threshold for past decisions
|
|
249
|
-
|
|
250
|
-
const meta = metadatas[i] as any
|
|
251
|
-
|
|
252
|
-
recommendations.push({
|
|
253
|
-
type: 'decision',
|
|
254
|
-
content: documents[i] || '',
|
|
255
|
-
confidence: similarity,
|
|
256
|
-
source: 'Past Decision',
|
|
257
|
-
sourceId: ids[i],
|
|
258
|
-
reasoning: meta?.reasoning || 'Based on a previous decision in similar context'
|
|
259
|
-
})
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
return { recommendations, considered: ids.length }
|
|
263
|
-
} catch (error) {
|
|
264
|
-
this.logger.debug({ error }, 'Failed to fetch decision recommendations')
|
|
265
|
-
return { recommendations: [], considered: 0 }
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Recommender
|
|
3
|
+
* Provides recommendations based on project history, patterns, and corrections
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { Logger } from 'pino'
|
|
7
|
+
import type { CollectionManager } from '@/memory/chroma/collection-manager'
|
|
8
|
+
import type { EmbeddingProvider } from '@/memory/chroma/embeddings'
|
|
9
|
+
|
|
10
|
+
export interface Recommendation {
|
|
11
|
+
type: 'pattern' | 'correction' | 'decision' | 'best-practice'
|
|
12
|
+
content: string
|
|
13
|
+
confidence: number
|
|
14
|
+
source: string
|
|
15
|
+
sourceId: string
|
|
16
|
+
reasoning: string
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface RecommendationResult {
|
|
20
|
+
query: string
|
|
21
|
+
project?: string
|
|
22
|
+
recommendations: Recommendation[]
|
|
23
|
+
totalConsidered: number
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export class Recommender {
|
|
27
|
+
private logger: Logger
|
|
28
|
+
private collections: CollectionManager
|
|
29
|
+
private embeddings?: EmbeddingProvider
|
|
30
|
+
|
|
31
|
+
constructor(logger: Logger, collections: CollectionManager, embeddings?: EmbeddingProvider) {
|
|
32
|
+
this.logger = logger.child({ component: 'recommender' })
|
|
33
|
+
this.collections = collections
|
|
34
|
+
this.embeddings = embeddings
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Get recommendations for a given context
|
|
39
|
+
*/
|
|
40
|
+
async getRecommendations(query: string, options: {
|
|
41
|
+
project?: string
|
|
42
|
+
limit?: number
|
|
43
|
+
types?: Array<'pattern' | 'correction' | 'decision'>
|
|
44
|
+
} = {}): Promise<RecommendationResult> {
|
|
45
|
+
const {
|
|
46
|
+
project,
|
|
47
|
+
limit = 10,
|
|
48
|
+
types = ['pattern', 'correction', 'decision']
|
|
49
|
+
} = options
|
|
50
|
+
|
|
51
|
+
const allRecommendations: Recommendation[] = []
|
|
52
|
+
let totalConsidered = 0
|
|
53
|
+
|
|
54
|
+
// Fetch from patterns
|
|
55
|
+
if (types.includes('pattern')) {
|
|
56
|
+
const patterns = await this.fetchPatternRecommendations(query, project, limit)
|
|
57
|
+
allRecommendations.push(...patterns.recommendations)
|
|
58
|
+
totalConsidered += patterns.considered
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Fetch from corrections (things to avoid)
|
|
62
|
+
if (types.includes('correction')) {
|
|
63
|
+
const corrections = await this.fetchCorrectionRecommendations(query, project, limit)
|
|
64
|
+
allRecommendations.push(...corrections.recommendations)
|
|
65
|
+
totalConsidered += corrections.considered
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Fetch from past decisions
|
|
69
|
+
if (types.includes('decision')) {
|
|
70
|
+
const decisions = await this.fetchDecisionRecommendations(query, project, limit)
|
|
71
|
+
allRecommendations.push(...decisions.recommendations)
|
|
72
|
+
totalConsidered += decisions.considered
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Sort by confidence and deduplicate
|
|
76
|
+
const sorted = allRecommendations
|
|
77
|
+
.sort((a, b) => b.confidence - a.confidence)
|
|
78
|
+
.slice(0, limit)
|
|
79
|
+
|
|
80
|
+
return {
|
|
81
|
+
query,
|
|
82
|
+
project,
|
|
83
|
+
recommendations: sorted,
|
|
84
|
+
totalConsidered
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
private async fetchPatternRecommendations(
|
|
89
|
+
query: string,
|
|
90
|
+
project?: string,
|
|
91
|
+
limit: number = 5
|
|
92
|
+
): Promise<{ recommendations: Recommendation[]; considered: number }> {
|
|
93
|
+
try {
|
|
94
|
+
const collection = await this.collections.getPatterns()
|
|
95
|
+
|
|
96
|
+
const where: any = project ? { project: { $eq: project } } : undefined
|
|
97
|
+
|
|
98
|
+
let results: any
|
|
99
|
+
|
|
100
|
+
if (this.embeddings) {
|
|
101
|
+
const embedding = await this.embeddings.generate(query)
|
|
102
|
+
results = await collection.query({
|
|
103
|
+
queryEmbeddings: [embedding],
|
|
104
|
+
nResults: limit,
|
|
105
|
+
where,
|
|
106
|
+
include: ['documents', 'metadatas', 'distances']
|
|
107
|
+
})
|
|
108
|
+
} else {
|
|
109
|
+
results = await collection.query({
|
|
110
|
+
queryTexts: [query],
|
|
111
|
+
nResults: limit,
|
|
112
|
+
where,
|
|
113
|
+
include: ['documents', 'metadatas', 'distances']
|
|
114
|
+
})
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (!results.ids || !results.ids[0]) return { recommendations: [], considered: 0 }
|
|
118
|
+
|
|
119
|
+
const recommendations: Recommendation[] = []
|
|
120
|
+
const ids = results.ids[0]
|
|
121
|
+
const documents = results.documents?.[0] || []
|
|
122
|
+
const metadatas = results.metadatas?.[0] || []
|
|
123
|
+
const distances = results.distances?.[0] || []
|
|
124
|
+
|
|
125
|
+
for (let i = 0; i < ids.length; i++) {
|
|
126
|
+
const similarity = 1 - (distances[i] || 0)
|
|
127
|
+
if (similarity < 0.3) continue
|
|
128
|
+
|
|
129
|
+
const meta = metadatas[i] as any
|
|
130
|
+
const patternType = meta?.pattern_type || 'pattern'
|
|
131
|
+
|
|
132
|
+
recommendations.push({
|
|
133
|
+
type: patternType === 'best-practice' ? 'best-practice' : 'pattern',
|
|
134
|
+
content: documents[i] || '',
|
|
135
|
+
confidence: similarity * (meta?.confidence || 0.8),
|
|
136
|
+
source: `Pattern (${patternType})`,
|
|
137
|
+
sourceId: ids[i],
|
|
138
|
+
reasoning: meta?.context || `Relevant ${patternType} pattern found`
|
|
139
|
+
})
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return { recommendations, considered: ids.length }
|
|
143
|
+
} catch (error) {
|
|
144
|
+
this.logger.debug({ error }, 'Failed to fetch pattern recommendations')
|
|
145
|
+
return { recommendations: [], considered: 0 }
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
private async fetchCorrectionRecommendations(
|
|
150
|
+
query: string,
|
|
151
|
+
project?: string,
|
|
152
|
+
limit: number = 5
|
|
153
|
+
): Promise<{ recommendations: Recommendation[]; considered: number }> {
|
|
154
|
+
try {
|
|
155
|
+
const collection = await this.collections.getCorrections()
|
|
156
|
+
|
|
157
|
+
const where: any = project ? { project: { $eq: project } } : undefined
|
|
158
|
+
|
|
159
|
+
let results: any
|
|
160
|
+
|
|
161
|
+
if (this.embeddings) {
|
|
162
|
+
const embedding = await this.embeddings.generate(query)
|
|
163
|
+
results = await collection.query({
|
|
164
|
+
queryEmbeddings: [embedding],
|
|
165
|
+
nResults: limit,
|
|
166
|
+
where,
|
|
167
|
+
include: ['documents', 'metadatas', 'distances']
|
|
168
|
+
})
|
|
169
|
+
} else {
|
|
170
|
+
results = await collection.query({
|
|
171
|
+
queryTexts: [query],
|
|
172
|
+
nResults: limit,
|
|
173
|
+
where,
|
|
174
|
+
include: ['documents', 'metadatas', 'distances']
|
|
175
|
+
})
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (!results.ids || !results.ids[0]) return { recommendations: [], considered: 0 }
|
|
179
|
+
|
|
180
|
+
const recommendations: Recommendation[] = []
|
|
181
|
+
const ids = results.ids[0]
|
|
182
|
+
const documents = results.documents?.[0] || []
|
|
183
|
+
const metadatas = results.metadatas?.[0] || []
|
|
184
|
+
const distances = results.distances?.[0] || []
|
|
185
|
+
|
|
186
|
+
for (let i = 0; i < ids.length; i++) {
|
|
187
|
+
const similarity = 1 - (distances[i] || 0)
|
|
188
|
+
if (similarity < 0.3) continue
|
|
189
|
+
|
|
190
|
+
const meta = metadatas[i] as any
|
|
191
|
+
|
|
192
|
+
recommendations.push({
|
|
193
|
+
type: 'correction',
|
|
194
|
+
content: `Avoid: ${meta?.original || ''}\nDo instead: ${documents[i] || ''}`,
|
|
195
|
+
confidence: similarity * (meta?.confidence || 0.9),
|
|
196
|
+
source: 'Lesson Learned',
|
|
197
|
+
sourceId: ids[i],
|
|
198
|
+
reasoning: meta?.reasoning || 'Based on a past correction'
|
|
199
|
+
})
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
return { recommendations, considered: ids.length }
|
|
203
|
+
} catch (error) {
|
|
204
|
+
this.logger.debug({ error }, 'Failed to fetch correction recommendations')
|
|
205
|
+
return { recommendations: [], considered: 0 }
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
private async fetchDecisionRecommendations(
|
|
210
|
+
query: string,
|
|
211
|
+
project?: string,
|
|
212
|
+
limit: number = 5
|
|
213
|
+
): Promise<{ recommendations: Recommendation[]; considered: number }> {
|
|
214
|
+
try {
|
|
215
|
+
const collection = await this.collections.getDecisions()
|
|
216
|
+
|
|
217
|
+
const where: any = project ? { project: { $eq: project } } : undefined
|
|
218
|
+
|
|
219
|
+
let results: any
|
|
220
|
+
|
|
221
|
+
if (this.embeddings) {
|
|
222
|
+
const embedding = await this.embeddings.generate(query)
|
|
223
|
+
results = await collection.query({
|
|
224
|
+
queryEmbeddings: [embedding],
|
|
225
|
+
nResults: limit,
|
|
226
|
+
where,
|
|
227
|
+
include: ['documents', 'metadatas', 'distances']
|
|
228
|
+
})
|
|
229
|
+
} else {
|
|
230
|
+
results = await collection.query({
|
|
231
|
+
queryTexts: [query],
|
|
232
|
+
nResults: limit,
|
|
233
|
+
where,
|
|
234
|
+
include: ['documents', 'metadatas', 'distances']
|
|
235
|
+
})
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
if (!results.ids || !results.ids[0]) return { recommendations: [], considered: 0 }
|
|
239
|
+
|
|
240
|
+
const recommendations: Recommendation[] = []
|
|
241
|
+
const ids = results.ids[0]
|
|
242
|
+
const documents = results.documents?.[0] || []
|
|
243
|
+
const metadatas = results.metadatas?.[0] || []
|
|
244
|
+
const distances = results.distances?.[0] || []
|
|
245
|
+
|
|
246
|
+
for (let i = 0; i < ids.length; i++) {
|
|
247
|
+
const similarity = 1 - (distances[i] || 0)
|
|
248
|
+
if (similarity < 0.5) continue // Higher threshold for past decisions
|
|
249
|
+
|
|
250
|
+
const meta = metadatas[i] as any
|
|
251
|
+
|
|
252
|
+
recommendations.push({
|
|
253
|
+
type: 'decision',
|
|
254
|
+
content: documents[i] || '',
|
|
255
|
+
confidence: similarity,
|
|
256
|
+
source: 'Past Decision',
|
|
257
|
+
sourceId: ids[i],
|
|
258
|
+
reasoning: meta?.reasoning || 'Based on a previous decision in similar context'
|
|
259
|
+
})
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
return { recommendations, considered: ids.length }
|
|
263
|
+
} catch (error) {
|
|
264
|
+
this.logger.debug({ error }, 'Failed to fetch decision recommendations')
|
|
265
|
+
return { recommendations: [], considered: 0 }
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|