@lobehub/chat 1.119.2 → 1.120.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/.vscode/settings.json +2 -3
  2. package/CHANGELOG.md +58 -0
  3. package/changelog/v1.json +21 -0
  4. package/locales/ar/models.json +24 -3
  5. package/locales/bg-BG/models.json +24 -3
  6. package/locales/de-DE/models.json +24 -3
  7. package/locales/en-US/models.json +24 -3
  8. package/locales/es-ES/models.json +24 -3
  9. package/locales/fa-IR/models.json +24 -3
  10. package/locales/fr-FR/models.json +24 -3
  11. package/locales/it-IT/models.json +24 -3
  12. package/locales/ja-JP/models.json +24 -3
  13. package/locales/ko-KR/models.json +24 -3
  14. package/locales/nl-NL/models.json +24 -3
  15. package/locales/pl-PL/models.json +24 -3
  16. package/locales/pt-BR/models.json +24 -3
  17. package/locales/ru-RU/models.json +24 -3
  18. package/locales/tr-TR/models.json +24 -3
  19. package/locales/vi-VN/models.json +24 -3
  20. package/locales/zh-CN/models.json +24 -3
  21. package/locales/zh-TW/models.json +24 -3
  22. package/package.json +2 -5
  23. package/packages/database/src/models/__tests__/generationBatch.test.ts +47 -1
  24. package/packages/database/src/models/generationBatch.ts +8 -1
  25. package/packages/model-bank/src/aiModels/aihubmix.ts +1 -1
  26. package/packages/model-bank/src/aiModels/google.ts +4 -4
  27. package/packages/model-bank/src/aiModels/openrouter.ts +2 -2
  28. package/packages/model-bank/src/aiModels/qwen.ts +3 -1
  29. package/packages/model-bank/src/aiModels/siliconcloud.ts +6 -0
  30. package/packages/model-bank/src/aiModels/vertexai.ts +2 -2
  31. package/packages/model-runtime/src/google/createImage.ts +52 -24
  32. package/packages/model-runtime/src/qwen/index.ts +1 -1
  33. package/packages/model-runtime/src/siliconcloud/index.ts +1 -1
  34. package/src/app/[variants]/(main)/(mobile)/me/settings/features/useCategory.tsx +2 -16
  35. package/src/app/[variants]/(main)/chat/@session/_layout/Desktop/SessionHeader.tsx +1 -3
  36. package/src/app/[variants]/(main)/chat/@session/_layout/Mobile/SessionHeader.tsx +1 -3
  37. package/src/app/[variants]/(main)/settings/hooks/useCategory.tsx +3 -21
  38. package/src/config/featureFlags/schema.test.ts +1 -2
  39. package/src/config/featureFlags/schema.ts +0 -6
  40. package/src/config/featureFlags/utils/parser.test.ts +7 -7
  41. package/src/database/_deprecated/core/index.ts +0 -1
  42. package/src/database/_deprecated/core/model.ts +4 -38
  43. package/src/database/_deprecated/models/message.ts +1 -1
  44. package/src/layout/GlobalProvider/StoreInitialization.tsx +0 -3
  45. package/src/store/serverConfig/selectors.test.ts +0 -1
  46. package/src/store/user/initialState.ts +1 -4
  47. package/src/store/user/selectors.ts +0 -1
  48. package/src/store/user/store.ts +1 -4
  49. package/docs/self-hosting/advanced/webrtc.mdx +0 -86
  50. package/docs/self-hosting/advanced/webrtc.zh-CN.mdx +0 -80
  51. package/src/app/[variants]/(main)/settings/sync/features/Alert.tsx +0 -53
  52. package/src/app/[variants]/(main)/settings/sync/features/DeviceInfo/Card.tsx +0 -42
  53. package/src/app/[variants]/(main)/settings/sync/features/DeviceInfo/DeviceName.tsx +0 -62
  54. package/src/app/[variants]/(main)/settings/sync/features/DeviceInfo/SystemIcon.tsx +0 -31
  55. package/src/app/[variants]/(main)/settings/sync/features/DeviceInfo/index.tsx +0 -103
  56. package/src/app/[variants]/(main)/settings/sync/features/WebRTC/ChannelNameInput.tsx +0 -45
  57. package/src/app/[variants]/(main)/settings/sync/features/WebRTC/SyncSwitch/index.css +0 -238
  58. package/src/app/[variants]/(main)/settings/sync/features/WebRTC/SyncSwitch/index.tsx +0 -79
  59. package/src/app/[variants]/(main)/settings/sync/features/WebRTC/generateRandomRoomName.ts +0 -4
  60. package/src/app/[variants]/(main)/settings/sync/features/WebRTC/index.tsx +0 -103
  61. package/src/app/[variants]/(main)/settings/sync/index.tsx +0 -17
  62. package/src/app/[variants]/(main)/settings/sync/page.tsx +0 -29
  63. package/src/database/_deprecated/core/sync.ts +0 -321
  64. package/src/features/SyncStatusInspector/DisableSync.tsx +0 -79
  65. package/src/features/SyncStatusInspector/EnableSync.tsx +0 -132
  66. package/src/features/SyncStatusInspector/EnableTag.tsx +0 -66
  67. package/src/features/SyncStatusInspector/index.tsx +0 -27
  68. package/src/hooks/useSyncData.ts +0 -50
  69. package/src/services/__tests__/sync.test.ts +0 -56
  70. package/src/services/sync.ts +0 -19
  71. package/src/store/user/slices/sync/action.test.ts +0 -164
  72. package/src/store/user/slices/sync/action.ts +0 -101
  73. package/src/store/user/slices/sync/initialState.ts +0 -13
  74. package/src/store/user/slices/sync/selectors.ts +0 -20
@@ -80,6 +80,9 @@
80
80
  "DeepSeek-V3-Fast": {
81
81
  "description": "模型供應商為:sophnet平台。DeepSeek V3 Fast 是 DeepSeek V3 0324 版本的高TPS極速版,滿血非量化,代碼與數學能力更強,響應更快!"
82
82
  },
83
+ "DeepSeek-V3.1": {
84
+ "description": "DeepSeek-V3.1 是深度求索全新推出的混合推理模型,支援思考與非思考兩種推理模式,較 DeepSeek-R1-0528 思考效率更高。經過後訓練優化,Agent 工具使用與智能體任務表現大幅提升。"
85
+ },
83
86
  "Doubao-lite-128k": {
84
87
  "description": "Doubao-lite 擁有極致的響應速度,更好的性價比,為客戶不同場景提供更靈活的選擇。支持128k上下文視窗的推理和精調。"
85
88
  },
@@ -134,9 +137,15 @@
134
137
  "ERNIE-Speed-Pro-128K": {
135
138
  "description": "百度2024年最新發布的自研高性能大語言模型,通用能力優異,效果比ERNIE Speed更優,適合作為基座模型進行精調,更好地處理特定場景問題,同時具備極佳的推理性能。"
136
139
  },
140
+ "FLUX-1.1-pro": {
141
+ "description": "FLUX.1.1 Pro"
142
+ },
137
143
  "FLUX.1-Kontext-dev": {
138
144
  "description": "FLUX.1-Kontext-dev 是由 Black Forest Labs 開發的一款基於 Rectified Flow Transformer 架構的多模態圖像生成與編輯模型,擁有 12B(120 億)參數規模,專注於在給定上下文條件下生成、重構、增強或編輯圖像。該模型結合了擴散模型的可控生成優勢與 Transformer 的上下文建模能力,支持高品質圖像輸出,廣泛適用於圖像修復、圖像補全、視覺場景重構等任務。"
139
145
  },
146
+ "FLUX.1-Kontext-pro": {
147
+ "description": "FLUX.1 Kontext [pro]"
148
+ },
140
149
  "FLUX.1-dev": {
141
150
  "description": "FLUX.1-dev 是由 Black Forest Labs 開發的一款開源多模態語言模型(Multimodal Language Model, MLLM),專為圖文任務優化,融合了圖像和文本的理解與生成能力。它建立在先進的大語言模型(如 Mistral-7B)基礎上,透過精心設計的視覺編碼器與多階段指令微調,實現了圖文協同處理與複雜任務推理的能力。"
142
151
  },
@@ -266,6 +275,9 @@
266
275
  "Pro/deepseek-ai/DeepSeek-V3": {
267
276
  "description": "DeepSeek-V3 是一款擁有 6710 億參數的混合專家(MoE)語言模型,採用多頭潛在注意力(MLA)和 DeepSeekMoE 架構,結合無輔助損失的負載平衡策略,優化推理和訓練效率。透過在 14.8 萬億高質量tokens上預訓練,並進行監督微調和強化學習,DeepSeek-V3 在性能上超越其他開源模型,接近領先閉源模型。"
268
277
  },
278
+ "Pro/deepseek-ai/DeepSeek-V3.1": {
279
+ "description": "DeepSeek-V3.1 是由深度求索(DeepSeek AI)發佈的混合模式大型語言模型,它在前代模型的基礎上進行了多方面的重要升級。該模型的一大創新是整合了「思考模式」(Thinking Mode)與「非思考模式」(Non-thinking Mode)於一體,使用者可以透過調整聊天範本靈活切換,以適應不同的任務需求。透過專門的後訓練優化,V3.1 在工具調用與 Agent 任務方面的效能獲得顯著提升,能更好地支援外部搜尋工具及執行多步複雜任務。該模型基於 DeepSeek-V3.1-Base 進行後訓練,透過兩階段長文本擴展方法,大幅增加訓練資料量,使其在處理長文件與長篇程式碼方面表現更佳。作為一個開源模型,DeepSeek-V3.1 在編碼、數學與推理等多個基準測試中展現了與頂尖閉源模型相媲美的能力,同時憑藉其混合專家(MoE)架構,在保持龐大模型容量的同時,有效降低推理成本。"
280
+ },
269
281
  "Pro/moonshotai/Kimi-K2-Instruct": {
270
282
  "description": "Kimi K2 是一款具備超強程式碼和 Agent 能力的 MoE 架構基礎模型,總參數 1T,激活參數 32B。在通用知識推理、程式設計、數學、Agent 等主要類別的基準性能測試中,K2 模型的性能超過其他主流開源模型。"
271
283
  },
@@ -845,6 +857,9 @@
845
857
  "deepseek-ai/DeepSeek-V3": {
846
858
  "description": "DeepSeek-V3 是一款擁有 6710 億參數的混合專家(MoE)語言模型,採用多頭潛在注意力(MLA)和 DeepSeekMoE 架構,結合無輔助損失的負載平衡策略,優化推理和訓練效率。通過在 14.8 萬億高品質 tokens 上預訓練,並進行監督微調和強化學習,DeepSeek-V3 在性能上超越其他開源模型,接近領先閉源模型。"
847
859
  },
860
+ "deepseek-ai/DeepSeek-V3.1": {
861
+ "description": "DeepSeek-V3.1 是由深度求索(DeepSeek AI)發佈的混合模式大型語言模型,它在前代模型的基礎上進行了多方面的重要升級。該模型的一大創新是整合了「思考模式」(Thinking Mode)與「非思考模式」(Non-thinking Mode)於一體,使用者可以透過調整聊天範本靈活切換,以適應不同的任務需求。透過專門的後訓練優化,V3.1 在工具調用與 Agent 任務方面的效能獲得顯著提升,能更好地支援外部搜尋工具及執行多步複雜任務。該模型基於 DeepSeek-V3.1-Base 進行後訓練,透過兩階段長文本擴展方法,大幅增加訓練資料量,使其在處理長文件與長篇程式碼方面表現更佳。作為一個開源模型,DeepSeek-V3.1 在編碼、數學與推理等多個基準測試中展現了與頂尖閉源模型相媲美的能力,同時憑藉其混合專家(MoE)架構,在保持龐大模型容量的同時,有效降低推理成本。"
862
+ },
848
863
  "deepseek-ai/deepseek-llm-67b-chat": {
849
864
  "description": "DeepSeek 67B 是為高複雜性對話訓練的先進模型。"
850
865
  },
@@ -915,7 +930,7 @@
915
930
  "description": "DeepSeek R1 滿血版,擁有 671B 參數,支持即時聯網搜索,具有更強大的理解和生成能力。"
916
931
  },
917
932
  "deepseek-reasoner": {
918
- "description": "DeepSeek 推出的推理模型。在輸出最終回答之前,模型會先輸出一段思維鏈內容,以提升最終答案的準確性。"
933
+ "description": "DeepSeek V3.1 思考模式。在輸出最終回答之前,模型會先輸出一段思維鏈內容,以提升最終答案的準確性。"
919
934
  },
920
935
  "deepseek-v2": {
921
936
  "description": "DeepSeek V2 是高效的 Mixture-of-Experts 語言模型,適用於經濟高效的處理需求。"
@@ -929,12 +944,18 @@
929
944
  "deepseek-v3-0324": {
930
945
  "description": "DeepSeek-V3-0324 為 671B 參數的 MoE 模型,在程式設計與技術能力、上下文理解與長文本處理等方面優勢突出。"
931
946
  },
947
+ "deepseek-v3.1": {
948
+ "description": "DeepSeek-V3.1 是深度求索全新推出的混合推理模型,支援思考與非思考兩種推理模式,較 DeepSeek-R1-0528 思考效率更高。經過後訓練優化,Agent 工具使用與智能體任務表現大幅提升。支援 128k 上下文視窗,輸出長度支援最大 64k tokens。"
949
+ },
932
950
  "deepseek/deepseek-chat-v3-0324": {
933
951
  "description": "DeepSeek V3 是一個 685B 參數的專家混合模型,是 DeepSeek 團隊旗艦聊天模型系列的最新迭代。\n\n它繼承了 [DeepSeek V3](/deepseek/deepseek-chat-v3) 模型,並在各種任務上表現出色。"
934
952
  },
935
953
  "deepseek/deepseek-chat-v3-0324:free": {
936
954
  "description": "DeepSeek V3 是一個 685B 參數的專家混合模型,是 DeepSeek 團隊旗艦聊天模型系列的最新迭代。\n\n它繼承了 [DeepSeek V3](/deepseek/deepseek-chat-v3) 模型,並在各種任務上表現出色。"
937
955
  },
956
+ "deepseek/deepseek-chat-v3.1": {
957
+ "description": "DeepSeek-V3.1 是一款支援 128K 長上下文與高效模式切換的大型混合推理模型,它在工具調用、程式碼生成和複雜推理任務上實現了卓越的效能與速度。"
958
+ },
938
959
  "deepseek/deepseek-r1": {
939
960
  "description": "DeepSeek-R1 在僅有極少標註數據的情況下,極大提升了模型推理能力。在輸出最終回答之前,模型會先輸出一段思維鏈內容,以提升最終答案的準確性。"
940
961
  },
@@ -1230,10 +1251,10 @@
1230
1251
  "description": "Gemini 2.5 Flash 是 Google 性價比最高的模型,提供全面的功能。"
1231
1252
  },
1232
1253
  "gemini-2.5-flash-image-preview": {
1233
- "description": "Gemini 2.5 Flash Image Preview 是 Google 最新、速度最快且效率最高的原生多模態模型,允許您透過對話生成與編輯圖像。"
1254
+ "description": "Nano Banana 是 Google 最新、最快、最高效的原生多模態模型,它允許您透過對話生成和編輯圖像。"
1234
1255
  },
1235
1256
  "gemini-2.5-flash-image-preview:image": {
1236
- "description": "Gemini 2.5 Flash Image Preview 是 Google 最新、最快、最高效的原生多模態模型,它允許您透過對話生成和編輯圖像。"
1257
+ "description": "Nano Banana 是 Google 最新、最快、最高效的原生多模態模型,它允許您透過對話生成和編輯圖像。"
1237
1258
  },
1238
1259
  "gemini-2.5-flash-lite": {
1239
1260
  "description": "Gemini 2.5 Flash-Lite 是 Google 最小、性價比最高的模型,專為大規模使用而設計。"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lobehub/chat",
3
- "version": "1.119.2",
3
+ "version": "1.120.1",
4
4
  "description": "Lobe Chat - an open-source, high-performance chatbot framework that supports speech synthesis, multimodal, and extensible Function Call plugin system. Supports one-click free deployment of your private ChatGPT/LLM web application.",
5
5
  "keywords": [
6
6
  "framework",
@@ -208,7 +208,7 @@
208
208
  "langfuse": "^3.38.4",
209
209
  "langfuse-core": "^3.38.4",
210
210
  "lodash-es": "^4.17.21",
211
- "lucide-react": "^0.541.0",
211
+ "lucide-react": "^0.542.0",
212
212
  "mammoth": "^1.10.0",
213
213
  "markdown-to-txt": "^2.0.1",
214
214
  "mdast-util-to-markdown": "^2.1.2",
@@ -275,10 +275,7 @@
275
275
  "use-merge-value": "^1.2.0",
276
276
  "uuid": "^11.1.0",
277
277
  "ws": "^8.18.3",
278
- "y-protocols": "^1.0.6",
279
- "y-webrtc": "^10.3.0",
280
278
  "yaml": "^2.8.1",
281
- "yjs": "^13.6.27",
282
279
  "zod": "^3.25.76",
283
280
  "zustand": "5.0.4",
284
281
  "zustand-utils": "^2.1.0"
@@ -2,7 +2,7 @@
2
2
  import { eq } from 'drizzle-orm';
3
3
  import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
4
4
 
5
- import { LobeChatDatabase } from '../../type';import { AsyncTaskStatus } from '@/types/asyncTask';
5
+ import { AsyncTaskStatus } from '@/types/asyncTask';
6
6
  import { GenerationConfig } from '@/types/generation';
7
7
 
8
8
  import {
@@ -12,6 +12,7 @@ import {
12
12
  generations,
13
13
  users,
14
14
  } from '../../schemas';
15
+ import { LobeChatDatabase } from '../../type';
15
16
  import { GenerationBatchModel } from '../generationBatch';
16
17
  import { getTestDB } from './_util';
17
18
 
@@ -367,6 +368,51 @@ describe('GenerationBatchModel', () => {
367
368
  });
368
369
  });
369
370
 
371
+ it('should transform single config imageUrl through FileService', async () => {
372
+ const [createdBatch] = await serverDB
373
+ .insert(generationBatches)
374
+ .values({
375
+ ...testBatch,
376
+ userId,
377
+ config: { imageUrl: 'single-image.jpg', prompt: 'test prompt' },
378
+ })
379
+ .returning();
380
+
381
+ const results = await generationBatchModel.queryGenerationBatchesByTopicIdWithGenerations(
382
+ testTopic.id,
383
+ );
384
+
385
+ expect(results[0].config).toEqual({
386
+ imageUrl: 'https://example.com/single-image.jpg',
387
+ prompt: 'test prompt',
388
+ });
389
+ });
390
+
391
+ it('should transform both imageUrl and imageUrls when both are present', async () => {
392
+ const [createdBatch] = await serverDB
393
+ .insert(generationBatches)
394
+ .values({
395
+ ...testBatch,
396
+ userId,
397
+ config: {
398
+ imageUrl: 'single-image.jpg',
399
+ imageUrls: ['url1.jpg', 'url2.jpg'],
400
+ prompt: 'test prompt',
401
+ },
402
+ })
403
+ .returning();
404
+
405
+ const results = await generationBatchModel.queryGenerationBatchesByTopicIdWithGenerations(
406
+ testTopic.id,
407
+ );
408
+
409
+ expect(results[0].config).toEqual({
410
+ imageUrl: 'https://example.com/single-image.jpg',
411
+ imageUrls: ['https://example.com/url1.jpg', 'https://example.com/url2.jpg'],
412
+ prompt: 'test prompt',
413
+ });
414
+ });
415
+
370
416
  it('should handle config without imageUrls', async () => {
371
417
  const [createdBatch] = await serverDB
372
418
  .insert(generationBatches)
@@ -1,7 +1,6 @@
1
1
  import debug from 'debug';
2
2
  import { and, eq } from 'drizzle-orm';
3
3
 
4
- import { LobeChatDatabase } from '../type';
5
4
  import { FileService } from '@/server/services/file';
6
5
  import { Generation, GenerationAsset, GenerationBatch, GenerationConfig } from '@/types/generation';
7
6
 
@@ -11,6 +10,7 @@ import {
11
10
  NewGenerationBatch,
12
11
  generationBatches,
13
12
  } from '../schemas/generation';
13
+ import { LobeChatDatabase } from '../type';
14
14
  import { GenerationModel } from './generation';
15
15
 
16
16
  const log = debug('lobe-image:generation-batch-model');
@@ -121,6 +121,13 @@ export class GenerationBatchModel {
121
121
  // Transform config
122
122
  (async () => {
123
123
  const config = batch.config as GenerationConfig;
124
+
125
+ // Handle single imageUrl
126
+ if (config.imageUrl) {
127
+ config.imageUrl = await this.fileService.getFullFileUrl(config.imageUrl);
128
+ }
129
+
130
+ // Handle imageUrls array
124
131
  if (Array.isArray(config.imageUrls)) {
125
132
  config.imageUrls = await Promise.all(
126
133
  config.imageUrls.map((url) => this.fileService.getFullFileUrl(url)),
@@ -700,7 +700,7 @@ const aihubmixModels: AIChatModelCard[] = [
700
700
  },
701
701
  contextWindowTokens: 32_768 + 8192,
702
702
  description: 'Gemini 2.5 Flash 实验模型,支持图像生成',
703
- displayName: 'Gemini 2.5 Flash Image Preview',
703
+ displayName: 'Nano Banana',
704
704
  id: 'gemini-2.5-flash-image-preview',
705
705
  maxOutput: 8192,
706
706
  pricing: {
@@ -196,8 +196,8 @@ const googleChatModels: AIChatModelCard[] = [
196
196
  },
197
197
  contextWindowTokens: 32_768 + 8192,
198
198
  description:
199
- 'Gemini 2.5 Flash Image Preview 是 Google 最新、最快、最高效的原生多模态模型,它允许您通过对话生成和编辑图像。',
200
- displayName: 'Gemini 2.5 Flash Image Preview',
199
+ 'Nano Banana 是 Google 最新、最快、最高效的原生多模态模型,它允许您通过对话生成和编辑图像。',
200
+ displayName: 'Nano Banana',
201
201
  enabled: true,
202
202
  id: 'gemini-2.5-flash-image-preview',
203
203
  maxOutput: 8192,
@@ -610,12 +610,12 @@ const imagenBaseParameters: ModelParamsSchema = {
610
610
  /* eslint-disable sort-keys-fix/sort-keys-fix */
611
611
  const googleImageModels: AIImageModelCard[] = [
612
612
  {
613
- displayName: 'Gemini 2.5 Flash Image Preview',
613
+ displayName: 'Nano Banana',
614
614
  id: 'gemini-2.5-flash-image-preview:image',
615
615
  enabled: true,
616
616
  type: 'image',
617
617
  description:
618
- 'Gemini 2.5 Flash Image Preview 是 Google 最新、最快、最高效的原生多模态模型,它允许您通过对话生成和编辑图像。',
618
+ 'Nano Banana 是 Google 最新、最快、最高效的原生多模态模型,它允许您通过对话生成和编辑图像。',
619
619
  releasedAt: '2025-08-26',
620
620
  parameters: CHAT_MODEL_IMAGE_GENERATION_PARAMS,
621
621
  pricing: {
@@ -37,7 +37,7 @@ const openrouterChatModels: AIChatModelCard[] = [
37
37
  },
38
38
  contextWindowTokens: 32_768 + 8192,
39
39
  description: 'Gemini 2.5 Flash 实验模型,支持图像生成',
40
- displayName: 'Gemini 2.5 Flash Image Preview',
40
+ displayName: 'Nano Banana',
41
41
  id: 'google/gemini-2.5-flash-image-preview',
42
42
  maxOutput: 8192,
43
43
  pricing: {
@@ -57,7 +57,7 @@ const openrouterChatModels: AIChatModelCard[] = [
57
57
  },
58
58
  contextWindowTokens: 32_768 + 8192,
59
59
  description: 'Gemini 2.5 Flash 实验模型,支持图像生成',
60
- displayName: 'Gemini 2.5 Flash Image Preview (free)',
60
+ displayName: 'Nano Banana (free)',
61
61
  id: 'google/gemini-2.5-flash-image-preview:free',
62
62
  maxOutput: 8192,
63
63
  releasedAt: '2025-08-26',
@@ -5,7 +5,6 @@ import { AIChatModelCard, AIImageModelCard } from '../types/aiModel';
5
5
  const qwenChatModels: AIChatModelCard[] = [
6
6
  {
7
7
  abilities: {
8
- functionCall: true,
9
8
  reasoning: true,
10
9
  },
11
10
  contextWindowTokens: 131_072,
@@ -20,6 +19,9 @@ const qwenChatModels: AIChatModelCard[] = [
20
19
  { name: 'textOutput', rate: 12, strategy: 'fixed', unit: 'millionTokens' },
21
20
  ],
22
21
  },
22
+ settings: {
23
+ extendParams: ['enableReasoning', 'reasoningBudgetToken'],
24
+ },
23
25
  type: 'chat',
24
26
  },
25
27
  {
@@ -20,6 +20,9 @@ const siliconcloudChatModels: AIChatModelCard[] = [
20
20
  { name: 'textOutput', rate: 12, strategy: 'fixed', unit: 'millionTokens' },
21
21
  ],
22
22
  },
23
+ settings: {
24
+ extendParams: ['enableReasoning', 'reasoningBudgetToken'],
25
+ },
23
26
  type: 'chat',
24
27
  },
25
28
  {
@@ -39,6 +42,9 @@ const siliconcloudChatModels: AIChatModelCard[] = [
39
42
  { name: 'textOutput', rate: 12, strategy: 'fixed', unit: 'millionTokens' },
40
43
  ],
41
44
  },
45
+ settings: {
46
+ extendParams: ['enableReasoning', 'reasoningBudgetToken'],
47
+ },
42
48
  type: 'chat',
43
49
  },
44
50
  {
@@ -126,8 +126,8 @@ const vertexaiChatModels: AIChatModelCard[] = [
126
126
  },
127
127
  contextWindowTokens: 32_768 + 8192,
128
128
  description:
129
- 'Gemini 2.5 Flash Image Preview 是 Google 最新、最快、最高效的原生多模态模型,它允许您通过对话生成和编辑图像。',
130
- displayName: 'Gemini 2.5 Flash Image Preview',
129
+ 'Nano Banana 是 Google 最新、最快、最高效的原生多模态模型,它允许您通过对话生成和编辑图像。',
130
+ displayName: 'Nano Banana',
131
131
  enabled: true,
132
132
  id: 'gemini-2.5-flash-image-preview',
133
133
  maxOutput: 8192,
@@ -6,6 +6,40 @@ import { parseGoogleErrorMessage } from '../utils/googleErrorParser';
6
6
  import { imageUrlToBase64 } from '../utils/imageToBase64';
7
7
  import { parseDataUri } from '../utils/uriParser';
8
8
 
9
+ // Maximum number of images allowed for processing
10
+ const MAX_IMAGE_COUNT = 10;
11
+
12
+ /**
13
+ * Process a single image URL and convert it to Google AI Part format
14
+ */
15
+ async function processImageForParts(imageUrl: string): Promise<Part> {
16
+ const { mimeType, base64, type } = parseDataUri(imageUrl);
17
+
18
+ if (type === 'base64') {
19
+ if (!base64) {
20
+ throw new TypeError("Image URL doesn't contain base64 data");
21
+ }
22
+
23
+ return {
24
+ inlineData: {
25
+ data: base64,
26
+ mimeType: mimeType || 'image/png',
27
+ },
28
+ };
29
+ } else if (type === 'url') {
30
+ const { base64: urlBase64, mimeType: urlMimeType } = await imageUrlToBase64(imageUrl);
31
+
32
+ return {
33
+ inlineData: {
34
+ data: urlBase64,
35
+ mimeType: urlMimeType,
36
+ },
37
+ };
38
+ } else {
39
+ throw new TypeError(`currently we don't support image url: ${imageUrl}`);
40
+ }
41
+ }
42
+
9
43
  /**
10
44
  * Extract image data from generateContent response
11
45
  */
@@ -71,36 +105,30 @@ async function generateImageByChatModel(
71
105
  const { model, params } = payload;
72
106
  const actualModel = model.replace(':image', '');
73
107
 
108
+ // Check for conflicting image parameters
109
+ if (params.imageUrl && params.imageUrls && params.imageUrls.length > 0) {
110
+ throw new TypeError('Cannot provide both imageUrl and imageUrls parameters simultaneously');
111
+ }
112
+
74
113
  // Build content parts
75
114
  const parts: Part[] = [{ text: params.prompt }];
76
115
 
77
116
  // Add image for editing if provided
78
117
  if (params.imageUrl && params.imageUrl !== null) {
79
- const { mimeType, base64, type } = parseDataUri(params.imageUrl);
80
-
81
- if (type === 'base64') {
82
- if (!base64) {
83
- throw new TypeError("Image URL doesn't contain base64 data");
84
- }
85
-
86
- parts.push({
87
- inlineData: {
88
- data: base64,
89
- mimeType: mimeType || 'image/png',
90
- },
91
- });
92
- } else if (type === 'url') {
93
- const { base64: urlBase64, mimeType: urlMimeType } = await imageUrlToBase64(params.imageUrl);
94
-
95
- parts.push({
96
- inlineData: {
97
- data: urlBase64,
98
- mimeType: urlMimeType,
99
- },
100
- });
101
- } else {
102
- throw new TypeError(`currently we don't support image url: ${params.imageUrl}`);
118
+ const imagePart = await processImageForParts(params.imageUrl);
119
+ parts.push(imagePart);
120
+ }
121
+
122
+ // Add multiple images for editing if provided
123
+ if (params.imageUrls && Array.isArray(params.imageUrls) && params.imageUrls.length > 0) {
124
+ if (params.imageUrls.length > MAX_IMAGE_COUNT) {
125
+ throw new TypeError(`Too many images provided. Maximum ${MAX_IMAGE_COUNT} images allowed`);
103
126
  }
127
+
128
+ const imageParts = await Promise.all(
129
+ params.imageUrls.map((imageUrl) => processImageForParts(imageUrl)),
130
+ );
131
+ parts.push(...imageParts);
104
132
  }
105
133
 
106
134
  const contents: Content[] = [
@@ -35,7 +35,7 @@ export const LobeQwenAI = createOpenAICompatibleRuntime({
35
35
  thinking_budget:
36
36
  thinking?.budget_tokens === 0 ? 0 : thinking?.budget_tokens || undefined,
37
37
  }
38
- : ['qwen3', 'qwen-turbo', 'qwen-plus'].some((keyword) =>
38
+ : ['qwen3', 'qwen-turbo', 'qwen-plus', 'deepseek-v3.1'].some((keyword) =>
39
39
  model.toLowerCase().includes(keyword),
40
40
  )
41
41
  ? {
@@ -45,7 +45,7 @@ export const LobeSiliconCloudAI = createOpenAICompatibleRuntime({
45
45
 
46
46
  return {
47
47
  ...rest,
48
- ...(['qwen3'].some((keyword) => model.toLowerCase().includes(keyword))
48
+ ...(['qwen3', 'deepseek-v3.1'].some((keyword) => model.toLowerCase().includes(keyword))
49
49
  ? {
50
50
  enable_thinking: thinking !== undefined ? thinking.type === 'enabled' : false,
51
51
  thinking_budget:
@@ -1,8 +1,6 @@
1
- import { Tag } from '@lobehub/ui';
2
- import { Bot, Brain, Cloudy, Info, Mic2, Settings2, Sparkles } from 'lucide-react';
1
+ import { Bot, Brain, Info, Mic2, Settings2, Sparkles } from 'lucide-react';
3
2
  import { useRouter } from 'next/navigation';
4
3
  import { useTranslation } from 'react-i18next';
5
- import { Flexbox } from 'react-layout-kit';
6
4
  import urlJoin from 'url-join';
7
5
 
8
6
  import { CellProps } from '@/components/Cell';
@@ -13,7 +11,7 @@ import { featureFlagsSelectors, useServerConfigStore } from '@/store/serverConfi
13
11
  export const useCategory = () => {
14
12
  const router = useRouter();
15
13
  const { t } = useTranslation('setting');
16
- const { enableWebrtc, showLLM } = useServerConfigStore(featureFlagsSelectors);
14
+ const { showLLM } = useServerConfigStore(featureFlagsSelectors);
17
15
 
18
16
  const items: CellProps[] = [
19
17
  {
@@ -26,18 +24,6 @@ export const useCategory = () => {
26
24
  key: SettingsTabs.SystemAgent,
27
25
  label: t('tab.system-agent'),
28
26
  },
29
- enableWebrtc && {
30
- icon: Cloudy,
31
- key: SettingsTabs.Sync,
32
- label: (
33
- <Flexbox align={'center'} gap={8} horizontal>
34
- {t('tab.sync')}
35
- <Tag bordered={false} color={'warning'}>
36
- {t('tab.experiment')}
37
- </Tag>
38
- </Flexbox>
39
- ),
40
- },
41
27
  showLLM &&
42
28
  (isDeprecatedEdition
43
29
  ? {
@@ -9,7 +9,6 @@ import { Flexbox } from 'react-layout-kit';
9
9
 
10
10
  import { ProductLogo } from '@/components/Branding';
11
11
  import { DESKTOP_HEADER_ICON_SIZE } from '@/const/layoutTokens';
12
- import SyncStatusTag from '@/features/SyncStatusInspector';
13
12
  import { useActionSWR } from '@/libs/swr';
14
13
  import { featureFlagsSelectors, useServerConfigStore } from '@/store/serverConfig';
15
14
  import { useSessionStore } from '@/store/session';
@@ -33,7 +32,7 @@ const Header = memo(() => {
33
32
  const { styles } = useStyles();
34
33
  const { t } = useTranslation('chat');
35
34
  const [createSession] = useSessionStore((s) => [s.createSession]);
36
- const { enableWebrtc, showCreateSession } = useServerConfigStore(featureFlagsSelectors);
35
+ const { showCreateSession } = useServerConfigStore(featureFlagsSelectors);
37
36
 
38
37
  const { mutate, isValidating } = useActionSWR('session.createSession', () => createSession());
39
38
 
@@ -50,7 +49,6 @@ const Header = memo(() => {
50
49
  }}
51
50
  >
52
51
  <ProductLogo className={styles.logo} size={36} type={'text'} />
53
- {enableWebrtc && <SyncStatusTag />}
54
52
  </Flexbox>
55
53
  <Flexbox align={'center'} gap={4} horizontal>
56
54
  <TogglePanelButton />
@@ -9,7 +9,6 @@ import { Flexbox } from 'react-layout-kit';
9
9
 
10
10
  import { ProductLogo } from '@/components/Branding';
11
11
  import { MOBILE_HEADER_ICON_SIZE } from '@/const/layoutTokens';
12
- import SyncStatusInspector from '@/features/SyncStatusInspector';
13
12
  import UserAvatar from '@/features/User/UserAvatar';
14
13
  import { featureFlagsSelectors, useServerConfigStore } from '@/store/serverConfig';
15
14
  import { useSessionStore } from '@/store/session';
@@ -18,7 +17,7 @@ import { mobileHeaderSticky } from '@/styles/mobileHeader';
18
17
  const Header = memo(() => {
19
18
  const [createSession] = useSessionStore((s) => [s.createSession]);
20
19
  const router = useRouter();
21
- const { enableWebrtc, showCreateSession } = useServerConfigStore(featureFlagsSelectors);
20
+ const { showCreateSession } = useServerConfigStore(featureFlagsSelectors);
22
21
 
23
22
  return (
24
23
  <ChatHeader
@@ -26,7 +25,6 @@ const Header = memo(() => {
26
25
  <Flexbox align={'center'} gap={8} horizontal style={{ marginLeft: 8 }}>
27
26
  <UserAvatar onClick={() => router.push('/me')} size={32} />
28
27
  <ProductLogo type={'text'} />
29
- {enableWebrtc && <SyncStatusInspector placement={'bottom'} />}
30
28
  </Flexbox>
31
29
  }
32
30
  right={
@@ -1,8 +1,7 @@
1
- import { Icon, Tag } from '@lobehub/ui';
1
+ import { Icon } from '@lobehub/ui';
2
2
  import {
3
3
  Bot,
4
4
  Brain,
5
- Cloudy,
6
5
  Database,
7
6
  EthernetPort,
8
7
  Info,
@@ -14,7 +13,6 @@ import {
14
13
  import Link from 'next/link';
15
14
  import { useMemo } from 'react';
16
15
  import { useTranslation } from 'react-i18next';
17
- import { Flexbox } from 'react-layout-kit';
18
16
 
19
17
  import type { MenuProps } from '@/components/Menu';
20
18
  import { isDeprecatedEdition, isDesktop } from '@/const/version';
@@ -24,8 +22,7 @@ import { featureFlagsSelectors, useServerConfigStore } from '@/store/serverConfi
24
22
  export const useCategory = () => {
25
23
  const { t } = useTranslation('setting');
26
24
  const mobile = useServerConfigStore((s) => s.isMobile);
27
- const { enableWebrtc, showLLM, enableSTT, hideDocs } =
28
- useServerConfigStore(featureFlagsSelectors);
25
+ const { showLLM, enableSTT, hideDocs } = useServerConfigStore(featureFlagsSelectors);
29
26
 
30
27
  const cateItems: MenuProps['items'] = useMemo(
31
28
  () =>
@@ -48,21 +45,6 @@ export const useCategory = () => {
48
45
  </Link>
49
46
  ),
50
47
  },
51
- // TODO: remove in V2
52
- enableWebrtc && {
53
- icon: <Icon icon={Cloudy} />,
54
- key: SettingsTabs.Sync,
55
- label: (
56
- <Link href={'/settings/sync'} onClick={(e) => e.preventDefault()}>
57
- <Flexbox align={'center'} gap={8} horizontal>
58
- {t('tab.sync')}
59
- <Tag bordered={false} color={'warning'}>
60
- {t('tab.experiment')}
61
- </Tag>
62
- </Flexbox>
63
- </Link>
64
- ),
65
- },
66
48
  !mobile && {
67
49
  icon: <Icon icon={KeyboardIcon} />,
68
50
  key: SettingsTabs.Hotkey,
@@ -146,7 +128,7 @@ export const useCategory = () => {
146
128
  ),
147
129
  },
148
130
  ].filter(Boolean) as MenuProps['items'],
149
- [t, enableWebrtc, showLLM],
131
+ [t, showLLM],
150
132
  );
151
133
 
152
134
  return cateItems;
@@ -20,7 +20,7 @@ describe('FeatureFlagsSchema', () => {
20
20
 
21
21
  it('should reject invalid feature flags', () => {
22
22
  const result = FeatureFlagsSchema.safeParse({
23
- webrtc_sync: 'yes', // Invalid type, should be boolean
23
+ edit_agent: 'yes', // Invalid type, should be boolean
24
24
  });
25
25
 
26
26
  expect(result.success).toBe(false);
@@ -43,7 +43,6 @@ describe('mapFeatureFlagsEnvToState', () => {
43
43
  };
44
44
 
45
45
  const expectedState = {
46
- enableWebrtc: true,
47
46
  isAgentEditable: false,
48
47
  showCreateSession: true,
49
48
  showLLM: false,
@@ -2,10 +2,6 @@
2
2
  import { z } from 'zod';
3
3
 
4
4
  export const FeatureFlagsSchema = z.object({
5
- /**
6
- * Enable WebRTC sync
7
- */
8
- webrtc_sync: z.boolean().optional(),
9
5
  check_updates: z.boolean().optional(),
10
6
  pin_list: z.boolean().optional(),
11
7
 
@@ -51,7 +47,6 @@ export const FeatureFlagsSchema = z.object({
51
47
  export type IFeatureFlags = z.infer<typeof FeatureFlagsSchema>;
52
48
 
53
49
  export const DEFAULT_FEATURE_FLAGS: IFeatureFlags = {
54
- webrtc_sync: false,
55
50
  pin_list: false,
56
51
 
57
52
  language_model_settings: true,
@@ -93,7 +88,6 @@ export const DEFAULT_FEATURE_FLAGS: IFeatureFlags = {
93
88
 
94
89
  export const mapFeatureFlagsEnvToState = (config: IFeatureFlags) => {
95
90
  return {
96
- enableWebrtc: config.webrtc_sync,
97
91
  isAgentEditable: config.edit_agent,
98
92
 
99
93
  showCreateSession: config.create_session,