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,92 +1,92 @@
|
|
|
1
|
-
import type { Collection } from 'chromadb'
|
|
2
|
-
import type { Logger } from 'pino'
|
|
3
|
-
import type { ChromaClientManager } from './client'
|
|
4
|
-
import { COLLECTIONS } from './schemas'
|
|
5
|
-
|
|
6
|
-
export class CollectionManager {
|
|
7
|
-
private logger: Logger
|
|
8
|
-
private client: ChromaClientManager
|
|
9
|
-
|
|
10
|
-
constructor(logger: Logger, client: ChromaClientManager) {
|
|
11
|
-
this.logger = logger.child({ component: 'collection-manager' })
|
|
12
|
-
this.client = client
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
async initialize(): Promise<void> {
|
|
16
|
-
this.logger.info('Initializing collections')
|
|
17
|
-
|
|
18
|
-
try {
|
|
19
|
-
for (const collectionName of Object.values(COLLECTIONS)) {
|
|
20
|
-
await this.client.getCollection(collectionName)
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
this.logger.info('All collections initialized')
|
|
24
|
-
|
|
25
|
-
} catch (error) {
|
|
26
|
-
this.logger.error({ error }, 'Failed to initialize collections')
|
|
27
|
-
throw error
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
async getDecisions(): Promise<Collection> {
|
|
32
|
-
return this.client.getCollection(COLLECTIONS.DECISIONS)
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
async getMemories(): Promise<Collection> {
|
|
36
|
-
return this.client.getCollection(COLLECTIONS.MEMORIES)
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
async getPatterns(): Promise<Collection> {
|
|
40
|
-
return this.client.getCollection(COLLECTIONS.PATTERNS)
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
async getCorrections(): Promise<Collection> {
|
|
44
|
-
return this.client.getCollection(COLLECTIONS.CORRECTIONS)
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
async getFeedback(): Promise<Collection> {
|
|
48
|
-
return this.client.getCollection(COLLECTIONS.FEEDBACK)
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
async getEpisodes(): Promise<Collection> {
|
|
52
|
-
return this.client.getCollection(COLLECTIONS.EPISODES)
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
async getArchivedMemories(): Promise<Collection> {
|
|
56
|
-
return this.client.getCollection(COLLECTIONS.ARCHIVED_MEMORIES)
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
async getProjectCollection(projectName: string): Promise<Collection> {
|
|
60
|
-
const collectionName = `project_${projectName.toLowerCase().replace(/[^a-z0-9]/g, '_')}`
|
|
61
|
-
return this.client.getCollection(collectionName)
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
async getStats(): Promise<Record<string, number>> {
|
|
65
|
-
const stats: Record<string, number> = {}
|
|
66
|
-
|
|
67
|
-
for (const collectionName of Object.values(COLLECTIONS)) {
|
|
68
|
-
try {
|
|
69
|
-
const collection = await this.client.getCollection(collectionName)
|
|
70
|
-
stats[collectionName] = await collection.count()
|
|
71
|
-
} catch {
|
|
72
|
-
stats[collectionName] = 0
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
return stats
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
async clearAll(): Promise<void> {
|
|
80
|
-
this.logger.warn('Clearing all collections')
|
|
81
|
-
|
|
82
|
-
for (const collectionName of Object.values(COLLECTIONS)) {
|
|
83
|
-
try {
|
|
84
|
-
await this.client.deleteCollection(collectionName)
|
|
85
|
-
} catch (error) {
|
|
86
|
-
this.logger.error({ error, collection: collectionName }, 'Failed to delete collection')
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
await this.initialize()
|
|
91
|
-
}
|
|
92
|
-
}
|
|
1
|
+
import type { Collection } from 'chromadb'
|
|
2
|
+
import type { Logger } from 'pino'
|
|
3
|
+
import type { ChromaClientManager } from './client'
|
|
4
|
+
import { COLLECTIONS } from './schemas'
|
|
5
|
+
|
|
6
|
+
export class CollectionManager {
|
|
7
|
+
private logger: Logger
|
|
8
|
+
private client: ChromaClientManager
|
|
9
|
+
|
|
10
|
+
constructor(logger: Logger, client: ChromaClientManager) {
|
|
11
|
+
this.logger = logger.child({ component: 'collection-manager' })
|
|
12
|
+
this.client = client
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
async initialize(): Promise<void> {
|
|
16
|
+
this.logger.info('Initializing collections')
|
|
17
|
+
|
|
18
|
+
try {
|
|
19
|
+
for (const collectionName of Object.values(COLLECTIONS)) {
|
|
20
|
+
await this.client.getCollection(collectionName)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
this.logger.info('All collections initialized')
|
|
24
|
+
|
|
25
|
+
} catch (error) {
|
|
26
|
+
this.logger.error({ error }, 'Failed to initialize collections')
|
|
27
|
+
throw error
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async getDecisions(): Promise<Collection> {
|
|
32
|
+
return this.client.getCollection(COLLECTIONS.DECISIONS)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async getMemories(): Promise<Collection> {
|
|
36
|
+
return this.client.getCollection(COLLECTIONS.MEMORIES)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
async getPatterns(): Promise<Collection> {
|
|
40
|
+
return this.client.getCollection(COLLECTIONS.PATTERNS)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async getCorrections(): Promise<Collection> {
|
|
44
|
+
return this.client.getCollection(COLLECTIONS.CORRECTIONS)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
async getFeedback(): Promise<Collection> {
|
|
48
|
+
return this.client.getCollection(COLLECTIONS.FEEDBACK)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
async getEpisodes(): Promise<Collection> {
|
|
52
|
+
return this.client.getCollection(COLLECTIONS.EPISODES)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
async getArchivedMemories(): Promise<Collection> {
|
|
56
|
+
return this.client.getCollection(COLLECTIONS.ARCHIVED_MEMORIES)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async getProjectCollection(projectName: string): Promise<Collection> {
|
|
60
|
+
const collectionName = `project_${projectName.toLowerCase().replace(/[^a-z0-9]/g, '_')}`
|
|
61
|
+
return this.client.getCollection(collectionName)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
async getStats(): Promise<Record<string, number>> {
|
|
65
|
+
const stats: Record<string, number> = {}
|
|
66
|
+
|
|
67
|
+
for (const collectionName of Object.values(COLLECTIONS)) {
|
|
68
|
+
try {
|
|
69
|
+
const collection = await this.client.getCollection(collectionName)
|
|
70
|
+
stats[collectionName] = await collection.count()
|
|
71
|
+
} catch {
|
|
72
|
+
stats[collectionName] = 0
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return stats
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
async clearAll(): Promise<void> {
|
|
80
|
+
this.logger.warn('Clearing all collections')
|
|
81
|
+
|
|
82
|
+
for (const collectionName of Object.values(COLLECTIONS)) {
|
|
83
|
+
try {
|
|
84
|
+
await this.client.deleteCollection(collectionName)
|
|
85
|
+
} catch (error) {
|
|
86
|
+
this.logger.error({ error, collection: collectionName }, 'Failed to delete collection')
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
await this.initialize()
|
|
91
|
+
}
|
|
92
|
+
}
|
|
@@ -1,57 +1,57 @@
|
|
|
1
|
-
import { z } from 'zod'
|
|
2
|
-
|
|
3
|
-
export const ChromaConfigSchema = z.object({
|
|
4
|
-
mode: z.enum(['persistent', 'client-server', 'ephemeral', 'cloud']).default('persistent'),
|
|
5
|
-
path: z.string().default('./data/chroma'),
|
|
6
|
-
host: z.string().optional(),
|
|
7
|
-
port: z.number().optional(),
|
|
8
|
-
embeddingProvider: z.enum(['default', 'transformers', 'openai']).default('default'),
|
|
9
|
-
embeddingModel: z.string().default('Xenova/all-MiniLM-L6-v2'),
|
|
10
|
-
defaultCollection: z.string().default('memories'),
|
|
11
|
-
batchSize: z.number().default(100),
|
|
12
|
-
openaiApiKey: z.string().optional(),
|
|
13
|
-
chromaAuthToken: z.string().optional(),
|
|
14
|
-
chromaTenant: z.string().optional(),
|
|
15
|
-
chromaDatabase: z.string().optional()
|
|
16
|
-
})
|
|
17
|
-
|
|
18
|
-
export type ChromaConfig = z.infer<typeof ChromaConfigSchema>
|
|
19
|
-
|
|
20
|
-
export const DEFAULT_CHROMA_CONFIG: ChromaConfig = {
|
|
21
|
-
mode: 'persistent',
|
|
22
|
-
path: './data/chroma',
|
|
23
|
-
embeddingProvider: 'default',
|
|
24
|
-
embeddingModel: 'Xenova/all-MiniLM-L6-v2',
|
|
25
|
-
defaultCollection: 'memories',
|
|
26
|
-
batchSize: 100
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export function getChromaConfigFromEnv(): Partial<ChromaConfig> {
|
|
30
|
-
const config: Partial<ChromaConfig> = {
|
|
31
|
-
chromaAuthToken: process.env.CHROMA_API_KEY,
|
|
32
|
-
chromaTenant: process.env.CHROMA_TENANT,
|
|
33
|
-
chromaDatabase: process.env.CHROMA_DATABASE
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
if (process.env.CHROMA_HOST) {
|
|
37
|
-
config.host = process.env.CHROMA_HOST
|
|
38
|
-
// Only default to cloud if CHROMA_MODE isn't explicitly set
|
|
39
|
-
if (!process.env.CHROMA_MODE) {
|
|
40
|
-
config.mode = 'cloud'
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
if (process.env.CHROMA_MODE) {
|
|
45
|
-
config.mode = process.env.CHROMA_MODE as any
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
if (process.env.CHROMA_PORT) {
|
|
49
|
-
config.port = parseInt(process.env.CHROMA_PORT, 10)
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
if (process.env.CHROMA_EMBEDDING_PROVIDER) {
|
|
53
|
-
config.embeddingProvider = process.env.CHROMA_EMBEDDING_PROVIDER as any
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
return config
|
|
57
|
-
}
|
|
1
|
+
import { z } from 'zod'
|
|
2
|
+
|
|
3
|
+
export const ChromaConfigSchema = z.object({
|
|
4
|
+
mode: z.enum(['persistent', 'client-server', 'ephemeral', 'cloud']).default('persistent'),
|
|
5
|
+
path: z.string().default('./data/chroma'),
|
|
6
|
+
host: z.string().optional(),
|
|
7
|
+
port: z.number().optional(),
|
|
8
|
+
embeddingProvider: z.enum(['default', 'transformers', 'openai']).default('default'),
|
|
9
|
+
embeddingModel: z.string().default('Xenova/all-MiniLM-L6-v2'),
|
|
10
|
+
defaultCollection: z.string().default('memories'),
|
|
11
|
+
batchSize: z.number().default(100),
|
|
12
|
+
openaiApiKey: z.string().optional(),
|
|
13
|
+
chromaAuthToken: z.string().optional(),
|
|
14
|
+
chromaTenant: z.string().optional(),
|
|
15
|
+
chromaDatabase: z.string().optional()
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
export type ChromaConfig = z.infer<typeof ChromaConfigSchema>
|
|
19
|
+
|
|
20
|
+
export const DEFAULT_CHROMA_CONFIG: ChromaConfig = {
|
|
21
|
+
mode: 'persistent',
|
|
22
|
+
path: './data/chroma',
|
|
23
|
+
embeddingProvider: 'default',
|
|
24
|
+
embeddingModel: 'Xenova/all-MiniLM-L6-v2',
|
|
25
|
+
defaultCollection: 'memories',
|
|
26
|
+
batchSize: 100
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function getChromaConfigFromEnv(): Partial<ChromaConfig> {
|
|
30
|
+
const config: Partial<ChromaConfig> = {
|
|
31
|
+
chromaAuthToken: process.env.CHROMA_API_KEY,
|
|
32
|
+
chromaTenant: process.env.CHROMA_TENANT,
|
|
33
|
+
chromaDatabase: process.env.CHROMA_DATABASE
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (process.env.CHROMA_HOST) {
|
|
37
|
+
config.host = process.env.CHROMA_HOST
|
|
38
|
+
// Only default to cloud if CHROMA_MODE isn't explicitly set
|
|
39
|
+
if (!process.env.CHROMA_MODE) {
|
|
40
|
+
config.mode = 'cloud'
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (process.env.CHROMA_MODE) {
|
|
45
|
+
config.mode = process.env.CHROMA_MODE as any
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (process.env.CHROMA_PORT) {
|
|
49
|
+
config.port = parseInt(process.env.CHROMA_PORT, 10)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (process.env.CHROMA_EMBEDDING_PROVIDER) {
|
|
53
|
+
config.embeddingProvider = process.env.CHROMA_EMBEDDING_PROVIDER as any
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return config
|
|
57
|
+
}
|
|
@@ -1,175 +1,177 @@
|
|
|
1
|
-
import type { Logger } from 'pino'
|
|
2
|
-
import type { ChromaConfig } from './config'
|
|
3
|
-
|
|
4
|
-
export interface EmbeddingProvider {
|
|
5
|
-
name: string
|
|
6
|
-
dimensions: number
|
|
7
|
-
generate(text: string): Promise<number[]>
|
|
8
|
-
generateBatch(texts: string[]): Promise<number[][]>
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export class DefaultEmbeddingProvider implements EmbeddingProvider {
|
|
12
|
-
name = 'default'
|
|
13
|
-
dimensions = 384
|
|
14
|
-
|
|
15
|
-
async generate(_text: string): Promise<number[]> {
|
|
16
|
-
throw new Error('Default provider uses ChromaDB auto-embedding')
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
async generateBatch(_texts: string[]): Promise<number[][]> {
|
|
20
|
-
throw new Error('Default provider uses ChromaDB auto-embedding')
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export class TransformersEmbeddingProvider implements EmbeddingProvider {
|
|
25
|
-
name = 'transformers'
|
|
26
|
-
dimensions = 384
|
|
27
|
-
|
|
28
|
-
private pipeline:
|
|
29
|
-
private logger: Logger
|
|
30
|
-
private modelName: string
|
|
31
|
-
|
|
32
|
-
constructor(logger: Logger, modelName: string = 'Xenova/all-MiniLM-L6-v2') {
|
|
33
|
-
this.logger = logger.child({ component: 'transformers-embeddings' })
|
|
34
|
-
this.modelName = modelName
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
private async getPipeline() {
|
|
38
|
-
if (!this.pipeline) {
|
|
39
|
-
try {
|
|
40
|
-
const { pipeline } = await import('@xenova/transformers')
|
|
41
|
-
this.pipeline = await pipeline('feature-extraction', this.modelName)
|
|
42
|
-
} catch (error) {
|
|
43
|
-
this.logger.warn({ error }, 'Model load failed, clearing cache and retrying')
|
|
44
|
-
await this.clearModelCache()
|
|
45
|
-
const { pipeline } = await import('@xenova/transformers')
|
|
46
|
-
this.pipeline = await pipeline('feature-extraction', this.modelName)
|
|
47
|
-
}
|
|
48
|
-
this.logger.info({ model: this.modelName }, 'Transformers pipeline initialized')
|
|
49
|
-
}
|
|
50
|
-
return this.pipeline
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
private async clearModelCache(): Promise<void> {
|
|
54
|
-
const { rm } = await import('fs/promises')
|
|
55
|
-
const { join } = await import('path')
|
|
56
|
-
const cacheDir = join(
|
|
57
|
-
require.resolve('@xenova/transformers'),
|
|
58
|
-
'..', '.cache', ...this.modelName.split('/')
|
|
59
|
-
)
|
|
60
|
-
try {
|
|
61
|
-
await rm(cacheDir, { recursive: true, force: true })
|
|
62
|
-
this.logger.info({ cacheDir }, 'Cleared corrupted model cache')
|
|
63
|
-
} catch {
|
|
64
|
-
// Cache dir may not exist, continue
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
async generate(text: string): Promise<number[]> {
|
|
69
|
-
const pipe = await this.getPipeline()
|
|
70
|
-
|
|
71
|
-
const output = await pipe(text, {
|
|
72
|
-
pooling: 'mean',
|
|
73
|
-
normalize: true
|
|
74
|
-
})
|
|
75
|
-
|
|
76
|
-
return Array.from(output.data as Float32Array)
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
async generateBatch(texts: string[]): Promise<number[][]> {
|
|
80
|
-
const embeddings: number[][] = []
|
|
81
|
-
|
|
82
|
-
const batchSize = 10
|
|
83
|
-
|
|
84
|
-
for (let i = 0; i < texts.length; i += batchSize) {
|
|
85
|
-
const batch = texts.slice(i, i + batchSize)
|
|
86
|
-
const batchEmbeddings = await Promise.all(
|
|
87
|
-
batch.map(text => this.generate(text))
|
|
88
|
-
)
|
|
89
|
-
embeddings.push(...batchEmbeddings)
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
return embeddings
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
export class OpenAIEmbeddingProvider implements EmbeddingProvider {
|
|
97
|
-
name = 'openai'
|
|
98
|
-
dimensions = 1536
|
|
99
|
-
|
|
100
|
-
private apiKey: string
|
|
101
|
-
private model: string
|
|
102
|
-
|
|
103
|
-
constructor(
|
|
104
|
-
_logger: Logger,
|
|
105
|
-
apiKey: string,
|
|
106
|
-
model: string = 'text-embedding-3-small'
|
|
107
|
-
) {
|
|
108
|
-
this.apiKey = apiKey
|
|
109
|
-
this.model = model
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
async generate(text: string): Promise<number[]> {
|
|
113
|
-
const response = await fetch('https://api.openai.com/v1/embeddings', {
|
|
114
|
-
method: 'POST',
|
|
115
|
-
headers: {
|
|
116
|
-
'Authorization': `Bearer ${this.apiKey}`,
|
|
117
|
-
'Content-Type': 'application/json'
|
|
118
|
-
},
|
|
119
|
-
body: JSON.stringify({
|
|
120
|
-
model: this.model,
|
|
121
|
-
input: text
|
|
122
|
-
})
|
|
123
|
-
})
|
|
124
|
-
|
|
125
|
-
if (!response.ok) {
|
|
126
|
-
throw new Error(`OpenAI API error: ${response.statusText}`)
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
const data
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
1
|
+
import type { Logger } from 'pino'
|
|
2
|
+
import type { ChromaConfig } from './config'
|
|
3
|
+
|
|
4
|
+
export interface EmbeddingProvider {
|
|
5
|
+
name: string
|
|
6
|
+
dimensions: number
|
|
7
|
+
generate(text: string): Promise<number[]>
|
|
8
|
+
generateBatch(texts: string[]): Promise<number[][]>
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export class DefaultEmbeddingProvider implements EmbeddingProvider {
|
|
12
|
+
name = 'default'
|
|
13
|
+
dimensions = 384
|
|
14
|
+
|
|
15
|
+
async generate(_text: string): Promise<number[]> {
|
|
16
|
+
throw new Error('Default provider uses ChromaDB auto-embedding')
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
async generateBatch(_texts: string[]): Promise<number[][]> {
|
|
20
|
+
throw new Error('Default provider uses ChromaDB auto-embedding')
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export class TransformersEmbeddingProvider implements EmbeddingProvider {
|
|
25
|
+
name = 'transformers'
|
|
26
|
+
dimensions = 384
|
|
27
|
+
|
|
28
|
+
private pipeline: unknown = null
|
|
29
|
+
private logger: Logger
|
|
30
|
+
private modelName: string
|
|
31
|
+
|
|
32
|
+
constructor(logger: Logger, modelName: string = 'Xenova/all-MiniLM-L6-v2') {
|
|
33
|
+
this.logger = logger.child({ component: 'transformers-embeddings' })
|
|
34
|
+
this.modelName = modelName
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
private async getPipeline(): Promise<(text: string, options: Record<string, unknown>) => Promise<{ data: Float32Array }>> {
|
|
38
|
+
if (!this.pipeline) {
|
|
39
|
+
try {
|
|
40
|
+
const { pipeline } = await import('@xenova/transformers')
|
|
41
|
+
this.pipeline = await pipeline('feature-extraction', this.modelName)
|
|
42
|
+
} catch (error) {
|
|
43
|
+
this.logger.warn({ error }, 'Model load failed, clearing cache and retrying')
|
|
44
|
+
await this.clearModelCache()
|
|
45
|
+
const { pipeline } = await import('@xenova/transformers')
|
|
46
|
+
this.pipeline = await pipeline('feature-extraction', this.modelName)
|
|
47
|
+
}
|
|
48
|
+
this.logger.info({ model: this.modelName }, 'Transformers pipeline initialized')
|
|
49
|
+
}
|
|
50
|
+
return this.pipeline as (text: string, options: Record<string, unknown>) => Promise<{ data: Float32Array }>
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
private async clearModelCache(): Promise<void> {
|
|
54
|
+
const { rm } = await import('fs/promises')
|
|
55
|
+
const { join } = await import('path')
|
|
56
|
+
const cacheDir = join(
|
|
57
|
+
require.resolve('@xenova/transformers'),
|
|
58
|
+
'..', '.cache', ...this.modelName.split('/')
|
|
59
|
+
)
|
|
60
|
+
try {
|
|
61
|
+
await rm(cacheDir, { recursive: true, force: true })
|
|
62
|
+
this.logger.info({ cacheDir }, 'Cleared corrupted model cache')
|
|
63
|
+
} catch {
|
|
64
|
+
// Cache dir may not exist, continue
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
async generate(text: string): Promise<number[]> {
|
|
69
|
+
const pipe = await this.getPipeline()
|
|
70
|
+
|
|
71
|
+
const output = await pipe(text, {
|
|
72
|
+
pooling: 'mean',
|
|
73
|
+
normalize: true
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
return Array.from(output.data as Float32Array)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
async generateBatch(texts: string[]): Promise<number[][]> {
|
|
80
|
+
const embeddings: number[][] = []
|
|
81
|
+
|
|
82
|
+
const batchSize = 10
|
|
83
|
+
|
|
84
|
+
for (let i = 0; i < texts.length; i += batchSize) {
|
|
85
|
+
const batch = texts.slice(i, i + batchSize)
|
|
86
|
+
const batchEmbeddings = await Promise.all(
|
|
87
|
+
batch.map(text => this.generate(text))
|
|
88
|
+
)
|
|
89
|
+
embeddings.push(...batchEmbeddings)
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return embeddings
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export class OpenAIEmbeddingProvider implements EmbeddingProvider {
|
|
97
|
+
name = 'openai'
|
|
98
|
+
dimensions = 1536
|
|
99
|
+
|
|
100
|
+
private apiKey: string
|
|
101
|
+
private model: string
|
|
102
|
+
|
|
103
|
+
constructor(
|
|
104
|
+
_logger: Logger,
|
|
105
|
+
apiKey: string,
|
|
106
|
+
model: string = 'text-embedding-3-small'
|
|
107
|
+
) {
|
|
108
|
+
this.apiKey = apiKey
|
|
109
|
+
this.model = model
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
async generate(text: string): Promise<number[]> {
|
|
113
|
+
const response = await fetch('https://api.openai.com/v1/embeddings', {
|
|
114
|
+
method: 'POST',
|
|
115
|
+
headers: {
|
|
116
|
+
'Authorization': `Bearer ${this.apiKey}`,
|
|
117
|
+
'Content-Type': 'application/json'
|
|
118
|
+
},
|
|
119
|
+
body: JSON.stringify({
|
|
120
|
+
model: this.model,
|
|
121
|
+
input: text
|
|
122
|
+
})
|
|
123
|
+
})
|
|
124
|
+
|
|
125
|
+
if (!response.ok) {
|
|
126
|
+
throw new Error(`OpenAI API error: ${response.statusText}`)
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const data = await response.json() as { data: Array<{ embedding: number[] }> }
|
|
130
|
+
const first = data.data[0]
|
|
131
|
+
if (!first) throw new Error('OpenAI returned empty embedding data')
|
|
132
|
+
return first.embedding
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
async generateBatch(texts: string[]): Promise<number[][]> {
|
|
136
|
+
const response = await fetch('https://api.openai.com/v1/embeddings', {
|
|
137
|
+
method: 'POST',
|
|
138
|
+
headers: {
|
|
139
|
+
'Authorization': `Bearer ${this.apiKey}`,
|
|
140
|
+
'Content-Type': 'application/json'
|
|
141
|
+
},
|
|
142
|
+
body: JSON.stringify({
|
|
143
|
+
model: this.model,
|
|
144
|
+
input: texts
|
|
145
|
+
})
|
|
146
|
+
})
|
|
147
|
+
|
|
148
|
+
if (!response.ok) {
|
|
149
|
+
throw new Error(`OpenAI API error: ${response.statusText}`)
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const data = await response.json() as { data: Array<{ embedding: number[] }> }
|
|
153
|
+
return data.data.map((d) => d.embedding)
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export function createEmbeddingProvider(
|
|
158
|
+
logger: Logger,
|
|
159
|
+
config: ChromaConfig
|
|
160
|
+
): EmbeddingProvider | undefined {
|
|
161
|
+
switch (config.embeddingProvider) {
|
|
162
|
+
case 'openai':
|
|
163
|
+
if (!config.openaiApiKey) {
|
|
164
|
+
throw new Error('OpenAI API key required for OpenAI embedding provider')
|
|
165
|
+
}
|
|
166
|
+
return new OpenAIEmbeddingProvider(logger, config.openaiApiKey)
|
|
167
|
+
|
|
168
|
+
case 'transformers':
|
|
169
|
+
return new TransformersEmbeddingProvider(logger, config.embeddingModel)
|
|
170
|
+
|
|
171
|
+
case 'default':
|
|
172
|
+
default:
|
|
173
|
+
// Return undefined so store/search code falls through to queryTexts path
|
|
174
|
+
// (ChromaDB's built-in auto-embedding)
|
|
175
|
+
return undefined
|
|
176
|
+
}
|
|
177
|
+
}
|