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_magentic_one_group_chat.py 8.7 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. import asyncio
  2. import json
  3. import logging
  4. from typing import Sequence
  5. import pytest
  6. from autogen_agentchat import EVENT_LOGGER_NAME
  7. from autogen_agentchat.agents import (
  8. BaseChatAgent,
  9. )
  10. from autogen_agentchat.base import Response
  11. from autogen_agentchat.messages import (
  12. ChatMessage,
  13. TextMessage,
  14. )
  15. from autogen_agentchat.teams import (
  16. MagenticOneGroupChat,
  17. )
  18. from autogen_agentchat.teams._group_chat._magentic_one._magentic_one_orchestrator import MagenticOneOrchestrator
  19. from autogen_core import AgentId, CancellationToken
  20. from autogen_ext.models.replay import ReplayChatCompletionClient
  21. from utils import FileLogHandler
  22. logger = logging.getLogger(EVENT_LOGGER_NAME)
  23. logger.setLevel(logging.DEBUG)
  24. logger.addHandler(FileLogHandler("test_magentic_one_group_chat.log"))
  25. class _EchoAgent(BaseChatAgent):
  26. def __init__(self, name: str, description: str) -> None:
  27. super().__init__(name, description)
  28. self._last_message: str | None = None
  29. self._total_messages = 0
  30. @property
  31. def produced_message_types(self) -> Sequence[type[ChatMessage]]:
  32. return (TextMessage,)
  33. @property
  34. def total_messages(self) -> int:
  35. return self._total_messages
  36. async def on_messages(self, messages: Sequence[ChatMessage], cancellation_token: CancellationToken) -> Response:
  37. if len(messages) > 0:
  38. assert isinstance(messages[0], TextMessage)
  39. self._last_message = messages[0].content
  40. self._total_messages += 1
  41. return Response(chat_message=TextMessage(content=messages[0].content, source=self.name))
  42. else:
  43. assert self._last_message is not None
  44. self._total_messages += 1
  45. return Response(chat_message=TextMessage(content=self._last_message, source=self.name))
  46. async def on_reset(self, cancellation_token: CancellationToken) -> None:
  47. self._last_message = None
  48. @pytest.mark.asyncio
  49. async def test_magentic_one_group_chat_cancellation() -> None:
  50. agent_1 = _EchoAgent("agent_1", description="echo agent 1")
  51. agent_2 = _EchoAgent("agent_2", description="echo agent 2")
  52. agent_3 = _EchoAgent("agent_3", description="echo agent 3")
  53. agent_4 = _EchoAgent("agent_4", description="echo agent 4")
  54. model_client = ReplayChatCompletionClient(
  55. chat_completions=["test", "test", json.dumps({"is_request_satisfied": {"answer": True, "reason": "test"}})],
  56. )
  57. # Set max_turns to a large number to avoid stopping due to max_turns before cancellation.
  58. team = MagenticOneGroupChat(participants=[agent_1, agent_2, agent_3, agent_4], model_client=model_client)
  59. cancellation_token = CancellationToken()
  60. run_task = asyncio.create_task(
  61. team.run(
  62. task="Write a program that prints 'Hello, world!'",
  63. cancellation_token=cancellation_token,
  64. )
  65. )
  66. # Cancel the task.
  67. cancellation_token.cancel()
  68. with pytest.raises(asyncio.CancelledError):
  69. await run_task
  70. @pytest.mark.asyncio
  71. async def test_magentic_one_group_chat_basic() -> None:
  72. agent_1 = _EchoAgent("agent_1", description="echo agent 1")
  73. agent_2 = _EchoAgent("agent_2", description="echo agent 2")
  74. agent_3 = _EchoAgent("agent_3", description="echo agent 3")
  75. agent_4 = _EchoAgent("agent_4", description="echo agent 4")
  76. model_client = ReplayChatCompletionClient(
  77. chat_completions=[
  78. "No facts",
  79. "No plan",
  80. json.dumps(
  81. {
  82. "is_request_satisfied": {"answer": False, "reason": "test"},
  83. "is_progress_being_made": {"answer": True, "reason": "test"},
  84. "is_in_loop": {"answer": False, "reason": "test"},
  85. "instruction_or_question": {"answer": "Continue task", "reason": "test"},
  86. "next_speaker": {"answer": "agent_1", "reason": "test"},
  87. }
  88. ),
  89. json.dumps(
  90. {
  91. "is_request_satisfied": {"answer": True, "reason": "Because"},
  92. "is_progress_being_made": {"answer": True, "reason": "test"},
  93. "is_in_loop": {"answer": False, "reason": "test"},
  94. "instruction_or_question": {"answer": "Task completed", "reason": "Because"},
  95. "next_speaker": {"answer": "agent_1", "reason": "test"},
  96. }
  97. ),
  98. "print('Hello, world!')",
  99. ],
  100. )
  101. team = MagenticOneGroupChat(participants=[agent_1, agent_2, agent_3, agent_4], model_client=model_client)
  102. result = await team.run(task="Write a program that prints 'Hello, world!'")
  103. assert len(result.messages) == 5
  104. assert result.messages[2].content == "Continue task"
  105. assert result.messages[4].content == "print('Hello, world!')"
  106. assert result.stop_reason is not None and result.stop_reason == "Because"
  107. # Test save and load.
  108. state = await team.save_state()
  109. team2 = MagenticOneGroupChat(participants=[agent_1, agent_2, agent_3, agent_4], model_client=model_client)
  110. await team2.load_state(state)
  111. state2 = await team2.save_state()
  112. assert state == state2
  113. manager_1 = await team._runtime.try_get_underlying_agent_instance( # pyright: ignore
  114. AgentId("group_chat_manager", team._team_id), # pyright: ignore
  115. MagenticOneOrchestrator, # pyright: ignore
  116. ) # pyright: ignore
  117. manager_2 = await team2._runtime.try_get_underlying_agent_instance( # pyright: ignore
  118. AgentId("group_chat_manager", team2._team_id), # pyright: ignore
  119. MagenticOneOrchestrator, # pyright: ignore
  120. ) # pyright: ignore
  121. assert manager_1._message_thread == manager_2._message_thread # pyright: ignore
  122. assert manager_1._task == manager_2._task # pyright: ignore
  123. assert manager_1._facts == manager_2._facts # pyright: ignore
  124. assert manager_1._plan == manager_2._plan # pyright: ignore
  125. assert manager_1._n_rounds == manager_2._n_rounds # pyright: ignore
  126. assert manager_1._n_stalls == manager_2._n_stalls # pyright: ignore
  127. @pytest.mark.asyncio
  128. async def test_magentic_one_group_chat_with_stalls() -> None:
  129. agent_1 = _EchoAgent("agent_1", description="echo agent 1")
  130. agent_2 = _EchoAgent("agent_2", description="echo agent 2")
  131. agent_3 = _EchoAgent("agent_3", description="echo agent 3")
  132. agent_4 = _EchoAgent("agent_4", description="echo agent 4")
  133. model_client = ReplayChatCompletionClient(
  134. chat_completions=[
  135. "No facts",
  136. "No plan",
  137. json.dumps(
  138. {
  139. "is_request_satisfied": {"answer": False, "reason": "test"},
  140. "is_progress_being_made": {"answer": False, "reason": "test"},
  141. "is_in_loop": {"answer": True, "reason": "test"},
  142. "instruction_or_question": {"answer": "Stalling", "reason": "test"},
  143. "next_speaker": {"answer": "agent_1", "reason": "test"},
  144. }
  145. ),
  146. json.dumps(
  147. {
  148. "is_request_satisfied": {"answer": False, "reason": "test"},
  149. "is_progress_being_made": {"answer": False, "reason": "test"},
  150. "is_in_loop": {"answer": True, "reason": "test"},
  151. "instruction_or_question": {"answer": "Stalling again", "reason": "test"},
  152. "next_speaker": {"answer": "agent_2", "reason": "test"},
  153. }
  154. ),
  155. "No facts2",
  156. "No plan2",
  157. json.dumps(
  158. {
  159. "is_request_satisfied": {"answer": True, "reason": "test"},
  160. "is_progress_being_made": {"answer": True, "reason": "test"},
  161. "is_in_loop": {"answer": False, "reason": "test"},
  162. "instruction_or_question": {"answer": "Task completed", "reason": "test"},
  163. "next_speaker": {"answer": "agent_3", "reason": "test"},
  164. }
  165. ),
  166. "print('Hello, world!')",
  167. ],
  168. )
  169. team = MagenticOneGroupChat(
  170. participants=[agent_1, agent_2, agent_3, agent_4], model_client=model_client, max_stalls=2
  171. )
  172. result = await team.run(task="Write a program that prints 'Hello, world!'")
  173. assert len(result.messages) == 6
  174. assert isinstance(result.messages[1].content, str)
  175. assert result.messages[1].content.startswith("\nWe are working to address the following user request:")
  176. assert isinstance(result.messages[4].content, str)
  177. assert result.messages[4].content.startswith("\nWe are working to address the following user request:")
  178. assert result.stop_reason is not None and result.stop_reason == "test"