@sunub/obsidian-mcp-server 0.3.28 → 0.3.30
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 +214 -72
- package/build/cli/ui/MainContent.d.ts +1 -2
- package/build/cli/ui/MainContent.js.map +1 -1
- package/build/index.js +28 -10
- package/build/index.js.map +1 -1
- package/build/server.d.ts +2 -1
- package/build/server.js +7 -1
- package/build/server.js.map +1 -1
- package/build/tools/index.d.ts +1 -1
- package/build/tools/organize_attachments/utils.d.ts +1 -1
- package/build/tools/organize_attachments/utils.js +1 -1
- package/build/tools/organize_attachments/utils.js.map +1 -1
- package/build/tools/vault/index.d.ts +1 -1
- package/build/tools/vault/params.d.ts +4 -4
- package/build/tools/vault/params.js +3 -3
- package/build/tools/vault/params.js.map +1 -1
- package/build/tools/vault/types/collect_context.d.ts +15 -15
- package/build/tools/vault/types/read_specific.d.ts +46 -46
- package/build/tools/vault/types/read_specific.js +4 -4
- package/build/tools/vault/types/read_specific.js.map +1 -1
- package/build/tools/vault/utils/actions/collect_context.js +15 -10
- package/build/tools/vault/utils/actions/collect_context.js.map +1 -1
- package/build/tools/vault/utils/actions/read.js +48 -12
- package/build/tools/vault/utils/actions/read.js.map +1 -1
- package/build/tools/vault/utils/actions/search.js +7 -3
- package/build/tools/vault/utils/actions/search.js.map +1 -1
- package/build/tools/vault/utils/shared.d.ts +1 -1
- package/build/tools/vault/utils/shared.js +9 -1
- package/build/tools/vault/utils/shared.js.map +1 -1
- package/build/utils/BackgroundTaskRegistry.d.ts +7 -0
- package/build/utils/BackgroundTaskRegistry.js +39 -0
- package/build/utils/BackgroundTaskRegistry.js.map +1 -0
- package/build/utils/Embedder.d.ts +4 -3
- package/build/utils/Embedder.js +20 -8
- package/build/utils/Embedder.js.map +1 -1
- package/build/utils/Indexer.js +36 -14
- package/build/utils/Indexer.js.map +1 -1
- package/build/utils/LocalModelManager.d.ts +45 -0
- package/build/utils/LocalModelManager.js +196 -0
- package/build/utils/LocalModelManager.js.map +1 -0
- package/build/utils/LocalReranker.d.ts +4 -3
- package/build/utils/LocalReranker.js +20 -8
- package/build/utils/LocalReranker.js.map +1 -1
- package/build/utils/RAGIndexer.d.ts +8 -3
- package/build/utils/RAGIndexer.js +61 -34
- package/build/utils/RAGIndexer.js.map +1 -1
- package/build/utils/ServerLifecycle.d.ts +23 -0
- package/build/utils/ServerLifecycle.js +50 -0
- package/build/utils/ServerLifecycle.js.map +1 -0
- package/build/utils/VaultManger/VaultManager.d.ts +2 -1
- package/build/utils/VaultManger/VaultManager.js +87 -60
- package/build/utils/VaultManger/VaultManager.js.map +1 -1
- package/build/utils/VaultWatcher.d.ts +2 -1
- package/build/utils/VaultWatcher.js +3 -6
- package/build/utils/VaultWatcher.js.map +1 -1
- package/build/utils/abort.d.ts +5 -0
- package/build/utils/abort.js +51 -0
- package/build/utils/abort.js.map +1 -0
- package/build/utils/worker/WorkerPool.d.ts +7 -2
- package/build/utils/worker/WorkerPool.js +22 -7
- package/build/utils/worker/WorkerPool.js.map +1 -1
- package/package.json +3 -1
|
@@ -1,17 +1,18 @@
|
|
|
1
|
-
declare class Reranker {
|
|
2
|
-
|
|
1
|
+
export declare class Reranker {
|
|
2
|
+
readonly modelName = "Xenova/bge-reranker-base";
|
|
3
3
|
private tokenizer;
|
|
4
4
|
private model;
|
|
5
5
|
private initPromise;
|
|
6
6
|
constructor();
|
|
7
7
|
checkModelPresence(): Promise<boolean>;
|
|
8
|
+
hasLocalModelFiles(): boolean;
|
|
8
9
|
get isReady(): boolean;
|
|
9
10
|
private loadModel;
|
|
10
11
|
init(): Promise<void>;
|
|
12
|
+
dispose(): Promise<void>;
|
|
11
13
|
rerank(query: string, documents: string[]): Promise<{
|
|
12
14
|
document: string;
|
|
13
15
|
score: number;
|
|
14
16
|
}[]>;
|
|
15
17
|
}
|
|
16
18
|
export declare const localReranker: Reranker;
|
|
17
|
-
export {};
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
1
3
|
import { AutoModelForSequenceClassification, AutoTokenizer, env, } from "@huggingface/transformers";
|
|
2
4
|
import z from "zod";
|
|
3
5
|
import { MODELS_DIR } from "./constants.js";
|
|
@@ -5,7 +7,7 @@ const rerankedResultsSchema = z.array(z.object({
|
|
|
5
7
|
document: z.string(),
|
|
6
8
|
score: z.number(),
|
|
7
9
|
}));
|
|
8
|
-
class Reranker {
|
|
10
|
+
export class Reranker {
|
|
9
11
|
modelName = "Xenova/bge-reranker-base";
|
|
10
12
|
tokenizer = null;
|
|
11
13
|
model = null;
|
|
@@ -16,13 +18,10 @@ class Reranker {
|
|
|
16
18
|
env.cacheDir = MODELS_DIR;
|
|
17
19
|
}
|
|
18
20
|
async checkModelPresence() {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
catch (_e) {
|
|
24
|
-
return false;
|
|
25
|
-
}
|
|
21
|
+
return this.hasLocalModelFiles();
|
|
22
|
+
}
|
|
23
|
+
hasLocalModelFiles() {
|
|
24
|
+
return existsSync(join(MODELS_DIR, this.modelName));
|
|
26
25
|
}
|
|
27
26
|
get isReady() {
|
|
28
27
|
return this.tokenizer !== null && this.model !== null;
|
|
@@ -41,6 +40,19 @@ class Reranker {
|
|
|
41
40
|
}
|
|
42
41
|
return this.initPromise;
|
|
43
42
|
}
|
|
43
|
+
async dispose() {
|
|
44
|
+
if (this.model) {
|
|
45
|
+
try {
|
|
46
|
+
await this.model.dispose();
|
|
47
|
+
}
|
|
48
|
+
catch (e) {
|
|
49
|
+
console.error("Failed to dispose reranker model:", e);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
this.tokenizer = null;
|
|
53
|
+
this.model = null;
|
|
54
|
+
this.initPromise = null;
|
|
55
|
+
}
|
|
44
56
|
async rerank(query, documents) {
|
|
45
57
|
if (!this.isReady) {
|
|
46
58
|
await this.init();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LocalReranker.js","sourceRoot":"","sources":["../../src/utils/LocalReranker.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"LocalReranker.js","sourceRoot":"","sources":["../../src/utils/LocalReranker.ts"],"names":[],"mappings":"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"}
|
|
@@ -24,12 +24,17 @@ export declare class RAGIndexer {
|
|
|
24
24
|
startIndexing(total: number): void;
|
|
25
25
|
stopIndexing(): void;
|
|
26
26
|
private buildFileRecords;
|
|
27
|
-
processFile(filePath: string, content?: string
|
|
28
|
-
|
|
27
|
+
processFile(filePath: string, content?: string, options?: {
|
|
28
|
+
signal?: AbortSignal;
|
|
29
|
+
}): Promise<void>;
|
|
30
|
+
processFileInMemory(filePath: string, content?: string, options?: {
|
|
31
|
+
signal?: AbortSignal;
|
|
32
|
+
}): Promise<{
|
|
29
33
|
records: VectorRecord[];
|
|
30
34
|
mtime: string;
|
|
31
35
|
} | null>;
|
|
32
|
-
indexAll(vaultPath: string): Promise<void>;
|
|
36
|
+
indexAll(vaultPath: string, signal?: AbortSignal): Promise<void>;
|
|
37
|
+
shutdown(): Promise<void>;
|
|
33
38
|
deleteFile(filePath: string): Promise<void>;
|
|
34
39
|
}
|
|
35
40
|
export declare const ragIndexer: RAGIndexer;
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import fs from "node:fs/promises";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import ora, {} from "ora";
|
|
4
|
+
import { throwIfAborted } from "./abort.js";
|
|
4
5
|
import { DirectoryWalker } from "./DirectoryWalker.js";
|
|
5
6
|
import { localEmbedder } from "./Embedder.js";
|
|
7
|
+
import { localModelManager } from "./LocalModelManager.js";
|
|
6
8
|
import { Semaphore } from "./semaphore.js";
|
|
7
9
|
import { vectorDB } from "./VectorDB.js";
|
|
8
10
|
import { WorkerPool } from "./worker/WorkerPool.js";
|
|
@@ -54,46 +56,59 @@ export class RAGIndexer {
|
|
|
54
56
|
stopIndexing() {
|
|
55
57
|
this._isIndexing = false;
|
|
56
58
|
}
|
|
57
|
-
async buildFileRecords(filePath, content) {
|
|
59
|
+
async buildFileRecords(filePath, content, signal) {
|
|
60
|
+
throwIfAborted(signal);
|
|
58
61
|
const fileStat = await fs.stat(filePath);
|
|
59
62
|
const fileContent = content ?? (await fs.readFile(filePath, "utf-8"));
|
|
63
|
+
throwIfAborted(signal);
|
|
60
64
|
const chunkMetadatas = await this.chukingWorkerPool.runTask({
|
|
61
65
|
filePath,
|
|
62
66
|
fileContent,
|
|
63
67
|
birthTime: fileStat.birthtime.toISOString(),
|
|
64
68
|
});
|
|
65
|
-
await
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
metadata.context ? metadata.context : "",
|
|
70
|
-
metadata.content,
|
|
71
|
-
]
|
|
72
|
-
.filter(Boolean)
|
|
73
|
-
.join("\n\n");
|
|
74
|
-
const MAX_EMBED_TOKENS = 500;
|
|
75
|
-
const combinedTokenCount = localEmbedder.getTokenCount(combined);
|
|
76
|
-
const safeText = combinedTokenCount > MAX_EMBED_TOKENS
|
|
77
|
-
? combined.slice(0, Math.floor(combined.length * (MAX_EMBED_TOKENS / combinedTokenCount)))
|
|
78
|
-
: combined;
|
|
79
|
-
await this.embeddingSemaphore.acquire();
|
|
80
|
-
let vector;
|
|
81
|
-
try {
|
|
82
|
-
vector = await localEmbedder.embed(`search_document: ${safeText}`);
|
|
69
|
+
return await localModelManager.withEmbedder(3000, async (isReady) => {
|
|
70
|
+
throwIfAborted(signal);
|
|
71
|
+
if (!isReady) {
|
|
72
|
+
return null;
|
|
83
73
|
}
|
|
84
|
-
|
|
85
|
-
|
|
74
|
+
const records = [];
|
|
75
|
+
for (const metadata of chunkMetadatas) {
|
|
76
|
+
throwIfAborted(signal);
|
|
77
|
+
const combined = [
|
|
78
|
+
metadata.context ? metadata.context : "",
|
|
79
|
+
metadata.content,
|
|
80
|
+
]
|
|
81
|
+
.filter(Boolean)
|
|
82
|
+
.join("\n\n");
|
|
83
|
+
const MAX_EMBED_TOKENS = 500;
|
|
84
|
+
const combinedTokenCount = localEmbedder.getTokenCount(combined);
|
|
85
|
+
const safeText = combinedTokenCount > MAX_EMBED_TOKENS
|
|
86
|
+
? combined.slice(0, Math.floor(combined.length * (MAX_EMBED_TOKENS / combinedTokenCount)))
|
|
87
|
+
: combined;
|
|
88
|
+
await this.embeddingSemaphore.acquire();
|
|
89
|
+
let vector;
|
|
90
|
+
try {
|
|
91
|
+
throwIfAborted(signal);
|
|
92
|
+
vector = await localEmbedder.embed(`search_document: ${safeText}`);
|
|
93
|
+
}
|
|
94
|
+
finally {
|
|
95
|
+
this.embeddingSemaphore.release();
|
|
96
|
+
}
|
|
97
|
+
records.push({
|
|
98
|
+
...metadata,
|
|
99
|
+
vector,
|
|
100
|
+
});
|
|
86
101
|
}
|
|
87
|
-
records.
|
|
88
|
-
|
|
89
|
-
vector,
|
|
90
|
-
});
|
|
91
|
-
}
|
|
92
|
-
return { records, mtime: fileStat.mtime.toISOString() };
|
|
102
|
+
return { records, mtime: fileStat.mtime.toISOString() };
|
|
103
|
+
});
|
|
93
104
|
}
|
|
94
|
-
async processFile(filePath, content) {
|
|
105
|
+
async processFile(filePath, content, options = {}) {
|
|
95
106
|
try {
|
|
96
|
-
const
|
|
107
|
+
const result = await this.buildFileRecords(filePath, content, options.signal);
|
|
108
|
+
if (!result) {
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
const { records, mtime } = result;
|
|
97
112
|
if (records.length > 0) {
|
|
98
113
|
await vectorDB.upsertChunks(records);
|
|
99
114
|
}
|
|
@@ -107,9 +122,9 @@ export class RAGIndexer {
|
|
|
107
122
|
this.updateProgress(filePath);
|
|
108
123
|
}
|
|
109
124
|
}
|
|
110
|
-
async processFileInMemory(filePath, content) {
|
|
125
|
+
async processFileInMemory(filePath, content, options = {}) {
|
|
111
126
|
try {
|
|
112
|
-
return await this.buildFileRecords(filePath, content);
|
|
127
|
+
return await this.buildFileRecords(filePath, content, options.signal);
|
|
113
128
|
}
|
|
114
129
|
catch (error) {
|
|
115
130
|
console.error(`\nError processing file for RAG: ${filePath}`, error);
|
|
@@ -119,10 +134,11 @@ export class RAGIndexer {
|
|
|
119
134
|
this.updateProgress(filePath);
|
|
120
135
|
}
|
|
121
136
|
}
|
|
122
|
-
async indexAll(vaultPath) {
|
|
137
|
+
async indexAll(vaultPath, signal) {
|
|
123
138
|
this._isIndexing = true;
|
|
124
139
|
this.chukingWorkerPool.init();
|
|
125
140
|
try {
|
|
141
|
+
throwIfAborted(signal);
|
|
126
142
|
const walker = new DirectoryWalker();
|
|
127
143
|
const filePaths = await walker.walk(vaultPath, this.ioSemaphore);
|
|
128
144
|
const markdownFiles = filePaths.filter((f) => f.endsWith(".md") || f.endsWith(".mdx"));
|
|
@@ -132,11 +148,14 @@ export class RAGIndexer {
|
|
|
132
148
|
let currentMeta = [];
|
|
133
149
|
const fileSemaphore = new Semaphore(8);
|
|
134
150
|
for (let i = 0; i < markdownFiles.length; i += BATCH_SIZE) {
|
|
151
|
+
throwIfAborted(signal);
|
|
135
152
|
const batchFiles = markdownFiles.slice(i, i + BATCH_SIZE);
|
|
136
153
|
await Promise.all(batchFiles.map(async (filePath) => {
|
|
137
154
|
await fileSemaphore.acquire();
|
|
138
155
|
try {
|
|
139
|
-
const result = await this.processFileInMemory(filePath
|
|
156
|
+
const result = await this.processFileInMemory(filePath, undefined, {
|
|
157
|
+
signal,
|
|
158
|
+
});
|
|
140
159
|
if (result && result.records.length > 0) {
|
|
141
160
|
currentBatch.push(...result.records);
|
|
142
161
|
currentMeta.push({ filePath, mtime: result.mtime });
|
|
@@ -158,8 +177,16 @@ export class RAGIndexer {
|
|
|
158
177
|
}
|
|
159
178
|
finally {
|
|
160
179
|
this._isIndexing = false;
|
|
161
|
-
this.chukingWorkerPool.terminateAll();
|
|
180
|
+
await this.chukingWorkerPool.terminateAll();
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
async shutdown() {
|
|
184
|
+
this._isIndexing = false;
|
|
185
|
+
if (this.spinner) {
|
|
186
|
+
this.spinner.stop();
|
|
187
|
+
this.spinner = null;
|
|
162
188
|
}
|
|
189
|
+
await this.chukingWorkerPool.terminateAll();
|
|
163
190
|
}
|
|
164
191
|
async deleteFile(filePath) {
|
|
165
192
|
await vectorDB.deleteByFilePath(filePath);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RAGIndexer.js","sourceRoot":"","sources":["../../src/utils/RAGIndexer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,GAAG,EAAE,EAAY,MAAM,KAAK,CAAC;AACpC,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAqB,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC5D,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAIpD,MAAM,OAAO,UAAU;IACd,kBAAkB,CAAY;IAC9B,WAAW,CAAY;IACvB,OAAO,GAAe,IAAI,CAAC;IAC3B,UAAU,GAAG,CAAC,CAAC;IACf,cAAc,GAAG,CAAC,CAAC;IACnB,WAAW,GAAG,KAAK,CAAC;IACpB,iBAAiB,GAAG,IAAI,UAAU,CAAC,CAAC,CAAC,CAAC;IAE9C;QACC,IAAI,CAAC,kBAAkB,GAAG,IAAI,SAAS,CAAC,CAAC,CAAC,CAAC;QAC3C,IAAI,CAAC,WAAW,GAAG,IAAI,SAAS,CAAC,EAAE,CAAC,CAAC;IACtC,CAAC;IAEM,UAAU,CAAC,KAAa;QAC9B,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC;QACxB,IAAI,CAAC,cAAc,GAAG,CAAC,CAAC;QACxB,IAAI,CAAC,OAAO,GAAG,GAAG,CAAC;YAClB,IAAI,EAAE,gCAAgC,KAAK,MAAM;YACjD,MAAM,EAAE,OAAO,CAAC,MAAM;SACtB,CAAC,CAAC,KAAK,EAAE,CAAC;IACZ,CAAC;IAEO,cAAc,CAAC,QAAgB;QACtC,IAAI,CAAC,cAAc,EAAE,CAAC;QACtB,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YAClB,IAAI,CAAC,OAAO,CAAC,IAAI,GAAG,IAAI,IAAI,CAAC,cAAc,IAAI,IAAI,CAAC,UAAU,eAAe,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QACxG,CAAC;QACD,IAAI,IAAI,CAAC,cAAc,IAAI,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YAC5D,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,wBAAwB,IAAI,CAAC,UAAU,SAAS,CAAC,CAAC;YACvE,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACrB,CAAC;IACF,CAAC;IAEM,SAAS;QACf,OAAO;YACN,UAAU,EAAE,IAAI,CAAC,WAAW;YAC5B,SAAS,EAAE,IAAI,CAAC,cAAc;YAC9B,KAAK,EAAE,IAAI,CAAC,UAAU;YACtB,QAAQ,EACP,IAAI,CAAC,UAAU,GAAG,CAAC;gBAClB,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,GAAG,CAAC;gBAC3D,CAAC,CAAC,CAAC;SACL,CAAC;IACH,CAAC;IAEM,aAAa,CAAC,KAAa;QACjC,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;QACxB,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC;QACxB,IAAI,CAAC,cAAc,GAAG,CAAC,CAAC;IACzB,CAAC;IAEM,YAAY;QAClB,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC;IAC1B,CAAC;IAEO,KAAK,CAAC,gBAAgB,CAC7B,QAAgB,EAChB,OAAgB;
|
|
1
|
+
{"version":3,"file":"RAGIndexer.js","sourceRoot":"","sources":["../../src/utils/RAGIndexer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,GAAG,EAAE,EAAY,MAAM,KAAK,CAAC;AACpC,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAqB,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC5D,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAIpD,MAAM,OAAO,UAAU;IACd,kBAAkB,CAAY;IAC9B,WAAW,CAAY;IACvB,OAAO,GAAe,IAAI,CAAC;IAC3B,UAAU,GAAG,CAAC,CAAC;IACf,cAAc,GAAG,CAAC,CAAC;IACnB,WAAW,GAAG,KAAK,CAAC;IACpB,iBAAiB,GAAG,IAAI,UAAU,CAAC,CAAC,CAAC,CAAC;IAE9C;QACC,IAAI,CAAC,kBAAkB,GAAG,IAAI,SAAS,CAAC,CAAC,CAAC,CAAC;QAC3C,IAAI,CAAC,WAAW,GAAG,IAAI,SAAS,CAAC,EAAE,CAAC,CAAC;IACtC,CAAC;IAEM,UAAU,CAAC,KAAa;QAC9B,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC;QACxB,IAAI,CAAC,cAAc,GAAG,CAAC,CAAC;QACxB,IAAI,CAAC,OAAO,GAAG,GAAG,CAAC;YAClB,IAAI,EAAE,gCAAgC,KAAK,MAAM;YACjD,MAAM,EAAE,OAAO,CAAC,MAAM;SACtB,CAAC,CAAC,KAAK,EAAE,CAAC;IACZ,CAAC;IAEO,cAAc,CAAC,QAAgB;QACtC,IAAI,CAAC,cAAc,EAAE,CAAC;QACtB,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YAClB,IAAI,CAAC,OAAO,CAAC,IAAI,GAAG,IAAI,IAAI,CAAC,cAAc,IAAI,IAAI,CAAC,UAAU,eAAe,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QACxG,CAAC;QACD,IAAI,IAAI,CAAC,cAAc,IAAI,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YAC5D,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,wBAAwB,IAAI,CAAC,UAAU,SAAS,CAAC,CAAC;YACvE,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACrB,CAAC;IACF,CAAC;IAEM,SAAS;QACf,OAAO;YACN,UAAU,EAAE,IAAI,CAAC,WAAW;YAC5B,SAAS,EAAE,IAAI,CAAC,cAAc;YAC9B,KAAK,EAAE,IAAI,CAAC,UAAU;YACtB,QAAQ,EACP,IAAI,CAAC,UAAU,GAAG,CAAC;gBAClB,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,GAAG,CAAC;gBAC3D,CAAC,CAAC,CAAC;SACL,CAAC;IACH,CAAC;IAEM,aAAa,CAAC,KAAa;QACjC,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;QACxB,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC;QACxB,IAAI,CAAC,cAAc,GAAG,CAAC,CAAC;IACzB,CAAC;IAEM,YAAY;QAClB,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC;IAC1B,CAAC;IAEO,KAAK,CAAC,gBAAgB,CAC7B,QAAgB,EAChB,OAAgB,EAChB,MAAoB;QAEpB,cAAc,CAAC,MAAM,CAAC,CAAC;QACvB,MAAM,QAAQ,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACzC,MAAM,WAAW,GAAG,OAAO,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC;QACtE,cAAc,CAAC,MAAM,CAAC,CAAC;QACvB,MAAM,cAAc,GAAG,MAAM,IAAI,CAAC,iBAAiB,CAAC,OAAO,CAAC;YAC3D,QAAQ;YACR,WAAW;YACX,SAAS,EAAE,QAAQ,CAAC,SAAS,CAAC,WAAW,EAAE;SAC3C,CAAC,CAAC;QAEH,OAAO,MAAM,iBAAiB,CAAC,YAAY,CAAC,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;YACnE,cAAc,CAAC,MAAM,CAAC,CAAC;YACvB,IAAI,CAAC,OAAO,EAAE,CAAC;gBACd,OAAO,IAAI,CAAC;YACb,CAAC;YAED,MAAM,OAAO,GAAmB,EAAE,CAAC;YAEnC,KAAK,MAAM,QAAQ,IAAI,cAAc,EAAE,CAAC;gBACvC,cAAc,CAAC,MAAM,CAAC,CAAC;gBACvB,MAAM,QAAQ,GAAG;oBAChB,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE;oBACxC,QAAQ,CAAC,OAAO;iBAChB;qBACC,MAAM,CAAC,OAAO,CAAC;qBACf,IAAI,CAAC,MAAM,CAAC,CAAC;gBAEf,MAAM,gBAAgB,GAAG,GAAG,CAAC;gBAC7B,MAAM,kBAAkB,GAAG,aAAa,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;gBACjE,MAAM,QAAQ,GACb,kBAAkB,GAAG,gBAAgB;oBACpC,CAAC,CAAC,QAAQ,CAAC,KAAK,CACd,CAAC,EACD,IAAI,CAAC,KAAK,CACT,QAAQ,CAAC,MAAM,GAAG,CAAC,gBAAgB,GAAG,kBAAkB,CAAC,CACzD,CACD;oBACF,CAAC,CAAC,QAAQ,CAAC;gBAEb,MAAM,IAAI,CAAC,kBAAkB,CAAC,OAAO,EAAE,CAAC;gBACxC,IAAI,MAAgB,CAAC;gBACrB,IAAI,CAAC;oBACJ,cAAc,CAAC,MAAM,CAAC,CAAC;oBACvB,MAAM,GAAG,MAAM,aAAa,CAAC,KAAK,CAAC,oBAAoB,QAAQ,EAAE,CAAC,CAAC;gBACpE,CAAC;wBAAS,CAAC;oBACV,IAAI,CAAC,kBAAkB,CAAC,OAAO,EAAE,CAAC;gBACnC,CAAC;gBAED,OAAO,CAAC,IAAI,CAAC;oBACZ,GAAG,QAAQ;oBACX,MAAM;iBACN,CAAC,CAAC;YACJ,CAAC;YAED,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,CAAC,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;QACzD,CAAC,CAAC,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,WAAW,CAChB,QAAgB,EAChB,OAAgB,EAChB,UAAoC,EAAE;QAEtC,IAAI,CAAC;YACJ,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,gBAAgB,CACzC,QAAQ,EACR,OAAO,EACP,OAAO,CAAC,MAAM,CACd,CAAC;YACF,IAAI,CAAC,MAAM,EAAE,CAAC;gBACb,OAAO;YACR,CAAC;YACD,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,MAAM,CAAC;YAClC,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACxB,MAAM,QAAQ,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;YACtC,CAAC;YACD,0CAA0C;YAC1C,MAAM,QAAQ,CAAC,cAAc,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;QAChD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,OAAO,CAAC,KAAK,CAAC,oCAAoC,QAAQ,EAAE,EAAE,KAAK,CAAC,CAAC;QACtE,CAAC;gBAAS,CAAC;YACV,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC;QAC/B,CAAC;IACF,CAAC;IAED,KAAK,CAAC,mBAAmB,CACxB,QAAgB,EAChB,OAAgB,EAChB,UAAoC,EAAE;QAEtC,IAAI,CAAC;YACJ,OAAO,MAAM,IAAI,CAAC,gBAAgB,CAAC,QAAQ,EAAE,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;QACvE,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,OAAO,CAAC,KAAK,CAAC,oCAAoC,QAAQ,EAAE,EAAE,KAAK,CAAC,CAAC;YACrE,OAAO,IAAI,CAAC;QACb,CAAC;gBAAS,CAAC;YACV,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC;QAC/B,CAAC;IACF,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,SAAiB,EAAE,MAAoB;QACrD,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;QACxB,IAAI,CAAC,iBAAiB,CAAC,IAAI,EAAE,CAAC;QAE9B,IAAI,CAAC;YACJ,cAAc,CAAC,MAAM,CAAC,CAAC;YACvB,MAAM,MAAM,GAAG,IAAI,eAAe,EAAE,CAAC;YACrC,MAAM,SAAS,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;YACjE,MAAM,aAAa,GAAG,SAAS,CAAC,MAAM,CACrC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAC9C,CAAC;YAEF,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;YAEtC,MAAM,UAAU,GAAG,EAAE,CAAC,CAAC,2BAA2B;YAClD,IAAI,YAAY,GAAmB,EAAE,CAAC;YACtC,IAAI,WAAW,GAA0C,EAAE,CAAC;YAC5D,MAAM,aAAa,GAAG,IAAI,SAAS,CAAC,CAAC,CAAC,CAAC;YAEvC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,aAAa,CAAC,MAAM,EAAE,CAAC,IAAI,UAAU,EAAE,CAAC;gBAC3D,cAAc,CAAC,MAAM,CAAC,CAAC;gBACvB,MAAM,UAAU,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,UAAU,CAAC,CAAC;gBAE1D,MAAM,OAAO,CAAC,GAAG,CAChB,UAAU,CAAC,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,EAAE;oBACjC,MAAM,aAAa,CAAC,OAAO,EAAE,CAAC;oBAC9B,IAAI,CAAC;wBACJ,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,mBAAmB,CAC5C,QAAQ,EACR,SAAS,EACT;4BACC,MAAM;yBACN,CACD,CAAC;wBACF,IAAI,MAAM,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;4BACzC,YAAY,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC;4BACrC,WAAW,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC;wBACrD,CAAC;oBACF,CAAC;4BAAS,CAAC;wBACV,aAAa,CAAC,OAAO,EAAE,CAAC;oBACzB,CAAC;gBACF,CAAC,CAAC,CACF,CAAC;gBAEF,yBAAyB;gBACzB,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBAC7B,MAAM,QAAQ,CAAC,YAAY,CAAC,YAAY,CAAC,CAAC;oBAC1C,MAAM,QAAQ,CAAC,mBAAmB,CAAC,WAAW,CAAC,CAAC;oBAChD,qBAAqB;oBACrB,YAAY,GAAG,EAAE,CAAC;oBAClB,WAAW,GAAG,EAAE,CAAC;gBAClB,CAAC;YACF,CAAC;QACF,CAAC;gBAAS,CAAC;YACV,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC;YACzB,MAAM,IAAI,CAAC,iBAAiB,CAAC,YAAY,EAAE,CAAC;QAC7C,CAAC;IACF,CAAC;IAED,KAAK,CAAC,QAAQ;QACb,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC;QACzB,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YAClB,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;YACpB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACrB,CAAC;QACD,MAAM,IAAI,CAAC,iBAAiB,CAAC,YAAY,EAAE,CAAC;IAC7C,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,QAAgB;QAChC,MAAM,QAAQ,CAAC,gBAAgB,CAAC,QAAQ,CAAC,CAAC;IAC3C,CAAC;CACD;AAED,MAAM,CAAC,MAAM,UAAU,GAAG,IAAI,UAAU,EAAE,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
type CleanupTask = () => Promise<void> | void;
|
|
2
|
+
type ToolCallModelManager = {
|
|
3
|
+
beginToolCall: () => void;
|
|
4
|
+
endToolCall: () => Promise<void>;
|
|
5
|
+
};
|
|
6
|
+
export interface ServerLifecycleOptions {
|
|
7
|
+
modelManager?: ToolCallModelManager;
|
|
8
|
+
}
|
|
9
|
+
export declare class ServerLifecycle {
|
|
10
|
+
private readonly controller;
|
|
11
|
+
private readonly backgroundTasks;
|
|
12
|
+
private readonly modelManager;
|
|
13
|
+
private readonly cleanups;
|
|
14
|
+
private shutdownPromise;
|
|
15
|
+
constructor(options?: ServerLifecycleOptions);
|
|
16
|
+
get signal(): AbortSignal;
|
|
17
|
+
registerCleanup(name: string, task: CleanupTask): void;
|
|
18
|
+
runBackgroundTask<T>(name: string, task: (signal: AbortSignal) => Promise<T>): Promise<T | undefined>;
|
|
19
|
+
runToolCall<T>(_name: string, task: () => Promise<T>): Promise<T>;
|
|
20
|
+
shutdown(reason: string, timeoutMs?: number): Promise<void>;
|
|
21
|
+
private executeShutdown;
|
|
22
|
+
}
|
|
23
|
+
export {};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { createAbortError, withTimeout } from "./abort.js";
|
|
2
|
+
import { BackgroundTaskRegistry } from "./BackgroundTaskRegistry.js";
|
|
3
|
+
import { localModelManager } from "./LocalModelManager.js";
|
|
4
|
+
export class ServerLifecycle {
|
|
5
|
+
controller = new AbortController();
|
|
6
|
+
backgroundTasks = new BackgroundTaskRegistry();
|
|
7
|
+
modelManager;
|
|
8
|
+
cleanups = [];
|
|
9
|
+
shutdownPromise = null;
|
|
10
|
+
constructor(options = {}) {
|
|
11
|
+
this.modelManager = options.modelManager ?? localModelManager;
|
|
12
|
+
}
|
|
13
|
+
get signal() {
|
|
14
|
+
return this.controller.signal;
|
|
15
|
+
}
|
|
16
|
+
registerCleanup(name, task) {
|
|
17
|
+
this.cleanups.push({ name, task });
|
|
18
|
+
}
|
|
19
|
+
runBackgroundTask(name, task) {
|
|
20
|
+
return this.backgroundTasks.run(name, task);
|
|
21
|
+
}
|
|
22
|
+
async runToolCall(_name, task) {
|
|
23
|
+
this.modelManager.beginToolCall();
|
|
24
|
+
try {
|
|
25
|
+
return await task();
|
|
26
|
+
}
|
|
27
|
+
finally {
|
|
28
|
+
await this.modelManager.endToolCall();
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
shutdown(reason, timeoutMs = 3000) {
|
|
32
|
+
if (this.shutdownPromise) {
|
|
33
|
+
return this.shutdownPromise;
|
|
34
|
+
}
|
|
35
|
+
this.shutdownPromise = this.executeShutdown(reason, timeoutMs);
|
|
36
|
+
return this.shutdownPromise;
|
|
37
|
+
}
|
|
38
|
+
async executeShutdown(reason, timeoutMs) {
|
|
39
|
+
if (!this.controller.signal.aborted) {
|
|
40
|
+
this.controller.abort(createAbortError(reason));
|
|
41
|
+
}
|
|
42
|
+
await this.backgroundTasks.abortAll(reason, timeoutMs);
|
|
43
|
+
const cleanups = [...this.cleanups].reverse();
|
|
44
|
+
this.cleanups.length = 0;
|
|
45
|
+
for (const { task } of cleanups) {
|
|
46
|
+
await withTimeout(Promise.resolve(task()), timeoutMs).catch(() => undefined);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=ServerLifecycle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ServerLifecycle.js","sourceRoot":"","sources":["../../src/utils/ServerLifecycle.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC3D,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAiB3D,MAAM,OAAO,eAAe;IACV,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;IACnC,eAAe,GAAG,IAAI,sBAAsB,EAAE,CAAC;IAC/C,YAAY,CAAuB;IACnC,QAAQ,GAAwB,EAAE,CAAC;IAC5C,eAAe,GAAyB,IAAI,CAAC;IAErD,YAAY,UAAkC,EAAE;QAC/C,IAAI,CAAC,YAAY,GAAG,OAAO,CAAC,YAAY,IAAI,iBAAiB,CAAC;IAC/D,CAAC;IAED,IAAI,MAAM;QACT,OAAO,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC;IAC/B,CAAC;IAED,eAAe,CAAC,IAAY,EAAE,IAAiB;QAC9C,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IACpC,CAAC;IAED,iBAAiB,CAChB,IAAY,EACZ,IAAyC;QAEzC,OAAO,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAC7C,CAAC;IAED,KAAK,CAAC,WAAW,CAAI,KAAa,EAAE,IAAsB;QACzD,IAAI,CAAC,YAAY,CAAC,aAAa,EAAE,CAAC;QAClC,IAAI,CAAC;YACJ,OAAO,MAAM,IAAI,EAAE,CAAC;QACrB,CAAC;gBAAS,CAAC;YACV,MAAM,IAAI,CAAC,YAAY,CAAC,WAAW,EAAE,CAAC;QACvC,CAAC;IACF,CAAC;IAED,QAAQ,CAAC,MAAc,EAAE,SAAS,GAAG,IAAI;QACxC,IAAI,IAAI,CAAC,eAAe,EAAE,CAAC;YAC1B,OAAO,IAAI,CAAC,eAAe,CAAC;QAC7B,CAAC;QAED,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC,eAAe,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;QAC/D,OAAO,IAAI,CAAC,eAAe,CAAC;IAC7B,CAAC;IAEO,KAAK,CAAC,eAAe,CAC5B,MAAc,EACd,SAAiB;QAEjB,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACrC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC,CAAC;QACjD,CAAC;QAED,MAAM,IAAI,CAAC,eAAe,CAAC,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;QAEvD,MAAM,QAAQ,GAAG,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,OAAO,EAAE,CAAC;QAC9C,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC;QACzB,KAAK,MAAM,EAAE,IAAI,EAAE,IAAI,QAAQ,EAAE,CAAC;YACjC,MAAM,WAAW,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,EAAE,SAAS,CAAC,CAAC,KAAK,CAC1D,GAAG,EAAE,CAAC,SAAS,CACf,CAAC;QACH,CAAC;IACF,CAAC;CACD"}
|
|
@@ -25,9 +25,10 @@ export declare class VaultManager {
|
|
|
25
25
|
diagnostic_message?: string;
|
|
26
26
|
}>;
|
|
27
27
|
private safeSemanticSearch;
|
|
28
|
-
syncMissingRagIndices(): Promise<void>;
|
|
28
|
+
syncMissingRagIndices(signal?: AbortSignal): Promise<void>;
|
|
29
29
|
private executeSync;
|
|
30
30
|
upsertDocument(filePath: string): Promise<void>;
|
|
31
|
+
shutdown(): Promise<void>;
|
|
31
32
|
removeDocument(filePath: string): Promise<void>;
|
|
32
33
|
getAllDocuments(): Promise<DocumentIndex[]>;
|
|
33
34
|
searchDocuments(keyword: string): Promise<DocumentIndex[]>;
|
|
@@ -4,9 +4,11 @@ import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
|
4
4
|
import { basename, dirname, extname, isAbsolute, join, relative, resolve, } from "node:path";
|
|
5
5
|
import matter from "gray-matter";
|
|
6
6
|
import { debugLogger } from "../../shared/index.js";
|
|
7
|
+
import { throwIfAborted } from "../abort.js";
|
|
7
8
|
import { DirectoryWalker } from "../DirectoryWalker.js";
|
|
8
9
|
import { localEmbedder } from "../Embedder.js";
|
|
9
10
|
import { Indexer } from "../Indexer.js";
|
|
11
|
+
import { localModelManager } from "../LocalModelManager.js";
|
|
10
12
|
import { localReranker } from "../LocalReranker.js";
|
|
11
13
|
import { ragIndexer } from "../RAGIndexer.js";
|
|
12
14
|
import { Semaphore } from "../semaphore.js";
|
|
@@ -89,6 +91,9 @@ export class VaultManager {
|
|
|
89
91
|
this.indexer.search(query),
|
|
90
92
|
this.safeSemanticSearch(query, limit * 3),
|
|
91
93
|
]);
|
|
94
|
+
const semanticFallbackMessage = semanticResults.length === 0
|
|
95
|
+
? "💡 [검색 품질 안내] 로컬 semantic 모델이 아직 준비 중이거나 사용할 수 없어 이번 검색은 키워드 중심으로 반환했습니다. 잠시 후 다시 검색하면 하이브리드 검색이 적용될 수 있습니다."
|
|
96
|
+
: undefined;
|
|
92
97
|
// 3. RRF (Reciprocal Rank Fusion) 스코어 계산
|
|
93
98
|
const rrfScores = new Map();
|
|
94
99
|
const RRF_K = 60;
|
|
@@ -143,7 +148,7 @@ export class VaultManager {
|
|
|
143
148
|
const dist = chunk["_distance"];
|
|
144
149
|
return typeof dist === "number" && dist < 0.2;
|
|
145
150
|
}));
|
|
146
|
-
if (hasHighlyRelevantMatch) {
|
|
151
|
+
if (hasHighlyRelevantMatch || semanticResults.length === 0) {
|
|
147
152
|
debugLogger.debug(`[RAG] Highly relevant semantic match found. Skipping rerank in hybridSearch.`);
|
|
148
153
|
}
|
|
149
154
|
else {
|
|
@@ -154,20 +159,24 @@ export class VaultManager {
|
|
|
154
159
|
item.document.frontmatter.summary ||
|
|
155
160
|
item.document.filePath);
|
|
156
161
|
});
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
f
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
162
|
+
await localModelManager.withReranker(3000, async (rerankerReady) => {
|
|
163
|
+
if (rerankerReady) {
|
|
164
|
+
const reranked = await localReranker.rerank(query, rerankDocs);
|
|
165
|
+
finalResults = reranked
|
|
166
|
+
.map((r) => {
|
|
167
|
+
const original = fusedResults.find((f) => {
|
|
168
|
+
const content = f.matchedChunks[0]?.content ||
|
|
169
|
+
f.document.frontmatter.summary ||
|
|
170
|
+
f.document.filePath;
|
|
171
|
+
return content === r.document;
|
|
172
|
+
});
|
|
173
|
+
if (!original)
|
|
174
|
+
return null;
|
|
175
|
+
return { ...original, finalScore: r.score };
|
|
176
|
+
})
|
|
177
|
+
.filter((r) => r !== null);
|
|
178
|
+
}
|
|
179
|
+
});
|
|
171
180
|
}
|
|
172
181
|
catch (error) {
|
|
173
182
|
console.error("[VaultManager] Reranking failed:", error);
|
|
@@ -179,6 +188,11 @@ export class VaultManager {
|
|
|
179
188
|
if (ragStatus.isIndexing) {
|
|
180
189
|
diagnostic_message = `⏳ [인덱싱 진행 중] 백그라운드에서 의미 기반 검색 인덱싱이 진행 중입니다 (${ragStatus.progress}% - ${ragStatus.processed}/${ragStatus.total}). 최근 변경된 파일은 검색 결과에 즉시 반영되지 않을 수 있습니다.`;
|
|
181
190
|
}
|
|
191
|
+
if (semanticFallbackMessage) {
|
|
192
|
+
diagnostic_message = diagnostic_message
|
|
193
|
+
? `${diagnostic_message}\n\n${semanticFallbackMessage}`
|
|
194
|
+
: semanticFallbackMessage;
|
|
195
|
+
}
|
|
182
196
|
return {
|
|
183
197
|
results: finalResults.slice(0, limit),
|
|
184
198
|
diagnostic_message,
|
|
@@ -190,42 +204,44 @@ export class VaultManager {
|
|
|
190
204
|
}
|
|
191
205
|
await this.dbSemaphore.acquire();
|
|
192
206
|
try {
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
207
|
+
return await localModelManager.withEmbedder(3000, async (isLocalReady) => {
|
|
208
|
+
if (!isLocalReady) {
|
|
209
|
+
return [];
|
|
210
|
+
}
|
|
211
|
+
const queryVector = await localEmbedder.embed(`search_query: ${query}`);
|
|
212
|
+
const recallLimit = Math.max(limit * 3, 15);
|
|
213
|
+
const initialResults = await vectorDB.search(queryVector, recallLimit);
|
|
214
|
+
if (initialResults.length === 0)
|
|
215
|
+
return [];
|
|
216
|
+
const documents = initialResults.map((r) => r.content);
|
|
217
|
+
// 1차 검색 결과 중 코사인 거리가 극도로 가까운(유사도 0.80 이상) 강력한 매칭인 경우 리랭킹 건너뜀
|
|
218
|
+
const SKIP_RERANK_DISTANCE_THRESHOLD = 0.2;
|
|
219
|
+
const firstDistance = initialResults[0]["_distance"];
|
|
220
|
+
if (typeof firstDistance === "number" &&
|
|
221
|
+
firstDistance < SKIP_RERANK_DISTANCE_THRESHOLD) {
|
|
222
|
+
debugLogger.debug(`[RAG] First semantic match distance is ${firstDistance.toFixed(4)}. Skipping rerank in safeSemanticSearch.`);
|
|
223
|
+
return initialResults.slice(0, limit);
|
|
224
|
+
}
|
|
225
|
+
return await localModelManager.withReranker(3000, async (isRerankerReady) => {
|
|
226
|
+
if (!isRerankerReady) {
|
|
227
|
+
return initialResults.slice(0, limit);
|
|
228
|
+
}
|
|
229
|
+
const reranked = await localReranker.rerank(query, documents);
|
|
230
|
+
const normalizeForComparison = (text) => text
|
|
231
|
+
.replace(/\r\n|\r|\n/g, " ")
|
|
232
|
+
.replace(/\s+/g, " ")
|
|
233
|
+
.trim();
|
|
234
|
+
const finalResults = reranked
|
|
235
|
+
.slice(0, limit)
|
|
236
|
+
.map((r) => {
|
|
237
|
+
const targetNorm = normalizeForComparison(r.document);
|
|
238
|
+
const originalIndex = documents.findIndex((doc) => normalizeForComparison(doc) === targetNorm);
|
|
239
|
+
return initialResults[originalIndex];
|
|
240
|
+
})
|
|
241
|
+
.filter((r) => r !== undefined);
|
|
242
|
+
return finalResults;
|
|
243
|
+
});
|
|
244
|
+
});
|
|
229
245
|
}
|
|
230
246
|
catch (_error) {
|
|
231
247
|
return [];
|
|
@@ -234,26 +250,29 @@ export class VaultManager {
|
|
|
234
250
|
this.dbSemaphore.release();
|
|
235
251
|
}
|
|
236
252
|
}
|
|
237
|
-
async syncMissingRagIndices() {
|
|
253
|
+
async syncMissingRagIndices(signal) {
|
|
254
|
+
throwIfAborted(signal);
|
|
238
255
|
// 로컬 모델이 있는 경우 우선적으로 사용
|
|
239
256
|
if (this.isLocalAIReady) {
|
|
240
|
-
await this.executeSync();
|
|
257
|
+
await this.executeSync(signal);
|
|
241
258
|
return;
|
|
242
259
|
}
|
|
243
260
|
const isLocalReady = await localEmbedder.checkModelPresence();
|
|
244
261
|
if (isLocalReady) {
|
|
245
|
-
await this.executeSync();
|
|
262
|
+
await this.executeSync(signal);
|
|
246
263
|
}
|
|
247
264
|
else {
|
|
248
265
|
// 아무것도 없으면 조용히 종료 (로그는 이미 index.ts에서 나옴)
|
|
249
266
|
return;
|
|
250
267
|
}
|
|
251
268
|
}
|
|
252
|
-
async executeSync() {
|
|
269
|
+
async executeSync(signal) {
|
|
270
|
+
throwIfAborted(signal);
|
|
253
271
|
const allDocs = await this.getAllDocuments();
|
|
254
272
|
const forceReindex = await vectorDB.checkAndMigrateIfNeeded();
|
|
255
273
|
const filesToProcess = [];
|
|
256
274
|
for (const doc of allDocs) {
|
|
275
|
+
throwIfAborted(signal);
|
|
257
276
|
if (forceReindex) {
|
|
258
277
|
filesToProcess.push(doc.filePath);
|
|
259
278
|
}
|
|
@@ -277,7 +296,8 @@ export class VaultManager {
|
|
|
277
296
|
await this.dbSemaphore.acquire();
|
|
278
297
|
try {
|
|
279
298
|
for (const filePath of filesToProcess) {
|
|
280
|
-
|
|
299
|
+
throwIfAborted(signal);
|
|
300
|
+
await ragIndexer.processFile(filePath, undefined, { signal });
|
|
281
301
|
}
|
|
282
302
|
await vectorDB.createVectorIndex();
|
|
283
303
|
}
|
|
@@ -289,11 +309,10 @@ export class VaultManager {
|
|
|
289
309
|
}
|
|
290
310
|
async upsertDocument(filePath) {
|
|
291
311
|
await this.indexer.upsertFile(filePath, this.ioSemaphore);
|
|
292
|
-
if (!this.isLocalAIReady) {
|
|
312
|
+
if (!this.isLocalAIReady || !localModelManager.isEmbedderReady) {
|
|
293
313
|
return;
|
|
294
314
|
}
|
|
295
|
-
|
|
296
|
-
if (isLocalReady) {
|
|
315
|
+
if (localModelManager.isEmbedderReady) {
|
|
297
316
|
await this.dbSemaphore.acquire();
|
|
298
317
|
try {
|
|
299
318
|
await ragIndexer.processFile(filePath);
|
|
@@ -309,6 +328,9 @@ export class VaultManager {
|
|
|
309
328
|
console.error(`[VaultManager] Embedding server is down. Skipping RAG index for: ${filePath}`);
|
|
310
329
|
}
|
|
311
330
|
}
|
|
331
|
+
async shutdown() {
|
|
332
|
+
await ragIndexer.shutdown();
|
|
333
|
+
}
|
|
312
334
|
async removeDocument(filePath) {
|
|
313
335
|
this.indexer.removeFileEntries(filePath);
|
|
314
336
|
await this.dbSemaphore.acquire();
|
|
@@ -449,9 +471,14 @@ export class VaultManager {
|
|
|
449
471
|
filename.replace(/\.mdx?$/, ""),
|
|
450
472
|
basename(filename, extname(filename)),
|
|
451
473
|
];
|
|
474
|
+
const normalizeForMatch = (str) => str.toLowerCase().replace(/[\s_-]/g, "");
|
|
452
475
|
for (const term of searchTerms) {
|
|
476
|
+
const normalizedTerm = normalizeForMatch(term);
|
|
453
477
|
const searchResults = this.indexer.search(term);
|
|
454
|
-
const foundDoc = searchResults.find((doc) =>
|
|
478
|
+
const foundDoc = searchResults.find((doc) => {
|
|
479
|
+
const fileBase = basename(doc.filePath, extname(doc.filePath));
|
|
480
|
+
return normalizeForMatch(fileBase) === normalizedTerm;
|
|
481
|
+
});
|
|
455
482
|
if (foundDoc) {
|
|
456
483
|
return foundDoc.filePath;
|
|
457
484
|
}
|