test_helloagents_integration.py 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. import json
  2. import threading
  3. import time
  4. from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
  5. from unittest.mock import MagicMock, patch
  6. from hello_agents import SimpleAgent
  7. from app.agent.agent import ModeratorAgent, ParticipantAgent, run_simple_agent
  8. from demo_helloagents import run_demo
  9. def _configure_llm(monkeypatch):
  10. monkeypatch.setenv("API_KEY", "test-key")
  11. monkeypatch.setenv("MODEL_NAME", "test-model")
  12. monkeypatch.setenv("BASE_URL", "https://example.test/v1/")
  13. def test_one_shot_task_is_driven_by_helloagents(monkeypatch):
  14. _configure_llm(monkeypatch)
  15. framework_agent = MagicMock()
  16. framework_agent.run.return_value = "framework response"
  17. with patch("app.agent.agent.HelloAgentsLLM") as llm_class, patch(
  18. "app.agent.agent.SimpleAgent", return_value=framework_agent
  19. ) as agent_class:
  20. response = run_simple_agent("TestAgent", "system", "hello")
  21. llm_class.assert_called_once()
  22. agent_class.assert_called_once()
  23. framework_agent.run.assert_called_once_with("hello")
  24. assert response == "framework response"
  25. def test_participant_reuses_helloagents_agent_for_multiple_turns(monkeypatch):
  26. _configure_llm(monkeypatch)
  27. framework_agent = MagicMock()
  28. framework_agent.run.return_value = '{"decision":"LISTEN","inner_monologue":"观察"}'
  29. framework_agent.stream_run.return_value = iter(["第一段", "第二段"])
  30. persona = {
  31. "name": "测试嘉宾",
  32. "bio": "测试生平",
  33. "title": "研究者",
  34. "theories": ["测试理论"],
  35. "stance": "审慎",
  36. "system_prompt": "保持审慎。",
  37. }
  38. with patch("app.agent.agent.HelloAgentsLLM"):
  39. participant = ParticipantAgent("测试嘉宾", persona, 2, "测试议题")
  40. with patch.object(participant, "run", return_value=framework_agent.run.return_value), patch.object(
  41. participant, "stream_run", return_value=framework_agent.stream_run.return_value
  42. ):
  43. thought = participant.think("当前讨论")
  44. chunks = list(participant.speak(thought, "当前讨论"))
  45. assert isinstance(participant, SimpleAgent)
  46. assert thought["action"] == "listen"
  47. assert chunks == ["第一段", "第二段"]
  48. def test_end_to_end_discussion_uses_helloagents_agents(monkeypatch):
  49. _configure_llm(monkeypatch)
  50. streams = iter([iter(["主持人开场"]), iter(["嘉宾发言"]), iter(["阶段总结"]), iter(["主持人闭幕"])])
  51. with patch("app.agent.agent.HelloAgentsLLM"), patch.object(
  52. SimpleAgent, "run", return_value='{"decision":"APPLY_SPEAK","inner_monologue":"回应议题"}'
  53. ), patch.object(SimpleAgent, "stream_run", side_effect=lambda *args, **kwargs: next(streams)):
  54. transcript = run_demo("测试议题")
  55. assert transcript["opening"] == "主持人开场"
  56. assert transcript["thought"]["action"] == "apply_to_speak"
  57. assert transcript["speech"] == "嘉宾发言"
  58. assert transcript["summary"] == "阶段总结"
  59. assert transcript["closing"] == "主持人闭幕"
  60. def test_madf_agents_are_native_helloagents_subclasses(monkeypatch):
  61. _configure_llm(monkeypatch)
  62. persona = {"system_prompt": "persona", "name": "P"}
  63. with patch("app.agent.agent.HelloAgentsLLM"):
  64. moderator = ModeratorAgent("topic")
  65. participant = ParticipantAgent("P", persona, 1, "topic")
  66. assert isinstance(moderator, SimpleAgent)
  67. assert isinstance(participant, SimpleAgent)
  68. assert not hasattr(participant, "_hello_agent")
  69. def test_end_to_end_discussion_through_real_helloagents_runtime(monkeypatch):
  70. responses = iter(
  71. [
  72. "真实框架开场",
  73. '{"decision":"APPLY_SPEAK","inner_monologue":"真实框架思考"}',
  74. "真实框架发言",
  75. "真实框架总结",
  76. "真实框架闭幕",
  77. ]
  78. )
  79. class Handler(BaseHTTPRequestHandler):
  80. def log_message(self, format, *args):
  81. return
  82. def do_POST(self):
  83. size = int(self.headers.get("Content-Length", "0"))
  84. request = json.loads(self.rfile.read(size))
  85. content = next(responses)
  86. if request.get("stream"):
  87. payload = {
  88. "id": "chatcmpl-madf",
  89. "object": "chat.completion.chunk",
  90. "created": int(time.time()),
  91. "model": "test-model",
  92. "choices": [{"index": 0, "delta": {"content": content}, "finish_reason": None}],
  93. }
  94. body = f"data: {json.dumps(payload, ensure_ascii=False)}\n\ndata: [DONE]\n\n".encode()
  95. self.send_response(200)
  96. self.send_header("Content-Type", "text/event-stream")
  97. self.send_header("Content-Length", str(len(body)))
  98. self.end_headers()
  99. self.wfile.write(body)
  100. return
  101. body = json.dumps(
  102. {
  103. "id": "chatcmpl-madf",
  104. "object": "chat.completion",
  105. "created": int(time.time()),
  106. "model": "test-model",
  107. "choices": [
  108. {
  109. "index": 0,
  110. "message": {"role": "assistant", "content": content},
  111. "finish_reason": "stop",
  112. }
  113. ],
  114. "usage": {"prompt_tokens": 1, "completion_tokens": 1, "total_tokens": 2},
  115. },
  116. ensure_ascii=False,
  117. ).encode()
  118. self.send_response(200)
  119. self.send_header("Content-Type", "application/json")
  120. self.send_header("Content-Length", str(len(body)))
  121. self.end_headers()
  122. self.wfile.write(body)
  123. server = ThreadingHTTPServer(("127.0.0.1", 0), Handler)
  124. thread = threading.Thread(target=server.serve_forever, daemon=True)
  125. thread.start()
  126. monkeypatch.setenv("API_KEY", "test-key")
  127. monkeypatch.setenv("MODEL_NAME", "test-model")
  128. monkeypatch.setenv("BASE_URL", f"http://127.0.0.1:{server.server_port}/v1")
  129. try:
  130. transcript = run_demo("真实 HelloAgents 链路测试")
  131. finally:
  132. server.shutdown()
  133. thread.join(timeout=5)
  134. assert transcript["opening"] == "真实框架开场"
  135. assert transcript["thought"]["action"] == "apply_to_speak"
  136. assert transcript["speech"] == "真实框架发言"
  137. assert transcript["summary"] == "真实框架总结"
  138. assert transcript["closing"] == "真实框架闭幕"