@lobehub/chat 1.91.0 → 1.91.2

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 (292) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/changelog/v1.json +18 -0
  3. package/docs/changelog/2023-09-09-plugin-system.mdx +2 -3
  4. package/docs/changelog/2023-11-14-gpt4-vision.mdx +4 -6
  5. package/docs/changelog/2023-11-19-tts-stt.mdx +2 -3
  6. package/docs/changelog/2023-12-22-dalle-3.mdx +2 -5
  7. package/docs/changelog/2023-12-22-dalle-3.zh-CN.mdx +2 -2
  8. package/docs/changelog/2024-02-08-sso-oauth.mdx +2 -2
  9. package/docs/changelog/2024-06-19-lobe-chat-v1.mdx +2 -3
  10. package/docs/changelog/2024-06-19-lobe-chat-v1.zh-CN.mdx +2 -2
  11. package/docs/changelog/2024-07-19-gpt-4o-mini.mdx +2 -3
  12. package/docs/changelog/2024-07-19-gpt-4o-mini.zh-CN.mdx +2 -2
  13. package/docs/changelog/2024-08-02-lobe-chat-database-docker.mdx +2 -3
  14. package/docs/changelog/2024-08-21-file-upload-and-knowledge-base.mdx +4 -5
  15. package/docs/changelog/2024-09-13-openai-o1-models.mdx +2 -2
  16. package/docs/changelog/2024-09-20-artifacts.mdx +2 -3
  17. package/docs/changelog/2024-09-20-artifacts.zh-CN.mdx +2 -2
  18. package/docs/changelog/2024-10-27-pin-assistant.mdx +2 -3
  19. package/docs/changelog/2024-11-06-share-text-json.mdx +2 -4
  20. package/docs/changelog/2024-11-06-share-text-json.zh-CN.mdx +2 -2
  21. package/docs/changelog/2024-11-25-november-providers.mdx +2 -2
  22. package/docs/changelog/2024-11-27-forkable-chat.mdx +2 -2
  23. package/docs/changelog/2025-01-03-user-profile.mdx +2 -2
  24. package/docs/changelog/2025-01-22-new-ai-provider.mdx +2 -2
  25. package/docs/changelog/2025-02-02-deepseek-r1.mdx +4 -4
  26. package/docs/development/basic/add-new-authentication-providers.zh-CN.mdx +1 -2
  27. package/docs/development/basic/chat-api.mdx +2 -4
  28. package/docs/development/basic/chat-api.zh-CN.mdx +2 -4
  29. package/docs/development/internationalization/internationalization-implementation.mdx +10 -10
  30. package/docs/development/internationalization/internationalization-implementation.zh-CN.mdx +10 -10
  31. package/docs/self-hosting/advanced/analytics.mdx +2 -2
  32. package/docs/self-hosting/advanced/auth/clerk.mdx +2 -2
  33. package/docs/self-hosting/advanced/auth/next-auth/auth0.mdx +2 -3
  34. package/docs/self-hosting/advanced/auth/next-auth/authelia.mdx +2 -3
  35. package/docs/self-hosting/advanced/auth/next-auth/authentik.mdx +2 -3
  36. package/docs/self-hosting/advanced/auth/next-auth/casdoor.mdx +4 -7
  37. package/docs/self-hosting/advanced/auth/next-auth/casdoor.zh-CN.mdx +0 -3
  38. package/docs/self-hosting/advanced/auth/next-auth/cloudflare-zero-trust.mdx +2 -3
  39. package/docs/self-hosting/advanced/auth/next-auth/cloudflare-zero-trust.zh-CN.mdx +2 -2
  40. package/docs/self-hosting/advanced/auth/next-auth/github.mdx +2 -3
  41. package/docs/self-hosting/advanced/auth/next-auth/keycloak.mdx +12 -6
  42. package/docs/self-hosting/advanced/auth/next-auth/keycloak.zh-CN.mdx +5 -1
  43. package/docs/self-hosting/advanced/auth/next-auth/logto.mdx +8 -14
  44. package/docs/self-hosting/advanced/auth/next-auth/logto.zh-CN.mdx +6 -12
  45. package/docs/self-hosting/advanced/auth/next-auth/microsoft-entra-id.mdx +2 -3
  46. package/docs/self-hosting/advanced/auth/next-auth/wechat.mdx +2 -2
  47. package/docs/self-hosting/advanced/auth/next-auth/zitadel.mdx +2 -3
  48. package/docs/self-hosting/advanced/auth.mdx +2 -3
  49. package/docs/self-hosting/advanced/desktop.mdx +2 -1
  50. package/docs/self-hosting/advanced/desktop.zh-CN.mdx +1 -3
  51. package/docs/self-hosting/advanced/feature-flags.mdx +2 -3
  52. package/docs/self-hosting/advanced/knowledge-base.mdx +4 -3
  53. package/docs/self-hosting/advanced/model-list.mdx +11 -10
  54. package/docs/self-hosting/advanced/model-list.zh-CN.mdx +10 -9
  55. package/docs/self-hosting/advanced/observability/langfuse.mdx +2 -3
  56. package/docs/self-hosting/advanced/online-search.mdx +11 -10
  57. package/docs/self-hosting/advanced/online-search.zh-CN.mdx +7 -7
  58. package/docs/self-hosting/advanced/s3/tencent-cloud.mdx +2 -2
  59. package/docs/self-hosting/advanced/settings-url-share.mdx +2 -3
  60. package/docs/self-hosting/advanced/upstream-sync.mdx +2 -3
  61. package/docs/self-hosting/advanced/webrtc.mdx +2 -2
  62. package/docs/self-hosting/environment-variables/analytics.mdx +2 -3
  63. package/docs/self-hosting/environment-variables/auth.mdx +2 -3
  64. package/docs/self-hosting/environment-variables/basic.mdx +4 -5
  65. package/docs/self-hosting/environment-variables/basic.zh-CN.mdx +2 -2
  66. package/docs/self-hosting/environment-variables/model-provider.mdx +2 -3
  67. package/docs/self-hosting/environment-variables/s3.mdx +3 -5
  68. package/docs/self-hosting/environment-variables.mdx +2 -2
  69. package/docs/self-hosting/examples/azure-openai.mdx +2 -2
  70. package/docs/self-hosting/examples/ollama.mdx +2 -3
  71. package/docs/self-hosting/faq/no-v1-suffix.mdx +4 -4
  72. package/docs/self-hosting/faq/proxy-with-unable-to-verify-leaf-signature.mdx +2 -3
  73. package/docs/self-hosting/platform/alibaba-cloud.mdx +2 -3
  74. package/docs/self-hosting/platform/btpanel.mdx +5 -5
  75. package/docs/self-hosting/platform/btpanel.zh-CN.mdx +4 -3
  76. package/docs/self-hosting/platform/docker-compose.mdx +2 -3
  77. package/docs/self-hosting/platform/docker-compose.zh-CN.mdx +0 -2
  78. package/docs/self-hosting/platform/docker.mdx +2 -2
  79. package/docs/self-hosting/platform/netlify.mdx +2 -4
  80. package/docs/self-hosting/platform/netlify.zh-CN.mdx +2 -2
  81. package/docs/self-hosting/platform/railway.mdx +2 -3
  82. package/docs/self-hosting/platform/repocloud.mdx +2 -3
  83. package/docs/self-hosting/platform/sealos.mdx +2 -2
  84. package/docs/self-hosting/platform/tencentcloud-lighthouse.mdx +2 -3
  85. package/docs/self-hosting/platform/vercel.mdx +2 -3
  86. package/docs/self-hosting/platform/zeabur.mdx +2 -2
  87. package/docs/self-hosting/server-database/docker-compose.mdx +65 -44
  88. package/docs/self-hosting/server-database/docker-compose.zh-CN.mdx +48 -55
  89. package/docs/self-hosting/server-database/docker.mdx +2 -2
  90. package/docs/self-hosting/server-database/docker.zh-CN.mdx +2 -2
  91. package/docs/self-hosting/server-database/dokploy.mdx +4 -5
  92. package/docs/self-hosting/server-database/dokploy.zh-CN.mdx +137 -138
  93. package/docs/self-hosting/server-database/netlify.mdx +2 -2
  94. package/docs/self-hosting/server-database/netlify.zh-CN.mdx +2 -2
  95. package/docs/self-hosting/server-database/railway.mdx +2 -2
  96. package/docs/self-hosting/server-database/repocloud.mdx +2 -2
  97. package/docs/self-hosting/server-database/sealos.mdx +4 -5
  98. package/docs/self-hosting/server-database/sealos.zh-CN.mdx +18 -20
  99. package/docs/self-hosting/server-database/vercel.mdx +5 -3
  100. package/docs/self-hosting/server-database/vercel.zh-CN.mdx +2 -2
  101. package/docs/self-hosting/server-database/zeabur.mdx +2 -2
  102. package/docs/self-hosting/server-database.mdx +1 -1
  103. package/docs/self-hosting/server-database.zh-CN.mdx +2 -1
  104. package/docs/self-hosting/start.mdx +2 -2
  105. package/docs/self-hosting/start.zh-CN.mdx +2 -2
  106. package/docs/usage/agents/agent-organization.mdx +2 -2
  107. package/docs/usage/agents/concepts.mdx +4 -5
  108. package/docs/usage/agents/concepts.zh-CN.mdx +2 -2
  109. package/docs/usage/agents/custom-agent.mdx +3 -4
  110. package/docs/usage/agents/custom-agent.zh-CN.mdx +1 -1
  111. package/docs/usage/agents/model.mdx +5 -5
  112. package/docs/usage/agents/model.zh-CN.mdx +3 -5
  113. package/docs/usage/agents/prompt.mdx +4 -5
  114. package/docs/usage/agents/topics.mdx +3 -4
  115. package/docs/usage/agents/topics.zh-CN.mdx +1 -1
  116. package/docs/usage/features/agent-market.mdx +3 -11
  117. package/docs/usage/features/agent-market.zh-CN.mdx +2 -7
  118. package/docs/usage/features/artifacts.mdx +2 -2
  119. package/docs/usage/features/auth.mdx +2 -3
  120. package/docs/usage/features/cot.mdx +2 -2
  121. package/docs/usage/features/database.mdx +2 -2
  122. package/docs/usage/features/knowledge-base.mdx +4 -3
  123. package/docs/usage/features/knowledge-base.zh-CN.mdx +2 -1
  124. package/docs/usage/features/local-llm.mdx +2 -3
  125. package/docs/usage/features/mobile.mdx +2 -2
  126. package/docs/usage/features/more.mdx +2 -3
  127. package/docs/usage/features/multi-ai-providers.mdx +2 -3
  128. package/docs/usage/features/plugin-system.mdx +3 -11
  129. package/docs/usage/features/plugin-system.zh-CN.mdx +1 -8
  130. package/docs/usage/features/pwa.mdx +4 -4
  131. package/docs/usage/features/pwa.zh-CN.mdx +2 -1
  132. package/docs/usage/features/text-to-image.mdx +3 -11
  133. package/docs/usage/features/text-to-image.zh-CN.mdx +3 -10
  134. package/docs/usage/features/theme.mdx +2 -3
  135. package/docs/usage/features/tts.mdx +3 -11
  136. package/docs/usage/features/tts.zh-CN.mdx +1 -8
  137. package/docs/usage/features/vision.mdx +3 -11
  138. package/docs/usage/features/vision.zh-CN.mdx +1 -8
  139. package/docs/usage/foundation/basic.mdx +2 -3
  140. package/docs/usage/foundation/share.mdx +2 -3
  141. package/docs/usage/foundation/text2image.mdx +2 -2
  142. package/docs/usage/foundation/translate.mdx +2 -2
  143. package/docs/usage/foundation/tts-stt.mdx +2 -2
  144. package/docs/usage/foundation/vision.mdx +2 -3
  145. package/docs/usage/plugins/basic-usage.mdx +2 -3
  146. package/docs/usage/plugins/custom-plugin.mdx +2 -2
  147. package/docs/usage/plugins/development.mdx +2 -4
  148. package/docs/usage/plugins/store.mdx +2 -2
  149. package/docs/usage/providers/ai21.mdx +2 -2
  150. package/docs/usage/providers/anthropic.mdx +2 -3
  151. package/docs/usage/providers/anthropic.zh-CN.mdx +2 -2
  152. package/docs/usage/providers/azure.mdx +2 -3
  153. package/docs/usage/providers/azureai.mdx +4 -2
  154. package/docs/usage/providers/azureai.zh-CN.mdx +2 -1
  155. package/docs/usage/providers/baichuan.mdx +2 -3
  156. package/docs/usage/providers/bedrock.mdx +2 -3
  157. package/docs/usage/providers/cloudflare.mdx +3 -2
  158. package/docs/usage/providers/deepseek.mdx +2 -2
  159. package/docs/usage/providers/fireworksai.mdx +2 -2
  160. package/docs/usage/providers/giteeai.mdx +2 -2
  161. package/docs/usage/providers/github.mdx +1 -1
  162. package/docs/usage/providers/github.zh-CN.mdx +1 -1
  163. package/docs/usage/providers/google.mdx +2 -3
  164. package/docs/usage/providers/groq.mdx +2 -2
  165. package/docs/usage/providers/hunyuan.mdx +2 -2
  166. package/docs/usage/providers/infiniai.zh-CN.mdx +3 -1
  167. package/docs/usage/providers/internlm.mdx +2 -2
  168. package/docs/usage/providers/jina.mdx +4 -3
  169. package/docs/usage/providers/jina.zh-CN.mdx +2 -2
  170. package/docs/usage/providers/lmstudio.mdx +2 -2
  171. package/docs/usage/providers/lmstudio.zh-CN.mdx +2 -4
  172. package/docs/usage/providers/minimax.mdx +2 -3
  173. package/docs/usage/providers/minimax.zh-CN.mdx +2 -2
  174. package/docs/usage/providers/mistral.mdx +2 -3
  175. package/docs/usage/providers/modelscope.mdx +4 -0
  176. package/docs/usage/providers/modelscope.zh-CN.mdx +4 -0
  177. package/docs/usage/providers/moonshot.mdx +2 -3
  178. package/docs/usage/providers/novita.mdx +2 -3
  179. package/docs/usage/providers/novita.zh-CN.mdx +2 -2
  180. package/docs/usage/providers/nvidia.mdx +3 -2
  181. package/docs/usage/providers/ollama/gemma.mdx +2 -3
  182. package/docs/usage/providers/ollama/gemma.zh-CN.mdx +2 -2
  183. package/docs/usage/providers/ollama.mdx +2 -2
  184. package/docs/usage/providers/openai.mdx +5 -5
  185. package/docs/usage/providers/openai.zh-CN.mdx +3 -3
  186. package/docs/usage/providers/openrouter.mdx +2 -3
  187. package/docs/usage/providers/perplexity.mdx +2 -2
  188. package/docs/usage/providers/ppio.mdx +5 -6
  189. package/docs/usage/providers/ppio.zh-CN.mdx +6 -6
  190. package/docs/usage/providers/qiniu.mdx +6 -6
  191. package/docs/usage/providers/qiniu.zh-CN.mdx +2 -1
  192. package/docs/usage/providers/qwen.mdx +2 -4
  193. package/docs/usage/providers/sambanova.mdx +2 -1
  194. package/docs/usage/providers/sensenova.mdx +2 -2
  195. package/docs/usage/providers/siliconcloud.mdx +2 -2
  196. package/docs/usage/providers/stepfun.mdx +2 -3
  197. package/docs/usage/providers/taichu.mdx +2 -3
  198. package/docs/usage/providers/togetherai.mdx +2 -2
  199. package/docs/usage/providers/vllm.mdx +15 -12
  200. package/docs/usage/providers/vllm.zh-CN.mdx +9 -7
  201. package/docs/usage/providers/volcengine.mdx +16 -14
  202. package/docs/usage/providers/wenxin.mdx +2 -2
  203. package/docs/usage/providers/xai.mdx +2 -2
  204. package/docs/usage/providers/zeroone.mdx +2 -3
  205. package/docs/usage/providers/zeroone.zh-CN.mdx +2 -2
  206. package/docs/usage/providers/zhipu.mdx +2 -3
  207. package/docs/usage/providers/zhipu.zh-CN.mdx +1 -1
  208. package/docs/usage/providers.mdx +2 -3
  209. package/docs/usage/start.mdx +2 -3
  210. package/docs/usage/tools-calling/anthropic.mdx +2 -2
  211. package/docs/usage/tools-calling/anthropic.zh-CN.mdx +2 -2
  212. package/docs/usage/tools-calling/google.mdx +2 -2
  213. package/docs/usage/tools-calling/google.zh-CN.mdx +4 -4
  214. package/docs/usage/tools-calling/groq.zh-CN.mdx +2 -2
  215. package/docs/usage/tools-calling/openai.mdx +2 -2
  216. package/docs/usage/tools-calling/openai.zh-CN.mdx +2 -2
  217. package/package.json +2 -2
  218. package/src/app/(backend)/middleware/auth/utils.ts +2 -1
  219. package/src/app/(backend)/webapi/user/avatar/[id]/[image]/route.ts +1 -1
  220. package/src/app/[variants]/(main)/repos/[id]/_layout/Mobile.tsx +7 -7
  221. package/src/config/aiModels/deepseek.ts +1 -0
  222. package/src/config/aiModels/hunyuan.ts +1 -0
  223. package/src/config/aiModels/mistral.ts +1 -2
  224. package/src/config/aiModels/novita.ts +23 -22
  225. package/src/config/aiModels/openrouter.ts +1 -0
  226. package/src/config/aiModels/qwen.ts +11 -11
  227. package/src/config/aiModels/siliconcloud.ts +7 -6
  228. package/src/config/aiModels/vertexai.ts +2 -2
  229. package/src/config/aiModels/wenxin.ts +1 -2
  230. package/src/config/modelProviders/baichuan.ts +3 -0
  231. package/src/config/modelProviders/fireworksai.ts +3 -0
  232. package/src/config/modelProviders/giteeai.ts +3 -0
  233. package/src/config/modelProviders/github.ts +1 -2
  234. package/src/config/modelProviders/groq.ts +0 -3
  235. package/src/config/modelProviders/hunyuan.ts +3 -0
  236. package/src/config/modelProviders/infiniai.ts +0 -3
  237. package/src/config/modelProviders/internlm.ts +3 -0
  238. package/src/config/modelProviders/minimax.ts +3 -4
  239. package/src/config/modelProviders/moonshot.ts +0 -7
  240. package/src/config/modelProviders/novita.ts +3 -0
  241. package/src/config/modelProviders/openrouter.ts +0 -4
  242. package/src/config/modelProviders/perplexity.ts +0 -3
  243. package/src/config/modelProviders/qiniu.ts +0 -3
  244. package/src/config/modelProviders/qwen.ts +0 -3
  245. package/src/config/modelProviders/sensenova.ts +3 -0
  246. package/src/config/modelProviders/siliconcloud.ts +0 -3
  247. package/src/config/modelProviders/spark.ts +0 -5
  248. package/src/config/modelProviders/stepfun.ts +3 -6
  249. package/src/config/modelProviders/taichu.ts +3 -0
  250. package/src/config/modelProviders/tencentcloud.ts +3 -0
  251. package/src/config/modelProviders/togetherai.ts +3 -0
  252. package/src/config/modelProviders/upstage.ts +3 -0
  253. package/src/config/modelProviders/wenxin.ts +3 -4
  254. package/src/config/modelProviders/xai.ts +0 -3
  255. package/src/config/modelProviders/zhipu.ts +3 -0
  256. package/src/database/migrations/meta/0014_snapshot.json +182 -539
  257. package/src/database/migrations/meta/0016_snapshot.json +182 -539
  258. package/src/database/repositories/dataImporter/__tests__/fixtures/with-client-id.json +13 -58
  259. package/src/features/ChatInput/ActionBar/Model/ControlsForm.tsx +1 -8
  260. package/src/features/ChatInput/ActionBar/Model/index.tsx +8 -16
  261. package/src/features/ChatInput/ActionBar/Search/Controls.tsx +4 -12
  262. package/src/features/ChatInput/ActionBar/Search/FCSearchModel.tsx +1 -7
  263. package/src/features/ChatInput/ActionBar/Search/index.tsx +2 -4
  264. package/src/features/ModelSwitchPanel/index.tsx +1 -4
  265. package/src/libs/model-runtime/anthropic/index.test.ts +4 -2
  266. package/src/libs/model-runtime/google/index.ts +30 -40
  267. package/src/libs/model-runtime/novita/__snapshots__/index.test.ts.snap +19 -1
  268. package/src/libs/model-runtime/novita/index.ts +14 -15
  269. package/src/libs/model-runtime/nvidia/index.ts +2 -21
  270. package/src/libs/model-runtime/openai/__snapshots__/index.test.ts.snap +39 -11
  271. package/src/libs/model-runtime/openai/index.ts +3 -38
  272. package/src/libs/model-runtime/openrouter/__snapshots__/index.test.ts.snap +3 -0
  273. package/src/libs/model-runtime/openrouter/index.ts +45 -54
  274. package/src/libs/model-runtime/qwen/index.ts +2 -45
  275. package/src/libs/model-runtime/siliconcloud/index.ts +2 -51
  276. package/src/libs/model-runtime/utils/modelParse.test.ts +761 -0
  277. package/src/libs/model-runtime/utils/modelParse.ts +186 -0
  278. package/src/libs/model-runtime/utils/streams/anthropic.ts +12 -11
  279. package/src/libs/model-runtime/utils/streams/openai.ts +6 -4
  280. package/src/libs/model-runtime/utils/streams/protocol.ts +1 -1
  281. package/src/libs/model-runtime/utils/streams/spark.test.ts +1 -1
  282. package/src/libs/model-runtime/utils/streams/spark.ts +1 -2
  283. package/src/libs/model-runtime/volcengine/index.ts +11 -0
  284. package/src/libs/model-runtime/zeroone/index.ts +2 -23
  285. package/src/libs/model-runtime/zhipu/index.ts +7 -34
  286. package/src/middleware.ts +1 -1
  287. package/src/server/services/user/index.ts +3 -4
  288. package/src/services/__tests__/assistant.test.ts +4 -6
  289. package/src/services/__tests__/tool.test.ts +3 -1
  290. package/src/store/user/slices/auth/selectors.ts +1 -1
  291. package/src/store/user/slices/common/action.test.ts +1 -1
  292. package/src/tools/web-browsing/index.ts +1 -7
@@ -0,0 +1,186 @@
1
+ import type { ChatModelCard } from '@/types/llm';
2
+
3
+ export interface ModelProcessorConfig {
4
+ excludeKeywords?: readonly string[]; // 对符合的模型不添加标签
5
+ functionCallKeywords?: readonly string[];
6
+ reasoningKeywords?: readonly string[];
7
+ visionKeywords?: readonly string[];
8
+ }
9
+
10
+ // 模型标签关键词配置
11
+ export const MODEL_LIST_CONFIGS = {
12
+ anthropic: {
13
+ functionCallKeywords: ['claude'],
14
+ reasoningKeywords: ['-3-7', '3.7', '-4'],
15
+ visionKeywords: ['claude'],
16
+ },
17
+ deepseek: {
18
+ functionCallKeywords: ['v3', 'r1'],
19
+ reasoningKeywords: ['r1'],
20
+ },
21
+ google: {
22
+ functionCallKeywords: ['gemini'],
23
+ reasoningKeywords: ['thinking', '-2.5-'],
24
+ visionKeywords: ['gemini', 'learnlm'],
25
+ },
26
+ llama: {
27
+ functionCallKeywords: ['llama-3.2', 'llama-3.3', 'llama-4'],
28
+ reasoningKeywords: [],
29
+ visionKeywords: [],
30
+ },
31
+ openai: {
32
+ excludeKeywords: ['audio'],
33
+ functionCallKeywords: ['4o', '4.1', 'o3', 'o4'],
34
+ reasoningKeywords: ['o1', 'o3', 'o4'],
35
+ visionKeywords: ['4o', '4.1', 'o4'],
36
+ },
37
+ qwen: {
38
+ functionCallKeywords: [
39
+ 'qwen-max',
40
+ 'qwen-plus',
41
+ 'qwen-turbo',
42
+ 'qwen-long',
43
+ 'qwen1.5',
44
+ 'qwen2',
45
+ 'qwen2.5',
46
+ 'qwen3',
47
+ ],
48
+ reasoningKeywords: ['qvq', 'qwq', 'qwen3'],
49
+ visionKeywords: ['qvq', 'vl'],
50
+ },
51
+ volcengine: {
52
+ functionCallKeywords: ['doubao-1.5'],
53
+ reasoningKeywords: ['thinking', '-r1'],
54
+ visionKeywords: ['vision', '-m'],
55
+ },
56
+ zeroone: {
57
+ functionCallKeywords: ['fc'],
58
+ visionKeywords: ['vision'],
59
+ },
60
+ zhipu: {
61
+ functionCallKeywords: ['glm-4', 'glm-z1'],
62
+ reasoningKeywords: ['glm-zero', 'glm-z1'],
63
+ visionKeywords: ['glm-4v'],
64
+ },
65
+ } as const;
66
+
67
+ // 模型提供商关键词配置
68
+ export const PROVIDER_DETECTION_CONFIG = {
69
+ anthropic: ['claude'],
70
+ deepseek: ['deepseek'],
71
+ google: ['gemini'],
72
+ llama: ['llama'],
73
+ openai: ['o1', 'o3', 'o4', 'gpt-'],
74
+ qwen: ['qwen', 'qwq', 'qvq'],
75
+ volcengine: ['doubao'],
76
+ zeroone: ['yi-'],
77
+ zhipu: ['glm'],
78
+ } as const;
79
+
80
+ /**
81
+ * 检测单个模型的提供商类型
82
+ * @param modelId 模型ID
83
+ * @returns 检测到的提供商配置键名,默认为 'openai'
84
+ */
85
+ export const detectModelProvider = (modelId: string): keyof typeof MODEL_LIST_CONFIGS => {
86
+ const lowerModelId = modelId.toLowerCase();
87
+
88
+ for (const [provider, keywords] of Object.entries(PROVIDER_DETECTION_CONFIG)) {
89
+ const hasKeyword = keywords.some((keyword) => lowerModelId.includes(keyword));
90
+
91
+ if (hasKeyword && provider in MODEL_LIST_CONFIGS) {
92
+ return provider as keyof typeof MODEL_LIST_CONFIGS;
93
+ }
94
+ }
95
+
96
+ return 'openai';
97
+ };
98
+
99
+ /**
100
+ * 处理模型卡片的通用逻辑
101
+ */
102
+ const processModelCard = (
103
+ model: { [key: string]: any; id: string },
104
+ config: ModelProcessorConfig,
105
+ knownModel?: any,
106
+ ): ChatModelCard => {
107
+ const {
108
+ functionCallKeywords = [],
109
+ visionKeywords = [],
110
+ reasoningKeywords = [],
111
+ excludeKeywords = [],
112
+ } = config;
113
+
114
+ const isExcludedModel = excludeKeywords.some((keyword) =>
115
+ model.id.toLowerCase().includes(keyword),
116
+ );
117
+
118
+ return {
119
+ contextWindowTokens: model.contextWindowTokens ?? knownModel?.contextWindowTokens ?? undefined,
120
+ displayName: model.displayName ?? knownModel?.displayName ?? model.id,
121
+ enabled: knownModel?.enabled || false,
122
+ functionCall:
123
+ (functionCallKeywords.some((keyword) => model.id.toLowerCase().includes(keyword)) &&
124
+ !isExcludedModel) ||
125
+ knownModel?.abilities?.functionCall ||
126
+ false,
127
+ id: model.id,
128
+ maxOutput: model.maxOutput ?? knownModel?.maxOutput ?? undefined,
129
+ reasoning:
130
+ reasoningKeywords.some((keyword) => model.id.toLowerCase().includes(keyword)) ||
131
+ knownModel?.abilities?.reasoning ||
132
+ false,
133
+ vision:
134
+ (visionKeywords.some((keyword) => model.id.toLowerCase().includes(keyword)) &&
135
+ !isExcludedModel) ||
136
+ knownModel?.abilities?.vision ||
137
+ false,
138
+ };
139
+ };
140
+
141
+ /**
142
+ * 处理单一提供商的模型列表
143
+ * @param modelList 模型列表
144
+ * @param config 提供商配置
145
+ * @returns 处理后的模型卡片列表
146
+ */
147
+ export const processModelList = async (
148
+ modelList: Array<{ id: string }>,
149
+ config: ModelProcessorConfig,
150
+ ): Promise<ChatModelCard[]> => {
151
+ const { LOBE_DEFAULT_MODEL_LIST } = await import('@/config/aiModels');
152
+
153
+ return modelList
154
+ .map((model) => {
155
+ const knownModel = LOBE_DEFAULT_MODEL_LIST.find(
156
+ (m) => model.id.toLowerCase() === m.id.toLowerCase(),
157
+ );
158
+
159
+ return processModelCard(model, config, knownModel);
160
+ })
161
+ .filter(Boolean);
162
+ };
163
+
164
+ /**
165
+ * 处理混合提供商的模型列表
166
+ * @param modelList 模型列表
167
+ * @returns 处理后的模型卡片列表
168
+ */
169
+ export const processMultiProviderModelList = async (
170
+ modelList: Array<{ id: string }>,
171
+ ): Promise<ChatModelCard[]> => {
172
+ const { LOBE_DEFAULT_MODEL_LIST } = await import('@/config/aiModels');
173
+
174
+ return modelList
175
+ .map((model) => {
176
+ const detectedProvider = detectModelProvider(model.id);
177
+ const config = MODEL_LIST_CONFIGS[detectedProvider];
178
+
179
+ const knownModel = LOBE_DEFAULT_MODEL_LIST.find(
180
+ (m) => model.id.toLowerCase() === m.id.toLowerCase(),
181
+ );
182
+
183
+ return processModelCard(model, config, knownModel);
184
+ })
185
+ .filter(Boolean);
186
+ };
@@ -1,7 +1,7 @@
1
1
  import Anthropic from '@anthropic-ai/sdk';
2
2
  import type { Stream } from '@anthropic-ai/sdk/streaming';
3
3
 
4
- import { ModelTokensUsage, CitationItem } from '@/types/message';
4
+ import { CitationItem, ModelTokensUsage } from '@/types/message';
5
5
 
6
6
  import { ChatStreamCallbacks } from '../../types';
7
7
  import {
@@ -180,7 +180,7 @@ export const transformAnthropicStream = (
180
180
  context.returnedCitationArray.push({
181
181
  title: citations.title,
182
182
  url: citations.url,
183
- } as CitationItem)
183
+ } as CitationItem);
184
184
  }
185
185
 
186
186
  return { data: null, id: context.id, type: 'text' };
@@ -219,15 +219,16 @@ export const transformAnthropicStream = (
219
219
 
220
220
  case 'message_stop': {
221
221
  return [
222
- ...(context.returnedCitationArray?.length
223
- ? [{
224
- data: { citations: context.returnedCitationArray },
225
- id: context.id,
226
- type: 'grounding'
227
- }]
228
- : []
229
- ),
230
- { data: 'message_stop', id: context.id, type: 'stop' }
222
+ ...(context.returnedCitationArray?.length
223
+ ? [
224
+ {
225
+ data: { citations: context.returnedCitationArray },
226
+ id: context.id,
227
+ type: 'grounding',
228
+ },
229
+ ]
230
+ : []),
231
+ { data: 'message_stop', id: context.id, type: 'stop' },
231
232
  ] as any;
232
233
  }
233
234
 
@@ -227,10 +227,12 @@ export const transformOpenAIStream = (
227
227
  return [
228
228
  {
229
229
  data: {
230
- citations: (citations as any[]).map((item) => ({
231
- title: typeof item === 'string' ? item : item.title,
232
- url: typeof item === 'string' ? item : item.url || item.link,
233
- })).filter(c => c.title && c.url), // Zhipu 内建搜索工具有时会返回空 link 引发程序崩溃
230
+ citations: (citations as any[])
231
+ .map((item) => ({
232
+ title: typeof item === 'string' ? item : item.title,
233
+ url: typeof item === 'string' ? item : item.url || item.link,
234
+ }))
235
+ .filter((c) => c.title && c.url), // Zhipu 内建搜索工具有时会返回空 link 引发程序崩溃
234
236
  },
235
237
  id: chunk.id,
236
238
  type: 'grounding',
@@ -18,7 +18,7 @@ export interface StreamContext {
18
18
  returnedCitation?: boolean;
19
19
  /**
20
20
  * Claude's citations are inline and interleaved with text output.
21
- * Each text segment may carry references to sources (e.g., web search results)
21
+ * Each text segment may carry references to sources (e.g., web search results)
22
22
  * relevant to that specific portion of the generated content.
23
23
  * This array accumulates all citation items received during the streaming response.
24
24
  */
@@ -40,7 +40,7 @@ describe('SparkAIStream', () => {
40
40
  },
41
41
  ],
42
42
  },
43
- ]
43
+ ];
44
44
 
45
45
  const mockSparkStream = new ReadableStream({
46
46
  start(controller) {
@@ -2,6 +2,7 @@ import OpenAI from 'openai';
2
2
  import type { Stream } from 'openai/streaming';
3
3
 
4
4
  import { ChatStreamCallbacks } from '../../types';
5
+ import { convertUsage } from '../usageConverter';
5
6
  import {
6
7
  StreamProtocolChunk,
7
8
  StreamProtocolToolCallChunk,
@@ -11,8 +12,6 @@ import {
11
12
  generateToolCallId,
12
13
  } from './protocol';
13
14
 
14
- import { convertUsage } from '../usageConverter';
15
-
16
15
  export function transformSparkResponseToStream(data: OpenAI.ChatCompletion) {
17
16
  return new ReadableStream({
18
17
  start(controller) {
@@ -1,5 +1,10 @@
1
1
  import { ModelProvider } from '../types';
2
2
  import { createOpenAICompatibleRuntime } from '../utils/openaiCompatibleFactory';
3
+ import { MODEL_LIST_CONFIGS, processModelList } from '../utils/modelParse';
4
+
5
+ export interface VolcengineModelCard {
6
+ id: string;
7
+ }
3
8
 
4
9
  export const LobeVolcengineAI = createOpenAICompatibleRuntime({
5
10
  baseURL: 'https://ark.cn-beijing.volces.com/api/v3',
@@ -24,5 +29,11 @@ export const LobeVolcengineAI = createOpenAICompatibleRuntime({
24
29
  debug: {
25
30
  chatCompletion: () => process.env.DEBUG_VOLCENGINE_CHAT_COMPLETION === '1',
26
31
  },
32
+ models: async ({ client }) => {
33
+ const modelsPage = (await client.models.list()) as any;
34
+ const modelList: VolcengineModelCard[] = modelsPage.data;
35
+
36
+ return processModelList(modelList, MODEL_LIST_CONFIGS.volcengine);
37
+ },
27
38
  provider: ModelProvider.Volcengine,
28
39
  });
@@ -1,6 +1,5 @@
1
- import type { ChatModelCard } from '@/types/llm';
2
-
3
1
  import { ModelProvider } from '../types';
2
+ import { MODEL_LIST_CONFIGS, processModelList } from '../utils/modelParse';
4
3
  import { createOpenAICompatibleRuntime } from '../utils/openaiCompatibleFactory';
5
4
 
6
5
  export interface ZeroOneModelCard {
@@ -13,30 +12,10 @@ export const LobeZeroOneAI = createOpenAICompatibleRuntime({
13
12
  chatCompletion: () => process.env.DEBUG_ZEROONE_CHAT_COMPLETION === '1',
14
13
  },
15
14
  models: async ({ client }) => {
16
- const { LOBE_DEFAULT_MODEL_LIST } = await import('@/config/aiModels');
17
-
18
15
  const modelsPage = (await client.models.list()) as any;
19
16
  const modelList: ZeroOneModelCard[] = modelsPage.data;
20
17
 
21
- return modelList
22
- .map((model) => {
23
- const knownModel = LOBE_DEFAULT_MODEL_LIST.find(
24
- (m) => model.id.toLowerCase() === m.id.toLowerCase(),
25
- );
26
-
27
- return {
28
- contextWindowTokens: knownModel?.contextWindowTokens ?? undefined,
29
- displayName: knownModel?.displayName ?? undefined,
30
- enabled: knownModel?.enabled || false,
31
- functionCall:
32
- model.id.toLowerCase().includes('fc') || knownModel?.abilities?.functionCall || false,
33
- id: model.id,
34
- reasoning: knownModel?.abilities?.reasoning || false,
35
- vision:
36
- model.id.toLowerCase().includes('vision') || knownModel?.abilities?.vision || false,
37
- };
38
- })
39
- .filter(Boolean) as ChatModelCard[];
18
+ return processModelList(modelList, MODEL_LIST_CONFIGS.zeroone);
40
19
  },
41
20
  provider: ModelProvider.ZeroOne,
42
21
  });
@@ -1,6 +1,5 @@
1
- import type { ChatModelCard } from '@/types/llm';
2
-
3
1
  import { ModelProvider } from '../types';
2
+ import { MODEL_LIST_CONFIGS, processModelList } from '../utils/modelParse';
4
3
  import { createOpenAICompatibleRuntime } from '../utils/openaiCompatibleFactory';
5
4
 
6
5
  export interface ZhipuModelCard {
@@ -60,10 +59,6 @@ export const LobeZhipuAI = createOpenAICompatibleRuntime({
60
59
  chatCompletion: () => process.env.DEBUG_ZHIPU_CHAT_COMPLETION === '1',
61
60
  },
62
61
  models: async ({ client }) => {
63
- const { LOBE_DEFAULT_MODEL_LIST } = await import('@/config/aiModels');
64
-
65
- const reasoningKeywords = ['glm-zero', 'glm-z1'];
66
-
67
62
  // ref: https://open.bigmodel.cn/console/modelcenter/square
68
63
  const url = 'https://open.bigmodel.cn/api/fine-tuning/model_center/list?pageSize=100&pageNum=1';
69
64
  const response = await fetch(url, {
@@ -78,34 +73,12 @@ export const LobeZhipuAI = createOpenAICompatibleRuntime({
78
73
 
79
74
  const modelList: ZhipuModelCard[] = json.rows;
80
75
 
81
- return modelList
82
- .map((model) => {
83
- const knownModel = LOBE_DEFAULT_MODEL_LIST.find(
84
- (m) => model.modelCode.toLowerCase() === m.id.toLowerCase(),
85
- );
86
-
87
- return {
88
- contextWindowTokens: knownModel?.contextWindowTokens ?? undefined,
89
- description: model.description,
90
- displayName: model.modelName,
91
- enabled: knownModel?.enabled || false,
92
- functionCall:
93
- (model.modelCode.toLowerCase().includes('glm-4') &&
94
- !model.modelCode.toLowerCase().includes('glm-4v')) ||
95
- knownModel?.abilities?.functionCall ||
96
- false,
97
- id: model.modelCode,
98
- reasoning:
99
- reasoningKeywords.some((keyword) => model.modelCode.toLowerCase().includes(keyword)) ||
100
- knownModel?.abilities?.reasoning ||
101
- false,
102
- vision:
103
- model.modelCode.toLowerCase().includes('glm-4v') ||
104
- knownModel?.abilities?.vision ||
105
- false,
106
- };
107
- })
108
- .filter(Boolean) as ChatModelCard[];
76
+ const standardModelList = modelList.map((model) => ({
77
+ description: model.description,
78
+ displayName: model.modelName,
79
+ id: model.modelCode,
80
+ }));
81
+ return processModelList(standardModelList, MODEL_LIST_CONFIGS.zhipu);
109
82
  },
110
83
  provider: ModelProvider.ZhiPu,
111
84
  });
package/src/middleware.ts CHANGED
@@ -136,7 +136,7 @@ const defaultMiddleware = (request: NextRequest) => {
136
136
 
137
137
  const isPublicRoute = createRouteMatcher([
138
138
  '/api/auth(.*)',
139
- '/trpc/edge(.*)',
139
+ '/trpc(.*)',
140
140
  // next auth
141
141
  '/next-auth/(.*)',
142
142
  // clerk
@@ -100,16 +100,15 @@ export class UserService {
100
100
  const s3 = new S3();
101
101
  const s3FileUrl = `user/avatar/${id}/${image}`;
102
102
 
103
- try{
103
+ try {
104
104
  const file = await s3.getFileByteArray(s3FileUrl);
105
105
  if (!file) {
106
106
  return null;
107
107
  }
108
108
  const fileBuffer = Buffer.from(file);
109
109
  return fileBuffer;
110
- }
111
- catch (error) {
110
+ } catch (error) {
112
111
  pino.error('Failed to get user avatar:', error);
113
112
  }
114
- }
113
+ };
115
114
  }
@@ -36,7 +36,7 @@ describe('AssistantService', () => {
36
36
  // Arrange
37
37
  const fakeResponse = { agents: [{ name: 'TestAssisstant' }] };
38
38
  (globalHelpers.getCurrentLanguage as Mock).mockReturnValue('tt');
39
-
39
+
40
40
  (edgeClient.market.getAgentIndex.query as Mock).mockResolvedValue(fakeResponse);
41
41
 
42
42
  // Act
@@ -50,21 +50,19 @@ describe('AssistantService', () => {
50
50
  it('should handle fetch error', async () => {
51
51
  // Arrange
52
52
  (globalHelpers.getCurrentLanguage as Mock).mockReturnValue('en');
53
- (edgeClient.market.getAgentIndex.query as Mock).mockRejectedValue(
54
- new Error('Network error'),
55
- );
53
+ (edgeClient.market.getAgentIndex.query as Mock).mockRejectedValue(new Error('Network error'));
56
54
 
57
55
  // Act & Assert
58
56
  await expect(assistantService.getAssistantList()).rejects.toThrow('Network error');
59
57
  });
60
58
  });
61
-
59
+
62
60
  describe('getAssistantById', () => {
63
61
  it('should fetch and return the assistant by id', async () => {
64
62
  // Arrange
65
63
  const fakeResponse = { identifier: 'test-assisstant' };
66
64
  (globalHelpers.getCurrentLanguage as Mock).mockReturnValue('tt');
67
-
65
+
68
66
  (edgeClient.market.getAgent.query as Mock).mockResolvedValue(fakeResponse);
69
67
 
70
68
  // Act
@@ -49,7 +49,9 @@ describe('ToolService', () => {
49
49
  it('should handle fetch error', async () => {
50
50
  // Arrange
51
51
  (globalHelpers.getCurrentLanguage as Mock).mockReturnValue('en');
52
- (edgeClient.market.getPluginIndex.query as Mock).mockRejectedValue(new Error('Network error'));
52
+ (edgeClient.market.getPluginIndex.query as Mock).mockRejectedValue(
53
+ new Error('Network error'),
54
+ );
53
55
 
54
56
  // Act & Assert
55
57
  await expect(toolService.getToolList()).rejects.toThrow('Network error');
@@ -2,9 +2,9 @@ import { t } from 'i18next';
2
2
 
3
3
  import { enableAuth, enableClerk, enableNextAuth } from '@/const/auth';
4
4
  import { BRANDING_NAME } from '@/const/branding';
5
+ import { isDesktop } from '@/const/version';
5
6
  import { UserStore } from '@/store/user';
6
7
  import { LobeUser } from '@/types/user';
7
- import { isDesktop } from '@/const/version';
8
8
 
9
9
  const DEFAULT_USERNAME = BRANDING_NAME;
10
10
 
@@ -83,7 +83,7 @@ describe('createCommonSlice', () => {
83
83
  settings: {
84
84
  general: { fontSize: 14 },
85
85
  },
86
- email: 'test@example.com'
86
+ email: 'test@example.com',
87
87
  };
88
88
 
89
89
  vi.spyOn(userService, 'getUserState').mockResolvedValueOnce(mockUserState);
@@ -25,13 +25,7 @@ export const WebBrowsingManifest: BuiltinToolManifest = {
25
25
  searchCategories: {
26
26
  description: 'The search categories you can set:',
27
27
  items: {
28
- enum: [
29
- 'general',
30
- 'images',
31
- 'news',
32
- 'science',
33
- 'videos',
34
- ],
28
+ enum: ['general', 'images', 'news', 'science', 'videos'],
35
29
  type: 'string',
36
30
  },
37
31
  type: 'array',