@hayhandsome/code-index-mcp 0.1.0
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/LICENSE +21 -0
- package/README.md +98 -0
- package/dist/cache/CacheManager.d.ts +19 -0
- package/dist/cache/CacheManager.js +51 -0
- package/dist/cache/CacheManager.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +13 -0
- package/dist/cli.js.map +1 -0
- package/dist/config/loader.d.ts +4 -0
- package/dist/config/loader.js +159 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/config/types.d.ts +41 -0
- package/dist/config/types.js +13 -0
- package/dist/config/types.js.map +1 -0
- package/dist/embedders/factory.d.ts +3 -0
- package/dist/embedders/factory.js +16 -0
- package/dist/embedders/factory.js.map +1 -0
- package/dist/embedders/ollama.d.ts +7 -0
- package/dist/embedders/ollama.js +41 -0
- package/dist/embedders/ollama.js.map +1 -0
- package/dist/embedders/openai.d.ts +8 -0
- package/dist/embedders/openai.js +39 -0
- package/dist/embedders/openai.js.map +1 -0
- package/dist/embedders/openaiCompatible.d.ts +8 -0
- package/dist/embedders/openaiCompatible.js +45 -0
- package/dist/embedders/openaiCompatible.js.map +1 -0
- package/dist/embedders/types.d.ts +6 -0
- package/dist/embedders/types.js +2 -0
- package/dist/embedders/types.js.map +1 -0
- package/dist/ignore/IgnoreManager.d.ts +10 -0
- package/dist/ignore/IgnoreManager.js +46 -0
- package/dist/ignore/IgnoreManager.js.map +1 -0
- package/dist/index.d.ts +37 -0
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -0
- package/dist/indexer/SyncService.d.ts +23 -0
- package/dist/indexer/SyncService.js +179 -0
- package/dist/indexer/SyncService.js.map +1 -0
- package/dist/mcp/tools.d.ts +7 -0
- package/dist/mcp/tools.js +115 -0
- package/dist/mcp/tools.js.map +1 -0
- package/dist/parser/CodeParser.d.ts +8 -0
- package/dist/parser/CodeParser.js +71 -0
- package/dist/parser/CodeParser.js.map +1 -0
- package/dist/parser/types.d.ts +13 -0
- package/dist/parser/types.js +2 -0
- package/dist/parser/types.js.map +1 -0
- package/dist/scanner/fileScanner.d.ts +2 -0
- package/dist/scanner/fileScanner.js +42 -0
- package/dist/scanner/fileScanner.js.map +1 -0
- package/dist/scanner/supportedExtensions.d.ts +3 -0
- package/dist/scanner/supportedExtensions.js +48 -0
- package/dist/scanner/supportedExtensions.js.map +1 -0
- package/dist/search/SearchService.d.ts +7 -0
- package/dist/search/SearchService.js +23 -0
- package/dist/search/SearchService.js.map +1 -0
- package/dist/vector-store/QdrantStore.d.ts +15 -0
- package/dist/vector-store/QdrantStore.js +120 -0
- package/dist/vector-store/QdrantStore.js.map +1 -0
- package/dist/vector-store/types.d.ts +21 -0
- package/dist/vector-store/types.js +2 -0
- package/dist/vector-store/types.js.map +1 -0
- package/package.json +33 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# code-index-mcp
|
|
2
|
+
|
|
3
|
+
一个可通过 `npx` 运行的 MCP 服务器,为 AI 工具提供代码索引与语义搜索能力。每次调用会执行按需增量同步,保证结果最新。
|
|
4
|
+
|
|
5
|
+
## 运行要求
|
|
6
|
+
|
|
7
|
+
- Node.js >= 18
|
|
8
|
+
- Qdrant(默认 `http://localhost:6333`)
|
|
9
|
+
|
|
10
|
+
## 快速开始
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npx @hayhandsome/code-index-mcp
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
默认使用 stdio 传输,适配 MCP 客户端的子进程方式调用。
|
|
17
|
+
|
|
18
|
+
## 配置
|
|
19
|
+
|
|
20
|
+
### 全局配置(推荐)
|
|
21
|
+
|
|
22
|
+
目录:`~/.code-index-mcp/`
|
|
23
|
+
|
|
24
|
+
`config.json`(非敏感):
|
|
25
|
+
```json
|
|
26
|
+
{
|
|
27
|
+
"qdrantUrl": "http://localhost:6333",
|
|
28
|
+
"embedderProvider": "openai",
|
|
29
|
+
"modelId": "text-embedding-3-small",
|
|
30
|
+
"modelDimension": 1536,
|
|
31
|
+
"embeddingBatchSize": 60,
|
|
32
|
+
"searchMinScore": 0.2,
|
|
33
|
+
"searchMaxResults": 20,
|
|
34
|
+
"timeoutMs": 300000,
|
|
35
|
+
"openAiCompatibleBaseUrl": "http://localhost:1234",
|
|
36
|
+
"ollamaBaseUrl": "http://localhost:11434"
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
`secrets.json`(敏感):
|
|
41
|
+
```json
|
|
42
|
+
{
|
|
43
|
+
"qdrantApiKey": "",
|
|
44
|
+
"openAiApiKey": "",
|
|
45
|
+
"openAiCompatibleApiKey": ""
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Workspace 覆盖(可选)
|
|
50
|
+
|
|
51
|
+
目录:`<workspace>/.code-index/`
|
|
52
|
+
|
|
53
|
+
`config.json` / `secrets.json` 会覆盖全局配置。
|
|
54
|
+
|
|
55
|
+
### 环境变量(最高优先级)
|
|
56
|
+
|
|
57
|
+
- `CODE_INDEX_QDRANT_URL`
|
|
58
|
+
- `CODE_INDEX_QDRANT_API_KEY`
|
|
59
|
+
- `CODE_INDEX_EMBEDDER_PROVIDER`
|
|
60
|
+
- `CODE_INDEX_MODEL_ID`
|
|
61
|
+
- `CODE_INDEX_MODEL_DIMENSION`
|
|
62
|
+
- `CODE_INDEX_EMBEDDING_BATCH_SIZE`
|
|
63
|
+
- `CODE_INDEX_SEARCH_MIN_SCORE`
|
|
64
|
+
- `CODE_INDEX_SEARCH_MAX_RESULTS`
|
|
65
|
+
- `CODE_INDEX_TIMEOUT_MS`
|
|
66
|
+
- `CODE_INDEX_OPENAI_API_KEY`
|
|
67
|
+
- `CODE_INDEX_OPENAI_COMPATIBLE_API_KEY`
|
|
68
|
+
- `CODE_INDEX_OPENAI_COMPATIBLE_BASE_URL`
|
|
69
|
+
- `CODE_INDEX_OLLAMA_BASE_URL`
|
|
70
|
+
|
|
71
|
+
## MCP 工具
|
|
72
|
+
|
|
73
|
+
- `code_index_search`:按需同步后搜索
|
|
74
|
+
- `code_index_update`:执行一次增量同步
|
|
75
|
+
- `code_index_reindex`:清空并重建索引
|
|
76
|
+
- `code_index_clear`:清空向量与本地缓存
|
|
77
|
+
- `code_index_status`:查看当前配置与索引状态
|
|
78
|
+
|
|
79
|
+
### 示例:搜索
|
|
80
|
+
|
|
81
|
+
```json
|
|
82
|
+
{
|
|
83
|
+
"tool": "code_index_search",
|
|
84
|
+
"arguments": {
|
|
85
|
+
"query": "How is the config loaded?",
|
|
86
|
+
"workspacePath": "/path/to/repo"
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## 忽略规则
|
|
92
|
+
|
|
93
|
+
- 自动读取 `.gitignore`
|
|
94
|
+
- 如果存在 `.rooignore`,会在 `.gitignore` 基础上叠加
|
|
95
|
+
|
|
96
|
+
## 许可
|
|
97
|
+
|
|
98
|
+
MIT
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export interface CacheEntry {
|
|
2
|
+
hash: string;
|
|
3
|
+
size?: number;
|
|
4
|
+
mtimeMs?: number;
|
|
5
|
+
}
|
|
6
|
+
export declare class CacheManager {
|
|
7
|
+
private readonly workspacePath;
|
|
8
|
+
private readonly cachePath;
|
|
9
|
+
private entries;
|
|
10
|
+
constructor(workspacePath: string);
|
|
11
|
+
load(): Promise<void>;
|
|
12
|
+
get(filePath: string): CacheEntry | undefined;
|
|
13
|
+
set(filePath: string, entry: CacheEntry): void;
|
|
14
|
+
delete(filePath: string): void;
|
|
15
|
+
getAll(): Record<string, CacheEntry>;
|
|
16
|
+
save(): Promise<void>;
|
|
17
|
+
clear(): Promise<void>;
|
|
18
|
+
private safeWriteJson;
|
|
19
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import fs from "fs/promises";
|
|
2
|
+
import path from "path";
|
|
3
|
+
export class CacheManager {
|
|
4
|
+
workspacePath;
|
|
5
|
+
cachePath;
|
|
6
|
+
entries = {};
|
|
7
|
+
constructor(workspacePath) {
|
|
8
|
+
this.workspacePath = workspacePath;
|
|
9
|
+
this.cachePath = path.join(workspacePath, ".code-index", "cache.json");
|
|
10
|
+
}
|
|
11
|
+
async load() {
|
|
12
|
+
try {
|
|
13
|
+
const raw = await fs.readFile(this.cachePath, "utf8");
|
|
14
|
+
this.entries = JSON.parse(raw);
|
|
15
|
+
}
|
|
16
|
+
catch (error) {
|
|
17
|
+
if (error?.code === "ENOENT") {
|
|
18
|
+
this.entries = {};
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
throw new Error(`Failed to load cache: ${error?.message ?? String(error)}`);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
get(filePath) {
|
|
25
|
+
return this.entries[filePath];
|
|
26
|
+
}
|
|
27
|
+
set(filePath, entry) {
|
|
28
|
+
this.entries[filePath] = entry;
|
|
29
|
+
}
|
|
30
|
+
delete(filePath) {
|
|
31
|
+
delete this.entries[filePath];
|
|
32
|
+
}
|
|
33
|
+
getAll() {
|
|
34
|
+
return { ...this.entries };
|
|
35
|
+
}
|
|
36
|
+
async save() {
|
|
37
|
+
await this.safeWriteJson(this.cachePath, this.entries);
|
|
38
|
+
}
|
|
39
|
+
async clear() {
|
|
40
|
+
this.entries = {};
|
|
41
|
+
await this.safeWriteJson(this.cachePath, this.entries);
|
|
42
|
+
}
|
|
43
|
+
async safeWriteJson(filePath, data) {
|
|
44
|
+
await fs.mkdir(path.dirname(filePath), { recursive: true });
|
|
45
|
+
const tempPath = `${filePath}.${process.pid}.${Date.now()}.tmp`;
|
|
46
|
+
const payload = JSON.stringify(data, null, 2);
|
|
47
|
+
await fs.writeFile(tempPath, payload, "utf8");
|
|
48
|
+
await fs.rename(tempPath, filePath);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=CacheManager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CacheManager.js","sourceRoot":"","sources":["../../src/cache/CacheManager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,aAAa,CAAA;AAC5B,OAAO,IAAI,MAAM,MAAM,CAAA;AAQvB,MAAM,OAAO,YAAY;IAIK;IAHZ,SAAS,CAAQ;IAC1B,OAAO,GAA+B,EAAE,CAAA;IAEhD,YAA6B,aAAqB;QAArB,kBAAa,GAAb,aAAa,CAAQ;QACjD,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,aAAa,EAAE,YAAY,CAAC,CAAA;IACvE,CAAC;IAED,KAAK,CAAC,IAAI;QACT,IAAI,CAAC;YACJ,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,CAAA;YACrD,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAA+B,CAAA;QAC7D,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YACrB,IAAI,KAAK,EAAE,IAAI,KAAK,QAAQ,EAAE,CAAC;gBAC9B,IAAI,CAAC,OAAO,GAAG,EAAE,CAAA;gBACjB,OAAM;YACP,CAAC;YACD,MAAM,IAAI,KAAK,CAAC,yBAAyB,KAAK,EAAE,OAAO,IAAI,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;QAC5E,CAAC;IACF,CAAC;IAED,GAAG,CAAC,QAAgB;QACnB,OAAO,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAA;IAC9B,CAAC;IAED,GAAG,CAAC,QAAgB,EAAE,KAAiB;QACtC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,KAAK,CAAA;IAC/B,CAAC;IAED,MAAM,CAAC,QAAgB;QACtB,OAAO,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAA;IAC9B,CAAC;IAED,MAAM;QACL,OAAO,EAAE,GAAG,IAAI,CAAC,OAAO,EAAE,CAAA;IAC3B,CAAC;IAED,KAAK,CAAC,IAAI;QACT,MAAM,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC,CAAA;IACvD,CAAC;IAED,KAAK,CAAC,KAAK;QACV,IAAI,CAAC,OAAO,GAAG,EAAE,CAAA;QACjB,MAAM,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC,CAAA;IACvD,CAAC;IAEO,KAAK,CAAC,aAAa,CAAC,QAAgB,EAAE,IAAa;QAC1D,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;QAC3D,MAAM,QAAQ,GAAG,GAAG,QAAQ,IAAI,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,EAAE,MAAM,CAAA;QAC/D,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAA;QAC7C,MAAM,EAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,OAAO,EAAE,MAAM,CAAC,CAAA;QAC7C,MAAM,EAAE,CAAC,MAAM,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAA;IACpC,CAAC;CACD"}
|
package/dist/cli.d.ts
ADDED
package/dist/cli.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3
|
+
import { createServer } from "./index.js";
|
|
4
|
+
async function main() {
|
|
5
|
+
const server = createServer();
|
|
6
|
+
const transport = new StdioServerTransport();
|
|
7
|
+
await server.connect(transport);
|
|
8
|
+
}
|
|
9
|
+
main().catch((error) => {
|
|
10
|
+
console.error(error);
|
|
11
|
+
process.exit(1);
|
|
12
|
+
});
|
|
13
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAA;AAChF,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAEzC,KAAK,UAAU,IAAI;IAClB,MAAM,MAAM,GAAG,YAAY,EAAE,CAAA;IAC7B,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAA;IAC5C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAA;AAChC,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACtB,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;IACpB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;AAChB,CAAC,CAAC,CAAA"}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import fs from "fs/promises";
|
|
2
|
+
import os from "os";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import { DEFAULT_CONFIG, } from "./types.js";
|
|
5
|
+
const GLOBAL_DIR_NAME = ".code-index-mcp";
|
|
6
|
+
const WORKSPACE_DIR_NAME = ".code-index";
|
|
7
|
+
const ENV_MAP = {
|
|
8
|
+
qdrantUrl: "CODE_INDEX_QDRANT_URL",
|
|
9
|
+
qdrantApiKey: "CODE_INDEX_QDRANT_API_KEY",
|
|
10
|
+
embedderProvider: "CODE_INDEX_EMBEDDER_PROVIDER",
|
|
11
|
+
modelId: "CODE_INDEX_MODEL_ID",
|
|
12
|
+
modelDimension: "CODE_INDEX_MODEL_DIMENSION",
|
|
13
|
+
embeddingBatchSize: "CODE_INDEX_EMBEDDING_BATCH_SIZE",
|
|
14
|
+
searchMinScore: "CODE_INDEX_SEARCH_MIN_SCORE",
|
|
15
|
+
searchMaxResults: "CODE_INDEX_SEARCH_MAX_RESULTS",
|
|
16
|
+
timeoutMs: "CODE_INDEX_TIMEOUT_MS",
|
|
17
|
+
openAiApiKey: "CODE_INDEX_OPENAI_API_KEY",
|
|
18
|
+
openAiCompatibleApiKey: "CODE_INDEX_OPENAI_COMPATIBLE_API_KEY",
|
|
19
|
+
openAiCompatibleBaseUrl: "CODE_INDEX_OPENAI_COMPATIBLE_BASE_URL",
|
|
20
|
+
ollamaBaseUrl: "CODE_INDEX_OLLAMA_BASE_URL",
|
|
21
|
+
};
|
|
22
|
+
async function fileExists(filePath) {
|
|
23
|
+
try {
|
|
24
|
+
await fs.access(filePath);
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
async function readJsonFile(filePath) {
|
|
32
|
+
if (!(await fileExists(filePath))) {
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
35
|
+
const raw = await fs.readFile(filePath, "utf8");
|
|
36
|
+
try {
|
|
37
|
+
return JSON.parse(raw);
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
throw new Error(`Invalid JSON in ${filePath}`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
function parseNumber(value, name) {
|
|
44
|
+
if (value === undefined || value.trim() === "") {
|
|
45
|
+
return undefined;
|
|
46
|
+
}
|
|
47
|
+
const parsed = Number(value);
|
|
48
|
+
if (!Number.isFinite(parsed)) {
|
|
49
|
+
throw new Error(`Invalid numeric value for ${name}: ${value}`);
|
|
50
|
+
}
|
|
51
|
+
return parsed;
|
|
52
|
+
}
|
|
53
|
+
function parseEmbedderProvider(value) {
|
|
54
|
+
if (!value) {
|
|
55
|
+
return undefined;
|
|
56
|
+
}
|
|
57
|
+
if (value === "openai" || value === "openai-compatible" || value === "ollama") {
|
|
58
|
+
return value;
|
|
59
|
+
}
|
|
60
|
+
throw new Error(`Invalid embedder provider: ${value}`);
|
|
61
|
+
}
|
|
62
|
+
function mergeDefined(base, ...sources) {
|
|
63
|
+
const result = { ...base };
|
|
64
|
+
for (const source of sources) {
|
|
65
|
+
if (!source) {
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
for (const [key, value] of Object.entries(source)) {
|
|
69
|
+
if (value !== undefined) {
|
|
70
|
+
;
|
|
71
|
+
result[key] = value;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return result;
|
|
76
|
+
}
|
|
77
|
+
function loadEnvConfig() {
|
|
78
|
+
const config = {
|
|
79
|
+
qdrantUrl: process.env[ENV_MAP.qdrantUrl],
|
|
80
|
+
embedderProvider: parseEmbedderProvider(process.env[ENV_MAP.embedderProvider]),
|
|
81
|
+
modelId: process.env[ENV_MAP.modelId],
|
|
82
|
+
modelDimension: parseNumber(process.env[ENV_MAP.modelDimension], ENV_MAP.modelDimension),
|
|
83
|
+
embeddingBatchSize: parseNumber(process.env[ENV_MAP.embeddingBatchSize], ENV_MAP.embeddingBatchSize),
|
|
84
|
+
searchMinScore: parseNumber(process.env[ENV_MAP.searchMinScore], ENV_MAP.searchMinScore),
|
|
85
|
+
searchMaxResults: parseNumber(process.env[ENV_MAP.searchMaxResults], ENV_MAP.searchMaxResults),
|
|
86
|
+
timeoutMs: parseNumber(process.env[ENV_MAP.timeoutMs], ENV_MAP.timeoutMs),
|
|
87
|
+
openAiCompatibleBaseUrl: process.env[ENV_MAP.openAiCompatibleBaseUrl],
|
|
88
|
+
ollamaBaseUrl: process.env[ENV_MAP.ollamaBaseUrl],
|
|
89
|
+
};
|
|
90
|
+
const secrets = {
|
|
91
|
+
qdrantApiKey: process.env[ENV_MAP.qdrantApiKey],
|
|
92
|
+
openAiApiKey: process.env[ENV_MAP.openAiApiKey],
|
|
93
|
+
openAiCompatibleApiKey: process.env[ENV_MAP.openAiCompatibleApiKey],
|
|
94
|
+
};
|
|
95
|
+
return { config, secrets };
|
|
96
|
+
}
|
|
97
|
+
function validateConfig(config, secrets) {
|
|
98
|
+
if (!config.qdrantUrl) {
|
|
99
|
+
throw new Error("Missing qdrantUrl in configuration");
|
|
100
|
+
}
|
|
101
|
+
switch (config.embedderProvider) {
|
|
102
|
+
case "openai":
|
|
103
|
+
if (!secrets.openAiApiKey) {
|
|
104
|
+
throw new Error("Missing OpenAI API key for embedder provider 'openai'");
|
|
105
|
+
}
|
|
106
|
+
break;
|
|
107
|
+
case "openai-compatible":
|
|
108
|
+
if (!config.openAiCompatibleBaseUrl) {
|
|
109
|
+
throw new Error("Missing OpenAI-Compatible base URL");
|
|
110
|
+
}
|
|
111
|
+
if (!secrets.openAiCompatibleApiKey) {
|
|
112
|
+
throw new Error("Missing OpenAI-Compatible API key");
|
|
113
|
+
}
|
|
114
|
+
break;
|
|
115
|
+
case "ollama":
|
|
116
|
+
if (!config.ollamaBaseUrl) {
|
|
117
|
+
throw new Error("Missing Ollama base URL");
|
|
118
|
+
}
|
|
119
|
+
break;
|
|
120
|
+
default:
|
|
121
|
+
throw new Error(`Unsupported embedder provider: ${config.embedderProvider}`);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
export async function loadConfig(workspacePath, options = {}) {
|
|
125
|
+
const validate = options.validate ?? true;
|
|
126
|
+
const globalDir = path.join(os.homedir(), GLOBAL_DIR_NAME);
|
|
127
|
+
const globalConfigPath = path.join(globalDir, "config.json");
|
|
128
|
+
const globalSecretsPath = path.join(globalDir, "secrets.json");
|
|
129
|
+
const resolvedWorkspacePath = workspacePath ?? process.cwd();
|
|
130
|
+
const workspaceDir = resolvedWorkspacePath ? path.join(resolvedWorkspacePath, WORKSPACE_DIR_NAME) : undefined;
|
|
131
|
+
const workspaceConfigPath = workspaceDir ? path.join(workspaceDir, "config.json") : undefined;
|
|
132
|
+
const workspaceSecretsPath = workspaceDir ? path.join(workspaceDir, "secrets.json") : undefined;
|
|
133
|
+
const paths = {
|
|
134
|
+
globalDir,
|
|
135
|
+
globalConfigPath,
|
|
136
|
+
globalSecretsPath,
|
|
137
|
+
workspaceDir,
|
|
138
|
+
workspaceConfigPath,
|
|
139
|
+
workspaceSecretsPath,
|
|
140
|
+
};
|
|
141
|
+
const [globalConfig, globalSecrets, workspaceConfig, workspaceSecrets] = await Promise.all([
|
|
142
|
+
readJsonFile(globalConfigPath),
|
|
143
|
+
readJsonFile(globalSecretsPath),
|
|
144
|
+
workspaceConfigPath ? readJsonFile(workspaceConfigPath) : undefined,
|
|
145
|
+
workspaceSecretsPath ? readJsonFile(workspaceSecretsPath) : undefined,
|
|
146
|
+
]);
|
|
147
|
+
const envResult = loadEnvConfig();
|
|
148
|
+
const mergedConfig = mergeDefined(DEFAULT_CONFIG, globalConfig, workspaceConfig, envResult.config);
|
|
149
|
+
const mergedSecrets = mergeDefined({}, globalSecrets, workspaceSecrets, envResult.secrets);
|
|
150
|
+
if (validate) {
|
|
151
|
+
validateConfig(mergedConfig, mergedSecrets);
|
|
152
|
+
}
|
|
153
|
+
return {
|
|
154
|
+
config: mergedConfig,
|
|
155
|
+
secrets: mergedSecrets,
|
|
156
|
+
paths,
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
//# sourceMappingURL=loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../../src/config/loader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,aAAa,CAAA;AAC5B,OAAO,EAAE,MAAM,IAAI,CAAA;AACnB,OAAO,IAAI,MAAM,MAAM,CAAA;AACvB,OAAO,EAGN,cAAc,GAKd,MAAM,YAAY,CAAA;AAEnB,MAAM,eAAe,GAAG,iBAAiB,CAAA;AACzC,MAAM,kBAAkB,GAAG,aAAa,CAAA;AAExC,MAAM,OAAO,GAAG;IACf,SAAS,EAAE,uBAAuB;IAClC,YAAY,EAAE,2BAA2B;IACzC,gBAAgB,EAAE,8BAA8B;IAChD,OAAO,EAAE,qBAAqB;IAC9B,cAAc,EAAE,4BAA4B;IAC5C,kBAAkB,EAAE,iCAAiC;IACrD,cAAc,EAAE,6BAA6B;IAC7C,gBAAgB,EAAE,+BAA+B;IACjD,SAAS,EAAE,uBAAuB;IAClC,YAAY,EAAE,2BAA2B;IACzC,sBAAsB,EAAE,sCAAsC;IAC9D,uBAAuB,EAAE,uCAAuC;IAChE,aAAa,EAAE,4BAA4B;CAClC,CAAA;AAEV,KAAK,UAAU,UAAU,CAAC,QAAgB;IACzC,IAAI,CAAC;QACJ,MAAM,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAA;QACzB,OAAO,IAAI,CAAA;IACZ,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,KAAK,CAAA;IACb,CAAC;AACF,CAAC;AAED,KAAK,UAAU,YAAY,CAAI,QAAgB;IAC9C,IAAI,CAAC,CAAC,MAAM,UAAU,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC;QACnC,OAAO,SAAS,CAAA;IACjB,CAAC;IACD,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAA;IAC/C,IAAI,CAAC;QACJ,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAM,CAAA;IAC5B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,MAAM,IAAI,KAAK,CAAC,mBAAmB,QAAQ,EAAE,CAAC,CAAA;IAC/C,CAAC;AACF,CAAC;AAED,SAAS,WAAW,CAAC,KAAyB,EAAE,IAAY;IAC3D,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;QAChD,OAAO,SAAS,CAAA;IACjB,CAAC;IACD,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,CAAA;IAC5B,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;QAC9B,MAAM,IAAI,KAAK,CAAC,6BAA6B,IAAI,KAAK,KAAK,EAAE,CAAC,CAAA;IAC/D,CAAC;IACD,OAAO,MAAM,CAAA;AACd,CAAC;AAED,SAAS,qBAAqB,CAAC,KAAyB;IACvD,IAAI,CAAC,KAAK,EAAE,CAAC;QACZ,OAAO,SAAS,CAAA;IACjB,CAAC;IACD,IAAI,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,mBAAmB,IAAI,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC/E,OAAO,KAAK,CAAA;IACb,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,8BAA8B,KAAK,EAAE,CAAC,CAAA;AACvD,CAAC;AAED,SAAS,YAAY,CAAI,IAAO,EAAE,GAAG,OAAsC;IAC1E,MAAM,MAAM,GAAG,EAAE,GAAG,IAAI,EAAO,CAAA;IAC/B,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC9B,IAAI,CAAC,MAAM,EAAE,CAAC;YACb,SAAQ;QACT,CAAC;QACD,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YACnD,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;gBACzB,CAAC;gBAAC,MAAkC,CAAC,GAAG,CAAC,GAAG,KAAK,CAAA;YAClD,CAAC;QACF,CAAC;IACF,CAAC;IACD,OAAO,MAAM,CAAA;AACd,CAAC;AAED,SAAS,aAAa;IACrB,MAAM,MAAM,GAAgC;QAC3C,SAAS,EAAE,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,SAAS,CAAC;QACzC,gBAAgB,EAAE,qBAAqB,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC;QAC9E,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC;QACrC,cAAc,EAAE,WAAW,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,cAAc,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC;QACxF,kBAAkB,EAAE,WAAW,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,kBAAkB,CAAC,EAAE,OAAO,CAAC,kBAAkB,CAAC;QACpG,cAAc,EAAE,WAAW,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,cAAc,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC;QACxF,gBAAgB,EAAE,WAAW,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,gBAAgB,CAAC,EAAE,OAAO,CAAC,gBAAgB,CAAC;QAC9F,SAAS,EAAE,WAAW,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC,SAAS,CAAC;QACzE,uBAAuB,EAAE,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,uBAAuB,CAAC;QACrE,aAAa,EAAE,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,aAAa,CAAC;KACjD,CAAA;IAED,MAAM,OAAO,GAAqB;QACjC,YAAY,EAAE,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,YAAY,CAAC;QAC/C,YAAY,EAAE,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,YAAY,CAAC;QAC/C,sBAAsB,EAAE,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,sBAAsB,CAAC;KACnE,CAAA;IAED,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,CAAA;AAC3B,CAAC;AAED,SAAS,cAAc,CAAC,MAAsB,EAAE,OAAgB;IAC/D,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC;QACvB,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAA;IACtD,CAAC;IAED,QAAQ,MAAM,CAAC,gBAAgB,EAAE,CAAC;QACjC,KAAK,QAAQ;YACZ,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE,CAAC;gBAC3B,MAAM,IAAI,KAAK,CAAC,uDAAuD,CAAC,CAAA;YACzE,CAAC;YACD,MAAK;QACN,KAAK,mBAAmB;YACvB,IAAI,CAAC,MAAM,CAAC,uBAAuB,EAAE,CAAC;gBACrC,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAA;YACtD,CAAC;YACD,IAAI,CAAC,OAAO,CAAC,sBAAsB,EAAE,CAAC;gBACrC,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAA;YACrD,CAAC;YACD,MAAK;QACN,KAAK,QAAQ;YACZ,IAAI,CAAC,MAAM,CAAC,aAAa,EAAE,CAAC;gBAC3B,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAA;YAC3C,CAAC;YACD,MAAK;QACN;YACC,MAAM,IAAI,KAAK,CAAC,kCAAkC,MAAM,CAAC,gBAAgB,EAAE,CAAC,CAAA;IAC9E,CAAC;AACF,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAC/B,aAAsB,EACtB,UAAkC,EAAE;IAEpC,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,IAAI,CAAA;IACzC,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,eAAe,CAAC,CAAA;IAC1D,MAAM,gBAAgB,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,aAAa,CAAC,CAAA;IAC5D,MAAM,iBAAiB,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,cAAc,CAAC,CAAA;IAE9D,MAAM,qBAAqB,GAAG,aAAa,IAAI,OAAO,CAAC,GAAG,EAAE,CAAA;IAC5D,MAAM,YAAY,GAAG,qBAAqB,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,qBAAqB,EAAE,kBAAkB,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;IAC7G,MAAM,mBAAmB,GAAG,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;IAC7F,MAAM,oBAAoB,GAAG,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,cAAc,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;IAE/F,MAAM,KAAK,GAAgB;QAC1B,SAAS;QACT,gBAAgB;QAChB,iBAAiB;QACjB,YAAY;QACZ,mBAAmB;QACnB,oBAAoB;KACpB,CAAA;IAED,MAAM,CAAC,YAAY,EAAE,aAAa,EAAE,eAAe,EAAE,gBAAgB,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QAC1F,YAAY,CAAqB,gBAAgB,CAAC;QAClD,YAAY,CAAU,iBAAiB,CAAC;QACxC,mBAAmB,CAAC,CAAC,CAAC,YAAY,CAAqB,mBAAmB,CAAC,CAAC,CAAC,CAAC,SAAS;QACvF,oBAAoB,CAAC,CAAC,CAAC,YAAY,CAAU,oBAAoB,CAAC,CAAC,CAAC,CAAC,SAAS;KAC9E,CAAC,CAAA;IAEF,MAAM,SAAS,GAAG,aAAa,EAAE,CAAA;IAEjC,MAAM,YAAY,GAAG,YAAY,CAChC,cAAc,EACd,YAAuC,EACvC,eAA0C,EAC1C,SAAS,CAAC,MAAiC,CAC3C,CAAA;IACD,MAAM,aAAa,GAAG,YAAY,CAAU,EAAE,EAAE,aAAa,EAAE,gBAAgB,EAAE,SAAS,CAAC,OAAO,CAAC,CAAA;IAEnG,IAAI,QAAQ,EAAE,CAAC;QACd,cAAc,CAAC,YAAY,EAAE,aAAa,CAAC,CAAA;IAC5C,CAAC;IAED,OAAO;QACN,MAAM,EAAE,YAAY;QACpB,OAAO,EAAE,aAAa;QACtB,KAAK;KACL,CAAA;AACF,CAAC"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
export type EmbedderProvider = "openai" | "openai-compatible" | "ollama";
|
|
2
|
+
export interface NonSensitiveConfig {
|
|
3
|
+
qdrantUrl?: string;
|
|
4
|
+
embedderProvider?: EmbedderProvider;
|
|
5
|
+
modelId?: string;
|
|
6
|
+
modelDimension?: number;
|
|
7
|
+
embeddingBatchSize?: number;
|
|
8
|
+
searchMinScore?: number;
|
|
9
|
+
searchMaxResults?: number;
|
|
10
|
+
timeoutMs?: number;
|
|
11
|
+
openAiCompatibleBaseUrl?: string;
|
|
12
|
+
ollamaBaseUrl?: string;
|
|
13
|
+
}
|
|
14
|
+
export interface Secrets {
|
|
15
|
+
openAiApiKey?: string;
|
|
16
|
+
openAiCompatibleApiKey?: string;
|
|
17
|
+
qdrantApiKey?: string;
|
|
18
|
+
}
|
|
19
|
+
export interface ResolvedConfig extends NonSensitiveConfig {
|
|
20
|
+
qdrantUrl: string;
|
|
21
|
+
embedderProvider: EmbedderProvider;
|
|
22
|
+
modelId: string;
|
|
23
|
+
embeddingBatchSize: number;
|
|
24
|
+
searchMinScore: number;
|
|
25
|
+
searchMaxResults: number;
|
|
26
|
+
timeoutMs: number;
|
|
27
|
+
}
|
|
28
|
+
export declare const DEFAULT_CONFIG: ResolvedConfig;
|
|
29
|
+
export interface ConfigPaths {
|
|
30
|
+
globalDir: string;
|
|
31
|
+
globalConfigPath: string;
|
|
32
|
+
globalSecretsPath: string;
|
|
33
|
+
workspaceDir?: string;
|
|
34
|
+
workspaceConfigPath?: string;
|
|
35
|
+
workspaceSecretsPath?: string;
|
|
36
|
+
}
|
|
37
|
+
export interface ConfigLoadResult {
|
|
38
|
+
config: ResolvedConfig;
|
|
39
|
+
secrets: Secrets;
|
|
40
|
+
paths: ConfigPaths;
|
|
41
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export const DEFAULT_CONFIG = {
|
|
2
|
+
qdrantUrl: "http://localhost:6333",
|
|
3
|
+
embedderProvider: "openai",
|
|
4
|
+
modelId: "text-embedding-3-small",
|
|
5
|
+
embeddingBatchSize: 60,
|
|
6
|
+
searchMinScore: 0.2,
|
|
7
|
+
searchMaxResults: 20,
|
|
8
|
+
timeoutMs: 300_000,
|
|
9
|
+
openAiCompatibleBaseUrl: undefined,
|
|
10
|
+
ollamaBaseUrl: "http://localhost:11434",
|
|
11
|
+
modelDimension: undefined,
|
|
12
|
+
};
|
|
13
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/config/types.ts"],"names":[],"mappings":"AA+BA,MAAM,CAAC,MAAM,cAAc,GAAmB;IAC7C,SAAS,EAAE,uBAAuB;IAClC,gBAAgB,EAAE,QAAQ;IAC1B,OAAO,EAAE,wBAAwB;IACjC,kBAAkB,EAAE,EAAE;IACtB,cAAc,EAAE,GAAG;IACnB,gBAAgB,EAAE,EAAE;IACpB,SAAS,EAAE,OAAO;IAClB,uBAAuB,EAAE,SAAS;IAClC,aAAa,EAAE,wBAAwB;IACvC,cAAc,EAAE,SAAS;CACzB,CAAA"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { OpenAiEmbedder } from "./openai.js";
|
|
2
|
+
import { OpenAiCompatibleEmbedder } from "./openaiCompatible.js";
|
|
3
|
+
import { OllamaEmbedder } from "./ollama.js";
|
|
4
|
+
export function createEmbedderFromConfig(config, secrets) {
|
|
5
|
+
switch (config.embedderProvider) {
|
|
6
|
+
case "openai":
|
|
7
|
+
return new OpenAiEmbedder(secrets.openAiApiKey ?? "", config.modelId);
|
|
8
|
+
case "openai-compatible":
|
|
9
|
+
return new OpenAiCompatibleEmbedder(secrets.openAiCompatibleApiKey ?? "", config.modelId, config.openAiCompatibleBaseUrl ?? "");
|
|
10
|
+
case "ollama":
|
|
11
|
+
return new OllamaEmbedder(config.modelId, config.ollamaBaseUrl ?? "");
|
|
12
|
+
default:
|
|
13
|
+
throw new Error(`Unsupported embedder provider: ${config.embedderProvider}`);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=factory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"factory.js","sourceRoot":"","sources":["../../src/embedders/factory.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAC5C,OAAO,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAA;AAChE,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAE5C,MAAM,UAAU,wBAAwB,CAAC,MAAsB,EAAE,OAAgB;IAChF,QAAQ,MAAM,CAAC,gBAAgB,EAAE,CAAC;QACjC,KAAK,QAAQ;YACZ,OAAO,IAAI,cAAc,CAAC,OAAO,CAAC,YAAY,IAAI,EAAE,EAAE,MAAM,CAAC,OAAO,CAAC,CAAA;QACtE,KAAK,mBAAmB;YACvB,OAAO,IAAI,wBAAwB,CAClC,OAAO,CAAC,sBAAsB,IAAI,EAAE,EACpC,MAAM,CAAC,OAAO,EACd,MAAM,CAAC,uBAAuB,IAAI,EAAE,CACpC,CAAA;QACF,KAAK,QAAQ;YACZ,OAAO,IAAI,cAAc,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,aAAa,IAAI,EAAE,CAAC,CAAA;QACtE;YACC,MAAM,IAAI,KAAK,CAAC,kCAAkC,MAAM,CAAC,gBAAgB,EAAE,CAAC,CAAA;IAC9E,CAAC;AACF,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Embedder, EmbeddingResponse } from "./types.js";
|
|
2
|
+
export declare class OllamaEmbedder implements Embedder {
|
|
3
|
+
private readonly modelId;
|
|
4
|
+
private readonly baseUrl;
|
|
5
|
+
constructor(modelId: string, baseUrl: string);
|
|
6
|
+
createEmbeddings(texts: string[]): Promise<EmbeddingResponse>;
|
|
7
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
function normalizeBaseUrl(baseUrl) {
|
|
2
|
+
return baseUrl.replace(/\/+$/, "");
|
|
3
|
+
}
|
|
4
|
+
export class OllamaEmbedder {
|
|
5
|
+
modelId;
|
|
6
|
+
baseUrl;
|
|
7
|
+
constructor(modelId, baseUrl) {
|
|
8
|
+
this.modelId = modelId;
|
|
9
|
+
this.baseUrl = baseUrl;
|
|
10
|
+
}
|
|
11
|
+
async createEmbeddings(texts) {
|
|
12
|
+
if (!this.baseUrl) {
|
|
13
|
+
throw new Error("Missing Ollama base URL");
|
|
14
|
+
}
|
|
15
|
+
const url = `${normalizeBaseUrl(this.baseUrl)}/api/embeddings`;
|
|
16
|
+
const embeddings = [];
|
|
17
|
+
for (const text of texts) {
|
|
18
|
+
const response = await fetch(url, {
|
|
19
|
+
method: "POST",
|
|
20
|
+
headers: {
|
|
21
|
+
"Content-Type": "application/json",
|
|
22
|
+
},
|
|
23
|
+
body: JSON.stringify({
|
|
24
|
+
model: this.modelId,
|
|
25
|
+
prompt: text,
|
|
26
|
+
}),
|
|
27
|
+
});
|
|
28
|
+
if (!response.ok) {
|
|
29
|
+
const message = await response.text();
|
|
30
|
+
throw new Error(`Ollama embeddings failed: ${response.status} ${message}`);
|
|
31
|
+
}
|
|
32
|
+
const data = (await response.json());
|
|
33
|
+
if (!data?.embedding || !Array.isArray(data.embedding)) {
|
|
34
|
+
throw new Error("Ollama embeddings response missing embedding");
|
|
35
|
+
}
|
|
36
|
+
embeddings.push(data.embedding);
|
|
37
|
+
}
|
|
38
|
+
return { embeddings };
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=ollama.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ollama.js","sourceRoot":"","sources":["../../src/embedders/ollama.ts"],"names":[],"mappings":"AAEA,SAAS,gBAAgB,CAAC,OAAe;IACxC,OAAO,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAA;AACnC,CAAC;AAED,MAAM,OAAO,cAAc;IAER;IACA;IAFlB,YACkB,OAAe,EACf,OAAe;QADf,YAAO,GAAP,OAAO,CAAQ;QACf,YAAO,GAAP,OAAO,CAAQ;IAC9B,CAAC;IAEJ,KAAK,CAAC,gBAAgB,CAAC,KAAe;QACrC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;YACnB,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAA;QAC3C,CAAC;QACD,MAAM,GAAG,GAAG,GAAG,gBAAgB,CAAC,IAAI,CAAC,OAAO,CAAC,iBAAiB,CAAA;QAC9D,MAAM,UAAU,GAAe,EAAE,CAAA;QAEjC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YAC1B,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;gBACjC,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE;oBACR,cAAc,EAAE,kBAAkB;iBAClC;gBACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;oBACpB,KAAK,EAAE,IAAI,CAAC,OAAO;oBACnB,MAAM,EAAE,IAAI;iBACZ,CAAC;aACF,CAAC,CAAA;YAEF,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;gBAClB,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAA;gBACrC,MAAM,IAAI,KAAK,CAAC,6BAA6B,QAAQ,CAAC,MAAM,IAAI,OAAO,EAAE,CAAC,CAAA;YAC3E,CAAC;YAED,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAA6B,CAAA;YAChE,IAAI,CAAC,IAAI,EAAE,SAAS,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;gBACxD,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC,CAAA;YAChE,CAAC;YACD,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;QAChC,CAAC;QAED,OAAO,EAAE,UAAU,EAAE,CAAA;IACtB,CAAC;CACD"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Embedder, EmbeddingResponse } from "./types.js";
|
|
2
|
+
export declare class OpenAiEmbedder implements Embedder {
|
|
3
|
+
private readonly apiKey;
|
|
4
|
+
private readonly modelId;
|
|
5
|
+
private readonly baseUrl;
|
|
6
|
+
constructor(apiKey: string, modelId: string, baseUrl?: string);
|
|
7
|
+
createEmbeddings(texts: string[]): Promise<EmbeddingResponse>;
|
|
8
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export class OpenAiEmbedder {
|
|
2
|
+
apiKey;
|
|
3
|
+
modelId;
|
|
4
|
+
baseUrl;
|
|
5
|
+
constructor(apiKey, modelId, baseUrl = "https://api.openai.com") {
|
|
6
|
+
this.apiKey = apiKey;
|
|
7
|
+
this.modelId = modelId;
|
|
8
|
+
this.baseUrl = baseUrl;
|
|
9
|
+
}
|
|
10
|
+
async createEmbeddings(texts) {
|
|
11
|
+
if (!this.apiKey) {
|
|
12
|
+
throw new Error("Missing OpenAI API key");
|
|
13
|
+
}
|
|
14
|
+
const url = `${this.baseUrl.replace(/\/+$/, "")}/v1/embeddings`;
|
|
15
|
+
const response = await fetch(url, {
|
|
16
|
+
method: "POST",
|
|
17
|
+
headers: {
|
|
18
|
+
"Content-Type": "application/json",
|
|
19
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
20
|
+
},
|
|
21
|
+
body: JSON.stringify({
|
|
22
|
+
model: this.modelId,
|
|
23
|
+
input: texts,
|
|
24
|
+
}),
|
|
25
|
+
});
|
|
26
|
+
if (!response.ok) {
|
|
27
|
+
const message = await response.text();
|
|
28
|
+
throw new Error(`OpenAI embeddings failed: ${response.status} ${message}`);
|
|
29
|
+
}
|
|
30
|
+
const data = (await response.json());
|
|
31
|
+
if (!data?.data || !Array.isArray(data.data)) {
|
|
32
|
+
throw new Error("OpenAI embeddings response missing data");
|
|
33
|
+
}
|
|
34
|
+
return {
|
|
35
|
+
embeddings: data.data.map((item) => item.embedding),
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=openai.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openai.js","sourceRoot":"","sources":["../../src/embedders/openai.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,cAAc;IAER;IACA;IACA;IAHlB,YACkB,MAAc,EACd,OAAe,EACf,UAAU,wBAAwB;QAFlC,WAAM,GAAN,MAAM,CAAQ;QACd,YAAO,GAAP,OAAO,CAAQ;QACf,YAAO,GAAP,OAAO,CAA2B;IACjD,CAAC;IAEJ,KAAK,CAAC,gBAAgB,CAAC,KAAe;QACrC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;YAClB,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAA;QAC1C,CAAC;QACD,MAAM,GAAG,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,gBAAgB,CAAA;QAC/D,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;YACjC,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACR,cAAc,EAAE,kBAAkB;gBAClC,aAAa,EAAE,UAAU,IAAI,CAAC,MAAM,EAAE;aACtC;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gBACpB,KAAK,EAAE,IAAI,CAAC,OAAO;gBACnB,KAAK,EAAE,KAAK;aACZ,CAAC;SACF,CAAC,CAAA;QAEF,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YAClB,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAA;YACrC,MAAM,IAAI,KAAK,CAAC,6BAA6B,QAAQ,CAAC,MAAM,IAAI,OAAO,EAAE,CAAC,CAAA;QAC3E,CAAC;QAED,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAA8C,CAAA;QACjF,IAAI,CAAC,IAAI,EAAE,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YAC9C,MAAM,IAAI,KAAK,CAAC,yCAAyC,CAAC,CAAA;QAC3D,CAAC;QAED,OAAO;YACN,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC;SACnD,CAAA;IACF,CAAC;CACD"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Embedder, EmbeddingResponse } from "./types.js";
|
|
2
|
+
export declare class OpenAiCompatibleEmbedder implements Embedder {
|
|
3
|
+
private readonly apiKey;
|
|
4
|
+
private readonly modelId;
|
|
5
|
+
private readonly baseUrl;
|
|
6
|
+
constructor(apiKey: string, modelId: string, baseUrl: string);
|
|
7
|
+
createEmbeddings(texts: string[]): Promise<EmbeddingResponse>;
|
|
8
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
function resolveEmbeddingUrl(baseUrl) {
|
|
2
|
+
const normalized = baseUrl.replace(/\/+$/, "");
|
|
3
|
+
return normalized.endsWith("/v1") ? `${normalized}/embeddings` : `${normalized}/v1/embeddings`;
|
|
4
|
+
}
|
|
5
|
+
export class OpenAiCompatibleEmbedder {
|
|
6
|
+
apiKey;
|
|
7
|
+
modelId;
|
|
8
|
+
baseUrl;
|
|
9
|
+
constructor(apiKey, modelId, baseUrl) {
|
|
10
|
+
this.apiKey = apiKey;
|
|
11
|
+
this.modelId = modelId;
|
|
12
|
+
this.baseUrl = baseUrl;
|
|
13
|
+
}
|
|
14
|
+
async createEmbeddings(texts) {
|
|
15
|
+
if (!this.baseUrl) {
|
|
16
|
+
throw new Error("Missing OpenAI-Compatible base URL");
|
|
17
|
+
}
|
|
18
|
+
if (!this.apiKey) {
|
|
19
|
+
throw new Error("Missing OpenAI-Compatible API key");
|
|
20
|
+
}
|
|
21
|
+
const response = await fetch(resolveEmbeddingUrl(this.baseUrl), {
|
|
22
|
+
method: "POST",
|
|
23
|
+
headers: {
|
|
24
|
+
"Content-Type": "application/json",
|
|
25
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
26
|
+
},
|
|
27
|
+
body: JSON.stringify({
|
|
28
|
+
model: this.modelId,
|
|
29
|
+
input: texts,
|
|
30
|
+
}),
|
|
31
|
+
});
|
|
32
|
+
if (!response.ok) {
|
|
33
|
+
const message = await response.text();
|
|
34
|
+
throw new Error(`OpenAI-Compatible embeddings failed: ${response.status} ${message}`);
|
|
35
|
+
}
|
|
36
|
+
const data = (await response.json());
|
|
37
|
+
if (!data?.data || !Array.isArray(data.data)) {
|
|
38
|
+
throw new Error("OpenAI-Compatible embeddings response missing data");
|
|
39
|
+
}
|
|
40
|
+
return {
|
|
41
|
+
embeddings: data.data.map((item) => item.embedding),
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=openaiCompatible.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openaiCompatible.js","sourceRoot":"","sources":["../../src/embedders/openaiCompatible.ts"],"names":[],"mappings":"AAEA,SAAS,mBAAmB,CAAC,OAAe;IAC3C,MAAM,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAA;IAC9C,OAAO,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,UAAU,aAAa,CAAC,CAAC,CAAC,GAAG,UAAU,gBAAgB,CAAA;AAC/F,CAAC;AAED,MAAM,OAAO,wBAAwB;IAElB;IACA;IACA;IAHlB,YACkB,MAAc,EACd,OAAe,EACf,OAAe;QAFf,WAAM,GAAN,MAAM,CAAQ;QACd,YAAO,GAAP,OAAO,CAAQ;QACf,YAAO,GAAP,OAAO,CAAQ;IAC9B,CAAC;IAEJ,KAAK,CAAC,gBAAgB,CAAC,KAAe;QACrC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;YACnB,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAA;QACtD,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;YAClB,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAA;QACrD,CAAC;QAED,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,mBAAmB,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE;YAC/D,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACR,cAAc,EAAE,kBAAkB;gBAClC,aAAa,EAAE,UAAU,IAAI,CAAC,MAAM,EAAE;aACtC;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gBACpB,KAAK,EAAE,IAAI,CAAC,OAAO;gBACnB,KAAK,EAAE,KAAK;aACZ,CAAC;SACF,CAAC,CAAA;QAEF,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YAClB,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAA;YACrC,MAAM,IAAI,KAAK,CAAC,wCAAwC,QAAQ,CAAC,MAAM,IAAI,OAAO,EAAE,CAAC,CAAA;QACtF,CAAC;QAED,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAA8C,CAAA;QACjF,IAAI,CAAC,IAAI,EAAE,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YAC9C,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAA;QACtE,CAAC;QAED,OAAO;YACN,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC;SACnD,CAAA;IACF,CAAC;CACD"}
|