@lobehub/lobehub 2.0.0-next.360 → 2.0.0-next.362
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/CHANGELOG.md +50 -0
- package/Dockerfile +2 -1
- package/changelog/v1.json +14 -0
- package/locales/en-US/chat.json +3 -1
- package/locales/zh-CN/chat.json +2 -0
- package/package.json +1 -1
- package/packages/const/src/userMemory.ts +1 -0
- package/packages/context-engine/src/base/BaseEveryUserContentProvider.ts +204 -0
- package/packages/context-engine/src/base/BaseLastUserContentProvider.ts +1 -8
- package/packages/context-engine/src/base/__tests__/BaseEveryUserContentProvider.test.ts +354 -0
- package/packages/context-engine/src/base/constants.ts +20 -0
- package/packages/context-engine/src/engine/messages/MessagesEngine.ts +27 -23
- package/packages/context-engine/src/engine/messages/__tests__/MessagesEngine.test.ts +364 -0
- package/packages/context-engine/src/providers/PageEditorContextInjector.ts +17 -13
- package/packages/context-engine/src/providers/PageSelectionsInjector.ts +65 -0
- package/packages/context-engine/src/providers/__tests__/PageSelectionsInjector.test.ts +333 -0
- package/packages/context-engine/src/providers/index.ts +3 -1
- package/packages/database/src/models/userMemory/model.ts +178 -3
- package/packages/database/src/models/userMemory/sources/benchmarkLoCoMo.ts +1 -1
- package/packages/memory-user-memory/package.json +2 -1
- package/packages/memory-user-memory/promptfoo/evals/activity/basic/buildMessages.ts +40 -0
- package/packages/memory-user-memory/promptfoo/evals/activity/basic/eval.yaml +13 -0
- package/packages/memory-user-memory/promptfoo/evals/activity/basic/prompt.ts +5 -0
- package/packages/memory-user-memory/promptfoo/evals/activity/basic/tests/cases.ts +106 -0
- package/packages/memory-user-memory/promptfoo/evals/activity/locomo/buildMessages.ts +104 -0
- package/packages/memory-user-memory/promptfoo/evals/activity/locomo/eval.yaml +13 -0
- package/packages/memory-user-memory/promptfoo/evals/activity/locomo/prompt.ts +5 -0
- package/packages/memory-user-memory/promptfoo/evals/activity/locomo/tests/benchmark-locomo-payload-conv-26.json +149 -0
- package/packages/memory-user-memory/promptfoo/evals/activity/locomo/tests/cases.ts +72 -0
- package/packages/memory-user-memory/promptfoo/response-formats/activity.json +370 -0
- package/packages/memory-user-memory/promptfoo/response-formats/experience.json +14 -0
- package/packages/memory-user-memory/promptfoo/response-formats/identity.json +281 -255
- package/packages/memory-user-memory/promptfooconfig.yaml +1 -0
- package/packages/memory-user-memory/scripts/generate-response-formats.ts +26 -2
- package/packages/memory-user-memory/src/extractors/activity.ts +44 -0
- package/packages/memory-user-memory/src/extractors/gatekeeper.test.ts +2 -1
- package/packages/memory-user-memory/src/extractors/gatekeeper.ts +2 -1
- package/packages/memory-user-memory/src/extractors/index.ts +1 -0
- package/packages/memory-user-memory/src/prompts/gatekeeper.ts +3 -3
- package/packages/memory-user-memory/src/prompts/index.ts +7 -1
- package/packages/memory-user-memory/src/prompts/layers/activity.ts +90 -0
- package/packages/memory-user-memory/src/prompts/layers/index.ts +1 -0
- package/packages/memory-user-memory/src/providers/existingUserMemory.test.ts +25 -1
- package/packages/memory-user-memory/src/providers/existingUserMemory.ts +113 -0
- package/packages/memory-user-memory/src/schemas/activity.ts +315 -0
- package/packages/memory-user-memory/src/schemas/experience.ts +5 -5
- package/packages/memory-user-memory/src/schemas/gatekeeper.ts +1 -0
- package/packages/memory-user-memory/src/schemas/index.ts +1 -0
- package/packages/memory-user-memory/src/services/extractExecutor.ts +29 -0
- package/packages/memory-user-memory/src/types.ts +7 -0
- package/packages/prompts/src/agents/index.ts +1 -0
- package/packages/prompts/src/agents/pageSelectionContext.ts +28 -0
- package/packages/types/src/aiChat.ts +4 -0
- package/packages/types/src/message/common/index.ts +1 -0
- package/packages/types/src/message/common/metadata.ts +8 -0
- package/packages/types/src/message/common/pageSelection.ts +36 -0
- package/packages/types/src/message/ui/params.ts +16 -0
- package/packages/types/src/serverConfig.ts +1 -1
- package/packages/types/src/userMemory/layers.ts +52 -0
- package/packages/types/src/userMemory/list.ts +20 -2
- package/packages/types/src/userMemory/shared.ts +22 -1
- package/packages/types/src/userMemory/trace.ts +1 -0
- package/packages/types/src/util.ts +9 -1
- package/scripts/prebuild.mts +1 -0
- package/src/features/ChatInput/Desktop/ContextContainer/ContextList.tsx +1 -1
- package/src/features/Conversation/ChatInput/index.tsx +9 -1
- package/src/features/Conversation/Messages/User/components/MessageContent.tsx +7 -1
- package/src/features/Conversation/Messages/User/components/PageSelections.tsx +62 -0
- package/src/features/PageEditor/EditorCanvas/useAskCopilotItem.tsx +5 -1
- package/src/libs/next/proxy/define-config.ts +1 -0
- package/src/locales/default/chat.ts +3 -2
- package/src/server/globalConfig/parseMemoryExtractionConfig.ts +7 -1
- package/src/server/routers/lambda/aiChat.ts +7 -0
- package/src/server/services/memory/userMemory/__tests__/extract.runtime.test.ts +2 -0
- package/src/server/services/memory/userMemory/extract.ts +108 -7
- package/src/store/chat/slices/aiChat/actions/conversationLifecycle.ts +5 -19
|
@@ -407,4 +407,368 @@ describe('MessagesEngine', () => {
|
|
|
407
407
|
expect(userMessage?.content).toBe('Please respond to: user input');
|
|
408
408
|
});
|
|
409
409
|
});
|
|
410
|
+
|
|
411
|
+
describe('Page Editor context', () => {
|
|
412
|
+
it('should inject page content to the last user message when pageContentContext is provided', async () => {
|
|
413
|
+
const messages: UIChatMessage[] = [
|
|
414
|
+
{
|
|
415
|
+
content: 'First question',
|
|
416
|
+
createdAt: Date.now(),
|
|
417
|
+
id: 'msg-1',
|
|
418
|
+
role: 'user',
|
|
419
|
+
updatedAt: Date.now(),
|
|
420
|
+
} as UIChatMessage,
|
|
421
|
+
{
|
|
422
|
+
content: 'Answer',
|
|
423
|
+
createdAt: Date.now(),
|
|
424
|
+
id: 'msg-2',
|
|
425
|
+
role: 'assistant',
|
|
426
|
+
updatedAt: Date.now(),
|
|
427
|
+
} as UIChatMessage,
|
|
428
|
+
{
|
|
429
|
+
content: 'Second question about the page',
|
|
430
|
+
createdAt: Date.now(),
|
|
431
|
+
id: 'msg-3',
|
|
432
|
+
role: 'user',
|
|
433
|
+
updatedAt: Date.now(),
|
|
434
|
+
} as UIChatMessage,
|
|
435
|
+
];
|
|
436
|
+
|
|
437
|
+
const params = createBasicParams({
|
|
438
|
+
messages,
|
|
439
|
+
pageContentContext: {
|
|
440
|
+
markdown: '# Document Title\n\nDocument content here.',
|
|
441
|
+
metadata: {
|
|
442
|
+
charCount: 40,
|
|
443
|
+
lineCount: 3,
|
|
444
|
+
title: 'Test Document',
|
|
445
|
+
},
|
|
446
|
+
},
|
|
447
|
+
});
|
|
448
|
+
const engine = new MessagesEngine(params);
|
|
449
|
+
|
|
450
|
+
const result = await engine.process();
|
|
451
|
+
|
|
452
|
+
expect(result.messages).toEqual([
|
|
453
|
+
{ content: 'First question', role: 'user' },
|
|
454
|
+
{ content: 'Answer', role: 'assistant' },
|
|
455
|
+
{
|
|
456
|
+
content: `Second question about the page
|
|
457
|
+
|
|
458
|
+
<!-- SYSTEM CONTEXT (NOT PART OF USER QUERY) -->
|
|
459
|
+
<context.instruction>following part contains context information injected by the system. Please follow these instructions:
|
|
460
|
+
|
|
461
|
+
1. Always prioritize handling user-visible content.
|
|
462
|
+
2. the context is only required when user's queries rely on it.
|
|
463
|
+
</context.instruction>
|
|
464
|
+
<current_page_context>
|
|
465
|
+
<current_page title="Test Document">
|
|
466
|
+
<markdown chars="40" lines="3">
|
|
467
|
+
# Document Title
|
|
468
|
+
|
|
469
|
+
Document content here.
|
|
470
|
+
</markdown>
|
|
471
|
+
</current_page>
|
|
472
|
+
</current_page_context>
|
|
473
|
+
<!-- END SYSTEM CONTEXT -->`,
|
|
474
|
+
role: 'user',
|
|
475
|
+
},
|
|
476
|
+
]);
|
|
477
|
+
|
|
478
|
+
expect(result.metadata.pageEditorContextInjected).toBe(true);
|
|
479
|
+
});
|
|
480
|
+
|
|
481
|
+
it('should not inject page content when not enabled', async () => {
|
|
482
|
+
const messages: UIChatMessage[] = [
|
|
483
|
+
{
|
|
484
|
+
content: 'Question',
|
|
485
|
+
createdAt: Date.now(),
|
|
486
|
+
id: 'msg-1',
|
|
487
|
+
role: 'user',
|
|
488
|
+
updatedAt: Date.now(),
|
|
489
|
+
} as UIChatMessage,
|
|
490
|
+
];
|
|
491
|
+
|
|
492
|
+
const params = createBasicParams({ messages });
|
|
493
|
+
const engine = new MessagesEngine(params);
|
|
494
|
+
|
|
495
|
+
const result = await engine.process();
|
|
496
|
+
|
|
497
|
+
expect(result.messages).toEqual([{ content: 'Question', role: 'user' }]);
|
|
498
|
+
expect(result.metadata.pageEditorContextInjected).toBeUndefined();
|
|
499
|
+
});
|
|
500
|
+
});
|
|
501
|
+
|
|
502
|
+
describe('Page Selections', () => {
|
|
503
|
+
it('should inject page selections to each user message that has them', async () => {
|
|
504
|
+
const messages: UIChatMessage[] = [
|
|
505
|
+
{
|
|
506
|
+
content: 'First question with selection',
|
|
507
|
+
createdAt: Date.now(),
|
|
508
|
+
id: 'msg-1',
|
|
509
|
+
metadata: {
|
|
510
|
+
pageSelections: [
|
|
511
|
+
{
|
|
512
|
+
content: 'Selected paragraph 1',
|
|
513
|
+
id: 'sel-1',
|
|
514
|
+
pageId: 'page-1',
|
|
515
|
+
xml: '<p>Selected paragraph 1</p>',
|
|
516
|
+
},
|
|
517
|
+
],
|
|
518
|
+
},
|
|
519
|
+
role: 'user',
|
|
520
|
+
updatedAt: Date.now(),
|
|
521
|
+
} as UIChatMessage,
|
|
522
|
+
{
|
|
523
|
+
content: 'Answer to first',
|
|
524
|
+
createdAt: Date.now(),
|
|
525
|
+
id: 'msg-2',
|
|
526
|
+
role: 'assistant',
|
|
527
|
+
updatedAt: Date.now(),
|
|
528
|
+
} as UIChatMessage,
|
|
529
|
+
{
|
|
530
|
+
content: 'Second question with different selection',
|
|
531
|
+
createdAt: Date.now(),
|
|
532
|
+
id: 'msg-3',
|
|
533
|
+
metadata: {
|
|
534
|
+
pageSelections: [
|
|
535
|
+
{
|
|
536
|
+
content: 'Selected paragraph 2',
|
|
537
|
+
id: 'sel-2',
|
|
538
|
+
pageId: 'page-1',
|
|
539
|
+
xml: '<p>Selected paragraph 2</p>',
|
|
540
|
+
},
|
|
541
|
+
],
|
|
542
|
+
},
|
|
543
|
+
role: 'user',
|
|
544
|
+
updatedAt: Date.now(),
|
|
545
|
+
} as UIChatMessage,
|
|
546
|
+
];
|
|
547
|
+
|
|
548
|
+
const params = createBasicParams({
|
|
549
|
+
messages,
|
|
550
|
+
pageContentContext: {
|
|
551
|
+
markdown: '# Doc',
|
|
552
|
+
metadata: { title: 'Doc' },
|
|
553
|
+
},
|
|
554
|
+
});
|
|
555
|
+
const engine = new MessagesEngine(params);
|
|
556
|
+
|
|
557
|
+
const result = await engine.process();
|
|
558
|
+
|
|
559
|
+
expect(result.messages).toEqual([
|
|
560
|
+
{
|
|
561
|
+
content: `First question with selection
|
|
562
|
+
|
|
563
|
+
<!-- SYSTEM CONTEXT (NOT PART OF USER QUERY) -->
|
|
564
|
+
<context.instruction>following part contains context information injected by the system. Please follow these instructions:
|
|
565
|
+
|
|
566
|
+
1. Always prioritize handling user-visible content.
|
|
567
|
+
2. the context is only required when user's queries rely on it.
|
|
568
|
+
</context.instruction>
|
|
569
|
+
<user_page_selections>
|
|
570
|
+
<user_selections count="1">
|
|
571
|
+
<selection >
|
|
572
|
+
<p>Selected paragraph 1</p>
|
|
573
|
+
</selection>
|
|
574
|
+
</user_selections>
|
|
575
|
+
</user_page_selections>
|
|
576
|
+
<!-- END SYSTEM CONTEXT -->`,
|
|
577
|
+
role: 'user',
|
|
578
|
+
},
|
|
579
|
+
{ content: 'Answer to first', role: 'assistant' },
|
|
580
|
+
{
|
|
581
|
+
content: `Second question with different selection
|
|
582
|
+
|
|
583
|
+
<!-- SYSTEM CONTEXT (NOT PART OF USER QUERY) -->
|
|
584
|
+
<context.instruction>following part contains context information injected by the system. Please follow these instructions:
|
|
585
|
+
|
|
586
|
+
1. Always prioritize handling user-visible content.
|
|
587
|
+
2. the context is only required when user's queries rely on it.
|
|
588
|
+
</context.instruction>
|
|
589
|
+
<user_page_selections>
|
|
590
|
+
<user_selections count="1">
|
|
591
|
+
<selection >
|
|
592
|
+
<p>Selected paragraph 2</p>
|
|
593
|
+
</selection>
|
|
594
|
+
</user_selections>
|
|
595
|
+
</user_page_selections>
|
|
596
|
+
<current_page_context>
|
|
597
|
+
<current_page title="Doc">
|
|
598
|
+
<markdown chars="5" lines="1">
|
|
599
|
+
# Doc
|
|
600
|
+
</markdown>
|
|
601
|
+
</current_page>
|
|
602
|
+
</current_page_context>
|
|
603
|
+
<!-- END SYSTEM CONTEXT -->`,
|
|
604
|
+
role: 'user',
|
|
605
|
+
},
|
|
606
|
+
]);
|
|
607
|
+
});
|
|
608
|
+
|
|
609
|
+
it('should skip user messages without pageSelections', async () => {
|
|
610
|
+
const messages: UIChatMessage[] = [
|
|
611
|
+
{
|
|
612
|
+
content: 'No selection here',
|
|
613
|
+
createdAt: Date.now(),
|
|
614
|
+
id: 'msg-1',
|
|
615
|
+
role: 'user',
|
|
616
|
+
updatedAt: Date.now(),
|
|
617
|
+
} as UIChatMessage,
|
|
618
|
+
{
|
|
619
|
+
content: 'Answer',
|
|
620
|
+
createdAt: Date.now(),
|
|
621
|
+
id: 'msg-2',
|
|
622
|
+
role: 'assistant',
|
|
623
|
+
updatedAt: Date.now(),
|
|
624
|
+
} as UIChatMessage,
|
|
625
|
+
{
|
|
626
|
+
content: 'With selection',
|
|
627
|
+
createdAt: Date.now(),
|
|
628
|
+
id: 'msg-3',
|
|
629
|
+
metadata: {
|
|
630
|
+
pageSelections: [
|
|
631
|
+
{
|
|
632
|
+
content: 'Selected text',
|
|
633
|
+
id: 'sel-1',
|
|
634
|
+
pageId: 'page-1',
|
|
635
|
+
xml: '<span>Selected text</span>',
|
|
636
|
+
},
|
|
637
|
+
],
|
|
638
|
+
},
|
|
639
|
+
role: 'user',
|
|
640
|
+
updatedAt: Date.now(),
|
|
641
|
+
} as UIChatMessage,
|
|
642
|
+
];
|
|
643
|
+
|
|
644
|
+
const params = createBasicParams({
|
|
645
|
+
messages,
|
|
646
|
+
pageContentContext: {
|
|
647
|
+
markdown: '# Doc',
|
|
648
|
+
metadata: { title: 'Doc' },
|
|
649
|
+
},
|
|
650
|
+
});
|
|
651
|
+
const engine = new MessagesEngine(params);
|
|
652
|
+
|
|
653
|
+
const result = await engine.process();
|
|
654
|
+
|
|
655
|
+
expect(result.messages).toEqual([
|
|
656
|
+
{ content: 'No selection here', role: 'user' },
|
|
657
|
+
{ content: 'Answer', role: 'assistant' },
|
|
658
|
+
{
|
|
659
|
+
content: `With selection
|
|
660
|
+
|
|
661
|
+
<!-- SYSTEM CONTEXT (NOT PART OF USER QUERY) -->
|
|
662
|
+
<context.instruction>following part contains context information injected by the system. Please follow these instructions:
|
|
663
|
+
|
|
664
|
+
1. Always prioritize handling user-visible content.
|
|
665
|
+
2. the context is only required when user's queries rely on it.
|
|
666
|
+
</context.instruction>
|
|
667
|
+
<user_page_selections>
|
|
668
|
+
<user_selections count="1">
|
|
669
|
+
<selection >
|
|
670
|
+
<span>Selected text</span>
|
|
671
|
+
</selection>
|
|
672
|
+
</user_selections>
|
|
673
|
+
</user_page_selections>
|
|
674
|
+
<current_page_context>
|
|
675
|
+
<current_page title="Doc">
|
|
676
|
+
<markdown chars="5" lines="1">
|
|
677
|
+
# Doc
|
|
678
|
+
</markdown>
|
|
679
|
+
</current_page>
|
|
680
|
+
</current_page_context>
|
|
681
|
+
<!-- END SYSTEM CONTEXT -->`,
|
|
682
|
+
role: 'user',
|
|
683
|
+
},
|
|
684
|
+
]);
|
|
685
|
+
});
|
|
686
|
+
|
|
687
|
+
it('should have only one SYSTEM CONTEXT wrapper when both selections and page content are injected', async () => {
|
|
688
|
+
const messages: UIChatMessage[] = [
|
|
689
|
+
{
|
|
690
|
+
content: 'Question about selection',
|
|
691
|
+
createdAt: Date.now(),
|
|
692
|
+
id: 'msg-1',
|
|
693
|
+
metadata: {
|
|
694
|
+
pageSelections: [
|
|
695
|
+
{
|
|
696
|
+
content: 'Selected text',
|
|
697
|
+
id: 'sel-1',
|
|
698
|
+
pageId: 'page-1',
|
|
699
|
+
xml: '<p>Selected text</p>',
|
|
700
|
+
},
|
|
701
|
+
],
|
|
702
|
+
},
|
|
703
|
+
role: 'user',
|
|
704
|
+
updatedAt: Date.now(),
|
|
705
|
+
} as UIChatMessage,
|
|
706
|
+
];
|
|
707
|
+
|
|
708
|
+
const params = createBasicParams({
|
|
709
|
+
messages,
|
|
710
|
+
pageContentContext: {
|
|
711
|
+
markdown: '# Full Document',
|
|
712
|
+
metadata: { title: 'Full Doc' },
|
|
713
|
+
},
|
|
714
|
+
});
|
|
715
|
+
const engine = new MessagesEngine(params);
|
|
716
|
+
|
|
717
|
+
const result = await engine.process();
|
|
718
|
+
|
|
719
|
+
expect(result.messages).toEqual([
|
|
720
|
+
{
|
|
721
|
+
content: `Question about selection
|
|
722
|
+
|
|
723
|
+
<!-- SYSTEM CONTEXT (NOT PART OF USER QUERY) -->
|
|
724
|
+
<context.instruction>following part contains context information injected by the system. Please follow these instructions:
|
|
725
|
+
|
|
726
|
+
1. Always prioritize handling user-visible content.
|
|
727
|
+
2. the context is only required when user's queries rely on it.
|
|
728
|
+
</context.instruction>
|
|
729
|
+
<user_page_selections>
|
|
730
|
+
<user_selections count="1">
|
|
731
|
+
<selection >
|
|
732
|
+
<p>Selected text</p>
|
|
733
|
+
</selection>
|
|
734
|
+
</user_selections>
|
|
735
|
+
</user_page_selections>
|
|
736
|
+
<current_page_context>
|
|
737
|
+
<current_page title="Full Doc">
|
|
738
|
+
<markdown chars="15" lines="1">
|
|
739
|
+
# Full Document
|
|
740
|
+
</markdown>
|
|
741
|
+
</current_page>
|
|
742
|
+
</current_page_context>
|
|
743
|
+
<!-- END SYSTEM CONTEXT -->`,
|
|
744
|
+
role: 'user',
|
|
745
|
+
},
|
|
746
|
+
]);
|
|
747
|
+
});
|
|
748
|
+
|
|
749
|
+
it('should not inject selections when page editor is not enabled', async () => {
|
|
750
|
+
const messages: UIChatMessage[] = [
|
|
751
|
+
{
|
|
752
|
+
content: 'Question',
|
|
753
|
+
createdAt: Date.now(),
|
|
754
|
+
id: 'msg-1',
|
|
755
|
+
metadata: {
|
|
756
|
+
pageSelections: [
|
|
757
|
+
{ content: 'Selected', id: 'sel-1', pageId: 'page-1', xml: '<p>Selected</p>' },
|
|
758
|
+
],
|
|
759
|
+
},
|
|
760
|
+
role: 'user',
|
|
761
|
+
updatedAt: Date.now(),
|
|
762
|
+
} as UIChatMessage,
|
|
763
|
+
];
|
|
764
|
+
|
|
765
|
+
// No pageContentContext or initialContext.pageEditor means not enabled
|
|
766
|
+
const params = createBasicParams({ messages });
|
|
767
|
+
const engine = new MessagesEngine(params);
|
|
768
|
+
|
|
769
|
+
const result = await engine.process();
|
|
770
|
+
|
|
771
|
+
expect(result.messages).toEqual([{ content: 'Question', role: 'user' }]);
|
|
772
|
+
});
|
|
773
|
+
});
|
|
410
774
|
});
|
|
@@ -20,6 +20,9 @@ export interface PageEditorContextInjectorConfig {
|
|
|
20
20
|
* Page Editor Context Injector
|
|
21
21
|
* Responsible for injecting current page context at the end of the last user message
|
|
22
22
|
* This ensures the model receives the most up-to-date page/document state
|
|
23
|
+
*
|
|
24
|
+
* Note: Page selections (user-selected text regions) are handled separately by
|
|
25
|
+
* PageSelectionsInjector, which injects selections into each user message that has them
|
|
23
26
|
*/
|
|
24
27
|
export class PageEditorContextInjector extends BaseLastUserContentProvider {
|
|
25
28
|
readonly name = 'PageEditorContextInjector';
|
|
@@ -37,20 +40,11 @@ export class PageEditorContextInjector extends BaseLastUserContentProvider {
|
|
|
37
40
|
|
|
38
41
|
const clonedContext = this.cloneContext(context);
|
|
39
42
|
|
|
40
|
-
//
|
|
41
|
-
|
|
42
|
-
log('Page Editor not enabled or no pageContentContext, skipping injection');
|
|
43
|
-
return this.markAsExecuted(clonedContext);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// Format page content context
|
|
47
|
-
const formattedContent = formatPageContentContext(this.config.pageContentContext);
|
|
48
|
-
|
|
49
|
-
log('Formatted content length:', formattedContent.length);
|
|
43
|
+
// Check if we have page content to inject
|
|
44
|
+
const hasPageContent = this.config.enabled && this.config.pageContentContext;
|
|
50
45
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
log('No content to inject after formatting');
|
|
46
|
+
if (!hasPageContent) {
|
|
47
|
+
log('No pageContentContext, skipping injection');
|
|
54
48
|
return this.markAsExecuted(clonedContext);
|
|
55
49
|
}
|
|
56
50
|
|
|
@@ -64,6 +58,16 @@ export class PageEditorContextInjector extends BaseLastUserContentProvider {
|
|
|
64
58
|
return this.markAsExecuted(clonedContext);
|
|
65
59
|
}
|
|
66
60
|
|
|
61
|
+
// Format page content
|
|
62
|
+
const formattedContent = formatPageContentContext(this.config.pageContentContext!);
|
|
63
|
+
|
|
64
|
+
if (!formattedContent) {
|
|
65
|
+
log('No content to inject after formatting');
|
|
66
|
+
return this.markAsExecuted(clonedContext);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
log('Page content formatted, length:', formattedContent.length);
|
|
70
|
+
|
|
67
71
|
// Check if system context wrapper already exists
|
|
68
72
|
// If yes, only insert context block; if no, use full wrapper
|
|
69
73
|
const hasExistingWrapper = this.hasExistingSystemContext(clonedContext);
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { formatPageSelections } from '@lobechat/prompts';
|
|
2
|
+
import type { PageSelection } from '@lobechat/types';
|
|
3
|
+
import debug from 'debug';
|
|
4
|
+
|
|
5
|
+
import { BaseEveryUserContentProvider } from '../base/BaseEveryUserContentProvider';
|
|
6
|
+
import type { Message, ProcessorOptions } from '../types';
|
|
7
|
+
|
|
8
|
+
const log = debug('context-engine:provider:PageSelectionsInjector');
|
|
9
|
+
|
|
10
|
+
export interface PageSelectionsInjectorConfig {
|
|
11
|
+
/** Whether Page Selections injection is enabled */
|
|
12
|
+
enabled?: boolean;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Page Selections Injector
|
|
17
|
+
* Responsible for injecting page selections into each user message that has them
|
|
18
|
+
* Unlike PageEditorContextInjector which only injects to the last user message,
|
|
19
|
+
* this processor handles selections attached to any user message in the conversation
|
|
20
|
+
*
|
|
21
|
+
* This injector runs BEFORE PageEditorContextInjector so that:
|
|
22
|
+
* - Each user message with selections gets a SYSTEM CONTEXT wrapper
|
|
23
|
+
* - PageEditorContextInjector can then reuse the wrapper for the last user message
|
|
24
|
+
*/
|
|
25
|
+
export class PageSelectionsInjector extends BaseEveryUserContentProvider {
|
|
26
|
+
readonly name = 'PageSelectionsInjector';
|
|
27
|
+
|
|
28
|
+
constructor(
|
|
29
|
+
private config: PageSelectionsInjectorConfig = {},
|
|
30
|
+
options: ProcessorOptions = {},
|
|
31
|
+
) {
|
|
32
|
+
super(options);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
protected buildContentForMessage(
|
|
36
|
+
message: Message,
|
|
37
|
+
index: number,
|
|
38
|
+
): { content: string; contextType: string } | null {
|
|
39
|
+
// Skip if not enabled
|
|
40
|
+
if (!this.config.enabled) {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Check if message has pageSelections in metadata
|
|
45
|
+
const pageSelections = message.metadata?.pageSelections as PageSelection[] | undefined;
|
|
46
|
+
|
|
47
|
+
if (!pageSelections || pageSelections.length === 0) {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Format the selections
|
|
52
|
+
const formattedSelections = formatPageSelections(pageSelections);
|
|
53
|
+
|
|
54
|
+
if (!formattedSelections) {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
log(`Building content for message at index ${index} with ${pageSelections.length} selections`);
|
|
59
|
+
|
|
60
|
+
return {
|
|
61
|
+
content: formattedSelections,
|
|
62
|
+
contextType: 'user_page_selections',
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
}
|