@lobehub/chat 1.43.6 → 1.44.0

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 (298) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/changelog/v1.json +9 -0
  3. package/docs/self-hosting/server-database/docker-compose.mdx +2 -2
  4. package/locales/ar/common.json +1 -0
  5. package/locales/ar/modelProvider.json +176 -0
  6. package/locales/ar/setting.json +1 -0
  7. package/locales/bg-BG/common.json +1 -0
  8. package/locales/bg-BG/modelProvider.json +176 -0
  9. package/locales/bg-BG/setting.json +1 -0
  10. package/locales/de-DE/common.json +1 -0
  11. package/locales/de-DE/modelProvider.json +176 -0
  12. package/locales/de-DE/setting.json +1 -0
  13. package/locales/en-US/common.json +1 -0
  14. package/locales/en-US/modelProvider.json +176 -0
  15. package/locales/en-US/setting.json +1 -0
  16. package/locales/es-ES/common.json +1 -0
  17. package/locales/es-ES/modelProvider.json +176 -0
  18. package/locales/es-ES/setting.json +1 -0
  19. package/locales/fa-IR/common.json +1 -0
  20. package/locales/fa-IR/modelProvider.json +176 -0
  21. package/locales/fa-IR/setting.json +1 -0
  22. package/locales/fr-FR/common.json +1 -0
  23. package/locales/fr-FR/modelProvider.json +176 -0
  24. package/locales/fr-FR/setting.json +1 -0
  25. package/locales/it-IT/common.json +1 -0
  26. package/locales/it-IT/modelProvider.json +176 -0
  27. package/locales/it-IT/setting.json +1 -0
  28. package/locales/ja-JP/common.json +1 -0
  29. package/locales/ja-JP/modelProvider.json +176 -0
  30. package/locales/ja-JP/setting.json +1 -0
  31. package/locales/ko-KR/common.json +1 -0
  32. package/locales/ko-KR/modelProvider.json +176 -0
  33. package/locales/ko-KR/setting.json +1 -0
  34. package/locales/nl-NL/common.json +1 -0
  35. package/locales/nl-NL/modelProvider.json +176 -0
  36. package/locales/nl-NL/setting.json +1 -0
  37. package/locales/pl-PL/common.json +1 -0
  38. package/locales/pl-PL/modelProvider.json +176 -0
  39. package/locales/pl-PL/setting.json +1 -0
  40. package/locales/pt-BR/common.json +1 -0
  41. package/locales/pt-BR/modelProvider.json +176 -0
  42. package/locales/pt-BR/setting.json +1 -0
  43. package/locales/ru-RU/common.json +1 -0
  44. package/locales/ru-RU/modelProvider.json +176 -0
  45. package/locales/ru-RU/setting.json +1 -0
  46. package/locales/tr-TR/common.json +1 -0
  47. package/locales/tr-TR/modelProvider.json +176 -0
  48. package/locales/tr-TR/setting.json +1 -0
  49. package/locales/vi-VN/common.json +1 -0
  50. package/locales/vi-VN/modelProvider.json +176 -0
  51. package/locales/vi-VN/setting.json +1 -0
  52. package/locales/zh-CN/common.json +1 -0
  53. package/locales/zh-CN/modelProvider.json +176 -0
  54. package/locales/zh-CN/setting.json +1 -0
  55. package/locales/zh-TW/common.json +1 -0
  56. package/locales/zh-TW/modelProvider.json +176 -0
  57. package/locales/zh-TW/setting.json +1 -0
  58. package/package.json +4 -4
  59. package/src/app/(main)/(mobile)/me/settings/features/Category.tsx +1 -1
  60. package/src/app/(main)/(mobile)/me/settings/features/useCategory.tsx +12 -5
  61. package/src/app/(main)/changelog/features/VersionTag.tsx +1 -2
  62. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatList/ChatItem/Thread.tsx +1 -1
  63. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatList/ChatItem/ThreadItem.tsx +1 -2
  64. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatList/ChatItem/index.tsx +0 -1
  65. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatList/WelcomeChatItem/InboxWelcome/AgentsSuggest.tsx +1 -1
  66. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatList/WelcomeChatItem/InboxWelcome/QuestionSuggest.tsx +1 -1
  67. package/src/app/(main)/chat/(workspace)/@conversation/features/ZenModeToast/Toast.tsx +1 -1
  68. package/src/app/(main)/chat/(workspace)/@topic/features/TopicListContent/ThreadItem/index.tsx +0 -2
  69. package/src/app/(main)/chat/(workspace)/@topic/features/TopicListContent/TopicItem/index.tsx +0 -1
  70. package/src/app/(main)/chat/(workspace)/_layout/Desktop/ChatHeader/Tags.tsx +2 -3
  71. package/src/app/(main)/chat/@session/features/SessionListContent/CollapseGroup/index.tsx +1 -1
  72. package/src/app/(main)/chat/features/Migration/Start.tsx +1 -1
  73. package/src/app/(main)/discover/(detail)/assistant/[slug]/features/ConversationExample/TopicList.tsx +4 -3
  74. package/src/app/(main)/discover/(detail)/assistant/[slug]/features/Header.tsx +1 -1
  75. package/src/app/(main)/discover/(detail)/features/ShareButton.tsx +2 -1
  76. package/src/app/(main)/discover/(detail)/model/[...slugs]/features/Header.tsx +1 -1
  77. package/src/app/(main)/discover/(detail)/plugin/[slug]/features/Header.tsx +1 -1
  78. package/src/app/(main)/discover/(detail)/provider/[slug]/features/Header.tsx +1 -1
  79. package/src/app/(main)/discover/(list)/_layout/Desktop/Nav.tsx +0 -1
  80. package/src/app/(main)/discover/(list)/assistants/features/Card.tsx +1 -1
  81. package/src/app/(main)/discover/(list)/models/features/Card.tsx +1 -1
  82. package/src/app/(main)/discover/(list)/plugins/features/Card.tsx +1 -1
  83. package/src/app/(main)/discover/(list)/providers/features/Card.tsx +1 -1
  84. package/src/app/(main)/discover/components/GridLoadingCard.tsx +2 -1
  85. package/src/app/(main)/discover/components/Title.tsx +1 -1
  86. package/src/app/(main)/files/(content)/@menu/features/KnowledgeBase/EmptyStatus.tsx +1 -1
  87. package/src/app/(main)/files/(content)/@menu/features/KnowledgeBase/Item/index.tsx +0 -1
  88. package/src/app/(main)/files/(content)/@modal/(.)[id]/FullscreenModal.tsx +2 -2
  89. package/src/app/(main)/files/(content)/NotSupportClient.tsx +2 -2
  90. package/src/app/(main)/profile/_layout/Desktop/SideBar.tsx +1 -1
  91. package/src/app/(main)/profile/stats/features/ShareButton/Preview.tsx +5 -5
  92. package/src/app/(main)/repos/[id]/evals/components/Container.tsx +1 -1
  93. package/src/app/(main)/repos/[id]/evals/dataset/DatasetList/Item.tsx +0 -1
  94. package/src/app/(main)/settings/_layout/Desktop/SideBar.tsx +1 -1
  95. package/src/app/(main)/settings/about/features/ItemCard.tsx +3 -3
  96. package/src/app/(main)/settings/about/features/Version.tsx +1 -1
  97. package/src/app/(main)/settings/hooks/useCategory.tsx +22 -9
  98. package/src/app/(main)/settings/llm/components/ProviderConfig/index.tsx +2 -1
  99. package/src/app/(main)/settings/llm/components/ProviderModelList/ModelFetcher.tsx +0 -1
  100. package/src/app/(main)/settings/provider/(detail)/[id]/index.tsx +19 -0
  101. package/src/app/(main)/settings/provider/(detail)/[id]/page.tsx +95 -0
  102. package/src/app/(main)/settings/provider/(detail)/azure/page.tsx +119 -0
  103. package/src/app/(main)/settings/provider/(detail)/bedrock/page.tsx +91 -0
  104. package/src/app/(main)/settings/provider/(detail)/cloudflare/page.tsx +58 -0
  105. package/src/app/(main)/settings/provider/(detail)/github/page.tsx +67 -0
  106. package/src/app/(main)/settings/provider/(detail)/huggingface/page.tsx +67 -0
  107. package/src/app/(main)/settings/provider/(detail)/ollama/Checker.tsx +73 -0
  108. package/src/app/(main)/settings/provider/(detail)/ollama/page.tsx +34 -0
  109. package/src/app/(main)/settings/provider/(detail)/openai/page.tsx +23 -0
  110. package/src/app/(main)/settings/provider/(detail)/wenxin/page.tsx +61 -0
  111. package/src/app/(main)/settings/provider/(list)/Footer.tsx +36 -0
  112. package/src/app/(main)/settings/provider/(list)/ProviderGrid/Card.tsx +134 -0
  113. package/src/app/(main)/settings/provider/(list)/ProviderGrid/index.tsx +91 -0
  114. package/src/app/(main)/settings/provider/(list)/index.tsx +19 -0
  115. package/src/app/(main)/settings/provider/ProviderMenu/AddNew.tsx +28 -0
  116. package/src/app/(main)/settings/provider/ProviderMenu/All.tsx +29 -0
  117. package/src/app/(main)/settings/provider/ProviderMenu/Item.tsx +69 -0
  118. package/src/app/(main)/settings/provider/ProviderMenu/List.tsx +76 -0
  119. package/src/app/(main)/settings/provider/ProviderMenu/SearchResult.tsx +43 -0
  120. package/src/app/(main)/settings/provider/ProviderMenu/SkeletonList.tsx +60 -0
  121. package/src/app/(main)/settings/provider/ProviderMenu/SortProviderModal/GroupItem.tsx +30 -0
  122. package/src/app/(main)/settings/provider/ProviderMenu/SortProviderModal/index.tsx +91 -0
  123. package/src/app/(main)/settings/provider/ProviderMenu/index.tsx +80 -0
  124. package/src/app/(main)/settings/provider/_layout/Desktop.tsx +37 -0
  125. package/src/app/(main)/settings/provider/_layout/Mobile.tsx +14 -0
  126. package/src/app/(main)/settings/provider/const.ts +20 -0
  127. package/src/app/(main)/settings/provider/features/CreateNewProvider/index.tsx +146 -0
  128. package/src/app/(main)/settings/provider/features/ModelList/CreateNewModelModal/Form.tsx +105 -0
  129. package/src/app/(main)/settings/provider/features/ModelList/CreateNewModelModal/index.tsx +69 -0
  130. package/src/app/(main)/settings/provider/features/ModelList/DisabledModels.tsx +29 -0
  131. package/src/app/(main)/settings/provider/features/ModelList/EmptyModels.tsx +101 -0
  132. package/src/app/(main)/settings/provider/features/ModelList/EnabledModelList/index.tsx +85 -0
  133. package/src/app/(main)/settings/provider/features/ModelList/ModelConfigModal/Form.tsx +109 -0
  134. package/src/app/(main)/settings/provider/features/ModelList/ModelConfigModal/index.tsx +76 -0
  135. package/src/app/(main)/settings/provider/features/ModelList/ModelItem.tsx +346 -0
  136. package/src/app/(main)/settings/provider/features/ModelList/ModelTitle/Search.tsx +37 -0
  137. package/src/app/(main)/settings/provider/features/ModelList/ModelTitle/index.tsx +145 -0
  138. package/src/app/(main)/settings/provider/features/ModelList/SearchResult.tsx +67 -0
  139. package/src/app/(main)/settings/provider/features/ModelList/SkeletonList.tsx +63 -0
  140. package/src/app/(main)/settings/provider/features/ModelList/SortModelModal/ListItem.tsx +20 -0
  141. package/src/app/(main)/settings/provider/features/ModelList/SortModelModal/index.tsx +96 -0
  142. package/src/app/(main)/settings/provider/features/ModelList/index.tsx +59 -0
  143. package/src/app/(main)/settings/provider/features/ProviderConfig/Checker.tsx +120 -0
  144. package/src/app/(main)/settings/provider/features/ProviderConfig/SkeletonInput.tsx +5 -0
  145. package/src/app/(main)/settings/provider/features/ProviderConfig/UpdateProviderInfo/SettingModal.tsx +137 -0
  146. package/src/app/(main)/settings/provider/features/ProviderConfig/UpdateProviderInfo/index.tsx +49 -0
  147. package/src/app/(main)/settings/provider/features/ProviderConfig/index.tsx +343 -0
  148. package/src/app/(main)/settings/provider/layout.tsx +21 -0
  149. package/src/app/(main)/settings/provider/page.tsx +17 -0
  150. package/src/app/(main)/settings/provider/type.ts +5 -0
  151. package/src/app/(main)/settings/sync/features/DeviceInfo/Card.tsx +1 -1
  152. package/src/app/(main)/settings/sync/features/DeviceInfo/index.tsx +1 -1
  153. package/src/app/@modal/(.)changelog/modal/features/ReadDetail.tsx +1 -1
  154. package/src/app/@modal/(.)changelog/modal/features/VersionTag.tsx +1 -2
  155. package/src/app/@modal/(.)changelog/modal/layout.tsx +1 -1
  156. package/src/components/Cell/index.tsx +1 -1
  157. package/src/components/DragUpload/index.tsx +2 -3
  158. package/src/components/FeatureList/index.tsx +1 -1
  159. package/src/components/FileParsingStatus/EmbeddingStatus.tsx +1 -1
  160. package/src/components/FileParsingStatus/index.tsx +1 -1
  161. package/src/components/FunctionModal/style.tsx +2 -2
  162. package/src/components/GoBack/index.tsx +1 -2
  163. package/src/components/HotKeys/index.tsx +1 -1
  164. package/src/components/InstantSwitch/index.tsx +28 -0
  165. package/src/components/Menu/index.tsx +1 -1
  166. package/src/components/ModelSelect/index.tsx +2 -3
  167. package/src/components/Notification/index.tsx +2 -1
  168. package/src/components/StatisticCard/index.tsx +5 -6
  169. package/src/config/aiModels/ai21.ts +38 -0
  170. package/src/config/aiModels/ai360.ts +71 -0
  171. package/src/config/aiModels/anthropic.ts +152 -0
  172. package/src/config/aiModels/azure.ts +86 -0
  173. package/src/config/aiModels/baichuan.ts +107 -0
  174. package/src/config/aiModels/bedrock.ts +315 -0
  175. package/src/config/aiModels/cloudflare.ts +88 -0
  176. package/src/config/aiModels/deepseek.ts +27 -0
  177. package/src/config/aiModels/fireworksai.ts +232 -0
  178. package/src/config/aiModels/giteeai.ts +137 -0
  179. package/src/config/aiModels/github.ts +273 -0
  180. package/src/config/aiModels/google.ts +317 -0
  181. package/src/config/aiModels/groq.ts +202 -0
  182. package/src/config/aiModels/higress.ts +2828 -0
  183. package/src/config/aiModels/huggingface.ts +56 -0
  184. package/src/config/aiModels/hunyuan.ts +151 -0
  185. package/src/config/aiModels/index.ts +98 -0
  186. package/src/config/aiModels/internlm.ts +40 -0
  187. package/src/config/aiModels/minimax.ts +55 -0
  188. package/src/config/aiModels/mistral.ts +172 -0
  189. package/src/config/aiModels/moonshot.ts +44 -0
  190. package/src/config/aiModels/novita.ts +124 -0
  191. package/src/config/aiModels/ollama.ts +412 -0
  192. package/src/config/aiModels/openai.ts +537 -0
  193. package/src/config/aiModels/openrouter.ts +252 -0
  194. package/src/config/aiModels/perplexity.ts +67 -0
  195. package/src/config/aiModels/qwen.ts +302 -0
  196. package/src/config/aiModels/sensenova.ts +114 -0
  197. package/src/config/aiModels/siliconcloud.ts +679 -0
  198. package/src/config/aiModels/spark.ts +68 -0
  199. package/src/config/aiModels/stepfun.ts +153 -0
  200. package/src/config/aiModels/taichu.ts +19 -0
  201. package/src/config/aiModels/togetherai.ts +334 -0
  202. package/src/config/aiModels/upstage.ts +37 -0
  203. package/src/config/aiModels/wenxin.ts +171 -0
  204. package/src/config/aiModels/xai.ts +72 -0
  205. package/src/config/aiModels/zeroone.ts +156 -0
  206. package/src/config/aiModels/zhipu.ts +235 -0
  207. package/src/config/featureFlags/schema.ts +3 -0
  208. package/src/config/modelProviders/anthropic.ts +1 -0
  209. package/src/config/modelProviders/github.ts +0 -1
  210. package/src/config/modelProviders/google.ts +1 -0
  211. package/src/config/modelProviders/stepfun.ts +2 -0
  212. package/src/database/migrations/0013_add_ai_infra.sql +44 -0
  213. package/src/database/migrations/meta/0013_snapshot.json +3598 -0
  214. package/src/database/migrations/meta/_journal.json +7 -0
  215. package/src/database/repositories/aiInfra/index.ts +115 -0
  216. package/src/database/schemas/aiInfra.ts +69 -0
  217. package/src/database/schemas/index.ts +1 -0
  218. package/src/database/server/models/__tests__/aiModel.test.ts +318 -0
  219. package/src/database/server/models/__tests__/aiProvider.test.ts +373 -0
  220. package/src/database/server/models/aiModel.ts +250 -0
  221. package/src/database/server/models/aiProvider.ts +234 -0
  222. package/src/features/AgentSetting/AgentPrompt/index.tsx +2 -2
  223. package/src/features/ChatInput/ActionBar/Token/TokenTag.tsx +2 -1
  224. package/src/features/ChatInput/ActionBar/Tools/index.tsx +2 -3
  225. package/src/features/ChatInput/ActionBar/Upload/ServerMode.tsx +2 -3
  226. package/src/features/ChatInput/Desktop/FilePreview/FileItem/index.tsx +3 -2
  227. package/src/features/ChatInput/Desktop/FilePreview/FileList.tsx +2 -2
  228. package/src/features/ChatInput/Mobile/Files/FileItem/File.tsx +2 -2
  229. package/src/features/ChatInput/Mobile/InputArea/index.tsx +1 -1
  230. package/src/features/ChatInput/STT/common.tsx +1 -1
  231. package/src/features/Conversation/Error/style.tsx +2 -2
  232. package/src/features/Conversation/Messages/Assistant/FileChunks/Item/style.ts +2 -2
  233. package/src/features/Conversation/Messages/Assistant/FileChunks/index.tsx +1 -1
  234. package/src/features/Conversation/Messages/Assistant/ToolCallItem/Inspector/style.ts +2 -3
  235. package/src/features/Conversation/Messages/Assistant/ToolCallItem/style.ts +2 -3
  236. package/src/features/Conversation/Messages/User/FileListViewer/Item.tsx +0 -1
  237. package/src/features/Conversation/components/BackBottom/style.ts +2 -2
  238. package/src/features/Conversation/components/MarkdownElements/LobeArtifact/Render/Icon.tsx +2 -3
  239. package/src/features/Conversation/components/MarkdownElements/LobeArtifact/Render/index.tsx +3 -3
  240. package/src/features/Conversation/components/MarkdownElements/LobeThinking/Render.tsx +1 -1
  241. package/src/features/Conversation/components/OTPInput.tsx +2 -2
  242. package/src/features/DataImporter/Loading.tsx +1 -1
  243. package/src/features/FileManager/FileList/EmptyStatus.tsx +1 -1
  244. package/src/features/FileManager/FileList/index.tsx +1 -1
  245. package/src/features/FileManager/UploadDock/Item.tsx +1 -1
  246. package/src/features/FileManager/UploadDock/index.tsx +4 -4
  247. package/src/features/FileViewer/NotSupport/index.tsx +1 -1
  248. package/src/features/FileViewer/Renderer/MSDoc/index.tsx +0 -1
  249. package/src/features/FileViewer/Renderer/TXT/index.tsx +1 -1
  250. package/src/features/InitClientDB/EnableModal.tsx +1 -1
  251. package/src/features/InitClientDB/ErrorResult.tsx +1 -1
  252. package/src/features/InitClientDB/InitIndicator.tsx +1 -1
  253. package/src/features/KnowledgeBaseModal/AddFilesToKnowledgeBase/SelectForm.tsx +0 -1
  254. package/src/features/ModelSwitchPanel/index.tsx +2 -2
  255. package/src/features/PluginsUI/Render/Loading.tsx +0 -1
  256. package/src/features/Portal/Home/Body/Files/FileList/Item.tsx +1 -1
  257. package/src/features/Portal/Home/Body/Plugins/ArtifactList/Item/style.ts +1 -2
  258. package/src/features/Setting/SettingContainer.tsx +8 -1
  259. package/src/features/ShareModal/ShareImage/style.ts +2 -2
  260. package/src/features/ShareModal/style.ts +2 -2
  261. package/src/features/User/DataStatistics.tsx +1 -1
  262. package/src/hooks/useEnabledChatModels.ts +10 -1
  263. package/src/hooks/useModelSupportToolUse.ts +15 -0
  264. package/src/hooks/useModelSupportVision.ts +15 -0
  265. package/src/layout/AuthProvider/Clerk/useAppearance.ts +3 -3
  266. package/src/layout/GlobalProvider/AppTheme.tsx +1 -1
  267. package/src/layout/GlobalProvider/StoreInitialization.tsx +5 -0
  268. package/src/locales/default/common.ts +1 -0
  269. package/src/locales/default/modelProvider.ts +178 -0
  270. package/src/locales/default/setting.ts +1 -0
  271. package/src/server/modules/KeyVaultsEncrypt/index.ts +1 -1
  272. package/src/server/routers/lambda/aiModel.ts +128 -0
  273. package/src/server/routers/lambda/aiProvider.ts +127 -0
  274. package/src/server/routers/lambda/index.ts +4 -0
  275. package/src/services/__tests__/_auth.test.ts +16 -49
  276. package/src/services/__tests__/chat.test.ts +2 -0
  277. package/src/services/_auth.ts +42 -25
  278. package/src/services/aiModel.ts +52 -0
  279. package/src/services/aiProvider.ts +47 -0
  280. package/src/services/chat.ts +62 -18
  281. package/src/store/aiInfra/index.ts +2 -0
  282. package/src/store/aiInfra/initialState.ts +11 -0
  283. package/src/store/aiInfra/selectors.ts +2 -0
  284. package/src/store/aiInfra/slices/aiModel/action.ts +146 -0
  285. package/src/store/aiInfra/slices/aiModel/index.ts +3 -0
  286. package/src/store/aiInfra/slices/aiModel/initialState.ts +14 -0
  287. package/src/store/aiInfra/slices/aiModel/selectors.ts +63 -0
  288. package/src/store/aiInfra/slices/aiProvider/action.ts +208 -0
  289. package/src/store/aiInfra/slices/aiProvider/index.ts +3 -0
  290. package/src/store/aiInfra/slices/aiProvider/initialState.ts +32 -0
  291. package/src/store/aiInfra/slices/aiProvider/selectors.ts +99 -0
  292. package/src/store/aiInfra/store.ts +25 -0
  293. package/src/store/global/initialState.ts +1 -0
  294. package/src/store/serverConfig/selectors.test.ts +1 -0
  295. package/src/styles/global.ts +1 -1
  296. package/src/types/aiModel.ts +32 -6
  297. package/src/types/aiProvider.ts +11 -4
  298. package/src/utils/fetch/fetchSSE.ts +3 -1
@@ -0,0 +1,146 @@
1
+ import isEqual from 'fast-deep-equal';
2
+ import { SWRResponse, mutate } from 'swr';
3
+ import { StateCreator } from 'zustand/vanilla';
4
+
5
+ import { useClientDataSWR } from '@/libs/swr';
6
+ import { aiModelService } from '@/services/aiModel';
7
+ import { AiInfraStore } from '@/store/aiInfra/store';
8
+ import {
9
+ AiModelSortMap,
10
+ AiProviderModelListItem,
11
+ CreateAiModelParams,
12
+ ToggleAiModelEnableParams,
13
+ } from '@/types/aiModel';
14
+
15
+ const FETCH_AI_PROVIDER_MODEL_LIST_KEY = 'FETCH_AI_PROVIDER_MODELS';
16
+
17
+ export interface AiModelAction {
18
+ batchToggleAiModels: (ids: string[], enabled: boolean) => Promise<void>;
19
+ batchUpdateAiModels: (models: AiProviderModelListItem[]) => Promise<void>;
20
+ clearRemoteModels: (provider: string) => Promise<void>;
21
+ createNewAiModel: (params: CreateAiModelParams) => Promise<void>;
22
+ fetchRemoteModelList: (providerId: string) => Promise<void>;
23
+ internal_toggleAiModelLoading: (id: string, loading: boolean) => void;
24
+
25
+ refreshAiModelList: () => Promise<void>;
26
+ removeAiModel: (id: string, providerId: string) => Promise<void>;
27
+ toggleModelEnabled: (params: Omit<ToggleAiModelEnableParams, 'providerId'>) => Promise<void>;
28
+ updateAiModelsConfig: (
29
+ id: string,
30
+ providerId: string,
31
+ data: Partial<AiProviderModelListItem>,
32
+ ) => Promise<void>;
33
+ updateAiModelsSort: (providerId: string, items: AiModelSortMap[]) => Promise<void>;
34
+
35
+ useFetchAiProviderModels: (id: string) => SWRResponse<AiProviderModelListItem[]>;
36
+ }
37
+
38
+ export const createAiModelSlice: StateCreator<
39
+ AiInfraStore,
40
+ [['zustand/devtools', never]],
41
+ [],
42
+ AiModelAction
43
+ > = (set, get) => ({
44
+ batchToggleAiModels: async (ids, enabled) => {
45
+ const { activeAiProvider } = get();
46
+ if (!activeAiProvider) return;
47
+
48
+ await aiModelService.batchToggleAiModels(activeAiProvider, ids, enabled);
49
+ await get().refreshAiModelList();
50
+ },
51
+ batchUpdateAiModels: async (models) => {
52
+ const { activeAiProvider: id } = get();
53
+ if (!id) return;
54
+
55
+ await aiModelService.batchUpdateAiModels(id, models);
56
+ await get().refreshAiModelList();
57
+ },
58
+ clearRemoteModels: async (provider) => {
59
+ await aiModelService.clearRemoteModels(provider);
60
+ await get().refreshAiModelList();
61
+ },
62
+ createNewAiModel: async (data) => {
63
+ await aiModelService.createAiModel(data);
64
+ await get().refreshAiModelList();
65
+ },
66
+ fetchRemoteModelList: async (providerId) => {
67
+ const { modelsService } = await import('@/services/models');
68
+
69
+ const data = await modelsService.getChatModels(providerId);
70
+ if (data) {
71
+ await get().batchUpdateAiModels(
72
+ data.map((model) => ({
73
+ ...model,
74
+ abilities: {
75
+ files: model.files,
76
+ functionCall: model.functionCall,
77
+ vision: model.vision,
78
+ },
79
+ enabled: model.enabled || false,
80
+ source: 'remote',
81
+ type: 'chat',
82
+ })),
83
+ );
84
+
85
+ await get().refreshAiModelList();
86
+ }
87
+ },
88
+ internal_toggleAiModelLoading: (id, loading) => {
89
+ set(
90
+ (state) => {
91
+ if (loading) return { aiModelLoadingIds: [...state.aiModelLoadingIds, id] };
92
+
93
+ return { aiModelLoadingIds: state.aiModelLoadingIds.filter((i) => i !== id) };
94
+ },
95
+ false,
96
+ 'toggleAiModelLoading',
97
+ );
98
+ },
99
+ refreshAiModelList: async () => {
100
+ await mutate([FETCH_AI_PROVIDER_MODEL_LIST_KEY, get().activeAiProvider]);
101
+ // make refresh provide runtime state async, not block
102
+ get().refreshAiProviderRuntimeState();
103
+ },
104
+ removeAiModel: async (id, providerId) => {
105
+ await aiModelService.deleteAiModel({ id, providerId });
106
+ await get().refreshAiModelList();
107
+ },
108
+ toggleModelEnabled: async (params) => {
109
+ const { activeAiProvider } = get();
110
+ if (!activeAiProvider) return;
111
+
112
+ get().internal_toggleAiModelLoading(params.id, true);
113
+
114
+ await aiModelService.toggleModelEnabled({ ...params, providerId: activeAiProvider });
115
+ await get().refreshAiModelList();
116
+
117
+ get().internal_toggleAiModelLoading(params.id, false);
118
+ },
119
+
120
+ updateAiModelsConfig: async (id, providerId, data) => {
121
+ await aiModelService.updateAiModel(id, providerId, data);
122
+ await get().refreshAiModelList();
123
+ },
124
+ updateAiModelsSort: async (id, items) => {
125
+ await aiModelService.updateAiModelOrder(id, items);
126
+ await get().refreshAiModelList();
127
+ },
128
+
129
+ useFetchAiProviderModels: (id) =>
130
+ useClientDataSWR<AiProviderModelListItem[]>(
131
+ [FETCH_AI_PROVIDER_MODEL_LIST_KEY, id],
132
+ ([, id]) => aiModelService.getAiProviderModelList(id as string),
133
+ {
134
+ onSuccess: (data) => {
135
+ // no need to update list if the list have been init and data is the same
136
+ if (get().isAiModelListInit && isEqual(data, get().aiProviderModelList)) return;
137
+
138
+ set(
139
+ { aiProviderModelList: data, isAiModelListInit: true },
140
+ false,
141
+ `useFetchAiProviderModels/${id}`,
142
+ );
143
+ },
144
+ },
145
+ ),
146
+ });
@@ -0,0 +1,3 @@
1
+ export * from './action';
2
+ export * from './initialState';
3
+ export * from './selectors';
@@ -0,0 +1,14 @@
1
+ import { AiProviderModelListItem } from '@/types/aiModel';
2
+
3
+ export interface AIModelsState {
4
+ aiModelLoadingIds: string[];
5
+ aiProviderModelList: AiProviderModelListItem[];
6
+ isAiModelListInit?: boolean;
7
+ modelSearchKeyword: string;
8
+ }
9
+
10
+ export const initialAIModelState: AIModelsState = {
11
+ aiModelLoadingIds: [],
12
+ aiProviderModelList: [],
13
+ modelSearchKeyword: '',
14
+ };
@@ -0,0 +1,63 @@
1
+ import { AIProviderStoreState } from '@/store/aiInfra/initialState';
2
+ import { AiModelSourceEnum } from '@/types/aiModel';
3
+
4
+ // List
5
+ const enabledAiProviderModelList = (s: AIProviderStoreState) =>
6
+ s.aiProviderModelList.filter((item) => item.enabled);
7
+
8
+ const disabledAiProviderModelList = (s: AIProviderStoreState) =>
9
+ s.aiProviderModelList.filter((item) => !item.enabled);
10
+
11
+ const filteredAiProviderModelList = (s: AIProviderStoreState) => {
12
+ const keyword = s.modelSearchKeyword.toLowerCase().trim();
13
+
14
+ return s.aiProviderModelList.filter(
15
+ (model) =>
16
+ model.id.toLowerCase().includes(keyword) ||
17
+ model.displayName?.toLowerCase().includes(keyword),
18
+ );
19
+ };
20
+
21
+ const totalAiProviderModelList = (s: AIProviderStoreState) => s.aiProviderModelList.length;
22
+ const isEmptyAiProviderModelList = (s: AIProviderStoreState) => totalAiProviderModelList(s) === 0;
23
+
24
+ const hasRemoteModels = (s: AIProviderStoreState) =>
25
+ s.aiProviderModelList.some((m) => m.source === AiModelSourceEnum.Remote);
26
+
27
+ const isModelEnabled = (id: string) => (s: AIProviderStoreState) =>
28
+ enabledAiProviderModelList(s).some((i) => i.id === id);
29
+
30
+ const isModelLoading = (id: string) => (s: AIProviderStoreState) =>
31
+ s.aiModelLoadingIds.includes(id);
32
+
33
+ const getAiModelById = (id: string) => (s: AIProviderStoreState) =>
34
+ s.aiProviderModelList.find((i) => i.id === id);
35
+
36
+ const getEnabledModelById = (id: string) => (s: AIProviderStoreState) =>
37
+ s.enabledAiModels?.find((i) => i.id === id);
38
+
39
+ const isModelSupportToolUse = (id: string) => (s: AIProviderStoreState) => {
40
+ const model = getEnabledModelById(id)(s);
41
+
42
+ return model?.abilities?.functionCall;
43
+ };
44
+
45
+ const isModelSupportVision = (id: string) => (s: AIProviderStoreState) => {
46
+ const model = getEnabledModelById(id)(s);
47
+
48
+ return model?.abilities?.vision;
49
+ };
50
+
51
+ export const aiModelSelectors = {
52
+ disabledAiProviderModelList,
53
+ enabledAiProviderModelList,
54
+ filteredAiProviderModelList,
55
+ getAiModelById,
56
+ hasRemoteModels,
57
+ isEmptyAiProviderModelList,
58
+ isModelEnabled,
59
+ isModelLoading,
60
+ isModelSupportToolUse,
61
+ isModelSupportVision,
62
+ totalAiProviderModelList,
63
+ };
@@ -0,0 +1,208 @@
1
+ import { uniqBy } from 'lodash-es';
2
+ import { SWRResponse, mutate } from 'swr';
3
+ import { StateCreator } from 'zustand/vanilla';
4
+
5
+ import { DEFAULT_MODEL_PROVIDER_LIST } from '@/config/modelProviders';
6
+ import { isServerMode } from '@/const/version';
7
+ import { useClientDataSWR } from '@/libs/swr';
8
+ import { aiProviderService } from '@/services/aiProvider';
9
+ import { AiInfraStore } from '@/store/aiInfra/store';
10
+ import { ModelAbilities } from '@/types/aiModel';
11
+ import {
12
+ AiProviderDetailItem,
13
+ AiProviderListItem,
14
+ AiProviderRuntimeState,
15
+ AiProviderSortMap,
16
+ AiProviderSourceEnum,
17
+ CreateAiProviderParams,
18
+ UpdateAiProviderConfigParams,
19
+ UpdateAiProviderParams,
20
+ } from '@/types/aiProvider';
21
+
22
+ enum AiProviderSwrKey {
23
+ fetchAiProviderItem = 'FETCH_AI_PROVIDER_ITEM',
24
+ fetchAiProviderList = 'FETCH_AI_PROVIDER',
25
+ fetchAiProviderRuntimeState = 'FETCH_AI_PROVIDER_RUNTIME_STATE',
26
+ }
27
+
28
+ export interface AiProviderAction {
29
+ createNewAiProvider: (params: CreateAiProviderParams) => Promise<void>;
30
+ deleteAiProvider: (id: string) => Promise<void>;
31
+ internal_toggleAiProviderLoading: (id: string, loading: boolean) => void;
32
+ refreshAiProviderDetail: () => Promise<void>;
33
+ refreshAiProviderList: () => Promise<void>;
34
+ refreshAiProviderRuntimeState: () => Promise<void>;
35
+ removeAiProvider: (id: string) => Promise<void>;
36
+ toggleProviderEnabled: (id: string, enabled: boolean) => Promise<void>;
37
+ updateAiProvider: (id: string, value: UpdateAiProviderParams) => Promise<void>;
38
+ updateAiProviderConfig: (id: string, value: UpdateAiProviderConfigParams) => Promise<void>;
39
+ updateAiProviderSort: (items: AiProviderSortMap[]) => Promise<void>;
40
+
41
+ useFetchAiProviderItem: (id: string) => SWRResponse<AiProviderDetailItem | undefined>;
42
+ useFetchAiProviderList: (params?: { suspense?: boolean }) => SWRResponse<AiProviderListItem[]>;
43
+ /**
44
+ * fetch provider keyVaults and user enabled model list
45
+ * @param isLoginOnInit
46
+ */
47
+ useFetchAiProviderRuntimeState: (
48
+ isLoginOnInit: boolean | undefined,
49
+ ) => SWRResponse<AiProviderRuntimeState | undefined>;
50
+ }
51
+
52
+ export const createAiProviderSlice: StateCreator<
53
+ AiInfraStore,
54
+ [['zustand/devtools', never]],
55
+ [],
56
+ AiProviderAction
57
+ > = (set, get) => ({
58
+ createNewAiProvider: async (params) => {
59
+ await aiProviderService.createAiProvider({ ...params, source: AiProviderSourceEnum.Custom });
60
+ await get().refreshAiProviderList();
61
+ },
62
+ deleteAiProvider: async (id: string) => {
63
+ await aiProviderService.deleteAiProvider(id);
64
+
65
+ await get().refreshAiProviderList();
66
+ },
67
+ internal_toggleAiProviderLoading: (id, loading) => {
68
+ set(
69
+ (state) => {
70
+ if (loading) return { aiProviderLoadingIds: [...state.aiProviderLoadingIds, id] };
71
+
72
+ return { aiProviderLoadingIds: state.aiProviderLoadingIds.filter((i) => i !== id) };
73
+ },
74
+ false,
75
+ 'toggleAiProviderLoading',
76
+ );
77
+ },
78
+ refreshAiProviderDetail: async () => {
79
+ await mutate([AiProviderSwrKey.fetchAiProviderItem, get().activeAiProvider]);
80
+ await get().refreshAiProviderRuntimeState();
81
+ },
82
+ refreshAiProviderList: async () => {
83
+ await mutate(AiProviderSwrKey.fetchAiProviderList);
84
+ await get().refreshAiProviderRuntimeState();
85
+ },
86
+ refreshAiProviderRuntimeState: async () => {
87
+ await mutate(AiProviderSwrKey.fetchAiProviderRuntimeState);
88
+ },
89
+ removeAiProvider: async (id) => {
90
+ await aiProviderService.deleteAiProvider(id);
91
+ await get().refreshAiProviderList();
92
+ },
93
+
94
+ toggleProviderEnabled: async (id: string, enabled: boolean) => {
95
+ get().internal_toggleAiProviderLoading(id, true);
96
+ await aiProviderService.toggleProviderEnabled(id, enabled);
97
+ await get().refreshAiProviderList();
98
+
99
+ get().internal_toggleAiProviderLoading(id, false);
100
+ },
101
+
102
+ updateAiProvider: async (id, value) => {
103
+ get().internal_toggleAiProviderLoading(id, true);
104
+ await aiProviderService.updateAiProvider(id, value);
105
+ await get().refreshAiProviderList();
106
+ await get().refreshAiProviderDetail();
107
+
108
+ get().internal_toggleAiProviderLoading(id, false);
109
+ },
110
+
111
+ updateAiProviderConfig: async (id, value) => {
112
+ get().internal_toggleAiProviderLoading(id, true);
113
+ await aiProviderService.updateAiProviderConfig(id, value);
114
+ await get().refreshAiProviderDetail();
115
+
116
+ get().internal_toggleAiProviderLoading(id, false);
117
+ },
118
+
119
+ updateAiProviderSort: async (items) => {
120
+ await aiProviderService.updateAiProviderOrder(items);
121
+ await get().refreshAiProviderList();
122
+ },
123
+ useFetchAiProviderItem: (id) =>
124
+ useClientDataSWR<AiProviderDetailItem | undefined>(
125
+ [AiProviderSwrKey.fetchAiProviderItem, id],
126
+ () => aiProviderService.getAiProviderById(id),
127
+ {
128
+ onSuccess: (data) => {
129
+ if (!data) return;
130
+
131
+ set({ activeAiProvider: id, aiProviderDetail: data }, false, 'useFetchAiProviderItem');
132
+ },
133
+ },
134
+ ),
135
+ useFetchAiProviderList: () =>
136
+ useClientDataSWR<AiProviderListItem[]>(
137
+ AiProviderSwrKey.fetchAiProviderList,
138
+ () => aiProviderService.getAiProviderList(),
139
+ {
140
+ fallbackData: [],
141
+ onSuccess: (data) => {
142
+ if (!get().initAiProviderList) {
143
+ set(
144
+ { aiProviderList: data, initAiProviderList: true },
145
+ false,
146
+ 'useFetchAiProviderList/init',
147
+ );
148
+ return;
149
+ }
150
+
151
+ set({ aiProviderList: data }, false, 'useFetchAiProviderList/refresh');
152
+ },
153
+ },
154
+ ),
155
+
156
+ useFetchAiProviderRuntimeState: (isLogin) =>
157
+ useClientDataSWR<AiProviderRuntimeState | undefined>(
158
+ isServerMode ? [AiProviderSwrKey.fetchAiProviderRuntimeState, isLogin] : null,
159
+ async ([, isLogin]) => {
160
+ if (isLogin) return aiProviderService.getAiProviderRuntimeState();
161
+
162
+ const { LOBE_DEFAULT_MODEL_LIST } = await import('@/config/aiModels');
163
+ return {
164
+ enabledAiModels: LOBE_DEFAULT_MODEL_LIST.filter((m) => m.enabled),
165
+ enabledAiProviders: DEFAULT_MODEL_PROVIDER_LIST.filter(
166
+ (provider) => provider.enabled,
167
+ ).map((item) => ({ id: item.id, name: item.name, source: 'builtin' })),
168
+ runtimeConfig: {},
169
+ };
170
+ },
171
+ {
172
+ onSuccess: (data) => {
173
+ if (!data) return;
174
+
175
+ const getModelListByType = (providerId: string, type: string) => {
176
+ const models = data.enabledAiModels
177
+ .filter((model) => model.providerId === providerId && model.type === type)
178
+ .map((model) => ({
179
+ abilities: (model.abilities || {}) as ModelAbilities,
180
+ contextWindowTokens: model.contextWindowTokens,
181
+ displayName: model.displayName ?? '',
182
+ id: model.id,
183
+ }));
184
+
185
+ return uniqBy(models, 'id');
186
+ };
187
+
188
+ // 3. 组装最终数据结构
189
+ const enabledChatModelList = data.enabledAiProviders.map((provider) => ({
190
+ children: getModelListByType(provider.id, 'chat'),
191
+ id: provider.id,
192
+ name: provider.name || provider.id,
193
+ }));
194
+
195
+ set(
196
+ {
197
+ aiProviderRuntimeConfig: data.runtimeConfig,
198
+ enabledAiModels: data.enabledAiModels,
199
+ enabledAiProviders: data.enabledAiProviders,
200
+ enabledChatModelList,
201
+ },
202
+ false,
203
+ 'useInitAiProviderKeyVaults',
204
+ );
205
+ },
206
+ },
207
+ ),
208
+ });
@@ -0,0 +1,3 @@
1
+ export * from './action';
2
+ export * from './initialState';
3
+ export * from './selectors';
@@ -0,0 +1,32 @@
1
+ import { EnabledProviderWithModels } from '@/types/aiModel';
2
+ import {
3
+ AiProviderDetailItem,
4
+ AiProviderListItem,
5
+ AiProviderRuntimeConfig,
6
+ EnabledAiModel,
7
+ EnabledProvider,
8
+ } from '@/types/aiProvider';
9
+
10
+ export interface AIProviderState {
11
+ activeAiProvider?: string;
12
+ activeProviderModelList: any[];
13
+ aiProviderDetail?: AiProviderDetailItem | null;
14
+ aiProviderList: AiProviderListItem[];
15
+ aiProviderLoadingIds: string[];
16
+ aiProviderRuntimeConfig: Record<string, AiProviderRuntimeConfig>;
17
+ enabledAiModels?: EnabledAiModel[];
18
+ enabledAiProviders?: EnabledProvider[];
19
+ // used for select
20
+ enabledChatModelList?: EnabledProviderWithModels[];
21
+ initAiProviderList: boolean;
22
+ providerSearchKeyword: string;
23
+ }
24
+
25
+ export const initialAIProviderState: AIProviderState = {
26
+ activeProviderModelList: [],
27
+ aiProviderList: [],
28
+ aiProviderLoadingIds: [],
29
+ aiProviderRuntimeConfig: {},
30
+ initAiProviderList: false,
31
+ providerSearchKeyword: '',
32
+ };
@@ -0,0 +1,99 @@
1
+ import { isProviderDisableBroswerRequest } from '@/config/modelProviders';
2
+ import { AIProviderStoreState } from '@/store/aiInfra/initialState';
3
+ import { AiProviderRuntimeConfig } from '@/types/aiProvider';
4
+ import { GlobalLLMProviderKey } from '@/types/user/settings';
5
+
6
+ // List
7
+ const enabledAiProviderList = (s: AIProviderStoreState) =>
8
+ s.aiProviderList.filter((item) => item.enabled).sort((a, b) => a.sort! - b.sort!);
9
+
10
+ const disabledAiProviderList = (s: AIProviderStoreState) =>
11
+ s.aiProviderList.filter((item) => !item.enabled);
12
+
13
+ const isProviderEnabled = (id: string) => (s: AIProviderStoreState) =>
14
+ enabledAiProviderList(s).some((i) => i.id === id);
15
+
16
+ const isProviderLoading = (id: string) => (s: AIProviderStoreState) =>
17
+ s.aiProviderLoadingIds.includes(id);
18
+
19
+ const activeProviderConfig = (s: AIProviderStoreState) => s.aiProviderDetail;
20
+
21
+ // Detail
22
+
23
+ const isAiProviderConfigLoading = (id: string) => (s: AIProviderStoreState) =>
24
+ s.activeAiProvider !== id;
25
+
26
+ const providerWhitelist = new Set(['ollama']);
27
+
28
+ const activeProviderKeyVaults = (s: AIProviderStoreState) => activeProviderConfig(s)?.keyVaults;
29
+
30
+ const isActiveProviderEndpointNotEmpty = (s: AIProviderStoreState) => {
31
+ const vault = activeProviderKeyVaults(s);
32
+ return !!vault?.baseURL || !!vault?.endpoint;
33
+ };
34
+
35
+ const isActiveProviderApiKeyNotEmpty = (s: AIProviderStoreState) => {
36
+ const vault = activeProviderKeyVaults(s);
37
+ return !!vault?.apiKey || !!vault?.accessKeyId || !!vault?.secretAccessKey;
38
+ };
39
+
40
+ /**
41
+ * @description The conditions to enable client fetch
42
+ * 1. If no baseUrl and apikey input, force on Server.
43
+ * 2. If only contains baseUrl, force on Client
44
+ * 3. Follow the user settings.
45
+ * 4. On Server, by default.
46
+ */
47
+ const isProviderFetchOnClient =
48
+ (provider: GlobalLLMProviderKey | string) => (s: AIProviderStoreState) => {
49
+ const config = activeProviderConfig(s);
50
+
51
+ // If the provider already disable broswer request in model config, force on Server.
52
+ if (isProviderDisableBroswerRequest(provider)) return false;
53
+
54
+ // If the provider in the whitelist, follow the user settings
55
+ if (providerWhitelist.has(provider) && typeof config?.fetchOnClient !== 'undefined')
56
+ return config?.fetchOnClient;
57
+
58
+ // 1. If no baseUrl and apikey input, force on Server.
59
+ const isProviderEndpointNotEmpty = isActiveProviderEndpointNotEmpty(s);
60
+ const isProviderApiKeyNotEmpty = isActiveProviderApiKeyNotEmpty(s);
61
+ if (!isProviderEndpointNotEmpty && !isProviderApiKeyNotEmpty) return false;
62
+
63
+ // 2. If only contains baseUrl, force on Client
64
+ if (isProviderEndpointNotEmpty && !isProviderApiKeyNotEmpty) return true;
65
+
66
+ // 3. Follow the user settings.
67
+ if (typeof config?.fetchOnClient !== 'undefined') return config?.fetchOnClient;
68
+
69
+ // 4. On Server, by default.
70
+ return false;
71
+ };
72
+
73
+ const providerKeyVaults = (provider: string | undefined) => (s: AIProviderStoreState) => {
74
+ if (!provider) return undefined;
75
+
76
+ return s.aiProviderRuntimeConfig?.[provider]?.keyVaults;
77
+ };
78
+
79
+ const providerConfigById =
80
+ (id: string) =>
81
+ (s: AIProviderStoreState): AiProviderRuntimeConfig | undefined => {
82
+ if (!id) return undefined;
83
+
84
+ return s.aiProviderRuntimeConfig?.[id];
85
+ };
86
+
87
+ export const aiProviderSelectors = {
88
+ activeProviderConfig,
89
+ disabledAiProviderList,
90
+ enabledAiProviderList,
91
+ isActiveProviderApiKeyNotEmpty,
92
+ isActiveProviderEndpointNotEmpty,
93
+ isAiProviderConfigLoading,
94
+ isProviderEnabled,
95
+ isProviderFetchOnClient,
96
+ isProviderLoading,
97
+ providerConfigById,
98
+ providerKeyVaults,
99
+ };
@@ -0,0 +1,25 @@
1
+ import { shallow } from 'zustand/shallow';
2
+ import { createWithEqualityFn } from 'zustand/traditional';
3
+ import { StateCreator } from 'zustand/vanilla';
4
+
5
+ import { createDevtools } from '../middleware/createDevtools';
6
+ import { AIProviderStoreState, initialState } from './initialState';
7
+ import { AiModelAction, createAiModelSlice } from './slices/aiModel';
8
+ import { AiProviderAction, createAiProviderSlice } from './slices/aiProvider';
9
+
10
+ // =============== 聚合 createStoreFn ============ //
11
+
12
+ export interface AiInfraStore extends AIProviderStoreState, AiProviderAction, AiModelAction {
13
+ /* empty */
14
+ }
15
+
16
+ const createStore: StateCreator<AiInfraStore, [['zustand/devtools', never]]> = (...parameters) => ({
17
+ ...initialState,
18
+ ...createAiModelSlice(...parameters),
19
+ ...createAiProviderSlice(...parameters),
20
+ });
21
+
22
+ // =============== 实装 useStore ============ //
23
+ const devtools = createDevtools('aiInfra');
24
+
25
+ export const useAiInfraStore = createWithEqualityFn<AiInfraStore>()(devtools(createStore), shallow);
@@ -26,6 +26,7 @@ export enum SettingsTabs {
26
26
  Agent = 'agent',
27
27
  Common = 'common',
28
28
  LLM = 'llm',
29
+ Provider = 'provider',
29
30
  Sync = 'sync',
30
31
  SystemAgent = 'system-agent',
31
32
  TTS = 'tts',
@@ -34,6 +34,7 @@ describe('featureFlagsSelectors', () => {
34
34
  enableCheckUpdates: true,
35
35
  showWelcomeSuggest: true,
36
36
  enableClerkSignUp: true,
37
+ showProvider: true,
37
38
  showMarket: true,
38
39
  showPinList: false,
39
40
  enableSTT: true,
@@ -36,9 +36,9 @@ export default ({ token }: { prefixCls: string; token: Theme }) => css`
36
36
  }
37
37
 
38
38
  :hover::-webkit-scrollbar-thumb {
39
+ border: 3px solid transparent;
39
40
  background-color: ${token.colorText};
40
41
  background-clip: content-box;
41
- border: 3px solid transparent;
42
42
  }
43
43
 
44
44
  ::-webkit-scrollbar-track {