|
4 | 4 | using System.Collections.Generic;
|
5 | 5 | using System.Text.Json;
|
6 | 6 | using Microsoft.SemanticKernel;
|
| 7 | +using Microsoft.SemanticKernel.ChatCompletion; |
7 | 8 | using Microsoft.SemanticKernel.Connectors.OpenAI;
|
8 | 9 | using Xunit;
|
9 | 10 |
|
@@ -470,6 +471,365 @@ public void ItCannotCreateOpenAIPromptExecutionSettingsWithInvalidBoolValues(obj
|
470 | 471 | Assert.Throws<ArgumentException>(() => OpenAIPromptExecutionSettings.FromExecutionSettings(originalSettings));
|
471 | 472 | }
|
472 | 473 |
|
| 474 | + [Fact] |
| 475 | + public void PrepareChatHistoryToRequestAsyncAddsSystemPromptWhenNotPresent() |
| 476 | + { |
| 477 | + // Arrange |
| 478 | + var settings = new TestableOpenAIPromptExecutionSettings |
| 479 | + { |
| 480 | + ChatSystemPrompt = "You are a helpful assistant." |
| 481 | + }; |
| 482 | + |
| 483 | + var chatHistory = new ChatHistory(); |
| 484 | + chatHistory.AddUserMessage("Hello"); |
| 485 | + |
| 486 | + // Act |
| 487 | + var result = settings.TestPrepareChatHistoryToRequest(chatHistory); |
| 488 | + |
| 489 | + // Assert |
| 490 | + Assert.Same(chatHistory, result); // Should return the same instance |
| 491 | + Assert.Equal(2, chatHistory.Count); |
| 492 | + Assert.Equal(AuthorRole.System, chatHistory[0].Role); |
| 493 | + Assert.Equal("You are a helpful assistant.", chatHistory[0].Content); |
| 494 | + Assert.Equal(AuthorRole.User, chatHistory[1].Role); |
| 495 | + Assert.Equal("Hello", chatHistory[1].Content); |
| 496 | + } |
| 497 | + |
| 498 | + [Fact] |
| 499 | + public void PrepareChatHistoryToRequestAsyncAddsSystemPromptAtBeginning() |
| 500 | + { |
| 501 | + // Arrange |
| 502 | + var settings = new TestableOpenAIPromptExecutionSettings |
| 503 | + { |
| 504 | + ChatSystemPrompt = "You are a helpful assistant." |
| 505 | + }; |
| 506 | + |
| 507 | + var chatHistory = new ChatHistory(); |
| 508 | + chatHistory.AddUserMessage("First message"); |
| 509 | + chatHistory.AddAssistantMessage("First response"); |
| 510 | + chatHistory.AddUserMessage("Second message"); |
| 511 | + |
| 512 | + // Act |
| 513 | + var result = settings.TestPrepareChatHistoryToRequest(chatHistory); |
| 514 | + |
| 515 | + // Assert |
| 516 | + Assert.Same(chatHistory, result); |
| 517 | + Assert.Equal(4, chatHistory.Count); |
| 518 | + Assert.Equal(AuthorRole.System, chatHistory[0].Role); |
| 519 | + Assert.Equal("You are a helpful assistant.", chatHistory[0].Content); |
| 520 | + Assert.Equal(AuthorRole.User, chatHistory[1].Role); |
| 521 | + Assert.Equal("First message", chatHistory[1].Content); |
| 522 | + Assert.Equal(AuthorRole.Assistant, chatHistory[2].Role); |
| 523 | + Assert.Equal("First response", chatHistory[2].Content); |
| 524 | + Assert.Equal(AuthorRole.User, chatHistory[3].Role); |
| 525 | + Assert.Equal("Second message", chatHistory[3].Content); |
| 526 | + } |
| 527 | + |
| 528 | + [Fact] |
| 529 | + public void PrepareChatHistoryToRequestAsyncDoesNotAddSystemPromptWhenAlreadyPresent() |
| 530 | + { |
| 531 | + // Arrange |
| 532 | + var settings = new TestableOpenAIPromptExecutionSettings |
| 533 | + { |
| 534 | + ChatSystemPrompt = "You are a helpful assistant." |
| 535 | + }; |
| 536 | + |
| 537 | + var chatHistory = new ChatHistory(); |
| 538 | + chatHistory.AddSystemMessage("Existing system message"); |
| 539 | + chatHistory.AddUserMessage("Hello"); |
| 540 | + |
| 541 | + // Act |
| 542 | + var result = settings.TestPrepareChatHistoryToRequest(chatHistory); |
| 543 | + |
| 544 | + // Assert |
| 545 | + Assert.Same(chatHistory, result); |
| 546 | + Assert.Equal(2, chatHistory.Count); |
| 547 | + Assert.Equal(AuthorRole.System, chatHistory[0].Role); |
| 548 | + Assert.Equal("Existing system message", chatHistory[0].Content); // Original system message preserved |
| 549 | + Assert.Equal(AuthorRole.User, chatHistory[1].Role); |
| 550 | + Assert.Equal("Hello", chatHistory[1].Content); |
| 551 | + } |
| 552 | + |
| 553 | + [Fact] |
| 554 | + public void PrepareChatHistoryToRequestAsyncAddsDeveloperPromptWhenNotPresent() |
| 555 | + { |
| 556 | + // Arrange |
| 557 | + var settings = new TestableOpenAIPromptExecutionSettings |
| 558 | + { |
| 559 | + ChatDeveloperPrompt = "Debug mode enabled." |
| 560 | + }; |
| 561 | + |
| 562 | + var chatHistory = new ChatHistory(); |
| 563 | + chatHistory.AddUserMessage("Hello"); |
| 564 | + |
| 565 | + // Act |
| 566 | + var result = settings.TestPrepareChatHistoryToRequest(chatHistory); |
| 567 | + |
| 568 | + // Assert |
| 569 | + Assert.Same(chatHistory, result); |
| 570 | + Assert.Equal(2, chatHistory.Count); |
| 571 | + Assert.Equal(AuthorRole.Developer, chatHistory[0].Role); |
| 572 | + Assert.Equal("Debug mode enabled.", chatHistory[0].Content); |
| 573 | + Assert.Equal(AuthorRole.User, chatHistory[1].Role); |
| 574 | + Assert.Equal("Hello", chatHistory[1].Content); |
| 575 | + } |
| 576 | + |
| 577 | + [Fact] |
| 578 | + public void PrepareChatHistoryToRequestAsyncDoesNotAddDeveloperPromptWhenAlreadyPresent() |
| 579 | + { |
| 580 | + // Arrange |
| 581 | + var settings = new TestableOpenAIPromptExecutionSettings |
| 582 | + { |
| 583 | + ChatDeveloperPrompt = "Debug mode enabled." |
| 584 | + }; |
| 585 | + |
| 586 | + var chatHistory = new ChatHistory(); |
| 587 | + chatHistory.AddDeveloperMessage("Existing developer message"); |
| 588 | + chatHistory.AddUserMessage("Hello"); |
| 589 | + |
| 590 | + // Act |
| 591 | + var result = settings.TestPrepareChatHistoryToRequest(chatHistory); |
| 592 | + |
| 593 | + // Assert |
| 594 | + Assert.Same(chatHistory, result); |
| 595 | + Assert.Equal(2, chatHistory.Count); |
| 596 | + Assert.Equal(AuthorRole.Developer, chatHistory[0].Role); |
| 597 | + Assert.Equal("Existing developer message", chatHistory[0].Content); // Original developer message preserved |
| 598 | + Assert.Equal(AuthorRole.User, chatHistory[1].Role); |
| 599 | + Assert.Equal("Hello", chatHistory[1].Content); |
| 600 | + } |
| 601 | + |
| 602 | + [Fact] |
| 603 | + public void PrepareChatHistoryToRequestAsyncAddsBothSystemAndDeveloperPrompts() |
| 604 | + { |
| 605 | + // Arrange |
| 606 | + var settings = new TestableOpenAIPromptExecutionSettings |
| 607 | + { |
| 608 | + ChatSystemPrompt = "You are a helpful assistant.", |
| 609 | + ChatDeveloperPrompt = "Debug mode enabled." |
| 610 | + }; |
| 611 | + |
| 612 | + var chatHistory = new ChatHistory(); |
| 613 | + chatHistory.AddUserMessage("Hello"); |
| 614 | + |
| 615 | + // Act |
| 616 | + var result = settings.TestPrepareChatHistoryToRequest(chatHistory); |
| 617 | + |
| 618 | + // Assert |
| 619 | + Assert.Same(chatHistory, result); |
| 620 | + Assert.Equal(3, chatHistory.Count); |
| 621 | + Assert.Equal(AuthorRole.System, chatHistory[0].Role); |
| 622 | + Assert.Equal("You are a helpful assistant.", chatHistory[0].Content); |
| 623 | + Assert.Equal(AuthorRole.Developer, chatHistory[1].Role); |
| 624 | + Assert.Equal("Debug mode enabled.", chatHistory[1].Content); |
| 625 | + Assert.Equal(AuthorRole.User, chatHistory[2].Role); |
| 626 | + Assert.Equal("Hello", chatHistory[2].Content); |
| 627 | + } |
| 628 | + |
| 629 | + [Fact] |
| 630 | + public void PrepareChatHistoryToRequestAsyncDoesNotAddEmptyOrWhitespacePrompts() |
| 631 | + { |
| 632 | + // Arrange |
| 633 | + var settings = new TestableOpenAIPromptExecutionSettings |
| 634 | + { |
| 635 | + ChatSystemPrompt = " ", // Whitespace only |
| 636 | + ChatDeveloperPrompt = "" // Empty string |
| 637 | + }; |
| 638 | + |
| 639 | + var chatHistory = new ChatHistory(); |
| 640 | + chatHistory.AddUserMessage("Hello"); |
| 641 | + |
| 642 | + // Act |
| 643 | + var result = settings.TestPrepareChatHistoryToRequest(chatHistory); |
| 644 | + |
| 645 | + // Assert |
| 646 | + Assert.Same(chatHistory, result); |
| 647 | + Assert.Single(chatHistory); // Only the original user message should remain |
| 648 | + Assert.Equal(AuthorRole.User, chatHistory[0].Role); |
| 649 | + Assert.Equal("Hello", chatHistory[0].Content); |
| 650 | + } |
| 651 | + |
| 652 | + [Fact] |
| 653 | + public void PrepareChatHistoryToRequestAsyncDoesNotAddNullPrompts() |
| 654 | + { |
| 655 | + // Arrange |
| 656 | + var settings = new TestableOpenAIPromptExecutionSettings |
| 657 | + { |
| 658 | + ChatSystemPrompt = null, |
| 659 | + ChatDeveloperPrompt = null |
| 660 | + }; |
| 661 | + |
| 662 | + var chatHistory = new ChatHistory(); |
| 663 | + chatHistory.AddUserMessage("Hello"); |
| 664 | + |
| 665 | + // Act |
| 666 | + var result = settings.TestPrepareChatHistoryToRequest(chatHistory); |
| 667 | + |
| 668 | + // Assert |
| 669 | + Assert.Same(chatHistory, result); |
| 670 | + Assert.Single(chatHistory); // Only the original user message should remain |
| 671 | + Assert.Equal(AuthorRole.User, chatHistory[0].Role); |
| 672 | + Assert.Equal("Hello", chatHistory[0].Content); |
| 673 | + } |
| 674 | + |
| 675 | + [Fact] |
| 676 | + public void PrepareChatHistoryToRequestAsyncWorksWithEmptyChatHistory() |
| 677 | + { |
| 678 | + // Arrange |
| 679 | + var settings = new TestableOpenAIPromptExecutionSettings |
| 680 | + { |
| 681 | + ChatSystemPrompt = "You are a helpful assistant.", |
| 682 | + ChatDeveloperPrompt = "Debug mode enabled." |
| 683 | + }; |
| 684 | + |
| 685 | + var chatHistory = new ChatHistory(); |
| 686 | + |
| 687 | + // Act |
| 688 | + var result = settings.TestPrepareChatHistoryToRequest(chatHistory); |
| 689 | + |
| 690 | + // Assert |
| 691 | + Assert.Same(chatHistory, result); |
| 692 | + Assert.Equal(2, chatHistory.Count); |
| 693 | + Assert.Equal(AuthorRole.System, chatHistory[0].Role); |
| 694 | + Assert.Equal("You are a helpful assistant.", chatHistory[0].Content); |
| 695 | + Assert.Equal(AuthorRole.Developer, chatHistory[1].Role); |
| 696 | + Assert.Equal("Debug mode enabled.", chatHistory[1].Content); |
| 697 | + } |
| 698 | + |
| 699 | + [Fact] |
| 700 | + public void PrepareChatHistoryToRequestAsyncPreservesExistingMessageOrder() |
| 701 | + { |
| 702 | + // Arrange |
| 703 | + var settings = new TestableOpenAIPromptExecutionSettings |
| 704 | + { |
| 705 | + ChatSystemPrompt = "You are a helpful assistant." |
| 706 | + }; |
| 707 | + |
| 708 | + var chatHistory = new ChatHistory(); |
| 709 | + chatHistory.AddDeveloperMessage("Existing developer message"); |
| 710 | + chatHistory.AddUserMessage("First user message"); |
| 711 | + chatHistory.AddAssistantMessage("Assistant response"); |
| 712 | + chatHistory.AddUserMessage("Second user message"); |
| 713 | + |
| 714 | + // Act |
| 715 | + var result = settings.TestPrepareChatHistoryToRequest(chatHistory); |
| 716 | + |
| 717 | + // Assert |
| 718 | + Assert.Same(chatHistory, result); |
| 719 | + Assert.Equal(5, chatHistory.Count); |
| 720 | + |
| 721 | + // System message should be added at the beginning, before existing developer message |
| 722 | + Assert.Equal(AuthorRole.System, chatHistory[0].Role); |
| 723 | + Assert.Equal("You are a helpful assistant.", chatHistory[0].Content); |
| 724 | + Assert.Equal(AuthorRole.Developer, chatHistory[1].Role); |
| 725 | + Assert.Equal("Existing developer message", chatHistory[1].Content); |
| 726 | + Assert.Equal(AuthorRole.User, chatHistory[2].Role); |
| 727 | + Assert.Equal("First user message", chatHistory[2].Content); |
| 728 | + Assert.Equal(AuthorRole.Assistant, chatHistory[3].Role); |
| 729 | + Assert.Equal("Assistant response", chatHistory[3].Content); |
| 730 | + Assert.Equal(AuthorRole.User, chatHistory[4].Role); |
| 731 | + Assert.Equal("Second user message", chatHistory[4].Content); |
| 732 | + } |
| 733 | + |
| 734 | + [Fact] |
| 735 | + public void PrepareChatHistoryToRequestAsyncInsertsSystemBeforeDeveloperWhenBothExist() |
| 736 | + { |
| 737 | + // Arrange |
| 738 | + var settings = new TestableOpenAIPromptExecutionSettings |
| 739 | + { |
| 740 | + ChatSystemPrompt = "You are a helpful assistant.", |
| 741 | + ChatDeveloperPrompt = "Debug mode enabled." |
| 742 | + }; |
| 743 | + |
| 744 | + var chatHistory = new ChatHistory(); |
| 745 | + chatHistory.AddDeveloperMessage("Existing developer message"); |
| 746 | + chatHistory.AddSystemMessage("Existing system message"); |
| 747 | + chatHistory.AddUserMessage("Hello"); |
| 748 | + |
| 749 | + // Act |
| 750 | + var result = settings.TestPrepareChatHistoryToRequest(chatHistory); |
| 751 | + |
| 752 | + // Assert |
| 753 | + Assert.Same(chatHistory, result); |
| 754 | + Assert.Equal(3, chatHistory.Count); // No new messages should be added since both already exist |
| 755 | + Assert.Equal(AuthorRole.Developer, chatHistory[0].Role); |
| 756 | + Assert.Equal("Existing developer message", chatHistory[0].Content); |
| 757 | + Assert.Equal(AuthorRole.System, chatHistory[1].Role); |
| 758 | + Assert.Equal("Existing system message", chatHistory[1].Content); |
| 759 | + Assert.Equal(AuthorRole.User, chatHistory[2].Role); |
| 760 | + Assert.Equal("Hello", chatHistory[2].Content); |
| 761 | + } |
| 762 | + |
| 763 | + [Fact] |
| 764 | + public void PrepareChatHistoryToRequestAsyncAddsSystemBeforeExistingDeveloper() |
| 765 | + { |
| 766 | + // Arrange |
| 767 | + var settings = new TestableOpenAIPromptExecutionSettings |
| 768 | + { |
| 769 | + ChatSystemPrompt = "You are a helpful assistant.", |
| 770 | + ChatDeveloperPrompt = "Debug mode enabled." |
| 771 | + }; |
| 772 | + |
| 773 | + var chatHistory = new ChatHistory(); |
| 774 | + chatHistory.AddDeveloperMessage("Existing developer message"); |
| 775 | + chatHistory.AddUserMessage("Hello"); |
| 776 | + |
| 777 | + // Act |
| 778 | + var result = settings.TestPrepareChatHistoryToRequest(chatHistory); |
| 779 | + |
| 780 | + // Assert |
| 781 | + Assert.Same(chatHistory, result); |
| 782 | + Assert.Equal(3, chatHistory.Count); |
| 783 | + |
| 784 | + // System message should be inserted at the beginning, before existing developer message |
| 785 | + Assert.Equal(AuthorRole.System, chatHistory[0].Role); |
| 786 | + Assert.Equal("You are a helpful assistant.", chatHistory[0].Content); |
| 787 | + Assert.Equal(AuthorRole.Developer, chatHistory[1].Role); |
| 788 | + Assert.Equal("Existing developer message", chatHistory[1].Content); |
| 789 | + Assert.Equal(AuthorRole.User, chatHistory[2].Role); |
| 790 | + Assert.Equal("Hello", chatHistory[2].Content); |
| 791 | + } |
| 792 | + |
| 793 | + [Fact] |
| 794 | + public void PrepareChatHistoryToRequestAsyncAddsDeveloperWhenSystemExists() |
| 795 | + { |
| 796 | + // Arrange |
| 797 | + var settings = new TestableOpenAIPromptExecutionSettings |
| 798 | + { |
| 799 | + ChatDeveloperPrompt = "Debug mode enabled." |
| 800 | + }; |
| 801 | + |
| 802 | + var chatHistory = new ChatHistory(); |
| 803 | + chatHistory.AddSystemMessage("Existing system message"); |
| 804 | + chatHistory.AddUserMessage("Hello"); |
| 805 | + |
| 806 | + // Act |
| 807 | + var result = settings.TestPrepareChatHistoryToRequest(chatHistory); |
| 808 | + |
| 809 | + // Assert |
| 810 | + Assert.Same(chatHistory, result); |
| 811 | + Assert.Equal(3, chatHistory.Count); |
| 812 | + |
| 813 | + // Developer message should be inserted at the beginning, before existing system message |
| 814 | + Assert.Equal(AuthorRole.Developer, chatHistory[0].Role); |
| 815 | + Assert.Equal("Debug mode enabled.", chatHistory[0].Content); |
| 816 | + Assert.Equal(AuthorRole.System, chatHistory[1].Role); |
| 817 | + Assert.Equal("Existing system message", chatHistory[1].Content); |
| 818 | + Assert.Equal(AuthorRole.User, chatHistory[2].Role); |
| 819 | + Assert.Equal("Hello", chatHistory[2].Content); |
| 820 | + } |
| 821 | + |
| 822 | + /// <summary> |
| 823 | + /// Test implementation of OpenAIPromptExecutionSettings that exposes the protected PrepareChatHistoryToRequestAsync method. |
| 824 | + /// </summary> |
| 825 | + private sealed class TestableOpenAIPromptExecutionSettings : OpenAIPromptExecutionSettings |
| 826 | + { |
| 827 | + public ChatHistory TestPrepareChatHistoryToRequest(ChatHistory chatHistory) |
| 828 | + { |
| 829 | + return base.PrepareChatHistoryForRequest(chatHistory); |
| 830 | + } |
| 831 | + } |
| 832 | + |
473 | 833 | private static void AssertExecutionSettings(OpenAIPromptExecutionSettings executionSettings)
|
474 | 834 | {
|
475 | 835 | Assert.NotNull(executionSettings);
|
|
0 commit comments