@lobehub/lobehub 2.0.0-next.324 → 2.0.0-next.326
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 +58 -0
- package/CLAUDE.md +4 -0
- package/apps/desktop/src/main/core/browser/Browser.ts +40 -1
- package/apps/desktop/src/main/core/infrastructure/I18nManager.ts +0 -11
- package/apps/desktop/src/main/core/infrastructure/UpdaterManager.ts +52 -2
- package/apps/desktop/src/main/core/infrastructure/__tests__/UpdaterManager.test.ts +41 -0
- package/changelog/v1.json +10 -0
- package/package.json +2 -2
- package/packages/database/src/models/__tests__/session.test.ts +0 -29
- package/src/app/[variants]/(main)/agent/features/Conversation/AgentWelcome/OpeningQuestions.tsx +0 -2
- package/src/app/[variants]/(main)/community/(detail)/agent/features/Sidebar/TocList/index.tsx +0 -36
- package/src/app/[variants]/(main)/community/(list)/_layout/Header.tsx +0 -2
- package/src/app/[variants]/(main)/group/_layout/Sidebar/GroupConfig/GroupMember.tsx +0 -4
- package/src/app/[variants]/(main)/group/features/Conversation/ConversationArea.tsx +0 -7
- package/src/app/[variants]/(main)/group/features/Conversation/MainChatInput/GroupChat.tsx +0 -2
- package/src/app/[variants]/(main)/home/_layout/Body/index.tsx +0 -2
- package/src/app/[variants]/(main)/page/_layout/Body/List/Item/useDropdownMenu.tsx +0 -6
- package/src/app/[variants]/(main)/page/_layout/Body/useDropdownMenu.tsx +0 -15
- package/src/app/[variants]/(main)/resource/features/DndContextWrapper.tsx +0 -5
- package/src/app/[variants]/(main)/settings/provider/features/ModelList/CreateNewModelModal/index.tsx +0 -1
- package/src/app/[variants]/(main)/settings/provider/features/ModelList/ModelItem.tsx +0 -10
- package/src/app/[variants]/(main)/settings/provider/features/ProviderConfig/Checker.tsx +1 -1
- package/src/app/[variants]/(mobile)/(home)/features/SessionListContent/List/Item/Actions.tsx +0 -1
- package/src/app/[variants]/layout.tsx +0 -2
- package/src/envs/__tests__/app.test.ts +0 -6
- package/src/features/ChatInput/ActionBar/Knowledge/useControls.tsx +0 -22
- package/src/features/ChatInput/store/action.ts +0 -2
- package/src/features/Conversation/Messages/Task/TaskDetailPanel/index.tsx +1 -15
- package/src/features/DataImporter/ImportDetail.tsx +0 -20
- package/src/features/DevPanel/features/Table/TableCell.tsx +1 -36
- package/src/features/DevPanel/index.tsx +0 -9
- package/src/features/ModelSwitchPanel/__mocks__/mockEnabledChatModels.ts +159 -0
- package/src/features/ModelSwitchPanel/components/List/{VirtualItemRenderer.tsx → ListItemRenderer.tsx} +15 -25
- package/src/features/ModelSwitchPanel/components/List/MultipleProvidersModelItem.tsx +95 -69
- package/src/features/ModelSwitchPanel/components/List/index.tsx +39 -40
- package/src/features/ModelSwitchPanel/components/PanelContent.tsx +0 -8
- package/src/features/ModelSwitchPanel/hooks/{useBuildVirtualItems.ts → useBuildListItems.ts} +7 -17
- package/src/features/ModelSwitchPanel/index.tsx +24 -23
- package/src/features/ModelSwitchPanel/styles.ts +3 -0
- package/src/features/ModelSwitchPanel/types.ts +3 -8
- package/src/features/ModelSwitchPanel/utils.ts +2 -2
- package/src/features/NavPanel/SideBarDrawer.tsx +12 -2
- package/src/features/NavPanel/SideBarHeaderLayout.tsx +3 -1
- package/src/features/Portal/GroupThread/Body/index.tsx +0 -6
- package/src/features/ResourceManager/components/Header/AddButton.tsx +0 -16
- package/src/features/ShareModal/ShareImage/index.tsx +0 -8
- package/src/hooks/useProviderName.ts +0 -1
- package/src/layout/GlobalProvider/Locale.tsx +0 -12
- package/src/layout/GlobalProvider/index.tsx +0 -1
- package/src/libs/better-auth/sso/helpers.ts +0 -1
- package/src/libs/next/config/define-config.ts +5 -0
- package/src/locales/create.ts +0 -17
- package/src/services/aiChat.ts +0 -4
- package/src/services/debug.ts +1 -34
- package/src/services/models.ts +0 -15
- package/src/store/chat/agents/GroupOrchestration/createGroupOrchestrationExecutors.ts +0 -9
- package/src/store/chat/slices/aiChat/actions/conversationLifecycle.ts +0 -3
- package/src/store/chat/slices/aiChat/actions/index.ts +1 -3
- package/src/store/file/slices/chat/action.test.ts +0 -89
- package/src/store/file/slices/chunk/selectors.ts +0 -1
- package/src/store/file/slices/fileManager/selectors.ts +0 -1
- package/src/store/file/slices/tts/selectors.ts +0 -2
- package/src/store/tool/slices/customPlugin/index.ts +0 -1
- package/src/store/tool/slices/mcpStore/index.ts +0 -1
- package/src/store/tool/slices/oldStore/index.ts +0 -1
- package/src/store/tool/slices/plugin/index.ts +0 -1
- package/src/styles/global.ts +6 -0
- package/src/utils/router.tsx +1 -7
- package/src/utils/server/parseModels.ts +0 -1
package/src/services/models.ts
CHANGED
|
@@ -25,10 +25,8 @@ export type ProgressCallback = (progress: ModelProgressInfo) => void;
|
|
|
25
25
|
export type ErrorCallback = (error: { message: string }) => void;
|
|
26
26
|
|
|
27
27
|
export class ModelsService {
|
|
28
|
-
// Controller for aborting downloads
|
|
29
28
|
private _abortController: AbortController | null = null;
|
|
30
29
|
|
|
31
|
-
// Get model list
|
|
32
30
|
getModels = async (provider: string): Promise<ChatModelCard[] | undefined> => {
|
|
33
31
|
const headers = await createHeaderWithAuth({
|
|
34
32
|
headers: { 'Content-Type': 'application/json' },
|
|
@@ -66,7 +64,6 @@ export class ModelsService {
|
|
|
66
64
|
{ onProgress }: { onError?: ErrorCallback; onProgress?: ProgressCallback } = {},
|
|
67
65
|
): Promise<void> => {
|
|
68
66
|
try {
|
|
69
|
-
// Create a new AbortController
|
|
70
67
|
this._abortController = new AbortController();
|
|
71
68
|
const signal = this._abortController.signal;
|
|
72
69
|
|
|
@@ -99,7 +96,6 @@ export class ModelsService {
|
|
|
99
96
|
throw await getMessageError(res);
|
|
100
97
|
}
|
|
101
98
|
|
|
102
|
-
// Process response stream
|
|
103
99
|
if (res.body) {
|
|
104
100
|
await this.processModelPullStream(res, { onProgress });
|
|
105
101
|
}
|
|
@@ -112,14 +108,11 @@ export class ModelsService {
|
|
|
112
108
|
console.error('download model error:', error);
|
|
113
109
|
throw error;
|
|
114
110
|
} finally {
|
|
115
|
-
// Clean up AbortController
|
|
116
111
|
this._abortController = null;
|
|
117
112
|
}
|
|
118
113
|
};
|
|
119
114
|
|
|
120
|
-
// Abort model download
|
|
121
115
|
abortPull = () => {
|
|
122
|
-
// Use AbortController to abort download
|
|
123
116
|
if (this._abortController) {
|
|
124
117
|
this._abortController.abort();
|
|
125
118
|
this._abortController = null;
|
|
@@ -136,17 +129,14 @@ export class ModelsService {
|
|
|
136
129
|
response: Response,
|
|
137
130
|
{ onProgress, onError }: { onError?: ErrorCallback; onProgress?: ProgressCallback },
|
|
138
131
|
): Promise<void> => {
|
|
139
|
-
// Process response stream
|
|
140
132
|
const reader = response.body?.getReader();
|
|
141
133
|
if (!reader) return;
|
|
142
134
|
|
|
143
|
-
// Read and process stream data
|
|
144
135
|
// eslint-disable-next-line no-constant-condition
|
|
145
136
|
while (true) {
|
|
146
137
|
const { done, value } = await reader.read();
|
|
147
138
|
if (done) break;
|
|
148
139
|
|
|
149
|
-
// Parse progress data
|
|
150
140
|
const progressText = new TextDecoder().decode(value);
|
|
151
141
|
// One line may contain multiple progress updates
|
|
152
142
|
const progressUpdates = progressText.trim().split('\n');
|
|
@@ -162,10 +152,6 @@ export class ModelsService {
|
|
|
162
152
|
|
|
163
153
|
if (progress.status === 'canceled') {
|
|
164
154
|
console.log('progress:', progress);
|
|
165
|
-
// const abortError = new Error('abort');
|
|
166
|
-
// abortError.name = 'AbortError';
|
|
167
|
-
//
|
|
168
|
-
// throw abortError;
|
|
169
155
|
}
|
|
170
156
|
|
|
171
157
|
if (progress.status === 'error') {
|
|
@@ -173,7 +159,6 @@ export class ModelsService {
|
|
|
173
159
|
throw new Error(progress.error);
|
|
174
160
|
}
|
|
175
161
|
|
|
176
|
-
// Call progress callback
|
|
177
162
|
if (progress.completed !== undefined || progress.status) {
|
|
178
163
|
onProgress?.(progress);
|
|
179
164
|
}
|
|
@@ -120,11 +120,6 @@ export const createGroupOrchestrationExecutors = (
|
|
|
120
120
|
};
|
|
121
121
|
}
|
|
122
122
|
|
|
123
|
-
// Variable to capture the decision from tool handler
|
|
124
|
-
// let decision: ExecutorResult['type'] | undefined;
|
|
125
|
-
// let decisionParams: Record<string, unknown> = {};
|
|
126
|
-
// let skipCallSupervisor = false;
|
|
127
|
-
|
|
128
123
|
// Execute Supervisor agent with the supervisor's agentId in context
|
|
129
124
|
// Mark isSupervisor=true so assistant messages get metadata.isSupervisor for UI rendering
|
|
130
125
|
// Note: Don't pass operationId - let it create a new child operation (same as call_agent)
|
|
@@ -139,10 +134,6 @@ export const createGroupOrchestrationExecutors = (
|
|
|
139
134
|
|
|
140
135
|
log(`[${sessionLogId}] Supervisor agent finished`);
|
|
141
136
|
|
|
142
|
-
// Check what decision was made by the supervisor
|
|
143
|
-
// This is captured from the groupOrchestration callbacks registered by tools
|
|
144
|
-
// const orchestrationCallbacks = get().getGroupOrchestrationCallbacks();
|
|
145
|
-
|
|
146
137
|
// If no tool was called (supervisor finished normally), end orchestration
|
|
147
138
|
// The actual decision is captured via the afterCompletion callbacks
|
|
148
139
|
// For now, return a finish decision if we reach here
|
|
@@ -399,9 +399,6 @@ export const conversationLifecycle: StateCreator<
|
|
|
399
399
|
skipCreateFirstMessage: true,
|
|
400
400
|
});
|
|
401
401
|
|
|
402
|
-
//
|
|
403
|
-
// // if there is relative files, then add files to agent
|
|
404
|
-
// // only available in server mode
|
|
405
402
|
const userFiles = dbMessageSelectors
|
|
406
403
|
.dbUserFiles(get())
|
|
407
404
|
.map((f) => f?.id)
|
|
@@ -16,7 +16,6 @@ vi.mock('@/components/AntdStaticMethods', () => ({
|
|
|
16
16
|
},
|
|
17
17
|
}));
|
|
18
18
|
|
|
19
|
-
// mock the arrayBuffer
|
|
20
19
|
beforeAll(() => {
|
|
21
20
|
Object.defineProperty(File.prototype, 'arrayBuffer', {
|
|
22
21
|
writable: true,
|
|
@@ -33,7 +32,6 @@ beforeAll(() => {
|
|
|
33
32
|
});
|
|
34
33
|
|
|
35
34
|
beforeEach(() => {
|
|
36
|
-
// Reset all mocks before each test
|
|
37
35
|
vi.resetAllMocks();
|
|
38
36
|
});
|
|
39
37
|
|
|
@@ -41,7 +39,6 @@ describe('useFileStore:chat', () => {
|
|
|
41
39
|
it('clearChatUploadFileList should clear the inputFilesList', () => {
|
|
42
40
|
const { result } = renderHook(() => useStore());
|
|
43
41
|
|
|
44
|
-
// Populate the list to clear it later
|
|
45
42
|
act(() => {
|
|
46
43
|
useStore.setState({ chatUploadFileList: [{ id: 'abc' }] as any });
|
|
47
44
|
});
|
|
@@ -54,90 +51,4 @@ describe('useFileStore:chat', () => {
|
|
|
54
51
|
|
|
55
52
|
expect(result.current.chatUploadFileList).toEqual([]);
|
|
56
53
|
});
|
|
57
|
-
|
|
58
|
-
// it('removeFile should call fileService.removeFile and update the store', async () => {
|
|
59
|
-
// const { result } = renderHook(() => useStore());
|
|
60
|
-
//
|
|
61
|
-
// const fileId = 'test-id';
|
|
62
|
-
//
|
|
63
|
-
// // Mock the fileService.removeFile to resolve
|
|
64
|
-
// vi.spyOn(fileService, 'removeFile').mockResolvedValue(undefined);
|
|
65
|
-
//
|
|
66
|
-
// // Populate the list to remove an item later
|
|
67
|
-
// act(() => {
|
|
68
|
-
// useStore.setState(({ inputFilesList }) => ({ inputFilesList: [...inputFilesList, fileId] }));
|
|
69
|
-
// // // result.current.inputFilesList.push(fileId);
|
|
70
|
-
// });
|
|
71
|
-
//
|
|
72
|
-
// await act(async () => {
|
|
73
|
-
// await result.current.removeFile(fileId);
|
|
74
|
-
// });
|
|
75
|
-
//
|
|
76
|
-
// expect(fileService.removeFile).toHaveBeenCalledWith(fileId);
|
|
77
|
-
// expect(result.current.inputFilesList).toEqual([]);
|
|
78
|
-
// });
|
|
79
|
-
|
|
80
|
-
// describe('uploadFile', () => {
|
|
81
|
-
// it('uploadFile should handle errors', async () => {
|
|
82
|
-
// const { result } = renderHook(() => useStore());
|
|
83
|
-
// const testFile = new File(['content'], 'test.png', { type: 'image/png' });
|
|
84
|
-
//
|
|
85
|
-
// // 模拟 fileService.uploadFile 抛出错误
|
|
86
|
-
// const errorMessage = 'Upload failed';
|
|
87
|
-
// vi.spyOn(uploadService, 'uploadFile').mockRejectedValue(new Error(errorMessage));
|
|
88
|
-
//
|
|
89
|
-
// // Mock console.error for testing
|
|
90
|
-
//
|
|
91
|
-
// await act(async () => {
|
|
92
|
-
// await result.current.uploadFile(testFile);
|
|
93
|
-
// });
|
|
94
|
-
//
|
|
95
|
-
// expect(uploadService.uploadFile).toHaveBeenCalledWith({
|
|
96
|
-
// createdAt: testFile.lastModified,
|
|
97
|
-
// data: await testFile.arrayBuffer(),
|
|
98
|
-
// fileType: testFile.type,
|
|
99
|
-
// name: testFile.name,
|
|
100
|
-
// saveMode: 'local',
|
|
101
|
-
// size: testFile.size,
|
|
102
|
-
// });
|
|
103
|
-
// // 由于上传失败,inputFilesList 应该没有变化
|
|
104
|
-
// expect(result.current.inputFilesList).toEqual([]);
|
|
105
|
-
//
|
|
106
|
-
// // 确保错误提示被调用
|
|
107
|
-
// expect(notification.error).toHaveBeenCalled();
|
|
108
|
-
// });
|
|
109
|
-
//
|
|
110
|
-
// it('uploadFile should upload the file and update inputFilesList', async () => {
|
|
111
|
-
// const { result } = renderHook(() => useStore());
|
|
112
|
-
// const testFile = new File(['content'], 'test.png', { type: 'image/png' });
|
|
113
|
-
//
|
|
114
|
-
// // 模拟 fileService.uploadFile 返回的数据
|
|
115
|
-
// const uploadedFileData = {
|
|
116
|
-
// createdAt: testFile.lastModified,
|
|
117
|
-
// data: await testFile.arrayBuffer(),
|
|
118
|
-
// fileType: testFile.type,
|
|
119
|
-
// name: testFile.name,
|
|
120
|
-
// saveMode: 'local',
|
|
121
|
-
// size: testFile.size,
|
|
122
|
-
// };
|
|
123
|
-
//
|
|
124
|
-
// // Mock the fileService.uploadFile to resolve with uploadedFileData
|
|
125
|
-
// vi.spyOn(uploadService, 'uploadFile').mockResolvedValue(uploadedFileData as DB_File);
|
|
126
|
-
// vi.spyOn(fileService, 'createFile').mockResolvedValue({ id: 'new-file-id', url: '' });
|
|
127
|
-
//
|
|
128
|
-
// await act(async () => {
|
|
129
|
-
// await result.current.uploadFile(testFile);
|
|
130
|
-
// });
|
|
131
|
-
//
|
|
132
|
-
// expect(fileService.createFile).toHaveBeenCalledWith({
|
|
133
|
-
// createdAt: testFile.lastModified,
|
|
134
|
-
// data: await testFile.arrayBuffer(),
|
|
135
|
-
// fileType: testFile.type,
|
|
136
|
-
// name: testFile.name,
|
|
137
|
-
// saveMode: 'local',
|
|
138
|
-
// size: testFile.size,
|
|
139
|
-
// });
|
|
140
|
-
// expect(result.current.inputFilesList).toContain('new-file-id');
|
|
141
|
-
// });
|
|
142
|
-
// });
|
|
143
54
|
});
|
package/src/styles/global.ts
CHANGED
|
@@ -59,4 +59,10 @@ export default ({ token }: { prefixCls: string; token: Theme }) => css`
|
|
|
59
59
|
.${CLASSNAMES.DropdownMenuTrigger}[data-popup-open]:not([data-no-highlight]) {
|
|
60
60
|
background: ${token.colorFillTertiary};
|
|
61
61
|
}
|
|
62
|
+
|
|
63
|
+
.ant-form-item-control:has([role='combobox'][aria-controls^='base-ui-']),
|
|
64
|
+
.ant-form-item-control:has([role='combobox'][aria-haspopup='listbox']) {
|
|
65
|
+
width: min(70%, 800px);
|
|
66
|
+
min-width: min(70%, 800px) !important;
|
|
67
|
+
}
|
|
62
68
|
`;
|
package/src/utils/router.tsx
CHANGED
|
@@ -145,13 +145,7 @@ export interface RouteConfig {
|
|
|
145
145
|
*/
|
|
146
146
|
export function renderRoutes(routes: RouteConfig[]): ReactElement[] {
|
|
147
147
|
return routes.map((route, index) => {
|
|
148
|
-
const { path, element, children, index: isIndex
|
|
149
|
-
|
|
150
|
-
// Handle redirect loaders (convert to Navigate element)
|
|
151
|
-
if (loader && !element && isIndex) {
|
|
152
|
-
// Check if loader is a redirect by inspecting it
|
|
153
|
-
// For now, we'll handle this case in the config itself
|
|
154
|
-
}
|
|
148
|
+
const { path, element, children, index: isIndex } = route;
|
|
155
149
|
|
|
156
150
|
const childRoutes = children ? renderRoutes(children) : undefined;
|
|
157
151
|
|