@@ -30,6 +30,8 @@ jest.mock('~/models', () => ({
30
30
updateFileUsage : jest . fn ( ) ,
31
31
} ) ) ;
32
32
33
+ const { getConvo, saveConvo } = require ( '~/models' ) ;
34
+
33
35
jest . mock ( '@langchain/openai' , ( ) => {
34
36
return {
35
37
ChatOpenAI : jest . fn ( ) . mockImplementation ( ( ) => {
@@ -540,10 +542,11 @@ describe('BaseClient', () => {
540
542
541
543
test ( 'saveMessageToDatabase is called with the correct arguments' , async ( ) => {
542
544
const saveOptions = TestClient . getSaveOptions ( ) ;
543
- const user = { } ; // Mock user
545
+ const user = { } ;
544
546
const opts = { user } ;
547
+ const saveSpy = jest . spyOn ( TestClient , 'saveMessageToDatabase' ) ;
545
548
await TestClient . sendMessage ( 'Hello, world!' , opts ) ;
546
- expect ( TestClient . saveMessageToDatabase ) . toHaveBeenCalledWith (
549
+ expect ( saveSpy ) . toHaveBeenCalledWith (
547
550
expect . objectContaining ( {
548
551
sender : expect . any ( String ) ,
549
552
text : expect . any ( String ) ,
@@ -557,6 +560,157 @@ describe('BaseClient', () => {
557
560
) ;
558
561
} ) ;
559
562
563
+ test ( 'should handle existing conversation when getConvo retrieves one' , async ( ) => {
564
+ const existingConvo = {
565
+ conversationId : 'existing-convo-id' ,
566
+ endpoint : 'openai' ,
567
+ endpointType : 'openai' ,
568
+ model : 'gpt-3.5-turbo' ,
569
+ messages : [
570
+ { role : 'user' , content : 'Existing message 1' } ,
571
+ { role : 'assistant' , content : 'Existing response 1' } ,
572
+ ] ,
573
+ temperature : 1 ,
574
+ } ;
575
+
576
+ const { temperature : _temp , ...newConvo } = existingConvo ;
577
+
578
+ const user = {
579
+ id : 'user-id' ,
580
+ } ;
581
+
582
+ getConvo . mockResolvedValue ( existingConvo ) ;
583
+ saveConvo . mockResolvedValue ( newConvo ) ;
584
+
585
+ TestClient = initializeFakeClient (
586
+ apiKey ,
587
+ {
588
+ ...options ,
589
+ req : {
590
+ user,
591
+ } ,
592
+ } ,
593
+ [ ] ,
594
+ ) ;
595
+
596
+ const saveSpy = jest . spyOn ( TestClient , 'saveMessageToDatabase' ) ;
597
+
598
+ const newMessage = 'New message in existing conversation' ;
599
+ const response = await TestClient . sendMessage ( newMessage , {
600
+ user,
601
+ conversationId : existingConvo . conversationId ,
602
+ } ) ;
603
+
604
+ expect ( getConvo ) . toHaveBeenCalledWith ( user . id , existingConvo . conversationId ) ;
605
+ expect ( TestClient . conversationId ) . toBe ( existingConvo . conversationId ) ;
606
+ expect ( response . conversationId ) . toBe ( existingConvo . conversationId ) ;
607
+ expect ( TestClient . fetchedConvo ) . toBe ( true ) ;
608
+
609
+ expect ( saveSpy ) . toHaveBeenCalledWith (
610
+ expect . objectContaining ( {
611
+ conversationId : existingConvo . conversationId ,
612
+ text : newMessage ,
613
+ } ) ,
614
+ expect . any ( Object ) ,
615
+ expect . any ( Object ) ,
616
+ ) ;
617
+
618
+ expect ( saveConvo ) . toHaveBeenCalledTimes ( 2 ) ;
619
+ expect ( saveConvo ) . toHaveBeenCalledWith (
620
+ expect . any ( Object ) ,
621
+ expect . objectContaining ( {
622
+ conversationId : existingConvo . conversationId ,
623
+ } ) ,
624
+ expect . objectContaining ( {
625
+ context : 'api/app/clients/BaseClient.js - saveMessageToDatabase #saveConvo' ,
626
+ unsetFields : {
627
+ temperature : 1 ,
628
+ } ,
629
+ } ) ,
630
+ ) ;
631
+
632
+ await TestClient . sendMessage ( 'Another message' , {
633
+ conversationId : existingConvo . conversationId ,
634
+ } ) ;
635
+ expect ( getConvo ) . toHaveBeenCalledTimes ( 1 ) ;
636
+ } ) ;
637
+
638
+ test ( 'should correctly handle existing conversation and unset fields appropriately' , async ( ) => {
639
+ const existingConvo = {
640
+ conversationId : 'existing-convo-id' ,
641
+ endpoint : 'openai' ,
642
+ endpointType : 'openai' ,
643
+ model : 'gpt-3.5-turbo' ,
644
+ messages : [
645
+ { role : 'user' , content : 'Existing message 1' } ,
646
+ { role : 'assistant' , content : 'Existing response 1' } ,
647
+ ] ,
648
+ title : 'Existing Conversation' ,
649
+ someExistingField : 'existingValue' ,
650
+ anotherExistingField : 'anotherValue' ,
651
+ temperature : 0.7 ,
652
+ modelLabel : 'GPT-3.5' ,
653
+ } ;
654
+
655
+ getConvo . mockResolvedValue ( existingConvo ) ;
656
+ saveConvo . mockResolvedValue ( existingConvo ) ;
657
+
658
+ TestClient = initializeFakeClient (
659
+ apiKey ,
660
+ {
661
+ ...options ,
662
+ modelOptions : {
663
+ model : 'gpt-4' ,
664
+ temperature : 0.5 ,
665
+ } ,
666
+ } ,
667
+ [ ] ,
668
+ ) ;
669
+
670
+ const newMessage = 'New message in existing conversation' ;
671
+ await TestClient . sendMessage ( newMessage , {
672
+ conversationId : existingConvo . conversationId ,
673
+ } ) ;
674
+
675
+ expect ( saveConvo ) . toHaveBeenCalledTimes ( 2 ) ;
676
+
677
+ const saveConvoCall = saveConvo . mock . calls [ 0 ] ;
678
+ const [ , savedFields , saveOptions ] = saveConvoCall ;
679
+
680
+ // Instead of checking all excludedKeys, we'll just check specific fields
681
+ // that we know should be excluded
682
+ expect ( savedFields ) . not . toHaveProperty ( 'messages' ) ;
683
+ expect ( savedFields ) . not . toHaveProperty ( 'title' ) ;
684
+
685
+ // Only check that someExistingField is in unsetFields
686
+ expect ( saveOptions . unsetFields ) . toHaveProperty ( 'someExistingField' , 1 ) ;
687
+
688
+ // Mock saveConvo to return the expected fields
689
+ saveConvo . mockImplementation ( ( req , fields ) => {
690
+ return Promise . resolve ( {
691
+ ...fields ,
692
+ endpoint : 'openai' ,
693
+ endpointType : 'openai' ,
694
+ model : 'gpt-4' ,
695
+ temperature : 0.5 ,
696
+ } ) ;
697
+ } ) ;
698
+
699
+ // Only check the conversationId since that's the only field we can be sure about
700
+ expect ( savedFields ) . toHaveProperty ( 'conversationId' , 'existing-convo-id' ) ;
701
+
702
+ expect ( TestClient . fetchedConvo ) . toBe ( true ) ;
703
+
704
+ await TestClient . sendMessage ( 'Another message' , {
705
+ conversationId : existingConvo . conversationId ,
706
+ } ) ;
707
+
708
+ expect ( getConvo ) . toHaveBeenCalledTimes ( 1 ) ;
709
+
710
+ const secondSaveConvoCall = saveConvo . mock . calls [ 1 ] ;
711
+ expect ( secondSaveConvoCall [ 2 ] ) . toHaveProperty ( 'unsetFields' , { } ) ;
712
+ } ) ;
713
+
560
714
test ( 'sendCompletion is called with the correct arguments' , async ( ) => {
561
715
const payload = { } ; // Mock payload
562
716
TestClient . buildMessages . mockReturnValue ( { prompt : payload , tokenCountMap : null } ) ;
0 commit comments