@lobehub/lobehub 2.0.0-next.322 → 2.0.0-next.323

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 (106) hide show
  1. package/CHANGELOG.md +55 -0
  2. package/apps/desktop/src/main/core/infrastructure/UpdaterManager.ts +9 -76
  3. package/apps/desktop/src/main/core/infrastructure/__tests__/UpdaterManager.test.ts +0 -1
  4. package/apps/desktop/src/main/modules/updater/configs.ts +0 -4
  5. package/changelog/v1.json +15 -0
  6. package/e2e/src/mocks/llm/index.ts +3 -3
  7. package/locales/ar/common.json +5 -0
  8. package/locales/ar/error.json +10 -1
  9. package/locales/bg-BG/common.json +5 -0
  10. package/locales/bg-BG/error.json +10 -1
  11. package/locales/de-DE/common.json +5 -0
  12. package/locales/de-DE/error.json +10 -1
  13. package/locales/en-US/common.json +5 -0
  14. package/locales/es-ES/common.json +5 -0
  15. package/locales/es-ES/error.json +10 -1
  16. package/locales/fa-IR/common.json +5 -0
  17. package/locales/fa-IR/error.json +10 -1
  18. package/locales/fr-FR/common.json +5 -0
  19. package/locales/fr-FR/error.json +10 -1
  20. package/locales/it-IT/common.json +5 -0
  21. package/locales/it-IT/error.json +10 -1
  22. package/locales/ja-JP/common.json +5 -0
  23. package/locales/ja-JP/error.json +10 -1
  24. package/locales/ko-KR/common.json +5 -0
  25. package/locales/ko-KR/error.json +10 -1
  26. package/locales/nl-NL/common.json +5 -0
  27. package/locales/nl-NL/error.json +10 -1
  28. package/locales/pl-PL/common.json +5 -0
  29. package/locales/pl-PL/error.json +10 -1
  30. package/locales/pt-BR/common.json +5 -0
  31. package/locales/pt-BR/error.json +10 -1
  32. package/locales/ru-RU/common.json +5 -0
  33. package/locales/ru-RU/error.json +10 -1
  34. package/locales/tr-TR/common.json +5 -0
  35. package/locales/tr-TR/error.json +10 -1
  36. package/locales/vi-VN/common.json +5 -0
  37. package/locales/vi-VN/error.json +10 -1
  38. package/locales/zh-CN/common.json +5 -0
  39. package/locales/zh-TW/common.json +5 -0
  40. package/locales/zh-TW/error.json +10 -1
  41. package/package.json +2 -2
  42. package/packages/business/const/src/branding.ts +1 -0
  43. package/packages/business/const/src/llm.ts +2 -1
  44. package/packages/const/src/settings/llm.ts +2 -1
  45. package/packages/const/src/settings/systemAgent.ts +12 -7
  46. package/packages/database/src/models/agent.ts +18 -1
  47. package/packages/database/src/models/chatGroup.ts +18 -1
  48. package/packages/database/src/types/chatGroup.ts +1 -0
  49. package/packages/model-bank/package.json +1 -1
  50. package/packages/model-bank/src/aiModels/index.ts +2 -2
  51. package/packages/model-bank/src/aiModels/lobehub/chat/anthropic.ts +256 -0
  52. package/packages/model-bank/src/aiModels/lobehub/chat/deepseek.ts +45 -0
  53. package/packages/model-bank/src/aiModels/lobehub/chat/google.ts +267 -0
  54. package/packages/model-bank/src/aiModels/lobehub/chat/index.ts +26 -0
  55. package/packages/model-bank/src/aiModels/lobehub/chat/minimax.ts +75 -0
  56. package/packages/model-bank/src/aiModels/lobehub/chat/moonshot.ts +28 -0
  57. package/packages/model-bank/src/aiModels/lobehub/chat/openai.ts +345 -0
  58. package/packages/model-bank/src/aiModels/lobehub/chat/xai.ts +32 -0
  59. package/packages/model-bank/src/aiModels/lobehub/image.ts +240 -0
  60. package/packages/model-bank/src/aiModels/lobehub/index.ts +10 -0
  61. package/packages/model-bank/src/aiModels/lobehub/utils.ts +58 -0
  62. package/packages/model-bank/src/modelProviders/index.ts +10 -10
  63. package/packages/model-runtime/src/core/streams/qwen.test.ts +320 -0
  64. package/packages/model-runtime/src/core/streams/qwen.ts +19 -10
  65. package/packages/types/package.json +1 -1
  66. package/packages/types/src/agentGroup/index.ts +2 -0
  67. package/packages/types/src/discover/assistants.ts +9 -0
  68. package/packages/types/src/discover/fork.ts +163 -0
  69. package/packages/types/src/discover/groupAgents.ts +13 -4
  70. package/packages/types/src/discover/index.ts +9 -0
  71. package/src/app/[variants]/(auth)/_layout/index.tsx +2 -1
  72. package/src/app/[variants]/(auth)/auth-error/page.tsx +5 -5
  73. package/src/app/[variants]/(main)/agent/_layout/Sidebar/Topic/List/Item/index.tsx +1 -2
  74. package/src/app/[variants]/(main)/community/(detail)/agent/features/Header.tsx +37 -0
  75. package/src/app/[variants]/(main)/community/(detail)/agent/features/Sidebar/ActionButton/ForkAndChat.tsx +133 -0
  76. package/src/app/[variants]/(main)/community/(detail)/agent/features/Sidebar/ActionButton/index.tsx +2 -2
  77. package/src/app/[variants]/(main)/community/(detail)/group_agent/features/Details/index.tsx +7 -10
  78. package/src/app/[variants]/(main)/community/(detail)/group_agent/features/Sidebar/ActionButton/ForkGroupAndChat.tsx +208 -0
  79. package/src/app/[variants]/(main)/community/(detail)/group_agent/features/Sidebar/ActionButton/index.tsx +2 -2
  80. package/src/app/[variants]/(main)/community/(detail)/user/features/DetailProvider.tsx +2 -0
  81. package/src/app/[variants]/(main)/community/(detail)/user/features/UserContent.tsx +7 -0
  82. package/src/app/[variants]/(main)/community/(detail)/user/features/UserForkedAgentGroups.tsx +63 -0
  83. package/src/app/[variants]/(main)/community/(detail)/user/features/UserForkedAgents.tsx +61 -0
  84. package/src/app/[variants]/(main)/community/(detail)/user/index.tsx +3 -1
  85. package/src/app/[variants]/(main)/group/_layout/Sidebar/Topic/List/Item/index.tsx +1 -2
  86. package/src/app/[variants]/(main)/settings/profile/index.tsx +92 -68
  87. package/src/app/[variants]/(mobile)/chat/features/Topic/index.tsx +2 -1
  88. package/src/features/CommandMenu/AskAgentCommands.tsx +105 -0
  89. package/src/features/CommandMenu/CommandMenuContext.tsx +57 -38
  90. package/src/features/CommandMenu/components/CommandInput.tsx +43 -9
  91. package/src/features/CommandMenu/index.tsx +89 -27
  92. package/src/features/CommandMenu/types.ts +6 -0
  93. package/src/features/CommandMenu/useCommandMenu.ts +62 -39
  94. package/src/locales/default/common.ts +5 -0
  95. package/src/locales/default/discover.ts +371 -0
  96. package/src/server/globalConfig/parseMemoryExtractionConfig.ts +7 -8
  97. package/src/server/routers/lambda/agent.ts +14 -0
  98. package/src/server/routers/lambda/agentGroup.ts +19 -3
  99. package/src/server/routers/lambda/market/agent.ts +234 -26
  100. package/src/server/routers/lambda/market/agentGroup.ts +204 -1
  101. package/src/server/services/discover/index.ts +52 -2
  102. package/src/services/agent.ts +8 -0
  103. package/src/services/chatGroup/index.ts +8 -0
  104. package/src/services/marketApi.ts +78 -0
  105. package/src/store/user/slices/settings/selectors/__snapshots__/settings.test.ts.snap +12 -12
  106. package/packages/model-bank/src/aiModels/lobehub.ts +0 -1315
@@ -1,6 +1,8 @@
1
1
  'use client';
2
2
 
3
+ import { Avatar } from '@lobehub/ui';
3
4
  import { Command } from 'cmdk';
5
+ import { CornerDownLeft } from 'lucide-react';
4
6
  import { memo, useEffect, useState } from 'react';
5
7
  import { createPortal } from 'react-dom';
6
8
  import { useTranslation } from 'react-i18next';
@@ -9,6 +11,7 @@ import { useLocation } from 'react-router-dom';
9
11
  import { useGlobalStore } from '@/store/global';
10
12
 
11
13
  import AskAIMenu from './AskAIMenu';
14
+ import AskAgentCommands from './AskAgentCommands';
12
15
  import { CommandMenuProvider, useCommandMenuContext } from './CommandMenuContext';
13
16
  import MainMenu from './MainMenu';
14
17
  import SearchResults from './SearchResults';
@@ -23,10 +26,19 @@ import { useCommandMenu } from './useCommandMenu';
23
26
  */
24
27
  const CommandMenuContent = memo(() => {
25
28
  const { t } = useTranslation('common');
26
- const { closeCommandMenu, handleBack, hasSearch, isSearching, searchQuery, searchResults } =
27
- useCommandMenu();
28
-
29
- const { setPages, page, pages, search, setTypeFilter, typeFilter } = useCommandMenuContext();
29
+ const {
30
+ closeCommandMenu,
31
+ handleBack,
32
+ handleSendToSelectedAgent,
33
+ hasSearch,
34
+ isSearching,
35
+ searchQuery,
36
+ searchResults,
37
+ selectedAgent,
38
+ } = useCommandMenu();
39
+
40
+ const { setPages, page, pages, search, setTypeFilter, setSelectedAgent, typeFilter } =
41
+ useCommandMenuContext();
30
42
 
31
43
  return (
32
44
  <div className={styles.overlay} onClick={closeCommandMenu}>
@@ -34,40 +46,81 @@ const CommandMenuContent = memo(() => {
34
46
  <Command
35
47
  className={styles.commandRoot}
36
48
  onKeyDown={(e) => {
49
+ // Enter key to send message to selected agent
50
+ if (e.key === 'Enter' && selectedAgent && search.trim()) {
51
+ e.preventDefault();
52
+ handleSendToSelectedAgent();
53
+ return;
54
+ }
37
55
  // Tab key to ask AI
38
- if (e.key === 'Tab' && page !== 'ask-ai') {
56
+ if (e.key === 'Tab' && page !== 'ask-ai' && !selectedAgent) {
39
57
  e.preventDefault();
40
58
  setPages([...pages, 'ask-ai']);
41
59
  return;
42
60
  }
43
- // Escape goes to previous page or closes
61
+ // Escape goes to previous page, clears selected agent, or closes
44
62
  if (e.key === 'Escape') {
45
63
  e.preventDefault();
46
- if (pages.length > 0) {
64
+ if (selectedAgent) {
65
+ setSelectedAgent(undefined);
66
+ } else if (pages.length > 0) {
47
67
  handleBack();
48
68
  } else {
49
69
  closeCommandMenu();
50
70
  }
51
71
  }
52
- // Backspace goes to previous page when search is empty
53
- if (e.key === 'Backspace' && !search && pages.length > 0) {
54
- e.preventDefault();
55
- setPages((prev) => prev.slice(0, -1));
72
+ // Backspace clears selected agent when search is empty, or goes to previous page
73
+ if (e.key === 'Backspace' && !search) {
74
+ if (selectedAgent) {
75
+ e.preventDefault();
76
+ setSelectedAgent(undefined);
77
+ } else if (pages.length > 0) {
78
+ e.preventDefault();
79
+ setPages((prev) => prev.slice(0, -1));
80
+ }
56
81
  }
57
82
  }}
58
- shouldFilter={page !== 'ask-ai'}
83
+ shouldFilter={page !== 'ask-ai' && !selectedAgent && !search.trimStart().startsWith('@')}
59
84
  >
60
85
  <CommandInput />
61
86
 
62
87
  <Command.List>
63
88
  <Command.Empty>{t('cmdk.noResults')}</Command.Empty>
64
89
 
65
- {!page && <MainMenu />}
90
+ {/* Show send command when agent is selected */}
91
+ {selectedAgent && (
92
+ <Command.Group>
93
+ <Command.Item
94
+ disabled={!search.trim()}
95
+ onSelect={handleSendToSelectedAgent}
96
+ value="send-to-agent"
97
+ >
98
+ <Avatar
99
+ avatar={selectedAgent.avatar}
100
+ emojiScaleWithBackground
101
+ shape="square"
102
+ size={20}
103
+ />
104
+ <div className={styles.itemContent}>
105
+ <div className={styles.itemLabel}>
106
+ {t('cmdk.sendToAgent', { agent: selectedAgent.title } as any)}
107
+ </div>
108
+ </div>
109
+ <CornerDownLeft className={styles.icon} />
110
+ </Command.Item>
111
+ </Command.Group>
112
+ )}
113
+
114
+ {/* @ mention agent commands */}
115
+ {!page && !selectedAgent && <AskAgentCommands />}
116
+
117
+ {/* Hide MainMenu and SearchResults when in @ mention mode */}
118
+ {!page && !selectedAgent && !search.trimStart().startsWith('@') && <MainMenu />}
66
119
 
67
120
  {page === 'theme' && <ThemeMenu />}
68
121
  {page === 'ask-ai' && <AskAIMenu />}
69
122
 
70
- {!page && hasSearch && (
123
+ {!page && !selectedAgent && hasSearch && !search.trimStart().startsWith('@') && (
71
124
  <SearchResults
72
125
  isLoading={isSearching}
73
126
  onClose={closeCommandMenu}
@@ -109,27 +162,36 @@ const CommandMenu = memo(() => {
109
162
  useEffect(() => {
110
163
  if (!mounted) return;
111
164
 
112
- const findAppRoot = () => {
113
- const appElement = document.querySelector('.ant-app') as HTMLElement;
114
- if (appElement) {
115
- setAppRoot(appElement);
116
- } else {
117
- // Fallback to body if App root not found
118
- setAppRoot(document.body);
165
+ const appElement = document.querySelector('.ant-app') as HTMLElement;
166
+ if (appElement) {
167
+ setAppRoot(appElement);
168
+ return;
169
+ }
170
+
171
+ // Fallback: use MutationObserver only if .ant-app not found yet
172
+ // Observe only direct children of body for better performance
173
+ const observer = new MutationObserver((_, obs) => {
174
+ const el = document.querySelector('.ant-app') as HTMLElement;
175
+ if (el) {
176
+ setAppRoot(el);
177
+ obs.disconnect(); // Stop observing once found
119
178
  }
120
- };
121
-
122
- findAppRoot();
179
+ });
123
180
 
124
- // Use MutationObserver to handle dynamic rendering
125
- const observer = new MutationObserver(findAppRoot);
126
181
  observer.observe(document.body, {
127
182
  childList: true,
128
- subtree: true,
183
+ subtree: false, // Only watch direct children, not entire DOM tree
129
184
  });
130
185
 
186
+ // Fallback timeout: if .ant-app not found after 2s, use body
187
+ const timeoutId = setTimeout(() => {
188
+ observer.disconnect();
189
+ setAppRoot((prev) => prev || document.body);
190
+ }, 2000);
191
+
131
192
  return () => {
132
193
  observer.disconnect();
194
+ clearTimeout(timeoutId);
133
195
  };
134
196
  }, [mounted]);
135
197
 
@@ -4,6 +4,12 @@ export interface ChatMessage {
4
4
  role: 'user' | 'assistant';
5
5
  }
6
6
 
7
+ export interface SelectedAgent {
8
+ avatar: string;
9
+ id: string;
10
+ title: string;
11
+ }
12
+
7
13
  export type ThemeMode = 'light' | 'dark' | 'system';
8
14
 
9
15
  export type PageType = 'theme' | 'ask-ai' | string;
@@ -1,6 +1,6 @@
1
1
  import { useDebounce } from 'ahooks';
2
2
  import { useTheme as useNextThemesTheme } from 'next-themes';
3
- import { useEffect, useMemo } from 'react';
3
+ import { useCallback, useEffect, useMemo } from 'react';
4
4
  import { useNavigate } from 'react-router-dom';
5
5
  import useSWR from 'swr';
6
6
 
@@ -35,6 +35,8 @@ export const useCommandMenu = () => {
35
35
  page,
36
36
  menuContext: context,
37
37
  pathname,
38
+ selectedAgent,
39
+ setSelectedAgent,
38
40
  } = useCommandMenuContext();
39
41
 
40
42
  const navigate = useNavigate();
@@ -92,48 +94,66 @@ export const useCommandMenu = () => {
92
94
  }
93
95
  }, [open]);
94
96
 
95
- const closeCommandMenu = () => {
97
+ const closeCommandMenu = useCallback(() => {
96
98
  setOpen({ showCommandMenu: false });
97
- };
99
+ }, [setOpen]);
98
100
 
99
- const handleNavigate = (path: string) => {
100
- navigate(path);
101
- closeCommandMenu();
102
- };
101
+ const handleNavigate = useCallback(
102
+ (path: string) => {
103
+ navigate(path);
104
+ setOpen({ showCommandMenu: false });
105
+ },
106
+ [navigate, setOpen],
107
+ );
103
108
 
104
- const handleExternalLink = (url: string) => {
105
- window.open(url, '_blank', 'noopener,noreferrer');
106
- closeCommandMenu();
107
- };
109
+ const handleExternalLink = useCallback(
110
+ (url: string) => {
111
+ window.open(url, '_blank', 'noopener,noreferrer');
112
+ setOpen({ showCommandMenu: false });
113
+ },
114
+ [setOpen],
115
+ );
108
116
 
109
- const handleThemeChange = (theme: ThemeMode) => {
110
- setTheme(theme);
111
- closeCommandMenu();
112
- };
117
+ const handleThemeChange = useCallback(
118
+ (theme: ThemeMode) => {
119
+ setTheme(theme);
120
+ setOpen({ showCommandMenu: false });
121
+ },
122
+ [setTheme, setOpen],
123
+ );
113
124
 
114
- const handleAskLobeAI = () => {
125
+ const handleAskLobeAI = useCallback(() => {
115
126
  // Navigate to inbox agent with the message query parameter
116
127
  if (inboxAgentId && search.trim()) {
117
128
  const message = encodeURIComponent(search.trim());
118
129
  navigate(`/agent/${inboxAgentId}?message=${message}`);
119
- closeCommandMenu();
130
+ setOpen({ showCommandMenu: false });
120
131
  }
121
- };
132
+ }, [inboxAgentId, search, navigate, setOpen]);
122
133
 
123
- const handleAIPainting = () => {
134
+ const handleAIPainting = useCallback(() => {
124
135
  // Navigate to painting page with search as prompt
125
136
  if (search.trim()) {
126
137
  const prompt = encodeURIComponent(search.trim());
127
138
  navigate(`/image?prompt=${prompt}`);
128
- closeCommandMenu();
139
+ setOpen({ showCommandMenu: false });
129
140
  }
130
- };
141
+ }, [search, navigate, setOpen]);
131
142
 
132
- const handleBack = () => {
143
+ const handleBack = useCallback(() => {
133
144
  setPages((prev) => prev.slice(0, -1));
134
- };
145
+ }, [setPages]);
135
146
 
136
- const handleCreateSession = async () => {
147
+ const handleSendToSelectedAgent = useCallback(() => {
148
+ if (selectedAgent && search.trim()) {
149
+ const message = encodeURIComponent(search.trim());
150
+ navigate(`/agent/${selectedAgent.id}?message=${message}`);
151
+ setSelectedAgent(undefined);
152
+ setOpen({ showCommandMenu: false });
153
+ }
154
+ }, [selectedAgent, search, navigate, setSelectedAgent, setOpen]);
155
+
156
+ const handleCreateSession = useCallback(async () => {
137
157
  const result = await createAgent({});
138
158
  await refreshAgentList();
139
159
 
@@ -142,32 +162,32 @@ export const useCommandMenu = () => {
142
162
  navigate(`/agent/${result.agentId}`);
143
163
  }
144
164
 
145
- closeCommandMenu();
146
- };
165
+ setOpen({ showCommandMenu: false });
166
+ }, [createAgent, refreshAgentList, navigate, setOpen]);
147
167
 
148
- const [openNewTopicOrSaveTopic] = useChatStore((s) => [s.openNewTopicOrSaveTopic]);
168
+ const openNewTopicOrSaveTopic = useChatStore((s) => s.openNewTopicOrSaveTopic);
149
169
 
150
- const handleCreateTopic = async () => {
170
+ const handleCreateTopic = useCallback(() => {
151
171
  openNewTopicOrSaveTopic();
152
- closeCommandMenu();
153
- };
172
+ setOpen({ showCommandMenu: false });
173
+ }, [openNewTopicOrSaveTopic, setOpen]);
154
174
 
155
- const handleCreateLibrary = async () => {
156
- closeCommandMenu();
175
+ const handleCreateLibrary = useCallback(() => {
176
+ setOpen({ showCommandMenu: false });
157
177
  openCreateLibraryModal({
158
178
  onSuccess: (id) => {
159
179
  navigate(`/resource/library/${id}`);
160
180
  },
161
181
  });
162
- };
182
+ }, [setOpen, openCreateLibraryModal, navigate]);
163
183
 
164
- const handleCreatePage = async () => {
184
+ const handleCreatePage = useCallback(async () => {
165
185
  await createPage();
166
- closeCommandMenu();
167
- };
186
+ setOpen({ showCommandMenu: false });
187
+ }, [createPage, setOpen]);
168
188
 
169
- const handleCreateAgentTeam = async () => {
170
- closeCommandMenu();
189
+ const handleCreateAgentTeam = useCallback(() => {
190
+ setOpen({ showCommandMenu: false });
171
191
  openGroupWizard({
172
192
  onCreateCustom: async (selectedAgents) => {
173
193
  await createGroupWithMembers(selectedAgents);
@@ -176,7 +196,7 @@ export const useCommandMenu = () => {
176
196
  await createGroupFromTemplate(templateId, selectedMemberTitles);
177
197
  },
178
198
  });
179
- };
199
+ }, [setOpen, openGroupWizard, createGroupWithMembers, createGroupFromTemplate]);
180
200
 
181
201
  return {
182
202
  closeCommandMenu,
@@ -190,6 +210,7 @@ export const useCommandMenu = () => {
190
210
  handleCreateTopic,
191
211
  handleExternalLink,
192
212
  handleNavigate,
213
+ handleSendToSelectedAgent,
193
214
  handleThemeChange,
194
215
  hasSearch,
195
216
  isSearching,
@@ -201,7 +222,9 @@ export const useCommandMenu = () => {
201
222
  search,
202
223
  searchQuery,
203
224
  searchResults: searchResults || ([] as SearchResult[]),
225
+ selectedAgent,
204
226
  setSearch,
227
+ setSelectedAgent,
205
228
  setTypeFilter,
206
229
  typeFilter,
207
230
  };
@@ -113,6 +113,8 @@ export default {
113
113
  'cmdk.askAI': 'Ask Agent',
114
114
  'cmdk.askAIHeading': 'Use the following features for {{query}}',
115
115
  'cmdk.askAIHeadingEmpty': 'Choose an AI feature',
116
+ 'cmdk.askAgentHeading': 'Ask Agent',
117
+ 'cmdk.askAgentPlaceholder': 'Ask {{agent}} something...',
116
118
  'cmdk.askLobeAI': 'Ask Lobe AI',
117
119
  'cmdk.community': 'Community',
118
120
  'cmdk.communitySupport': 'Community Support',
@@ -128,8 +130,10 @@ export default {
128
130
  'cmdk.context.settings': 'Settings',
129
131
  'cmdk.discover': 'Discover',
130
132
  'cmdk.keyboard.ESC': 'ESC',
133
+ 'cmdk.keyboard.Enter': 'Enter',
131
134
  'cmdk.keyboard.Tab': 'Tab',
132
135
  'cmdk.memory': 'Memory',
136
+ 'cmdk.mentionAgent': 'Mention Agent',
133
137
  'cmdk.navigate': 'Navigate',
134
138
  'cmdk.newAgent': 'Create New Agent',
135
139
  'cmdk.newAgentTeam': 'Create New Group',
@@ -165,6 +169,7 @@ export default {
165
169
  'cmdk.search.topic': 'Topic',
166
170
  'cmdk.search.topics': 'Topics',
167
171
  'cmdk.searchPlaceholder': 'Enter a command or search...',
172
+ 'cmdk.sendToAgent': 'Send to {{agent}}',
168
173
  'cmdk.settings': 'Settings',
169
174
  'cmdk.starOnGitHub': 'Star us on GitHub',
170
175
  'cmdk.submitIssue': 'Submit Issue',