@lobehub/lobehub 2.0.0-next.186 → 2.0.0-next.187

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.
Files changed (31) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/changelog/v1.json +9 -0
  3. package/package.json +1 -1
  4. package/packages/fetch-sse/src/__tests__/request.test.ts +608 -0
  5. package/packages/model-bank/src/aiModels/aihubmix.ts +44 -8
  6. package/packages/model-bank/src/aiModels/google.ts +49 -17
  7. package/packages/model-bank/src/aiModels/hunyuan.ts +20 -0
  8. package/packages/model-bank/src/aiModels/infiniai.ts +48 -7
  9. package/packages/model-bank/src/aiModels/lobehub.ts +13 -11
  10. package/packages/model-bank/src/aiModels/minimax.ts +46 -2
  11. package/packages/model-bank/src/aiModels/ollamacloud.ts +40 -5
  12. package/packages/model-bank/src/aiModels/openai.ts +6 -3
  13. package/packages/model-bank/src/aiModels/qwen.ts +1 -1
  14. package/packages/model-bank/src/aiModels/siliconcloud.ts +60 -0
  15. package/packages/model-bank/src/aiModels/vertexai.ts +77 -44
  16. package/packages/model-bank/src/aiModels/volcengine.ts +111 -2
  17. package/packages/model-bank/src/aiModels/zenmux.ts +19 -13
  18. package/packages/model-bank/src/aiModels/zhipu.ts +64 -2
  19. package/packages/model-bank/src/types/aiModel.ts +3 -0
  20. package/packages/model-runtime/src/providers/volcengine/index.ts +2 -1
  21. package/packages/model-runtime/src/providers/zhipu/index.test.ts +0 -27
  22. package/packages/model-runtime/src/providers/zhipu/index.ts +1 -1
  23. package/packages/model-runtime/src/utils/modelParse.ts +26 -21
  24. package/packages/types/src/agent/chatConfig.ts +6 -2
  25. package/src/features/ChatInput/ActionBar/Model/ControlsForm.tsx +40 -1
  26. package/src/features/ChatInput/ActionBar/Model/GPT52ProReasoningEffortSlider.tsx +59 -0
  27. package/src/features/ChatInput/ActionBar/Model/GPT52ReasoningEffortSlider.tsx +61 -0
  28. package/src/features/ChatInput/ActionBar/Model/TextVerbositySlider.tsx +1 -1
  29. package/src/features/ChatInput/ActionBar/Model/ThinkingLevel2Slider.tsx +58 -0
  30. package/src/features/ChatInput/ActionBar/Model/ThinkingLevelSlider.tsx +10 -8
  31. package/src/services/chat/mecha/modelParamsResolver.ts +11 -0
@@ -382,33 +382,6 @@ describe('LobeZhipuAI - custom features', () => {
382
382
  expect.anything(),
383
383
  );
384
384
  });
385
-
386
- it('should not include thinking for non-4.5 models', async () => {
387
- await instance.chat({
388
- messages: [{ content: 'Hello', role: 'user' }],
389
- model: 'glm-4',
390
- temperature: 0.5,
391
- thinking: { type: 'enabled', budget_tokens: 1000 },
392
- });
393
-
394
- const callArgs = (instance['client'].chat.completions.create as any).mock.calls[0][0];
395
- expect(callArgs.thinking).toBeUndefined();
396
- });
397
-
398
- it('should handle undefined thinking gracefully for 4.5 models', async () => {
399
- await instance.chat({
400
- messages: [{ content: 'Hello', role: 'user' }],
401
- model: 'glm-4.5',
402
- temperature: 0.5,
403
- });
404
-
405
- expect(instance['client'].chat.completions.create).toHaveBeenCalledWith(
406
- expect.objectContaining({
407
- thinking: { type: undefined },
408
- }),
409
- expect.anything(),
410
- );
411
- });
412
385
  });
413
386
 
414
387
  describe('Stream parameter', () => {
@@ -61,7 +61,7 @@ export const params = {
61
61
  ...resolvedParams,
62
62
  model,
63
63
  stream: true,
64
- thinking: model.includes('-4.5') ? { type: thinking?.type } : undefined,
64
+ thinking: thinking ? { type: thinking.type } : undefined,
65
65
  tools: zhipuTools,
66
66
  } as any;
67
67
  },
@@ -38,9 +38,9 @@ export const MODEL_LIST_CONFIGS = {
38
38
  excludeKeywords: ['tts'],
39
39
  functionCallKeywords: ['gemini', '!-image-'],
40
40
  imageOutputKeywords: ['-image-'],
41
- reasoningKeywords: ['thinking', '-2.5-', '!-image-'],
41
+ reasoningKeywords: ['thinking', '-2.5-', '!-image-', '-3-'],
42
42
  searchKeywords: ['-search', '!-image-'],
43
- videoKeywords: ['-2.5-', '!-image-'],
43
+ videoKeywords: ['-2.5-', '!-image-', '-3-'],
44
44
  visionKeywords: ['gemini', 'learnlm'],
45
45
  },
46
46
  inclusionai: {
@@ -126,8 +126,8 @@ export const MODEL_LIST_CONFIGS = {
126
126
  },
127
127
  zhipu: {
128
128
  functionCallKeywords: ['glm-4', 'glm-z1'],
129
- reasoningKeywords: ['glm-zero', 'glm-z1', 'glm-4.5'],
130
- visionKeywords: ['glm-4v', 'glm-4.1v', 'glm-4.5v'],
129
+ reasoningKeywords: ['glm-zero', 'glm-z1', 'glm-4.'],
130
+ visionKeywords: ['re:glm-4(\\.\\d)?v'],
131
131
  },
132
132
  } as const;
133
133
 
@@ -183,36 +183,41 @@ export const EMBEDDING_MODEL_KEYWORDS = ['embedding', 'embed', 'bge', 'm3e'] as
183
183
  * @param keywords 关键词列表,支持以下前缀:
184
184
  * - ^ 开头:只在模型ID开头匹配
185
185
  * - ! 开头:排除匹配,优先级最高
186
+ * - re: 开头:正则表达式匹配(支持 !re: 正则排除)
186
187
  * - 无前缀:包含匹配(默认行为)
187
188
  * @returns 是否匹配(排除逻辑优先)
188
189
  */
189
190
  const isKeywordListMatch = (modelId: string, keywords: readonly string[]): boolean => {
190
- // 先检查排除规则(感叹号开头)
191
+ const matchKeyword = (keyword: string): boolean => {
192
+ const rawKeyword = keyword.startsWith('!') ? keyword.slice(1) : keyword;
193
+
194
+ if (rawKeyword.startsWith('re:')) {
195
+ try {
196
+ return new RegExp(rawKeyword.slice(3)).test(modelId);
197
+ } catch {
198
+ return false;
199
+ }
200
+ }
201
+
202
+ if (rawKeyword.startsWith('^')) {
203
+ return modelId.startsWith(rawKeyword.slice(1));
204
+ }
205
+
206
+ return modelId.includes(rawKeyword);
207
+ };
208
+
209
+ // 先检查排除规则(感叹号开头,包括 !re:)
191
210
  const excludeKeywords = keywords.filter((keyword) => keyword.startsWith('!'));
192
211
  const includeKeywords = keywords.filter((keyword) => !keyword.startsWith('!'));
193
212
 
194
- // 如果匹配任何排除规则,直接返回 false
195
213
  for (const excludeKeyword of excludeKeywords) {
196
- const keywordWithoutPrefix = excludeKeyword.slice(1);
197
- const isMatch = keywordWithoutPrefix.startsWith('^')
198
- ? modelId.startsWith(keywordWithoutPrefix.slice(1))
199
- : modelId.includes(keywordWithoutPrefix);
200
-
201
- if (isMatch) {
214
+ if (matchKeyword(excludeKeyword)) {
202
215
  return false;
203
216
  }
204
217
  }
205
218
 
206
219
  // 检查包含规则
207
- return includeKeywords.some((keyword) => {
208
- if (keyword.startsWith('^')) {
209
- // ^ 开头则只在开头匹配
210
- const keywordWithoutPrefix = keyword.slice(1);
211
- return modelId.startsWith(keywordWithoutPrefix);
212
- }
213
- // 默认行为:包含匹配
214
- return modelId.includes(keyword);
215
- });
220
+ return includeKeywords.some((keyword) => matchKeyword(keyword));
216
221
  };
217
222
 
218
223
  /**
@@ -31,12 +31,14 @@ export interface LobeAgentChatConfig {
31
31
  reasoningEffort?: 'low' | 'medium' | 'high';
32
32
  gpt5ReasoningEffort?: 'minimal' | 'low' | 'medium' | 'high';
33
33
  gpt5_1ReasoningEffort?: 'none' | 'low' | 'medium' | 'high';
34
+ gpt5_2ReasoningEffort?: 'none' | 'low' | 'medium' | 'high' | 'xhigh';
35
+ gpt5_2ProReasoningEffort?: 'medium' | 'high' | 'xhigh';
34
36
  /**
35
37
  * Output text verbosity control
36
38
  */
37
39
  textVerbosity?: 'low' | 'medium' | 'high';
38
40
  thinking?: 'disabled' | 'auto' | 'enabled';
39
- thinkingLevel?: 'low' | 'high';
41
+ thinkingLevel?: 'minimal' | 'low' | 'medium' | 'high';
40
42
  thinkingBudget?: number;
41
43
  /**
42
44
  * Image aspect ratio for image generation models
@@ -84,6 +86,8 @@ export const AgentChatConfigSchema = z.object({
84
86
  enableStreaming: z.boolean().optional(),
85
87
  gpt5ReasoningEffort: z.enum(['minimal', 'low', 'medium', 'high']).optional(),
86
88
  gpt5_1ReasoningEffort: z.enum(['none', 'low', 'medium', 'high']).optional(),
89
+ gpt5_2ProReasoningEffort: z.enum(['medium', 'high', 'xhigh']).optional(),
90
+ gpt5_2ReasoningEffort: z.enum(['none', 'low', 'medium', 'high', 'xhigh']).optional(),
87
91
  historyCount: z.number().optional(),
88
92
  imageAspectRatio: z.string().optional(),
89
93
  imageResolution: z.enum(['1K', '2K', '4K']).optional(),
@@ -99,7 +103,7 @@ export const AgentChatConfigSchema = z.object({
99
103
  textVerbosity: z.enum(['low', 'medium', 'high']).optional(),
100
104
  thinking: z.enum(['disabled', 'auto', 'enabled']).optional(),
101
105
  thinkingBudget: z.number().optional(),
102
- thinkingLevel: z.enum(['low', 'high']).optional(),
106
+ thinkingLevel: z.enum(['minimal', 'low', 'medium', 'high']).optional(),
103
107
  urlContext: z.boolean().optional(),
104
108
  useModelBuiltinSearch: z.boolean().optional(),
105
109
  });
@@ -15,12 +15,15 @@ import { useUpdateAgentConfig } from '../../hooks/useUpdateAgentConfig';
15
15
  import ContextCachingSwitch from './ContextCachingSwitch';
16
16
  import GPT5ReasoningEffortSlider from './GPT5ReasoningEffortSlider';
17
17
  import GPT51ReasoningEffortSlider from './GPT51ReasoningEffortSlider';
18
+ import GPT52ProReasoningEffortSlider from './GPT52ProReasoningEffortSlider';
19
+ import GPT52ReasoningEffortSlider from './GPT52ReasoningEffortSlider';
18
20
  import ImageAspectRatioSelect from './ImageAspectRatioSelect';
19
21
  import ImageResolutionSlider from './ImageResolutionSlider';
20
22
  import ReasoningEffortSlider from './ReasoningEffortSlider';
21
23
  import ReasoningTokenSlider from './ReasoningTokenSlider';
22
24
  import TextVerbositySlider from './TextVerbositySlider';
23
25
  import ThinkingBudgetSlider from './ThinkingBudgetSlider';
26
+ import ThinkingLevel2Slider from './ThinkingLevel2Slider';
24
27
  import ThinkingLevelSlider from './ThinkingLevelSlider';
25
28
  import ThinkingSlider from './ThinkingSlider';
26
29
 
@@ -140,6 +143,28 @@ const ControlsForm = memo(() => {
140
143
  paddingBottom: 0,
141
144
  },
142
145
  },
146
+ {
147
+ children: <GPT52ReasoningEffortSlider />,
148
+ desc: 'reasoning_effort',
149
+ label: t('extendParams.reasoningEffort.title'),
150
+ layout: 'horizontal',
151
+ minWidth: undefined,
152
+ name: 'gpt5_2ReasoningEffort',
153
+ style: {
154
+ paddingBottom: 0,
155
+ },
156
+ },
157
+ {
158
+ children: <GPT52ProReasoningEffortSlider />,
159
+ desc: 'reasoning_effort',
160
+ label: t('extendParams.reasoningEffort.title'),
161
+ layout: 'horizontal',
162
+ minWidth: undefined,
163
+ name: 'gpt5_2ProReasoningEffort',
164
+ style: {
165
+ paddingBottom: 0,
166
+ },
167
+ },
143
168
  {
144
169
  children: <TextVerbositySlider />,
145
170
  desc: 'text_verbosity',
@@ -173,7 +198,7 @@ const ControlsForm = memo(() => {
173
198
  layout: isNarrow ? 'vertical' : 'horizontal',
174
199
  minWidth: undefined,
175
200
  name: 'urlContext',
176
- style: isNarrow ? undefined : { width: 445 },
201
+ style: isNarrow ? undefined : { minWidth: 360 },
177
202
  tag: 'urlContext',
178
203
  },
179
204
  {
@@ -193,8 +218,22 @@ const ControlsForm = memo(() => {
193
218
  minWidth: undefined,
194
219
  name: 'thinkingLevel',
195
220
  style: {
221
+ minWidth: 400,
222
+ paddingBottom: 0,
223
+ },
224
+ tag: 'thinkingLevel',
225
+ },
226
+ {
227
+ children: <ThinkingLevel2Slider />,
228
+ label: t('extendParams.thinkingLevel.title'),
229
+ layout: 'horizontal',
230
+ minWidth: undefined,
231
+ name: 'thinkingLevel2',
232
+ style: {
233
+ minWidth: 400,
196
234
  paddingBottom: 0,
197
235
  },
236
+ tag: 'thinkingLevel',
198
237
  },
199
238
  {
200
239
  children: <ImageAspectRatioSelect />,
@@ -0,0 +1,59 @@
1
+ import { Flexbox } from '@lobehub/ui';
2
+ import { Slider } from 'antd';
3
+ import { memo, useCallback } from 'react';
4
+
5
+ import { useAgentStore } from '@/store/agent';
6
+ import { chatConfigByIdSelectors } from '@/store/agent/selectors';
7
+
8
+ import { useAgentId } from '../../hooks/useAgentId';
9
+ import { useUpdateAgentConfig } from '../../hooks/useUpdateAgentConfig';
10
+
11
+ const GPT52ProReasoningEffortSlider = memo(() => {
12
+ const agentId = useAgentId();
13
+ const { updateAgentChatConfig } = useUpdateAgentConfig();
14
+ const config = useAgentStore((s) => chatConfigByIdSelectors.getChatConfigById(agentId)(s));
15
+
16
+ const gpt5_2ProReasoningEffort = config.gpt5_2ProReasoningEffort || 'medium';
17
+
18
+ const marks = {
19
+ 0: 'medium',
20
+ 1: 'high',
21
+ 2: 'xhigh',
22
+ };
23
+
24
+ const effortValues = ['medium', 'high', 'xhigh'];
25
+ const indexValue = effortValues.indexOf(gpt5_2ProReasoningEffort);
26
+ const currentValue = indexValue === -1 ? 0 : indexValue;
27
+
28
+ const updateGPT52ProReasoningEffort = useCallback(
29
+ (value: number) => {
30
+ const effort = effortValues[value] as 'medium' | 'high' | 'xhigh';
31
+ updateAgentChatConfig({ gpt5_2ProReasoningEffort: effort });
32
+ },
33
+ [updateAgentChatConfig],
34
+ );
35
+
36
+ return (
37
+ <Flexbox
38
+ align={'center'}
39
+ gap={12}
40
+ horizontal
41
+ paddingInline={'0 20px'}
42
+ style={{ minWidth: 160, width: '100%' }}
43
+ >
44
+ <Flexbox flex={1}>
45
+ <Slider
46
+ marks={marks}
47
+ max={2}
48
+ min={0}
49
+ onChange={updateGPT52ProReasoningEffort}
50
+ step={1}
51
+ tooltip={{ open: false }}
52
+ value={currentValue}
53
+ />
54
+ </Flexbox>
55
+ </Flexbox>
56
+ );
57
+ });
58
+
59
+ export default GPT52ProReasoningEffortSlider;
@@ -0,0 +1,61 @@
1
+ import { Flexbox } from '@lobehub/ui';
2
+ import { Slider } from 'antd';
3
+ import { memo, useCallback } from 'react';
4
+
5
+ import { useAgentStore } from '@/store/agent';
6
+ import { chatConfigByIdSelectors } from '@/store/agent/selectors';
7
+
8
+ import { useAgentId } from '../../hooks/useAgentId';
9
+ import { useUpdateAgentConfig } from '../../hooks/useUpdateAgentConfig';
10
+
11
+ const GPT52ReasoningEffortSlider = memo(() => {
12
+ const agentId = useAgentId();
13
+ const { updateAgentChatConfig } = useUpdateAgentConfig();
14
+ const config = useAgentStore((s) => chatConfigByIdSelectors.getChatConfigById(agentId)(s));
15
+
16
+ const gpt5_2ReasoningEffort = config.gpt5_2ReasoningEffort || 'none';
17
+
18
+ const marks = {
19
+ 0: 'none',
20
+ 1: 'low',
21
+ 2: 'medium',
22
+ 3: 'high',
23
+ 4: 'xhigh',
24
+ };
25
+
26
+ const effortValues = ['none', 'low', 'medium', 'high', 'xhigh'];
27
+ const indexValue = effortValues.indexOf(gpt5_2ReasoningEffort);
28
+ const currentValue = indexValue === -1 ? 0 : indexValue;
29
+
30
+ const updateGPT52ReasoningEffort = useCallback(
31
+ (value: number) => {
32
+ const effort = effortValues[value] as 'none' | 'low' | 'medium' | 'high' | 'xhigh';
33
+ updateAgentChatConfig({ gpt5_2ReasoningEffort: effort });
34
+ },
35
+ [updateAgentChatConfig],
36
+ );
37
+
38
+ return (
39
+ <Flexbox
40
+ align={'center'}
41
+ gap={12}
42
+ horizontal
43
+ paddingInline={'0 20px'}
44
+ style={{ minWidth: 230, width: '100%' }}
45
+ >
46
+ <Flexbox flex={1}>
47
+ <Slider
48
+ marks={marks}
49
+ max={4}
50
+ min={0}
51
+ onChange={updateGPT52ReasoningEffort}
52
+ step={1}
53
+ tooltip={{ open: false }}
54
+ value={currentValue}
55
+ />
56
+ </Flexbox>
57
+ </Flexbox>
58
+ );
59
+ });
60
+
61
+ export default GPT52ReasoningEffortSlider;
@@ -39,7 +39,7 @@ const TextVerbositySlider = memo(() => {
39
39
  gap={12}
40
40
  horizontal
41
41
  paddingInline={'0 20px'}
42
- style={{ minWidth: 200, width: '100%' }}
42
+ style={{ minWidth: 160, width: '100%' }}
43
43
  >
44
44
  <Flexbox flex={1}>
45
45
  <Slider
@@ -0,0 +1,58 @@
1
+ import { Flexbox } from '@lobehub/ui';
2
+ import { Slider } from 'antd';
3
+ import { memo, useCallback } from 'react';
4
+
5
+ import { useAgentStore } from '@/store/agent';
6
+ import { chatConfigByIdSelectors } from '@/store/agent/selectors';
7
+
8
+ import { useAgentId } from '../../hooks/useAgentId';
9
+ import { useUpdateAgentConfig } from '../../hooks/useUpdateAgentConfig';
10
+
11
+ const ThinkingLevel2Slider = memo(() => {
12
+ const agentId = useAgentId();
13
+ const { updateAgentChatConfig } = useUpdateAgentConfig();
14
+ const config = useAgentStore((s) => chatConfigByIdSelectors.getChatConfigById(agentId)(s));
15
+
16
+ const thinkingLevel = config.thinkingLevel || 'high'; // Default to 'high' if not set
17
+
18
+ const marks = {
19
+ 0: 'low',
20
+ 1: 'high',
21
+ };
22
+
23
+ const levelValues = ['low', 'high'];
24
+ const indexValue = levelValues.indexOf(thinkingLevel as any);
25
+ const currentValue = indexValue === -1 ? 1 : indexValue;
26
+
27
+ const updateThinkingLevel = useCallback(
28
+ (value: number) => {
29
+ const level = levelValues[value] as 'low' | 'high';
30
+ updateAgentChatConfig({ thinkingLevel: level });
31
+ },
32
+ [updateAgentChatConfig],
33
+ );
34
+
35
+ return (
36
+ <Flexbox
37
+ align={'center'}
38
+ gap={12}
39
+ horizontal
40
+ paddingInline={'0 20px'}
41
+ style={{ minWidth: 110, width: '100%' }}
42
+ >
43
+ <Flexbox flex={1}>
44
+ <Slider
45
+ marks={marks}
46
+ max={1}
47
+ min={0}
48
+ onChange={updateThinkingLevel}
49
+ step={1}
50
+ tooltip={{ open: false }}
51
+ value={currentValue}
52
+ />
53
+ </Flexbox>
54
+ </Flexbox>
55
+ );
56
+ });
57
+
58
+ export default ThinkingLevel2Slider;
@@ -16,17 +16,19 @@ const ThinkingLevelSlider = memo(() => {
16
16
  const thinkingLevel = config.thinkingLevel || 'high'; // Default to 'high' if not set
17
17
 
18
18
  const marks = {
19
- 0: 'low',
20
- 1: 'high',
19
+ 0: 'minimal',
20
+ 1: 'low',
21
+ 2: 'medium',
22
+ 3: 'high',
21
23
  };
22
24
 
23
- const levelValues = ['low', 'high'];
24
- const indexValue = levelValues.indexOf(thinkingLevel);
25
- const currentValue = indexValue === -1 ? 1 : indexValue;
25
+ const levelValues = ['minimal', 'low', 'medium', 'high'];
26
+ const indexValue = levelValues.indexOf(thinkingLevel as any);
27
+ const currentValue = indexValue === -1 ? 3 : indexValue;
26
28
 
27
29
  const updateThinkingLevel = useCallback(
28
30
  (value: number) => {
29
- const level = levelValues[value] as 'low' | 'high';
31
+ const level = levelValues[value] as 'minimal' | 'low' | 'medium' | 'high';
30
32
  updateAgentChatConfig({ thinkingLevel: level });
31
33
  },
32
34
  [updateAgentChatConfig],
@@ -38,12 +40,12 @@ const ThinkingLevelSlider = memo(() => {
38
40
  gap={12}
39
41
  horizontal
40
42
  paddingInline={'0 20px'}
41
- style={{ minWidth: 130, width: '100%' }} // 三项时宽度需改回 200
43
+ style={{ minWidth: 200, width: '100%' }}
42
44
  >
43
45
  <Flexbox flex={1}>
44
46
  <Slider
45
47
  marks={marks}
46
- max={1}
48
+ max={3}
47
49
  min={0}
48
50
  onChange={updateThinkingLevel}
49
51
  step={1}
@@ -95,6 +95,17 @@ export const resolveModelExtendParams = (ctx: ModelParamsContext): ModelExtendPa
95
95
  extendParams.reasoning_effort = chatConfig.gpt5_1ReasoningEffort;
96
96
  }
97
97
 
98
+ if (modelExtendParams.includes('gpt5_2ReasoningEffort') && chatConfig.gpt5_2ReasoningEffort) {
99
+ extendParams.reasoning_effort = chatConfig.gpt5_2ReasoningEffort;
100
+ }
101
+
102
+ if (
103
+ modelExtendParams.includes('gpt5_2ProReasoningEffort') &&
104
+ chatConfig.gpt5_2ProReasoningEffort
105
+ ) {
106
+ extendParams.reasoning_effort = chatConfig.gpt5_2ProReasoningEffort;
107
+ }
108
+
98
109
  // Text verbosity
99
110
  if (modelExtendParams.includes('textVerbosity') && chatConfig.textVerbosity) {
100
111
  extendParams.verbosity = chatConfig.textVerbosity;