@lobehub/lobehub 2.1.2 → 2.1.4
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/.env.example +4 -6
- package/.env.example.development +0 -3
- package/.github/workflows/release-desktop-stable.yml +1 -1
- package/CHANGELOG.md +59 -0
- package/Dockerfile +6 -4
- package/README.md +2 -3
- package/README.zh-CN.md +2 -3
- package/changelog/v2.json +14 -0
- package/docker-compose/deploy/.env.example +3 -1
- package/docker-compose/deploy/.env.zh-CN.example +4 -1
- package/docker-compose/local/.env.example +0 -1
- package/docker-compose/local/.env.zh-CN.example +0 -1
- package/docker-compose/local/grafana/.env.example +0 -1
- package/docker-compose/local/grafana/.env.zh-CN.example +0 -1
- package/docker-compose/local/logto/docker-compose.yml +0 -1
- package/docker-compose/local/zitadel/.env.example +1 -2
- package/docker-compose/local/zitadel/.env.zh-CN.example +1 -2
- package/docker-compose/production/grafana/.env.example +0 -1
- package/docker-compose/production/grafana/.env.zh-CN.example +0 -1
- package/docker-compose/production/logto/.env.example +0 -2
- package/docker-compose/production/logto/.env.zh-CN.example +0 -2
- package/docker-compose/production/zitadel/.env.example +0 -2
- package/docker-compose/production/zitadel/.env.zh-CN.example +0 -2
- package/docker-compose/setup.sh +16 -2
- package/docs/development/basic/folder-structure.mdx +23 -14
- package/docs/development/basic/folder-structure.zh-CN.mdx +23 -14
- package/docs/development/basic/work-with-server-side-database.mdx +0 -1
- package/docs/development/basic/work-with-server-side-database.zh-CN.mdx +0 -1
- package/docs/development/start.mdx +19 -12
- package/docs/development/start.zh-CN.mdx +19 -12
- package/docs/self-hosting/advanced/s3/cloudflare-r2.mdx +0 -5
- package/docs/self-hosting/advanced/s3/cloudflare-r2.zh-CN.mdx +0 -5
- package/docs/self-hosting/advanced/s3/rustfs.mdx +0 -2
- package/docs/self-hosting/advanced/s3/rustfs.zh-CN.mdx +0 -2
- package/docs/self-hosting/advanced/s3/tencent-cloud.mdx +0 -1
- package/docs/self-hosting/advanced/s3/tencent-cloud.zh-CN.mdx +0 -2
- package/docs/self-hosting/advanced/s3.mdx +0 -9
- package/docs/self-hosting/advanced/s3.zh-CN.mdx +0 -8
- package/docs/self-hosting/auth/providers/password.mdx +112 -0
- package/docs/self-hosting/auth/providers/password.zh-CN.mdx +103 -0
- package/docs/self-hosting/auth.mdx +12 -0
- package/docs/self-hosting/auth.zh-CN.mdx +12 -0
- package/docs/self-hosting/environment-variables/auth.mdx +7 -0
- package/docs/self-hosting/environment-variables/auth.zh-CN.mdx +7 -0
- package/docs/self-hosting/environment-variables/basic.mdx +0 -7
- package/docs/self-hosting/environment-variables/basic.zh-CN.mdx +0 -7
- package/docs/self-hosting/environment-variables/s3.mdx +0 -7
- package/docs/self-hosting/environment-variables/s3.zh-CN.mdx +0 -7
- package/docs/self-hosting/examples/azure-openai.mdx +0 -1
- package/docs/self-hosting/examples/azure-openai.zh-CN.mdx +0 -1
- package/docs/self-hosting/platform/docker-compose.mdx +0 -1
- package/docs/self-hosting/platform/docker-compose.zh-CN.mdx +0 -1
- package/docs/self-hosting/platform/docker.mdx +5 -3
- package/docs/self-hosting/platform/docker.zh-CN.mdx +5 -4
- package/docs/self-hosting/platform/dokploy.mdx +0 -2
- package/docs/self-hosting/platform/dokploy.zh-CN.mdx +0 -2
- package/docs/self-hosting/platform/vercel.mdx +0 -7
- package/docs/self-hosting/platform/vercel.zh-CN.mdx +0 -7
- package/e2e/src/steps/home/sidebarAgent.steps.ts +56 -24
- package/locales/ar/authError.json +1 -0
- package/locales/ar/models.json +25 -22
- package/locales/ar/providers.json +0 -1
- package/locales/ar/setting.json +16 -0
- package/locales/bg-BG/authError.json +1 -0
- package/locales/bg-BG/models.json +18 -21
- package/locales/bg-BG/providers.json +0 -1
- package/locales/bg-BG/setting.json +16 -0
- package/locales/de-DE/authError.json +1 -0
- package/locales/de-DE/models.json +20 -20
- package/locales/de-DE/providers.json +0 -1
- package/locales/de-DE/setting.json +16 -0
- package/locales/en-US/auth.json +1 -0
- package/locales/en-US/models.json +22 -22
- package/locales/en-US/providers.json +0 -1
- package/locales/es-ES/authError.json +1 -0
- package/locales/es-ES/models.json +84 -20
- package/locales/es-ES/providers.json +0 -1
- package/locales/es-ES/setting.json +16 -0
- package/locales/fa-IR/authError.json +1 -0
- package/locales/fa-IR/models.json +43 -20
- package/locales/fa-IR/providers.json +0 -1
- package/locales/fa-IR/setting.json +16 -0
- package/locales/fr-FR/authError.json +1 -0
- package/locales/fr-FR/models.json +19 -21
- package/locales/fr-FR/providers.json +0 -1
- package/locales/fr-FR/setting.json +16 -0
- package/locales/it-IT/authError.json +1 -0
- package/locales/it-IT/models.json +17 -19
- package/locales/it-IT/providers.json +0 -1
- package/locales/it-IT/setting.json +16 -0
- package/locales/ja-JP/authError.json +1 -0
- package/locales/ja-JP/models.json +43 -22
- package/locales/ja-JP/providers.json +0 -1
- package/locales/ja-JP/setting.json +16 -0
- package/locales/ko-KR/authError.json +1 -0
- package/locales/ko-KR/models.json +41 -20
- package/locales/ko-KR/providers.json +0 -1
- package/locales/ko-KR/setting.json +16 -0
- package/locales/nl-NL/authError.json +1 -0
- package/locales/nl-NL/models.json +48 -20
- package/locales/nl-NL/providers.json +0 -1
- package/locales/nl-NL/setting.json +16 -0
- package/locales/pl-PL/authError.json +1 -0
- package/locales/pl-PL/models.json +19 -22
- package/locales/pl-PL/providers.json +0 -1
- package/locales/pl-PL/setting.json +16 -0
- package/locales/pt-BR/authError.json +1 -0
- package/locales/pt-BR/models.json +21 -21
- package/locales/pt-BR/providers.json +0 -1
- package/locales/pt-BR/setting.json +16 -0
- package/locales/ru-RU/authError.json +1 -0
- package/locales/ru-RU/models.json +23 -20
- package/locales/ru-RU/providers.json +0 -1
- package/locales/ru-RU/setting.json +16 -0
- package/locales/tr-TR/authError.json +1 -0
- package/locales/tr-TR/models.json +37 -20
- package/locales/tr-TR/providers.json +0 -1
- package/locales/tr-TR/setting.json +16 -0
- package/locales/vi-VN/authError.json +1 -0
- package/locales/vi-VN/models.json +15 -19
- package/locales/vi-VN/providers.json +0 -1
- package/locales/vi-VN/setting.json +16 -0
- package/locales/zh-CN/auth.json +1 -0
- package/locales/zh-CN/models.json +20 -20
- package/locales/zh-CN/providers.json +0 -1
- package/locales/zh-TW/authError.json +1 -0
- package/locales/zh-TW/models.json +20 -20
- package/locales/zh-TW/providers.json +0 -1
- package/locales/zh-TW/setting.json +16 -0
- package/netlify.toml +0 -1
- package/package.json +1 -1
- package/packages/model-bank/src/aiModels/google.ts +0 -19
- package/packages/model-bank/src/aiModels/moonshot.ts +56 -5
- package/packages/model-bank/src/aiModels/ollamacloud.ts +14 -0
- package/packages/model-bank/src/aiModels/openrouter.ts +0 -14
- package/packages/model-bank/src/aiModels/qwen.ts +105 -4
- package/packages/model-bank/src/aiModels/siliconcloud.ts +39 -0
- package/packages/model-bank/src/aiModels/wenxin.ts +0 -99
- package/packages/model-runtime/src/core/contextBuilders/openai.test.ts +24 -0
- package/packages/model-runtime/src/core/contextBuilders/openai.ts +22 -5
- package/packages/model-runtime/src/core/openaiCompatibleFactory/index.ts +10 -3
- package/packages/model-runtime/src/core/streams/google/google-ai.test.ts +54 -13
- package/packages/model-runtime/src/core/streams/google/index.ts +1 -4
- package/packages/model-runtime/src/providers/moonshot/index.ts +24 -2
- package/packages/model-runtime/src/providers/qwen/index.ts +16 -15
- package/packages/types/src/serverConfig.ts +1 -0
- package/src/app/[variants]/(auth)/signin/SignInEmailStep.tsx +56 -49
- package/src/app/[variants]/(auth)/signin/page.tsx +2 -0
- package/src/app/[variants]/(auth)/signin/useSignIn.ts +2 -0
- package/src/app/[variants]/(auth)/signup/[[...signup]]/page.tsx +7 -0
- package/src/envs/app.ts +0 -2
- package/src/envs/auth.ts +3 -0
- package/src/libs/better-auth/define-config.ts +1 -1
- package/src/libs/next/proxy/define-config.ts +0 -1
- package/src/locales/default/auth.ts +2 -0
- package/src/server/globalConfig/index.ts +1 -0
- package/src/server/routers/lambda/__tests__/integration/aiAgent/execAgent.integration.test.ts +3 -2
- package/src/store/chat/slices/topic/action.ts +1 -1
- package/src/store/electron/actions/settings.ts +7 -7
- package/src/store/electron/actions/sync.ts +11 -11
- package/src/store/global/actions/general.ts +12 -12
- package/src/store/global/initialState.ts +11 -11
- package/src/store/global/selectors/clientDB.ts +1 -1
- package/src/store/global/selectors/systemStatus.ts +1 -1
- package/src/store/image/slices/generationConfig/action.ts +12 -12
- package/src/store/image/utils/size.ts +11 -11
- package/src/store/library/slices/ragEval/actions/dataset.ts +1 -1
- package/src/store/serverConfig/selectors.ts +1 -0
- package/src/store/session/slices/session/initialState.ts +6 -6
- package/src/store/session/slices/session/reducers.ts +1 -1
- package/src/store/session/slices/sessionGroup/initialState.ts +2 -2
- package/src/store/tool/slices/customPlugin/action.ts +2 -2
- package/src/store/tool/slices/oldStore/action.ts +5 -5
- package/src/store/userMemory/slices/preference/action.ts +6 -6
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { redirect } from 'next/navigation';
|
|
2
|
+
|
|
3
|
+
import { authEnv } from '@/envs/auth';
|
|
1
4
|
import { metadataModule } from '@/server/metadata';
|
|
2
5
|
import { translation } from '@/server/translation';
|
|
3
6
|
import { type DynamicLayoutProps } from '@/types/next';
|
|
@@ -17,6 +20,10 @@ export const generateMetadata = async (props: DynamicLayoutProps) => {
|
|
|
17
20
|
};
|
|
18
21
|
|
|
19
22
|
const Page = () => {
|
|
23
|
+
if (authEnv.AUTH_DISABLE_EMAIL_PASSWORD) {
|
|
24
|
+
redirect('/signin');
|
|
25
|
+
}
|
|
26
|
+
|
|
20
27
|
return <BetterAuthSignUpForm />;
|
|
21
28
|
};
|
|
22
29
|
|
package/src/envs/app.ts
CHANGED
|
@@ -52,7 +52,6 @@ export const getAppConfig = () => {
|
|
|
52
52
|
INTERNAL_APP_URL: z.string().optional(),
|
|
53
53
|
VERCEL_EDGE_CONFIG: z.string().optional(),
|
|
54
54
|
MIDDLEWARE_REWRITE_THROUGH_LOCAL: z.boolean().optional(),
|
|
55
|
-
ENABLE_AUTH_PROTECTION: z.boolean().optional(),
|
|
56
55
|
|
|
57
56
|
CDN_USE_GLOBAL: z.boolean().optional(),
|
|
58
57
|
CUSTOM_FONT_FAMILY: z.string().optional(),
|
|
@@ -107,7 +106,6 @@ export const getAppConfig = () => {
|
|
|
107
106
|
APP_URL,
|
|
108
107
|
INTERNAL_APP_URL,
|
|
109
108
|
MIDDLEWARE_REWRITE_THROUGH_LOCAL: process.env.MIDDLEWARE_REWRITE_THROUGH_LOCAL === '1',
|
|
110
|
-
ENABLE_AUTH_PROTECTION: process.env.ENABLE_AUTH_PROTECTION === '1',
|
|
111
109
|
|
|
112
110
|
CUSTOM_FONT_FAMILY: process.env.CUSTOM_FONT_FAMILY,
|
|
113
111
|
CUSTOM_FONT_URL: process.env.CUSTOM_FONT_URL,
|
package/src/envs/auth.ts
CHANGED
|
@@ -13,6 +13,7 @@ declare global {
|
|
|
13
13
|
AUTH_SSO_PROVIDERS?: string;
|
|
14
14
|
AUTH_TRUSTED_ORIGINS?: string;
|
|
15
15
|
AUTH_ALLOWED_EMAILS?: string;
|
|
16
|
+
AUTH_DISABLE_EMAIL_PASSWORD?: string;
|
|
16
17
|
|
|
17
18
|
// ===== Auth Provider Credentials ===== //
|
|
18
19
|
AUTH_GOOGLE_ID?: string;
|
|
@@ -112,6 +113,7 @@ export const getAuthConfig = () => {
|
|
|
112
113
|
AUTH_EMAIL_VERIFICATION: z.boolean().optional().default(false),
|
|
113
114
|
AUTH_ENABLE_MAGIC_LINK: z.boolean().optional().default(false),
|
|
114
115
|
AUTH_ALLOWED_EMAILS: z.string().optional(),
|
|
116
|
+
AUTH_DISABLE_EMAIL_PASSWORD: z.boolean().optional().default(false),
|
|
115
117
|
|
|
116
118
|
AUTH_GOOGLE_ID: z.string().optional(),
|
|
117
119
|
AUTH_GOOGLE_SECRET: z.string().optional(),
|
|
@@ -199,6 +201,7 @@ export const getAuthConfig = () => {
|
|
|
199
201
|
AUTH_SSO_PROVIDERS: process.env.AUTH_SSO_PROVIDERS,
|
|
200
202
|
AUTH_TRUSTED_ORIGINS: process.env.AUTH_TRUSTED_ORIGINS,
|
|
201
203
|
AUTH_ALLOWED_EMAILS: process.env.AUTH_ALLOWED_EMAILS,
|
|
204
|
+
AUTH_DISABLE_EMAIL_PASSWORD: process.env.AUTH_DISABLE_EMAIL_PASSWORD === '1',
|
|
202
205
|
|
|
203
206
|
// Cognito provider specific env vars
|
|
204
207
|
AUTH_COGNITO_DOMAIN: process.env.AUTH_COGNITO_DOMAIN,
|
|
@@ -107,7 +107,7 @@ export function defineConfig(customOptions: CustomBetterAuthOptions) {
|
|
|
107
107
|
|
|
108
108
|
emailAndPassword: {
|
|
109
109
|
autoSignIn: true,
|
|
110
|
-
enabled:
|
|
110
|
+
enabled: !authEnv.AUTH_DISABLE_EMAIL_PASSWORD,
|
|
111
111
|
maxPasswordLength: 64,
|
|
112
112
|
minPasswordLength: 8,
|
|
113
113
|
requireEmailVerification: authEnv.AUTH_EMAIL_VERIFICATION,
|
|
@@ -102,6 +102,8 @@ export default {
|
|
|
102
102
|
'betterAuth.signin.socialError': 'Social sign in failed, please try again',
|
|
103
103
|
'betterAuth.signin.socialOnlyHint':
|
|
104
104
|
'This email was registered via a third-party social account. Sign in with that provider, or',
|
|
105
|
+
'betterAuth.signin.ssoOnlyNoProviders':
|
|
106
|
+
'Email registration is disabled and no SSO providers are configured. Please contact your administrator.',
|
|
105
107
|
'betterAuth.signin.submit': 'Sign In',
|
|
106
108
|
'betterAuth.signup.confirmPasswordPlaceholder': 'Confirm your password',
|
|
107
109
|
'betterAuth.signup.emailPlaceholder': 'Enter your email address',
|
|
@@ -74,6 +74,7 @@ export const getServerGlobalConfig = async () => {
|
|
|
74
74
|
defaultAgent: {
|
|
75
75
|
config: parseAgentConfig(DEFAULT_AGENT_CONFIG),
|
|
76
76
|
},
|
|
77
|
+
disableEmailPassword: authEnv.AUTH_DISABLE_EMAIL_PASSWORD,
|
|
77
78
|
enableBusinessFeatures: ENABLE_BUSINESS_FEATURES,
|
|
78
79
|
enableEmailVerification: authEnv.AUTH_EMAIL_VERIFICATION,
|
|
79
80
|
enableKlavis: !!klavisEnv.KLAVIS_API_KEY,
|
package/src/server/routers/lambda/__tests__/integration/aiAgent/execAgent.integration.test.ts
CHANGED
|
@@ -232,14 +232,15 @@ describe('execAgent', () => {
|
|
|
232
232
|
})
|
|
233
233
|
.returning();
|
|
234
234
|
|
|
235
|
-
const
|
|
235
|
+
const threadResult = (await serverDB
|
|
236
236
|
.insert(threads)
|
|
237
237
|
.values({
|
|
238
238
|
topicId: topic.id,
|
|
239
239
|
type: 'standalone',
|
|
240
240
|
userId,
|
|
241
241
|
})
|
|
242
|
-
.returning();
|
|
242
|
+
.returning()) as { id: string }[];
|
|
243
|
+
const thread = threadResult[0];
|
|
243
244
|
|
|
244
245
|
const caller = aiAgentRouter.createCaller(createTestContext());
|
|
245
246
|
|
|
@@ -9,7 +9,7 @@ import { desktopSettingsService } from '@/services/electron/settings';
|
|
|
9
9
|
import type { ElectronStore } from '../store';
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
|
-
*
|
|
12
|
+
* Settings actions
|
|
13
13
|
*/
|
|
14
14
|
export interface ElectronSettingsAction {
|
|
15
15
|
refreshDesktopHotkeys: () => Promise<void>;
|
|
@@ -39,29 +39,29 @@ export const settingsSlice: StateCreator<
|
|
|
39
39
|
|
|
40
40
|
setProxySettings: async (values) => {
|
|
41
41
|
try {
|
|
42
|
-
//
|
|
42
|
+
// Update settings
|
|
43
43
|
await desktopSettingsService.setSettings(values);
|
|
44
44
|
|
|
45
|
-
//
|
|
45
|
+
// Refresh state
|
|
46
46
|
await get().refreshProxySettings();
|
|
47
47
|
} catch (error) {
|
|
48
|
-
console.error('
|
|
48
|
+
console.error('Proxy settings update failed:', error);
|
|
49
49
|
}
|
|
50
50
|
},
|
|
51
51
|
|
|
52
52
|
updateDesktopHotkey: async (id, accelerator) => {
|
|
53
53
|
try {
|
|
54
|
-
//
|
|
54
|
+
// Update hotkey configuration
|
|
55
55
|
const result = await desktopSettingsService.updateDesktopHotkey(id, accelerator);
|
|
56
56
|
|
|
57
|
-
//
|
|
57
|
+
// If update successful, refresh state
|
|
58
58
|
if (result.success) {
|
|
59
59
|
await get().refreshDesktopHotkeys();
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
return result;
|
|
63
63
|
} catch (error) {
|
|
64
|
-
console.error('
|
|
64
|
+
console.error('Desktop hotkey update failed:', error);
|
|
65
65
|
return {
|
|
66
66
|
errorType: 'UNKNOWN' as const,
|
|
67
67
|
success: false,
|
|
@@ -10,7 +10,7 @@ import { initialState } from '../initialState';
|
|
|
10
10
|
import type { ElectronStore } from '../store';
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
|
-
*
|
|
13
|
+
* Remote server actions
|
|
14
14
|
*/
|
|
15
15
|
export interface ElectronRemoteServerAction {
|
|
16
16
|
clearRemoteServerSyncError: () => void;
|
|
@@ -39,28 +39,28 @@ export const remoteSyncSlice: StateCreator<
|
|
|
39
39
|
set({ isConnectingServer: true });
|
|
40
40
|
get().clearRemoteServerSyncError();
|
|
41
41
|
try {
|
|
42
|
-
//
|
|
42
|
+
// Get current configuration
|
|
43
43
|
const config = await remoteServerService.getRemoteServerConfig();
|
|
44
44
|
|
|
45
|
-
//
|
|
45
|
+
// If already active, need to clear first
|
|
46
46
|
if (!isEqual(config, values)) {
|
|
47
47
|
await remoteServerService.setRemoteServerConfig({ ...values, active: false });
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
//
|
|
50
|
+
// Request authorization
|
|
51
51
|
const result = await remoteServerService.requestAuthorization(values);
|
|
52
52
|
|
|
53
53
|
if (!result.success) {
|
|
54
|
-
console.error('
|
|
54
|
+
console.error('Authorization request failed:', result.error);
|
|
55
55
|
|
|
56
56
|
set({
|
|
57
57
|
remoteServerSyncError: { message: result.error, type: 'AUTH_ERROR' },
|
|
58
58
|
});
|
|
59
59
|
}
|
|
60
|
-
//
|
|
60
|
+
// Refresh state
|
|
61
61
|
await get().refreshServerConfig();
|
|
62
62
|
} catch (error) {
|
|
63
|
-
console.error('
|
|
63
|
+
console.error('Remote server configuration error:', error);
|
|
64
64
|
set({
|
|
65
65
|
remoteServerSyncError: { message: (error as Error).message, type: 'CONFIG_ERROR' },
|
|
66
66
|
});
|
|
@@ -74,12 +74,12 @@ export const remoteSyncSlice: StateCreator<
|
|
|
74
74
|
get().clearRemoteServerSyncError();
|
|
75
75
|
try {
|
|
76
76
|
await remoteServerService.setRemoteServerConfig({ active: false, storageMode: 'cloud' });
|
|
77
|
-
//
|
|
77
|
+
// Update form URL to empty
|
|
78
78
|
set({ dataSyncConfig: initialState.dataSyncConfig });
|
|
79
|
-
//
|
|
79
|
+
// Refresh state
|
|
80
80
|
await get().refreshServerConfig();
|
|
81
81
|
} catch (error) {
|
|
82
|
-
console.error('
|
|
82
|
+
console.error('Disconnect failed:', error);
|
|
83
83
|
set({
|
|
84
84
|
remoteServerSyncError: { message: (error as Error).message, type: 'DISCONNECT_ERROR' },
|
|
85
85
|
});
|
|
@@ -110,7 +110,7 @@ export const remoteSyncSlice: StateCreator<
|
|
|
110
110
|
try {
|
|
111
111
|
return await remoteServerService.getRemoteServerConfig();
|
|
112
112
|
} catch (error) {
|
|
113
|
-
console.error('
|
|
113
|
+
console.error('Failed to get remote server configuration:', error);
|
|
114
114
|
throw error;
|
|
115
115
|
}
|
|
116
116
|
},
|
|
@@ -188,18 +188,18 @@ export const generalActionSlice: StateCreator<
|
|
|
188
188
|
if (!clientVersion || !serverVersion) return;
|
|
189
189
|
|
|
190
190
|
const DIFF_THRESHOLD = 5;
|
|
191
|
-
//
|
|
192
|
-
//
|
|
193
|
-
// │
|
|
194
|
-
//
|
|
195
|
-
// │ 1.0.5 → 1.0.0 │ 5 │ ⚠️
|
|
196
|
-
//
|
|
197
|
-
// │ 1.1.0 → 1.0.5 │ 5 │ ⚠️
|
|
198
|
-
//
|
|
199
|
-
// │ 2.0.0 → 1.9.9 │ 91 │ ⚠️
|
|
200
|
-
//
|
|
201
|
-
// │ 1.0.4 → 1.0.0 │ 4 │ ✅
|
|
202
|
-
//
|
|
191
|
+
// Version difference calculation rules
|
|
192
|
+
// ┌─────────────────┬────────┬───────────┐
|
|
193
|
+
// │ Client → Server │ Diff │ Result │
|
|
194
|
+
// ├─────────────────┼────────┼───────────┤
|
|
195
|
+
// │ 1.0.5 → 1.0.0 │ 5 │ ⚠️ Too old│
|
|
196
|
+
// ├─────────────────┼────────┼───────────┤
|
|
197
|
+
// │ 1.1.0 → 1.0.5 │ 5 │ ⚠️ Too old│
|
|
198
|
+
// ├─────────────────┼────────┼───────────┤
|
|
199
|
+
// │ 2.0.0 → 1.9.9 │ 91 │ ⚠️ Too old│
|
|
200
|
+
// ├─────────────────┼────────┼───────────┤
|
|
201
|
+
// │ 1.0.4 → 1.0.0 │ 4 │ ✅ Normal │
|
|
202
|
+
// └─────────────────┴────────┴───────────┘
|
|
203
203
|
const versionDiff =
|
|
204
204
|
(clientVersion.major - serverVersion.major) * 100 +
|
|
205
205
|
(clientVersion.minor - serverVersion.minor) * 10 +
|
|
@@ -105,18 +105,18 @@ export interface SystemStatus {
|
|
|
105
105
|
imagePanelWidth: number;
|
|
106
106
|
imageTopicPanelWidth?: number;
|
|
107
107
|
/**
|
|
108
|
-
*
|
|
108
|
+
* Do not enable PGLite on app initialization, only enable when user manually turns it on
|
|
109
109
|
*/
|
|
110
110
|
isEnablePglite?: boolean;
|
|
111
111
|
isShowCredit?: boolean;
|
|
112
112
|
knowledgeBaseModalViewMode?: 'list' | 'masonry';
|
|
113
113
|
language?: LocaleMode;
|
|
114
114
|
/**
|
|
115
|
-
*
|
|
115
|
+
* Remember user's last selected image generation model
|
|
116
116
|
*/
|
|
117
117
|
lastSelectedImageModel?: string;
|
|
118
118
|
/**
|
|
119
|
-
*
|
|
119
|
+
* Remember user's last selected image generation provider
|
|
120
120
|
*/
|
|
121
121
|
lastSelectedImageProvider?: string;
|
|
122
122
|
latestChangelogId?: string;
|
|
@@ -124,11 +124,11 @@ export interface SystemStatus {
|
|
|
124
124
|
mobileShowPortal?: boolean;
|
|
125
125
|
mobileShowTopic?: boolean;
|
|
126
126
|
/**
|
|
127
|
-
* ModelSwitchPanel
|
|
127
|
+
* ModelSwitchPanel grouping mode
|
|
128
128
|
*/
|
|
129
129
|
modelSwitchPanelGroupMode?: 'byModel' | 'byProvider';
|
|
130
130
|
/**
|
|
131
|
-
* ModelSwitchPanel
|
|
131
|
+
* ModelSwitchPanel width
|
|
132
132
|
*/
|
|
133
133
|
modelSwitchPanelWidth?: number;
|
|
134
134
|
noWideScreen?: boolean;
|
|
@@ -157,7 +157,7 @@ export interface SystemStatus {
|
|
|
157
157
|
showSystemRole?: boolean;
|
|
158
158
|
systemRoleExpandedMap: Record<string, boolean>;
|
|
159
159
|
/**
|
|
160
|
-
*
|
|
160
|
+
* Whether to display tokens in short format
|
|
161
161
|
*/
|
|
162
162
|
tokenDisplayFormatShort?: boolean;
|
|
163
163
|
/**
|
|
@@ -177,21 +177,21 @@ export interface GlobalState {
|
|
|
177
177
|
|
|
178
178
|
initClientDBProcess?: { costTime?: number; phase: 'wasm' | 'dependencies'; progress: number };
|
|
179
179
|
/**
|
|
180
|
-
*
|
|
181
|
-
*
|
|
180
|
+
* Client database initialization state
|
|
181
|
+
* Idle on startup, Ready when complete, Error on failure
|
|
182
182
|
*/
|
|
183
183
|
initClientDBStage: DatabaseLoadingState;
|
|
184
184
|
isMobile?: boolean;
|
|
185
185
|
/**
|
|
186
|
-
*
|
|
187
|
-
*
|
|
186
|
+
* Server version is too old, does not support /api/version endpoint
|
|
187
|
+
* Need to prompt user to update server
|
|
188
188
|
*/
|
|
189
189
|
isServerVersionOutdated?: boolean;
|
|
190
190
|
isStatusInit?: boolean;
|
|
191
191
|
latestVersion?: string;
|
|
192
192
|
navigate?: NavigateFunction;
|
|
193
193
|
/**
|
|
194
|
-
*
|
|
194
|
+
* Server version number, used to detect client-server version consistency
|
|
195
195
|
*/
|
|
196
196
|
serverVersion?: string;
|
|
197
197
|
sidebarKey: SidebarTabKey;
|
|
@@ -51,7 +51,7 @@ const getAgentSystemRoleExpanded =
|
|
|
51
51
|
(agentId: string) =>
|
|
52
52
|
(s: GlobalState): boolean => {
|
|
53
53
|
const map = s.status.systemRoleExpandedMap || {};
|
|
54
|
-
return map[agentId] === true; //
|
|
54
|
+
return map[agentId] === true; // System role is collapsed by default
|
|
55
55
|
};
|
|
56
56
|
|
|
57
57
|
const disabledModelProvidersSortType = (s: GlobalState) =>
|
|
@@ -40,7 +40,7 @@ export interface GenerationConfigAction {
|
|
|
40
40
|
toggleAspectRatioLock(): void;
|
|
41
41
|
setAspectRatio(aspectRatio: string): void;
|
|
42
42
|
|
|
43
|
-
//
|
|
43
|
+
// Initialization related methods
|
|
44
44
|
_initializeDefaultImageConfig(): void;
|
|
45
45
|
initializeImageConfig(
|
|
46
46
|
isLogin?: boolean,
|
|
@@ -185,12 +185,12 @@ export const createGenerationConfigSlice: StateCreator<
|
|
|
185
185
|
} = state;
|
|
186
186
|
const newLockState = !isAspectRatioLocked;
|
|
187
187
|
|
|
188
|
-
//
|
|
188
|
+
// If transitioning from unlocked to locked and there's an active aspect ratio, adjust dimensions immediately
|
|
189
189
|
if (newLockState && activeAspectRatio && parameters && parametersSchema) {
|
|
190
190
|
const currentWidth = parameters.width;
|
|
191
191
|
const currentHeight = parameters.height;
|
|
192
192
|
|
|
193
|
-
//
|
|
193
|
+
// Only adjust when both width and height exist
|
|
194
194
|
if (
|
|
195
195
|
typeof currentWidth === 'number' &&
|
|
196
196
|
typeof currentHeight === 'number' &&
|
|
@@ -200,9 +200,9 @@ export const createGenerationConfigSlice: StateCreator<
|
|
|
200
200
|
const targetRatio = parseRatio(activeAspectRatio);
|
|
201
201
|
const currentRatio = currentWidth / currentHeight;
|
|
202
202
|
|
|
203
|
-
//
|
|
203
|
+
// If current ratio doesn't match target ratio, adjustment is needed
|
|
204
204
|
if (Math.abs(currentRatio - targetRatio) > 0.01) {
|
|
205
|
-
//
|
|
205
|
+
// Allow small margin of error
|
|
206
206
|
const widthSchema = parametersSchema.width;
|
|
207
207
|
const heightSchema = parametersSchema.height;
|
|
208
208
|
|
|
@@ -214,19 +214,19 @@ export const createGenerationConfigSlice: StateCreator<
|
|
|
214
214
|
typeof heightSchema.max === 'number' &&
|
|
215
215
|
typeof heightSchema.min === 'number'
|
|
216
216
|
) {
|
|
217
|
-
//
|
|
217
|
+
// Prioritize keeping width, adjust height
|
|
218
218
|
let newWidth = currentWidth;
|
|
219
219
|
let newHeight = Math.round(currentWidth / targetRatio);
|
|
220
220
|
|
|
221
|
-
//
|
|
221
|
+
// If calculated height is out of range, switch to keeping height and adjust width
|
|
222
222
|
if (newHeight > heightSchema.max || newHeight < heightSchema.min) {
|
|
223
223
|
newHeight = currentHeight;
|
|
224
224
|
newWidth = Math.round(currentHeight * targetRatio);
|
|
225
225
|
|
|
226
|
-
//
|
|
226
|
+
// Ensure width is also within range
|
|
227
227
|
newWidth = Math.max(Math.min(newWidth, widthSchema.max), widthSchema.min);
|
|
228
228
|
} else {
|
|
229
|
-
//
|
|
229
|
+
// Ensure height is within range
|
|
230
230
|
newHeight = Math.max(Math.min(newHeight, heightSchema.max), heightSchema.min);
|
|
231
231
|
}
|
|
232
232
|
|
|
@@ -253,7 +253,7 @@ export const createGenerationConfigSlice: StateCreator<
|
|
|
253
253
|
const defaultValues = extractDefaultValues(parametersSchema);
|
|
254
254
|
const newParams = { ...parameters };
|
|
255
255
|
|
|
256
|
-
//
|
|
256
|
+
// If model supports width/height, calculate new dimensions
|
|
257
257
|
if (
|
|
258
258
|
parametersSchema?.width &&
|
|
259
259
|
parametersSchema?.height &&
|
|
@@ -266,7 +266,7 @@ export const createGenerationConfigSlice: StateCreator<
|
|
|
266
266
|
newParams.height = height;
|
|
267
267
|
}
|
|
268
268
|
|
|
269
|
-
//
|
|
269
|
+
// If model itself supports aspectRatio, update it
|
|
270
270
|
if (parametersSchema?.aspectRatio) {
|
|
271
271
|
newParams.aspectRatio = aspectRatio;
|
|
272
272
|
}
|
|
@@ -297,7 +297,7 @@ export const createGenerationConfigSlice: StateCreator<
|
|
|
297
297
|
`setModelAndProviderOnSelect/${model}/${provider}`,
|
|
298
298
|
);
|
|
299
299
|
|
|
300
|
-
//
|
|
300
|
+
// Only remember last selection for logged-in users, consistent with recovery strategy
|
|
301
301
|
const isLogin = authSelectors.isLogin(useUserStore.getState());
|
|
302
302
|
if (isLogin) {
|
|
303
303
|
useGlobalStore.getState().updateSystemStatus({
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* @param ratio -
|
|
4
|
-
* @returns
|
|
2
|
+
* Parse ratio string, e.g., "16:9" -> 1.777
|
|
3
|
+
* @param ratio - Ratio string in "width:height" format
|
|
4
|
+
* @returns Ratio value, returns 1:1 ratio on error
|
|
5
5
|
*/
|
|
6
6
|
export function parseRatio(ratio: string): number {
|
|
7
7
|
if (!ratio || typeof ratio !== 'string') return 1;
|
|
@@ -21,14 +21,14 @@ export function parseRatio(ratio: string): number {
|
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
/**
|
|
24
|
-
*
|
|
25
|
-
* @param ratio -
|
|
26
|
-
* @param defaultWidth -
|
|
27
|
-
* @param defaultHeight -
|
|
28
|
-
* @returns
|
|
24
|
+
* Calculate the most appropriate size based on target ratio and default dimensions
|
|
25
|
+
* @param ratio - Target aspect ratio
|
|
26
|
+
* @param defaultWidth - Default width
|
|
27
|
+
* @param defaultHeight - Default height
|
|
28
|
+
* @returns Calculated size object
|
|
29
29
|
*/
|
|
30
30
|
export function adaptSizeToRatio(ratio: number, defaultWidth: number, defaultHeight: number) {
|
|
31
|
-
//
|
|
31
|
+
// Validate input parameters
|
|
32
32
|
if (!Number.isFinite(ratio) || ratio <= 0) {
|
|
33
33
|
throw new Error('Invalid ratio: must be a positive finite number');
|
|
34
34
|
}
|
|
@@ -42,10 +42,10 @@ export function adaptSizeToRatio(ratio: number, defaultWidth: number, defaultHei
|
|
|
42
42
|
const currentRatio = defaultWidth / defaultHeight;
|
|
43
43
|
|
|
44
44
|
if (ratio > currentRatio) {
|
|
45
|
-
//
|
|
45
|
+
// Target ratio is wider, keep width and adjust height
|
|
46
46
|
return { width: defaultWidth, height: Math.round(defaultWidth / ratio) };
|
|
47
47
|
} else {
|
|
48
|
-
//
|
|
48
|
+
// Target ratio is taller, keep height and adjust width
|
|
49
49
|
return { width: Math.round(defaultHeight * ratio), height: defaultHeight };
|
|
50
50
|
}
|
|
51
51
|
}
|
|
@@ -42,7 +42,7 @@ export const createRagEvalDatasetSlice: StateCreator<
|
|
|
42
42
|
const fileType = file.name.split('.').pop();
|
|
43
43
|
|
|
44
44
|
if (fileType === 'jsonl') {
|
|
45
|
-
// jsonl
|
|
45
|
+
// jsonl file needs to be split into individual entries, then validated one by one
|
|
46
46
|
const jsonl = await file.text();
|
|
47
47
|
const { default: JSONL } = await import('jsonl-parse-stringify');
|
|
48
48
|
|
|
@@ -3,6 +3,7 @@ import { type ServerConfigStore } from './store';
|
|
|
3
3
|
export const featureFlagsSelectors = (s: ServerConfigStore) => s.featureFlags;
|
|
4
4
|
|
|
5
5
|
export const serverConfigSelectors = {
|
|
6
|
+
disableEmailPassword: (s: ServerConfigStore) => s.serverConfig.disableEmailPassword || false,
|
|
6
7
|
enableBusinessFeatures: (s: ServerConfigStore) => s.serverConfig.enableBusinessFeatures || false,
|
|
7
8
|
enableEmailVerification: (s: ServerConfigStore) =>
|
|
8
9
|
s.serverConfig.enableEmailVerification || false,
|
|
@@ -3,8 +3,8 @@ import { type LobeSessions } from '@/types/session';
|
|
|
3
3
|
export interface SessionState {
|
|
4
4
|
activeAgentId?: string;
|
|
5
5
|
/**
|
|
6
|
-
* @title
|
|
7
|
-
* @description
|
|
6
|
+
* @title Current active session
|
|
7
|
+
* @description The session currently being edited or viewed
|
|
8
8
|
*/
|
|
9
9
|
activeId: string;
|
|
10
10
|
/**
|
|
@@ -22,14 +22,14 @@ export interface SessionState {
|
|
|
22
22
|
pinnedSessions: LobeSessions;
|
|
23
23
|
searchKeywords: string;
|
|
24
24
|
/**
|
|
25
|
-
* @title
|
|
26
|
-
* @description
|
|
25
|
+
* @title Session ID being renamed
|
|
26
|
+
* @description Used to control the display state of the session rename modal
|
|
27
27
|
*/
|
|
28
28
|
sessionRenamingId: string | null;
|
|
29
29
|
sessionSearchKeywords?: string;
|
|
30
30
|
/**
|
|
31
|
-
* @title
|
|
32
|
-
* @description
|
|
31
|
+
* @title Session ID being updated
|
|
32
|
+
* @description Used to display loading state when session is being updated
|
|
33
33
|
*/
|
|
34
34
|
sessionUpdatingId: string | null;
|
|
35
35
|
/**
|
|
@@ -27,7 +27,7 @@ export const sessionsReducer = (state: LobeSessions, payload: SessionDispatch):
|
|
|
27
27
|
const { session } = payload;
|
|
28
28
|
if (!session) return;
|
|
29
29
|
|
|
30
|
-
// TODO:
|
|
30
|
+
// TODO: Migrate Date type in the future to remove this ignore
|
|
31
31
|
// @ts-ignore
|
|
32
32
|
draft.unshift({ ...session, createdAt: new Date(), updatedAt: new Date() });
|
|
33
33
|
});
|
|
@@ -4,8 +4,8 @@ export interface SessionGroupState {
|
|
|
4
4
|
customSessionGroups: CustomSessionGroup[];
|
|
5
5
|
sessionGroupRenamingId: string | null;
|
|
6
6
|
/**
|
|
7
|
-
* @title
|
|
8
|
-
* @description
|
|
7
|
+
* @title Group ID being updated
|
|
8
|
+
* @description Used to display loading state when group is being updated
|
|
9
9
|
*/
|
|
10
10
|
sessionGroupUpdatingId: string | null;
|
|
11
11
|
sessionGroups: LobeSessionGroups;
|
|
@@ -93,10 +93,10 @@ export const createCustomPluginSlice: StateCreator<
|
|
|
93
93
|
|
|
94
94
|
updateCustomPlugin: async (id, value) => {
|
|
95
95
|
const { reinstallCustomPlugin } = get();
|
|
96
|
-
// 1.
|
|
96
|
+
// 1. Update list item information
|
|
97
97
|
await pluginService.updatePlugin(id, value);
|
|
98
98
|
|
|
99
|
-
// 2.
|
|
99
|
+
// 2. Reinstall plugin
|
|
100
100
|
await reinstallCustomPlugin(id);
|
|
101
101
|
},
|
|
102
102
|
updateNewCustomPlugin: (newCustomPlugin) => {
|
|
@@ -148,7 +148,7 @@ export const createPluginStoreSlice: StateCreator<
|
|
|
148
148
|
loadMorePlugins: () => {
|
|
149
149
|
const { oldPluginItems, pluginTotalCount, currentPluginPage } = get();
|
|
150
150
|
|
|
151
|
-
//
|
|
151
|
+
// Check if there is more data to load
|
|
152
152
|
if (oldPluginItems.length < (pluginTotalCount || 0)) {
|
|
153
153
|
set(
|
|
154
154
|
produce((draft: PluginStoreState) => {
|
|
@@ -234,19 +234,19 @@ export const createPluginStoreSlice: StateCreator<
|
|
|
234
234
|
produce((draft: PluginStoreState) => {
|
|
235
235
|
draft.pluginSearchLoading = false;
|
|
236
236
|
|
|
237
|
-
//
|
|
237
|
+
// Set basic information
|
|
238
238
|
if (!draft.isPluginListInit) {
|
|
239
239
|
draft.activePluginIdentifier = data.items?.[0]?.identifier;
|
|
240
240
|
draft.isPluginListInit = true;
|
|
241
241
|
draft.pluginTotalCount = data.totalCount;
|
|
242
242
|
}
|
|
243
243
|
|
|
244
|
-
//
|
|
244
|
+
// Accumulate data logic
|
|
245
245
|
if (params.page === 1) {
|
|
246
|
-
//
|
|
246
|
+
// First page, set directly
|
|
247
247
|
draft.oldPluginItems = uniqBy(data.items, 'identifier');
|
|
248
248
|
} else {
|
|
249
|
-
//
|
|
249
|
+
// Subsequent pages, accumulate data
|
|
250
250
|
draft.oldPluginItems = uniqBy(
|
|
251
251
|
[...draft.oldPluginItems, ...data.items],
|
|
252
252
|
'identifier',
|