Spaces:
Running
Running
| # Phase 9 Implementation Spec: Remove DuckDuckGo | |
| **Goal**: Remove unreliable web search, focus on credible scientific sources. | |
| **Philosophy**: "Scientific credibility over source quantity." | |
| **Prerequisite**: Phase 8 complete (all agents working) | |
| **Estimated Time**: 30-45 minutes | |
| --- | |
| ## 1. Why Remove DuckDuckGo? | |
| ### Current Problems | |
| | Issue | Impact | | |
| |-------|--------| | |
| | Rate-limited aggressively | Returns 0 results frequently | | |
| | Not peer-reviewed | Random blogs, news, misinformation | | |
| | Not citable | Cannot use in scientific reports | | |
| | Adds noise | Dilutes quality evidence | | |
| ### After Removal | |
| | Benefit | Impact | | |
| |---------|--------| | |
| | Cleaner codebase | -150 lines of dead code | | |
| | No rate limit failures | 100% source reliability | | |
| | Scientific credibility | All sources peer-reviewed/preprint | | |
| | Simpler debugging | Fewer failure modes | | |
| --- | |
| ## 2. Files to Modify/Delete | |
| ### 2.1 DELETE: `src/tools/websearch.py` | |
| ```bash | |
| # File to delete entirely | |
| src/tools/websearch.py # ~80 lines | |
| ``` | |
| ### 2.2 MODIFY: SearchHandler Usage | |
| Update all files that instantiate `SearchHandler` with `WebTool()`: | |
| | File | Change | | |
| |------|--------| | |
| | `examples/search_demo/run_search.py` | Remove `WebTool()` from tools list | | |
| | `examples/hypothesis_demo/run_hypothesis.py` | Remove `WebTool()` from tools list | | |
| | `examples/full_stack_demo/run_full.py` | Remove `WebTool()` from tools list | | |
| | `examples/orchestrator_demo/run_agent.py` | Remove `WebTool()` from tools list | | |
| | `examples/orchestrator_demo/run_magentic.py` | Remove `WebTool()` from tools list | | |
| ### 2.3 MODIFY: Type Definitions | |
| Update `src/utils/models.py`: | |
| ```python | |
| # BEFORE | |
| sources_searched: list[Literal["pubmed", "web"]] | |
| # AFTER (Phase 9) | |
| sources_searched: list[Literal["pubmed"]] | |
| # AFTER (Phase 10-11) | |
| sources_searched: list[Literal["pubmed", "clinicaltrials", "biorxiv"]] | |
| ``` | |
| ### 2.4 DELETE: Tests for WebTool | |
| ```bash | |
| # File to delete | |
| tests/unit/tools/test_websearch.py | |
| ``` | |
| --- | |
| ## 3. TDD Implementation | |
| ### 3.1 Test: SearchHandler Works Without WebTool | |
| ```python | |
| # tests/unit/tools/test_search_handler.py | |
| @pytest.mark.asyncio | |
| async def test_search_handler_pubmed_only(): | |
| """SearchHandler should work with only PubMed tool.""" | |
| from src.tools.pubmed import PubMedTool | |
| from src.tools.search_handler import SearchHandler | |
| handler = SearchHandler(tools=[PubMedTool()], timeout=30.0) | |
| # Should not raise | |
| result = await handler.execute("metformin diabetes", max_results_per_tool=3) | |
| assert result.sources_searched == ["pubmed"] | |
| assert "web" not in result.sources_searched | |
| assert len(result.errors) == 0 # No failures | |
| ``` | |
| ### 3.2 Test: WebTool Import Fails (Deleted) | |
| ```python | |
| # tests/unit/tools/test_websearch_removed.py | |
| def test_websearch_module_deleted(): | |
| """WebTool should no longer exist.""" | |
| with pytest.raises(ImportError): | |
| from src.tools.websearch import WebTool | |
| ``` | |
| ### 3.3 Test: Examples Don't Reference WebTool | |
| ```python | |
| # tests/unit/test_no_webtool_references.py | |
| import ast | |
| import pathlib | |
| def test_examples_no_webtool_imports(): | |
| """No example files should import WebTool.""" | |
| examples_dir = pathlib.Path("examples") | |
| for py_file in examples_dir.rglob("*.py"): | |
| content = py_file.read_text() | |
| tree = ast.parse(content) | |
| for node in ast.walk(tree): | |
| if isinstance(node, ast.ImportFrom): | |
| if node.module and "websearch" in node.module: | |
| pytest.fail(f"{py_file} imports websearch (should be removed)") | |
| if isinstance(node, ast.Import): | |
| for alias in node.names: | |
| if "websearch" in alias.name: | |
| pytest.fail(f"{py_file} imports websearch (should be removed)") | |
| ``` | |
| --- | |
| ## 4. Step-by-Step Implementation | |
| ### Step 1: Write Tests First (TDD) | |
| ```bash | |
| # Create the test file | |
| touch tests/unit/tools/test_websearch_removed.py | |
| # Write the tests from section 3 | |
| ``` | |
| ### Step 2: Run Tests (Should Fail) | |
| ```bash | |
| uv run pytest tests/unit/tools/test_websearch_removed.py -v | |
| # Expected: FAIL (websearch still exists) | |
| ``` | |
| ### Step 3: Delete WebTool | |
| ```bash | |
| rm src/tools/websearch.py | |
| rm tests/unit/tools/test_websearch.py | |
| ``` | |
| ### Step 4: Update SearchHandler Usages | |
| ```python | |
| # BEFORE (in each example file) | |
| from src.tools.websearch import WebTool | |
| search_handler = SearchHandler(tools=[PubMedTool(), WebTool()], timeout=30.0) | |
| # AFTER | |
| from src.tools.pubmed import PubMedTool | |
| search_handler = SearchHandler(tools=[PubMedTool()], timeout=30.0) | |
| ``` | |
| ### Step 5: Update Type Definitions | |
| ```python | |
| # src/utils/models.py | |
| # BEFORE | |
| sources_searched: list[Literal["pubmed", "web"]] | |
| # AFTER | |
| sources_searched: list[Literal["pubmed"]] | |
| ``` | |
| ### Step 6: Run All Tests | |
| ```bash | |
| uv run pytest tests/unit/ -v | |
| # Expected: ALL PASS | |
| ``` | |
| ### Step 7: Run Lints | |
| ```bash | |
| uv run ruff check src tests examples | |
| uv run mypy src | |
| # Expected: No errors | |
| ``` | |
| --- | |
| ## 5. Definition of Done | |
| Phase 9 is **COMPLETE** when: | |
| - [ ] `src/tools/websearch.py` deleted | |
| - [ ] `tests/unit/tools/test_websearch.py` deleted | |
| - [ ] All example files updated (no WebTool imports) | |
| - [ ] Type definitions updated in models.py | |
| - [ ] New tests verify WebTool is removed | |
| - [ ] All existing tests pass | |
| - [ ] Lints pass | |
| - [ ] Examples run successfully with PubMed only | |
| --- | |
| ## 6. Verification Commands | |
| ```bash | |
| # 1. Verify websearch.py is gone | |
| ls src/tools/websearch.py 2>&1 | grep "No such file" | |
| # 2. Verify no WebTool imports remain | |
| grep -r "WebTool" src/ examples/ && echo "FAIL: WebTool references found" || echo "PASS" | |
| grep -r "websearch" src/ examples/ && echo "FAIL: websearch references found" || echo "PASS" | |
| # 3. Run tests | |
| uv run pytest tests/unit/ -v | |
| # 4. Run example (should work) | |
| source .env && uv run python examples/search_demo/run_search.py "metformin cancer" | |
| ``` | |
| --- | |
| ## 7. Rollback Plan | |
| If something breaks: | |
| ```bash | |
| git checkout HEAD -- src/tools/websearch.py | |
| git checkout HEAD -- tests/unit/tools/test_websearch.py | |
| ``` | |
| --- | |
| ## 8. Value Delivered | |
| | Before | After | | |
| |--------|-------| | |
| | 2 search sources (1 broken) | 1 reliable source | | |
| | Rate limit failures | No failures | | |
| | Web noise in results | Pure scientific sources | | |
| | ~230 lines for websearch | 0 lines | | |
| **Net effect**: Simpler, more reliable, more credible. | |