@lobehub/lobehub 2.0.0-next.311 → 2.0.0-next.313

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 (151) hide show
  1. package/CHANGELOG.md +59 -0
  2. package/apps/desktop/src/main/controllers/AuthCtr.ts +75 -7
  3. package/changelog/v1.json +21 -0
  4. package/docs/usage/providers/internlm.mdx +2 -2
  5. package/docs/usage/providers/internlm.zh-CN.mdx +3 -3
  6. package/e2e/README.md +1 -1
  7. package/e2e/src/features/community/detail-pages.feature +2 -2
  8. package/e2e/src/features/community/interactions.feature +5 -5
  9. package/e2e/src/features/community/smoke.feature +1 -1
  10. package/e2e/src/steps/community/detail-pages.steps.ts +6 -4
  11. package/e2e/src/steps/community/interactions.steps.ts +3 -3
  12. package/locales/en-US/error.json +10 -1
  13. package/locales/en-US/subscription.json +1 -1
  14. package/locales/zh-CN/desktop-onboarding.json +5 -0
  15. package/locales/zh-CN/error.json +10 -1
  16. package/locales/zh-CN/subscription.json +1 -1
  17. package/package.json +1 -1
  18. package/packages/agent-runtime/src/agents/GeneralChatAgent.ts +14 -2
  19. package/packages/agent-runtime/src/agents/__tests__/GeneralChatAgent.test.ts +275 -1
  20. package/packages/builtin-tool-agent-builder/src/systemRole.ts +9 -0
  21. package/packages/builtin-tool-cloud-sandbox/package.json +1 -0
  22. package/packages/builtin-tool-cloud-sandbox/src/ExecutionRuntime/index.ts +105 -134
  23. package/packages/builtin-tool-cloud-sandbox/src/executor/index.ts +254 -0
  24. package/packages/builtin-tool-cloud-sandbox/src/index.ts +1 -0
  25. package/packages/builtin-tool-cloud-sandbox/src/types/api.ts +22 -0
  26. package/packages/builtin-tool-cloud-sandbox/src/types/index.ts +4 -0
  27. package/packages/builtin-tool-cloud-sandbox/src/types/params.ts +85 -0
  28. package/packages/builtin-tool-cloud-sandbox/src/types/service.ts +48 -0
  29. package/packages/builtin-tool-cloud-sandbox/src/{types.ts → types/state.ts} +0 -23
  30. package/packages/builtin-tool-memory/src/manifest.ts +5 -5
  31. package/packages/editor-runtime/src/__tests__/EditorRuntime.real.test.ts +1 -1
  32. package/packages/editor-runtime/src/__tests__/EditorRuntime.test.ts +1 -1
  33. package/packages/electron-client-ipc/src/events/index.ts +5 -1
  34. package/packages/electron-client-ipc/src/events/remoteServer.ts +23 -0
  35. package/packages/memory-user-memory/src/schemas/index.ts +0 -1
  36. package/packages/model-bank/src/modelProviders/internlm.ts +1 -1
  37. package/packages/model-runtime/src/core/RouterRuntime/createRuntime.ts +5 -15
  38. package/packages/model-runtime/src/providers/internlm/index.test.ts +15 -15
  39. package/packages/model-runtime/src/providers/internlm/index.ts +1 -1
  40. package/packages/types/src/tool/intervention.ts +4 -2
  41. package/packages/types/src/user/preference.ts +1 -0
  42. package/public/favicon-32x-32-error.ico +0 -0
  43. package/public/favicon-32x32-done-dev.ico +0 -0
  44. package/public/favicon-32x32-done.ico +0 -0
  45. package/public/favicon-32x32-error-dev.ico +0 -0
  46. package/public/favicon-32x32-progress-dev.ico +0 -0
  47. package/public/favicon-32x32-progress.ico +0 -0
  48. package/public/favicon-done-dev.ico +0 -0
  49. package/public/favicon-done.ico +0 -0
  50. package/public/favicon-error-dev.ico +0 -0
  51. package/public/favicon-error.ico +0 -0
  52. package/public/favicon-progress-dev.ico +0 -0
  53. package/public/favicon-progress.ico +0 -0
  54. package/src/app/[variants]/(desktop)/desktop-onboarding/features/LoginStep.tsx +84 -26
  55. package/src/app/[variants]/(main)/_layout/DesktopAutoOidcOnFirstOpen.tsx +4 -0
  56. package/src/app/[variants]/(main)/agent/profile/features/Header/AgentPublishButton/PublishResultModal.tsx +1 -1
  57. package/src/app/[variants]/(main)/community/(detail)/_layout/Header.tsx +15 -3
  58. package/src/app/[variants]/(main)/community/(detail)/{assistant → agent}/features/Details/Overview/TagList.tsx +1 -1
  59. package/src/app/[variants]/(main)/community/(detail)/{assistant → agent}/features/Details/Related/index.tsx +2 -2
  60. package/src/app/[variants]/(main)/community/(detail)/{assistant → agent}/features/Details/SystemRole/TagList.tsx +1 -1
  61. package/src/app/[variants]/(main)/community/(detail)/{assistant → agent}/features/Details/SystemRole/index.tsx +1 -1
  62. package/src/app/[variants]/(main)/community/(detail)/{assistant → agent}/features/Header.tsx +2 -2
  63. package/src/app/[variants]/(main)/community/(detail)/{assistant → agent}/features/Sidebar/ActionButton/AddAgent.tsx +1 -1
  64. package/src/app/[variants]/(main)/community/(detail)/{assistant → agent}/features/Sidebar/ActionButton/index.tsx +1 -1
  65. package/src/app/[variants]/(main)/community/(detail)/{assistant → agent}/features/Sidebar/Related/index.tsx +2 -2
  66. package/src/app/[variants]/(main)/community/(detail)/{assistant → agent}/features/StatusPage/index.tsx +2 -2
  67. package/src/app/[variants]/(main)/community/(detail)/user/features/UserAgentCard.tsx +2 -2
  68. package/src/app/[variants]/(main)/community/(detail)/user/features/UserFavoriteAgents.tsx +1 -1
  69. package/src/app/[variants]/(main)/community/(list)/(home)/index.tsx +2 -2
  70. package/src/app/[variants]/(main)/community/(list)/(home)/loading.tsx +1 -1
  71. package/src/app/[variants]/(main)/community/(list)/{assistant → agent}/Client.tsx +5 -1
  72. package/src/app/[variants]/(main)/community/(list)/{assistant → agent}/features/Category/index.tsx +1 -1
  73. package/src/app/[variants]/(main)/community/(list)/{assistant → agent}/features/List/Item.tsx +1 -1
  74. package/src/app/[variants]/(main)/community/(list)/{assistant → agent}/features/MarketSourceSwitch.tsx +1 -1
  75. package/src/app/[variants]/(main)/community/_layout/Sidebar/Header/Nav.tsx +2 -2
  76. package/src/app/[variants]/(main)/home/features/CommunityAgents/List.tsx +1 -1
  77. package/src/app/[variants]/(main)/home/features/CommunityAgents/index.tsx +1 -1
  78. package/src/app/[variants]/(mobile)/_layout/index.tsx +1 -1
  79. package/src/app/[variants]/(mobile)/router/mobileRouter.config.tsx +6 -6
  80. package/src/app/[variants]/router/desktopRouter.config.tsx +8 -8
  81. package/src/app/[variants]/share/t/[id]/_layout/index.tsx +1 -1
  82. package/src/business/server/user.ts +4 -0
  83. package/src/features/CommandMenu/SearchResults.tsx +1 -1
  84. package/src/features/Conversation/Messages/Task/Actions/index.tsx +0 -2
  85. package/src/features/Conversation/Messages/Task/index.tsx +1 -1
  86. package/src/features/Conversation/Messages/Tasks/shared/ProcessingState.tsx +0 -2
  87. package/src/features/Electron/navigation/routeMetadata.ts +1 -1
  88. package/src/features/NavPanel/components/NavPanelDraggable.tsx +0 -14
  89. package/src/features/ResourceManager/components/Explorer/ItemDropdown/useFileItemDropdown.tsx +4 -3
  90. package/src/features/SharePopover/index.tsx +5 -3
  91. package/src/hooks/useAppOrigin.ts +16 -0
  92. package/src/layout/GlobalProvider/FaviconProvider.tsx +92 -0
  93. package/src/layout/GlobalProvider/index.tsx +15 -11
  94. package/src/layout/GlobalProvider/useUserStateRedirect.ts +37 -24
  95. package/src/libs/next/config/define-config.ts +1 -1
  96. package/src/libs/trusted-client/index.ts +2 -5
  97. package/src/locales/default/desktop-onboarding.ts +5 -0
  98. package/src/locales/default/error.ts +11 -0
  99. package/src/locales/default/subscription.ts +1 -1
  100. package/src/server/modules/AgentRuntime/RuntimeExecutors.ts +2 -0
  101. package/src/server/routers/lambda/user.ts +24 -10
  102. package/src/server/services/agentRuntime/AgentRuntimeService.test.ts +3 -0
  103. package/src/server/services/agentRuntime/AgentRuntimeService.ts +8 -5
  104. package/src/server/services/agentRuntime/types.ts +7 -0
  105. package/src/server/services/aiAgent/__tests__/execGroupSubAgentTask.test.ts +3 -0
  106. package/src/server/services/aiAgent/index.ts +10 -4
  107. package/src/server/services/market/index.ts +7 -0
  108. package/src/server/services/sandbox/index.ts +120 -0
  109. package/src/server/services/toolExecution/builtin.ts +12 -18
  110. package/src/server/services/toolExecution/index.ts +1 -1
  111. package/src/server/services/toolExecution/serverRuntimes/cloudSandbox.ts +31 -0
  112. package/src/server/services/toolExecution/serverRuntimes/index.ts +55 -0
  113. package/src/server/services/toolExecution/serverRuntimes/types.ts +14 -0
  114. package/src/server/services/toolExecution/serverRuntimes/webBrowsing.ts +20 -0
  115. package/src/server/services/toolExecution/types.ts +2 -0
  116. package/src/server/sitemap.test.ts +5 -5
  117. package/src/server/sitemap.ts +3 -3
  118. package/src/services/{codeInterpreter.ts → cloudSandbox.ts} +3 -3
  119. package/src/services/electron/remoteServer.ts +8 -0
  120. package/src/store/chat/agents/GroupOrchestration/__tests__/batch-exec-async-tasks.test.ts +626 -0
  121. package/src/store/chat/agents/GroupOrchestration/createGroupOrchestrationExecutors.ts +294 -0
  122. package/src/store/chat/slices/plugin/action.test.ts +0 -48
  123. package/src/store/chat/slices/plugin/actions/pluginTypes.ts +0 -131
  124. package/src/store/tool/slices/builtin/executors/index.ts +2 -0
  125. package/src/store/user/slices/settings/selectors/toolIntervention.test.ts +143 -0
  126. package/src/store/user/slices/settings/selectors/toolIntervention.ts +11 -2
  127. package/packages/memory-user-memory/src/schemas/jsonSchemas.ts +0 -37
  128. /package/src/app/[variants]/(main)/community/(detail)/{assistant → agent}/features/DetailProvider.tsx +0 -0
  129. /package/src/app/[variants]/(main)/community/(detail)/{assistant → agent}/features/Details/Capabilities/Block.tsx +0 -0
  130. /package/src/app/[variants]/(main)/community/(detail)/{assistant → agent}/features/Details/Capabilities/Knowledge.tsx +0 -0
  131. /package/src/app/[variants]/(main)/community/(detail)/{assistant → agent}/features/Details/Capabilities/KnowledgeItem.tsx +0 -0
  132. /package/src/app/[variants]/(main)/community/(detail)/{assistant → agent}/features/Details/Capabilities/PluginItem.tsx +0 -0
  133. /package/src/app/[variants]/(main)/community/(detail)/{assistant → agent}/features/Details/Capabilities/Plugins.tsx +0 -0
  134. /package/src/app/[variants]/(main)/community/(detail)/{assistant → agent}/features/Details/Capabilities/index.tsx +0 -0
  135. /package/src/app/[variants]/(main)/community/(detail)/{assistant → agent}/features/Details/Nav.tsx +0 -0
  136. /package/src/app/[variants]/(main)/community/(detail)/{assistant → agent}/features/Details/Overview/index.tsx +0 -0
  137. /package/src/app/[variants]/(main)/community/(detail)/{assistant → agent}/features/Details/Versions/index.tsx +0 -0
  138. /package/src/app/[variants]/(main)/community/(detail)/{assistant → agent}/features/Details/index.tsx +0 -0
  139. /package/src/app/[variants]/(main)/community/(detail)/{assistant → agent}/features/Sidebar/Related/Item.tsx +0 -0
  140. /package/src/app/[variants]/(main)/community/(detail)/{assistant → agent}/features/Sidebar/Summary/index.tsx +0 -0
  141. /package/src/app/[variants]/(main)/community/(detail)/{assistant → agent}/features/Sidebar/TocList/index.tsx +0 -0
  142. /package/src/app/[variants]/(main)/community/(detail)/{assistant → agent}/features/Sidebar/index.tsx +0 -0
  143. /package/src/app/[variants]/(main)/community/(detail)/{assistant → agent}/index.tsx +0 -0
  144. /package/src/app/[variants]/(main)/community/(detail)/{assistant → agent}/loading.tsx +0 -0
  145. /package/src/app/[variants]/(main)/community/(list)/{assistant → agent}/_layout/index.tsx +0 -0
  146. /package/src/app/[variants]/(main)/community/(list)/{assistant → agent}/_layout/style.ts +0 -0
  147. /package/src/app/[variants]/(main)/community/(list)/{assistant → agent}/features/Category/useCategory.tsx +0 -0
  148. /package/src/app/[variants]/(main)/community/(list)/{assistant → agent}/features/List/TokenTag.tsx +0 -0
  149. /package/src/app/[variants]/(main)/community/(list)/{assistant → agent}/features/List/index.tsx +0 -0
  150. /package/src/app/[variants]/(main)/community/(list)/{assistant → agent}/index.tsx +0 -0
  151. /package/src/app/[variants]/(main)/community/(list)/{assistant → agent}/loading.tsx +0 -0
@@ -41,7 +41,7 @@ const MarketSourceSwitch = memo(() => {
41
41
  );
42
42
 
43
43
  const handleChange = (value: AssistantMarketSource) => {
44
- router.push('/community/assistant', {
44
+ router.push('/community/agent', {
45
45
  query: {
46
46
  page: null,
47
47
  source: value === 'new' ? null : value,
@@ -3,12 +3,12 @@
3
3
  import { Flexbox } from '@lobehub/ui';
4
4
  import { McpIcon, ProviderIcon } from '@lobehub/ui/icons';
5
5
  import { Bot, Brain, ShapesIcon } from 'lucide-react';
6
- import { usePathname } from '@/libs/router/navigation';
7
6
  import { memo, useMemo } from 'react';
8
7
  import { useTranslation } from 'react-i18next';
9
8
  import { Link, useNavigate } from 'react-router-dom';
10
9
 
11
10
  import NavItem, { type NavItemProps } from '@/features/NavPanel/components/NavItem';
11
+ import { usePathname } from '@/libs/router/navigation';
12
12
  import { DiscoverTab } from '@/types/discover';
13
13
 
14
14
  interface Item {
@@ -42,7 +42,7 @@ const Nav = memo(() => {
42
42
  icon: Bot,
43
43
  key: DiscoverTab.Assistants,
44
44
  title: t('tab.assistant'),
45
- url: '/community/assistant',
45
+ url: '/community/agent',
46
46
  },
47
47
  {
48
48
  icon: McpIcon,
@@ -41,7 +41,7 @@ const CommunityAgentsList = memo(() => {
41
41
  color: 'inherit',
42
42
  textDecoration: 'none',
43
43
  }}
44
- to={urlJoin('/community/assistant', item.identifier)}
44
+ to={urlJoin('/community/agent', item.identifier)}
45
45
  >
46
46
  <CommunityAgentItem {...item} />
47
47
  </Link>
@@ -24,7 +24,7 @@ const CommunityAgents = memo(() => {
24
24
  key: 'all-assistants',
25
25
  label: t('home.more'),
26
26
  onClick: () => {
27
- navigate('/community/assistant');
27
+ navigate('/community/agent');
28
28
  },
29
29
  },
30
30
  ]}
@@ -15,7 +15,7 @@ const CloudBanner = dynamic(() => import('@/features/AlertBanner/CloudBanner'));
15
15
  const MOBILE_NAV_ROUTES = new Set([
16
16
  '/',
17
17
  '/community',
18
- '/community/assistant',
18
+ '/community/agent',
19
19
  '/community/mcp',
20
20
  '/community/plugin',
21
21
  '/community/model',
@@ -65,10 +65,10 @@ export const mobileRoutes: RouteConfig[] = [
65
65
  children: [
66
66
  {
67
67
  element: dynamicElement(
68
- () => import('../../(main)/community/(list)/assistant'),
69
- 'Mobile > Discover > List > Assistant',
68
+ () => import('../../(main)/community/(list)/agent'),
69
+ 'Mobile > Discover > List > Agent',
70
70
  ),
71
- path: 'assistant',
71
+ path: 'agent',
72
72
  },
73
73
  ],
74
74
  },
@@ -113,12 +113,12 @@ export const mobileRoutes: RouteConfig[] = [
113
113
  {
114
114
  element: dynamicElement(
115
115
  () =>
116
- import('../../(main)/community/(detail)/assistant').then(
116
+ import('../../(main)/community/(detail)/agent').then(
117
117
  (m) => m.MobileDiscoverAssistantDetailPage,
118
118
  ),
119
- 'Mobile > Discover > Detail > Assistant',
119
+ 'Mobile > Discover > Detail > Agent',
120
120
  ),
121
- path: 'assistant/:slug',
121
+ path: 'agent/:slug',
122
122
  },
123
123
  {
124
124
  element: dynamicElement(
@@ -94,17 +94,17 @@ export const desktopRoutes: RouteConfig[] = [
94
94
  children: [
95
95
  {
96
96
  element: dynamicElement(
97
- () => import('../(main)/community/(list)/assistant'),
98
- 'Desktop > Discover > List > Assistant',
97
+ () => import('../(main)/community/(list)/agent'),
98
+ 'Desktop > Discover > List > Agent',
99
99
  ),
100
100
  index: true,
101
101
  },
102
102
  ],
103
103
  element: dynamicElement(
104
- () => import('../(main)/community/(list)/assistant/_layout'),
105
- 'Desktop > Discover > List > Assistant > Layout',
104
+ () => import('../(main)/community/(list)/agent/_layout'),
105
+ 'Desktop > Discover > List > Agent > Layout',
106
106
  ),
107
- path: 'assistant',
107
+ path: 'agent',
108
108
  },
109
109
  {
110
110
  children: [
@@ -163,10 +163,10 @@ export const desktopRoutes: RouteConfig[] = [
163
163
  children: [
164
164
  {
165
165
  element: dynamicElement(
166
- () => import('../(main)/community/(detail)/assistant'),
167
- 'Desktop > Discover > Detail > Assistant',
166
+ () => import('../(main)/community/(detail)/agent'),
167
+ 'Desktop > Discover > Detail > Agent',
168
168
  ),
169
- path: 'assistant/:slug',
169
+ path: 'agent/:slug',
170
170
  },
171
171
  {
172
172
  element: dynamicElement(
@@ -116,7 +116,7 @@ const ShareTopicLayout = memo<PropsWithChildren>(({ children }) => {
116
116
  // If agent has marketIdentifier, render as link to assistant page
117
117
  if (agentMarketIdentifier && !data?.groupMeta?.title) {
118
118
  return (
119
- <a href={`/community/assistant/${agentMarketIdentifier}`} rel="noreferrer" target="_blank">
119
+ <a href={`/community/agent/${agentMarketIdentifier}`} rel="noreferrer" target="_blank">
120
120
  <Typography.Text ellipsis strong>
121
121
  {agentOrGroupTitle}
122
122
  </Typography.Text>
@@ -13,6 +13,10 @@ export async function getIsInWaitList(userId: string): Promise<boolean> {
13
13
  return false;
14
14
  }
15
15
 
16
+ export async function getIsInviteCodeRequired(userId: string): Promise<boolean> {
17
+ return false;
18
+ }
19
+
16
20
  export async function initNewUserForBusiness(
17
21
  userId: string,
18
22
  createdAt: Date | null | undefined,
@@ -101,7 +101,7 @@ const SearchResults = memo<SearchResultsProps>(
101
101
  break;
102
102
  }
103
103
  case 'communityAgent': {
104
- navigate(`/community/assistant/${result.identifier}`);
104
+ navigate(`/community/agent/${result.identifier}`);
105
105
  break;
106
106
  }
107
107
  }
@@ -128,8 +128,6 @@ export const AssistantActionsBar = memo<AssistantActionsBarProps>(
128
128
  defaultActions.edit,
129
129
  defaultActions.copy,
130
130
  collapseAction,
131
- defaultActions.divider,
132
-
133
131
  defaultActions.divider,
134
132
  defaultActions.share,
135
133
  defaultActions.divider,
@@ -43,7 +43,7 @@ const TaskMessage = memo<TaskMessageProps>(({ id, index, disableEditing, isLates
43
43
  const editing = useConversationStore(messageStateSelectors.isMessageEditing(id));
44
44
  const generating = useConversationStore(messageStateSelectors.isMessageGenerating(id));
45
45
  const creating = useConversationStore(messageStateSelectors.isMessageCreating(id));
46
- const newScreen = useNewScreen({ creating, isLatestItem });
46
+ const newScreen = useNewScreen({ creating: generating || creating, isLatestItem });
47
47
 
48
48
  const errorContent = useErrorContent(error);
49
49
 
@@ -28,9 +28,7 @@ const styles = createStaticStyles(({ css, cssVar }) => ({
28
28
  display: flex;
29
29
  gap: 8px;
30
30
  align-items: center;
31
-
32
31
  padding-block: 8px;
33
- padding-inline: 16px;
34
32
  `,
35
33
  footer: css`
36
34
  padding-block-start: 8px;
@@ -79,7 +79,7 @@ const routePatterns: RoutePattern[] = [
79
79
  // Community/Discover routes
80
80
  {
81
81
  icon: Compass,
82
- test: (p) => p.startsWith('/community/assistant'),
82
+ test: (p) => p.startsWith('/community/agent'),
83
83
  titleKey: 'navigation.discoverAssistants',
84
84
  },
85
85
  {
@@ -13,7 +13,6 @@ import { systemStatusSelectors } from '@/store/global/selectors';
13
13
  import { isMacOS } from '@/utils/platform';
14
14
 
15
15
  import { useNavPanelSizeChangeHandler } from '../hooks/useNavPanel';
16
- import { BACK_BUTTON_ID } from './BackButton';
17
16
 
18
17
  const motionVariants = {
19
18
  animate: { opacity: 1, x: 0 },
@@ -78,12 +77,6 @@ const draggableStyles = createStaticStyles(({ css, cssVar }) => ({
78
77
  width 0.2s ${cssVar.motionEaseOut};
79
78
  }
80
79
 
81
- #${BACK_BUTTON_ID} {
82
- width: 0 !important;
83
- opacity: 0;
84
- transition: all 0.2s ${cssVar.motionEaseOut};
85
- }
86
-
87
80
  &:hover {
88
81
  #${TOGGLE_BUTTON_ID} {
89
82
  width: 32px !important;
@@ -94,13 +87,6 @@ const draggableStyles = createStaticStyles(({ css, cssVar }) => ({
94
87
  width: 14px !important;
95
88
  opacity: 1;
96
89
  }
97
-
98
- &:hover {
99
- #${BACK_BUTTON_ID} {
100
- width: 24px !important;
101
- opacity: 1;
102
- }
103
- }
104
90
  }
105
91
  `,
106
92
  }));
@@ -17,6 +17,7 @@ import { shallow } from 'zustand/shallow';
17
17
  import RepoIcon from '@/components/LibIcon';
18
18
  import { clearTreeFolderCache } from '@/features/ResourceManager/components/LibraryHierarchy';
19
19
  import { PAGE_FILE_TYPE } from '@/features/ResourceManager/constants';
20
+ import { useAppOrigin } from '@/hooks/useAppOrigin';
20
21
  import { documentService } from '@/services/document';
21
22
  import { useFileStore } from '@/store/file';
22
23
  import { useKnowledgeBaseStore } from '@/store/library';
@@ -53,6 +54,7 @@ export const useFileItemDropdown = ({
53
54
  }: UseFileItemDropdownParams): UseFileItemDropdownReturn => {
54
55
  const { t } = useTranslation(['components', 'common', 'knowledgeBase']);
55
56
  const { message, modal } = App.useApp();
57
+ const appOrigin = useAppOrigin();
56
58
 
57
59
  const { deleteResource, refreshFileList } = useFileStore(
58
60
  (s) => ({
@@ -184,11 +186,10 @@ export const useFileItemDropdown = ({
184
186
  // For pages, use the route path instead of the storage URL
185
187
  let urlToCopy = url;
186
188
  if (isPage) {
187
- const baseUrl = window.location.origin;
188
189
  if (libraryId) {
189
- urlToCopy = `${baseUrl}/resource/library/${libraryId}?file=${id}`;
190
+ urlToCopy = `${appOrigin}/resource/library/${libraryId}?file=${id}`;
190
191
  } else {
191
- urlToCopy = `${baseUrl}/resource?file=${id}`;
192
+ urlToCopy = `${appOrigin}/resource?file=${id}`;
192
193
  }
193
194
  }
194
195
 
@@ -2,11 +2,12 @@
2
2
 
3
3
  import { Button, Flexbox, Popover, copyToClipboard, usePopoverContext } from '@lobehub/ui';
4
4
  import { App, Divider, Select, Skeleton, Typography } from 'antd';
5
- import { CopyIcon, ExternalLinkIcon, LinkIcon, LockIcon } from 'lucide-react';
5
+ import { ExternalLinkIcon, LinkIcon, LockIcon } from 'lucide-react';
6
6
  import { type ReactNode, memo, useCallback, useEffect, useRef, useState } from 'react';
7
7
  import { useTranslation } from 'react-i18next';
8
8
  import useSWR from 'swr';
9
9
 
10
+ import { useAppOrigin } from '@/hooks/useAppOrigin';
10
11
  import { useIsMobile } from '@/hooks/useIsMobile';
11
12
  import { topicService } from '@/services/topic';
12
13
  import { useChatStore } from '@/store/chat';
@@ -26,6 +27,7 @@ const SharePopoverContent = memo<SharePopoverContentProps>(({ onOpenModal }) =>
26
27
  const [updating, setUpdating] = useState(false);
27
28
  const { close } = usePopoverContext();
28
29
  const containerRef = useRef<HTMLDivElement>(null);
30
+ const appOrigin = useAppOrigin();
29
31
 
30
32
  const activeTopicId = useChatStore((s) => s.activeTopicId);
31
33
 
@@ -46,7 +48,7 @@ const SharePopoverContent = memo<SharePopoverContentProps>(({ onOpenModal }) =>
46
48
  }
47
49
  }, [isLoading, shareInfo, activeTopicId, mutate]);
48
50
 
49
- const shareUrl = shareInfo?.id ? `${window.location.origin}/share/t/${shareInfo.id}` : '';
51
+ const shareUrl = shareInfo?.id ? `${appOrigin}/share/t/${shareInfo.id}` : '';
50
52
  const currentVisibility = (shareInfo?.visibility as Visibility) || 'private';
51
53
 
52
54
  const updateVisibility = useCallback(
@@ -178,7 +180,7 @@ const SharePopoverContent = memo<SharePopoverContentProps>(({ onOpenModal }) =>
178
180
  >
179
181
  {t('shareModal.popover.moreOptions')}
180
182
  </Button>
181
- <Button icon={CopyIcon} onClick={handleCopyLink} size="small" type="primary">
183
+ <Button icon={LinkIcon} onClick={handleCopyLink} size="small" type="primary">
182
184
  {t('shareModal.copyLink')}
183
185
  </Button>
184
186
  </Flexbox>
@@ -0,0 +1,16 @@
1
+ 'use client';
2
+
3
+ import { isDesktop } from '@lobechat/const';
4
+
5
+ import { useElectronStore } from '@/store/electron';
6
+ import { electronSyncSelectors } from '@/store/electron/selectors';
7
+
8
+ /**
9
+ * Returns the correct app origin URL for sharing/linking.
10
+ * - Web: uses window.location.origin
11
+ * - Desktop: uses remoteServerUrl from electron store
12
+ */
13
+ export const useAppOrigin = () => {
14
+ const remoteServerUrl = useElectronStore(electronSyncSelectors.remoteServerUrl);
15
+ return isDesktop ? remoteServerUrl : window.location.origin;
16
+ };
@@ -0,0 +1,92 @@
1
+ 'use client';
2
+
3
+ import { type ReactNode, createContext, memo, useCallback, useContext, useState } from 'react';
4
+
5
+ export type FaviconState = 'default' | 'done' | 'error' | 'progress';
6
+
7
+ interface FaviconContextValue {
8
+ currentState: FaviconState;
9
+ isDevMode: boolean;
10
+ setFavicon: (state: FaviconState) => void;
11
+ setIsDevMode: (isDev: boolean) => void;
12
+ }
13
+
14
+ const FaviconContext = createContext<FaviconContextValue | null>(null);
15
+
16
+ export const useFavicon = () => {
17
+ const context = useContext(FaviconContext);
18
+ if (!context) {
19
+ throw new Error('useFavicon must be used within FaviconProvider');
20
+ }
21
+ return context;
22
+ };
23
+
24
+ const stateToFileName: Record<FaviconState, string> = {
25
+ default: '',
26
+ done: '-done',
27
+ error: '-error',
28
+ progress: '-progress',
29
+ };
30
+
31
+ const getFaviconPath = (state: FaviconState, isDev: boolean, size?: '32x32'): string => {
32
+ const devSuffix = isDev ? '-dev' : '';
33
+ const stateSuffix = stateToFileName[state];
34
+ const sizeSuffix = size ? `-${size}` : '';
35
+ return `/favicon${sizeSuffix}${stateSuffix}${devSuffix}.ico`;
36
+ };
37
+
38
+ const updateFaviconDOM = (state: FaviconState, isDev: boolean) => {
39
+ if (typeof document === 'undefined') return;
40
+
41
+ const head = document.head;
42
+ const existingLinks = document.querySelectorAll<HTMLLinkElement>(
43
+ 'link[rel="icon"], link[rel="shortcut icon"]',
44
+ );
45
+
46
+ // Remove existing favicon links and create new ones to bust cache
47
+ existingLinks.forEach((link) => {
48
+ const oldHref = link.href;
49
+ const is32 = oldHref.includes('32x32');
50
+ const rel = link.rel;
51
+
52
+ // Remove old link
53
+ link.remove();
54
+
55
+ // Create new link with cache-busting query param
56
+ const newLink = document.createElement('link');
57
+ newLink.rel = rel;
58
+ newLink.href = `${getFaviconPath(state, isDev, is32 ? '32x32' : undefined)}?v=${Date.now()}`;
59
+ head.append(newLink);
60
+ });
61
+ };
62
+
63
+ const defaultIsDev = process.env.NODE_ENV === 'development';
64
+
65
+ export const FaviconProvider = memo<{ children: ReactNode }>(({ children }) => {
66
+ const [currentState, setCurrentState] = useState<FaviconState>('default');
67
+ const [isDevMode, setIsDevModeState] = useState<boolean>(defaultIsDev);
68
+
69
+ const setFavicon = useCallback(
70
+ (state: FaviconState) => {
71
+ setCurrentState(state);
72
+ updateFaviconDOM(state, isDevMode);
73
+ },
74
+ [isDevMode],
75
+ );
76
+
77
+ const setIsDevMode = useCallback(
78
+ (isDev: boolean) => {
79
+ setIsDevModeState(isDev);
80
+ updateFaviconDOM(currentState, isDev);
81
+ },
82
+ [currentState],
83
+ );
84
+
85
+ return (
86
+ <FaviconContext.Provider value={{ currentState, isDevMode, setFavicon, setIsDevMode }}>
87
+ {children}
88
+ </FaviconContext.Provider>
89
+ );
90
+ });
91
+
92
+ FaviconProvider.displayName = 'FaviconProvider';
@@ -14,6 +14,7 @@ import { ServerConfigStoreProvider } from '@/store/serverConfig/Provider';
14
14
  import { getAntdLocale } from '@/utils/locale';
15
15
 
16
16
  import AppTheme from './AppTheme';
17
+ import { FaviconProvider } from './FaviconProvider';
17
18
  import { GroupWizardProvider } from './GroupWizardProvider';
18
19
  import ImportSettings from './ImportSettings';
19
20
  import Locale from './Locale';
@@ -65,17 +66,20 @@ const GlobalLayout = async ({
65
66
  >
66
67
  <QueryProvider>
67
68
  <StoreInitialization />
68
- <GroupWizardProvider>
69
- <DragUploadProvider>
70
- <LazyMotion features={domMax}>
71
- <TooltipGroup layoutAnimation={false}>
72
- <LobeAnalyticsProviderWrapper>{children}</LobeAnalyticsProviderWrapper>
73
- </TooltipGroup>
74
- <ModalHost />
75
- <ContextMenuHost />
76
- </LazyMotion>
77
- </DragUploadProvider>
78
- </GroupWizardProvider>
69
+ <FaviconProvider>
70
+ {/* {process.env.NODE_ENV === 'development' && <FaviconTestPanel />} */}
71
+ <GroupWizardProvider>
72
+ <DragUploadProvider>
73
+ <LazyMotion features={domMax}>
74
+ <TooltipGroup layoutAnimation={false}>
75
+ <LobeAnalyticsProviderWrapper>{children}</LobeAnalyticsProviderWrapper>
76
+ </TooltipGroup>
77
+ <ModalHost />
78
+ <ContextMenuHost />
79
+ </LazyMotion>
80
+ </DragUploadProvider>
81
+ </GroupWizardProvider>
82
+ </FaviconProvider>
79
83
  </QueryProvider>
80
84
  <Suspense>
81
85
  {ENABLE_BUSINESS_FEATURES ? <ReferralProvider /> : null}
@@ -20,43 +20,51 @@ export const useDesktopUserStateRedirect = () => {
20
20
  const dataSyncConfig = useElectronStore((s) => s.dataSyncConfig);
21
21
  const logout = useUserStore((s) => s.logout);
22
22
 
23
- const handleDesktopWaitlist = useCallback(async () => {
24
- const waitlistBaseUrl = dataSyncConfig.remoteServerUrl || OFFICIAL_URL;
25
- let waitlistUrl = waitlistBaseUrl;
26
- try {
27
- waitlistUrl = new URL('/waitlist', waitlistBaseUrl).toString();
28
- } catch {
29
- // Ignore: keep fallback URL for external open attempt.
30
- }
23
+ const openExternalAndLogout = useCallback(
24
+ async (path: string) => {
25
+ const baseUrl = dataSyncConfig.remoteServerUrl || OFFICIAL_URL;
26
+ let targetUrl = baseUrl;
27
+ try {
28
+ targetUrl = new URL(path, baseUrl).toString();
29
+ } catch {
30
+ // Ignore: keep fallback URL for external open attempt.
31
+ }
31
32
 
32
- try {
33
- const { electronSystemService } = await import('@/services/electron/system');
34
- await electronSystemService.openExternalLink(waitlistUrl);
35
- } catch {
36
- // Ignore: fallback to logout flow even if IPC is unavailable.
37
- }
33
+ try {
34
+ const { electronSystemService } = await import('@/services/electron/system');
35
+ await electronSystemService.openExternalLink(targetUrl);
36
+ } catch {
37
+ // Ignore: fallback to logout flow even if IPC is unavailable.
38
+ }
38
39
 
39
- try {
40
- const { remoteServerService } = await import('@/services/electron/remoteServer');
41
- await remoteServerService.clearRemoteServerConfig();
42
- } catch {
43
- // Ignore: fallback to logout flow even if IPC is unavailable.
44
- }
40
+ try {
41
+ const { remoteServerService } = await import('@/services/electron/remoteServer');
42
+ await remoteServerService.clearRemoteServerConfig();
43
+ } catch {
44
+ // Ignore: fallback to logout flow even if IPC is unavailable.
45
+ }
45
46
 
46
- await logout();
47
- }, [dataSyncConfig.remoteServerUrl, logout]);
47
+ await logout();
48
+ },
49
+ [dataSyncConfig.remoteServerUrl, logout],
50
+ );
48
51
 
49
52
  return useCallback(
50
53
  (state: UserInitializationState) => {
51
54
  if (state.isInWaitList === true) {
52
- void handleDesktopWaitlist();
55
+ void openExternalAndLogout('/waitlist');
56
+ return;
57
+ }
58
+
59
+ if (state.isInviteCodeRequired === true) {
60
+ void openExternalAndLogout('/invite-code');
53
61
  return;
54
62
  }
55
63
 
56
64
  if (!getDesktopOnboardingCompleted()) return;
57
65
  // Desktop onboarding is handled by desktop-only flow.
58
66
  },
59
- [handleDesktopWaitlist],
67
+ [openExternalAndLogout],
60
68
  );
61
69
  };
62
70
 
@@ -68,6 +76,11 @@ export const useWebUserStateRedirect = () =>
68
76
  return;
69
77
  }
70
78
 
79
+ if (state.isInviteCodeRequired === true) {
80
+ redirectIfNotOn(pathname, '/invite-code');
81
+ return;
82
+ }
83
+
71
84
  if (!onboardingSelectors.needsOnboarding(state)) return;
72
85
 
73
86
  redirectIfNotOn(pathname, '/onboarding');
@@ -267,7 +267,7 @@ export function defineConfig(config: CustomNextConfig) {
267
267
  source: '/manifest.json',
268
268
  },
269
269
  {
270
- destination: '/community/assistant',
270
+ destination: '/community/agent',
271
271
  permanent: true,
272
272
  source: '/community/assistants',
273
273
  },
@@ -31,14 +31,11 @@ export const generateTrustedClientToken = (userInfo: TrustedClientUserInfo): str
31
31
  return undefined;
32
32
  }
33
33
 
34
- if (!userInfo.email) {
35
- return undefined;
36
- }
37
-
38
34
  try {
39
35
  const payload = buildTrustedClientPayload({
40
36
  clientId: MARKET_TRUSTED_CLIENT_ID,
41
- email: userInfo.email,
37
+ // TODO: remove '' when sdk update
38
+ email: userInfo.email || '',
42
39
  name: userInfo.name,
43
40
  userId: userInfo.userId,
44
41
  });
@@ -73,6 +73,7 @@ export default {
73
73
  'screen4.title2': 'Your choice helps us improve',
74
74
  'screen4.title3': 'You can change this anytime in settings',
75
75
 
76
+ 'screen5.actions.cancel': 'Cancel',
76
77
  'screen5.actions.connectToServer': 'Connect to Server',
77
78
  'screen5.actions.connecting': 'Connecting...',
78
79
  'screen5.actions.signInCloud': 'Sign in to LobeHub Cloud',
@@ -80,6 +81,10 @@ export default {
80
81
  'screen5.actions.signingIn': 'Signing in...',
81
82
  'screen5.actions.signingOut': 'Signing out...',
82
83
  'screen5.actions.tryAgain': 'Try Again',
84
+ 'screen5.auth.phase.browserOpened': 'Browser opened, please sign in...',
85
+ 'screen5.auth.phase.verifying': 'Verifying credentials...',
86
+ 'screen5.auth.phase.waitingForAuth': 'Waiting for authorization...',
87
+ 'screen5.auth.remaining': 'Remaining: {{time}}s',
83
88
  'screen5.badge': 'Sign in',
84
89
  'screen5.description':
85
90
  'Sign in to sync Agents, Groups, settings, and Context across all devices.',
@@ -16,6 +16,12 @@ export default {
16
16
  'import.incompatible.description':
17
17
  'This file was exported from a higher version. Please try upgrading to the latest version and then re-importing.',
18
18
  'import.incompatible.title': 'Current application does not support importing this file',
19
+ 'inviteCode.currentEmail': 'Current account: {{email}}',
20
+ 'inviteCode.desc':
21
+ 'An invite code is required to access LobeHub. Please enter a valid invite code to continue.',
22
+ 'inviteCode.friends': 'Friends',
23
+ 'inviteCode.getCodeHint': 'Get an invite code from:',
24
+ 'inviteCode.title': 'Invite Code Required',
19
25
  'loginRequired.desc': 'You will be redirected to the login page shortly',
20
26
  'loginRequired.title': 'Please log in to use this feature',
21
27
  'notFound.backHome': 'Back to Home',
@@ -238,5 +244,10 @@ export default {
238
244
  'upload.title': 'File upload failed. Please check your network connection or try again later',
239
245
  'upload.unknownError': 'Error reason: {{reason}}',
240
246
  'upload.uploadFailed': 'File upload failed.',
247
+ 'waitlist.currentEmail': 'Current account: {{email}}',
248
+ 'waitlist.desc':
249
+ 'Your account is not on the whitelist. Please contact the administrator to request access.',
250
+ 'waitlist.switchAccount': 'Switch Account',
251
+ 'waitlist.title': 'Access Restricted',
241
252
  ...businessErrorsLocales,
242
253
  };
@@ -328,7 +328,7 @@ export default {
328
328
  'referral.rules.backfill.expiredTip':
329
329
  'Backfill period has expired. Cannot backfill after 3 days of registration',
330
330
  'referral.rules.backfill.link': 'Backfill Invite Code',
331
- 'referral.rules.backfill.placeholder': 'Enter invite code',
331
+ 'referral.rules.backfill.placeholder': 'Enter invite code or link',
332
332
  'referral.rules.backfill.submit': 'Confirm Binding',
333
333
  'referral.rules.backfill.success': 'Invite code bound successfully',
334
334
  'referral.rules.backfill.title': 'Backfill Invite Code',
@@ -36,6 +36,7 @@ export interface RuntimeExecutorContext {
36
36
  stepIndex: number;
37
37
  streamManager: IStreamEventManager;
38
38
  toolExecutionService: ToolExecutionService;
39
+ topicId?: string;
39
40
  userId?: string;
40
41
  }
41
42
 
@@ -475,6 +476,7 @@ export const createRuntimeExecutors = (
475
476
  const executionResult = await toolExecutionService.executeTool(chatToolPayload, {
476
477
  serverDB: ctx.serverDB,
477
478
  toolManifestMap: state.toolManifestMap,
479
+ topicId: ctx.topicId,
478
480
  userId: ctx.userId,
479
481
  });
480
482