@cicctencent/agent-midway 0.1.1
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 +280 -0
- package/dist/adapters/express.d.ts +8 -0
- package/dist/adapters/express.js +91 -0
- package/dist/adapters/index.d.ts +5 -0
- package/dist/adapters/index.js +21 -0
- package/dist/adapters/koa.d.ts +3 -0
- package/dist/adapters/koa.js +75 -0
- package/dist/adapters/midway.d.ts +5 -0
- package/dist/adapters/midway.js +11 -0
- package/dist/adapters/next.d.ts +12 -0
- package/dist/adapters/next.js +89 -0
- package/dist/adapters/shared.d.ts +4 -0
- package/dist/adapters/shared.js +31 -0
- package/dist/channel/dingtalk.d.ts +18 -0
- package/dist/channel/dingtalk.js +68 -0
- package/dist/channel/feishu.d.ts +20 -0
- package/dist/channel/feishu.js +96 -0
- package/dist/channel/index.d.ts +46 -0
- package/dist/channel/index.js +311 -0
- package/dist/channel/types.d.ts +77 -0
- package/dist/channel/types.js +7 -0
- package/dist/channel/wecom.d.ts +22 -0
- package/dist/channel/wecom.js +106 -0
- package/dist/component.d.ts +49 -0
- package/dist/component.js +129 -0
- package/dist/connector/calendar-adapter.d.ts +19 -0
- package/dist/connector/calendar-adapter.js +236 -0
- package/dist/connector/db-adapter.d.ts +28 -0
- package/dist/connector/db-adapter.js +193 -0
- package/dist/connector/email-adapter.d.ts +23 -0
- package/dist/connector/email-adapter.js +192 -0
- package/dist/connector/fs-adapter.d.ts +15 -0
- package/dist/connector/fs-adapter.js +199 -0
- package/dist/connector/http-adapter.d.ts +29 -0
- package/dist/connector/http-adapter.js +181 -0
- package/dist/connector/index.d.ts +24 -0
- package/dist/connector/index.js +454 -0
- package/dist/connector/mcp-adapter.d.ts +27 -0
- package/dist/connector/mcp-adapter.js +156 -0
- package/dist/connector/mq-adapter.d.ts +25 -0
- package/dist/connector/mq-adapter.js +181 -0
- package/dist/connector/types.d.ts +205 -0
- package/dist/connector/types.js +9 -0
- package/dist/controller/a2a.controller.d.ts +41 -0
- package/dist/controller/a2a.controller.js +150 -0
- package/dist/controller/agent-profile.controller.d.ts +97 -0
- package/dist/controller/agent-profile.controller.js +200 -0
- package/dist/controller/agent.controller.d.ts +199 -0
- package/dist/controller/agent.controller.js +414 -0
- package/dist/controller/application.controller.d.ts +113 -0
- package/dist/controller/application.controller.js +217 -0
- package/dist/controller/automation.controller.d.ts +113 -0
- package/dist/controller/automation.controller.js +246 -0
- package/dist/controller/channel.controller.d.ts +73 -0
- package/dist/controller/channel.controller.js +183 -0
- package/dist/controller/chat.controller.d.ts +188 -0
- package/dist/controller/chat.controller.js +375 -0
- package/dist/controller/connector.controller.d.ts +134 -0
- package/dist/controller/connector.controller.js +257 -0
- package/dist/controller/knowledge-base.controller.d.ts +157 -0
- package/dist/controller/knowledge-base.controller.js +278 -0
- package/dist/controller/mcp-server.controller.d.ts +115 -0
- package/dist/controller/mcp-server.controller.js +236 -0
- package/dist/controller/model-config.controller.d.ts +139 -0
- package/dist/controller/model-config.controller.js +274 -0
- package/dist/controller/observability.controller.d.ts +124 -0
- package/dist/controller/observability.controller.js +142 -0
- package/dist/controller/security.controller.d.ts +91 -0
- package/dist/controller/security.controller.js +172 -0
- package/dist/controller/settings.controller.d.ts +83 -0
- package/dist/controller/settings.controller.js +280 -0
- package/dist/core/ai-workstation.d.ts +17 -0
- package/dist/core/ai-workstation.js +129 -0
- package/dist/core/index.d.ts +4 -0
- package/dist/core/index.js +20 -0
- package/dist/core/service-container.d.ts +12 -0
- package/dist/core/service-container.js +54 -0
- package/dist/core/sse.d.ts +6 -0
- package/dist/core/sse.js +56 -0
- package/dist/core/types.d.ts +72 -0
- package/dist/core/types.js +2 -0
- package/dist/dto/agent.dto.d.ts +21 -0
- package/dist/dto/agent.dto.js +79 -0
- package/dist/dto/ai-config.dto.d.ts +67 -0
- package/dist/dto/ai-config.dto.js +249 -0
- package/dist/dto/chat.dto.d.ts +40 -0
- package/dist/dto/chat.dto.js +122 -0
- package/dist/index.d.ts +101 -0
- package/dist/index.js +195 -0
- package/dist/memory/db-store.d.ts +33 -0
- package/dist/memory/db-store.js +143 -0
- package/dist/memory/index.d.ts +187 -0
- package/dist/memory/index.js +443 -0
- package/dist/model/ai-agent-profile.entity.d.ts +32 -0
- package/dist/model/ai-agent-profile.entity.js +289 -0
- package/dist/model/ai-application.entity.d.ts +20 -0
- package/dist/model/ai-application.entity.js +166 -0
- package/dist/model/ai-chat-memory.entity.d.ts +16 -0
- package/dist/model/ai-chat-memory.entity.js +123 -0
- package/dist/model/ai-chat-message.entity.d.ts +16 -0
- package/dist/model/ai-chat-message.entity.js +122 -0
- package/dist/model/ai-chat-skill.entity.d.ts +19 -0
- package/dist/model/ai-chat-skill.entity.js +155 -0
- package/dist/model/ai-chat-thread.entity.d.ts +15 -0
- package/dist/model/ai-chat-thread.entity.js +113 -0
- package/dist/model/ai-chat-workspace.entity.d.ts +17 -0
- package/dist/model/ai-chat-workspace.entity.js +136 -0
- package/dist/model/ai-kb-document.entity.d.ts +16 -0
- package/dist/model/ai-kb-document.entity.js +122 -0
- package/dist/model/ai-knowledge-base.entity.d.ts +22 -0
- package/dist/model/ai-knowledge-base.entity.js +185 -0
- package/dist/model/ai-mcp-server.entity.d.ts +23 -0
- package/dist/model/ai-mcp-server.entity.js +198 -0
- package/dist/model/ai-model-config.entity.d.ts +24 -0
- package/dist/model/ai-model-config.entity.js +200 -0
- package/dist/service/a2a.service.d.ts +142 -0
- package/dist/service/a2a.service.js +537 -0
- package/dist/service/agent-profile.service.d.ts +34 -0
- package/dist/service/agent-profile.service.js +110 -0
- package/dist/service/agent-server.service.d.ts +91 -0
- package/dist/service/agent-server.service.js +634 -0
- package/dist/service/agent-task-queue.service.d.ts +98 -0
- package/dist/service/agent-task-queue.service.js +283 -0
- package/dist/service/ai-chat.service.d.ts +103 -0
- package/dist/service/ai-chat.service.js +431 -0
- package/dist/service/ai-skill.service.d.ts +116 -0
- package/dist/service/ai-skill.service.js +457 -0
- package/dist/service/application.service.d.ts +42 -0
- package/dist/service/application.service.js +139 -0
- package/dist/service/automation.service.d.ts +37 -0
- package/dist/service/automation.service.js +196 -0
- package/dist/service/connector.service.d.ts +136 -0
- package/dist/service/connector.service.js +524 -0
- package/dist/service/knowledge-base.service.d.ts +138 -0
- package/dist/service/knowledge-base.service.js +528 -0
- package/dist/service/mcp-server.service.d.ts +39 -0
- package/dist/service/mcp-server.service.js +143 -0
- package/dist/service/model-config.service.d.ts +57 -0
- package/dist/service/model-config.service.js +168 -0
- package/dist/service/observability.service.d.ts +145 -0
- package/dist/service/observability.service.js +281 -0
- package/dist/service/openai.service.d.ts +88 -0
- package/dist/service/openai.service.js +406 -0
- package/dist/service/prompt-builder.service.d.ts +50 -0
- package/dist/service/prompt-builder.service.js +246 -0
- package/dist/tools/code-exec.tool.d.ts +37 -0
- package/dist/tools/code-exec.tool.js +162 -0
- package/dist/tools/datetime.tool.d.ts +21 -0
- package/dist/tools/datetime.tool.js +379 -0
- package/dist/tools/http-request.tool.d.ts +43 -0
- package/dist/tools/http-request.tool.js +455 -0
- package/dist/tools/registry.d.ts +71 -0
- package/dist/tools/registry.js +77 -0
- package/dist/tools/text-process.tool.d.ts +7 -0
- package/dist/tools/text-process.tool.js +366 -0
- package/dist/tools/web-search.tool.d.ts +28 -0
- package/dist/tools/web-search.tool.js +304 -0
- package/dist/types.d.ts +70 -0
- package/dist/types.js +7 -0
- package/package.json +69 -0
|
@@ -0,0 +1,524 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
19
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
20
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
21
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
22
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
23
|
+
};
|
|
24
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
25
|
+
var ownKeys = function(o) {
|
|
26
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
27
|
+
var ar = [];
|
|
28
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
29
|
+
return ar;
|
|
30
|
+
};
|
|
31
|
+
return ownKeys(o);
|
|
32
|
+
};
|
|
33
|
+
return function (mod) {
|
|
34
|
+
if (mod && mod.__esModule) return mod;
|
|
35
|
+
var result = {};
|
|
36
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
37
|
+
__setModuleDefault(result, mod);
|
|
38
|
+
return result;
|
|
39
|
+
};
|
|
40
|
+
})();
|
|
41
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
42
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
43
|
+
};
|
|
44
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
45
|
+
exports.ConnectorService = void 0;
|
|
46
|
+
/**
|
|
47
|
+
* 连接器服务
|
|
48
|
+
*
|
|
49
|
+
* 文件系统驱动的连接器管理服务。
|
|
50
|
+
* 扫描 data/connectors/ 目录,每个 JSON 文件代表一个连接器配置。
|
|
51
|
+
* 同时支持目录式连接器包(含 manifest.json + mcp-servers/ + skills/)。
|
|
52
|
+
* 提供连接器的 CRUD、连接测试、工具发现、清单生成等能力。
|
|
53
|
+
*/
|
|
54
|
+
const core_1 = require("@midwayjs/core");
|
|
55
|
+
const midwayjs_base_1 = require("@cicctencent/midwayjs-base");
|
|
56
|
+
const fs = __importStar(require("fs"));
|
|
57
|
+
const fsp = __importStar(require("fs/promises"));
|
|
58
|
+
const path = __importStar(require("path"));
|
|
59
|
+
const agent_server_1 = require("@cicctencent/agent-server");
|
|
60
|
+
const index_1 = require("../connector/index");
|
|
61
|
+
/** 连接器存储目录 */
|
|
62
|
+
const CONNECTORS_DIR = path.resolve(process.cwd(), 'data', 'connectors');
|
|
63
|
+
/** 内存缓存:目录式连接器实体 */
|
|
64
|
+
let connectorCache = [];
|
|
65
|
+
/** 连接器 ID → 目录名 映射 */
|
|
66
|
+
const connectorDirMap = new Map();
|
|
67
|
+
let ConnectorService = class ConnectorService extends midwayjs_base_1.BaseService {
|
|
68
|
+
constructor() {
|
|
69
|
+
super(...arguments);
|
|
70
|
+
this.initialized = false;
|
|
71
|
+
}
|
|
72
|
+
async init() {
|
|
73
|
+
try {
|
|
74
|
+
await fsp.mkdir(CONNECTORS_DIR, { recursive: true });
|
|
75
|
+
this.initialized = true;
|
|
76
|
+
// 自动发现目录式连接器
|
|
77
|
+
await this.autoDiscoverConnectors();
|
|
78
|
+
console.log('[ConnectorService] 初始化完成');
|
|
79
|
+
}
|
|
80
|
+
catch (err) {
|
|
81
|
+
console.error('[ConnectorService] 初始化失败:', err.message);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
/** 列出所有连接器 */
|
|
85
|
+
async list() {
|
|
86
|
+
await this.ensureDir();
|
|
87
|
+
const files = await fsp.readdir(CONNECTORS_DIR);
|
|
88
|
+
const records = [];
|
|
89
|
+
for (const file of files) {
|
|
90
|
+
if (!file.endsWith('.json'))
|
|
91
|
+
continue;
|
|
92
|
+
try {
|
|
93
|
+
const raw = await fsp.readFile(path.join(CONNECTORS_DIR, file), 'utf-8');
|
|
94
|
+
const record = JSON.parse(raw);
|
|
95
|
+
records.push(record);
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
// 跳过损坏的文件
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return records.sort((a, b) => b.updatedAt - a.updatedAt);
|
|
102
|
+
}
|
|
103
|
+
/** 获取单个连接器 */
|
|
104
|
+
async get(id) {
|
|
105
|
+
const filePath = this.getFilePath(id);
|
|
106
|
+
try {
|
|
107
|
+
const raw = await fsp.readFile(filePath, 'utf-8');
|
|
108
|
+
return JSON.parse(raw);
|
|
109
|
+
}
|
|
110
|
+
catch {
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
/** 创建连接器 */
|
|
115
|
+
async create(config) {
|
|
116
|
+
const id = this.generateId(config.name);
|
|
117
|
+
const record = {
|
|
118
|
+
id,
|
|
119
|
+
config,
|
|
120
|
+
createdAt: Date.now(),
|
|
121
|
+
updatedAt: Date.now(),
|
|
122
|
+
};
|
|
123
|
+
await this.ensureDir();
|
|
124
|
+
await fsp.writeFile(this.getFilePath(id), JSON.stringify(record, null, 2), 'utf-8');
|
|
125
|
+
return record;
|
|
126
|
+
}
|
|
127
|
+
/** 更新连接器 */
|
|
128
|
+
async update(id, config) {
|
|
129
|
+
const existing = await this.get(id);
|
|
130
|
+
if (!existing) {
|
|
131
|
+
return null;
|
|
132
|
+
}
|
|
133
|
+
const record = {
|
|
134
|
+
...existing,
|
|
135
|
+
config: { ...existing.config, ...config },
|
|
136
|
+
updatedAt: Date.now(),
|
|
137
|
+
};
|
|
138
|
+
await fsp.writeFile(this.getFilePath(id), JSON.stringify(record, null, 2), 'utf-8');
|
|
139
|
+
return record;
|
|
140
|
+
}
|
|
141
|
+
/** 删除连接器 */
|
|
142
|
+
async delete(id) {
|
|
143
|
+
const filePath = this.getFilePath(id);
|
|
144
|
+
try {
|
|
145
|
+
await fsp.unlink(filePath);
|
|
146
|
+
return true;
|
|
147
|
+
}
|
|
148
|
+
catch {
|
|
149
|
+
return false;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
/** 测试连接 */
|
|
153
|
+
async testConnection(id) {
|
|
154
|
+
const record = await this.get(id);
|
|
155
|
+
if (!record) {
|
|
156
|
+
return {
|
|
157
|
+
success: false,
|
|
158
|
+
message: '连接器不存在',
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
const adapter = (0, index_1.getAdapter)(record.config.type);
|
|
162
|
+
return adapter.testConnection(record.config);
|
|
163
|
+
}
|
|
164
|
+
/** 测试配置(未保存的配置) */
|
|
165
|
+
async testConfig(config) {
|
|
166
|
+
const adapter = (0, index_1.getAdapter)(config.type);
|
|
167
|
+
return adapter.testConnection(config);
|
|
168
|
+
}
|
|
169
|
+
/** 发现工具 */
|
|
170
|
+
async discoverTools(id) {
|
|
171
|
+
const record = await this.get(id);
|
|
172
|
+
if (!record) {
|
|
173
|
+
throw new Error('连接器不存在');
|
|
174
|
+
}
|
|
175
|
+
const adapter = (0, index_1.getAdapter)(record.config.type);
|
|
176
|
+
return adapter.discoverTools(record.config);
|
|
177
|
+
}
|
|
178
|
+
/** 生成清单 */
|
|
179
|
+
async generateManifest(id) {
|
|
180
|
+
const record = await this.get(id);
|
|
181
|
+
if (!record) {
|
|
182
|
+
throw new Error('连接器不存在');
|
|
183
|
+
}
|
|
184
|
+
const adapter = (0, index_1.getAdapter)(record.config.type);
|
|
185
|
+
return adapter.generateManifest(record.config);
|
|
186
|
+
}
|
|
187
|
+
/** 生成 MCP 服务器配置 */
|
|
188
|
+
async generateMCPServerConfigs(id) {
|
|
189
|
+
const record = await this.get(id);
|
|
190
|
+
if (!record) {
|
|
191
|
+
throw new Error('连接器不存在');
|
|
192
|
+
}
|
|
193
|
+
const adapter = (0, index_1.getAdapter)(record.config.type);
|
|
194
|
+
return adapter.generateMCPServerConfigs(record.config);
|
|
195
|
+
}
|
|
196
|
+
/** 获取所有数据源类型 */
|
|
197
|
+
getDataSourceTypes() {
|
|
198
|
+
return (0, index_1.listDataSourceTypes)();
|
|
199
|
+
}
|
|
200
|
+
/** 获取所有适配器类型 */
|
|
201
|
+
getAdapterTypes() {
|
|
202
|
+
return (0, index_1.listAdapterTypes)();
|
|
203
|
+
}
|
|
204
|
+
/** 获取数据源类型信息(前端向导展示用) */
|
|
205
|
+
getDataSourceTypeInfos() {
|
|
206
|
+
return (0, index_1.getDataSourceTypeInfos)();
|
|
207
|
+
}
|
|
208
|
+
/** 获取指定类型的信息 */
|
|
209
|
+
getDataSourceTypeInfo(type) {
|
|
210
|
+
return (0, index_1.getDataSourceTypeInfo)(type);
|
|
211
|
+
}
|
|
212
|
+
// ===================== 目录式连接器包管理 =====================
|
|
213
|
+
/** 自动发现连接器:扫描 data/connectors/ 目录,为每个有 manifest.json 的目录构建连接器实体 */
|
|
214
|
+
async autoDiscoverConnectors() {
|
|
215
|
+
if (!fs.existsSync(CONNECTORS_DIR)) {
|
|
216
|
+
fs.mkdirSync(CONNECTORS_DIR, { recursive: true });
|
|
217
|
+
connectorCache = [];
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
const newCache = [];
|
|
221
|
+
connectorDirMap.clear();
|
|
222
|
+
for (const dirName of fs.readdirSync(CONNECTORS_DIR)) {
|
|
223
|
+
const manifestPath = path.join(CONNECTORS_DIR, dirName, 'manifest.json');
|
|
224
|
+
if (!fs.existsSync(manifestPath))
|
|
225
|
+
continue;
|
|
226
|
+
try {
|
|
227
|
+
const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf-8'));
|
|
228
|
+
const packageDir = path.join(CONNECTORS_DIR, dirName);
|
|
229
|
+
const connector = this.buildConnectorFromManifest(dirName, manifest, packageDir);
|
|
230
|
+
connectorDirMap.set(connector.id, dirName);
|
|
231
|
+
newCache.push(connector);
|
|
232
|
+
console.log(`[ConnectorService] Discovered: ${manifest.name} (${connector.mcpServerIds.length} MCP, ${connector.skillIds.length} skills, enabled=${connector.enabled})`);
|
|
233
|
+
}
|
|
234
|
+
catch (e) {
|
|
235
|
+
console.warn(`[ConnectorService] Failed to load ${dirName}:`, e?.message);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
connectorCache = newCache;
|
|
239
|
+
console.log(`[ConnectorService] Auto-discovery complete: ${connectorCache.length} connectors`);
|
|
240
|
+
}
|
|
241
|
+
/** 从 manifest 构建连接器实体 */
|
|
242
|
+
buildConnectorFromManifest(dirName, manifest, packageDir) {
|
|
243
|
+
const id = dirName;
|
|
244
|
+
const now = new Date().toISOString();
|
|
245
|
+
const enabled = manifest.enabled !== false;
|
|
246
|
+
// 扫描 mcp-servers/ 目录获取 MCP 服务器 ID 列表
|
|
247
|
+
const mcpServerIds = [];
|
|
248
|
+
const mcpServersDir = path.join(packageDir, 'mcp-servers');
|
|
249
|
+
if (enabled && fs.existsSync(mcpServersDir)) {
|
|
250
|
+
for (const file of fs.readdirSync(mcpServersDir)) {
|
|
251
|
+
if (!file.endsWith('.json'))
|
|
252
|
+
continue;
|
|
253
|
+
try {
|
|
254
|
+
const serverConfig = JSON.parse(fs.readFileSync(path.join(mcpServersDir, file), 'utf-8'));
|
|
255
|
+
mcpServerIds.push(serverConfig.id || path.basename(file, '.json'));
|
|
256
|
+
}
|
|
257
|
+
catch { /* skip */ }
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
// 扫描 skills/ 目录获取 Skill ID 列表
|
|
261
|
+
const skillIds = [];
|
|
262
|
+
const skillsDir = path.join(packageDir, 'skills');
|
|
263
|
+
if (fs.existsSync(skillsDir)) {
|
|
264
|
+
for (const file of fs.readdirSync(skillsDir)) {
|
|
265
|
+
if (file.endsWith('.md')) {
|
|
266
|
+
skillIds.push(path.basename(file, '.md'));
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
return {
|
|
271
|
+
id,
|
|
272
|
+
name: manifest.name,
|
|
273
|
+
description: manifest.description,
|
|
274
|
+
icon: manifest.icon,
|
|
275
|
+
color: manifest.color,
|
|
276
|
+
category: manifest.category || 'data',
|
|
277
|
+
version: manifest.version,
|
|
278
|
+
author: manifest.author,
|
|
279
|
+
mcpServerIds,
|
|
280
|
+
skillIds,
|
|
281
|
+
enabled,
|
|
282
|
+
status: 'installed',
|
|
283
|
+
dataSourceType: manifest.dataSourceType,
|
|
284
|
+
dataSourceConfig: manifest.dataSourceConfig,
|
|
285
|
+
createdAt: now,
|
|
286
|
+
updatedAt: now,
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
/** 列出所有目录式连接器实体 */
|
|
290
|
+
listConnectorEntities() {
|
|
291
|
+
return [...connectorCache];
|
|
292
|
+
}
|
|
293
|
+
/** 获取单个目录式连接器实体 */
|
|
294
|
+
getConnectorEntity(id) {
|
|
295
|
+
return connectorCache.find(c => c.id === id);
|
|
296
|
+
}
|
|
297
|
+
/** 获取连接器包目录(校验存在性) */
|
|
298
|
+
getConnectorPackageDir(connectorId) {
|
|
299
|
+
const dirName = connectorDirMap.get(connectorId);
|
|
300
|
+
if (!dirName)
|
|
301
|
+
throw new Error(`连接器不存在: ${connectorId}`);
|
|
302
|
+
return path.join(CONNECTORS_DIR, dirName);
|
|
303
|
+
}
|
|
304
|
+
/** 读取 manifest.json */
|
|
305
|
+
getManifest(connectorId) {
|
|
306
|
+
const dirName = connectorDirMap.get(connectorId);
|
|
307
|
+
if (!dirName)
|
|
308
|
+
throw new Error(`连接器不存在: ${connectorId}`);
|
|
309
|
+
const manifestPath = path.join(CONNECTORS_DIR, dirName, 'manifest.json');
|
|
310
|
+
if (!fs.existsSync(manifestPath))
|
|
311
|
+
throw new Error(`manifest.json 不存在: ${dirName}`);
|
|
312
|
+
return JSON.parse(fs.readFileSync(manifestPath, 'utf-8'));
|
|
313
|
+
}
|
|
314
|
+
/** 更新 manifest.json */
|
|
315
|
+
updateManifest(connectorId, updates) {
|
|
316
|
+
const dirName = connectorDirMap.get(connectorId);
|
|
317
|
+
if (!dirName)
|
|
318
|
+
throw new Error(`连接器不存在: ${connectorId}`);
|
|
319
|
+
const manifestPath = path.join(CONNECTORS_DIR, dirName, 'manifest.json');
|
|
320
|
+
const manifest = this.getManifest(connectorId);
|
|
321
|
+
const updated = { ...manifest, ...updates };
|
|
322
|
+
fs.writeFileSync(manifestPath, JSON.stringify(updated, null, 2), 'utf-8');
|
|
323
|
+
return updated;
|
|
324
|
+
}
|
|
325
|
+
/** 启用/禁用连接器,回写 manifest.json */
|
|
326
|
+
toggleConnector(id, enabled) {
|
|
327
|
+
const connector = connectorCache.find(c => c.id === id);
|
|
328
|
+
if (!connector)
|
|
329
|
+
return undefined;
|
|
330
|
+
if (connector.enabled === enabled)
|
|
331
|
+
return { ...connector };
|
|
332
|
+
connector.enabled = enabled;
|
|
333
|
+
connector.updatedAt = new Date().toISOString();
|
|
334
|
+
// 回写 manifest.json
|
|
335
|
+
const dirName = connectorDirMap.get(connector.id);
|
|
336
|
+
if (dirName) {
|
|
337
|
+
const manifest = this.getManifest(connector.id);
|
|
338
|
+
manifest.enabled = enabled;
|
|
339
|
+
const manifestPath = path.join(CONNECTORS_DIR, dirName, 'manifest.json');
|
|
340
|
+
fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2), 'utf-8');
|
|
341
|
+
}
|
|
342
|
+
if (enabled) {
|
|
343
|
+
// 启用:重新扫描 MCP/Skills
|
|
344
|
+
const packageDir = this.getConnectorPackageDir(connector.id);
|
|
345
|
+
const manifest = this.getManifest(connector.id);
|
|
346
|
+
connector.mcpServerIds = [];
|
|
347
|
+
const mcpServersDir = path.join(packageDir, 'mcp-servers');
|
|
348
|
+
if (fs.existsSync(mcpServersDir)) {
|
|
349
|
+
for (const file of fs.readdirSync(mcpServersDir)) {
|
|
350
|
+
if (!file.endsWith('.json'))
|
|
351
|
+
continue;
|
|
352
|
+
try {
|
|
353
|
+
const serverConfig = JSON.parse(fs.readFileSync(path.join(mcpServersDir, file), 'utf-8'));
|
|
354
|
+
connector.mcpServerIds.push(serverConfig.id || path.basename(file, '.json'));
|
|
355
|
+
}
|
|
356
|
+
catch { /* skip */ }
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
console.log(`[ConnectorService] Enabled: ${connector.name}`);
|
|
360
|
+
}
|
|
361
|
+
else {
|
|
362
|
+
// 禁用:清理 MCP 引用
|
|
363
|
+
connector.mcpServerIds = [];
|
|
364
|
+
console.log(`[ConnectorService] Disabled: ${connector.name}`);
|
|
365
|
+
}
|
|
366
|
+
return { ...connector };
|
|
367
|
+
}
|
|
368
|
+
/** 重新生成连接器:重新调用适配器发现工具,清空并重写 mcp-servers/*.json */
|
|
369
|
+
async regenerateConnector(connectorId) {
|
|
370
|
+
const dirName = connectorDirMap.get(connectorId);
|
|
371
|
+
if (!dirName)
|
|
372
|
+
throw new Error(`连接器不存在: ${connectorId}`);
|
|
373
|
+
const packageDir = path.join(CONNECTORS_DIR, dirName);
|
|
374
|
+
const manifest = this.getManifest(connectorId);
|
|
375
|
+
const dsType = manifest.dataSourceType;
|
|
376
|
+
const dsConfig = manifest.dataSourceConfig;
|
|
377
|
+
if (!dsType || !dsConfig) {
|
|
378
|
+
throw new Error('此连接器无数据源配置,无法重新生成');
|
|
379
|
+
}
|
|
380
|
+
// 调用适配器重新发现工具
|
|
381
|
+
const adapter = (0, index_1.getAdapter)(dsType);
|
|
382
|
+
const resolvedDsConfig = (0, agent_server_1.expandEnvVars)(dsConfig);
|
|
383
|
+
const config = { type: dsType, name: manifest.name, ...resolvedDsConfig, enabled: true };
|
|
384
|
+
const tools = await adapter.discoverTools(config);
|
|
385
|
+
// 清空并重写 mcp-servers/*.json
|
|
386
|
+
const mcpDir = path.join(packageDir, 'mcp-servers');
|
|
387
|
+
if (fs.existsSync(mcpDir)) {
|
|
388
|
+
for (const file of fs.readdirSync(mcpDir)) {
|
|
389
|
+
if (file.endsWith('.json')) {
|
|
390
|
+
fs.unlinkSync(path.join(mcpDir, file));
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
else {
|
|
395
|
+
fs.mkdirSync(mcpDir, { recursive: true });
|
|
396
|
+
}
|
|
397
|
+
// 生成并写入新的 MCP 服务器配置
|
|
398
|
+
const mcpConfigs = await adapter.generateMCPServerConfigs(config);
|
|
399
|
+
for (const mcpConfig of mcpConfigs) {
|
|
400
|
+
const fileName = mcpConfig.name.replace(/[^a-zA-Z0-9_-]/g, '_');
|
|
401
|
+
const serverConfig = {
|
|
402
|
+
name: mcpConfig.name,
|
|
403
|
+
transport: mcpConfig.transport,
|
|
404
|
+
command: mcpConfig.command,
|
|
405
|
+
args: mcpConfig.args,
|
|
406
|
+
env: mcpConfig.env,
|
|
407
|
+
url: mcpConfig.url,
|
|
408
|
+
toolDefinitions: mcpConfig.tools.map(t => ({
|
|
409
|
+
name: t.name,
|
|
410
|
+
description: t.description,
|
|
411
|
+
parameters: t.inputSchema,
|
|
412
|
+
})),
|
|
413
|
+
};
|
|
414
|
+
fs.writeFileSync(path.join(mcpDir, `${fileName}.json`), JSON.stringify(serverConfig, null, 2), 'utf-8');
|
|
415
|
+
}
|
|
416
|
+
console.log(`[ConnectorService] Regenerated: ${dirName} (${tools.length} tools)`);
|
|
417
|
+
// 重新加载连接器
|
|
418
|
+
await this.autoDiscoverConnectors();
|
|
419
|
+
const connector = connectorCache.find(c => c.id === connectorId);
|
|
420
|
+
if (!connector)
|
|
421
|
+
throw new Error(`连接器重新生成后未找到: ${connectorId}`);
|
|
422
|
+
return { toolCount: tools.length, connector };
|
|
423
|
+
}
|
|
424
|
+
// ===================== MCP Server 文件 CRUD =====================
|
|
425
|
+
/** 新增 MCP 服务器配置文件 */
|
|
426
|
+
async addConnectorMCPServer(connectorId, config) {
|
|
427
|
+
const packageDir = this.getConnectorPackageDir(connectorId);
|
|
428
|
+
const name = config.name || 'new-server';
|
|
429
|
+
const fileName = name.replace(/[^a-zA-Z0-9_-]/g, '_');
|
|
430
|
+
const mcpDir = path.join(packageDir, 'mcp-servers');
|
|
431
|
+
const filePath = path.join(mcpDir, `${fileName}.json`);
|
|
432
|
+
if (!fs.existsSync(mcpDir))
|
|
433
|
+
fs.mkdirSync(mcpDir, { recursive: true });
|
|
434
|
+
if (fs.existsSync(filePath))
|
|
435
|
+
throw new Error(`MCP 服务器配置已存在: ${fileName}`);
|
|
436
|
+
fs.writeFileSync(filePath, JSON.stringify(config, null, 2), 'utf-8');
|
|
437
|
+
await this.autoDiscoverConnectors();
|
|
438
|
+
return { serverName: fileName };
|
|
439
|
+
}
|
|
440
|
+
/** 更新 MCP 服务器配置文件 */
|
|
441
|
+
async updateConnectorMCPServer(connectorId, serverName, config) {
|
|
442
|
+
const packageDir = this.getConnectorPackageDir(connectorId);
|
|
443
|
+
const fileName = serverName.replace(/[^a-zA-Z0-9_-]/g, '_');
|
|
444
|
+
const filePath = path.join(packageDir, 'mcp-servers', `${fileName}.json`);
|
|
445
|
+
if (!fs.existsSync(filePath))
|
|
446
|
+
throw new Error(`MCP 服务器配置不存在: ${fileName}`);
|
|
447
|
+
fs.writeFileSync(filePath, JSON.stringify(config, null, 2), 'utf-8');
|
|
448
|
+
await this.autoDiscoverConnectors();
|
|
449
|
+
}
|
|
450
|
+
/** 删除 MCP 服务器配置文件 */
|
|
451
|
+
async removeConnectorMCPServer(connectorId, serverName) {
|
|
452
|
+
const packageDir = this.getConnectorPackageDir(connectorId);
|
|
453
|
+
const fileName = serverName.replace(/[^a-zA-Z0-9_-]/g, '_');
|
|
454
|
+
const filePath = path.join(packageDir, 'mcp-servers', `${fileName}.json`);
|
|
455
|
+
if (!fs.existsSync(filePath))
|
|
456
|
+
throw new Error(`MCP 服务器配置不存在: ${fileName}`);
|
|
457
|
+
fs.unlinkSync(filePath);
|
|
458
|
+
await this.autoDiscoverConnectors();
|
|
459
|
+
}
|
|
460
|
+
// ===================== Skill 文件 CRUD =====================
|
|
461
|
+
/** 读取 Skill .md 文件完整内容 */
|
|
462
|
+
getConnectorSkillFile(connectorId, skillId) {
|
|
463
|
+
const packageDir = this.getConnectorPackageDir(connectorId);
|
|
464
|
+
const filePath = path.join(packageDir, 'skills', `${skillId}.md`);
|
|
465
|
+
if (!fs.existsSync(filePath))
|
|
466
|
+
throw new Error(`Skill 文件不存在: ${skillId}`);
|
|
467
|
+
return { content: fs.readFileSync(filePath, 'utf-8') };
|
|
468
|
+
}
|
|
469
|
+
/** 新建 Skill .md 文件 */
|
|
470
|
+
async addConnectorSkill(connectorId, skillId, content) {
|
|
471
|
+
const packageDir = this.getConnectorPackageDir(connectorId);
|
|
472
|
+
const safeId = skillId.replace(/[^a-zA-Z0-9_-]/g, '-');
|
|
473
|
+
const skillsDir = path.join(packageDir, 'skills');
|
|
474
|
+
const filePath = path.join(skillsDir, `${safeId}.md`);
|
|
475
|
+
if (!fs.existsSync(skillsDir))
|
|
476
|
+
fs.mkdirSync(skillsDir, { recursive: true });
|
|
477
|
+
if (fs.existsSync(filePath))
|
|
478
|
+
throw new Error(`Skill 已存在: ${safeId}`);
|
|
479
|
+
fs.writeFileSync(filePath, content, 'utf-8');
|
|
480
|
+
await this.autoDiscoverConnectors();
|
|
481
|
+
}
|
|
482
|
+
/** 更新 Skill .md 文件 */
|
|
483
|
+
async updateConnectorSkill(connectorId, skillId, content) {
|
|
484
|
+
const packageDir = this.getConnectorPackageDir(connectorId);
|
|
485
|
+
const filePath = path.join(packageDir, 'skills', `${skillId}.md`);
|
|
486
|
+
if (!fs.existsSync(filePath))
|
|
487
|
+
throw new Error(`Skill 文件不存在: ${skillId}`);
|
|
488
|
+
fs.writeFileSync(filePath, content, 'utf-8');
|
|
489
|
+
await this.autoDiscoverConnectors();
|
|
490
|
+
}
|
|
491
|
+
/** 删除 Skill .md 文件 */
|
|
492
|
+
async removeConnectorSkill(connectorId, skillId) {
|
|
493
|
+
const packageDir = this.getConnectorPackageDir(connectorId);
|
|
494
|
+
const filePath = path.join(packageDir, 'skills', `${skillId}.md`);
|
|
495
|
+
if (!fs.existsSync(filePath))
|
|
496
|
+
throw new Error(`Skill 文件不存在: ${skillId}`);
|
|
497
|
+
fs.unlinkSync(filePath);
|
|
498
|
+
await this.autoDiscoverConnectors();
|
|
499
|
+
}
|
|
500
|
+
// ===================== 私有方法 =====================
|
|
501
|
+
getFilePath(id) {
|
|
502
|
+
return path.join(CONNECTORS_DIR, `${id}.json`);
|
|
503
|
+
}
|
|
504
|
+
generateId(name) {
|
|
505
|
+
const slug = (name || 'connector')
|
|
506
|
+
.toLowerCase()
|
|
507
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
508
|
+
.replace(/^-|-$/g, '');
|
|
509
|
+
return `${slug}-${Date.now().toString(36)}`;
|
|
510
|
+
}
|
|
511
|
+
async ensureDir() {
|
|
512
|
+
await fsp.mkdir(CONNECTORS_DIR, { recursive: true });
|
|
513
|
+
}
|
|
514
|
+
};
|
|
515
|
+
exports.ConnectorService = ConnectorService;
|
|
516
|
+
__decorate([
|
|
517
|
+
(0, core_1.Init)(),
|
|
518
|
+
__metadata("design:type", Function),
|
|
519
|
+
__metadata("design:paramtypes", []),
|
|
520
|
+
__metadata("design:returntype", Promise)
|
|
521
|
+
], ConnectorService.prototype, "init", null);
|
|
522
|
+
exports.ConnectorService = ConnectorService = __decorate([
|
|
523
|
+
(0, core_1.Provide)()
|
|
524
|
+
], ConnectorService);
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { BaseService } from '@cicctencent/midwayjs-base';
|
|
2
|
+
import { DataSource, Repository } from 'typeorm';
|
|
3
|
+
import { OpenAIService } from './openai.service';
|
|
4
|
+
import AIKnowledgeBaseEntity from '../model/ai-knowledge-base.entity';
|
|
5
|
+
import AIKBDocumentEntity from '../model/ai-kb-document.entity';
|
|
6
|
+
import type { EmbeddingProvider } from '@cicctencent/agent-core';
|
|
7
|
+
/**
|
|
8
|
+
* 文档分块
|
|
9
|
+
*/
|
|
10
|
+
export interface DocumentChunk {
|
|
11
|
+
id: string;
|
|
12
|
+
documentId: number;
|
|
13
|
+
content: string;
|
|
14
|
+
embedding: number[];
|
|
15
|
+
metadata: Record<string, any>;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* 搜索选项
|
|
19
|
+
*/
|
|
20
|
+
export interface SearchOptions {
|
|
21
|
+
topK?: number;
|
|
22
|
+
scoreThreshold?: number;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* 知识库服务
|
|
26
|
+
* 管理知识库的创建、文档索引、向量搜索
|
|
27
|
+
*
|
|
28
|
+
* 向量存储委托给 agent-server 的 FileKnowledgeBase,
|
|
29
|
+
* 元数据(KnowledgeBase / KBDocument)仍由 TypeORM 实体管理。
|
|
30
|
+
*/
|
|
31
|
+
export declare class KnowledgeBaseService extends BaseService {
|
|
32
|
+
dataSource: DataSource;
|
|
33
|
+
openaiService: OpenAIService;
|
|
34
|
+
openaiConfig: any;
|
|
35
|
+
private kbRepo?;
|
|
36
|
+
private docRepo?;
|
|
37
|
+
/** FileKnowledgeBase 实例缓存: Map<knowledgeBaseId, FileKnowledgeBase> */
|
|
38
|
+
private kbInstances;
|
|
39
|
+
/** EmbeddingProvider 实例(懒加载) */
|
|
40
|
+
private _embeddingProvider?;
|
|
41
|
+
get kbModel(): Repository<AIKnowledgeBaseEntity>;
|
|
42
|
+
get docModel(): Repository<AIKBDocumentEntity>;
|
|
43
|
+
/**
|
|
44
|
+
* 获取 EmbeddingProvider,使用 OpenAIService 生成 embedding
|
|
45
|
+
*/
|
|
46
|
+
getEmbeddingProvider(): EmbeddingProvider;
|
|
47
|
+
/**
|
|
48
|
+
* 获取或创建 FileKnowledgeBase 实例
|
|
49
|
+
* 每个 KnowledgeBase 对应一个 FileKnowledgeBase(通过 docId 前缀隔离)
|
|
50
|
+
*/
|
|
51
|
+
private getFileKB;
|
|
52
|
+
/** 列出知识库 */
|
|
53
|
+
list(applicationId: number, options?: {
|
|
54
|
+
enabled?: boolean;
|
|
55
|
+
status?: string;
|
|
56
|
+
}): Promise<AIKnowledgeBaseEntity[]>;
|
|
57
|
+
/** 获取单个知识库 */
|
|
58
|
+
get(id: number, applicationId?: number): Promise<AIKnowledgeBaseEntity>;
|
|
59
|
+
/** 创建知识库 */
|
|
60
|
+
create(applicationId: number, data: Partial<AIKnowledgeBaseEntity>): Promise<AIKnowledgeBaseEntity>;
|
|
61
|
+
/** 更新知识库 */
|
|
62
|
+
update(id: number, applicationId: number, data: Partial<AIKnowledgeBaseEntity>): Promise<AIKnowledgeBaseEntity>;
|
|
63
|
+
/** 删除知识库 */
|
|
64
|
+
delete(id: number, applicationId: number): Promise<void>;
|
|
65
|
+
/** 启用知识库 */
|
|
66
|
+
enable(id: number, applicationId: number): Promise<AIKnowledgeBaseEntity>;
|
|
67
|
+
/** 禁用知识库 */
|
|
68
|
+
disable(id: number, applicationId: number): Promise<AIKnowledgeBaseEntity>;
|
|
69
|
+
/** 获取文档列表 */
|
|
70
|
+
getDocuments(knowledgeBaseId: number): Promise<AIKBDocumentEntity[]>;
|
|
71
|
+
/** 删除文档 */
|
|
72
|
+
deleteDocument(documentId: number): Promise<void>;
|
|
73
|
+
/**
|
|
74
|
+
* 从文件索引文档
|
|
75
|
+
* 使用 agent-server 的 parseDocument() 解析文件 + FileKnowledgeBase.ingest() 存储
|
|
76
|
+
*
|
|
77
|
+
* @param id 知识库 ID
|
|
78
|
+
* @param filePath 文件路径
|
|
79
|
+
* @param title 文档标题(可选,默认使用文件名)
|
|
80
|
+
*/
|
|
81
|
+
indexFromFile(id: number, filePath: string, title?: string): Promise<{
|
|
82
|
+
documentId: number;
|
|
83
|
+
chunkCount: number;
|
|
84
|
+
}>;
|
|
85
|
+
/**
|
|
86
|
+
* 索引文档
|
|
87
|
+
* 对于有 sourcePath 的文档使用 parseDocument() 解析,否则使用内置分块逻辑
|
|
88
|
+
* 所有分块通过 FileKnowledgeBase.ingest() 存储
|
|
89
|
+
*/
|
|
90
|
+
indexDocuments(id: number, documents: Array<{
|
|
91
|
+
title: string;
|
|
92
|
+
content: string;
|
|
93
|
+
sourcePath?: string;
|
|
94
|
+
sourceType?: string;
|
|
95
|
+
meta?: Record<string, any>;
|
|
96
|
+
}>): Promise<{
|
|
97
|
+
documentCount: number;
|
|
98
|
+
chunkCount: number;
|
|
99
|
+
}>;
|
|
100
|
+
/**
|
|
101
|
+
* 重新索引
|
|
102
|
+
*/
|
|
103
|
+
reindex(id: number): Promise<{
|
|
104
|
+
documentCount: number;
|
|
105
|
+
chunkCount: number;
|
|
106
|
+
}>;
|
|
107
|
+
/**
|
|
108
|
+
* 向量搜索
|
|
109
|
+
* 使用 FileKnowledgeBase.search(query, topK) 进行语义检索
|
|
110
|
+
*/
|
|
111
|
+
search(id: number, query: string, options?: SearchOptions): Promise<Array<{
|
|
112
|
+
content: string;
|
|
113
|
+
score: number;
|
|
114
|
+
metadata: Record<string, any>;
|
|
115
|
+
}>>;
|
|
116
|
+
/**
|
|
117
|
+
* 使用 EmbeddingVectorIndex 进行向量搜索
|
|
118
|
+
* 适用于需要自定义向量索引的场景
|
|
119
|
+
*
|
|
120
|
+
* @param id 知识库 ID
|
|
121
|
+
* @param query 查询文本
|
|
122
|
+
* @param topK 返回结果数
|
|
123
|
+
*/
|
|
124
|
+
searchWithVectorIndex(id: number, query: string, topK?: number): Promise<Array<{
|
|
125
|
+
content: string;
|
|
126
|
+
score: number;
|
|
127
|
+
metadata: Record<string, any>;
|
|
128
|
+
}>>;
|
|
129
|
+
/**
|
|
130
|
+
* 使用配置参数对文本进行分块
|
|
131
|
+
* 参考 agent-server parseDocument 的 chunkText 逻辑
|
|
132
|
+
*/
|
|
133
|
+
private chunkTextWithConfig;
|
|
134
|
+
/**
|
|
135
|
+
* 哈希向量(降级方案)
|
|
136
|
+
*/
|
|
137
|
+
private hashEmbedding;
|
|
138
|
+
}
|