@lobehub/lobehub 2.0.0-next.303 → 2.0.0-next.305
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/.github/workflows/manual-build-desktop.yml +11 -1
- package/CHANGELOG.md +50 -0
- package/apps/desktop/.i18nrc.js +3 -3
- package/apps/desktop/electron.vite.config.ts +0 -2
- package/apps/desktop/resources/locales/ar/dialog.json +5 -1
- package/apps/desktop/resources/locales/ar/menu.json +16 -0
- package/apps/desktop/resources/locales/bg-BG/dialog.json +5 -1
- package/apps/desktop/resources/locales/bg-BG/menu.json +16 -0
- package/apps/desktop/resources/locales/de-DE/dialog.json +5 -1
- package/apps/desktop/resources/locales/de-DE/menu.json +16 -0
- package/apps/desktop/resources/locales/en/common.json +26 -0
- package/apps/desktop/resources/locales/en/dialog.json +27 -0
- package/apps/desktop/resources/locales/en/menu.json +73 -0
- package/apps/desktop/resources/locales/es-ES/dialog.json +5 -1
- package/apps/desktop/resources/locales/es-ES/menu.json +16 -0
- package/apps/desktop/resources/locales/fa-IR/dialog.json +5 -1
- package/apps/desktop/resources/locales/fa-IR/menu.json +16 -0
- package/apps/desktop/resources/locales/fr-FR/dialog.json +5 -1
- package/apps/desktop/resources/locales/fr-FR/menu.json +16 -0
- package/apps/desktop/resources/locales/it-IT/dialog.json +5 -1
- package/apps/desktop/resources/locales/it-IT/menu.json +16 -0
- package/apps/desktop/resources/locales/ja-JP/dialog.json +5 -1
- package/apps/desktop/resources/locales/ja-JP/menu.json +16 -0
- package/apps/desktop/resources/locales/ko-KR/dialog.json +5 -1
- package/apps/desktop/resources/locales/ko-KR/menu.json +16 -0
- package/apps/desktop/resources/locales/nl-NL/dialog.json +5 -1
- package/apps/desktop/resources/locales/nl-NL/menu.json +16 -0
- package/apps/desktop/resources/locales/pl-PL/dialog.json +5 -1
- package/apps/desktop/resources/locales/pl-PL/menu.json +16 -0
- package/apps/desktop/resources/locales/pt-BR/dialog.json +5 -1
- package/apps/desktop/resources/locales/pt-BR/menu.json +16 -0
- package/apps/desktop/resources/locales/ru-RU/dialog.json +5 -1
- package/apps/desktop/resources/locales/ru-RU/menu.json +16 -0
- package/apps/desktop/resources/locales/tr-TR/dialog.json +5 -1
- package/apps/desktop/resources/locales/tr-TR/menu.json +16 -0
- package/apps/desktop/resources/locales/vi-VN/dialog.json +5 -1
- package/apps/desktop/resources/locales/vi-VN/menu.json +16 -0
- package/apps/desktop/resources/locales/zh-TW/dialog.json +5 -1
- package/apps/desktop/resources/locales/zh-TW/menu.json +16 -0
- package/apps/desktop/scripts/update-test/README.md +15 -0
- package/apps/desktop/src/common/routes.ts +8 -8
- package/apps/desktop/src/main/const/dir.ts +2 -2
- package/apps/desktop/src/main/const/env.ts +4 -4
- package/apps/desktop/src/main/const/store.ts +3 -3
- package/apps/desktop/src/main/controllers/AuthCtr.ts +1 -1
- package/apps/desktop/src/main/controllers/McpInstallCtr.ts +8 -8
- package/apps/desktop/src/main/controllers/NetworkProxyCtr.ts +9 -9
- package/apps/desktop/src/main/controllers/RemoteServerSyncCtr.ts +8 -8
- package/apps/desktop/src/main/core/App.ts +9 -9
- package/apps/desktop/src/main/core/infrastructure/BackendProxyProtocolManager.ts +7 -6
- package/apps/desktop/src/main/core/infrastructure/StaticFileServerManager.ts +2 -2
- package/apps/desktop/src/main/core/infrastructure/UpdaterManager.ts +38 -5
- package/apps/desktop/src/main/core/ui/ShortcutManager.ts +10 -10
- package/apps/desktop/src/main/core/ui/TrayManager.ts +12 -12
- package/apps/desktop/src/main/locales/resources.ts +4 -4
- package/apps/desktop/src/main/menus/impls/macOS.ts +1 -1
- package/apps/desktop/src/main/menus/types.ts +5 -5
- package/apps/desktop/src/main/modules/updater/configs.ts +10 -10
- package/apps/desktop/src/main/modules/updater/utils.ts +9 -9
- package/apps/desktop/src/main/services/fileSrv.ts +62 -62
- package/apps/desktop/src/main/shortcuts/config.ts +3 -3
- package/apps/desktop/src/main/types/protocol.ts +12 -12
- package/apps/desktop/src/main/utils/file-system.ts +2 -2
- package/apps/desktop/src/main/utils/logger.ts +4 -4
- package/apps/desktop/src/main/utils/protocol.ts +32 -32
- package/changelog/v1.json +14 -0
- package/locales/en-US/auth.json +5 -0
- package/locales/en-US/plugin.json +1 -0
- package/locales/zh-CN/auth.json +5 -0
- package/locales/zh-CN/discover.json +4 -4
- package/locales/zh-CN/plugin.json +1 -0
- package/package.json +6 -5
- package/packages/builtin-tool-agent-builder/src/ExecutionRuntime/index.ts +362 -30
- package/packages/builtin-tool-agent-builder/src/client/Intervention/InstallPlugin.tsx +28 -4
- package/packages/builtin-tool-group-management/src/client/Inspector/ExecuteAgentTask/index.tsx +78 -0
- package/packages/builtin-tool-group-management/src/client/Inspector/{ExecuteTasks → ExecuteAgentTasks}/index.tsx +1 -5
- package/packages/builtin-tool-group-management/src/client/Inspector/index.ts +4 -2
- package/packages/database/src/schemas/relations.ts +4 -4
- package/scripts/electronWorkflow/buildDesktopChannel.ts +135 -0
- package/src/app/[variants]/(main)/_layout/index.tsx +2 -0
- package/src/features/Conversation/ChatList/components/AutoScroll.tsx +3 -9
- package/src/features/Conversation/ChatList/components/VirtualizedList.tsx +2 -6
- package/src/features/DesktopNavigationBridge/index.tsx +0 -9
- package/src/features/Electron/AuthRequiredModal/index.tsx +151 -0
- package/src/locales/default/auth.ts +6 -0
- package/src/locales/default/plugin.ts +1 -0
- package/src/utils/errorResponse.ts +21 -1
|
@@ -344,7 +344,139 @@ export class AgentBuilderExecutionRuntime {
|
|
|
344
344
|
}
|
|
345
345
|
|
|
346
346
|
/**
|
|
347
|
-
* Open OAuth window and wait for authentication completion
|
|
347
|
+
* Open OAuth window and wait for LobehubSkill authentication completion
|
|
348
|
+
* Returns a Promise that resolves when OAuth completes or fails
|
|
349
|
+
*/
|
|
350
|
+
private openLobehubSkillOAuthWindowAndWait(
|
|
351
|
+
oauthUrl: string,
|
|
352
|
+
provider: string,
|
|
353
|
+
): Promise<{ cancelled: boolean; success: boolean }> {
|
|
354
|
+
return new Promise((resolve) => {
|
|
355
|
+
// Configuration
|
|
356
|
+
const WINDOW_CHECK_INTERVAL_MS = 500;
|
|
357
|
+
const POLL_INTERVAL_MS = 1000;
|
|
358
|
+
const POLL_TIMEOUT_MS = 300_000; // 5 minutes timeout
|
|
359
|
+
|
|
360
|
+
let pollInterval: ReturnType<typeof setInterval> | null = null;
|
|
361
|
+
let pollTimeout: ReturnType<typeof setTimeout> | null = null;
|
|
362
|
+
let windowCheckInterval: ReturnType<typeof setInterval> | null = null;
|
|
363
|
+
let messageHandler: ((event: MessageEvent) => void) | null = null;
|
|
364
|
+
let resolved = false;
|
|
365
|
+
|
|
366
|
+
const cleanup = () => {
|
|
367
|
+
if (windowCheckInterval) {
|
|
368
|
+
clearInterval(windowCheckInterval);
|
|
369
|
+
windowCheckInterval = null;
|
|
370
|
+
}
|
|
371
|
+
if (pollInterval) {
|
|
372
|
+
clearInterval(pollInterval);
|
|
373
|
+
pollInterval = null;
|
|
374
|
+
}
|
|
375
|
+
if (pollTimeout) {
|
|
376
|
+
clearTimeout(pollTimeout);
|
|
377
|
+
pollTimeout = null;
|
|
378
|
+
}
|
|
379
|
+
if (messageHandler) {
|
|
380
|
+
window.removeEventListener('message', messageHandler);
|
|
381
|
+
messageHandler = null;
|
|
382
|
+
}
|
|
383
|
+
};
|
|
384
|
+
|
|
385
|
+
const resolveOnce = (result: { cancelled: boolean; success: boolean }) => {
|
|
386
|
+
if (resolved) return;
|
|
387
|
+
resolved = true;
|
|
388
|
+
cleanup();
|
|
389
|
+
resolve(result);
|
|
390
|
+
};
|
|
391
|
+
|
|
392
|
+
// Listen for OAuth success message from popup window
|
|
393
|
+
messageHandler = async (event: MessageEvent) => {
|
|
394
|
+
// Verify origin for security
|
|
395
|
+
if (event.origin !== window.location.origin) return;
|
|
396
|
+
|
|
397
|
+
if (
|
|
398
|
+
event.data?.type === 'LOBEHUB_SKILL_AUTH_SUCCESS' &&
|
|
399
|
+
event.data?.provider === provider
|
|
400
|
+
) {
|
|
401
|
+
console.log('[LobehubSkill] OAuth success message received for provider:', provider);
|
|
402
|
+
|
|
403
|
+
// Refresh status to get the connected state
|
|
404
|
+
const server = await getToolStoreState().checkLobehubSkillStatus(provider);
|
|
405
|
+
const isConnected = server?.status === LobehubSkillStatus.CONNECTED;
|
|
406
|
+
|
|
407
|
+
resolveOnce({ cancelled: false, success: isConnected });
|
|
408
|
+
}
|
|
409
|
+
};
|
|
410
|
+
|
|
411
|
+
window.addEventListener('message', messageHandler);
|
|
412
|
+
|
|
413
|
+
// eslint-disable-next-line unicorn/consistent-function-scoping
|
|
414
|
+
const checkAuthStatus = async (): Promise<boolean> => {
|
|
415
|
+
try {
|
|
416
|
+
// Check LobehubSkill status
|
|
417
|
+
const server = await getToolStoreState().checkLobehubSkillStatus(provider);
|
|
418
|
+
return server?.status === LobehubSkillStatus.CONNECTED;
|
|
419
|
+
} catch (error) {
|
|
420
|
+
console.error('[LobehubSkill] Failed to check auth status:', error);
|
|
421
|
+
return false;
|
|
422
|
+
}
|
|
423
|
+
};
|
|
424
|
+
|
|
425
|
+
const startFallbackPolling = () => {
|
|
426
|
+
if (pollInterval) return;
|
|
427
|
+
|
|
428
|
+
pollInterval = setInterval(async () => {
|
|
429
|
+
const isConnected = await checkAuthStatus();
|
|
430
|
+
if (isConnected) {
|
|
431
|
+
resolveOnce({ cancelled: false, success: true });
|
|
432
|
+
}
|
|
433
|
+
}, POLL_INTERVAL_MS);
|
|
434
|
+
|
|
435
|
+
// Timeout after 5 minutes
|
|
436
|
+
pollTimeout = setTimeout(() => {
|
|
437
|
+
resolveOnce({ cancelled: true, success: false });
|
|
438
|
+
}, POLL_TIMEOUT_MS);
|
|
439
|
+
};
|
|
440
|
+
|
|
441
|
+
// Open OAuth window
|
|
442
|
+
const oauthWindow = window.open(oauthUrl, '_blank', 'width=600,height=700');
|
|
443
|
+
|
|
444
|
+
if (oauthWindow) {
|
|
445
|
+
// Monitor window close
|
|
446
|
+
windowCheckInterval = setInterval(async () => {
|
|
447
|
+
try {
|
|
448
|
+
if (oauthWindow.closed) {
|
|
449
|
+
if (windowCheckInterval) {
|
|
450
|
+
clearInterval(windowCheckInterval);
|
|
451
|
+
windowCheckInterval = null;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
// Window closed, check auth status
|
|
455
|
+
const isConnected = await checkAuthStatus();
|
|
456
|
+
resolveOnce({ cancelled: !isConnected, success: isConnected });
|
|
457
|
+
}
|
|
458
|
+
} catch {
|
|
459
|
+
// COOP blocked window.closed access, fall back to polling
|
|
460
|
+
console.log(
|
|
461
|
+
'[LobehubSkill] COOP blocked window.closed access, falling back to polling',
|
|
462
|
+
);
|
|
463
|
+
if (windowCheckInterval) {
|
|
464
|
+
clearInterval(windowCheckInterval);
|
|
465
|
+
windowCheckInterval = null;
|
|
466
|
+
}
|
|
467
|
+
startFallbackPolling();
|
|
468
|
+
}
|
|
469
|
+
}, WINDOW_CHECK_INTERVAL_MS);
|
|
470
|
+
} else {
|
|
471
|
+
// Window was blocked, use polling
|
|
472
|
+
console.log('[LobehubSkill] OAuth window was blocked, falling back to polling');
|
|
473
|
+
startFallbackPolling();
|
|
474
|
+
}
|
|
475
|
+
});
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
/**
|
|
479
|
+
* Open OAuth window and wait for Klavis authentication completion
|
|
348
480
|
* Returns a Promise that resolves when OAuth completes or fails
|
|
349
481
|
*/
|
|
350
482
|
private openOAuthWindowAndWait(
|
|
@@ -777,34 +909,187 @@ export class AgentBuilderExecutionRuntime {
|
|
|
777
909
|
success: true,
|
|
778
910
|
};
|
|
779
911
|
} else {
|
|
780
|
-
// Server exists but not connected - need to reconnect
|
|
912
|
+
// Server exists but not connected - need to reconnect via OAuth
|
|
913
|
+
try {
|
|
914
|
+
// Get OAuth authorization URL with correct redirectUri
|
|
915
|
+
const redirectUri =
|
|
916
|
+
typeof window !== 'undefined'
|
|
917
|
+
? `${window.location.origin}/oauth/callback/success?provider=${encodeURIComponent(identifier)}`
|
|
918
|
+
: undefined;
|
|
919
|
+
const authInfo = await getToolStoreState().getLobehubSkillAuthorizeUrl(
|
|
920
|
+
identifier,
|
|
921
|
+
{
|
|
922
|
+
redirectUri,
|
|
923
|
+
},
|
|
924
|
+
);
|
|
925
|
+
|
|
926
|
+
if (!authInfo.authorizeUrl) {
|
|
927
|
+
return {
|
|
928
|
+
content: `LobehubSkill provider "${lobehubSkillProviderInfo.label}" requires OAuth authorization but no authorization URL is available.`,
|
|
929
|
+
state: {
|
|
930
|
+
installed: false,
|
|
931
|
+
isLobehubSkill: true,
|
|
932
|
+
pluginId: identifier,
|
|
933
|
+
pluginName: lobehubSkillProviderInfo.label,
|
|
934
|
+
serverStatus: lobehubSkillServer.status,
|
|
935
|
+
success: false,
|
|
936
|
+
} as InstallPluginState,
|
|
937
|
+
success: false,
|
|
938
|
+
};
|
|
939
|
+
}
|
|
940
|
+
|
|
941
|
+
// Open OAuth window and wait for authorization
|
|
942
|
+
const authResult = await this.openLobehubSkillOAuthWindowAndWait(
|
|
943
|
+
authInfo.authorizeUrl,
|
|
944
|
+
identifier,
|
|
945
|
+
);
|
|
946
|
+
|
|
947
|
+
if (authResult.success) {
|
|
948
|
+
// OAuth successful, enable the plugin
|
|
949
|
+
const agentState = getAgentStoreState();
|
|
950
|
+
const currentPlugins =
|
|
951
|
+
agentSelectors.getAgentConfigById(agentId)(agentState).plugins || [];
|
|
952
|
+
|
|
953
|
+
if (!currentPlugins.includes(identifier)) {
|
|
954
|
+
await getAgentStoreState().optimisticUpdateAgentConfig(agentId, {
|
|
955
|
+
plugins: [...currentPlugins, identifier],
|
|
956
|
+
});
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
return {
|
|
960
|
+
content: `Successfully reconnected and enabled LobehubSkill provider: ${lobehubSkillProviderInfo.label}`,
|
|
961
|
+
state: {
|
|
962
|
+
installed: true,
|
|
963
|
+
isLobehubSkill: true,
|
|
964
|
+
pluginId: identifier,
|
|
965
|
+
pluginName: lobehubSkillProviderInfo.label,
|
|
966
|
+
serverStatus: 'connected',
|
|
967
|
+
success: true,
|
|
968
|
+
} as InstallPluginState,
|
|
969
|
+
success: true,
|
|
970
|
+
};
|
|
971
|
+
} else {
|
|
972
|
+
// OAuth cancelled or failed
|
|
973
|
+
return {
|
|
974
|
+
content: `OAuth authorization was cancelled or failed for LobehubSkill provider: ${lobehubSkillProviderInfo.label}. Please try again.`,
|
|
975
|
+
state: {
|
|
976
|
+
installed: false,
|
|
977
|
+
isLobehubSkill: true,
|
|
978
|
+
pluginId: identifier,
|
|
979
|
+
pluginName: lobehubSkillProviderInfo.label,
|
|
980
|
+
serverStatus: lobehubSkillServer.status,
|
|
981
|
+
success: false,
|
|
982
|
+
} as InstallPluginState,
|
|
983
|
+
success: false,
|
|
984
|
+
};
|
|
985
|
+
}
|
|
986
|
+
} catch (authError) {
|
|
987
|
+
const err = authError as Error;
|
|
988
|
+
return {
|
|
989
|
+
content: `Failed to reconnect LobehubSkill provider "${lobehubSkillProviderInfo.label}": ${err.message}`,
|
|
990
|
+
error: authError,
|
|
991
|
+
state: {
|
|
992
|
+
error: err.message,
|
|
993
|
+
installed: false,
|
|
994
|
+
isLobehubSkill: true,
|
|
995
|
+
pluginId: identifier,
|
|
996
|
+
pluginName: lobehubSkillProviderInfo.label,
|
|
997
|
+
serverStatus: lobehubSkillServer.status,
|
|
998
|
+
success: false,
|
|
999
|
+
} as InstallPluginState,
|
|
1000
|
+
success: false,
|
|
1001
|
+
};
|
|
1002
|
+
}
|
|
1003
|
+
}
|
|
1004
|
+
} else {
|
|
1005
|
+
// Server doesn't exist - need to initiate OAuth authorization
|
|
1006
|
+
try {
|
|
1007
|
+
// Get OAuth authorization URL with correct redirectUri
|
|
1008
|
+
const redirectUri =
|
|
1009
|
+
typeof window !== 'undefined'
|
|
1010
|
+
? `${window.location.origin}/oauth/callback/success?provider=${encodeURIComponent(identifier)}`
|
|
1011
|
+
: undefined;
|
|
1012
|
+
const authInfo = await getToolStoreState().getLobehubSkillAuthorizeUrl(identifier, {
|
|
1013
|
+
redirectUri,
|
|
1014
|
+
});
|
|
1015
|
+
|
|
1016
|
+
if (!authInfo.authorizeUrl) {
|
|
1017
|
+
return {
|
|
1018
|
+
content: `LobehubSkill provider "${lobehubSkillProviderInfo.label}" requires OAuth authorization but no authorization URL is available.`,
|
|
1019
|
+
state: {
|
|
1020
|
+
installed: false,
|
|
1021
|
+
isLobehubSkill: true,
|
|
1022
|
+
pluginId: identifier,
|
|
1023
|
+
pluginName: lobehubSkillProviderInfo.label,
|
|
1024
|
+
serverStatus: 'not_connected',
|
|
1025
|
+
success: false,
|
|
1026
|
+
} as InstallPluginState,
|
|
1027
|
+
success: false,
|
|
1028
|
+
};
|
|
1029
|
+
}
|
|
1030
|
+
|
|
1031
|
+
// Open OAuth window and wait for authorization
|
|
1032
|
+
const authResult = await this.openLobehubSkillOAuthWindowAndWait(
|
|
1033
|
+
authInfo.authorizeUrl,
|
|
1034
|
+
identifier,
|
|
1035
|
+
);
|
|
1036
|
+
|
|
1037
|
+
if (authResult.success) {
|
|
1038
|
+
// OAuth successful, enable the plugin
|
|
1039
|
+
const agentState = getAgentStoreState();
|
|
1040
|
+
const currentPlugins =
|
|
1041
|
+
agentSelectors.getAgentConfigById(agentId)(agentState).plugins || [];
|
|
1042
|
+
|
|
1043
|
+
if (!currentPlugins.includes(identifier)) {
|
|
1044
|
+
await getAgentStoreState().optimisticUpdateAgentConfig(agentId, {
|
|
1045
|
+
plugins: [...currentPlugins, identifier],
|
|
1046
|
+
});
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1049
|
+
return {
|
|
1050
|
+
content: `Successfully connected and enabled LobehubSkill provider: ${lobehubSkillProviderInfo.label}`,
|
|
1051
|
+
state: {
|
|
1052
|
+
installed: true,
|
|
1053
|
+
isLobehubSkill: true,
|
|
1054
|
+
pluginId: identifier,
|
|
1055
|
+
pluginName: lobehubSkillProviderInfo.label,
|
|
1056
|
+
serverStatus: 'connected',
|
|
1057
|
+
success: true,
|
|
1058
|
+
} as InstallPluginState,
|
|
1059
|
+
success: true,
|
|
1060
|
+
};
|
|
1061
|
+
} else {
|
|
1062
|
+
// OAuth cancelled or failed
|
|
1063
|
+
return {
|
|
1064
|
+
content: `OAuth authorization was cancelled or failed for LobehubSkill provider: ${lobehubSkillProviderInfo.label}. Please try again.`,
|
|
1065
|
+
state: {
|
|
1066
|
+
installed: false,
|
|
1067
|
+
isLobehubSkill: true,
|
|
1068
|
+
pluginId: identifier,
|
|
1069
|
+
pluginName: lobehubSkillProviderInfo.label,
|
|
1070
|
+
serverStatus: 'not_connected',
|
|
1071
|
+
success: false,
|
|
1072
|
+
} as InstallPluginState,
|
|
1073
|
+
success: false,
|
|
1074
|
+
};
|
|
1075
|
+
}
|
|
1076
|
+
} catch (authError) {
|
|
1077
|
+
const err = authError as Error;
|
|
781
1078
|
return {
|
|
782
|
-
content: `LobehubSkill provider "${lobehubSkillProviderInfo.label}"
|
|
1079
|
+
content: `Failed to authorize LobehubSkill provider "${lobehubSkillProviderInfo.label}": ${err.message}`,
|
|
1080
|
+
error: authError,
|
|
783
1081
|
state: {
|
|
1082
|
+
error: err.message,
|
|
784
1083
|
installed: false,
|
|
785
1084
|
isLobehubSkill: true,
|
|
786
1085
|
pluginId: identifier,
|
|
787
1086
|
pluginName: lobehubSkillProviderInfo.label,
|
|
788
|
-
serverStatus:
|
|
1087
|
+
serverStatus: 'not_connected',
|
|
789
1088
|
success: false,
|
|
790
1089
|
} as InstallPluginState,
|
|
791
1090
|
success: false,
|
|
792
1091
|
};
|
|
793
1092
|
}
|
|
794
|
-
} else {
|
|
795
|
-
// Server doesn't exist - need to connect first
|
|
796
|
-
return {
|
|
797
|
-
content: `LobehubSkill provider "${lobehubSkillProviderInfo.label}" is not connected. Please connect it from the tools settings first.`,
|
|
798
|
-
state: {
|
|
799
|
-
installed: false,
|
|
800
|
-
isLobehubSkill: true,
|
|
801
|
-
pluginId: identifier,
|
|
802
|
-
pluginName: lobehubSkillProviderInfo.label,
|
|
803
|
-
serverStatus: 'not_connected',
|
|
804
|
-
success: false,
|
|
805
|
-
} as InstallPluginState,
|
|
806
|
-
success: false,
|
|
807
|
-
};
|
|
808
1093
|
}
|
|
809
1094
|
}
|
|
810
1095
|
}
|
|
@@ -878,18 +1163,65 @@ export class AgentBuilderExecutionRuntime {
|
|
|
878
1163
|
};
|
|
879
1164
|
}
|
|
880
1165
|
|
|
881
|
-
// Plugin needs to be installed -
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
1166
|
+
// Plugin needs to be installed - trigger actual installation from market
|
|
1167
|
+
try {
|
|
1168
|
+
// Call the store's installMCPPlugin to trigger the real installation flow
|
|
1169
|
+
const installSuccess = await getToolStoreState().installMCPPlugin(identifier);
|
|
1170
|
+
|
|
1171
|
+
if (installSuccess) {
|
|
1172
|
+
// Installation successful, enable it for the agent
|
|
1173
|
+
const agentState = getAgentStoreState();
|
|
1174
|
+
const currentPlugins =
|
|
1175
|
+
agentSelectors.getAgentConfigById(agentId)(agentState).plugins || [];
|
|
1176
|
+
|
|
1177
|
+
if (!currentPlugins.includes(identifier)) {
|
|
1178
|
+
await getAgentStoreState().optimisticUpdateAgentConfig(agentId, {
|
|
1179
|
+
plugins: [...currentPlugins, identifier],
|
|
1180
|
+
});
|
|
1181
|
+
}
|
|
1182
|
+
|
|
1183
|
+
// Refresh tool state to get the installed plugin info
|
|
1184
|
+
await getToolStoreState().refreshPlugins();
|
|
1185
|
+
const freshToolState = getToolStoreState();
|
|
1186
|
+
const installedPlugin =
|
|
1187
|
+
pluginSelectors.getInstalledPluginById(identifier)(freshToolState);
|
|
1188
|
+
|
|
1189
|
+
return {
|
|
1190
|
+
content: `Successfully installed and enabled MCP plugin "${installedPlugin?.manifest?.meta?.title || identifier}".`,
|
|
1191
|
+
state: {
|
|
1192
|
+
installed: true,
|
|
1193
|
+
pluginId: identifier,
|
|
1194
|
+
pluginName: installedPlugin?.manifest?.meta?.title || identifier,
|
|
1195
|
+
success: true,
|
|
1196
|
+
} as InstallPluginState,
|
|
1197
|
+
success: true,
|
|
1198
|
+
};
|
|
1199
|
+
} else {
|
|
1200
|
+
// Installation failed or was cancelled
|
|
1201
|
+
return {
|
|
1202
|
+
content: `Failed to install MCP plugin "${identifier}". Installation was cancelled or configuration is needed.`,
|
|
1203
|
+
state: {
|
|
1204
|
+
installed: false,
|
|
1205
|
+
pluginId: identifier,
|
|
1206
|
+
success: false,
|
|
1207
|
+
} as InstallPluginState,
|
|
1208
|
+
success: false,
|
|
1209
|
+
};
|
|
1210
|
+
}
|
|
1211
|
+
} catch (installError) {
|
|
1212
|
+
const err = installError as Error;
|
|
1213
|
+
return {
|
|
1214
|
+
content: `Failed to install MCP plugin "${identifier}": ${err.message}`,
|
|
1215
|
+
error: installError,
|
|
1216
|
+
state: {
|
|
1217
|
+
error: err.message,
|
|
1218
|
+
installed: false,
|
|
1219
|
+
pluginId: identifier,
|
|
1220
|
+
success: false,
|
|
1221
|
+
} as InstallPluginState,
|
|
1222
|
+
success: false,
|
|
1223
|
+
};
|
|
1224
|
+
}
|
|
893
1225
|
} catch (error) {
|
|
894
1226
|
const err = error as Error;
|
|
895
1227
|
return {
|
|
@@ -12,6 +12,7 @@ import { useToolStore } from '@/store/tool';
|
|
|
12
12
|
import {
|
|
13
13
|
klavisStoreSelectors,
|
|
14
14
|
lobehubSkillStoreSelectors,
|
|
15
|
+
mcpStoreSelectors,
|
|
15
16
|
pluginSelectors,
|
|
16
17
|
} from '@/store/tool/selectors';
|
|
17
18
|
import { KlavisServerStatus } from '@/store/tool/slices/klavisStore/types';
|
|
@@ -44,6 +45,14 @@ const InstallPluginIntervention = memo<BuiltinInterventionProps<InstallPluginPar
|
|
|
44
45
|
lobehubSkillStoreSelectors.getServers(s).find((srv) => srv.identifier === identifier),
|
|
45
46
|
);
|
|
46
47
|
|
|
48
|
+
// Get Market MCP plugin info
|
|
49
|
+
const marketPlugin = useToolStore((s) => mcpStoreSelectors.getPluginById(identifier)(s));
|
|
50
|
+
|
|
51
|
+
// Get Builtin tool info
|
|
52
|
+
const builtinTool = useToolStore((s) =>
|
|
53
|
+
s.builtinTools.find((tool) => tool.identifier === identifier),
|
|
54
|
+
);
|
|
55
|
+
|
|
47
56
|
// Check if it's a Klavis tool
|
|
48
57
|
const klavisTypeInfo = KLAVIS_SERVER_TYPES.find((t) => t.identifier === identifier);
|
|
49
58
|
const isKlavis = source === 'official' && !!klavisTypeInfo;
|
|
@@ -166,19 +175,34 @@ const InstallPluginIntervention = memo<BuiltinInterventionProps<InstallPluginPar
|
|
|
166
175
|
);
|
|
167
176
|
}
|
|
168
177
|
|
|
169
|
-
// Render MCP marketplace plugin
|
|
178
|
+
// Render MCP marketplace plugin or Builtin tool
|
|
170
179
|
// Note: The actual installation happens in ExecutionRuntime after user approves
|
|
180
|
+
const pluginName = marketPlugin?.name || builtinTool?.manifest?.meta?.title || identifier;
|
|
181
|
+
const pluginIcon = marketPlugin?.icon || builtinTool?.manifest?.meta?.avatar;
|
|
182
|
+
const pluginType = source === 'market' ? 'MCP Plugin' : 'Builtin Tool';
|
|
183
|
+
|
|
171
184
|
return (
|
|
172
185
|
<Flexbox
|
|
173
186
|
gap={12}
|
|
174
187
|
style={{ background: 'var(--lobe-fill-tertiary)', borderRadius: 8, padding: 16 }}
|
|
175
188
|
>
|
|
176
189
|
<Flexbox align="center" gap={12} horizontal>
|
|
177
|
-
|
|
190
|
+
{pluginIcon && typeof pluginIcon === 'string' && pluginIcon.startsWith('http') ? (
|
|
191
|
+
<Image
|
|
192
|
+
alt={pluginName}
|
|
193
|
+
height={40}
|
|
194
|
+
src={pluginIcon}
|
|
195
|
+
style={{ borderRadius: 8 }}
|
|
196
|
+
unoptimized
|
|
197
|
+
width={40}
|
|
198
|
+
/>
|
|
199
|
+
) : (
|
|
200
|
+
<Avatar avatar={pluginIcon || '🔧'} size={40} style={{ borderRadius: 8 }} />
|
|
201
|
+
)}
|
|
178
202
|
<Flexbox flex={1} gap={4}>
|
|
179
203
|
<Flexbox align="center" gap={8} horizontal>
|
|
180
|
-
<span style={{ fontWeight: 600 }}>{
|
|
181
|
-
<span style={{ color: 'var(--lobe-text-tertiary)', fontSize: 12 }}>
|
|
204
|
+
<span style={{ fontWeight: 600 }}>{pluginName}</span>
|
|
205
|
+
<span style={{ color: 'var(--lobe-text-tertiary)', fontSize: 12 }}>{pluginType}</span>
|
|
182
206
|
</Flexbox>
|
|
183
207
|
<span style={{ color: 'var(--lobe-text-secondary)', fontSize: 12 }}>
|
|
184
208
|
{t('agentBuilder.installPlugin.clickApproveToInstall')}
|
package/packages/builtin-tool-group-management/src/client/Inspector/ExecuteAgentTask/index.tsx
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { DEFAULT_AVATAR } from '@lobechat/const';
|
|
4
|
+
import type { BuiltinInspectorProps } from '@lobechat/types';
|
|
5
|
+
import { Avatar, Flexbox } from '@lobehub/ui';
|
|
6
|
+
import { createStaticStyles, cx, useTheme } from 'antd-style';
|
|
7
|
+
import { memo } from 'react';
|
|
8
|
+
import { useTranslation } from 'react-i18next';
|
|
9
|
+
|
|
10
|
+
import { useAgentGroupStore } from '@/store/agentGroup';
|
|
11
|
+
import { agentGroupSelectors } from '@/store/agentGroup/selectors';
|
|
12
|
+
import { highlightTextStyles, shinyTextStyles } from '@/styles';
|
|
13
|
+
|
|
14
|
+
import type { ExecuteTaskParams } from '../../../types';
|
|
15
|
+
|
|
16
|
+
const styles = createStaticStyles(({ css, cssVar }) => ({
|
|
17
|
+
root: css`
|
|
18
|
+
overflow: hidden;
|
|
19
|
+
display: flex;
|
|
20
|
+
gap: 8px;
|
|
21
|
+
align-items: center;
|
|
22
|
+
`,
|
|
23
|
+
title: css`
|
|
24
|
+
flex-shrink: 0;
|
|
25
|
+
color: ${cssVar.colorTextSecondary};
|
|
26
|
+
white-space: nowrap;
|
|
27
|
+
`,
|
|
28
|
+
}));
|
|
29
|
+
|
|
30
|
+
export const ExecuteAgentTaskInspector = memo<BuiltinInspectorProps<ExecuteTaskParams>>(
|
|
31
|
+
({ args, partialArgs, isArgumentsStreaming }) => {
|
|
32
|
+
const { t } = useTranslation('plugin');
|
|
33
|
+
|
|
34
|
+
const agentId = args?.agentId || partialArgs?.agentId;
|
|
35
|
+
|
|
36
|
+
// Get active group ID and agent from store
|
|
37
|
+
const activeGroupId = useAgentGroupStore(agentGroupSelectors.activeGroupId);
|
|
38
|
+
const agent = useAgentGroupStore((s) =>
|
|
39
|
+
activeGroupId && agentId
|
|
40
|
+
? agentGroupSelectors.getAgentByIdFromGroup(activeGroupId, agentId)(s)
|
|
41
|
+
: undefined,
|
|
42
|
+
);
|
|
43
|
+
const theme = useTheme();
|
|
44
|
+
|
|
45
|
+
if (isArgumentsStreaming && !agent) {
|
|
46
|
+
return (
|
|
47
|
+
<div className={cx(styles.root, shinyTextStyles.shinyText)}>
|
|
48
|
+
<span>{t('builtins.lobe-group-management.apiName.executeAgentTask')}</span>
|
|
49
|
+
</div>
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const agentName = agent?.title || agentId;
|
|
54
|
+
|
|
55
|
+
return (
|
|
56
|
+
<Flexbox
|
|
57
|
+
align={'center'}
|
|
58
|
+
className={cx(styles.root, isArgumentsStreaming && shinyTextStyles.shinyText)}
|
|
59
|
+
gap={8}
|
|
60
|
+
horizontal
|
|
61
|
+
>
|
|
62
|
+
<span className={styles.title}>
|
|
63
|
+
{t('builtins.lobe-group-management.inspector.executeAgentTask.title')}
|
|
64
|
+
</span>
|
|
65
|
+
{agent && (
|
|
66
|
+
<Avatar
|
|
67
|
+
avatar={agent.avatar || DEFAULT_AVATAR}
|
|
68
|
+
background={agent.backgroundColor || theme.colorBgContainer}
|
|
69
|
+
shape={'square'}
|
|
70
|
+
size={24}
|
|
71
|
+
title={agent.title || undefined}
|
|
72
|
+
/>
|
|
73
|
+
)}
|
|
74
|
+
{agentName && <span className={highlightTextStyles.primary}>{agentName}</span>}
|
|
75
|
+
</Flexbox>
|
|
76
|
+
);
|
|
77
|
+
},
|
|
78
|
+
);
|
|
@@ -27,7 +27,7 @@ const styles = createStaticStyles(({ css, cssVar }) => ({
|
|
|
27
27
|
`,
|
|
28
28
|
}));
|
|
29
29
|
|
|
30
|
-
export const
|
|
30
|
+
export const ExecuteAgentTasksInspector = memo<BuiltinInspectorProps<ExecuteTasksParams>>(
|
|
31
31
|
({ args, partialArgs, isArgumentsStreaming }) => {
|
|
32
32
|
const { t } = useTranslation('plugin');
|
|
33
33
|
|
|
@@ -84,7 +84,3 @@ export const ExecuteTasksInspector = memo<BuiltinInspectorProps<ExecuteTasksPara
|
|
|
84
84
|
);
|
|
85
85
|
},
|
|
86
86
|
);
|
|
87
|
-
|
|
88
|
-
ExecuteTasksInspector.displayName = 'ExecuteTasksInspector';
|
|
89
|
-
|
|
90
|
-
export default ExecuteTasksInspector;
|
|
@@ -2,7 +2,8 @@ import { type BuiltinInspector } from '@lobechat/types';
|
|
|
2
2
|
|
|
3
3
|
import { GroupManagementApiName } from '../../types';
|
|
4
4
|
import { BroadcastInspector } from './Broadcast';
|
|
5
|
-
import {
|
|
5
|
+
import { ExecuteAgentTaskInspector } from './ExecuteAgentTask';
|
|
6
|
+
import { ExecuteAgentTasksInspector } from './ExecuteAgentTasks';
|
|
6
7
|
import { SpeakInspector } from './Speak';
|
|
7
8
|
|
|
8
9
|
/**
|
|
@@ -13,6 +14,7 @@ import { SpeakInspector } from './Speak';
|
|
|
13
14
|
*/
|
|
14
15
|
export const GroupManagementInspectors: Record<string, BuiltinInspector> = {
|
|
15
16
|
[GroupManagementApiName.broadcast]: BroadcastInspector as BuiltinInspector,
|
|
16
|
-
[GroupManagementApiName.
|
|
17
|
+
[GroupManagementApiName.executeAgentTask]: ExecuteAgentTaskInspector as BuiltinInspector,
|
|
18
|
+
[GroupManagementApiName.executeAgentTasks]: ExecuteAgentTasksInspector as BuiltinInspector,
|
|
17
19
|
[GroupManagementApiName.speak]: SpeakInspector as BuiltinInspector,
|
|
18
20
|
};
|
|
@@ -220,7 +220,7 @@ export const filesRelations = relations(files, ({ many, one }) => ({
|
|
|
220
220
|
}),
|
|
221
221
|
}));
|
|
222
222
|
|
|
223
|
-
// Document
|
|
223
|
+
// Document-related relation definitions
|
|
224
224
|
export const documentsRelations = relations(documents, ({ one, many }) => ({
|
|
225
225
|
file: one(files, {
|
|
226
226
|
fields: [documents.fileId],
|
|
@@ -249,7 +249,7 @@ export const documentChunksRelations = relations(documentChunks, ({ one }) => ({
|
|
|
249
249
|
}),
|
|
250
250
|
}));
|
|
251
251
|
|
|
252
|
-
// Generation
|
|
252
|
+
// Generation-related relation definitions
|
|
253
253
|
export const generationTopicsRelations = relations(generationTopics, ({ one, many }) => ({
|
|
254
254
|
user: one(users, {
|
|
255
255
|
fields: [generationTopics.userId],
|
|
@@ -289,7 +289,7 @@ export const generationsRelations = relations(generations, ({ one }) => ({
|
|
|
289
289
|
}),
|
|
290
290
|
}));
|
|
291
291
|
|
|
292
|
-
// Chat Groups
|
|
292
|
+
// Chat Groups-related relation definitions
|
|
293
293
|
export const chatGroupsRelations = relations(chatGroups, ({ many, one }) => ({
|
|
294
294
|
user: one(users, {
|
|
295
295
|
fields: [chatGroups.userId],
|
|
@@ -313,7 +313,7 @@ export const chatGroupsAgentsRelations = relations(chatGroupsAgents, ({ one }) =
|
|
|
313
313
|
}),
|
|
314
314
|
}));
|
|
315
315
|
|
|
316
|
-
// Message Groups
|
|
316
|
+
// Message Groups-related relation definitions
|
|
317
317
|
export const messageGroupsRelations = relations(messageGroups, ({ many, one }) => ({
|
|
318
318
|
user: one(users, {
|
|
319
319
|
fields: [messageGroups.userId],
|