@lobehub/lobehub 2.0.0-next.94 → 2.0.0-next.96

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 (63) hide show
  1. package/.github/workflows/issue-auto-comments.yml +0 -19
  2. package/CHANGELOG.md +50 -0
  3. package/changelog/v1.json +18 -0
  4. package/locales/ar/common.json +21 -0
  5. package/locales/ar/hotkey.json +4 -0
  6. package/locales/bg-BG/common.json +21 -0
  7. package/locales/bg-BG/hotkey.json +4 -0
  8. package/locales/de-DE/common.json +21 -0
  9. package/locales/de-DE/hotkey.json +4 -0
  10. package/locales/en-US/common.json +21 -0
  11. package/locales/en-US/hotkey.json +4 -0
  12. package/locales/es-ES/common.json +21 -0
  13. package/locales/es-ES/hotkey.json +4 -0
  14. package/locales/fa-IR/common.json +21 -0
  15. package/locales/fa-IR/hotkey.json +4 -0
  16. package/locales/fr-FR/common.json +21 -0
  17. package/locales/fr-FR/hotkey.json +4 -0
  18. package/locales/it-IT/common.json +21 -0
  19. package/locales/it-IT/hotkey.json +4 -0
  20. package/locales/ja-JP/common.json +21 -0
  21. package/locales/ja-JP/hotkey.json +4 -0
  22. package/locales/ko-KR/common.json +21 -0
  23. package/locales/ko-KR/hotkey.json +4 -0
  24. package/locales/nl-NL/common.json +21 -0
  25. package/locales/nl-NL/hotkey.json +4 -0
  26. package/locales/pl-PL/common.json +21 -0
  27. package/locales/pl-PL/hotkey.json +4 -0
  28. package/locales/pt-BR/common.json +21 -0
  29. package/locales/pt-BR/hotkey.json +4 -0
  30. package/locales/ru-RU/common.json +21 -0
  31. package/locales/ru-RU/hotkey.json +4 -0
  32. package/locales/tr-TR/common.json +21 -0
  33. package/locales/tr-TR/hotkey.json +4 -0
  34. package/locales/vi-VN/common.json +21 -0
  35. package/locales/vi-VN/hotkey.json +4 -0
  36. package/locales/zh-CN/common.json +21 -0
  37. package/locales/zh-CN/hotkey.json +4 -0
  38. package/locales/zh-TW/common.json +21 -0
  39. package/locales/zh-TW/hotkey.json +4 -0
  40. package/package.json +3 -1
  41. package/packages/agent-runtime/src/core/InterventionChecker.ts +85 -0
  42. package/packages/agent-runtime/src/core/__tests__/InterventionChecker.test.ts +492 -22
  43. package/packages/agent-runtime/src/core/defaultSecurityBlacklist.ts +335 -0
  44. package/packages/agent-runtime/src/core/index.ts +1 -0
  45. package/packages/agent-runtime/src/types/state.ts +10 -1
  46. package/packages/const/src/hotkeys.ts +6 -0
  47. package/packages/conversation-flow/src/__tests__/indexing.test.ts +513 -0
  48. package/packages/conversation-flow/src/__tests__/structuring.test.ts +600 -0
  49. package/packages/types/src/hotkey.ts +1 -0
  50. package/packages/types/src/tool/intervention.ts +38 -0
  51. package/src/app/[variants]/(main)/settings/_layout/Desktop/index.tsx +41 -8
  52. package/src/app/[variants]/(main)/settings/provider/(list)/ProviderGrid/Card.tsx +6 -4
  53. package/src/app/[variants]/(main)/settings/provider/(list)/ProviderGrid/index.tsx +16 -4
  54. package/src/app/[variants]/(main)/settings/provider/(list)/index.tsx +15 -3
  55. package/src/app/[variants]/(main)/settings/provider/detail/index.tsx +23 -15
  56. package/src/features/Conversation/MarkdownElements/remarkPlugins/createRemarkSelfClosingTagPlugin.test.ts +25 -0
  57. package/src/features/Conversation/MarkdownElements/remarkPlugins/createRemarkSelfClosingTagPlugin.ts +28 -0
  58. package/src/layout/GlobalProvider/Cmdk.tsx +470 -0
  59. package/src/layout/GlobalProvider/CmdkLazy.tsx +17 -0
  60. package/src/layout/GlobalProvider/index.tsx +2 -0
  61. package/src/locales/default/common.ts +21 -0
  62. package/src/locales/default/hotkey.ts +4 -0
  63. package/src/store/chat/agents/GeneralChatAgent.ts +22 -8
@@ -0,0 +1,600 @@
1
+ import { describe, expect, it } from 'vitest';
2
+
3
+ import { buildHelperMaps } from '../indexing';
4
+ import { buildIdTree } from '../structuring';
5
+ import type { Message } from '../types';
6
+
7
+ describe('buildIdTree', () => {
8
+ describe('basic tree building', () => {
9
+ it('should build tree from single root message', () => {
10
+ const messages: Message[] = [
11
+ {
12
+ content: 'Root',
13
+ createdAt: 1000,
14
+ id: 'msg-1',
15
+ meta: {},
16
+ role: 'user',
17
+ updatedAt: 1000,
18
+ },
19
+ ];
20
+
21
+ const helperMaps = buildHelperMaps(messages);
22
+ const result = buildIdTree(helperMaps);
23
+
24
+ expect(result).toHaveLength(1);
25
+ expect(result[0]).toEqual({
26
+ children: [],
27
+ id: 'msg-1',
28
+ });
29
+ });
30
+
31
+ it('should build tree with linear conversation', () => {
32
+ const messages: Message[] = [
33
+ {
34
+ content: 'Message 1',
35
+ createdAt: 1000,
36
+ id: 'msg-1',
37
+ meta: {},
38
+ role: 'user',
39
+ updatedAt: 1000,
40
+ },
41
+ {
42
+ content: 'Message 2',
43
+ createdAt: 2000,
44
+ id: 'msg-2',
45
+ meta: {},
46
+ parentId: 'msg-1',
47
+ role: 'assistant',
48
+ updatedAt: 2000,
49
+ },
50
+ {
51
+ content: 'Message 3',
52
+ createdAt: 3000,
53
+ id: 'msg-3',
54
+ meta: {},
55
+ parentId: 'msg-2',
56
+ role: 'user',
57
+ updatedAt: 3000,
58
+ },
59
+ ];
60
+
61
+ const helperMaps = buildHelperMaps(messages);
62
+ const result = buildIdTree(helperMaps);
63
+
64
+ expect(result).toHaveLength(1);
65
+ expect(result[0].id).toBe('msg-1');
66
+ expect(result[0].children).toHaveLength(1);
67
+ expect(result[0].children[0].id).toBe('msg-2');
68
+ expect(result[0].children[0].children).toHaveLength(1);
69
+ expect(result[0].children[0].children[0].id).toBe('msg-3');
70
+ });
71
+
72
+ it('should handle multiple root messages', () => {
73
+ const messages: Message[] = [
74
+ {
75
+ content: 'Root 1',
76
+ createdAt: 1000,
77
+ id: 'msg-1',
78
+ meta: {},
79
+ role: 'user',
80
+ updatedAt: 1000,
81
+ },
82
+ {
83
+ content: 'Root 2',
84
+ createdAt: 2000,
85
+ id: 'msg-2',
86
+ meta: {},
87
+ role: 'user',
88
+ updatedAt: 2000,
89
+ },
90
+ ];
91
+
92
+ const helperMaps = buildHelperMaps(messages);
93
+ const result = buildIdTree(helperMaps);
94
+
95
+ expect(result).toHaveLength(2);
96
+ expect(result[0].id).toBe('msg-1');
97
+ expect(result[1].id).toBe('msg-2');
98
+ });
99
+ });
100
+
101
+ describe('branching conversations', () => {
102
+ it('should build tree with branches', () => {
103
+ const messages: Message[] = [
104
+ {
105
+ content: 'Root',
106
+ createdAt: 1000,
107
+ id: 'msg-1',
108
+ meta: {},
109
+ role: 'user',
110
+ updatedAt: 1000,
111
+ },
112
+ {
113
+ content: 'Branch 1',
114
+ createdAt: 2000,
115
+ id: 'msg-2',
116
+ meta: {},
117
+ parentId: 'msg-1',
118
+ role: 'assistant',
119
+ updatedAt: 2000,
120
+ },
121
+ {
122
+ content: 'Branch 2',
123
+ createdAt: 3000,
124
+ id: 'msg-3',
125
+ meta: {},
126
+ parentId: 'msg-1',
127
+ role: 'assistant',
128
+ updatedAt: 3000,
129
+ },
130
+ ];
131
+
132
+ const helperMaps = buildHelperMaps(messages);
133
+ const result = buildIdTree(helperMaps);
134
+
135
+ expect(result).toHaveLength(1);
136
+ expect(result[0].id).toBe('msg-1');
137
+ expect(result[0].children).toHaveLength(2);
138
+ expect(result[0].children[0].id).toBe('msg-2');
139
+ expect(result[0].children[1].id).toBe('msg-3');
140
+ });
141
+
142
+ it('should handle nested branches', () => {
143
+ const messages: Message[] = [
144
+ {
145
+ content: 'Root',
146
+ createdAt: 1000,
147
+ id: 'msg-1',
148
+ meta: {},
149
+ role: 'user',
150
+ updatedAt: 1000,
151
+ },
152
+ {
153
+ content: 'Branch 1',
154
+ createdAt: 2000,
155
+ id: 'msg-2',
156
+ meta: {},
157
+ parentId: 'msg-1',
158
+ role: 'assistant',
159
+ updatedAt: 2000,
160
+ },
161
+ {
162
+ content: 'Branch 1.1',
163
+ createdAt: 3000,
164
+ id: 'msg-3',
165
+ meta: {},
166
+ parentId: 'msg-2',
167
+ role: 'user',
168
+ updatedAt: 3000,
169
+ },
170
+ {
171
+ content: 'Branch 1.2',
172
+ createdAt: 4000,
173
+ id: 'msg-4',
174
+ meta: {},
175
+ parentId: 'msg-2',
176
+ role: 'user',
177
+ updatedAt: 4000,
178
+ },
179
+ ];
180
+
181
+ const helperMaps = buildHelperMaps(messages);
182
+ const result = buildIdTree(helperMaps);
183
+
184
+ expect(result).toHaveLength(1);
185
+ expect(result[0].children[0].id).toBe('msg-2');
186
+ expect(result[0].children[0].children).toHaveLength(2);
187
+ expect(result[0].children[0].children[0].id).toBe('msg-3');
188
+ expect(result[0].children[0].children[1].id).toBe('msg-4');
189
+ });
190
+
191
+ it('should handle deeply nested tree (4 levels)', () => {
192
+ const messages: Message[] = [
193
+ {
194
+ content: 'Level 0',
195
+ createdAt: 1000,
196
+ id: 'msg-1',
197
+ meta: {},
198
+ role: 'user',
199
+ updatedAt: 1000,
200
+ },
201
+ {
202
+ content: 'Level 1',
203
+ createdAt: 2000,
204
+ id: 'msg-2',
205
+ meta: {},
206
+ parentId: 'msg-1',
207
+ role: 'assistant',
208
+ updatedAt: 2000,
209
+ },
210
+ {
211
+ content: 'Level 2',
212
+ createdAt: 3000,
213
+ id: 'msg-3',
214
+ meta: {},
215
+ parentId: 'msg-2',
216
+ role: 'user',
217
+ updatedAt: 3000,
218
+ },
219
+ {
220
+ content: 'Level 3',
221
+ createdAt: 4000,
222
+ id: 'msg-4',
223
+ meta: {},
224
+ parentId: 'msg-3',
225
+ role: 'assistant',
226
+ updatedAt: 4000,
227
+ },
228
+ ];
229
+
230
+ const helperMaps = buildHelperMaps(messages);
231
+ const result = buildIdTree(helperMaps);
232
+
233
+ expect(result).toHaveLength(1);
234
+
235
+ let current = result[0];
236
+ expect(current.id).toBe('msg-1');
237
+
238
+ current = current.children[0];
239
+ expect(current.id).toBe('msg-2');
240
+
241
+ current = current.children[0];
242
+ expect(current.id).toBe('msg-3');
243
+
244
+ current = current.children[0];
245
+ expect(current.id).toBe('msg-4');
246
+ expect(current.children).toHaveLength(0);
247
+ });
248
+ });
249
+
250
+ describe('thread handling', () => {
251
+ it('should exclude messages with threadId from main tree', () => {
252
+ const messages: Message[] = [
253
+ {
254
+ content: 'Root',
255
+ createdAt: 1000,
256
+ id: 'msg-1',
257
+ meta: {},
258
+ role: 'user',
259
+ updatedAt: 1000,
260
+ },
261
+ {
262
+ content: 'Main flow',
263
+ createdAt: 2000,
264
+ id: 'msg-2',
265
+ meta: {},
266
+ parentId: 'msg-1',
267
+ role: 'assistant',
268
+ updatedAt: 2000,
269
+ },
270
+ {
271
+ content: 'Thread message',
272
+ createdAt: 3000,
273
+ id: 'msg-3',
274
+ meta: {},
275
+ parentId: 'msg-1',
276
+ role: 'assistant',
277
+ threadId: 'thread-1',
278
+ updatedAt: 3000,
279
+ },
280
+ ];
281
+
282
+ const helperMaps = buildHelperMaps(messages);
283
+ const result = buildIdTree(helperMaps);
284
+
285
+ expect(result).toHaveLength(1);
286
+ expect(result[0].id).toBe('msg-1');
287
+ expect(result[0].children).toHaveLength(1);
288
+ expect(result[0].children[0].id).toBe('msg-2');
289
+ });
290
+
291
+ it('should exclude root messages with threadId', () => {
292
+ const messages: Message[] = [
293
+ {
294
+ content: 'Main root',
295
+ createdAt: 1000,
296
+ id: 'msg-1',
297
+ meta: {},
298
+ role: 'user',
299
+ updatedAt: 1000,
300
+ },
301
+ {
302
+ content: 'Thread root',
303
+ createdAt: 2000,
304
+ id: 'msg-2',
305
+ meta: {},
306
+ role: 'assistant',
307
+ threadId: 'thread-1',
308
+ updatedAt: 2000,
309
+ },
310
+ ];
311
+
312
+ const helperMaps = buildHelperMaps(messages);
313
+ const result = buildIdTree(helperMaps);
314
+
315
+ expect(result).toHaveLength(1);
316
+ expect(result[0].id).toBe('msg-1');
317
+ });
318
+
319
+ it('should filter out thread children at any level', () => {
320
+ const messages: Message[] = [
321
+ {
322
+ content: 'Root',
323
+ createdAt: 1000,
324
+ id: 'msg-1',
325
+ meta: {},
326
+ role: 'user',
327
+ updatedAt: 1000,
328
+ },
329
+ {
330
+ content: 'Main child',
331
+ createdAt: 2000,
332
+ id: 'msg-2',
333
+ meta: {},
334
+ parentId: 'msg-1',
335
+ role: 'assistant',
336
+ updatedAt: 2000,
337
+ },
338
+ {
339
+ content: 'Main grandchild',
340
+ createdAt: 3000,
341
+ id: 'msg-3',
342
+ meta: {},
343
+ parentId: 'msg-2',
344
+ role: 'user',
345
+ updatedAt: 3000,
346
+ },
347
+ {
348
+ content: 'Thread grandchild',
349
+ createdAt: 4000,
350
+ id: 'msg-4',
351
+ meta: {},
352
+ parentId: 'msg-2',
353
+ role: 'user',
354
+ threadId: 'thread-1',
355
+ updatedAt: 4000,
356
+ },
357
+ ];
358
+
359
+ const helperMaps = buildHelperMaps(messages);
360
+ const result = buildIdTree(helperMaps);
361
+
362
+ expect(result).toHaveLength(1);
363
+ expect(result[0].children[0].id).toBe('msg-2');
364
+ expect(result[0].children[0].children).toHaveLength(1);
365
+ expect(result[0].children[0].children[0].id).toBe('msg-3');
366
+ });
367
+ });
368
+
369
+ describe('edge cases', () => {
370
+ it('should handle empty messages', () => {
371
+ const helperMaps = buildHelperMaps([]);
372
+ const result = buildIdTree(helperMaps);
373
+
374
+ expect(result).toEqual([]);
375
+ });
376
+
377
+ it('should handle messages with no children', () => {
378
+ const messages: Message[] = [
379
+ {
380
+ content: 'Lone message',
381
+ createdAt: 1000,
382
+ id: 'msg-1',
383
+ meta: {},
384
+ role: 'user',
385
+ updatedAt: 1000,
386
+ },
387
+ ];
388
+
389
+ const helperMaps = buildHelperMaps(messages);
390
+ const result = buildIdTree(helperMaps);
391
+
392
+ expect(result).toHaveLength(1);
393
+ expect(result[0]).toEqual({
394
+ children: [],
395
+ id: 'msg-1',
396
+ });
397
+ });
398
+
399
+ it('should handle messages with missing parent references', () => {
400
+ const messages: Message[] = [
401
+ {
402
+ content: 'Orphan',
403
+ createdAt: 1000,
404
+ id: 'msg-1',
405
+ meta: {},
406
+ parentId: 'non-existent',
407
+ role: 'user',
408
+ updatedAt: 1000,
409
+ },
410
+ ];
411
+
412
+ const helperMaps = buildHelperMaps(messages);
413
+ const result = buildIdTree(helperMaps);
414
+
415
+ // Orphan messages without valid parents are not in main flow
416
+ expect(result).toEqual([]);
417
+ });
418
+
419
+ it('should build correct tree when all messages are threaded', () => {
420
+ const messages: Message[] = [
421
+ {
422
+ content: 'Thread 1',
423
+ createdAt: 1000,
424
+ id: 'msg-1',
425
+ meta: {},
426
+ role: 'user',
427
+ threadId: 'thread-1',
428
+ updatedAt: 1000,
429
+ },
430
+ {
431
+ content: 'Thread 2',
432
+ createdAt: 2000,
433
+ id: 'msg-2',
434
+ meta: {},
435
+ role: 'assistant',
436
+ threadId: 'thread-1',
437
+ updatedAt: 2000,
438
+ },
439
+ ];
440
+
441
+ const helperMaps = buildHelperMaps(messages);
442
+ const result = buildIdTree(helperMaps);
443
+
444
+ expect(result).toEqual([]);
445
+ });
446
+ });
447
+
448
+ describe('complex scenarios', () => {
449
+ it('should build tree with mixed branches and linear paths', () => {
450
+ const messages: Message[] = [
451
+ {
452
+ content: 'Root',
453
+ createdAt: 1000,
454
+ id: 'msg-1',
455
+ meta: {},
456
+ role: 'user',
457
+ updatedAt: 1000,
458
+ },
459
+ {
460
+ content: 'Branch A',
461
+ createdAt: 2000,
462
+ id: 'msg-2',
463
+ meta: {},
464
+ parentId: 'msg-1',
465
+ role: 'assistant',
466
+ updatedAt: 2000,
467
+ },
468
+ {
469
+ content: 'Branch A -> Child',
470
+ createdAt: 3000,
471
+ id: 'msg-3',
472
+ meta: {},
473
+ parentId: 'msg-2',
474
+ role: 'user',
475
+ updatedAt: 3000,
476
+ },
477
+ {
478
+ content: 'Branch B',
479
+ createdAt: 4000,
480
+ id: 'msg-4',
481
+ meta: {},
482
+ parentId: 'msg-1',
483
+ role: 'assistant',
484
+ updatedAt: 4000,
485
+ },
486
+ {
487
+ content: 'Branch B -> Child 1',
488
+ createdAt: 5000,
489
+ id: 'msg-5',
490
+ meta: {},
491
+ parentId: 'msg-4',
492
+ role: 'user',
493
+ updatedAt: 5000,
494
+ },
495
+ {
496
+ content: 'Branch B -> Child 2',
497
+ createdAt: 6000,
498
+ id: 'msg-6',
499
+ meta: {},
500
+ parentId: 'msg-4',
501
+ role: 'user',
502
+ updatedAt: 6000,
503
+ },
504
+ ];
505
+
506
+ const helperMaps = buildHelperMaps(messages);
507
+ const result = buildIdTree(helperMaps);
508
+
509
+ expect(result).toHaveLength(1);
510
+ expect(result[0].id).toBe('msg-1');
511
+ expect(result[0].children).toHaveLength(2);
512
+
513
+ // Branch A
514
+ expect(result[0].children[0].id).toBe('msg-2');
515
+ expect(result[0].children[0].children).toHaveLength(1);
516
+ expect(result[0].children[0].children[0].id).toBe('msg-3');
517
+
518
+ // Branch B
519
+ expect(result[0].children[1].id).toBe('msg-4');
520
+ expect(result[0].children[1].children).toHaveLength(2);
521
+ expect(result[0].children[1].children[0].id).toBe('msg-5');
522
+ expect(result[0].children[1].children[1].id).toBe('msg-6');
523
+ });
524
+
525
+ it('should handle multiple root trees', () => {
526
+ const messages: Message[] = [
527
+ // Tree 1
528
+ {
529
+ content: 'Tree 1 Root',
530
+ createdAt: 1000,
531
+ id: 'msg-1',
532
+ meta: {},
533
+ role: 'user',
534
+ updatedAt: 1000,
535
+ },
536
+ {
537
+ content: 'Tree 1 Child',
538
+ createdAt: 2000,
539
+ id: 'msg-2',
540
+ meta: {},
541
+ parentId: 'msg-1',
542
+ role: 'assistant',
543
+ updatedAt: 2000,
544
+ },
545
+ // Tree 2
546
+ {
547
+ content: 'Tree 2 Root',
548
+ createdAt: 3000,
549
+ id: 'msg-3',
550
+ meta: {},
551
+ role: 'user',
552
+ updatedAt: 3000,
553
+ },
554
+ {
555
+ content: 'Tree 2 Child',
556
+ createdAt: 4000,
557
+ id: 'msg-4',
558
+ meta: {},
559
+ parentId: 'msg-3',
560
+ role: 'assistant',
561
+ updatedAt: 4000,
562
+ },
563
+ ];
564
+
565
+ const helperMaps = buildHelperMaps(messages);
566
+ const result = buildIdTree(helperMaps);
567
+
568
+ expect(result).toHaveLength(2);
569
+ expect(result[0].id).toBe('msg-1');
570
+ expect(result[0].children[0].id).toBe('msg-2');
571
+ expect(result[1].id).toBe('msg-3');
572
+ expect(result[1].children[0].id).toBe('msg-4');
573
+ });
574
+ });
575
+
576
+ describe('performance', () => {
577
+ it('should build tree for large dataset efficiently', () => {
578
+ const messages: Message[] = Array.from({ length: 1000 }, (_, i) => ({
579
+ content: `Message ${i}`,
580
+ createdAt: i,
581
+ id: `msg-${i}`,
582
+ meta: {},
583
+ parentId: i > 0 ? `msg-${i - 1}` : undefined,
584
+ role: i % 2 === 0 ? ('user' as const) : ('assistant' as const),
585
+ updatedAt: i,
586
+ }));
587
+
588
+ const helperMaps = buildHelperMaps(messages);
589
+
590
+ const startTime = performance.now();
591
+ const result = buildIdTree(helperMaps);
592
+ const endTime = performance.now();
593
+
594
+ const executionTime = endTime - startTime;
595
+
596
+ expect(result).toHaveLength(1);
597
+ expect(executionTime).toBeLessThan(50); // Should be fast
598
+ });
599
+ });
600
+ });
@@ -60,6 +60,7 @@ export const KeyEnum = {
60
60
  export const HotkeyEnum = {
61
61
  AddUserMessage: 'addUserMessage',
62
62
  ClearCurrentMessages: 'clearCurrentMessages',
63
+ CommandPalette: 'commandPalette',
63
64
  DeleteAndRegenerateMessage: 'deleteAndRegenerateMessage',
64
65
  DeleteLastMessage: 'deleteLastMessage',
65
66
  EditMessage: 'editMessage',
@@ -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
  });