@lobehub/lobehub 2.0.0-next.23 → 2.0.0-next.24

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 (50) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/changelog/v1.json +9 -0
  3. package/locales/ar/labs.json +4 -0
  4. package/locales/bg-BG/labs.json +4 -0
  5. package/locales/de-DE/labs.json +4 -0
  6. package/locales/en-US/labs.json +4 -0
  7. package/locales/es-ES/labs.json +4 -0
  8. package/locales/fa-IR/labs.json +4 -0
  9. package/locales/fr-FR/labs.json +4 -0
  10. package/locales/it-IT/labs.json +4 -0
  11. package/locales/ja-JP/labs.json +4 -0
  12. package/locales/ko-KR/labs.json +4 -0
  13. package/locales/nl-NL/labs.json +4 -0
  14. package/locales/pl-PL/labs.json +4 -0
  15. package/locales/pt-BR/labs.json +4 -0
  16. package/locales/ru-RU/labs.json +4 -0
  17. package/locales/tr-TR/labs.json +4 -0
  18. package/locales/vi-VN/labs.json +4 -0
  19. package/locales/zh-CN/labs.json +4 -0
  20. package/locales/zh-TW/labs.json +4 -0
  21. package/package.json +1 -1
  22. package/packages/const/src/user.ts +5 -2
  23. package/packages/types/src/index.ts +0 -1
  24. package/packages/types/src/user/index.ts +2 -88
  25. package/packages/types/src/user/preference.ts +105 -0
  26. package/renovate.json +1 -6
  27. package/src/app/[variants]/(main)/labs/components/LabCard.tsx +5 -5
  28. package/src/app/[variants]/(main)/labs/page.tsx +18 -22
  29. package/src/app/[variants]/(main)/settings/provider/detail/azure/index.tsx +1 -1
  30. package/src/app/[variants]/(main)/settings/provider/detail/azureai/index.tsx +1 -1
  31. package/src/app/[variants]/(main)/settings/provider/detail/bedrock/index.tsx +1 -1
  32. package/src/app/[variants]/(main)/settings/provider/detail/cloudflare/index.tsx +1 -1
  33. package/src/app/[variants]/(main)/settings/provider/detail/comfyui/index.tsx +1 -1
  34. package/src/app/[variants]/(main)/settings/provider/detail/github/index.tsx +1 -1
  35. package/src/app/[variants]/(main)/settings/provider/detail/vertexai/index.tsx +1 -1
  36. package/src/app/[variants]/(main)/settings/provider/features/ProviderConfig/index.tsx +2 -4
  37. package/src/components/Skeleton/SkeletonSwitch.tsx +13 -0
  38. package/src/components/Skeleton/index.ts +2 -0
  39. package/src/features/ChatInput/ActionBar/index.tsx +2 -2
  40. package/src/features/ChatInput/InputEditor/index.tsx +2 -2
  41. package/src/locales/default/labs.ts +4 -0
  42. package/src/server/routers/lambda/message.ts +5 -20
  43. package/src/services/message/server.ts +0 -10
  44. package/src/services/message/type.ts +0 -2
  45. package/src/store/user/selectors.ts +1 -1
  46. package/src/store/user/slices/preference/action.ts +8 -1
  47. package/src/store/user/slices/preference/selectors/index.ts +2 -0
  48. package/src/store/user/slices/preference/selectors/labPrefer.ts +13 -0
  49. package/src/store/user/slices/preference/{selectors.ts → selectors/preference.ts} +0 -2
  50. /package/src/{app/[variants]/(main)/settings/provider/features/ProviderConfig → components/Skeleton}/SkeletonInput.tsx +0 -0
package/CHANGELOG.md CHANGED
@@ -2,6 +2,31 @@
2
2
 
3
3
  # Changelog
4
4
 
5
+ ## [Version 2.0.0-next.24](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.23...v2.0.0-next.24)
6
+
7
+ <sup>Released on **2025-11-04**</sup>
8
+
9
+ #### 💄 Styles
10
+
11
+ - **misc**: Improve lab style.
12
+
13
+ <br/>
14
+
15
+ <details>
16
+ <summary><kbd>Improvements and Fixes</kbd></summary>
17
+
18
+ #### Styles
19
+
20
+ - **misc**: Improve lab style, closes [#10040](https://github.com/lobehub/lobe-chat/issues/10040) ([bbf1c0b](https://github.com/lobehub/lobe-chat/commit/bbf1c0b))
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
+
5
30
  ## [Version 2.0.0-next.23](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.22...v2.0.0-next.23)
6
31
 
7
32
  <sup>Released on **2025-11-04**</sup>
package/changelog/v1.json CHANGED
@@ -1,4 +1,13 @@
1
1
  [
2
+ {
3
+ "children": {
4
+ "improvements": [
5
+ "Improve lab style."
6
+ ]
7
+ },
8
+ "date": "2025-11-04",
9
+ "version": "2.0.0-next.24"
10
+ },
2
11
  {
3
12
  "children": {
4
13
  "fixes": [
@@ -1,6 +1,10 @@
1
1
  {
2
2
  "desc": "سنقوم بتحديث الميزات الجديدة التي نستكشفها من وقت لآخر، ندعوك لتجربتها!",
3
3
  "features": {
4
+ "assistantMessageGroup": {
5
+ "desc": "تجميع رسائل المساعد ونتائج استدعاء الأدوات في مجموعة واحدة للعرض",
6
+ "title": "تجميع رسائل المساعد"
7
+ },
4
8
  "groupChat": {
5
9
  "desc": "تفعيل إمكانية تنسيق المحادثات الجماعية متعددة الوكلاء.",
6
10
  "title": "دردشة جماعية (متعددة الوكلاء)"
@@ -1,6 +1,10 @@
1
1
  {
2
2
  "desc": "Тук периодично ще актуализираме новите функции, които изследваме. Добре дошли да ги изпробвате!",
3
3
  "features": {
4
+ "assistantMessageGroup": {
5
+ "desc": "Групиране на съобщенията от асистента и резултатите от извикванията на инструменти за показване в група",
6
+ "title": "Групиране на съобщенията от асистента"
7
+ },
4
8
  "groupChat": {
5
9
  "desc": "Активиране на възможността за координация в групов чат с множество интелигентни агенти.",
6
10
  "title": "Групов чат (множество агенти)"
@@ -1,6 +1,10 @@
1
1
  {
2
2
  "desc": "Hier werden wir regelmäßig neue Funktionen vorstellen, die wir gerade erforschen – probieren Sie sie gerne aus!",
3
3
  "features": {
4
+ "assistantMessageGroup": {
5
+ "desc": "Assistentennachrichten und die Ergebnisse von Toolaufrufen werden gruppiert angezeigt",
6
+ "title": "Gruppierung von Assistentennachrichten"
7
+ },
4
8
  "groupChat": {
5
9
  "desc": "Aktivieren Sie die Koordination von Gruppenchats mit mehreren KI-Agenten.",
6
10
  "title": "Gruppenchats (mehrere Agenten)"
@@ -1,6 +1,10 @@
1
1
  {
2
2
  "desc": "Here you'll find occasional updates on new features we're exploring—feel free to try them out!",
3
3
  "features": {
4
+ "assistantMessageGroup": {
5
+ "desc": "Group assistant messages and their tool call results together for display",
6
+ "title": "Assistant Message Grouping"
7
+ },
4
8
  "groupChat": {
5
9
  "desc": "Enable multi-agent group chat coordination.",
6
10
  "title": "Group Chat (Multi-Agent)"
@@ -1,6 +1,10 @@
1
1
  {
2
2
  "desc": "Aquí actualizaremos periódicamente las nuevas funciones que estamos explorando. ¡Te invitamos a probarlas!",
3
3
  "features": {
4
+ "assistantMessageGroup": {
5
+ "desc": "Agrupa los mensajes del asistente y los resultados de las herramientas utilizadas para mostrarlos juntos",
6
+ "title": "Agrupación de mensajes del asistente"
7
+ },
4
8
  "groupChat": {
5
9
  "desc": "Activa la capacidad de coordinación de chats grupales con múltiples agentes.",
6
10
  "title": "Chat grupal (multiagente)"
@@ -1,6 +1,10 @@
1
1
  {
2
2
  "desc": "در اینجا به‌طور دوره‌ای ویژگی‌های جدیدی که در حال آزمایش آن‌ها هستیم به‌روزرسانی می‌شود. خوشحال می‌شویم آن‌ها را امتحان کنید!",
3
3
  "features": {
4
+ "assistantMessageGroup": {
5
+ "desc": "نمایش گروهی پیام‌های دستیار و نتایج فراخوانی ابزارهای آن",
6
+ "title": "گروه‌بندی پیام‌های دستیار"
7
+ },
4
8
  "groupChat": {
5
9
  "desc": "قابلیت هماهنگی چت گروهی با چند عامل هوشمند را فعال کنید.",
6
10
  "title": "گفت‌وگوی گروهی (چند عاملی)"
@@ -1,6 +1,10 @@
1
1
  {
2
2
  "desc": "Nous mettons à jour régulièrement cette section avec de nouvelles fonctionnalités en cours d'exploration. N'hésitez pas à les essayer !",
3
3
  "features": {
4
+ "assistantMessageGroup": {
5
+ "desc": "Regrouper les messages de l'assistant et les résultats des appels d'outils pour les afficher ensemble",
6
+ "title": "Regroupement des messages de l'assistant"
7
+ },
4
8
  "groupChat": {
5
9
  "desc": "Activez la coordination de discussions de groupe avec plusieurs agents intelligents.",
6
10
  "title": "Discussion de groupe (multi-agents)"
@@ -1,6 +1,10 @@
1
1
  {
2
2
  "desc": "Qui troverai aggiornamenti periodici sulle nuove funzionalità che stiamo esplorando. Sentiti libero di provarle!",
3
3
  "features": {
4
+ "assistantMessageGroup": {
5
+ "desc": "Raggruppa i messaggi dell'assistente e i risultati delle chiamate agli strumenti in un unico gruppo",
6
+ "title": "Raggruppamento dei messaggi dell'assistente"
7
+ },
4
8
  "groupChat": {
5
9
  "desc": "Abilita la capacità di coordinamento in chat di gruppo con più agenti intelligenti.",
6
10
  "title": "Chat di gruppo (multi-agente)"
@@ -1,6 +1,10 @@
1
1
  {
2
2
  "desc": "ここでは、私たちが現在試している新機能を不定期に更新しています。ぜひお試しください!",
3
3
  "features": {
4
+ "assistantMessageGroup": {
5
+ "desc": "アシスタントのメッセージとそのツール呼び出し結果をグループ化して表示します",
6
+ "title": "アシスタントメッセージのグループ化表示"
7
+ },
4
8
  "groupChat": {
5
9
  "desc": "複数のAIエージェントによるグループチャット機能を有効にします。",
6
10
  "title": "グループチャット(マルチエージェント)"
@@ -1,6 +1,10 @@
1
1
  {
2
2
  "desc": "이곳에서는 우리가 탐색 중인 새로운 기능들을 수시로 업데이트합니다. 사용해보시고 의견을 들려주세요!",
3
3
  "features": {
4
+ "assistantMessageGroup": {
5
+ "desc": "도우미 메시지와 해당 도구 호출 결과를 그룹으로 묶어 표시합니다",
6
+ "title": "도우미 메시지 그룹화"
7
+ },
4
8
  "groupChat": {
5
9
  "desc": "다중 에이전트 그룹 채팅 조정 기능을 활성화합니다.",
6
10
  "title": "그룹 채팅 (다중 에이전트)"
@@ -1,6 +1,10 @@
1
1
  {
2
2
  "desc": "Hier worden regelmatig nieuwe functies bijgewerkt die we aan het verkennen zijn. Probeer ze gerust uit!",
3
3
  "features": {
4
+ "assistantMessageGroup": {
5
+ "desc": "Assistentberichten en de resultaten van hulpoproepen gegroepeerd weergeven",
6
+ "title": "Gegroepeerde weergave van assistentberichten"
7
+ },
4
8
  "groupChat": {
5
9
  "desc": "Schakel de mogelijkheid in om groepschats met meerdere AI-agenten te organiseren.",
6
10
  "title": "Groepschat (meerdere agenten)"
@@ -1,6 +1,10 @@
1
1
  {
2
2
  "desc": "Tutaj będziemy okresowo aktualizować nowe funkcje, które obecnie testujemy — zapraszamy do wypróbowania!",
3
3
  "features": {
4
+ "assistantMessageGroup": {
5
+ "desc": "Grupowanie wiadomości asystenta i wyników wywołań narzędzi w jednym widoku",
6
+ "title": "Grupowanie wiadomości asystenta"
7
+ },
4
8
  "groupChat": {
5
9
  "desc": "Włącz możliwość organizowania czatów grupowych z wieloma agentami.",
6
10
  "title": "Czat grupowy (wielu agentów)"
@@ -1,6 +1,10 @@
1
1
  {
2
2
  "desc": "Aqui você encontrará atualizações periódicas sobre os novos recursos que estamos explorando. Sinta-se à vontade para testá-los!",
3
3
  "features": {
4
+ "assistantMessageGroup": {
5
+ "desc": "Agrupa as mensagens do assistente e os resultados das ferramentas chamadas para exibição conjunta",
6
+ "title": "Agrupamento de Mensagens do Assistente"
7
+ },
4
8
  "groupChat": {
5
9
  "desc": "Ative a capacidade de orquestração de bate-papo em grupo com múltiplos agentes.",
6
10
  "title": "Bate-papo em Grupo (Múltiplos Agentes)"
@@ -1,6 +1,10 @@
1
1
  {
2
2
  "desc": "Здесь мы будем периодически обновлять информацию о новых функциях, которые мы исследуем. Добро пожаловать на пробное использование!",
3
3
  "features": {
4
+ "assistantMessageGroup": {
5
+ "desc": "Группировка сообщений помощника и результатов вызова инструментов для отображения в одном блоке",
6
+ "title": "Группировка сообщений помощника"
7
+ },
4
8
  "groupChat": {
5
9
  "desc": "Включить возможность организации группового чата с несколькими интеллектуальными агентами.",
6
10
  "title": "Групповой чат (мультиагенты)"
@@ -1,6 +1,10 @@
1
1
  {
2
2
  "desc": "Burada keşfetmekte olduğumuz yeni özellikleri düzenli olarak güncelliyoruz, denemekten çekinmeyin!",
3
3
  "features": {
4
+ "assistantMessageGroup": {
5
+ "desc": "Asistan mesajlarını ve araç çağrısı sonuçlarını gruplar hâlinde göster",
6
+ "title": "Asistan Mesajları Gruplama"
7
+ },
4
8
  "groupChat": {
5
9
  "desc": "Çoklu yapay zeka ajanlarıyla grup sohbeti düzenleme yeteneğini etkinleştirir.",
6
10
  "title": "Grup Sohbeti (Çoklu Ajan)"
@@ -1,6 +1,10 @@
1
1
  {
2
2
  "desc": "Tại đây, chúng tôi sẽ cập nhật định kỳ các tính năng mới đang được khám phá. Rất hoan nghênh bạn dùng thử!",
3
3
  "features": {
4
+ "assistantMessageGroup": {
5
+ "desc": "Tổng hợp tin nhắn trợ lý và kết quả gọi công cụ vào cùng một nhóm để hiển thị",
6
+ "title": "Nhóm tin nhắn trợ lý"
7
+ },
4
8
  "groupChat": {
5
9
  "desc": "Kích hoạt khả năng điều phối trò chuyện nhóm với nhiều tác nhân thông minh.",
6
10
  "title": "Trò chuyện nhóm (đa tác nhân)"
@@ -1,6 +1,10 @@
1
1
  {
2
2
  "desc": "这里会不定期更新我们正在探索的新功能,欢迎试用!",
3
3
  "features": {
4
+ "assistantMessageGroup": {
5
+ "desc": "将助手消息及其工具调用结果聚合到分组里显示",
6
+ "title": "助手消息聚合分组"
7
+ },
4
8
  "groupChat": {
5
9
  "desc": "启用多智能体群聊编排能力。",
6
10
  "title": "群聊(多智能体)"
@@ -1,6 +1,10 @@
1
1
  {
2
2
  "desc": "這裡會不定期更新我們正在探索的新功能,歡迎試用!",
3
3
  "features": {
4
+ "assistantMessageGroup": {
5
+ "desc": "將助手訊息及其工具調用結果彙整成群組顯示",
6
+ "title": "助手訊息彙整群組"
7
+ },
4
8
  "groupChat": {
5
9
  "desc": "啟用多智能體群組聊天編排功能。",
6
10
  "title": "群組聊天(多智能體)"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lobehub/lobehub",
3
- "version": "2.0.0-next.23",
3
+ "version": "2.0.0-next.24",
4
4
  "description": "LobeHub - an open-source,comprehensive AI Agent 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",
@@ -1,12 +1,15 @@
1
1
  import { TopicDisplayMode, UserPreference } from '@lobechat/types';
2
2
 
3
3
  export const DEFAULT_PREFERENCE: UserPreference = {
4
- disableInputMarkdownRender: false,
5
- enableGroupChat: false,
6
4
  guide: {
7
5
  moveSettingsToAvatar: true,
8
6
  topic: true,
9
7
  },
8
+ lab: {
9
+ enableAssistantMessageGroup: false,
10
+ enableGroupChat: false,
11
+ enableInputMarkdown: true,
12
+ },
10
13
  telemetry: null,
11
14
  topicDisplayMode: TopicDisplayMode.ByTime,
12
15
  useCmdEnterToSend: false,
@@ -26,7 +26,6 @@ export * from './session';
26
26
  export * from './tool';
27
27
  export * from './topic';
28
28
  export * from './user';
29
- export * from './user/settings';
30
29
  // FIXME: I think we need a refactor for the "openai" types
31
30
  // it more likes the UI message payload
32
31
  export * from './openai/chat';
@@ -1,88 +1,2 @@
1
- import type { PartialDeep } from 'type-fest';
2
- import { z } from 'zod';
3
-
4
- import { Plans } from '../subscription';
5
- import { TopicDisplayMode } from '../topic';
6
- import { UserSettings } from './settings';
7
-
8
- export interface LobeUser {
9
- avatar?: string;
10
- email?: string | null;
11
- firstName?: string | null;
12
- fullName?: string | null;
13
- id: string;
14
- latestName?: string | null;
15
- username?: string | null;
16
- }
17
-
18
- export const UserGuideSchema = z.object({
19
- /**
20
- * Move the settings button to the avatar dropdown
21
- */
22
- moveSettingsToAvatar: z.boolean().optional(),
23
-
24
- /**
25
- * Topic Guide
26
- */
27
- topic: z.boolean().optional(),
28
-
29
- /**
30
- * tell user that uploaded files can be found in knowledge base
31
- */
32
- uploadFileInKnowledgeBase: z.boolean().optional(),
33
- });
34
-
35
- export type UserGuide = z.infer<typeof UserGuideSchema>;
36
-
37
- export interface UserPreference {
38
- /**
39
- * disable markdown rendering in chat input editor
40
- */
41
- disableInputMarkdownRender?: boolean;
42
- /**
43
- * enable multi-agent group chat mode
44
- */
45
- enableGroupChat?: boolean;
46
- guide?: UserGuide;
47
- hideSyncAlert?: boolean;
48
- telemetry: boolean | null;
49
- topicDisplayMode?: TopicDisplayMode;
50
- /**
51
- * whether to use cmd + enter to send message
52
- */
53
- useCmdEnterToSend?: boolean;
54
- }
55
-
56
- export interface UserInitializationState {
57
- avatar?: string;
58
- canEnablePWAGuide?: boolean;
59
- canEnableTrace?: boolean;
60
- email?: string;
61
- firstName?: string;
62
- fullName?: string;
63
- hasConversation?: boolean;
64
- isOnboard?: boolean;
65
- lastName?: string;
66
- preference: UserPreference;
67
- settings: PartialDeep<UserSettings>;
68
- subscriptionPlan?: Plans;
69
- userId?: string;
70
- username?: string;
71
- }
72
-
73
- export const NextAuthAccountSchame = z.object({
74
- provider: z.string(),
75
- providerAccountId: z.string(),
76
- });
77
-
78
- export const UserPreferenceSchema = z
79
- .object({
80
- disableInputMarkdownRender: z.boolean().optional(),
81
- enableGroupChat: z.boolean().optional(),
82
- guide: UserGuideSchema.optional(),
83
- hideSyncAlert: z.boolean().optional(),
84
- telemetry: z.boolean().nullable(),
85
- topicDisplayMode: z.nativeEnum(TopicDisplayMode).optional(),
86
- useCmdEnterToSend: z.boolean().optional(),
87
- })
88
- .partial();
1
+ export * from './preference';
2
+ export * from './settings';
@@ -0,0 +1,105 @@
1
+ import type { PartialDeep } from 'type-fest';
2
+ import { z } from 'zod';
3
+
4
+ import { Plans } from '../subscription';
5
+ import { TopicDisplayMode } from '../topic';
6
+ import { UserSettings } from './settings';
7
+
8
+ export interface LobeUser {
9
+ avatar?: string;
10
+ email?: string | null;
11
+ firstName?: string | null;
12
+ fullName?: string | null;
13
+ id: string;
14
+ latestName?: string | null;
15
+ username?: string | null;
16
+ }
17
+
18
+ export const UserGuideSchema = z.object({
19
+ /**
20
+ * Move the settings button to the avatar dropdown
21
+ */
22
+ moveSettingsToAvatar: z.boolean().optional(),
23
+
24
+ /**
25
+ * Topic Guide
26
+ */
27
+ topic: z.boolean().optional(),
28
+
29
+ /**
30
+ * tell user that uploaded files can be found in knowledge base
31
+ */
32
+ uploadFileInKnowledgeBase: z.boolean().optional(),
33
+ });
34
+
35
+ export type UserGuide = z.infer<typeof UserGuideSchema>;
36
+
37
+ export const UserLabSchema = z.object({
38
+ /**
39
+ * enable assistant message grouping in chat display
40
+ */
41
+ enableAssistantMessageGroup: z.boolean().optional(),
42
+ /**
43
+ * enable multi-agent group chat mode
44
+ */
45
+ enableGroupChat: z.boolean().optional(),
46
+ /**
47
+ * enable markdown rendering in chat input editor
48
+ */
49
+ enableInputMarkdown: z.boolean().optional(),
50
+ });
51
+
52
+ export type UserLab = z.infer<typeof UserLabSchema>;
53
+
54
+ export interface UserPreference {
55
+ /**
56
+ * disable markdown rendering in chat input editor
57
+ * @deprecated Use lab.enableInputMarkdown instead
58
+ */
59
+ disableInputMarkdownRender?: boolean;
60
+ guide?: UserGuide;
61
+ hideSyncAlert?: boolean;
62
+ /**
63
+ * lab experimental features
64
+ */
65
+ lab?: UserLab;
66
+ telemetry: boolean | null;
67
+ topicDisplayMode?: TopicDisplayMode;
68
+ /**
69
+ * whether to use cmd + enter to send message
70
+ */
71
+ useCmdEnterToSend?: boolean;
72
+ }
73
+
74
+ export interface UserInitializationState {
75
+ avatar?: string;
76
+ canEnablePWAGuide?: boolean;
77
+ canEnableTrace?: boolean;
78
+ email?: string;
79
+ firstName?: string;
80
+ fullName?: string;
81
+ hasConversation?: boolean;
82
+ isOnboard?: boolean;
83
+ lastName?: string;
84
+ preference: UserPreference;
85
+ settings: PartialDeep<UserSettings>;
86
+ subscriptionPlan?: Plans;
87
+ userId?: string;
88
+ username?: string;
89
+ }
90
+
91
+ export const NextAuthAccountSchame = z.object({
92
+ provider: z.string(),
93
+ providerAccountId: z.string(),
94
+ });
95
+
96
+ export const UserPreferenceSchema = z
97
+ .object({
98
+ guide: UserGuideSchema.optional(),
99
+ hideSyncAlert: z.boolean().optional(),
100
+ lab: UserLabSchema.optional(),
101
+ telemetry: z.boolean().nullable(),
102
+ topicDisplayMode: z.nativeEnum(TopicDisplayMode).optional(),
103
+ useCmdEnterToSend: z.boolean().optional(),
104
+ })
105
+ .partial();
package/renovate.json CHANGED
@@ -30,9 +30,7 @@
30
30
  "matchCurrentValue": "^\\d+\\.\\d+\\.\\d+([+-][0-9A-Za-z.-]+)?$",
31
31
  "groupName": null,
32
32
  "separateMinorPatch": true,
33
- "separateMajorMinor": true,
34
- "separateMultipleMinor": true,
35
- "separateMultipleMajor": true
33
+ "separateMajorMinor": true
36
34
  },
37
35
  // 2a) Non-pinned deps: override splitting so patch+minor can be combined
38
36
  {
@@ -70,9 +68,6 @@
70
68
  "rebaseWhen": "conflicted",
71
69
  "schedule": "on sunday before 6:00am",
72
70
  "separateMajorMinor": true,
73
- // Global defaults are fine; rule 2a overrides minor/patch splitting for ranged deps
74
- "separateMinorPatch": true,
75
71
  "separateMultipleMajor": true,
76
- "separateMultipleMinor": true,
77
72
  "timezone": "UTC"
78
73
  }
@@ -6,6 +6,8 @@ import Image from 'next/image';
6
6
  import { PropsWithChildren, memo } from 'react';
7
7
  import { Flexbox } from 'react-layout-kit';
8
8
 
9
+ import { SkeletonSwitch } from '@/components/Skeleton';
10
+
9
11
  interface LabCardProps {
10
12
  checked: boolean;
11
13
  cover?: string;
@@ -80,11 +82,9 @@ const LabCard = memo<PropsWithChildren<LabCardProps>>(
80
82
  <div className={styles.desc}>{desc}</div>
81
83
  {meta ? <div className={styles.meta}>{meta}</div> : null}
82
84
  </Flexbox>
83
- {!loading && (
84
- <Flexbox align={'flex-end'} height={'100%'} justify={'center'} paddingInline={8}>
85
- <Switch checked={checked} onChange={onChange} />
86
- </Flexbox>
87
- )}
85
+ <Flexbox align={'flex-end'} height={'100%'} justify={'center'} paddingInline={8}>
86
+ {loading ? <SkeletonSwitch /> : <Switch checked={checked} onChange={onChange} />}
87
+ </Flexbox>
88
88
  </div>
89
89
  </div>
90
90
  </div>
@@ -1,11 +1,11 @@
1
1
  'use client';
2
2
 
3
- import { memo, useCallback } from 'react';
3
+ import { memo } from 'react';
4
4
  import { useTranslation } from 'react-i18next';
5
5
  import { Flexbox } from 'react-layout-kit';
6
6
 
7
7
  import { useUserStore } from '@/store/user';
8
- import { preferenceSelectors } from '@/store/user/selectors';
8
+ import { labPreferSelectors, preferenceSelectors } from '@/store/user/selectors';
9
9
 
10
10
  import Hero from './components/Hero';
11
11
  import LabCard from './components/LabCard';
@@ -15,7 +15,6 @@ interface LabItem {
15
15
  cover?: string;
16
16
  desc: string;
17
17
  key: string;
18
- onChange: (checked: boolean) => void;
19
18
  title: string;
20
19
  }
21
20
 
@@ -24,40 +23,37 @@ const LabsPage = memo(() => {
24
23
 
25
24
  const [
26
25
  isPreferenceInit,
27
- inputMarkdownRender,
26
+ enableInputMarkdown,
27
+ // enableAssistantMessageGroup,
28
28
  // enableGroupChat,
29
- updatePreference,
29
+ updateLab,
30
30
  ] = useUserStore((s) => [
31
31
  preferenceSelectors.isPreferenceInit(s),
32
- preferenceSelectors.inputMarkdownRender(s),
33
- // preferenceSelectors.enableGroupChat(s),
34
- s.updatePreference,
32
+ labPreferSelectors.enableInputMarkdown(s),
33
+ // labPreferSelectors.enableAssistantMessageGroup(s),
34
+ // labPreferSelectors.enableGroupChat(s),
35
+ s.updateLab,
35
36
  ]);
36
37
 
37
- const onToggleMarkdown = useCallback(
38
- (checked: boolean) => updatePreference({ disableInputMarkdownRender: !checked }),
39
- [updatePreference],
40
- );
41
- // const onToggleGroupChat = useCallback(
42
- // (checked: boolean) => updatePreference({ enableGroupChat: checked }),
43
- // [updatePreference],
44
- // );
45
-
46
38
  const labItems: LabItem[] = [
47
39
  {
48
- checked: inputMarkdownRender,
40
+ checked: enableInputMarkdown,
49
41
  cover: 'https://github.com/user-attachments/assets/0527a966-3d95-46b4-b880-c0f3fca18f02',
50
42
  desc: t('features.inputMarkdown.desc'),
51
- key: 'inputMarkdown',
52
- onChange: onToggleMarkdown,
43
+ key: 'enableInputMarkdown',
53
44
  title: t('features.inputMarkdown.title'),
54
45
  },
55
46
  // {
47
+ // checked: enableAssistantMessageGroup,
48
+ // desc: t('features.assistantMessageGroup.desc'),
49
+ // key: 'enableAssistantMessageGroup',
50
+ // title: t('features.assistantMessageGroup.title'),
51
+ // },
52
+ // {
56
53
  // checked: enableGroupChat,
57
54
  // cover: 'https://github.com/user-attachments/assets/72894d24-a96a-4d7c-a823-ff9e6a1a8b6d',
58
55
  // desc: t('features.groupChat.desc'),
59
56
  // key: 'groupChat',
60
- // onChange: onToggleGroupChat,
61
57
  // title: t('features.groupChat.title'),
62
58
  // },
63
59
  ];
@@ -73,7 +69,7 @@ const LabsPage = memo(() => {
73
69
  desc={item.desc}
74
70
  key={item.key}
75
71
  loading={!isPreferenceInit}
76
- onChange={item.onChange}
72
+ onChange={(checked: boolean) => updateLab({ [item.key]: checked })}
77
73
  title={item.title}
78
74
  />
79
75
  ))}
@@ -6,11 +6,11 @@ import { ModelProvider } from 'model-bank';
6
6
  import { useTranslation } from 'react-i18next';
7
7
 
8
8
  import { FormInput, FormPassword } from '@/components/FormInput';
9
+ import { SkeletonInput } from '@/components/Skeleton';
9
10
  import { AzureProviderCard } from '@/config/modelProviders';
10
11
  import { aiModelSelectors, aiProviderSelectors, useAiInfraStore } from '@/store/aiInfra';
11
12
 
12
13
  import { KeyVaultsConfigKey, LLMProviderApiTokenKey, LLMProviderBaseUrlKey } from '../../const';
13
- import { SkeletonInput } from '../../features/ProviderConfig';
14
14
  import { ProviderItem } from '../../type';
15
15
  import ProviderDetail from '../default';
16
16
 
@@ -4,11 +4,11 @@ import { ModelProvider } from 'model-bank';
4
4
  import { useTranslation } from 'react-i18next';
5
5
 
6
6
  import { FormInput, FormPassword } from '@/components/FormInput';
7
+ import { SkeletonInput } from '@/components/Skeleton';
7
8
  import { AzureAIProviderCard } from '@/config/modelProviders';
8
9
  import { aiProviderSelectors, useAiInfraStore } from '@/store/aiInfra';
9
10
 
10
11
  import { KeyVaultsConfigKey, LLMProviderApiTokenKey, LLMProviderBaseUrlKey } from '../../const';
11
- import { SkeletonInput } from '../../features/ProviderConfig';
12
12
  import { ProviderItem } from '../../type';
13
13
  import ProviderDetail from '../default';
14
14
 
@@ -4,12 +4,12 @@ import { Select } from '@lobehub/ui';
4
4
  import { useTranslation } from 'react-i18next';
5
5
 
6
6
  import { FormPassword } from '@/components/FormInput';
7
+ import { SkeletonInput } from '@/components/Skeleton';
7
8
  import { BedrockProviderCard } from '@/config/modelProviders';
8
9
  import { aiProviderSelectors, useAiInfraStore } from '@/store/aiInfra';
9
10
  import { GlobalLLMProviderKey } from '@/types/user/settings';
10
11
 
11
12
  import { KeyVaultsConfigKey } from '../../const';
12
- import { SkeletonInput } from '../../features/ProviderConfig';
13
13
  import { ProviderItem } from '../../type';
14
14
  import ProviderDetail from '../default';
15
15
 
@@ -3,12 +3,12 @@
3
3
  import { useTranslation } from 'react-i18next';
4
4
 
5
5
  import { FormInput, FormPassword } from '@/components/FormInput';
6
+ import { SkeletonInput } from '@/components/Skeleton';
6
7
  import { CloudflareProviderCard } from '@/config/modelProviders';
7
8
  import { aiProviderSelectors, useAiInfraStore } from '@/store/aiInfra';
8
9
  import { GlobalLLMProviderKey } from '@/types/user/settings';
9
10
 
10
11
  import { KeyVaultsConfigKey } from '../../const';
11
- import { SkeletonInput } from '../../features/ProviderConfig';
12
12
  import { ProviderItem } from '../../type';
13
13
  import ProviderDetail from '../default';
14
14
 
@@ -5,12 +5,12 @@ import { useTranslation } from 'react-i18next';
5
5
 
6
6
  import { FormInput, FormPassword } from '@/components/FormInput';
7
7
  import KeyValueEditor from '@/components/KeyValueEditor';
8
+ import { SkeletonInput } from '@/components/Skeleton';
8
9
  import { ComfyUIProviderCard } from '@/config/modelProviders';
9
10
  import { aiProviderSelectors, useAiInfraStore } from '@/store/aiInfra';
10
11
  import { GlobalLLMProviderKey } from '@/types/user/settings';
11
12
 
12
13
  import { KeyVaultsConfigKey } from '../../const';
13
- import { SkeletonInput } from '../../features/ProviderConfig';
14
14
  import { ProviderItem } from '../../type';
15
15
  import ProviderDetail from '../default';
16
16
 
@@ -5,12 +5,12 @@ import { createStyles } from 'antd-style';
5
5
  import { useTranslation } from 'react-i18next';
6
6
 
7
7
  import { FormPassword } from '@/components/FormInput';
8
+ import { SkeletonInput } from '@/components/Skeleton';
8
9
  import { GithubProviderCard } from '@/config/modelProviders';
9
10
  import { aiProviderSelectors, useAiInfraStore } from '@/store/aiInfra';
10
11
  import { GlobalLLMProviderKey } from '@/types/user/settings';
11
12
 
12
13
  import { KeyVaultsConfigKey, LLMProviderApiTokenKey } from '../../const';
13
- import { SkeletonInput } from '../../features/ProviderConfig';
14
14
  import { ProviderItem } from '../../type';
15
15
  import ProviderDetail from '../default';
16
16
 
@@ -5,12 +5,12 @@ import { createStyles } from 'antd-style';
5
5
  import { useTranslation } from 'react-i18next';
6
6
 
7
7
  import { FormPassword } from '@/components/FormInput';
8
+ import { SkeletonInput } from '@/components/Skeleton';
8
9
  import { VertexAIProviderCard } from '@/config/modelProviders';
9
10
  import { aiProviderSelectors, useAiInfraStore } from '@/store/aiInfra';
10
11
  import { GlobalLLMProviderKey } from '@/types/user/settings';
11
12
 
12
13
  import { KeyVaultsConfigKey, LLMProviderApiTokenKey } from '../../const';
13
- import { SkeletonInput } from '../../features/ProviderConfig';
14
14
  import { ProviderItem } from '../../type';
15
15
  import ProviderDetail from '../default';
16
16
 
@@ -21,6 +21,7 @@ import urlJoin from 'url-join';
21
21
  import { z } from 'zod';
22
22
 
23
23
  import { FormInput, FormPassword } from '@/components/FormInput';
24
+ import { SkeletonInput, SkeletonSwitch } from '@/components/Skeleton';
24
25
  import { FORM_STYLE } from '@/const/layoutTokens';
25
26
  import { AES_GCM_URL, BASE_PROVIDER_DOC_URL } from '@/const/url';
26
27
  import { isDesktop, isServerMode } from '@/const/version';
@@ -34,7 +35,6 @@ import {
34
35
  import { KeyVaultsConfigKey, LLMProviderApiTokenKey, LLMProviderBaseUrlKey } from '../../const';
35
36
  import Checker, { CheckErrorRender } from './Checker';
36
37
  import EnableSwitch from './EnableSwitch';
37
- import { SkeletonInput } from './SkeletonInput';
38
38
  import UpdateProviderInfo from './UpdateProviderInfo';
39
39
 
40
40
  const useStyles = createStyles(({ css, prefixCls, responsive, token }) => ({
@@ -298,7 +298,7 @@ const ProviderConfig = memo<ProviderConfigProps>(
298
298
  (showApiKey && isProviderApiKeyNotEmpty));
299
299
  const clientFetchItem = showClientFetch && {
300
300
  children: isLoading ? (
301
- <Skeleton.Button active className={styles.switchLoading} />
301
+ <SkeletonSwitch />
302
302
  ) : (
303
303
  <Switch checked={isFetchOnClient} disabled={configUpdating} />
304
304
  ),
@@ -424,5 +424,3 @@ const ProviderConfig = memo<ProviderConfigProps>(
424
424
  );
425
425
 
426
426
  export default ProviderConfig;
427
-
428
- export { SkeletonInput } from './SkeletonInput';
@@ -0,0 +1,13 @@
1
+ import { Skeleton } from 'antd';
2
+ import { css, cx } from 'antd-style';
3
+
4
+ const switchLoading = cx(css`
5
+ width: 44px !important;
6
+ min-width: 44px !important;
7
+ height: 22px !important;
8
+ border-radius: 12px !important;
9
+ `);
10
+
11
+ export const SkeletonSwitch = () => {
12
+ return <Skeleton.Button active className={switchLoading} />;
13
+ };
@@ -0,0 +1,2 @@
1
+ export * from './SkeletonInput';
2
+ export * from './SkeletonSwitch';
@@ -4,7 +4,7 @@ import { memo, useMemo } from 'react';
4
4
  import { useGlobalStore } from '@/store/global';
5
5
  import { systemStatusSelectors } from '@/store/global/selectors';
6
6
  import { useUserStore } from '@/store/user';
7
- import { preferenceSelectors } from '@/store/user/slices/preference/selectors';
7
+ import { labPreferSelectors } from '@/store/user/slices/preference/selectors';
8
8
 
9
9
  import { ActionKeys, actionMap } from '../ActionBar/config';
10
10
  import { useChatInputStore } from '../store';
@@ -44,7 +44,7 @@ const ActionToolbar = memo(() => {
44
44
  systemStatusSelectors.expandInputActionbar(s),
45
45
  s.toggleExpandInputActionbar,
46
46
  ]);
47
- const enableRichRender = useUserStore(preferenceSelectors.inputMarkdownRender);
47
+ const enableRichRender = useUserStore(labPreferSelectors.enableInputMarkdown);
48
48
 
49
49
  const leftActions = useChatInputStore((s) =>
50
50
  s.leftActions.filter((item) => (enableRichRender ? true : item !== 'typo')),
@@ -21,7 +21,7 @@ import { useHotkeysContext } from 'react-hotkeys-hook';
21
21
  import { useTranslation } from 'react-i18next';
22
22
 
23
23
  import { useUserStore } from '@/store/user';
24
- import { preferenceSelectors, settingsSelectors } from '@/store/user/selectors';
24
+ import { labPreferSelectors, preferenceSelectors, settingsSelectors } from '@/store/user/selectors';
25
25
 
26
26
  import { useChatInputStore, useStoreApi } from '../store';
27
27
  import Placeholder from './Placeholder';
@@ -69,7 +69,7 @@ const InputEditor = memo<{ defaultRows?: number }>(({ defaultRows = 2 }) => {
69
69
  };
70
70
  }, [state.isEmpty]);
71
71
 
72
- const enableRichRender = useUserStore(preferenceSelectors.inputMarkdownRender);
72
+ const enableRichRender = useUserStore(labPreferSelectors.enableInputMarkdown);
73
73
 
74
74
  const richRenderProps = useMemo(
75
75
  () =>
@@ -1,6 +1,10 @@
1
1
  export default {
2
2
  desc: '这里会不定期更新我们正在探索的新功能,欢迎试用!',
3
3
  features: {
4
+ assistantMessageGroup: {
5
+ desc: '将助手消息及其工具调用结果聚合到分组里显示',
6
+ title: '助手消息聚合分组',
7
+ },
4
8
  groupChat: {
5
9
  desc: '启用多智能体群聊编排能力。',
6
10
  title: '群聊(多智能体)',
@@ -1,7 +1,6 @@
1
1
  import {
2
2
  CreateMessageParamsSchema,
3
3
  CreateNewMessageParamsSchema,
4
- UIChatMessage,
5
4
  UpdateMessageParamsSchema,
6
5
  UpdateMessageRAGParamsSchema,
7
6
  } from '@lobechat/types';
@@ -14,8 +13,6 @@ import { authedProcedure, publicProcedure, router } from '@/libs/trpc/lambda';
14
13
  import { serverDatabase } from '@/libs/trpc/lambda/middleware';
15
14
  import { FileService } from '@/server/services/file';
16
15
 
17
- type ChatMessageList = UIChatMessage[];
18
-
19
16
  const messageProcedure = authedProcedure.use(serverDatabase).use(async (opts) => {
20
17
  const { ctx } = opts;
21
18
 
@@ -72,22 +69,6 @@ export const messageRouter = router({
72
69
  });
73
70
  }),
74
71
 
75
- // TODO: it will be removed in V2
76
- getAllMessages: messageProcedure.query(async ({ ctx }): Promise<ChatMessageList> => {
77
- return ctx.messageModel.queryAll() as any;
78
- }),
79
-
80
- // TODO: it will be removed in V2
81
- getAllMessagesInSession: messageProcedure
82
- .input(
83
- z.object({
84
- sessionId: z.string().nullable().optional(),
85
- }),
86
- )
87
- .query(async ({ ctx, input }): Promise<ChatMessageList> => {
88
- return ctx.messageModel.queryBySessionId(input.sessionId) as any;
89
- }),
90
-
91
72
  getHeatmaps: messageProcedure.query(async ({ ctx }) => {
92
73
  return ctx.messageModel.getHeatmaps();
93
74
  }),
@@ -101,16 +82,20 @@ export const messageRouter = router({
101
82
  pageSize: z.number().optional(),
102
83
  sessionId: z.string().nullable().optional(),
103
84
  topicId: z.string().nullable().optional(),
85
+ useGroup: z.boolean().optional(),
104
86
  }),
105
87
  )
106
88
  .query(async ({ input, ctx }) => {
107
89
  if (!ctx.userId) return [];
108
90
  const serverDB = await getServerDB();
109
91
 
92
+ const { useGroup, ...queryParams } = input;
93
+
110
94
  const messageModel = new MessageModel(serverDB, ctx.userId);
111
95
  const fileService = new FileService(serverDB, ctx.userId);
112
96
 
113
- return messageModel.query(input, {
97
+ return messageModel.query(queryParams, {
98
+ groupAssistantMessages: useGroup ?? false,
114
99
  postProcessUrl: (path) => fileService.getFullFileUrl(path),
115
100
  });
116
101
  }),
@@ -39,16 +39,6 @@ export class ServerService implements IMessageService {
39
39
  return data as unknown as UIChatMessage[];
40
40
  };
41
41
 
42
- getAllMessages: IMessageService['getAllMessages'] = async () => {
43
- return lambdaClient.message.getAllMessages.query();
44
- };
45
-
46
- getAllMessagesInSession: IMessageService['getAllMessagesInSession'] = async (sessionId) => {
47
- return lambdaClient.message.getAllMessagesInSession.query({
48
- sessionId: this.toDbSessionId(sessionId),
49
- });
50
- };
51
-
52
42
  countMessages: IMessageService['countMessages'] = async (params) => {
53
43
  return lambdaClient.message.count.query(params);
54
44
  };
@@ -21,8 +21,6 @@ export interface IMessageService {
21
21
 
22
22
  getMessages(sessionId: string, topicId?: string, groupId?: string): Promise<UIChatMessage[]>;
23
23
  getGroupMessages(groupId: string, topicId?: string): Promise<UIChatMessage[]>;
24
- getAllMessages(): Promise<UIChatMessage[]>;
25
- getAllMessagesInSession(sessionId: string): Promise<UIChatMessage[]>;
26
24
  countMessages(params?: {
27
25
  endDate?: string;
28
26
  range?: [string, string];
@@ -1,5 +1,5 @@
1
1
  export { authSelectors, userProfileSelectors } from './slices/auth/selectors';
2
- export { preferenceSelectors } from './slices/preference/selectors';
2
+ export { labPreferSelectors, preferenceSelectors } from './slices/preference/selectors';
3
3
  export {
4
4
  keyVaultsConfigSelectors,
5
5
  settingsSelectors,
@@ -2,7 +2,7 @@ import type { StateCreator } from 'zustand/vanilla';
2
2
 
3
3
  import { userService } from '@/services/user';
4
4
  import type { UserStore } from '@/store/user';
5
- import { UserGuide, UserPreference } from '@/types/user';
5
+ import { UserGuide, UserLab, UserPreference } from '@/types/user';
6
6
  import { merge } from '@/utils/merge';
7
7
  import { setNamespace } from '@/utils/storeDebug';
8
8
 
@@ -10,6 +10,7 @@ const n = setNamespace('preference');
10
10
 
11
11
  export interface PreferenceAction {
12
12
  updateGuideState: (guide: Partial<UserGuide>) => Promise<void>;
13
+ updateLab: (lab: Partial<UserLab>) => Promise<void>;
13
14
  updatePreference: (preference: Partial<UserPreference>, action?: any) => Promise<void>;
14
15
  }
15
16
 
@@ -25,6 +26,12 @@ export const createPreferenceSlice: StateCreator<
25
26
  await updatePreference({ guide: nextGuide });
26
27
  },
27
28
 
29
+ updateLab: async (lab) => {
30
+ const { updatePreference } = get();
31
+ const nextLab = merge(get().preference.lab, lab);
32
+ await updatePreference({ lab: nextLab }, n('updateLab'));
33
+ },
34
+
28
35
  updatePreference: async (preference, action) => {
29
36
  const nextPreference = merge(get().preference, preference);
30
37
 
@@ -0,0 +1,2 @@
1
+ export * from './labPrefer';
2
+ export * from './preference';
@@ -0,0 +1,13 @@
1
+ import { DEFAULT_PREFERENCE } from '@lobechat/const';
2
+
3
+ import type { UserState } from '@/store/user/initialState';
4
+
5
+ export const labPreferSelectors = {
6
+ enableAssistantMessageGroup: (s: UserState): boolean =>
7
+ s.preference.lab?.enableAssistantMessageGroup ??
8
+ DEFAULT_PREFERENCE.lab!.enableAssistantMessageGroup!,
9
+ enableGroupChat: (s: UserState): boolean =>
10
+ s.preference.lab?.enableGroupChat ?? DEFAULT_PREFERENCE.lab!.enableGroupChat!,
11
+ enableInputMarkdown: (s: UserState): boolean =>
12
+ s.preference.lab?.enableInputMarkdown ?? DEFAULT_PREFERENCE.lab!.enableInputMarkdown!,
13
+ };
@@ -21,10 +21,8 @@ const shouldTriggerFileInKnowledgeBaseTip = (s: UserStore) =>
21
21
  const isPreferenceInit = (s: UserStore) => s.isUserStateInit;
22
22
 
23
23
  export const preferenceSelectors = {
24
- enableGroupChat: (s: UserStore) => s.preference.enableGroupChat || false,
25
24
  hideSettingsMoveGuide,
26
25
  hideSyncAlert,
27
- inputMarkdownRender: (s: UserStore) => !s.preference.disableInputMarkdownRender,
28
26
  isPreferenceInit,
29
27
  shouldTriggerFileInKnowledgeBaseTip,
30
28
  showUploadFileInKnowledgeBaseTip,