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_runtime.py 9.5 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. import asyncio
  2. import pytest
  3. from autogen_core.application import SingleThreadedAgentRuntime
  4. from autogen_core.components import TypeSubscription, DefaultTopicId, DefaultSubscription
  5. from autogen_core.base import AgentId, AgentInstantiationContext
  6. from autogen_core.base import TopicId
  7. from autogen_core.base import Subscription
  8. from autogen_core.base import SubscriptionInstantiationContext
  9. from test_utils import CascadingAgent, CascadingMessageType, LoopbackAgent, MessageType, NoopAgent
  10. @pytest.mark.asyncio
  11. async def test_agent_names_must_be_unique() -> None:
  12. runtime = SingleThreadedAgentRuntime()
  13. def agent_factory() -> NoopAgent:
  14. id = AgentInstantiationContext.current_agent_id()
  15. assert id == AgentId("name1", "default")
  16. agent = NoopAgent()
  17. assert agent.id == id
  18. return agent
  19. await runtime.register("name1", agent_factory)
  20. with pytest.raises(ValueError):
  21. await runtime.register("name1", NoopAgent)
  22. await runtime.register("name3", NoopAgent)
  23. @pytest.mark.asyncio
  24. async def test_register_receives_publish() -> None:
  25. runtime = SingleThreadedAgentRuntime()
  26. await runtime.register("name", LoopbackAgent)
  27. runtime.start()
  28. await runtime.add_subscription(TypeSubscription("default", "name"))
  29. agent_id = AgentId("name", key="default")
  30. topic_id = TopicId("default", "default")
  31. await runtime.publish_message(MessageType(), topic_id=topic_id)
  32. await runtime.stop_when_idle()
  33. # Agent in default namespace should have received the message
  34. long_running_agent = await runtime.try_get_underlying_agent_instance(agent_id, type=LoopbackAgent)
  35. assert long_running_agent.num_calls == 1
  36. # Agent in other namespace should not have received the message
  37. other_long_running_agent: LoopbackAgent = await runtime.try_get_underlying_agent_instance(AgentId("name", key="other"), type=LoopbackAgent)
  38. assert other_long_running_agent.num_calls == 0
  39. @pytest.mark.asyncio
  40. async def test_register_receives_publish_cascade() -> None:
  41. runtime = SingleThreadedAgentRuntime()
  42. num_agents = 5
  43. num_initial_messages = 5
  44. max_rounds = 5
  45. total_num_calls_expected = 0
  46. for i in range(0, max_rounds):
  47. total_num_calls_expected += num_initial_messages * ((num_agents - 1) ** i)
  48. # Register agents
  49. for i in range(num_agents):
  50. await runtime.register(f"name{i}", lambda: CascadingAgent(max_rounds))
  51. await runtime.add_subscription(TypeSubscription("default", f"name{i}"))
  52. runtime.start()
  53. # Publish messages
  54. topic_id = TopicId("default", "default")
  55. for _ in range(num_initial_messages):
  56. await runtime.publish_message(CascadingMessageType(round=1), topic_id)
  57. # Process until idle.
  58. await runtime.stop_when_idle()
  59. # Check that each agent received the correct number of messages.
  60. for i in range(num_agents):
  61. agent = await runtime.try_get_underlying_agent_instance(AgentId(f"name{i}", "default"), CascadingAgent)
  62. assert agent.num_calls == total_num_calls_expected
  63. @pytest.mark.asyncio
  64. async def test_register_factory_explicit_name() -> None:
  65. runtime = SingleThreadedAgentRuntime()
  66. await runtime.register("name", LoopbackAgent, lambda: [TypeSubscription("default", "name")])
  67. runtime.start()
  68. agent_id = AgentId("name", key="default")
  69. topic_id = TopicId("default", "default")
  70. await runtime.publish_message(MessageType(), topic_id=topic_id)
  71. await runtime.stop_when_idle()
  72. # Agent in default namespace should have received the message
  73. long_running_agent = await runtime.try_get_underlying_agent_instance(agent_id, type=LoopbackAgent)
  74. assert long_running_agent.num_calls == 1
  75. # Agent in other namespace should not have received the message
  76. other_long_running_agent: LoopbackAgent = await runtime.try_get_underlying_agent_instance(AgentId("name", key="other"), type=LoopbackAgent)
  77. assert other_long_running_agent.num_calls == 0
  78. @pytest.mark.asyncio
  79. async def test_register_factory_context_var_name() -> None:
  80. runtime = SingleThreadedAgentRuntime()
  81. await runtime.register("name", LoopbackAgent, lambda: [TypeSubscription("default", SubscriptionInstantiationContext.agent_type().type)])
  82. runtime.start()
  83. agent_id = AgentId("name", key="default")
  84. topic_id = TopicId("default", "default")
  85. await runtime.publish_message(MessageType(), topic_id=topic_id)
  86. await runtime.stop_when_idle()
  87. # Agent in default namespace should have received the message
  88. long_running_agent = await runtime.try_get_underlying_agent_instance(agent_id, type=LoopbackAgent)
  89. assert long_running_agent.num_calls == 1
  90. # Agent in other namespace should not have received the message
  91. other_long_running_agent: LoopbackAgent = await runtime.try_get_underlying_agent_instance(AgentId("name", key="other"), type=LoopbackAgent)
  92. assert other_long_running_agent.num_calls == 0
  93. @pytest.mark.asyncio
  94. async def test_register_factory_async() -> None:
  95. runtime = SingleThreadedAgentRuntime()
  96. async def sub_factory() -> list[Subscription]:
  97. await asyncio.sleep(0.1)
  98. return [TypeSubscription("default", SubscriptionInstantiationContext.agent_type().type)]
  99. await runtime.register("name", LoopbackAgent, sub_factory)
  100. runtime.start()
  101. agent_id = AgentId("name", key="default")
  102. topic_id = TopicId("default", "default")
  103. await runtime.publish_message(MessageType(), topic_id=topic_id)
  104. await runtime.stop_when_idle()
  105. # Agent in default namespace should have received the message
  106. long_running_agent = await runtime.try_get_underlying_agent_instance(agent_id, type=LoopbackAgent)
  107. assert long_running_agent.num_calls == 1
  108. # Agent in other namespace should not have received the message
  109. other_long_running_agent: LoopbackAgent = await runtime.try_get_underlying_agent_instance(AgentId("name", key="other"), type=LoopbackAgent)
  110. assert other_long_running_agent.num_calls == 0
  111. @pytest.mark.asyncio
  112. async def test_register_factory_direct_list() -> None:
  113. runtime = SingleThreadedAgentRuntime()
  114. await runtime.register("name", LoopbackAgent, [TypeSubscription("default", "name")])
  115. runtime.start()
  116. agent_id = AgentId("name", key="default")
  117. topic_id = TopicId("default", "default")
  118. await runtime.publish_message(MessageType(), topic_id=topic_id)
  119. await runtime.stop_when_idle()
  120. # Agent in default namespace should have received the message
  121. long_running_agent = await runtime.try_get_underlying_agent_instance(agent_id, type=LoopbackAgent)
  122. assert long_running_agent.num_calls == 1
  123. # Agent in other namespace should not have received the message
  124. other_long_running_agent: LoopbackAgent = await runtime.try_get_underlying_agent_instance(AgentId("name", key="other"), type=LoopbackAgent)
  125. assert other_long_running_agent.num_calls == 0
  126. @pytest.mark.asyncio
  127. async def test_default_subscription() -> None:
  128. runtime = SingleThreadedAgentRuntime()
  129. await runtime.register("name", LoopbackAgent, lambda: [DefaultSubscription()])
  130. runtime.start()
  131. agent_id = AgentId("name", key="default")
  132. await runtime.publish_message(MessageType(), topic_id=DefaultTopicId())
  133. await runtime.stop_when_idle()
  134. # Agent in default namespace should have received the message
  135. long_running_agent = await runtime.try_get_underlying_agent_instance(agent_id, type=LoopbackAgent)
  136. assert long_running_agent.num_calls == 1
  137. # Agent in other namespace should not have received the message
  138. other_long_running_agent: LoopbackAgent = await runtime.try_get_underlying_agent_instance(AgentId("name", key="other"), type=LoopbackAgent)
  139. assert other_long_running_agent.num_calls == 0
  140. @pytest.mark.asyncio
  141. async def test_non_default_default_subscription() -> None:
  142. runtime = SingleThreadedAgentRuntime()
  143. await runtime.register("name", LoopbackAgent, lambda: [DefaultSubscription(topic_type="Other")])
  144. runtime.start()
  145. agent_id = AgentId("name", key="default")
  146. await runtime.publish_message(MessageType(), topic_id=DefaultTopicId(type="Other"))
  147. await runtime.stop_when_idle()
  148. # Agent in default namespace should have received the message
  149. long_running_agent = await runtime.try_get_underlying_agent_instance(agent_id, type=LoopbackAgent)
  150. assert long_running_agent.num_calls == 1
  151. # Agent in other namespace should not have received the message
  152. other_long_running_agent: LoopbackAgent = await runtime.try_get_underlying_agent_instance(AgentId("name", key="other"), type=LoopbackAgent)
  153. assert other_long_running_agent.num_calls == 0
  154. @pytest.mark.asyncio
  155. async def test_non_publish_to_other_source() -> None:
  156. runtime = SingleThreadedAgentRuntime()
  157. await runtime.register("name", LoopbackAgent, lambda: [DefaultSubscription()])
  158. runtime.start()
  159. agent_id = AgentId("name", key="default")
  160. await runtime.publish_message(MessageType(), topic_id=DefaultTopicId(source="other"))
  161. await runtime.stop_when_idle()
  162. # Agent in default namespace should have received the message
  163. long_running_agent = await runtime.try_get_underlying_agent_instance(agent_id, type=LoopbackAgent)
  164. assert long_running_agent.num_calls == 0
  165. # Agent in other namespace should not have received the message
  166. other_long_running_agent: LoopbackAgent = await runtime.try_get_underlying_agent_instance(AgentId("name", key="other"), type=LoopbackAgent)
  167. assert other_long_running_agent.num_calls == 1