@customize-agent/knowledge 4.0.1 → 4.0.2

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.
Files changed (33) hide show
  1. package/dist/chunking/bge-tokenizer.d.ts +10 -0
  2. package/dist/chunking/bge-tokenizer.js +68 -0
  3. package/dist/chunking/text-chunker.d.ts +10 -0
  4. package/dist/chunking/text-chunker.js +158 -53
  5. package/dist/classification/classifier.js +0 -1
  6. package/dist/core/index-state-store.d.ts +47 -0
  7. package/dist/core/index-state-store.js +184 -50
  8. package/dist/core/knowledge-base-manager.d.ts +24 -2
  9. package/dist/core/knowledge-base-manager.js +195 -51
  10. package/dist/core/multi-project-manager.d.ts +2 -0
  11. package/dist/core/multi-project-manager.js +13 -2
  12. package/dist/embedding/embedding-provider.d.ts +22 -0
  13. package/dist/embedding/embedding-provider.js +116 -2
  14. package/dist/extraction/content-extractor.d.ts +30 -2
  15. package/dist/extraction/content-extractor.js +514 -115
  16. package/dist/index.d.ts +2 -2
  17. package/dist/index.js +2 -2
  18. package/dist/search/federation-search.d.ts +1 -0
  19. package/dist/search/federation-search.js +1 -0
  20. package/dist/vector/hnsw-vector-store.d.ts +20 -0
  21. package/dist/vector/hnsw-vector-store.js +107 -0
  22. package/dist/vector/types.d.ts +2 -0
  23. package/dist/vector/vector-indexer.d.ts +2 -0
  24. package/dist/vector/vector-indexer.js +13 -1
  25. package/models/bge-small-zh-v1.5/config.json +31 -0
  26. package/models/bge-small-zh-v1.5/onnx/model_quantized.onnx +0 -0
  27. package/models/bge-small-zh-v1.5/special_tokens_map.json +7 -0
  28. package/models/bge-small-zh-v1.5/tokenizer.json +21278 -0
  29. package/models/bge-small-zh-v1.5/tokenizer_config.json +15 -0
  30. package/package.json +11 -4
  31. package/scripts/install-hnsw.cjs +47 -0
  32. package/dist/vector/sqlite-vec-store.d.ts +0 -38
  33. package/dist/vector/sqlite-vec-store.js +0 -203
package/dist/index.d.ts CHANGED
@@ -2,7 +2,7 @@ export { TextChunker, type ChunkConfig, type TextChunk } from './chunking/text-c
2
2
  export { FileClassifier } from './classification/classifier.js';
3
3
  export { DedupEngine, type MinHashSignature, type SimilarityMatch } from './dedup/dedup-engine.js';
4
4
  export { RelationshipDetector } from './dedup/relationship-detector.js';
5
- export { HashEmbeddingProvider, OpenAICompatibleEmbeddingProvider, createEmbeddingProviderFromEnvironment, type EmbeddingProvider, type OpenAICompatibleEmbeddingOptions } from './embedding/embedding-provider.js';
5
+ export { HashEmbeddingProvider, LocalTransformersEmbeddingProvider, OpenAICompatibleEmbeddingProvider, createEmbeddingProviderFromEnvironment, type EmbeddingProvider, type LocalTransformersEmbeddingOptions, type OpenAICompatibleEmbeddingOptions } from './embedding/embedding-provider.js';
6
6
  export { ContentExtractor, type ExtractionResult } from './extraction/content-extractor.js';
7
7
  export { CommandExternalExtractor, ExternalExtractorRegistry, type CommandExternalExtractorOptions, type ExternalExtractionResult, type ExternalExtractor, type ExternalExtractorCapability } from './extraction/external-extractor.js';
8
8
  export { ChangeTracker } from './core/change-tracker.js';
@@ -13,7 +13,7 @@ export { MultiProjectManager } from './core/multi-project-manager.js';
13
13
  export { computeProjectId } from './core/project-id.js';
14
14
  export { ensureProjectCustomizeFile, getProjectConfigPath, getProjectKbPath, ProjectConfigManager } from './core/project-config.js';
15
15
  export { ProjectRegistry } from './core/project-registry.js';
16
- export { SQLiteVecClient, SQLiteVecVectorStore, type SQLiteVecClientOptions } from './vector/sqlite-vec-store.js';
16
+ export { HNSWVectorStore } from './vector/hnsw-vector-store.js';
17
17
  export { CollectionManager, globalCollectionName, projectCollectionName } from './vector/collection-manager.js';
18
18
  export type { CollectionClient, VectorCollectionInfo, VectorDocument, VectorSearchQuery, VectorSearchResult, VectorStoreInterface } from './vector/types.js';
19
19
  export { VectorIndexer, type VectorIndexResult } from './vector/vector-indexer.js';
package/dist/index.js CHANGED
@@ -4,7 +4,7 @@ export { TextChunker } from './chunking/text-chunker.js';
4
4
  export { FileClassifier } from './classification/classifier.js';
5
5
  export { DedupEngine } from './dedup/dedup-engine.js';
6
6
  export { RelationshipDetector } from './dedup/relationship-detector.js';
7
- export { HashEmbeddingProvider, OpenAICompatibleEmbeddingProvider, createEmbeddingProviderFromEnvironment } from './embedding/embedding-provider.js';
7
+ export { HashEmbeddingProvider, LocalTransformersEmbeddingProvider, OpenAICompatibleEmbeddingProvider, createEmbeddingProviderFromEnvironment } from './embedding/embedding-provider.js';
8
8
  export { ContentExtractor } from './extraction/content-extractor.js';
9
9
  export { CommandExternalExtractor, ExternalExtractorRegistry } from './extraction/external-extractor.js';
10
10
  export { ChangeTracker } from './core/change-tracker.js';
@@ -15,7 +15,7 @@ export { MultiProjectManager } from './core/multi-project-manager.js';
15
15
  export { computeProjectId } from './core/project-id.js';
16
16
  export { ensureProjectCustomizeFile, getProjectConfigPath, getProjectKbPath, ProjectConfigManager } from './core/project-config.js';
17
17
  export { ProjectRegistry } from './core/project-registry.js';
18
- export { SQLiteVecClient, SQLiteVecVectorStore } from './vector/sqlite-vec-store.js';
18
+ export { HNSWVectorStore } from './vector/hnsw-vector-store.js';
19
19
  export { CollectionManager, globalCollectionName, projectCollectionName } from './vector/collection-manager.js';
20
20
  export { VectorIndexer } from './vector/vector-indexer.js';
21
21
  export { FederationSearch } from './search/federation-search.js';
@@ -2,6 +2,7 @@ import type { VectorStoreInterface } from '../vector/types.js';
2
2
  export type SearchScope = 'project' | 'global' | 'all';
3
3
  export interface FederatedSearchItem {
4
4
  id: string;
5
+ rowid?: number;
5
6
  content: string;
6
7
  filePath: string;
7
8
  scope: 'project' | 'global';
@@ -73,6 +73,7 @@ export class FederationSearch {
73
73
  toFederatedItem(result, scope) {
74
74
  return {
75
75
  id: result.document.id,
76
+ rowid: typeof result.document.metadata.sqlite_rowid === 'number' ? result.document.metadata.sqlite_rowid : undefined,
76
77
  content: result.document.content,
77
78
  filePath: String(result.document.metadata.file_path ?? ''),
78
79
  scope,
@@ -0,0 +1,20 @@
1
+ import type { VectorDocument, VectorSearchQuery, VectorSearchResult, VectorStoreInterface } from './types.js';
2
+ export declare class HNSWVectorStore implements VectorStoreInterface {
3
+ readonly collectionName: string;
4
+ private readonly indexPath;
5
+ private readonly dimensions;
6
+ private readonly maxElements;
7
+ private index?;
8
+ private deletedSinceRebuild;
9
+ private readonly documents;
10
+ constructor(collectionName: string, indexPath: string, dimensions?: number, maxElements?: number);
11
+ ensureCollection(): Promise<void>;
12
+ upsert(documents: VectorDocument[]): Promise<void>;
13
+ clearCollection(): Promise<void>;
14
+ deleteByFilePath(filePath: string): Promise<void>;
15
+ needsRebuild(): boolean;
16
+ search(query: VectorSearchQuery): Promise<VectorSearchResult[]>;
17
+ private persist;
18
+ private loadDocuments;
19
+ private metadataPath;
20
+ }
@@ -0,0 +1,107 @@
1
+ import * as fs from 'node:fs';
2
+ import * as path from 'node:path';
3
+ import { createRequire } from 'node:module';
4
+ const require = createRequire(import.meta.url);
5
+ export class HNSWVectorStore {
6
+ collectionName;
7
+ indexPath;
8
+ dimensions;
9
+ maxElements;
10
+ index;
11
+ deletedSinceRebuild = 0;
12
+ documents = new Map();
13
+ constructor(collectionName, indexPath, dimensions = 512, maxElements = 500_000) {
14
+ this.collectionName = collectionName;
15
+ this.indexPath = indexPath;
16
+ this.dimensions = dimensions;
17
+ this.maxElements = maxElements;
18
+ }
19
+ async ensureCollection() {
20
+ if (this.index)
21
+ return;
22
+ fs.mkdirSync(path.dirname(this.indexPath), { recursive: true });
23
+ this.loadDocuments();
24
+ const mod = require('hnswlib-node');
25
+ this.index = new mod.HierarchicalNSW('cosine', this.dimensions);
26
+ if (fs.existsSync(this.indexPath))
27
+ this.index.readIndexSync(this.indexPath, true);
28
+ else
29
+ this.index.initIndex(this.maxElements, 16, 200, 100, true);
30
+ }
31
+ async upsert(documents) {
32
+ await this.ensureCollection();
33
+ for (const document of documents) {
34
+ const rowid = Number(document.metadata.sqlite_rowid);
35
+ if (!Number.isFinite(rowid) || rowid <= 0)
36
+ throw new Error(`HNSW 向量写入缺少有效 sqlite_rowid: ${document.id}`);
37
+ this.index.addPoint(document.embedding, rowid, true);
38
+ this.documents.set(rowid, document);
39
+ }
40
+ this.persist();
41
+ }
42
+ async clearCollection() {
43
+ if (fs.existsSync(this.indexPath))
44
+ fs.rmSync(this.indexPath, { force: true });
45
+ if (fs.existsSync(this.metadataPath()))
46
+ fs.rmSync(this.metadataPath(), { force: true });
47
+ this.documents.clear();
48
+ this.deletedSinceRebuild = 0;
49
+ this.index = undefined;
50
+ await this.ensureCollection();
51
+ }
52
+ async deleteByFilePath(filePath) {
53
+ await this.ensureCollection();
54
+ for (const [rowid, document] of this.documents.entries()) {
55
+ if (document.metadata.file_path === filePath) {
56
+ try {
57
+ this.index.markDelete(rowid);
58
+ this.deletedSinceRebuild += 1;
59
+ }
60
+ catch { /* ignore missing labels */ }
61
+ this.documents.delete(rowid);
62
+ }
63
+ }
64
+ this.persist();
65
+ }
66
+ needsRebuild() {
67
+ const total = this.documents.size + this.deletedSinceRebuild;
68
+ return total >= 1000 && this.deletedSinceRebuild / total > 0.25;
69
+ }
70
+ async search(query) {
71
+ await this.ensureCollection();
72
+ const result = this.index.searchKnn(query.queryEmbedding, query.topK);
73
+ return result.neighbors.flatMap((rowid, index) => {
74
+ const document = this.documents.get(rowid);
75
+ if (!document)
76
+ return [];
77
+ if (typeof query.where?.file_path === 'string' && document.metadata.file_path !== query.where.file_path)
78
+ return [];
79
+ const { embedding: _embedding, ...stored } = document;
80
+ const distance = result.distances[index] ?? 0;
81
+ return [{ collection: this.collectionName, document: stored, score: 1 / (1 + distance) }];
82
+ });
83
+ }
84
+ persist() {
85
+ this.index.writeIndexSync(this.indexPath);
86
+ fs.writeFileSync(this.metadataPath(), JSON.stringify({ deletedSinceRebuild: this.deletedSinceRebuild, documents: [...this.documents.entries()] }), 'utf8');
87
+ }
88
+ loadDocuments() {
89
+ const file = this.metadataPath();
90
+ if (!fs.existsSync(file))
91
+ return;
92
+ try {
93
+ const parsed = JSON.parse(fs.readFileSync(file, 'utf8'));
94
+ const entries = Array.isArray(parsed) ? parsed : parsed.documents ?? [];
95
+ this.deletedSinceRebuild = Array.isArray(parsed) ? 0 : Number(parsed.deletedSinceRebuild ?? 0);
96
+ this.documents.clear();
97
+ for (const [rowid, document] of entries)
98
+ this.documents.set(Number(rowid), document);
99
+ }
100
+ catch {
101
+ this.documents.clear();
102
+ }
103
+ }
104
+ metadataPath() {
105
+ return `${this.indexPath}.documents.json`;
106
+ }
107
+ }
@@ -24,6 +24,8 @@ export interface VectorStoreInterface {
24
24
  ensureCollection(metadata?: Record<string, unknown>): Promise<void>;
25
25
  upsert(documents: VectorDocument[]): Promise<void>;
26
26
  deleteByFilePath(filePath: string): Promise<void>;
27
+ clearCollection?(): Promise<void>;
28
+ needsRebuild?(): boolean;
27
29
  search(query: VectorSearchQuery): Promise<VectorSearchResult[]>;
28
30
  }
29
31
  export interface CollectionClient {
@@ -13,6 +13,8 @@ export declare class VectorIndexer {
13
13
  constructor(embeddingProvider: EmbeddingProvider, vectorStores: Map<string, VectorStoreInterface>);
14
14
  indexChunks(chunks: StoredChunk[]): Promise<VectorIndexResult[]>;
15
15
  deleteFile(collectionName: string, filePath: string): Promise<void>;
16
+ private embedDocuments;
17
+ private isValidEmbeddings;
16
18
  private groupByCollection;
17
19
  private toVectorDocument;
18
20
  private parseMetadata;
@@ -12,11 +12,12 @@ export class VectorIndexer {
12
12
  const store = this.vectorStores.get(collectionName);
13
13
  if (!store)
14
14
  continue;
15
+ const texts = collectionChunks.map(chunk => chunk.content);
16
+ const embeddings = await this.embedDocuments(texts);
15
17
  await store.ensureCollection({
16
18
  embedding_model: this.embeddingProvider.model,
17
19
  embedding_dimension: this.embeddingProvider.dimensions,
18
20
  });
19
- const embeddings = await this.embeddingProvider.embedDocuments(collectionChunks.map(chunk => chunk.content));
20
21
  const documents = collectionChunks.map((chunk, index) => this.toVectorDocument(chunk, embeddings[index] ?? []));
21
22
  await store.upsert(documents);
22
23
  results.push({
@@ -34,6 +35,16 @@ export class VectorIndexer {
34
35
  return;
35
36
  await store.deleteByFilePath(filePath);
36
37
  }
38
+ async embedDocuments(texts) {
39
+ const embeddings = await this.embeddingProvider.embedDocuments(texts);
40
+ if (!this.isValidEmbeddings(embeddings, texts.length, this.embeddingProvider.dimensions)) {
41
+ throw new Error(`Embedding 结果异常:期望 ${texts.length} 条 ${this.embeddingProvider.dimensions} 维向量,实际返回 ${embeddings.length} 条`);
42
+ }
43
+ return embeddings;
44
+ }
45
+ isValidEmbeddings(embeddings, count, dimensions) {
46
+ return embeddings.length === count && embeddings.every(vector => vector.length === dimensions && vector.every(value => Number.isFinite(value)));
47
+ }
37
48
  groupByCollection(chunks) {
38
49
  const grouped = new Map();
39
50
  for (const chunk of chunks) {
@@ -50,6 +61,7 @@ export class VectorIndexer {
50
61
  content: chunk.content,
51
62
  embedding,
52
63
  metadata: {
64
+ sqlite_rowid: chunk.rowid,
53
65
  file_path: chunk.relativePath,
54
66
  chunk_index: chunk.chunkIndex,
55
67
  category: chunk.category,
@@ -0,0 +1,31 @@
1
+ {
2
+ "_name_or_path": "BAAI/bge-small-zh-v1.5",
3
+ "architectures": [
4
+ "BertModel"
5
+ ],
6
+ "attention_probs_dropout_prob": 0.1,
7
+ "classifier_dropout": null,
8
+ "gradient_checkpointing": false,
9
+ "hidden_act": "gelu",
10
+ "hidden_dropout_prob": 0.1,
11
+ "hidden_size": 512,
12
+ "id2label": {
13
+ "0": "LABEL_0"
14
+ },
15
+ "initializer_range": 0.02,
16
+ "intermediate_size": 2048,
17
+ "label2id": {
18
+ "LABEL_0": 0
19
+ },
20
+ "layer_norm_eps": 1e-12,
21
+ "max_position_embeddings": 512,
22
+ "model_type": "bert",
23
+ "num_attention_heads": 8,
24
+ "num_hidden_layers": 4,
25
+ "pad_token_id": 0,
26
+ "position_embedding_type": "absolute",
27
+ "transformers_version": "4.34.0.dev0",
28
+ "type_vocab_size": 2,
29
+ "use_cache": true,
30
+ "vocab_size": 21128
31
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "cls_token": "[CLS]",
3
+ "mask_token": "[MASK]",
4
+ "pad_token": "[PAD]",
5
+ "sep_token": "[SEP]",
6
+ "unk_token": "[UNK]"
7
+ }