@lobehub/chat 1.127.2 → 1.127.4

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 (232) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/changelog/v1.json +18 -0
  3. package/docker-compose/local/docker-compose.yml +83 -1
  4. package/docker-compose/local/grafana/.env.example +42 -0
  5. package/docker-compose/local/grafana/.env.zh-CN.example +42 -0
  6. package/docker-compose/local/grafana/docker-compose.yml +251 -0
  7. package/docker-compose/local/grafana/grafana/dashboards/.gitkeep +0 -0
  8. package/docker-compose/local/grafana/grafana/datasources/datasource-prometheus.yaml +15 -0
  9. package/docker-compose/local/grafana/grafana/datasources/datasource-tempo.yaml +16 -0
  10. package/docker-compose/local/grafana/otel-collector/collector-config.yaml +45 -0
  11. package/docker-compose/local/grafana/prometheus/prometheus.yml +11 -0
  12. package/docker-compose/local/grafana/tempo/tempo.yaml +58 -0
  13. package/docker-compose/production/grafana/.env.example +44 -0
  14. package/docker-compose/production/grafana/.env.zh-CN.example +42 -0
  15. package/docker-compose/production/grafana/docker-compose.yml +249 -0
  16. package/docker-compose/production/grafana/grafana/dashboards/.gitkeep +0 -0
  17. package/docker-compose/production/grafana/grafana/datasources/datasource-prometheus.yaml +15 -0
  18. package/docker-compose/production/grafana/grafana/datasources/datasource-tempo.yaml +20 -0
  19. package/docker-compose/production/grafana/otel-collector/collector-config.yaml +45 -0
  20. package/docker-compose/production/grafana/prometheus/prometheus.yml +11 -0
  21. package/docker-compose/production/grafana/tempo/tempo.yaml +58 -0
  22. package/docker-compose.development.yml +44 -0
  23. package/docs/self-hosting/advanced/observability/grafana.mdx +71 -0
  24. package/docs/self-hosting/advanced/observability/grafana.zh-CN.mdx +70 -0
  25. package/package.json +2 -2
  26. package/packages/model-runtime/package.json +2 -1
  27. package/packages/model-runtime/src/const/modelProvider.ts +65 -0
  28. package/packages/model-runtime/src/const/type.test.ts +9 -0
  29. package/packages/model-runtime/src/{BaseAI.ts → core/BaseAI.ts} +3 -4
  30. package/packages/model-runtime/src/{ModelRuntime.test.ts → core/ModelRuntime.test.ts} +3 -3
  31. package/packages/model-runtime/src/{ModelRuntime.ts → core/ModelRuntime.ts} +9 -8
  32. package/packages/model-runtime/src/core/RouterRuntime/baseRuntimeMap.ts +17 -0
  33. package/packages/model-runtime/src/{RouterRuntime → core/RouterRuntime}/createRuntime.ts +9 -7
  34. package/packages/model-runtime/src/{RouterRuntime → core/RouterRuntime}/index.ts +1 -0
  35. package/packages/model-runtime/src/{utils → core}/openaiCompatibleFactory/createImage.ts +3 -3
  36. package/packages/model-runtime/src/{utils → core}/openaiCompatibleFactory/index.test.ts +2 -2
  37. package/packages/model-runtime/src/{utils → core}/openaiCompatibleFactory/index.ts +9 -9
  38. package/packages/model-runtime/src/{utils → core}/streams/bedrock/claude.ts +1 -1
  39. package/packages/model-runtime/src/{utils → core}/streams/bedrock/llama.test.ts +1 -1
  40. package/packages/model-runtime/src/{utils → core}/streams/bedrock/llama.ts +1 -1
  41. package/packages/model-runtime/src/{utils → core}/streams/google-ai.test.ts +1 -1
  42. package/packages/model-runtime/src/{utils → core}/streams/google-ai.ts +1 -1
  43. package/packages/model-runtime/src/core/streams/model.test.ts +268 -0
  44. package/packages/model-runtime/src/{utils → core}/streams/ollama.test.ts +1 -1
  45. package/packages/model-runtime/src/{utils → core}/streams/ollama.ts +1 -1
  46. package/packages/model-runtime/src/{utils → core}/streams/openai/openai.test.ts +39 -6
  47. package/packages/model-runtime/src/{utils → core}/streams/openai/openai.ts +4 -3
  48. package/packages/model-runtime/src/{utils → core}/streams/openai/responsesStream.ts +1 -1
  49. package/packages/model-runtime/src/{utils → core}/streams/protocol.ts +2 -2
  50. package/packages/model-runtime/src/{utils → core}/streams/qwen.ts +1 -1
  51. package/packages/model-runtime/src/{utils → core}/streams/spark.ts +1 -1
  52. package/packages/model-runtime/src/core/streams/utils.test.ts +164 -0
  53. package/packages/model-runtime/src/{utils → core}/streams/vertex-ai.test.ts +1 -1
  54. package/packages/model-runtime/src/{utils → core}/streams/vertex-ai.ts +1 -1
  55. package/packages/model-runtime/src/index.ts +29 -27
  56. package/packages/model-runtime/src/providerTestUtils.ts +1 -1
  57. package/packages/model-runtime/src/{ai21 → providers/ai21}/index.test.ts +1 -1
  58. package/packages/model-runtime/src/{ai21 → providers/ai21}/index.ts +2 -2
  59. package/packages/model-runtime/src/{ai302 → providers/ai302}/index.ts +4 -4
  60. package/packages/model-runtime/src/{ai360 → providers/ai360}/index.test.ts +1 -1
  61. package/packages/model-runtime/src/{ai360 → providers/ai360}/index.ts +2 -2
  62. package/packages/model-runtime/src/{aihubmix → providers/aihubmix}/index.ts +5 -5
  63. package/packages/model-runtime/src/{akashchat → providers/akashchat}/index.test.ts +1 -1
  64. package/packages/model-runtime/src/{akashchat → providers/akashchat}/index.ts +5 -4
  65. package/packages/model-runtime/src/{anthropic → providers/anthropic}/index.test.ts +2 -2
  66. package/packages/model-runtime/src/{anthropic → providers/anthropic}/index.ts +10 -10
  67. package/packages/model-runtime/src/{azureOpenai → providers/azureOpenai}/index.test.ts +4 -4
  68. package/packages/model-runtime/src/{azureOpenai → providers/azureOpenai}/index.ts +11 -11
  69. package/packages/model-runtime/src/{azureai → providers/azureai}/index.ts +9 -9
  70. package/packages/model-runtime/src/{baichuan → providers/baichuan}/index.test.ts +1 -1
  71. package/packages/model-runtime/src/{baichuan → providers/baichuan}/index.ts +2 -2
  72. package/packages/model-runtime/src/{bedrock → providers/bedrock}/index.test.ts +1 -1
  73. package/packages/model-runtime/src/{bedrock → providers/bedrock}/index.ts +12 -12
  74. package/packages/model-runtime/src/{bfl → providers/bfl}/createImage.test.ts +25 -25
  75. package/packages/model-runtime/src/{bfl → providers/bfl}/createImage.ts +6 -6
  76. package/packages/model-runtime/src/{bfl → providers/bfl}/index.test.ts +1 -1
  77. package/packages/model-runtime/src/{bfl → providers/bfl}/index.ts +4 -4
  78. package/packages/model-runtime/src/{cloudflare → providers/cloudflare}/index.test.ts +1 -1
  79. package/packages/model-runtime/src/{cloudflare → providers/cloudflare}/index.ts +8 -8
  80. package/packages/model-runtime/src/{cohere → providers/cohere}/index.test.ts +1 -1
  81. package/packages/model-runtime/src/{cohere → providers/cohere}/index.ts +2 -2
  82. package/packages/model-runtime/src/providers/cometapi/index.test.ts +12 -0
  83. package/packages/model-runtime/src/{cometapi → providers/cometapi}/index.ts +3 -3
  84. package/packages/model-runtime/src/{deepseek → providers/deepseek}/index.test.ts +1 -1
  85. package/packages/model-runtime/src/{deepseek → providers/deepseek}/index.ts +3 -5
  86. package/packages/model-runtime/src/{fal → providers/fal}/index.test.ts +1 -1
  87. package/packages/model-runtime/src/{fal → providers/fal}/index.ts +4 -4
  88. package/packages/model-runtime/src/{fireworksai → providers/fireworksai}/index.test.ts +1 -1
  89. package/packages/model-runtime/src/{fireworksai → providers/fireworksai}/index.ts +2 -2
  90. package/packages/model-runtime/src/{giteeai → providers/giteeai}/index.test.ts +1 -1
  91. package/packages/model-runtime/src/{giteeai → providers/giteeai}/index.ts +3 -3
  92. package/packages/model-runtime/src/{github → providers/github}/index.test.ts +1 -1
  93. package/packages/model-runtime/src/{github → providers/github}/index.ts +5 -5
  94. package/packages/model-runtime/src/{google → providers/google}/createImage.test.ts +2 -2
  95. package/packages/model-runtime/src/{google → providers/google}/createImage.ts +5 -5
  96. package/packages/model-runtime/src/{google → providers/google}/index.test.ts +2 -2
  97. package/packages/model-runtime/src/{google → providers/google}/index.ts +13 -13
  98. package/packages/model-runtime/src/{groq → providers/groq}/index.test.ts +1 -1
  99. package/packages/model-runtime/src/{groq → providers/groq}/index.ts +3 -3
  100. package/packages/model-runtime/src/{higress → providers/higress}/index.ts +6 -5
  101. package/packages/model-runtime/src/{huggingface → providers/huggingface}/index.ts +4 -4
  102. package/packages/model-runtime/src/{hunyuan → providers/hunyuan}/index.test.ts +1 -1
  103. package/packages/model-runtime/src/{hunyuan → providers/hunyuan}/index.ts +2 -2
  104. package/packages/model-runtime/src/{infiniai → providers/infiniai}/index.ts +3 -3
  105. package/packages/model-runtime/src/{internlm → providers/internlm}/index.test.ts +1 -1
  106. package/packages/model-runtime/src/{internlm → providers/internlm}/index.ts +2 -2
  107. package/packages/model-runtime/src/{jina → providers/jina}/index.test.ts +1 -1
  108. package/packages/model-runtime/src/{jina → providers/jina}/index.ts +2 -2
  109. package/packages/model-runtime/src/{lmstudio → providers/lmstudio}/index.test.ts +1 -1
  110. package/packages/model-runtime/src/{lmstudio → providers/lmstudio}/index.ts +2 -2
  111. package/packages/model-runtime/src/{minimax → providers/minimax}/createImage.test.ts +2 -2
  112. package/packages/model-runtime/src/{minimax → providers/minimax}/createImage.ts +3 -3
  113. package/packages/model-runtime/src/{minimax → providers/minimax}/index.test.ts +1 -1
  114. package/packages/model-runtime/src/{minimax → providers/minimax}/index.ts +2 -2
  115. package/packages/model-runtime/src/{mistral → providers/mistral}/index.test.ts +1 -1
  116. package/packages/model-runtime/src/{mistral → providers/mistral}/index.ts +2 -2
  117. package/packages/model-runtime/src/{modelscope → providers/modelscope}/index.test.ts +1 -1
  118. package/packages/model-runtime/src/{modelscope → providers/modelscope}/index.ts +3 -3
  119. package/packages/model-runtime/src/{moonshot → providers/moonshot}/index.test.ts +1 -1
  120. package/packages/model-runtime/src/{moonshot → providers/moonshot}/index.ts +3 -3
  121. package/packages/model-runtime/src/{nebius → providers/nebius}/index.test.ts +1 -1
  122. package/packages/model-runtime/src/{nebius → providers/nebius}/index.ts +3 -3
  123. package/packages/model-runtime/src/{newapi → providers/newapi}/index.test.ts +4 -4
  124. package/packages/model-runtime/src/{newapi → providers/newapi}/index.ts +5 -5
  125. package/packages/model-runtime/src/{novita → providers/novita}/index.test.ts +1 -1
  126. package/packages/model-runtime/src/{novita → providers/novita}/index.ts +3 -3
  127. package/packages/model-runtime/src/{nvidia → providers/nvidia}/index.test.ts +1 -1
  128. package/packages/model-runtime/src/{nvidia → providers/nvidia}/index.ts +3 -3
  129. package/packages/model-runtime/src/{ollama → providers/ollama}/index.test.ts +3 -3
  130. package/packages/model-runtime/src/{ollama → providers/ollama}/index.ts +11 -10
  131. package/packages/model-runtime/src/{openai → providers/openai}/index.test.ts +1 -1
  132. package/packages/model-runtime/src/{openai → providers/openai}/index.ts +6 -5
  133. package/packages/model-runtime/src/{openrouter → providers/openrouter}/index.test.ts +1 -1
  134. package/packages/model-runtime/src/{openrouter → providers/openrouter}/index.ts +3 -3
  135. package/packages/model-runtime/src/{perplexity → providers/perplexity}/index.test.ts +1 -1
  136. package/packages/model-runtime/src/{perplexity → providers/perplexity}/index.ts +2 -2
  137. package/packages/model-runtime/src/{ppio → providers/ppio}/index.test.ts +1 -1
  138. package/packages/model-runtime/src/{ppio → providers/ppio}/index.ts +2 -2
  139. package/packages/model-runtime/src/{qiniu → providers/qiniu}/index.test.ts +2 -2
  140. package/packages/model-runtime/src/{qiniu → providers/qiniu}/index.ts +3 -3
  141. package/packages/model-runtime/src/{qwen → providers/qwen}/createImage.test.ts +2 -2
  142. package/packages/model-runtime/src/{qwen → providers/qwen}/createImage.ts +4 -4
  143. package/packages/model-runtime/src/{qwen → providers/qwen}/index.test.ts +1 -1
  144. package/packages/model-runtime/src/{qwen → providers/qwen}/index.ts +4 -4
  145. package/packages/model-runtime/src/{sambanova → providers/sambanova}/index.test.ts +1 -1
  146. package/packages/model-runtime/src/{sambanova → providers/sambanova}/index.ts +2 -2
  147. package/packages/model-runtime/src/{search1api → providers/search1api}/index.test.ts +1 -1
  148. package/packages/model-runtime/src/{search1api → providers/search1api}/index.ts +2 -2
  149. package/packages/model-runtime/src/{sensenova → providers/sensenova}/index.test.ts +1 -1
  150. package/packages/model-runtime/src/{sensenova → providers/sensenova}/index.ts +3 -3
  151. package/packages/model-runtime/src/{siliconcloud → providers/siliconcloud}/index.ts +4 -4
  152. package/packages/model-runtime/src/{spark → providers/spark}/index.test.ts +1 -1
  153. package/packages/model-runtime/src/{spark → providers/spark}/index.ts +3 -3
  154. package/packages/model-runtime/src/{stepfun → providers/stepfun}/index.test.ts +1 -1
  155. package/packages/model-runtime/src/{stepfun → providers/stepfun}/index.ts +2 -2
  156. package/packages/model-runtime/src/{taichu → providers/taichu}/index.test.ts +2 -2
  157. package/packages/model-runtime/src/{taichu → providers/taichu}/index.ts +2 -2
  158. package/packages/model-runtime/src/{tencentcloud → providers/tencentcloud}/index.test.ts +1 -1
  159. package/packages/model-runtime/src/{tencentcloud → providers/tencentcloud}/index.ts +2 -2
  160. package/packages/model-runtime/src/{togetherai → providers/togetherai}/index.test.ts +1 -1
  161. package/packages/model-runtime/src/{togetherai → providers/togetherai}/index.ts +2 -2
  162. package/packages/model-runtime/src/{upstage → providers/upstage}/index.test.ts +1 -1
  163. package/packages/model-runtime/src/{upstage → providers/upstage}/index.ts +2 -2
  164. package/packages/model-runtime/src/{v0 → providers/v0}/index.ts +3 -3
  165. package/packages/model-runtime/src/providers/vertexai/index.test.ts +54 -0
  166. package/packages/model-runtime/src/{vertexai → providers/vertexai}/index.ts +2 -2
  167. package/packages/model-runtime/src/providers/vllm/index.test.ts +12 -0
  168. package/packages/model-runtime/src/{vllm → providers/vllm}/index.ts +2 -2
  169. package/packages/model-runtime/src/{volcengine → providers/volcengine}/createImage.test.ts +2 -2
  170. package/packages/model-runtime/src/{volcengine → providers/volcengine}/createImage.ts +2 -2
  171. package/packages/model-runtime/src/{volcengine → providers/volcengine}/index.ts +3 -3
  172. package/packages/model-runtime/src/{wenxin → providers/wenxin}/index.test.ts +1 -1
  173. package/packages/model-runtime/src/{wenxin → providers/wenxin}/index.ts +2 -2
  174. package/packages/model-runtime/src/{xai → providers/xai}/index.test.ts +1 -1
  175. package/packages/model-runtime/src/{xai → providers/xai}/index.ts +3 -3
  176. package/packages/model-runtime/src/providers/xinference/index.test.ts +12 -0
  177. package/packages/model-runtime/src/{xinference → providers/xinference}/index.ts +2 -2
  178. package/packages/model-runtime/src/{zeroone → providers/zeroone}/index.test.ts +1 -1
  179. package/packages/model-runtime/src/{zeroone → providers/zeroone}/index.ts +3 -3
  180. package/packages/model-runtime/src/{zhipu → providers/zhipu}/index.test.ts +1 -1
  181. package/packages/model-runtime/src/{zhipu → providers/zhipu}/index.ts +5 -5
  182. package/packages/model-runtime/src/runtimeMap.ts +61 -61
  183. package/packages/model-runtime/src/types/index.ts +1 -0
  184. package/packages/model-runtime/src/types/type.ts +1 -65
  185. package/packages/model-runtime/src/utils/createError.test.ts +95 -0
  186. package/packages/model-runtime/src/utils/handleOpenAIError.test.ts +149 -0
  187. package/packages/model-runtime/src/utils/postProcessModelList.test.ts +190 -0
  188. package/packages/model-runtime/src/utils/response.test.ts +91 -0
  189. package/packages/types/src/fetch.ts +1 -1
  190. package/packages/types/src/message/base.ts +2 -3
  191. package/packages/types/src/user/settings/index.ts +1 -2
  192. package/packages/types/src/user/settings/keyVaults.ts +1 -0
  193. package/packages/types/src/user/settings/modelProvider.ts +4 -3
  194. package/src/app/[variants]/(main)/settings/llm/ProviderList/HuggingFace/index.tsx +1 -1
  195. package/src/server/modules/ModelRuntime/index.test.ts +2 -4
  196. package/src/services/__tests__/chat.test.ts +13 -8
  197. package/src/store/user/slices/settings/initialState.ts +2 -3
  198. package/tsconfig.json +0 -2
  199. package/vitest.config.mts +0 -1
  200. package/packages/model-runtime/src/RouterRuntime/baseRuntimeMap.ts +0 -17
  201. /package/packages/model-runtime/src/{RouterRuntime → core/RouterRuntime}/createRuntime.test.ts +0 -0
  202. /package/packages/model-runtime/src/{utils → core}/streams/__snapshots__/protocol.test.ts.snap +0 -0
  203. /package/packages/model-runtime/src/{utils → core}/streams/anthropic.test.ts +0 -0
  204. /package/packages/model-runtime/src/{utils → core}/streams/anthropic.ts +0 -0
  205. /package/packages/model-runtime/src/{utils → core}/streams/bedrock/common.ts +0 -0
  206. /package/packages/model-runtime/src/{utils → core}/streams/bedrock/index.ts +0 -0
  207. /package/packages/model-runtime/src/{utils → core}/streams/index.ts +0 -0
  208. /package/packages/model-runtime/src/{utils → core}/streams/model.ts +0 -0
  209. /package/packages/model-runtime/src/{utils → core}/streams/openai/__snapshots__/responsesStream.test.ts.snap +0 -0
  210. /package/packages/model-runtime/src/{utils → core}/streams/openai/index.ts +0 -0
  211. /package/packages/model-runtime/src/{utils → core}/streams/openai/responsesStream.test.ts +0 -0
  212. /package/packages/model-runtime/src/{utils → core}/streams/protocol.test.ts +0 -0
  213. /package/packages/model-runtime/src/{utils → core}/streams/qwen.test.ts +0 -0
  214. /package/packages/model-runtime/src/{utils → core}/streams/spark.test.ts +0 -0
  215. /package/packages/model-runtime/src/{utils → core}/streams/utils.ts +0 -0
  216. /package/packages/model-runtime/src/{anthropic → providers/anthropic}/handleAnthropicError.ts +0 -0
  217. /package/packages/model-runtime/src/{bfl → providers/bfl}/types.ts +0 -0
  218. /package/packages/model-runtime/src/{huggingface → providers/huggingface}/index.test.ts +0 -0
  219. /package/packages/model-runtime/src/{novita → providers/novita}/__snapshots__/index.test.ts.snap +0 -0
  220. /package/packages/model-runtime/src/{novita → providers/novita}/fixtures/models.json +0 -0
  221. /package/packages/model-runtime/src/{novita → providers/novita}/type.ts +0 -0
  222. /package/packages/model-runtime/src/{ollama → providers/ollama}/type.ts +0 -0
  223. /package/packages/model-runtime/src/{openai → providers/openai}/__snapshots__/index.test.ts.snap +0 -0
  224. /package/packages/model-runtime/src/{openai → providers/openai}/fixtures/openai-models.json +0 -0
  225. /package/packages/model-runtime/src/{openrouter → providers/openrouter}/fixtures/frontendModels.json +0 -0
  226. /package/packages/model-runtime/src/{openrouter → providers/openrouter}/fixtures/models.json +0 -0
  227. /package/packages/model-runtime/src/{openrouter → providers/openrouter}/type.ts +0 -0
  228. /package/packages/model-runtime/src/{ppio → providers/ppio}/__snapshots__/index.test.ts.snap +0 -0
  229. /package/packages/model-runtime/src/{ppio → providers/ppio}/fixtures/models.json +0 -0
  230. /package/packages/model-runtime/src/{ppio → providers/ppio}/type.ts +0 -0
  231. /package/packages/model-runtime/src/{togetherai → providers/togetherai}/fixtures/models.json +0 -0
  232. /package/packages/model-runtime/src/{togetherai → providers/togetherai}/type.ts +0 -0
@@ -0,0 +1,190 @@
1
+ import type { AiModelType } from 'model-bank';
2
+ import { describe, expect, it, vi } from 'vitest';
3
+
4
+ import type { ChatModelCard } from '@/types/llm';
5
+
6
+ import { IMAGE_GENERATION_MODEL_WHITELIST, postProcessModelList } from './postProcessModelList';
7
+
8
+ // Mock model-bank
9
+ vi.mock('model-bank', () => ({
10
+ CHAT_MODEL_IMAGE_GENERATION_PARAMS: {
11
+ max_tokens: 1000,
12
+ temperature: 0.7,
13
+ },
14
+ }));
15
+
16
+ describe('IMAGE_GENERATION_MODEL_WHITELIST', () => {
17
+ it('should contain expected whitelisted models', () => {
18
+ expect(IMAGE_GENERATION_MODEL_WHITELIST).toContain('gemini-2.5-flash-image-preview');
19
+ expect(IMAGE_GENERATION_MODEL_WHITELIST).toContain('gemini-2.5-flash-image-preview:free');
20
+ });
21
+ });
22
+
23
+ describe('postProcessModelList', () => {
24
+ const mockModels: ChatModelCard[] = [
25
+ {
26
+ id: 'gpt-3.5-turbo',
27
+ displayName: 'GPT-3.5 Turbo',
28
+ enabled: true,
29
+ },
30
+ {
31
+ id: 'gemini-2.5-flash-image-preview',
32
+ displayName: 'Gemini 2.5 Flash Image Preview',
33
+ enabled: true,
34
+ },
35
+ {
36
+ id: 'claude-3-opus',
37
+ displayName: 'Claude 3 Opus',
38
+ enabled: true,
39
+ type: 'chat' as AiModelType,
40
+ },
41
+ ];
42
+
43
+ it('should ensure all models have type field with default "chat"', async () => {
44
+ const result = await postProcessModelList(mockModels);
45
+
46
+ expect(result.length).toBeGreaterThanOrEqual(mockModels.length);
47
+ // Filter out generated image models for this test
48
+ const originalModels = result.filter((model) => !model.id.endsWith(':image'));
49
+ originalModels.forEach((model) => {
50
+ expect(model.type).toBeDefined();
51
+ if (!mockModels.find((m) => m.id === model.id)?.type) {
52
+ expect(model.type).toBe('chat');
53
+ }
54
+ });
55
+ });
56
+
57
+ it('should preserve existing type field', async () => {
58
+ const result = await postProcessModelList(mockModels);
59
+ const claudeModel = result.find((m) => m.id === 'claude-3-opus');
60
+
61
+ expect(claudeModel?.type).toBe('chat');
62
+ });
63
+
64
+ it('should use getModelTypeProperty when type is missing', async () => {
65
+ const modelsWithoutType: ChatModelCard[] = [
66
+ {
67
+ id: 'custom-model',
68
+ displayName: 'Custom Model',
69
+ enabled: true,
70
+ },
71
+ ];
72
+
73
+ const getModelTypeProperty = vi.fn().mockResolvedValue('embedding' as AiModelType);
74
+ const result = await postProcessModelList(modelsWithoutType, getModelTypeProperty);
75
+
76
+ expect(getModelTypeProperty).toHaveBeenCalledWith('custom-model');
77
+ expect(result[0].type).toBe('embedding');
78
+ });
79
+
80
+ it('should generate image models for whitelisted models', async () => {
81
+ const result = await postProcessModelList(mockModels);
82
+ const imageModel = result.find((m) => m.id === 'gemini-2.5-flash-image-preview:image');
83
+
84
+ expect(imageModel).toBeDefined();
85
+ expect(imageModel?.type).toBe('image');
86
+ expect(imageModel?.displayName).toBe('Gemini 2.5 Flash Image Preview');
87
+ expect(imageModel?.enabled).toBe(true);
88
+ expect(imageModel?.parameters).toEqual({
89
+ max_tokens: 1000,
90
+ temperature: 0.7,
91
+ });
92
+ });
93
+
94
+ it('should handle models that partially match whitelist patterns', async () => {
95
+ const modelsWithPartialMatch: ChatModelCard[] = [
96
+ {
97
+ id: 'custom-gemini-2.5-flash-image-preview',
98
+ displayName: 'Custom Gemini',
99
+ enabled: true,
100
+ },
101
+ {
102
+ id: 'gemini-2.5-flash-image-preview-custom',
103
+ displayName: 'Gemini Custom',
104
+ enabled: false,
105
+ },
106
+ ];
107
+
108
+ const result = await postProcessModelList(modelsWithPartialMatch);
109
+
110
+ // Should generate image model for the one that ends with whitelist pattern
111
+ const imageModel = result.find((m) => m.id === 'custom-gemini-2.5-flash-image-preview:image');
112
+ expect(imageModel).toBeDefined();
113
+ expect(imageModel?.enabled).toBe(true);
114
+
115
+ // Should not generate for the one that doesn't end with whitelist pattern
116
+ const noImageModel = result.find((m) => m.id === 'gemini-2.5-flash-image-preview-custom:image');
117
+ expect(noImageModel).toBeUndefined();
118
+ });
119
+
120
+ it('should handle empty model list', async () => {
121
+ const result = await postProcessModelList([]);
122
+ expect(result).toEqual([]);
123
+ });
124
+
125
+ it('should handle multiple whitelisted models', async () => {
126
+ const multipleWhitelistedModels: ChatModelCard[] = [
127
+ {
128
+ id: 'test-gemini-2.5-flash-image-preview',
129
+ displayName: 'Test Gemini',
130
+ enabled: true,
131
+ },
132
+ {
133
+ id: 'another-gemini-2.5-flash-image-preview:free',
134
+ displayName: 'Another Gemini Free',
135
+ enabled: false,
136
+ },
137
+ ];
138
+
139
+ const result = await postProcessModelList(multipleWhitelistedModels);
140
+
141
+ // Should have original models plus image versions
142
+ expect(result).toHaveLength(4);
143
+
144
+ const imageModel1 = result.find((m) => m.id === 'test-gemini-2.5-flash-image-preview:image');
145
+ const imageModel2 = result.find(
146
+ (m) => m.id === 'another-gemini-2.5-flash-image-preview:free:image',
147
+ );
148
+
149
+ expect(imageModel1).toBeDefined();
150
+ expect(imageModel2).toBeDefined();
151
+ expect(imageModel1?.type).toBe('image');
152
+ expect(imageModel2?.type).toBe('image');
153
+ });
154
+
155
+ it('should preserve all original model properties in image versions', async () => {
156
+ const modelWithManyProps: ChatModelCard[] = [
157
+ {
158
+ id: 'gemini-2.5-flash-image-preview',
159
+ displayName: 'Gemini Flash',
160
+ enabled: true,
161
+ contextWindowTokens: 4096,
162
+ description: 'A flash model',
163
+ functionCall: true,
164
+ vision: true,
165
+ reasoning: false,
166
+ maxOutput: 2048,
167
+ },
168
+ ];
169
+
170
+ const result = await postProcessModelList(modelWithManyProps);
171
+ const imageModel = result.find((m) => m.id === 'gemini-2.5-flash-image-preview:image');
172
+
173
+ expect(imageModel).toMatchObject({
174
+ id: 'gemini-2.5-flash-image-preview:image',
175
+ displayName: 'Gemini Flash',
176
+ enabled: true,
177
+ contextWindowTokens: 4096,
178
+ description: 'A flash model',
179
+ functionCall: true,
180
+ vision: true,
181
+ reasoning: false,
182
+ maxOutput: 2048,
183
+ type: 'image',
184
+ parameters: {
185
+ max_tokens: 1000,
186
+ temperature: 0.7,
187
+ },
188
+ });
189
+ });
190
+ });
@@ -0,0 +1,91 @@
1
+ import { describe, expect, it } from 'vitest';
2
+
3
+ import { StreamingResponse } from './response';
4
+
5
+ describe('StreamingResponse', () => {
6
+ it('should create Response with default headers', () => {
7
+ const mockStream = new ReadableStream();
8
+ const response = StreamingResponse(mockStream);
9
+
10
+ expect(response).toBeInstanceOf(Response);
11
+ expect(response.body).toBe(mockStream);
12
+ expect(response.headers.get('Cache-Control')).toBe('no-cache');
13
+ expect(response.headers.get('Content-Type')).toBe('text/event-stream');
14
+ expect(response.headers.get('X-Accel-Buffering')).toBe('no');
15
+ });
16
+
17
+ it('should create Response with custom headers', () => {
18
+ const mockStream = new ReadableStream();
19
+ const customHeaders = {
20
+ 'Custom-Header': 'custom-value',
21
+ 'Authorization': 'Bearer token',
22
+ };
23
+
24
+ const response = StreamingResponse(mockStream, { headers: customHeaders });
25
+
26
+ expect(response).toBeInstanceOf(Response);
27
+ expect(response.body).toBe(mockStream);
28
+
29
+ // Default headers should still be present
30
+ expect(response.headers.get('Cache-Control')).toBe('no-cache');
31
+ expect(response.headers.get('Content-Type')).toBe('text/event-stream');
32
+ expect(response.headers.get('X-Accel-Buffering')).toBe('no');
33
+
34
+ // Custom headers should be added
35
+ expect(response.headers.get('Custom-Header')).toBe('custom-value');
36
+ expect(response.headers.get('Authorization')).toBe('Bearer token');
37
+ });
38
+
39
+ it('should allow custom headers to override default headers', () => {
40
+ const mockStream = new ReadableStream();
41
+ const overrideHeaders = {
42
+ 'Content-Type': 'application/json',
43
+ 'Cache-Control': 'max-age=3600',
44
+ };
45
+
46
+ const response = StreamingResponse(mockStream, { headers: overrideHeaders });
47
+
48
+ expect(response.headers.get('Content-Type')).toBe('application/json');
49
+ expect(response.headers.get('Cache-Control')).toBe('max-age=3600');
50
+ expect(response.headers.get('X-Accel-Buffering')).toBe('no');
51
+ });
52
+
53
+ it('should handle empty options object', () => {
54
+ const mockStream = new ReadableStream();
55
+ const response = StreamingResponse(mockStream, {});
56
+
57
+ expect(response).toBeInstanceOf(Response);
58
+ expect(response.body).toBe(mockStream);
59
+ expect(response.headers.get('Cache-Control')).toBe('no-cache');
60
+ expect(response.headers.get('Content-Type')).toBe('text/event-stream');
61
+ expect(response.headers.get('X-Accel-Buffering')).toBe('no');
62
+ });
63
+
64
+ it('should handle options with empty headers', () => {
65
+ const mockStream = new ReadableStream();
66
+ const response = StreamingResponse(mockStream, { headers: {} });
67
+
68
+ expect(response).toBeInstanceOf(Response);
69
+ expect(response.body).toBe(mockStream);
70
+ expect(response.headers.get('Cache-Control')).toBe('no-cache');
71
+ expect(response.headers.get('Content-Type')).toBe('text/event-stream');
72
+ expect(response.headers.get('X-Accel-Buffering')).toBe('no');
73
+ });
74
+
75
+ it('should work with actual ReadableStream data', async () => {
76
+ const testData = 'data: {"test": "value"}\n\n';
77
+ const encoder = new TextEncoder();
78
+
79
+ const stream = new ReadableStream({
80
+ start(controller) {
81
+ controller.enqueue(encoder.encode(testData));
82
+ controller.close();
83
+ },
84
+ });
85
+
86
+ const response = StreamingResponse(stream);
87
+ const responseText = await response.text();
88
+
89
+ expect(responseText).toBe(testData);
90
+ });
91
+ });
@@ -1,5 +1,5 @@
1
1
  /* eslint-disable sort-keys-fix/sort-keys-fix */
2
- import { ILobeAgentRuntimeErrorType } from '@/libs/model-runtime';
2
+ import type { ILobeAgentRuntimeErrorType } from '@lobechat/model-runtime';
3
3
 
4
4
  export const ChatErrorType = {
5
5
  // ******* 业务错误语义 ******* //
@@ -1,6 +1,5 @@
1
- import { IPluginErrorType } from '@lobehub/chat-plugin-sdk';
2
-
3
- import { ILobeAgentRuntimeErrorType } from '@/libs/model-runtime';
1
+ import type { ILobeAgentRuntimeErrorType } from '@lobechat/model-runtime';
2
+ import type { IPluginErrorType } from '@lobehub/chat-plugin-sdk';
4
3
 
5
4
  import { ErrorType } from '../fetch';
6
5
  import { GroundingSearch } from '../search';
@@ -1,5 +1,4 @@
1
- import type { LobeAgentSettings } from '@/types/session';
2
-
1
+ import type { LobeAgentSettings } from '../../session';
3
2
  import { UserGeneralConfig } from './general';
4
3
  import { UserHotkeyConfig } from './hotkey';
5
4
  import { UserKeyVaults } from './keyVaults';
@@ -47,6 +47,7 @@ export interface UserKeyVaults extends SearchEngineKeyVaults {
47
47
  azureai?: AzureOpenAIKeyVault;
48
48
  baichuan?: OpenAICompatibleKeyVault;
49
49
  bedrock?: AWSBedrockKeyVault;
50
+ bfl?: any;
50
51
  cloudflare?: CloudflareKeyVault;
51
52
  cohere?: OpenAICompatibleKeyVault;
52
53
  cometapi?: OpenAICompatibleKeyVault;
@@ -1,6 +1,7 @@
1
- import { ModelProviderKey } from '@/libs/model-runtime';
2
- import { AiFullModelCard } from '../../../../model-bank/src/types/aiModel';
3
- import { ChatModelCard } from '@/types/llm';
1
+ import type { ModelProviderKey } from '@lobechat/model-runtime';
2
+ import { AiFullModelCard } from 'model-bank';
3
+
4
+ import { ChatModelCard } from '../../llm';
4
5
 
5
6
  export interface ProviderConfig {
6
7
  /**
@@ -1,11 +1,11 @@
1
1
  'use client';
2
2
 
3
+ import { GlobalLLMProviderKey } from '@lobechat/types';
3
4
  import { InputPassword, Markdown } from '@lobehub/ui';
4
5
  import { createStyles } from 'antd-style';
5
6
  import { useTranslation } from 'react-i18next';
6
7
 
7
8
  import { HuggingFaceProviderCard } from '@/config/modelProviders';
8
- import { GlobalLLMProviderKey } from '@/types/user/settings';
9
9
 
10
10
  import { KeyVaultsConfigKey, LLMProviderApiTokenKey } from '../../const';
11
11
  import { ProviderItem } from '../../type';
@@ -14,18 +14,16 @@ import {
14
14
  LobeOpenRouterAI,
15
15
  LobePerplexityAI,
16
16
  LobeQwenAI,
17
- LobeRuntimeAI,
17
+ LobeStepfunAI,
18
18
  LobeTogetherAI,
19
19
  LobeZeroOneAI,
20
20
  LobeZhipuAI,
21
21
  ModelProvider,
22
+ ModelRuntime,
22
23
  } from '@lobechat/model-runtime';
23
- import { ModelRuntime } from '@lobechat/model-runtime';
24
24
  import { ClientSecretPayload } from '@lobechat/types';
25
25
  import { describe, expect, it, vi } from 'vitest';
26
26
 
27
- import { LobeStepfunAI } from '@/libs/model-runtime/stepfun';
28
-
29
27
  import { initModelRuntimeWithUserPayload } from './index';
30
28
 
31
29
  // 模拟依赖项
@@ -17,8 +17,8 @@ import {
17
17
  LobeZeroOneAI,
18
18
  LobeZhipuAI,
19
19
  ModelProvider,
20
+ ModelRuntime,
20
21
  } from '@lobechat/model-runtime';
21
- import { ModelRuntime } from '@lobechat/model-runtime';
22
22
  import { ChatErrorType } from '@lobechat/types';
23
23
  import { LobeChatPluginManifest } from '@lobehub/chat-plugin-sdk';
24
24
  import { act } from '@testing-library/react';
@@ -67,9 +67,14 @@ vi.mock('@/utils/imageToBase64', () => ({
67
67
  imageUrlToBase64: vi.fn(),
68
68
  }));
69
69
 
70
- vi.mock('@/libs/model-runtime/utils/uriParser', () => ({
71
- parseDataUri: vi.fn(),
72
- }));
70
+ vi.mock('@lobechat/model-runtime', async (importOriginal) => {
71
+ const actual = await importOriginal();
72
+
73
+ return {
74
+ ...(actual as any),
75
+ parseDataUri: vi.fn(),
76
+ };
77
+ });
73
78
 
74
79
  afterEach(() => {
75
80
  vi.restoreAllMocks();
@@ -92,7 +97,7 @@ beforeEach(async () => {
92
97
  // Set default mock return values for image processing utilities
93
98
  const { isLocalUrl } = await import('@/utils/url');
94
99
  const { imageUrlToBase64 } = await import('@/utils/imageToBase64');
95
- const { parseDataUri } = await import('@/libs/model-runtime/utils/uriParser');
100
+ const { parseDataUri } = await import('@lobechat/model-runtime');
96
101
 
97
102
  vi.mocked(parseDataUri).mockReturnValue({ type: 'url', base64: null, mimeType: null });
98
103
  vi.mocked(isLocalUrl).mockReturnValue(false);
@@ -404,7 +409,7 @@ describe('ChatService', () => {
404
409
  it('should convert local image URLs to base64 and call processImageList', async () => {
405
410
  const { isLocalUrl } = await import('@/utils/url');
406
411
  const { imageUrlToBase64 } = await import('@/utils/imageToBase64');
407
- const { parseDataUri } = await import('@/libs/model-runtime/utils/uriParser');
412
+ const { parseDataUri } = await import('@lobechat/model-runtime');
408
413
 
409
414
  // Mock for local URL
410
415
  vi.mocked(parseDataUri).mockReturnValue({ type: 'url', base64: null, mimeType: null });
@@ -490,7 +495,7 @@ describe('ChatService', () => {
490
495
  it('should not convert remote URLs to base64 and call processImageList', async () => {
491
496
  const { isLocalUrl } = await import('@/utils/url');
492
497
  const { imageUrlToBase64 } = await import('@/utils/imageToBase64');
493
- const { parseDataUri } = await import('@/libs/model-runtime/utils/uriParser');
498
+ const { parseDataUri } = await import('@lobechat/model-runtime');
494
499
 
495
500
  // Mock for remote URL
496
501
  vi.mocked(parseDataUri).mockReturnValue({ type: 'url', base64: null, mimeType: null });
@@ -570,7 +575,7 @@ describe('ChatService', () => {
570
575
  it('should handle mixed local and remote URLs correctly', async () => {
571
576
  const { isLocalUrl } = await import('@/utils/url');
572
577
  const { imageUrlToBase64 } = await import('@/utils/imageToBase64');
573
- const { parseDataUri } = await import('@/libs/model-runtime/utils/uriParser');
578
+ const { parseDataUri } = await import('@lobechat/model-runtime');
574
579
 
575
580
  // Mock parseDataUri to always return url type
576
581
  vi.mocked(parseDataUri).mockReturnValue({ type: 'url', base64: null, mimeType: null });
@@ -1,8 +1,7 @@
1
+ import { DEFAULT_SETTINGS } from '@lobechat/const';
2
+ import { UserSettings } from '@lobechat/types';
1
3
  import type { PartialDeep } from 'type-fest';
2
4
 
3
- import { DEFAULT_SETTINGS } from '@/const/settings';
4
- import { UserSettings } from '@/types/user/settings';
5
-
6
5
  export interface UserSettingsState {
7
6
  defaultSettings: UserSettings;
8
7
  settings: PartialDeep<UserSettings>;
package/tsconfig.json CHANGED
@@ -18,8 +18,6 @@
18
18
  "baseUrl": ".",
19
19
  "types": ["vitest/globals", "@serwist/next/typings"],
20
20
  "paths": {
21
- "@/libs/model-runtime": ["./packages/model-runtime/src/index.ts"],
22
- "@/libs/model-runtime/*": ["./packages/model-runtime/src/*"],
23
21
  "@/database/*": ["./packages/database/src/*", "./src/database/*"],
24
22
  "@/const/*": ["./packages/const/src/*", "./src/const/*"],
25
23
  "@/utils/*": ["./packages/utils/src/*", "./src/utils/*"],
package/vitest.config.mts CHANGED
@@ -9,7 +9,6 @@ export default defineConfig({
9
9
  test: {
10
10
  alias: {
11
11
  /* eslint-disable sort-keys-fix/sort-keys-fix */
12
- '@/libs/model-runtime': resolve(__dirname, './packages/model-runtime/src'),
13
12
  '@/database/_deprecated': resolve(__dirname, './src/database/_deprecated'),
14
13
  '@/database': resolve(__dirname, './packages/database/src'),
15
14
  '@/utils/client/switchLang': resolve(__dirname, './src/utils/client/switchLang'),
@@ -1,17 +0,0 @@
1
- import { LobeAnthropicAI } from '../anthropic';
2
- import { LobeAzureAI } from '../azureai';
3
- import { LobeCloudflareAI } from '../cloudflare';
4
- import { LobeFalAI } from '../fal';
5
- import { LobeGoogleAI } from '../google';
6
- import { LobeOpenAI } from '../openai';
7
- import { LobeXAI } from '../xai';
8
-
9
- export const baseRuntimeMap = {
10
- anthropic: LobeAnthropicAI,
11
- azure: LobeAzureAI,
12
- cloudflare: LobeCloudflareAI,
13
- fal: LobeFalAI,
14
- google: LobeGoogleAI,
15
- openai: LobeOpenAI,
16
- xai: LobeXAI,
17
- };