@lobehub/chat 0.147.11 → 0.147.13
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/CHANGELOG.md +50 -0
- package/contributing/Basic/Feature-Development.md +2 -2
- package/contributing/Basic/Feature-Development.zh-CN.md +2 -2
- package/package.json +1 -1
- package/src/database/{core → client/core}/__tests__/db-upgrade.test.ts +2 -2
- package/src/database/{core → client/core}/__tests__/db.test.ts +5 -6
- package/src/database/{core → client/core}/db.ts +18 -18
- package/src/database/{core → client/core}/index.ts +1 -1
- package/src/database/{core → client/core}/migrations/migrateSettingsToUser/index.ts +1 -1
- package/src/database/{core → client/core}/model.ts +7 -7
- package/src/database/{core → client/core}/sync.ts +3 -3
- package/src/database/{models → client/models}/__DEBUG.ts +3 -3
- package/src/database/{models → client/models}/__tests__/file.test.ts +3 -4
- package/src/database/{models → client/models}/__tests__/session.test.ts +3 -3
- package/src/database/{models → client/models}/__tests__/sessionGroup.test.ts +1 -1
- package/src/database/{models → client/models}/__tests__/topic.test.ts +4 -4
- package/src/database/{models → client/models}/file.ts +1 -1
- package/src/database/{models → client/models}/message.ts +3 -3
- package/src/database/{models → client/models}/plugin.ts +1 -1
- package/src/database/{models → client/models}/session.ts +3 -3
- package/src/database/{models → client/models}/sessionGroup.ts +2 -2
- package/src/database/{models → client/models}/topic.ts +4 -4
- package/src/database/{models → client/models}/user.ts +1 -1
- package/src/database/{schemas → client/schemas}/user.ts +1 -1
- package/src/features/PluginDevModal/UrlManifestForm.tsx +2 -2
- package/src/services/__tests__/__snapshots__/{plugin.test.ts.snap → tool.test.ts.snap} +2 -2
- package/src/services/__tests__/chat.test.ts +0 -1
- package/src/services/__tests__/{plugin.test.ts → tool.test.ts} +13 -160
- package/src/services/debug.ts +1 -1
- package/src/services/{file.ts → file/client.ts} +4 -6
- package/src/services/{__tests__ → file}/file.test.ts +6 -4
- package/src/services/file/index.ts +3 -0
- package/src/services/global.ts +1 -1
- package/src/services/{__tests__/message.test.ts → message/client.test.ts} +6 -10
- package/src/services/{message.ts → message/client.ts} +11 -4
- package/src/services/message/index.ts +4 -0
- package/src/services/plugin/client.ts +44 -0
- package/src/services/plugin/index.ts +5 -0
- package/src/services/plugin/plugin.test.ts +162 -0
- package/src/services/{session.ts → session/client.ts} +3 -5
- package/src/services/session/index.ts +3 -0
- package/src/services/{__tests__ → session}/session.test.ts +7 -5
- package/src/services/{plugin.ts → tool.ts} +2 -41
- package/src/services/{topic.ts → topic/client.ts} +2 -4
- package/src/services/topic/index.ts +3 -0
- package/src/services/{__tests__ → topic}/topic.test.ts +4 -3
- package/src/services/{user.ts → user/client.ts} +2 -4
- package/src/services/user/index.ts +5 -0
- package/src/store/chat/slices/message/action.ts +1 -2
- package/src/store/chat/slices/plugin/action.ts +1 -2
- package/src/store/tool/slices/customPlugin/action.test.ts +7 -1
- package/src/store/tool/slices/customPlugin/action.ts +2 -1
- package/src/store/tool/slices/store/action.test.ts +16 -10
- package/src/store/tool/slices/store/action.ts +3 -2
- package/src/types/sync.ts +1 -1
- /package/src/database/{core → client/core}/__tests__/model.test.ts +0 -0
- /package/src/database/{core → client/core}/migrations/migrateSettingsToUser/fixtures/input.json +0 -0
- /package/src/database/{core → client/core}/migrations/migrateSettingsToUser/fixtures/output.json +0 -0
- /package/src/database/{core → client/core}/migrations/migrateSettingsToUser/index.test.ts +0 -0
- /package/src/database/{core → client/core}/migrations/migrateSettingsToUser/type.ts +0 -0
- /package/src/database/{core → client/core}/schemas.ts +0 -0
- /package/src/database/{core → client/core}/types/db.ts +0 -0
- /package/src/database/{models → client/models}/__tests__/message.test.ts +0 -0
- /package/src/database/{models → client/models}/__tests__/plugin.test.ts +0 -0
- /package/src/database/{models → client/models}/__tests__/user.test.ts +0 -0
- /package/src/database/{schemas → client/schemas}/files.ts +0 -0
- /package/src/database/{schemas → client/schemas}/message.ts +0 -0
- /package/src/database/{schemas → client/schemas}/plugin.ts +0 -0
- /package/src/database/{schemas → client/schemas}/session.ts +0 -0
- /package/src/database/{schemas → client/schemas}/sessionGroup.ts +0 -0
- /package/src/database/{schemas → client/schemas}/topic.ts +0 -0
|
@@ -1,13 +1,8 @@
|
|
|
1
|
-
import { LobeChatPluginManifest } from '@lobehub/chat-plugin-sdk';
|
|
2
1
|
import { Mock, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
3
2
|
|
|
4
|
-
import { PluginModel } from '@/database/models/plugin';
|
|
5
|
-
import { DB_Plugin } from '@/database/schemas/plugin';
|
|
6
3
|
import { globalHelpers } from '@/store/global/helpers';
|
|
7
|
-
import { LobeTool } from '@/types/tool';
|
|
8
|
-
import { LobeToolCustomPlugin } from '@/types/tool/plugin';
|
|
9
4
|
|
|
10
|
-
import {
|
|
5
|
+
import { toolService } from '../tool';
|
|
11
6
|
import openAPIV3 from './openai/OpenAPI_V3.json';
|
|
12
7
|
import OpenAIPlugin from './openai/plugin.json';
|
|
13
8
|
|
|
@@ -18,21 +13,12 @@ vi.mock('@/store/global/helpers', () => ({
|
|
|
18
13
|
getCurrentLanguage: vi.fn(),
|
|
19
14
|
},
|
|
20
15
|
}));
|
|
21
|
-
vi.mock('@/database/models/plugin', () => ({
|
|
22
|
-
PluginModel: {
|
|
23
|
-
getList: vi.fn(),
|
|
24
|
-
create: vi.fn(),
|
|
25
|
-
delete: vi.fn(),
|
|
26
|
-
update: vi.fn(),
|
|
27
|
-
clear: vi.fn(),
|
|
28
|
-
},
|
|
29
|
-
}));
|
|
30
16
|
|
|
31
17
|
beforeEach(() => {
|
|
32
18
|
vi.resetAllMocks();
|
|
33
19
|
});
|
|
34
20
|
|
|
35
|
-
describe('
|
|
21
|
+
describe('ToolService', () => {
|
|
36
22
|
describe('getPluginList', () => {
|
|
37
23
|
it('should fetch and return the plugin list', async () => {
|
|
38
24
|
// Arrange
|
|
@@ -45,7 +31,7 @@ describe('PluginService', () => {
|
|
|
45
31
|
) as any;
|
|
46
32
|
|
|
47
33
|
// Act
|
|
48
|
-
const pluginList = await
|
|
34
|
+
const pluginList = await toolService.getPluginList();
|
|
49
35
|
|
|
50
36
|
// Assert
|
|
51
37
|
expect(globalHelpers.getCurrentLanguage).toHaveBeenCalled();
|
|
@@ -60,7 +46,7 @@ describe('PluginService', () => {
|
|
|
60
46
|
global.fetch = vi.fn(() => Promise.reject(new Error('Network error')));
|
|
61
47
|
|
|
62
48
|
// Act & Assert
|
|
63
|
-
await expect(
|
|
49
|
+
await expect(toolService.getPluginList()).rejects.toThrow('Network error');
|
|
64
50
|
});
|
|
65
51
|
});
|
|
66
52
|
|
|
@@ -112,7 +98,7 @@ describe('PluginService', () => {
|
|
|
112
98
|
}),
|
|
113
99
|
) as any;
|
|
114
100
|
|
|
115
|
-
const manifest = await
|
|
101
|
+
const manifest = await toolService.getPluginManifest(manifestUrl);
|
|
116
102
|
|
|
117
103
|
expect(fetch).toHaveBeenCalledWith(manifestUrl);
|
|
118
104
|
expect(manifest).toEqual(fakeManifest);
|
|
@@ -120,7 +106,7 @@ describe('PluginService', () => {
|
|
|
120
106
|
|
|
121
107
|
it('should return error on noManifest', async () => {
|
|
122
108
|
try {
|
|
123
|
-
await
|
|
109
|
+
await toolService.getPluginManifest();
|
|
124
110
|
} catch (e) {
|
|
125
111
|
expect(e).toEqual(new TypeError('noManifest'));
|
|
126
112
|
}
|
|
@@ -138,7 +124,7 @@ describe('PluginService', () => {
|
|
|
138
124
|
) as any;
|
|
139
125
|
|
|
140
126
|
try {
|
|
141
|
-
await
|
|
127
|
+
await toolService.getPluginManifest(manifestUrl);
|
|
142
128
|
} catch (e) {
|
|
143
129
|
expect(e).toEqual(new TypeError('manifestInvalid'));
|
|
144
130
|
}
|
|
@@ -149,7 +135,7 @@ describe('PluginService', () => {
|
|
|
149
135
|
global.fetch = vi.fn(() => Promise.reject(new Error('Network error')));
|
|
150
136
|
|
|
151
137
|
try {
|
|
152
|
-
await
|
|
138
|
+
await toolService.getPluginManifest(manifestUrl);
|
|
153
139
|
} catch (e) {
|
|
154
140
|
expect(e).toEqual(new TypeError('fetchError'));
|
|
155
141
|
}
|
|
@@ -170,7 +156,7 @@ describe('PluginService', () => {
|
|
|
170
156
|
) as any;
|
|
171
157
|
|
|
172
158
|
try {
|
|
173
|
-
await
|
|
159
|
+
await toolService.getPluginManifest(manifestUrl);
|
|
174
160
|
} catch (e) {
|
|
175
161
|
expect(e).toEqual(new TypeError('urlError'));
|
|
176
162
|
}
|
|
@@ -188,7 +174,7 @@ describe('PluginService', () => {
|
|
|
188
174
|
) as any;
|
|
189
175
|
|
|
190
176
|
try {
|
|
191
|
-
await
|
|
177
|
+
await toolService.getPluginManifest(manifestUrl);
|
|
192
178
|
} catch (e) {
|
|
193
179
|
expect(e).toEqual(new TypeError('fetchError'));
|
|
194
180
|
}
|
|
@@ -228,7 +214,7 @@ describe('PluginService', () => {
|
|
|
228
214
|
}),
|
|
229
215
|
) as any;
|
|
230
216
|
|
|
231
|
-
const manifest = await
|
|
217
|
+
const manifest = await toolService.getPluginManifest(manifestUrl);
|
|
232
218
|
|
|
233
219
|
expect(manifest).toMatchSnapshot();
|
|
234
220
|
});
|
|
@@ -266,7 +252,7 @@ describe('PluginService', () => {
|
|
|
266
252
|
) as any;
|
|
267
253
|
|
|
268
254
|
try {
|
|
269
|
-
await
|
|
255
|
+
await toolService.getPluginManifest(manifestUrl);
|
|
270
256
|
} catch (e) {
|
|
271
257
|
expect(e).toEqual(new TypeError('openAPIInvalid'));
|
|
272
258
|
}
|
|
@@ -274,141 +260,8 @@ describe('PluginService', () => {
|
|
|
274
260
|
});
|
|
275
261
|
});
|
|
276
262
|
|
|
277
|
-
describe('installPlugin', () => {
|
|
278
|
-
it('should install a plugin', async () => {
|
|
279
|
-
// Arrange
|
|
280
|
-
const fakePlugin = {
|
|
281
|
-
identifier: 'test-plugin',
|
|
282
|
-
manifest: { name: 'TestPlugin', version: '1.0.0' } as unknown as LobeChatPluginManifest,
|
|
283
|
-
type: 'plugin',
|
|
284
|
-
} as InstallPluginParams;
|
|
285
|
-
vi.mocked(PluginModel.create).mockResolvedValue(fakePlugin);
|
|
286
|
-
|
|
287
|
-
// Act
|
|
288
|
-
const installedPlugin = await pluginService.installPlugin(fakePlugin);
|
|
289
|
-
|
|
290
|
-
// Assert
|
|
291
|
-
expect(PluginModel.create).toHaveBeenCalledWith(fakePlugin);
|
|
292
|
-
expect(installedPlugin).toEqual(fakePlugin);
|
|
293
|
-
});
|
|
294
|
-
});
|
|
295
|
-
|
|
296
|
-
describe('getInstalledPlugins', () => {
|
|
297
|
-
it('should return a list of installed plugins', async () => {
|
|
298
|
-
// Arrange
|
|
299
|
-
const fakePlugins = [{ identifier: 'test-plugin', type: 'plugin' }] as LobeTool[];
|
|
300
|
-
vi.mocked(PluginModel.getList).mockResolvedValue(fakePlugins as DB_Plugin[]);
|
|
301
|
-
|
|
302
|
-
// Act
|
|
303
|
-
const installedPlugins = await pluginService.getInstalledPlugins();
|
|
304
|
-
|
|
305
|
-
// Assert
|
|
306
|
-
expect(PluginModel.getList).toHaveBeenCalled();
|
|
307
|
-
expect(installedPlugins).toEqual(fakePlugins);
|
|
308
|
-
});
|
|
309
|
-
});
|
|
310
|
-
|
|
311
|
-
describe('uninstallPlugin', () => {
|
|
312
|
-
it('should uninstall a plugin', async () => {
|
|
313
|
-
// Arrange
|
|
314
|
-
const identifier = 'test-plugin';
|
|
315
|
-
vi.mocked(PluginModel.delete).mockResolvedValue();
|
|
316
|
-
|
|
317
|
-
// Act
|
|
318
|
-
const result = await pluginService.uninstallPlugin(identifier);
|
|
319
|
-
|
|
320
|
-
// Assert
|
|
321
|
-
expect(PluginModel.delete).toHaveBeenCalledWith(identifier);
|
|
322
|
-
expect(result).toBe(undefined);
|
|
323
|
-
});
|
|
324
|
-
});
|
|
325
|
-
|
|
326
|
-
describe('createCustomPlugin', () => {
|
|
327
|
-
it('should create a custom plugin', async () => {
|
|
328
|
-
// Arrange
|
|
329
|
-
const customPlugin = {
|
|
330
|
-
identifier: 'custom-plugin',
|
|
331
|
-
manifest: {},
|
|
332
|
-
type: 'customPlugin',
|
|
333
|
-
} as LobeToolCustomPlugin;
|
|
334
|
-
vi.mocked(PluginModel.create).mockResolvedValue(customPlugin);
|
|
335
|
-
|
|
336
|
-
// Act
|
|
337
|
-
const result = await pluginService.createCustomPlugin(customPlugin);
|
|
338
|
-
|
|
339
|
-
// Assert
|
|
340
|
-
expect(PluginModel.create).toHaveBeenCalledWith({
|
|
341
|
-
...customPlugin,
|
|
342
|
-
type: 'customPlugin',
|
|
343
|
-
});
|
|
344
|
-
expect(result).toEqual(customPlugin);
|
|
345
|
-
});
|
|
346
|
-
});
|
|
347
|
-
|
|
348
|
-
describe('updatePlugin', () => {
|
|
349
|
-
it('should update a plugin', async () => {
|
|
350
|
-
// Arrange
|
|
351
|
-
const id = 'plugin-id';
|
|
352
|
-
const value = { settings: { ab: '1' } } as unknown as LobeToolCustomPlugin;
|
|
353
|
-
vi.mocked(PluginModel.update).mockResolvedValue(1);
|
|
354
|
-
|
|
355
|
-
// Act
|
|
356
|
-
const result = await pluginService.updatePlugin(id, value);
|
|
357
|
-
|
|
358
|
-
// Assert
|
|
359
|
-
expect(PluginModel.update).toHaveBeenCalledWith(id, value);
|
|
360
|
-
expect(result).toEqual(1);
|
|
361
|
-
});
|
|
362
|
-
});
|
|
363
|
-
|
|
364
|
-
describe('updatePluginManifest', () => {
|
|
365
|
-
it('should update a plugin manifest', async () => {
|
|
366
|
-
// Arrange
|
|
367
|
-
const id = 'plugin-id';
|
|
368
|
-
const manifest = { name: 'NewPluginManifest' } as unknown as LobeChatPluginManifest;
|
|
369
|
-
vi.mocked(PluginModel.update).mockResolvedValue(1);
|
|
370
|
-
|
|
371
|
-
// Act
|
|
372
|
-
const result = await pluginService.updatePluginManifest(id, manifest);
|
|
373
|
-
|
|
374
|
-
// Assert
|
|
375
|
-
expect(PluginModel.update).toHaveBeenCalledWith(id, { manifest });
|
|
376
|
-
expect(result).toEqual(1);
|
|
377
|
-
});
|
|
378
|
-
});
|
|
379
|
-
|
|
380
|
-
describe('removeAllPlugins', () => {
|
|
381
|
-
it('should remove all plugins', async () => {
|
|
382
|
-
// Arrange
|
|
383
|
-
vi.mocked(PluginModel.clear).mockResolvedValue(undefined);
|
|
384
|
-
|
|
385
|
-
// Act
|
|
386
|
-
const result = await pluginService.removeAllPlugins();
|
|
387
|
-
|
|
388
|
-
// Assert
|
|
389
|
-
expect(PluginModel.clear).toHaveBeenCalled();
|
|
390
|
-
expect(result).toBe(undefined);
|
|
391
|
-
});
|
|
392
|
-
});
|
|
393
|
-
|
|
394
|
-
describe('updatePluginSettings', () => {
|
|
395
|
-
it('should update plugin settings', async () => {
|
|
396
|
-
// Arrange
|
|
397
|
-
const id = 'plugin-id';
|
|
398
|
-
const settings = { color: 'blue' };
|
|
399
|
-
vi.mocked(PluginModel.update).mockResolvedValue(1);
|
|
400
|
-
|
|
401
|
-
// Act
|
|
402
|
-
const result = await pluginService.updatePluginSettings(id, settings);
|
|
403
|
-
|
|
404
|
-
// Assert
|
|
405
|
-
expect(PluginModel.update).toHaveBeenCalledWith(id, { settings });
|
|
406
|
-
expect(result).toEqual(1);
|
|
407
|
-
});
|
|
408
|
-
});
|
|
409
|
-
|
|
410
263
|
it('can parse the OpenAI plugin', async () => {
|
|
411
|
-
const manifest =
|
|
264
|
+
const manifest = toolService['convertOpenAIManifestToLobeManifest'](OpenAIPlugin as any);
|
|
412
265
|
|
|
413
266
|
expect(manifest).toMatchSnapshot();
|
|
414
267
|
});
|
package/src/services/debug.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { FileModel } from '@/database/models/file';
|
|
2
|
-
import { DB_File } from '@/database/schemas/files';
|
|
1
|
+
import { FileModel } from '@/database/client/models/file';
|
|
2
|
+
import { DB_File } from '@/database/client/schemas/files';
|
|
3
3
|
import { FilePreview } from '@/types/files';
|
|
4
4
|
import compressImage from '@/utils/compressImage';
|
|
5
5
|
|
|
6
|
-
import { API_ENDPOINTS } from '
|
|
6
|
+
import { API_ENDPOINTS } from '../_url';
|
|
7
7
|
|
|
8
|
-
class FileService {
|
|
8
|
+
export class FileService {
|
|
9
9
|
private isImage(fileType: string) {
|
|
10
10
|
const imageRegex = /^image\//;
|
|
11
11
|
return imageRegex.test(fileType);
|
|
@@ -84,5 +84,3 @@ class FileService {
|
|
|
84
84
|
};
|
|
85
85
|
}
|
|
86
86
|
}
|
|
87
|
-
|
|
88
|
-
export const fileService = new FileService();
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { Mock, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
2
2
|
|
|
3
|
-
import { FileModel } from '@/database/models/file';
|
|
4
|
-
import { DB_File } from '@/database/schemas/files';
|
|
3
|
+
import { FileModel } from '@/database/client/models/file';
|
|
4
|
+
import { DB_File } from '@/database/client/schemas/files';
|
|
5
5
|
|
|
6
|
-
import {
|
|
6
|
+
import { FileService } from './client';
|
|
7
|
+
|
|
8
|
+
const fileService = new FileService();
|
|
7
9
|
|
|
8
10
|
// Mocks for the FileModel
|
|
9
|
-
vi.mock('@/database/models/file', () => ({
|
|
11
|
+
vi.mock('@/database/client/models/file', () => ({
|
|
10
12
|
FileModel: {
|
|
11
13
|
create: vi.fn(),
|
|
12
14
|
delete: vi.fn(),
|
package/src/services/global.ts
CHANGED
|
@@ -1,18 +1,14 @@
|
|
|
1
1
|
import { Mock, describe, expect, it, vi } from 'vitest';
|
|
2
2
|
|
|
3
|
-
import { CreateMessageParams, MessageModel } from '@/database/models/message';
|
|
4
|
-
import {
|
|
5
|
-
ChatMessage,
|
|
6
|
-
ChatMessageError,
|
|
7
|
-
ChatPluginPayload,
|
|
8
|
-
ChatTTS,
|
|
9
|
-
ChatTranslate,
|
|
10
|
-
} from '@/types/message';
|
|
3
|
+
import { CreateMessageParams, MessageModel } from '@/database/client/models/message';
|
|
4
|
+
import { ChatMessage, ChatMessageError, ChatPluginPayload } from '@/types/message';
|
|
11
5
|
|
|
12
|
-
import {
|
|
6
|
+
import { MessageService } from './client';
|
|
7
|
+
|
|
8
|
+
const messageService = new MessageService();
|
|
13
9
|
|
|
14
10
|
// Mock the MessageModel
|
|
15
|
-
vi.mock('@/database/models/message', () => {
|
|
11
|
+
vi.mock('@/database/client/models/message', () => {
|
|
16
12
|
return {
|
|
17
13
|
MessageModel: {
|
|
18
14
|
create: vi.fn(),
|
|
@@ -1,7 +1,16 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { DB_Message } from '@/database/schemas/message';
|
|
1
|
+
import { MessageModel } from '@/database/client/models/message';
|
|
2
|
+
import { DB_Message } from '@/database/client/schemas/message';
|
|
3
3
|
import { ChatMessage, ChatMessageError, ChatPluginPayload } from '@/types/message';
|
|
4
4
|
|
|
5
|
+
export interface CreateMessageParams
|
|
6
|
+
extends Partial<Omit<ChatMessage, 'content' | 'role'>>,
|
|
7
|
+
Pick<ChatMessage, 'content' | 'role'> {
|
|
8
|
+
fromModel?: string;
|
|
9
|
+
fromProvider?: string;
|
|
10
|
+
sessionId: string;
|
|
11
|
+
traceId?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
5
14
|
export class MessageService {
|
|
6
15
|
async create(data: CreateMessageParams) {
|
|
7
16
|
const { id } = await MessageModel.create(data);
|
|
@@ -67,5 +76,3 @@ export class MessageService {
|
|
|
67
76
|
return MessageModel.queryAll();
|
|
68
77
|
}
|
|
69
78
|
}
|
|
70
|
-
|
|
71
|
-
export const messageService = new MessageService();
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { LobeChatPluginManifest } from '@lobehub/chat-plugin-sdk';
|
|
2
|
+
|
|
3
|
+
import { PluginModel } from '@/database/client/models/plugin';
|
|
4
|
+
import { LobeTool } from '@/types/tool';
|
|
5
|
+
import { LobeToolCustomPlugin } from '@/types/tool/plugin';
|
|
6
|
+
|
|
7
|
+
export interface InstallPluginParams {
|
|
8
|
+
identifier: string;
|
|
9
|
+
manifest: LobeChatPluginManifest;
|
|
10
|
+
type: 'plugin' | 'customPlugin';
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export class PluginService {
|
|
14
|
+
installPlugin = async (plugin: InstallPluginParams) => {
|
|
15
|
+
return PluginModel.create(plugin);
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
getInstalledPlugins = () => {
|
|
19
|
+
return PluginModel.getList() as Promise<LobeTool[]>;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
uninstallPlugin(identifier: string) {
|
|
23
|
+
return PluginModel.delete(identifier);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
async createCustomPlugin(customPlugin: LobeToolCustomPlugin) {
|
|
27
|
+
return PluginModel.create({ ...customPlugin, type: 'customPlugin' });
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async updatePlugin(id: string, value: LobeToolCustomPlugin) {
|
|
31
|
+
return PluginModel.update(id, value);
|
|
32
|
+
}
|
|
33
|
+
async updatePluginManifest(id: string, manifest: LobeChatPluginManifest) {
|
|
34
|
+
return PluginModel.update(id, { manifest });
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
async removeAllPlugins() {
|
|
38
|
+
return PluginModel.clear();
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
async updatePluginSettings(id: string, settings: any) {
|
|
42
|
+
return PluginModel.update(id, { settings });
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { LobeChatPluginManifest } from '@lobehub/chat-plugin-sdk';
|
|
2
|
+
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
3
|
+
|
|
4
|
+
import { PluginModel } from '@/database/client/models/plugin';
|
|
5
|
+
import { DB_Plugin } from '@/database/client/schemas/plugin';
|
|
6
|
+
import { LobeTool } from '@/types/tool';
|
|
7
|
+
import { LobeToolCustomPlugin } from '@/types/tool/plugin';
|
|
8
|
+
|
|
9
|
+
import { InstallPluginParams, PluginService } from './client';
|
|
10
|
+
|
|
11
|
+
const pluginService = new PluginService();
|
|
12
|
+
|
|
13
|
+
// Mocking modules and functions
|
|
14
|
+
|
|
15
|
+
vi.mock('@/database/client/models/plugin', () => ({
|
|
16
|
+
PluginModel: {
|
|
17
|
+
getList: vi.fn(),
|
|
18
|
+
create: vi.fn(),
|
|
19
|
+
delete: vi.fn(),
|
|
20
|
+
update: vi.fn(),
|
|
21
|
+
clear: vi.fn(),
|
|
22
|
+
},
|
|
23
|
+
}));
|
|
24
|
+
|
|
25
|
+
beforeEach(() => {
|
|
26
|
+
vi.resetAllMocks();
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
describe('PluginService', () => {
|
|
30
|
+
describe('installPlugin', () => {
|
|
31
|
+
it('should install a plugin', async () => {
|
|
32
|
+
// Arrange
|
|
33
|
+
const fakePlugin = {
|
|
34
|
+
identifier: 'test-plugin',
|
|
35
|
+
manifest: { name: 'TestPlugin', version: '1.0.0' } as unknown as LobeChatPluginManifest,
|
|
36
|
+
type: 'plugin',
|
|
37
|
+
} as InstallPluginParams;
|
|
38
|
+
vi.mocked(PluginModel.create).mockResolvedValue(fakePlugin);
|
|
39
|
+
|
|
40
|
+
// Act
|
|
41
|
+
const installedPlugin = await pluginService.installPlugin(fakePlugin);
|
|
42
|
+
|
|
43
|
+
// Assert
|
|
44
|
+
expect(PluginModel.create).toHaveBeenCalledWith(fakePlugin);
|
|
45
|
+
expect(installedPlugin).toEqual(fakePlugin);
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
describe('getInstalledPlugins', () => {
|
|
50
|
+
it('should return a list of installed plugins', async () => {
|
|
51
|
+
// Arrange
|
|
52
|
+
const fakePlugins = [{ identifier: 'test-plugin', type: 'plugin' }] as LobeTool[];
|
|
53
|
+
vi.mocked(PluginModel.getList).mockResolvedValue(fakePlugins as DB_Plugin[]);
|
|
54
|
+
|
|
55
|
+
// Act
|
|
56
|
+
const installedPlugins = await pluginService.getInstalledPlugins();
|
|
57
|
+
|
|
58
|
+
// Assert
|
|
59
|
+
expect(PluginModel.getList).toHaveBeenCalled();
|
|
60
|
+
expect(installedPlugins).toEqual(fakePlugins);
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
describe('uninstallPlugin', () => {
|
|
65
|
+
it('should uninstall a plugin', async () => {
|
|
66
|
+
// Arrange
|
|
67
|
+
const identifier = 'test-plugin';
|
|
68
|
+
vi.mocked(PluginModel.delete).mockResolvedValue();
|
|
69
|
+
|
|
70
|
+
// Act
|
|
71
|
+
const result = await pluginService.uninstallPlugin(identifier);
|
|
72
|
+
|
|
73
|
+
// Assert
|
|
74
|
+
expect(PluginModel.delete).toHaveBeenCalledWith(identifier);
|
|
75
|
+
expect(result).toBe(undefined);
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
describe('createCustomPlugin', () => {
|
|
80
|
+
it('should create a custom plugin', async () => {
|
|
81
|
+
// Arrange
|
|
82
|
+
const customPlugin = {
|
|
83
|
+
identifier: 'custom-plugin',
|
|
84
|
+
manifest: {},
|
|
85
|
+
type: 'customPlugin',
|
|
86
|
+
} as LobeToolCustomPlugin;
|
|
87
|
+
vi.mocked(PluginModel.create).mockResolvedValue(customPlugin);
|
|
88
|
+
|
|
89
|
+
// Act
|
|
90
|
+
const result = await pluginService.createCustomPlugin(customPlugin);
|
|
91
|
+
|
|
92
|
+
// Assert
|
|
93
|
+
expect(PluginModel.create).toHaveBeenCalledWith({
|
|
94
|
+
...customPlugin,
|
|
95
|
+
type: 'customPlugin',
|
|
96
|
+
});
|
|
97
|
+
expect(result).toEqual(customPlugin);
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
describe('updatePlugin', () => {
|
|
102
|
+
it('should update a plugin', async () => {
|
|
103
|
+
// Arrange
|
|
104
|
+
const id = 'plugin-id';
|
|
105
|
+
const value = { settings: { ab: '1' } } as unknown as LobeToolCustomPlugin;
|
|
106
|
+
vi.mocked(PluginModel.update).mockResolvedValue(1);
|
|
107
|
+
|
|
108
|
+
// Act
|
|
109
|
+
const result = await pluginService.updatePlugin(id, value);
|
|
110
|
+
|
|
111
|
+
// Assert
|
|
112
|
+
expect(PluginModel.update).toHaveBeenCalledWith(id, value);
|
|
113
|
+
expect(result).toEqual(1);
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
describe('updatePluginManifest', () => {
|
|
118
|
+
it('should update a plugin manifest', async () => {
|
|
119
|
+
// Arrange
|
|
120
|
+
const id = 'plugin-id';
|
|
121
|
+
const manifest = { name: 'NewPluginManifest' } as unknown as LobeChatPluginManifest;
|
|
122
|
+
vi.mocked(PluginModel.update).mockResolvedValue(1);
|
|
123
|
+
|
|
124
|
+
// Act
|
|
125
|
+
const result = await pluginService.updatePluginManifest(id, manifest);
|
|
126
|
+
|
|
127
|
+
// Assert
|
|
128
|
+
expect(PluginModel.update).toHaveBeenCalledWith(id, { manifest });
|
|
129
|
+
expect(result).toEqual(1);
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
describe('removeAllPlugins', () => {
|
|
134
|
+
it('should remove all plugins', async () => {
|
|
135
|
+
// Arrange
|
|
136
|
+
vi.mocked(PluginModel.clear).mockResolvedValue(undefined);
|
|
137
|
+
|
|
138
|
+
// Act
|
|
139
|
+
const result = await pluginService.removeAllPlugins();
|
|
140
|
+
|
|
141
|
+
// Assert
|
|
142
|
+
expect(PluginModel.clear).toHaveBeenCalled();
|
|
143
|
+
expect(result).toBe(undefined);
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
describe('updatePluginSettings', () => {
|
|
148
|
+
it('should update plugin settings', async () => {
|
|
149
|
+
// Arrange
|
|
150
|
+
const id = 'plugin-id';
|
|
151
|
+
const settings = { color: 'blue' };
|
|
152
|
+
vi.mocked(PluginModel.update).mockResolvedValue(1);
|
|
153
|
+
|
|
154
|
+
// Act
|
|
155
|
+
const result = await pluginService.updatePluginSettings(id, settings);
|
|
156
|
+
|
|
157
|
+
// Assert
|
|
158
|
+
expect(PluginModel.update).toHaveBeenCalledWith(id, { settings });
|
|
159
|
+
expect(result).toEqual(1);
|
|
160
|
+
});
|
|
161
|
+
});
|
|
162
|
+
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { DeepPartial } from 'utility-types';
|
|
2
2
|
|
|
3
|
-
import { SessionModel } from '@/database/models/session';
|
|
4
|
-
import { SessionGroupModel } from '@/database/models/sessionGroup';
|
|
3
|
+
import { SessionModel } from '@/database/client/models/session';
|
|
4
|
+
import { SessionGroupModel } from '@/database/client/models/sessionGroup';
|
|
5
5
|
import { LobeAgentConfig } from '@/types/agent';
|
|
6
6
|
import { MetaData } from '@/types/meta';
|
|
7
7
|
import {
|
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
SessionGroups,
|
|
15
15
|
} from '@/types/session';
|
|
16
16
|
|
|
17
|
-
class SessionService {
|
|
17
|
+
export class SessionService {
|
|
18
18
|
async createNewSession(
|
|
19
19
|
type: LobeSessionType,
|
|
20
20
|
defaultValue: Partial<LobeAgentSession>,
|
|
@@ -118,5 +118,3 @@ class SessionService {
|
|
|
118
118
|
return SessionGroupModel.clear();
|
|
119
119
|
}
|
|
120
120
|
}
|
|
121
|
-
|
|
122
|
-
export const sessionService = new SessionService();
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import { Mock, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
2
2
|
|
|
3
|
-
import { SessionModel } from '@/database/models/session';
|
|
4
|
-
import { SessionGroupModel } from '@/database/models/sessionGroup';
|
|
3
|
+
import { SessionModel } from '@/database/client/models/session';
|
|
4
|
+
import { SessionGroupModel } from '@/database/client/models/sessionGroup';
|
|
5
5
|
import { LobeAgentConfig } from '@/types/agent';
|
|
6
6
|
import { LobeAgentSession, LobeSessionType, SessionGroups } from '@/types/session';
|
|
7
7
|
|
|
8
|
-
import {
|
|
8
|
+
import { SessionService } from './client';
|
|
9
|
+
|
|
10
|
+
const sessionService = new SessionService();
|
|
9
11
|
|
|
10
12
|
// Mock the SessionModel
|
|
11
|
-
vi.mock('@/database/models/session', () => {
|
|
13
|
+
vi.mock('@/database/client/models/session', () => {
|
|
12
14
|
return {
|
|
13
15
|
SessionModel: {
|
|
14
16
|
create: vi.fn(),
|
|
@@ -29,7 +31,7 @@ vi.mock('@/database/models/session', () => {
|
|
|
29
31
|
});
|
|
30
32
|
|
|
31
33
|
// Mock the SessionGroupModel
|
|
32
|
-
vi.mock('@/database/models/sessionGroup', () => {
|
|
34
|
+
vi.mock('@/database/client/models/sessionGroup', () => {
|
|
33
35
|
return {
|
|
34
36
|
SessionGroupModel: {
|
|
35
37
|
create: vi.fn(),
|