@kafca/agentdock 0.1.7
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 +70 -0
- package/bin/agentdock.mjs +275 -0
- package/build/icon.png +0 -0
- package/dist/renderer/assets/index-BaNpzC6d.js +482 -0
- package/dist/renderer/assets/index-CLWJyO0E.css +11 -0
- package/dist/renderer/favicon.svg +19 -0
- package/dist/renderer/index.html +14 -0
- package/dist/renderer/logo-options.svg +153 -0
- package/dist-electron/electron/knowledge-skill-script.test.js +125 -0
- package/dist-electron/electron/lac-cli.test.js +221 -0
- package/dist-electron/electron/local-core-refactor.test.js +1075 -0
- package/dist-electron/electron/main.js +163 -0
- package/dist-electron/electron/plugin-kernel.test.js +534 -0
- package/dist-electron/electron/preload.js +2 -0
- package/dist-electron/package.json +3 -0
- package/dist-electron/packages/contracts/src/index.js +18 -0
- package/dist-electron/packages/contracts/src/local-core.js +2 -0
- package/dist-electron/packages/core-sdk/src/index.js +406 -0
- package/dist-electron/packages/knowledge-api/src/ai-vector-provider.js +388 -0
- package/dist-electron/packages/knowledge-api/src/index.js +146 -0
- package/dist-electron/packages/knowledge-api/src/sqlite-store.js +467 -0
- package/dist-electron/packages/knowledge-api/src/thread-knowledge-store.js +21 -0
- package/dist-electron/packages/knowledge-api/test/ai-vector-provider.test.js +412 -0
- package/dist-electron/packages/plugin-sdk/src/index.js +2 -0
- package/dist-electron/services/local-ai-core/src/acp/local-core-acp-backend.js +369 -0
- package/dist-electron/services/local-ai-core/src/acp/local-core-acp-response-processor.js +110 -0
- package/dist-electron/services/local-ai-core/src/acp/local-core-acp-session-coordinator.js +171 -0
- package/dist-electron/services/local-ai-core/src/acp/local-core-acp-store.js +635 -0
- package/dist-electron/services/local-ai-core/src/acp/local-core-acp-transport.js +190 -0
- package/dist-electron/services/local-ai-core/src/acp/local-core-acp-turn-coordinator.js +244 -0
- package/dist-electron/services/local-ai-core/src/acp/workspace-acp-permissions.js +52 -0
- package/dist-electron/services/local-ai-core/src/cli/lac.js +290 -0
- package/dist-electron/services/local-ai-core/src/gateway/local-core-lark-gateway.js +976 -0
- package/dist-electron/services/local-ai-core/src/gateway/local-core-weixin-gateway.js +1143 -0
- package/dist-electron/services/local-ai-core/src/kernel/bootstrap.js +291 -0
- package/dist-electron/services/local-ai-core/src/kernel/capability-registry.js +67 -0
- package/dist-electron/services/local-ai-core/src/kernel/diagnostics.js +27 -0
- package/dist-electron/services/local-ai-core/src/kernel/event-bus.js +27 -0
- package/dist-electron/services/local-ai-core/src/kernel/lifecycle-manager.js +85 -0
- package/dist-electron/services/local-ai-core/src/kernel/plugin-registry.js +60 -0
- package/dist-electron/services/local-ai-core/src/plugins/builtin/agent-localcore-acp-plugin.js +114 -0
- package/dist-electron/services/local-ai-core/src/plugins/builtin/channel-lark-plugin.js +59 -0
- package/dist-electron/services/local-ai-core/src/plugins/builtin/channel-weixin-plugin.js +56 -0
- package/dist-electron/services/local-ai-core/src/plugins/builtin/knowledge-ai-vector-plugin.js +7 -0
- package/dist-electron/services/local-ai-core/src/plugins/builtin/knowledge-noop-plugin.js +7 -0
- package/dist-electron/services/local-ai-core/src/plugins/builtin/runtime-capabilities-plugin.js +62 -0
- package/dist-electron/services/local-ai-core/src/plugins/builtin/scheduler-cron-plugin.js +49 -0
- package/dist-electron/services/local-ai-core/src/plugins/builtin/scheduler-lark-plugin.js +38 -0
- package/dist-electron/services/local-ai-core/src/plugins/builtin/scheduler-weixin-plugin.js +38 -0
- package/dist-electron/services/local-ai-core/src/router/workspace-route-config.js +230 -0
- package/dist-electron/services/local-ai-core/src/router/workspace-router-types.js +2 -0
- package/dist-electron/services/local-ai-core/src/router/workspace-router.js +389 -0
- package/dist-electron/services/local-ai-core/src/runtime/local-core-controller.js +315 -0
- package/dist-electron/services/local-ai-core/src/runtime/local-core-runtime-state.js +282 -0
- package/dist-electron/services/local-ai-core/src/runtime/server.js +465 -0
- package/dist-electron/services/local-ai-core/src/runtime/standalone.js +38 -0
- package/dist-electron/services/local-ai-core/src/scheduler/adapters.js +2 -0
- package/dist-electron/services/local-ai-core/src/scheduler/cron-command-detector.js +70 -0
- package/dist-electron/services/local-ai-core/src/scheduler/cron.js +53 -0
- package/dist-electron/services/local-ai-core/src/scheduler/execution-policy.js +2 -0
- package/dist-electron/services/local-ai-core/src/scheduler/lark-execution-policies.js +66 -0
- package/dist-electron/services/local-ai-core/src/scheduler/lark-schedule-adapter.js +77 -0
- package/dist-electron/services/local-ai-core/src/scheduler/scheduled-conversation-executor.js +46 -0
- package/dist-electron/services/local-ai-core/src/scheduler/scheduler-run-lifecycle.js +64 -0
- package/dist-electron/services/local-ai-core/src/scheduler/scheduler-service.js +133 -0
- package/dist-electron/services/local-ai-core/src/scheduler/weixin-execution-policies.js +66 -0
- package/dist-electron/services/local-ai-core/src/scheduler/weixin-schedule-adapter.js +78 -0
- package/dist-electron/services/local-ai-core/src/thread/workspace-thread-id.js +17 -0
- package/dist-electron/services/local-ai-core/src/thread/workspace-thread-mappers.js +43 -0
- package/dist-electron/shared/desktop.js +195 -0
- package/dist-electron/src/api/client.js +73 -0
- package/dist-electron/src/api/sessions.js +21 -0
- package/dist-electron/src/lib/session-utils.js +51 -0
- package/dist-electron/src/pages/Threads/thread-chat-model.js +246 -0
- package/dist-electron/src/pages/Threads/thread-chat-model.test.js +76 -0
- package/dist-electron/src/pages/Threads/thread-chat-permission.js +26 -0
- package/dist-electron/src/pages/Threads/thread-chat-permission.test.js +102 -0
- package/dist-electron/src/pages/Threads/thread-chat-task-state.js +65 -0
- package/package.json +146 -0
|
@@ -0,0 +1,388 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AiVectorKnowledgeProvider = void 0;
|
|
4
|
+
exports.defaultKnowledgeConfig = defaultKnowledgeConfig;
|
|
5
|
+
const sqlite_store_js_1 = require("./sqlite-store.js");
|
|
6
|
+
const DEFAULT_CONFIG = {
|
|
7
|
+
baseUrl: '',
|
|
8
|
+
authMode: 'none',
|
|
9
|
+
token: '',
|
|
10
|
+
headerName: 'X-API-Key',
|
|
11
|
+
defaultCollection: 'personal_knowledge',
|
|
12
|
+
};
|
|
13
|
+
function clone(value) {
|
|
14
|
+
return JSON.parse(JSON.stringify(value));
|
|
15
|
+
}
|
|
16
|
+
function nowIso() {
|
|
17
|
+
return new Date().toISOString();
|
|
18
|
+
}
|
|
19
|
+
function randomId(prefix) {
|
|
20
|
+
return `${prefix}_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}`;
|
|
21
|
+
}
|
|
22
|
+
function normalizeConfig(input) {
|
|
23
|
+
return {
|
|
24
|
+
baseUrl: String(input?.baseUrl || '').trim(),
|
|
25
|
+
authMode: input?.authMode === 'bearer' || input?.authMode === 'header'
|
|
26
|
+
? input.authMode
|
|
27
|
+
: 'none',
|
|
28
|
+
token: String(input?.token || '').trim(),
|
|
29
|
+
headerName: String(input?.headerName || DEFAULT_CONFIG.headerName).trim() || DEFAULT_CONFIG.headerName,
|
|
30
|
+
defaultCollection: String(input?.defaultCollection || DEFAULT_CONFIG.defaultCollection).trim() || DEFAULT_CONFIG.defaultCollection,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
function normalizeBaseUrl(baseUrl) {
|
|
34
|
+
const trimmed = String(baseUrl || '').trim().replace(/\/+$/, '');
|
|
35
|
+
if (!trimmed) {
|
|
36
|
+
return '';
|
|
37
|
+
}
|
|
38
|
+
return trimmed.endsWith('/ai/vector/v1') ? trimmed : `${trimmed}/ai/vector/v1`;
|
|
39
|
+
}
|
|
40
|
+
function summarizeSnippet(text, limit = 220) {
|
|
41
|
+
const normalized = text.replace(/\s+/g, ' ').trim();
|
|
42
|
+
if (normalized.length <= limit) {
|
|
43
|
+
return normalized;
|
|
44
|
+
}
|
|
45
|
+
return `${normalized.slice(0, limit).trimEnd()}...`;
|
|
46
|
+
}
|
|
47
|
+
class AiVectorKnowledgeProvider {
|
|
48
|
+
store;
|
|
49
|
+
getConfigValue;
|
|
50
|
+
setConfigValue;
|
|
51
|
+
constructor(options) {
|
|
52
|
+
this.store = new sqlite_store_js_1.KnowledgeSqliteStore({ userDataPath: options.userDataPath });
|
|
53
|
+
this.getConfigValue = options.getConfig;
|
|
54
|
+
this.setConfigValue = options.setConfig;
|
|
55
|
+
}
|
|
56
|
+
async listSources() {
|
|
57
|
+
const bases = await this.listKnowledgeBases();
|
|
58
|
+
return bases.map((base) => ({
|
|
59
|
+
id: base.id,
|
|
60
|
+
name: base.name,
|
|
61
|
+
type: 'knowledge-base',
|
|
62
|
+
status: 'ready',
|
|
63
|
+
description: base.description,
|
|
64
|
+
fileCount: base.fileCount,
|
|
65
|
+
wordCount: base.wordCount,
|
|
66
|
+
}));
|
|
67
|
+
}
|
|
68
|
+
async getConfig() {
|
|
69
|
+
return normalizeConfig(this.getConfigValue());
|
|
70
|
+
}
|
|
71
|
+
async updateConfig(input) {
|
|
72
|
+
const merged = normalizeConfig({
|
|
73
|
+
...normalizeConfig(this.getConfigValue()),
|
|
74
|
+
...input,
|
|
75
|
+
});
|
|
76
|
+
return normalizeConfig(await this.setConfigValue(merged));
|
|
77
|
+
}
|
|
78
|
+
async listFolders() {
|
|
79
|
+
return this.store.listFolders();
|
|
80
|
+
}
|
|
81
|
+
async createFolder(input) {
|
|
82
|
+
const name = String(input.name || '').trim();
|
|
83
|
+
if (!name) {
|
|
84
|
+
throw new Error('Folder name is required.');
|
|
85
|
+
}
|
|
86
|
+
const folders = this.store.listFolders();
|
|
87
|
+
const parent = input.parentId ? folders.find((folder) => folder.id === input.parentId) || null : null;
|
|
88
|
+
if (input.parentId && !parent) {
|
|
89
|
+
throw new Error('Parent folder does not exist.');
|
|
90
|
+
}
|
|
91
|
+
const siblings = folders.filter((folder) => folder.parentId === (input.parentId || null));
|
|
92
|
+
const timestamp = nowIso();
|
|
93
|
+
const nextFolder = {
|
|
94
|
+
id: randomId('folder'),
|
|
95
|
+
name,
|
|
96
|
+
parentId: input.parentId || null,
|
|
97
|
+
path: this.buildFolderPath(name, parent || null),
|
|
98
|
+
sortOrder: siblings.length,
|
|
99
|
+
createdAt: timestamp,
|
|
100
|
+
updatedAt: timestamp,
|
|
101
|
+
};
|
|
102
|
+
return this.store.insertFolder(nextFolder);
|
|
103
|
+
}
|
|
104
|
+
async updateFolder(id, input) {
|
|
105
|
+
const name = String(input.name || '').trim();
|
|
106
|
+
if (!name) {
|
|
107
|
+
throw new Error('Folder name is required.');
|
|
108
|
+
}
|
|
109
|
+
const folder = this.store.getFolder(id);
|
|
110
|
+
if (!folder) {
|
|
111
|
+
throw new Error('Folder does not exist.');
|
|
112
|
+
}
|
|
113
|
+
const parent = folder.parentId ? this.store.getFolder(folder.parentId) : null;
|
|
114
|
+
const previousPath = folder.path;
|
|
115
|
+
const nextPath = this.buildFolderPath(name, parent);
|
|
116
|
+
return this.store.renameFolder(id, {
|
|
117
|
+
name,
|
|
118
|
+
previousPath,
|
|
119
|
+
nextPath,
|
|
120
|
+
updatedAt: nowIso(),
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
async deleteFolder(id) {
|
|
124
|
+
const hasChildren = this.store.hasFolderChildren(id);
|
|
125
|
+
if (hasChildren) {
|
|
126
|
+
throw new Error('Delete or move child folders before removing this folder.');
|
|
127
|
+
}
|
|
128
|
+
const hasBases = this.store.hasKnowledgeBasesInFolder(id);
|
|
129
|
+
if (hasBases) {
|
|
130
|
+
throw new Error('Delete or move knowledge bases before removing this folder.');
|
|
131
|
+
}
|
|
132
|
+
if (!this.store.getFolder(id)) {
|
|
133
|
+
throw new Error('Folder does not exist.');
|
|
134
|
+
}
|
|
135
|
+
this.store.deleteFolder(id);
|
|
136
|
+
return { deleted: true };
|
|
137
|
+
}
|
|
138
|
+
async listKnowledgeBases() {
|
|
139
|
+
return this.store.listKnowledgeBases();
|
|
140
|
+
}
|
|
141
|
+
async getKnowledgeBase(id) {
|
|
142
|
+
return this.findLocalKnowledgeBase(id);
|
|
143
|
+
}
|
|
144
|
+
async createKnowledgeBase(input) {
|
|
145
|
+
const name = String(input.name || '').trim();
|
|
146
|
+
if (!name) {
|
|
147
|
+
throw new Error('Knowledge base name is required.');
|
|
148
|
+
}
|
|
149
|
+
if (input.folderId && !this.store.getFolder(input.folderId)) {
|
|
150
|
+
throw new Error('Selected folder does not exist.');
|
|
151
|
+
}
|
|
152
|
+
const timestamp = nowIso();
|
|
153
|
+
const nextBase = {
|
|
154
|
+
id: randomId('kb'),
|
|
155
|
+
name,
|
|
156
|
+
description: String(input.description || '').trim(),
|
|
157
|
+
folderId: input.folderId || null,
|
|
158
|
+
creatorName: String(input.creatorName || '系统管理员').trim() || '系统管理员',
|
|
159
|
+
icon: String(input.icon || 'book').trim() || 'book',
|
|
160
|
+
fileCount: 0,
|
|
161
|
+
wordCount: 0,
|
|
162
|
+
createdAt: timestamp,
|
|
163
|
+
updatedAt: timestamp,
|
|
164
|
+
};
|
|
165
|
+
return this.store.insertKnowledgeBase(nextBase);
|
|
166
|
+
}
|
|
167
|
+
async updateKnowledgeBase(id, input) {
|
|
168
|
+
const current = this.findLocalKnowledgeBase(id);
|
|
169
|
+
if (input.folderId && !this.store.getFolder(input.folderId)) {
|
|
170
|
+
throw new Error('Selected folder does not exist.');
|
|
171
|
+
}
|
|
172
|
+
const next = {
|
|
173
|
+
...current,
|
|
174
|
+
name: input.name === undefined ? current.name : String(input.name || '').trim() || current.name,
|
|
175
|
+
description: input.description === undefined ? current.description : String(input.description || '').trim(),
|
|
176
|
+
folderId: input.folderId === undefined ? current.folderId : input.folderId || null,
|
|
177
|
+
creatorName: input.creatorName === undefined ? current.creatorName : String(input.creatorName || '').trim() || current.creatorName,
|
|
178
|
+
icon: input.icon === undefined ? current.icon : String(input.icon || '').trim() || current.icon,
|
|
179
|
+
updatedAt: nowIso(),
|
|
180
|
+
};
|
|
181
|
+
return this.store.updateKnowledgeBase(next);
|
|
182
|
+
}
|
|
183
|
+
async deleteKnowledgeBase(id) {
|
|
184
|
+
const base = this.store.getKnowledgeBase(id);
|
|
185
|
+
if (!base) {
|
|
186
|
+
throw new Error('Knowledge base does not exist.');
|
|
187
|
+
}
|
|
188
|
+
try {
|
|
189
|
+
const files = await this.listKnowledgeBaseFiles(id);
|
|
190
|
+
const remoteFileIds = files.length > 0
|
|
191
|
+
? files.map((file) => file.fileId)
|
|
192
|
+
: await this.discoverKnowledgeBaseFileIds(id);
|
|
193
|
+
if (remoteFileIds.length > 0) {
|
|
194
|
+
const config = this.requireConfigured();
|
|
195
|
+
await this.aiVectorRequest('/qdrant/batchDelete', {
|
|
196
|
+
method: 'POST',
|
|
197
|
+
body: JSON.stringify({
|
|
198
|
+
collection: config.defaultCollection,
|
|
199
|
+
file_ids: remoteFileIds,
|
|
200
|
+
knowledgebase_id: id,
|
|
201
|
+
}),
|
|
202
|
+
headers: {
|
|
203
|
+
'Content-Type': 'application/json',
|
|
204
|
+
},
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
catch {
|
|
209
|
+
// Best effort remote cleanup. Local metadata is still the source of truth for this module.
|
|
210
|
+
}
|
|
211
|
+
this.store.deleteKnowledgeBase(id);
|
|
212
|
+
return { deleted: true };
|
|
213
|
+
}
|
|
214
|
+
async listKnowledgeBaseFiles(knowledgeBaseId) {
|
|
215
|
+
this.findLocalKnowledgeBase(knowledgeBaseId);
|
|
216
|
+
return this.store.listKnowledgeBaseFiles(knowledgeBaseId);
|
|
217
|
+
}
|
|
218
|
+
async uploadKnowledgeBaseFiles(knowledgeBaseId, request) {
|
|
219
|
+
this.findLocalKnowledgeBase(knowledgeBaseId);
|
|
220
|
+
this.requireConfigured();
|
|
221
|
+
const response = await this.aiVectorRequest('/qdrant/file', {
|
|
222
|
+
method: 'POST',
|
|
223
|
+
body: request.body,
|
|
224
|
+
headers: {
|
|
225
|
+
'Content-Type': request.contentType,
|
|
226
|
+
},
|
|
227
|
+
});
|
|
228
|
+
const cachedFiles = (response || [])
|
|
229
|
+
.filter((item) => Boolean(item.success))
|
|
230
|
+
.map((item) => this.mapFile(item));
|
|
231
|
+
if (cachedFiles.length > 0) {
|
|
232
|
+
this.store.upsertKnowledgeBaseFiles(cachedFiles);
|
|
233
|
+
this.store.touchKnowledgeBase(knowledgeBaseId, nowIso());
|
|
234
|
+
}
|
|
235
|
+
return (response || []).map((item) => ({
|
|
236
|
+
fileId: String(item.file_id || ''),
|
|
237
|
+
fileName: String(item.file_name || ''),
|
|
238
|
+
fileType: String(item.file_type || ''),
|
|
239
|
+
success: Boolean(item.success),
|
|
240
|
+
message: String(item.msg || (item.success ? 'success' : 'Upload failed')),
|
|
241
|
+
wordCount: typeof item.word_count === 'number' ? item.word_count : null,
|
|
242
|
+
}));
|
|
243
|
+
}
|
|
244
|
+
async deleteKnowledgeBaseFile(knowledgeBaseId, fileId) {
|
|
245
|
+
this.findLocalKnowledgeBase(knowledgeBaseId);
|
|
246
|
+
const config = this.requireConfigured();
|
|
247
|
+
const response = await this.aiVectorRequest('/qdrant/delete', {
|
|
248
|
+
method: 'POST',
|
|
249
|
+
body: JSON.stringify({
|
|
250
|
+
collection: config.defaultCollection,
|
|
251
|
+
file_id: fileId,
|
|
252
|
+
knowledgebase_id: knowledgeBaseId,
|
|
253
|
+
}),
|
|
254
|
+
headers: {
|
|
255
|
+
'Content-Type': 'application/json',
|
|
256
|
+
},
|
|
257
|
+
});
|
|
258
|
+
const deleted = Boolean(response?.success);
|
|
259
|
+
if (deleted) {
|
|
260
|
+
this.store.deleteKnowledgeBaseFile(fileId);
|
|
261
|
+
this.store.touchKnowledgeBase(knowledgeBaseId, nowIso());
|
|
262
|
+
}
|
|
263
|
+
return { deleted };
|
|
264
|
+
}
|
|
265
|
+
async searchKnowledgeBase(knowledgeBaseId, input) {
|
|
266
|
+
const base = this.findLocalKnowledgeBase(knowledgeBaseId);
|
|
267
|
+
const config = this.requireConfigured();
|
|
268
|
+
const response = await this.aiVectorRequest('/qdrant/query', {
|
|
269
|
+
method: 'POST',
|
|
270
|
+
body: JSON.stringify({
|
|
271
|
+
collection: config.defaultCollection,
|
|
272
|
+
query: String(input.query || '').trim(),
|
|
273
|
+
knowledgebase_id: knowledgeBaseId,
|
|
274
|
+
limit: Math.max(1, Number(input.limit || 8)),
|
|
275
|
+
}),
|
|
276
|
+
headers: {
|
|
277
|
+
'Content-Type': 'application/json',
|
|
278
|
+
},
|
|
279
|
+
});
|
|
280
|
+
return (response?.documents || []).map((item) => {
|
|
281
|
+
const metadata = item.metadata || {};
|
|
282
|
+
const content = String(metadata.document || '');
|
|
283
|
+
return {
|
|
284
|
+
id: String(item.id || randomId('result')),
|
|
285
|
+
knowledgeBaseId,
|
|
286
|
+
fileId: String(metadata.file_id || ''),
|
|
287
|
+
fileName: String(metadata.file_name || '未命名文件'),
|
|
288
|
+
title: `${base.name} · ${String(metadata.file_name || '搜索结果')}`,
|
|
289
|
+
snippet: summarizeSnippet(content),
|
|
290
|
+
score: Number(item.score || 0),
|
|
291
|
+
chunkOffset: Number(metadata.chunk_offset || 0),
|
|
292
|
+
content,
|
|
293
|
+
};
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
buildFolderPath(name, parent) {
|
|
297
|
+
return parent ? `${parent.path}/${name}` : name;
|
|
298
|
+
}
|
|
299
|
+
findLocalKnowledgeBase(id) {
|
|
300
|
+
const base = this.store.getKnowledgeBase(id);
|
|
301
|
+
if (!base) {
|
|
302
|
+
throw new Error('Knowledge base does not exist.');
|
|
303
|
+
}
|
|
304
|
+
return clone(base);
|
|
305
|
+
}
|
|
306
|
+
requireConfigured() {
|
|
307
|
+
const config = normalizeConfig(this.getConfigValue());
|
|
308
|
+
if (!config.baseUrl) {
|
|
309
|
+
throw new Error('Knowledge service is not configured. Set the ai_vector base URL in Workspace settings.');
|
|
310
|
+
}
|
|
311
|
+
return config;
|
|
312
|
+
}
|
|
313
|
+
mapFile(file) {
|
|
314
|
+
return {
|
|
315
|
+
knowledgebaseId: file.knowledgebase_id || null,
|
|
316
|
+
fileId: String(file.file_id || ''),
|
|
317
|
+
fileName: String(file.file_name || ''),
|
|
318
|
+
fileType: String(file.file_type || ''),
|
|
319
|
+
fileSize: Number(file.file_size || 0),
|
|
320
|
+
folder: file.folder || null,
|
|
321
|
+
createTime: String(file.create_time || ''),
|
|
322
|
+
wordCount: typeof file.word_count === 'number' ? file.word_count : null,
|
|
323
|
+
metadata: file.metadata || null,
|
|
324
|
+
abstract: file.abstract || null,
|
|
325
|
+
fullContent: file.full_content || null,
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
async discoverKnowledgeBaseFileIds(knowledgeBaseId) {
|
|
329
|
+
const config = this.requireConfigured();
|
|
330
|
+
const response = await this.aiVectorRequest('/qdrant/query', {
|
|
331
|
+
method: 'POST',
|
|
332
|
+
body: JSON.stringify({
|
|
333
|
+
collection: config.defaultCollection,
|
|
334
|
+
query: '*',
|
|
335
|
+
knowledgebase_id: knowledgeBaseId,
|
|
336
|
+
limit: 200,
|
|
337
|
+
}),
|
|
338
|
+
headers: {
|
|
339
|
+
'Content-Type': 'application/json',
|
|
340
|
+
},
|
|
341
|
+
});
|
|
342
|
+
return Array.from(new Set((response?.documents || [])
|
|
343
|
+
.map((item) => String(item.metadata?.file_id || '').trim())
|
|
344
|
+
.filter(Boolean)));
|
|
345
|
+
}
|
|
346
|
+
async aiVectorRequest(path, init) {
|
|
347
|
+
const config = this.requireConfigured();
|
|
348
|
+
const baseUrl = normalizeBaseUrl(config.baseUrl);
|
|
349
|
+
const headers = {
|
|
350
|
+
...(init.headers || {}),
|
|
351
|
+
...this.buildAuthHeaders(config),
|
|
352
|
+
};
|
|
353
|
+
const response = await fetch(`${baseUrl}${path}`, {
|
|
354
|
+
method: init.method,
|
|
355
|
+
headers,
|
|
356
|
+
body: init.body,
|
|
357
|
+
});
|
|
358
|
+
const text = await response.text();
|
|
359
|
+
const payload = text ? JSON.parse(text) : null;
|
|
360
|
+
if (!response.ok) {
|
|
361
|
+
if (payload && typeof payload === 'object' && 'resultMsg' in payload) {
|
|
362
|
+
throw new Error(String(payload.resultMsg || `ai_vector request failed: ${response.status}`));
|
|
363
|
+
}
|
|
364
|
+
throw new Error(`ai_vector request failed: ${response.status}`);
|
|
365
|
+
}
|
|
366
|
+
if (payload && typeof payload === 'object' && ('resultCode' in payload || 'resultMsg' in payload || 'data' in payload)) {
|
|
367
|
+
const envelope = payload;
|
|
368
|
+
if (Number(envelope.resultCode || 0) !== 0) {
|
|
369
|
+
throw new Error(String(envelope.resultMsg || `ai_vector request failed: ${response.status}`));
|
|
370
|
+
}
|
|
371
|
+
return envelope.data;
|
|
372
|
+
}
|
|
373
|
+
return payload;
|
|
374
|
+
}
|
|
375
|
+
buildAuthHeaders(config) {
|
|
376
|
+
if (config.authMode === 'bearer' && config.token) {
|
|
377
|
+
return { Authorization: `Bearer ${config.token}` };
|
|
378
|
+
}
|
|
379
|
+
if (config.authMode === 'header' && config.token) {
|
|
380
|
+
return { [config.headerName || DEFAULT_CONFIG.headerName]: config.token };
|
|
381
|
+
}
|
|
382
|
+
return {};
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
exports.AiVectorKnowledgeProvider = AiVectorKnowledgeProvider;
|
|
386
|
+
function defaultKnowledgeConfig() {
|
|
387
|
+
return clone(DEFAULT_CONFIG);
|
|
388
|
+
}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.defaultKnowledgeConfig = exports.SqliteThreadKnowledgeAttachmentStore = exports.AiVectorKnowledgeProvider = exports.NoopKnowledgeProvider = exports.NoopThreadKnowledgeAttachmentStore = void 0;
|
|
4
|
+
exports.createAiVectorKnowledgePlugin = createAiVectorKnowledgePlugin;
|
|
5
|
+
exports.createNoopKnowledgePlugin = createNoopKnowledgePlugin;
|
|
6
|
+
const ai_vector_provider_js_1 = require("./ai-vector-provider.js");
|
|
7
|
+
Object.defineProperty(exports, "AiVectorKnowledgeProvider", { enumerable: true, get: function () { return ai_vector_provider_js_1.AiVectorKnowledgeProvider; } });
|
|
8
|
+
Object.defineProperty(exports, "defaultKnowledgeConfig", { enumerable: true, get: function () { return ai_vector_provider_js_1.defaultKnowledgeConfig; } });
|
|
9
|
+
const thread_knowledge_store_js_1 = require("./thread-knowledge-store.js");
|
|
10
|
+
Object.defineProperty(exports, "SqliteThreadKnowledgeAttachmentStore", { enumerable: true, get: function () { return thread_knowledge_store_js_1.SqliteThreadKnowledgeAttachmentStore; } });
|
|
11
|
+
class NoopThreadKnowledgeAttachmentStore {
|
|
12
|
+
async listThreadKnowledgeBaseIds() {
|
|
13
|
+
return [];
|
|
14
|
+
}
|
|
15
|
+
async updateThreadKnowledgeBaseIds() {
|
|
16
|
+
return [];
|
|
17
|
+
}
|
|
18
|
+
async deleteThreadKnowledgeBaseLinks() {
|
|
19
|
+
return { deleted: true };
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
exports.NoopThreadKnowledgeAttachmentStore = NoopThreadKnowledgeAttachmentStore;
|
|
23
|
+
class NoopKnowledgeProvider {
|
|
24
|
+
async listSources() {
|
|
25
|
+
return [];
|
|
26
|
+
}
|
|
27
|
+
async getConfig() {
|
|
28
|
+
return (0, ai_vector_provider_js_1.defaultKnowledgeConfig)();
|
|
29
|
+
}
|
|
30
|
+
async updateConfig() {
|
|
31
|
+
return (0, ai_vector_provider_js_1.defaultKnowledgeConfig)();
|
|
32
|
+
}
|
|
33
|
+
async listFolders() {
|
|
34
|
+
return [];
|
|
35
|
+
}
|
|
36
|
+
async createFolder(_input) {
|
|
37
|
+
throw new Error('Knowledge provider is unavailable.');
|
|
38
|
+
}
|
|
39
|
+
async updateFolder(_id, _input) {
|
|
40
|
+
throw new Error('Knowledge provider is unavailable.');
|
|
41
|
+
}
|
|
42
|
+
async deleteFolder(_id) {
|
|
43
|
+
throw new Error('Knowledge provider is unavailable.');
|
|
44
|
+
}
|
|
45
|
+
async listKnowledgeBases() {
|
|
46
|
+
return [];
|
|
47
|
+
}
|
|
48
|
+
async getKnowledgeBase(_id) {
|
|
49
|
+
throw new Error('Knowledge provider is unavailable.');
|
|
50
|
+
}
|
|
51
|
+
async createKnowledgeBase(_input) {
|
|
52
|
+
throw new Error('Knowledge provider is unavailable.');
|
|
53
|
+
}
|
|
54
|
+
async updateKnowledgeBase(_id, _input) {
|
|
55
|
+
throw new Error('Knowledge provider is unavailable.');
|
|
56
|
+
}
|
|
57
|
+
async deleteKnowledgeBase(_id) {
|
|
58
|
+
throw new Error('Knowledge provider is unavailable.');
|
|
59
|
+
}
|
|
60
|
+
async listKnowledgeBaseFiles(_knowledgeBaseId) {
|
|
61
|
+
return [];
|
|
62
|
+
}
|
|
63
|
+
async uploadKnowledgeBaseFiles(_knowledgeBaseId, _request) {
|
|
64
|
+
throw new Error('Knowledge provider is unavailable.');
|
|
65
|
+
}
|
|
66
|
+
async deleteKnowledgeBaseFile(_knowledgeBaseId, _fileId) {
|
|
67
|
+
throw new Error('Knowledge provider is unavailable.');
|
|
68
|
+
}
|
|
69
|
+
async searchKnowledgeBase(_knowledgeBaseId, _input) {
|
|
70
|
+
return [];
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
exports.NoopKnowledgeProvider = NoopKnowledgeProvider;
|
|
74
|
+
function createAiVectorKnowledgePlugin(options) {
|
|
75
|
+
let provider = null;
|
|
76
|
+
let attachments = null;
|
|
77
|
+
return {
|
|
78
|
+
manifest: {
|
|
79
|
+
id: 'knowledge.ai-vector',
|
|
80
|
+
kind: 'knowledge',
|
|
81
|
+
version: '0.1.0',
|
|
82
|
+
provides: ['knowledge:ai-vector'],
|
|
83
|
+
configSchema: {
|
|
84
|
+
fields: [
|
|
85
|
+
{ key: 'baseUrl', type: 'string', label: 'Base URL' },
|
|
86
|
+
{ key: 'authMode', type: 'string', label: 'Auth mode', defaultValue: 'none' },
|
|
87
|
+
{ key: 'defaultCollection', type: 'string', label: 'Default collection' },
|
|
88
|
+
],
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
capabilities: {
|
|
92
|
+
knowledge: [
|
|
93
|
+
{
|
|
94
|
+
id: 'knowledge.ai-vector',
|
|
95
|
+
sourceType: 'ai-vector',
|
|
96
|
+
enabled: true,
|
|
97
|
+
displayName: 'AI Vector Knowledge',
|
|
98
|
+
},
|
|
99
|
+
],
|
|
100
|
+
},
|
|
101
|
+
createRuntime(_ctx) {
|
|
102
|
+
provider ??= new ai_vector_provider_js_1.AiVectorKnowledgeProvider({
|
|
103
|
+
userDataPath: options.userDataPath,
|
|
104
|
+
getConfig: options.getConfig,
|
|
105
|
+
setConfig: options.setConfig,
|
|
106
|
+
});
|
|
107
|
+
attachments ??= new thread_knowledge_store_js_1.SqliteThreadKnowledgeAttachmentStore({
|
|
108
|
+
userDataPath: options.userDataPath,
|
|
109
|
+
});
|
|
110
|
+
return { provider, attachments };
|
|
111
|
+
},
|
|
112
|
+
healthCheck() {
|
|
113
|
+
return { status: 'healthy' };
|
|
114
|
+
},
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
function createNoopKnowledgePlugin() {
|
|
118
|
+
let provider = null;
|
|
119
|
+
let attachments = null;
|
|
120
|
+
return {
|
|
121
|
+
manifest: {
|
|
122
|
+
id: 'knowledge.noop',
|
|
123
|
+
kind: 'knowledge',
|
|
124
|
+
version: '0.1.0',
|
|
125
|
+
provides: ['knowledge:noop'],
|
|
126
|
+
},
|
|
127
|
+
capabilities: {
|
|
128
|
+
knowledge: [
|
|
129
|
+
{
|
|
130
|
+
id: 'knowledge.noop',
|
|
131
|
+
sourceType: 'noop',
|
|
132
|
+
enabled: false,
|
|
133
|
+
displayName: 'Disabled Knowledge',
|
|
134
|
+
},
|
|
135
|
+
],
|
|
136
|
+
},
|
|
137
|
+
createRuntime(_ctx) {
|
|
138
|
+
provider ??= new NoopKnowledgeProvider();
|
|
139
|
+
attachments ??= new NoopThreadKnowledgeAttachmentStore();
|
|
140
|
+
return { provider, attachments };
|
|
141
|
+
},
|
|
142
|
+
healthCheck() {
|
|
143
|
+
return { status: 'healthy' };
|
|
144
|
+
},
|
|
145
|
+
};
|
|
146
|
+
}
|