UNPKG

@lobehub/chat

Version:

Lobe Chat - an open-source, high-performance chatbot framework that supports speech synthesis, multimodal, and extensible Function Call plugin system. Supports one-click free deployment of your private ChatGPT/LLM web application.

248 lines (227 loc) • 7.54 kB
import { LobeChatPluginManifest, LobeChatPluginMeta } from '@lobehub/chat-plugin-sdk'; import { describe, expect, it } from 'vitest'; import { initialState } from '../initialState'; import { ToolStoreState } from '../initialState'; import { toolSelectors } from './tool'; const mockState = { ...initialState, installedPlugins: [ { identifier: 'plugin-1', manifest: { identifier: 'plugin-1', api: [{ name: 'api-1' }], meta: { title: 'Plugin 1', description: 'Plugin 1 description' }, } as LobeChatPluginManifest, type: 'plugin', }, { identifier: 'plugin-2', manifest: { identifier: 'plugin-2', api: [{ name: 'api-2' }], } as LobeChatPluginManifest, type: 'plugin', }, { identifier: 'plugin-3', manifest: { identifier: 'plugin-3', api: [ { name: 'api-3', url: 'bac', description: '123123', parameters: { type: 'object', properties: { a: { type: 'string' } } }, }, ], }, type: 'customPlugin', }, ], builtinTools: [ { type: 'builtin', identifier: 'builtin-1', manifest: { identifier: 'builtin-1', api: [{ name: 'builtin-api-1' }], meta: { title: 'Builtin 1', description: 'Builtin 1 description' }, } as LobeChatPluginManifest, }, ], pluginInstallLoading: { 'plugin-1': false, 'plugin-2': true, }, } as ToolStoreState; describe('toolSelectors', () => { describe('enabledSchema', () => { it('enabledSchema should return correct ChatCompletionFunctions array', () => { const result = toolSelectors.enabledSchema(['plugin-1', 'plugin-2'])(mockState); expect(result).toEqual([ { type: 'function', function: { name: 'plugin-1____api-1', }, }, { type: 'function', function: { name: 'plugin-2____api-2', }, }, ]); }); it('enabledSchema should return with standalone plugin', () => { const result = toolSelectors.enabledSchema(['plugin-4'])({ ...mockState, installedPlugins: [ ...mockState.installedPlugins, { identifier: 'plugin-4', manifest: { identifier: 'plugin-4', api: [{ name: 'api-4' }], type: 'standalone', }, type: 'plugin', }, ], } as ToolStoreState); expect(result).toEqual([ { type: 'function', function: { name: 'plugin-4____api-4____standalone', }, }, ]); }); it('enabledSchema should return md5 hash apiName', () => { const result = toolSelectors.enabledSchema(['long-long-plugin-with-id'])({ ...mockState, installedPlugins: [ ...mockState.installedPlugins, { identifier: 'long-long-plugin-with-id', manifest: { identifier: 'long-long-plugin-with-id', api: [{ name: 'long-long-manifest-long-long-apiName' }], }, type: 'plugin', }, ], } as ToolStoreState); expect(result).toEqual([ { type: 'function', function: { name: 'long-long-plugin-with-id____MD5HASH_396eae4c671da3fb642c49ad2b9e8790', }, }, ]); }); it('enabledSchema should return empty', () => { const result = toolSelectors.enabledSchema([])(mockState); expect(result).toEqual([]); }); // fix https://github.com/lobehub/lobe-chat/issues/2036 it('should not contain url', () => { const result = toolSelectors.enabledSchema(['plugin-3'])(mockState); expect(result[0].function).toEqual({ description: '123123', name: 'plugin-3____api-3', parameters: { properties: { a: { type: 'string', }, }, type: 'object', }, }); expect(result[0].function).not.toHaveProperty('url'); }); }); describe('getToolManifestLoadingStatus', () => { it('should return "loading" if the plugin manifest is being loaded', () => { const result = toolSelectors.getManifestLoadingStatus('plugin-2')(mockState); expect(result).toBe('loading'); }); it('should return "error" if the plugin manifest is not found', () => { const result = toolSelectors.getManifestLoadingStatus('non-existing-plugin')(mockState); expect(result).toBe('error'); }); it('should return "success" if the plugin manifest is loaded', () => { const result = toolSelectors.getManifestLoadingStatus('plugin-1')(mockState); expect(result).toBe('success'); }); }); describe('metaList and getMetaById', () => { it('should return the correct list of tool metadata', () => { const result = toolSelectors.metaList()(mockState); expect(result).toEqual([ { type: 'builtin', author: 'LobeHub', identifier: 'builtin-1', meta: { title: 'Builtin 1', description: 'Builtin 1 description' }, }, { identifier: 'plugin-1', type: 'plugin', meta: { title: 'Plugin 1', description: 'Plugin 1 description' }, }, { type: 'plugin', identifier: 'plugin-2', meta: undefined, }, { identifier: 'plugin-3', type: 'customPlugin', }, ]); }); it('should return the correct metadata by identifier', () => { const result = toolSelectors.getMetaById('plugin-1')(mockState); expect(result).toEqual({ title: 'Plugin 1', description: 'Plugin 1 description' }); }); it('should return undefined for non-existent identifier', () => { const result = toolSelectors.getMetaById('non-existent')(mockState); expect(result).toBeUndefined(); }); }); describe('getManifestById and getManifestLoadingStatus', () => { it('should return the correct manifest by identifier', () => { const result = toolSelectors.getManifestById('plugin-1')(mockState); expect(result).toEqual({ identifier: 'plugin-1', api: [{ name: 'api-1' }], meta: { title: 'Plugin 1', description: 'Plugin 1 description' }, }); }); it('should return undefined for non-existent identifier', () => { const result = toolSelectors.getManifestById('non-existent')(mockState); expect(result).toBeUndefined(); }); it('should return the correct loading status for a plugin', () => { expect(toolSelectors.getManifestLoadingStatus('plugin-1')(mockState)).toBe('success'); expect(toolSelectors.getManifestLoadingStatus('plugin-2')(mockState)).toBe('loading'); expect(toolSelectors.getManifestLoadingStatus('non-existent')(mockState)).toBe('error'); }); }); describe('isToolHasUI', () => { it('should return false if the tool has no UI', () => { expect(toolSelectors.isToolHasUI('plugin-1')(mockState)).toBe(false); }); it('should return true if the tool has UI', () => { expect(toolSelectors.isToolHasUI('builtin-1')(mockState)).toBe(true); }); it('should return false if the tool does not exist', () => { expect(toolSelectors.isToolHasUI('non-existent')(mockState)).toBe(false); }); }); });