@lobehub/chat 0.114.9 → 0.115.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.
Files changed (88) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/locales/de-DE/tool.json +8 -0
  3. package/locales/en-US/tool.json +8 -0
  4. package/locales/es-ES/tool.json +8 -0
  5. package/locales/fr-FR/tool.json +8 -0
  6. package/locales/it-IT/tool.json +8 -0
  7. package/locales/ja-JP/tool.json +8 -0
  8. package/locales/ko-KR/tool.json +8 -0
  9. package/locales/nl-NL/tool.json +8 -0
  10. package/locales/pl-PL/tool.json +8 -0
  11. package/locales/pt-BR/tool.json +8 -0
  12. package/locales/ru-RU/tool.json +8 -0
  13. package/locales/tr-TR/tool.json +8 -0
  14. package/locales/zh-CN/plugin.json +2 -2
  15. package/locales/zh-CN/setting.json +1 -1
  16. package/locales/zh-CN/tool.json +8 -0
  17. package/locales/zh-TW/tool.json +8 -0
  18. package/package.json +2 -2
  19. package/src/app/api/openai/images/createImageGeneration.ts +26 -0
  20. package/src/app/api/openai/images/route.ts +16 -0
  21. package/src/app/api/proxy/route.ts +3 -1
  22. package/src/app/chat/(desktop)/features/ChatHeader.tsx +56 -56
  23. package/src/app/chat/features/ChatHeader/PluginTag/PluginStatus.tsx +7 -4
  24. package/src/app/chat/features/ChatHeader/PluginTag/index.tsx +3 -3
  25. package/src/app/chat/features/SystemRole/index.tsx +0 -1
  26. package/src/components/GalleyGrid/Grid.tsx +36 -0
  27. package/src/components/GalleyGrid/index.tsx +58 -0
  28. package/src/components/GalleyGrid/style.ts +24 -0
  29. package/src/const/settings.ts +7 -0
  30. package/src/database/schemas/files.ts +1 -0
  31. package/src/database/schemas/message.ts +1 -1
  32. package/src/features/AgentSetting/AgentPlugin/index.tsx +2 -2
  33. package/src/features/ChatInput/ActionBar/ModelSwitch.tsx +2 -1
  34. package/src/features/ChatInput/ActionBar/Token/TokenTag.tsx +3 -3
  35. package/src/features/ChatInput/ActionBar/Tools/index.tsx +26 -14
  36. package/src/features/Conversation/ChatList/Messages/Function.tsx +1 -1
  37. package/src/features/Conversation/ChatList/Plugins/Inspector/index.tsx +4 -2
  38. package/src/features/Conversation/ChatList/Plugins/Render/BuiltinType/index.tsx +36 -0
  39. package/src/features/Conversation/ChatList/Plugins/Render/DefaultType/index.tsx +6 -66
  40. package/src/features/Conversation/ChatList/Plugins/Render/Loading.tsx +61 -0
  41. package/src/features/Conversation/ChatList/Plugins/Render/index.tsx +21 -12
  42. package/src/features/Conversation/ChatList/Plugins/Render/useParseContent.ts +15 -0
  43. package/src/locales/default/index.ts +2 -0
  44. package/src/locales/default/plugin.ts +2 -2
  45. package/src/locales/default/setting.ts +1 -1
  46. package/src/locales/default/tool.ts +9 -0
  47. package/src/services/__tests__/chat.test.ts +132 -2
  48. package/src/services/_url.ts +1 -0
  49. package/src/services/chat.ts +3 -5
  50. package/src/services/file.ts +20 -5
  51. package/src/services/imageGeneration.ts +26 -0
  52. package/src/store/chat/actions/enhance.ts +65 -1
  53. package/src/store/chat/actions/plugin.test.ts +9 -9
  54. package/src/store/chat/actions/plugin.ts +38 -6
  55. package/src/store/chat/initialState.ts +3 -0
  56. package/src/store/chat/selectors/enchance.ts +11 -0
  57. package/src/store/chat/selectors/index.ts +1 -0
  58. package/src/store/global/selectors/__snapshots__/settings.test.ts.snap +5 -0
  59. package/src/store/global/selectors/settings.ts +5 -0
  60. package/src/store/tool/helpers.ts +6 -5
  61. package/src/store/tool/initialState.ts +3 -1
  62. package/src/store/tool/selectors/index.ts +5 -0
  63. package/src/store/tool/selectors/tool.test.ts +128 -0
  64. package/src/store/tool/selectors/tool.ts +125 -0
  65. package/src/store/tool/slices/builtin/action.ts +54 -0
  66. package/src/store/tool/slices/builtin/index.ts +2 -0
  67. package/src/store/tool/slices/builtin/initialState.ts +13 -0
  68. package/src/store/tool/slices/builtin/selectors.test.ts +70 -0
  69. package/src/store/tool/slices/builtin/selectors.ts +20 -0
  70. package/src/store/tool/slices/customPlugin/action.ts +0 -3
  71. package/src/store/tool/slices/plugin/selectors.test.ts +0 -69
  72. package/src/store/tool/slices/plugin/selectors.ts +1 -84
  73. package/src/store/tool/store.ts +8 -2
  74. package/src/tools/dalle/Render/EditMode.tsx +66 -0
  75. package/src/tools/dalle/Render/Item.tsx +97 -0
  76. package/src/tools/dalle/Render/ToolBar.tsx +54 -0
  77. package/src/tools/dalle/Render/index.tsx +21 -0
  78. package/src/tools/dalle/index.ts +81 -0
  79. package/src/tools/index.ts +11 -0
  80. package/src/tools/renders.ts +8 -0
  81. package/src/types/chatMessage.ts +1 -1
  82. package/src/types/openai/image.ts +34 -0
  83. package/src/types/settings.ts +6 -0
  84. package/src/types/tool/builtin.ts +36 -0
  85. package/src/types/tool/dalle.ts +12 -0
  86. package/src/types/tool/index.ts +5 -1
  87. package/src/types/tool/tool.ts +9 -0
  88. package/src/store/tool/selectors.ts +0 -3
@@ -0,0 +1,125 @@
1
+ import { LobeChatPluginManifest } from '@lobehub/chat-plugin-sdk';
2
+ import { uniqBy } from 'lodash-es';
3
+ import { Md5 } from 'ts-md5';
4
+
5
+ import { PLUGIN_SCHEMA_API_MD5_PREFIX, PLUGIN_SCHEMA_SEPARATOR } from '@/const/plugin';
6
+ import { MetaData } from '@/types/meta';
7
+ import { ChatCompletionFunctions } from '@/types/openai/chat';
8
+ import { LobeToolMeta } from '@/types/tool/tool';
9
+
10
+ import { pluginHelpers } from '../helpers';
11
+ import { ToolStoreState } from '../initialState';
12
+ import { builtinToolSelectors } from '../slices/builtin/selectors';
13
+ import { pluginSelectors } from '../slices/plugin/selectors';
14
+
15
+ const getAPIName = (identifier: string, name: string, type?: string) => {
16
+ const pluginType = type && type !== 'default' ? `${PLUGIN_SCHEMA_SEPARATOR + type}` : '';
17
+
18
+ // 将插件的 identifier 作为前缀,避免重复
19
+ let apiName = identifier + PLUGIN_SCHEMA_SEPARATOR + name + pluginType;
20
+
21
+ // OpenAI GPT function_call name can't be longer than 64 characters
22
+ // So we need to use md5 to shorten the name
23
+ // and then find the correct apiName in response by md5
24
+ if (apiName.length >= 64) {
25
+ const md5Content = PLUGIN_SCHEMA_API_MD5_PREFIX + Md5.hashStr(name).toString();
26
+
27
+ apiName = identifier + PLUGIN_SCHEMA_SEPARATOR + md5Content + pluginType;
28
+ }
29
+
30
+ return apiName;
31
+ };
32
+
33
+ const enabledSchema =
34
+ (tools: string[] = []) =>
35
+ (s: ToolStoreState): ChatCompletionFunctions[] => {
36
+ const list = pluginSelectors
37
+ .installedPluginManifestList(s)
38
+ .concat(s.builtinTools.map((b) => b.manifest as LobeChatPluginManifest))
39
+ // 如果存在 enabledPlugins,那么只启用 enabledPlugins 中的插件
40
+ .filter((m) => tools.includes(m?.identifier))
41
+ .flatMap((manifest) =>
42
+ manifest.api.map((m) => ({
43
+ ...m,
44
+ name: getAPIName(manifest.identifier, m.name, manifest.type),
45
+ })),
46
+ );
47
+
48
+ return uniqBy(list, 'name');
49
+ };
50
+
51
+ const enabledSystemRoles =
52
+ (tools: string[] = []) =>
53
+ (s: ToolStoreState) => {
54
+ const toolsSystemRole = pluginSelectors
55
+ .installedPluginManifestList(s)
56
+ .concat(s.builtinTools.map((b) => b.manifest as LobeChatPluginManifest))
57
+ // 如果存在 enabledPlugins,那么只启用 enabledPlugins 中的插件
58
+ .filter((m) => tools.includes(m?.identifier))
59
+ .map((manifest) => {
60
+ if (!manifest) return '';
61
+
62
+ const meta = manifest.meta || {};
63
+
64
+ const title = pluginHelpers.getPluginTitle(meta) || manifest.identifier;
65
+ const systemRole = manifest.systemRole || pluginHelpers.getPluginDesc(meta);
66
+
67
+ const methods = manifest.api
68
+ .map((m) =>
69
+ [`#### ${getAPIName(manifest.identifier, m.name, manifest.type)}`, m.description].join(
70
+ '\n\n',
71
+ ),
72
+ )
73
+ .join('\n\n');
74
+
75
+ return [`### ${title}`, systemRole, 'The APIs you can use:', methods].join('\n\n');
76
+ })
77
+ .filter(Boolean);
78
+
79
+ if (toolsSystemRole.length > 0) {
80
+ return ['## Tools', 'You can use these tools below:', ...toolsSystemRole]
81
+ .filter(Boolean)
82
+ .join('\n\n');
83
+ }
84
+
85
+ return '';
86
+ };
87
+
88
+ const metaList = (s: ToolStoreState): LobeToolMeta[] => {
89
+ const pluginList = pluginSelectors.installedPluginMetaList(s) as LobeToolMeta[];
90
+
91
+ return builtinToolSelectors.metaList(s).concat(pluginList);
92
+ };
93
+
94
+ const getMetaById =
95
+ (id: string) =>
96
+ (s: ToolStoreState): MetaData | undefined =>
97
+ metaList(s).find((m) => m.identifier === id)?.meta;
98
+
99
+ const getManifestById =
100
+ (id: string) =>
101
+ (s: ToolStoreState): LobeChatPluginManifest | undefined =>
102
+ pluginSelectors
103
+ .installedPluginManifestList(s)
104
+ .concat(s.builtinTools.map((b) => b.manifest as LobeChatPluginManifest))
105
+ .find((i) => i.identifier === id);
106
+
107
+ // 获取插件 manifest 加载状态
108
+ const getManifestLoadingStatus = (id: string) => (s: ToolStoreState) => {
109
+ const manifest = getManifestById(id)(s);
110
+
111
+ if (s.pluginInstallLoading[id]) return 'loading';
112
+
113
+ if (!manifest) return 'error';
114
+
115
+ if (!!manifest) return 'success';
116
+ };
117
+
118
+ export const toolSelectors = {
119
+ enabledSchema,
120
+ enabledSystemRoles,
121
+ getManifestById,
122
+ getManifestLoadingStatus,
123
+ getMetaById,
124
+ metaList,
125
+ };
@@ -0,0 +1,54 @@
1
+ import { StateCreator } from 'zustand/vanilla';
2
+
3
+ import { OpenAIImagePayload } from '@/types/openai/image';
4
+ import { DallEImageItem } from '@/types/tool/dalle';
5
+ import { setNamespace } from '@/utils/storeDebug';
6
+
7
+ import { ToolStore } from '../../store';
8
+
9
+ const n = setNamespace('builtinTool');
10
+
11
+ interface Text2ImageParams extends Pick<OpenAIImagePayload, 'quality' | 'style' | 'size'> {
12
+ prompts: string[];
13
+ }
14
+
15
+ /**
16
+ * 代理行为接口
17
+ */
18
+ export interface BuiltinToolAction {
19
+ invokeBuiltinTool: (key: string, params: any) => Promise<string | undefined>;
20
+ text2image: (params: Text2ImageParams, messageId: string) => DallEImageItem[];
21
+ toggleBuiltinToolLoading: (key: string, value: boolean) => void;
22
+ }
23
+
24
+ export const createBuiltinToolSlice: StateCreator<
25
+ ToolStore,
26
+ [['zustand/devtools', never]],
27
+ [],
28
+ BuiltinToolAction
29
+ > = (set, get) => ({
30
+ invokeBuiltinTool: async (key, params) => {
31
+ const { builtinToolLoading, toggleBuiltinToolLoading } = get();
32
+
33
+ if (builtinToolLoading[key]) return;
34
+
35
+ toggleBuiltinToolLoading(key, true);
36
+
37
+ const { [key as keyof BuiltinToolAction]: action } = get();
38
+
39
+ if (!action) return;
40
+
41
+ // @ts-ignore
42
+ const result = await action(params);
43
+
44
+ toggleBuiltinToolLoading(key, false);
45
+
46
+ return JSON.stringify(result);
47
+ },
48
+ text2image: ({ prompts, size = '1024x1024' as const, quality = 'standard', style = 'vivid' }) =>
49
+ prompts.map((p) => ({ prompt: p, quality, size, style })),
50
+
51
+ toggleBuiltinToolLoading: (key, value) => {
52
+ set({ builtinToolLoading: { [key]: value } }, false, n('toggleBuiltinToolLoading'));
53
+ },
54
+ });
@@ -0,0 +1,2 @@
1
+ export * from './action';
2
+ export * from './initialState';
@@ -0,0 +1,13 @@
1
+ import { LobeBuiltinTool } from '@/types/tool';
2
+
3
+ import { builtinTools } from '../../../../tools';
4
+
5
+ export interface BuiltinToolState {
6
+ builtinToolLoading: Record<string, boolean>;
7
+ builtinTools: LobeBuiltinTool[];
8
+ }
9
+
10
+ export const initialBuiltinToolState: BuiltinToolState = {
11
+ builtinToolLoading: {},
12
+ builtinTools,
13
+ };
@@ -0,0 +1,70 @@
1
+ import { LobeChatPluginManifest, LobeChatPluginMeta } from '@lobehub/chat-plugin-sdk';
2
+ import { describe, expect, it } from 'vitest';
3
+
4
+ import { ToolStoreState, initialState } from '../../initialState';
5
+ import { builtinToolSelectors } from './selectors';
6
+
7
+ const mockState = {
8
+ ...initialState,
9
+ pluginManifestLoading: {
10
+ 'plugin-1': false,
11
+ 'plugin-2': true,
12
+ },
13
+ installedPlugins: [
14
+ {
15
+ identifier: 'plugin-1',
16
+ type: 'plugin',
17
+ manifest: {
18
+ identifier: 'plugin-1',
19
+ api: [{ name: 'api-1' }],
20
+ type: 'default',
21
+ } as LobeChatPluginManifest,
22
+ },
23
+ {
24
+ identifier: 'plugin-2',
25
+ manifest: {
26
+ identifier: 'plugin-2',
27
+ api: [{ name: 'api-2' }],
28
+ type: 'default',
29
+ },
30
+ type: 'plugin',
31
+ },
32
+ ],
33
+ pluginStoreList: [
34
+ {
35
+ identifier: 'plugin-1',
36
+ author: 'Author 1',
37
+ createdAt: '2021-01-01',
38
+ meta: { avatar: 'avatar-url-1', title: 'Plugin 1' },
39
+ homepage: 'http://homepage-1.com',
40
+ } as LobeChatPluginMeta,
41
+ {
42
+ identifier: 'plugin-2',
43
+ author: 'Author 2',
44
+ createdAt: '2022-02-02',
45
+ meta: { avatar: 'avatar-url-2', title: 'Plugin 2' },
46
+ homepage: 'http://homepage-2.com',
47
+ },
48
+ ],
49
+ } as ToolStoreState;
50
+
51
+ describe('pluginSelectors', () => {
52
+ describe('isCustomPlugin', () => {
53
+ it('should return false for a non-custom plugin', () => {
54
+ const result = builtinToolSelectors.isBuiltinTool('plugin-1')(mockState);
55
+ expect(result).toBe(false);
56
+ });
57
+
58
+ it('should return true for a custom plugin', () => {
59
+ const stateWithCustomPlugin = {
60
+ ...mockState,
61
+ installedPlugins: [
62
+ ...mockState.installedPlugins,
63
+ { identifier: 'custom-plugin', type: 'customPlugin' },
64
+ ],
65
+ } as ToolStoreState;
66
+ const result = builtinToolSelectors.isBuiltinTool('custom-plugin')(stateWithCustomPlugin);
67
+ expect(result).toBe(true);
68
+ });
69
+ });
70
+ });
@@ -0,0 +1,20 @@
1
+ import { LobeToolMeta } from '@/types/tool/tool';
2
+
3
+ import { pluginHelpers } from '../../helpers';
4
+ import type { ToolStoreState } from '../../initialState';
5
+
6
+ const isBuiltinTool = (id: string) => (s: ToolStoreState) =>
7
+ pluginHelpers.isCustomPlugin(id, s.installedPlugins);
8
+
9
+ const metaList = (s: ToolStoreState): LobeToolMeta[] =>
10
+ s.builtinTools.map((t) => ({
11
+ author: 'LobeHub',
12
+ identifier: t.identifier,
13
+ meta: t.manifest.meta,
14
+ type: 'builtin',
15
+ }));
16
+
17
+ export const builtinToolSelectors = {
18
+ isBuiltinTool,
19
+ metaList,
20
+ };
@@ -14,9 +14,6 @@ import { defaultCustomPlugin } from './initialState';
14
14
 
15
15
  const n = setNamespace('customPlugin');
16
16
 
17
- /**
18
- * 代理行为接口
19
- */
20
17
  export interface CustomPluginAction {
21
18
  installCustomPlugin: (value: LobeToolCustomPlugin) => Promise<void>;
22
19
  reinstallCustomPlugin: (id: string) => Promise<void>;
@@ -58,57 +58,6 @@ const mockState = {
58
58
  } as ToolStoreState;
59
59
 
60
60
  describe('pluginSelectors', () => {
61
- describe('enabledSchema', () => {
62
- it('enabledSchema should return correct ChatCompletionFunctions array', () => {
63
- const result = pluginSelectors.enabledSchema(['plugin-1', 'plugin-2'])(mockState);
64
- expect(result).toEqual([{ name: 'plugin-1____api-1' }, { name: 'plugin-2____api-2' }]);
65
- });
66
-
67
- it('enabledSchema should return with standalone plugin', () => {
68
- const result = pluginSelectors.enabledSchema(['plugin-4'])({
69
- ...mockState,
70
- installedPlugins: [
71
- ...mockState.installedPlugins,
72
- {
73
- identifier: 'plugin-4',
74
- manifest: {
75
- identifier: 'plugin-4',
76
- api: [{ name: 'api-4' }],
77
- type: 'standalone',
78
- },
79
- type: 'plugin',
80
- },
81
- ],
82
- } as ToolStoreState);
83
- expect(result).toEqual([{ name: 'plugin-4____api-4____standalone' }]);
84
- });
85
-
86
- it('enabledSchema should return md5 hash apiName', () => {
87
- const result = pluginSelectors.enabledSchema(['long-long-plugin-with-id'])({
88
- ...mockState,
89
- installedPlugins: [
90
- ...mockState.installedPlugins,
91
- {
92
- identifier: 'long-long-plugin-with-id',
93
- manifest: {
94
- identifier: 'long-long-plugin-with-id',
95
- api: [{ name: 'long-long-manifest-long-long-apiName' }],
96
- },
97
- type: 'plugin',
98
- },
99
- ],
100
- } as ToolStoreState);
101
- expect(result).toEqual([
102
- { name: 'long-long-plugin-with-id____MD5HASH_396eae4c671da3fb642c49ad2b9e8790' },
103
- ]);
104
- });
105
-
106
- it('enabledSchema should return empty', () => {
107
- const result = pluginSelectors.enabledSchema([])(mockState);
108
- expect(result).toEqual([]);
109
- });
110
- });
111
-
112
61
  describe('getPluginManifestById', () => {
113
62
  it('getPluginManifestById should return the correct manifest', () => {
114
63
  const result = pluginSelectors.getPluginManifestById('plugin-1')(mockState);
@@ -211,24 +160,6 @@ describe('pluginSelectors', () => {
211
160
  });
212
161
  });
213
162
 
214
- describe('getPluginManifestLoadingStatus', () => {
215
- it('should return "loading" if the plugin manifest is being loaded', () => {
216
- const result = pluginSelectors.getPluginManifestLoadingStatus('plugin-2')(mockState);
217
- expect(result).toBe('loading');
218
- });
219
-
220
- it('should return "error" if the plugin manifest is not found', () => {
221
- const result =
222
- pluginSelectors.getPluginManifestLoadingStatus('non-existing-plugin')(mockState);
223
- expect(result).toBe('error');
224
- });
225
-
226
- it('should return "success" if the plugin manifest is loaded', () => {
227
- const result = pluginSelectors.getPluginManifestLoadingStatus('plugin-1')(mockState);
228
- expect(result).toBe('success');
229
- });
230
- });
231
-
232
163
  describe('storeAndInstallPluginsIdList', () => {
233
164
  it('should return a list of unique plugin identifiers from both installed and store lists', () => {
234
165
  const result = pluginSelectors.storeAndInstallPluginsIdList(mockState);
@@ -1,12 +1,8 @@
1
1
  import { LobeChatPluginManifest } from '@lobehub/chat-plugin-sdk';
2
- import { uniq, uniqBy } from 'lodash-es';
3
- import { Md5 } from 'ts-md5';
2
+ import { uniq } from 'lodash-es';
4
3
 
5
- import { PLUGIN_SCHEMA_API_MD5_PREFIX, PLUGIN_SCHEMA_SEPARATOR } from '@/const/plugin';
6
- import { ChatCompletionFunctions } from '@/types/openai/chat';
7
4
  import { InstallPluginMeta, LobeToolCustomPlugin } from '@/types/tool/plugin';
8
5
 
9
- import { pluginHelpers } from '../../helpers';
10
6
  import type { ToolStoreState } from '../../initialState';
11
7
 
12
8
  const installedPlugins = (s: ToolStoreState) => s.installedPlugins;
@@ -37,17 +33,6 @@ const getPluginManifestById = (id: string) => (s: ToolStoreState) =>
37
33
  const getPluginSettingsById = (id: string) => (s: ToolStoreState) =>
38
34
  getInstalledPluginById(id)(s)?.settings || {};
39
35
 
40
- // 获取插件 manifest 加载状态
41
- const getPluginManifestLoadingStatus = (id: string) => (s: ToolStoreState) => {
42
- const manifest = getPluginManifestById(id)(s);
43
-
44
- if (s.pluginInstallLoading[id]) return 'loading';
45
-
46
- if (!manifest) return 'error';
47
-
48
- if (!!manifest) return 'success';
49
- };
50
-
51
36
  const storeAndInstallPluginsIdList = (s: ToolStoreState) =>
52
37
  uniq(
53
38
  [
@@ -79,78 +64,10 @@ const isPluginHasUI = (id: string) => (s: ToolStoreState) => {
79
64
  return !!plugin?.ui;
80
65
  };
81
66
 
82
- const enabledSchema =
83
- (enabledPlugins: string[] = []) =>
84
- (s: ToolStoreState): ChatCompletionFunctions[] => {
85
- // 如果不存在 enabledPlugins,那么全部不启用
86
- if (!enabledPlugins) return [];
87
-
88
- const list = installedPluginManifestList(s)
89
- .filter((m) =>
90
- // 如果存在 enabledPlugins,那么只启用 enabledPlugins 中的插件
91
- enabledPlugins.includes(m?.identifier),
92
- )
93
- .flatMap((manifest) =>
94
- manifest.api.map((m) => {
95
- const pluginType =
96
- manifest.type && manifest.type !== 'default'
97
- ? `${PLUGIN_SCHEMA_SEPARATOR + manifest.type}`
98
- : '';
99
-
100
- // 将插件的 identifier 作为前缀,避免重复
101
- let apiName = manifest.identifier + PLUGIN_SCHEMA_SEPARATOR + m.name + pluginType;
102
-
103
- // OpenAI GPT function_call name can't be longer than 64 characters
104
- // So we need to use md5 to shorten the name
105
- // and then find the correct apiName in response by md5
106
- if (apiName.length >= 64) {
107
- const md5Content = PLUGIN_SCHEMA_API_MD5_PREFIX + Md5.hashStr(m.name).toString();
108
-
109
- apiName = manifest.identifier + PLUGIN_SCHEMA_SEPARATOR + md5Content + pluginType;
110
- }
111
-
112
- return {
113
- ...m,
114
- name: apiName,
115
- };
116
- }),
117
- );
118
-
119
- return uniqBy(list, 'name');
120
- };
121
-
122
- const enabledPluginsSystemRoles =
123
- (enabledPlugins: string[] = []) =>
124
- (s: ToolStoreState) => {
125
- const toolsSystemRole = enabledPlugins
126
- .map((id) => {
127
- const manifest = getPluginManifestById(id)(s);
128
- if (!manifest) return '';
129
- const meta = getPluginMetaById(id)(s);
130
-
131
- const title = pluginHelpers.getPluginTitle(meta);
132
- const desc = pluginHelpers.getPluginDesc(meta);
133
-
134
- return [`### ${title}`, manifest.systemRole || desc].join('\n\n');
135
- })
136
- .filter(Boolean);
137
-
138
- if (toolsSystemRole.length > 0) {
139
- return ['## Tools', 'You can use these tools below:', ...toolsSystemRole]
140
- .filter(Boolean)
141
- .join('\n\n');
142
- }
143
-
144
- return '';
145
- };
146
-
147
67
  export const pluginSelectors = {
148
- enabledPluginsSystemRoles,
149
- enabledSchema,
150
68
  getCustomPluginById,
151
69
  getInstalledPluginById,
152
70
  getPluginManifestById,
153
- getPluginManifestLoadingStatus,
154
71
  getPluginMetaById,
155
72
  getPluginSettingsById,
156
73
  installedCustomPluginMetaList,
@@ -6,26 +6,32 @@ import { StateCreator } from 'zustand/vanilla';
6
6
  import { isDev } from '@/utils/env';
7
7
 
8
8
  import { ToolStoreState, initialState } from './initialState';
9
+ import { BuiltinToolAction, createBuiltinToolSlice } from './slices/builtin';
9
10
  import { CustomPluginAction, createCustomPluginSlice } from './slices/customPlugin';
10
11
  import { PluginAction, createPluginSlice } from './slices/plugin';
11
12
  import { PluginStoreAction, createPluginStoreSlice } from './slices/store';
12
13
 
13
14
  // =============== 聚合 createStoreFn ============ //
14
15
 
15
- export type ToolStore = ToolStoreState & CustomPluginAction & PluginAction & PluginStoreAction;
16
+ export type ToolStore = ToolStoreState &
17
+ CustomPluginAction &
18
+ PluginAction &
19
+ PluginStoreAction &
20
+ BuiltinToolAction;
16
21
 
17
22
  const createStore: StateCreator<ToolStore, [['zustand/devtools', never]]> = (...parameters) => ({
18
23
  ...initialState,
19
24
  ...createPluginSlice(...parameters),
20
25
  ...createCustomPluginSlice(...parameters),
21
26
  ...createPluginStoreSlice(...parameters),
27
+ ...createBuiltinToolSlice(...parameters),
22
28
  });
23
29
 
24
30
  // =============== 实装 useStore ============ //
25
31
 
26
32
  export const useToolStore = createWithEqualityFn<ToolStore>()(
27
33
  devtools(createStore, {
28
- name: 'LobeChat_Plugin' + (isDev ? '_DEV' : ''),
34
+ name: 'LobeChat_Tool' + (isDev ? '_DEV' : ''),
29
35
  }),
30
36
  shallow,
31
37
  );
@@ -0,0 +1,66 @@
1
+ import { TextArea } from '@lobehub/ui';
2
+ import { Button, Radio, Select } from 'antd';
3
+ import { memo } from 'react';
4
+ import { useTranslation } from 'react-i18next';
5
+ import { Flexbox } from 'react-layout-kit';
6
+
7
+ import { DallEImageItem } from '@/types/tool/dalle';
8
+
9
+ interface EditModeProps extends DallEImageItem {
10
+ setEdit: (edit: boolean) => void;
11
+ }
12
+
13
+ const EditMode = memo<EditModeProps>(({ prompt, setEdit, style, size, quality }) => {
14
+ const { t } = useTranslation('tool');
15
+
16
+ return (
17
+ <Flexbox gap={16}>
18
+ <TextArea style={{ minHeight: 120 }} type={'block'} value={prompt} />
19
+ <Flexbox horizontal justify={'space-between'}>
20
+ 风格
21
+ <Radio.Group
22
+ defaultValue={style}
23
+ options={[
24
+ { label: 'vivid', value: 'vivid' },
25
+ { label: 'natural', value: 'natural' },
26
+ ]}
27
+ />
28
+ </Flexbox>
29
+ <Flexbox horizontal justify={'space-between'}>
30
+ 质量
31
+ <Radio.Group
32
+ defaultValue={quality}
33
+ options={[
34
+ { label: 'standard', value: 'standard' },
35
+ { label: 'hd', value: 'hd' },
36
+ ]}
37
+ />
38
+ </Flexbox>
39
+ <Flexbox horizontal justify={'space-between'}>
40
+ 尺寸
41
+ <Select
42
+ defaultValue={size}
43
+ options={[
44
+ { label: '1792x1024', value: '1792x1024' },
45
+ { label: '1024x1024', value: '1024x1024' },
46
+ { label: '1024x1792', value: '1024x1792' },
47
+ ]}
48
+ size={'small'}
49
+ />
50
+ </Flexbox>
51
+
52
+ <Flexbox direction={'horizontal-reverse'} gap={12}>
53
+ <Button type={'primary'}>{t('dalle.generate')}</Button>
54
+ <Button
55
+ onClick={() => {
56
+ setEdit(false);
57
+ }}
58
+ >
59
+ {t('cancel', { ns: 'common' })}
60
+ </Button>
61
+ </Flexbox>
62
+ </Flexbox>
63
+ );
64
+ });
65
+
66
+ export default EditMode;