@lobehub/lobehub 2.0.0-next.232 → 2.0.0-next.234
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/bundle-analyzer.yml +1 -1
- package/.github/workflows/e2e.yml +62 -53
- package/.github/workflows/manual-build-desktop.yml +5 -5
- package/.github/workflows/pr-build-desktop.yml +4 -4
- package/.github/workflows/pr-build-docker.yml +2 -2
- package/.github/workflows/release-desktop-beta.yml +4 -4
- package/.github/workflows/release-docker.yml +2 -2
- package/.github/workflows/test.yml +44 -7
- package/CHANGELOG.md +59 -0
- package/CLAUDE.md +1 -1
- package/changelog/v1.json +14 -0
- package/docs/development/basic/feature-development.mdx +4 -5
- package/docs/development/basic/feature-development.zh-CN.mdx +4 -5
- package/docs/self-hosting/environment-variables/auth.mdx +7 -0
- package/docs/self-hosting/environment-variables/auth.zh-CN.mdx +7 -0
- package/e2e/README.md +6 -6
- package/e2e/src/features/community/detail-pages.feature +9 -9
- package/e2e/src/features/community/interactions.feature +13 -13
- package/e2e/src/features/community/smoke.feature +6 -6
- package/e2e/src/steps/agent/conversation-mgmt.steps.ts +196 -25
- package/e2e/src/steps/agent/conversation.steps.ts +58 -0
- package/e2e/src/steps/agent/message-ops.steps.ts +20 -15
- package/e2e/src/steps/community/detail-pages.steps.ts +60 -19
- package/e2e/src/steps/community/interactions.steps.ts +145 -32
- package/e2e/src/steps/hooks.ts +12 -2
- package/locales/en-US/setting.json +3 -0
- package/locales/zh-CN/file.json +4 -0
- package/locales/zh-CN/setting.json +3 -0
- package/package.json +5 -5
- package/packages/business/config/src/llm.ts +6 -1
- package/packages/const/src/index.ts +1 -0
- package/packages/const/src/lobehubSkill.ts +55 -0
- package/packages/const/src/settings/image.ts +1 -1
- package/packages/model-bank/src/aiModels/azure.ts +2 -2
- package/packages/model-bank/src/aiModels/google.ts +1 -0
- package/packages/model-bank/src/aiModels/lobehub.ts +33 -13
- package/packages/model-bank/src/aiModels/openai.ts +21 -4
- package/packages/model-runtime/src/core/openaiCompatibleFactory/createImage.ts +4 -1
- package/packages/model-runtime/src/providers/openai/__snapshots__/index.test.ts.snap +1 -1
- package/packages/ssrf-safe-fetch/index.test.ts +5 -34
- package/packages/ssrf-safe-fetch/index.ts +12 -2
- package/packages/types/package.json +1 -1
- package/packages/types/src/files/upload.ts +11 -1
- package/packages/types/src/message/common/tools.ts +1 -1
- package/packages/types/src/serverConfig.ts +1 -0
- package/public/not-compatible.html +1296 -0
- package/src/app/[variants]/(main)/image/_layout/ConfigPanel/components/MultiImagesUpload/index.tsx +3 -3
- package/src/app/[variants]/(main)/image/features/GenerationFeed/index.tsx +3 -10
- package/src/app/[variants]/(main)/image/index.tsx +1 -1
- package/src/app/[variants]/(main)/resource/features/FileDetail.tsx +20 -12
- package/src/app/[variants]/(main)/resource/features/modal/FullscreenModal.tsx +2 -4
- package/src/app/[variants]/layout.tsx +50 -1
- package/src/envs/auth.ts +15 -0
- package/src/features/ChatInput/ActionBar/Tools/LobehubSkillServerItem.tsx +304 -0
- package/src/features/ChatInput/ActionBar/Tools/useControls.tsx +74 -10
- package/src/features/Conversation/Messages/AssistantGroup/Tool/Inspector/ToolTitle.tsx +9 -0
- package/src/features/FileViewer/Renderer/Code/index.tsx +224 -0
- package/src/features/FileViewer/Renderer/Image/index.tsx +8 -1
- package/src/features/FileViewer/Renderer/PDF/index.tsx +3 -1
- package/src/features/FileViewer/Renderer/PDF/style.ts +2 -1
- package/src/features/FileViewer/index.tsx +135 -24
- package/src/features/PageEditor/EditorCanvas/useSlashItems.tsx +7 -4
- package/src/features/PageEditor/store/initialState.ts +2 -1
- package/src/features/ResourceManager/components/Editor/FileContent.tsx +1 -4
- package/src/features/ResourceManager/components/Editor/FileCopilot.tsx +64 -0
- package/src/features/ResourceManager/components/Editor/index.tsx +98 -31
- package/src/features/ResourceManager/components/Explorer/ItemDropdown/useFileItemDropdown.tsx +3 -2
- package/src/features/ResourceManager/components/Explorer/ListView/ColumnResizeHandle.tsx +119 -0
- package/src/features/ResourceManager/components/Explorer/ListView/ListItem/index.tsx +67 -22
- package/src/features/ResourceManager/components/Explorer/ListView/Skeleton.tsx +46 -11
- package/src/features/ResourceManager/components/Explorer/ListView/index.tsx +140 -81
- package/src/features/ResourceManager/components/Explorer/ToolBar/SortDropdown.tsx +20 -12
- package/src/features/ResourceManager/components/Explorer/ToolBar/ViewSwitcher.tsx +18 -10
- package/src/features/ResourceManager/components/UploadDock/Item.tsx +38 -6
- package/src/features/ResourceManager/components/UploadDock/index.tsx +62 -41
- package/src/features/ResourceManager/index.tsx +1 -0
- package/src/helpers/toolEngineering/index.test.ts +3 -0
- package/src/helpers/toolEngineering/index.ts +12 -1
- package/src/hooks/useFetchAiImageConfig.ts +54 -10
- package/src/libs/trpc/utils/internalJwt.ts +2 -2
- package/src/locales/default/file.ts +4 -0
- package/src/locales/default/setting.ts +3 -0
- package/src/server/globalConfig/index.ts +1 -0
- package/src/server/modules/ModelRuntime/index.test.ts +214 -1
- package/src/server/modules/ModelRuntime/index.ts +43 -7
- package/src/server/routers/lambda/document.ts +44 -0
- package/src/server/routers/tools/market.ts +261 -0
- package/src/server/services/document/index.ts +22 -0
- package/src/services/document/index.ts +4 -0
- package/src/services/upload.ts +22 -2
- package/src/store/chat/slices/plugin/actions/internals.ts +15 -2
- package/src/store/chat/slices/plugin/actions/pluginTypes.ts +104 -0
- package/src/store/file/slices/fileManager/action.test.ts +9 -3
- package/src/store/file/slices/fileManager/action.ts +165 -70
- package/src/store/file/slices/upload/action.ts +3 -0
- package/src/store/global/actions/general.ts +15 -0
- package/src/store/global/initialState.ts +13 -0
- package/src/store/image/slices/generationConfig/initialState.ts +5 -5
- package/src/store/image/slices/generationConfig/selectors.test.ts +11 -4
- package/src/store/serverConfig/selectors.ts +1 -0
- package/src/store/tool/initialState.ts +11 -2
- package/src/store/tool/selectors/index.ts +1 -0
- package/src/store/tool/selectors/tool.ts +3 -1
- package/src/store/tool/slices/lobehubSkillStore/action.ts +361 -0
- package/src/store/tool/slices/lobehubSkillStore/index.ts +4 -0
- package/src/store/tool/slices/lobehubSkillStore/initialState.ts +24 -0
- package/src/store/tool/slices/lobehubSkillStore/selectors.ts +145 -0
- package/src/store/tool/slices/lobehubSkillStore/types.ts +100 -0
- package/src/store/tool/store.ts +8 -2
- package/vitest.config.mts +11 -6
- package/src/features/FileViewer/Renderer/JavaScript/index.tsx +0 -66
- package/src/features/FileViewer/Renderer/TXT/index.tsx +0 -50
|
@@ -1,10 +1,18 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
buildFolderTree,
|
|
3
|
+
createNanoId,
|
|
4
|
+
sanitizeFolderName,
|
|
5
|
+
topologicalSortFolders,
|
|
6
|
+
} from '@lobechat/utils';
|
|
7
|
+
import { t } from 'i18next';
|
|
2
8
|
import pMap from 'p-map';
|
|
3
9
|
import type { SWRResponse } from 'swr';
|
|
4
10
|
import { type StateCreator } from 'zustand/vanilla';
|
|
5
11
|
|
|
12
|
+
import { message } from '@/components/AntdStaticMethods';
|
|
6
13
|
import { FILE_UPLOAD_BLACKLIST, MAX_UPLOAD_FILE_COUNT } from '@/const/file';
|
|
7
14
|
import { mutate, useClientDataSWR } from '@/libs/swr';
|
|
15
|
+
import { documentService } from '@/services/document';
|
|
8
16
|
import { FileService, fileService } from '@/services/file';
|
|
9
17
|
import { ragService } from '@/services/rag';
|
|
10
18
|
import {
|
|
@@ -27,6 +35,7 @@ export interface FolderCrumb {
|
|
|
27
35
|
}
|
|
28
36
|
|
|
29
37
|
export interface FileManageAction {
|
|
38
|
+
cancelUpload: (id: string) => void;
|
|
30
39
|
dispatchDockFileList: (payload: UploadFileListDispatch) => void;
|
|
31
40
|
embeddingChunks: (fileIds: string[]) => Promise<void>;
|
|
32
41
|
loadMoreKnowledgeItems: () => Promise<void>;
|
|
@@ -67,6 +76,21 @@ export const createFileManageSlice: StateCreator<
|
|
|
67
76
|
[],
|
|
68
77
|
FileManageAction
|
|
69
78
|
> = (set, get) => ({
|
|
79
|
+
cancelUpload: (id) => {
|
|
80
|
+
const { dockUploadFileList, dispatchDockFileList } = get();
|
|
81
|
+
const uploadItem = dockUploadFileList.find((item) => item.id === id);
|
|
82
|
+
|
|
83
|
+
if (uploadItem?.abortController) {
|
|
84
|
+
uploadItem.abortController.abort();
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Update status to cancelled
|
|
88
|
+
dispatchDockFileList({
|
|
89
|
+
id,
|
|
90
|
+
status: 'cancelled',
|
|
91
|
+
type: 'updateFileStatus',
|
|
92
|
+
});
|
|
93
|
+
},
|
|
70
94
|
dispatchDockFileList: (payload: UploadFileListDispatch) => {
|
|
71
95
|
const nextValue = uploadFileListReducer(get().dockUploadFileList, payload);
|
|
72
96
|
if (nextValue === get().dockUploadFileList) return;
|
|
@@ -186,19 +210,31 @@ export const createFileManageSlice: StateCreator<
|
|
|
186
210
|
// 1. skip file in blacklist
|
|
187
211
|
const files = filesToUpload.filter((file) => !FILE_UPLOAD_BLACKLIST.includes(file.name));
|
|
188
212
|
|
|
189
|
-
// 2.
|
|
213
|
+
// 2. Create upload items with abort controllers
|
|
214
|
+
const uploadFiles = files.map((file) => {
|
|
215
|
+
const abortController = new AbortController();
|
|
216
|
+
return {
|
|
217
|
+
abortController,
|
|
218
|
+
file,
|
|
219
|
+
id: file.name,
|
|
220
|
+
status: 'pending' as const,
|
|
221
|
+
};
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
// 3. Add all files to dock
|
|
190
225
|
dispatchDockFileList({
|
|
191
226
|
atStart: true,
|
|
192
|
-
files:
|
|
227
|
+
files: uploadFiles,
|
|
193
228
|
type: 'addFiles',
|
|
194
229
|
});
|
|
195
230
|
|
|
196
|
-
//
|
|
231
|
+
// 4. Upload files with concurrency limit using p-map
|
|
197
232
|
const uploadResults = await pMap(
|
|
198
|
-
|
|
199
|
-
async (
|
|
233
|
+
uploadFiles,
|
|
234
|
+
async (uploadFileItem) => {
|
|
200
235
|
const result = await get().uploadWithProgress({
|
|
201
|
-
|
|
236
|
+
abortController: uploadFileItem.abortController,
|
|
237
|
+
file: uploadFileItem.file,
|
|
202
238
|
knowledgeBaseId,
|
|
203
239
|
onStatusUpdate: dispatchDockFileList,
|
|
204
240
|
parentId,
|
|
@@ -207,7 +243,11 @@ export const createFileManageSlice: StateCreator<
|
|
|
207
243
|
// Note: Don't refresh after each file to avoid flickering
|
|
208
244
|
// We'll refresh once at the end
|
|
209
245
|
|
|
210
|
-
return {
|
|
246
|
+
return {
|
|
247
|
+
file: uploadFileItem.file,
|
|
248
|
+
fileId: result?.id,
|
|
249
|
+
fileType: uploadFileItem.file.type,
|
|
250
|
+
};
|
|
211
251
|
},
|
|
212
252
|
{ concurrency: MAX_UPLOAD_FILE_COUNT },
|
|
213
253
|
);
|
|
@@ -215,7 +255,7 @@ export const createFileManageSlice: StateCreator<
|
|
|
215
255
|
// Refresh the file list once after all uploads are complete
|
|
216
256
|
await get().refreshFileList();
|
|
217
257
|
|
|
218
|
-
//
|
|
258
|
+
// 5. auto-embed files that support chunking
|
|
219
259
|
const fileIdsToEmbed = uploadResults
|
|
220
260
|
.filter(({ fileType, fileId }) => fileId && !isChunkingUnsupported(fileType))
|
|
221
261
|
.map(({ fileId }) => fileId!);
|
|
@@ -353,82 +393,137 @@ export const createFileManageSlice: StateCreator<
|
|
|
353
393
|
// 2. Sort folders by depth to ensure parents are created before children
|
|
354
394
|
const sortedFolderPaths = topologicalSortFolders(folders);
|
|
355
395
|
|
|
356
|
-
//
|
|
357
|
-
const
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
396
|
+
// Show toast notification if there are folders to create
|
|
397
|
+
const messageKey = 'uploadFolder.creatingFolders';
|
|
398
|
+
if (sortedFolderPaths.length > 0) {
|
|
399
|
+
message.loading({
|
|
400
|
+
content: t('header.actions.uploadFolder.creatingFolders', { ns: 'file' }),
|
|
401
|
+
duration: 0, // Don't auto-dismiss
|
|
402
|
+
key: messageKey,
|
|
403
|
+
});
|
|
404
|
+
}
|
|
362
405
|
|
|
363
|
-
|
|
364
|
-
|
|
406
|
+
try {
|
|
407
|
+
// Map to store created folder IDs: relative path -> folder ID
|
|
408
|
+
const folderIdMap = new Map<string, string>();
|
|
409
|
+
|
|
410
|
+
// 3. Group folders by depth level for batch creation
|
|
411
|
+
const foldersByLevel = new Map<number, string[]>();
|
|
412
|
+
for (const folderPath of sortedFolderPaths) {
|
|
413
|
+
const depth = (folderPath.match(/\//g) || []).length;
|
|
414
|
+
if (!foldersByLevel.has(depth)) {
|
|
415
|
+
foldersByLevel.set(depth, []);
|
|
416
|
+
}
|
|
417
|
+
foldersByLevel.get(depth)!.push(folderPath);
|
|
418
|
+
}
|
|
365
419
|
|
|
366
|
-
//
|
|
367
|
-
const
|
|
420
|
+
// 4. Create folders level by level using batch API
|
|
421
|
+
const generateSlug = createNanoId(8);
|
|
422
|
+
const levels = Array.from(foldersByLevel.keys()).sort((a, b) => a - b);
|
|
423
|
+
for (const level of levels) {
|
|
424
|
+
const foldersAtThisLevel = foldersByLevel.get(level)!;
|
|
425
|
+
|
|
426
|
+
// Prepare batch creation data for this level
|
|
427
|
+
const batchCreateData = foldersAtThisLevel.map((folderPath) => {
|
|
428
|
+
const folder = folders[folderPath];
|
|
429
|
+
const parentId = folder.parent ? folderIdMap.get(folder.parent) : currentFolderId;
|
|
430
|
+
const sanitizedName = sanitizeFolderName(folder.name);
|
|
431
|
+
|
|
432
|
+
// Generate unique slug for the folder
|
|
433
|
+
const slug = generateSlug();
|
|
434
|
+
|
|
435
|
+
return {
|
|
436
|
+
content: '',
|
|
437
|
+
editorData: '{}',
|
|
438
|
+
fileType: 'custom/folder',
|
|
439
|
+
knowledgeBaseId,
|
|
440
|
+
metadata: { createdAt: Date.now() },
|
|
441
|
+
parentId,
|
|
442
|
+
slug,
|
|
443
|
+
title: sanitizedName,
|
|
444
|
+
};
|
|
445
|
+
});
|
|
368
446
|
|
|
369
|
-
|
|
370
|
-
|
|
447
|
+
// Create all folders at this level in a single batch request
|
|
448
|
+
const createdFolders = await documentService.createDocuments(batchCreateData);
|
|
371
449
|
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
450
|
+
// Store folder ID mappings for the next level
|
|
451
|
+
for (const [i, element] of foldersAtThisLevel.entries()) {
|
|
452
|
+
folderIdMap.set(element, createdFolders[i].id);
|
|
453
|
+
}
|
|
454
|
+
}
|
|
375
455
|
|
|
376
|
-
|
|
377
|
-
|
|
456
|
+
// Dismiss the toast after folders are created
|
|
457
|
+
if (sortedFolderPaths.length > 0) {
|
|
458
|
+
message.destroy(messageKey);
|
|
459
|
+
}
|
|
378
460
|
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
const targetFolderId = folderPath ? folderIdMap.get(folderPath) : currentFolderId;
|
|
461
|
+
// Refresh file list to show the new folders
|
|
462
|
+
await get().refreshFileList();
|
|
382
463
|
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
file,
|
|
386
|
-
parentId: targetFolderId,
|
|
387
|
-
})),
|
|
388
|
-
);
|
|
389
|
-
}
|
|
464
|
+
// 5. Prepare all file uploads with their target folder IDs
|
|
465
|
+
const allUploads: Array<{ file: File; parentId: string | undefined }> = [];
|
|
390
466
|
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
);
|
|
467
|
+
for (const [folderPath, folderFiles] of Object.entries(filesByFolder)) {
|
|
468
|
+
// Root-level files (no folder path) go to currentFolderId
|
|
469
|
+
const targetFolderId = folderPath ? folderIdMap.get(folderPath) : currentFolderId;
|
|
395
470
|
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
471
|
+
allUploads.push(
|
|
472
|
+
...folderFiles.map((file) => ({
|
|
473
|
+
file,
|
|
474
|
+
parentId: targetFolderId,
|
|
475
|
+
})),
|
|
476
|
+
);
|
|
477
|
+
}
|
|
402
478
|
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
const result = await get().uploadWithProgress({
|
|
408
|
-
file,
|
|
409
|
-
knowledgeBaseId,
|
|
410
|
-
onStatusUpdate: dispatchDockFileList,
|
|
411
|
-
parentId,
|
|
412
|
-
});
|
|
479
|
+
// 6. Filter out blacklisted files
|
|
480
|
+
const validUploads = allUploads.filter(
|
|
481
|
+
({ file }) => !FILE_UPLOAD_BLACKLIST.includes(file.name),
|
|
482
|
+
);
|
|
413
483
|
|
|
414
|
-
|
|
415
|
-
|
|
484
|
+
// 7. Add all files to dock
|
|
485
|
+
dispatchDockFileList({
|
|
486
|
+
atStart: true,
|
|
487
|
+
files: validUploads.map(({ file }) => ({ file, id: file.name, status: 'pending' })),
|
|
488
|
+
type: 'addFiles',
|
|
489
|
+
});
|
|
416
490
|
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
491
|
+
// 8. Upload files with concurrency limit
|
|
492
|
+
const uploadResults = await pMap(
|
|
493
|
+
validUploads,
|
|
494
|
+
async ({ file, parentId }) => {
|
|
495
|
+
const result = await get().uploadWithProgress({
|
|
496
|
+
file,
|
|
497
|
+
knowledgeBaseId,
|
|
498
|
+
onStatusUpdate: dispatchDockFileList,
|
|
499
|
+
parentId,
|
|
500
|
+
});
|
|
501
|
+
|
|
502
|
+
// Note: Don't refresh after each file to avoid flickering
|
|
503
|
+
// We'll refresh once at the end
|
|
504
|
+
|
|
505
|
+
return { file, fileId: result?.id, fileType: file.type };
|
|
506
|
+
},
|
|
507
|
+
{ concurrency: MAX_UPLOAD_FILE_COUNT },
|
|
508
|
+
);
|
|
421
509
|
|
|
422
|
-
|
|
423
|
-
|
|
510
|
+
// Refresh the file list once after all uploads are complete
|
|
511
|
+
await get().refreshFileList();
|
|
424
512
|
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
513
|
+
// 9. Auto-embed files that support chunking
|
|
514
|
+
const fileIdsToEmbed = uploadResults
|
|
515
|
+
.filter(({ fileType, fileId }) => fileId && !isChunkingUnsupported(fileType))
|
|
516
|
+
.map(({ fileId }) => fileId!);
|
|
429
517
|
|
|
430
|
-
|
|
431
|
-
|
|
518
|
+
if (fileIdsToEmbed.length > 0) {
|
|
519
|
+
await get().parseFilesToChunks(fileIdsToEmbed, { skipExist: false });
|
|
520
|
+
}
|
|
521
|
+
} catch (error) {
|
|
522
|
+
// Dismiss toast on error
|
|
523
|
+
if (sortedFolderPaths.length > 0) {
|
|
524
|
+
message.destroy(messageKey);
|
|
525
|
+
}
|
|
526
|
+
throw error;
|
|
432
527
|
}
|
|
433
528
|
},
|
|
434
529
|
|
|
@@ -25,6 +25,7 @@ type OnStatusUpdate = (
|
|
|
25
25
|
) => void;
|
|
26
26
|
|
|
27
27
|
interface UploadWithProgressParams {
|
|
28
|
+
abortController?: AbortController;
|
|
28
29
|
file: File;
|
|
29
30
|
knowledgeBaseId?: string;
|
|
30
31
|
onStatusUpdate?: OnStatusUpdate;
|
|
@@ -93,6 +94,7 @@ export const createFileUploadSlice: StateCreator<
|
|
|
93
94
|
skipCheckFileType,
|
|
94
95
|
parentId,
|
|
95
96
|
source,
|
|
97
|
+
abortController,
|
|
96
98
|
}) => {
|
|
97
99
|
const fileArrayBuffer = await file.arrayBuffer();
|
|
98
100
|
|
|
@@ -117,6 +119,7 @@ export const createFileUploadSlice: StateCreator<
|
|
|
117
119
|
// 3. if file don't exist, need upload files
|
|
118
120
|
else {
|
|
119
121
|
const { data, success } = await uploadService.uploadFileToS3(file, {
|
|
122
|
+
abortController,
|
|
120
123
|
onNotSupported: () => {
|
|
121
124
|
onStatusUpdate?.({ id: file.name, type: 'removeFile' });
|
|
122
125
|
message.info({
|
|
@@ -20,6 +20,7 @@ export interface GlobalGeneralAction {
|
|
|
20
20
|
openAgentInNewWindow: (agentId: string) => Promise<void>;
|
|
21
21
|
openTopicInNewWindow: (agentId: string, topicId: string) => Promise<void>;
|
|
22
22
|
switchLocale: (locale: LocaleMode, params?: { skipBroadcast?: boolean }) => void;
|
|
23
|
+
updateResourceManagerColumnWidth: (column: 'name' | 'date' | 'size', width: number) => void;
|
|
23
24
|
updateSystemStatus: (status: Partial<SystemStatus>, action?: any) => void;
|
|
24
25
|
useCheckLatestVersion: (enabledCheck?: boolean) => SWRResponse<string>;
|
|
25
26
|
useInitSystemStatus: () => SWRResponse;
|
|
@@ -110,6 +111,20 @@ export const generalActionSlice: StateCreator<
|
|
|
110
111
|
})();
|
|
111
112
|
}
|
|
112
113
|
},
|
|
114
|
+
updateResourceManagerColumnWidth: (column, width) => {
|
|
115
|
+
const currentWidths = get().status.resourceManagerColumnWidths || {
|
|
116
|
+
date: 160,
|
|
117
|
+
name: 574,
|
|
118
|
+
size: 140,
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
get().updateSystemStatus({
|
|
122
|
+
resourceManagerColumnWidths: {
|
|
123
|
+
...currentWidths,
|
|
124
|
+
[column]: width,
|
|
125
|
+
},
|
|
126
|
+
});
|
|
127
|
+
},
|
|
113
128
|
updateSystemStatus: (status, action) => {
|
|
114
129
|
if (!get().isStatusInit) return;
|
|
115
130
|
|
|
@@ -127,6 +127,14 @@ export interface SystemStatus {
|
|
|
127
127
|
*/
|
|
128
128
|
pagePageSize?: number;
|
|
129
129
|
portalWidth: number;
|
|
130
|
+
/**
|
|
131
|
+
* Resource Manager column widths
|
|
132
|
+
*/
|
|
133
|
+
resourceManagerColumnWidths?: {
|
|
134
|
+
date: number;
|
|
135
|
+
name: number;
|
|
136
|
+
size: number;
|
|
137
|
+
};
|
|
130
138
|
showCommandMenu?: boolean;
|
|
131
139
|
showFilePanel?: boolean;
|
|
132
140
|
showHotkeyHelper?: boolean;
|
|
@@ -192,6 +200,11 @@ export const INITIAL_STATUS = {
|
|
|
192
200
|
noWideScreen: true,
|
|
193
201
|
pagePageSize: 20,
|
|
194
202
|
portalWidth: 400,
|
|
203
|
+
resourceManagerColumnWidths: {
|
|
204
|
+
date: 160,
|
|
205
|
+
name: 574,
|
|
206
|
+
size: 140,
|
|
207
|
+
},
|
|
195
208
|
showCommandMenu: false,
|
|
196
209
|
showFilePanel: true,
|
|
197
210
|
showHotkeyHelper: false,
|
|
@@ -4,13 +4,13 @@ import {
|
|
|
4
4
|
ModelProvider,
|
|
5
5
|
type RuntimeImageGenParams,
|
|
6
6
|
extractDefaultValues,
|
|
7
|
-
gptImage1ParamsSchema,
|
|
8
7
|
} from 'model-bank';
|
|
8
|
+
import { nanoBananaProParameters } from 'model-bank/google';
|
|
9
9
|
|
|
10
10
|
import { DEFAULT_IMAGE_CONFIG } from '@/const/settings';
|
|
11
11
|
|
|
12
|
-
export const DEFAULT_AI_IMAGE_PROVIDER = ModelProvider.
|
|
13
|
-
export const DEFAULT_AI_IMAGE_MODEL = '
|
|
12
|
+
export const DEFAULT_AI_IMAGE_PROVIDER = ModelProvider.Google;
|
|
13
|
+
export const DEFAULT_AI_IMAGE_MODEL = 'gemini-3-pro-image-preview:image';
|
|
14
14
|
|
|
15
15
|
export interface GenerationConfigState {
|
|
16
16
|
parameters: RuntimeImageGenParams;
|
|
@@ -30,14 +30,14 @@ export interface GenerationConfigState {
|
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
export const DEFAULT_IMAGE_GENERATION_PARAMETERS: RuntimeImageGenParams =
|
|
33
|
-
extractDefaultValues(
|
|
33
|
+
extractDefaultValues(nanoBananaProParameters);
|
|
34
34
|
|
|
35
35
|
export const initialGenerationConfigState: GenerationConfigState = {
|
|
36
36
|
model: DEFAULT_AI_IMAGE_MODEL,
|
|
37
37
|
provider: DEFAULT_AI_IMAGE_PROVIDER,
|
|
38
38
|
imageNum: DEFAULT_IMAGE_CONFIG.defaultImageNum,
|
|
39
39
|
parameters: DEFAULT_IMAGE_GENERATION_PARAMETERS,
|
|
40
|
-
parametersSchema:
|
|
40
|
+
parametersSchema: nanoBananaProParameters,
|
|
41
41
|
isAspectRatioLocked: false,
|
|
42
42
|
activeAspectRatio: null,
|
|
43
43
|
isInit: false,
|
|
@@ -6,6 +6,7 @@ import { ImageStore } from '@/store/image';
|
|
|
6
6
|
import { initialState } from '@/store/image/initialState';
|
|
7
7
|
import { merge } from '@/utils/merge';
|
|
8
8
|
|
|
9
|
+
import { DEFAULT_AI_IMAGE_MODEL, DEFAULT_AI_IMAGE_PROVIDER } from './initialState';
|
|
9
10
|
import { imageGenerationConfigSelectors } from './selectors';
|
|
10
11
|
|
|
11
12
|
// Mock external dependencies
|
|
@@ -57,7 +58,7 @@ describe('imageGenerationConfigSelectors', () => {
|
|
|
57
58
|
|
|
58
59
|
it('should return the default model from initial state', () => {
|
|
59
60
|
const result = imageGenerationConfigSelectors.model(initialStore);
|
|
60
|
-
expect(result).toBe(
|
|
61
|
+
expect(result).toBe(DEFAULT_AI_IMAGE_MODEL);
|
|
61
62
|
});
|
|
62
63
|
});
|
|
63
64
|
|
|
@@ -70,7 +71,7 @@ describe('imageGenerationConfigSelectors', () => {
|
|
|
70
71
|
|
|
71
72
|
it('should return the default provider from initial state', () => {
|
|
72
73
|
const result = imageGenerationConfigSelectors.provider(initialStore);
|
|
73
|
-
expect(result).toBe(
|
|
74
|
+
expect(result).toBe(DEFAULT_AI_IMAGE_PROVIDER);
|
|
74
75
|
});
|
|
75
76
|
});
|
|
76
77
|
|
|
@@ -98,7 +99,10 @@ describe('imageGenerationConfigSelectors', () => {
|
|
|
98
99
|
it('should return the current parameters', () => {
|
|
99
100
|
const state = merge(initialStore, { parameters: testParameters });
|
|
100
101
|
const result = imageGenerationConfigSelectors.parameters(state);
|
|
101
|
-
|
|
102
|
+
// merge does deep merge, so result contains both default and test values
|
|
103
|
+
expect(result.prompt).toBe(testParameters.prompt);
|
|
104
|
+
expect(result.size).toBe(testParameters.size);
|
|
105
|
+
expect(result.imageUrls).toEqual(testParameters.imageUrls);
|
|
102
106
|
});
|
|
103
107
|
|
|
104
108
|
it('should return the default parameters from initial state', () => {
|
|
@@ -120,7 +124,10 @@ describe('imageGenerationConfigSelectors', () => {
|
|
|
120
124
|
it('should return the current parametersSchema', () => {
|
|
121
125
|
const state = merge(initialStore, { parametersSchema: testModelSchema });
|
|
122
126
|
const result = imageGenerationConfigSelectors.parametersSchema(state);
|
|
123
|
-
|
|
127
|
+
// merge does deep merge, so result contains both default and test values
|
|
128
|
+
expect(result.prompt).toEqual(testModelSchema.prompt);
|
|
129
|
+
expect(result.size).toEqual(testModelSchema.size);
|
|
130
|
+
expect(result.imageUrls).toEqual(testModelSchema.imageUrls);
|
|
124
131
|
});
|
|
125
132
|
|
|
126
133
|
it('should return default parametersSchema when not explicitly overridden', () => {
|
|
@@ -6,6 +6,7 @@ export const serverConfigSelectors = {
|
|
|
6
6
|
enableEmailVerification: (s: ServerConfigStore) =>
|
|
7
7
|
s.serverConfig.enableEmailVerification || false,
|
|
8
8
|
enableKlavis: (s: ServerConfigStore) => s.serverConfig.enableKlavis || false,
|
|
9
|
+
enableLobehubSkill: (s: ServerConfigStore) => s.serverConfig.enableLobehubSkill || false,
|
|
9
10
|
enableMagicLink: (s: ServerConfigStore) => s.serverConfig.enableMagicLink || false,
|
|
10
11
|
enableMarketTrustedClient: (s: ServerConfigStore) =>
|
|
11
12
|
s.serverConfig.enableMarketTrustedClient || false,
|
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
import { type BuiltinToolState, initialBuiltinToolState } from './slices/builtin/initialState';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
type CustomPluginState,
|
|
4
|
+
initialCustomPluginState,
|
|
5
|
+
} from './slices/customPlugin/initialState';
|
|
3
6
|
import { type KlavisStoreState, initialKlavisStoreState } from './slices/klavisStore/initialState';
|
|
7
|
+
import {
|
|
8
|
+
type LobehubSkillStoreState,
|
|
9
|
+
initialLobehubSkillStoreState,
|
|
10
|
+
} from './slices/lobehubSkillStore/initialState';
|
|
4
11
|
import { type MCPStoreState, initialMCPStoreState } from './slices/mcpStore/initialState';
|
|
5
12
|
import { type PluginStoreState, initialPluginStoreState } from './slices/oldStore/initialState';
|
|
6
13
|
import { type PluginState, initialPluginState } from './slices/plugin/initialState';
|
|
@@ -10,7 +17,8 @@ export type ToolStoreState = PluginState &
|
|
|
10
17
|
PluginStoreState &
|
|
11
18
|
BuiltinToolState &
|
|
12
19
|
MCPStoreState &
|
|
13
|
-
KlavisStoreState
|
|
20
|
+
KlavisStoreState &
|
|
21
|
+
LobehubSkillStoreState;
|
|
14
22
|
|
|
15
23
|
export const initialState: ToolStoreState = {
|
|
16
24
|
...initialPluginState,
|
|
@@ -19,4 +27,5 @@ export const initialState: ToolStoreState = {
|
|
|
19
27
|
...initialBuiltinToolState,
|
|
20
28
|
...initialMCPStoreState,
|
|
21
29
|
...initialKlavisStoreState,
|
|
30
|
+
...initialLobehubSkillStoreState,
|
|
22
31
|
};
|
|
@@ -4,6 +4,7 @@ export {
|
|
|
4
4
|
} from '../slices/builtin/selectors';
|
|
5
5
|
export { customPluginSelectors } from '../slices/customPlugin/selectors';
|
|
6
6
|
export { klavisStoreSelectors } from '../slices/klavisStore/selectors';
|
|
7
|
+
export { lobehubSkillStoreSelectors } from '../slices/lobehubSkillStore/selectors';
|
|
7
8
|
export { mcpStoreSelectors } from '../slices/mcpStore/selectors';
|
|
8
9
|
export { pluginStoreSelectors } from '../slices/oldStore/selectors';
|
|
9
10
|
export { pluginSelectors } from '../slices/plugin/selectors';
|
|
@@ -6,12 +6,14 @@ import { type LobeToolMeta } from '@/types/tool/tool';
|
|
|
6
6
|
|
|
7
7
|
import { type ToolStoreState } from '../initialState';
|
|
8
8
|
import { builtinToolSelectors } from '../slices/builtin/selectors';
|
|
9
|
+
import { lobehubSkillStoreSelectors } from '../slices/lobehubSkillStore/selectors';
|
|
9
10
|
import { pluginSelectors } from '../slices/plugin/selectors';
|
|
10
11
|
|
|
11
12
|
const metaList = (s: ToolStoreState): LobeToolMeta[] => {
|
|
12
13
|
const pluginList = pluginSelectors.installedPluginMetaList(s) as LobeToolMeta[];
|
|
14
|
+
const lobehubSkillList = lobehubSkillStoreSelectors.metaList(s) as LobeToolMeta[];
|
|
13
15
|
|
|
14
|
-
return builtinToolSelectors.metaList(s).concat(pluginList);
|
|
16
|
+
return builtinToolSelectors.metaList(s).concat(pluginList).concat(lobehubSkillList);
|
|
15
17
|
};
|
|
16
18
|
|
|
17
19
|
const getMetaById =
|