@lobehub/lobehub 2.0.0-next.312 → 2.0.0-next.314

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 (93) hide show
  1. package/CHANGELOG.md +51 -0
  2. package/apps/desktop/src/main/appBrowsers.ts +4 -1
  3. package/apps/desktop/src/main/controllers/AuthCtr.ts +75 -7
  4. package/apps/desktop/src/main/controllers/BrowserWindowsCtr.ts +15 -3
  5. package/apps/desktop/src/main/core/browser/Browser.ts +14 -4
  6. package/apps/desktop/src/main/core/browser/BrowserManager.ts +7 -2
  7. package/changelog/v1.json +18 -0
  8. package/docs/usage/providers/internlm.mdx +2 -2
  9. package/docs/usage/providers/internlm.zh-CN.mdx +3 -3
  10. package/e2e/src/steps/community/detail-pages.steps.ts +2 -2
  11. package/e2e/src/steps/community/interactions.steps.ts +6 -6
  12. package/e2e/src/steps/hooks.ts +19 -3
  13. package/locales/en-US/error.json +10 -1
  14. package/locales/en-US/subscription.json +1 -1
  15. package/locales/zh-CN/desktop-onboarding.json +5 -0
  16. package/locales/zh-CN/error.json +10 -1
  17. package/locales/zh-CN/subscription.json +1 -1
  18. package/package.json +1 -1
  19. package/packages/agent-runtime/src/agents/GeneralChatAgent.ts +14 -2
  20. package/packages/agent-runtime/src/agents/__tests__/GeneralChatAgent.test.ts +275 -1
  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/desktop-bridge/src/index.ts +5 -0
  32. package/packages/editor-runtime/src/__tests__/EditorRuntime.real.test.ts +1 -1
  33. package/packages/editor-runtime/src/__tests__/EditorRuntime.test.ts +1 -1
  34. package/packages/electron-client-ipc/src/events/index.ts +5 -1
  35. package/packages/electron-client-ipc/src/events/remoteServer.ts +23 -0
  36. package/packages/electron-client-ipc/src/types/window.ts +3 -2
  37. package/packages/memory-user-memory/src/schemas/index.ts +0 -1
  38. package/packages/model-bank/src/modelProviders/internlm.ts +1 -1
  39. package/packages/model-runtime/src/core/RouterRuntime/createRuntime.ts +5 -15
  40. package/packages/model-runtime/src/providers/internlm/index.test.ts +15 -15
  41. package/packages/model-runtime/src/providers/internlm/index.ts +1 -1
  42. package/packages/types/src/tool/intervention.ts +4 -2
  43. package/packages/types/src/user/preference.ts +1 -0
  44. package/src/app/[variants]/(desktop)/desktop-onboarding/_layout/index.tsx +6 -3
  45. package/src/app/[variants]/(desktop)/desktop-onboarding/components/OnboardingFooterActions.tsx +38 -0
  46. package/src/app/[variants]/(desktop)/desktop-onboarding/features/DataModeStep.tsx +19 -14
  47. package/src/app/[variants]/(desktop)/desktop-onboarding/features/LoginStep.tsx +121 -29
  48. package/src/app/[variants]/(desktop)/desktop-onboarding/features/PermissionsStep.tsx +19 -14
  49. package/src/app/[variants]/(desktop)/desktop-onboarding/index.tsx +8 -7
  50. package/src/app/[variants]/(main)/_layout/DesktopAutoOidcOnFirstOpen.tsx +4 -0
  51. package/src/app/manifest.ts +1 -1
  52. package/src/business/server/user.ts +4 -0
  53. package/src/features/Conversation/Messages/Task/Actions/index.tsx +0 -2
  54. package/src/features/Conversation/Messages/Task/index.tsx +1 -1
  55. package/src/features/Conversation/Messages/Tasks/shared/ProcessingState.tsx +0 -2
  56. package/src/features/Electron/titlebar/NavigationBar.tsx +1 -2
  57. package/src/features/NavPanel/components/NavPanelDraggable.tsx +0 -14
  58. package/src/features/ResourceManager/components/Explorer/ItemDropdown/useFileItemDropdown.tsx +4 -3
  59. package/src/features/SharePopover/index.tsx +5 -3
  60. package/src/hooks/useAppOrigin.ts +16 -0
  61. package/src/layout/GlobalProvider/useUserStateRedirect.ts +37 -24
  62. package/src/libs/trusted-client/index.ts +2 -5
  63. package/src/locales/default/desktop-onboarding.ts +5 -0
  64. package/src/locales/default/error.ts +11 -0
  65. package/src/locales/default/subscription.ts +1 -1
  66. package/src/server/manifest.ts +2 -2
  67. package/src/server/modules/AgentRuntime/RuntimeExecutors.ts +2 -0
  68. package/src/server/routers/lambda/user.ts +24 -10
  69. package/src/server/services/agentRuntime/AgentRuntimeService.test.ts +3 -0
  70. package/src/server/services/agentRuntime/AgentRuntimeService.ts +8 -5
  71. package/src/server/services/agentRuntime/types.ts +7 -0
  72. package/src/server/services/aiAgent/__tests__/execGroupSubAgentTask.test.ts +3 -0
  73. package/src/server/services/aiAgent/index.ts +10 -4
  74. package/src/server/services/market/index.ts +20 -0
  75. package/src/server/services/sandbox/index.ts +186 -0
  76. package/src/server/services/toolExecution/builtin.ts +12 -18
  77. package/src/server/services/toolExecution/index.ts +1 -1
  78. package/src/server/services/toolExecution/serverRuntimes/cloudSandbox.ts +38 -0
  79. package/src/server/services/toolExecution/serverRuntimes/index.ts +55 -0
  80. package/src/server/services/toolExecution/serverRuntimes/types.ts +14 -0
  81. package/src/server/services/toolExecution/serverRuntimes/webBrowsing.ts +20 -0
  82. package/src/server/services/toolExecution/types.ts +2 -0
  83. package/src/services/{codeInterpreter.ts → cloudSandbox.ts} +3 -3
  84. package/src/services/electron/remoteServer.ts +8 -0
  85. package/src/services/electron/system.ts +5 -5
  86. package/src/store/chat/agents/GroupOrchestration/__tests__/batch-exec-async-tasks.test.ts +626 -0
  87. package/src/store/chat/agents/GroupOrchestration/createGroupOrchestrationExecutors.ts +294 -0
  88. package/src/store/chat/slices/plugin/action.test.ts +0 -48
  89. package/src/store/chat/slices/plugin/actions/pluginTypes.ts +0 -131
  90. package/src/store/tool/slices/builtin/executors/index.ts +2 -0
  91. package/src/store/user/slices/settings/selectors/toolIntervention.test.ts +143 -0
  92. package/src/store/user/slices/settings/selectors/toolIntervention.ts +11 -2
  93. package/packages/memory-user-memory/src/schemas/jsonSchemas.ts +0 -37
package/CHANGELOG.md CHANGED
@@ -2,6 +2,57 @@
2
2
 
3
3
  # Changelog
4
4
 
5
+ ## [Version 2.0.0-next.314](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.313...v2.0.0-next.314)
6
+
7
+ <sup>Released on **2026-01-19**</sup>
8
+
9
+ #### ✨ Features
10
+
11
+ - **misc**: Improve desktop onboarding window management and footer actions.
12
+
13
+ <br/>
14
+
15
+ <details>
16
+ <summary><kbd>Improvements and Fixes</kbd></summary>
17
+
18
+ #### What's improved
19
+
20
+ - **misc**: Improve desktop onboarding window management and footer actions, closes [#11619](https://github.com/lobehub/lobe-chat/issues/11619) ([6ed280e](https://github.com/lobehub/lobe-chat/commit/6ed280e))
21
+
22
+ </details>
23
+
24
+ <div align="right">
25
+
26
+ [![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
27
+
28
+ </div>
29
+
30
+ ## [Version 2.0.0-next.313](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.312...v2.0.0-next.313)
31
+
32
+ <sup>Released on **2026-01-19**</sup>
33
+
34
+ #### 🐛 Bug Fixes
35
+
36
+ - **misc**: Fix server agent task run with headless, internlm provider base url and homepage.
37
+
38
+ <br/>
39
+
40
+ <details>
41
+ <summary><kbd>Improvements and Fixes</kbd></summary>
42
+
43
+ #### What's fixed
44
+
45
+ - **misc**: Fix server agent task run with headless, closes [#11600](https://github.com/lobehub/lobe-chat/issues/11600) ([435eede](https://github.com/lobehub/lobe-chat/commit/435eede))
46
+ - **misc**: Internlm provider base url and homepage, closes [#11612](https://github.com/lobehub/lobe-chat/issues/11612) ([38725da](https://github.com/lobehub/lobe-chat/commit/38725da))
47
+
48
+ </details>
49
+
50
+ <div align="right">
51
+
52
+ [![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
53
+
54
+ </div>
55
+
5
56
  ## [Version 2.0.0-next.312](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.311...v2.0.0-next.312)
6
57
 
7
58
  <sup>Released on **2026-01-19**</sup>
@@ -1,3 +1,5 @@
1
+ import { APP_WINDOW_MIN_SIZE } from '@lobechat/desktop-bridge';
2
+
1
3
  import type { BrowserWindowOpts } from './core/browser/Browser';
2
4
 
3
5
  export const BrowsersIdentifiers = {
@@ -11,7 +13,8 @@ export const appBrowsers = {
11
13
  height: 800,
12
14
  identifier: 'app',
13
15
  keepAlive: true,
14
- minWidth: 400,
16
+ minHeight: APP_WINDOW_MIN_SIZE.height,
17
+ minWidth: APP_WINDOW_MIN_SIZE.width,
15
18
  path: '/',
16
19
  showOnInit: true,
17
20
  titleBarStyle: 'hidden',
@@ -1,4 +1,9 @@
1
- import { DataSyncConfig, MarketAuthorizationParams } from '@lobechat/electron-client-ipc';
1
+ import {
2
+ AuthorizationPhase,
3
+ AuthorizationProgress,
4
+ DataSyncConfig,
5
+ MarketAuthorizationParams,
6
+ } from '@lobechat/electron-client-ipc';
2
7
  import { BrowserWindow, shell } from 'electron';
3
8
  import crypto from 'node:crypto';
4
9
  import querystring from 'node:querystring';
@@ -9,9 +14,11 @@ import { createLogger } from '@/utils/logger';
9
14
  import RemoteServerConfigCtr from './RemoteServerConfigCtr';
10
15
  import { ControllerModule, IpcMethod } from './index';
11
16
 
12
- // Create logger
13
17
  const logger = createLogger('controllers:AuthCtr');
14
18
 
19
+ const MAX_POLL_TIME = 2 * 60 * 1000; // 2 minutes (reduced from 5 minutes for better UX)
20
+ const POLL_INTERVAL = 3000; // 3 seconds
21
+
15
22
  /**
16
23
  * Authentication Controller
17
24
  * Implements OAuth authorization flow using intermediate page + polling mechanism
@@ -107,6 +114,12 @@ export default class AuthCtr extends ControllerModule {
107
114
  await shell.openExternal(authUrl.toString());
108
115
  logger.debug('Opening authorization URL in default browser');
109
116
 
117
+ this.broadcastAuthorizationProgress({
118
+ elapsed: 0,
119
+ maxPollTime: MAX_POLL_TIME,
120
+ phase: 'browser_opened',
121
+ });
122
+
110
123
  // Start polling for credentials
111
124
  this.startPolling();
112
125
 
@@ -117,6 +130,24 @@ export default class AuthCtr extends ControllerModule {
117
130
  }
118
131
  }
119
132
 
133
+ /**
134
+ * Cancel current authorization process
135
+ */
136
+ @IpcMethod()
137
+ async cancelAuthorization() {
138
+ if (this.authRequestState) {
139
+ logger.info('User cancelled authorization');
140
+ this.clearAuthorizationState();
141
+ this.broadcastAuthorizationProgress({
142
+ elapsed: 0,
143
+ maxPollTime: MAX_POLL_TIME,
144
+ phase: 'cancelled',
145
+ });
146
+ return { success: true };
147
+ }
148
+ return { error: 'No active authorization', success: false };
149
+ }
150
+
120
151
  /**
121
152
  * Request Market OAuth authorization (desktop)
122
153
  */
@@ -152,14 +183,29 @@ export default class AuthCtr extends ControllerModule {
152
183
  }
153
184
 
154
185
  logger.info('Starting credential polling');
155
- const pollInterval = 3000; // 3 seconds
156
- const maxPollTime = 5 * 60 * 1000; // 5 minutes
186
+
157
187
  const startTime = Date.now();
158
188
 
189
+ // Broadcast initial state
190
+ this.broadcastAuthorizationProgress({
191
+ elapsed: 0,
192
+ maxPollTime: MAX_POLL_TIME,
193
+ phase: 'waiting_for_auth',
194
+ });
195
+
159
196
  this.pollingInterval = setInterval(async () => {
197
+ const elapsed = Date.now() - startTime;
198
+
199
+ // Broadcast progress on every tick
200
+ this.broadcastAuthorizationProgress({
201
+ elapsed,
202
+ maxPollTime: MAX_POLL_TIME,
203
+ phase: 'waiting_for_auth',
204
+ });
205
+
160
206
  try {
161
207
  // Check if polling has timed out
162
- if (Date.now() - startTime > maxPollTime) {
208
+ if (elapsed > MAX_POLL_TIME) {
163
209
  logger.warn('Credential polling timed out');
164
210
  this.clearAuthorizationState();
165
211
  this.broadcastAuthorizationFailed('Authorization timed out');
@@ -173,6 +219,13 @@ export default class AuthCtr extends ControllerModule {
173
219
  logger.info('Successfully received credentials from polling');
174
220
  this.stopPolling();
175
221
 
222
+ // Broadcast verifying state
223
+ this.broadcastAuthorizationProgress({
224
+ elapsed,
225
+ maxPollTime: MAX_POLL_TIME,
226
+ phase: 'verifying',
227
+ });
228
+
176
229
  // Validate state parameter
177
230
  if (result.state !== this.authRequestState) {
178
231
  logger.error(
@@ -198,7 +251,7 @@ export default class AuthCtr extends ControllerModule {
198
251
  this.clearAuthorizationState();
199
252
  this.broadcastAuthorizationFailed('Polling error: ' + error.message);
200
253
  }
201
- }, pollInterval);
254
+ }, POLL_INTERVAL);
202
255
  }
203
256
 
204
257
  /**
@@ -511,6 +564,21 @@ export default class AuthCtr extends ControllerModule {
511
564
  }
512
565
  }
513
566
 
567
+ /**
568
+ * Broadcast authorization progress event
569
+ */
570
+ private broadcastAuthorizationProgress(progress: AuthorizationProgress) {
571
+ // Avoid logging too frequently
572
+ // logger.debug('Broadcasting authorizationProgress event');
573
+ const allWindows = BrowserWindow.getAllWindows();
574
+
575
+ for (const win of allWindows) {
576
+ if (!win.isDestroyed()) {
577
+ win.webContents.send('authorizationProgress', progress);
578
+ }
579
+ }
580
+ }
581
+
514
582
  /**
515
583
  * Broadcast authorization failed event
516
584
  */
@@ -563,7 +631,7 @@ export default class AuthCtr extends ControllerModule {
563
631
  // Hash codeVerifier using SHA-256
564
632
  const encoder = new TextEncoder();
565
633
  const data = encoder.encode(codeVerifier);
566
- const digest = await crypto.subtle.digest('SHA-256', data as unknown as NodeJS.BufferSource);
634
+ const digest = await crypto.subtle.digest('SHA-256', data.buffer);
567
635
 
568
636
  // Convert hash result to base64url encoding
569
637
  const challenge = Buffer.from(digest)
@@ -1,7 +1,7 @@
1
1
  import type {
2
2
  InterceptRouteParams,
3
3
  OpenSettingsWindowOptions,
4
- WindowResizableParams,
4
+ WindowMinimumSizeParams,
5
5
  WindowSizeParams,
6
6
  } from '@lobechat/electron-client-ipc';
7
7
  import { findMatchingRoute } from '~common/routes';
@@ -81,9 +81,21 @@ export default class BrowserWindowsCtr extends ControllerModule {
81
81
  }
82
82
 
83
83
  @IpcMethod()
84
- setWindowResizable(params: WindowResizableParams) {
84
+ setWindowMinimumSize(params: WindowMinimumSizeParams) {
85
85
  this.withSenderIdentifier((identifier) => {
86
- this.app.browserManager.setWindowResizable(identifier, params.resizable);
86
+ const currentSize = this.app.browserManager.getWindowSize(identifier);
87
+ const nextWindowSize = {
88
+ ...currentSize,
89
+ };
90
+ if (params.height) {
91
+ nextWindowSize.height = Math.max(currentSize.height, params.height);
92
+ }
93
+ if (params.width) {
94
+ nextWindowSize.width = Math.max(currentSize.width, params.width);
95
+ }
96
+
97
+ this.app.browserManager.setWindowSize(identifier, nextWindowSize);
98
+ this.app.browserManager.setWindowMinimumSize(identifier, params);
87
99
  });
88
100
  }
89
101
 
@@ -1,4 +1,4 @@
1
- import { TITLE_BAR_HEIGHT } from '@lobechat/desktop-bridge';
1
+ import { APP_WINDOW_MIN_SIZE, TITLE_BAR_HEIGHT } from '@lobechat/desktop-bridge';
2
2
  import { MainBroadcastEventKey, MainBroadcastParams } from '@lobechat/electron-client-ipc';
3
3
  import {
4
4
  BrowserWindow,
@@ -291,9 +291,19 @@ export default class Browser {
291
291
  });
292
292
  }
293
293
 
294
- setWindowResizable(resizable: boolean): void {
295
- logger.debug(`[${this.identifier}] Setting window resizable: ${resizable}`);
296
- this._browserWindow?.setResizable(resizable);
294
+ setWindowMinimumSize(size: { height?: number; width?: number }): void {
295
+ logger.debug(`[${this.identifier}] Setting window minimum size: ${JSON.stringify(size)}`);
296
+
297
+ const currentMinimumSize = this._browserWindow?.getMinimumSize?.() ?? [0, 0];
298
+ const rawWidth = size.width ?? currentMinimumSize[0];
299
+ const rawHeight = size.height ?? currentMinimumSize[1];
300
+
301
+ // Electron doesn't "reset" minimum size with 0x0 reliably.
302
+ // Treat 0 / negative as fallback to app-level default preset.
303
+ const width = rawWidth > 0 ? rawWidth : APP_WINDOW_MIN_SIZE.width;
304
+ const height = rawHeight > 0 ? rawHeight : APP_WINDOW_MIN_SIZE.height;
305
+
306
+ this._browserWindow?.setMinimumSize?.(width, height);
297
307
  }
298
308
 
299
309
  // ==================== Window Position ====================
@@ -250,9 +250,14 @@ export class BrowserManager {
250
250
  browser?.setWindowSize(size);
251
251
  }
252
252
 
253
- setWindowResizable(identifier: string, resizable: boolean) {
253
+ getWindowSize(identifier: string) {
254
254
  const browser = this.browsers.get(identifier);
255
- browser?.setWindowResizable(resizable);
255
+ return browser?.browserWindow.getBounds();
256
+ }
257
+
258
+ setWindowMinimumSize(identifier: string, size: { height?: number; width?: number }) {
259
+ const browser = this.browsers.get(identifier);
260
+ browser?.setWindowMinimumSize(size);
256
261
  }
257
262
 
258
263
  getIdentifierByWebContents(webContents: WebContents): string | null {
package/changelog/v1.json CHANGED
@@ -1,4 +1,22 @@
1
1
  [
2
+ {
3
+ "children": {
4
+ "features": [
5
+ "Improve desktop onboarding window management and footer actions."
6
+ ]
7
+ },
8
+ "date": "2026-01-19",
9
+ "version": "2.0.0-next.314"
10
+ },
11
+ {
12
+ "children": {
13
+ "fixes": [
14
+ "Fix server agent task run with headless, internlm provider base url and homepage."
15
+ ]
16
+ },
17
+ "date": "2026-01-19",
18
+ "version": "2.0.0-next.313"
19
+ },
2
20
  {
3
21
  "children": {
4
22
  "improvements": [
@@ -14,7 +14,7 @@ tags:
14
14
 
15
15
  <Image cover src={'https://github.com/user-attachments/assets/be7dcd49-0165-4f7b-bf90-0739cc9dd212'} />
16
16
 
17
- [InternLM](https://platform.sensenova.cn/home) is a large pre-trained language model jointly launched by the Shanghai Artificial Intelligence Laboratory and Shusheng Group. This model focuses on natural language processing, aimed at understanding and generating human language, boasting powerful semantic comprehension and text generation capabilities.
17
+ [InternLM](https://internlm.intern-ai.org.cn/) is a large pre-trained language model jointly launched by the Shanghai Artificial Intelligence Laboratory and Shusheng Group. This model focuses on natural language processing, aimed at understanding and generating human language, boasting powerful semantic comprehension and text generation capabilities.
18
18
 
19
19
  This article will guide you on how to use InternLM in LobeChat.
20
20
 
@@ -39,7 +39,7 @@ This article will guide you on how to use InternLM in LobeChat.
39
39
 
40
40
  <Image alt={'Enter API Key'} inStep src={'https://github.com/user-attachments/assets/8ec7656e-1e3d-41e0-95a0-f6883135c2fc'} />
41
41
 
42
- - Enter the obtained `AccessKey ID` and `AccessKey Secret`
42
+ - Enter the obtained API Key
43
43
  - Choose a InternLM model for your AI assistant to start a conversation
44
44
 
45
45
  <Image alt={'Select InternLM Model and Start Conversation'} inStep src={'https://github.com/user-attachments/assets/76ad163e-ee19-4f95-a712-85bea764d3ec'} />
@@ -12,7 +12,7 @@ tags:
12
12
 
13
13
  <Image cover src={'https://github.com/user-attachments/assets/be7dcd49-0165-4f7b-bf90-0739cc9dd212'} />
14
14
 
15
- [书生浦语(InternLM)](https://platform.sensenova.cn/home) 是由上海人工智能实验室与书生集团联合推出的一款大型预训练语言模型。该模型专注于自然语言处理,旨在理解和生成自然语言,具备强大的语义理解和文本生成能力。
15
+ [书生浦语(InternLM)](https://internlm.intern-ai.org.cn/) 是由上海人工智能实验室与书生集团联合推出的一款大型预训练语言模型。该模型专注于自然语言处理,旨在理解和生成自然语言,具备强大的语义理解和文本生成能力。
16
16
 
17
17
  本文将指导你如何在 LobeChat 中使用书生浦语。
18
18
 
@@ -32,11 +32,11 @@ tags:
32
32
  ### 步骤二:在 LobeChat 中配置书生浦语
33
33
 
34
34
  - 访问 LobeChat 的`设置`界面
35
- - 在`AI 服务商`下找到 `书生浦语` 的设置项
35
+ - 在`AI 服务商`下找到 `书生` 的设置项
36
36
 
37
37
  <Image alt={'填入 API 密钥'} inStep src={'https://github.com/user-attachments/assets/8ec7656e-1e3d-41e0-95a0-f6883135c2fc'} />
38
38
 
39
- - 填入获得的 `AccessKey ID` 和 `AccessKey Secret`
39
+ - 填入获得的 API Key
40
40
  - 为你的 AI 助手选择一个书生浦语的模型即可开始对话
41
41
 
42
42
  <Image alt={'选择书生浦语模型并开始对话'} inStep src={'https://github.com/user-attachments/assets/76ad163e-ee19-4f95-a712-85bea764d3ec'} />
@@ -68,7 +68,7 @@ Then('I should be on an assistant detail page', async function (this: CustomWorl
68
68
 
69
69
  const currentUrl = this.page.url();
70
70
  // Check if URL matches assistant detail page pattern
71
- const hasAssistantDetail = /\/community\/assistant\/[^#?]+/.test(currentUrl);
71
+ const hasAssistantDetail = /\/community\/agent\/[^#?]+/.test(currentUrl);
72
72
  expect(
73
73
  hasAssistantDetail,
74
74
  `Expected URL to match assistant detail page pattern, but got: ${currentUrl}`,
@@ -138,7 +138,7 @@ Then('I should be on the assistant list page', async function (this: CustomWorld
138
138
  // After back navigation, URL should be /community/agent or /community
139
139
  const isListPage =
140
140
  (currentUrl.includes('/community/agent') &&
141
- !/\/community\/assistant\/[\dA-Za-z-]+$/.test(currentUrl)) ||
141
+ !/\/community\/agent\/[\dA-Za-z-]+$/.test(currentUrl)) ||
142
142
  currentUrl.endsWith('/community') ||
143
143
  currentUrl.includes('/community#');
144
144
 
@@ -230,10 +230,10 @@ When('I click on the sort dropdown', async function (this: CustomWorld) {
230
230
  });
231
231
 
232
232
  When('I select a sort option', async function (this: CustomWorld) {
233
- await this.page.waitForTimeout(500);
233
+ await this.page.waitForTimeout(1000);
234
234
 
235
- // Find and click a sort option (assuming dropdown opens a menu)
236
- const sortOptions = this.page.locator('[role="option"], [role="menuitem"]');
235
+ // The sort dropdown uses checkbox items with role="menuitemcheckbox"
236
+ const sortOptions = this.page.locator('[role="menuitemcheckbox"]');
237
237
 
238
238
  // Wait for options to appear
239
239
  await sortOptions.first().waitFor({ state: 'visible', timeout: 30_000 });
@@ -381,7 +381,7 @@ Then('the URL should contain the category parameter', async function (this: Cust
381
381
  currentUrl.includes('category=') ||
382
382
  currentUrl.includes('tag=') ||
383
383
  // For path-based routing like /community/agent/category-name
384
- /\/community\/assistant\/[^/?]+/.test(currentUrl);
384
+ /\/community\/agent\/[^/?]+/.test(currentUrl);
385
385
 
386
386
  expect(
387
387
  hasCategory,
@@ -433,8 +433,8 @@ Then('I should be navigated to the assistant detail page', async function (this:
433
433
  await this.page.waitForLoadState('networkidle', { timeout: 30_000 });
434
434
 
435
435
  const currentUrl = this.page.url();
436
- // Verify that URL changed and contains /assistant/ followed by an identifier
437
- const hasAssistantDetail = /\/community\/assistant\/[^#?]+/.test(currentUrl);
436
+ // Verify that URL changed and contains /agent/ followed by an identifier
437
+ const hasAssistantDetail = /\/community\/agent\/[^#?]+/.test(currentUrl);
438
438
  const urlChanged = currentUrl !== this.testContext.previousUrl;
439
439
 
440
440
  expect(
@@ -45,10 +45,24 @@ BeforeAll({ timeout: 600_000 }, async function () {
45
45
  // Navigate to signin page
46
46
  await page.goto(`${baseUrl}/signin`, { waitUntil: 'networkidle' });
47
47
 
48
+ // Wait for the page to fully hydrate
49
+ await page.waitForTimeout(2000);
50
+
51
+ // Check if we can find the email input
52
+ const emailInput = page
53
+ .locator('input[id="email"], input[name="email"], input[type="text"]')
54
+ .first();
55
+ const emailInputVisible = await emailInput.isVisible().catch(() => false);
56
+
57
+ if (!emailInputVisible) {
58
+ console.log(
59
+ '⚠️ Login form not available, skipping authentication (tests requiring auth may fail)',
60
+ );
61
+ return;
62
+ }
63
+
48
64
  // Step 1: Enter email
49
65
  console.log(' Step 1: Entering email...');
50
- const emailInput = page.locator('input[id="email"]').first();
51
- await emailInput.waitFor({ state: 'visible', timeout: 30_000 });
52
66
  await emailInput.fill(TEST_USER.email);
53
67
 
54
68
  // Click the next button
@@ -57,7 +71,9 @@ BeforeAll({ timeout: 600_000 }, async function () {
57
71
 
58
72
  // Step 2: Wait for password step and enter password
59
73
  console.log(' Step 2: Entering password...');
60
- const passwordInput = page.locator('input[id="password"]').first();
74
+ const passwordInput = page
75
+ .locator('input[id="password"], input[name="password"], input[type="password"]')
76
+ .first();
61
77
  await passwordInput.waitFor({ state: 'visible', timeout: 30_000 });
62
78
  await passwordInput.fill(TEST_USER.password);
63
79
 
@@ -12,6 +12,11 @@
12
12
  "import.importConfigFile.title": "Import Failed",
13
13
  "import.incompatible.description": "This file was exported from a higher version. Please try upgrading to the latest version and then re-importing.",
14
14
  "import.incompatible.title": "Current application does not support importing this file",
15
+ "inviteCode.currentEmail": "Current account: {{email}}",
16
+ "inviteCode.desc": "An invite code is required to access LobeHub. Please enter a valid invite code to continue.",
17
+ "inviteCode.friends": "Friends",
18
+ "inviteCode.getCodeHint": "Get an invite code from:",
19
+ "inviteCode.title": "Invite Code Required",
15
20
  "loginRequired.desc": "You will be redirected to the login page shortly",
16
21
  "loginRequired.title": "Please log in to use this feature",
17
22
  "notFound.backHome": "Back to Home",
@@ -144,5 +149,9 @@
144
149
  "upload.networkError": "Please check your network connection and ensure that the file storage service's cross-origin configuration is correct.",
145
150
  "upload.title": "File upload failed. Please check your network connection or try again later",
146
151
  "upload.unknownError": "Error reason: {{reason}}",
147
- "upload.uploadFailed": "File upload failed."
152
+ "upload.uploadFailed": "File upload failed.",
153
+ "waitlist.currentEmail": "Current account: {{email}}",
154
+ "waitlist.desc": "Your account is not on the whitelist. Please contact the administrator to request access.",
155
+ "waitlist.switchAccount": "Switch Account",
156
+ "waitlist.title": "Access Restricted"
148
157
  }
@@ -288,7 +288,7 @@
288
288
  "referral.rules.backfill.description": "Forgot to enter invite code? You can backfill within 3 days of registration",
289
289
  "referral.rules.backfill.expiredTip": "Backfill period has expired. Cannot backfill after 3 days of registration",
290
290
  "referral.rules.backfill.link": "Backfill Invite Code",
291
- "referral.rules.backfill.placeholder": "Enter invite code",
291
+ "referral.rules.backfill.placeholder": "Enter invite code or link",
292
292
  "referral.rules.backfill.submit": "Confirm Binding",
293
293
  "referral.rules.backfill.success": "Invite code bound successfully",
294
294
  "referral.rules.backfill.title": "Backfill Invite Code",
@@ -58,6 +58,7 @@
58
58
  "screen4.title": "您希望如何共享数据?",
59
59
  "screen4.title2": "您的选择将帮助我们改进",
60
60
  "screen4.title3": "您可以随时在设置中更改",
61
+ "screen5.actions.cancel": "取消",
61
62
  "screen5.actions.connectToServer": "连接服务器",
62
63
  "screen5.actions.connecting": "正在连接…",
63
64
  "screen5.actions.signInCloud": "登录 LobeHub Cloud",
@@ -65,6 +66,10 @@
65
66
  "screen5.actions.signingIn": "正在登录…",
66
67
  "screen5.actions.signingOut": "正在退出…",
67
68
  "screen5.actions.tryAgain": "重试",
69
+ "screen5.auth.phase.browserOpened": "浏览器已打开,请前往登录…",
70
+ "screen5.auth.phase.verifying": "正在验证凭证…",
71
+ "screen5.auth.phase.waitingForAuth": "等待授权完成…",
72
+ "screen5.auth.remaining": "剩余时间:{{time}}秒",
68
73
  "screen5.badge": "登录",
69
74
  "screen5.description": "登录以在所有设备间同步代理、群组、设置和上下文。",
70
75
  "screen5.errors.desktopOnlyOidc": "OIDC 授权仅在桌面端运行时可用。",
@@ -12,6 +12,11 @@
12
12
  "import.importConfigFile.title": "导入遇到了问题",
13
13
  "import.incompatible.description": "该文件由更高版本导出。请升级到最新版后再导入",
14
14
  "import.incompatible.title": "版本不兼容",
15
+ "inviteCode.currentEmail": "当前账号:{{email}}",
16
+ "inviteCode.desc": "需要邀请码才能访问 LobeHub。请输入有效的邀请码以继续。",
17
+ "inviteCode.friends": "好友",
18
+ "inviteCode.getCodeHint": "获取邀请码:",
19
+ "inviteCode.title": "需要邀请码",
15
20
  "loginRequired.desc": "将为你跳转到登录页。登录后即可继续",
16
21
  "loginRequired.title": "需要登录后继续",
17
22
  "notFound.backHome": "返回首页",
@@ -144,5 +149,9 @@
144
149
  "upload.networkError": "网络异常或跨域配置不正确。请检查文件存储服务的 CORS 设置后重试",
145
150
  "upload.title": "上传未能完成",
146
151
  "upload.unknownError": "原因:{{reason}}",
147
- "upload.uploadFailed": "上传未能完成"
152
+ "upload.uploadFailed": "上传未能完成",
153
+ "waitlist.currentEmail": "当前账号:{{email}}",
154
+ "waitlist.desc": "你的账号不在白名单中。请联系管理员申请访问权限。",
155
+ "waitlist.switchAccount": "切换账号",
156
+ "waitlist.title": "访问受限"
148
157
  }
@@ -288,7 +288,7 @@
288
288
  "referral.rules.backfill.description": "忘记填写邀请码?注册三天内可以补填",
289
289
  "referral.rules.backfill.expiredTip": "补填期限已过,注册超过三天后无法补填",
290
290
  "referral.rules.backfill.link": "补填邀请码",
291
- "referral.rules.backfill.placeholder": "请输入邀请码",
291
+ "referral.rules.backfill.placeholder": "请输入邀请码或链接",
292
292
  "referral.rules.backfill.submit": "确认绑定",
293
293
  "referral.rules.backfill.success": "邀请码绑定成功",
294
294
  "referral.rules.backfill.title": "补填邀请码",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lobehub/lobehub",
3
- "version": "2.0.0-next.312",
3
+ "version": "2.0.0-next.314",
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",
@@ -88,10 +88,22 @@ export class GeneralChatAgent implements Agent {
88
88
  }
89
89
 
90
90
  // Priority 0: CRITICAL - Check security blacklist FIRST
91
- // This overrides ALL other settings, including auto-run mode
92
91
  const securityCheck = InterventionChecker.checkSecurityBlacklist(securityBlacklist, toolArgs);
92
+
93
+ // Priority 0.5: Headless mode - fully automated for async tasks
94
+ // In headless mode: blacklisted tools are skipped, all other tools execute directly
95
+ if (approvalMode === 'headless') {
96
+ if (securityCheck.blocked) {
97
+ // Skip blacklisted tools entirely (don't execute, don't wait for approval)
98
+ continue;
99
+ }
100
+ // All other tools execute directly
101
+ toolsToExecute.push(toolCalling);
102
+ continue;
103
+ }
104
+
105
+ // For non-headless modes: security blacklist requires intervention
93
106
  if (securityCheck.blocked) {
94
- // Security blacklist always requires intervention
95
107
  toolsNeedingIntervention.push(toolCalling);
96
108
  continue;
97
109
  }