| import unittest |
| from unittest.mock import MagicMock, patch |
|
|
| from agents.research_graph import ( |
| plan_search_node, |
| execute_search_node, |
| route_research, |
| save_note_node, |
| finalize_research_node |
| ) |
|
|
|
|
| class ResearchAgentNodesTests(unittest.TestCase): |
| @patch("agents.research_graph.generate_sub_queries") |
| def test_plan_search_node_extracts_queries(self, mock_generate_sub_queries): |
| state = {"topic": "AI agents", "debug_mode": False} |
| llm = MagicMock() |
| mock_generate_sub_queries.return_value = [ |
| "what are ai agents", |
| "benefits of ai agents", |
| "future of ai agents", |
| ] |
| |
| updated_state = plan_search_node(state, llm=llm, max_queries=3) |
| |
| expected_queries = ["what are ai agents", "benefits of ai agents", "future of ai agents"] |
| self.assertEqual(updated_state["search_queries"], expected_queries) |
|
|
| @patch("agents.research_graph.generate_sub_queries") |
| def test_plan_search_node_respects_max_queries(self, mock_generate_sub_queries): |
| state = {"topic": "AI agents", "debug_mode": False} |
| llm = MagicMock() |
| mock_generate_sub_queries.return_value = ["q1", "q2"] |
| |
| updated_state = plan_search_node(state, llm=llm, max_queries=2) |
| |
| self.assertEqual(len(updated_state["search_queries"]), 2) |
| self.assertEqual(updated_state["search_queries"], ["q1", "q2"]) |
|
|
| @patch("agents.research_graph.fetch_urls_parallel") |
| @patch("agents.research_graph.web_search") |
| def test_execute_search_node_collects_results(self, mock_search, mock_fetch_parallel): |
| mock_search.return_value = [ |
| {"url": "http://e1.com", "title": "T1", "snippet": "S1"}, |
| {"url": "http://e2.com", "title": "T2", "snippet": "S2"} |
| ] |
| mock_fetch_parallel.return_value = [ |
| {"source_url": "http://e1.com", "page_text": "Full Content"}, |
| ] |
|
|
| state = {"search_queries": ["query 1"], "debug_mode": False} |
| updated_state = execute_search_node(state) |
|
|
| self.assertEqual(len(updated_state["search_results"]), 2) |
| self.assertEqual(updated_state["search_results"][0]["content"], "Full Content") |
|
|
| @patch("agents.research_graph.save_note") |
| def test_save_note_node_calls_save_note_when_requested(self, mock_save): |
| mock_save.return_value = "note_123" |
| state = { |
| "topic": "Research Topic", |
| "synthesis": "The Synthesis", |
| "save_to_notes": True, |
| "search_results": [{"url": "U1", "snippet": "S1"}] |
| } |
| |
| updated_state = save_note_node(state) |
| |
| self.assertEqual(updated_state["note_id"], "note_123") |
| mock_save.assert_called_once() |
|
|
| def test_save_note_node_skips_when_not_requested(self): |
| state = {"save_to_notes": False} |
| updated_state = save_note_node(state) |
| self.assertNotIn("note_id", updated_state) |
|
|
| def test_finalize_research_node_handles_no_results_error(self): |
| state = {"topic": "Unknown topic", "error": "no_search_results"} |
| updated_state = finalize_research_node(state) |
| self.assertIn("unable to find", updated_state["synthesis"]) |
|
|
| def test_finalize_research_node_builds_lightweight_summary_when_results_exist(self): |
| state = { |
| "topic": "Topic", |
| "search_results": [ |
| {"title": "Result One"}, |
| {"title": "Result Two"}, |
| ], |
| } |
| updated_state = finalize_research_node(state) |
| self.assertIn("Collected web sources", updated_state["synthesis"]) |
|
|
| def test_route_research_returns_finalize_on_error(self): |
| state = {"error": "no_search_results"} |
| self.assertEqual(route_research(state), "finalize") |
|
|
| def test_route_research_returns_finalize_when_no_error(self): |
| state = {"search_results": [{"url": "http://e1.com"}]} |
| self.assertEqual(route_research(state), "finalize") |
|
|