Spaces:
Running
Running
Commit
Β·
ff16d8e
1
Parent(s):
5d12635
fix: resolve all test warnings and complete DeepBoner rebrand
Browse filesCode fixes:
- Update OpenAIModel β OpenAIChatModel (pydantic-ai deprecation)
- Add pytest.importorskip guards to 3 test files for optional deps
Rebrand fixes (missed in initial rename):
- src/services/llamaindex_rag.py: collection name
- src/tools/clinicaltrials.py: User-Agent header
- 7 doc files: package names, URLs, examples
Config:
- Add targeted pytest warning filters for Pydantic mock introspection
(known upstream issue: pydantic/pydantic#9927)
Result: 127 tests pass, 0 warnings (was 50 warnings)
- docs/architecture/design-patterns.md +1 -1
- docs/brainstorming/04_OPENALEX_INTEGRATION.md +1 -1
- docs/brainstorming/implementation/15_PHASE_OPENALEX.md +1 -1
- docs/guides/deployment.md +2 -2
- docs/implementation/01_phase_foundation.md +4 -4
- docs/implementation/12_phase_mcp_server.md +4 -4
- docs/implementation/14_phase_demo_submission.md +1 -1
- pyproject.toml +12 -0
- src/agent_factory/judges.py +2 -2
- src/services/llamaindex_rag.py +2 -2
- src/tools/clinicaltrials.py +1 -1
- tests/unit/agent_factory/test_judges_factory.py +3 -3
- tests/unit/agents/test_hypothesis_agent.py +12 -3
- tests/unit/agents/test_report_agent.py +5 -2
- tests/unit/test_magentic_fix.py +6 -2
docs/architecture/design-patterns.md
CHANGED
|
@@ -811,7 +811,7 @@ uvx fastmcp run src/mcp_servers/pubmed_server.py
|
|
| 811 |
"pubmed": {
|
| 812 |
"command": "python",
|
| 813 |
"args": ["-m", "src.mcp_servers.pubmed_server"],
|
| 814 |
-
"cwd": "/path/to/
|
| 815 |
}
|
| 816 |
}
|
| 817 |
}
|
|
|
|
| 811 |
"pubmed": {
|
| 812 |
"command": "python",
|
| 813 |
"args": ["-m", "src.mcp_servers.pubmed_server"],
|
| 814 |
+
"cwd": "/path/to/deepboner"
|
| 815 |
}
|
| 816 |
}
|
| 817 |
}
|
docs/brainstorming/04_OPENALEX_INTEGRATION.md
CHANGED
|
@@ -212,7 +212,7 @@ class OpenAlexTool(SearchTool):
|
|
| 212 |
"filter": "type:article,is_oa:true",
|
| 213 |
"sort": "cited_by_count:desc",
|
| 214 |
"per_page": max_results,
|
| 215 |
-
"mailto": "
|
| 216 |
},
|
| 217 |
)
|
| 218 |
data = resp.json()
|
|
|
|
| 212 |
"filter": "type:article,is_oa:true",
|
| 213 |
"sort": "cited_by_count:desc",
|
| 214 |
"per_page": max_results,
|
| 215 |
+
"mailto": "deepboner@example.com", # Polite pool
|
| 216 |
},
|
| 217 |
)
|
| 218 |
data = resp.json()
|
docs/brainstorming/implementation/15_PHASE_OPENALEX.md
CHANGED
|
@@ -305,7 +305,7 @@ class OpenAlexTool:
|
|
| 305 |
Args:
|
| 306 |
email: Optional email for polite pool (faster responses)
|
| 307 |
"""
|
| 308 |
-
self.email = email or "
|
| 309 |
|
| 310 |
@property
|
| 311 |
def name(self) -> str:
|
|
|
|
| 305 |
Args:
|
| 306 |
email: Optional email for polite pool (faster responses)
|
| 307 |
"""
|
| 308 |
+
self.email = email or "deepboner@example.com"
|
| 309 |
|
| 310 |
@property
|
| 311 |
def name(self) -> str:
|
docs/guides/deployment.md
CHANGED
|
@@ -69,7 +69,7 @@ def predict(message, history):
|
|
| 69 |
```json
|
| 70 |
{
|
| 71 |
"mcpServers": {
|
| 72 |
-
"
|
| 73 |
"command": "uv",
|
| 74 |
"args": ["run", "fastmcp", "run", "src/mcp_servers/pubmed_server.py"],
|
| 75 |
"cwd": "/absolute/path/to/DeepBoner"
|
|
@@ -111,7 +111,7 @@ Instead of calling Anthropic API, we call a Modal function:
|
|
| 111 |
# src/llm/modal_client.py
|
| 112 |
import modal
|
| 113 |
|
| 114 |
-
stub = modal.Stub("
|
| 115 |
|
| 116 |
@stub.function(gpu="A100")
|
| 117 |
def generate_text(prompt: str):
|
|
|
|
| 69 |
```json
|
| 70 |
{
|
| 71 |
"mcpServers": {
|
| 72 |
+
"deepboner": {
|
| 73 |
"command": "uv",
|
| 74 |
"args": ["run", "fastmcp", "run", "src/mcp_servers/pubmed_server.py"],
|
| 75 |
"cwd": "/absolute/path/to/DeepBoner"
|
|
|
|
| 111 |
# src/llm/modal_client.py
|
| 112 |
import modal
|
| 113 |
|
| 114 |
+
stub = modal.Stub("deepboner-inference")
|
| 115 |
|
| 116 |
@stub.function(gpu="A100")
|
| 117 |
def generate_text(prompt: str):
|
docs/implementation/01_phase_foundation.md
CHANGED
|
@@ -23,7 +23,7 @@ uv --version # Should be >= 0.4.0
|
|
| 23 |
|
| 24 |
```bash
|
| 25 |
# From project root
|
| 26 |
-
uv init --name
|
| 27 |
uv python install 3.11 # Pin Python version
|
| 28 |
```
|
| 29 |
|
|
@@ -35,9 +35,9 @@ uv python install 3.11 # Pin Python version
|
|
| 35 |
|
| 36 |
```toml
|
| 37 |
[project]
|
| 38 |
-
name = "
|
| 39 |
version = "0.1.0"
|
| 40 |
-
description = "AI-Native
|
| 41 |
readme = "README.md"
|
| 42 |
requires-python = ">=3.11"
|
| 43 |
dependencies = [
|
|
@@ -558,7 +558,7 @@ uv run pre-commit install
|
|
| 558 |
## 10. Implementation Checklist
|
| 559 |
|
| 560 |
- [ ] Install `uv` and verify version
|
| 561 |
-
- [ ] Run `uv init --name
|
| 562 |
- [ ] Create `pyproject.toml` (copy from above)
|
| 563 |
- [ ] Create directory structure (run mkdir commands)
|
| 564 |
- [ ] Create `.env.example` and `.env`
|
|
|
|
| 23 |
|
| 24 |
```bash
|
| 25 |
# From project root
|
| 26 |
+
uv init --name deepboner
|
| 27 |
uv python install 3.11 # Pin Python version
|
| 28 |
```
|
| 29 |
|
|
|
|
| 35 |
|
| 36 |
```toml
|
| 37 |
[project]
|
| 38 |
+
name = "deepboner"
|
| 39 |
version = "0.1.0"
|
| 40 |
+
description = "AI-Native Sexual Health Research Agent"
|
| 41 |
readme = "README.md"
|
| 42 |
requires-python = ">=3.11"
|
| 43 |
dependencies = [
|
|
|
|
| 558 |
## 10. Implementation Checklist
|
| 559 |
|
| 560 |
- [ ] Install `uv` and verify version
|
| 561 |
+
- [ ] Run `uv init --name deepboner`
|
| 562 |
- [ ] Create `pyproject.toml` (copy from above)
|
| 563 |
- [ ] Create directory structure (run mkdir commands)
|
| 564 |
- [ ] Create `.env.example` and `.env`
|
docs/implementation/12_phase_mcp_server.md
CHANGED
|
@@ -672,7 +672,7 @@ class TestMCPServerIntegration:
|
|
| 672 |
// %APPDATA%\Claude\claude_desktop_config.json (Windows)
|
| 673 |
{
|
| 674 |
"mcpServers": {
|
| 675 |
-
"
|
| 676 |
"url": "http://localhost:7860/gradio_api/mcp/"
|
| 677 |
}
|
| 678 |
}
|
|
@@ -684,8 +684,8 @@ class TestMCPServerIntegration:
|
|
| 684 |
```json
|
| 685 |
{
|
| 686 |
"mcpServers": {
|
| 687 |
-
"
|
| 688 |
-
"url": "https://
|
| 689 |
}
|
| 690 |
}
|
| 691 |
}
|
|
@@ -696,7 +696,7 @@ class TestMCPServerIntegration:
|
|
| 696 |
```json
|
| 697 |
{
|
| 698 |
"mcpServers": {
|
| 699 |
-
"
|
| 700 |
"url": "https://your-space.hf.space/gradio_api/mcp/",
|
| 701 |
"headers": {
|
| 702 |
"Authorization": "Bearer hf_xxxxxxxxxxxxx"
|
|
|
|
| 672 |
// %APPDATA%\Claude\claude_desktop_config.json (Windows)
|
| 673 |
{
|
| 674 |
"mcpServers": {
|
| 675 |
+
"deepboner": {
|
| 676 |
"url": "http://localhost:7860/gradio_api/mcp/"
|
| 677 |
}
|
| 678 |
}
|
|
|
|
| 684 |
```json
|
| 685 |
{
|
| 686 |
"mcpServers": {
|
| 687 |
+
"deepboner": {
|
| 688 |
+
"url": "https://your-space.hf.space/gradio_api/mcp/"
|
| 689 |
}
|
| 690 |
}
|
| 691 |
}
|
|
|
|
| 696 |
```json
|
| 697 |
{
|
| 698 |
"mcpServers": {
|
| 699 |
+
"deepboner": {
|
| 700 |
"url": "https://your-space.hf.space/gradio_api/mcp/",
|
| 701 |
"headers": {
|
| 702 |
"Authorization": "Bearer hf_xxxxxxxxxxxxx"
|
docs/implementation/14_phase_demo_submission.md
CHANGED
|
@@ -198,7 +198,7 @@ AI-Powered Drug Repurposing Research Agent
|
|
| 198 |
|
| 199 |
Connect to our MCP server at:
|
| 200 |
```
|
| 201 |
-
https://
|
| 202 |
```
|
| 203 |
|
| 204 |
Available tools:
|
|
|
|
| 198 |
|
| 199 |
Connect to our MCP server at:
|
| 200 |
```
|
| 201 |
+
https://your-space.hf.space/gradio_api/mcp/
|
| 202 |
```
|
| 203 |
|
| 204 |
Available tools:
|
pyproject.toml
CHANGED
|
@@ -126,6 +126,18 @@ markers = [
|
|
| 126 |
"integration: Integration tests (real APIs)",
|
| 127 |
"slow: Slow tests",
|
| 128 |
]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 129 |
|
| 130 |
# ============== COVERAGE CONFIG ==============
|
| 131 |
[tool.coverage.run]
|
|
|
|
| 126 |
"integration: Integration tests (real APIs)",
|
| 127 |
"slow: Slow tests",
|
| 128 |
]
|
| 129 |
+
# Filter warnings from unittest.mock introspecting Pydantic models.
|
| 130 |
+
# This is a known upstream issue: https://github.com/pydantic/pydantic/issues/9927
|
| 131 |
+
# When autospec=True, mock.py accesses deprecated Pydantic attributes during introspection.
|
| 132 |
+
# We filter these specifically because it's NOT our code triggering deprecations.
|
| 133 |
+
filterwarnings = [
|
| 134 |
+
# Pydantic 2.0 deprecations triggered by mock introspection
|
| 135 |
+
"ignore:The `__fields__` attribute is deprecated:pydantic.warnings.PydanticDeprecatedSince20",
|
| 136 |
+
"ignore:The `__fields_set__` attribute is deprecated:pydantic.warnings.PydanticDeprecatedSince20",
|
| 137 |
+
# Pydantic 2.11 deprecations triggered by mock introspection
|
| 138 |
+
"ignore:Accessing the 'model_computed_fields' attribute on the instance is deprecated:pydantic.warnings.PydanticDeprecatedSince211",
|
| 139 |
+
"ignore:Accessing the 'model_fields' attribute on the instance is deprecated:pydantic.warnings.PydanticDeprecatedSince211",
|
| 140 |
+
]
|
| 141 |
|
| 142 |
# ============== COVERAGE CONFIG ==============
|
| 143 |
[tool.coverage.run]
|
src/agent_factory/judges.py
CHANGED
|
@@ -9,7 +9,7 @@ from huggingface_hub import InferenceClient
|
|
| 9 |
from pydantic_ai import Agent
|
| 10 |
from pydantic_ai.models.anthropic import AnthropicModel
|
| 11 |
from pydantic_ai.models.huggingface import HuggingFaceModel
|
| 12 |
-
from pydantic_ai.models.openai import
|
| 13 |
from pydantic_ai.providers.anthropic import AnthropicProvider
|
| 14 |
from pydantic_ai.providers.huggingface import HuggingFaceProvider
|
| 15 |
from pydantic_ai.providers.openai import OpenAIProvider
|
|
@@ -48,7 +48,7 @@ def get_model() -> Any:
|
|
| 48 |
logger.warning("Unknown LLM provider, defaulting to OpenAI", provider=llm_provider)
|
| 49 |
|
| 50 |
openai_provider = OpenAIProvider(api_key=settings.openai_api_key)
|
| 51 |
-
return
|
| 52 |
|
| 53 |
|
| 54 |
class JudgeHandler:
|
|
|
|
| 9 |
from pydantic_ai import Agent
|
| 10 |
from pydantic_ai.models.anthropic import AnthropicModel
|
| 11 |
from pydantic_ai.models.huggingface import HuggingFaceModel
|
| 12 |
+
from pydantic_ai.models.openai import OpenAIChatModel
|
| 13 |
from pydantic_ai.providers.anthropic import AnthropicProvider
|
| 14 |
from pydantic_ai.providers.huggingface import HuggingFaceProvider
|
| 15 |
from pydantic_ai.providers.openai import OpenAIProvider
|
|
|
|
| 48 |
logger.warning("Unknown LLM provider, defaulting to OpenAI", provider=llm_provider)
|
| 49 |
|
| 50 |
openai_provider = OpenAIProvider(api_key=settings.openai_api_key)
|
| 51 |
+
return OpenAIChatModel(settings.openai_model, provider=openai_provider)
|
| 52 |
|
| 53 |
|
| 54 |
class JudgeHandler:
|
src/services/llamaindex_rag.py
CHANGED
|
@@ -25,7 +25,7 @@ class LlamaIndexRAGService:
|
|
| 25 |
|
| 26 |
def __init__(
|
| 27 |
self,
|
| 28 |
-
collection_name: str = "
|
| 29 |
persist_dir: str | None = None,
|
| 30 |
embedding_model: str | None = None,
|
| 31 |
similarity_top_k: int = 5,
|
|
@@ -248,7 +248,7 @@ class LlamaIndexRAGService:
|
|
| 248 |
|
| 249 |
|
| 250 |
def get_rag_service(
|
| 251 |
-
collection_name: str = "
|
| 252 |
**kwargs: Any,
|
| 253 |
) -> LlamaIndexRAGService:
|
| 254 |
"""
|
|
|
|
| 25 |
|
| 26 |
def __init__(
|
| 27 |
self,
|
| 28 |
+
collection_name: str = "deepboner_evidence",
|
| 29 |
persist_dir: str | None = None,
|
| 30 |
embedding_model: str | None = None,
|
| 31 |
similarity_top_k: int = 5,
|
|
|
|
| 248 |
|
| 249 |
|
| 250 |
def get_rag_service(
|
| 251 |
+
collection_name: str = "deepboner_evidence",
|
| 252 |
**kwargs: Any,
|
| 253 |
) -> LlamaIndexRAGService:
|
| 254 |
"""
|
src/tools/clinicaltrials.py
CHANGED
|
@@ -75,7 +75,7 @@ class ClinicalTrialsTool:
|
|
| 75 |
requests.get,
|
| 76 |
self.BASE_URL,
|
| 77 |
params=params,
|
| 78 |
-
headers={"User-Agent": "
|
| 79 |
timeout=30,
|
| 80 |
)
|
| 81 |
response.raise_for_status()
|
|
|
|
| 75 |
requests.get,
|
| 76 |
self.BASE_URL,
|
| 77 |
params=params,
|
| 78 |
+
headers={"User-Agent": "DeepBoner-Research-Agent/1.0"},
|
| 79 |
timeout=30,
|
| 80 |
)
|
| 81 |
response.raise_for_status()
|
tests/unit/agent_factory/test_judges_factory.py
CHANGED
|
@@ -10,7 +10,7 @@ from pydantic_ai.models.anthropic import AnthropicModel
|
|
| 10 |
# We expect this import to exist after we implement it, or we mock it if it's not there yet
|
| 11 |
# For TDD, we assume we will use the library class
|
| 12 |
from pydantic_ai.models.huggingface import HuggingFaceModel
|
| 13 |
-
from pydantic_ai.models.openai import
|
| 14 |
|
| 15 |
from src.agent_factory.judges import get_model
|
| 16 |
|
|
@@ -28,7 +28,7 @@ def test_get_model_openai(mock_settings):
|
|
| 28 |
mock_settings.openai_model = "gpt-5.1"
|
| 29 |
|
| 30 |
model = get_model()
|
| 31 |
-
assert isinstance(model,
|
| 32 |
assert model.model_name == "gpt-5.1"
|
| 33 |
|
| 34 |
|
|
@@ -61,4 +61,4 @@ def test_get_model_default_fallback(mock_settings):
|
|
| 61 |
mock_settings.openai_model = "gpt-5.1"
|
| 62 |
|
| 63 |
model = get_model()
|
| 64 |
-
assert isinstance(model,
|
|
|
|
| 10 |
# We expect this import to exist after we implement it, or we mock it if it's not there yet
|
| 11 |
# For TDD, we assume we will use the library class
|
| 12 |
from pydantic_ai.models.huggingface import HuggingFaceModel
|
| 13 |
+
from pydantic_ai.models.openai import OpenAIChatModel
|
| 14 |
|
| 15 |
from src.agent_factory.judges import get_model
|
| 16 |
|
|
|
|
| 28 |
mock_settings.openai_model = "gpt-5.1"
|
| 29 |
|
| 30 |
model = get_model()
|
| 31 |
+
assert isinstance(model, OpenAIChatModel)
|
| 32 |
assert model.model_name == "gpt-5.1"
|
| 33 |
|
| 34 |
|
|
|
|
| 61 |
mock_settings.openai_model = "gpt-5.1"
|
| 62 |
|
| 63 |
model = get_model()
|
| 64 |
+
assert isinstance(model, OpenAIChatModel)
|
tests/unit/agents/test_hypothesis_agent.py
CHANGED
|
@@ -3,10 +3,19 @@
|
|
| 3 |
from unittest.mock import AsyncMock, MagicMock, patch
|
| 4 |
|
| 5 |
import pytest
|
| 6 |
-
from agent_framework import AgentRunResponse
|
| 7 |
|
| 8 |
-
|
| 9 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 10 |
|
| 11 |
|
| 12 |
@pytest.fixture
|
|
|
|
| 3 |
from unittest.mock import AsyncMock, MagicMock, patch
|
| 4 |
|
| 5 |
import pytest
|
|
|
|
| 6 |
|
| 7 |
+
# Skip all tests if agent_framework not installed (optional dep)
|
| 8 |
+
pytest.importorskip("agent_framework")
|
| 9 |
+
|
| 10 |
+
from agent_framework import AgentRunResponse # noqa: E402
|
| 11 |
+
|
| 12 |
+
from src.agents.hypothesis_agent import HypothesisAgent # noqa: E402
|
| 13 |
+
from src.utils.models import ( # noqa: E402
|
| 14 |
+
Citation,
|
| 15 |
+
Evidence,
|
| 16 |
+
HypothesisAssessment,
|
| 17 |
+
MechanismHypothesis,
|
| 18 |
+
)
|
| 19 |
|
| 20 |
|
| 21 |
@pytest.fixture
|
tests/unit/agents/test_report_agent.py
CHANGED
|
@@ -5,8 +5,11 @@ from unittest.mock import AsyncMock, MagicMock, patch
|
|
| 5 |
|
| 6 |
import pytest
|
| 7 |
|
| 8 |
-
|
| 9 |
-
|
|
|
|
|
|
|
|
|
|
| 10 |
Citation,
|
| 11 |
Evidence,
|
| 12 |
MechanismHypothesis,
|
|
|
|
| 5 |
|
| 6 |
import pytest
|
| 7 |
|
| 8 |
+
# Skip all tests if agent_framework not installed (optional dep)
|
| 9 |
+
pytest.importorskip("agent_framework")
|
| 10 |
+
|
| 11 |
+
from src.agents.report_agent import ReportAgent # noqa: E402
|
| 12 |
+
from src.utils.models import ( # noqa: E402
|
| 13 |
Citation,
|
| 14 |
Evidence,
|
| 15 |
MechanismHypothesis,
|
tests/unit/test_magentic_fix.py
CHANGED
|
@@ -3,9 +3,13 @@
|
|
| 3 |
from unittest.mock import MagicMock, patch
|
| 4 |
|
| 5 |
import pytest
|
| 6 |
-
from agent_framework import MagenticFinalResultEvent
|
| 7 |
|
| 8 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 9 |
|
| 10 |
|
| 11 |
class MockChatMessage:
|
|
|
|
| 3 |
from unittest.mock import MagicMock, patch
|
| 4 |
|
| 5 |
import pytest
|
|
|
|
| 6 |
|
| 7 |
+
# Skip all tests if agent_framework not installed (optional dep)
|
| 8 |
+
pytest.importorskip("agent_framework")
|
| 9 |
+
|
| 10 |
+
from agent_framework import MagenticFinalResultEvent # noqa: E402
|
| 11 |
+
|
| 12 |
+
from src.orchestrator_magentic import MagenticOrchestrator # noqa: E402
|
| 13 |
|
| 14 |
|
| 15 |
class MockChatMessage:
|