@lobehub/lobehub 2.0.0-next.312 → 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 (75) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/apps/desktop/src/main/controllers/AuthCtr.ts +75 -7
  3. package/changelog/v1.json +9 -0
  4. package/docs/usage/providers/internlm.mdx +2 -2
  5. package/docs/usage/providers/internlm.zh-CN.mdx +3 -3
  6. package/locales/en-US/error.json +10 -1
  7. package/locales/en-US/subscription.json +1 -1
  8. package/locales/zh-CN/desktop-onboarding.json +5 -0
  9. package/locales/zh-CN/error.json +10 -1
  10. package/locales/zh-CN/subscription.json +1 -1
  11. package/package.json +1 -1
  12. package/packages/agent-runtime/src/agents/GeneralChatAgent.ts +14 -2
  13. package/packages/agent-runtime/src/agents/__tests__/GeneralChatAgent.test.ts +275 -1
  14. package/packages/builtin-tool-cloud-sandbox/package.json +1 -0
  15. package/packages/builtin-tool-cloud-sandbox/src/ExecutionRuntime/index.ts +105 -134
  16. package/packages/builtin-tool-cloud-sandbox/src/executor/index.ts +254 -0
  17. package/packages/builtin-tool-cloud-sandbox/src/index.ts +1 -0
  18. package/packages/builtin-tool-cloud-sandbox/src/types/api.ts +22 -0
  19. package/packages/builtin-tool-cloud-sandbox/src/types/index.ts +4 -0
  20. package/packages/builtin-tool-cloud-sandbox/src/types/params.ts +85 -0
  21. package/packages/builtin-tool-cloud-sandbox/src/types/service.ts +48 -0
  22. package/packages/builtin-tool-cloud-sandbox/src/{types.ts → types/state.ts} +0 -23
  23. package/packages/builtin-tool-memory/src/manifest.ts +5 -5
  24. package/packages/editor-runtime/src/__tests__/EditorRuntime.real.test.ts +1 -1
  25. package/packages/editor-runtime/src/__tests__/EditorRuntime.test.ts +1 -1
  26. package/packages/electron-client-ipc/src/events/index.ts +5 -1
  27. package/packages/electron-client-ipc/src/events/remoteServer.ts +23 -0
  28. package/packages/memory-user-memory/src/schemas/index.ts +0 -1
  29. package/packages/model-bank/src/modelProviders/internlm.ts +1 -1
  30. package/packages/model-runtime/src/core/RouterRuntime/createRuntime.ts +5 -15
  31. package/packages/model-runtime/src/providers/internlm/index.test.ts +15 -15
  32. package/packages/model-runtime/src/providers/internlm/index.ts +1 -1
  33. package/packages/types/src/tool/intervention.ts +4 -2
  34. package/packages/types/src/user/preference.ts +1 -0
  35. package/src/app/[variants]/(desktop)/desktop-onboarding/features/LoginStep.tsx +84 -26
  36. package/src/app/[variants]/(main)/_layout/DesktopAutoOidcOnFirstOpen.tsx +4 -0
  37. package/src/business/server/user.ts +4 -0
  38. package/src/features/Conversation/Messages/Task/Actions/index.tsx +0 -2
  39. package/src/features/Conversation/Messages/Task/index.tsx +1 -1
  40. package/src/features/Conversation/Messages/Tasks/shared/ProcessingState.tsx +0 -2
  41. package/src/features/NavPanel/components/NavPanelDraggable.tsx +0 -14
  42. package/src/features/ResourceManager/components/Explorer/ItemDropdown/useFileItemDropdown.tsx +4 -3
  43. package/src/features/SharePopover/index.tsx +5 -3
  44. package/src/hooks/useAppOrigin.ts +16 -0
  45. package/src/layout/GlobalProvider/useUserStateRedirect.ts +37 -24
  46. package/src/libs/trusted-client/index.ts +2 -5
  47. package/src/locales/default/desktop-onboarding.ts +5 -0
  48. package/src/locales/default/error.ts +11 -0
  49. package/src/locales/default/subscription.ts +1 -1
  50. package/src/server/modules/AgentRuntime/RuntimeExecutors.ts +2 -0
  51. package/src/server/routers/lambda/user.ts +24 -10
  52. package/src/server/services/agentRuntime/AgentRuntimeService.test.ts +3 -0
  53. package/src/server/services/agentRuntime/AgentRuntimeService.ts +8 -5
  54. package/src/server/services/agentRuntime/types.ts +7 -0
  55. package/src/server/services/aiAgent/__tests__/execGroupSubAgentTask.test.ts +3 -0
  56. package/src/server/services/aiAgent/index.ts +10 -4
  57. package/src/server/services/market/index.ts +7 -0
  58. package/src/server/services/sandbox/index.ts +120 -0
  59. package/src/server/services/toolExecution/builtin.ts +12 -18
  60. package/src/server/services/toolExecution/index.ts +1 -1
  61. package/src/server/services/toolExecution/serverRuntimes/cloudSandbox.ts +31 -0
  62. package/src/server/services/toolExecution/serverRuntimes/index.ts +55 -0
  63. package/src/server/services/toolExecution/serverRuntimes/types.ts +14 -0
  64. package/src/server/services/toolExecution/serverRuntimes/webBrowsing.ts +20 -0
  65. package/src/server/services/toolExecution/types.ts +2 -0
  66. package/src/services/{codeInterpreter.ts → cloudSandbox.ts} +3 -3
  67. package/src/services/electron/remoteServer.ts +8 -0
  68. package/src/store/chat/agents/GroupOrchestration/__tests__/batch-exec-async-tasks.test.ts +626 -0
  69. package/src/store/chat/agents/GroupOrchestration/createGroupOrchestrationExecutors.ts +294 -0
  70. package/src/store/chat/slices/plugin/action.test.ts +0 -48
  71. package/src/store/chat/slices/plugin/actions/pluginTypes.ts +0 -131
  72. package/src/store/tool/slices/builtin/executors/index.ts +2 -0
  73. package/src/store/user/slices/settings/selectors/toolIntervention.test.ts +143 -0
  74. package/src/store/user/slices/settings/selectors/toolIntervention.ts +11 -2
  75. package/packages/memory-user-memory/src/schemas/jsonSchemas.ts +0 -37
@@ -0,0 +1,85 @@
1
+ // ==================== File Operations Params ====================
2
+
3
+ export interface ListLocalFilesParams {
4
+ directoryPath: string;
5
+ }
6
+
7
+ export interface ReadLocalFileParams {
8
+ endLine?: number;
9
+ path: string;
10
+ startLine?: number;
11
+ }
12
+
13
+ export interface WriteLocalFileParams {
14
+ content: string;
15
+ createDirectories?: boolean;
16
+ path: string;
17
+ }
18
+
19
+ export interface EditLocalFileParams {
20
+ all?: boolean;
21
+ path: string;
22
+ replace: string;
23
+ search: string;
24
+ }
25
+
26
+ export interface SearchLocalFilesParams {
27
+ directory: string;
28
+ fileType?: string;
29
+ keyword?: string;
30
+ modifiedAfter?: string;
31
+ modifiedBefore?: string;
32
+ }
33
+
34
+ export interface MoveLocalFilesParams {
35
+ operations: Array<{
36
+ destination: string;
37
+ source: string;
38
+ }>;
39
+ }
40
+
41
+ export interface RenameLocalFileParams {
42
+ newName: string;
43
+ oldPath: string;
44
+ }
45
+
46
+ export interface GlobLocalFilesParams {
47
+ directory?: string;
48
+ pattern: string;
49
+ }
50
+
51
+ export interface ExportFileParams {
52
+ path: string;
53
+ }
54
+
55
+ // ==================== Code Execution Params ====================
56
+
57
+ export interface ExecuteCodeParams {
58
+ code: string;
59
+ language?: 'javascript' | 'python' | 'typescript';
60
+ }
61
+
62
+ // ==================== Shell Command Params ====================
63
+
64
+ export interface RunCommandParams {
65
+ background?: boolean;
66
+ command: string;
67
+ timeout?: number;
68
+ }
69
+
70
+ export interface GetCommandOutputParams {
71
+ commandId: string;
72
+ }
73
+
74
+ export interface KillCommandParams {
75
+ commandId: string;
76
+ }
77
+
78
+ // ==================== Search & Find Params ====================
79
+
80
+ export interface GrepContentParams {
81
+ directory: string;
82
+ filePattern?: string;
83
+ pattern: string;
84
+ recursive?: boolean;
85
+ }
@@ -0,0 +1,48 @@
1
+ // ==================== Sandbox Service Interface ====================
2
+
3
+ /**
4
+ * Result of calling a sandbox tool
5
+ */
6
+ export interface SandboxCallToolResult {
7
+ error?: { message: string; name?: string };
8
+ result: any;
9
+ sessionExpiredAndRecreated?: boolean;
10
+ success: boolean;
11
+ }
12
+
13
+ /**
14
+ * Result of exporting and uploading a file from sandbox
15
+ */
16
+ export interface SandboxExportFileResult {
17
+ error?: { message: string };
18
+ fileId?: string;
19
+ filename: string;
20
+ mimeType?: string;
21
+ size?: number;
22
+ success: boolean;
23
+ url?: string;
24
+ }
25
+
26
+ /**
27
+ * Sandbox Service Interface - for dependency injection
28
+ *
29
+ * Context (topicId, userId) is bound at service creation time, not passed per-call.
30
+ * This allows CloudSandboxExecutionRuntime to work on both client and server:
31
+ * - Client: Implemented via tRPC client (codeInterpreterService)
32
+ * - Server: Implemented via MarketSDK directly (ServerSandboxService)
33
+ */
34
+ export interface ISandboxService {
35
+ /**
36
+ * Call a sandbox tool
37
+ * @param toolName - The name of the tool to call (e.g., 'runCommand', 'writeLocalFile')
38
+ * @param params - The parameters for the tool
39
+ */
40
+ callTool(toolName: string, params: Record<string, any>): Promise<SandboxCallToolResult>;
41
+
42
+ /**
43
+ * Export a file from sandbox and upload to cloud storage
44
+ * @param path - The file path in the sandbox
45
+ * @param filename - The name of the file to export
46
+ */
47
+ exportAndUploadFile(path: string, filename: string): Promise<SandboxExportFileResult>;
48
+ }
@@ -1,26 +1,3 @@
1
- /**
2
- * API names for Cloud Sandbox tool
3
- */
4
- export const CloudSandboxApiName = {
5
- editLocalFile: 'editLocalFile',
6
- executeCode: 'executeCode',
7
- exportFile: 'exportFile',
8
- getCommandOutput: 'getCommandOutput',
9
- globLocalFiles: 'globLocalFiles',
10
- grepContent: 'grepContent',
11
- killCommand: 'killCommand',
12
- listLocalFiles: 'listLocalFiles',
13
- moveLocalFiles: 'moveLocalFiles',
14
- readLocalFile: 'readLocalFile',
15
- renameLocalFile: 'renameLocalFile',
16
- runCommand: 'runCommand',
17
- searchLocalFiles: 'searchLocalFiles',
18
- writeLocalFile: 'writeLocalFile',
19
- } as const;
20
-
21
- export type CloudSandboxApiNameType =
22
- (typeof CloudSandboxApiName)[keyof typeof CloudSandboxApiName];
23
-
24
1
  // ==================== File Operations ====================
25
2
 
26
3
  export interface ListLocalFilesState {
@@ -278,16 +278,16 @@ export const MemoryManifest: BuiltinToolManifest = {
278
278
  },
279
279
  },
280
280
  required: [
281
+ 'situation',
282
+ 'reasoning',
281
283
  'action',
284
+ 'possibleOutcome',
282
285
  'keyLearning',
283
- 'knowledgeValueScore',
286
+ 'type',
284
287
  'labels',
285
- 'possibleOutcome',
286
288
  'problemSolvingScore',
287
- 'reasoning',
288
289
  'scoreConfidence',
289
- 'situation',
290
- 'type',
290
+ 'knowledgeValueScore',
291
291
  ],
292
292
  type: 'object',
293
293
  },
@@ -21,7 +21,7 @@ describe('EditorRuntime - Real Cases', () => {
21
21
  let mockTitleGetter: ReturnType<typeof vi.fn>;
22
22
 
23
23
  beforeEach(() => {
24
- editor = new Kernel();
24
+ editor = new Kernel() as unknown as IEditor;
25
25
  editor.registerPlugins([CommonPlugin, MarkdownPlugin, ListPlugin, LitexmlPlugin]);
26
26
  editor.initNodeEditor();
27
27
 
@@ -19,7 +19,7 @@ describe('EditorRuntime', () => {
19
19
 
20
20
  beforeEach(() => {
21
21
  resetRandomKey();
22
- editor = new Kernel();
22
+ editor = new Kernel() as unknown as IEditor;
23
23
  editor.registerPlugins([CommonPlugin, MarkdownPlugin, LitexmlPlugin]);
24
24
  editor.initNodeEditor();
25
25
 
@@ -22,5 +22,9 @@ export type MainBroadcastParams<T extends MainBroadcastEventKey> = Parameters<
22
22
  MainBroadcastEvents[T]
23
23
  >[0];
24
24
 
25
- export type { MarketAuthorizationParams } from './remoteServer';
25
+ export type {
26
+ AuthorizationPhase,
27
+ AuthorizationProgress,
28
+ MarketAuthorizationParams,
29
+ } from './remoteServer';
26
30
  export type { OpenSettingsWindowOptions } from './windows';
@@ -2,11 +2,34 @@ export interface MarketAuthorizationParams {
2
2
  authUrl: string;
3
3
  }
4
4
 
5
+ /**
6
+ * Authorization phase for progress tracking
7
+ */
8
+ export type AuthorizationPhase =
9
+ | 'browser_opened' // Browser has been opened for authorization
10
+ | 'waiting_for_auth' // Waiting for user to complete browser login
11
+ | 'verifying' // Received credentials, verifying with server
12
+ | 'cancelled'; // Authorization was cancelled by user
13
+
14
+ /**
15
+ * Authorization progress info for UI updates
16
+ */
17
+ export interface AuthorizationProgress {
18
+ /** Elapsed time in milliseconds since authorization started */
19
+ elapsed: number;
20
+ /** Maximum polling time in milliseconds */
21
+ maxPollTime: number;
22
+ /** Current authorization phase */
23
+ phase: AuthorizationPhase;
24
+ }
25
+
5
26
  /**
6
27
  * 从主进程广播的远程服务器相关事件
7
28
  */
8
29
  export interface RemoteServerBroadcastEvents {
9
30
  authorizationFailed: (params: { error: string }) => void;
31
+ /** Broadcast authorization progress for UI updates */
32
+ authorizationProgress: (params: AuthorizationProgress) => void;
10
33
  authorizationRequired: (params: void) => void;
11
34
  authorizationSuccessful: (params: void) => void;
12
35
  remoteServerConfigUpdated: (params: void) => void;
@@ -3,5 +3,4 @@ export * from './context';
3
3
  export * from './experience';
4
4
  export * from './gatekeeper';
5
5
  export * from './identity';
6
- export * from './jsonSchemas';
7
6
  export * from './preference';
@@ -14,7 +14,7 @@ const InternLM: ModelProviderCard = {
14
14
  settings: {
15
15
  disableBrowserRequest: true,
16
16
  proxyUrl: {
17
- placeholder: 'https://internlm-chat.intern-ai.org.cn/puyu/api/v1',
17
+ placeholder: 'https://chat.intern-ai.org.cn/api/v1',
18
18
  },
19
19
  sdkType: 'openai',
20
20
  showModelFetcher: true,
@@ -133,14 +133,6 @@ export interface CreateRouterRuntimeOptions<T extends Record<string, any> = any>
133
133
  routers: Routers;
134
134
  }
135
135
 
136
- const formatErrorMessage = (error: unknown): string => {
137
- if (error instanceof Error) {
138
- return error.name ? `${error.name}: ${error.message}` : error.message;
139
- }
140
-
141
- return String(error);
142
- };
143
-
144
136
  export const createRouterRuntime = ({
145
137
  id,
146
138
  routers,
@@ -310,30 +302,28 @@ export const createRouterRuntime = ({
310
302
  } catch (error) {
311
303
  lastError = error;
312
304
 
313
- const message = formatErrorMessage(error);
314
305
  if (attempt < totalOptions) {
315
306
  log(
316
- 'attempt failed, fallback to next: model=%s attempt=%d/%d apiType=%s channelId=%s remark=%s error=%s',
317
- model,
307
+ 'attempt %d/%d failed (model=%s apiType=%s channelId=%s remark=%s), trying next',
318
308
  attempt,
319
309
  totalOptions,
310
+ model,
320
311
  resolvedApiType,
321
312
  channelId ?? '',
322
313
  remark ?? '',
323
- message,
324
314
  );
325
315
  } else {
326
316
  log(
327
- 'attempt failed, no more fallbacks: model=%s attempt=%d/%d apiType=%s channelId=%s remark=%s error=%s',
328
- model,
317
+ 'attempt %d/%d failed (model=%s apiType=%s channelId=%s remark=%s), no more fallbacks',
329
318
  attempt,
330
319
  totalOptions,
320
+ model,
331
321
  resolvedApiType,
332
322
  channelId ?? '',
333
323
  remark ?? '',
334
- message,
335
324
  );
336
325
  }
326
+ console.error(error);
337
327
  }
338
328
  }
339
329
 
@@ -9,7 +9,7 @@ import { LobeInternLMAI, params } from './index';
9
9
  testProvider({
10
10
  Runtime: LobeInternLMAI,
11
11
  provider: ModelProvider.InternLM,
12
- defaultBaseURL: 'https://internlm-chat.intern-ai.org.cn/puyu/api/v1',
12
+ defaultBaseURL: 'https://chat.intern-ai.org.cn/api/v1',
13
13
  chatDebugEnv: 'DEBUG_INTERNLM_CHAT_COMPLETION',
14
14
  chatModel: 'internlm2_5-7b-chat',
15
15
  test: {
@@ -30,7 +30,7 @@ describe('LobeInternLMAI - custom features', () => {
30
30
 
31
31
  describe('params object', () => {
32
32
  it('should export params with correct baseURL', () => {
33
- expect(params.baseURL).toBe('https://internlm-chat.intern-ai.org.cn/puyu/api/v1');
33
+ expect(params.baseURL).toBe('https://chat.intern-ai.org.cn/api/v1');
34
34
  });
35
35
 
36
36
  it('should have correct provider', () => {
@@ -116,7 +116,7 @@ describe('LobeInternLMAI - custom features', () => {
116
116
  describe('models', () => {
117
117
  it('should fetch and process models', async () => {
118
118
  const mockClient = {
119
- baseURL: 'https://internlm-chat.intern-ai.org.cn/puyu/api/v1',
119
+ baseURL: 'https://chat.intern-ai.org.cn/api/v1',
120
120
  apiKey: 'test',
121
121
  models: {
122
122
  list: vi.fn().mockResolvedValue({
@@ -137,7 +137,7 @@ describe('LobeInternLMAI - custom features', () => {
137
137
 
138
138
  it('should detect function call capability from model name', async () => {
139
139
  const mockClient = {
140
- baseURL: 'https://internlm-chat.intern-ai.org.cn/puyu/api/v1',
140
+ baseURL: 'https://chat.intern-ai.org.cn/api/v1',
141
141
  apiKey: 'test',
142
142
  models: {
143
143
  list: vi.fn().mockResolvedValue({
@@ -156,7 +156,7 @@ describe('LobeInternLMAI - custom features', () => {
156
156
 
157
157
  it('should detect vision capability from model name', async () => {
158
158
  const mockClient = {
159
- baseURL: 'https://internlm-chat.intern-ai.org.cn/puyu/api/v1',
159
+ baseURL: 'https://chat.intern-ai.org.cn/api/v1',
160
160
  apiKey: 'test',
161
161
  models: {
162
162
  list: vi.fn().mockResolvedValue({
@@ -175,7 +175,7 @@ describe('LobeInternLMAI - custom features', () => {
175
175
 
176
176
  it('should handle case-insensitive keyword matching', async () => {
177
177
  const mockClient = {
178
- baseURL: 'https://internlm-chat.intern-ai.org.cn/puyu/api/v1',
178
+ baseURL: 'https://chat.intern-ai.org.cn/api/v1',
179
179
  apiKey: 'test',
180
180
  models: {
181
181
  list: vi.fn().mockResolvedValue({
@@ -194,7 +194,7 @@ describe('LobeInternLMAI - custom features', () => {
194
194
 
195
195
  it('should merge with known model data from model-bank', async () => {
196
196
  const mockClient = {
197
- baseURL: 'https://internlm-chat.intern-ai.org.cn/puyu/api/v1',
197
+ baseURL: 'https://chat.intern-ai.org.cn/api/v1',
198
198
  apiKey: 'test',
199
199
  models: {
200
200
  list: vi.fn().mockResolvedValue({
@@ -215,7 +215,7 @@ describe('LobeInternLMAI - custom features', () => {
215
215
 
216
216
  it('should handle models not in model-bank', async () => {
217
217
  const mockClient = {
218
- baseURL: 'https://internlm-chat.intern-ai.org.cn/puyu/api/v1',
218
+ baseURL: 'https://chat.intern-ai.org.cn/api/v1',
219
219
  apiKey: 'test',
220
220
  models: {
221
221
  list: vi.fn().mockResolvedValue({
@@ -238,7 +238,7 @@ describe('LobeInternLMAI - custom features', () => {
238
238
 
239
239
  it('should set enabled flag from known model', async () => {
240
240
  const mockClient = {
241
- baseURL: 'https://internlm-chat.intern-ai.org.cn/puyu/api/v1',
241
+ baseURL: 'https://chat.intern-ai.org.cn/api/v1',
242
242
  apiKey: 'test',
243
243
  models: {
244
244
  list: vi.fn().mockResolvedValue({
@@ -255,7 +255,7 @@ describe('LobeInternLMAI - custom features', () => {
255
255
 
256
256
  it('should inherit abilities from known model', async () => {
257
257
  const mockClient = {
258
- baseURL: 'https://internlm-chat.intern-ai.org.cn/puyu/api/v1',
258
+ baseURL: 'https://chat.intern-ai.org.cn/api/v1',
259
259
  apiKey: 'test',
260
260
  models: {
261
261
  list: vi.fn().mockResolvedValue({
@@ -291,7 +291,7 @@ describe('LobeInternLMAI - custom features', () => {
291
291
 
292
292
  it('should handle empty model list', async () => {
293
293
  const mockClient = {
294
- baseURL: 'https://internlm-chat.intern-ai.org.cn/puyu/api/v1',
294
+ baseURL: 'https://chat.intern-ai.org.cn/api/v1',
295
295
  apiKey: 'test',
296
296
  models: {
297
297
  list: vi.fn().mockResolvedValue({
@@ -306,7 +306,7 @@ describe('LobeInternLMAI - custom features', () => {
306
306
 
307
307
  it('should filter out null/undefined models', async () => {
308
308
  const mockClient = {
309
- baseURL: 'https://internlm-chat.intern-ai.org.cn/puyu/api/v1',
309
+ baseURL: 'https://chat.intern-ai.org.cn/api/v1',
310
310
  apiKey: 'test',
311
311
  models: {
312
312
  list: vi.fn().mockResolvedValue({
@@ -322,7 +322,7 @@ describe('LobeInternLMAI - custom features', () => {
322
322
 
323
323
  it('should set contextWindowTokens from known model', async () => {
324
324
  const mockClient = {
325
- baseURL: 'https://internlm-chat.intern-ai.org.cn/puyu/api/v1',
325
+ baseURL: 'https://chat.intern-ai.org.cn/api/v1',
326
326
  apiKey: 'test',
327
327
  models: {
328
328
  list: vi.fn().mockResolvedValue({
@@ -340,7 +340,7 @@ describe('LobeInternLMAI - custom features', () => {
340
340
 
341
341
  it('should set displayName from known model', async () => {
342
342
  const mockClient = {
343
- baseURL: 'https://internlm-chat.intern-ai.org.cn/puyu/api/v1',
343
+ baseURL: 'https://chat.intern-ai.org.cn/api/v1',
344
344
  apiKey: 'test',
345
345
  models: {
346
346
  list: vi.fn().mockResolvedValue({
@@ -358,7 +358,7 @@ describe('LobeInternLMAI - custom features', () => {
358
358
 
359
359
  it('should combine keyword detection with known model abilities', async () => {
360
360
  const mockClient = {
361
- baseURL: 'https://internlm-chat.intern-ai.org.cn/puyu/api/v1',
361
+ baseURL: 'https://chat.intern-ai.org.cn/api/v1',
362
362
  apiKey: 'test',
363
363
  models: {
364
364
  list: vi.fn().mockResolvedValue({
@@ -11,7 +11,7 @@ export interface InternLMModelCard {
11
11
  }
12
12
 
13
13
  export const params = {
14
- baseURL: 'https://internlm-chat.intern-ai.org.cn/puyu/api/v1',
14
+ baseURL: 'https://chat.intern-ai.org.cn/api/v1',
15
15
  chatCompletion: {
16
16
  handlePayload: (payload) => {
17
17
  return {
@@ -138,13 +138,15 @@ export interface UserInterventionConfig {
138
138
  * - auto-run: Automatically approve all tools without user consent
139
139
  * - allow-list: Only approve tools in the allow list
140
140
  * - manual: Use tool's own humanIntervention config (default)
141
+ * - headless: Fully automated mode for async tasks - all tools execute automatically,
142
+ * security blacklist tools are skipped (not blocked)
141
143
  */
142
- approvalMode: 'auto-run' | 'allow-list' | 'manual';
144
+ approvalMode: 'auto-run' | 'allow-list' | 'manual' | 'headless';
143
145
  }
144
146
 
145
147
  export const UserInterventionConfigSchema = z.object({
146
148
  allowList: z.array(z.string()).optional(),
147
- approvalMode: z.enum(['auto-run', 'allow-list', 'manual']),
149
+ approvalMode: z.enum(['auto-run', 'allow-list', 'manual', 'headless']),
148
150
  });
149
151
 
150
152
  /**
@@ -84,6 +84,7 @@ export interface UserInitializationState {
84
84
  hasConversation?: boolean;
85
85
  interests?: string[];
86
86
  isFreePlan?: boolean;
87
+ isInviteCodeRequired?: boolean;
87
88
  isInWaitList?: boolean;
88
89
  /** @deprecated Use onboarding field instead */
89
90
  isOnboard?: boolean;
@@ -1,6 +1,6 @@
1
1
  'use client';
2
2
 
3
- import { useWatchBroadcast } from '@lobechat/electron-client-ipc';
3
+ import { AuthorizationProgress, useWatchBroadcast } from '@lobechat/electron-client-ipc';
4
4
  import { Alert, Button, Center, Flexbox, Icon, Input, Text } from '@lobehub/ui';
5
5
  import { Divider } from 'antd';
6
6
  import { cssVar } from 'antd-style';
@@ -9,6 +9,7 @@ import { memo, useEffect, useState } from 'react';
9
9
  import { useTranslation } from 'react-i18next';
10
10
 
11
11
  import { isDesktop } from '@/const/version';
12
+ import { remoteServerService } from '@/services/electron/remoteServer';
12
13
  import { useElectronStore } from '@/store/electron';
13
14
  import { setDesktopAutoOidcFirstOpenHandled } from '@/utils/electron/autoOidc';
14
15
 
@@ -44,6 +45,7 @@ const LoginStep = memo<LoginStepProps>(({ onBack, onNext }) => {
44
45
  const { t } = useTranslation('desktop-onboarding');
45
46
  const [endpoint, setEndpoint] = useState('');
46
47
  const [cloudLoginStatus, setCloudLoginStatus] = useState<LoginStatus>('idle');
48
+ const [authProgress, setAuthProgress] = useState<AuthorizationProgress | null>(null);
47
49
  const [selfhostLoginStatus, setSelfhostLoginStatus] = useState<LoginStatus>('idle');
48
50
  const [remoteError, setRemoteError] = useState<string | null>(null);
49
51
  const [isSigningOut, setIsSigningOut] = useState(false);
@@ -164,29 +166,53 @@ const LoginStep = memo<LoginStepProps>(({ onBack, onNext }) => {
164
166
  useWatchBroadcast('authorizationSuccessful', async () => {
165
167
  setRemoteError(null);
166
168
  clearRemoteServerSyncError();
169
+ setAuthProgress(null);
167
170
  await refreshServerConfig();
168
171
  });
169
172
 
170
173
  useWatchBroadcast('authorizationFailed', ({ error }) => {
171
174
  setRemoteError(error);
175
+ setAuthProgress(null);
172
176
  if (cloudLoginStatus === 'loading') setCloudLoginStatus('error');
173
177
  if (selfhostLoginStatus === 'loading') setSelfhostLoginStatus('error');
174
178
  });
175
179
 
180
+ useWatchBroadcast('authorizationProgress', (progress) => {
181
+ setAuthProgress(progress);
182
+ if (progress.phase === 'cancelled') {
183
+ setCloudLoginStatus('idle');
184
+ setAuthProgress(null);
185
+ }
186
+ });
187
+
188
+ const handleCancelAuth = async () => {
189
+ await remoteServerService.cancelAuthorization();
190
+ setCloudLoginStatus('idle');
191
+ setAuthProgress(null);
192
+ };
193
+
176
194
  // 渲染 Cloud 登录内容
177
195
  const renderCloudContent = () => {
178
196
  if (cloudLoginStatus === 'success') {
179
197
  return (
180
- <Button
181
- block
182
- disabled={isSigningOut || isConnectingServer}
183
- icon={Cloud}
184
- onClick={handleSignOut}
185
- size={'large'}
186
- type={'default'}
187
- >
188
- {isSigningOut ? t('screen5.actions.signingOut') : t('screen5.actions.signOut')}
189
- </Button>
198
+ <Flexbox gap={12} style={{ width: '100%' }}>
199
+ <Alert
200
+ description={t('authResult.success.desc')}
201
+ style={{ width: '100%' }}
202
+ title={t('authResult.success.title')}
203
+ type={'success'}
204
+ />
205
+ <Button
206
+ block
207
+ disabled={isSigningOut || isConnectingServer}
208
+ icon={Cloud}
209
+ onClick={handleSignOut}
210
+ size={'large'}
211
+ type={'default'}
212
+ >
213
+ {isSigningOut ? t('screen5.actions.signingOut') : t('screen5.actions.signOut')}
214
+ </Button>
215
+ </Flexbox>
190
216
  );
191
217
  }
192
218
 
@@ -212,19 +238,43 @@ const LoginStep = memo<LoginStepProps>(({ onBack, onNext }) => {
212
238
  );
213
239
  }
214
240
 
241
+ if (cloudLoginStatus === 'loading') {
242
+ return (
243
+ <Flexbox gap={8} style={{ width: '100%' }}>
244
+ <Button block disabled={true} icon={Cloud} loading={true} size={'large'} type={'primary'}>
245
+ {authProgress
246
+ ? t(`screen5.auth.phase.${authProgress.phase}`, {
247
+ defaultValue: t('screen5.actions.signingIn'),
248
+ })
249
+ : t('screen5.actions.signingIn')}
250
+ </Button>
251
+ {authProgress && (
252
+ <Flexbox align={'center'} horizontal justify={'space-between'}>
253
+ <Text style={{ color: cssVar.colorTextDescription }} type={'secondary'}>
254
+ {t('screen5.auth.remaining', {
255
+ time: Math.round((authProgress.maxPollTime - authProgress.elapsed) / 1000),
256
+ })}
257
+ </Text>
258
+ <Button onClick={handleCancelAuth} size={'small'} type={'text'}>
259
+ {t('screen5.actions.cancel')}
260
+ </Button>
261
+ </Flexbox>
262
+ )}
263
+ </Flexbox>
264
+ );
265
+ }
266
+
215
267
  return (
216
268
  <Button
217
269
  block
218
- disabled={cloudLoginStatus === 'loading' || isConnectingServer}
270
+ disabled={isConnectingServer}
219
271
  icon={Cloud}
220
- loading={cloudLoginStatus === 'loading'}
272
+ loading={false}
221
273
  onClick={handleCloudLogin}
222
274
  size={'large'}
223
275
  type={'primary'}
224
276
  >
225
- {cloudLoginStatus === 'loading'
226
- ? t('screen5.actions.signingIn')
227
- : t('screen5.actions.signInCloud')}
277
+ {t('screen5.actions.signInCloud')}
228
278
  </Button>
229
279
  );
230
280
  };
@@ -233,16 +283,24 @@ const LoginStep = memo<LoginStepProps>(({ onBack, onNext }) => {
233
283
  const renderSelfhostContent = () => {
234
284
  if (selfhostLoginStatus === 'success') {
235
285
  return (
236
- <Button
237
- block
238
- disabled={isSigningOut || isConnectingServer}
239
- icon={Server}
240
- onClick={handleSignOut}
241
- size={'large'}
242
- type={'default'}
243
- >
244
- {isSigningOut ? t('screen5.actions.signingOut') : t('screen5.actions.signOut')}
245
- </Button>
286
+ <Flexbox gap={12} style={{ width: '100%' }}>
287
+ <Alert
288
+ description={t('authResult.success.desc')}
289
+ style={{ width: '100%' }}
290
+ title={t('authResult.success.title')}
291
+ type={'success'}
292
+ />
293
+ <Button
294
+ block
295
+ disabled={isSigningOut || isConnectingServer}
296
+ icon={Server}
297
+ onClick={handleSignOut}
298
+ size={'large'}
299
+ type={'default'}
300
+ >
301
+ {isSigningOut ? t('screen5.actions.signingOut') : t('screen5.actions.signOut')}
302
+ </Button>
303
+ </Flexbox>
246
304
  );
247
305
  }
248
306