|
14 | 14 | from azure.ai.projects.models import ( |
15 | 15 | ResponseTextFormatConfigurationJsonSchema, |
16 | 16 | ) |
| 17 | +from openai.types.responses.parsed_response import ParsedResponse |
| 18 | +from openai.types.responses.response import Response as OpenAIResponse |
17 | 19 | from pydantic import BaseModel, ConfigDict, ValidationError |
18 | 20 |
|
19 | 21 | from agent_framework_azure_ai import AzureAIClient, AzureAISettings |
@@ -537,6 +539,192 @@ async def test_azure_ai_client_prepare_options_excludes_response_format( |
537 | 539 | assert run_options["extra_body"]["agent"]["name"] == "test-agent" |
538 | 540 |
|
539 | 541 |
|
| 542 | +async def test_azure_ai_client_prepare_options_with_resp_conversation_id( |
| 543 | + mock_project_client: MagicMock, |
| 544 | +) -> None: |
| 545 | + """Test prepare_options with conversation ID starting with 'resp_'.""" |
| 546 | + client = create_test_azure_ai_client(mock_project_client, agent_name="test-agent", agent_version="1.0") |
| 547 | + |
| 548 | + messages = [ChatMessage(role=Role.USER, contents=[TextContent(text="Hello")])] |
| 549 | + chat_options = ChatOptions(conversation_id="resp_12345") |
| 550 | + |
| 551 | + with ( |
| 552 | + patch.object( |
| 553 | + client.__class__.__bases__[0], |
| 554 | + "prepare_options", |
| 555 | + return_value={"model": "test-model", "previous_response_id": "old_value", "conversation": "old_conv"}, |
| 556 | + ), |
| 557 | + patch.object( |
| 558 | + client, |
| 559 | + "_get_agent_reference_or_create", |
| 560 | + return_value={"name": "test-agent", "version": "1.0", "type": "agent_reference"}, |
| 561 | + ), |
| 562 | + ): |
| 563 | + run_options = await client.prepare_options(messages, chat_options) |
| 564 | + |
| 565 | + # Should set previous_response_id and remove conversation property |
| 566 | + assert run_options["previous_response_id"] == "resp_12345" |
| 567 | + assert "conversation" not in run_options |
| 568 | + |
| 569 | + |
| 570 | +async def test_azure_ai_client_prepare_options_with_conv_conversation_id( |
| 571 | + mock_project_client: MagicMock, |
| 572 | +) -> None: |
| 573 | + """Test prepare_options with conversation ID starting with 'conv_'.""" |
| 574 | + client = create_test_azure_ai_client(mock_project_client, agent_name="test-agent", agent_version="1.0") |
| 575 | + |
| 576 | + messages = [ChatMessage(role=Role.USER, contents=[TextContent(text="Hello")])] |
| 577 | + chat_options = ChatOptions(conversation_id="conv_67890") |
| 578 | + |
| 579 | + with ( |
| 580 | + patch.object( |
| 581 | + client.__class__.__bases__[0], |
| 582 | + "prepare_options", |
| 583 | + return_value={"model": "test-model", "previous_response_id": "old_value", "conversation": "old_conv"}, |
| 584 | + ), |
| 585 | + patch.object( |
| 586 | + client, |
| 587 | + "_get_agent_reference_or_create", |
| 588 | + return_value={"name": "test-agent", "version": "1.0", "type": "agent_reference"}, |
| 589 | + ), |
| 590 | + ): |
| 591 | + run_options = await client.prepare_options(messages, chat_options) |
| 592 | + |
| 593 | + # Should set conversation and remove previous_response_id property |
| 594 | + assert run_options["conversation"] == "conv_67890" |
| 595 | + assert "previous_response_id" not in run_options |
| 596 | + |
| 597 | + |
| 598 | +async def test_azure_ai_client_prepare_options_with_client_conversation_id( |
| 599 | + mock_project_client: MagicMock, |
| 600 | +) -> None: |
| 601 | + """Test prepare_options using client's default conversation ID when chat options don't have one.""" |
| 602 | + client = create_test_azure_ai_client( |
| 603 | + mock_project_client, agent_name="test-agent", agent_version="1.0", conversation_id="resp_client_default" |
| 604 | + ) |
| 605 | + |
| 606 | + messages = [ChatMessage(role=Role.USER, contents=[TextContent(text="Hello")])] |
| 607 | + chat_options = ChatOptions() # No conversation_id specified |
| 608 | + |
| 609 | + with ( |
| 610 | + patch.object( |
| 611 | + client.__class__.__bases__[0], |
| 612 | + "prepare_options", |
| 613 | + return_value={"model": "test-model", "previous_response_id": "old_value", "conversation": "old_conv"}, |
| 614 | + ), |
| 615 | + patch.object( |
| 616 | + client, |
| 617 | + "_get_agent_reference_or_create", |
| 618 | + return_value={"name": "test-agent", "version": "1.0", "type": "agent_reference"}, |
| 619 | + ), |
| 620 | + ): |
| 621 | + run_options = await client.prepare_options(messages, chat_options) |
| 622 | + |
| 623 | + # Should use client's default conversation_id and set previous_response_id |
| 624 | + assert run_options["previous_response_id"] == "resp_client_default" |
| 625 | + assert "conversation" not in run_options |
| 626 | + |
| 627 | + |
| 628 | +def test_get_conversation_id_with_store_true_and_conversation_id() -> None: |
| 629 | + """Test get_conversation_id returns conversation ID when store is True and conversation exists.""" |
| 630 | + client = create_test_azure_ai_client(MagicMock()) |
| 631 | + |
| 632 | + # Mock OpenAI response with conversation |
| 633 | + mock_response = MagicMock(spec=OpenAIResponse) |
| 634 | + mock_response.id = "resp_12345" |
| 635 | + mock_conversation = MagicMock() |
| 636 | + mock_conversation.id = "conv_67890" |
| 637 | + mock_response.conversation = mock_conversation |
| 638 | + |
| 639 | + result = client.get_conversation_id(mock_response, store=True) |
| 640 | + |
| 641 | + assert result == "conv_67890" |
| 642 | + |
| 643 | + |
| 644 | +def test_get_conversation_id_with_store_true_and_no_conversation() -> None: |
| 645 | + """Test get_conversation_id returns response ID when store is True and no conversation exists.""" |
| 646 | + client = create_test_azure_ai_client(MagicMock()) |
| 647 | + |
| 648 | + # Mock OpenAI response without conversation |
| 649 | + mock_response = MagicMock(spec=OpenAIResponse) |
| 650 | + mock_response.id = "resp_12345" |
| 651 | + mock_response.conversation = None |
| 652 | + |
| 653 | + result = client.get_conversation_id(mock_response, store=True) |
| 654 | + |
| 655 | + assert result == "resp_12345" |
| 656 | + |
| 657 | + |
| 658 | +def test_get_conversation_id_with_store_true_and_empty_conversation_id() -> None: |
| 659 | + """Test get_conversation_id returns response ID when store is True and conversation ID is empty.""" |
| 660 | + client = create_test_azure_ai_client(MagicMock()) |
| 661 | + |
| 662 | + # Mock OpenAI response with conversation but empty ID |
| 663 | + mock_response = MagicMock(spec=OpenAIResponse) |
| 664 | + mock_response.id = "resp_12345" |
| 665 | + mock_conversation = MagicMock() |
| 666 | + mock_conversation.id = "" |
| 667 | + mock_response.conversation = mock_conversation |
| 668 | + |
| 669 | + result = client.get_conversation_id(mock_response, store=True) |
| 670 | + |
| 671 | + assert result == "resp_12345" |
| 672 | + |
| 673 | + |
| 674 | +def test_get_conversation_id_with_store_false() -> None: |
| 675 | + """Test get_conversation_id returns None when store is False.""" |
| 676 | + client = create_test_azure_ai_client(MagicMock()) |
| 677 | + |
| 678 | + # Mock OpenAI response with conversation |
| 679 | + mock_response = MagicMock(spec=OpenAIResponse) |
| 680 | + mock_response.id = "resp_12345" |
| 681 | + mock_conversation = MagicMock() |
| 682 | + mock_conversation.id = "conv_67890" |
| 683 | + mock_response.conversation = mock_conversation |
| 684 | + |
| 685 | + result = client.get_conversation_id(mock_response, store=False) |
| 686 | + |
| 687 | + assert result is None |
| 688 | + |
| 689 | + |
| 690 | +def test_get_conversation_id_with_parsed_response_and_store_true() -> None: |
| 691 | + """Test get_conversation_id works with ParsedResponse when store is True.""" |
| 692 | + client = create_test_azure_ai_client(MagicMock()) |
| 693 | + |
| 694 | + # Create a simple BaseModel for testing |
| 695 | + class TestModel(BaseModel): |
| 696 | + content: str = "test" |
| 697 | + |
| 698 | + # Mock ParsedResponse with conversation |
| 699 | + mock_response = MagicMock(spec=ParsedResponse[BaseModel]) |
| 700 | + mock_response.id = "resp_parsed_12345" |
| 701 | + mock_conversation = MagicMock() |
| 702 | + mock_conversation.id = "conv_parsed_67890" |
| 703 | + mock_response.conversation = mock_conversation |
| 704 | + |
| 705 | + result = client.get_conversation_id(mock_response, store=True) |
| 706 | + |
| 707 | + assert result == "conv_parsed_67890" |
| 708 | + |
| 709 | + |
| 710 | +def test_get_conversation_id_with_parsed_response_no_conversation() -> None: |
| 711 | + """Test get_conversation_id returns response ID with ParsedResponse when no conversation exists.""" |
| 712 | + client = create_test_azure_ai_client(MagicMock()) |
| 713 | + |
| 714 | + # Create a simple BaseModel for testing |
| 715 | + class TestModel(BaseModel): |
| 716 | + content: str = "test" |
| 717 | + |
| 718 | + # Mock ParsedResponse without conversation |
| 719 | + mock_response = MagicMock(spec=ParsedResponse[BaseModel]) |
| 720 | + mock_response.id = "resp_parsed_12345" |
| 721 | + mock_response.conversation = None |
| 722 | + |
| 723 | + result = client.get_conversation_id(mock_response, store=True) |
| 724 | + |
| 725 | + assert result == "resp_parsed_12345" |
| 726 | + |
| 727 | + |
540 | 728 | @pytest.fixture |
541 | 729 | def mock_project_client() -> MagicMock: |
542 | 730 | """Fixture that provides a mock AIProjectClient.""" |
|
0 commit comments