@lobehub/chat 1.3.4 → 1.3.6

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 CHANGED
@@ -2,6 +2,56 @@
2
2
 
3
3
  # Changelog
4
4
 
5
+ ### [Version 1.3.6](https://github.com/lobehub/lobe-chat/compare/v1.3.5...v1.3.6)
6
+
7
+ <sup>Released on **2024-07-11**</sup>
8
+
9
+ #### ♻ Code Refactoring
10
+
11
+ - **misc**: Improve agent runtime code.
12
+
13
+ <br/>
14
+
15
+ <details>
16
+ <summary><kbd>Improvements and Fixes</kbd></summary>
17
+
18
+ #### Code refactoring
19
+
20
+ - **misc**: Improve agent runtime code, closes [#3199](https://github.com/lobehub/lobe-chat/issues/3199) ([9f211e2](https://github.com/lobehub/lobe-chat/commit/9f211e2))
21
+
22
+ </details>
23
+
24
+ <div align="right">
25
+
26
+ [![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
27
+
28
+ </div>
29
+
30
+ ### [Version 1.3.5](https://github.com/lobehub/lobe-chat/compare/v1.3.4...v1.3.5)
31
+
32
+ <sup>Released on **2024-07-10**</sup>
33
+
34
+ #### 🐛 Bug Fixes
35
+
36
+ - **misc**: Fix assistant meta change race issue.
37
+
38
+ <br/>
39
+
40
+ <details>
41
+ <summary><kbd>Improvements and Fixes</kbd></summary>
42
+
43
+ #### What's fixed
44
+
45
+ - **misc**: Fix assistant meta change race issue, closes [#3184](https://github.com/lobehub/lobe-chat/issues/3184) ([6335be4](https://github.com/lobehub/lobe-chat/commit/6335be4))
46
+
47
+ </details>
48
+
49
+ <div align="right">
50
+
51
+ [![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
52
+
53
+ </div>
54
+
5
55
  ### [Version 1.3.4](https://github.com/lobehub/lobe-chat/compare/v1.3.3...v1.3.4)
6
56
 
7
57
  <sup>Released on **2024-07-09**</sup>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lobehub/chat",
3
- "version": "1.3.4",
3
+ "version": "1.3.6",
4
4
  "description": "Lobe Chat - an open-source, high-performance chatbot framework that supports speech synthesis, multimodal, and extensible Function Call plugin system. Supports one-click free deployment of your private ChatGPT/LLM web application.",
5
5
  "keywords": [
6
6
  "framework",
@@ -193,11 +193,16 @@ const getLlmOptionsFromPayload = (provider: string, payload: JWTPayload) => {
193
193
  * Initializes the agent runtime with the user payload in backend
194
194
  * @param provider - The provider name.
195
195
  * @param payload - The JWT payload.
196
+ * @param params
196
197
  * @returns A promise that resolves when the agent runtime is initialized.
197
198
  */
198
- export const initAgentRuntimeWithUserPayload = (provider: string, payload: JWTPayload) => {
199
+ export const initAgentRuntimeWithUserPayload = (
200
+ provider: string,
201
+ payload: JWTPayload,
202
+ params: any = {},
203
+ ) => {
199
204
  return AgentRuntime.initializeWithProviderOptions(provider, {
200
- [provider]: getLlmOptionsFromPayload(provider, payload),
205
+ [provider]: { ...getLlmOptionsFromPayload(provider, payload), ...params },
201
206
  });
202
207
  };
203
208
 
@@ -2,20 +2,35 @@ import { ActionIcon } from '@lobehub/ui';
2
2
  import { Input, InputProps } from 'antd';
3
3
  import { useTheme } from 'antd-style';
4
4
  import { Wand2 } from 'lucide-react';
5
- import { memo } from 'react';
5
+ import { memo, useCallback, useEffect, useRef, useState } from 'react';
6
6
  import { useTranslation } from 'react-i18next';
7
7
 
8
- export interface AutoGenerateInputProps extends InputProps {
8
+ export interface AutoGenerateInputProps extends Omit<InputProps, 'onChange'> {
9
9
  canAutoGenerate?: boolean;
10
10
  loading?: boolean;
11
+ onChange?: (value: string) => void;
11
12
  onGenerate?: () => void;
13
+ value?: string | any;
12
14
  }
13
15
 
14
16
  const AutoGenerateInput = memo<AutoGenerateInputProps>(
15
- ({ loading, onGenerate, canAutoGenerate, ...props }) => {
17
+ ({ loading, value, onChange, onGenerate, canAutoGenerate, ...props }) => {
16
18
  const { t } = useTranslation('common');
17
19
  const theme = useTheme();
18
20
 
21
+ const [input, setInput] = useState<string>(value || '');
22
+
23
+ const isChineseInput = useRef(false);
24
+ const isFocusing = useRef(false);
25
+
26
+ const updateValue = useCallback(() => {
27
+ onChange?.(input);
28
+ }, [input]);
29
+
30
+ useEffect(() => {
31
+ if (value !== undefined) setInput(value);
32
+ }, [value]);
33
+
19
34
  return (
20
35
  <Input
21
36
  suffix={
@@ -37,6 +52,29 @@ const AutoGenerateInput = memo<AutoGenerateInputProps>(
37
52
  }
38
53
  type="block"
39
54
  {...props}
55
+ onBlur={() => {
56
+ isFocusing.current = false;
57
+ }}
58
+ onChange={(e) => {
59
+ setInput(e.target.value);
60
+ }}
61
+ onCompositionEnd={() => {
62
+ isChineseInput.current = false;
63
+ }}
64
+ onCompositionStart={() => {
65
+ isChineseInput.current = true;
66
+ }}
67
+ onFocus={() => {
68
+ isFocusing.current = true;
69
+ }}
70
+ onPressEnter={(e) => {
71
+ if (!e.shiftKey && !isChineseInput.current) {
72
+ e.preventDefault();
73
+ updateValue();
74
+ isFocusing.current = false;
75
+ }
76
+ }}
77
+ value={input}
40
78
  />
41
79
  );
42
80
  },
@@ -34,14 +34,14 @@ const AgentMeta = memo(() => {
34
34
  Render: AutoGenerateInput,
35
35
  key: 'title',
36
36
  label: t('settingAgent.name.title'),
37
- onChange: (e: any) => updateMeta({ title: e.target.value }),
37
+ onChange: (value: string) => updateMeta({ title: value }),
38
38
  placeholder: t('settingAgent.name.placeholder'),
39
39
  },
40
40
  {
41
41
  Render: AutoGenerateInput,
42
42
  key: 'description',
43
43
  label: t('settingAgent.description.title'),
44
- onChange: (e: any) => updateMeta({ description: e.target.value }),
44
+ onChange: (value: string) => updateMeta({ description: value }),
45
45
  placeholder: t('settingAgent.description.placeholder'),
46
46
  },
47
47
  {
@@ -145,93 +145,93 @@ class AgentRuntime {
145
145
  }
146
146
 
147
147
  case ModelProvider.ZhiPu: {
148
- runtimeModel = await LobeZhipuAI.fromAPIKey(params.zhipu ?? {});
148
+ runtimeModel = await LobeZhipuAI.fromAPIKey(params.zhipu);
149
149
  break;
150
150
  }
151
151
 
152
152
  case ModelProvider.Google: {
153
- runtimeModel = new LobeGoogleAI(params.google ?? {});
153
+ runtimeModel = new LobeGoogleAI(params.google);
154
154
  break;
155
155
  }
156
156
 
157
157
  case ModelProvider.Moonshot: {
158
- runtimeModel = new LobeMoonshotAI(params.moonshot ?? {});
158
+ runtimeModel = new LobeMoonshotAI(params.moonshot);
159
159
  break;
160
160
  }
161
161
 
162
162
  case ModelProvider.Bedrock: {
163
- runtimeModel = new LobeBedrockAI(params.bedrock ?? {});
163
+ runtimeModel = new LobeBedrockAI(params.bedrock);
164
164
  break;
165
165
  }
166
166
 
167
167
  case ModelProvider.Ollama: {
168
- runtimeModel = new LobeOllamaAI(params.ollama ?? {});
168
+ runtimeModel = new LobeOllamaAI(params.ollama);
169
169
  break;
170
170
  }
171
171
 
172
172
  case ModelProvider.Perplexity: {
173
- runtimeModel = new LobePerplexityAI(params.perplexity ?? {});
173
+ runtimeModel = new LobePerplexityAI(params.perplexity);
174
174
  break;
175
175
  }
176
176
 
177
177
  case ModelProvider.Anthropic: {
178
- runtimeModel = new LobeAnthropicAI(params.anthropic ?? {});
178
+ runtimeModel = new LobeAnthropicAI(params.anthropic);
179
179
  break;
180
180
  }
181
181
 
182
182
  case ModelProvider.DeepSeek: {
183
- runtimeModel = new LobeDeepSeekAI(params.deepseek ?? {});
183
+ runtimeModel = new LobeDeepSeekAI(params.deepseek);
184
184
  break;
185
185
  }
186
186
 
187
187
  case ModelProvider.Minimax: {
188
- runtimeModel = new LobeMinimaxAI(params.minimax ?? {});
188
+ runtimeModel = new LobeMinimaxAI(params.minimax);
189
189
  break;
190
190
  }
191
191
 
192
192
  case ModelProvider.Mistral: {
193
- runtimeModel = new LobeMistralAI(params.mistral ?? {});
193
+ runtimeModel = new LobeMistralAI(params.mistral);
194
194
  break;
195
195
  }
196
196
 
197
197
  case ModelProvider.Groq: {
198
- runtimeModel = new LobeGroq(params.groq ?? {});
198
+ runtimeModel = new LobeGroq(params.groq);
199
199
  break;
200
200
  }
201
201
 
202
202
  case ModelProvider.OpenRouter: {
203
- runtimeModel = new LobeOpenRouterAI(params.openrouter ?? {});
203
+ runtimeModel = new LobeOpenRouterAI(params.openrouter);
204
204
  break;
205
205
  }
206
206
 
207
207
  case ModelProvider.TogetherAI: {
208
- runtimeModel = new LobeTogetherAI(params.togetherai ?? {});
208
+ runtimeModel = new LobeTogetherAI(params.togetherai);
209
209
  break;
210
210
  }
211
211
 
212
212
  case ModelProvider.ZeroOne: {
213
- runtimeModel = new LobeZeroOneAI(params.zeroone ?? {});
213
+ runtimeModel = new LobeZeroOneAI(params.zeroone);
214
214
  break;
215
215
  }
216
216
 
217
217
  case ModelProvider.Qwen: {
218
- runtimeModel = new LobeQwenAI(params.qwen ?? {});
218
+ runtimeModel = new LobeQwenAI(params.qwen);
219
219
  break;
220
220
  }
221
221
 
222
222
  case ModelProvider.Stepfun: {
223
- runtimeModel = new LobeStepfunAI(params.stepfun ?? {});
223
+ runtimeModel = new LobeStepfunAI(params.stepfun);
224
224
  break;
225
225
  }
226
226
 
227
227
  case ModelProvider.Baichuan: {
228
- runtimeModel = new LobeBaichuanAI(params.baichuan ?? {});
229
- break
228
+ runtimeModel = new LobeBaichuanAI(params.baichuan);
229
+ break;
230
230
  }
231
231
 
232
232
  case ModelProvider.Taichu: {
233
- runtimeModel = new LobeTaichuAI(params.taichu ?? {});
234
- break
233
+ runtimeModel = new LobeTaichuAI(params.taichu);
234
+ break;
235
235
  }
236
236
  }
237
237
 
@@ -20,7 +20,7 @@ export class LobeAnthropicAI implements LobeRuntimeAI {
20
20
 
21
21
  baseURL: string;
22
22
 
23
- constructor({ apiKey, baseURL = DEFAULT_BASE_URL }: ClientOptions) {
23
+ constructor({ apiKey, baseURL = DEFAULT_BASE_URL }: ClientOptions = {}) {
24
24
  if (!apiKey) throw AgentRuntimeError.createError(AgentRuntimeErrorType.InvalidProviderAPIKey);
25
25
 
26
26
  this.client = new Anthropic({ apiKey, baseURL });
@@ -28,7 +28,7 @@ export class LobeBedrockAI implements LobeRuntimeAI {
28
28
 
29
29
  region: string;
30
30
 
31
- constructor({ region, accessKeyId, accessKeySecret }: LobeBedrockAIParams) {
31
+ constructor({ region, accessKeyId, accessKeySecret }: LobeBedrockAIParams = {}) {
32
32
  if (!(accessKeyId && accessKeySecret))
33
33
  throw AgentRuntimeError.createError(AgentRuntimeErrorType.InvalidBedrockCredentials);
34
34
 
@@ -41,7 +41,7 @@ export class LobeGoogleAI implements LobeRuntimeAI {
41
41
  private client: GoogleGenerativeAI;
42
42
  baseURL?: string;
43
43
 
44
- constructor({ apiKey, baseURL }: { apiKey?: string; baseURL?: string }) {
44
+ constructor({ apiKey, baseURL }: { apiKey?: string; baseURL?: string } = {}) {
45
45
  if (!apiKey) throw AgentRuntimeError.createError(AgentRuntimeErrorType.InvalidProviderAPIKey);
46
46
 
47
47
  this.client = new GoogleGenerativeAI(apiKey);
@@ -63,7 +63,7 @@ function parseMinimaxResponse(chunk: string): MinimaxResponse | undefined {
63
63
  export class LobeMinimaxAI implements LobeRuntimeAI {
64
64
  apiKey: string;
65
65
 
66
- constructor({ apiKey }: { apiKey?: string }) {
66
+ constructor({ apiKey }: { apiKey?: string } = {}) {
67
67
  if (!apiKey) throw AgentRuntimeError.createError(AgentRuntimeErrorType.InvalidProviderAPIKey);
68
68
 
69
69
  this.apiKey = apiKey;
@@ -18,7 +18,7 @@ export class LobeOllamaAI implements LobeRuntimeAI {
18
18
 
19
19
  baseURL?: string;
20
20
 
21
- constructor({ baseURL }: ClientOptions) {
21
+ constructor({ baseURL }: ClientOptions = {}) {
22
22
  try {
23
23
  if (baseURL) new URL(baseURL);
24
24
  } catch {
@@ -27,13 +27,18 @@ const CHAT_MODELS_BLOCK_LIST = [
27
27
  'dall-e',
28
28
  ];
29
29
 
30
- interface OpenAICompatibleFactoryOptions {
30
+ type ConstructorOptions<T extends Record<string, any> = any> = ClientOptions & T;
31
+
32
+ interface OpenAICompatibleFactoryOptions<T extends Record<string, any> = any> {
31
33
  baseURL?: string;
32
34
  chatCompletion?: {
33
- handleError?: (error: any) => Omit<ChatCompletionErrorPayload, 'provider'> | undefined;
35
+ handleError?: (
36
+ error: any,
37
+ options: ConstructorOptions<T>,
38
+ ) => Omit<ChatCompletionErrorPayload, 'provider'> | undefined;
34
39
  handlePayload?: (payload: ChatStreamPayload) => OpenAI.ChatCompletionCreateParamsStreaming;
35
40
  };
36
- constructorOptions?: ClientOptions;
41
+ constructorOptions?: ConstructorOptions<T>;
37
42
  debug?: {
38
43
  chatCompletion: () => boolean;
39
44
  };
@@ -49,7 +54,7 @@ interface OpenAICompatibleFactoryOptions {
49
54
  provider: string;
50
55
  }
51
56
 
52
- export const LobeOpenAICompatibleFactory = ({
57
+ export const LobeOpenAICompatibleFactory = <T extends Record<string, any> = any>({
53
58
  provider,
54
59
  baseURL: DEFAULT_BASE_URL,
55
60
  errorType,
@@ -57,7 +62,7 @@ export const LobeOpenAICompatibleFactory = ({
57
62
  constructorOptions,
58
63
  chatCompletion,
59
64
  models,
60
- }: OpenAICompatibleFactoryOptions) => {
65
+ }: OpenAICompatibleFactoryOptions<T>) => {
61
66
  const ErrorType = {
62
67
  bizError: errorType?.bizError || AgentRuntimeErrorType.ProviderBizError,
63
68
  invalidAPIKey: errorType?.invalidAPIKey || AgentRuntimeErrorType.InvalidProviderAPIKey,
@@ -67,8 +72,11 @@ export const LobeOpenAICompatibleFactory = ({
67
72
  client: OpenAI;
68
73
 
69
74
  baseURL: string;
75
+ private _options: ConstructorOptions<T>;
70
76
 
71
- constructor({ apiKey, baseURL = DEFAULT_BASE_URL, ...res }: ClientOptions) {
77
+ constructor(options: ClientOptions & Record<string, any> = {}) {
78
+ const { apiKey, baseURL = DEFAULT_BASE_URL, ...res } = options;
79
+ this._options = options as ConstructorOptions<T>;
72
80
  if (!apiKey) throw AgentRuntimeError.createError(ErrorType?.invalidAPIKey);
73
81
 
74
82
  this.client = new OpenAI({ apiKey, baseURL, ...constructorOptions, ...res });
@@ -115,48 +123,7 @@ export const LobeOpenAICompatibleFactory = ({
115
123
  headers: options?.headers,
116
124
  });
117
125
  } catch (error) {
118
- let desensitizedEndpoint = this.baseURL;
119
-
120
- // refs: https://github.com/lobehub/lobe-chat/issues/842
121
- if (this.baseURL !== DEFAULT_BASE_URL) {
122
- desensitizedEndpoint = desensitizeUrl(this.baseURL);
123
- }
124
-
125
- if ('status' in (error as any)) {
126
- switch ((error as Response).status) {
127
- case 401: {
128
- throw AgentRuntimeError.chat({
129
- endpoint: desensitizedEndpoint,
130
- error: error as any,
131
- errorType: ErrorType.invalidAPIKey,
132
- provider: provider as any,
133
- });
134
- }
135
-
136
- default: {
137
- break;
138
- }
139
- }
140
- }
141
-
142
- if (chatCompletion?.handleError) {
143
- const errorResult = chatCompletion.handleError(error);
144
-
145
- if (errorResult)
146
- throw AgentRuntimeError.chat({
147
- ...errorResult,
148
- provider,
149
- } as ChatCompletionErrorPayload);
150
- }
151
-
152
- const { errorResult, RuntimeError } = handleOpenAIError(error);
153
-
154
- throw AgentRuntimeError.chat({
155
- endpoint: desensitizedEndpoint,
156
- error: errorResult,
157
- errorType: RuntimeError || ErrorType.bizError,
158
- provider: provider as any,
159
- });
126
+ throw this.handleError(error);
160
127
  }
161
128
  }
162
129
 
@@ -191,48 +158,7 @@ export const LobeOpenAICompatibleFactory = ({
191
158
  const res = await this.client.images.generate(payload);
192
159
  return res.data.map((o) => o.url) as string[];
193
160
  } catch (error) {
194
- let desensitizedEndpoint = this.baseURL;
195
-
196
- // refs: https://github.com/lobehub/lobe-chat/issues/842
197
- if (this.baseURL !== DEFAULT_BASE_URL) {
198
- desensitizedEndpoint = desensitizeUrl(this.baseURL);
199
- }
200
-
201
- if ('status' in (error as any)) {
202
- switch ((error as Response).status) {
203
- case 401: {
204
- throw AgentRuntimeError.chat({
205
- endpoint: desensitizedEndpoint,
206
- error: error as any,
207
- errorType: ErrorType.invalidAPIKey,
208
- provider: provider as any,
209
- });
210
- }
211
-
212
- default: {
213
- break;
214
- }
215
- }
216
- }
217
-
218
- if (chatCompletion?.handleError) {
219
- const errorResult = chatCompletion.handleError(error);
220
-
221
- if (errorResult)
222
- throw AgentRuntimeError.chat({
223
- ...errorResult,
224
- provider,
225
- } as ChatCompletionErrorPayload);
226
- }
227
-
228
- const { errorResult, RuntimeError } = handleOpenAIError(error);
229
-
230
- throw AgentRuntimeError.chat({
231
- endpoint: desensitizedEndpoint,
232
- error: errorResult,
233
- errorType: RuntimeError || ErrorType.bizError,
234
- provider: provider as any,
235
- });
161
+ throw this.handleError(error);
236
162
  }
237
163
  }
238
164
 
@@ -289,5 +215,50 @@ export const LobeOpenAICompatibleFactory = ({
289
215
  },
290
216
  });
291
217
  }
218
+
219
+ private handleError(error: any): ChatCompletionErrorPayload {
220
+ let desensitizedEndpoint = this.baseURL;
221
+
222
+ // refs: https://github.com/lobehub/lobe-chat/issues/842
223
+ if (this.baseURL !== DEFAULT_BASE_URL) {
224
+ desensitizedEndpoint = desensitizeUrl(this.baseURL);
225
+ }
226
+
227
+ if (chatCompletion?.handleError) {
228
+ const errorResult = chatCompletion.handleError(error, this._options);
229
+
230
+ if (errorResult)
231
+ return AgentRuntimeError.chat({
232
+ ...errorResult,
233
+ provider,
234
+ } as ChatCompletionErrorPayload);
235
+ }
236
+
237
+ if ('status' in (error as any)) {
238
+ switch ((error as Response).status) {
239
+ case 401: {
240
+ return AgentRuntimeError.chat({
241
+ endpoint: desensitizedEndpoint,
242
+ error: error as any,
243
+ errorType: ErrorType.invalidAPIKey,
244
+ provider: provider as any,
245
+ });
246
+ }
247
+
248
+ default: {
249
+ break;
250
+ }
251
+ }
252
+ }
253
+
254
+ const { errorResult, RuntimeError } = handleOpenAIError(error);
255
+
256
+ return AgentRuntimeError.chat({
257
+ endpoint: desensitizedEndpoint,
258
+ error: errorResult,
259
+ errorType: RuntimeError || ErrorType.bizError,
260
+ provider: provider as any,
261
+ });
262
+ }
292
263
  };
293
264
  };
@@ -29,7 +29,7 @@ export class LobeZhipuAI implements LobeRuntimeAI {
29
29
  this.baseURL = this.client.baseURL;
30
30
  }
31
31
 
32
- static async fromAPIKey({ apiKey, baseURL = DEFAULT_BASE_URL, ...res }: ClientOptions) {
32
+ static async fromAPIKey({ apiKey, baseURL = DEFAULT_BASE_URL, ...res }: ClientOptions = {}) {
33
33
  const invalidZhipuAPIKey = AgentRuntimeError.createError(
34
34
  AgentRuntimeErrorType.InvalidProviderAPIKey,
35
35
  );