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,248 +1,248 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Counterfactual Analysis
|
|
3
|
-
* What-if analysis using knowledge graph and decision history
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import type { Logger } from 'pino'
|
|
7
|
-
import type { InMemoryKnowledgeGraph } from '@/knowledge/graph/memory-graph'
|
|
8
|
-
import type { CollectionManager } from '@/memory/chroma/collection-manager'
|
|
9
|
-
import type { EmbeddingProvider } from '@/memory/chroma/embeddings'
|
|
10
|
-
|
|
11
|
-
export interface WhatIfScenario {
|
|
12
|
-
change: string
|
|
13
|
-
affectedDecisions: Array<{
|
|
14
|
-
id: string
|
|
15
|
-
decision: string
|
|
16
|
-
impact: 'high' | 'medium' | 'low'
|
|
17
|
-
reason: string
|
|
18
|
-
}>
|
|
19
|
-
affectedTechnologies: string[]
|
|
20
|
-
riskLevel: 'high' | 'medium' | 'low'
|
|
21
|
-
summary: string
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export class CounterfactualAnalyzer {
|
|
25
|
-
private logger: Logger
|
|
26
|
-
private graph: InMemoryKnowledgeGraph | null
|
|
27
|
-
private collections: CollectionManager
|
|
28
|
-
private embeddings?: EmbeddingProvider
|
|
29
|
-
|
|
30
|
-
constructor(
|
|
31
|
-
logger: Logger,
|
|
32
|
-
graph: InMemoryKnowledgeGraph | null,
|
|
33
|
-
collections: CollectionManager,
|
|
34
|
-
embeddings?: EmbeddingProvider
|
|
35
|
-
) {
|
|
36
|
-
this.logger = logger.child({ component: 'counterfactual' })
|
|
37
|
-
this.graph = graph
|
|
38
|
-
this.collections = collections
|
|
39
|
-
this.embeddings = embeddings
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Analyze what would happen if a technology/decision changed
|
|
44
|
-
*/
|
|
45
|
-
async whatIf(change: string, options: {
|
|
46
|
-
project?: string
|
|
47
|
-
maxResults?: number
|
|
48
|
-
} = {}): Promise<WhatIfScenario> {
|
|
49
|
-
const { project, maxResults = 20 } = options
|
|
50
|
-
|
|
51
|
-
// Find decisions related to the change
|
|
52
|
-
const relatedDecisions = await this.findRelatedDecisions(change, project, maxResults)
|
|
53
|
-
|
|
54
|
-
// Find affected technologies via knowledge graph
|
|
55
|
-
const affectedTechnologies = this.findAffectedTechnologies(change)
|
|
56
|
-
|
|
57
|
-
// Assess impact on each decision
|
|
58
|
-
const affectedDecisions = relatedDecisions.map(d => ({
|
|
59
|
-
id: d.id,
|
|
60
|
-
decision: d.content.slice(0, 200),
|
|
61
|
-
impact: this.assessImpact(d, change),
|
|
62
|
-
reason: this.explainImpact(d, change)
|
|
63
|
-
}))
|
|
64
|
-
|
|
65
|
-
// Determine overall risk
|
|
66
|
-
const riskLevel = this.calculateRisk(affectedDecisions)
|
|
67
|
-
|
|
68
|
-
// Build summary
|
|
69
|
-
const summary = this.buildSummary(change, affectedDecisions, affectedTechnologies, riskLevel)
|
|
70
|
-
|
|
71
|
-
return {
|
|
72
|
-
change,
|
|
73
|
-
affectedDecisions,
|
|
74
|
-
affectedTechnologies,
|
|
75
|
-
riskLevel,
|
|
76
|
-
summary
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
private async findRelatedDecisions(
|
|
81
|
-
change: string,
|
|
82
|
-
project?: string,
|
|
83
|
-
limit: number = 20
|
|
84
|
-
): Promise<Array<{ id: string; content: string; metadata: Record<string, any>; similarity: number }>> {
|
|
85
|
-
try {
|
|
86
|
-
const collection = await this.collections.getDecisions()
|
|
87
|
-
|
|
88
|
-
const where: any = project ? { project: { $eq: project } } : undefined
|
|
89
|
-
|
|
90
|
-
let results: any
|
|
91
|
-
|
|
92
|
-
if (this.embeddings) {
|
|
93
|
-
const embedding = await this.embeddings.generate(change)
|
|
94
|
-
results = await collection.query({
|
|
95
|
-
queryEmbeddings: [embedding],
|
|
96
|
-
nResults: limit,
|
|
97
|
-
where,
|
|
98
|
-
include: ['documents', 'metadatas', 'distances']
|
|
99
|
-
})
|
|
100
|
-
} else {
|
|
101
|
-
results = await collection.query({
|
|
102
|
-
queryTexts: [change],
|
|
103
|
-
nResults: limit,
|
|
104
|
-
where,
|
|
105
|
-
include: ['documents', 'metadatas', 'distances']
|
|
106
|
-
})
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
if (!results.ids || !results.ids[0]) return []
|
|
110
|
-
|
|
111
|
-
const processed: Array<{ id: string; content: string; metadata: Record<string, any>; similarity: number }> = []
|
|
112
|
-
const ids = results.ids[0]
|
|
113
|
-
const documents = results.documents?.[0] || []
|
|
114
|
-
const metadatas = results.metadatas?.[0] || []
|
|
115
|
-
const distances = results.distances?.[0] || []
|
|
116
|
-
|
|
117
|
-
for (let i = 0; i < ids.length; i++) {
|
|
118
|
-
const similarity = 1 - (distances[i] || 0)
|
|
119
|
-
if (similarity < 0.2) continue
|
|
120
|
-
|
|
121
|
-
processed.push({
|
|
122
|
-
id: ids[i],
|
|
123
|
-
content: documents[i] || '',
|
|
124
|
-
metadata: metadatas[i] || {},
|
|
125
|
-
similarity
|
|
126
|
-
})
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
return processed
|
|
130
|
-
} catch (error) {
|
|
131
|
-
this.logger.warn({ error, change }, 'Failed to find related decisions for what-if')
|
|
132
|
-
return []
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
private findAffectedTechnologies(change: string): string[] {
|
|
137
|
-
if (!this.graph) return []
|
|
138
|
-
|
|
139
|
-
const technologies: string[] = []
|
|
140
|
-
|
|
141
|
-
try {
|
|
142
|
-
// Find nodes matching the change description
|
|
143
|
-
const changeWords = change.toLowerCase().split(/\s+/)
|
|
144
|
-
|
|
145
|
-
const matchingNodes = this.graph.findNodes({ type: 'technology' })
|
|
146
|
-
.filter(node => {
|
|
147
|
-
const name = node.name.toLowerCase()
|
|
148
|
-
return changeWords.some(w => name.includes(w) || w.includes(name))
|
|
149
|
-
})
|
|
150
|
-
|
|
151
|
-
for (const node of matchingNodes) {
|
|
152
|
-
technologies.push(node.name)
|
|
153
|
-
|
|
154
|
-
// Traverse to find connected technologies
|
|
155
|
-
const connected = this.graph.traverse(node.id, {
|
|
156
|
-
maxDepth: 2,
|
|
157
|
-
nodeTypes: ['technology']
|
|
158
|
-
})
|
|
159
|
-
|
|
160
|
-
for (const connNode of connected) {
|
|
161
|
-
if (connNode.id !== node.id && !technologies.includes(connNode.name)) {
|
|
162
|
-
technologies.push(connNode.name)
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
} catch (error) {
|
|
167
|
-
this.logger.debug({ error }, 'Failed to traverse knowledge graph')
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
return technologies.slice(0, 20)
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
private assessImpact(
|
|
174
|
-
decision: { content: string; metadata: Record<string, any>; similarity: number },
|
|
175
|
-
change: string
|
|
176
|
-
): 'high' | 'medium' | 'low' {
|
|
177
|
-
// High similarity = high impact
|
|
178
|
-
if (decision.similarity > 0.7) return 'high'
|
|
179
|
-
if (decision.similarity > 0.5) return 'medium'
|
|
180
|
-
|
|
181
|
-
// Check if the decision directly references the change topic
|
|
182
|
-
const changeTerms = change.toLowerCase().split(/\s+/)
|
|
183
|
-
const content = decision.content.toLowerCase()
|
|
184
|
-
const directMentions = changeTerms.filter(t => t.length > 3 && content.includes(t)).length
|
|
185
|
-
|
|
186
|
-
if (directMentions >= 3) return 'high'
|
|
187
|
-
if (directMentions >= 1) return 'medium'
|
|
188
|
-
|
|
189
|
-
return 'low'
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
private explainImpact(
|
|
193
|
-
decision: { content: string; metadata: Record<string, any> },
|
|
194
|
-
change: string
|
|
195
|
-
): string {
|
|
196
|
-
const reasoning = decision.metadata.reasoning || ''
|
|
197
|
-
const context = decision.metadata.context || ''
|
|
198
|
-
|
|
199
|
-
if (reasoning) {
|
|
200
|
-
return `This decision was based on: "${reasoning.slice(0, 100)}..." which may need revision.`
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
if (context) {
|
|
204
|
-
return `Made in context: "${context.slice(0, 100)}..." which would be affected.`
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
return 'This decision may need to be reconsidered.'
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
private calculateRisk(
|
|
211
|
-
affectedDecisions: Array<{ impact: 'high' | 'medium' | 'low' }>
|
|
212
|
-
): 'high' | 'medium' | 'low' {
|
|
213
|
-
const highCount = affectedDecisions.filter(d => d.impact === 'high').length
|
|
214
|
-
const medCount = affectedDecisions.filter(d => d.impact === 'medium').length
|
|
215
|
-
|
|
216
|
-
if (highCount >= 3) return 'high'
|
|
217
|
-
if (highCount >= 1 || medCount >= 5) return 'medium'
|
|
218
|
-
return 'low'
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
private buildSummary(
|
|
222
|
-
change: string,
|
|
223
|
-
affectedDecisions: Array<{ impact: string }>,
|
|
224
|
-
affectedTechnologies: string[],
|
|
225
|
-
riskLevel: string
|
|
226
|
-
): string {
|
|
227
|
-
const parts: string[] = []
|
|
228
|
-
|
|
229
|
-
parts.push(`## What-If Analysis: "${change}"`)
|
|
230
|
-
parts.push('')
|
|
231
|
-
parts.push(`**Risk Level:** ${riskLevel.toUpperCase()}`)
|
|
232
|
-
parts.push(`**Affected Decisions:** ${affectedDecisions.length}`)
|
|
233
|
-
|
|
234
|
-
const highImpact = affectedDecisions.filter(d => d.impact === 'high').length
|
|
235
|
-
const medImpact = affectedDecisions.filter(d => d.impact === 'medium').length
|
|
236
|
-
const lowImpact = affectedDecisions.filter(d => d.impact === 'low').length
|
|
237
|
-
|
|
238
|
-
parts.push(` - High impact: ${highImpact}`)
|
|
239
|
-
parts.push(` - Medium impact: ${medImpact}`)
|
|
240
|
-
parts.push(` - Low impact: ${lowImpact}`)
|
|
241
|
-
|
|
242
|
-
if (affectedTechnologies.length > 0) {
|
|
243
|
-
parts.push(`\n**Affected Technologies:** ${affectedTechnologies.join(', ')}`)
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
return parts.join('\n')
|
|
247
|
-
}
|
|
248
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Counterfactual Analysis
|
|
3
|
+
* What-if analysis using knowledge graph and decision history
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { Logger } from 'pino'
|
|
7
|
+
import type { InMemoryKnowledgeGraph } from '@/knowledge/graph/memory-graph'
|
|
8
|
+
import type { CollectionManager } from '@/memory/chroma/collection-manager'
|
|
9
|
+
import type { EmbeddingProvider } from '@/memory/chroma/embeddings'
|
|
10
|
+
|
|
11
|
+
export interface WhatIfScenario {
|
|
12
|
+
change: string
|
|
13
|
+
affectedDecisions: Array<{
|
|
14
|
+
id: string
|
|
15
|
+
decision: string
|
|
16
|
+
impact: 'high' | 'medium' | 'low'
|
|
17
|
+
reason: string
|
|
18
|
+
}>
|
|
19
|
+
affectedTechnologies: string[]
|
|
20
|
+
riskLevel: 'high' | 'medium' | 'low'
|
|
21
|
+
summary: string
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export class CounterfactualAnalyzer {
|
|
25
|
+
private logger: Logger
|
|
26
|
+
private graph: InMemoryKnowledgeGraph | null
|
|
27
|
+
private collections: CollectionManager
|
|
28
|
+
private embeddings?: EmbeddingProvider
|
|
29
|
+
|
|
30
|
+
constructor(
|
|
31
|
+
logger: Logger,
|
|
32
|
+
graph: InMemoryKnowledgeGraph | null,
|
|
33
|
+
collections: CollectionManager,
|
|
34
|
+
embeddings?: EmbeddingProvider
|
|
35
|
+
) {
|
|
36
|
+
this.logger = logger.child({ component: 'counterfactual' })
|
|
37
|
+
this.graph = graph
|
|
38
|
+
this.collections = collections
|
|
39
|
+
this.embeddings = embeddings
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Analyze what would happen if a technology/decision changed
|
|
44
|
+
*/
|
|
45
|
+
async whatIf(change: string, options: {
|
|
46
|
+
project?: string
|
|
47
|
+
maxResults?: number
|
|
48
|
+
} = {}): Promise<WhatIfScenario> {
|
|
49
|
+
const { project, maxResults = 20 } = options
|
|
50
|
+
|
|
51
|
+
// Find decisions related to the change
|
|
52
|
+
const relatedDecisions = await this.findRelatedDecisions(change, project, maxResults)
|
|
53
|
+
|
|
54
|
+
// Find affected technologies via knowledge graph
|
|
55
|
+
const affectedTechnologies = this.findAffectedTechnologies(change)
|
|
56
|
+
|
|
57
|
+
// Assess impact on each decision
|
|
58
|
+
const affectedDecisions = relatedDecisions.map(d => ({
|
|
59
|
+
id: d.id,
|
|
60
|
+
decision: d.content.slice(0, 200),
|
|
61
|
+
impact: this.assessImpact(d, change),
|
|
62
|
+
reason: this.explainImpact(d, change)
|
|
63
|
+
}))
|
|
64
|
+
|
|
65
|
+
// Determine overall risk
|
|
66
|
+
const riskLevel = this.calculateRisk(affectedDecisions)
|
|
67
|
+
|
|
68
|
+
// Build summary
|
|
69
|
+
const summary = this.buildSummary(change, affectedDecisions, affectedTechnologies, riskLevel)
|
|
70
|
+
|
|
71
|
+
return {
|
|
72
|
+
change,
|
|
73
|
+
affectedDecisions,
|
|
74
|
+
affectedTechnologies,
|
|
75
|
+
riskLevel,
|
|
76
|
+
summary
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
private async findRelatedDecisions(
|
|
81
|
+
change: string,
|
|
82
|
+
project?: string,
|
|
83
|
+
limit: number = 20
|
|
84
|
+
): Promise<Array<{ id: string; content: string; metadata: Record<string, any>; similarity: number }>> {
|
|
85
|
+
try {
|
|
86
|
+
const collection = await this.collections.getDecisions()
|
|
87
|
+
|
|
88
|
+
const where: any = project ? { project: { $eq: project } } : undefined
|
|
89
|
+
|
|
90
|
+
let results: any
|
|
91
|
+
|
|
92
|
+
if (this.embeddings) {
|
|
93
|
+
const embedding = await this.embeddings.generate(change)
|
|
94
|
+
results = await collection.query({
|
|
95
|
+
queryEmbeddings: [embedding],
|
|
96
|
+
nResults: limit,
|
|
97
|
+
where,
|
|
98
|
+
include: ['documents', 'metadatas', 'distances']
|
|
99
|
+
})
|
|
100
|
+
} else {
|
|
101
|
+
results = await collection.query({
|
|
102
|
+
queryTexts: [change],
|
|
103
|
+
nResults: limit,
|
|
104
|
+
where,
|
|
105
|
+
include: ['documents', 'metadatas', 'distances']
|
|
106
|
+
})
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (!results.ids || !results.ids[0]) return []
|
|
110
|
+
|
|
111
|
+
const processed: Array<{ id: string; content: string; metadata: Record<string, any>; similarity: number }> = []
|
|
112
|
+
const ids = results.ids[0]
|
|
113
|
+
const documents = results.documents?.[0] || []
|
|
114
|
+
const metadatas = results.metadatas?.[0] || []
|
|
115
|
+
const distances = results.distances?.[0] || []
|
|
116
|
+
|
|
117
|
+
for (let i = 0; i < ids.length; i++) {
|
|
118
|
+
const similarity = 1 - (distances[i] || 0)
|
|
119
|
+
if (similarity < 0.2) continue
|
|
120
|
+
|
|
121
|
+
processed.push({
|
|
122
|
+
id: ids[i],
|
|
123
|
+
content: documents[i] || '',
|
|
124
|
+
metadata: metadatas[i] || {},
|
|
125
|
+
similarity
|
|
126
|
+
})
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return processed
|
|
130
|
+
} catch (error) {
|
|
131
|
+
this.logger.warn({ error, change }, 'Failed to find related decisions for what-if')
|
|
132
|
+
return []
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
private findAffectedTechnologies(change: string): string[] {
|
|
137
|
+
if (!this.graph) return []
|
|
138
|
+
|
|
139
|
+
const technologies: string[] = []
|
|
140
|
+
|
|
141
|
+
try {
|
|
142
|
+
// Find nodes matching the change description
|
|
143
|
+
const changeWords = change.toLowerCase().split(/\s+/)
|
|
144
|
+
|
|
145
|
+
const matchingNodes = this.graph.findNodes({ type: 'technology' })
|
|
146
|
+
.filter(node => {
|
|
147
|
+
const name = node.name.toLowerCase()
|
|
148
|
+
return changeWords.some(w => name.includes(w) || w.includes(name))
|
|
149
|
+
})
|
|
150
|
+
|
|
151
|
+
for (const node of matchingNodes) {
|
|
152
|
+
technologies.push(node.name)
|
|
153
|
+
|
|
154
|
+
// Traverse to find connected technologies
|
|
155
|
+
const connected = this.graph.traverse(node.id, {
|
|
156
|
+
maxDepth: 2,
|
|
157
|
+
nodeTypes: ['technology']
|
|
158
|
+
})
|
|
159
|
+
|
|
160
|
+
for (const connNode of connected) {
|
|
161
|
+
if (connNode.id !== node.id && !technologies.includes(connNode.name)) {
|
|
162
|
+
technologies.push(connNode.name)
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
} catch (error) {
|
|
167
|
+
this.logger.debug({ error }, 'Failed to traverse knowledge graph')
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
return technologies.slice(0, 20)
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
private assessImpact(
|
|
174
|
+
decision: { content: string; metadata: Record<string, any>; similarity: number },
|
|
175
|
+
change: string
|
|
176
|
+
): 'high' | 'medium' | 'low' {
|
|
177
|
+
// High similarity = high impact
|
|
178
|
+
if (decision.similarity > 0.7) return 'high'
|
|
179
|
+
if (decision.similarity > 0.5) return 'medium'
|
|
180
|
+
|
|
181
|
+
// Check if the decision directly references the change topic
|
|
182
|
+
const changeTerms = change.toLowerCase().split(/\s+/)
|
|
183
|
+
const content = decision.content.toLowerCase()
|
|
184
|
+
const directMentions = changeTerms.filter(t => t.length > 3 && content.includes(t)).length
|
|
185
|
+
|
|
186
|
+
if (directMentions >= 3) return 'high'
|
|
187
|
+
if (directMentions >= 1) return 'medium'
|
|
188
|
+
|
|
189
|
+
return 'low'
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
private explainImpact(
|
|
193
|
+
decision: { content: string; metadata: Record<string, any> },
|
|
194
|
+
change: string
|
|
195
|
+
): string {
|
|
196
|
+
const reasoning = decision.metadata.reasoning || ''
|
|
197
|
+
const context = decision.metadata.context || ''
|
|
198
|
+
|
|
199
|
+
if (reasoning) {
|
|
200
|
+
return `This decision was based on: "${reasoning.slice(0, 100)}..." which may need revision.`
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if (context) {
|
|
204
|
+
return `Made in context: "${context.slice(0, 100)}..." which would be affected.`
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
return 'This decision may need to be reconsidered.'
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
private calculateRisk(
|
|
211
|
+
affectedDecisions: Array<{ impact: 'high' | 'medium' | 'low' }>
|
|
212
|
+
): 'high' | 'medium' | 'low' {
|
|
213
|
+
const highCount = affectedDecisions.filter(d => d.impact === 'high').length
|
|
214
|
+
const medCount = affectedDecisions.filter(d => d.impact === 'medium').length
|
|
215
|
+
|
|
216
|
+
if (highCount >= 3) return 'high'
|
|
217
|
+
if (highCount >= 1 || medCount >= 5) return 'medium'
|
|
218
|
+
return 'low'
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
private buildSummary(
|
|
222
|
+
change: string,
|
|
223
|
+
affectedDecisions: Array<{ impact: string }>,
|
|
224
|
+
affectedTechnologies: string[],
|
|
225
|
+
riskLevel: string
|
|
226
|
+
): string {
|
|
227
|
+
const parts: string[] = []
|
|
228
|
+
|
|
229
|
+
parts.push(`## What-If Analysis: "${change}"`)
|
|
230
|
+
parts.push('')
|
|
231
|
+
parts.push(`**Risk Level:** ${riskLevel.toUpperCase()}`)
|
|
232
|
+
parts.push(`**Affected Decisions:** ${affectedDecisions.length}`)
|
|
233
|
+
|
|
234
|
+
const highImpact = affectedDecisions.filter(d => d.impact === 'high').length
|
|
235
|
+
const medImpact = affectedDecisions.filter(d => d.impact === 'medium').length
|
|
236
|
+
const lowImpact = affectedDecisions.filter(d => d.impact === 'low').length
|
|
237
|
+
|
|
238
|
+
parts.push(` - High impact: ${highImpact}`)
|
|
239
|
+
parts.push(` - Medium impact: ${medImpact}`)
|
|
240
|
+
parts.push(` - Low impact: ${lowImpact}`)
|
|
241
|
+
|
|
242
|
+
if (affectedTechnologies.length > 0) {
|
|
243
|
+
parts.push(`\n**Affected Technologies:** ${affectedTechnologies.join(', ')}`)
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
return parts.join('\n')
|
|
247
|
+
}
|
|
248
|
+
}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Multi-Hop Reasoning Module
|
|
3
|
-
* Phase 15.2 - Chain retrieval, result synthesis, counterfactual analysis
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
export { ChainRetrieval } from './chain-retrieval'
|
|
7
|
-
export type { ChainStep, ChainResult, ChainRetrievalResult } from './chain-retrieval'
|
|
8
|
-
|
|
9
|
-
export { ResultSynthesizer } from './synthesizer'
|
|
10
|
-
export type { SynthesizedResult } from './synthesizer'
|
|
11
|
-
|
|
12
|
-
export { CounterfactualAnalyzer } from './counterfactual'
|
|
13
|
-
export type { WhatIfScenario } from './counterfactual'
|
|
1
|
+
/**
|
|
2
|
+
* Multi-Hop Reasoning Module
|
|
3
|
+
* Phase 15.2 - Chain retrieval, result synthesis, counterfactual analysis
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export { ChainRetrieval } from './chain-retrieval'
|
|
7
|
+
export type { ChainStep, ChainResult, ChainRetrievalResult } from './chain-retrieval'
|
|
8
|
+
|
|
9
|
+
export { ResultSynthesizer } from './synthesizer'
|
|
10
|
+
export type { SynthesizedResult } from './synthesizer'
|
|
11
|
+
|
|
12
|
+
export { CounterfactualAnalyzer } from './counterfactual'
|
|
13
|
+
export type { WhatIfScenario } from './counterfactual'
|