@lobehub/chat 1.135.0 → 1.135.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 (34) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/changelog/v1.json +14 -0
  3. package/locales/ar/chat.json +2 -2
  4. package/locales/bg-BG/chat.json +2 -2
  5. package/locales/de-DE/chat.json +2 -2
  6. package/locales/en-US/chat.json +2 -2
  7. package/locales/es-ES/chat.json +2 -2
  8. package/locales/fa-IR/chat.json +2 -2
  9. package/locales/fr-FR/chat.json +2 -2
  10. package/locales/it-IT/chat.json +2 -2
  11. package/locales/ja-JP/chat.json +2 -2
  12. package/locales/ko-KR/chat.json +2 -2
  13. package/locales/nl-NL/chat.json +2 -2
  14. package/locales/pl-PL/chat.json +2 -2
  15. package/locales/pt-BR/chat.json +2 -2
  16. package/locales/ru-RU/chat.json +2 -2
  17. package/locales/tr-TR/chat.json +2 -2
  18. package/locales/vi-VN/chat.json +2 -2
  19. package/locales/zh-CN/chat.json +2 -2
  20. package/locales/zh-TW/chat.json +2 -2
  21. package/next.config.ts +5 -6
  22. package/package.json +1 -1
  23. package/packages/context-engine/src/tools/ToolsEngine.ts +27 -5
  24. package/packages/context-engine/src/tools/__tests__/ToolsEngine.test.ts +89 -0
  25. package/packages/model-bank/src/aiModels/fal.ts +20 -18
  26. package/src/app/[variants]/(main)/chat/(workspace)/@conversation/features/ChatList/WelcomeChatItem/index.tsx +1 -17
  27. package/src/app/[variants]/(main)/chat/(workspace)/@conversation/features/ChatMinimap/index.tsx +7 -4
  28. package/src/app/[variants]/(main)/chat/@session/features/SessionListContent/List/Item/index.tsx +16 -17
  29. package/src/app/[variants]/(main)/chat/@session/features/SessionListContent/ListItem/index.tsx +2 -2
  30. package/src/app/[variants]/(main)/image/@menu/features/ConfigPanel/components/ImageConfigSkeleton.tsx +8 -7
  31. package/src/features/Conversation/Messages/Assistant/Tool/Inspector/BuiltinPluginTitle.tsx +15 -17
  32. package/src/features/Conversation/Messages/Assistant/Tool/Inspector/ToolTitle.tsx +5 -7
  33. package/src/features/Conversation/Messages/Assistant/Tool/Render/Arguments/index.tsx +1 -8
  34. package/src/locales/default/chat.ts +2 -2
package/CHANGELOG.md CHANGED
@@ -2,6 +2,56 @@
2
2
 
3
3
  # Changelog
4
4
 
5
+ ### [Version 1.135.2](https://github.com/lobehub/lobe-chat/compare/v1.135.1...v1.135.2)
6
+
7
+ <sup>Released on **2025-10-06**</sup>
8
+
9
+ #### 💄 Styles
10
+
11
+ - **image**: Optimize UX and fix fal pricing.
12
+
13
+ <br/>
14
+
15
+ <details>
16
+ <summary><kbd>Improvements and Fixes</kbd></summary>
17
+
18
+ #### Styles
19
+
20
+ - **image**: Optimize UX and fix fal pricing, closes [#9592](https://github.com/lobehub/lobe-chat/issues/9592) ([dddbfcd](https://github.com/lobehub/lobe-chat/commit/dddbfcd))
21
+
22
+ </details>
23
+
24
+ <div align="right">
25
+
26
+ [![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
27
+
28
+ </div>
29
+
30
+ ### [Version 1.135.1](https://github.com/lobehub/lobe-chat/compare/v1.135.0...v1.135.1)
31
+
32
+ <sup>Released on **2025-10-06**</sup>
33
+
34
+ #### 💄 Styles
35
+
36
+ - **misc**: Improve styles and fix tools calling condition.
37
+
38
+ <br/>
39
+
40
+ <details>
41
+ <summary><kbd>Improvements and Fixes</kbd></summary>
42
+
43
+ #### Styles
44
+
45
+ - **misc**: Improve styles and fix tools calling condition, closes [#9591](https://github.com/lobehub/lobe-chat/issues/9591) ([1695f2f](https://github.com/lobehub/lobe-chat/commit/1695f2f))
46
+
47
+ </details>
48
+
49
+ <div align="right">
50
+
51
+ [![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
52
+
53
+ </div>
54
+
5
55
  ## [Version 1.135.0](https://github.com/lobehub/lobe-chat/compare/v1.134.7...v1.135.0)
6
56
 
7
57
  <sup>Released on **2025-10-06**</sup>
package/changelog/v1.json CHANGED
@@ -1,4 +1,18 @@
1
1
  [
2
+ {
3
+ "children": {},
4
+ "date": "2025-10-06",
5
+ "version": "1.135.2"
6
+ },
7
+ {
8
+ "children": {
9
+ "improvements": [
10
+ "Improve styles and fix tools calling condition."
11
+ ]
12
+ },
13
+ "date": "2025-10-06",
14
+ "version": "1.135.1"
15
+ },
2
16
  {
3
17
  "children": {
4
18
  "features": [
@@ -3,8 +3,8 @@
3
3
  "title": "النموذج"
4
4
  },
5
5
  "agentDefaultMessage": "مرحبًا، أنا **{{name}}**، يمكنك بدء المحادثة معي على الفور، أو يمكنك الذهاب إلى [إعدادات المساعد]({{url}}) لإكمال معلوماتي.",
6
- "agentDefaultMessageWithSystemRole": "مرحبًا، أنا **{{name}}**، {{systemRole}}، دعنا نبدأ الدردشة!",
7
- "agentDefaultMessageWithoutEdit": "مرحبًا، أنا **{{name}}**، دعنا نبدأ المحادثة!",
6
+ "agentDefaultMessageWithSystemRole": "مرحبًا، أنا **{{name}}**، كيف يمكنني مساعدتك؟",
7
+ "agentDefaultMessageWithoutEdit": "مرحبًا، أنا **{{name}}**، كيف يمكنني مساعدتك؟",
8
8
  "agents": "مساعد",
9
9
  "artifact": {
10
10
  "generating": "جاري الإنشاء",
@@ -3,8 +3,8 @@
3
3
  "title": "Модел"
4
4
  },
5
5
  "agentDefaultMessage": "Здравейте, аз съм **{{name}}**, можете да започнете разговор с мен веднага или да отидете на [Настройки на асистента]({{url}}), за да попълните информацията ми.",
6
- "agentDefaultMessageWithSystemRole": "Здравей, аз съм **{{name}}**, {{systemRole}}. Нека започнем да чатим!",
7
- "agentDefaultMessageWithoutEdit": "Здравей, аз съм **{{name}}** и нека започнем разговора!",
6
+ "agentDefaultMessageWithSystemRole": "Здравейте, аз съм **{{name}}**. Как мога да ви помогна?",
7
+ "agentDefaultMessageWithoutEdit": "Здравейте, аз съм **{{name}}**. Как мога да ви помогна?",
8
8
  "agents": "Асистент",
9
9
  "artifact": {
10
10
  "generating": "Генериране",
@@ -3,8 +3,8 @@
3
3
  "title": "Modell"
4
4
  },
5
5
  "agentDefaultMessage": "Hallo, ich bin **{{name}}**. Du kannst sofort mit mir sprechen oder zu den [Assistenteneinstellungen]({{url}}) gehen, um meine Informationen zu vervollständigen.",
6
- "agentDefaultMessageWithSystemRole": "Hallo, ich bin **{{name}}**, {{systemRole}}. Lass uns chatten!",
7
- "agentDefaultMessageWithoutEdit": "Hallo, ich bin **{{name}}**. Lassen Sie uns ins Gespräch kommen!",
6
+ "agentDefaultMessageWithSystemRole": "Hallo, ich bin **{{name}}**. Wie kann ich Ihnen behilflich sein?",
7
+ "agentDefaultMessageWithoutEdit": "Hallo, ich bin **{{name}}**. Wie kann ich Ihnen behilflich sein?",
8
8
  "agents": "Assistent",
9
9
  "artifact": {
10
10
  "generating": "Wird generiert",
@@ -3,8 +3,8 @@
3
3
  "title": "Model"
4
4
  },
5
5
  "agentDefaultMessage": "Hello, I am **{{name}}**. You can start a conversation with me right away, or you can go to [Assistant Settings]({{url}}) to complete my information.",
6
- "agentDefaultMessageWithSystemRole": "Hello, I'm **{{name}}**, {{systemRole}}. Let's start chatting!",
7
- "agentDefaultMessageWithoutEdit": "Hello, I'm **{{name}}**, let's start chatting!",
6
+ "agentDefaultMessageWithSystemRole": "Hello, I am **{{name}}**. How can I assist you today?",
7
+ "agentDefaultMessageWithoutEdit": "Hello, I am **{{name}}**. How can I assist you today?",
8
8
  "agents": "Assistants",
9
9
  "artifact": {
10
10
  "generating": "Generating",
@@ -3,8 +3,8 @@
3
3
  "title": "Cambiar modelo"
4
4
  },
5
5
  "agentDefaultMessage": "Hola, soy **{{name}}**. Puedes comenzar a hablar conmigo de inmediato o ir a [Configuración del asistente]({{url}}) para completar mi información.",
6
- "agentDefaultMessageWithSystemRole": "Hola, soy **{{name}}**, {{systemRole}}, ¡comencemos a chatear!",
7
- "agentDefaultMessageWithoutEdit": "¡Hola, soy **{{name}}**! Comencemos nuestra conversación.",
6
+ "agentDefaultMessageWithSystemRole": "Hola, soy **{{name}}**, ¿en qué puedo ayudarte?",
7
+ "agentDefaultMessageWithoutEdit": "Hola, soy **{{name}}**, ¿en qué puedo ayudarte?",
8
8
  "agents": "Asistente",
9
9
  "artifact": {
10
10
  "generating": "Generando",
@@ -3,8 +3,8 @@
3
3
  "title": "مدل"
4
4
  },
5
5
  "agentDefaultMessage": "سلام، من **{{name}}** هستم. می‌توانید همین حالا با من گفتگو را شروع کنید یا به [تنظیمات دستیار]({{url}}) بروید و اطلاعات من را تکمیل کنید.",
6
- "agentDefaultMessageWithSystemRole": "سلام، من **{{name}}** هستم، {{systemRole}}، بیایید گفتگو را شروع کنیم!",
7
- "agentDefaultMessageWithoutEdit": "سلام، من **{{name}}** هستم، بیایید گفتگو را شروع کنیم!",
6
+ "agentDefaultMessageWithSystemRole": "سلام، من **{{name}}** هستم، چگونه می‌توانم به شما کمک کنم؟",
7
+ "agentDefaultMessageWithoutEdit": "سلام، من **{{name}}** هستم، چگونه می‌توانم به شما کمک کنم؟",
8
8
  "agents": "دستیار",
9
9
  "artifact": {
10
10
  "generating": "در حال تولید",
@@ -3,8 +3,8 @@
3
3
  "title": "Modèle"
4
4
  },
5
5
  "agentDefaultMessage": "Bonjour, je suis **{{name}}**, vous pouvez commencer à discuter avec moi immédiatement ou vous rendre dans [Paramètres de l'assistant]({{url}}) pour compléter mes informations.",
6
- "agentDefaultMessageWithSystemRole": "Bonjour, je suis **{{name}}**, {{systemRole}}. Commençons la conversation !",
7
- "agentDefaultMessageWithoutEdit": "Bonjour, je suis **{{name}}**. Commençons notre conversation !",
6
+ "agentDefaultMessageWithSystemRole": "Bonjour, je suis **{{name}}**, comment puis-je vous aider ?",
7
+ "agentDefaultMessageWithoutEdit": "Bonjour, je suis **{{name}}**, comment puis-je vous aider ?",
8
8
  "agents": "Assistant",
9
9
  "artifact": {
10
10
  "generating": "Génération en cours",
@@ -3,8 +3,8 @@
3
3
  "title": "Modelli"
4
4
  },
5
5
  "agentDefaultMessage": "Ciao, sono **{{name}}**, puoi iniziare subito a parlare con me oppure andare su [Impostazioni assistente]({{url}}) per completare le mie informazioni.",
6
- "agentDefaultMessageWithSystemRole": "Ciao, sono **{{name}}**, {{systemRole}}, iniziamo a chattare!",
7
- "agentDefaultMessageWithoutEdit": "Ciao, sono **{{name}}**. Cominciamo a chiacchierare!",
6
+ "agentDefaultMessageWithSystemRole": "Ciao, sono **{{name}}**, come posso aiutarti?",
7
+ "agentDefaultMessageWithoutEdit": "Ciao, sono **{{name}}**, come posso aiutarti?",
8
8
  "agents": "Assistente",
9
9
  "artifact": {
10
10
  "generating": "Generazione in corso",
@@ -3,8 +3,8 @@
3
3
  "title": "モデル"
4
4
  },
5
5
  "agentDefaultMessage": "こんにちは、私は **{{name}}** です。すぐに私と会話を始めることもできますし、[アシスタント設定]({{url}}) に行って私の情報を充実させることもできます。",
6
- "agentDefaultMessageWithSystemRole": "こんにちは、私は **{{name}}** です、{{systemRole}}、さあ、チャットを始めましょう!",
7
- "agentDefaultMessageWithoutEdit": "こんにちは、私は**{{name}}**です。会話しましょう!",
6
+ "agentDefaultMessageWithSystemRole": "こんにちは、私は **{{name}}** です。何かお手伝いできることはありますか?",
7
+ "agentDefaultMessageWithoutEdit": "こんにちは、私は **{{name}}** です。何かお手伝いできることはありますか?",
8
8
  "agents": "エージェント",
9
9
  "artifact": {
10
10
  "generating": "生成中",
@@ -3,8 +3,8 @@
3
3
  "title": "모델"
4
4
  },
5
5
  "agentDefaultMessage": "안녕하세요, 저는 **{{name}}**입니다. 지금 바로 저와 대화를 시작하시거나 [도우미 설정]({{url}})으로 가셔서 제 정보를 완성하실 수 있습니다.",
6
- "agentDefaultMessageWithSystemRole": "안녕하세요, 저는 **{{name}}**입니다. {{systemRole}}입니다. 대화를 시작해 봅시다!",
7
- "agentDefaultMessageWithoutEdit": "안녕하세요, 저는 **{{name}}**입니다. 대화를 시작해보세요!",
6
+ "agentDefaultMessageWithSystemRole": "안녕하세요, 저는 **{{name}}**입니다. 무엇을 도와드릴까요?",
7
+ "agentDefaultMessageWithoutEdit": "안녕하세요, 저는 **{{name}}**입니다. 무엇을 도와드릴까요?",
8
8
  "agents": "도우미",
9
9
  "artifact": {
10
10
  "generating": "생성 중",
@@ -3,8 +3,8 @@
3
3
  "title": "Modelen"
4
4
  },
5
5
  "agentDefaultMessage": "Hallo, ik ben **{{name}}**. Je kunt meteen met me beginnen praten, of je kunt naar [Assistentinstellingen]({{url}}) gaan om mijn informatie aan te vullen.",
6
- "agentDefaultMessageWithSystemRole": "Hallo, ik ben **{{name}}**, {{systemRole}}, laten we beginnen met praten!",
7
- "agentDefaultMessageWithoutEdit": "Hallo, ik ben **{{name}}**. Laten we beginnen met een gesprek!",
6
+ "agentDefaultMessageWithSystemRole": "Hallo, ik ben **{{name}}**. Waarmee kan ik u van dienst zijn?",
7
+ "agentDefaultMessageWithoutEdit": "Hallo, ik ben **{{name}}**. Waarmee kan ik u van dienst zijn?",
8
8
  "agents": "Assistent",
9
9
  "artifact": {
10
10
  "generating": "Genereren",
@@ -3,8 +3,8 @@
3
3
  "title": "Przełącz model"
4
4
  },
5
5
  "agentDefaultMessage": "Cześć, jestem **{{name}}**, możesz od razu rozpocząć ze mną rozmowę lub przejść do [ustawień asystenta]({{url}}), aby uzupełnić moje informacje.",
6
- "agentDefaultMessageWithSystemRole": "Cześć, jestem **{{name}}**, {{systemRole}}, zacznijmy rozmowę!",
7
- "agentDefaultMessageWithoutEdit": "Cześć, jestem **{{name}}**. Zacznijmy rozmowę!",
6
+ "agentDefaultMessageWithSystemRole": "Cześć, jestem **{{name}}**. W czym mogę pomóc?",
7
+ "agentDefaultMessageWithoutEdit": "Cześć, jestem **{{name}}**. W czym mogę pomóc?",
8
8
  "agents": "Asystent",
9
9
  "artifact": {
10
10
  "generating": "Generowanie",
@@ -3,8 +3,8 @@
3
3
  "title": "Modelo"
4
4
  },
5
5
  "agentDefaultMessage": "Olá, eu sou **{{name}}**, você pode começar a conversar comigo agora ou ir para [Configurações do Assistente]({{url}}) para completar minhas informações.",
6
- "agentDefaultMessageWithSystemRole": "Olá, eu sou **{{name}}**, {{systemRole}}, vamos conversar!",
7
- "agentDefaultMessageWithoutEdit": "Olá, sou o **{{name}}**, vamos começar a conversa!",
6
+ "agentDefaultMessageWithSystemRole": "Olá, eu sou **{{name}}**. Como posso ajudar você?",
7
+ "agentDefaultMessageWithoutEdit": "Olá, eu sou **{{name}}**. Como posso ajudar você?",
8
8
  "agents": "Assistente",
9
9
  "artifact": {
10
10
  "generating": "Gerando",
@@ -3,8 +3,8 @@
3
3
  "title": "Модель"
4
4
  },
5
5
  "agentDefaultMessage": "Здравствуйте, я **{{name}}**. Вы можете сразу начать со мной разговор или перейти в [настройки помощника]({{url}}), чтобы дополнить мою информацию.",
6
- "agentDefaultMessageWithSystemRole": "Привет, я **{{name}}**, {{systemRole}}. Давай начнем разговор!",
7
- "agentDefaultMessageWithoutEdit": "Привет, я **{{name}}**, давай начнём разговор!",
6
+ "agentDefaultMessageWithSystemRole": "Здравствуйте, я **{{name}}**, чем могу помочь?",
7
+ "agentDefaultMessageWithoutEdit": "Здравствуйте, я **{{name}}**, чем могу помочь?",
8
8
  "agents": "Ассистент",
9
9
  "artifact": {
10
10
  "generating": "Генерация",
@@ -3,8 +3,8 @@
3
3
  "title": "Model Değiştir"
4
4
  },
5
5
  "agentDefaultMessage": "Merhaba, ben **{{name}}**. Hemen benimle konuşmaya başlayabilir veya [Asistan Ayarları]({{url}}) sayfasına giderek bilgilerimi güncelleyebilirsin.",
6
- "agentDefaultMessageWithSystemRole": "Merhaba, Ben **{{name}}**, {{systemRole}}. Hemen sohbet etmeye başlayalım!",
7
- "agentDefaultMessageWithoutEdit": "Merhaba, ben **{{name}}**. Konuşmaya başlayalım!",
6
+ "agentDefaultMessageWithSystemRole": "Merhaba, ben **{{name}}**. Size nasıl yardımcı olabilirim?",
7
+ "agentDefaultMessageWithoutEdit": "Merhaba, ben **{{name}}**. Size nasıl yardımcı olabilirim?",
8
8
  "agents": "Asistan",
9
9
  "artifact": {
10
10
  "generating": "Üretiliyor",
@@ -3,8 +3,8 @@
3
3
  "title": "Mô hình"
4
4
  },
5
5
  "agentDefaultMessage": "Xin chào, tôi là **{{name}}**, bạn có thể bắt đầu trò chuyện với tôi ngay bây giờ, hoặc bạn có thể đến [Cài đặt trợ lý]({{url}}) để hoàn thiện thông tin của tôi.",
6
- "agentDefaultMessageWithSystemRole": "Xin chào, tôi là **{{name}}**, {{systemRole}}. Hãy bắt đầu trò chuyện ngay!",
7
- "agentDefaultMessageWithoutEdit": "Xin chào, tôi là **{{name}}**, chúng ta hãy bắt đầu trò chuyện nào!",
6
+ "agentDefaultMessageWithSystemRole": "Xin chào, tôi là **{{name}}**, tôi thể giúp cho bạn?",
7
+ "agentDefaultMessageWithoutEdit": "Xin chào, tôi là **{{name}}**, tôi thể giúp cho bạn?",
8
8
  "agents": "Trợ lý",
9
9
  "artifact": {
10
10
  "generating": "Đang tạo",
@@ -3,8 +3,8 @@
3
3
  "title": "模型"
4
4
  },
5
5
  "agentDefaultMessage": "你好,我是 **{{name}}**,你可以立即与我开始对话,也可以前往 [助手设置]({{url}}) 完善我的信息。",
6
- "agentDefaultMessageWithSystemRole": "你好,我是 **{{name}}**,{{systemRole}},让我们开始对话吧!",
7
- "agentDefaultMessageWithoutEdit": "你好,我是 **{{name}}**,让我们开始对话吧!",
6
+ "agentDefaultMessageWithSystemRole": "你好,我是 **{{name}}**,有什么我可以帮忙的吗?",
7
+ "agentDefaultMessageWithoutEdit": "你好,我是 **{{name}}**,有什么我可以帮忙的吗?",
8
8
  "agents": "助手",
9
9
  "artifact": {
10
10
  "generating": "生成中",
@@ -3,8 +3,8 @@
3
3
  "title": "模型"
4
4
  },
5
5
  "agentDefaultMessage": "你好,我是 **{{name}}**,你可以立即與我開始對話,也可以前往 [助手設定]({{url}}) 完善我的資訊。",
6
- "agentDefaultMessageWithSystemRole": "你好,我是 **{{name}}**,{{systemRole}},讓我們開始對話吧!",
7
- "agentDefaultMessageWithoutEdit": "你好,我是 **{{name}}**,讓我們開始對話吧!",
6
+ "agentDefaultMessageWithSystemRole": "你好,我是 **{{name}}**,有什麼我可以幫忙的嗎?",
7
+ "agentDefaultMessageWithoutEdit": "你好,我是 **{{name}}**,有什麼我可以幫忙的嗎?",
8
8
  "agents": "助手",
9
9
  "artifact": {
10
10
  "generating": "生成中",
package/next.config.ts CHANGED
@@ -250,17 +250,16 @@ const nextConfig: NextConfig = {
250
250
  // permanent: true,
251
251
  // source: '/settings',
252
252
  // },
253
+ {
254
+ destination: '/chat',
255
+ permanent: false,
256
+ source: '/',
257
+ },
253
258
  {
254
259
  destination: '/chat',
255
260
  permanent: true,
256
261
  source: '/welcome',
257
262
  },
258
- // TODO: 等 V2 做强制跳转吧
259
- // {
260
- // destination: '/settings/provider/volcengine',
261
- // permanent: true,
262
- // source: '/settings/provider/doubao',
263
- // },
264
263
  // we need back /repos url in the further
265
264
  {
266
265
  destination: '/files',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lobehub/chat",
3
- "version": "1.135.0",
3
+ "version": "1.135.2",
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",
@@ -107,28 +107,33 @@ export class ToolsEngine {
107
107
  this.defaultToolIds.length,
108
108
  );
109
109
 
110
- // Filter and validate plugins
110
+ // Check if model supports Function Calling
111
+ const supportsFunctionCall = this.checkFunctionCallSupport(model, provider);
112
+
113
+ // Filter and validate plugins with FC support information
111
114
  const { enabledManifests, filteredPlugins } = this.filterEnabledPlugins(
112
115
  allToolIds,
113
116
  model,
114
117
  provider,
115
118
  context,
119
+ supportsFunctionCall,
116
120
  );
117
121
 
118
- // Convert to UniformTool format
119
- const tools = this.convertManifestsToTools(enabledManifests);
122
+ // Convert to UniformTool format only if there are enabled manifests
123
+ const tools =
124
+ enabledManifests.length > 0 ? this.convertManifestsToTools(enabledManifests) : undefined;
120
125
 
121
126
  log(
122
127
  'Generated detailed result: enabled=%d, filtered=%d, tools=%d',
123
128
  enabledManifests.length,
124
129
  filteredPlugins.length,
125
- tools.length,
130
+ tools?.length ?? 0,
126
131
  );
127
132
 
128
133
  return {
129
134
  enabledToolIds: enabledManifests.map((m) => m.identifier),
130
135
  filteredTools: filteredPlugins,
131
- tools: tools.length > 0 ? tools : undefined,
136
+ tools,
132
137
  };
133
138
  }
134
139
 
@@ -155,6 +160,7 @@ export class ToolsEngine {
155
160
  model: string,
156
161
  provider: string,
157
162
  context?: ToolsGenerationContext,
163
+ supportsFunctionCall?: boolean,
158
164
  ): {
159
165
  enabledManifests: LobeChatPluginManifest[];
160
166
  filteredPlugins: Array<{
@@ -170,6 +176,22 @@ export class ToolsEngine {
170
176
 
171
177
  log('Filtering plugins: %o', pluginIds);
172
178
 
179
+ // If function calling is not supported, filter all plugins as incompatible
180
+ if (supportsFunctionCall === false) {
181
+ for (const pluginId of pluginIds) {
182
+ const manifest = this.manifestSchemas.get(pluginId);
183
+ if (!manifest) {
184
+ log('Plugin not found: %s', pluginId);
185
+ filteredPlugins.push({ id: pluginId, reason: 'not_found' });
186
+ } else {
187
+ log('Plugin incompatible (no FC support): %s', pluginId);
188
+ filteredPlugins.push({ id: pluginId, reason: 'incompatible' });
189
+ }
190
+ }
191
+ log('Filtering complete: enabled=%d, filtered=%d', 0, filteredPlugins.length);
192
+ return { enabledManifests, filteredPlugins };
193
+ }
194
+
173
195
  for (const pluginId of pluginIds) {
174
196
  const manifest = this.manifestSchemas.get(pluginId);
175
197
 
@@ -206,6 +206,95 @@ describe('ToolsEngine', () => {
206
206
  { id: 'non-existent', reason: 'not_found' },
207
207
  ]);
208
208
  });
209
+
210
+ it('should filter all plugins as incompatible when function calling is not supported', () => {
211
+ const mockFunctionCallChecker = vi.fn().mockReturnValue(false);
212
+ const engine = new ToolsEngine({
213
+ manifestSchemas: [mockWebBrowsingManifest, mockDalleManifest],
214
+ functionCallChecker: mockFunctionCallChecker,
215
+ });
216
+
217
+ const result = engine.generateToolsDetailed({
218
+ toolIds: ['lobe-web-browsing', 'dalle'],
219
+ model: 'gpt-5-chat-latest',
220
+ provider: 'openai',
221
+ });
222
+
223
+ expect(mockFunctionCallChecker).toHaveBeenCalledWith('gpt-5-chat-latest', 'openai');
224
+ expect(result.tools).toBeUndefined();
225
+ expect(result.enabledToolIds).toEqual([]);
226
+ expect(result.filteredTools).toEqual([
227
+ { id: 'lobe-web-browsing', reason: 'incompatible' },
228
+ { id: 'dalle', reason: 'incompatible' },
229
+ ]);
230
+ });
231
+
232
+ it('should combine incompatible and not_found reasons when FC is not supported', () => {
233
+ const engine = new ToolsEngine({
234
+ manifestSchemas: [mockWebBrowsingManifest],
235
+ functionCallChecker: () => false,
236
+ });
237
+
238
+ const result = engine.generateToolsDetailed({
239
+ toolIds: ['lobe-web-browsing', 'non-existent', 'dalle'],
240
+ model: 'gpt-5-chat-latest',
241
+ provider: 'openai',
242
+ });
243
+
244
+ expect(result.tools).toBeUndefined();
245
+ expect(result.enabledToolIds).toEqual([]);
246
+ expect(result.filteredTools).toEqual([
247
+ { id: 'lobe-web-browsing', reason: 'incompatible' },
248
+ { id: 'non-existent', reason: 'not_found' },
249
+ { id: 'dalle', reason: 'not_found' },
250
+ ]);
251
+ });
252
+
253
+ it('should still call enableChecker when FC is supported', () => {
254
+ const mockEnableChecker = vi.fn().mockReturnValue(false);
255
+ const engine = new ToolsEngine({
256
+ manifestSchemas: [mockWebBrowsingManifest, mockDalleManifest],
257
+ enableChecker: mockEnableChecker,
258
+ functionCallChecker: () => true,
259
+ });
260
+
261
+ const result = engine.generateToolsDetailed({
262
+ toolIds: ['lobe-web-browsing', 'dalle'],
263
+ model: 'gpt-4',
264
+ provider: 'openai',
265
+ });
266
+
267
+ expect(mockEnableChecker).toHaveBeenCalledTimes(2);
268
+ expect(result.tools).toBeUndefined();
269
+ expect(result.enabledToolIds).toEqual([]);
270
+ expect(result.filteredTools).toEqual([
271
+ { id: 'lobe-web-browsing', reason: 'disabled' },
272
+ { id: 'dalle', reason: 'disabled' },
273
+ ]);
274
+ });
275
+
276
+ it('should not call enableChecker when FC is not supported', () => {
277
+ const mockEnableChecker = vi.fn().mockReturnValue(true);
278
+ const engine = new ToolsEngine({
279
+ manifestSchemas: [mockWebBrowsingManifest, mockDalleManifest],
280
+ enableChecker: mockEnableChecker,
281
+ functionCallChecker: () => false,
282
+ });
283
+
284
+ const result = engine.generateToolsDetailed({
285
+ toolIds: ['lobe-web-browsing', 'dalle'],
286
+ model: 'gpt-5-chat-latest',
287
+ provider: 'openai',
288
+ });
289
+
290
+ expect(mockEnableChecker).not.toHaveBeenCalled();
291
+ expect(result.tools).toBeUndefined();
292
+ expect(result.enabledToolIds).toEqual([]);
293
+ expect(result.filteredTools).toEqual([
294
+ { id: 'lobe-web-browsing', reason: 'incompatible' },
295
+ { id: 'dalle', reason: 'incompatible' },
296
+ ]);
297
+ });
209
298
  });
210
299
 
211
300
  describe('plugin management', () => {
@@ -39,6 +39,24 @@ export const qwenEditParamsSchema: ModelParamsSchema = {
39
39
  width: { default: 1328, max: 1536, min: 512, step: 1 },
40
40
  };
41
41
 
42
+ export const huanyuanImageParamsSchema: ModelParamsSchema = {
43
+ cfg: { default: 7.5, max: 20, min: 1, step: 0.1 },
44
+ prompt: { default: '' },
45
+ seed: { default: null },
46
+ size: {
47
+ default: 'square_hd',
48
+ enum: [
49
+ 'square_hd',
50
+ 'square',
51
+ 'portrait_4_3',
52
+ 'portrait_16_9',
53
+ 'landscape_4_3',
54
+ 'landscape_16_9',
55
+ ],
56
+ },
57
+ steps: { default: 28, max: 50, min: 1, step: 1 },
58
+ };
59
+
42
60
  const falImageModels: AIImageModelCard[] = [
43
61
  {
44
62
  description:
@@ -84,23 +102,7 @@ const falImageModels: AIImageModelCard[] = [
84
102
  displayName: 'HunyuanImage 3.0',
85
103
  enabled: true,
86
104
  id: 'fal-ai/hunyuan-image/v3',
87
- parameters: {
88
- cfg: { default: 7.5, max: 20, min: 1, step: 0.1 },
89
- prompt: { default: '' },
90
- seed: { default: null },
91
- size: {
92
- default: 'square_hd',
93
- enum: [
94
- 'square_hd',
95
- 'square',
96
- 'portrait_4_3',
97
- 'portrait_16_9',
98
- 'landscape_4_3',
99
- 'landscape_16_9',
100
- ],
101
- },
102
- steps: { default: 28, max: 50, min: 1, step: 1 },
103
- },
105
+ parameters: huanyuanImageParamsSchema,
104
106
  pricing: {
105
107
  units: [{ name: 'imageGeneration', rate: 0.1, strategy: 'fixed', unit: 'megapixel' }],
106
108
  },
@@ -197,7 +199,7 @@ const falImageModels: AIImageModelCard[] = [
197
199
  id: 'fal-ai/qwen-image-edit',
198
200
  parameters: qwenEditParamsSchema,
199
201
  pricing: {
200
- units: [{ name: 'imageGeneration', rate: 0.025, strategy: 'fixed', unit: 'image' }],
202
+ units: [{ name: 'imageGeneration', rate: 0.03, strategy: 'fixed', unit: 'megapixel' }],
201
203
  },
202
204
  releasedAt: '2025-08-19',
203
205
  type: 'image',
@@ -1,17 +1 @@
1
- import React, { memo } from 'react';
2
-
3
- import { useChatStore } from '@/store/chat';
4
- import { chatSelectors } from '@/store/chat/selectors';
5
-
6
- import InboxWelcome from './InboxWelcome';
7
- import WelcomeMessage from './WelcomeMessage';
8
-
9
- const WelcomeChatItem = memo(() => {
10
- const showInboxWelcome = useChatStore(chatSelectors.showInboxWelcome);
11
-
12
- if (showInboxWelcome) return <InboxWelcome />;
13
-
14
- return <WelcomeMessage />;
15
- });
16
-
17
- export default WelcomeChatItem;
1
+ export { default } from './WelcomeMessage';
@@ -3,6 +3,7 @@
3
3
  import { Icon } from '@lobehub/ui';
4
4
  import { Tooltip } from 'antd';
5
5
  import { createStyles, useTheme } from 'antd-style';
6
+ import debug from 'debug';
6
7
  import { ChevronDown, ChevronUp } from 'lucide-react';
7
8
  import { memo, useCallback, useMemo, useState, useSyncExternalStore } from 'react';
8
9
  import { useTranslation } from 'react-i18next';
@@ -17,10 +18,12 @@ import {
17
18
  import { useChatStore } from '@/store/chat';
18
19
  import { chatSelectors } from '@/store/chat/selectors';
19
20
 
21
+ const log = debug('lobe-react:chat-minimap');
22
+
20
23
  const MIN_WIDTH = 16;
21
24
  const MAX_WIDTH = 30;
22
25
  const MAX_CONTENT_LENGTH = 320;
23
- const MIN_MESSAGES = 6;
26
+ const MIN_MESSAGES = 4;
24
27
 
25
28
  const useStyles = createStyles(({ css, token }) => ({
26
29
  arrow: css`
@@ -219,8 +222,8 @@ const ChatMinimap = () => {
219
222
  const activeIndicatorPosition = useMemo(() => {
220
223
  if (activeIndex === null) return null;
221
224
 
222
- console.log('> activeIndex', activeIndex);
223
- console.log('> indicatorIndexMap', indicatorIndexMap);
225
+ log('> activeIndex', activeIndex);
226
+ log('> indicatorIndexMap', indicatorIndexMap);
224
227
 
225
228
  return indicatorIndexMap.get(activeIndex) ?? null;
226
229
  }, [activeIndex, indicatorIndexMap]);
@@ -246,7 +249,7 @@ const ChatMinimap = () => {
246
249
  let targetPosition: number;
247
250
 
248
251
  if (activeIndicatorPosition !== null) {
249
- console.log('activeIndicatorPosition', activeIndicatorPosition);
252
+ log('activeIndicatorPosition', activeIndicatorPosition);
250
253
  // We're on an indicator, move to prev/next
251
254
  const delta = direction === 'prev' ? -1 : 1;
252
255
  targetPosition = Math.min(
@@ -31,22 +31,21 @@ const SessionItem = memo<SessionItemProps>(({ id }) => {
31
31
  const [active] = useSessionStore((s) => [s.activeId === id]);
32
32
  const [loading] = useChatStore((s) => [chatSelectors.isAIGenerating(s) && id === s.activeId]);
33
33
 
34
- const [pin, title, description, avatar, avatarBackground, updateAt, model, group] =
35
- useSessionStore((s) => {
36
- const session = sessionSelectors.getSessionById(id)(s);
37
- const meta = session.meta;
38
-
39
- return [
40
- sessionHelpers.getSessionPinned(session),
41
- sessionMetaSelectors.getTitle(meta),
42
- sessionMetaSelectors.getDescription(meta),
43
- sessionMetaSelectors.getAvatar(meta),
44
- meta.backgroundColor,
45
- session?.updatedAt,
46
- session.model,
47
- session?.group,
48
- ];
49
- });
34
+ const [pin, title, avatar, avatarBackground, updateAt, model, group] = useSessionStore((s) => {
35
+ const session = sessionSelectors.getSessionById(id)(s);
36
+ const meta = session.meta;
37
+
38
+ return [
39
+ sessionHelpers.getSessionPinned(session),
40
+ sessionMetaSelectors.getTitle(meta),
41
+ sessionMetaSelectors.getAvatar(meta),
42
+ meta.backgroundColor,
43
+ session?.updatedAt,
44
+ session.model,
45
+ session?.group,
46
+ // sessionMetaSelectors.getDescription(meta),
47
+ ];
48
+ });
50
49
 
51
50
  const showModel = model !== defaultModel;
52
51
 
@@ -99,7 +98,7 @@ const SessionItem = memo<SessionItemProps>(({ id }) => {
99
98
  avatar={avatar}
100
99
  avatarBackground={avatarBackground}
101
100
  date={updateAt?.valueOf()}
102
- description={description}
101
+ // description={description}
103
102
  draggable={isDesktop}
104
103
  key={id}
105
104
  loading={loading}
@@ -12,7 +12,7 @@ const useStyles = createStyles(({ css, token }) => {
12
12
  container: css`
13
13
  position: relative;
14
14
  margin-block: 2px;
15
- padding-inline: 8px 16px;
15
+ padding-inline: 12px 16px;
16
16
  border-radius: ${token.borderRadius}px;
17
17
  `,
18
18
  mobile: css`
@@ -40,7 +40,7 @@ const ListItem = memo<ListItemProps & { avatar: string; avatarBackground?: strin
40
40
  avatar={avatar}
41
41
  background={avatarBackground}
42
42
  shape="circle"
43
- size={40}
43
+ size={32}
44
44
  />
45
45
  ),
46
46
  [isHovering, avatar, avatarBackground],
@@ -13,14 +13,15 @@ const ImageConfigSkeleton = memo(() => {
13
13
  <Flexbox gap={32} padding="12px 12px 0 12px" style={{ height: '100%' }}>
14
14
  {/* Model Selection */}
15
15
  <Flexbox gap={8}>
16
- <Skeleton.Input size="small" style={{ width: 100 }} />
17
- <Skeleton.Input size="large" style={{ width: '100%' }} />
16
+ <Skeleton.Input active size="small" style={{ width: 100 }} />
17
+ <Skeleton.Input active size="large" style={{ width: '100%' }} />
18
18
  </Flexbox>
19
19
 
20
20
  {/* Image Upload Area */}
21
21
  <Flexbox gap={8}>
22
- <Skeleton.Input size="small" style={{ width: 60 }} />
22
+ <Skeleton.Input active size="small" style={{ width: 60 }} />
23
23
  <Skeleton.Node
24
+ active
24
25
  style={{
25
26
  borderRadius: 8,
26
27
  height: 100,
@@ -32,16 +33,16 @@ const ImageConfigSkeleton = memo(() => {
32
33
  {/* Parameter Controls */}
33
34
  {Array.from({ length: 2 }, (_, index) => (
34
35
  <Flexbox gap={8} key={index}>
35
- <Skeleton.Input size="small" style={{ width: 80 }} />
36
- <Skeleton.Input size="default" style={{ width: '100%' }} />
36
+ <Skeleton.Input active size="small" style={{ width: 80 }} />
37
+ <Skeleton.Input active size="default" style={{ width: '100%' }} />
37
38
  </Flexbox>
38
39
  ))}
39
40
 
40
41
  {/* Image Number Control (Sticky at bottom) */}
41
42
  <Flexbox padding="12px 0" style={{ marginTop: 'auto' }}>
42
43
  <Flexbox gap={8}>
43
- <Skeleton.Input size="small" style={{ width: 60 }} />
44
- <Skeleton.Input size="default" style={{ width: '100%' }} />
44
+ <Skeleton.Input active size="small" style={{ width: 60 }} />
45
+ <Skeleton.Input active size="default" style={{ width: '100%' }} />
45
46
  </Flexbox>
46
47
  </Flexbox>
47
48
  </Flexbox>
@@ -1,8 +1,9 @@
1
+ import { Icon } from '@lobehub/ui';
1
2
  import { createStyles } from 'antd-style';
3
+ import { ChevronRight } from 'lucide-react';
2
4
  import { ReactNode, memo } from 'react';
3
5
  import { Flexbox } from 'react-layout-kit';
4
6
 
5
- import Loader from '@/components/CircleLoader';
6
7
  import { useChatStore } from '@/store/chat';
7
8
  import { chatSelectors } from '@/store/chat/selectors';
8
9
  import { shinyTextStylish } from '@/styles/loading';
@@ -32,21 +33,18 @@ interface BuiltinPluginTitleProps {
32
33
  toolCallId: string;
33
34
  }
34
35
 
35
- const BuiltinPluginTitle = memo<BuiltinPluginTitleProps>(
36
- ({ messageId, index, apiName, icon, title }) => {
37
- const { styles } = useStyles();
38
-
39
- const isLoading = useChatStore(chatSelectors.isInToolsCalling(messageId, index));
40
-
41
- return (
42
- <Flexbox align={'center'} className={isLoading ? styles.shinyText : ''} gap={4} horizontal>
43
- {isLoading ? <Loader /> : icon}
44
- <Flexbox align={'baseline'} gap={4} horizontal>
45
- <div>{title}</div>/<span className={styles.apiName}>{apiName}</span>
46
- </Flexbox>
47
- </Flexbox>
48
- );
49
- },
50
- );
36
+ const BuiltinPluginTitle = memo<BuiltinPluginTitleProps>(({ messageId, index, apiName, title }) => {
37
+ const { styles } = useStyles();
38
+
39
+ const isLoading = useChatStore(chatSelectors.isInToolsCalling(messageId, index));
40
+
41
+ return (
42
+ <Flexbox align={'center'} className={isLoading ? styles.shinyText : ''} gap={4} horizontal>
43
+ <div>{title}</div>
44
+ <Icon icon={ChevronRight} />
45
+ <span className={styles.apiName}>{apiName}</span>
46
+ </Flexbox>
47
+ );
48
+ });
51
49
 
52
50
  export default BuiltinPluginTitle;
@@ -1,13 +1,11 @@
1
1
  import { Icon } from '@lobehub/ui';
2
2
  import { createStyles } from 'antd-style';
3
3
  import isEqual from 'fast-deep-equal';
4
- import { Globe, Laptop } from 'lucide-react';
4
+ import { ChevronRight } from 'lucide-react';
5
5
  import { memo, useMemo } from 'react';
6
6
  import { useTranslation } from 'react-i18next';
7
7
  import { Flexbox } from 'react-layout-kit';
8
8
 
9
- import Loader from '@/components/CircleLoader';
10
- import PluginAvatar from '@/features/PluginAvatar';
11
9
  import { useChatStore } from '@/store/chat';
12
10
  import { chatSelectors } from '@/store/chat/selectors';
13
11
  import { pluginHelpers, useToolStore } from '@/store/tool';
@@ -60,13 +58,13 @@ const ToolTitle = memo<ToolTitleProps>(({ identifier, messageId, index, apiName,
60
58
  () => [
61
59
  {
62
60
  apiName: t(`search.apiName.${apiName}`, apiName),
63
- icon: <Icon icon={Globe} size={13} />,
61
+ // icon: <Icon icon={Globe} size={13} />,
64
62
  id: WebBrowsingManifest.identifier,
65
63
  title: t('search.title'),
66
64
  },
67
65
  {
68
66
  apiName: t(`localSystem.apiName.${apiName}`, apiName),
69
- icon: <Icon icon={Laptop} size={13} />,
67
+ // icon: <Icon icon={Laptop} size={13} />,
70
68
  id: LocalSystemManifest.identifier,
71
69
  title: t('localSystem.title'),
72
70
  },
@@ -92,8 +90,8 @@ const ToolTitle = memo<ToolTitleProps>(({ identifier, messageId, index, apiName,
92
90
 
93
91
  return (
94
92
  <Flexbox align={'center'} className={isLoading ? styles.shinyText : ''} gap={6} horizontal>
95
- {isLoading ? <Loader /> : <PluginAvatar identifier={identifier} size={18} />}
96
- <div>{pluginTitle}</div>/<span className={styles.apiName}>{apiName}</span>
93
+ <div>{pluginTitle}</div> <Icon icon={ChevronRight} />
94
+ <span className={styles.apiName}>{apiName}</span>
97
95
  </Flexbox>
98
96
  );
99
97
  });
@@ -116,14 +116,7 @@ const Arguments = memo<ArgumentsProps>(({ arguments: args = '', shine, actions }
116
116
  </Flexbox>
117
117
  )}
118
118
  {args.length > 100 ? (
119
- <Highlighter
120
- language={'json'}
121
- showLanguage={false}
122
- style={{ padding: 8 }}
123
- variant={'borderless'}
124
- >
125
- {JSON.stringify(displayArgs, null, 2)}
126
- </Highlighter>
119
+ <pre style={{ padding: 8 }}>{JSON.stringify(displayArgs, null, 2)}</pre>
127
120
  ) : (
128
121
  Object.entries(displayArgs).map(([key, value]) => {
129
122
  return (
@@ -4,8 +4,8 @@ export default {
4
4
  },
5
5
  agentDefaultMessage:
6
6
  '你好,我是 **{{name}}**,你可以立即与我开始对话,也可以前往 [助手设置]({{url}}) 完善我的信息。',
7
- agentDefaultMessageWithSystemRole: '你好,我是 **{{name}}**,{{systemRole}},让我们开始对话吧!',
8
- agentDefaultMessageWithoutEdit: '你好,我是 **{{name}}**,让我们开始对话吧!',
7
+ agentDefaultMessageWithSystemRole: '你好,我是 **{{name}}**,有什么我可以帮忙的吗?',
8
+ agentDefaultMessageWithoutEdit: '你好,我是 **{{name}}**,有什么我可以帮忙的吗?',
9
9
  agents: '助手',
10
10
  artifact: {
11
11
  generating: '生成中',