@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.
- package/CHANGELOG.md +59 -0
- package/apps/desktop/src/main/controllers/AuthCtr.ts +75 -7
- package/changelog/v1.json +21 -0
- package/docs/usage/providers/internlm.mdx +2 -2
- package/docs/usage/providers/internlm.zh-CN.mdx +3 -3
- package/e2e/README.md +1 -1
- package/e2e/src/features/community/detail-pages.feature +2 -2
- package/e2e/src/features/community/interactions.feature +5 -5
- package/e2e/src/features/community/smoke.feature +1 -1
- package/e2e/src/steps/community/detail-pages.steps.ts +6 -4
- package/e2e/src/steps/community/interactions.steps.ts +3 -3
- package/locales/en-US/error.json +10 -1
- package/locales/en-US/subscription.json +1 -1
- package/locales/zh-CN/desktop-onboarding.json +5 -0
- package/locales/zh-CN/error.json +10 -1
- package/locales/zh-CN/subscription.json +1 -1
- package/package.json +1 -1
- package/packages/agent-runtime/src/agents/GeneralChatAgent.ts +14 -2
- package/packages/agent-runtime/src/agents/__tests__/GeneralChatAgent.test.ts +275 -1
- package/packages/builtin-tool-agent-builder/src/systemRole.ts +9 -0
- package/packages/builtin-tool-cloud-sandbox/package.json +1 -0
- package/packages/builtin-tool-cloud-sandbox/src/ExecutionRuntime/index.ts +105 -134
- package/packages/builtin-tool-cloud-sandbox/src/executor/index.ts +254 -0
- package/packages/builtin-tool-cloud-sandbox/src/index.ts +1 -0
- package/packages/builtin-tool-cloud-sandbox/src/types/api.ts +22 -0
- package/packages/builtin-tool-cloud-sandbox/src/types/index.ts +4 -0
- package/packages/builtin-tool-cloud-sandbox/src/types/params.ts +85 -0
- package/packages/builtin-tool-cloud-sandbox/src/types/service.ts +48 -0
- package/packages/builtin-tool-cloud-sandbox/src/{types.ts → types/state.ts} +0 -23
- package/packages/builtin-tool-memory/src/manifest.ts +5 -5
- package/packages/editor-runtime/src/__tests__/EditorRuntime.real.test.ts +1 -1
- package/packages/editor-runtime/src/__tests__/EditorRuntime.test.ts +1 -1
- package/packages/electron-client-ipc/src/events/index.ts +5 -1
- package/packages/electron-client-ipc/src/events/remoteServer.ts +23 -0
- package/packages/memory-user-memory/src/schemas/index.ts +0 -1
- package/packages/model-bank/src/modelProviders/internlm.ts +1 -1
- package/packages/model-runtime/src/core/RouterRuntime/createRuntime.ts +5 -15
- package/packages/model-runtime/src/providers/internlm/index.test.ts +15 -15
- package/packages/model-runtime/src/providers/internlm/index.ts +1 -1
- package/packages/types/src/tool/intervention.ts +4 -2
- package/packages/types/src/user/preference.ts +1 -0
- package/public/favicon-32x-32-error.ico +0 -0
- package/public/favicon-32x32-done-dev.ico +0 -0
- package/public/favicon-32x32-done.ico +0 -0
- package/public/favicon-32x32-error-dev.ico +0 -0
- package/public/favicon-32x32-progress-dev.ico +0 -0
- package/public/favicon-32x32-progress.ico +0 -0
- package/public/favicon-done-dev.ico +0 -0
- package/public/favicon-done.ico +0 -0
- package/public/favicon-error-dev.ico +0 -0
- package/public/favicon-error.ico +0 -0
- package/public/favicon-progress-dev.ico +0 -0
- package/public/favicon-progress.ico +0 -0
- package/src/app/[variants]/(desktop)/desktop-onboarding/features/LoginStep.tsx +84 -26
- package/src/app/[variants]/(main)/_layout/DesktopAutoOidcOnFirstOpen.tsx +4 -0
- package/src/app/[variants]/(main)/agent/profile/features/Header/AgentPublishButton/PublishResultModal.tsx +1 -1
- package/src/app/[variants]/(main)/community/(detail)/_layout/Header.tsx +15 -3
- package/src/app/[variants]/(main)/community/(detail)/{assistant → agent}/features/Details/Overview/TagList.tsx +1 -1
- package/src/app/[variants]/(main)/community/(detail)/{assistant → agent}/features/Details/Related/index.tsx +2 -2
- package/src/app/[variants]/(main)/community/(detail)/{assistant → agent}/features/Details/SystemRole/TagList.tsx +1 -1
- package/src/app/[variants]/(main)/community/(detail)/{assistant → agent}/features/Details/SystemRole/index.tsx +1 -1
- package/src/app/[variants]/(main)/community/(detail)/{assistant → agent}/features/Header.tsx +2 -2
- package/src/app/[variants]/(main)/community/(detail)/{assistant → agent}/features/Sidebar/ActionButton/AddAgent.tsx +1 -1
- package/src/app/[variants]/(main)/community/(detail)/{assistant → agent}/features/Sidebar/ActionButton/index.tsx +1 -1
- package/src/app/[variants]/(main)/community/(detail)/{assistant → agent}/features/Sidebar/Related/index.tsx +2 -2
- package/src/app/[variants]/(main)/community/(detail)/{assistant → agent}/features/StatusPage/index.tsx +2 -2
- package/src/app/[variants]/(main)/community/(detail)/user/features/UserAgentCard.tsx +2 -2
- package/src/app/[variants]/(main)/community/(detail)/user/features/UserFavoriteAgents.tsx +1 -1
- package/src/app/[variants]/(main)/community/(list)/(home)/index.tsx +2 -2
- package/src/app/[variants]/(main)/community/(list)/(home)/loading.tsx +1 -1
- package/src/app/[variants]/(main)/community/(list)/{assistant → agent}/Client.tsx +5 -1
- package/src/app/[variants]/(main)/community/(list)/{assistant → agent}/features/Category/index.tsx +1 -1
- package/src/app/[variants]/(main)/community/(list)/{assistant → agent}/features/List/Item.tsx +1 -1
- package/src/app/[variants]/(main)/community/(list)/{assistant → agent}/features/MarketSourceSwitch.tsx +1 -1
- package/src/app/[variants]/(main)/community/_layout/Sidebar/Header/Nav.tsx +2 -2
- package/src/app/[variants]/(main)/home/features/CommunityAgents/List.tsx +1 -1
- package/src/app/[variants]/(main)/home/features/CommunityAgents/index.tsx +1 -1
- package/src/app/[variants]/(mobile)/_layout/index.tsx +1 -1
- package/src/app/[variants]/(mobile)/router/mobileRouter.config.tsx +6 -6
- package/src/app/[variants]/router/desktopRouter.config.tsx +8 -8
- package/src/app/[variants]/share/t/[id]/_layout/index.tsx +1 -1
- package/src/business/server/user.ts +4 -0
- package/src/features/CommandMenu/SearchResults.tsx +1 -1
- package/src/features/Conversation/Messages/Task/Actions/index.tsx +0 -2
- package/src/features/Conversation/Messages/Task/index.tsx +1 -1
- package/src/features/Conversation/Messages/Tasks/shared/ProcessingState.tsx +0 -2
- package/src/features/Electron/navigation/routeMetadata.ts +1 -1
- package/src/features/NavPanel/components/NavPanelDraggable.tsx +0 -14
- package/src/features/ResourceManager/components/Explorer/ItemDropdown/useFileItemDropdown.tsx +4 -3
- package/src/features/SharePopover/index.tsx +5 -3
- package/src/hooks/useAppOrigin.ts +16 -0
- package/src/layout/GlobalProvider/FaviconProvider.tsx +92 -0
- package/src/layout/GlobalProvider/index.tsx +15 -11
- package/src/layout/GlobalProvider/useUserStateRedirect.ts +37 -24
- package/src/libs/next/config/define-config.ts +1 -1
- package/src/libs/trusted-client/index.ts +2 -5
- package/src/locales/default/desktop-onboarding.ts +5 -0
- package/src/locales/default/error.ts +11 -0
- package/src/locales/default/subscription.ts +1 -1
- package/src/server/modules/AgentRuntime/RuntimeExecutors.ts +2 -0
- package/src/server/routers/lambda/user.ts +24 -10
- package/src/server/services/agentRuntime/AgentRuntimeService.test.ts +3 -0
- package/src/server/services/agentRuntime/AgentRuntimeService.ts +8 -5
- package/src/server/services/agentRuntime/types.ts +7 -0
- package/src/server/services/aiAgent/__tests__/execGroupSubAgentTask.test.ts +3 -0
- package/src/server/services/aiAgent/index.ts +10 -4
- package/src/server/services/market/index.ts +7 -0
- package/src/server/services/sandbox/index.ts +120 -0
- package/src/server/services/toolExecution/builtin.ts +12 -18
- package/src/server/services/toolExecution/index.ts +1 -1
- package/src/server/services/toolExecution/serverRuntimes/cloudSandbox.ts +31 -0
- package/src/server/services/toolExecution/serverRuntimes/index.ts +55 -0
- package/src/server/services/toolExecution/serverRuntimes/types.ts +14 -0
- package/src/server/services/toolExecution/serverRuntimes/webBrowsing.ts +20 -0
- package/src/server/services/toolExecution/types.ts +2 -0
- package/src/server/sitemap.test.ts +5 -5
- package/src/server/sitemap.ts +3 -3
- package/src/services/{codeInterpreter.ts → cloudSandbox.ts} +3 -3
- package/src/services/electron/remoteServer.ts +8 -0
- package/src/store/chat/agents/GroupOrchestration/__tests__/batch-exec-async-tasks.test.ts +626 -0
- package/src/store/chat/agents/GroupOrchestration/createGroupOrchestrationExecutors.ts +294 -0
- package/src/store/chat/slices/plugin/action.test.ts +0 -48
- package/src/store/chat/slices/plugin/actions/pluginTypes.ts +0 -131
- package/src/store/tool/slices/builtin/executors/index.ts +2 -0
- package/src/store/user/slices/settings/selectors/toolIntervention.test.ts +143 -0
- package/src/store/user/slices/settings/selectors/toolIntervention.ts +11 -2
- package/packages/memory-user-memory/src/schemas/jsonSchemas.ts +0 -37
- /package/src/app/[variants]/(main)/community/(detail)/{assistant → agent}/features/DetailProvider.tsx +0 -0
- /package/src/app/[variants]/(main)/community/(detail)/{assistant → agent}/features/Details/Capabilities/Block.tsx +0 -0
- /package/src/app/[variants]/(main)/community/(detail)/{assistant → agent}/features/Details/Capabilities/Knowledge.tsx +0 -0
- /package/src/app/[variants]/(main)/community/(detail)/{assistant → agent}/features/Details/Capabilities/KnowledgeItem.tsx +0 -0
- /package/src/app/[variants]/(main)/community/(detail)/{assistant → agent}/features/Details/Capabilities/PluginItem.tsx +0 -0
- /package/src/app/[variants]/(main)/community/(detail)/{assistant → agent}/features/Details/Capabilities/Plugins.tsx +0 -0
- /package/src/app/[variants]/(main)/community/(detail)/{assistant → agent}/features/Details/Capabilities/index.tsx +0 -0
- /package/src/app/[variants]/(main)/community/(detail)/{assistant → agent}/features/Details/Nav.tsx +0 -0
- /package/src/app/[variants]/(main)/community/(detail)/{assistant → agent}/features/Details/Overview/index.tsx +0 -0
- /package/src/app/[variants]/(main)/community/(detail)/{assistant → agent}/features/Details/Versions/index.tsx +0 -0
- /package/src/app/[variants]/(main)/community/(detail)/{assistant → agent}/features/Details/index.tsx +0 -0
- /package/src/app/[variants]/(main)/community/(detail)/{assistant → agent}/features/Sidebar/Related/Item.tsx +0 -0
- /package/src/app/[variants]/(main)/community/(detail)/{assistant → agent}/features/Sidebar/Summary/index.tsx +0 -0
- /package/src/app/[variants]/(main)/community/(detail)/{assistant → agent}/features/Sidebar/TocList/index.tsx +0 -0
- /package/src/app/[variants]/(main)/community/(detail)/{assistant → agent}/features/Sidebar/index.tsx +0 -0
- /package/src/app/[variants]/(main)/community/(detail)/{assistant → agent}/index.tsx +0 -0
- /package/src/app/[variants]/(main)/community/(detail)/{assistant → agent}/loading.tsx +0 -0
- /package/src/app/[variants]/(main)/community/(list)/{assistant → agent}/_layout/index.tsx +0 -0
- /package/src/app/[variants]/(main)/community/(list)/{assistant → agent}/_layout/style.ts +0 -0
- /package/src/app/[variants]/(main)/community/(list)/{assistant → agent}/features/Category/useCategory.tsx +0 -0
- /package/src/app/[variants]/(main)/community/(list)/{assistant → agent}/features/List/TokenTag.tsx +0 -0
- /package/src/app/[variants]/(main)/community/(list)/{assistant → agent}/features/List/index.tsx +0 -0
- /package/src/app/[variants]/(main)/community/(list)/{assistant → agent}/index.tsx +0 -0
- /package/src/app/[variants]/(main)/community/(list)/{assistant → agent}/loading.tsx +0 -0
|
@@ -16,7 +16,12 @@ import { after } from 'next/server';
|
|
|
16
16
|
import { v4 as uuidv4 } from 'uuid';
|
|
17
17
|
import { z } from 'zod';
|
|
18
18
|
|
|
19
|
-
import {
|
|
19
|
+
import {
|
|
20
|
+
getIsInviteCodeRequired,
|
|
21
|
+
getIsInWaitList,
|
|
22
|
+
getReferralStatus,
|
|
23
|
+
getSubscriptionPlan,
|
|
24
|
+
} from '@/business/server/user';
|
|
20
25
|
import { MessageModel } from '@/database/models/message';
|
|
21
26
|
import { SessionModel } from '@/database/models/session';
|
|
22
27
|
import { UserModel, UserNotFoundError } from '@/database/models/user';
|
|
@@ -129,15 +134,23 @@ export const userRouter = router({
|
|
|
129
134
|
};
|
|
130
135
|
|
|
131
136
|
// Run user state fetch and count queries in parallel
|
|
132
|
-
const [
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
137
|
+
const [
|
|
138
|
+
state,
|
|
139
|
+
messageCount,
|
|
140
|
+
hasExtraSession,
|
|
141
|
+
referralStatus,
|
|
142
|
+
subscriptionPlan,
|
|
143
|
+
isInWaitList,
|
|
144
|
+
isInviteCodeRequired,
|
|
145
|
+
] = await Promise.all([
|
|
146
|
+
getOrCreateUserState(),
|
|
147
|
+
ctx.messageModel.countUpTo(5),
|
|
148
|
+
ctx.sessionModel.hasMoreThanN(1),
|
|
149
|
+
getReferralStatus(ctx.userId),
|
|
150
|
+
getSubscriptionPlan(ctx.userId),
|
|
151
|
+
getIsInWaitList(ctx.userId),
|
|
152
|
+
getIsInviteCodeRequired(ctx.userId),
|
|
153
|
+
]);
|
|
141
154
|
|
|
142
155
|
const hasMoreThan4Messages = messageCount > 4;
|
|
143
156
|
const hasAnyMessages = messageCount > 0;
|
|
@@ -168,6 +181,7 @@ export const userRouter = router({
|
|
|
168
181
|
referralStatus,
|
|
169
182
|
subscriptionPlan,
|
|
170
183
|
isInWaitList,
|
|
184
|
+
isInviteCodeRequired,
|
|
171
185
|
isFreePlan: !subscriptionPlan || subscriptionPlan === Plans.Free,
|
|
172
186
|
} satisfies UserInitializationState;
|
|
173
187
|
/* eslint-enable sort-keys-fix/sort-keys-fix */
|
|
@@ -40,6 +40,9 @@ vi.mock('@/server/modules/ModelRuntime', () => ({
|
|
|
40
40
|
|
|
41
41
|
// Mock search service to avoid server-side env access
|
|
42
42
|
vi.mock('@/server/services/search', () => ({
|
|
43
|
+
SearchService: vi.fn().mockImplementation(() => ({
|
|
44
|
+
search: vi.fn(),
|
|
45
|
+
})),
|
|
43
46
|
searchService: {
|
|
44
47
|
search: vi.fn(),
|
|
45
48
|
},
|
|
@@ -233,6 +233,7 @@ export class AgentRuntimeService {
|
|
|
233
233
|
toolManifestMap,
|
|
234
234
|
toolSourceMap,
|
|
235
235
|
stepCallbacks,
|
|
236
|
+
userInterventionConfig,
|
|
236
237
|
} = params;
|
|
237
238
|
|
|
238
239
|
try {
|
|
@@ -261,6 +262,8 @@ export class AgentRuntimeService {
|
|
|
261
262
|
toolManifestMap,
|
|
262
263
|
toolSourceMap,
|
|
263
264
|
tools,
|
|
265
|
+
// User intervention config for headless mode in async tasks
|
|
266
|
+
userInterventionConfig,
|
|
264
267
|
} as Partial<AgentState>;
|
|
265
268
|
|
|
266
269
|
// Use coordinator to create operation, automatically sends initialization event
|
|
@@ -329,10 +332,7 @@ export class AgentRuntimeService {
|
|
|
329
332
|
});
|
|
330
333
|
|
|
331
334
|
// Get operation state and metadata
|
|
332
|
-
const
|
|
333
|
-
this.coordinator.loadAgentState(operationId),
|
|
334
|
-
this.coordinator.getOperationMetadata(operationId),
|
|
335
|
-
]);
|
|
335
|
+
const agentState = await this.coordinator.loadAgentState(operationId);
|
|
336
336
|
|
|
337
337
|
if (!agentState) {
|
|
338
338
|
throw new Error(`Agent state not found for operation ${operationId}`);
|
|
@@ -353,8 +353,10 @@ export class AgentRuntimeService {
|
|
|
353
353
|
}
|
|
354
354
|
|
|
355
355
|
// Create Agent and Runtime instances
|
|
356
|
+
// Use agentState.metadata which contains the full app context (topicId, agentId, etc.)
|
|
357
|
+
// operationMetadata only contains basic fields (agentConfig, modelRuntimeConfig, userId)
|
|
356
358
|
const { runtime } = await this.createAgentRuntime({
|
|
357
|
-
metadata:
|
|
359
|
+
metadata: agentState?.metadata,
|
|
358
360
|
operationId,
|
|
359
361
|
stepIndex,
|
|
360
362
|
});
|
|
@@ -850,6 +852,7 @@ export class AgentRuntimeService {
|
|
|
850
852
|
stepIndex,
|
|
851
853
|
streamManager: this.streamManager,
|
|
852
854
|
toolExecutionService: this.toolExecutionService,
|
|
855
|
+
topicId: metadata?.topicId,
|
|
853
856
|
userId: metadata?.userId,
|
|
854
857
|
};
|
|
855
858
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type AgentRuntimeContext, type AgentState } from '@lobechat/agent-runtime';
|
|
2
2
|
import { type LobeToolManifest } from '@lobechat/context-engine';
|
|
3
|
+
import type { UserInterventionConfig } from '@lobechat/types';
|
|
3
4
|
|
|
4
5
|
// ==================== Step Lifecycle Callbacks ====================
|
|
5
6
|
|
|
@@ -90,6 +91,12 @@ export interface OperationCreationParams {
|
|
|
90
91
|
toolSourceMap?: Record<string, 'builtin' | 'plugin' | 'mcp' | 'klavis' | 'lobehubSkill'>;
|
|
91
92
|
tools?: any[];
|
|
92
93
|
userId?: string;
|
|
94
|
+
/**
|
|
95
|
+
* User intervention configuration
|
|
96
|
+
* Controls how tools requiring approval are handled
|
|
97
|
+
* Use { approvalMode: 'headless' } for async tasks that should never wait for human approval
|
|
98
|
+
*/
|
|
99
|
+
userInterventionConfig?: UserInterventionConfig;
|
|
93
100
|
}
|
|
94
101
|
|
|
95
102
|
export interface OperationCreationResult {
|
|
@@ -8,6 +8,7 @@ import type {
|
|
|
8
8
|
ExecGroupAgentResult,
|
|
9
9
|
ExecSubAgentTaskParams,
|
|
10
10
|
ExecSubAgentTaskResult,
|
|
11
|
+
UserInterventionConfig,
|
|
11
12
|
} from '@lobechat/types';
|
|
12
13
|
import { ThreadStatus, ThreadType } from '@lobechat/types';
|
|
13
14
|
import { nanoid } from '@lobechat/utils';
|
|
@@ -66,6 +67,11 @@ interface InternalExecAgentParams extends ExecAgentParams {
|
|
|
66
67
|
stepCallbacks?: StepLifecycleCallbacks;
|
|
67
68
|
/** Topic creation trigger source ('cron' | 'chat' | 'api') */
|
|
68
69
|
trigger?: string;
|
|
70
|
+
/**
|
|
71
|
+
* User intervention configuration
|
|
72
|
+
* Use { approvalMode: 'headless' } for async tasks that should never wait for human approval
|
|
73
|
+
*/
|
|
74
|
+
userInterventionConfig?: UserInterventionConfig;
|
|
69
75
|
}
|
|
70
76
|
|
|
71
77
|
/**
|
|
@@ -125,6 +131,7 @@ export class AiAgentService {
|
|
|
125
131
|
stepCallbacks,
|
|
126
132
|
trigger,
|
|
127
133
|
cronJobId,
|
|
134
|
+
userInterventionConfig,
|
|
128
135
|
} = params;
|
|
129
136
|
|
|
130
137
|
// Validate that either agentId or slug is provided
|
|
@@ -231,10 +238,6 @@ export class AiAgentService {
|
|
|
231
238
|
|
|
232
239
|
const tools = toolsResult.tools;
|
|
233
240
|
|
|
234
|
-
// Log detailed tools generation result
|
|
235
|
-
if (toolsResult.filteredTools && toolsResult.filteredTools.length > 0) {
|
|
236
|
-
log('execAgent: filtered tools: %O', toolsResult.filteredTools);
|
|
237
|
-
}
|
|
238
241
|
log('execAgent: enabled tool ids: %O', toolsResult.enabledToolIds);
|
|
239
242
|
|
|
240
243
|
// Get manifest map and convert from Map to Record
|
|
@@ -396,6 +399,7 @@ export class AiAgentService {
|
|
|
396
399
|
toolSourceMap,
|
|
397
400
|
tools,
|
|
398
401
|
userId: this.userId,
|
|
402
|
+
userInterventionConfig,
|
|
399
403
|
});
|
|
400
404
|
|
|
401
405
|
log('execAgent: created operation %s (autoStarted: %s)', operationId, result.autoStarted);
|
|
@@ -572,12 +576,14 @@ export class AiAgentService {
|
|
|
572
576
|
|
|
573
577
|
// 4. Delegate to execAgent with threadId in appContext and callbacks
|
|
574
578
|
// The instruction will be created as user message in the Thread
|
|
579
|
+
// Use headless mode to skip human approval in async task execution
|
|
575
580
|
const result = await this.execAgent({
|
|
576
581
|
agentId,
|
|
577
582
|
appContext: { groupId, threadId: thread.id, topicId },
|
|
578
583
|
autoStart: true,
|
|
579
584
|
prompt: instruction,
|
|
580
585
|
stepCallbacks,
|
|
586
|
+
userInterventionConfig: { approvalMode: 'headless' },
|
|
581
587
|
});
|
|
582
588
|
|
|
583
589
|
log(
|
|
@@ -368,6 +368,13 @@ export class MarketService {
|
|
|
368
368
|
return this.market.user.getUserInfo(username, options);
|
|
369
369
|
}
|
|
370
370
|
|
|
371
|
+
/**
|
|
372
|
+
* Register user on market and optionally follow another user
|
|
373
|
+
*/
|
|
374
|
+
async registerUser(params: { followUserId?: string; registerUserId: string }): Promise<void> {
|
|
375
|
+
await this.market.user.register(params);
|
|
376
|
+
}
|
|
377
|
+
|
|
371
378
|
// ============================== Skills Methods ==============================
|
|
372
379
|
|
|
373
380
|
/**
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { type CodeInterpreterToolName } from '@lobehub/market-sdk';
|
|
2
|
+
import {
|
|
3
|
+
type ISandboxService,
|
|
4
|
+
type SandboxCallToolResult,
|
|
5
|
+
type SandboxExportFileResult,
|
|
6
|
+
} from '@lobechat/builtin-tool-cloud-sandbox';
|
|
7
|
+
import debug from 'debug';
|
|
8
|
+
|
|
9
|
+
import { MarketService } from '@/server/services/market';
|
|
10
|
+
|
|
11
|
+
const log = debug('lobe-server:sandbox-service');
|
|
12
|
+
|
|
13
|
+
export interface ServerSandboxServiceOptions {
|
|
14
|
+
marketService: MarketService;
|
|
15
|
+
topicId: string;
|
|
16
|
+
userId: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Server-side Sandbox Service
|
|
21
|
+
*
|
|
22
|
+
* This service implements ISandboxService for server-side execution.
|
|
23
|
+
* Context (topicId, userId) is bound at construction time.
|
|
24
|
+
* It uses MarketService to call sandbox tools.
|
|
25
|
+
*
|
|
26
|
+
* Usage:
|
|
27
|
+
* - Used by BuiltinToolsExecutor when executing CloudSandbox tools on server
|
|
28
|
+
* - MarketService handles authentication via trustedClientToken
|
|
29
|
+
*/
|
|
30
|
+
export class ServerSandboxService implements ISandboxService {
|
|
31
|
+
private marketService: MarketService;
|
|
32
|
+
private topicId: string;
|
|
33
|
+
private userId: string;
|
|
34
|
+
|
|
35
|
+
constructor(options: ServerSandboxServiceOptions) {
|
|
36
|
+
this.marketService = options.marketService;
|
|
37
|
+
this.topicId = options.topicId;
|
|
38
|
+
this.userId = options.userId;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Call a sandbox tool via MarketService
|
|
43
|
+
*/
|
|
44
|
+
async callTool(toolName: string, params: Record<string, any>): Promise<SandboxCallToolResult> {
|
|
45
|
+
log('Calling sandbox tool: %s with params: %O, topicId: %s', toolName, params, this.topicId);
|
|
46
|
+
|
|
47
|
+
try {
|
|
48
|
+
const response = await this.marketService.getSDK().plugins.runBuildInTool(
|
|
49
|
+
toolName as CodeInterpreterToolName,
|
|
50
|
+
params as any,
|
|
51
|
+
{ topicId: this.topicId, userId: this.userId },
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
log('Sandbox tool %s response: %O', toolName, response);
|
|
55
|
+
|
|
56
|
+
if (!response.success) {
|
|
57
|
+
return {
|
|
58
|
+
error: {
|
|
59
|
+
message: response.error?.message || 'Unknown error',
|
|
60
|
+
name: response.error?.code,
|
|
61
|
+
},
|
|
62
|
+
result: null,
|
|
63
|
+
sessionExpiredAndRecreated: false,
|
|
64
|
+
success: false,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return {
|
|
69
|
+
result: response.data?.result,
|
|
70
|
+
sessionExpiredAndRecreated: response.data?.sessionExpiredAndRecreated || false,
|
|
71
|
+
success: true,
|
|
72
|
+
};
|
|
73
|
+
} catch (error) {
|
|
74
|
+
log('Error calling sandbox tool %s: %O', toolName, error);
|
|
75
|
+
|
|
76
|
+
return {
|
|
77
|
+
error: {
|
|
78
|
+
message: (error as Error).message,
|
|
79
|
+
name: (error as Error).name,
|
|
80
|
+
},
|
|
81
|
+
result: null,
|
|
82
|
+
sessionExpiredAndRecreated: false,
|
|
83
|
+
success: false,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Export and upload a file from sandbox
|
|
90
|
+
*
|
|
91
|
+
* Note: This is a simplified version for server-side use.
|
|
92
|
+
* The full implementation with S3 upload is in the tRPC router.
|
|
93
|
+
*/
|
|
94
|
+
async exportAndUploadFile(path: string, filename: string): Promise<SandboxExportFileResult> {
|
|
95
|
+
log('Exporting file: %s from path: %s, topicId: %s', filename, path, this.topicId);
|
|
96
|
+
|
|
97
|
+
// For server-side, we need to call the exportFile tool
|
|
98
|
+
// The full S3 upload logic should be handled separately
|
|
99
|
+
// This is a basic implementation that can be extended
|
|
100
|
+
|
|
101
|
+
try {
|
|
102
|
+
return {
|
|
103
|
+
error: {
|
|
104
|
+
message:
|
|
105
|
+
'Server-side file export not fully implemented. Use tRPC endpoint for file exports.',
|
|
106
|
+
},
|
|
107
|
+
filename,
|
|
108
|
+
success: false,
|
|
109
|
+
};
|
|
110
|
+
} catch (error) {
|
|
111
|
+
log('Error exporting file: %O', error);
|
|
112
|
+
|
|
113
|
+
return {
|
|
114
|
+
error: { message: (error as Error).message },
|
|
115
|
+
filename,
|
|
116
|
+
success: false,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
@@ -1,28 +1,26 @@
|
|
|
1
|
-
import { WebBrowsingManifest } from '@lobechat/builtin-tool-web-browsing';
|
|
2
|
-
import { WebBrowsingExecutionRuntime } from '@lobechat/builtin-tool-web-browsing/executionRuntime';
|
|
3
1
|
import { type LobeChatDatabase } from '@lobechat/database';
|
|
4
2
|
import { type ChatToolPayload } from '@lobechat/types';
|
|
5
3
|
import { safeParseJSON } from '@lobechat/utils';
|
|
6
4
|
import debug from 'debug';
|
|
7
5
|
|
|
8
6
|
import { MarketService } from '@/server/services/market';
|
|
9
|
-
import { SearchService } from '@/server/services/search';
|
|
10
7
|
|
|
11
|
-
import {
|
|
8
|
+
import { getServerRuntime, hasServerRuntime } from './serverRuntimes';
|
|
9
|
+
import { type IToolExecutor, type ToolExecutionContext, type ToolExecutionResult } from './types';
|
|
12
10
|
|
|
13
11
|
const log = debug('lobe-server:builtin-tools-executor');
|
|
14
12
|
|
|
15
|
-
const BuiltinToolServerRuntimes: Record<string, any> = {
|
|
16
|
-
[WebBrowsingManifest.identifier]: WebBrowsingExecutionRuntime,
|
|
17
|
-
};
|
|
18
|
-
|
|
19
13
|
export class BuiltinToolsExecutor implements IToolExecutor {
|
|
20
14
|
private marketService: MarketService;
|
|
21
15
|
|
|
22
16
|
constructor(db: LobeChatDatabase, userId: string) {
|
|
23
17
|
this.marketService = new MarketService({ userInfo: { userId } });
|
|
24
18
|
}
|
|
25
|
-
|
|
19
|
+
|
|
20
|
+
async execute(
|
|
21
|
+
payload: ChatToolPayload,
|
|
22
|
+
context: ToolExecutionContext,
|
|
23
|
+
): Promise<ToolExecutionResult> {
|
|
26
24
|
const { identifier, apiName, arguments: argsStr, source } = payload;
|
|
27
25
|
const args = safeParseJSON(argsStr) || {};
|
|
28
26
|
|
|
@@ -43,19 +41,15 @@ export class BuiltinToolsExecutor implements IToolExecutor {
|
|
|
43
41
|
});
|
|
44
42
|
}
|
|
45
43
|
|
|
46
|
-
//
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
if (!ServerRuntime) {
|
|
44
|
+
// Use server runtime registry (handles both pre-instantiated and per-request runtimes)
|
|
45
|
+
if (!hasServerRuntime(identifier)) {
|
|
50
46
|
throw new Error(`Builtin tool "${identifier}" is not implemented`);
|
|
51
47
|
}
|
|
52
48
|
|
|
53
|
-
const runtime =
|
|
54
|
-
searchService: new SearchService(),
|
|
55
|
-
});
|
|
49
|
+
const runtime = getServerRuntime(identifier, context);
|
|
56
50
|
|
|
57
51
|
if (!runtime[apiName]) {
|
|
58
|
-
throw new Error(`Builtin tool ${identifier}
|
|
52
|
+
throw new Error(`Builtin tool ${identifier}'s ${apiName} is not implemented`);
|
|
59
53
|
}
|
|
60
54
|
|
|
61
55
|
try {
|
|
@@ -64,7 +58,7 @@ export class BuiltinToolsExecutor implements IToolExecutor {
|
|
|
64
58
|
const error = e as Error;
|
|
65
59
|
console.error('Error executing builtin tool %s:%s: %O', identifier, apiName, error);
|
|
66
60
|
|
|
67
|
-
return { content: error.message, error
|
|
61
|
+
return { content: error.message, error, success: false };
|
|
68
62
|
}
|
|
69
63
|
}
|
|
70
64
|
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CloudSandboxExecutionRuntime,
|
|
3
|
+
CloudSandboxIdentifier,
|
|
4
|
+
} from '@lobechat/builtin-tool-cloud-sandbox';
|
|
5
|
+
|
|
6
|
+
import { MarketService } from '@/server/services/market';
|
|
7
|
+
import { ServerSandboxService } from '@/server/services/sandbox';
|
|
8
|
+
|
|
9
|
+
import { type ServerRuntimeRegistration } from './types';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* CloudSandbox Server Runtime
|
|
13
|
+
* Per-request runtime (needs topicId, userId)
|
|
14
|
+
*/
|
|
15
|
+
export const cloudSandboxRuntime: ServerRuntimeRegistration = {
|
|
16
|
+
factory: (context) => {
|
|
17
|
+
if (!context.userId || !context.topicId) {
|
|
18
|
+
throw new Error('userId and topicId are required for Cloud Sandbox execution');
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const marketService = new MarketService({ userInfo: { userId: context.userId } });
|
|
22
|
+
const sandboxService = new ServerSandboxService({
|
|
23
|
+
marketService,
|
|
24
|
+
topicId: context.topicId,
|
|
25
|
+
userId: context.userId,
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
return new CloudSandboxExecutionRuntime(sandboxService);
|
|
29
|
+
},
|
|
30
|
+
identifier: CloudSandboxIdentifier,
|
|
31
|
+
};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Server Runtime Registry
|
|
3
|
+
*
|
|
4
|
+
* Central registry for all builtin tool server runtimes.
|
|
5
|
+
* Uses factory functions to support both:
|
|
6
|
+
* - Pre-instantiated runtimes (e.g., WebBrowsing - no per-request context needed)
|
|
7
|
+
* - Per-request runtimes (e.g., CloudSandbox - needs topicId, userId)
|
|
8
|
+
*/
|
|
9
|
+
import { type ToolExecutionContext } from '../types';
|
|
10
|
+
import { cloudSandboxRuntime } from './cloudSandbox';
|
|
11
|
+
import { type ServerRuntimeFactory, type ServerRuntimeRegistration } from './types';
|
|
12
|
+
import { webBrowsingRuntime } from './webBrowsing';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Registry of server runtime factories by identifier
|
|
16
|
+
*/
|
|
17
|
+
const serverRuntimeFactories = new Map<string, ServerRuntimeFactory>();
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Register server runtimes
|
|
21
|
+
*/
|
|
22
|
+
const registerRuntimes = (runtimes: ServerRuntimeRegistration[]) => {
|
|
23
|
+
for (const runtime of runtimes) {
|
|
24
|
+
serverRuntimeFactories.set(runtime.identifier, runtime.factory);
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
// Register all server runtimes
|
|
29
|
+
registerRuntimes([webBrowsingRuntime, cloudSandboxRuntime]);
|
|
30
|
+
|
|
31
|
+
// ==================== Registry API ====================
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Get a server runtime by identifier
|
|
35
|
+
* @param identifier - The tool identifier
|
|
36
|
+
* @param context - Execution context (required for per-request runtimes)
|
|
37
|
+
*/
|
|
38
|
+
export const getServerRuntime = (identifier: string, context: ToolExecutionContext): any => {
|
|
39
|
+
const factory = serverRuntimeFactories.get(identifier);
|
|
40
|
+
return factory?.(context);
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Check if a server runtime exists for the given identifier
|
|
45
|
+
*/
|
|
46
|
+
export const hasServerRuntime = (identifier: string): boolean => {
|
|
47
|
+
return serverRuntimeFactories.has(identifier);
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Get all registered server runtime identifiers
|
|
52
|
+
*/
|
|
53
|
+
export const getServerRuntimeIdentifiers = (): string[] => {
|
|
54
|
+
return Array.from(serverRuntimeFactories.keys());
|
|
55
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type ToolExecutionContext } from '../types';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Factory function type for creating server runtimes
|
|
5
|
+
*/
|
|
6
|
+
export type ServerRuntimeFactory = (context: ToolExecutionContext) => any;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Server runtime registration object
|
|
10
|
+
*/
|
|
11
|
+
export interface ServerRuntimeRegistration {
|
|
12
|
+
factory: ServerRuntimeFactory;
|
|
13
|
+
identifier: string;
|
|
14
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { WebBrowsingManifest } from '@lobechat/builtin-tool-web-browsing';
|
|
2
|
+
import { WebBrowsingExecutionRuntime } from '@lobechat/builtin-tool-web-browsing/executionRuntime';
|
|
3
|
+
|
|
4
|
+
import { SearchService } from '@/server/services/search';
|
|
5
|
+
|
|
6
|
+
import { type ServerRuntimeRegistration } from './types';
|
|
7
|
+
|
|
8
|
+
// Pre-instantiated (no per-request context needed)
|
|
9
|
+
const runtime = new WebBrowsingExecutionRuntime({
|
|
10
|
+
searchService: new SearchService(),
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* WebBrowsing Server Runtime
|
|
15
|
+
* Pre-instantiated runtime (no per-request context needed)
|
|
16
|
+
*/
|
|
17
|
+
export const webBrowsingRuntime: ServerRuntimeRegistration = {
|
|
18
|
+
factory: () => runtime,
|
|
19
|
+
identifier: WebBrowsingManifest.identifier,
|
|
20
|
+
};
|
|
@@ -6,6 +6,8 @@ export interface ToolExecutionContext {
|
|
|
6
6
|
/** Server database for LobeHub Skills execution */
|
|
7
7
|
serverDB?: LobeChatDatabase;
|
|
8
8
|
toolManifestMap: Record<string, LobeToolManifest>;
|
|
9
|
+
/** Topic ID for sandbox session management */
|
|
10
|
+
topicId?: string;
|
|
9
11
|
userId?: string;
|
|
10
12
|
}
|
|
11
13
|
|
|
@@ -59,7 +59,7 @@ describe('Sitemap', () => {
|
|
|
59
59
|
);
|
|
60
60
|
expect(pageSitemap).toContainEqual(
|
|
61
61
|
expect.objectContaining({
|
|
62
|
-
url: getCanonicalUrl('/community/
|
|
62
|
+
url: getCanonicalUrl('/community/agent'),
|
|
63
63
|
changeFrequency: 'daily',
|
|
64
64
|
priority: 0.7,
|
|
65
65
|
}),
|
|
@@ -85,13 +85,13 @@ describe('Sitemap', () => {
|
|
|
85
85
|
expect(assistantsSitemap.length).toBe(LOCALE_COUNT);
|
|
86
86
|
expect(assistantsSitemap).toContainEqual(
|
|
87
87
|
expect.objectContaining({
|
|
88
|
-
url: getCanonicalUrl('/community/
|
|
88
|
+
url: getCanonicalUrl('/community/agent/test-assistant'),
|
|
89
89
|
lastModified: '2023-01-01T00:00:00.000Z',
|
|
90
90
|
}),
|
|
91
91
|
);
|
|
92
92
|
expect(assistantsSitemap).toContainEqual(
|
|
93
93
|
expect.objectContaining({
|
|
94
|
-
url: getCanonicalUrl('/community/
|
|
94
|
+
url: getCanonicalUrl('/community/agent/test-assistant?hl=zh-CN'),
|
|
95
95
|
lastModified: '2023-01-01T00:00:00.000Z',
|
|
96
96
|
}),
|
|
97
97
|
);
|
|
@@ -113,7 +113,7 @@ describe('Sitemap', () => {
|
|
|
113
113
|
expect(firstPageSitemap.length).toBe(100 * LOCALE_COUNT); // 100 items * LOCALE_COUNT locales
|
|
114
114
|
expect(firstPageSitemap).toContainEqual(
|
|
115
115
|
expect.objectContaining({
|
|
116
|
-
url: getCanonicalUrl('/community/
|
|
116
|
+
url: getCanonicalUrl('/community/agent/test-assistant-0'),
|
|
117
117
|
lastModified: '2023-01-01T00:00:00.000Z',
|
|
118
118
|
}),
|
|
119
119
|
);
|
|
@@ -123,7 +123,7 @@ describe('Sitemap', () => {
|
|
|
123
123
|
expect(secondPageSitemap.length).toBe(50 * LOCALE_COUNT); // 50 items * LOCALE_COUNT locales
|
|
124
124
|
expect(secondPageSitemap).toContainEqual(
|
|
125
125
|
expect.objectContaining({
|
|
126
|
-
url: getCanonicalUrl('/community/
|
|
126
|
+
url: getCanonicalUrl('/community/agent/test-assistant-100'),
|
|
127
127
|
lastModified: '2023-01-01T00:00:00.000Z',
|
|
128
128
|
}),
|
|
129
129
|
);
|
package/src/server/sitemap.ts
CHANGED
|
@@ -213,7 +213,7 @@ export class Sitemap {
|
|
|
213
213
|
const sitmap = pageAssistants
|
|
214
214
|
.filter((item) => item.identifier) // Filter out items with empty identifiers
|
|
215
215
|
.map((item) =>
|
|
216
|
-
this._genSitemap(urlJoin('/community/
|
|
216
|
+
this._genSitemap(urlJoin('/community/agent', item.identifier), {
|
|
217
217
|
lastModified: item?.lastModified || LAST_MODIFIED,
|
|
218
218
|
}),
|
|
219
219
|
);
|
|
@@ -224,7 +224,7 @@ export class Sitemap {
|
|
|
224
224
|
const sitmap = list
|
|
225
225
|
.filter((item) => item.identifier) // 过滤掉 identifier 为空的项目
|
|
226
226
|
.map((item) =>
|
|
227
|
-
this._genSitemap(urlJoin('/community/
|
|
227
|
+
this._genSitemap(urlJoin('/community/agent', item.identifier), {
|
|
228
228
|
lastModified: item?.lastModified || LAST_MODIFIED,
|
|
229
229
|
}),
|
|
230
230
|
);
|
|
@@ -311,7 +311,7 @@ export class Sitemap {
|
|
|
311
311
|
|
|
312
312
|
/* ↑ cloud slot ↑ */
|
|
313
313
|
...this._genSitemap('/community', { changeFrequency: 'daily', priority: 0.7 }),
|
|
314
|
-
...this._genSitemap('/community/
|
|
314
|
+
...this._genSitemap('/community/agent', { changeFrequency: 'daily', priority: 0.7 }),
|
|
315
315
|
...this._genSitemap('/community/mcp', { changeFrequency: 'daily', priority: 0.7 }),
|
|
316
316
|
...this._genSitemap('/community/plugin', { changeFrequency: 'daily', priority: 0.7 }),
|
|
317
317
|
...this._genSitemap('/community/model', { changeFrequency: 'daily', priority: 0.7 }),
|
|
@@ -6,9 +6,9 @@ import type {
|
|
|
6
6
|
ExportAndUploadFileResult,
|
|
7
7
|
} from '@/server/routers/tools/market';
|
|
8
8
|
|
|
9
|
-
class
|
|
9
|
+
class CloudSandboxService {
|
|
10
10
|
/**
|
|
11
|
-
* Call a cloud
|
|
11
|
+
* Call a cloud sandbox tool
|
|
12
12
|
* @param toolName - The name of the tool to call (e.g., 'runCommand', 'writeLocalFile')
|
|
13
13
|
* @param params - The parameters for the tool
|
|
14
14
|
* @param context - Session context containing userId and topicId for isolation
|
|
@@ -51,4 +51,4 @@ class CodeInterpreterService {
|
|
|
51
51
|
}
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
export const
|
|
54
|
+
export const cloudSandboxService = new CloudSandboxService();
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type DataSyncConfig, type MarketAuthorizationParams } from '@lobechat/electron-client-ipc';
|
|
2
|
+
|
|
2
3
|
import { ensureElectronIpc } from '@/utils/electron/ipc';
|
|
3
4
|
|
|
4
5
|
class RemoteServerService {
|
|
@@ -36,6 +37,13 @@ class RemoteServerService {
|
|
|
36
37
|
requestMarketAuthorization = async (params: MarketAuthorizationParams) => {
|
|
37
38
|
return ensureElectronIpc().auth.requestMarketAuthorization(params);
|
|
38
39
|
};
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Cancel authorization
|
|
43
|
+
*/
|
|
44
|
+
cancelAuthorization = async () => {
|
|
45
|
+
return ensureElectronIpc().auth.cancelAuthorization();
|
|
46
|
+
};
|
|
39
47
|
}
|
|
40
48
|
|
|
41
49
|
export const remoteServerService = new RemoteServerService();
|