@lobehub/chat 0.132.2 → 0.133.1
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 +5 -0
- package/CHANGELOG.md +50 -0
- package/Dockerfile +3 -0
- package/README.md +5 -1
- package/README.zh-CN.md +5 -1
- package/docs/self-hosting/environment-variables/model-provider.mdx +8 -0
- package/docs/self-hosting/environment-variables/model-provider.zh-CN.mdx +10 -1
- package/locales/ar/common.json +1 -0
- package/locales/ar/error.json +6 -0
- package/locales/ar/setting.json +8 -0
- package/locales/de-DE/common.json +1 -0
- package/locales/de-DE/error.json +6 -0
- package/locales/de-DE/setting.json +8 -0
- package/locales/en-US/common.json +1 -0
- package/locales/en-US/error.json +6 -0
- package/locales/en-US/setting.json +8 -0
- package/locales/es-ES/common.json +1 -0
- package/locales/es-ES/error.json +6 -0
- package/locales/es-ES/setting.json +8 -0
- package/locales/fr-FR/common.json +1 -0
- package/locales/fr-FR/error.json +6 -0
- package/locales/fr-FR/setting.json +8 -0
- package/locales/it-IT/common.json +1 -0
- package/locales/it-IT/error.json +6 -0
- package/locales/it-IT/setting.json +8 -0
- package/locales/ja-JP/common.json +1 -0
- package/locales/ja-JP/error.json +6 -0
- package/locales/ja-JP/setting.json +8 -0
- package/locales/ko-KR/common.json +1 -0
- package/locales/ko-KR/error.json +6 -0
- package/locales/ko-KR/setting.json +8 -0
- package/locales/nl-NL/common.json +1 -0
- package/locales/nl-NL/error.json +6 -0
- package/locales/nl-NL/setting.json +8 -0
- package/locales/pl-PL/common.json +1 -0
- package/locales/pl-PL/error.json +6 -0
- package/locales/pl-PL/setting.json +8 -0
- package/locales/pt-BR/common.json +1 -0
- package/locales/pt-BR/error.json +6 -0
- package/locales/pt-BR/setting.json +8 -0
- package/locales/ru-RU/common.json +1 -0
- package/locales/ru-RU/error.json +6 -0
- package/locales/ru-RU/setting.json +8 -0
- package/locales/tr-TR/common.json +1 -0
- package/locales/tr-TR/error.json +6 -0
- package/locales/tr-TR/setting.json +8 -0
- package/locales/vi-VN/common.json +1 -0
- package/locales/vi-VN/error.json +6 -0
- package/locales/vi-VN/setting.json +8 -0
- package/locales/zh-CN/common.json +1 -0
- package/locales/zh-CN/error.json +6 -0
- package/locales/zh-CN/setting.json +8 -0
- package/locales/zh-TW/common.json +1 -0
- package/locales/zh-TW/error.json +6 -0
- package/locales/zh-TW/setting.json +8 -0
- package/next-sitemap.config.mjs +2 -3
- package/package.json +1 -1
- package/src/app/api/chat/[provider]/agentRuntime.test.ts +52 -0
- package/src/app/api/chat/[provider]/agentRuntime.ts +13 -0
- package/src/app/api/config/route.ts +2 -0
- package/src/app/api/errorResponse.test.ts +15 -0
- package/src/app/api/errorResponse.ts +3 -0
- package/src/app/settings/llm/Mistral/index.tsx +52 -0
- package/src/app/settings/llm/index.tsx +2 -0
- package/src/config/modelProviders/index.ts +3 -0
- package/src/config/modelProviders/mistral.ts +34 -0
- package/src/config/server/provider.ts +8 -0
- package/src/const/settings.ts +4 -0
- package/src/features/Conversation/Error/APIKeyForm/Mistral.tsx +60 -0
- package/src/features/Conversation/Error/APIKeyForm/index.tsx +5 -0
- package/src/features/Conversation/Error/index.tsx +1 -0
- package/src/libs/agent-runtime/anthropic/index.test.ts +78 -0
- package/src/libs/agent-runtime/error.ts +3 -0
- package/src/libs/agent-runtime/index.ts +1 -0
- package/src/libs/agent-runtime/mistral/index.test.ts +378 -0
- package/src/libs/agent-runtime/mistral/index.ts +87 -0
- package/src/locales/default/common.ts +1 -0
- package/src/locales/default/error.ts +7 -0
- package/src/locales/default/setting.ts +8 -0
- package/src/services/_auth.test.ts +20 -0
- package/src/services/_auth.ts +4 -0
- package/src/store/global/slices/settings/selectors/modelProvider.ts +9 -0
- package/src/types/settings/modelProvider.ts +6 -0
- package/public/robots.txt +0 -4
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { OpenAIStream, StreamingTextResponse } from 'ai';
|
|
2
|
+
import OpenAI, { ClientOptions } from 'openai';
|
|
3
|
+
|
|
4
|
+
import { LobeRuntimeAI } from '../BaseAI';
|
|
5
|
+
import { AgentRuntimeErrorType } from '../error';
|
|
6
|
+
import { ChatCompetitionOptions, ChatStreamPayload, ModelProvider } from '../types';
|
|
7
|
+
import { AgentRuntimeError } from '../utils/createError';
|
|
8
|
+
import { debugStream } from '../utils/debugStream';
|
|
9
|
+
import { desensitizeUrl } from '../utils/desensitizeUrl';
|
|
10
|
+
import { handleOpenAIError } from '../utils/handleOpenAIError';
|
|
11
|
+
|
|
12
|
+
const DEFAULT_BASE_URL = 'https://api.mistral.ai/v1';
|
|
13
|
+
|
|
14
|
+
export class LobeMistralAI implements LobeRuntimeAI {
|
|
15
|
+
private client: OpenAI;
|
|
16
|
+
|
|
17
|
+
baseURL: string;
|
|
18
|
+
|
|
19
|
+
constructor({ apiKey, baseURL = DEFAULT_BASE_URL, ...res }: ClientOptions) {
|
|
20
|
+
if (!apiKey) throw AgentRuntimeError.createError(AgentRuntimeErrorType.InvalidMistralAPIKey);
|
|
21
|
+
|
|
22
|
+
this.client = new OpenAI({ apiKey, baseURL, ...res });
|
|
23
|
+
this.baseURL = this.client.baseURL;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
async chat(payload: ChatStreamPayload, options?: ChatCompetitionOptions) {
|
|
27
|
+
try {
|
|
28
|
+
// Pick supported properties from payload
|
|
29
|
+
const chatPayload = {
|
|
30
|
+
max_tokens: payload.max_tokens,
|
|
31
|
+
messages: payload.messages,
|
|
32
|
+
model: payload.model,
|
|
33
|
+
stream: true,
|
|
34
|
+
temperature: payload.temperature,
|
|
35
|
+
top_p: payload.top_p,
|
|
36
|
+
};
|
|
37
|
+
const response = await this.client.chat.completions.create(
|
|
38
|
+
chatPayload as unknown as OpenAI.ChatCompletionCreateParamsStreaming,
|
|
39
|
+
);
|
|
40
|
+
const [prod, debug] = response.tee();
|
|
41
|
+
|
|
42
|
+
if (process.env.DEBUG_MISTRAL_CHAT_COMPLETION === '1') {
|
|
43
|
+
debugStream(debug.toReadableStream()).catch(console.error);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return new StreamingTextResponse(OpenAIStream(prod, options?.callback), {
|
|
47
|
+
headers: options?.headers,
|
|
48
|
+
});
|
|
49
|
+
} catch (error) {
|
|
50
|
+
let desensitizedEndpoint = this.baseURL;
|
|
51
|
+
|
|
52
|
+
if (this.baseURL !== DEFAULT_BASE_URL) {
|
|
53
|
+
desensitizedEndpoint = desensitizeUrl(this.baseURL);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if ('status' in (error as any)) {
|
|
57
|
+
switch ((error as Response).status) {
|
|
58
|
+
case 401: {
|
|
59
|
+
throw AgentRuntimeError.chat({
|
|
60
|
+
endpoint: desensitizedEndpoint,
|
|
61
|
+
error: error as any,
|
|
62
|
+
errorType: AgentRuntimeErrorType.InvalidMistralAPIKey,
|
|
63
|
+
provider: ModelProvider.Mistral,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
default: {
|
|
68
|
+
break;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const { errorResult, RuntimeError } = handleOpenAIError(error);
|
|
74
|
+
|
|
75
|
+
const errorType = RuntimeError || AgentRuntimeErrorType.MistralBizError;
|
|
76
|
+
|
|
77
|
+
throw AgentRuntimeError.chat({
|
|
78
|
+
endpoint: desensitizedEndpoint,
|
|
79
|
+
error: errorResult,
|
|
80
|
+
errorType,
|
|
81
|
+
provider: ModelProvider.Mistral,
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export default LobeMistralAI;
|
|
@@ -61,6 +61,9 @@ export default {
|
|
|
61
61
|
ZhipuBizError: '请求智谱服务出错,请根据以下信息排查或重试',
|
|
62
62
|
InvalidZhipuAPIKey: 'Zhipu API Key 不正确或为空,请检查 Zhipu API Key 后重试',
|
|
63
63
|
|
|
64
|
+
MistralBizError: '请求 Mistral AI 服务出错,请根据以下信息排查或重试',
|
|
65
|
+
InvalidMistralAPIKey: 'Mistral AI API Key 不正确或为空,请检查 Mistral API Key 后重试',
|
|
66
|
+
|
|
64
67
|
MoonshotBizError: '请求月之暗面服务出错,请根据以下信息排查或重试',
|
|
65
68
|
InvalidMoonshotAPIKey: 'Moonshot AI API Key 不正确或为空,请检查 Moonshot API Key 后重试',
|
|
66
69
|
|
|
@@ -107,6 +110,10 @@ export default {
|
|
|
107
110
|
description: '输入你的 Google API Key 即可开始会话。应用不会记录你的 API Key',
|
|
108
111
|
title: '使用自定义 Google API Key',
|
|
109
112
|
},
|
|
113
|
+
Mistral: {
|
|
114
|
+
description: '输入你的 Mistral AI API Key 即可开始会话。应用不会记录你的 API Key',
|
|
115
|
+
title: '使用自定义 Mistral AI API Key',
|
|
116
|
+
},
|
|
110
117
|
Moonshot: {
|
|
111
118
|
description: '输入你的 Moonshot AI API Key 即可开始会话。应用不会记录你的 API Key',
|
|
112
119
|
title: '使用自定义 Moonshot AI API Key',
|
|
@@ -95,6 +95,14 @@ export default {
|
|
|
95
95
|
title: 'API Key',
|
|
96
96
|
},
|
|
97
97
|
},
|
|
98
|
+
Mistral: {
|
|
99
|
+
title: 'Mistral AI',
|
|
100
|
+
token: {
|
|
101
|
+
desc: '填入来自 Mistral AI 的 API Key',
|
|
102
|
+
placeholder: 'Mistral AI API Key',
|
|
103
|
+
title: 'API Key',
|
|
104
|
+
},
|
|
105
|
+
},
|
|
98
106
|
Moonshot: {
|
|
99
107
|
title: '月之暗面',
|
|
100
108
|
token: {
|
|
@@ -11,6 +11,8 @@ import { getProviderAuthPayload } from './_auth';
|
|
|
11
11
|
const mockZhiPuAPIKey = 'zhipu-api-key';
|
|
12
12
|
const mockMoonshotAPIKey = 'moonshot-api-key';
|
|
13
13
|
const mockGoogleAPIKey = 'google-api-key';
|
|
14
|
+
const mockAnthropicAPIKey = 'anthropic-api-key';
|
|
15
|
+
const mockMistralAPIKey = 'mistral-api-key';
|
|
14
16
|
|
|
15
17
|
// mock the traditional zustand
|
|
16
18
|
vi.mock('zustand/traditional');
|
|
@@ -43,6 +45,24 @@ describe('getProviderAuthPayload', () => {
|
|
|
43
45
|
expect(payload).toEqual({ apiKey: mockMoonshotAPIKey });
|
|
44
46
|
});
|
|
45
47
|
|
|
48
|
+
it('should return correct payload for Anthropic provider', () => {
|
|
49
|
+
act(() => {
|
|
50
|
+
setModelProviderConfig('anthropic', { apiKey: mockAnthropicAPIKey });
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
const payload = getProviderAuthPayload(ModelProvider.Anthropic);
|
|
54
|
+
expect(payload).toEqual({ apiKey: mockAnthropicAPIKey });
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it('should return correct payload for Mistral provider', () => {
|
|
58
|
+
act(() => {
|
|
59
|
+
setModelProviderConfig('mistral', { apiKey: mockMistralAPIKey });
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
const payload = getProviderAuthPayload(ModelProvider.Mistral);
|
|
63
|
+
expect(payload).toEqual({ apiKey: mockMistralAPIKey });
|
|
64
|
+
});
|
|
65
|
+
|
|
46
66
|
it('should return correct payload for Google provider', () => {
|
|
47
67
|
act(() => {
|
|
48
68
|
setModelProviderConfig('google', { apiKey: mockGoogleAPIKey });
|
package/src/services/_auth.ts
CHANGED
|
@@ -55,6 +55,10 @@ export const getProviderAuthPayload = (provider: string) => {
|
|
|
55
55
|
case ModelProvider.Anthropic: {
|
|
56
56
|
return { apiKey: modelProviderSelectors.anthropicAPIKey(useGlobalStore.getState()) };
|
|
57
57
|
}
|
|
58
|
+
|
|
59
|
+
case ModelProvider.Mistral: {
|
|
60
|
+
return { apiKey: modelProviderSelectors.mistralAPIKey(useGlobalStore.getState()) };
|
|
61
|
+
}
|
|
58
62
|
|
|
59
63
|
default:
|
|
60
64
|
case ModelProvider.OpenAI: {
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
BedrockProvider,
|
|
6
6
|
GoogleProvider,
|
|
7
7
|
LOBE_DEFAULT_MODEL_LIST,
|
|
8
|
+
MistralProvider,
|
|
8
9
|
MoonshotProvider,
|
|
9
10
|
OllamaProvider,
|
|
10
11
|
OpenAIProvider,
|
|
@@ -41,6 +42,9 @@ const googleProxyUrl = (s: GlobalStore) => modelProvider(s).google.endpoint;
|
|
|
41
42
|
const enableAzure = (s: GlobalStore) => modelProvider(s).openAI.useAzure;
|
|
42
43
|
const azureConfig = (s: GlobalStore) => modelProvider(s).azure;
|
|
43
44
|
|
|
45
|
+
const enableMistral = (s: GlobalStore) => modelProvider(s).mistral.enabled;
|
|
46
|
+
const mistralAPIKey = (s: GlobalStore) => modelProvider(s).mistral.apiKey;
|
|
47
|
+
|
|
44
48
|
const enableMoonshot = (s: GlobalStore) => modelProvider(s).moonshot.enabled;
|
|
45
49
|
const moonshotAPIKey = (s: GlobalStore) => modelProvider(s).moonshot.apiKey;
|
|
46
50
|
|
|
@@ -143,6 +147,7 @@ const modelSelectList = (s: GlobalStore): ModelProviderCard[] => {
|
|
|
143
147
|
{ ...OllamaProvider, chatModels: ollamaChatModels, enabled: enableOllama(s) },
|
|
144
148
|
{ ...PerplexityProvider, enabled: enablePerplexity(s) },
|
|
145
149
|
{ ...AnthropicProvider, enabled: enableAnthropic(s) },
|
|
150
|
+
{ ...MistralProvider, enabled: enableMistral(s) },
|
|
146
151
|
];
|
|
147
152
|
};
|
|
148
153
|
|
|
@@ -221,4 +226,8 @@ export const modelProviderSelectors = {
|
|
|
221
226
|
// Anthropic
|
|
222
227
|
enableAnthropic,
|
|
223
228
|
anthropicAPIKey,
|
|
229
|
+
|
|
230
|
+
// Mistral
|
|
231
|
+
enableMistral,
|
|
232
|
+
mistralAPIKey,
|
|
224
233
|
};
|
|
@@ -65,11 +65,17 @@ export interface AnthropicConfig {
|
|
|
65
65
|
enabled: boolean;
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
+
export interface MistralConfig {
|
|
69
|
+
apiKey?: string;
|
|
70
|
+
enabled: boolean;
|
|
71
|
+
}
|
|
72
|
+
|
|
68
73
|
export interface GlobalLLMConfig {
|
|
69
74
|
anthropic: AnthropicConfig;
|
|
70
75
|
azure: AzureOpenAIConfig;
|
|
71
76
|
bedrock: AWSBedrockConfig;
|
|
72
77
|
google: GoogleConfig;
|
|
78
|
+
mistral: MistralConfig;
|
|
73
79
|
moonshot: MoonshotConfig;
|
|
74
80
|
ollama: OllamaConfig;
|
|
75
81
|
openAI: OpenAIConfig;
|
package/public/robots.txt
DELETED