@lobehub/chat 0.122.9 → 0.123.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 (231) hide show
  1. package/.env.example +22 -2
  2. package/.eslintrc.js +1 -0
  3. package/CHANGELOG.md +59 -0
  4. package/Dockerfile +7 -1
  5. package/README.md +12 -10
  6. package/README.zh-CN.md +12 -10
  7. package/docs/Deployment/Docker-Deployment.md +1 -1
  8. package/docs/Deployment/Docker-Deployment.zh-CN.md +1 -1
  9. package/docs/Deployment/Environment-Variable.md +65 -23
  10. package/docs/Deployment/Environment-Variable.zh-CN.md +64 -22
  11. package/locales/ar/chat.json +12 -1
  12. package/locales/ar/common.json +16 -0
  13. package/locales/ar/error.json +35 -6
  14. package/locales/ar/setting.json +53 -6
  15. package/locales/de-DE/chat.json +12 -1
  16. package/locales/de-DE/common.json +16 -0
  17. package/locales/de-DE/error.json +35 -6
  18. package/locales/de-DE/setting.json +53 -6
  19. package/locales/en-US/chat.json +13 -2
  20. package/locales/en-US/common.json +16 -0
  21. package/locales/en-US/error.json +35 -6
  22. package/locales/en-US/setting.json +53 -6
  23. package/locales/es-ES/chat.json +12 -1
  24. package/locales/es-ES/common.json +16 -0
  25. package/locales/es-ES/error.json +35 -6
  26. package/locales/es-ES/setting.json +53 -6
  27. package/locales/fr-FR/chat.json +13 -2
  28. package/locales/fr-FR/common.json +16 -0
  29. package/locales/fr-FR/error.json +35 -6
  30. package/locales/fr-FR/setting.json +53 -6
  31. package/locales/it-IT/chat.json +12 -1
  32. package/locales/it-IT/common.json +16 -0
  33. package/locales/it-IT/error.json +35 -6
  34. package/locales/it-IT/setting.json +53 -6
  35. package/locales/ja-JP/chat.json +12 -1
  36. package/locales/ja-JP/common.json +16 -0
  37. package/locales/ja-JP/error.json +35 -6
  38. package/locales/ja-JP/setting.json +53 -6
  39. package/locales/ko-KR/chat.json +12 -1
  40. package/locales/ko-KR/common.json +16 -0
  41. package/locales/ko-KR/error.json +35 -6
  42. package/locales/ko-KR/setting.json +53 -6
  43. package/locales/nl-NL/chat.json +12 -1
  44. package/locales/nl-NL/common.json +16 -0
  45. package/locales/nl-NL/error.json +35 -6
  46. package/locales/nl-NL/setting.json +53 -6
  47. package/locales/pl-PL/chat.json +12 -1
  48. package/locales/pl-PL/common.json +16 -0
  49. package/locales/pl-PL/error.json +35 -6
  50. package/locales/pl-PL/setting.json +53 -6
  51. package/locales/pt-BR/chat.json +12 -1
  52. package/locales/pt-BR/common.json +16 -0
  53. package/locales/pt-BR/error.json +35 -6
  54. package/locales/pt-BR/setting.json +53 -6
  55. package/locales/ru-RU/chat.json +12 -1
  56. package/locales/ru-RU/common.json +16 -0
  57. package/locales/ru-RU/error.json +35 -6
  58. package/locales/ru-RU/setting.json +53 -6
  59. package/locales/tr-TR/chat.json +12 -1
  60. package/locales/tr-TR/common.json +16 -0
  61. package/locales/tr-TR/error.json +35 -6
  62. package/locales/tr-TR/setting.json +53 -6
  63. package/locales/vi-VN/chat.json +12 -1
  64. package/locales/vi-VN/common.json +16 -0
  65. package/locales/vi-VN/error.json +35 -6
  66. package/locales/vi-VN/setting.json +53 -6
  67. package/locales/zh-CN/chat.json +12 -1
  68. package/locales/zh-CN/common.json +16 -0
  69. package/locales/zh-CN/error.json +34 -5
  70. package/locales/zh-CN/setting.json +59 -12
  71. package/locales/zh-TW/chat.json +12 -1
  72. package/locales/zh-TW/common.json +16 -0
  73. package/locales/zh-TW/error.json +35 -6
  74. package/locales/zh-TW/setting.json +53 -6
  75. package/next.config.mjs +8 -2
  76. package/package.json +8 -2
  77. package/src/app/api/chat/[provider]/agentRuntime.ts +129 -0
  78. package/src/app/api/chat/[provider]/route.ts +64 -0
  79. package/src/app/api/chat/auth.ts +42 -0
  80. package/src/app/api/chat/google/route.ts +86 -0
  81. package/src/app/api/config/route.ts +6 -1
  82. package/src/app/api/config.ts +3 -3
  83. package/src/app/api/errorResponse.test.ts +8 -8
  84. package/src/app/api/errorResponse.ts +43 -6
  85. package/src/app/api/openai/createBizOpenAI/createAzureOpenai.ts +1 -1
  86. package/src/app/api/openai/createBizOpenAI/createOpenai.ts +1 -1
  87. package/src/app/api/openai/createBizOpenAI/index.ts +2 -2
  88. package/src/app/api/plugin/gateway/route.ts +4 -1
  89. package/src/app/chat/(desktop)/features/ChatHeader.tsx +6 -4
  90. package/src/app/chat/(desktop)/features/ChatInput/Footer/index.tsx +13 -3
  91. package/src/app/chat/(desktop)/features/ChatInput/Header/index.tsx +16 -24
  92. package/src/app/chat/(desktop)/features/SideBar/index.tsx +1 -0
  93. package/src/app/chat/features/ChatHeader/ShareButton/Preview.tsx +3 -3
  94. package/src/app/chat/features/SessionListContent/List/Item/index.tsx +2 -3
  95. package/src/app/settings/llm/Azure/index.tsx +145 -0
  96. package/src/app/settings/llm/Bedrock/index.tsx +109 -0
  97. package/src/app/settings/llm/{LLM/Checker.tsx → Checker.tsx} +11 -14
  98. package/src/app/settings/llm/Google/index.tsx +74 -0
  99. package/src/app/settings/llm/{LLM → OpenAI}/index.tsx +26 -44
  100. package/src/app/settings/llm/Zhipu/index.tsx +78 -0
  101. package/src/app/settings/llm/const.ts +13 -0
  102. package/src/app/settings/llm/page.tsx +42 -2
  103. package/src/app/settings/llm/useSyncSettings.ts +23 -0
  104. package/src/chains/__tests__/langDetect.test.ts +2 -2
  105. package/src/chains/__tests__/pickEmoji.test.ts +2 -2
  106. package/src/chains/langDetect.ts +2 -2
  107. package/src/chains/pickEmoji.ts +2 -2
  108. package/src/chains/summaryAgentName.ts +2 -2
  109. package/src/chains/summaryDescription.ts +2 -2
  110. package/src/chains/summaryTags.ts +2 -2
  111. package/src/chains/summaryTitle.ts +2 -2
  112. package/src/chains/translate.ts +2 -2
  113. package/src/components/ModelIcon/index.tsx +37 -0
  114. package/src/components/ModelProviderIcon/index.tsx +44 -0
  115. package/src/components/ModelSelect/index.tsx +133 -0
  116. package/src/components/ModelTag/ModelIcon.tsx +35 -0
  117. package/src/components/ModelTag/index.tsx +13 -0
  118. package/src/config/modelProviders/bedrock.ts +43 -0
  119. package/src/config/modelProviders/google.ts +20 -0
  120. package/src/config/modelProviders/index.ts +18 -0
  121. package/src/config/modelProviders/openai.ts +110 -0
  122. package/src/config/modelProviders/zhipu.ts +34 -0
  123. package/src/config/{server.ts → server/app.ts} +1 -24
  124. package/src/config/server/index.ts +13 -0
  125. package/src/config/server/provider.ts +78 -0
  126. package/src/const/auth.ts +30 -0
  127. package/src/const/fetch.ts +3 -0
  128. package/src/const/settings.ts +24 -4
  129. package/src/database/core/migrations/migrateSettingsToUser/index.test.ts +2 -1
  130. package/src/database/core/migrations/migrateSettingsToUser/index.ts +1 -18
  131. package/src/database/core/migrations/migrateSettingsToUser/type.ts +100 -0
  132. package/src/database/models/message.ts +3 -1
  133. package/src/database/schemas/message.ts +1 -0
  134. package/src/database/schemas/session.ts +1 -0
  135. package/src/features/AgentSetting/AgentConfig/ModelSelect.tsx +71 -0
  136. package/src/features/AgentSetting/AgentConfig/index.tsx +171 -161
  137. package/src/features/AgentSetting/AgentConfig/useSyncConfig.ts +23 -0
  138. package/src/features/AgentSetting/AgentPrompt/TokenTag.tsx +39 -0
  139. package/src/features/AgentSetting/AgentPrompt/index.tsx +4 -26
  140. package/src/features/AgentSetting/store/index.ts +10 -2
  141. package/src/features/ChatInput/ActionBar/FileUpload.tsx +15 -5
  142. package/src/features/ChatInput/ActionBar/ModelSwitch.tsx +56 -14
  143. package/src/features/ChatInput/ActionBar/Token/TokenTag.tsx +42 -7
  144. package/src/features/ChatInput/ActionBar/Token/index.tsx +5 -2
  145. package/src/features/ChatInput/ActionBar/Tools/index.tsx +11 -1
  146. package/src/features/ChatInput/useChatInput.ts +5 -1
  147. package/src/features/Conversation/Error/APIKeyForm/Bedrock.tsx +80 -0
  148. package/src/features/Conversation/Error/APIKeyForm/Google.tsx +61 -0
  149. package/src/features/Conversation/Error/APIKeyForm/OpenAI.tsx +63 -0
  150. package/src/features/Conversation/Error/APIKeyForm/Zhipu.tsx +62 -0
  151. package/src/features/Conversation/Error/APIKeyForm/index.tsx +72 -0
  152. package/src/features/Conversation/Error/AccessCodeForm.tsx +63 -0
  153. package/src/features/Conversation/Error/ErrorJsonViewer.tsx +26 -0
  154. package/src/features/Conversation/Error/InvalidAPIKey.tsx +16 -0
  155. package/src/features/Conversation/Error/InvalidAccessCode.tsx +50 -0
  156. package/src/features/Conversation/Error/OpenAiBizError.tsx +9 -17
  157. package/src/features/Conversation/Error/{Plugin/PluginSettings.tsx → PluginSettings.tsx} +8 -3
  158. package/src/features/Conversation/Error/index.tsx +75 -70
  159. package/src/features/Conversation/Error/style.tsx +9 -3
  160. package/src/features/Conversation/Extras/Assistant.tsx +2 -3
  161. package/src/features/Conversation/Plugins/Inspector/index.tsx +8 -2
  162. package/src/features/Conversation/components/ChatItem/index.tsx +9 -24
  163. package/src/features/Conversation/types/index.tsx +2 -5
  164. package/src/hooks/_header.ts +35 -0
  165. package/src/libs/agent-runtime/BaseAI.ts +9 -0
  166. package/src/libs/agent-runtime/azureOpenai/index.ts +72 -0
  167. package/src/libs/agent-runtime/bedrock/index.ts +134 -0
  168. package/src/libs/agent-runtime/error.ts +26 -0
  169. package/src/libs/agent-runtime/google/index.ts +160 -0
  170. package/src/libs/agent-runtime/index.ts +9 -0
  171. package/src/libs/agent-runtime/openai/index.test.ts +176 -0
  172. package/src/libs/agent-runtime/openai/index.ts +107 -0
  173. package/src/libs/agent-runtime/types/chat.ts +119 -0
  174. package/src/libs/agent-runtime/types/index.ts +2 -0
  175. package/src/libs/agent-runtime/types/type.ts +34 -0
  176. package/src/libs/agent-runtime/utils/createError.ts +10 -0
  177. package/src/libs/agent-runtime/utils/debugStream.ts +18 -0
  178. package/src/libs/agent-runtime/utils/env.ts +1 -0
  179. package/src/libs/agent-runtime/utils/handleOpenAIError.ts +39 -0
  180. package/src/libs/agent-runtime/utils/uriParser.ts +16 -0
  181. package/src/libs/agent-runtime/zhipu/authToken.ts +22 -0
  182. package/src/libs/agent-runtime/zhipu/index.ts +125 -0
  183. package/src/locales/default/chat.ts +12 -2
  184. package/src/locales/default/common.ts +16 -0
  185. package/src/locales/default/error.ts +42 -5
  186. package/src/locales/default/setting.ts +61 -12
  187. package/src/services/__tests__/chat.test.ts +8 -2
  188. package/src/services/__tests__/message.test.ts +1 -1
  189. package/src/services/_auth.ts +106 -0
  190. package/src/services/_header.ts +1 -0
  191. package/src/services/_url.ts +0 -2
  192. package/src/services/chat.ts +34 -14
  193. package/src/store/chat/slices/message/action.ts +9 -6
  194. package/src/store/global/slices/common/action.ts +8 -2
  195. package/src/store/global/slices/settings/action.test.ts +2 -2
  196. package/src/store/global/slices/settings/action.ts +11 -4
  197. package/src/store/global/slices/settings/selectors/__snapshots__/modelProvider.test.ts.snap +24 -92
  198. package/src/store/global/slices/settings/selectors/__snapshots__/selectors.test.ts.snap +2 -0
  199. package/src/store/global/slices/settings/selectors/modelProvider.test.ts +127 -50
  200. package/src/store/global/slices/settings/selectors/modelProvider.ts +145 -43
  201. package/src/store/session/slices/agent/selectors.test.ts +0 -48
  202. package/src/store/session/slices/agent/selectors.ts +7 -12
  203. package/src/types/agent/index.ts +6 -2
  204. package/src/types/fetch.ts +4 -2
  205. package/src/types/files.ts +3 -3
  206. package/src/types/llm.ts +34 -0
  207. package/src/types/message/index.ts +7 -3
  208. package/src/types/openai/chat.ts +6 -11
  209. package/src/types/settings/index.ts +1 -0
  210. package/src/types/settings/modelProvider.ts +37 -1
  211. package/src/utils/__snapshots__/parseModels.test.ts.snap +63 -0
  212. package/src/utils/parseModels.test.ts +24 -0
  213. package/src/utils/parseModels.ts +37 -0
  214. package/src/app/api/openai/chat/createChatCompletion.test.ts +0 -166
  215. package/src/app/api/openai/chat/createChatCompletion.ts +0 -76
  216. package/src/app/api/openai/chat/route.ts +0 -19
  217. package/src/app/api/openai/models/route.ts +0 -17
  218. package/src/app/settings/llm/LLM/ModelList.tsx +0 -51
  219. package/src/app/settings/llm/LLM/getModelList.ts +0 -9
  220. package/src/app/settings/llm/index.tsx +0 -36
  221. package/src/const/llm.ts +0 -32
  222. package/src/features/Conversation/Error/ApiKeyForm.tsx +0 -87
  223. package/src/features/Conversation/Error/ErrorActionContainer.tsx +0 -23
  224. package/src/features/Conversation/Error/InvalidAccess.tsx +0 -90
  225. package/src/features/Conversation/Error/OpenAPIKey.tsx +0 -13
  226. package/src/features/Conversation/Error/Plugin/PluginError.tsx +0 -30
  227. package/src/services/modelList.ts +0 -15
  228. /package/src/app/chat/(desktop)/features/ChatInput/{Header → Footer}/DragUpload.tsx +0 -0
  229. /package/src/{app/api/openai/chat → libs/agent-runtime/utils}/desensitizeUrl.test.ts +0 -0
  230. /package/src/{app/api/openai/chat → libs/agent-runtime/utils}/desensitizeUrl.ts +0 -0
  231. /package/src/types/{translate.ts → message/translate.ts} +0 -0
@@ -1,64 +1,166 @@
1
- import { DEFAULT_OPENAI_MODEL_LIST } from '@/const/llm';
2
- import { CustomModels } from '@/types/settings';
1
+ import { produce } from 'immer';
2
+
3
+ import {
4
+ BedrockProvider,
5
+ GoogleProvider,
6
+ LOBE_DEFAULT_MODEL_LIST,
7
+ OpenAIProvider,
8
+ ZhiPuProvider,
9
+ } from '@/config/modelProviders';
10
+ import { ChatModelCard, ModelProviderCard } from '@/types/llm';
11
+ import { parseModelString } from '@/utils/parseModels';
3
12
 
4
13
  import { GlobalStore } from '../../../store';
5
14
  import { currentSettings } from './settings';
6
15
 
7
- const openAIConfig = (s: GlobalStore) => currentSettings(s).languageModel.openAI;
16
+ const modelProvider = (s: GlobalStore) => currentSettings(s).languageModel;
17
+ const openAIConfig = (s: GlobalStore) => modelProvider(s).openAI;
8
18
 
9
- const openAIAPIKeySelectors = (s: GlobalStore) =>
10
- currentSettings(s).languageModel.openAI.OPENAI_API_KEY;
19
+ const openAIAPIKey = (s: GlobalStore) => openAIConfig(s).OPENAI_API_KEY;
20
+ const openAIProxyUrl = (s: GlobalStore) => openAIConfig(s).endpoint;
11
21
 
12
- const enableAzure = (s: GlobalStore) => currentSettings(s).languageModel.openAI.useAzure;
22
+ const enableZhipu = (s: GlobalStore) => modelProvider(s).zhipu.enabled;
23
+ const zhipuAPIKey = (s: GlobalStore) => modelProvider(s).zhipu.apiKey;
24
+ const zhipuProxyUrl = (s: GlobalStore) => modelProvider(s).zhipu.endpoint;
13
25
 
14
- const openAIProxyUrlSelectors = (s: GlobalStore) =>
15
- currentSettings(s).languageModel.openAI.endpoint;
26
+ const enableBedrock = (s: GlobalStore) => modelProvider(s).bedrock.enabled;
27
+ const bedrockConfig = (s: GlobalStore) => modelProvider(s).bedrock;
16
28
 
17
- const modelListSelectors = (s: GlobalStore) => {
18
- let models: CustomModels = [];
29
+ const enableGoogle = (s: GlobalStore) => modelProvider(s).google.enabled;
30
+ const googleAPIKey = (s: GlobalStore) => modelProvider(s).google.apiKey;
31
+ const googleProxyUrl = (s: GlobalStore) => modelProvider(s).google.endpoint;
19
32
 
20
- const removedModels: string[] = [];
21
- const modelNames = [
22
- ...DEFAULT_OPENAI_MODEL_LIST,
23
- ...(s.serverConfig.customModelName || '').split(/[,,]/).filter(Boolean),
24
- ...(currentSettings(s).languageModel.openAI.customModelName || '')
25
- .split(/[,,]/)
26
- .filter(Boolean),
27
- ];
33
+ const enableAzure = (s: GlobalStore) => modelProvider(s).openAI.useAzure;
34
+ const azureConfig = (s: GlobalStore) => modelProvider(s).azure;
28
35
 
29
- for (const item of modelNames) {
30
- const disable = item.startsWith('-');
31
- const nameConfig = item.startsWith('+') || item.startsWith('-') ? item.slice(1) : item;
32
- const [name, displayName] = nameConfig.split('=');
36
+ // const azureModelList = (s: GlobalStore): ModelProviderCard => {
37
+ // const azure = azureConfig(s);
38
+ // return {
39
+ // chatModels: parseModelString(azure.deployments),
40
+ // id: 'azure',
41
+ // };
42
+ // };
33
43
 
34
- if (disable) {
35
- // Disable all models.
36
- if (name === 'all') {
37
- models = [];
44
+ // 提取处理 chatModels 的专门方法
45
+ const processChatModels = (modelConfig: ReturnType<typeof parseModelString>): ChatModelCard[] => {
46
+ let chatModels = modelConfig.removeAll ? [] : OpenAIProvider.chatModels;
47
+
48
+ // 处理移除逻辑
49
+ if (!modelConfig.removeAll) {
50
+ chatModels = chatModels.filter((m) => !modelConfig.removed.includes(m.id));
51
+ }
52
+
53
+ return produce(chatModels, (draft) => {
54
+ // 处理添加或替换逻辑
55
+ for (const customModel of modelConfig.add) {
56
+ // 首先尝试在 LOBE_DEFAULT_MODEL_LIST 中查找模型
57
+ const defaultModel = LOBE_DEFAULT_MODEL_LIST.find((model) => model.id === customModel.id);
58
+
59
+ // 如果在默认列表中找到了模型,则基于该模型进行更新
60
+ if (defaultModel) {
61
+ const model = draft.find((model) => model.id === customModel.id);
62
+ // 如果当前 chatModels 中已有该模型,更新它
63
+ if (model) {
64
+ if (model.hidden) delete model.hidden;
65
+ if (customModel.displayName) model.displayName = customModel.displayName;
66
+ } else {
67
+ // 如果当前 chatModels 中没有该模型,添加它
68
+ draft.push({
69
+ ...defaultModel,
70
+ displayName: customModel.displayName || defaultModel.displayName,
71
+ });
72
+ }
73
+ } else {
74
+ // 如果在默认列表中未找到模型,作为新的自定义模型添加
75
+ draft.push({
76
+ ...customModel,
77
+ displayName: customModel.displayName || customModel.id,
78
+ functionCall: true,
79
+ isCustom: true,
80
+ vision: true,
81
+ });
38
82
  }
39
- removedModels.push(name);
40
- continue;
41
83
  }
84
+ });
85
+ };
42
86
 
43
- // Remove duplicate model entries.
44
- const existingIndex = models.findIndex(({ name: n }) => n === name);
45
- if (existingIndex !== -1) {
46
- models.splice(existingIndex, 1);
47
- }
87
+ const modelSelectList = (s: GlobalStore): ModelProviderCard[] => {
88
+ const string = [
89
+ s.serverConfig.customModelName,
90
+ currentSettings(s).languageModel.openAI.customModelName,
91
+ ]
92
+ .filter(Boolean)
93
+ .join(',');
48
94
 
49
- models.push({
50
- displayName: displayName || name,
51
- name,
52
- });
53
- }
95
+ const modelConfig = parseModelString(string);
96
+
97
+ const chatModels = processChatModels(modelConfig);
54
98
 
55
- return models.filter((m) => !removedModels.includes(m.name));
99
+ return [
100
+ {
101
+ ...OpenAIProvider,
102
+ chatModels,
103
+ },
104
+ // { ...azureModelList(s), enabled: enableAzure(s) },
105
+ { ...ZhiPuProvider, enabled: enableZhipu(s) },
106
+ { ...GoogleProvider, enabled: enableGoogle(s) },
107
+ { ...BedrockProvider, enabled: enableBedrock(s) },
108
+ ];
56
109
  };
57
110
 
111
+ const modelCardById = (id: string) => (s: GlobalStore) => {
112
+ const list = modelSelectList(s);
113
+
114
+ return list.flatMap((i) => i.chatModels).find((m) => m.id === id);
115
+ };
116
+
117
+ const modelEnabledFunctionCall = (id: string) => (s: GlobalStore) =>
118
+ modelCardById(id)(s)?.functionCall || false;
119
+
120
+ // vision model white list, these models will change the content from string to array
121
+ // refs: https://github.com/lobehub/lobe-chat/issues/790
122
+ const modelEnabledVision = (id: string) => (s: GlobalStore) =>
123
+ modelCardById(id)(s)?.vision || id.includes('vision');
124
+
125
+ const modelEnabledFiles = (id: string) => (s: GlobalStore) => modelCardById(id)(s)?.files;
126
+
127
+ const modelEnabledUpload = (id: string) => (s: GlobalStore) =>
128
+ modelEnabledVision(id)(s) || modelEnabledFiles(id)(s);
129
+
130
+ const modelHasMaxToken = (id: string) => (s: GlobalStore) =>
131
+ typeof modelCardById(id)(s)?.tokens !== 'undefined';
132
+
133
+ const modelMaxToken = (id: string) => (s: GlobalStore) => modelCardById(id)(s)?.tokens || 0;
134
+
135
+ /* eslint-disable sort-keys-fix/sort-keys-fix, */
58
136
  export const modelProviderSelectors = {
59
- enableAzure,
60
- modelList: modelListSelectors,
61
- openAIAPI: openAIAPIKeySelectors,
137
+ modelSelectList,
138
+
139
+ modelCardById,
140
+ modelMaxToken,
141
+ modelHasMaxToken,
142
+
143
+ modelEnabledFunctionCall,
144
+ modelEnabledVision,
145
+ modelEnabledFiles,
146
+ modelEnabledUpload,
147
+
148
+ // OpenAI
62
149
  openAIConfig,
63
- openAIProxyUrl: openAIProxyUrlSelectors,
150
+ openAIAPIKey,
151
+ openAIProxyUrl,
152
+ // Azure OpenAI
153
+ enableAzure,
154
+ azureConfig,
155
+ // Zhipu
156
+ enableZhipu,
157
+ zhipuAPIKey,
158
+ zhipuProxyUrl,
159
+ // Google
160
+ enableGoogle,
161
+ googleAPIKey,
162
+ googleProxyUrl,
163
+ // Bedrock
164
+ enableBedrock,
165
+ bedrockConfig,
64
166
  };
@@ -177,52 +177,4 @@ describe('agentSelectors', () => {
177
177
  expect(description).toBe('noDescription'); // Assuming translation returns this key
178
178
  });
179
179
  });
180
-
181
- describe('showTokenTag', () => {
182
- it('should return true if the model is in the list of models that show tokens', () => {
183
- const show = agentSelectors.showTokenTag(mockSessionStore);
184
- expect(show).toBe(true);
185
- });
186
-
187
- it('should return false if the model is not in the list of models that show tokens', () => {
188
- const modifiedSessionStore = {
189
- ...mockSessionStore,
190
- sessions: [
191
- {
192
- ...mockSessionStore.sessions[0],
193
- config: {
194
- ...mockSessionStore.sessions[0].config,
195
- model: 'some-other-model',
196
- },
197
- },
198
- ],
199
- };
200
- const show = agentSelectors.showTokenTag(modifiedSessionStore);
201
- expect(show).toBe(false);
202
- });
203
- });
204
-
205
- describe('modelHasVisionAbility', () => {
206
- it('should return true if the model has vision ability', () => {
207
- const hasAbility = agentSelectors.modelHasVisionAbility(mockSessionStore);
208
- expect(hasAbility).toBe(false);
209
- });
210
-
211
- it('should return false if the model does not have vision ability', () => {
212
- const modifiedSessionStore = {
213
- ...mockSessionStore,
214
- sessions: [
215
- {
216
- ...mockSessionStore.sessions[0],
217
- config: {
218
- ...mockSessionStore.sessions[0].config,
219
- model: 'some-other-model',
220
- },
221
- },
222
- ],
223
- };
224
- const hasAbility = agentSelectors.modelHasVisionAbility(modifiedSessionStore);
225
- expect(hasAbility).toBe(false);
226
- });
227
- });
228
180
  });
@@ -1,7 +1,6 @@
1
1
  import { VoiceList } from '@lobehub/tts';
2
2
  import { t } from 'i18next';
3
3
 
4
- import { DEFAULT_OPENAI_MODEL_LIST, isVisionModel } from '@/const/llm';
5
4
  import { DEFAULT_AVATAR, DEFAULT_BACKGROUND_COLOR, DEFAULT_INBOX_AVATAR } from '@/const/meta';
6
5
  import { DEFAULT_AGENT_CONFIG, DEFAUTT_AGENT_TTS_CONFIG } from '@/const/settings';
7
6
  import { useGlobalStore } from '@/store/global';
@@ -36,6 +35,12 @@ const currentAgentModel = (s: SessionStore): LanguageModel | string => {
36
35
  return config?.model || LanguageModel.GPT3_5;
37
36
  };
38
37
 
38
+ const currentAgentModelProvider = (s: SessionStore) => {
39
+ const config = currentAgentConfig(s);
40
+
41
+ return config?.provider;
42
+ };
43
+
39
44
  const currentAgentPlugins = (s: SessionStore) => {
40
45
  const config = currentAgentConfig(s);
41
46
 
@@ -99,20 +104,11 @@ const getTitle = (s: MetaData) => s.title || t('defaultSession', { ns: 'common'
99
104
  export const getDescription = (s: MetaData) =>
100
105
  s.description || t('noDescription', { ns: 'common' });
101
106
 
102
- const showTokenTag = (s: SessionStore) => {
103
- const model = currentAgentModel(s);
104
-
105
- return DEFAULT_OPENAI_MODEL_LIST.includes(model);
106
- };
107
107
  const hasSystemRole = (s: SessionStore) => {
108
108
  const config = currentAgentConfig(s);
109
109
 
110
110
  return !!config.systemRole;
111
111
  };
112
- const modelHasVisionAbility = (s: SessionStore): boolean => {
113
- const model = currentAgentModel(s);
114
- return isVisionModel(model);
115
- };
116
112
 
117
113
  export const agentSelectors = {
118
114
  currentAgentAvatar,
@@ -121,6 +117,7 @@ export const agentSelectors = {
121
117
  currentAgentDescription,
122
118
  currentAgentMeta,
123
119
  currentAgentModel,
120
+ currentAgentModelProvider,
124
121
  currentAgentPlugins,
125
122
  currentAgentSystemRole,
126
123
  currentAgentTTS,
@@ -130,6 +127,4 @@ export const agentSelectors = {
130
127
  getDescription,
131
128
  getTitle,
132
129
  hasSystemRole,
133
- modelHasVisionAbility,
134
- showTokenTag,
135
130
  };
@@ -1,4 +1,4 @@
1
- import { FewShots, LLMParams, LanguageModel } from '@/types/llm';
1
+ import { FewShots, LLMParams } from '@/types/llm';
2
2
 
3
3
  export type TTSServer = 'openai' | 'edge' | 'microsoft';
4
4
 
@@ -37,7 +37,7 @@ export interface LobeAgentConfig {
37
37
  * 角色所使用的语言模型
38
38
  * @default gpt-3.5-turbo
39
39
  */
40
- model: LanguageModel | string;
40
+ model: string;
41
41
  /**
42
42
  * 语言模型参数
43
43
  */
@@ -46,6 +46,10 @@ export interface LobeAgentConfig {
46
46
  * 启用的插件
47
47
  */
48
48
  plugins?: string[];
49
+ /**
50
+ * 模型供应商
51
+ */
52
+ provider?: string;
49
53
  /**
50
54
  * 系统角色
51
55
  */
@@ -1,10 +1,12 @@
1
1
  /* eslint-disable sort-keys-fix/sort-keys-fix */
2
+ import { ILobeAgentRuntimeErrorType } from '@/libs/agent-runtime';
3
+
2
4
  export const ChatErrorType = {
3
5
  // ******* 业务错误语义 ******* //
4
6
 
5
7
  InvalidAccessCode: 'InvalidAccessCode', // 密码无效
6
8
  OpenAIBizError: 'OpenAIBizError', // OpenAI 返回的业务错误
7
- NoAPIKey: 'NoAPIKey',
9
+ NoOpenAIAPIKey: 'NoOpenAIAPIKey',
8
10
 
9
11
  // ******* 客户端错误 ******* //
10
12
  BadRequest: 400,
@@ -26,5 +28,5 @@ export type ErrorType = (typeof ChatErrorType)[keyof typeof ChatErrorType];
26
28
 
27
29
  export interface ErrorResponse {
28
30
  body: any;
29
- errorType: ErrorType;
31
+ errorType: ErrorType | ILobeAgentRuntimeErrorType;
30
32
  }
@@ -1,8 +1,8 @@
1
- import { DB_File } from '../database/schemas/files';
2
-
3
- export interface FilePreview extends Pick<DB_File, 'saveMode' | 'fileType'> {
1
+ export interface FilePreview {
4
2
  base64Url?: string;
5
3
  data?: ArrayBuffer;
4
+ fileType: string;
6
5
  name: string;
6
+ saveMode: 'local' | 'url';
7
7
  url: string;
8
8
  }
package/src/types/llm.ts CHANGED
@@ -17,6 +17,40 @@ export enum LanguageModel {
17
17
  GPT4_VISION_PREVIEW = 'gpt-4-vision-preview',
18
18
  }
19
19
 
20
+ export interface ChatModelCard {
21
+ description?: string;
22
+ displayName?: string;
23
+ /**
24
+ * whether model supports file upload
25
+ */
26
+ files?: boolean;
27
+ /**
28
+ * whether model supports function call
29
+ */
30
+ functionCall?: boolean;
31
+ hidden?: boolean;
32
+ id: string;
33
+ /**
34
+ * whether model is custom
35
+ */
36
+ isCustom?: boolean;
37
+ /**
38
+ * whether model is legacy (deprecated but not removed yet)
39
+ */
40
+ legacy?: boolean;
41
+ tokens?: number;
42
+ /**
43
+ * whether model supports vision
44
+ */
45
+ vision?: boolean;
46
+ }
47
+
48
+ export interface ModelProviderCard {
49
+ chatModels: ChatModelCard[];
50
+ enabled?: boolean;
51
+ id: string;
52
+ }
53
+
20
54
  // 语言模型的设置参数
21
55
  export interface LLMParams {
22
56
  /**
@@ -1,9 +1,12 @@
1
+ import { IPluginErrorType } from '@lobehub/chat-plugin-sdk';
2
+
3
+ import { ILobeAgentRuntimeErrorType } from '@/libs/agent-runtime';
1
4
  import { ErrorType } from '@/types/fetch';
2
- import { Translate } from '@/types/translate';
3
5
 
4
6
  import { LLMRoleType } from '../llm';
5
7
  import { BaseDataModel } from '../meta';
6
8
  import { ChatPluginPayload } from './tools';
9
+ import { Translate } from './translate';
7
10
 
8
11
  /**
9
12
  * 聊天消息错误对象
@@ -11,7 +14,7 @@ import { ChatPluginPayload } from './tools';
11
14
  export interface ChatMessageError {
12
15
  body?: any;
13
16
  message: string;
14
- type: ErrorType;
17
+ type: ErrorType | IPluginErrorType | ILobeAgentRuntimeErrorType;
15
18
  }
16
19
 
17
20
  export interface ChatTranslate extends Translate {
@@ -28,10 +31,11 @@ export * from './tools';
28
31
 
29
32
  export interface ChatMessage extends BaseDataModel {
30
33
  content: string;
31
- error?: any;
34
+ error?: ChatMessageError;
32
35
  // 扩展字段
33
36
  extra?: {
34
37
  fromModel?: string;
38
+ fromProvider?: string;
35
39
  // 翻译
36
40
  translate?: ChatTranslate | false;
37
41
  // TTS
@@ -32,24 +32,15 @@ export interface OpenAIChatMessage {
32
32
  role: LLMRoleType;
33
33
  }
34
34
 
35
- export interface OpenAIChatStringMessage {
36
- content: string;
37
- role: LLMRoleType;
38
- }
39
-
40
35
  /**
41
- * @title OpenAI Stream Payload
36
+ * @title Chat Stream Payload
42
37
  */
43
- export interface OpenAIChatStreamPayload {
38
+ export interface ChatStreamPayload {
44
39
  /**
45
40
  * @title 控制生成文本中的惩罚系数,用于减少重复性
46
41
  * @default 0
47
42
  */
48
43
  frequency_penalty?: number;
49
- /**
50
- * @deprecated
51
- */
52
- functions?: ChatCompletionFunctions[];
53
44
  /**
54
45
  * @title 生成文本的最大长度
55
46
  */
@@ -75,6 +66,10 @@ export interface OpenAIChatStreamPayload {
75
66
  * @default 0
76
67
  */
77
68
  presence_penalty?: number;
69
+ /**
70
+ * @default openai
71
+ */
72
+ provider?: string;
78
73
  /**
79
74
  * @title 是否开启流式请求
80
75
  * @default true
@@ -21,6 +21,7 @@ export interface GlobalTool {
21
21
  export interface GlobalServerConfig {
22
22
  customModelName?: string;
23
23
  defaultAgent?: DeepPartial<GlobalDefaultAgent>;
24
+ languageModel?: DeepPartial<GlobalLLMConfig>;
24
25
  }
25
26
 
26
27
  /**
@@ -1,4 +1,4 @@
1
- export type CustomModels = { displayName: string; name: string }[];
1
+ export type CustomModels = { displayName: string; id: string }[];
2
2
 
3
3
  export interface OpenAIConfig {
4
4
  OPENAI_API_KEY: string;
@@ -8,10 +8,46 @@ export interface OpenAIConfig {
8
8
  */
9
9
  customModelName?: string;
10
10
  endpoint?: string;
11
+ /**
12
+ * @deprecated
13
+ */
11
14
  models?: string[];
12
15
  useAzure?: boolean;
13
16
  }
14
17
 
18
+ export interface AzureOpenAIConfig {
19
+ apiKey: string;
20
+ apiVersion?: string;
21
+ deployments: string;
22
+ enabled: boolean;
23
+ endpoint?: string;
24
+ }
25
+
26
+ export interface ZhiPuConfig {
27
+ apiKey?: string;
28
+ enabled: boolean;
29
+ endpoint?: string;
30
+ }
31
+
32
+ export interface GoogleConfig {
33
+ apiKey?: string;
34
+ enabled: boolean;
35
+ endpoint?: string;
36
+ }
37
+
38
+ export interface AWSBedrockConfig {
39
+ accessKeyId?: string;
40
+ enabled: boolean;
41
+ region?: string;
42
+ secretAccessKey?: string;
43
+ }
44
+
15
45
  export interface GlobalLLMConfig {
46
+ azure: AzureOpenAIConfig;
47
+ bedrock: AWSBedrockConfig;
48
+ google: GoogleConfig;
16
49
  openAI: OpenAIConfig;
50
+ zhipu: ZhiPuConfig;
17
51
  }
52
+
53
+ export type GlobalLLMProviderKey = keyof GlobalLLMConfig;
@@ -0,0 +1,63 @@
1
+ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
+
3
+ exports[`parseModelString > custom deletion, addition, and renaming of models 1`] = `
4
+ {
5
+ "add": [
6
+ {
7
+ "displayName": undefined,
8
+ "id": "llama",
9
+ },
10
+ {
11
+ "displayName": undefined,
12
+ "id": "claude-2",
13
+ },
14
+ {
15
+ "displayName": "gpt-4-32k",
16
+ "id": "gpt-4-1106-preview",
17
+ },
18
+ ],
19
+ "removeAll": true,
20
+ "removed": [
21
+ "all",
22
+ "gpt-3.5-turbo",
23
+ ],
24
+ }
25
+ `;
26
+
27
+ exports[`parseModelString > duplicate naming model 1`] = `
28
+ {
29
+ "add": [
30
+ {
31
+ "displayName": "gpt-4-32k",
32
+ "id": "gpt-4-1106-preview",
33
+ },
34
+ ],
35
+ "removeAll": false,
36
+ "removed": [],
37
+ }
38
+ `;
39
+
40
+ exports[`parseModelString > only add the model 1`] = `
41
+ {
42
+ "add": [
43
+ {
44
+ "displayName": undefined,
45
+ "id": "model1",
46
+ },
47
+ {
48
+ "displayName": undefined,
49
+ "id": "model2",
50
+ },
51
+ {
52
+ "displayName": undefined,
53
+ "id": "model3",
54
+ },
55
+ {
56
+ "displayName": undefined,
57
+ "id": "model4",
58
+ },
59
+ ],
60
+ "removeAll": false,
61
+ "removed": [],
62
+ }
63
+ `;
@@ -0,0 +1,24 @@
1
+ import { describe, expect, it } from 'vitest';
2
+
3
+ import { parseModelString } from './parseModels';
4
+
5
+ describe('parseModelString', () => {
6
+ it('custom deletion, addition, and renaming of models', () => {
7
+ const result = parseModelString(
8
+ '-all,+llama,+claude-2,-gpt-3.5-turbo,gpt-4-1106-preview=gpt-4-turbo,gpt-4-1106-preview=gpt-4-32k',
9
+ );
10
+
11
+ expect(result).toMatchSnapshot();
12
+ });
13
+
14
+ it('duplicate naming model', () => {
15
+ const result = parseModelString('gpt-4-1106-preview=gpt-4-turbo,gpt-4-1106-preview=gpt-4-32k');
16
+ expect(result).toMatchSnapshot();
17
+ });
18
+
19
+ it('only add the model', () => {
20
+ const result = parseModelString('model1,model2,model3,model4');
21
+
22
+ expect(result).toMatchSnapshot();
23
+ });
24
+ });
@@ -0,0 +1,37 @@
1
+ import { CustomModels } from '@/types/settings';
2
+
3
+ export const parseModelString = (modelString: string = '') => {
4
+ let models: CustomModels = [];
5
+ let removeAll = false;
6
+ const removedModels: string[] = [];
7
+ const modelNames = modelString.split(/[,,]/).filter(Boolean);
8
+
9
+ for (const item of modelNames) {
10
+ const disable = item.startsWith('-');
11
+ const nameConfig = item.startsWith('+') || item.startsWith('-') ? item.slice(1) : item;
12
+ const [id, displayName] = nameConfig.split('=');
13
+
14
+ if (disable) {
15
+ // Disable all models.
16
+ if (id === 'all') {
17
+ removeAll = true;
18
+ }
19
+ removedModels.push(id);
20
+ continue;
21
+ }
22
+
23
+ // Remove duplicate model entries.
24
+ const existingIndex = models.findIndex(({ id: n }) => n === id);
25
+ if (existingIndex !== -1) {
26
+ models.splice(existingIndex, 1);
27
+ }
28
+
29
+ models.push({ displayName, id: id });
30
+ }
31
+
32
+ return {
33
+ add: models,
34
+ removeAll,
35
+ removed: removedModels,
36
+ };
37
+ };