@lobehub/lobehub 2.0.0-next.93 → 2.0.0-next.95
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/.github/workflows/issue-auto-comments.yml +0 -19
- package/CHANGELOG.md +50 -0
- package/changelog/v1.json +18 -0
- package/package.json +1 -1
- package/packages/agent-runtime/src/core/InterventionChecker.ts +85 -0
- package/packages/agent-runtime/src/core/__tests__/InterventionChecker.test.ts +492 -22
- package/packages/agent-runtime/src/core/defaultSecurityBlacklist.ts +335 -0
- package/packages/agent-runtime/src/core/index.ts +1 -0
- package/packages/agent-runtime/src/types/state.ts +10 -1
- package/packages/model-bank/src/aiModels/xai.ts +85 -6
- package/packages/types/src/tool/intervention.ts +38 -0
- package/src/features/Conversation/MarkdownElements/remarkPlugins/createRemarkSelfClosingTagPlugin.test.ts +25 -0
- package/src/features/Conversation/MarkdownElements/remarkPlugins/createRemarkSelfClosingTagPlugin.ts +28 -0
- package/src/features/ModelSwitchPanel/index.tsx +15 -13
- package/src/store/chat/agents/GeneralChatAgent.ts +22 -8
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
import type { SecurityBlacklistConfig } from '@lobechat/types';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Default Security Blacklist
|
|
5
|
+
* These rules will ALWAYS block execution and require human intervention,
|
|
6
|
+
* regardless of user settings (even in auto-run mode)
|
|
7
|
+
*
|
|
8
|
+
* This is the last line of defense against dangerous operations
|
|
9
|
+
*/
|
|
10
|
+
export const DEFAULT_SECURITY_BLACKLIST: SecurityBlacklistConfig = [
|
|
11
|
+
// ==================== File System Dangers ====================
|
|
12
|
+
{
|
|
13
|
+
description: 'Recursive deletion of home directory is extremely dangerous',
|
|
14
|
+
match: {
|
|
15
|
+
command: {
|
|
16
|
+
pattern: 'rm.*-r.*(~|\\$HOME|/Users/[^/]+|/home/[^/]+)/?\\s*$',
|
|
17
|
+
type: 'regex',
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
description: 'Recursive deletion of root directory will destroy the system',
|
|
23
|
+
match: {
|
|
24
|
+
command: {
|
|
25
|
+
pattern: 'rm.*-r.*/\\s*$',
|
|
26
|
+
type: 'regex',
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
description: 'Force recursive deletion without specific target is too dangerous',
|
|
32
|
+
match: {
|
|
33
|
+
command: {
|
|
34
|
+
pattern: 'rm\\s+-rf\\s+[~./]\\s*$',
|
|
35
|
+
type: 'regex',
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
|
|
40
|
+
// ==================== System Configuration Dangers ====================
|
|
41
|
+
{
|
|
42
|
+
description: 'Modifying /etc/passwd could lock you out of the system',
|
|
43
|
+
match: {
|
|
44
|
+
command: {
|
|
45
|
+
pattern: '.*(/etc/passwd|/etc/shadow).*',
|
|
46
|
+
type: 'regex',
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
description: 'Modifying sudoers file without proper validation is dangerous',
|
|
52
|
+
match: {
|
|
53
|
+
command: {
|
|
54
|
+
pattern: '.*/etc/sudoers.*',
|
|
55
|
+
type: 'regex',
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
|
|
60
|
+
// ==================== Dangerous Commands ====================
|
|
61
|
+
{
|
|
62
|
+
description: 'Fork bomb can crash the system',
|
|
63
|
+
match: {
|
|
64
|
+
command: {
|
|
65
|
+
pattern: '.*:\\(\\).*\\{.*\\|.*&.*\\};.*:.*',
|
|
66
|
+
type: 'regex',
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
description: 'Writing random data to disk devices can destroy data',
|
|
72
|
+
match: {
|
|
73
|
+
command: {
|
|
74
|
+
pattern: 'dd.*of=/dev/(sd|hd|nvme).*',
|
|
75
|
+
type: 'regex',
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
description: 'Formatting system partitions will destroy data',
|
|
81
|
+
match: {
|
|
82
|
+
command: {
|
|
83
|
+
pattern: '(mkfs|fdisk|parted).*(/dev/(sd|hd|nvme)|/)',
|
|
84
|
+
type: 'regex',
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
|
|
89
|
+
// ==================== Network & Remote Access Dangers ====================
|
|
90
|
+
{
|
|
91
|
+
description: 'Disabling firewall exposes system to attacks',
|
|
92
|
+
match: {
|
|
93
|
+
command: {
|
|
94
|
+
pattern: '(ufw\\s+disable|iptables\\s+-F|systemctl\\s+stop\\s+firewalld)',
|
|
95
|
+
type: 'regex',
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
description: 'Changing SSH configuration could lock you out',
|
|
101
|
+
match: {
|
|
102
|
+
command: {
|
|
103
|
+
pattern: '.*(/etc/ssh/sshd_config).*',
|
|
104
|
+
type: 'regex',
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
|
|
109
|
+
// ==================== Package Manager Dangers ====================
|
|
110
|
+
{
|
|
111
|
+
description: 'Removing essential system packages can break the system',
|
|
112
|
+
match: {
|
|
113
|
+
command: {
|
|
114
|
+
pattern: '(apt|yum|dnf|pacman)\\s+(remove|purge|erase).*(systemd|kernel|glibc|bash|sudo)',
|
|
115
|
+
type: 'regex',
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
|
|
120
|
+
// ==================== Kernel & System Core Dangers ====================
|
|
121
|
+
{
|
|
122
|
+
description: 'Modifying kernel parameters without understanding can crash the system',
|
|
123
|
+
match: {
|
|
124
|
+
command: {
|
|
125
|
+
pattern: 'echo.*>/proc/sys/.*',
|
|
126
|
+
type: 'regex',
|
|
127
|
+
},
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
description: 'Direct memory access is extremely dangerous',
|
|
132
|
+
match: {
|
|
133
|
+
command: {
|
|
134
|
+
pattern: '.*(/dev/(mem|kmem|port)).*',
|
|
135
|
+
type: 'regex',
|
|
136
|
+
},
|
|
137
|
+
},
|
|
138
|
+
},
|
|
139
|
+
|
|
140
|
+
// ==================== Privilege Escalation Dangers ====================
|
|
141
|
+
{
|
|
142
|
+
description: 'Changing file ownership of system directories is dangerous',
|
|
143
|
+
match: {
|
|
144
|
+
command: {
|
|
145
|
+
pattern: 'chown.*-R.*(/(etc|bin|sbin|usr|var|sys|proc)|~).*',
|
|
146
|
+
type: 'regex',
|
|
147
|
+
},
|
|
148
|
+
},
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
description: 'Setting SUID on shells or interpreters is a security risk',
|
|
152
|
+
match: {
|
|
153
|
+
command: {
|
|
154
|
+
pattern: 'chmod.*(4755|u\\+s).*(sh|bash|python|perl|ruby|node)',
|
|
155
|
+
type: 'regex',
|
|
156
|
+
},
|
|
157
|
+
},
|
|
158
|
+
},
|
|
159
|
+
|
|
160
|
+
// ==================== Sensitive Information Leakage ====================
|
|
161
|
+
{
|
|
162
|
+
description: 'Reading .env files may leak sensitive credentials and API keys',
|
|
163
|
+
match: {
|
|
164
|
+
command: {
|
|
165
|
+
pattern: '(cat|less|more|head|tail|vim|nano|vi|emacs|code).*\\.env.*',
|
|
166
|
+
type: 'regex',
|
|
167
|
+
},
|
|
168
|
+
},
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
description: 'Reading .env files may leak sensitive credentials and API keys',
|
|
172
|
+
match: {
|
|
173
|
+
path: {
|
|
174
|
+
pattern: '.*\\.env.*',
|
|
175
|
+
type: 'regex',
|
|
176
|
+
},
|
|
177
|
+
},
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
description: 'Reading SSH private keys can compromise system security',
|
|
181
|
+
match: {
|
|
182
|
+
command: {
|
|
183
|
+
pattern:
|
|
184
|
+
'(cat|less|more|head|tail|vim|nano|vi|emacs|code).*(id_rsa|id_ed25519|id_ecdsa)(?!\\.pub).*',
|
|
185
|
+
type: 'regex',
|
|
186
|
+
},
|
|
187
|
+
},
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
description: 'Reading SSH private keys can compromise system security',
|
|
191
|
+
match: {
|
|
192
|
+
path: {
|
|
193
|
+
pattern: '.*/\\.ssh/(id_rsa|id_ed25519|id_ecdsa)$',
|
|
194
|
+
type: 'regex',
|
|
195
|
+
},
|
|
196
|
+
},
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
description: 'Accessing AWS credentials can leak cloud access keys',
|
|
200
|
+
match: {
|
|
201
|
+
command: {
|
|
202
|
+
pattern: '(cat|less|more|head|tail|vim|nano|vi|emacs|code).*/\\.aws/credentials.*',
|
|
203
|
+
type: 'regex',
|
|
204
|
+
},
|
|
205
|
+
},
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
description: 'Accessing AWS credentials can leak cloud access keys',
|
|
209
|
+
match: {
|
|
210
|
+
path: {
|
|
211
|
+
pattern: '.*/\\.aws/credentials.*',
|
|
212
|
+
type: 'regex',
|
|
213
|
+
},
|
|
214
|
+
},
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
description: 'Reading Docker config may expose registry credentials',
|
|
218
|
+
match: {
|
|
219
|
+
command: {
|
|
220
|
+
pattern: '(cat|less|more|head|tail|vim|nano|vi|emacs|code).*/\\.docker/config\\.json.*',
|
|
221
|
+
type: 'regex',
|
|
222
|
+
},
|
|
223
|
+
},
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
description: 'Reading Docker config may expose registry credentials',
|
|
227
|
+
match: {
|
|
228
|
+
path: {
|
|
229
|
+
pattern: '.*/\\.docker/config\\.json$',
|
|
230
|
+
type: 'regex',
|
|
231
|
+
},
|
|
232
|
+
},
|
|
233
|
+
},
|
|
234
|
+
{
|
|
235
|
+
description: 'Reading Kubernetes config may expose cluster credentials',
|
|
236
|
+
match: {
|
|
237
|
+
command: {
|
|
238
|
+
pattern: '(cat|less|more|head|tail|vim|nano|vi|emacs|code).*/\\.kube/config.*',
|
|
239
|
+
type: 'regex',
|
|
240
|
+
},
|
|
241
|
+
},
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
description: 'Reading Kubernetes config may expose cluster credentials',
|
|
245
|
+
match: {
|
|
246
|
+
path: {
|
|
247
|
+
pattern: '.*/\\.kube/config$',
|
|
248
|
+
type: 'regex',
|
|
249
|
+
},
|
|
250
|
+
},
|
|
251
|
+
},
|
|
252
|
+
{
|
|
253
|
+
description: 'Reading Git credentials file may leak access tokens',
|
|
254
|
+
match: {
|
|
255
|
+
command: {
|
|
256
|
+
pattern: '(cat|less|more|head|tail|vim|nano|vi|emacs|code).*/\\.git-credentials.*',
|
|
257
|
+
type: 'regex',
|
|
258
|
+
},
|
|
259
|
+
},
|
|
260
|
+
},
|
|
261
|
+
{
|
|
262
|
+
description: 'Reading Git credentials file may leak access tokens',
|
|
263
|
+
match: {
|
|
264
|
+
path: {
|
|
265
|
+
pattern: '.*/\\.git-credentials$',
|
|
266
|
+
type: 'regex',
|
|
267
|
+
},
|
|
268
|
+
},
|
|
269
|
+
},
|
|
270
|
+
{
|
|
271
|
+
description: 'Reading npm token file may expose package registry credentials',
|
|
272
|
+
match: {
|
|
273
|
+
command: {
|
|
274
|
+
pattern: '(cat|less|more|head|tail|vim|nano|vi|emacs|code).*/\\.npmrc.*',
|
|
275
|
+
type: 'regex',
|
|
276
|
+
},
|
|
277
|
+
},
|
|
278
|
+
},
|
|
279
|
+
{
|
|
280
|
+
description: 'Reading npm token file may expose package registry credentials',
|
|
281
|
+
match: {
|
|
282
|
+
path: {
|
|
283
|
+
pattern: '.*/\\.npmrc$',
|
|
284
|
+
type: 'regex',
|
|
285
|
+
},
|
|
286
|
+
},
|
|
287
|
+
},
|
|
288
|
+
{
|
|
289
|
+
description: 'Reading history files may expose sensitive commands and credentials',
|
|
290
|
+
match: {
|
|
291
|
+
command: {
|
|
292
|
+
pattern:
|
|
293
|
+
'(cat|less|more|head|tail|vim|nano|vi|emacs|code).*/\\.(bash_history|zsh_history|history).*',
|
|
294
|
+
type: 'regex',
|
|
295
|
+
},
|
|
296
|
+
},
|
|
297
|
+
},
|
|
298
|
+
{
|
|
299
|
+
description: 'Reading history files may expose sensitive commands and credentials',
|
|
300
|
+
match: {
|
|
301
|
+
path: {
|
|
302
|
+
pattern: '.*/\\.(bash_history|zsh_history|history)$',
|
|
303
|
+
type: 'regex',
|
|
304
|
+
},
|
|
305
|
+
},
|
|
306
|
+
},
|
|
307
|
+
{
|
|
308
|
+
description: 'Accessing browser credential storage may leak passwords',
|
|
309
|
+
match: {
|
|
310
|
+
command: {
|
|
311
|
+
pattern:
|
|
312
|
+
'(cat|less|more|head|tail|vim|nano|vi|emacs|code).*(Cookies|Login Data|Web Data).*',
|
|
313
|
+
type: 'regex',
|
|
314
|
+
},
|
|
315
|
+
},
|
|
316
|
+
},
|
|
317
|
+
{
|
|
318
|
+
description: 'Reading GCP credentials may leak cloud service account keys',
|
|
319
|
+
match: {
|
|
320
|
+
command: {
|
|
321
|
+
pattern: '(cat|less|more|head|tail|vim|nano|vi|emacs|code).*/\\.config/gcloud/.*\\.json.*',
|
|
322
|
+
type: 'regex',
|
|
323
|
+
},
|
|
324
|
+
},
|
|
325
|
+
},
|
|
326
|
+
{
|
|
327
|
+
description: 'Reading GCP credentials may leak cloud service account keys',
|
|
328
|
+
match: {
|
|
329
|
+
path: {
|
|
330
|
+
pattern: '.*/\\.config/gcloud/.*\\.json$',
|
|
331
|
+
type: 'regex',
|
|
332
|
+
},
|
|
333
|
+
},
|
|
334
|
+
},
|
|
335
|
+
];
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/* eslint-disable sort-keys-fix/sort-keys-fix, typescript-sort-keys/interface */
|
|
2
|
-
import { ChatToolPayload, UserInterventionConfig } from '@lobechat/types';
|
|
2
|
+
import { ChatToolPayload, SecurityBlacklistConfig, UserInterventionConfig } from '@lobechat/types';
|
|
3
3
|
|
|
4
4
|
import type { Cost, CostLimit, Usage } from './usage';
|
|
5
5
|
|
|
@@ -23,6 +23,15 @@ export interface AgentState {
|
|
|
23
23
|
* Controls how tools requiring approval are handled
|
|
24
24
|
*/
|
|
25
25
|
userInterventionConfig?: UserInterventionConfig;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Security blacklist configuration
|
|
29
|
+
* These rules will ALWAYS block execution and require human intervention,
|
|
30
|
+
* regardless of user settings (even in auto-run mode).
|
|
31
|
+
* If not provided, DEFAULT_SECURITY_BLACKLIST will be used.
|
|
32
|
+
*/
|
|
33
|
+
securityBlacklist?: SecurityBlacklistConfig;
|
|
34
|
+
|
|
26
35
|
// --- Execution Tracking ---
|
|
27
36
|
/**
|
|
28
37
|
* Number of execution steps in this session.
|
|
@@ -6,13 +6,94 @@ const xaiChatModels: AIChatModelCard[] = [
|
|
|
6
6
|
abilities: {
|
|
7
7
|
functionCall: true,
|
|
8
8
|
search: true,
|
|
9
|
+
structuredOutput: true,
|
|
9
10
|
vision: true,
|
|
10
11
|
},
|
|
11
12
|
contextWindowTokens: 2_000_000,
|
|
12
|
-
description:
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
description: '前沿多模态模型,专门针对高性能代理工具调用进行优化。',
|
|
14
|
+
displayName: 'Grok 4.1 Fast (Non-Reasoning)',
|
|
15
|
+
enabled: true,
|
|
16
|
+
id: 'grok-4-1-fast-non-reasoning',
|
|
17
|
+
pricing: {
|
|
18
|
+
units: [
|
|
19
|
+
{ name: 'textInput_cacheRead', rate: 0.05, strategy: 'fixed', unit: 'millionTokens' },
|
|
20
|
+
{
|
|
21
|
+
name: 'textInput',
|
|
22
|
+
strategy: 'tiered',
|
|
23
|
+
tiers: [
|
|
24
|
+
{ rate: 0.2, upTo: 0.128 },
|
|
25
|
+
{ rate: 0.4, upTo: 'infinity' },
|
|
26
|
+
],
|
|
27
|
+
unit: 'millionTokens',
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
name: 'textOutput',
|
|
31
|
+
strategy: 'tiered',
|
|
32
|
+
tiers: [
|
|
33
|
+
{ rate: 0.5, upTo: 0.128 },
|
|
34
|
+
{ rate: 1, upTo: 'infinity' },
|
|
35
|
+
],
|
|
36
|
+
unit: 'millionTokens',
|
|
37
|
+
},
|
|
38
|
+
],
|
|
39
|
+
},
|
|
40
|
+
releasedAt: '2025-11-20',
|
|
41
|
+
settings: {
|
|
42
|
+
searchImpl: 'params',
|
|
43
|
+
},
|
|
44
|
+
type: 'chat',
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
abilities: {
|
|
48
|
+
functionCall: true,
|
|
49
|
+
reasoning: true,
|
|
50
|
+
search: true,
|
|
51
|
+
structuredOutput: true,
|
|
52
|
+
vision: true,
|
|
53
|
+
},
|
|
54
|
+
contextWindowTokens: 2_000_000,
|
|
55
|
+
description: '前沿多模态模型,专门针对高性能代理工具调用进行优化。',
|
|
56
|
+
displayName: 'Grok 4.1 Fast',
|
|
15
57
|
enabled: true,
|
|
58
|
+
id: 'grok-4-1-fast-reasoning',
|
|
59
|
+
pricing: {
|
|
60
|
+
units: [
|
|
61
|
+
{ name: 'textInput_cacheRead', rate: 0.05, strategy: 'fixed', unit: 'millionTokens' },
|
|
62
|
+
{
|
|
63
|
+
name: 'textInput',
|
|
64
|
+
strategy: 'tiered',
|
|
65
|
+
tiers: [
|
|
66
|
+
{ rate: 0.2, upTo: 0.128 },
|
|
67
|
+
{ rate: 0.4, upTo: 'infinity' },
|
|
68
|
+
],
|
|
69
|
+
unit: 'millionTokens',
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
name: 'textOutput',
|
|
73
|
+
strategy: 'tiered',
|
|
74
|
+
tiers: [
|
|
75
|
+
{ rate: 0.5, upTo: 0.128 },
|
|
76
|
+
{ rate: 1, upTo: 'infinity' },
|
|
77
|
+
],
|
|
78
|
+
unit: 'millionTokens',
|
|
79
|
+
},
|
|
80
|
+
],
|
|
81
|
+
},
|
|
82
|
+
releasedAt: '2025-11-20',
|
|
83
|
+
settings: {
|
|
84
|
+
searchImpl: 'params',
|
|
85
|
+
},
|
|
86
|
+
type: 'chat',
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
abilities: {
|
|
90
|
+
functionCall: true,
|
|
91
|
+
search: true,
|
|
92
|
+
vision: true,
|
|
93
|
+
},
|
|
94
|
+
contextWindowTokens: 2_000_000,
|
|
95
|
+
description: '我们很高兴发布 Grok 4 Fast,这是我们在成本效益推理模型方面的最新进展。',
|
|
96
|
+
displayName: 'Grok 4 Fast (Non-Reasoning)',
|
|
16
97
|
id: 'grok-4-fast-non-reasoning',
|
|
17
98
|
pricing: {
|
|
18
99
|
units: [
|
|
@@ -51,10 +132,8 @@ const xaiChatModels: AIChatModelCard[] = [
|
|
|
51
132
|
vision: true,
|
|
52
133
|
},
|
|
53
134
|
contextWindowTokens: 2_000_000,
|
|
54
|
-
description:
|
|
55
|
-
'我们很高兴发布 Grok 4 Fast,这是我们在成本效益推理模型方面的最新进展。',
|
|
135
|
+
description: '我们很高兴发布 Grok 4 Fast,这是我们在成本效益推理模型方面的最新进展。',
|
|
56
136
|
displayName: 'Grok 4 Fast',
|
|
57
|
-
enabled: true,
|
|
58
137
|
id: 'grok-4-fast-reasoning',
|
|
59
138
|
pricing: {
|
|
60
139
|
units: [
|
|
@@ -146,6 +146,36 @@ export const UserInterventionConfigSchema = z.object({
|
|
|
146
146
|
approvalMode: z.enum(['auto-run', 'allow-list', 'manual']),
|
|
147
147
|
});
|
|
148
148
|
|
|
149
|
+
/**
|
|
150
|
+
* Security Blacklist Rule
|
|
151
|
+
* Used to forcefully block dangerous operations regardless of user settings
|
|
152
|
+
*/
|
|
153
|
+
export interface SecurityBlacklistRule {
|
|
154
|
+
/**
|
|
155
|
+
* Description of why this rule exists (for error messages)
|
|
156
|
+
*/
|
|
157
|
+
description: string;
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Parameter filter - matches against tool call arguments
|
|
161
|
+
* Same format as HumanInterventionRule.match
|
|
162
|
+
*/
|
|
163
|
+
match: Record<string, ArgumentMatcher>;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
export const SecurityBlacklistRuleSchema = z.object({
|
|
167
|
+
description: z.string(),
|
|
168
|
+
match: z.record(z.string(), ArgumentMatcherSchema),
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Security Blacklist Configuration
|
|
173
|
+
* A list of rules that will always block execution and require intervention
|
|
174
|
+
*/
|
|
175
|
+
export type SecurityBlacklistConfig = SecurityBlacklistRule[];
|
|
176
|
+
|
|
177
|
+
export const SecurityBlacklistConfigSchema = z.array(SecurityBlacklistRuleSchema);
|
|
178
|
+
|
|
149
179
|
/**
|
|
150
180
|
* Parameters for shouldIntervene method
|
|
151
181
|
*/
|
|
@@ -161,6 +191,13 @@ export interface ShouldInterveneParams {
|
|
|
161
191
|
*/
|
|
162
192
|
confirmedHistory?: string[];
|
|
163
193
|
|
|
194
|
+
/**
|
|
195
|
+
* Security blacklist rules that will be checked first
|
|
196
|
+
* These rules override all other settings including auto-run mode
|
|
197
|
+
* @default []
|
|
198
|
+
*/
|
|
199
|
+
securityBlacklist?: SecurityBlacklistConfig;
|
|
200
|
+
|
|
164
201
|
/**
|
|
165
202
|
* Tool call arguments to check against rules
|
|
166
203
|
* @default {}
|
|
@@ -177,6 +214,7 @@ export interface ShouldInterveneParams {
|
|
|
177
214
|
export const ShouldInterveneParamsSchema = z.object({
|
|
178
215
|
config: HumanInterventionConfigSchema.optional(),
|
|
179
216
|
confirmedHistory: z.array(z.string()).optional(),
|
|
217
|
+
securityBlacklist: SecurityBlacklistConfigSchema.optional(),
|
|
180
218
|
toolArgs: z.record(z.string(), z.any()).optional(),
|
|
181
219
|
toolKey: z.string().optional(),
|
|
182
220
|
});
|
|
@@ -249,4 +249,29 @@ describe('createRemarkSelfClosingTagPlugin', () => {
|
|
|
249
249
|
|
|
250
250
|
expect(tree).toMatchSnapshot();
|
|
251
251
|
});
|
|
252
|
+
|
|
253
|
+
it('should handle tags wrapped in backticks (code)', () => {
|
|
254
|
+
const markdown = `Use this file: \`<${tagName} name="config.json" path="/app/config.json" />\` in your code.`;
|
|
255
|
+
const tree = processMarkdown(markdown, tagName);
|
|
256
|
+
|
|
257
|
+
expect(tree.children).toHaveLength(1);
|
|
258
|
+
expect(tree.children[0].type).toBe('paragraph');
|
|
259
|
+
|
|
260
|
+
const paragraphChildren = tree.children[0].children;
|
|
261
|
+
expect(paragraphChildren).toHaveLength(3);
|
|
262
|
+
|
|
263
|
+
expect(paragraphChildren[0].type).toBe('text');
|
|
264
|
+
expect(paragraphChildren[0].value).toBe('Use this file: ');
|
|
265
|
+
|
|
266
|
+
// The tag should be parsed even inside backticks
|
|
267
|
+
const tagNode = paragraphChildren[1];
|
|
268
|
+
expect(tagNode.type).toBe(tagName);
|
|
269
|
+
expect(tagNode.data?.hProperties).toEqual({
|
|
270
|
+
name: 'config.json',
|
|
271
|
+
path: '/app/config.json',
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
expect(paragraphChildren[2].type).toBe('text');
|
|
275
|
+
expect(paragraphChildren[2].value).toBe(' in your code.');
|
|
276
|
+
});
|
|
252
277
|
});
|
package/src/features/Conversation/MarkdownElements/remarkPlugins/createRemarkSelfClosingTagPlugin.ts
CHANGED
|
@@ -130,5 +130,33 @@ export const createRemarkSelfClosingTagPlugin =
|
|
|
130
130
|
return [SKIP, index + newChildren.length]; // Skip new nodes
|
|
131
131
|
}
|
|
132
132
|
});
|
|
133
|
+
|
|
134
|
+
// 3. Visit inlineCode nodes (backtick-wrapped tags like `<localFile ... />`)
|
|
135
|
+
// @ts-ignore
|
|
136
|
+
visit(tree, 'inlineCode', (node: any, index: number, parent) => {
|
|
137
|
+
log('>>> Visiting inlineCode node: "%s"', node.value);
|
|
138
|
+
|
|
139
|
+
if (!parent || typeof index !== 'number' || !node.value?.includes(`<${tagName}`)) {
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const match = node.value.match(exactTagRegex);
|
|
144
|
+
if (match) {
|
|
145
|
+
const [, attributesString] = match;
|
|
146
|
+
const properties = attributesString ? parseAttributes(attributesString.trim()) : {};
|
|
147
|
+
|
|
148
|
+
const newNode = {
|
|
149
|
+
data: {
|
|
150
|
+
hName: tagName,
|
|
151
|
+
hProperties: properties,
|
|
152
|
+
},
|
|
153
|
+
type: tagName,
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
log('Replacing inlineCode node at index %d with %s node: %o', index, tagName, newNode);
|
|
157
|
+
parent.children.splice(index, 1, newNode);
|
|
158
|
+
return [SKIP, index + 1];
|
|
159
|
+
}
|
|
160
|
+
});
|
|
133
161
|
};
|
|
134
162
|
};
|
|
@@ -2,11 +2,10 @@ import { ActionIcon, Icon } from '@lobehub/ui';
|
|
|
2
2
|
import { createStyles } from 'antd-style';
|
|
3
3
|
import type { ItemType } from 'antd/es/menu/interface';
|
|
4
4
|
import { LucideArrowRight, LucideBolt } from 'lucide-react';
|
|
5
|
-
import Link from 'next/link';
|
|
6
|
-
import { useRouter } from 'next/navigation';
|
|
7
5
|
import { type ReactNode, memo, useMemo } from 'react';
|
|
8
6
|
import { useTranslation } from 'react-i18next';
|
|
9
7
|
import { Flexbox } from 'react-layout-kit';
|
|
8
|
+
import { useNavigate } from 'react-router-dom';
|
|
10
9
|
|
|
11
10
|
import { ModelItemRender, ProviderItemRender } from '@/components/ModelSelect';
|
|
12
11
|
import ActionDropdown from '@/features/ChatInput/ActionBar/components/ActionDropdown';
|
|
@@ -53,7 +52,7 @@ const ModelSwitchPanel = memo<IProps>(({ children, onOpenChange, open }) => {
|
|
|
53
52
|
agentSelectors.currentAgentModelProvider(s),
|
|
54
53
|
s.updateAgentConfig,
|
|
55
54
|
]);
|
|
56
|
-
const
|
|
55
|
+
const navigate = useNavigate();
|
|
57
56
|
const enabledList = useEnabledChatModels();
|
|
58
57
|
|
|
59
58
|
const items = useMemo<ItemType[]>(() => {
|
|
@@ -78,7 +77,7 @@ const ModelSwitchPanel = memo<IProps>(({ children, onOpenChange, open }) => {
|
|
|
78
77
|
</Flexbox>
|
|
79
78
|
),
|
|
80
79
|
onClick: () => {
|
|
81
|
-
|
|
80
|
+
navigate(`/settings?active=provider&provider=${provider.id}`);
|
|
82
81
|
},
|
|
83
82
|
},
|
|
84
83
|
];
|
|
@@ -97,7 +96,7 @@ const ModelSwitchPanel = memo<IProps>(({ children, onOpenChange, open }) => {
|
|
|
97
96
|
</Flexbox>
|
|
98
97
|
),
|
|
99
98
|
onClick: () => {
|
|
100
|
-
|
|
99
|
+
navigate('/settings?active=provider');
|
|
101
100
|
},
|
|
102
101
|
},
|
|
103
102
|
];
|
|
@@ -114,18 +113,21 @@ const ModelSwitchPanel = memo<IProps>(({ children, onOpenChange, open }) => {
|
|
|
114
113
|
provider={provider.id}
|
|
115
114
|
source={provider.source}
|
|
116
115
|
/>
|
|
117
|
-
<
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
116
|
+
<ActionIcon
|
|
117
|
+
icon={LucideBolt}
|
|
118
|
+
onClick={(e) => {
|
|
119
|
+
e.preventDefault();
|
|
120
|
+
e.stopPropagation();
|
|
121
|
+
navigate(`/settings?active=provider&provider=${provider.id}`);
|
|
122
|
+
}}
|
|
123
|
+
size={'small'}
|
|
124
|
+
title={t('ModelSwitchPanel.goToSettings')}
|
|
125
|
+
/>
|
|
124
126
|
</Flexbox>
|
|
125
127
|
),
|
|
126
128
|
type: 'group',
|
|
127
129
|
}));
|
|
128
|
-
}, [enabledList]);
|
|
130
|
+
}, [enabledList, navigate, t, theme.colorTextTertiary]);
|
|
129
131
|
|
|
130
132
|
const icon = <div className={styles.tag}>{children}</div>;
|
|
131
133
|
|