@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,513 @@
1
+ import { describe, expect, it } from 'vitest';
2
+
3
+ import { buildHelperMaps } from '../indexing';
4
+ import type { Message, MessageGroupMetadata } from '../types';
5
+
6
+ describe('buildHelperMaps', () => {
7
+ describe('messageMap', () => {
8
+ it('should build messageMap for O(1) access', () => {
9
+ const messages: Message[] = [
10
+ {
11
+ content: 'Hello',
12
+ createdAt: 1000,
13
+ id: 'msg-1',
14
+ meta: {},
15
+ role: 'user',
16
+ updatedAt: 1000,
17
+ },
18
+ {
19
+ content: 'Hi there',
20
+ createdAt: 2000,
21
+ id: 'msg-2',
22
+ meta: {},
23
+ parentId: 'msg-1',
24
+ role: 'assistant',
25
+ updatedAt: 2000,
26
+ },
27
+ ];
28
+
29
+ const result = buildHelperMaps(messages);
30
+
31
+ expect(result.messageMap.size).toBe(2);
32
+ expect(result.messageMap.get('msg-1')).toEqual(messages[0]);
33
+ expect(result.messageMap.get('msg-2')).toEqual(messages[1]);
34
+ });
35
+
36
+ it('should handle empty messages array', () => {
37
+ const result = buildHelperMaps([]);
38
+
39
+ expect(result.messageMap.size).toBe(0);
40
+ });
41
+
42
+ it('should handle single message', () => {
43
+ const messages: Message[] = [
44
+ {
45
+ content: 'Single message',
46
+ createdAt: 1000,
47
+ id: 'msg-1',
48
+ meta: {},
49
+ role: 'user',
50
+ updatedAt: 1000,
51
+ },
52
+ ];
53
+
54
+ const result = buildHelperMaps(messages);
55
+
56
+ expect(result.messageMap.size).toBe(1);
57
+ expect(result.messageMap.get('msg-1')).toEqual(messages[0]);
58
+ });
59
+ });
60
+
61
+ describe('childrenMap', () => {
62
+ it('should build childrenMap for parent-child relationships', () => {
63
+ const messages: Message[] = [
64
+ {
65
+ content: 'Root',
66
+ createdAt: 1000,
67
+ id: 'msg-1',
68
+ meta: {},
69
+ role: 'user',
70
+ updatedAt: 1000,
71
+ },
72
+ {
73
+ content: 'Child 1',
74
+ createdAt: 2000,
75
+ id: 'msg-2',
76
+ meta: {},
77
+ parentId: 'msg-1',
78
+ role: 'assistant',
79
+ updatedAt: 2000,
80
+ },
81
+ {
82
+ content: 'Child 2',
83
+ createdAt: 3000,
84
+ id: 'msg-3',
85
+ meta: {},
86
+ parentId: 'msg-1',
87
+ role: 'assistant',
88
+ updatedAt: 3000,
89
+ },
90
+ ];
91
+
92
+ const result = buildHelperMaps(messages);
93
+
94
+ expect(result.childrenMap.get(null)).toEqual(['msg-1']);
95
+ expect(result.childrenMap.get('msg-1')).toEqual(['msg-2', 'msg-3']);
96
+ });
97
+
98
+ it('should handle messages with no parent (root messages)', () => {
99
+ const messages: Message[] = [
100
+ {
101
+ content: 'Root 1',
102
+ createdAt: 1000,
103
+ id: 'msg-1',
104
+ meta: {},
105
+ role: 'user',
106
+ updatedAt: 1000,
107
+ },
108
+ {
109
+ content: 'Root 2',
110
+ createdAt: 2000,
111
+ id: 'msg-2',
112
+ meta: {},
113
+ role: 'user',
114
+ updatedAt: 2000,
115
+ },
116
+ ];
117
+
118
+ const result = buildHelperMaps(messages);
119
+
120
+ expect(result.childrenMap.get(null)).toEqual(['msg-1', 'msg-2']);
121
+ });
122
+
123
+ it('should handle deeply nested parent-child relationships', () => {
124
+ const messages: Message[] = [
125
+ {
126
+ content: 'Level 0',
127
+ createdAt: 1000,
128
+ id: 'msg-1',
129
+ meta: {},
130
+ role: 'user',
131
+ updatedAt: 1000,
132
+ },
133
+ {
134
+ content: 'Level 1',
135
+ createdAt: 2000,
136
+ id: 'msg-2',
137
+ meta: {},
138
+ parentId: 'msg-1',
139
+ role: 'assistant',
140
+ updatedAt: 2000,
141
+ },
142
+ {
143
+ content: 'Level 2',
144
+ createdAt: 3000,
145
+ id: 'msg-3',
146
+ meta: {},
147
+ parentId: 'msg-2',
148
+ role: 'user',
149
+ updatedAt: 3000,
150
+ },
151
+ {
152
+ content: 'Level 3',
153
+ createdAt: 4000,
154
+ id: 'msg-4',
155
+ meta: {},
156
+ parentId: 'msg-3',
157
+ role: 'assistant',
158
+ updatedAt: 4000,
159
+ },
160
+ ];
161
+
162
+ const result = buildHelperMaps(messages);
163
+
164
+ expect(result.childrenMap.get(null)).toEqual(['msg-1']);
165
+ expect(result.childrenMap.get('msg-1')).toEqual(['msg-2']);
166
+ expect(result.childrenMap.get('msg-2')).toEqual(['msg-3']);
167
+ expect(result.childrenMap.get('msg-3')).toEqual(['msg-4']);
168
+ });
169
+
170
+ it('should handle branching conversations', () => {
171
+ const messages: Message[] = [
172
+ {
173
+ content: 'Root',
174
+ createdAt: 1000,
175
+ id: 'msg-1',
176
+ meta: {},
177
+ role: 'user',
178
+ updatedAt: 1000,
179
+ },
180
+ {
181
+ content: 'Branch 1',
182
+ createdAt: 2000,
183
+ id: 'msg-2',
184
+ meta: {},
185
+ parentId: 'msg-1',
186
+ role: 'assistant',
187
+ updatedAt: 2000,
188
+ },
189
+ {
190
+ content: 'Branch 2',
191
+ createdAt: 3000,
192
+ id: 'msg-3',
193
+ meta: {},
194
+ parentId: 'msg-1',
195
+ role: 'assistant',
196
+ updatedAt: 3000,
197
+ },
198
+ {
199
+ content: 'Sub-branch 1',
200
+ createdAt: 4000,
201
+ id: 'msg-4',
202
+ meta: {},
203
+ parentId: 'msg-2',
204
+ role: 'user',
205
+ updatedAt: 4000,
206
+ },
207
+ {
208
+ content: 'Sub-branch 2',
209
+ createdAt: 5000,
210
+ id: 'msg-5',
211
+ meta: {},
212
+ parentId: 'msg-2',
213
+ role: 'user',
214
+ updatedAt: 5000,
215
+ },
216
+ ];
217
+
218
+ const result = buildHelperMaps(messages);
219
+
220
+ expect(result.childrenMap.get(null)).toEqual(['msg-1']);
221
+ expect(result.childrenMap.get('msg-1')).toEqual(['msg-2', 'msg-3']);
222
+ expect(result.childrenMap.get('msg-2')).toEqual(['msg-4', 'msg-5']);
223
+ });
224
+ });
225
+
226
+ describe('threadMap', () => {
227
+ it('should build threadMap for messages with threadId', () => {
228
+ const messages: Message[] = [
229
+ {
230
+ content: 'Main message',
231
+ createdAt: 1000,
232
+ id: 'msg-1',
233
+ meta: {},
234
+ role: 'user',
235
+ updatedAt: 1000,
236
+ },
237
+ {
238
+ content: 'Thread message 1',
239
+ createdAt: 2000,
240
+ id: 'msg-2',
241
+ meta: {},
242
+ parentId: 'msg-1',
243
+ role: 'assistant',
244
+ threadId: 'thread-1',
245
+ updatedAt: 2000,
246
+ },
247
+ {
248
+ content: 'Thread message 2',
249
+ createdAt: 3000,
250
+ id: 'msg-3',
251
+ meta: {},
252
+ parentId: 'msg-2',
253
+ role: 'user',
254
+ threadId: 'thread-1',
255
+ updatedAt: 3000,
256
+ },
257
+ ];
258
+
259
+ const result = buildHelperMaps(messages);
260
+
261
+ expect(result.threadMap.size).toBe(1);
262
+ expect(result.threadMap.get('thread-1')).toHaveLength(2);
263
+ expect(result.threadMap.get('thread-1')).toEqual([messages[1], messages[2]]);
264
+ });
265
+
266
+ it('should handle multiple threads', () => {
267
+ const messages: Message[] = [
268
+ {
269
+ content: 'Thread 1 - msg 1',
270
+ createdAt: 1000,
271
+ id: 'msg-1',
272
+ meta: {},
273
+ role: 'user',
274
+ threadId: 'thread-1',
275
+ updatedAt: 1000,
276
+ },
277
+ {
278
+ content: 'Thread 1 - msg 2',
279
+ createdAt: 2000,
280
+ id: 'msg-2',
281
+ meta: {},
282
+ role: 'assistant',
283
+ threadId: 'thread-1',
284
+ updatedAt: 2000,
285
+ },
286
+ {
287
+ content: 'Thread 2 - msg 1',
288
+ createdAt: 3000,
289
+ id: 'msg-3',
290
+ meta: {},
291
+ role: 'user',
292
+ threadId: 'thread-2',
293
+ updatedAt: 3000,
294
+ },
295
+ ];
296
+
297
+ const result = buildHelperMaps(messages);
298
+
299
+ expect(result.threadMap.size).toBe(2);
300
+ expect(result.threadMap.get('thread-1')).toEqual([messages[0], messages[1]]);
301
+ expect(result.threadMap.get('thread-2')).toEqual([messages[2]]);
302
+ });
303
+
304
+ it('should not include messages without threadId in threadMap', () => {
305
+ const messages: Message[] = [
306
+ {
307
+ content: 'No thread',
308
+ createdAt: 1000,
309
+ id: 'msg-1',
310
+ meta: {},
311
+ role: 'user',
312
+ updatedAt: 1000,
313
+ },
314
+ {
315
+ content: 'With thread',
316
+ createdAt: 2000,
317
+ id: 'msg-2',
318
+ meta: {},
319
+ role: 'assistant',
320
+ threadId: 'thread-1',
321
+ updatedAt: 2000,
322
+ },
323
+ ];
324
+
325
+ const result = buildHelperMaps(messages);
326
+
327
+ expect(result.threadMap.size).toBe(1);
328
+ expect(result.threadMap.get('thread-1')).toEqual([messages[1]]);
329
+ });
330
+
331
+ it('should handle empty threadMap when no messages have threadId', () => {
332
+ const messages: Message[] = [
333
+ {
334
+ content: 'Message 1',
335
+ createdAt: 1000,
336
+ id: 'msg-1',
337
+ meta: {},
338
+ role: 'user',
339
+ updatedAt: 1000,
340
+ },
341
+ {
342
+ content: 'Message 2',
343
+ createdAt: 2000,
344
+ id: 'msg-2',
345
+ meta: {},
346
+ role: 'assistant',
347
+ updatedAt: 2000,
348
+ },
349
+ ];
350
+
351
+ const result = buildHelperMaps(messages);
352
+
353
+ expect(result.threadMap.size).toBe(0);
354
+ });
355
+ });
356
+
357
+ describe('messageGroupMap', () => {
358
+ it('should build messageGroupMap from provided metadata', () => {
359
+ const messages: Message[] = [
360
+ {
361
+ content: 'Message',
362
+ createdAt: 1000,
363
+ id: 'msg-1',
364
+ meta: {},
365
+ role: 'user',
366
+ updatedAt: 1000,
367
+ },
368
+ ];
369
+
370
+ const messageGroups: MessageGroupMetadata[] = [
371
+ {
372
+ id: 'group-1',
373
+ mode: 'compare',
374
+ },
375
+ {
376
+ id: 'group-2',
377
+ mode: 'summary',
378
+ },
379
+ ];
380
+
381
+ const result = buildHelperMaps(messages, messageGroups);
382
+
383
+ expect(result.messageGroupMap.size).toBe(2);
384
+ expect(result.messageGroupMap.get('group-1')).toEqual(messageGroups[0]);
385
+ expect(result.messageGroupMap.get('group-2')).toEqual(messageGroups[1]);
386
+ });
387
+
388
+ it('should handle empty messageGroupMap when no metadata provided', () => {
389
+ const messages: Message[] = [
390
+ {
391
+ content: 'Message',
392
+ createdAt: 1000,
393
+ id: 'msg-1',
394
+ meta: {},
395
+ role: 'user',
396
+ updatedAt: 1000,
397
+ },
398
+ ];
399
+
400
+ const result = buildHelperMaps(messages);
401
+
402
+ expect(result.messageGroupMap.size).toBe(0);
403
+ });
404
+
405
+ it('should handle empty messageGroupMap when empty array provided', () => {
406
+ const messages: Message[] = [
407
+ {
408
+ content: 'Message',
409
+ createdAt: 1000,
410
+ id: 'msg-1',
411
+ meta: {},
412
+ role: 'user',
413
+ updatedAt: 1000,
414
+ },
415
+ ];
416
+
417
+ const result = buildHelperMaps(messages, []);
418
+
419
+ expect(result.messageGroupMap.size).toBe(0);
420
+ });
421
+ });
422
+
423
+ describe('integration scenarios', () => {
424
+ it('should build all maps correctly in complex conversation', () => {
425
+ const messages: Message[] = [
426
+ {
427
+ content: 'Root message',
428
+ createdAt: 1000,
429
+ id: 'msg-1',
430
+ meta: {},
431
+ role: 'user',
432
+ updatedAt: 1000,
433
+ },
434
+ {
435
+ content: 'Assistant response',
436
+ createdAt: 2000,
437
+ groupId: 'group-1',
438
+ id: 'msg-2',
439
+ meta: {},
440
+ parentId: 'msg-1',
441
+ role: 'assistant',
442
+ updatedAt: 2000,
443
+ },
444
+ {
445
+ content: 'Thread message',
446
+ createdAt: 3000,
447
+ id: 'msg-3',
448
+ meta: {},
449
+ parentId: 'msg-2',
450
+ role: 'user',
451
+ threadId: 'thread-1',
452
+ updatedAt: 3000,
453
+ },
454
+ {
455
+ content: 'Branch message',
456
+ createdAt: 4000,
457
+ id: 'msg-4',
458
+ meta: {},
459
+ parentId: 'msg-1',
460
+ role: 'assistant',
461
+ updatedAt: 4000,
462
+ },
463
+ ];
464
+
465
+ const messageGroups: MessageGroupMetadata[] = [
466
+ {
467
+ id: 'group-1',
468
+ mode: 'compare',
469
+ },
470
+ ];
471
+
472
+ const result = buildHelperMaps(messages, messageGroups);
473
+
474
+ // Verify messageMap
475
+ expect(result.messageMap.size).toBe(4);
476
+
477
+ // Verify childrenMap
478
+ expect(result.childrenMap.get(null)).toEqual(['msg-1']);
479
+ expect(result.childrenMap.get('msg-1')).toEqual(['msg-2', 'msg-4']);
480
+ expect(result.childrenMap.get('msg-2')).toEqual(['msg-3']);
481
+
482
+ // Verify threadMap
483
+ expect(result.threadMap.size).toBe(1);
484
+ expect(result.threadMap.get('thread-1')).toEqual([messages[2]]);
485
+
486
+ // Verify messageGroupMap
487
+ expect(result.messageGroupMap.size).toBe(1);
488
+ expect(result.messageGroupMap.get('group-1')).toEqual(messageGroups[0]);
489
+ });
490
+
491
+ it('should handle large number of messages efficiently', () => {
492
+ const messages: Message[] = Array.from({ length: 1000 }, (_, i) => ({
493
+ content: `Message ${i}`,
494
+ createdAt: i,
495
+ id: `msg-${i}`,
496
+ meta: {},
497
+ parentId: i > 0 ? `msg-${i - 1}` : undefined,
498
+ role: i % 2 === 0 ? ('user' as const) : ('assistant' as const),
499
+ updatedAt: i,
500
+ }));
501
+
502
+ const startTime = performance.now();
503
+ const result = buildHelperMaps(messages);
504
+ const endTime = performance.now();
505
+
506
+ const executionTime = endTime - startTime;
507
+
508
+ expect(result.messageMap.size).toBe(1000);
509
+ expect(result.childrenMap.size).toBe(1000);
510
+ expect(executionTime).toBeLessThan(50); // Should be fast
511
+ });
512
+ });
513
+ });