You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

test_openai_assistant_agent.py 6.9 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. import os
  2. from enum import Enum
  3. from typing import List, Literal, Optional, Union
  4. import pytest
  5. from autogen_agentchat.messages import TextMessage
  6. from autogen_core import CancellationToken
  7. from autogen_core.tools._base import BaseTool, Tool
  8. from autogen_ext.agents.openai import OpenAIAssistantAgent
  9. from azure.identity import DefaultAzureCredential, get_bearer_token_provider
  10. from openai import AsyncAzureOpenAI
  11. from pydantic import BaseModel
  12. class QuestionType(str, Enum):
  13. MULTIPLE_CHOICE = "MULTIPLE_CHOICE"
  14. FREE_RESPONSE = "FREE_RESPONSE"
  15. class Question(BaseModel):
  16. question_text: str
  17. question_type: QuestionType
  18. choices: Optional[List[str]] = None
  19. class DisplayQuizArgs(BaseModel):
  20. title: str
  21. questions: List[Question]
  22. class QuizResponses(BaseModel):
  23. responses: List[str]
  24. class DisplayQuizTool(BaseTool[DisplayQuizArgs, QuizResponses]):
  25. def __init__(self) -> None:
  26. super().__init__(
  27. args_type=DisplayQuizArgs,
  28. return_type=QuizResponses,
  29. name="display_quiz",
  30. description=(
  31. "Displays a quiz to the student and returns the student's responses. "
  32. "A single quiz can have multiple questions."
  33. ),
  34. )
  35. async def run(self, args: DisplayQuizArgs, cancellation_token: CancellationToken) -> QuizResponses:
  36. responses: List[str] = []
  37. for q in args.questions:
  38. if q.question_type == QuestionType.MULTIPLE_CHOICE:
  39. response = q.choices[0] if q.choices else ""
  40. elif q.question_type == QuestionType.FREE_RESPONSE:
  41. response = "Sample free response"
  42. else:
  43. response = ""
  44. responses.append(response)
  45. return QuizResponses(responses=responses)
  46. @pytest.fixture
  47. def client() -> AsyncAzureOpenAI:
  48. azure_endpoint = os.getenv("AZURE_OPENAI_ENDPOINT")
  49. api_version = os.getenv("AZURE_OPENAI_API_VERSION", "2024-08-01-preview")
  50. api_key = os.getenv("AZURE_OPENAI_API_KEY")
  51. if not azure_endpoint:
  52. pytest.skip("Azure OpenAI endpoint not found in environment variables")
  53. # Try Azure CLI credentials if API key not provided
  54. if not api_key:
  55. try:
  56. token_provider = get_bearer_token_provider(
  57. DefaultAzureCredential(), "https://cognitiveservices.azure.com/.default"
  58. )
  59. return AsyncAzureOpenAI(
  60. azure_endpoint=azure_endpoint, api_version=api_version, azure_ad_token_provider=token_provider
  61. )
  62. except Exception:
  63. pytest.skip("Failed to get Azure CLI credentials and no API key provided")
  64. # Fall back to API key auth if provided
  65. return AsyncAzureOpenAI(azure_endpoint=azure_endpoint, api_version=api_version, api_key=api_key)
  66. @pytest.fixture
  67. def agent(client: AsyncAzureOpenAI) -> OpenAIAssistantAgent:
  68. tools: List[Union[Literal["code_interpreter", "file_search"], Tool]] = [
  69. "code_interpreter",
  70. "file_search",
  71. DisplayQuizTool(),
  72. ]
  73. return OpenAIAssistantAgent(
  74. name="assistant",
  75. instructions="Help the user with their task.",
  76. model="gpt-4o-mini",
  77. description="OpenAI Assistant Agent",
  78. client=client,
  79. tools=tools,
  80. )
  81. @pytest.fixture
  82. def cancellation_token() -> CancellationToken:
  83. return CancellationToken()
  84. @pytest.mark.asyncio
  85. async def test_file_retrieval(agent: OpenAIAssistantAgent, cancellation_token: CancellationToken) -> None:
  86. file_path = r"C:\Users\lpinheiro\Github\autogen-test\data\SampleBooks\jungle_book.txt"
  87. await agent.on_upload_for_file_search(file_path, cancellation_token)
  88. message = TextMessage(source="user", content="What is the first sentence of the jungle scout book?")
  89. response = await agent.on_messages([message], cancellation_token)
  90. assert response.chat_message.content is not None
  91. assert isinstance(response.chat_message.content, str)
  92. assert len(response.chat_message.content) > 0
  93. await agent.delete_uploaded_files(cancellation_token)
  94. await agent.delete_vector_store(cancellation_token)
  95. await agent.delete_assistant(cancellation_token)
  96. @pytest.mark.asyncio
  97. async def test_code_interpreter(agent: OpenAIAssistantAgent, cancellation_token: CancellationToken) -> None:
  98. message = TextMessage(source="user", content="I need to solve the equation `3x + 11 = 14`. Can you help me?")
  99. response = await agent.on_messages([message], cancellation_token)
  100. assert response.chat_message.content is not None
  101. assert isinstance(response.chat_message.content, str)
  102. assert len(response.chat_message.content) > 0
  103. assert "x = 1" in response.chat_message.content.lower()
  104. await agent.delete_assistant(cancellation_token)
  105. @pytest.mark.asyncio
  106. async def test_quiz_creation(agent: OpenAIAssistantAgent, cancellation_token: CancellationToken) -> None:
  107. message = TextMessage(
  108. source="user",
  109. content="Create a short quiz about basic math with one multiple choice question and one free response question.",
  110. )
  111. response = await agent.on_messages([message], cancellation_token)
  112. assert response.chat_message.content is not None
  113. assert isinstance(response.chat_message.content, str)
  114. assert len(response.chat_message.content) > 0
  115. assert isinstance(response.inner_messages, list)
  116. assert any(tool_msg.content for tool_msg in response.inner_messages if hasattr(tool_msg, "content"))
  117. await agent.delete_assistant(cancellation_token)
  118. @pytest.mark.asyncio
  119. async def test_on_reset_behavior(client: AsyncAzureOpenAI, cancellation_token: CancellationToken) -> None:
  120. # Create thread with initial message
  121. thread = await client.beta.threads.create()
  122. await client.beta.threads.messages.create(
  123. thread_id=thread.id,
  124. content="Hi, my name is John and I'm a software engineer. Use this information to help me.",
  125. role="user",
  126. )
  127. # Create agent with existing thread
  128. agent = OpenAIAssistantAgent(
  129. name="assistant",
  130. instructions="Help the user with their task.",
  131. model="gpt-4o-mini",
  132. description="OpenAI Assistant Agent",
  133. client=client,
  134. thread_id=thread.id,
  135. )
  136. # Test before reset
  137. message1 = TextMessage(source="user", content="What is my name?")
  138. response1 = await agent.on_messages([message1], cancellation_token)
  139. assert isinstance(response1.chat_message.content, str)
  140. assert "john" in response1.chat_message.content.lower()
  141. # Reset agent state
  142. await agent.on_reset(cancellation_token)
  143. # Test after reset
  144. message2 = TextMessage(source="user", content="What is my name?")
  145. response2 = await agent.on_messages([message2], cancellation_token)
  146. assert isinstance(response2.chat_message.content, str)
  147. assert "john" in response2.chat_message.content.lower()
  148. await agent.delete_assistant(cancellation_token)