@lobehub/lobehub 2.0.0-next.52 → 2.0.0-next.54

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 (39) hide show
  1. package/CHANGELOG.md +58 -0
  2. package/README.md +8 -8
  3. package/README.zh-CN.md +8 -8
  4. package/apps/desktop/package.json +1 -1
  5. package/changelog/v1.json +21 -0
  6. package/package.json +2 -2
  7. package/packages/const/src/models.ts +2 -0
  8. package/packages/electron-server-ipc/src/ipcClient.ts +31 -31
  9. package/packages/electron-server-ipc/src/ipcServer.ts +15 -15
  10. package/packages/model-bank/src/aiModels/aihubmix.ts +106 -2
  11. package/packages/model-bank/src/aiModels/openai.ts +107 -3
  12. package/packages/model-bank/src/aiModels/qwen.ts +76 -7
  13. package/packages/model-bank/src/types/aiModel.ts +1 -0
  14. package/packages/types/src/agent/chatConfig.ts +9 -0
  15. package/src/app/[variants]/(main)/chat/components/WorkspaceLayout.tsx +32 -23
  16. package/src/features/ChatInput/ActionBar/Model/ControlsForm.tsx +12 -0
  17. package/src/features/ChatInput/ActionBar/Model/GPT51ReasoningEffortSlider.tsx +58 -0
  18. package/src/features/ChatItem/components/MessageContent.tsx +3 -1
  19. package/src/features/Conversation/Messages/Assistant/index.tsx +7 -1
  20. package/src/features/Conversation/Messages/Group/Tool/Render/Intervention/ApprovalActions.tsx +34 -13
  21. package/src/features/Conversation/Messages/User/index.tsx +11 -1
  22. package/src/libs/mcp/__tests__/__snapshots__/index.test.ts.snap +0 -6
  23. package/src/locales/default/chat.ts +2 -0
  24. package/src/locales/default/tool.ts +8 -0
  25. package/src/services/chat/index.ts +7 -0
  26. package/src/store/chat/slices/aiChat/actions/conversationControl.ts +42 -0
  27. package/src/store/chat/slices/builtinTool/actions/localSystem.ts +1 -1
  28. package/src/tools/interventions.ts +3 -5
  29. package/src/tools/local-system/Intervention/MoveLocalFiles/MoveFileItem.tsx +56 -0
  30. package/src/tools/local-system/Intervention/MoveLocalFiles/index.tsx +26 -0
  31. package/src/tools/local-system/Intervention/RunCommand/index.tsx +3 -5
  32. package/src/tools/local-system/Intervention/index.ts +11 -0
  33. package/src/tools/local-system/Render/MoveLocalFiles/MoveFileItem.tsx +56 -0
  34. package/src/tools/local-system/Render/MoveLocalFiles/index.tsx +26 -0
  35. package/src/tools/local-system/Render/ReadLocalFile/ReadFileView.tsx +2 -1
  36. package/src/tools/local-system/Render/index.ts +21 -0
  37. package/src/tools/local-system/index.ts +1 -0
  38. package/src/tools/renders.ts +6 -24
  39. package/src/tools/web-browsing/Render/index.ts +13 -0
@@ -18,6 +18,112 @@ export const gptImage1ParamsSchema: ModelParamsSchema = {
18
18
  };
19
19
 
20
20
  export const openaiChatModels: AIChatModelCard[] = [
21
+ {
22
+ abilities: {
23
+ functionCall: true,
24
+ imageOutput: true,
25
+ reasoning: true,
26
+ search: true,
27
+ vision: true,
28
+ },
29
+ contextWindowTokens: 400_000,
30
+ description:
31
+ 'GPT-5.1 — 针对编码和 agent 任务优化的旗舰模型,支持可配置的推理强度与更长上下文。',
32
+ displayName: 'GPT-5.1',
33
+ enabled: true,
34
+ id: 'gpt-5.1',
35
+ maxOutput: 128_000,
36
+ pricing: {
37
+ units: [
38
+ { name: 'textInput', rate: 1.25, strategy: 'fixed', unit: 'millionTokens' },
39
+ { name: 'textInput_cacheRead', rate: 0.125, strategy: 'fixed', unit: 'millionTokens' },
40
+ { name: 'textOutput', rate: 10, strategy: 'fixed', unit: 'millionTokens' },
41
+ ],
42
+ },
43
+ releasedAt: '2025-11-13',
44
+ settings: {
45
+ extendParams: ['gpt5_1ReasoningEffort', 'textVerbosity'],
46
+ searchImpl: 'params',
47
+ },
48
+ type: 'chat',
49
+ },
50
+ {
51
+ abilities: {
52
+ functionCall: true,
53
+ vision: true,
54
+ },
55
+ contextWindowTokens: 128_000,
56
+ description: 'GPT-5.1 Chat:用于 ChatGPT 的 GPT-5.1 变体,适合聊天场景。',
57
+ displayName: 'GPT-5.1 Chat',
58
+ enabled: true,
59
+ id: 'gpt-5.1-chat-latest',
60
+ maxOutput: 16_384,
61
+ pricing: {
62
+ units: [
63
+ { name: 'textInput', rate: 1.25, strategy: 'fixed', unit: 'millionTokens' },
64
+ { name: 'textInput_cacheRead', rate: 0.125, strategy: 'fixed', unit: 'millionTokens' },
65
+ { name: 'textOutput', rate: 10, strategy: 'fixed', unit: 'millionTokens' },
66
+ ],
67
+ },
68
+ releasedAt: '2025-11-13',
69
+ type: 'chat',
70
+ },
71
+ {
72
+ abilities: {
73
+ functionCall: true,
74
+ imageOutput: true,
75
+ reasoning: true,
76
+ search: true,
77
+ vision: true,
78
+ },
79
+ contextWindowTokens: 400_000,
80
+ description:
81
+ 'GPT-5.1 Codex:针对 agentic 编码任务优化的 GPT-5.1 版本,可在 Responses API 中用于更复杂的代码/代理工作流。',
82
+ displayName: 'GPT-5.1 Codex',
83
+ id: 'gpt-5.1-codex',
84
+ maxOutput: 128_000,
85
+ pricing: {
86
+ units: [
87
+ { name: 'textInput', rate: 1.25, strategy: 'fixed', unit: 'millionTokens' },
88
+ { name: 'textInput_cacheRead', rate: 0.125, strategy: 'fixed', unit: 'millionTokens' },
89
+ { name: 'textOutput', rate: 10, strategy: 'fixed', unit: 'millionTokens' },
90
+ ],
91
+ },
92
+ releasedAt: '2025-11-13',
93
+ settings: {
94
+ extendParams: ['gpt5_1ReasoningEffort'],
95
+ searchImpl: 'params',
96
+ },
97
+ type: 'chat',
98
+ },
99
+ {
100
+ abilities: {
101
+ functionCall: true,
102
+ imageOutput: true,
103
+ reasoning: true,
104
+ search: true,
105
+ vision: true,
106
+ },
107
+ contextWindowTokens: 400_000,
108
+ description:
109
+ 'GPT-5.1 Codex mini:体积更小、成本更低的 Codex 变体,针对 agentic 编码任务进行了优化。',
110
+ displayName: 'GPT-5.1 Codex mini',
111
+ id: 'gpt-5.1-codex-mini',
112
+ maxOutput: 128_000,
113
+ pricing: {
114
+ units: [
115
+ { name: 'textInput', rate: 0.25, strategy: 'fixed', unit: 'millionTokens' },
116
+ { name: 'textInput_cacheRead', rate: 0.025, strategy: 'fixed', unit: 'millionTokens' },
117
+ { name: 'textOutput', rate: 2, strategy: 'fixed', unit: 'millionTokens' },
118
+ ],
119
+ },
120
+ releasedAt: '2025-11-13',
121
+ settings: {
122
+ extendParams: ['gpt5_1ReasoningEffort'],
123
+ searchImpl: 'params',
124
+ },
125
+ type: 'chat',
126
+ },
21
127
  {
22
128
  abilities: {
23
129
  functionCall: true,
@@ -64,7 +170,7 @@ export const openaiChatModels: AIChatModelCard[] = [
64
170
  },
65
171
  releasedAt: '2024-09-15',
66
172
  settings: {
67
- extendParams: ['gpt5ReasoningEffort', 'textVerbosity'],
173
+ extendParams: ['gpt5ReasoningEffort'],
68
174
  searchImpl: 'params',
69
175
  },
70
176
  type: 'chat',
@@ -81,7 +187,6 @@ export const openaiChatModels: AIChatModelCard[] = [
81
187
  description:
82
188
  '跨领域编码和代理任务的最佳模型。GPT-5 在准确性、速度、推理、上下文识别、结构化思维和问题解决方面实现了飞跃。',
83
189
  displayName: 'GPT-5',
84
- enabled: true,
85
190
  id: 'gpt-5',
86
191
  maxOutput: 128_000,
87
192
  pricing: {
@@ -159,7 +264,6 @@ export const openaiChatModels: AIChatModelCard[] = [
159
264
  description:
160
265
  'ChatGPT 中使用的 GPT-5 模型。结合了强大的语言理解与生成能力,适合对话式交互应用。',
161
266
  displayName: 'GPT-5 Chat',
162
- enabled: true,
163
267
  id: 'gpt-5-chat-latest',
164
268
  maxOutput: 128_000,
165
269
  pricing: {
@@ -1016,6 +1016,71 @@ const qwenChatModels: AIChatModelCard[] = [
1016
1016
  id: 'qwen3-max',
1017
1017
  maxOutput: 65_536,
1018
1018
  organization: 'Qwen',
1019
+ pricing: {
1020
+ currency: 'CNY',
1021
+ units: [
1022
+ {
1023
+ lookup: {
1024
+ prices: {
1025
+ '[0, 0.032]': 3.2 * 0.2,
1026
+ '[0.032, 0.128]': 6.4 * 0.2,
1027
+ '[0.128, infinity]': 9.6 * 0.2,
1028
+ },
1029
+ pricingParams: ['textInputRange'],
1030
+ },
1031
+ name: 'textInput_cacheRead',
1032
+ strategy: 'lookup',
1033
+ unit: 'millionTokens',
1034
+ },
1035
+ {
1036
+ lookup: {
1037
+ prices: {
1038
+ '[0, 0.032]': 3.2,
1039
+ '[0.032, 0.128]': 6.4,
1040
+ '[0.128, infinity]': 9.6,
1041
+ },
1042
+ pricingParams: ['textInputRange'],
1043
+ },
1044
+ name: 'textInput',
1045
+ strategy: 'lookup',
1046
+ unit: 'millionTokens',
1047
+ },
1048
+ {
1049
+ lookup: {
1050
+ prices: {
1051
+ '[0, 0.032]': 12.8,
1052
+ '[0.032, 0.128]': 25.6,
1053
+ '[0.128, infinity]': 38.4,
1054
+ },
1055
+ pricingParams: ['textInputRange'],
1056
+ },
1057
+ name: 'textOutput',
1058
+ strategy: 'lookup',
1059
+ unit: 'millionTokens',
1060
+ },
1061
+ ],
1062
+ },
1063
+ releasedAt: '2025-09-23',
1064
+ settings: {
1065
+ searchImpl: 'params',
1066
+ },
1067
+ type: 'chat',
1068
+ },
1069
+ {
1070
+ abilities: {
1071
+ functionCall: true,
1072
+ reasoning: true,
1073
+ search: true,
1074
+ },
1075
+ config: {
1076
+ deploymentName: 'qwen3-max-preview', // 其支持上下文缓存
1077
+ },
1078
+ contextWindowTokens: 262_144,
1079
+ description: '通义千问系列效果最好的模型,适合复杂、多步骤的任务。预览版已支持思考。',
1080
+ displayName: 'Qwen3 Max Preview',
1081
+ id: 'qwen3-max-preview',
1082
+ maxOutput: 65_536,
1083
+ organization: 'Qwen',
1019
1084
  pricing: {
1020
1085
  currency: 'CNY',
1021
1086
  units: [
@@ -1060,8 +1125,9 @@ const qwenChatModels: AIChatModelCard[] = [
1060
1125
  },
1061
1126
  ],
1062
1127
  },
1063
- releasedAt: '2025-09-23',
1128
+ releasedAt: '2025-10-30',
1064
1129
  settings: {
1130
+ extendParams: ['enableReasoning', 'reasoningBudgetToken'],
1065
1131
  searchImpl: 'params',
1066
1132
  },
1067
1133
  type: 'chat',
@@ -1260,8 +1326,8 @@ const qwenChatModels: AIChatModelCard[] = [
1260
1326
  },
1261
1327
  {
1262
1328
  abilities: {
1263
- vision: true,
1264
1329
  reasoning: true,
1330
+ vision: true,
1265
1331
  },
1266
1332
  contextWindowTokens: 131_072,
1267
1333
  description:
@@ -1287,7 +1353,8 @@ const qwenChatModels: AIChatModelCard[] = [
1287
1353
  vision: true,
1288
1354
  },
1289
1355
  contextWindowTokens: 131_072,
1290
- description: 'Qwen3 VL 30B 非思考模式(Instruct),面向普通指令跟随场景,保持较高的多模态理解与生成能力。',
1356
+ description:
1357
+ 'Qwen3 VL 30B 非思考模式(Instruct),面向普通指令跟随场景,保持较高的多模态理解与生成能力。',
1291
1358
  displayName: 'Qwen3 VL 30B A3B Instruct',
1292
1359
  id: 'qwen3-vl-30b-a3b-instruct',
1293
1360
  maxOutput: 32_768,
@@ -1303,8 +1370,8 @@ const qwenChatModels: AIChatModelCard[] = [
1303
1370
  },
1304
1371
  {
1305
1372
  abilities: {
1306
- vision: true,
1307
1373
  reasoning: true,
1374
+ vision: true,
1308
1375
  },
1309
1376
  contextWindowTokens: 131_072,
1310
1377
  description: 'Qwen3 VL 8B 思考模式,面向轻量级多模态推理与交互场景,保留长上下文理解能力。',
@@ -1342,11 +1409,12 @@ const qwenChatModels: AIChatModelCard[] = [
1342
1409
  },
1343
1410
  {
1344
1411
  abilities: {
1345
- vision: true,
1346
1412
  reasoning: true,
1413
+ vision: true,
1347
1414
  },
1348
1415
  contextWindowTokens: 131_072,
1349
- description: 'Qwen3 VL 235B A22B 思考模式(开源版),针对高难度强推理与长视频理解场景,提供顶尖的视觉+文本推理能力。',
1416
+ description:
1417
+ 'Qwen3 VL 235B A22B 思考模式(开源版),针对高难度强推理与长视频理解场景,提供顶尖的视觉+文本推理能力。',
1350
1418
  displayName: 'Qwen3 VL 235B A22B Thinking',
1351
1419
  id: 'qwen3-vl-235b-a22b-thinking',
1352
1420
  maxOutput: 32_768,
@@ -1368,7 +1436,8 @@ const qwenChatModels: AIChatModelCard[] = [
1368
1436
  vision: true,
1369
1437
  },
1370
1438
  contextWindowTokens: 131_072,
1371
- description: 'Qwen3 VL 235B A22B 非思考模式(Instruct),适用于非思考指令场景,保持强大的视觉理解能力。',
1439
+ description:
1440
+ 'Qwen3 VL 235B A22B 非思考模式(Instruct),适用于非思考指令场景,保持强大的视觉理解能力。',
1372
1441
  displayName: 'Qwen3 VL 235B A22B Instruct',
1373
1442
  id: 'qwen3-vl-235b-a22b-instruct',
1374
1443
  maxOutput: 32_768,
@@ -234,6 +234,7 @@ export type ExtendParamsType =
234
234
  | 'disableContextCaching'
235
235
  | 'reasoningEffort'
236
236
  | 'gpt5ReasoningEffort'
237
+ | 'gpt5_1ReasoningEffort'
237
238
  | 'textVerbosity'
238
239
  | 'thinking'
239
240
  | 'thinkingBudget'
@@ -32,6 +32,7 @@ export interface LobeAgentChatConfig {
32
32
  reasoningBudgetToken?: number;
33
33
  reasoningEffort?: 'low' | 'medium' | 'high';
34
34
  gpt5ReasoningEffort?: 'minimal' | 'low' | 'medium' | 'high';
35
+ gpt5_1ReasoningEffort?: 'none' | 'low' | 'medium' | 'high';
35
36
  /**
36
37
  * 输出文本详细程度控制
37
38
  */
@@ -66,6 +67,7 @@ export interface LobeAgentChatConfig {
66
67
 
67
68
  export const AgentChatConfigSchema = z.object({
68
69
  autoCreateTopicThreshold: z.number().default(2),
70
+ disableContextCaching: z.boolean().optional(),
69
71
  displayMode: z.enum(['chat', 'docs']).optional(),
70
72
  enableAutoCreateTopic: z.boolean().optional(),
71
73
  enableCompressHistory: z.boolean().optional(),
@@ -74,8 +76,11 @@ export const AgentChatConfigSchema = z.object({
74
76
  enableReasoning: z.boolean().optional(),
75
77
  enableReasoningEffort: z.boolean().optional(),
76
78
  enableStreaming: z.boolean().optional(),
79
+ gpt5ReasoningEffort: z.enum(['minimal', 'low', 'medium', 'high']).optional(),
80
+ gpt5_1ReasoningEffort: z.enum(['none', 'low', 'medium', 'high']).optional(),
77
81
  historyCount: z.number().optional(),
78
82
  reasoningBudgetToken: z.number().optional(),
83
+ reasoningEffort: z.enum(['low', 'medium', 'high']).optional(),
79
84
  searchFCModel: z
80
85
  .object({
81
86
  model: z.string(),
@@ -84,4 +89,8 @@ export const AgentChatConfigSchema = z.object({
84
89
  .optional(),
85
90
  searchMode: z.enum(['off', 'on', 'auto']).optional(),
86
91
  textVerbosity: z.enum(['low', 'medium', 'high']).optional(),
92
+ thinking: z.enum(['disabled', 'auto', 'enabled']).optional(),
93
+ thinkingBudget: z.number().optional(),
94
+ urlContext: z.boolean().optional(),
95
+ useModelBuiltinSearch: z.boolean().optional(),
87
96
  });
@@ -1,3 +1,4 @@
1
+ import { useTheme } from 'antd-style';
1
2
  import { Suspense, memo } from 'react';
2
3
  import { Flexbox } from 'react-layout-kit';
3
4
 
@@ -18,30 +19,38 @@ interface WorkspaceLayoutProps {
18
19
  mobile?: boolean;
19
20
  }
20
21
 
21
- const DesktopWorkspace = memo(() => (
22
- <>
23
- <ChatHeaderDesktop />
24
- <Flexbox
25
- height={'100%'}
26
- horizontal
27
- style={{ overflow: 'hidden', position: 'relative' }}
28
- width={'100%'}
29
- >
30
- <Flexbox height={'100%'} style={{ overflow: 'hidden', position: 'relative' }} width={'100%'}>
31
- <ConversationArea mobile={false} />
22
+ const DesktopWorkspace = memo(() => {
23
+ const theme = useTheme();
24
+
25
+ return (
26
+ <>
27
+ <ChatHeaderDesktop />
28
+ <Flexbox
29
+ height={'100%'}
30
+ horizontal
31
+ style={{ overflow: 'hidden', position: 'relative' }}
32
+ width={'100%'}
33
+ >
34
+ <Flexbox
35
+ height={'100%'}
36
+ style={{ background: theme.colorBgContainer, overflow: 'hidden', position: 'relative' }}
37
+ width={'100%'}
38
+ >
39
+ <ConversationArea mobile={false} />
40
+ </Flexbox>
41
+ <Portal>
42
+ <Suspense fallback={<BrandTextLoading />}>
43
+ <PortalPanel mobile={false} />
44
+ </Suspense>
45
+ </Portal>
46
+ <TopicPanel>
47
+ <TopicSidebar mobile={false} />
48
+ </TopicPanel>
32
49
  </Flexbox>
33
- <Portal>
34
- <Suspense fallback={<BrandTextLoading />}>
35
- <PortalPanel mobile={false} />
36
- </Suspense>
37
- </Portal>
38
- <TopicPanel>
39
- <TopicSidebar mobile={false} />
40
- </TopicPanel>
41
- </Flexbox>
42
- <MainInterfaceTracker />
43
- </>
44
- ));
50
+ <MainInterfaceTracker />
51
+ </>
52
+ );
53
+ });
45
54
 
46
55
  DesktopWorkspace.displayName = 'DesktopWorkspace';
47
56
 
@@ -12,6 +12,7 @@ import { aiModelSelectors, useAiInfraStore } from '@/store/aiInfra';
12
12
 
13
13
  import ContextCachingSwitch from './ContextCachingSwitch';
14
14
  import GPT5ReasoningEffortSlider from './GPT5ReasoningEffortSlider';
15
+ import GPT51ReasoningEffortSlider from './GPT51ReasoningEffortSlider';
15
16
  import ReasoningEffortSlider from './ReasoningEffortSlider';
16
17
  import ReasoningTokenSlider from './ReasoningTokenSlider';
17
18
  import TextVerbositySlider from './TextVerbositySlider';
@@ -119,6 +120,17 @@ const ControlsForm = memo(() => {
119
120
  paddingBottom: 0,
120
121
  },
121
122
  },
123
+ {
124
+ children: <GPT51ReasoningEffortSlider />,
125
+ desc: 'reasoning_effort',
126
+ label: t('extendParams.reasoningEffort.title'),
127
+ layout: 'horizontal',
128
+ minWidth: undefined,
129
+ name: 'gpt5_1ReasoningEffort',
130
+ style: {
131
+ paddingBottom: 0,
132
+ },
133
+ },
122
134
  {
123
135
  children: <TextVerbositySlider />,
124
136
  desc: 'text_verbosity',
@@ -0,0 +1,58 @@
1
+ import { Slider } from 'antd';
2
+ import { memo, useCallback } from 'react';
3
+ import { Flexbox } from 'react-layout-kit';
4
+
5
+ import { useAgentStore } from '@/store/agent';
6
+ import { agentChatConfigSelectors } from '@/store/agent/selectors';
7
+
8
+ const GPT51ReasoningEffortSlider = memo(() => {
9
+ const [config, updateAgentChatConfig] = useAgentStore((s) => [
10
+ agentChatConfigSelectors.currentChatConfig(s),
11
+ s.updateAgentChatConfig,
12
+ ]);
13
+
14
+ const gpt5_1ReasoningEffort = config.gpt5_1ReasoningEffort || 'none'; // Default to 'none' if not set
15
+
16
+ const marks = {
17
+ 0: 'none',
18
+ 1: 'low',
19
+ 2: 'medium',
20
+ 3: 'high',
21
+ };
22
+
23
+ const effortValues = ['none', 'low', 'medium', 'high'];
24
+ const indexValue = effortValues.indexOf(gpt5_1ReasoningEffort);
25
+ const currentValue = indexValue === -1 ? 0 : indexValue;
26
+
27
+ const updateGPT51ReasoningEffort = useCallback(
28
+ (value: number) => {
29
+ const effort = effortValues[value] as 'none' | 'low' | 'medium' | 'high';
30
+ updateAgentChatConfig({ gpt5_1ReasoningEffort: effort });
31
+ },
32
+ [updateAgentChatConfig],
33
+ );
34
+
35
+ return (
36
+ <Flexbox
37
+ align={'center'}
38
+ gap={12}
39
+ horizontal
40
+ paddingInline={'0 20px'}
41
+ style={{ minWidth: 200, width: '100%' }}
42
+ >
43
+ <Flexbox flex={1}>
44
+ <Slider
45
+ marks={marks}
46
+ max={3}
47
+ min={0}
48
+ onChange={updateGPT51ReasoningEffort}
49
+ step={1}
50
+ tooltip={{ open: false }}
51
+ value={currentValue}
52
+ />
53
+ </Flexbox>
54
+ </Flexbox>
55
+ );
56
+ });
57
+
58
+ export default GPT51ReasoningEffortSlider;
@@ -13,6 +13,7 @@ import { useStyles } from '../style';
13
13
  import { ChatItemProps } from '../type';
14
14
 
15
15
  export interface MessageContentProps {
16
+ className?: string;
16
17
  disabled?: ChatItemProps['disabled'];
17
18
  editing?: ChatItemProps['editing'];
18
19
  id: string;
@@ -39,6 +40,7 @@ const MessageContent = memo<MessageContentProps>(
39
40
  onDoubleClick,
40
41
  markdownProps,
41
42
  disabled,
43
+ className,
42
44
  }) => {
43
45
  const { t } = useTranslation('common');
44
46
  const { cx, styles } = useStyles({ disabled, editing, placement, primary, variant });
@@ -81,7 +83,7 @@ const MessageContent = memo<MessageContentProps>(
81
83
 
82
84
  return (
83
85
  <Flexbox
84
- className={cx(styles.message, editing && styles.editingContainer)}
86
+ className={cx(styles.message, editing && styles.editingContainer, className)}
85
87
  onDoubleClick={onDoubleClick}
86
88
  >
87
89
  {messageContent}
@@ -3,7 +3,7 @@
3
3
  import { LOADING_FLAT } from '@lobechat/const';
4
4
  import { UIChatMessage } from '@lobechat/types';
5
5
  import { Tag } from '@lobehub/ui';
6
- import { useResponsive } from 'antd-style';
6
+ import { css, cx, useResponsive } from 'antd-style';
7
7
  import isEqual from 'fast-deep-equal';
8
8
  import { ReactNode, memo, useCallback, useMemo } from 'react';
9
9
  import { useTranslation } from 'react-i18next';
@@ -39,6 +39,11 @@ import { AssistantMessageContent } from './MessageContent';
39
39
  const rehypePlugins = markdownElements.map((element) => element.rehypePlugin).filter(Boolean);
40
40
  const remarkPlugins = markdownElements.map((element) => element.remarkPlugin).filter(Boolean);
41
41
 
42
+ const messageContainer = cx(css`
43
+ border: none;
44
+ background: none;
45
+ `);
46
+
42
47
  const isHtmlCode = (content: string, language: string) => {
43
48
  return (
44
49
  language === 'html' ||
@@ -248,6 +253,7 @@ const AssistantMessage = memo<AssistantMessageProps>(({ id, index, disableEditin
248
253
  <ErrorContent error={errorContent} message={errorMessage} placement={placement} />
249
254
  ) : (
250
255
  <MessageContent
256
+ className={messageContainer}
251
257
  editing={editing}
252
258
  id={id}
253
259
  markdownProps={markdownProps}
@@ -28,10 +28,12 @@ const ApprovalActions = memo<ApprovalActionsProps>(
28
28
  const [approveLoading, setApproveLoading] = useState(false);
29
29
 
30
30
  const { assistantGroupId } = useGroupMessage();
31
- const [approveToolIntervention, rejectToolIntervention] = useChatStore((s) => [
32
- s.approveToolCalling,
33
- s.rejectToolCalling,
34
- ]);
31
+ const [approveToolIntervention, rejectToolIntervention, rejectAndContinueToolIntervention] =
32
+ useChatStore((s) => [
33
+ s.approveToolCalling,
34
+ s.rejectToolCalling,
35
+ s.rejectAndContinueToolCalling,
36
+ ]);
35
37
  const addToolToAllowList = useUserStore((s) => s.addToolToAllowList);
36
38
 
37
39
  const handleApprove = async (remember?: boolean) => {
@@ -58,6 +60,14 @@ const ApprovalActions = memo<ApprovalActionsProps>(
58
60
  setRejectReason('');
59
61
  };
60
62
 
63
+ const handleRejectAndContinue = async (reason?: string) => {
64
+ setRejectLoading(true);
65
+ await rejectAndContinueToolIntervention(messageId, reason);
66
+ setRejectLoading(false);
67
+ setRejectPopoverOpen(false);
68
+ setRejectReason('');
69
+ };
70
+
61
71
  return (
62
72
  <Flexbox gap={8} horizontal>
63
73
  <Popover
@@ -67,14 +77,25 @@ const ApprovalActions = memo<ApprovalActionsProps>(
67
77
  <Flexbox align={'center'} horizontal justify={'space-between'}>
68
78
  <div>{t('tool.intervention.rejectTitle')}</div>
69
79
 
70
- <Button
71
- loading={rejectLoading}
72
- onClick={() => handleReject(rejectReason)}
73
- size="small"
74
- type="primary"
75
- >
76
- {t('confirm', { ns: 'common' })}
77
- </Button>
80
+ <Space>
81
+ <Button
82
+ color={'default'}
83
+ loading={rejectLoading}
84
+ onClick={() => handleReject(rejectReason)}
85
+ size="small"
86
+ variant={'filled'}
87
+ >
88
+ {t('tool.intervention.rejectOnly')}
89
+ </Button>
90
+ <Button
91
+ loading={rejectLoading}
92
+ onClick={() => handleRejectAndContinue(rejectReason)}
93
+ size="small"
94
+ type="primary"
95
+ >
96
+ {t('tool.intervention.rejectAndContinue')}
97
+ </Button>
98
+ </Space>
78
99
  </Flexbox>
79
100
  <Input.TextArea
80
101
  autoFocus
@@ -95,7 +116,7 @@ const ApprovalActions = memo<ApprovalActionsProps>(
95
116
  placement="bottomRight"
96
117
  trigger="click"
97
118
  >
98
- <Button size="small" type="default">
119
+ <Button color={'default'} size="small" variant={'filled'}>
99
120
  {t('tool.intervention.reject')}
100
121
  </Button>
101
122
  </Popover>
@@ -1,6 +1,6 @@
1
1
  import { UIChatMessage } from '@lobechat/types';
2
2
  import { Tag } from '@lobehub/ui';
3
- import { useResponsive } from 'antd-style';
3
+ import { createStyles, useResponsive } from 'antd-style';
4
4
  import isEqual from 'fast-deep-equal';
5
5
  import { ReactNode, memo, useCallback, useMemo } from 'react';
6
6
  import { useTranslation } from 'react-i18next';
@@ -45,6 +45,13 @@ const remarkPlugins = markdownElements
45
45
  .map((element) => element.remarkPlugin)
46
46
  .filter(Boolean);
47
47
 
48
+ const useUserStyles = createStyles(({ css, token }) => ({
49
+ messageContainer: css`
50
+ border: none;
51
+ background: ${token.colorFillTertiary};
52
+ `,
53
+ }));
54
+
48
55
  const UserMessage = memo<UserMessageProps>(({ id, disableEditing, index }) => {
49
56
  const item = useChatStore(
50
57
  displayMessageSelectors.getDisplayMessageById(id),
@@ -56,6 +63,8 @@ const UserMessage = memo<UserMessageProps>(({ id, disableEditing, index }) => {
56
63
  const { t } = useTranslation('chat');
57
64
  const { mobile } = useResponsive();
58
65
  const avatar = useUserAvatar();
66
+ const { styles: userStyles } = useUserStyles();
67
+
59
68
  const title = useUserStore(userProfileSelectors.displayUserName);
60
69
 
61
70
  const displayMode = useAgentStore(agentChatConfigSelectors.displayMode);
@@ -165,6 +174,7 @@ const UserMessage = memo<UserMessageProps>(({ id, disableEditing, index }) => {
165
174
  >
166
175
  <Flexbox flex={1} style={{ maxWidth: '100%', minWidth: 0 }}>
167
176
  <MessageContent
177
+ className={userStyles.messageContainer}
168
178
  editing={editing}
169
179
  id={id}
170
180
  markdownProps={markdownProps}
@@ -5,8 +5,6 @@ exports[`MCPClient > Stdio Transport > should list tools via stdio 1`] = `
5
5
  {
6
6
  "description": "Echoes back a message with 'Hello' prefix",
7
7
  "inputSchema": {
8
- "$schema": "http://json-schema.org/draft-07/schema#",
9
- "additionalProperties": false,
10
8
  "properties": {
11
9
  "message": {
12
10
  "description": "The message to echo",
@@ -23,8 +21,6 @@ exports[`MCPClient > Stdio Transport > should list tools via stdio 1`] = `
23
21
  {
24
22
  "description": "Lists all available tools and methods",
25
23
  "inputSchema": {
26
- "$schema": "http://json-schema.org/draft-07/schema#",
27
- "additionalProperties": false,
28
24
  "properties": {},
29
25
  "type": "object",
30
26
  },
@@ -33,8 +29,6 @@ exports[`MCPClient > Stdio Transport > should list tools via stdio 1`] = `
33
29
  {
34
30
  "description": "Adds two numbers",
35
31
  "inputSchema": {
36
- "$schema": "http://json-schema.org/draft-07/schema#",
37
- "additionalProperties": false,
38
32
  "properties": {
39
33
  "a": {
40
34
  "description": "The first number",
@@ -414,6 +414,8 @@ export default {
414
414
  manualDesc: '每次调用都需要手动批准',
415
415
  },
416
416
  reject: '拒绝',
417
+ rejectAndContinue: '拒绝后重试执行',
418
+ rejectOnly: '拒绝',
417
419
  rejectReasonPlaceholder: '输入拒绝原因将帮助 Agent 理解并优化后续行动',
418
420
  rejectTitle: '拒绝本次工具调用',
419
421
  rejectedWithReason: '本次工具调用被主动拒绝:{{reason}}',