@lobehub/chat 0.146.1 → 0.147.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 (358) hide show
  1. package/.env.example +3 -5
  2. package/.github/workflows/issue-close-require.yml +1 -1
  3. package/.github/workflows/release.yml +1 -1
  4. package/.github/workflows/test.yml +3 -1
  5. package/.i18nrc.js +13 -8
  6. package/.seorc.cjs +9 -0
  7. package/CHANGELOG.md +98 -0
  8. package/README.md +25 -25
  9. package/README.zh-CN.md +25 -25
  10. package/contributing/Home.md +1 -1
  11. package/docs/self-hosting/advanced/analytics.mdx +12 -0
  12. package/docs/self-hosting/advanced/analytics.zh-CN.mdx +10 -0
  13. package/docs/self-hosting/advanced/authentication.mdx +19 -0
  14. package/docs/self-hosting/advanced/authentication.zh-CN.mdx +15 -0
  15. package/docs/self-hosting/advanced/sso-providers/auth0.mdx +19 -2
  16. package/docs/self-hosting/advanced/sso-providers/auth0.zh-CN.mdx +15 -2
  17. package/docs/self-hosting/advanced/sso-providers/authentik.mdx +18 -3
  18. package/docs/self-hosting/advanced/sso-providers/authentik.zh-CN.mdx +14 -2
  19. package/docs/self-hosting/advanced/sso-providers/github.mdx +13 -0
  20. package/docs/self-hosting/advanced/sso-providers/github.zh-CN.mdx +13 -3
  21. package/docs/self-hosting/advanced/sso-providers/microsoft-entra-id.mdx +18 -2
  22. package/docs/self-hosting/advanced/sso-providers/microsoft-entra-id.zh-CN.mdx +15 -2
  23. package/docs/self-hosting/advanced/sso-providers/zitadel.mdx +17 -2
  24. package/docs/self-hosting/advanced/sso-providers/zitadel.zh-CN.mdx +14 -2
  25. package/docs/self-hosting/advanced/upstream-sync.mdx +13 -0
  26. package/docs/self-hosting/advanced/upstream-sync.zh-CN.mdx +10 -0
  27. package/docs/self-hosting/environment-variables/analytics.mdx +15 -0
  28. package/docs/self-hosting/environment-variables/analytics.zh-CN.mdx +13 -0
  29. package/docs/self-hosting/environment-variables/auth.mdx +14 -0
  30. package/docs/self-hosting/environment-variables/auth.zh-CN.mdx +15 -1
  31. package/docs/self-hosting/environment-variables/basic.mdx +15 -0
  32. package/docs/self-hosting/environment-variables/basic.zh-CN.mdx +11 -0
  33. package/docs/self-hosting/environment-variables/model-provider.mdx +26 -0
  34. package/docs/self-hosting/environment-variables/model-provider.zh-CN.mdx +10 -0
  35. package/docs/self-hosting/environment-variables.mdx +13 -2
  36. package/docs/self-hosting/environment-variables.zh-CN.mdx +9 -0
  37. package/docs/self-hosting/examples/azure-openai.mdx +12 -0
  38. package/docs/self-hosting/examples/azure-openai.zh-CN.mdx +12 -0
  39. package/docs/self-hosting/examples/ollama.mdx +13 -0
  40. package/docs/self-hosting/examples/ollama.zh-CN.mdx +11 -0
  41. package/docs/self-hosting/faq/no-v1-suffix.mdx +12 -0
  42. package/docs/self-hosting/faq/no-v1-suffix.zh-CN.mdx +9 -0
  43. package/docs/self-hosting/faq/proxy-with-unable-to-verify-leaf-signature.mdx +14 -0
  44. package/docs/self-hosting/faq/proxy-with-unable-to-verify-leaf-signature.zh-CN.mdx +11 -0
  45. package/docs/self-hosting/platform/docker-compose.mdx +21 -5
  46. package/docs/self-hosting/platform/docker-compose.zh-CN.mdx +18 -5
  47. package/docs/self-hosting/platform/docker.mdx +26 -8
  48. package/docs/self-hosting/platform/docker.zh-CN.mdx +27 -9
  49. package/docs/self-hosting/platform/netlify.mdx +18 -2
  50. package/docs/self-hosting/platform/netlify.zh-CN.mdx +14 -1
  51. package/docs/self-hosting/platform/railway.mdx +12 -0
  52. package/docs/self-hosting/platform/railway.zh-CN.mdx +11 -0
  53. package/docs/self-hosting/platform/repocloud.mdx +12 -0
  54. package/docs/self-hosting/platform/repocloud.zh-CN.mdx +10 -0
  55. package/docs/self-hosting/platform/sealos.mdx +11 -0
  56. package/docs/self-hosting/platform/sealos.zh-CN.mdx +10 -0
  57. package/docs/self-hosting/platform/vercel.mdx +12 -0
  58. package/docs/self-hosting/platform/vercel.zh-CN.mdx +11 -0
  59. package/docs/self-hosting/platform/zeabur.mdx +11 -0
  60. package/docs/self-hosting/platform/zeabur.zh-CN.mdx +10 -0
  61. package/docs/self-hosting/start.mdx +12 -0
  62. package/docs/self-hosting/start.zh-CN.mdx +13 -0
  63. package/docs/usage/agents/concepts.mdx +13 -0
  64. package/docs/usage/agents/concepts.zh-CN.mdx +10 -0
  65. package/docs/usage/agents/custom-agent.mdx +16 -2
  66. package/docs/usage/agents/custom-agent.zh-CN.mdx +14 -2
  67. package/docs/usage/agents/model.mdx +11 -2
  68. package/docs/usage/agents/model.zh-CN.mdx +12 -0
  69. package/docs/usage/agents/prompt.mdx +15 -0
  70. package/docs/usage/agents/prompt.zh-CN.mdx +10 -0
  71. package/docs/usage/agents/topics.mdx +13 -0
  72. package/docs/usage/agents/topics.zh-CN.mdx +11 -0
  73. package/docs/usage/features/agent-market.mdx +11 -1
  74. package/docs/usage/features/agent-market.zh-CN.mdx +13 -0
  75. package/docs/usage/features/local-llm.mdx +12 -2
  76. package/docs/usage/features/local-llm.zh-CN.mdx +3 -3
  77. package/docs/usage/features/mobile.mdx +10 -1
  78. package/docs/usage/features/mobile.zh-CN.mdx +11 -0
  79. package/docs/usage/features/more.mdx +13 -0
  80. package/docs/usage/features/more.zh-CN.mdx +10 -0
  81. package/docs/usage/features/multi-ai-providers.mdx +14 -1
  82. package/docs/usage/features/multi-ai-providers.zh-CN.mdx +16 -0
  83. package/docs/usage/features/plugin-system.mdx +12 -1
  84. package/docs/usage/features/plugin-system.zh-CN.mdx +9 -0
  85. package/docs/usage/features/pwa.mdx +11 -1
  86. package/docs/usage/features/pwa.zh-CN.mdx +13 -0
  87. package/docs/usage/features/text-to-image.mdx +11 -1
  88. package/docs/usage/features/text-to-image.zh-CN.mdx +13 -0
  89. package/docs/usage/features/theme.mdx +12 -1
  90. package/docs/usage/features/theme.zh-CN.mdx +11 -0
  91. package/docs/usage/features/tts.mdx +14 -1
  92. package/docs/usage/features/tts.zh-CN.mdx +12 -0
  93. package/docs/usage/features/vision.mdx +11 -1
  94. package/docs/usage/features/vision.zh-CN.mdx +10 -0
  95. package/docs/usage/plugins/basic-usage.mdx +12 -0
  96. package/docs/usage/plugins/basic-usage.zh-CN.mdx +10 -0
  97. package/docs/usage/plugins/custom-plugin.mdx +12 -0
  98. package/docs/usage/plugins/custom-plugin.zh-CN.mdx +10 -0
  99. package/docs/usage/plugins/development.mdx +18 -0
  100. package/docs/usage/plugins/development.zh-CN.mdx +12 -0
  101. package/docs/usage/plugins/store.mdx +12 -0
  102. package/docs/usage/plugins/store.zh-CN.mdx +9 -0
  103. package/docs/usage/providers/groq.mdx +14 -2
  104. package/docs/usage/providers/groq.zh-CN.mdx +12 -2
  105. package/docs/usage/providers/ollama/gemma.mdx +13 -3
  106. package/docs/usage/providers/ollama/gemma.zh-CN.mdx +12 -3
  107. package/docs/usage/providers/ollama/qwen.mdx +12 -4
  108. package/docs/usage/providers/ollama/qwen.zh-CN.mdx +10 -3
  109. package/docs/usage/providers/ollama.mdx +19 -9
  110. package/docs/usage/providers/ollama.zh-CN.mdx +20 -9
  111. package/docs/usage/start.mdx +13 -2
  112. package/docs/usage/start.zh-CN.mdx +11 -2
  113. package/locales/ar/common.json +0 -26
  114. package/locales/ar/components.json +15 -0
  115. package/locales/ar/error.json +1 -52
  116. package/locales/ar/modelProvider.json +226 -0
  117. package/locales/ar/setting.json +48 -199
  118. package/locales/bg-BG/common.json +0 -26
  119. package/locales/bg-BG/components.json +15 -0
  120. package/locales/bg-BG/error.json +1 -52
  121. package/locales/bg-BG/modelProvider.json +226 -0
  122. package/locales/bg-BG/setting.json +48 -199
  123. package/locales/de-DE/common.json +0 -26
  124. package/locales/de-DE/components.json +15 -0
  125. package/locales/de-DE/error.json +1 -52
  126. package/locales/de-DE/modelProvider.json +226 -0
  127. package/locales/de-DE/setting.json +48 -199
  128. package/locales/en-US/common.json +0 -26
  129. package/locales/en-US/components.json +15 -0
  130. package/locales/en-US/error.json +1 -52
  131. package/locales/en-US/modelProvider.json +226 -0
  132. package/locales/en-US/setting.json +48 -199
  133. package/locales/es-ES/common.json +0 -26
  134. package/locales/es-ES/components.json +15 -0
  135. package/locales/es-ES/error.json +1 -52
  136. package/locales/es-ES/modelProvider.json +226 -0
  137. package/locales/es-ES/setting.json +48 -199
  138. package/locales/fr-FR/common.json +0 -26
  139. package/locales/fr-FR/components.json +15 -0
  140. package/locales/fr-FR/error.json +1 -52
  141. package/locales/fr-FR/modelProvider.json +226 -0
  142. package/locales/fr-FR/setting.json +48 -199
  143. package/locales/it-IT/common.json +0 -26
  144. package/locales/it-IT/components.json +15 -0
  145. package/locales/it-IT/error.json +1 -52
  146. package/locales/it-IT/modelProvider.json +226 -0
  147. package/locales/it-IT/setting.json +59 -210
  148. package/locales/ja-JP/common.json +0 -26
  149. package/locales/ja-JP/components.json +15 -0
  150. package/locales/ja-JP/error.json +1 -52
  151. package/locales/ja-JP/modelProvider.json +226 -0
  152. package/locales/ja-JP/setting.json +59 -210
  153. package/locales/ko-KR/common.json +0 -26
  154. package/locales/ko-KR/components.json +15 -0
  155. package/locales/ko-KR/error.json +1 -52
  156. package/locales/ko-KR/modelProvider.json +226 -0
  157. package/locales/ko-KR/setting.json +48 -199
  158. package/locales/nl-NL/common.json +0 -26
  159. package/locales/nl-NL/components.json +15 -0
  160. package/locales/nl-NL/error.json +4 -55
  161. package/locales/nl-NL/modelProvider.json +226 -0
  162. package/locales/nl-NL/setting.json +49 -200
  163. package/locales/pl-PL/common.json +0 -26
  164. package/locales/pl-PL/components.json +15 -0
  165. package/locales/pl-PL/error.json +1 -52
  166. package/locales/pl-PL/modelProvider.json +226 -0
  167. package/locales/pl-PL/setting.json +48 -199
  168. package/locales/pt-BR/common.json +0 -26
  169. package/locales/pt-BR/components.json +15 -0
  170. package/locales/pt-BR/error.json +1 -52
  171. package/locales/pt-BR/modelProvider.json +226 -0
  172. package/locales/pt-BR/setting.json +48 -199
  173. package/locales/ru-RU/common.json +0 -26
  174. package/locales/ru-RU/components.json +15 -0
  175. package/locales/ru-RU/error.json +1 -52
  176. package/locales/ru-RU/modelProvider.json +226 -0
  177. package/locales/ru-RU/setting.json +48 -199
  178. package/locales/tr-TR/common.json +0 -26
  179. package/locales/tr-TR/components.json +15 -0
  180. package/locales/tr-TR/error.json +1 -52
  181. package/locales/tr-TR/modelProvider.json +226 -0
  182. package/locales/tr-TR/setting.json +48 -199
  183. package/locales/vi-VN/common.json +0 -26
  184. package/locales/vi-VN/components.json +15 -0
  185. package/locales/vi-VN/error.json +1 -52
  186. package/locales/vi-VN/modelProvider.json +226 -0
  187. package/locales/vi-VN/setting.json +48 -199
  188. package/locales/zh-CN/common.json +0 -26
  189. package/locales/zh-CN/components.json +15 -0
  190. package/locales/zh-CN/error.json +2 -53
  191. package/locales/zh-CN/modelProvider.json +226 -0
  192. package/locales/zh-CN/setting.json +48 -199
  193. package/locales/zh-TW/common.json +0 -26
  194. package/locales/zh-TW/components.json +15 -0
  195. package/locales/zh-TW/error.json +1 -52
  196. package/locales/zh-TW/modelProvider.json +226 -0
  197. package/locales/zh-TW/setting.json +48 -199
  198. package/package.json +121 -117
  199. package/scripts/mdxWorkflow/index.ts +48 -0
  200. package/src/app/api/chat/[provider]/route.test.ts +4 -9
  201. package/src/app/api/chat/[provider]/route.ts +6 -23
  202. package/src/app/api/chat/{[provider]/agentRuntime.test.ts → agentRuntime.test.ts} +12 -12
  203. package/src/app/api/chat/{[provider]/agentRuntime.ts → agentRuntime.ts} +11 -30
  204. package/src/app/api/chat/auth/index.ts +42 -0
  205. package/src/app/api/chat/models/[provider]/route.ts +45 -0
  206. package/src/app/api/config/__snapshots__/route.test.ts.snap +127 -0
  207. package/src/app/api/config/route.test.ts +170 -0
  208. package/src/app/api/config/route.ts +46 -11
  209. package/src/app/api/plugin/gateway/route.ts +1 -1
  210. package/src/app/settings/llm/Azure/index.tsx +36 -43
  211. package/src/app/settings/llm/Bedrock/index.tsx +12 -20
  212. package/src/app/settings/llm/Ollama/index.tsx +2 -2
  213. package/src/app/settings/llm/OpenAI/index.tsx +9 -121
  214. package/src/app/settings/llm/OpenRouter/index.tsx +1 -1
  215. package/src/app/settings/llm/TogetherAI/index.tsx +0 -1
  216. package/src/app/settings/llm/components/ProviderConfig/index.tsx +48 -32
  217. package/src/app/settings/llm/components/ProviderModelList/CustomModelOption.tsx +94 -0
  218. package/src/app/settings/llm/components/ProviderModelList/MaxTokenSlider.tsx +88 -0
  219. package/src/app/settings/llm/components/ProviderModelList/ModelConfigModal.tsx +128 -0
  220. package/src/app/settings/llm/components/ProviderModelList/ModelFetcher.tsx +81 -0
  221. package/src/app/settings/llm/components/ProviderModelList/Option.tsx +38 -0
  222. package/src/app/settings/llm/components/ProviderModelList/index.tsx +142 -0
  223. package/src/app/settings/llm/const.ts +1 -1
  224. package/src/app/settings/llm/index.tsx +7 -6
  225. package/src/app/settings/tts/TTS/index.tsx +1 -1
  226. package/src/components/AntdStaticMethods/index.test.tsx +43 -0
  227. package/src/components/ModelIcon/index.tsx +25 -7
  228. package/src/components/ModelSelect/index.tsx +67 -56
  229. package/src/config/modelProviders/anthropic.ts +6 -1
  230. package/src/config/modelProviders/azure.ts +42 -0
  231. package/src/config/modelProviders/bedrock.ts +4 -1
  232. package/src/config/modelProviders/google.ts +2 -14
  233. package/src/config/modelProviders/groq.ts +3 -0
  234. package/src/config/modelProviders/index.ts +19 -14
  235. package/src/config/modelProviders/mistral.ts +5 -0
  236. package/src/config/modelProviders/moonshot.ts +3 -1
  237. package/src/config/modelProviders/ollama.ts +6 -17
  238. package/src/config/modelProviders/openai.ts +9 -13
  239. package/src/config/modelProviders/openrouter.ts +6 -1
  240. package/src/config/modelProviders/perplexity.ts +2 -0
  241. package/src/config/modelProviders/togetherai.ts +11 -0
  242. package/src/config/modelProviders/zeroone.ts +3 -0
  243. package/src/config/modelProviders/zhipu.ts +3 -0
  244. package/src/config/server/provider.ts +52 -7
  245. package/src/const/auth.ts +0 -1
  246. package/src/const/{settings.ts → settings/index.ts} +31 -4
  247. package/src/const/url.ts +1 -1
  248. package/src/database/core/db.ts +14 -0
  249. package/src/database/schemas/user.ts +1 -25
  250. package/src/features/AgentSetting/AgentConfig/ModelSelect.tsx +7 -11
  251. package/src/features/ChatInput/STT/common.tsx +80 -78
  252. package/src/features/ChatInput/STT/index.tsx +8 -6
  253. package/src/features/Conversation/Error/APIKeyForm/Bedrock.tsx +8 -8
  254. package/src/features/Conversation/Error/APIKeyForm/ProviderApiKeyForm.tsx +73 -0
  255. package/src/features/Conversation/Error/APIKeyForm/ProviderAvatar.tsx +74 -0
  256. package/src/features/Conversation/Error/APIKeyForm/index.tsx +25 -49
  257. package/src/features/ModelSwitchPanel/index.tsx +40 -13
  258. package/src/hooks/_header.ts +5 -20
  259. package/src/libs/agent-runtime/BaseAI.ts +17 -1
  260. package/src/libs/agent-runtime/anthropic/index.ts +3 -7
  261. package/src/libs/agent-runtime/azureOpenai/index.test.ts +166 -0
  262. package/src/libs/agent-runtime/azureOpenai/index.ts +16 -8
  263. package/src/libs/agent-runtime/bedrock/index.test.ts +199 -22
  264. package/src/libs/agent-runtime/bedrock/index.ts +11 -18
  265. package/src/libs/agent-runtime/groq/index.test.ts +350 -0
  266. package/src/libs/agent-runtime/groq/index.ts +14 -77
  267. package/src/libs/agent-runtime/mistral/index.test.ts +25 -19
  268. package/src/libs/agent-runtime/mistral/index.ts +24 -86
  269. package/src/libs/agent-runtime/moonshot/index.test.ts +2 -2
  270. package/src/libs/agent-runtime/moonshot/index.ts +14 -77
  271. package/src/libs/agent-runtime/openai/__snapshots__/index.test.ts.snap +99 -0
  272. package/src/libs/agent-runtime/openai/fixtures/openai-models.json +170 -0
  273. package/src/libs/agent-runtime/openai/index.test.ts +15 -50
  274. package/src/libs/agent-runtime/openai/index.ts +15 -107
  275. package/src/libs/agent-runtime/openrouter/__snapshots__/index.test.ts.snap +82 -0
  276. package/src/libs/agent-runtime/openrouter/fixtures/models.json +62 -0
  277. package/src/libs/agent-runtime/openrouter/index.test.ts +25 -9
  278. package/src/libs/agent-runtime/openrouter/index.ts +42 -84
  279. package/src/libs/agent-runtime/openrouter/type.ts +28 -0
  280. package/src/libs/agent-runtime/togetherai/index.test.ts +12 -9
  281. package/src/libs/agent-runtime/togetherai/index.ts +20 -85
  282. package/src/libs/agent-runtime/utils/anthropicHelpers.test.ts +14 -22
  283. package/src/libs/agent-runtime/utils/anthropicHelpers.ts +4 -10
  284. package/src/libs/agent-runtime/utils/openaiCompatibleFactory/index.ts +147 -0
  285. package/src/libs/agent-runtime/zeroone/index.test.ts +350 -0
  286. package/src/libs/agent-runtime/zeroone/index.ts +14 -77
  287. package/src/locales/default/common.ts +0 -28
  288. package/src/locales/default/components.ts +15 -0
  289. package/src/locales/default/error.ts +2 -54
  290. package/src/locales/default/index.ts +4 -0
  291. package/src/locales/default/modelProvider.ts +229 -0
  292. package/src/locales/default/setting.ts +51 -202
  293. package/src/migrations/FromV3ToV4/fixtures/azure-input-v3.json +79 -0
  294. package/src/migrations/FromV3ToV4/fixtures/azure-output-v4.json +75 -0
  295. package/src/migrations/FromV3ToV4/fixtures/ollama-input-v3.json +85 -0
  296. package/src/migrations/FromV3ToV4/fixtures/ollama-output-v4.json +86 -0
  297. package/src/migrations/FromV3ToV4/fixtures/openai-input-v3.json +77 -0
  298. package/src/migrations/FromV3ToV4/fixtures/openai-output-v4.json +79 -0
  299. package/src/migrations/FromV3ToV4/fixtures/openrouter-input-v3.json +82 -0
  300. package/src/migrations/FromV3ToV4/fixtures/openrouter-output-v4.json +89 -0
  301. package/src/migrations/FromV3ToV4/fixtures/output-v4-from-v1.json +203 -0
  302. package/src/migrations/FromV3ToV4/index.ts +96 -0
  303. package/src/migrations/FromV3ToV4/migrations.test.ts +195 -0
  304. package/src/migrations/FromV3ToV4/types/v3.ts +59 -0
  305. package/src/migrations/FromV3ToV4/types/v4.ts +37 -0
  306. package/src/migrations/index.ts +11 -3
  307. package/src/services/_auth.test.ts +4 -6
  308. package/src/services/_auth.ts +8 -60
  309. package/src/services/_header.ts +5 -22
  310. package/src/services/_url.ts +1 -0
  311. package/src/services/chat.ts +16 -6
  312. package/src/services/global.ts +1 -1
  313. package/src/services/models.ts +23 -0
  314. package/src/services/ollama.ts +2 -2
  315. package/src/store/chat/slices/share/action.test.ts +113 -0
  316. package/src/store/chat/slices/share/action.ts +1 -1
  317. package/src/store/global/slices/common/action.test.ts +166 -1
  318. package/src/store/global/slices/common/action.ts +2 -1
  319. package/src/store/global/slices/settings/{action.test.ts → actions/general.test.ts} +1 -19
  320. package/src/store/global/slices/settings/{action.ts → actions/general.ts} +4 -19
  321. package/src/store/global/slices/settings/actions/index.ts +18 -0
  322. package/src/store/global/slices/settings/actions/llm.test.ts +60 -0
  323. package/src/store/global/slices/settings/actions/llm.ts +88 -0
  324. package/src/store/global/slices/settings/initialState.ts +3 -1
  325. package/src/store/global/slices/settings/reducers/customModelCard.test.ts +204 -0
  326. package/src/store/global/slices/settings/reducers/customModelCard.ts +64 -0
  327. package/src/store/global/slices/settings/selectors/index.ts +1 -0
  328. package/src/store/global/slices/settings/selectors/modelConfig.test.ts +189 -0
  329. package/src/store/global/slices/settings/selectors/modelConfig.ts +179 -0
  330. package/src/store/global/slices/settings/selectors/modelProvider.test.ts +47 -138
  331. package/src/store/global/slices/settings/selectors/modelProvider.ts +102 -243
  332. package/src/store/global/store.ts +1 -1
  333. package/src/types/llm.ts +12 -1
  334. package/src/types/serverConfig.ts +22 -0
  335. package/src/types/settings/index.ts +0 -12
  336. package/src/types/settings/modelProvider.ts +34 -90
  337. package/src/utils/client/switchLang.test.ts +34 -0
  338. package/src/utils/difference.test.ts +46 -0
  339. package/src/utils/difference.ts +15 -2
  340. package/src/utils/fetch.ts +1 -3
  341. package/src/utils/parseModels.ts +62 -0
  342. package/vercel.json +1 -1
  343. package/docs/package.json +0 -5
  344. package/src/features/Conversation/Error/APIKeyForm/Anthropic.tsx +0 -40
  345. package/src/features/Conversation/Error/APIKeyForm/Google.tsx +0 -61
  346. package/src/features/Conversation/Error/APIKeyForm/Groq.tsx +0 -60
  347. package/src/features/Conversation/Error/APIKeyForm/Mistral.tsx +0 -60
  348. package/src/features/Conversation/Error/APIKeyForm/Moonshot.tsx +0 -60
  349. package/src/features/Conversation/Error/APIKeyForm/OpenAI.tsx +0 -63
  350. package/src/features/Conversation/Error/APIKeyForm/OpenRouter.tsx +0 -40
  351. package/src/features/Conversation/Error/APIKeyForm/Perplexity.tsx +0 -60
  352. package/src/features/Conversation/Error/APIKeyForm/TogetherAI.tsx +0 -40
  353. package/src/features/Conversation/Error/APIKeyForm/ZeroOne.tsx +0 -60
  354. package/src/features/Conversation/Error/APIKeyForm/Zhipu.tsx +0 -62
  355. package/src/libs/agent-runtime/utils/env.ts +0 -1
  356. package/src/store/global/slices/settings/selectors/__snapshots__/modelProvider.test.ts.snap +0 -230
  357. /package/src/app/api/chat/{auth.ts → auth/utils.ts} +0 -0
  358. /package/src/components/{AntdStaticMethods.tsx → AntdStaticMethods/index.tsx} +0 -0
@@ -1,25 +1,13 @@
1
1
  import { JWTPayload, LOBE_CHAT_AUTH_HEADER } from '@/const/auth';
2
2
  import { ModelProvider } from '@/libs/agent-runtime';
3
3
  import { useGlobalStore } from '@/store/global';
4
- import { modelProviderSelectors, settingsSelectors } from '@/store/global/selectors';
4
+ import { modelConfigSelectors, settingsSelectors } from '@/store/global/selectors';
5
5
  import { createJWT } from '@/utils/jwt';
6
6
 
7
7
  export const getProviderAuthPayload = (provider: string) => {
8
8
  switch (provider) {
9
- case ModelProvider.ZhiPu: {
10
- return { apiKey: modelProviderSelectors.zhipuAPIKey(useGlobalStore.getState()) };
11
- }
12
-
13
- case ModelProvider.Moonshot: {
14
- return { apiKey: modelProviderSelectors.moonshotAPIKey(useGlobalStore.getState()) };
15
- }
16
-
17
- case ModelProvider.Google: {
18
- return { apiKey: modelProviderSelectors.googleAPIKey(useGlobalStore.getState()) };
19
- }
20
-
21
9
  case ModelProvider.Bedrock: {
22
- const { accessKeyId, region, secretAccessKey } = modelProviderSelectors.bedrockConfig(
10
+ const { accessKeyId, region, secretAccessKey } = modelConfigSelectors.bedrockConfig(
23
11
  useGlobalStore.getState(),
24
12
  );
25
13
  const awsSecretAccessKey = secretAccessKey;
@@ -31,7 +19,7 @@ export const getProviderAuthPayload = (provider: string) => {
31
19
  }
32
20
 
33
21
  case ModelProvider.Azure: {
34
- const azure = modelProviderSelectors.azureConfig(useGlobalStore.getState());
22
+ const azure = modelConfigSelectors.azureConfig(useGlobalStore.getState());
35
23
 
36
24
  return {
37
25
  apiKey: azure.apiKey,
@@ -41,55 +29,15 @@ export const getProviderAuthPayload = (provider: string) => {
41
29
  }
42
30
 
43
31
  case ModelProvider.Ollama: {
44
- const endpoint = modelProviderSelectors.ollamaProxyUrl(useGlobalStore.getState());
45
-
46
- return {
47
- endpoint,
48
- };
49
- }
50
-
51
- case ModelProvider.Perplexity: {
52
- return { apiKey: modelProviderSelectors.perplexityAPIKey(useGlobalStore.getState()) };
53
- }
32
+ const endpoint = modelConfigSelectors.ollamaProxyUrl(useGlobalStore.getState());
54
33
 
55
- case ModelProvider.Anthropic: {
56
- const apiKey = modelProviderSelectors.anthropicAPIKey(useGlobalStore.getState());
57
- const endpoint = modelProviderSelectors.anthropicProxyUrl(useGlobalStore.getState());
58
- return { apiKey, endpoint };
34
+ return { endpoint };
59
35
  }
60
36
 
61
- case ModelProvider.Mistral: {
62
- return { apiKey: modelProviderSelectors.mistralAPIKey(useGlobalStore.getState()) };
63
- }
64
-
65
- case ModelProvider.Groq: {
66
- return { apiKey: modelProviderSelectors.groqAPIKey(useGlobalStore.getState()) };
67
- }
68
-
69
- case ModelProvider.OpenRouter: {
70
- return { apiKey: modelProviderSelectors.openrouterAPIKey(useGlobalStore.getState()) };
71
- }
72
-
73
- case ModelProvider.TogetherAI: {
74
- return { apiKey: modelProviderSelectors.togetheraiAPIKey(useGlobalStore.getState()) };
75
- }
76
-
77
- case ModelProvider.ZeroOne: {
78
- return { apiKey: modelProviderSelectors.zerooneAPIKey(useGlobalStore.getState()) };
79
- }
37
+ default: {
38
+ const config = modelConfigSelectors.providerConfig(provider)(useGlobalStore.getState());
80
39
 
81
- default:
82
- case ModelProvider.OpenAI: {
83
- const openai = modelProviderSelectors.openAIConfig(useGlobalStore.getState());
84
- const apiKey = openai.OPENAI_API_KEY || '';
85
- const endpoint = openai.endpoint || '';
86
-
87
- return {
88
- apiKey,
89
- azureApiVersion: openai.azureApiVersion,
90
- endpoint,
91
- useAzure: openai.useAzure,
92
- };
40
+ return { apiKey: config?.apiKey, endpoint: config?.endpoint };
93
41
  }
94
42
  }
95
43
  };
@@ -1,12 +1,6 @@
1
- import {
2
- AZURE_OPENAI_API_VERSION,
3
- LOBE_CHAT_ACCESS_CODE,
4
- OPENAI_API_KEY_HEADER_KEY,
5
- OPENAI_END_POINT,
6
- USE_AZURE_OPENAI,
7
- } from '@/const/fetch';
1
+ import { LOBE_CHAT_ACCESS_CODE, OPENAI_API_KEY_HEADER_KEY, OPENAI_END_POINT } from '@/const/fetch';
8
2
  import { useGlobalStore } from '@/store/global';
9
- import { modelProviderSelectors, settingsSelectors } from '@/store/global/selectors';
3
+ import { modelConfigSelectors, settingsSelectors } from '@/store/global/selectors';
10
4
 
11
5
  /**
12
6
  * TODO: Need to be removed after tts refactor
@@ -14,25 +8,14 @@ import { modelProviderSelectors, settingsSelectors } from '@/store/global/select
14
8
  */
15
9
  // eslint-disable-next-line no-undef
16
10
  export const createHeaderWithOpenAI = (header?: HeadersInit): HeadersInit => {
17
- const openai = modelProviderSelectors.openAIConfig(useGlobalStore.getState());
18
-
19
- const apiKey = openai.OPENAI_API_KEY || '';
20
- const endpoint = openai.endpoint || '';
11
+ const apiKey = modelConfigSelectors.openAIAPIKey(useGlobalStore.getState()) || '';
12
+ const endpoint = modelConfigSelectors.openAIProxyUrl(useGlobalStore.getState()) || '';
21
13
 
22
14
  // eslint-disable-next-line no-undef
23
- const result: HeadersInit = {
15
+ return {
24
16
  ...header,
25
17
  [LOBE_CHAT_ACCESS_CODE]: settingsSelectors.password(useGlobalStore.getState()),
26
18
  [OPENAI_API_KEY_HEADER_KEY]: apiKey,
27
19
  [OPENAI_END_POINT]: endpoint,
28
20
  };
29
-
30
- if (openai.useAzure) {
31
- Object.assign(result, {
32
- [AZURE_OPENAI_API_VERSION]: openai.azureApiVersion || '',
33
- [USE_AZURE_OPENAI]: '1',
34
- });
35
- }
36
-
37
- return result;
38
21
  };
@@ -29,6 +29,7 @@ export const API_ENDPOINTS = mapWithBasePath({
29
29
 
30
30
  // chat
31
31
  chat: (provider: string) => withBasePath(`/api/chat/${provider}`),
32
+ chatModels: (provider: string) => withBasePath(`/api/chat/models/${provider}`),
32
33
 
33
34
  // trace
34
35
  trace: '/api/trace',
@@ -9,6 +9,7 @@ import { filesSelectors, useFileStore } from '@/store/file';
9
9
  import { useGlobalStore } from '@/store/global';
10
10
  import {
11
11
  commonSelectors,
12
+ modelConfigSelectors,
12
13
  modelProviderSelectors,
13
14
  preferenceSelectors,
14
15
  } from '@/store/global/selectors';
@@ -131,13 +132,22 @@ class ChatService {
131
132
  const { signal } = options ?? {};
132
133
 
133
134
  const { provider = ModelProvider.OpenAI, ...res } = params;
135
+
136
+ let model = res.model || DEFAULT_AGENT_CONFIG.model;
137
+
138
+ // if the provider is Azure, get the deployment name as the request model
139
+ if (provider === ModelProvider.Azure) {
140
+ const chatModelCards = modelConfigSelectors.providerModelCards(provider)(
141
+ useGlobalStore.getState(),
142
+ );
143
+
144
+ const deploymentName = chatModelCards.find((i) => i.id === model)?.deploymentName;
145
+ if (deploymentName) model = deploymentName;
146
+ }
147
+
134
148
  const payload = merge(
135
- {
136
- model: DEFAULT_AGENT_CONFIG.model,
137
- stream: true,
138
- ...DEFAULT_AGENT_CONFIG.params,
139
- },
140
- res,
149
+ { model: DEFAULT_AGENT_CONFIG.model, stream: true, ...DEFAULT_AGENT_CONFIG.params },
150
+ { ...res, model },
141
151
  );
142
152
 
143
153
  const traceHeader = createTraceHeader({ ...options?.trace });
@@ -1,5 +1,5 @@
1
1
  import { dataSync } from '@/database/core';
2
- import { GlobalServerConfig } from '@/types/settings';
2
+ import { GlobalServerConfig } from '@/types/serverConfig';
3
3
  import { StartDataSyncParams } from '@/types/sync';
4
4
 
5
5
  import { API_ENDPOINTS } from './_url';
@@ -0,0 +1,23 @@
1
+ import { createHeaderWithAuth } from '@/services/_auth';
2
+ import { ChatModelCard } from '@/types/llm';
3
+
4
+ import { API_ENDPOINTS } from './_url';
5
+
6
+ class ModelsService {
7
+ getChatModels = async (provider: string): Promise<ChatModelCard[] | undefined> => {
8
+ const headers = await createHeaderWithAuth({
9
+ headers: { 'Content-Type': 'application/json' },
10
+ provider,
11
+ });
12
+ try {
13
+ const res = await fetch(API_ENDPOINTS.chatModels(provider), { headers });
14
+ if (!res.ok) return;
15
+
16
+ return res.json();
17
+ } catch {
18
+ return;
19
+ }
20
+ };
21
+ }
22
+
23
+ export const modelsService = new ModelsService();
@@ -3,7 +3,7 @@ import { ListResponse, Ollama as OllamaBrowser, ProgressResponse } from 'ollama/
3
3
  import { createErrorResponse } from '@/app/api/errorResponse';
4
4
  import { ModelProvider } from '@/libs/agent-runtime';
5
5
  import { useGlobalStore } from '@/store/global';
6
- import { modelProviderSelectors } from '@/store/global/selectors';
6
+ import { modelConfigSelectors } from '@/store/global/selectors';
7
7
  import { ChatErrorType } from '@/types/fetch';
8
8
  import { getMessageError } from '@/utils/fetch';
9
9
 
@@ -11,7 +11,7 @@ const DEFAULT_BASE_URL = 'http://127.0.0.1:11434/v1';
11
11
 
12
12
  class OllamaService {
13
13
  getHost = (): string => {
14
- const endpoint = modelProviderSelectors.ollamaProxyUrl(useGlobalStore.getState());
14
+ const endpoint = modelConfigSelectors.ollamaProxyUrl(useGlobalStore.getState());
15
15
  const url = new URL(endpoint || DEFAULT_BASE_URL);
16
16
  return url.host;
17
17
  };
@@ -3,6 +3,7 @@ import { act, renderHook } from '@testing-library/react';
3
3
  import { DEFAULT_USER_AVATAR_URL } from '@/const/meta';
4
4
  import { shareGPTService } from '@/services/share';
5
5
  import { useChatStore } from '@/store/chat';
6
+ import { ChatMessage } from '@/types/message';
6
7
 
7
8
  describe('shareSlice actions', () => {
8
9
  let shareGPTServiceSpy: any;
@@ -82,5 +83,117 @@ describe('shareSlice actions', () => {
82
83
  expect(result.current.shareLoading).toBe(false);
83
84
  // 注意:这里的验证可能需要你根据实际的状态管理逻辑进行调整
84
85
  });
86
+
87
+ it('should include plugin information when withPluginInfo is true', async () => {
88
+ // 模拟带有插件信息的消息
89
+ const pluginMessage = {
90
+ role: 'function',
91
+ content: 'plugin content',
92
+ plugin: {
93
+ type: 'default',
94
+ arguments: '{}',
95
+ apiName: 'test-api',
96
+ identifier: 'test-identifier',
97
+ },
98
+ id: 'abc',
99
+ } as ChatMessage;
100
+
101
+ act(() => {
102
+ useChatStore.setState({ messages: [pluginMessage] });
103
+ });
104
+
105
+ const { result } = renderHook(() => useChatStore());
106
+ await act(async () => {
107
+ result.current.shareToShareGPT({ withPluginInfo: true });
108
+ });
109
+ expect(shareGPTServiceSpy).toHaveBeenCalledWith(
110
+ expect.objectContaining({
111
+ items: expect.arrayContaining([
112
+ expect.objectContaining({
113
+ from: 'gpt',
114
+ value: expect.stringContaining('Function Calling Plugin'),
115
+ }),
116
+ ]),
117
+ }),
118
+ );
119
+ });
120
+
121
+ it('should not include plugin information when withPluginInfo is false', async () => {
122
+ const pluginMessage = {
123
+ role: 'function',
124
+ content: 'plugin content',
125
+ plugin: {
126
+ type: 'default',
127
+ arguments: '{}',
128
+ apiName: 'test-api',
129
+ identifier: 'test-identifier',
130
+ },
131
+ id: 'abc',
132
+ } as ChatMessage;
133
+
134
+ act(() => {
135
+ useChatStore.setState({ messages: [pluginMessage] });
136
+ });
137
+
138
+ const { result } = renderHook(() => useChatStore());
139
+ await act(async () => {
140
+ result.current.shareToShareGPT({ withPluginInfo: false });
141
+ });
142
+ expect(shareGPTServiceSpy).toHaveBeenCalledWith(
143
+ expect.objectContaining({
144
+ items: expect.not.arrayContaining([
145
+ expect.objectContaining({
146
+ from: 'gpt',
147
+ value: expect.stringContaining('Function Calling Plugin'),
148
+ }),
149
+ ]),
150
+ }),
151
+ );
152
+ });
153
+
154
+ it('should handle messages from different roles correctly', async () => {
155
+ const messages = [
156
+ { role: 'user', content: 'user message', id: '1' },
157
+ { role: 'assistant', content: 'assistant message', id: '2' },
158
+ {
159
+ role: 'function',
160
+ content: 'plugin content',
161
+ plugin: {
162
+ type: 'default',
163
+ arguments: '{}',
164
+ apiName: 'test-api',
165
+ identifier: 'test-identifier',
166
+ },
167
+ id: '3',
168
+ },
169
+ ] as ChatMessage[];
170
+
171
+ act(() => {
172
+ useChatStore.setState({ messages });
173
+ });
174
+
175
+ const { result } = renderHook(() => useChatStore());
176
+ await act(async () => {
177
+ await result.current.shareToShareGPT({
178
+ withPluginInfo: true,
179
+ withSystemRole: true,
180
+ });
181
+ });
182
+
183
+ expect(shareGPTServiceSpy).toHaveBeenCalledWith(
184
+ expect.objectContaining({
185
+ items: [
186
+ expect.objectContaining({ from: 'gpt' }), // Agent meta info
187
+ expect.objectContaining({ from: 'human', value: 'user message' }),
188
+ expect.objectContaining({ from: 'gpt', value: 'assistant message' }),
189
+ expect.objectContaining({
190
+ from: 'gpt',
191
+ value: expect.stringContaining('Function Calling Plugin'),
192
+ }),
193
+ expect.objectContaining({ from: 'gpt', value: expect.stringContaining('Share from') }), // Footer
194
+ ],
195
+ }),
196
+ );
197
+ });
85
198
  });
86
199
  });
@@ -47,7 +47,7 @@ export interface ShareAction {
47
47
  avatar?: string;
48
48
  withPluginInfo?: boolean;
49
49
  withSystemRole?: boolean;
50
- }) => void;
50
+ }) => Promise<void>;
51
51
  }
52
52
 
53
53
  export const chatShare: StateCreator<ChatStore, [['zustand/devtools', never]], [], ShareAction> = (
@@ -4,9 +4,13 @@ import { afterEach, describe, expect, it, vi } from 'vitest';
4
4
  import { withSWR } from '~test-utils';
5
5
 
6
6
  import { globalService } from '@/services/global';
7
+ import { messageService } from '@/services/message';
7
8
  import { userService } from '@/services/user';
8
9
  import { useGlobalStore } from '@/store/global';
9
- import { GlobalServerConfig } from '@/types/settings';
10
+ import { commonSelectors } from '@/store/global/slices/common/selectors';
11
+ import { preferenceSelectors } from '@/store/global/slices/preference/selectors';
12
+ import { syncSettingsSelectors } from '@/store/global/slices/settings/selectors';
13
+ import { GlobalServerConfig } from '@/types/serverConfig';
10
14
  import { switchLang } from '@/utils/client/switchLang';
11
15
 
12
16
  vi.mock('zustand/traditional');
@@ -200,4 +204,165 @@ describe('createCommonSlice', () => {
200
204
  expect(useGlobalStore.getState().settings).toEqual({});
201
205
  });
202
206
  });
207
+
208
+ describe('refreshConnection', () => {
209
+ it('should not call triggerEnableSync when userId is empty', async () => {
210
+ const { result } = renderHook(() => useGlobalStore());
211
+ const onEvent = vi.fn();
212
+
213
+ vi.spyOn(commonSelectors, 'userId').mockReturnValueOnce(undefined);
214
+ const triggerEnableSyncSpy = vi.spyOn(result.current, 'triggerEnableSync');
215
+
216
+ await act(async () => {
217
+ await result.current.refreshConnection(onEvent);
218
+ });
219
+
220
+ expect(triggerEnableSyncSpy).not.toHaveBeenCalled();
221
+ });
222
+
223
+ it('should call triggerEnableSync when userId exists', async () => {
224
+ const { result } = renderHook(() => useGlobalStore());
225
+ const onEvent = vi.fn();
226
+ const userId = 'user-id';
227
+
228
+ vi.spyOn(commonSelectors, 'userId').mockReturnValueOnce(userId);
229
+ const triggerEnableSyncSpy = vi.spyOn(result.current, 'triggerEnableSync');
230
+
231
+ await act(async () => {
232
+ await result.current.refreshConnection(onEvent);
233
+ });
234
+
235
+ expect(triggerEnableSyncSpy).toHaveBeenCalledWith(userId, onEvent);
236
+ });
237
+ });
238
+
239
+ describe('triggerEnableSync', () => {
240
+ it('should return false when sync.channelName is empty', async () => {
241
+ const { result } = renderHook(() => useGlobalStore());
242
+ const userId = 'user-id';
243
+ const onEvent = vi.fn();
244
+
245
+ vi.spyOn(syncSettingsSelectors, 'webrtcConfig').mockReturnValueOnce({
246
+ channelName: '',
247
+ enabled: true,
248
+ });
249
+
250
+ const data = await act(async () => {
251
+ return result.current.triggerEnableSync(userId, onEvent);
252
+ });
253
+
254
+ expect(data).toBe(false);
255
+ });
256
+
257
+ it('should call globalService.enabledSync when sync.channelName exists', async () => {
258
+ const userId = 'user-id';
259
+ const onEvent = vi.fn();
260
+ const channelName = 'channel-name';
261
+ const channelPassword = 'channel-password';
262
+ const deviceName = 'device-name';
263
+ const signaling = 'signaling';
264
+
265
+ vi.spyOn(syncSettingsSelectors, 'webrtcConfig').mockReturnValueOnce({
266
+ channelName,
267
+ channelPassword,
268
+ signaling,
269
+ enabled: true,
270
+ });
271
+ vi.spyOn(syncSettingsSelectors, 'deviceName').mockReturnValueOnce(deviceName);
272
+ const enabledSyncSpy = vi.spyOn(globalService, 'enabledSync').mockResolvedValueOnce(true);
273
+ const { result } = renderHook(() => useGlobalStore());
274
+
275
+ const data = await act(async () => {
276
+ return result.current.triggerEnableSync(userId, onEvent);
277
+ });
278
+
279
+ expect(enabledSyncSpy).toHaveBeenCalledWith({
280
+ channel: { name: channelName, password: channelPassword },
281
+ onAwarenessChange: expect.any(Function),
282
+ onSyncEvent: onEvent,
283
+ onSyncStatusChange: expect.any(Function),
284
+ signaling,
285
+ user: expect.objectContaining({ id: userId, name: deviceName }),
286
+ });
287
+ expect(data).toBe(true);
288
+ });
289
+ });
290
+
291
+ describe('useCheckTrace', () => {
292
+ it('should return false when shouldFetch is false', async () => {
293
+ const { result } = renderHook(() => useGlobalStore().useCheckTrace(false), {
294
+ wrapper: withSWR,
295
+ });
296
+
297
+ await waitFor(() => expect(result.current.data).toBe(false));
298
+ });
299
+
300
+ it('should return false when userAllowTrace is already set', async () => {
301
+ vi.spyOn(preferenceSelectors, 'userAllowTrace').mockReturnValueOnce(true);
302
+
303
+ const { result } = renderHook(() => useGlobalStore().useCheckTrace(true), {
304
+ wrapper: withSWR,
305
+ });
306
+
307
+ await waitFor(() => expect(result.current.data).toBe(false));
308
+ });
309
+
310
+ it('should call messageService.messageCountToCheckTrace when needed', async () => {
311
+ vi.spyOn(preferenceSelectors, 'userAllowTrace').mockReturnValueOnce(null);
312
+ const messageCountToCheckTraceSpy = vi
313
+ .spyOn(messageService, 'messageCountToCheckTrace')
314
+ .mockResolvedValueOnce(true);
315
+
316
+ const { result } = renderHook(() => useGlobalStore().useCheckTrace(true), {
317
+ wrapper: withSWR,
318
+ });
319
+
320
+ await waitFor(() => expect(result.current.data).toBe(true));
321
+ expect(messageCountToCheckTraceSpy).toHaveBeenCalled();
322
+ });
323
+ });
324
+
325
+ describe('useEnabledSync', () => {
326
+ it('should return false when userId is empty', async () => {
327
+ const { result } = renderHook(
328
+ () => useGlobalStore().useEnabledSync(true, undefined, vi.fn()),
329
+ { wrapper: withSWR },
330
+ );
331
+
332
+ await waitFor(() => expect(result.current.data).toBe(false));
333
+ });
334
+
335
+ it('should call globalService.disableSync when userEnableSync is false', async () => {
336
+ const disableSyncSpy = vi.spyOn(globalService, 'disableSync').mockResolvedValueOnce(false);
337
+
338
+ const { result } = renderHook(
339
+ () => useGlobalStore().useEnabledSync(false, 'user-id', vi.fn()),
340
+ { wrapper: withSWR },
341
+ );
342
+
343
+ await waitFor(() => expect(result.current.data).toBeUndefined());
344
+ expect(disableSyncSpy).toHaveBeenCalled();
345
+ });
346
+
347
+ it('should call triggerEnableSync when userEnableSync and userId exist', async () => {
348
+ const userId = 'user-id';
349
+ const onEvent = vi.fn();
350
+ const triggerEnableSyncSpy = vi.fn().mockResolvedValueOnce(true);
351
+
352
+ const { result } = renderHook(() => useGlobalStore());
353
+
354
+ // replace triggerEnableSync as a mock
355
+ result.current.triggerEnableSync = triggerEnableSyncSpy;
356
+
357
+ const { result: swrResult } = renderHook(
358
+ () => result.current.useEnabledSync(true, userId, onEvent),
359
+ {
360
+ wrapper: withSWR,
361
+ },
362
+ );
363
+
364
+ await waitFor(() => expect(swrResult.current.data).toBe(true));
365
+ expect(triggerEnableSyncSpy).toHaveBeenCalledWith(userId, onEvent);
366
+ });
367
+ });
203
368
  });
@@ -10,7 +10,8 @@ import { globalService } from '@/services/global';
10
10
  import { messageService } from '@/services/message';
11
11
  import { UserConfig, userService } from '@/services/user';
12
12
  import type { GlobalStore } from '@/store/global';
13
- import type { GlobalServerConfig, GlobalSettings } from '@/types/settings';
13
+ import type { GlobalServerConfig } from '@/types/serverConfig';
14
+ import type { GlobalSettings } from '@/types/settings';
14
15
  import { OnSyncEvent, PeerSyncStatus } from '@/types/sync';
15
16
  import { switchLang } from '@/utils/client/switchLang';
16
17
  import { merge } from '@/utils/merge';
@@ -7,7 +7,7 @@ import { DEFAULT_AGENT, DEFAULT_SETTINGS } from '@/const/settings';
7
7
  import { userService } from '@/services/user';
8
8
  import { useGlobalStore } from '@/store/global';
9
9
  import { LobeAgentSettings } from '@/types/session';
10
- import { GlobalSettings, OpenAIConfig } from '@/types/settings';
10
+ import { GlobalSettings } from '@/types/settings';
11
11
 
12
12
  // Mock userService
13
13
  vi.mock('@/services/user', () => ({
@@ -66,24 +66,6 @@ describe('SettingsAction', () => {
66
66
  });
67
67
  });
68
68
 
69
- describe('setModelProviderConfig', () => {
70
- it('should set OpenAI configuration', async () => {
71
- const { result } = renderHook(() => useGlobalStore());
72
- const openAIConfig: Partial<OpenAIConfig> = { OPENAI_API_KEY: 'test-key' };
73
-
74
- // Perform the action
75
- await act(async () => {
76
- await result.current.setModelProviderConfig('openAI', openAIConfig);
77
- });
78
-
79
- // Assert that updateUserSettings was called with the correct OpenAI configuration
80
- expect(userService.updateUserSettings).toHaveBeenCalledWith({
81
- languageModel: {
82
- openAI: openAIConfig,
83
- },
84
- });
85
- });
86
- });
87
69
  describe('setSettings', () => {
88
70
  it('should set partial settings', async () => {
89
71
  const { result } = renderHook(() => useGlobalStore());
@@ -6,31 +6,23 @@ import type { StateCreator } from 'zustand/vanilla';
6
6
  import { userService } from '@/services/user';
7
7
  import type { GlobalStore } from '@/store/global';
8
8
  import { LobeAgentSettings } from '@/types/session';
9
- import { GlobalLLMConfig, GlobalLLMProviderKey, GlobalSettings } from '@/types/settings';
9
+ import { GlobalSettings } from '@/types/settings';
10
10
  import { difference } from '@/utils/difference';
11
11
  import { merge } from '@/utils/merge';
12
12
 
13
- /**
14
- * 设置操作
15
- */
16
- export interface SettingsAction {
13
+ export interface GeneralSettingsAction {
17
14
  importAppSettings: (settings: GlobalSettings) => Promise<void>;
18
15
  resetSettings: () => Promise<void>;
19
- setModelProviderConfig: <T extends GlobalLLMProviderKey>(
20
- provider: T,
21
- config: Partial<GlobalLLMConfig[T]>,
22
- ) => Promise<void>;
23
16
  setSettings: (settings: DeepPartial<GlobalSettings>) => Promise<void>;
24
17
  switchThemeMode: (themeMode: ThemeMode) => Promise<void>;
25
- toggleProviderEnabled: (provider: GlobalLLMProviderKey, enabled: boolean) => Promise<void>;
26
18
  updateDefaultAgent: (agent: DeepPartial<LobeAgentSettings>) => Promise<void>;
27
19
  }
28
20
 
29
- export const createSettingsSlice: StateCreator<
21
+ export const generalSettingsSlice: StateCreator<
30
22
  GlobalStore,
31
23
  [['zustand/devtools', never]],
32
24
  [],
33
- SettingsAction
25
+ GeneralSettingsAction
34
26
  > = (set, get) => ({
35
27
  importAppSettings: async (importAppSettings) => {
36
28
  const { setSettings } = get();
@@ -43,9 +35,6 @@ export const createSettingsSlice: StateCreator<
43
35
  await userService.resetUserSettings();
44
36
  await get().refreshUserConfig();
45
37
  },
46
- setModelProviderConfig: async (provider, config) => {
47
- await get().setSettings({ languageModel: { [provider]: config } });
48
- },
49
38
  setSettings: async (settings) => {
50
39
  const { settings: prevSetting, defaultSettings } = get();
51
40
 
@@ -58,13 +47,9 @@ export const createSettingsSlice: StateCreator<
58
47
  await userService.updateUserSettings(diffs);
59
48
  await get().refreshUserConfig();
60
49
  },
61
-
62
50
  switchThemeMode: async (themeMode) => {
63
51
  await get().setSettings({ themeMode });
64
52
  },
65
- toggleProviderEnabled: async (provider, enabled) => {
66
- await get().setSettings({ languageModel: { [provider]: { enabled } } });
67
- },
68
53
  updateDefaultAgent: async (defaultAgent) => {
69
54
  await get().setSettings({ defaultAgent });
70
55
  },
@@ -0,0 +1,18 @@
1
+ import type { StateCreator } from 'zustand/vanilla';
2
+
3
+ import type { GlobalStore } from '@/store/global';
4
+
5
+ import { GeneralSettingsAction, generalSettingsSlice } from './general';
6
+ import { LLMSettingsAction, llmSettingsSlice } from './llm';
7
+
8
+ export interface SettingsAction extends LLMSettingsAction, GeneralSettingsAction {}
9
+
10
+ export const createSettingsSlice: StateCreator<
11
+ GlobalStore,
12
+ [['zustand/devtools', never]],
13
+ [],
14
+ SettingsAction
15
+ > = (...params) => ({
16
+ ...llmSettingsSlice(...params),
17
+ ...generalSettingsSlice(...params),
18
+ });