@lobehub/lobehub 2.0.0-next.15 → 2.0.0-next.17
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 +50 -0
- package/README.md +2 -45
- package/README.zh-CN.md +2 -45
- package/changelog/v1.json +18 -0
- package/docs/self-hosting/advanced/feature-flags.mdx +0 -1
- package/docs/self-hosting/advanced/feature-flags.zh-CN.mdx +0 -1
- package/e2e/src/features/discover/smoke.feature +34 -1
- package/e2e/src/steps/discover/smoke.steps.ts +116 -4
- package/package.json +1 -1
- package/packages/model-runtime/src/utils/googleErrorParser.test.ts +125 -0
- package/packages/model-runtime/src/utils/googleErrorParser.ts +103 -77
- package/packages/types/src/serverConfig.ts +2 -6
- package/src/app/[variants]/(auth)/signup/[[...signup]]/page.tsx +1 -8
- package/src/app/[variants]/(main)/(mobile)/me/(home)/features/UserBanner.tsx +3 -6
- package/src/app/[variants]/(main)/discover/(list)/features/Pagination.tsx +1 -0
- package/src/app/[variants]/(main)/discover/(list)/features/SortButton/index.tsx +1 -1
- package/src/app/[variants]/(main)/discover/(list)/mcp/features/List/Item.tsx +1 -0
- package/src/app/[variants]/(main)/discover/(list)/model/features/List/Item.tsx +1 -0
- package/src/app/[variants]/(main)/discover/(list)/provider/features/List/Item.tsx +1 -0
- package/src/app/[variants]/(main)/discover/components/CategoryMenu.tsx +9 -1
- package/src/app/[variants]/(main)/labs/components/LabCard.tsx +3 -1
- package/src/app/[variants]/(main)/settings/provider/detail/azure/index.tsx +5 -7
- package/src/components/InvalidAPIKey/APIKeyForm/Bedrock.tsx +8 -13
- package/src/config/featureFlags/schema.test.ts +0 -2
- package/src/config/featureFlags/schema.ts +0 -6
- package/src/config/modelProviders/ai21.ts +1 -16
- package/src/config/modelProviders/ai302.ts +1 -128
- package/src/config/modelProviders/ai360.ts +1 -32
- package/src/config/modelProviders/anthropic.ts +1 -71
- package/src/config/modelProviders/azure.ts +1 -51
- package/src/config/modelProviders/baichuan.ts +1 -57
- package/src/config/modelProviders/bedrock.ts +1 -276
- package/src/config/modelProviders/cloudflare.ts +1 -64
- package/src/config/modelProviders/deepseek.ts +1 -19
- package/src/config/modelProviders/fireworksai.ts +1 -174
- package/src/config/modelProviders/giteeai.ts +1 -135
- package/src/config/modelProviders/github.ts +1 -254
- package/src/config/modelProviders/google.ts +1 -130
- package/src/config/modelProviders/groq.ts +1 -119
- package/src/config/modelProviders/higress.ts +1 -1713
- package/src/config/modelProviders/huggingface.ts +1 -54
- package/src/config/modelProviders/hunyuan.ts +1 -83
- package/src/config/modelProviders/infiniai.ts +1 -74
- package/src/config/modelProviders/internlm.ts +1 -20
- package/src/config/modelProviders/mistral.ts +1 -95
- package/src/config/modelProviders/modelscope.ts +1 -27
- package/src/config/modelProviders/moonshot.ts +1 -29
- package/src/config/modelProviders/novita.ts +1 -105
- package/src/config/modelProviders/ollama.ts +1 -325
- package/src/config/modelProviders/openai.ts +1 -242
- package/src/config/modelProviders/openrouter.ts +1 -240
- package/src/config/modelProviders/perplexity.ts +1 -45
- package/src/config/modelProviders/ppio.ts +1 -152
- package/src/config/modelProviders/qiniu.ts +1 -18
- package/src/config/modelProviders/qwen.ts +1 -245
- package/src/config/modelProviders/search1api.ts +1 -34
- package/src/config/modelProviders/sensenova.ts +1 -69
- package/src/config/modelProviders/siliconcloud.ts +1 -417
- package/src/config/modelProviders/spark.ts +1 -59
- package/src/config/modelProviders/stepfun.ts +1 -98
- package/src/config/modelProviders/taichu.ts +1 -18
- package/src/config/modelProviders/togetherai.ts +1 -274
- package/src/config/modelProviders/upstage.ts +1 -28
- package/src/config/modelProviders/wenxin.ts +1 -140
- package/src/config/modelProviders/xai.ts +1 -38
- package/src/config/modelProviders/zeroone.ts +1 -81
- package/src/config/modelProviders/zhipu.ts +1 -108
- package/src/helpers/isCanUseFC.ts +0 -8
- package/src/hooks/useEnabledChatModels.ts +0 -8
- package/src/hooks/useModelContextWindowTokens.ts +0 -8
- package/src/hooks/useModelHasContextWindowToken.ts +1 -10
- package/src/hooks/useModelSupportFiles.ts +1 -11
- package/src/hooks/useModelSupportReasoning.ts +1 -11
- package/src/hooks/useModelSupportToolUse.ts +1 -11
- package/src/hooks/useModelSupportVision.ts +1 -11
- package/src/layout/AuthProvider/Clerk/index.tsx +2 -16
- package/src/server/globalConfig/index.ts +0 -23
- package/src/server/routers/lambda/config/__snapshots__/index.test.ts.snap +175 -12
- package/src/server/routers/lambda/config/index.test.ts +36 -28
- package/src/services/chat/chat.test.ts +12 -0
- package/src/services/chat/helper.ts +7 -31
- package/src/services/models.ts +2 -11
- package/src/store/chat/slices/aiChat/actions/generateAIChat.ts +41 -14
- package/src/store/global/store.ts +1 -7
- package/src/store/user/initialState.ts +1 -7
- package/src/store/user/selectors.ts +1 -5
- package/src/store/user/slices/common/action.ts +5 -4
- package/src/store/user/slices/settings/selectors/index.ts +1 -0
- package/src/store/user/slices/settings/selectors/keyVaults.ts +21 -0
- package/src/store/user/store.ts +0 -3
- package/src/tools/web-browsing/Render/Search/ConfigForm/Form.tsx +1 -1
- package/packages/utils/src/_deprecated/__snapshots__/parseModels.test.ts.snap +0 -104
- package/packages/utils/src/_deprecated/parseModels.test.ts +0 -287
- package/packages/utils/src/_deprecated/parseModels.ts +0 -165
- package/src/hooks/_header.ts +0 -23
- package/src/server/globalConfig/_deprecated.test.ts +0 -92
- package/src/server/globalConfig/_deprecated.ts +0 -41
- package/src/store/global/actions/clientDb.ts +0 -67
- package/src/store/user/slices/modelList/__snapshots__/action.test.ts.snap +0 -12
- package/src/store/user/slices/modelList/action.test.ts +0 -359
- package/src/store/user/slices/modelList/action.ts +0 -223
- package/src/store/user/slices/modelList/initialState.ts +0 -15
- package/src/store/user/slices/modelList/reducers/customModelCard.test.ts +0 -204
- package/src/store/user/slices/modelList/reducers/customModelCard.ts +0 -64
- package/src/store/user/slices/modelList/selectors/index.ts +0 -3
- package/src/store/user/slices/modelList/selectors/keyVaults.test.ts +0 -201
- package/src/store/user/slices/modelList/selectors/keyVaults.ts +0 -50
- package/src/store/user/slices/modelList/selectors/modelConfig.test.ts +0 -219
- package/src/store/user/slices/modelList/selectors/modelConfig.ts +0 -95
- package/src/store/user/slices/modelList/selectors/modelProvider.test.ts +0 -138
- package/src/store/user/slices/modelList/selectors/modelProvider.ts +0 -170
|
@@ -17,64 +17,81 @@ export interface GoogleChatError {
|
|
|
17
17
|
export type GoogleChatErrors = GoogleChatError[];
|
|
18
18
|
|
|
19
19
|
/**
|
|
20
|
-
*
|
|
21
|
-
* @param message -
|
|
22
|
-
* @returns
|
|
20
|
+
* Clean error message by removing formatting characters and extra spaces
|
|
21
|
+
* @param message - Original error message
|
|
22
|
+
* @returns Cleaned error message
|
|
23
23
|
*/
|
|
24
24
|
export function cleanErrorMessage(message: string): string {
|
|
25
25
|
return message
|
|
26
|
-
.replaceAll(/^\*\s*/g, '') //
|
|
27
|
-
.replaceAll('\\n', '\n') //
|
|
28
|
-
.replaceAll(/\n+/g, ' ') //
|
|
29
|
-
.trim(); //
|
|
26
|
+
.replaceAll(/^\*\s*/g, '') // Remove leading asterisks and spaces
|
|
27
|
+
.replaceAll('\\n', '\n') // Convert escaped newlines
|
|
28
|
+
.replaceAll(/\n+/g, ' ') // Replace multiple newlines with single space
|
|
29
|
+
.trim(); // Trim leading/trailing spaces
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
/**
|
|
33
|
-
*
|
|
34
|
-
* @param message -
|
|
35
|
-
* @returns
|
|
33
|
+
* Extract status code information from error message
|
|
34
|
+
* @param message - Error message
|
|
35
|
+
* @returns Extracted error details and prefix
|
|
36
36
|
*/
|
|
37
37
|
export function extractStatusCodeFromError(message: string): {
|
|
38
38
|
errorDetails: any;
|
|
39
39
|
prefix: string;
|
|
40
40
|
} {
|
|
41
|
-
//
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
const statusCode = statusCodeMatch ? parseInt(statusCodeMatch[1]) : null;
|
|
53
|
-
|
|
54
|
-
// 创建包含状态码和消息的JSON
|
|
55
|
-
const resultJson = {
|
|
56
|
-
message: messageContent,
|
|
57
|
-
statusCode: statusCode,
|
|
58
|
-
statusCodeText: statusCodeWithBrackets,
|
|
59
|
-
};
|
|
41
|
+
// Match status code pattern [number description text]
|
|
42
|
+
// Use string methods instead of regex to avoid ReDoS attacks
|
|
43
|
+
// We need to find a bracket that contains a status code (3-digit number followed by space and text)
|
|
44
|
+
|
|
45
|
+
let searchStart = 0;
|
|
46
|
+
// eslint-disable-next-line no-constant-condition
|
|
47
|
+
while (true) {
|
|
48
|
+
const openBracketIndex = message.indexOf('[', searchStart);
|
|
49
|
+
if (openBracketIndex === -1) {
|
|
50
|
+
return { errorDetails: null, prefix: message };
|
|
51
|
+
}
|
|
60
52
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
prefix:
|
|
64
|
-
}
|
|
65
|
-
}
|
|
53
|
+
const closeBracketIndex = message.indexOf(']', openBracketIndex);
|
|
54
|
+
if (closeBracketIndex === -1) {
|
|
55
|
+
return { errorDetails: null, prefix: message };
|
|
56
|
+
}
|
|
66
57
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
58
|
+
const bracketContent = message.slice(openBracketIndex + 1, closeBracketIndex).trim();
|
|
59
|
+
|
|
60
|
+
// Find the first space to separate status code from description
|
|
61
|
+
const spaceIndex = bracketContent.indexOf(' ');
|
|
62
|
+
if (spaceIndex !== -1) {
|
|
63
|
+
const statusCodeStr = bracketContent.slice(0, spaceIndex);
|
|
64
|
+
const statusCode = parseInt(statusCodeStr, 10);
|
|
65
|
+
|
|
66
|
+
// Validate that statusCode is a valid HTTP status code (3 digits)
|
|
67
|
+
if (!isNaN(statusCode) && statusCode >= 100 && statusCode < 600) {
|
|
68
|
+
const statusText = bracketContent.slice(spaceIndex + 1).trim();
|
|
69
|
+
const prefix = message.slice(0, openBracketIndex).trim();
|
|
70
|
+
const messageContent = message.slice(closeBracketIndex + 1).trim();
|
|
71
|
+
|
|
72
|
+
// Create JSON containing status code and message
|
|
73
|
+
const resultJson = {
|
|
74
|
+
message: messageContent,
|
|
75
|
+
statusCode: statusCode,
|
|
76
|
+
statusCodeText: `[${statusCode} ${statusText}]`,
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
return {
|
|
80
|
+
errorDetails: resultJson,
|
|
81
|
+
prefix: prefix,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Move to next bracket
|
|
87
|
+
searchStart = openBracketIndex + 1;
|
|
88
|
+
}
|
|
72
89
|
}
|
|
73
90
|
|
|
74
91
|
/**
|
|
75
|
-
*
|
|
76
|
-
* @param message -
|
|
77
|
-
* @returns
|
|
92
|
+
* Parse error message from Google AI API
|
|
93
|
+
* @param message - Original error message
|
|
94
|
+
* @returns Parsed error object and error type
|
|
78
95
|
*/
|
|
79
96
|
export function parseGoogleErrorMessage(message: string): ParsedError {
|
|
80
97
|
const defaultError = {
|
|
@@ -82,12 +99,12 @@ export function parseGoogleErrorMessage(message: string): ParsedError {
|
|
|
82
99
|
errorType: AgentRuntimeErrorType.ProviderBizError,
|
|
83
100
|
};
|
|
84
101
|
|
|
85
|
-
//
|
|
102
|
+
// Quick identification of special errors
|
|
86
103
|
if (message.includes('location is not supported')) {
|
|
87
104
|
return { error: { message }, errorType: AgentRuntimeErrorType.LocationNotSupportError };
|
|
88
105
|
}
|
|
89
106
|
|
|
90
|
-
//
|
|
107
|
+
// Unified error type determination function
|
|
91
108
|
const getErrorType = (code: number | null, message: string): ILobeAgentRuntimeErrorType => {
|
|
92
109
|
if (code === 400 && message.includes('API key not valid')) {
|
|
93
110
|
return AgentRuntimeErrorType.InvalidProviderAPIKey;
|
|
@@ -97,30 +114,30 @@ export function parseGoogleErrorMessage(message: string): ParsedError {
|
|
|
97
114
|
return AgentRuntimeErrorType.ProviderBizError;
|
|
98
115
|
};
|
|
99
116
|
|
|
100
|
-
//
|
|
117
|
+
// Recursively parse JSON, handling nested JSON strings
|
|
101
118
|
const parseJsonRecursively = (str: string, maxDepth: number = 5): any => {
|
|
102
119
|
if (maxDepth <= 0) return null;
|
|
103
120
|
|
|
104
121
|
try {
|
|
105
122
|
const parsed = JSON.parse(str);
|
|
106
123
|
|
|
107
|
-
//
|
|
124
|
+
// If parsed object contains error field
|
|
108
125
|
if (parsed && typeof parsed === 'object' && parsed.error) {
|
|
109
126
|
const errorInfo = parsed.error;
|
|
110
127
|
|
|
111
|
-
//
|
|
128
|
+
// Clean error message
|
|
112
129
|
if (typeof errorInfo.message === 'string') {
|
|
113
130
|
errorInfo.message = cleanErrorMessage(errorInfo.message);
|
|
114
131
|
|
|
115
|
-
//
|
|
132
|
+
// If error.message is still a JSON string, continue recursive parsing
|
|
116
133
|
try {
|
|
117
134
|
const nestedResult = parseJsonRecursively(errorInfo.message, maxDepth - 1);
|
|
118
|
-
//
|
|
135
|
+
// Only return deeper result if it contains an error object with code
|
|
119
136
|
if (nestedResult && nestedResult.error && nestedResult.error.code) {
|
|
120
137
|
return nestedResult;
|
|
121
138
|
}
|
|
122
139
|
} catch {
|
|
123
|
-
//
|
|
140
|
+
// If nested parsing fails, use current layer info
|
|
124
141
|
}
|
|
125
142
|
}
|
|
126
143
|
|
|
@@ -133,31 +150,40 @@ export function parseGoogleErrorMessage(message: string): ParsedError {
|
|
|
133
150
|
}
|
|
134
151
|
};
|
|
135
152
|
|
|
136
|
-
// 1.
|
|
137
|
-
const
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
const
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
const
|
|
145
|
-
const
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
error
|
|
151
|
-
|
|
152
|
-
message
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
153
|
+
// 1. Handle "got status: UNAVAILABLE. {JSON}" format
|
|
154
|
+
const statusPrefix = 'got status: ';
|
|
155
|
+
const statusPrefixIndex = message.indexOf(statusPrefix);
|
|
156
|
+
if (statusPrefixIndex !== -1) {
|
|
157
|
+
const afterPrefix = message.slice(statusPrefixIndex + statusPrefix.length);
|
|
158
|
+
const dotIndex = afterPrefix.indexOf('.');
|
|
159
|
+
if (dotIndex !== -1) {
|
|
160
|
+
const statusFromMessage = afterPrefix.slice(0, dotIndex).trim();
|
|
161
|
+
const afterDot = afterPrefix.slice(dotIndex + 1).trim();
|
|
162
|
+
const braceIndex = afterDot.indexOf('{');
|
|
163
|
+
if (braceIndex !== -1) {
|
|
164
|
+
const jsonPart = afterDot.slice(braceIndex);
|
|
165
|
+
|
|
166
|
+
const parsedError = parseJsonRecursively(jsonPart);
|
|
167
|
+
if (parsedError && parsedError.error) {
|
|
168
|
+
const errorInfo = parsedError.error;
|
|
169
|
+
const finalMessage = errorInfo.message || message;
|
|
170
|
+
const finalCode = errorInfo.code || null;
|
|
171
|
+
const finalStatus = errorInfo.status || statusFromMessage;
|
|
172
|
+
|
|
173
|
+
return {
|
|
174
|
+
error: {
|
|
175
|
+
code: finalCode,
|
|
176
|
+
message: finalMessage,
|
|
177
|
+
status: finalStatus,
|
|
178
|
+
},
|
|
179
|
+
errorType: getErrorType(finalCode, finalMessage),
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
}
|
|
157
183
|
}
|
|
158
184
|
}
|
|
159
185
|
|
|
160
|
-
// 2.
|
|
186
|
+
// 2. Try to parse entire message as JSON directly
|
|
161
187
|
const directParsed = parseJsonRecursively(message);
|
|
162
188
|
if (directParsed && directParsed.error) {
|
|
163
189
|
const errorInfo = directParsed.error;
|
|
@@ -175,7 +201,7 @@ export function parseGoogleErrorMessage(message: string): ParsedError {
|
|
|
175
201
|
};
|
|
176
202
|
}
|
|
177
203
|
|
|
178
|
-
// 3.
|
|
204
|
+
// 3. Handle nested JSON format, especially when message field contains JSON
|
|
179
205
|
try {
|
|
180
206
|
const firstLevelParsed = JSON.parse(message);
|
|
181
207
|
if (firstLevelParsed && firstLevelParsed.error && firstLevelParsed.error.message) {
|
|
@@ -197,10 +223,10 @@ export function parseGoogleErrorMessage(message: string): ParsedError {
|
|
|
197
223
|
}
|
|
198
224
|
}
|
|
199
225
|
} catch {
|
|
200
|
-
//
|
|
226
|
+
// Continue with other parsing methods
|
|
201
227
|
}
|
|
202
228
|
|
|
203
|
-
// 4.
|
|
229
|
+
// 4. Original array format parsing logic
|
|
204
230
|
const startIndex = message.lastIndexOf('[');
|
|
205
231
|
if (startIndex !== -1) {
|
|
206
232
|
try {
|
|
@@ -214,11 +240,11 @@ export function parseGoogleErrorMessage(message: string): ParsedError {
|
|
|
214
240
|
|
|
215
241
|
return { error: json, errorType: AgentRuntimeErrorType.ProviderBizError };
|
|
216
242
|
} catch {
|
|
217
|
-
//
|
|
243
|
+
// Ignore parsing errors
|
|
218
244
|
}
|
|
219
245
|
}
|
|
220
246
|
|
|
221
|
-
// 5.
|
|
247
|
+
// 5. Use status code extraction logic as last fallback
|
|
222
248
|
const errorObj = extractStatusCodeFromError(message);
|
|
223
249
|
if (errorObj.errorDetails) {
|
|
224
250
|
return { error: errorObj.errorDetails, errorType: AgentRuntimeErrorType.ProviderBizError };
|
|
@@ -15,9 +15,9 @@ export interface ServerModelProviderConfig {
|
|
|
15
15
|
enabledModels?: string[];
|
|
16
16
|
fetchOnClient?: boolean;
|
|
17
17
|
/**
|
|
18
|
-
* the model
|
|
18
|
+
* the model lists defined in server
|
|
19
19
|
*/
|
|
20
|
-
|
|
20
|
+
serverModelLists?: ChatModelCard[];
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
export type ServerLanguageModel = Partial<Record<GlobalLLMProviderKey, ServerModelProviderConfig>>;
|
|
@@ -32,10 +32,6 @@ export interface GlobalServerConfig {
|
|
|
32
32
|
*/
|
|
33
33
|
enabledOAuthSSO?: boolean;
|
|
34
34
|
image?: PartialDeep<UserImageConfig>;
|
|
35
|
-
/**
|
|
36
|
-
* @deprecated
|
|
37
|
-
*/
|
|
38
|
-
languageModel?: ServerLanguageModel;
|
|
39
35
|
oAuthSSOProviders?: string[];
|
|
40
36
|
systemAgent?: PartialDeep<UserSystemAgentConfig>;
|
|
41
37
|
telemetry: {
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { SignUp } from '@clerk/nextjs';
|
|
2
|
-
import { notFound
|
|
2
|
+
import { notFound } from 'next/navigation';
|
|
3
3
|
|
|
4
|
-
import { serverFeatureFlags } from '@/config/featureFlags';
|
|
5
4
|
import { enableClerk } from '@/const/auth';
|
|
6
5
|
import { metadataModule } from '@/server/metadata';
|
|
7
6
|
import { translation } from '@/server/translation';
|
|
@@ -21,12 +20,6 @@ export const generateMetadata = async (props: DynamicLayoutProps) => {
|
|
|
21
20
|
const Page = () => {
|
|
22
21
|
if (!enableClerk) return notFound();
|
|
23
22
|
|
|
24
|
-
const enableClerkSignUp = serverFeatureFlags().enableClerkSignUp;
|
|
25
|
-
|
|
26
|
-
if (!enableClerkSignUp) {
|
|
27
|
-
redirect('/login');
|
|
28
|
-
}
|
|
29
|
-
|
|
30
23
|
return <SignUp path="/signup" />;
|
|
31
24
|
};
|
|
32
25
|
|
|
@@ -6,7 +6,6 @@ import { memo } from 'react';
|
|
|
6
6
|
import { Flexbox } from 'react-layout-kit';
|
|
7
7
|
|
|
8
8
|
import { enableAuth, enableNextAuth } from '@/const/auth';
|
|
9
|
-
import { isDeprecatedEdition } from '@/const/version';
|
|
10
9
|
import DataStatistics from '@/features/User/DataStatistics';
|
|
11
10
|
import UserInfo from '@/features/User/UserInfo';
|
|
12
11
|
import UserLoginOrSignup from '@/features/User/UserLoginOrSignup/Community';
|
|
@@ -25,11 +24,9 @@ const UserBanner = memo(() => {
|
|
|
25
24
|
<Link href={'/profile'} style={{ color: 'inherit' }}>
|
|
26
25
|
<UserInfo />
|
|
27
26
|
</Link>
|
|
28
|
-
{
|
|
29
|
-
<
|
|
30
|
-
|
|
31
|
-
</Link>
|
|
32
|
-
)}
|
|
27
|
+
<Link href={'/profile/stats'} style={{ color: 'inherit' }}>
|
|
28
|
+
<DataStatistics paddingInline={12} />
|
|
29
|
+
</Link>
|
|
33
30
|
</>
|
|
34
31
|
) : (
|
|
35
32
|
<UserLoginOrSignup
|
|
@@ -52,6 +52,7 @@ const Pagination = memo<PaginationProps>(({ tab, currentPage, total, pageSize })
|
|
|
52
52
|
<Page
|
|
53
53
|
className={styles.page}
|
|
54
54
|
current={page ? Number(page) : currentPage}
|
|
55
|
+
data-testid="pagination"
|
|
55
56
|
onChange={handlePageChange}
|
|
56
57
|
pageSize={pageSize}
|
|
57
58
|
showSizeChanger={false}
|
|
@@ -174,7 +174,7 @@ const SortButton = memo(() => {
|
|
|
174
174
|
}}
|
|
175
175
|
trigger={['click', 'hover']}
|
|
176
176
|
>
|
|
177
|
-
<Button icon={<Icon icon={ArrowDownWideNarrow} />} type={'text'}>
|
|
177
|
+
<Button data-testid="sort-dropdown" icon={<Icon icon={ArrowDownWideNarrow} />} type={'text'}>
|
|
178
178
|
{activeItem.label}
|
|
179
179
|
<Icon icon={ChevronDown} />
|
|
180
180
|
</Button>
|
|
@@ -31,7 +31,15 @@ const useStyles = createStyles(({ css, prefixCls }) => {
|
|
|
31
31
|
const CategoryMenu = memo<MenuProps>(({ style, ...rest }) => {
|
|
32
32
|
const { styles } = useStyles();
|
|
33
33
|
|
|
34
|
-
return
|
|
34
|
+
return (
|
|
35
|
+
<Menu
|
|
36
|
+
className={styles.menu}
|
|
37
|
+
data-testid="category-menu"
|
|
38
|
+
mode="inline"
|
|
39
|
+
style={style}
|
|
40
|
+
{...rest}
|
|
41
|
+
/>
|
|
42
|
+
);
|
|
35
43
|
});
|
|
36
44
|
|
|
37
45
|
export default CategoryMenu;
|
|
@@ -71,7 +71,9 @@ const LabCard = memo<PropsWithChildren<LabCardProps>>(
|
|
|
71
71
|
<div className={styles.card}>
|
|
72
72
|
<div className={styles.row}>
|
|
73
73
|
<div className={styles.thumb}>
|
|
74
|
-
{cover &&
|
|
74
|
+
{cover && (
|
|
75
|
+
<Image alt={title} fill src={cover} style={{ objectFit: 'cover' }} unoptimized />
|
|
76
|
+
)}
|
|
75
77
|
</div>
|
|
76
78
|
<Flexbox gap={6}>
|
|
77
79
|
<div className={styles.title}>{title}</div>
|
|
@@ -7,9 +7,7 @@ import { useTranslation } from 'react-i18next';
|
|
|
7
7
|
|
|
8
8
|
import { FormInput, FormPassword } from '@/components/FormInput';
|
|
9
9
|
import { AzureProviderCard } from '@/config/modelProviders';
|
|
10
|
-
import { aiProviderSelectors, useAiInfraStore } from '@/store/aiInfra';
|
|
11
|
-
import { useUserStore } from '@/store/user';
|
|
12
|
-
import { modelProviderSelectors } from '@/store/user/selectors';
|
|
10
|
+
import { aiModelSelectors, aiProviderSelectors, useAiInfraStore } from '@/store/aiInfra';
|
|
13
11
|
|
|
14
12
|
import { KeyVaultsConfigKey, LLMProviderApiTokenKey, LLMProviderBaseUrlKey } from '../../const';
|
|
15
13
|
import { SkeletonInput } from '../../features/ProviderConfig';
|
|
@@ -35,11 +33,11 @@ const useProviderCard = (): ProviderItem => {
|
|
|
35
33
|
const { styles } = useStyles();
|
|
36
34
|
|
|
37
35
|
// Get the first model card's deployment name as the check model
|
|
38
|
-
const checkModel =
|
|
39
|
-
const
|
|
36
|
+
const checkModel = useAiInfraStore((s) => {
|
|
37
|
+
const modelList = aiModelSelectors.enabledAiProviderModelList(s);
|
|
40
38
|
|
|
41
|
-
if (
|
|
42
|
-
return
|
|
39
|
+
if (modelList.length > 0) {
|
|
40
|
+
return modelList[0].id;
|
|
43
41
|
}
|
|
44
42
|
|
|
45
43
|
return 'gpt-35-turbo';
|
|
@@ -7,21 +7,16 @@ import { memo, useState } from 'react';
|
|
|
7
7
|
import { useTranslation } from 'react-i18next';
|
|
8
8
|
|
|
9
9
|
import { FormAction } from '@/features/Conversation/Error/style';
|
|
10
|
-
import {
|
|
11
|
-
import { keyVaultsConfigSelectors } from '@/store/user/selectors';
|
|
10
|
+
import { aiProviderSelectors, useAiInfraStore } from '@/store/aiInfra';
|
|
12
11
|
|
|
13
12
|
const BedrockForm = memo<{ description: string }>(({ description }) => {
|
|
14
13
|
const { t } = useTranslation('modelProvider');
|
|
15
14
|
const [showRegion, setShow] = useState(false);
|
|
16
15
|
const [showSessionToken, setShowSessionToken] = useState(false);
|
|
17
16
|
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
keyVaultsConfigSelectors.bedrockConfig(s).sessionToken,
|
|
22
|
-
keyVaultsConfigSelectors.bedrockConfig(s).region,
|
|
23
|
-
s.updateKeyVaultConfig,
|
|
24
|
-
]);
|
|
17
|
+
const config = useAiInfraStore(aiProviderSelectors.providerKeyVaults(ModelProvider.Bedrock));
|
|
18
|
+
const setConfig = useAiInfraStore((s) => s.updateAiProviderConfig);
|
|
19
|
+
const { accessKeyId, secretAccessKey, sessionToken, region } = config || {};
|
|
25
20
|
|
|
26
21
|
const theme = useTheme();
|
|
27
22
|
return (
|
|
@@ -33,7 +28,7 @@ const BedrockForm = memo<{ description: string }>(({ description }) => {
|
|
|
33
28
|
<InputPassword
|
|
34
29
|
autoComplete={'new-password'}
|
|
35
30
|
onChange={(e) => {
|
|
36
|
-
setConfig(ModelProvider.Bedrock, { accessKeyId: e.target.value });
|
|
31
|
+
setConfig(ModelProvider.Bedrock, { keyVaults: { accessKeyId: e.target.value } });
|
|
37
32
|
}}
|
|
38
33
|
placeholder={'Aws Access Key Id'}
|
|
39
34
|
value={accessKeyId}
|
|
@@ -42,7 +37,7 @@ const BedrockForm = memo<{ description: string }>(({ description }) => {
|
|
|
42
37
|
<InputPassword
|
|
43
38
|
autoComplete={'new-password'}
|
|
44
39
|
onChange={(e) => {
|
|
45
|
-
setConfig(ModelProvider.Bedrock, { secretAccessKey: e.target.value });
|
|
40
|
+
setConfig(ModelProvider.Bedrock, { keyVaults: { secretAccessKey: e.target.value } });
|
|
46
41
|
}}
|
|
47
42
|
placeholder={'Aws Secret Access Key'}
|
|
48
43
|
value={secretAccessKey}
|
|
@@ -52,7 +47,7 @@ const BedrockForm = memo<{ description: string }>(({ description }) => {
|
|
|
52
47
|
<InputPassword
|
|
53
48
|
autoComplete={'new-password'}
|
|
54
49
|
onChange={(e) => {
|
|
55
|
-
setConfig(ModelProvider.Bedrock, { sessionToken: e.target.value });
|
|
50
|
+
setConfig(ModelProvider.Bedrock, { keyVaults: { sessionToken: e.target.value } });
|
|
56
51
|
}}
|
|
57
52
|
placeholder={'Aws Session Token'}
|
|
58
53
|
value={sessionToken}
|
|
@@ -73,7 +68,7 @@ const BedrockForm = memo<{ description: string }>(({ description }) => {
|
|
|
73
68
|
{showRegion ? (
|
|
74
69
|
<Select
|
|
75
70
|
onChange={(region) => {
|
|
76
|
-
setConfig('bedrock', { region });
|
|
71
|
+
setConfig('bedrock', { keyVaults: { region } });
|
|
77
72
|
}}
|
|
78
73
|
options={['us-east-1', 'us-west-2', 'ap-southeast-1', 'eu-central-1'].map((i) => ({
|
|
79
74
|
label: i,
|
|
@@ -111,7 +111,6 @@ describe('mapFeatureFlagsEnvToState', () => {
|
|
|
111
111
|
plugins: true,
|
|
112
112
|
knowledge_base: false,
|
|
113
113
|
rag_eval: true,
|
|
114
|
-
clerk_sign_up: false,
|
|
115
114
|
market: true,
|
|
116
115
|
speech_to_text: true,
|
|
117
116
|
changelog: false,
|
|
@@ -140,7 +139,6 @@ describe('mapFeatureFlagsEnvToState', () => {
|
|
|
140
139
|
showWelcomeSuggest: true,
|
|
141
140
|
enableKnowledgeBase: false,
|
|
142
141
|
enableRAGEval: true,
|
|
143
|
-
enableClerkSignUp: false,
|
|
144
142
|
showMarket: true,
|
|
145
143
|
enableSTT: true,
|
|
146
144
|
showPinList: true,
|
|
@@ -30,8 +30,6 @@ export const FeatureFlagsSchema = z.object({
|
|
|
30
30
|
welcome_suggest: FeatureFlagValue.optional(),
|
|
31
31
|
changelog: FeatureFlagValue.optional(),
|
|
32
32
|
|
|
33
|
-
clerk_sign_up: FeatureFlagValue.optional(),
|
|
34
|
-
|
|
35
33
|
market: FeatureFlagValue.optional(),
|
|
36
34
|
knowledge_base: FeatureFlagValue.optional(),
|
|
37
35
|
|
|
@@ -93,8 +91,6 @@ export const DEFAULT_FEATURE_FLAGS: IFeatureFlags = {
|
|
|
93
91
|
knowledge_base: true,
|
|
94
92
|
rag_eval: false,
|
|
95
93
|
|
|
96
|
-
clerk_sign_up: true,
|
|
97
|
-
|
|
98
94
|
cloud_promotion: false,
|
|
99
95
|
|
|
100
96
|
market: true,
|
|
@@ -133,8 +129,6 @@ export const mapFeatureFlagsEnvToState = (config: IFeatureFlags, userId?: string
|
|
|
133
129
|
enableCheckUpdates: evaluateFeatureFlag(config.check_updates, userId),
|
|
134
130
|
showWelcomeSuggest: evaluateFeatureFlag(config.welcome_suggest, userId),
|
|
135
131
|
|
|
136
|
-
enableClerkSignUp: evaluateFeatureFlag(config.clerk_sign_up, userId),
|
|
137
|
-
|
|
138
132
|
enableKnowledgeBase: evaluateFeatureFlag(config.knowledge_base, userId),
|
|
139
133
|
enableRAGEval: evaluateFeatureFlag(config.rag_eval, userId),
|
|
140
134
|
|
|
@@ -2,22 +2,7 @@ import { ModelProviderCard } from '@/types/llm';
|
|
|
2
2
|
|
|
3
3
|
// ref https://docs.ai21.com/reference/jamba-15-api-ref
|
|
4
4
|
const Ai21: ModelProviderCard = {
|
|
5
|
-
chatModels: [
|
|
6
|
-
{
|
|
7
|
-
contextWindowTokens: 256_000,
|
|
8
|
-
displayName: 'Jamba 1.5 Mini',
|
|
9
|
-
enabled: true,
|
|
10
|
-
functionCall: true,
|
|
11
|
-
id: 'jamba-1.5-mini',
|
|
12
|
-
},
|
|
13
|
-
{
|
|
14
|
-
contextWindowTokens: 256_000,
|
|
15
|
-
displayName: 'Jamba 1.5 Large',
|
|
16
|
-
enabled: true,
|
|
17
|
-
functionCall: true,
|
|
18
|
-
id: 'jamba-1.5-large',
|
|
19
|
-
},
|
|
20
|
-
],
|
|
5
|
+
chatModels: [],
|
|
21
6
|
checkModel: 'jamba-mini',
|
|
22
7
|
description: 'AI21 Labs 为企业构建基础模型和人工智能系统,加速生成性人工智能在生产中的应用。',
|
|
23
8
|
id: 'ai21',
|