@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
@@ -56,11 +56,64 @@ export class IndexStateStore {
56
56
  `).all();
57
57
  return rows.map(row => this.rowToRecord(row));
58
58
  }
59
+ enqueueIndexJob(job) {
60
+ const now = Date.now();
61
+ this.db.prepare(`
62
+ INSERT INTO kb_index_jobs (id, relative_path, status, percent, message, created_at, updated_at)
63
+ VALUES (?, ?, 'PENDING', 0, ?, ?, ?)
64
+ ON CONFLICT(id) DO UPDATE SET status = 'PENDING', percent = 0, message = excluded.message, error_message = NULL, updated_at = excluded.updated_at
65
+ `).run(job.id, job.relativePath, job.message ?? '等待后台索引', now, now);
66
+ return this.getIndexJob(job.id);
67
+ }
68
+ updateIndexJob(id, patch) {
69
+ const current = this.getIndexJob(id);
70
+ if (!current)
71
+ return;
72
+ this.db.prepare(`
73
+ UPDATE kb_index_jobs
74
+ SET status = ?, percent = ?, message = ?, error_message = ?, updated_at = ?
75
+ WHERE id = ?
76
+ `).run(patch.status ?? current.status, patch.percent ?? current.percent, patch.message ?? current.message, patch.errorMessage ?? null, Date.now(), id);
77
+ }
78
+ getIndexJob(id) {
79
+ const row = this.db.prepare('SELECT * FROM kb_index_jobs WHERE id = ?').get(id);
80
+ return row ? this.rowToJob(row) : undefined;
81
+ }
82
+ listPendingIndexJobs(limit = 20) {
83
+ const rows = this.db.prepare(`
84
+ SELECT * FROM kb_index_jobs
85
+ WHERE status = 'PENDING'
86
+ ORDER BY created_at ASC
87
+ LIMIT ?
88
+ `).all(limit);
89
+ return rows.map(row => this.rowToJob(row));
90
+ }
91
+ countPendingIndexJobs() {
92
+ const row = this.db.prepare("SELECT COUNT(*) as count FROM kb_index_jobs WHERE status = 'PENDING'").get();
93
+ return Number(row?.count ?? 0);
94
+ }
95
+ listActiveIndexJobsByPath(relativePath) {
96
+ const rows = this.db.prepare(`
97
+ SELECT * FROM kb_index_jobs
98
+ WHERE relative_path = ? AND status IN ('PENDING', 'PARSING', 'CHUNKING', 'INDEXING')
99
+ ORDER BY created_at ASC
100
+ `).all(relativePath);
101
+ return rows.map(row => this.rowToJob(row));
102
+ }
103
+ listIndexJobsByPrefix(prefix) {
104
+ const rows = this.db.prepare(`
105
+ SELECT * FROM kb_index_jobs
106
+ WHERE id LIKE ?
107
+ ORDER BY created_at ASC
108
+ `).all(`${prefix}%`);
109
+ return rows.map(row => this.rowToJob(row));
110
+ }
59
111
  replaceChunks(relativePath, chunks, file) {
60
112
  const now = Date.now();
61
113
  const transaction = this.db.transaction(() => {
62
114
  this.db.prepare('DELETE FROM kb_chunks WHERE relative_path = ?').run(relativePath);
63
115
  this.db.prepare('DELETE FROM kb_parent_chunks WHERE relative_path = ?').run(relativePath);
116
+ this.db.prepare('DELETE FROM kb_document_chunks WHERE relative_path = ?').run(relativePath);
64
117
  if (this.ftsEnabled)
65
118
  this.db.prepare('DELETE FROM kb_chunks_fts WHERE relative_path = ?').run(relativePath);
66
119
  const insert = this.db.prepare(`
@@ -78,6 +131,12 @@ export class IndexStateStore {
78
131
  id, relative_path, parent_id, content, category, format,
79
132
  collection_name, section_title, chunk_count, metadata_json, created_at
80
133
  ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
134
+ `);
135
+ const insertDocument = this.db.prepare(`
136
+ INSERT INTO kb_document_chunks (
137
+ id, relative_path, content, category, format,
138
+ collection_name, parent_count, chunk_count, metadata_json, created_at
139
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
81
140
  `);
82
141
  const parentGroups = new Map();
83
142
  const groupedChunks = this.splitParentGroups(relativePath, chunks);
@@ -87,9 +146,13 @@ export class IndexStateStore {
87
146
  group.push(chunk);
88
147
  parentGroups.set(parentId, group);
89
148
  }
149
+ const parentContents = [];
90
150
  for (const [parentId, group] of parentGroups.entries()) {
91
- insertParent.run(parentId, relativePath, parentId, group.map(chunk => chunk.text).join('\n\n---\n\n'), file.category, file.format, file.collectionName, group.find(chunk => chunk.sectionTitle)?.sectionTitle ?? null, group.length, JSON.stringify({ parentId, splitStrategy: this.metadataString(group[0]?.metadata.splitStrategy), chunkKind: this.metadataString(group[0]?.metadata.chunkKind) }), now);
151
+ const parentContent = group.map(chunk => chunk.text).join('\n\n---\n\n');
152
+ parentContents.push(parentContent);
153
+ insertParent.run(parentId, relativePath, parentId, parentContent, file.category, file.format, file.collectionName, group.find(chunk => chunk.sectionTitle)?.sectionTitle ?? null, group.length, JSON.stringify({ parentId, splitStrategy: this.metadataString(group[0]?.metadata.splitStrategy), chunkKind: this.metadataString(group[0]?.metadata.chunkKind) }), now);
92
154
  }
155
+ insertDocument.run(`${relativePath}#document`, relativePath, parentContents.join('\n\n=== SECTION ===\n\n'), file.category, file.format, file.collectionName, parentGroups.size, groupedChunks.length, JSON.stringify({ parentType: 'document', splitStrategy: 'document_section_child_v1' }), now);
93
156
  for (const chunk of groupedChunks) {
94
157
  const chunkId = `${relativePath}#${chunk.index}`;
95
158
  insert.run(chunkId, relativePath, chunk.index, chunk.text, file.category, file.format, file.collectionName, chunk.tokenCount, chunk.sectionTitle ?? null, JSON.stringify(chunk.metadata), now);
@@ -114,16 +177,28 @@ export class IndexStateStore {
114
177
  if (options.limit)
115
178
  params.push(options.limit);
116
179
  const rows = this.db.prepare(`
117
- SELECT * FROM kb_chunks
180
+ SELECT rowid, * FROM kb_chunks
118
181
  ${where}
119
182
  ORDER BY relative_path, chunk_index
120
183
  ${limit}
121
184
  `).all(...params);
122
185
  return rows.map(row => this.rowToChunk(row, 0));
123
186
  }
187
+ getChunkByRowid(rowid) {
188
+ const row = this.db.prepare('SELECT rowid, * FROM kb_chunks WHERE rowid = ?').get(rowid);
189
+ return row ? this.rowToChunk(row, 0) : undefined;
190
+ }
191
+ getChunksByRowids(rowids) {
192
+ if (rowids.length === 0)
193
+ return [];
194
+ const placeholders = rowids.map(() => '?').join(',');
195
+ const rows = this.db.prepare(`SELECT rowid, * FROM kb_chunks WHERE rowid IN (${placeholders})`).all(...rowids);
196
+ const byRowid = new Map(rows.map(row => [Number(row.rowid), this.rowToChunk(row, 0)]));
197
+ return rowids.flatMap(rowid => byRowid.get(rowid) ?? []);
198
+ }
124
199
  getContextChunks(relativePath, chunkIndex, window = 1) {
125
200
  const rows = this.db.prepare(`
126
- SELECT * FROM kb_chunks
201
+ SELECT rowid, * FROM kb_chunks
127
202
  WHERE relative_path = ? AND chunk_index BETWEEN ? AND ?
128
203
  ORDER BY chunk_index
129
204
  `).all(relativePath, Math.max(0, chunkIndex - window), chunkIndex + window);
@@ -145,9 +220,17 @@ export class IndexStateStore {
145
220
  `).get(relativePath, parentId);
146
221
  return row ? this.rowToParentChunk(row) : undefined;
147
222
  }
223
+ getDocumentChunk(relativePath) {
224
+ const row = this.db.prepare(`
225
+ SELECT * FROM kb_document_chunks
226
+ WHERE relative_path = ?
227
+ LIMIT 1
228
+ `).get(relativePath);
229
+ return row ? this.rowToDocumentChunk(row) : undefined;
230
+ }
148
231
  getChunksByParent(relativePath, parentId, limit = 6) {
149
232
  const rows = this.db.prepare(`
150
- SELECT * FROM kb_chunks
233
+ SELECT rowid, * FROM kb_chunks
151
234
  WHERE relative_path = ? AND metadata_json LIKE ?
152
235
  ORDER BY chunk_index
153
236
  LIMIT ?
@@ -158,12 +241,11 @@ export class IndexStateStore {
158
241
  const terms = this.expandSearchTerms(query);
159
242
  if (terms.length === 0)
160
243
  return [];
161
- if (this.ftsEnabled) {
162
- const ftsResults = this.searchChunksFts(terms, limit);
163
- if (ftsResults.length > 0)
164
- return ftsResults;
165
- }
166
- return this.searchChunksLike(terms, limit);
244
+ const results = [
245
+ ...(this.ftsEnabled ? this.searchChunksFts(terms, limit) : []),
246
+ ...this.searchChunksLike(terms, limit),
247
+ ];
248
+ return this.mergeKeywordResults(results, limit);
167
249
  }
168
250
  searchChunksFts(terms, limit) {
169
251
  try {
@@ -171,7 +253,7 @@ export class IndexStateStore {
171
253
  if (!matchQuery)
172
254
  return [];
173
255
  const rows = this.db.prepare(`
174
- SELECT c.*, bm25(kb_chunks_fts, 1.2, 0.8, 0.6, 1.0, 2.0) as bm25_score
256
+ SELECT c.rowid, c.*, bm25(kb_chunks_fts, 1.2, 0.8, 0.6, 1.0, 2.0) as bm25_score
175
257
  FROM kb_chunks_fts
176
258
  INNER JOIN kb_chunks c ON c.id = kb_chunks_fts.id
177
259
  WHERE kb_chunks_fts MATCH ?
@@ -194,7 +276,7 @@ export class IndexStateStore {
194
276
  }
195
277
  searchChunksLike(terms, limit) {
196
278
  const rows = this.db.prepare(`
197
- SELECT * FROM kb_chunks
279
+ SELECT rowid, * FROM kb_chunks
198
280
  WHERE ${terms.map(() => '(LOWER(content) LIKE ? OR LOWER(relative_path) LIKE ? OR LOWER(category) LIKE ? OR LOWER(format) LIKE ?)').join(' OR ')}
199
281
  ORDER BY created_at DESC
200
282
  LIMIT ?
@@ -331,6 +413,7 @@ export class IndexStateStore {
331
413
  deleteRecord(relativePath) {
332
414
  this.db.prepare('DELETE FROM kb_chunks WHERE relative_path = ?').run(relativePath);
333
415
  this.db.prepare('DELETE FROM kb_parent_chunks WHERE relative_path = ?').run(relativePath);
416
+ this.db.prepare('DELETE FROM kb_document_chunks WHERE relative_path = ?').run(relativePath);
334
417
  if (this.ftsEnabled)
335
418
  this.db.prepare('DELETE FROM kb_chunks_fts WHERE relative_path = ?').run(relativePath);
336
419
  this.db.prepare('DELETE FROM kb_index_state WHERE relative_path = ?').run(relativePath);
@@ -398,7 +481,8 @@ export class IndexStateStore {
398
481
  CREATE INDEX IF NOT EXISTS idx_kb_state_collection ON kb_index_state(collection_name);
399
482
 
400
483
  CREATE TABLE IF NOT EXISTS kb_chunks (
401
- id TEXT PRIMARY KEY,
484
+ rowid INTEGER PRIMARY KEY AUTOINCREMENT,
485
+ id TEXT NOT NULL UNIQUE,
402
486
  relative_path TEXT NOT NULL,
403
487
  chunk_index INTEGER NOT NULL,
404
488
  content TEXT NOT NULL,
@@ -430,6 +514,20 @@ export class IndexStateStore {
430
514
  CREATE INDEX IF NOT EXISTS idx_kb_parent_path ON kb_parent_chunks(relative_path);
431
515
  CREATE INDEX IF NOT EXISTS idx_kb_parent_id ON kb_parent_chunks(parent_id);
432
516
 
517
+ CREATE TABLE IF NOT EXISTS kb_document_chunks (
518
+ id TEXT PRIMARY KEY,
519
+ relative_path TEXT NOT NULL,
520
+ content TEXT NOT NULL,
521
+ category TEXT NOT NULL,
522
+ format TEXT NOT NULL,
523
+ collection_name TEXT NOT NULL,
524
+ parent_count INTEGER NOT NULL,
525
+ chunk_count INTEGER NOT NULL,
526
+ metadata_json TEXT,
527
+ created_at INTEGER NOT NULL
528
+ );
529
+ CREATE INDEX IF NOT EXISTS idx_kb_document_path ON kb_document_chunks(relative_path);
530
+
433
531
  CREATE TABLE IF NOT EXISTS kb_file_hashes (
434
532
  content_hash TEXT NOT NULL,
435
533
  file_path TEXT PRIMARY KEY,
@@ -481,6 +579,19 @@ export class IndexStateStore {
481
579
  );
482
580
  CREATE INDEX IF NOT EXISTS idx_tags_tag ON kb_tags(tag);
483
581
 
582
+ CREATE TABLE IF NOT EXISTS kb_index_jobs (
583
+ id TEXT PRIMARY KEY,
584
+ relative_path TEXT NOT NULL,
585
+ status TEXT NOT NULL,
586
+ percent INTEGER NOT NULL DEFAULT 0,
587
+ message TEXT NOT NULL DEFAULT '',
588
+ error_message TEXT,
589
+ created_at INTEGER NOT NULL,
590
+ updated_at INTEGER NOT NULL
591
+ );
592
+ CREATE INDEX IF NOT EXISTS idx_kb_jobs_status ON kb_index_jobs(status);
593
+ CREATE INDEX IF NOT EXISTS idx_kb_jobs_path ON kb_index_jobs(relative_path);
594
+
484
595
  CREATE TABLE IF NOT EXISTS kb_metadata (
485
596
  key TEXT PRIMARY KEY,
486
597
  value TEXT NOT NULL
@@ -575,7 +686,7 @@ export class IndexStateStore {
575
686
  relativePath: String(row.relative_path),
576
687
  parentId: String(row.parent_id),
577
688
  content: String(row.content),
578
- category: String(row.category),
689
+ category: row.category,
579
690
  format: String(row.format),
580
691
  collectionName: String(row.collection_name),
581
692
  sectionTitle: row.section_title == null ? undefined : String(row.section_title),
@@ -584,45 +695,41 @@ export class IndexStateStore {
584
695
  createdAt: Number(row.created_at),
585
696
  };
586
697
  }
587
- splitParentGroups(relativePath, chunks) {
588
- const maxChildrenPerParent = 12;
589
- const maxTokensPerParent = 4_000;
590
- const grouped = new Map();
591
- for (const chunk of chunks) {
592
- const parentId = this.metadataString(chunk.metadata.parentId) ?? `${relativePath}#parent-${chunk.index}`;
593
- const list = grouped.get(parentId) ?? [];
594
- list.push(chunk);
595
- grouped.set(parentId, list);
596
- }
597
- const result = [];
598
- for (const [parentId, list] of grouped.entries()) {
599
- let batch = [];
600
- let tokenCount = 0;
601
- let batchIndex = 0;
602
- const flush = () => {
603
- if (batch.length === 0)
604
- return;
605
- const nextParentId = list.length <= maxChildrenPerParent && tokenCount <= maxTokensPerParent ? parentId : `${parentId}@${batchIndex + 1}`;
606
- result.push(...batch.map(chunk => ({ ...chunk, metadata: { ...chunk.metadata, parentId: nextParentId, parentGroupIndex: batchIndex } })));
607
- batch = [];
608
- tokenCount = 0;
609
- batchIndex += 1;
610
- };
611
- for (const chunk of list) {
612
- if (batch.length > 0 && (batch.length >= maxChildrenPerParent || tokenCount + chunk.tokenCount > maxTokensPerParent))
613
- flush();
614
- batch.push(chunk);
615
- tokenCount += chunk.tokenCount;
616
- }
617
- flush();
618
- }
619
- return result.sort((a, b) => a.index - b.index);
698
+ rowToDocumentChunk(row) {
699
+ return {
700
+ id: String(row.id),
701
+ relativePath: String(row.relative_path),
702
+ content: String(row.content),
703
+ category: row.category,
704
+ format: String(row.format),
705
+ collectionName: String(row.collection_name),
706
+ parentCount: Number(row.parent_count),
707
+ chunkCount: Number(row.chunk_count),
708
+ metadataJson: row.metadata_json == null ? undefined : String(row.metadata_json),
709
+ createdAt: Number(row.created_at),
710
+ };
711
+ }
712
+ splitParentGroups(_relativePath, chunks) {
713
+ return chunks;
714
+ }
715
+ rowToJob(row) {
716
+ return {
717
+ id: String(row.id),
718
+ relativePath: String(row.relative_path),
719
+ status: String(row.status),
720
+ percent: Number(row.percent),
721
+ message: String(row.message ?? ''),
722
+ errorMessage: row.error_message == null ? undefined : String(row.error_message),
723
+ createdAt: Number(row.created_at),
724
+ updatedAt: Number(row.updated_at),
725
+ };
620
726
  }
621
727
  metadataString(value) {
622
728
  return typeof value === 'string' ? value : undefined;
623
729
  }
624
730
  rowToChunk(row, score, scoreDetails) {
625
731
  return {
732
+ rowid: Number(row.rowid ?? 0),
626
733
  id: String(row.id),
627
734
  relativePath: String(row.relative_path),
628
735
  chunkIndex: Number(row.chunk_index),
@@ -641,8 +748,13 @@ export class IndexStateStore {
641
748
  expandSearchTerms(query) {
642
749
  const normalized = query.toLowerCase().trim();
643
750
  const terms = new Set(normalized ? [normalized] : []);
644
- for (const term of normalized.split(/[\s,,。;;::、]+/u).filter(Boolean))
751
+ for (const term of normalized.split(/[\s,,。;;::、]+/u).filter(Boolean)) {
645
752
  terms.add(term);
753
+ for (const gram of this.chineseNgrams(term))
754
+ terms.add(gram);
755
+ }
756
+ for (const gram of this.chineseNgrams(normalized))
757
+ terms.add(gram);
646
758
  const synonyms = {
647
759
  招标: ['招标', '投标', '标书', '招标文件', '投标文件', 'bid', 'tender', 'bidding'],
648
760
  投标: ['招标', '投标', '标书', '招标文件', '投标文件', 'bid', 'tender', 'bidding'],
@@ -656,7 +768,7 @@ export class IndexStateStore {
656
768
  for (const value of values)
657
769
  terms.add(value.toLowerCase());
658
770
  }
659
- return [...terms];
771
+ return [...terms].filter(term => term.length > 0).slice(0, 40);
660
772
  }
661
773
  toFtsQuery(terms) {
662
774
  const normalized = terms.map(term => term.replace(/["*^:(){}\]\\[]/gu, ' ').trim()).filter(term => term.length > 0);
@@ -664,10 +776,32 @@ export class IndexStateStore {
664
776
  const weak = normalized.slice(1).filter(term => term.length >= 2).slice(0, 12);
665
777
  return [exact ? `"${exact}"` : '', ...weak.map(term => `"${term}"`)].filter(Boolean).join(' OR ');
666
778
  }
779
+ mergeKeywordResults(results, limit) {
780
+ const byId = new Map();
781
+ for (const result of results) {
782
+ const existing = byId.get(result.id);
783
+ if (!existing || result.score > existing.score)
784
+ byId.set(result.id, result);
785
+ }
786
+ return [...byId.values()].sort((a, b) => b.score - a.score).slice(0, limit);
787
+ }
788
+ chineseNgrams(text) {
789
+ const han = text.match(/[\p{Script=Han}]+/gu) ?? [];
790
+ const grams = [];
791
+ for (const token of han) {
792
+ for (let size = 2; size <= 3; size++) {
793
+ if (token.length <= size)
794
+ continue;
795
+ for (let index = 0; index <= token.length - size; index++)
796
+ grams.push(token.slice(index, index + size));
797
+ }
798
+ }
799
+ return grams;
800
+ }
667
801
  bm25ToPositiveScore(score) {
668
802
  if (!Number.isFinite(score))
669
803
  return 0;
670
- return 1 / (1 + Math.max(0, score));
804
+ return score < 0 ? -score : 1 / (1 + score);
671
805
  }
672
806
  scoreChunkDetailed(content, terms) {
673
807
  const lower = content.toLowerCase();
@@ -34,7 +34,7 @@ export declare class KnowledgeBaseManager {
34
34
  readonly projectId?: string;
35
35
  readonly kbPath: string;
36
36
  readonly store: IndexStateStore;
37
- private readonly sqliteVecClient;
37
+ private readonly vectorRoot;
38
38
  private readonly classifier;
39
39
  private readonly scanner;
40
40
  private readonly collections;
@@ -51,9 +51,19 @@ export declare class KnowledgeBaseManager {
51
51
  private onProgress?;
52
52
  constructor(options: KnowledgeBaseManagerOptions);
53
53
  initialize(): void;
54
+ forceReindexAll(options?: {
55
+ onProgress?: (progress: KnowledgeIndexProgress) => void;
56
+ vectorMode?: 'sync' | 'defer';
57
+ }): Promise<DiffResult>;
58
+ consumePendingIndexJobs(options?: {
59
+ onProgress?: (progress: KnowledgeIndexProgress) => void;
60
+ vectorMode?: 'sync' | 'defer';
61
+ limit?: number;
62
+ }): Promise<DiffResult>;
54
63
  incrementalIndex(options?: {
55
64
  onProgress?: (progress: KnowledgeIndexProgress) => void;
56
65
  vectorMode?: 'sync' | 'defer';
66
+ onlyRelativePaths?: string[];
57
67
  }): Promise<DiffResult>;
58
68
  search(query: string, limit?: number): ChunkSearchResult[];
59
69
  keywordSearchItems(query: string, limit?: number): FederatedSearchItem[];
@@ -90,6 +100,11 @@ export declare class KnowledgeBaseManager {
90
100
  uploadFile(fileName: string, content: Buffer, targetRelativePath?: string, onProgress?: (progress: KnowledgeIndexProgress) => void, options?: {
91
101
  vectorMode?: 'sync' | 'defer';
92
102
  }): Promise<DiffResult>;
103
+ stageUploadedFiles(files: Array<{
104
+ fileName: string;
105
+ content: Buffer;
106
+ targetRelativePath?: string;
107
+ }>, operationId?: string): Promise<import("./index-state-store.js").KnowledgeIndexJob[]>;
93
108
  uploadFiles(files: Array<{
94
109
  fileName: string;
95
110
  content: Buffer;
@@ -119,6 +134,9 @@ export declare class KnowledgeBaseManager {
119
134
  }): Promise<VectorIndexResult[]>;
120
135
  getProjectConfig(): ProjectConfig | undefined;
121
136
  getStats(): KnowledgeBaseStats;
137
+ listIndexJobsByPrefix(prefix: string): import("./index-state-store.js").KnowledgeIndexJob[];
138
+ countPendingIndexJobs(): number;
139
+ failPendingIndexJobs(message: string): void;
122
140
  getVectorStatus(): {
123
141
  status: string;
124
142
  error?: string;
@@ -131,8 +149,11 @@ export declare class KnowledgeBaseManager {
131
149
  private retrievalWeights;
132
150
  private heuristicRerank;
133
151
  private llmRerank;
152
+ private hydrateVectorResultsFromSqlite;
134
153
  private toFederatedItem;
135
- private mergeHybridItems;
154
+ private mergeHybridRankedLists;
155
+ private mergeContexts;
156
+ private contextKey;
136
157
  private parseChunkIndex;
137
158
  private parseMetadataString;
138
159
  private parseMetadata;
@@ -140,6 +161,7 @@ export declare class KnowledgeBaseManager {
140
161
  private metadataFacets;
141
162
  close(): void;
142
163
  private reportProgress;
164
+ private updateJobsForFile;
143
165
  private ensureVectorStore;
144
166
  private deleteVectorFile;
145
167
  private ensureVectorIndexFresh;