docs: Add comprehensive documentation structure
Browse filesAdd professional documentation structure with:
Root-level standard docs:
- CONTRIBUTING.md - Contribution guidelines
- CHANGELOG.md - Release history tracking
- SECURITY.md - Vulnerability reporting policy
- CODE_OF_CONDUCT.md - Community standards
Documentation index:
- docs/README.md - Navigation and overview
Getting started guides:
- installation.md - Setup instructions
- quickstart.md - 5-minute guide
- configuration.md - Configuration options
- troubleshooting.md - Common issues
Architecture documentation:
- overview.md - High-level architecture
- component-inventory.md - Complete module catalog
- data-models.md - Pydantic model reference
- exception-hierarchy.md - Exception types
Development guides:
- testing.md - Testing strategy and patterns
- code-style.md - Style conventions
- release-process.md - Release workflow
Deployment guides:
- docker.md - Container deployment
- huggingface-spaces.md - Cloud deployment
- mcp-integration.md - MCP server setup
Technical debt tracking:
- index.md - Debt overview
- debt-registry.md - Itemized debt items (14 tracked)
Reference documentation:
- configuration.md - All config options
- environment-variables.md - Env var reference
- CHANGELOG.md +113 -0
- CODE_OF_CONDUCT.md +111 -0
- CONTRIBUTING.md +229 -0
- SECURITY.md +125 -0
- docs/README.md +129 -0
- docs/architecture/component-inventory.md +458 -0
- docs/architecture/data-models.md +342 -0
- docs/architecture/exception-hierarchy.md +350 -0
- docs/architecture/overview.md +224 -0
- docs/deployment/docker.md +290 -0
- docs/deployment/huggingface-spaces.md +224 -0
- docs/deployment/mcp-integration.md +226 -0
- docs/development/code-style.md +373 -0
- docs/development/release-process.md +191 -0
- docs/development/testing.md +408 -0
- docs/getting-started/configuration.md +172 -0
- docs/getting-started/installation.md +164 -0
- docs/getting-started/quickstart.md +147 -0
- docs/getting-started/troubleshooting.md +280 -0
- docs/reference/configuration.md +185 -0
- docs/reference/environment-variables.md +284 -0
- docs/technical-debt/debt-registry.md +409 -0
- docs/technical-debt/index.md +106 -0
|
@@ -0,0 +1,113 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Changelog
|
| 2 |
+
|
| 3 |
+
All notable changes to DeepBoner will be documented in this file.
|
| 4 |
+
|
| 5 |
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
| 6 |
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
| 7 |
+
|
| 8 |
+
## [Unreleased]
|
| 9 |
+
|
| 10 |
+
### Added
|
| 11 |
+
- Comprehensive documentation structure (CONTRIBUTING.md, SECURITY.md, CODE_OF_CONDUCT.md)
|
| 12 |
+
- Technical debt tracking documentation
|
| 13 |
+
- Component inventory documentation
|
| 14 |
+
- Data models reference documentation
|
| 15 |
+
|
| 16 |
+
## [0.1.0] - 2025-12-04
|
| 17 |
+
|
| 18 |
+
### Added
|
| 19 |
+
- **Core Research Agent**
|
| 20 |
+
- Search-and-judge loop with multi-tool orchestration
|
| 21 |
+
- PubMed E-utilities API integration
|
| 22 |
+
- ClinicalTrials.gov API integration
|
| 23 |
+
- Europe PMC API integration
|
| 24 |
+
- OpenAlex API integration
|
| 25 |
+
- LLM-based evidence quality assessment (Judge)
|
| 26 |
+
- Research report synthesis with citations
|
| 27 |
+
|
| 28 |
+
- **Multi-Agent Architecture**
|
| 29 |
+
- Microsoft Agent Framework integration (Magentic)
|
| 30 |
+
- SearchAgent, JudgeAgent, ReportAgent coordination
|
| 31 |
+
- Pydantic AI structured outputs
|
| 32 |
+
- LangGraph workflow state management (experimental)
|
| 33 |
+
|
| 34 |
+
- **Dual-Backend LLM Support**
|
| 35 |
+
- Free tier: HuggingFace Inference API (Qwen 2.5 7B)
|
| 36 |
+
- Paid tier: OpenAI GPT-5 (auto-detected with API key)
|
| 37 |
+
- Factory pattern for backend selection
|
| 38 |
+
|
| 39 |
+
- **Evidence Processing**
|
| 40 |
+
- Cross-source deduplication by PMID/DOI
|
| 41 |
+
- ChromaDB + Sentence-Transformers for embeddings
|
| 42 |
+
- LlamaIndex RAG support (premium tier)
|
| 43 |
+
- Citation validation and formatting
|
| 44 |
+
|
| 45 |
+
- **User Interface**
|
| 46 |
+
- Gradio streaming UI
|
| 47 |
+
- MCP (Model Context Protocol) server integration
|
| 48 |
+
- Claude Desktop tool support
|
| 49 |
+
|
| 50 |
+
- **Developer Experience**
|
| 51 |
+
- Makefile with common commands
|
| 52 |
+
- Pre-commit hooks (ruff, mypy)
|
| 53 |
+
- Comprehensive test suite (unit, integration, e2e)
|
| 54 |
+
- GitHub Actions CI/CD pipeline
|
| 55 |
+
- Docker support with model pre-loading
|
| 56 |
+
|
| 57 |
+
- **Documentation**
|
| 58 |
+
- README with quick start guide
|
| 59 |
+
- CLAUDE.md/AGENTS.md for AI agent guidance
|
| 60 |
+
- Architecture documentation with Mermaid diagrams
|
| 61 |
+
- Example scripts for all major features
|
| 62 |
+
|
| 63 |
+
### Technical Notes
|
| 64 |
+
|
| 65 |
+
This release represents the completion of Phases 1-14 of the original development plan:
|
| 66 |
+
|
| 67 |
+
1. Foundation (project structure, TDD setup)
|
| 68 |
+
2. PubMed search implementation
|
| 69 |
+
3. ClinicalTrials.gov integration
|
| 70 |
+
4. Basic orchestrator loop
|
| 71 |
+
5. Evidence quality judgment
|
| 72 |
+
6. Report synthesis
|
| 73 |
+
7. Europe PMC integration
|
| 74 |
+
8. Evidence deduplication
|
| 75 |
+
9. Advanced search refinement
|
| 76 |
+
10. Hypothesis generation
|
| 77 |
+
11. Mechanistic pathway analysis
|
| 78 |
+
12. LangGraph workflow
|
| 79 |
+
13. Microsoft Agent Framework integration
|
| 80 |
+
14. Demo submission
|
| 81 |
+
|
| 82 |
+
### Known Issues
|
| 83 |
+
|
| 84 |
+
See `docs/technical-debt/` for documented technical debt and known issues.
|
| 85 |
+
|
| 86 |
+
---
|
| 87 |
+
|
| 88 |
+
## Release Notes Format
|
| 89 |
+
|
| 90 |
+
For each release, document:
|
| 91 |
+
|
| 92 |
+
### Added
|
| 93 |
+
New features and capabilities
|
| 94 |
+
|
| 95 |
+
### Changed
|
| 96 |
+
Changes to existing functionality
|
| 97 |
+
|
| 98 |
+
### Deprecated
|
| 99 |
+
Features that will be removed in future versions
|
| 100 |
+
|
| 101 |
+
### Removed
|
| 102 |
+
Features that were removed
|
| 103 |
+
|
| 104 |
+
### Fixed
|
| 105 |
+
Bug fixes
|
| 106 |
+
|
| 107 |
+
### Security
|
| 108 |
+
Security-related changes
|
| 109 |
+
|
| 110 |
+
---
|
| 111 |
+
|
| 112 |
+
[Unreleased]: https://github.com/The-Obstacle-Is-The-Way/DeepBoner/compare/v0.1.0...HEAD
|
| 113 |
+
[0.1.0]: https://github.com/The-Obstacle-Is-The-Way/DeepBoner/releases/tag/v0.1.0
|
|
@@ -0,0 +1,111 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Code of Conduct
|
| 2 |
+
|
| 3 |
+
## Our Pledge
|
| 4 |
+
|
| 5 |
+
We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, caste, color, religion, or sexual identity and orientation.
|
| 6 |
+
|
| 7 |
+
We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community.
|
| 8 |
+
|
| 9 |
+
## Our Standards
|
| 10 |
+
|
| 11 |
+
Examples of behavior that contributes to a positive environment:
|
| 12 |
+
|
| 13 |
+
* Demonstrating empathy and kindness toward other people
|
| 14 |
+
* Being respectful of differing opinions, viewpoints, and experiences
|
| 15 |
+
* Giving and gracefully accepting constructive feedback
|
| 16 |
+
* Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience
|
| 17 |
+
* Focusing on what is best not just for us as individuals, but for the overall community
|
| 18 |
+
|
| 19 |
+
Examples of unacceptable behavior:
|
| 20 |
+
|
| 21 |
+
* The use of sexualized language or imagery, and sexual attention or advances of any kind
|
| 22 |
+
* Trolling, insulting or derogatory comments, and personal or political attacks
|
| 23 |
+
* Public or private harassment
|
| 24 |
+
* Publishing others' private information without their explicit permission
|
| 25 |
+
* Other conduct which could reasonably be considered inappropriate in a professional setting
|
| 26 |
+
|
| 27 |
+
## Project-Specific Guidelines
|
| 28 |
+
|
| 29 |
+
Given DeepBoner's focus on sexual health research:
|
| 30 |
+
|
| 31 |
+
### Respectful Discussion
|
| 32 |
+
- Sexual health is a legitimate medical topic deserving serious discussion
|
| 33 |
+
- Approach all topics with professionalism and scientific rigor
|
| 34 |
+
- Avoid jokes or comments that trivialize sexual health issues
|
| 35 |
+
- Remember that users may be dealing with personal health concerns
|
| 36 |
+
|
| 37 |
+
### Inclusive Language
|
| 38 |
+
- Use inclusive, gender-neutral language when possible
|
| 39 |
+
- Recognize that sexual health affects all genders
|
| 40 |
+
- Avoid assumptions about users' identities or experiences
|
| 41 |
+
|
| 42 |
+
### Scientific Integrity
|
| 43 |
+
- Base discussions on peer-reviewed evidence when possible
|
| 44 |
+
- Clearly distinguish between established science and speculation
|
| 45 |
+
- Respect the complexity of medical topics
|
| 46 |
+
|
| 47 |
+
## Enforcement Responsibilities
|
| 48 |
+
|
| 49 |
+
Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful.
|
| 50 |
+
|
| 51 |
+
Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for moderation decisions when appropriate.
|
| 52 |
+
|
| 53 |
+
## Scope
|
| 54 |
+
|
| 55 |
+
This Code of Conduct applies within all community spaces, including:
|
| 56 |
+
- GitHub repository (issues, PRs, discussions)
|
| 57 |
+
- Discord/Slack channels (if applicable)
|
| 58 |
+
- Project-related social media
|
| 59 |
+
- Events and meetups
|
| 60 |
+
|
| 61 |
+
It also applies when an individual is officially representing the community in public spaces.
|
| 62 |
+
|
| 63 |
+
## Enforcement
|
| 64 |
+
|
| 65 |
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement via:
|
| 66 |
+
|
| 67 |
+
1. GitHub's reporting features
|
| 68 |
+
2. Direct message to maintainers
|
| 69 |
+
3. Email to repository owners
|
| 70 |
+
|
| 71 |
+
All complaints will be reviewed and investigated promptly and fairly.
|
| 72 |
+
|
| 73 |
+
All community leaders are obligated to respect the privacy and security of the reporter of any incident.
|
| 74 |
+
|
| 75 |
+
## Enforcement Guidelines
|
| 76 |
+
|
| 77 |
+
Community leaders will follow these Community Impact Guidelines:
|
| 78 |
+
|
| 79 |
+
### 1. Correction
|
| 80 |
+
|
| 81 |
+
**Community Impact**: Use of inappropriate language or other behavior deemed unprofessional.
|
| 82 |
+
|
| 83 |
+
**Consequence**: A private, written warning providing clarity around the nature of the violation and an explanation of why the behavior was inappropriate. A public apology may be requested.
|
| 84 |
+
|
| 85 |
+
### 2. Warning
|
| 86 |
+
|
| 87 |
+
**Community Impact**: A violation through a single incident or series of actions.
|
| 88 |
+
|
| 89 |
+
**Consequence**: A warning with consequences for continued behavior. No interaction with the people involved for a specified period. This includes avoiding interactions in community spaces as well as external channels. Violating these terms may lead to a temporary or permanent ban.
|
| 90 |
+
|
| 91 |
+
### 3. Temporary Ban
|
| 92 |
+
|
| 93 |
+
**Community Impact**: A serious violation of community standards, including sustained inappropriate behavior.
|
| 94 |
+
|
| 95 |
+
**Consequence**: A temporary ban from any sort of interaction or public communication with the community for a specified period. No public or private interaction with the people involved is allowed. Violating these terms may lead to a permanent ban.
|
| 96 |
+
|
| 97 |
+
### 4. Permanent Ban
|
| 98 |
+
|
| 99 |
+
**Community Impact**: Demonstrating a pattern of violation of community standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals.
|
| 100 |
+
|
| 101 |
+
**Consequence**: A permanent ban from any sort of public interaction within the community.
|
| 102 |
+
|
| 103 |
+
## Attribution
|
| 104 |
+
|
| 105 |
+
This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org), version 2.1, available at [https://www.contributor-covenant.org/version/2/1/code_of_conduct.html](https://www.contributor-covenant.org/version/2/1/code_of_conduct.html).
|
| 106 |
+
|
| 107 |
+
Community Impact Guidelines were inspired by [Mozilla's code of conduct enforcement ladder](https://github.com/mozilla/diversity).
|
| 108 |
+
|
| 109 |
+
---
|
| 110 |
+
|
| 111 |
+
*"We take evidence-based community standards very seriously."* π€
|
|
@@ -0,0 +1,229 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Contributing to DeepBoner
|
| 2 |
+
|
| 3 |
+
Thank you for your interest in contributing to DeepBoner! This document provides guidelines and instructions for contributing to the project.
|
| 4 |
+
|
| 5 |
+
## Table of Contents
|
| 6 |
+
|
| 7 |
+
- [Code of Conduct](#code-of-conduct)
|
| 8 |
+
- [Getting Started](#getting-started)
|
| 9 |
+
- [Development Setup](#development-setup)
|
| 10 |
+
- [Making Changes](#making-changes)
|
| 11 |
+
- [Testing](#testing)
|
| 12 |
+
- [Submitting Changes](#submitting-changes)
|
| 13 |
+
- [Code Style](#code-style)
|
| 14 |
+
- [Documentation](#documentation)
|
| 15 |
+
|
| 16 |
+
## Code of Conduct
|
| 17 |
+
|
| 18 |
+
Please read and follow our [Code of Conduct](CODE_OF_CONDUCT.md) to keep our community welcoming and respectful.
|
| 19 |
+
|
| 20 |
+
## Getting Started
|
| 21 |
+
|
| 22 |
+
### Prerequisites
|
| 23 |
+
|
| 24 |
+
- Python 3.11 or higher
|
| 25 |
+
- [uv](https://github.com/astral-sh/uv) package manager
|
| 26 |
+
- Git
|
| 27 |
+
|
| 28 |
+
### Development Setup
|
| 29 |
+
|
| 30 |
+
1. **Fork the repository** on GitHub
|
| 31 |
+
|
| 32 |
+
2. **Clone your fork**:
|
| 33 |
+
```bash
|
| 34 |
+
git clone https://github.com/YOUR_USERNAME/DeepBoner.git
|
| 35 |
+
cd DeepBoner
|
| 36 |
+
```
|
| 37 |
+
|
| 38 |
+
3. **Install dependencies**:
|
| 39 |
+
```bash
|
| 40 |
+
make install
|
| 41 |
+
# or manually:
|
| 42 |
+
uv sync --all-extras && uv run pre-commit install
|
| 43 |
+
```
|
| 44 |
+
|
| 45 |
+
4. **Copy the environment template**:
|
| 46 |
+
```bash
|
| 47 |
+
cp .env.example .env
|
| 48 |
+
# Edit .env with your API keys if needed
|
| 49 |
+
```
|
| 50 |
+
|
| 51 |
+
5. **Verify your setup**:
|
| 52 |
+
```bash
|
| 53 |
+
make check
|
| 54 |
+
```
|
| 55 |
+
|
| 56 |
+
## Making Changes
|
| 57 |
+
|
| 58 |
+
### Branch Naming Convention
|
| 59 |
+
|
| 60 |
+
- `feature/short-description` - New features
|
| 61 |
+
- `fix/short-description` - Bug fixes
|
| 62 |
+
- `docs/short-description` - Documentation changes
|
| 63 |
+
- `refactor/short-description` - Code refactoring
|
| 64 |
+
- `test/short-description` - Test additions/improvements
|
| 65 |
+
|
| 66 |
+
### Commit Message Format
|
| 67 |
+
|
| 68 |
+
We follow conventional commit messages:
|
| 69 |
+
|
| 70 |
+
```
|
| 71 |
+
type(scope): short description
|
| 72 |
+
|
| 73 |
+
Optional longer description explaining the change.
|
| 74 |
+
|
| 75 |
+
Closes #123
|
| 76 |
+
```
|
| 77 |
+
|
| 78 |
+
Types:
|
| 79 |
+
- `feat` - New feature
|
| 80 |
+
- `fix` - Bug fix
|
| 81 |
+
- `docs` - Documentation only
|
| 82 |
+
- `style` - Code style (formatting, no logic change)
|
| 83 |
+
- `refactor` - Code refactoring
|
| 84 |
+
- `test` - Adding/updating tests
|
| 85 |
+
- `chore` - Build process, tooling, dependencies
|
| 86 |
+
|
| 87 |
+
Examples:
|
| 88 |
+
```
|
| 89 |
+
feat(tools): add OpenAlex API integration
|
| 90 |
+
fix(pubmed): handle empty search results gracefully
|
| 91 |
+
docs(readme): update quick start instructions
|
| 92 |
+
```
|
| 93 |
+
|
| 94 |
+
## Testing
|
| 95 |
+
|
| 96 |
+
### Running Tests
|
| 97 |
+
|
| 98 |
+
```bash
|
| 99 |
+
# Run all tests
|
| 100 |
+
make test
|
| 101 |
+
|
| 102 |
+
# Run with coverage
|
| 103 |
+
make test-cov
|
| 104 |
+
|
| 105 |
+
# Run specific test file
|
| 106 |
+
uv run pytest tests/unit/utils/test_config.py -v
|
| 107 |
+
|
| 108 |
+
# Run specific test
|
| 109 |
+
uv run pytest tests/unit/utils/test_config.py::TestSettings::test_default_max_iterations -v
|
| 110 |
+
```
|
| 111 |
+
|
| 112 |
+
### Test Markers
|
| 113 |
+
|
| 114 |
+
- `@pytest.mark.unit` - Unit tests (mocked, fast)
|
| 115 |
+
- `@pytest.mark.integration` - Integration tests (real APIs)
|
| 116 |
+
- `@pytest.mark.slow` - Slow tests
|
| 117 |
+
- `@pytest.mark.e2e` - End-to-end tests
|
| 118 |
+
|
| 119 |
+
### Writing Tests
|
| 120 |
+
|
| 121 |
+
- **TDD preferred**: Write tests first, then implementation
|
| 122 |
+
- **Location**: Place unit tests in `tests/unit/` mirroring `src/` structure
|
| 123 |
+
- **Mocking**: Use `respx` for httpx, `pytest-mock` for general mocking
|
| 124 |
+
- **Fixtures**: Add reusable fixtures to `tests/conftest.py`
|
| 125 |
+
|
| 126 |
+
Example test structure:
|
| 127 |
+
```python
|
| 128 |
+
"""Tests for search handler module."""
|
| 129 |
+
import pytest
|
| 130 |
+
from src.tools.search_handler import SearchHandler
|
| 131 |
+
|
| 132 |
+
class TestSearchHandler:
|
| 133 |
+
"""Tests for SearchHandler class."""
|
| 134 |
+
|
| 135 |
+
@pytest.mark.unit
|
| 136 |
+
def test_parallel_search_returns_results(self, mock_httpx_client):
|
| 137 |
+
"""Verify parallel search aggregates results correctly."""
|
| 138 |
+
handler = SearchHandler()
|
| 139 |
+
result = handler.search("test query")
|
| 140 |
+
assert len(result.evidence) > 0
|
| 141 |
+
```
|
| 142 |
+
|
| 143 |
+
## Code Style
|
| 144 |
+
|
| 145 |
+
### Pre-commit Hooks
|
| 146 |
+
|
| 147 |
+
Pre-commit hooks run automatically on commit:
|
| 148 |
+
- **Ruff** - Linting and formatting
|
| 149 |
+
- **MyPy** - Type checking
|
| 150 |
+
|
| 151 |
+
To run manually:
|
| 152 |
+
```bash
|
| 153 |
+
make lint # Check linting
|
| 154 |
+
make format # Auto-format code
|
| 155 |
+
make typecheck # Type checking
|
| 156 |
+
```
|
| 157 |
+
|
| 158 |
+
### Style Guidelines
|
| 159 |
+
|
| 160 |
+
1. **Type hints required** - All functions must have type annotations
|
| 161 |
+
2. **Docstrings** - Use Google-style docstrings for public APIs
|
| 162 |
+
3. **Line length** - Maximum 100 characters
|
| 163 |
+
4. **Imports** - Sorted by isort (handled by ruff)
|
| 164 |
+
|
| 165 |
+
### Code Quality Rules
|
| 166 |
+
|
| 167 |
+
We use Ruff with these rule sets:
|
| 168 |
+
- `E` - pycodestyle errors
|
| 169 |
+
- `F` - pyflakes
|
| 170 |
+
- `B` - flake8-bugbear
|
| 171 |
+
- `I` - isort
|
| 172 |
+
- `N` - pep8-naming
|
| 173 |
+
- `UP` - pyupgrade
|
| 174 |
+
- `PL` - pylint
|
| 175 |
+
- `RUF` - ruff-specific
|
| 176 |
+
|
| 177 |
+
## Submitting Changes
|
| 178 |
+
|
| 179 |
+
### Pull Request Process
|
| 180 |
+
|
| 181 |
+
1. **Ensure tests pass**: `make check`
|
| 182 |
+
2. **Update documentation** if adding features
|
| 183 |
+
3. **Create PR** against `main` branch
|
| 184 |
+
4. **Fill out the PR template** with:
|
| 185 |
+
- Summary of changes
|
| 186 |
+
- Related issues
|
| 187 |
+
- Test plan
|
| 188 |
+
5. **Wait for review** - Address any feedback
|
| 189 |
+
|
| 190 |
+
### PR Checklist
|
| 191 |
+
|
| 192 |
+
- [ ] Tests added/updated and passing
|
| 193 |
+
- [ ] `make check` passes locally
|
| 194 |
+
- [ ] Documentation updated (if applicable)
|
| 195 |
+
- [ ] Commit messages follow convention
|
| 196 |
+
- [ ] No secrets or API keys committed
|
| 197 |
+
- [ ] Changes are focused (one concern per PR)
|
| 198 |
+
|
| 199 |
+
## Documentation
|
| 200 |
+
|
| 201 |
+
### Where to Document
|
| 202 |
+
|
| 203 |
+
- **README.md** - User-facing overview and quick start
|
| 204 |
+
- **CLAUDE.md** - Developer/AI agent reference
|
| 205 |
+
- **docs/** - Detailed documentation
|
| 206 |
+
- `architecture/` - System design
|
| 207 |
+
- `development/` - Developer guides
|
| 208 |
+
- `deployment/` - Deployment instructions
|
| 209 |
+
- `reference/` - API/config reference
|
| 210 |
+
|
| 211 |
+
### Documentation Standards
|
| 212 |
+
|
| 213 |
+
- Use clear, concise language
|
| 214 |
+
- Include code examples where helpful
|
| 215 |
+
- Keep diagrams updated (Mermaid format)
|
| 216 |
+
- Link to related documentation
|
| 217 |
+
|
| 218 |
+
## Getting Help
|
| 219 |
+
|
| 220 |
+
- **Issues**: Open a GitHub issue for bugs or feature requests
|
| 221 |
+
- **Discussions**: Use GitHub Discussions for questions
|
| 222 |
+
|
| 223 |
+
## Recognition
|
| 224 |
+
|
| 225 |
+
Contributors will be recognized in release notes. Thank you for helping make DeepBoner better!
|
| 226 |
+
|
| 227 |
+
---
|
| 228 |
+
|
| 229 |
+
*"Peer-reviewed contributions only. We take evidence-based code very seriously."* π¬
|
|
@@ -0,0 +1,125 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Security Policy
|
| 2 |
+
|
| 3 |
+
## Supported Versions
|
| 4 |
+
|
| 5 |
+
| Version | Supported |
|
| 6 |
+
| ------- | ------------------ |
|
| 7 |
+
| 0.1.x | :white_check_mark: |
|
| 8 |
+
|
| 9 |
+
## Reporting a Vulnerability
|
| 10 |
+
|
| 11 |
+
We take security seriously. If you discover a security vulnerability in DeepBoner, please report it responsibly.
|
| 12 |
+
|
| 13 |
+
### How to Report
|
| 14 |
+
|
| 15 |
+
1. **DO NOT** open a public GitHub issue for security vulnerabilities
|
| 16 |
+
2. Email security concerns to the repository maintainers via GitHub's private vulnerability reporting
|
| 17 |
+
3. Or use GitHub's Security Advisory feature: **Security** tab > **Report a vulnerability**
|
| 18 |
+
|
| 19 |
+
### What to Include
|
| 20 |
+
|
| 21 |
+
- Description of the vulnerability
|
| 22 |
+
- Steps to reproduce
|
| 23 |
+
- Potential impact
|
| 24 |
+
- Suggested fix (if any)
|
| 25 |
+
|
| 26 |
+
### Response Timeline
|
| 27 |
+
|
| 28 |
+
- **Acknowledgment**: Within 48 hours
|
| 29 |
+
- **Initial assessment**: Within 7 days
|
| 30 |
+
- **Fix timeline**: Depends on severity
|
| 31 |
+
- Critical: Within 48 hours
|
| 32 |
+
- High: Within 7 days
|
| 33 |
+
- Medium: Within 30 days
|
| 34 |
+
- Low: Next release cycle
|
| 35 |
+
|
| 36 |
+
## Security Measures
|
| 37 |
+
|
| 38 |
+
### API Key Handling
|
| 39 |
+
|
| 40 |
+
- API keys are loaded from environment variables only
|
| 41 |
+
- Keys are never logged or exposed in error messages
|
| 42 |
+
- `.env` files are gitignored
|
| 43 |
+
- No hardcoded credentials in source code
|
| 44 |
+
|
| 45 |
+
### Dependency Security
|
| 46 |
+
|
| 47 |
+
- Regular dependency audits via `pip-audit`
|
| 48 |
+
- Security scanning with `bandit` in CI
|
| 49 |
+
- Pinned dependencies for reproducibility
|
| 50 |
+
- Known CVE fixes:
|
| 51 |
+
- `mcp>=1.23.0` - Fixes GHSA-9h52-p55h-vw2f
|
| 52 |
+
- `langgraph-checkpoint-sqlite>=3.0.0` - Fixes GHSA-wwqv-p2pp-99h5
|
| 53 |
+
- `urllib3>=2.6.0` - Fixes GHSA-gm62-xv2j-4w53 and GHSA-2xpw-w6gg-jr37
|
| 54 |
+
|
| 55 |
+
### External API Security
|
| 56 |
+
|
| 57 |
+
- HTTPS enforced for all external API calls
|
| 58 |
+
- Rate limiting prevents abuse
|
| 59 |
+
- No sensitive data sent to external services (only search queries)
|
| 60 |
+
|
| 61 |
+
### Input Validation
|
| 62 |
+
|
| 63 |
+
- Pydantic models for strict input validation
|
| 64 |
+
- Query sanitization before external API calls
|
| 65 |
+
- Length limits on user inputs
|
| 66 |
+
|
| 67 |
+
## Security Best Practices for Users
|
| 68 |
+
|
| 69 |
+
### API Keys
|
| 70 |
+
|
| 71 |
+
1. Never commit `.env` files
|
| 72 |
+
2. Use environment variables in production
|
| 73 |
+
3. Rotate keys periodically
|
| 74 |
+
4. Use minimal permissions (read-only where possible)
|
| 75 |
+
|
| 76 |
+
### Deployment
|
| 77 |
+
|
| 78 |
+
1. Use the provided Docker image for consistency
|
| 79 |
+
2. Keep dependencies updated
|
| 80 |
+
3. Monitor for security advisories
|
| 81 |
+
4. Use HTTPS in production
|
| 82 |
+
|
| 83 |
+
### HuggingFace Spaces
|
| 84 |
+
|
| 85 |
+
1. Use Secrets (not public variables) for API keys
|
| 86 |
+
2. The HF_TOKEN is used server-side only
|
| 87 |
+
3. Users don't need their own tokens
|
| 88 |
+
|
| 89 |
+
## Known Security Considerations
|
| 90 |
+
|
| 91 |
+
### Third-Party APIs
|
| 92 |
+
|
| 93 |
+
DeepBoner queries external biomedical databases:
|
| 94 |
+
- PubMed (NCBI)
|
| 95 |
+
- ClinicalTrials.gov
|
| 96 |
+
- Europe PMC
|
| 97 |
+
- OpenAlex
|
| 98 |
+
|
| 99 |
+
These are trusted public APIs, but:
|
| 100 |
+
- Query content is visible to these services
|
| 101 |
+
- Rate limits apply
|
| 102 |
+
- Availability depends on upstream services
|
| 103 |
+
|
| 104 |
+
### LLM Providers
|
| 105 |
+
|
| 106 |
+
- OpenAI and HuggingFace process your queries
|
| 107 |
+
- Review their privacy policies if handling sensitive research
|
| 108 |
+
- Consider on-premise alternatives for sensitive use cases
|
| 109 |
+
|
| 110 |
+
### Local Data
|
| 111 |
+
|
| 112 |
+
- ChromaDB stores embeddings locally
|
| 113 |
+
- Default path: `./chroma_db/`
|
| 114 |
+
- Contains processed search results (not raw user data)
|
| 115 |
+
- Secure or delete when decommissioning
|
| 116 |
+
|
| 117 |
+
## Security Updates
|
| 118 |
+
|
| 119 |
+
Security updates will be released as patch versions (e.g., 0.1.1) and announced via:
|
| 120 |
+
- GitHub Security Advisories
|
| 121 |
+
- Release notes
|
| 122 |
+
|
| 123 |
+
---
|
| 124 |
+
|
| 125 |
+
*"Security is rock solid. We take evidence-based security very seriously."* π
|
|
@@ -0,0 +1,129 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# DeepBoner Documentation
|
| 2 |
+
|
| 3 |
+
Welcome to the DeepBoner documentation. This directory contains comprehensive documentation for developers, contributors, and operators.
|
| 4 |
+
|
| 5 |
+
## Quick Navigation
|
| 6 |
+
|
| 7 |
+
| Need to... | Go to... |
|
| 8 |
+
|------------|----------|
|
| 9 |
+
| Get started quickly | [Getting Started](getting-started/installation.md) |
|
| 10 |
+
| Understand the architecture | [Architecture Overview](architecture/overview.md) |
|
| 11 |
+
| Set up for development | [Development Guide](development/testing.md) |
|
| 12 |
+
| Deploy the application | [Deployment Guide](deployment/docker.md) |
|
| 13 |
+
| Look up configuration | [Reference](reference/configuration.md) |
|
| 14 |
+
| Track technical debt | [Technical Debt](technical-debt/index.md) |
|
| 15 |
+
|
| 16 |
+
## Documentation Structure
|
| 17 |
+
|
| 18 |
+
```
|
| 19 |
+
docs/
|
| 20 |
+
βββ README.md # This file - documentation index
|
| 21 |
+
β
|
| 22 |
+
βββ getting-started/ # Onboarding documentation
|
| 23 |
+
β βββ installation.md # Installation guide
|
| 24 |
+
β βββ quickstart.md # 5-minute quickstart
|
| 25 |
+
β βββ configuration.md # Configuration guide
|
| 26 |
+
β βββ troubleshooting.md # Common issues and solutions
|
| 27 |
+
β
|
| 28 |
+
βββ architecture/ # System design documentation
|
| 29 |
+
β βββ overview.md # High-level architecture
|
| 30 |
+
β βββ system-registry.md # Service registry (canonical wiring)
|
| 31 |
+
β βββ workflow-diagrams.md # Visual workflow diagrams
|
| 32 |
+
β βββ component-inventory.md # Complete component catalog
|
| 33 |
+
β βββ data-models.md # Pydantic model documentation
|
| 34 |
+
β βββ exception-hierarchy.md # Exception types and handling
|
| 35 |
+
β
|
| 36 |
+
βββ development/ # Developer guides
|
| 37 |
+
β βββ testing.md # Testing strategy and patterns
|
| 38 |
+
β βββ code-style.md # Code style and conventions
|
| 39 |
+
β βββ release-process.md # Release workflow
|
| 40 |
+
β
|
| 41 |
+
βββ deployment/ # Deployment documentation
|
| 42 |
+
β βββ docker.md # Docker deployment
|
| 43 |
+
β βββ huggingface-spaces.md # HuggingFace Spaces deployment
|
| 44 |
+
β βββ mcp-integration.md # MCP server setup
|
| 45 |
+
β
|
| 46 |
+
βββ technical-debt/ # Known issues and improvements
|
| 47 |
+
β βββ index.md # Technical debt overview
|
| 48 |
+
β βββ debt-registry.md # Itemized debt tracking
|
| 49 |
+
β
|
| 50 |
+
βββ reference/ # API and configuration reference
|
| 51 |
+
β βββ configuration.md # All configuration options
|
| 52 |
+
β βββ environment-variables.md # Environment variable reference
|
| 53 |
+
β
|
| 54 |
+
βββ bugs/ # Bug tracking (existing)
|
| 55 |
+
β βββ active-bugs.md
|
| 56 |
+
β βββ p3-progress-bar-positioning.md
|
| 57 |
+
β
|
| 58 |
+
βββ decisions/ # Architecture Decision Records (existing)
|
| 59 |
+
β βββ 2025-11-27-pr55-evaluation.md
|
| 60 |
+
β
|
| 61 |
+
βββ future-roadmap/ # Future feature specs (existing)
|
| 62 |
+
βββ 16-pubmed-fulltext.md
|
| 63 |
+
```
|
| 64 |
+
|
| 65 |
+
## Documentation Standards
|
| 66 |
+
|
| 67 |
+
### File Naming
|
| 68 |
+
- Use **kebab-case** for all filenames (e.g., `getting-started.md`)
|
| 69 |
+
- Keep names descriptive but concise
|
| 70 |
+
|
| 71 |
+
### Content Guidelines
|
| 72 |
+
- Start each document with a clear title and purpose
|
| 73 |
+
- Include a table of contents for longer documents
|
| 74 |
+
- Use Mermaid diagrams for visual documentation
|
| 75 |
+
- Link to related documentation
|
| 76 |
+
- Keep content current - update when code changes
|
| 77 |
+
|
| 78 |
+
### Markdown Conventions
|
| 79 |
+
- Use ATX-style headers (`#`, `##`, etc.)
|
| 80 |
+
- Code blocks with language specification
|
| 81 |
+
- Tables for structured data
|
| 82 |
+
- Admonitions for warnings/notes (where supported)
|
| 83 |
+
|
| 84 |
+
## Key Documents
|
| 85 |
+
|
| 86 |
+
### For New Developers
|
| 87 |
+
1. [Installation](getting-started/installation.md) - Set up your environment
|
| 88 |
+
2. [Quickstart](getting-started/quickstart.md) - Run your first query
|
| 89 |
+
3. [Architecture Overview](architecture/overview.md) - Understand the system
|
| 90 |
+
4. [Testing](development/testing.md) - Run and write tests
|
| 91 |
+
|
| 92 |
+
### For Contributors
|
| 93 |
+
1. [CONTRIBUTING.md](../CONTRIBUTING.md) - Contribution guidelines
|
| 94 |
+
2. [Code Style](development/code-style.md) - Style conventions
|
| 95 |
+
3. [Testing](development/testing.md) - Testing requirements
|
| 96 |
+
|
| 97 |
+
### For Operators
|
| 98 |
+
1. [Docker Deployment](deployment/docker.md) - Container deployment
|
| 99 |
+
2. [HuggingFace Spaces](deployment/huggingface-spaces.md) - Cloud deployment
|
| 100 |
+
3. [Configuration Reference](reference/configuration.md) - All options
|
| 101 |
+
|
| 102 |
+
### For Understanding the Codebase
|
| 103 |
+
1. [Component Inventory](architecture/component-inventory.md) - All modules
|
| 104 |
+
2. [Data Models](architecture/data-models.md) - Core types
|
| 105 |
+
3. [System Registry](architecture/system-registry.md) - Service wiring
|
| 106 |
+
4. [Technical Debt](technical-debt/index.md) - Known issues
|
| 107 |
+
|
| 108 |
+
## Related Documentation
|
| 109 |
+
|
| 110 |
+
- **[README.md](../README.md)** - Project overview and quick start
|
| 111 |
+
- **[CLAUDE.md](../CLAUDE.md)** - AI agent developer reference
|
| 112 |
+
- **[CHANGELOG.md](../CHANGELOG.md)** - Release history
|
| 113 |
+
- **[SECURITY.md](../SECURITY.md)** - Security policy
|
| 114 |
+
- **[CODE_OF_CONDUCT.md](../CODE_OF_CONDUCT.md)** - Community guidelines
|
| 115 |
+
|
| 116 |
+
## Contributing to Documentation
|
| 117 |
+
|
| 118 |
+
Documentation is code. Please:
|
| 119 |
+
|
| 120 |
+
1. Keep docs updated when changing related code
|
| 121 |
+
2. Follow the naming and style conventions
|
| 122 |
+
3. Test links before committing
|
| 123 |
+
4. Add new documents to this index
|
| 124 |
+
|
| 125 |
+
See [CONTRIBUTING.md](../CONTRIBUTING.md) for full guidelines.
|
| 126 |
+
|
| 127 |
+
---
|
| 128 |
+
|
| 129 |
+
*"Well-documented boners only. We take evidence-based documentation very seriously."* π
|
|
@@ -0,0 +1,458 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Component Inventory
|
| 2 |
+
|
| 3 |
+
> **Last Updated**: 2025-12-06
|
| 4 |
+
|
| 5 |
+
This document provides a complete catalog of all components in the DeepBoner codebase.
|
| 6 |
+
|
| 7 |
+
## Source Code Statistics
|
| 8 |
+
|
| 9 |
+
| Category | Count |
|
| 10 |
+
|----------|-------|
|
| 11 |
+
| Python files in `src/` | ~67 |
|
| 12 |
+
| Python files in `tests/` | ~76 |
|
| 13 |
+
| Total modules | ~143 |
|
| 14 |
+
|
| 15 |
+
## Directory Structure
|
| 16 |
+
|
| 17 |
+
```
|
| 18 |
+
src/
|
| 19 |
+
βββ app.py # Gradio UI entry point
|
| 20 |
+
βββ mcp_tools.py # MCP server tool wrappers
|
| 21 |
+
βββ orchestrators/ # Research orchestration
|
| 22 |
+
βββ clients/ # LLM backend adapters
|
| 23 |
+
βββ agents/ # Multi-agent components
|
| 24 |
+
βββ agent_factory/ # Agent creation
|
| 25 |
+
βββ tools/ # Search tool implementations
|
| 26 |
+
βββ services/ # Cross-cutting services
|
| 27 |
+
βββ prompts/ # LLM prompt templates
|
| 28 |
+
βββ utils/ # Shared utilities
|
| 29 |
+
βββ config/ # Domain configuration
|
| 30 |
+
βββ middleware/ # Processing middleware
|
| 31 |
+
βββ state/ # State management
|
| 32 |
+
```
|
| 33 |
+
|
| 34 |
+
---
|
| 35 |
+
|
| 36 |
+
## Core Entry Points
|
| 37 |
+
|
| 38 |
+
### `src/app.py`
|
| 39 |
+
**Purpose:** Main application entry point
|
| 40 |
+
|
| 41 |
+
| Component | Type | Description |
|
| 42 |
+
|-----------|------|-------------|
|
| 43 |
+
| `create_demo()` | Function | Creates Gradio interface |
|
| 44 |
+
| `main()` | Function | Application entry point |
|
| 45 |
+
|
| 46 |
+
**Dependencies:** Gradio, orchestrators, config
|
| 47 |
+
|
| 48 |
+
### `src/mcp_tools.py`
|
| 49 |
+
**Purpose:** MCP (Model Context Protocol) tool wrappers
|
| 50 |
+
|
| 51 |
+
| Component | Type | Description |
|
| 52 |
+
|-----------|------|-------------|
|
| 53 |
+
| `search_pubmed()` | Tool | PubMed search wrapper |
|
| 54 |
+
| `search_clinical_trials()` | Tool | ClinicalTrials.gov wrapper |
|
| 55 |
+
| `search_europepmc()` | Tool | Europe PMC wrapper |
|
| 56 |
+
| `search_all_sources()` | Tool | Multi-source search |
|
| 57 |
+
|
| 58 |
+
---
|
| 59 |
+
|
| 60 |
+
## Orchestrators (`src/orchestrators/`)
|
| 61 |
+
|
| 62 |
+
### `advanced.py`
|
| 63 |
+
**Purpose:** Main multi-agent orchestrator using Microsoft Agent Framework
|
| 64 |
+
|
| 65 |
+
| Component | Type | Description |
|
| 66 |
+
|-----------|------|-------------|
|
| 67 |
+
| `AdvancedOrchestrator` | Class | Primary research orchestrator |
|
| 68 |
+
| `run()` | Method | Execute research workflow |
|
| 69 |
+
| `_search_phase()` | Method | Search execution |
|
| 70 |
+
| `_judge_phase()` | Method | Evidence evaluation |
|
| 71 |
+
| `_synthesize_phase()` | Method | Report generation |
|
| 72 |
+
|
| 73 |
+
**Framework:** Microsoft Agent Framework (agent-framework-core)
|
| 74 |
+
|
| 75 |
+
### `factory.py`
|
| 76 |
+
**Purpose:** Orchestrator selection
|
| 77 |
+
|
| 78 |
+
| Component | Type | Description |
|
| 79 |
+
|-----------|------|-------------|
|
| 80 |
+
| `OrchestratorFactory` | Class | Creates appropriate orchestrator |
|
| 81 |
+
| `create()` | Method | Factory method |
|
| 82 |
+
|
| 83 |
+
### `base.py`
|
| 84 |
+
**Purpose:** Base orchestrator interface
|
| 85 |
+
|
| 86 |
+
| Component | Type | Description |
|
| 87 |
+
|-----------|------|-------------|
|
| 88 |
+
| `BaseOrchestrator` | ABC | Abstract base class |
|
| 89 |
+
|
| 90 |
+
### `langgraph_orchestrator.py`
|
| 91 |
+
**Purpose:** LangGraph-based workflow (experimental)
|
| 92 |
+
|
| 93 |
+
| Component | Type | Description |
|
| 94 |
+
|-----------|------|-------------|
|
| 95 |
+
| `LangGraphOrchestrator` | Class | Workflow state machine |
|
| 96 |
+
|
| 97 |
+
### `hierarchical.py`
|
| 98 |
+
**Purpose:** Hierarchical agent coordination
|
| 99 |
+
|
| 100 |
+
| Component | Type | Description |
|
| 101 |
+
|-----------|------|-------------|
|
| 102 |
+
| `HierarchicalOrchestrator` | Class | Manager-agent hierarchy |
|
| 103 |
+
|
| 104 |
+
---
|
| 105 |
+
|
| 106 |
+
## LLM Clients (`src/clients/`)
|
| 107 |
+
|
| 108 |
+
### `factory.py`
|
| 109 |
+
**Purpose:** Auto-select LLM backend
|
| 110 |
+
|
| 111 |
+
| Component | Type | Description |
|
| 112 |
+
|-----------|------|-------------|
|
| 113 |
+
| `get_chat_client()` | Function | Returns appropriate client |
|
| 114 |
+
|
| 115 |
+
**Selection Logic:**
|
| 116 |
+
```python
|
| 117 |
+
if settings.has_openai_key:
|
| 118 |
+
return OpenAIChatClient()
|
| 119 |
+
else:
|
| 120 |
+
return HuggingFaceChatClient()
|
| 121 |
+
```
|
| 122 |
+
|
| 123 |
+
### `huggingface.py`
|
| 124 |
+
**Purpose:** HuggingFace Inference API adapter
|
| 125 |
+
|
| 126 |
+
| Component | Type | Description |
|
| 127 |
+
|-----------|------|-------------|
|
| 128 |
+
| `HuggingFaceChatClient` | Class | Free tier LLM client |
|
| 129 |
+
| `chat_completion()` | Method | Generate completion |
|
| 130 |
+
|
| 131 |
+
**Model:** Qwen 2.5 7B Instruct (free tier)
|
| 132 |
+
|
| 133 |
+
### `base.py`
|
| 134 |
+
**Purpose:** Client interface
|
| 135 |
+
|
| 136 |
+
| Component | Type | Description |
|
| 137 |
+
|-----------|------|-------------|
|
| 138 |
+
| `BaseChatClient` | ABC | Client interface |
|
| 139 |
+
|
| 140 |
+
### `providers.py`
|
| 141 |
+
**Purpose:** Provider implementations
|
| 142 |
+
|
| 143 |
+
### `registry.py`
|
| 144 |
+
**Purpose:** Provider registration
|
| 145 |
+
|
| 146 |
+
---
|
| 147 |
+
|
| 148 |
+
## Agents (`src/agents/`)
|
| 149 |
+
|
| 150 |
+
### `search_agent.py`
|
| 151 |
+
| Component | Type | Description |
|
| 152 |
+
|-----------|------|-------------|
|
| 153 |
+
| `SearchAgent` | Class | Evidence gathering agent |
|
| 154 |
+
|
| 155 |
+
### `judge_agent.py`
|
| 156 |
+
| Component | Type | Description |
|
| 157 |
+
|-----------|------|-------------|
|
| 158 |
+
| `JudgeAgent` | Class | Evidence evaluation |
|
| 159 |
+
|
| 160 |
+
### `judge_agent_llm.py`
|
| 161 |
+
| Component | Type | Description |
|
| 162 |
+
|-----------|------|-------------|
|
| 163 |
+
| `LLMJudgeAgent` | Class | LLM-based judge implementation |
|
| 164 |
+
|
| 165 |
+
### `report_agent.py`
|
| 166 |
+
| Component | Type | Description |
|
| 167 |
+
|-----------|------|-------------|
|
| 168 |
+
| `ReportAgent` | Class | Report synthesis |
|
| 169 |
+
|
| 170 |
+
### `retrieval_agent.py`
|
| 171 |
+
| Component | Type | Description |
|
| 172 |
+
|-----------|------|-------------|
|
| 173 |
+
| `RetrievalAgent` | Class | Evidence retrieval coordination |
|
| 174 |
+
|
| 175 |
+
### `hypothesis_agent.py`
|
| 176 |
+
| Component | Type | Description |
|
| 177 |
+
|-----------|------|-------------|
|
| 178 |
+
| `HypothesisAgent` | Class | Mechanistic hypothesis generation |
|
| 179 |
+
|
| 180 |
+
### `magentic_agents.py`
|
| 181 |
+
| Component | Type | Description |
|
| 182 |
+
|-----------|------|-------------|
|
| 183 |
+
| Multi-agent mode | Module | Microsoft Agent Framework integration |
|
| 184 |
+
|
| 185 |
+
### `state.py`
|
| 186 |
+
| Component | Type | Description |
|
| 187 |
+
|-----------|------|-------------|
|
| 188 |
+
| Agent state models | Module | Shared state definitions |
|
| 189 |
+
|
| 190 |
+
### `tools.py`
|
| 191 |
+
| Component | Type | Description |
|
| 192 |
+
|-----------|------|-------------|
|
| 193 |
+
| Tool bindings | Module | Agent tool configuration |
|
| 194 |
+
|
| 195 |
+
---
|
| 196 |
+
|
| 197 |
+
## Graph Workflow (`src/agents/graph/`)
|
| 198 |
+
|
| 199 |
+
### `workflow.py`
|
| 200 |
+
| Component | Type | Description |
|
| 201 |
+
|-----------|------|-------------|
|
| 202 |
+
| `create_workflow()` | Function | LangGraph workflow builder |
|
| 203 |
+
|
| 204 |
+
### `nodes.py`
|
| 205 |
+
| Component | Type | Description |
|
| 206 |
+
|-----------|------|-------------|
|
| 207 |
+
| `search_node()` | Function | Search workflow node |
|
| 208 |
+
| `judge_node()` | Function | Judge workflow node |
|
| 209 |
+
| `report_node()` | Function | Report workflow node |
|
| 210 |
+
|
| 211 |
+
### `state.py`
|
| 212 |
+
| Component | Type | Description |
|
| 213 |
+
|-----------|------|-------------|
|
| 214 |
+
| `WorkflowState` | Class | LangGraph state schema |
|
| 215 |
+
|
| 216 |
+
---
|
| 217 |
+
|
| 218 |
+
## Agent Factory (`src/agent_factory/`)
|
| 219 |
+
|
| 220 |
+
### `judges.py`
|
| 221 |
+
**Purpose:** Evidence quality judgment
|
| 222 |
+
|
| 223 |
+
| Component | Type | Description |
|
| 224 |
+
|-----------|------|-------------|
|
| 225 |
+
| `create_judge()` | Function | Judge agent factory |
|
| 226 |
+
| `JudgeResult` | Model | Assessment output |
|
| 227 |
+
|
| 228 |
+
**Framework:** Pydantic AI
|
| 229 |
+
|
| 230 |
+
### `agents.py`
|
| 231 |
+
| Component | Type | Description |
|
| 232 |
+
|-----------|------|-------------|
|
| 233 |
+
| Agent creation | Module | Factory functions |
|
| 234 |
+
|
| 235 |
+
---
|
| 236 |
+
|
| 237 |
+
## Search Tools (`src/tools/`)
|
| 238 |
+
|
| 239 |
+
### `pubmed.py`
|
| 240 |
+
| Component | Type | Description |
|
| 241 |
+
|-----------|------|-------------|
|
| 242 |
+
| `PubMedTool` | Class | NCBI E-utilities client |
|
| 243 |
+
| `search()` | Method | Execute search |
|
| 244 |
+
|
| 245 |
+
**API:** PubMed E-utilities (eutils.ncbi.nlm.nih.gov)
|
| 246 |
+
|
| 247 |
+
### `clinicaltrials.py`
|
| 248 |
+
| Component | Type | Description |
|
| 249 |
+
|-----------|------|-------------|
|
| 250 |
+
| `ClinicalTrialsTool` | Class | ClinicalTrials.gov client |
|
| 251 |
+
| `search()` | Method | Execute search |
|
| 252 |
+
|
| 253 |
+
**API:** ClinicalTrials.gov API (uses `requests` due to WAF blocking httpx)
|
| 254 |
+
|
| 255 |
+
### `europepmc.py`
|
| 256 |
+
| Component | Type | Description |
|
| 257 |
+
|-----------|------|-------------|
|
| 258 |
+
| `EuropePMCTool` | Class | Europe PMC client |
|
| 259 |
+
| `search()` | Method | Execute search |
|
| 260 |
+
|
| 261 |
+
**API:** Europe PMC API
|
| 262 |
+
|
| 263 |
+
### `openalex.py`
|
| 264 |
+
| Component | Type | Description |
|
| 265 |
+
|-----------|------|-------------|
|
| 266 |
+
| `OpenAlexTool` | Class | OpenAlex client |
|
| 267 |
+
| `search()` | Method | Execute search |
|
| 268 |
+
|
| 269 |
+
**API:** OpenAlex API
|
| 270 |
+
|
| 271 |
+
### `search_handler.py`
|
| 272 |
+
| Component | Type | Description |
|
| 273 |
+
|-----------|------|-------------|
|
| 274 |
+
| `SearchHandler` | Class | Scatter-gather orchestration |
|
| 275 |
+
| `search_all()` | Method | Parallel multi-source search |
|
| 276 |
+
|
| 277 |
+
### `query_utils.py`
|
| 278 |
+
| Component | Type | Description |
|
| 279 |
+
|-----------|------|-------------|
|
| 280 |
+
| Query utilities | Module | Query refinement and expansion |
|
| 281 |
+
|
| 282 |
+
### `rate_limiter.py`
|
| 283 |
+
| Component | Type | Description |
|
| 284 |
+
|-----------|------|-------------|
|
| 285 |
+
| `RateLimiter` | Class | API rate limiting |
|
| 286 |
+
|
| 287 |
+
### `base.py`
|
| 288 |
+
| Component | Type | Description |
|
| 289 |
+
|-----------|------|-------------|
|
| 290 |
+
| `BaseSearchTool` | ABC | Search tool interface |
|
| 291 |
+
|
| 292 |
+
### `web_search.py`
|
| 293 |
+
| Component | Type | Description |
|
| 294 |
+
|-----------|------|-------------|
|
| 295 |
+
| Web search | Module | DuckDuckGo integration |
|
| 296 |
+
|
| 297 |
+
---
|
| 298 |
+
|
| 299 |
+
## Services (`src/services/`)
|
| 300 |
+
|
| 301 |
+
### `embeddings.py`
|
| 302 |
+
| Component | Type | Description |
|
| 303 |
+
|-----------|------|-------------|
|
| 304 |
+
| `EmbeddingService` | Class | Local embedding service |
|
| 305 |
+
| `embed()` | Method | Generate embeddings |
|
| 306 |
+
| `deduplicate()` | Method | Cross-source deduplication |
|
| 307 |
+
|
| 308 |
+
**Stack:** sentence-transformers + ChromaDB
|
| 309 |
+
|
| 310 |
+
### `llamaindex_rag.py`
|
| 311 |
+
| Component | Type | Description |
|
| 312 |
+
|-----------|------|-------------|
|
| 313 |
+
| `LlamaIndexRAG` | Class | Premium RAG service |
|
| 314 |
+
|
| 315 |
+
**Stack:** LlamaIndex + OpenAI embeddings + ChromaDB
|
| 316 |
+
|
| 317 |
+
### `embedding_protocol.py`
|
| 318 |
+
| Component | Type | Description |
|
| 319 |
+
|-----------|------|-------------|
|
| 320 |
+
| `EmbeddingProtocol` | Protocol | Interface for embedding services |
|
| 321 |
+
|
| 322 |
+
### `research_memory.py`
|
| 323 |
+
| Component | Type | Description |
|
| 324 |
+
|-----------|------|-------------|
|
| 325 |
+
| `ResearchMemory` | Class | Shared research state |
|
| 326 |
+
|
| 327 |
+
---
|
| 328 |
+
|
| 329 |
+
## Utilities (`src/utils/`)
|
| 330 |
+
|
| 331 |
+
### `config.py`
|
| 332 |
+
| Component | Type | Description |
|
| 333 |
+
|-----------|------|-------------|
|
| 334 |
+
| `Settings` | Class | Pydantic Settings configuration |
|
| 335 |
+
| `settings` | Instance | Global settings singleton |
|
| 336 |
+
| `get_settings()` | Function | Settings factory |
|
| 337 |
+
| `configure_logging()` | Function | Logging setup |
|
| 338 |
+
|
| 339 |
+
### `models.py`
|
| 340 |
+
| Component | Type | Description |
|
| 341 |
+
|-----------|------|-------------|
|
| 342 |
+
| `Evidence` | Model | Evidence with citation |
|
| 343 |
+
| `Citation` | Model | Source citation |
|
| 344 |
+
| `SearchResult` | Model | Search response |
|
| 345 |
+
| `JudgeAssessment` | Model | Judge evaluation |
|
| 346 |
+
| `ResearchReport` | Model | Final report |
|
| 347 |
+
| `AgentEvent` | Model | UI streaming events |
|
| 348 |
+
|
| 349 |
+
See [Data Models](data-models.md) for complete documentation.
|
| 350 |
+
|
| 351 |
+
### `exceptions.py`
|
| 352 |
+
| Component | Type | Description |
|
| 353 |
+
|-----------|------|-------------|
|
| 354 |
+
| `DeepBonerError` | Exception | Base exception |
|
| 355 |
+
| `SearchError` | Exception | Search failures |
|
| 356 |
+
| `JudgeError` | Exception | Judge failures |
|
| 357 |
+
| `ConfigurationError` | Exception | Config errors |
|
| 358 |
+
| `RateLimitError` | Exception | Rate limits |
|
| 359 |
+
|
| 360 |
+
See [Exception Hierarchy](exception-hierarchy.md) for details.
|
| 361 |
+
|
| 362 |
+
### `service_loader.py`
|
| 363 |
+
| Component | Type | Description |
|
| 364 |
+
|-----------|------|-------------|
|
| 365 |
+
| Service loading | Module | Tiered service selection |
|
| 366 |
+
|
| 367 |
+
### `citation_validator.py`
|
| 368 |
+
| Component | Type | Description |
|
| 369 |
+
|-----------|------|-------------|
|
| 370 |
+
| Citation validation | Module | URL verification |
|
| 371 |
+
|
| 372 |
+
### `text_utils.py`
|
| 373 |
+
| Component | Type | Description |
|
| 374 |
+
|-----------|------|-------------|
|
| 375 |
+
| Text utilities | Module | Text processing |
|
| 376 |
+
|
| 377 |
+
### `parsers.py`
|
| 378 |
+
| Component | Type | Description |
|
| 379 |
+
|-----------|------|-------------|
|
| 380 |
+
| Response parsing | Module | LLM output parsing |
|
| 381 |
+
|
| 382 |
+
### `dataloaders.py`
|
| 383 |
+
| Component | Type | Description |
|
| 384 |
+
|-----------|------|-------------|
|
| 385 |
+
| Data loading | Module | Data loading utilities |
|
| 386 |
+
|
| 387 |
+
---
|
| 388 |
+
|
| 389 |
+
## Configuration (`src/config/`)
|
| 390 |
+
|
| 391 |
+
### `domain.py`
|
| 392 |
+
| Component | Type | Description |
|
| 393 |
+
|-----------|------|-------------|
|
| 394 |
+
| `ResearchDomain` | Enum | Research domain types |
|
| 395 |
+
|
| 396 |
+
---
|
| 397 |
+
|
| 398 |
+
## Prompts (`src/prompts/`)
|
| 399 |
+
|
| 400 |
+
| File | Purpose |
|
| 401 |
+
|------|---------|
|
| 402 |
+
| `search.py` | Query refinement prompts |
|
| 403 |
+
| `judge.py` | Evidence assessment prompts |
|
| 404 |
+
| `hypothesis.py` | Hypothesis generation prompts |
|
| 405 |
+
| `synthesis.py` | Evidence synthesis prompts |
|
| 406 |
+
| `report.py` | Report generation prompts |
|
| 407 |
+
|
| 408 |
+
---
|
| 409 |
+
|
| 410 |
+
## Middleware (`src/middleware/`)
|
| 411 |
+
|
| 412 |
+
### `sub_iteration.py`
|
| 413 |
+
| Component | Type | Description |
|
| 414 |
+
|-----------|------|-------------|
|
| 415 |
+
| Sub-iteration | Module | Nested iteration logic |
|
| 416 |
+
|
| 417 |
+
---
|
| 418 |
+
|
| 419 |
+
## Reserved Directories
|
| 420 |
+
|
| 421 |
+
These directories exist but are placeholders for future features:
|
| 422 |
+
|
| 423 |
+
| Directory | Purpose |
|
| 424 |
+
|-----------|---------|
|
| 425 |
+
| `src/database_services/` | Future database services |
|
| 426 |
+
| `src/retrieval_factory/` | Future retrieval configuration |
|
| 427 |
+
|
| 428 |
+
---
|
| 429 |
+
|
| 430 |
+
## Test Structure
|
| 431 |
+
|
| 432 |
+
```
|
| 433 |
+
tests/
|
| 434 |
+
βββ conftest.py # Shared fixtures
|
| 435 |
+
βββ unit/ # Unit tests (mocked)
|
| 436 |
+
β βββ orchestrators/
|
| 437 |
+
β βββ agents/
|
| 438 |
+
β βββ clients/
|
| 439 |
+
β βββ tools/
|
| 440 |
+
β βββ services/
|
| 441 |
+
β βββ utils/
|
| 442 |
+
β βββ prompts/
|
| 443 |
+
β βββ agent_factory/
|
| 444 |
+
β βββ config/
|
| 445 |
+
β βββ graph/
|
| 446 |
+
β βββ mcp/
|
| 447 |
+
βββ integration/ # Integration tests (real APIs)
|
| 448 |
+
βββ e2e/ # End-to-end tests
|
| 449 |
+
```
|
| 450 |
+
|
| 451 |
+
---
|
| 452 |
+
|
| 453 |
+
## Related Documentation
|
| 454 |
+
|
| 455 |
+
- [Architecture Overview](overview.md)
|
| 456 |
+
- [Data Models](data-models.md)
|
| 457 |
+
- [Exception Hierarchy](exception-hierarchy.md)
|
| 458 |
+
- [System Registry](system-registry.md)
|
|
@@ -0,0 +1,342 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Data Models Reference
|
| 2 |
+
|
| 3 |
+
> **Last Updated**: 2025-12-06
|
| 4 |
+
|
| 5 |
+
This document describes all Pydantic models used in DeepBoner.
|
| 6 |
+
|
| 7 |
+
## Location
|
| 8 |
+
|
| 9 |
+
All core models are defined in `src/utils/models.py`.
|
| 10 |
+
|
| 11 |
+
## Type Definitions
|
| 12 |
+
|
| 13 |
+
### SourceName
|
| 14 |
+
|
| 15 |
+
```python
|
| 16 |
+
SourceName = Literal["pubmed", "clinicaltrials", "europepmc", "preprint", "openalex", "web"]
|
| 17 |
+
```
|
| 18 |
+
|
| 19 |
+
Centralized source type. Add new sources here when integrating new databases.
|
| 20 |
+
|
| 21 |
+
---
|
| 22 |
+
|
| 23 |
+
## Core Models
|
| 24 |
+
|
| 25 |
+
### Citation
|
| 26 |
+
|
| 27 |
+
Represents a citation to a source document.
|
| 28 |
+
|
| 29 |
+
```python
|
| 30 |
+
class Citation(BaseModel):
|
| 31 |
+
source: SourceName # Where this came from
|
| 32 |
+
title: str # Title (1-500 chars)
|
| 33 |
+
url: str # URL to source
|
| 34 |
+
date: str # Publication date (YYYY-MM-DD or 'Unknown')
|
| 35 |
+
authors: list[str] # Author list
|
| 36 |
+
|
| 37 |
+
MAX_AUTHORS_IN_CITATION: ClassVar[int] = 3
|
| 38 |
+
|
| 39 |
+
@property
|
| 40 |
+
def formatted(self) -> str:
|
| 41 |
+
"""Format as citation string."""
|
| 42 |
+
```
|
| 43 |
+
|
| 44 |
+
**Example:**
|
| 45 |
+
```python
|
| 46 |
+
citation = Citation(
|
| 47 |
+
source="pubmed",
|
| 48 |
+
title="Effects of testosterone on female libido",
|
| 49 |
+
url="https://pubmed.ncbi.nlm.nih.gov/12345678",
|
| 50 |
+
date="2024-01-15",
|
| 51 |
+
authors=["Smith J", "Jones A", "Brown B"]
|
| 52 |
+
)
|
| 53 |
+
print(citation.formatted)
|
| 54 |
+
# "Smith J, Jones A, Brown B (2024-01-15). Effects of testosterone..."
|
| 55 |
+
```
|
| 56 |
+
|
| 57 |
+
---
|
| 58 |
+
|
| 59 |
+
### Evidence
|
| 60 |
+
|
| 61 |
+
A piece of evidence retrieved from search.
|
| 62 |
+
|
| 63 |
+
```python
|
| 64 |
+
class Evidence(BaseModel):
|
| 65 |
+
content: str # The actual text content (min 1 char)
|
| 66 |
+
citation: Citation # Source citation
|
| 67 |
+
relevance: float # Relevance score 0-1
|
| 68 |
+
metadata: dict[str, Any] # Additional metadata
|
| 69 |
+
|
| 70 |
+
model_config = {"frozen": True} # Immutable
|
| 71 |
+
```
|
| 72 |
+
|
| 73 |
+
**Metadata fields** (source-dependent):
|
| 74 |
+
- `cited_by_count` - Citation count
|
| 75 |
+
- `concepts` - Subject concepts
|
| 76 |
+
- `is_open_access` - OA status
|
| 77 |
+
- `pmid` - PubMed ID
|
| 78 |
+
- `doi` - Digital Object Identifier
|
| 79 |
+
|
| 80 |
+
**Example:**
|
| 81 |
+
```python
|
| 82 |
+
evidence = Evidence(
|
| 83 |
+
content="The study found significant improvement...",
|
| 84 |
+
citation=citation,
|
| 85 |
+
relevance=0.85,
|
| 86 |
+
metadata={"pmid": "12345678", "cited_by_count": 42}
|
| 87 |
+
)
|
| 88 |
+
```
|
| 89 |
+
|
| 90 |
+
---
|
| 91 |
+
|
| 92 |
+
### SearchResult
|
| 93 |
+
|
| 94 |
+
Result of a search operation.
|
| 95 |
+
|
| 96 |
+
```python
|
| 97 |
+
class SearchResult(BaseModel):
|
| 98 |
+
query: str # Original query
|
| 99 |
+
evidence: list[Evidence] # Retrieved evidence
|
| 100 |
+
sources_searched: list[SourceName] # Which sources were queried
|
| 101 |
+
total_found: int # Total matches
|
| 102 |
+
errors: list[str] # Any errors encountered
|
| 103 |
+
```
|
| 104 |
+
|
| 105 |
+
---
|
| 106 |
+
|
| 107 |
+
## Assessment Models
|
| 108 |
+
|
| 109 |
+
### AssessmentDetails
|
| 110 |
+
|
| 111 |
+
Detailed assessment of evidence quality by the Judge.
|
| 112 |
+
|
| 113 |
+
```python
|
| 114 |
+
class AssessmentDetails(BaseModel):
|
| 115 |
+
mechanism_score: int # 0-10: How well explained
|
| 116 |
+
mechanism_reasoning: str # Explanation (min 10 chars)
|
| 117 |
+
clinical_evidence_score: int # 0-10: Clinical strength
|
| 118 |
+
clinical_reasoning: str # Explanation (min 10 chars)
|
| 119 |
+
drug_candidates: list[str] # Specific drugs mentioned
|
| 120 |
+
key_findings: list[str] # Key findings
|
| 121 |
+
```
|
| 122 |
+
|
| 123 |
+
---
|
| 124 |
+
|
| 125 |
+
### JudgeAssessment
|
| 126 |
+
|
| 127 |
+
Complete assessment from the Judge.
|
| 128 |
+
|
| 129 |
+
```python
|
| 130 |
+
class JudgeAssessment(BaseModel):
|
| 131 |
+
details: AssessmentDetails
|
| 132 |
+
sufficient: bool # Is evidence sufficient?
|
| 133 |
+
confidence: float # 0-1 confidence
|
| 134 |
+
recommendation: Literal["continue", "synthesize"]
|
| 135 |
+
next_search_queries: list[str] # If continue, what to search
|
| 136 |
+
reasoning: str # Overall reasoning (min 20 chars)
|
| 137 |
+
```
|
| 138 |
+
|
| 139 |
+
**Decision Logic:**
|
| 140 |
+
- `recommendation="continue"` β More evidence needed, loop back
|
| 141 |
+
- `recommendation="synthesize"` β Ready to generate report
|
| 142 |
+
|
| 143 |
+
---
|
| 144 |
+
|
| 145 |
+
## Event Models
|
| 146 |
+
|
| 147 |
+
### AgentEvent
|
| 148 |
+
|
| 149 |
+
Event emitted by orchestrator for UI streaming.
|
| 150 |
+
|
| 151 |
+
```python
|
| 152 |
+
class AgentEvent(BaseModel):
|
| 153 |
+
type: Literal[
|
| 154 |
+
"started",
|
| 155 |
+
"thinking",
|
| 156 |
+
"searching",
|
| 157 |
+
"search_complete",
|
| 158 |
+
"judging",
|
| 159 |
+
"judge_complete",
|
| 160 |
+
"looping",
|
| 161 |
+
"synthesizing",
|
| 162 |
+
"complete",
|
| 163 |
+
"error",
|
| 164 |
+
"streaming",
|
| 165 |
+
"hypothesizing",
|
| 166 |
+
"analyzing",
|
| 167 |
+
"analysis_complete",
|
| 168 |
+
"progress",
|
| 169 |
+
]
|
| 170 |
+
message: str
|
| 171 |
+
data: Any = None
|
| 172 |
+
timestamp: datetime
|
| 173 |
+
iteration: int = 0
|
| 174 |
+
|
| 175 |
+
def to_markdown(self) -> str:
|
| 176 |
+
"""Format event as markdown with emoji."""
|
| 177 |
+
```
|
| 178 |
+
|
| 179 |
+
**Event Types:**
|
| 180 |
+
| Type | Icon | Meaning |
|
| 181 |
+
|------|------|---------|
|
| 182 |
+
| `started` | π | Research started |
|
| 183 |
+
| `thinking` | β³ | Processing |
|
| 184 |
+
| `searching` | π | Searching databases |
|
| 185 |
+
| `search_complete` | π | Search finished |
|
| 186 |
+
| `judging` | π§ | Evaluating evidence |
|
| 187 |
+
| `judge_complete` | β
| Judgment done |
|
| 188 |
+
| `looping` | π | Refining query |
|
| 189 |
+
| `synthesizing` | π | Generating report |
|
| 190 |
+
| `complete` | π | Research complete |
|
| 191 |
+
| `error` | β | Error occurred |
|
| 192 |
+
| `progress` | β±οΈ | Progress update |
|
| 193 |
+
|
| 194 |
+
---
|
| 195 |
+
|
| 196 |
+
## Hypothesis Models
|
| 197 |
+
|
| 198 |
+
### MechanismHypothesis
|
| 199 |
+
|
| 200 |
+
A scientific hypothesis about drug mechanism.
|
| 201 |
+
|
| 202 |
+
```python
|
| 203 |
+
class MechanismHypothesis(BaseModel):
|
| 204 |
+
drug: str # Drug being studied
|
| 205 |
+
target: str # Molecular target
|
| 206 |
+
pathway: str # Biological pathway
|
| 207 |
+
effect: str # Downstream effect
|
| 208 |
+
confidence: float # 0-1 confidence
|
| 209 |
+
supporting_evidence: list[str] # Supporting PMIDs/URLs
|
| 210 |
+
contradicting_evidence: list[str]
|
| 211 |
+
search_suggestions: list[str]
|
| 212 |
+
|
| 213 |
+
def to_search_queries(self) -> list[str]:
|
| 214 |
+
"""Generate queries to test hypothesis."""
|
| 215 |
+
```
|
| 216 |
+
|
| 217 |
+
---
|
| 218 |
+
|
| 219 |
+
### HypothesisAssessment
|
| 220 |
+
|
| 221 |
+
Assessment of evidence against hypotheses.
|
| 222 |
+
|
| 223 |
+
```python
|
| 224 |
+
class HypothesisAssessment(BaseModel):
|
| 225 |
+
hypotheses: list[MechanismHypothesis]
|
| 226 |
+
primary_hypothesis: MechanismHypothesis | None
|
| 227 |
+
knowledge_gaps: list[str]
|
| 228 |
+
recommended_searches: list[str]
|
| 229 |
+
```
|
| 230 |
+
|
| 231 |
+
---
|
| 232 |
+
|
| 233 |
+
## Report Models
|
| 234 |
+
|
| 235 |
+
### ReportSection
|
| 236 |
+
|
| 237 |
+
A section of the research report.
|
| 238 |
+
|
| 239 |
+
```python
|
| 240 |
+
class ReportSection(BaseModel):
|
| 241 |
+
title: str
|
| 242 |
+
content: str
|
| 243 |
+
citations: list[str] = [] # Reserved for inline citations
|
| 244 |
+
```
|
| 245 |
+
|
| 246 |
+
---
|
| 247 |
+
|
| 248 |
+
### ResearchReport
|
| 249 |
+
|
| 250 |
+
Structured scientific report (final output).
|
| 251 |
+
|
| 252 |
+
```python
|
| 253 |
+
class ResearchReport(BaseModel):
|
| 254 |
+
title: str
|
| 255 |
+
executive_summary: str # 100-1000 chars
|
| 256 |
+
research_question: str
|
| 257 |
+
|
| 258 |
+
methodology: ReportSection
|
| 259 |
+
hypotheses_tested: list[dict[str, Any]]
|
| 260 |
+
|
| 261 |
+
mechanistic_findings: ReportSection
|
| 262 |
+
clinical_findings: ReportSection
|
| 263 |
+
|
| 264 |
+
drug_candidates: list[str]
|
| 265 |
+
limitations: list[str]
|
| 266 |
+
conclusion: str
|
| 267 |
+
|
| 268 |
+
references: list[dict[str, str]]
|
| 269 |
+
|
| 270 |
+
# Metadata
|
| 271 |
+
sources_searched: list[str]
|
| 272 |
+
total_papers_reviewed: int
|
| 273 |
+
search_iterations: int
|
| 274 |
+
confidence_score: float # 0-1
|
| 275 |
+
|
| 276 |
+
def to_markdown(self) -> str:
|
| 277 |
+
"""Render report as markdown."""
|
| 278 |
+
```
|
| 279 |
+
|
| 280 |
+
**Reference Format:**
|
| 281 |
+
```python
|
| 282 |
+
{
|
| 283 |
+
"title": "Paper title",
|
| 284 |
+
"authors": "Smith J et al.",
|
| 285 |
+
"source": "pubmed",
|
| 286 |
+
"date": "2024-01-15",
|
| 287 |
+
"url": "https://..."
|
| 288 |
+
}
|
| 289 |
+
```
|
| 290 |
+
|
| 291 |
+
---
|
| 292 |
+
|
| 293 |
+
## Configuration Models
|
| 294 |
+
|
| 295 |
+
### OrchestratorConfig
|
| 296 |
+
|
| 297 |
+
Configuration for the orchestrator.
|
| 298 |
+
|
| 299 |
+
```python
|
| 300 |
+
class OrchestratorConfig(BaseModel):
|
| 301 |
+
max_iterations: int = 10 # 1-20
|
| 302 |
+
max_results_per_tool: int = 10 # 1-50
|
| 303 |
+
search_timeout: float = 30.0 # 5-120 seconds
|
| 304 |
+
```
|
| 305 |
+
|
| 306 |
+
---
|
| 307 |
+
|
| 308 |
+
## Model Relationships
|
| 309 |
+
|
| 310 |
+
```
|
| 311 |
+
SearchResult
|
| 312 |
+
βββ Evidence[]
|
| 313 |
+
βββ Citation
|
| 314 |
+
|
| 315 |
+
JudgeAssessment
|
| 316 |
+
βββ AssessmentDetails
|
| 317 |
+
|
| 318 |
+
ResearchReport
|
| 319 |
+
βββ ReportSection (methodology)
|
| 320 |
+
βββ ReportSection (mechanistic_findings)
|
| 321 |
+
βββ ReportSection (clinical_findings)
|
| 322 |
+
βββ HypothesisAssessment
|
| 323 |
+
βββ MechanismHypothesis[]
|
| 324 |
+
```
|
| 325 |
+
|
| 326 |
+
---
|
| 327 |
+
|
| 328 |
+
## Validation Notes
|
| 329 |
+
|
| 330 |
+
All models use Pydantic v2 with:
|
| 331 |
+
|
| 332 |
+
- **Field constraints** - `ge=0`, `le=1` for scores, `min_length` for strings
|
| 333 |
+
- **Frozen models** - Evidence is immutable (`frozen=True`)
|
| 334 |
+
- **Default factories** - Lists default to `[]` via `default_factory=list`
|
| 335 |
+
|
| 336 |
+
---
|
| 337 |
+
|
| 338 |
+
## Related Documentation
|
| 339 |
+
|
| 340 |
+
- [Component Inventory](component-inventory.md)
|
| 341 |
+
- [Exception Hierarchy](exception-hierarchy.md)
|
| 342 |
+
- [Architecture Overview](overview.md)
|
|
@@ -0,0 +1,350 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Exception Hierarchy
|
| 2 |
+
|
| 3 |
+
> **Last Updated**: 2025-12-06
|
| 4 |
+
|
| 5 |
+
This document describes all custom exceptions in DeepBoner.
|
| 6 |
+
|
| 7 |
+
## Location
|
| 8 |
+
|
| 9 |
+
All exceptions are defined in `src/utils/exceptions.py`.
|
| 10 |
+
|
| 11 |
+
## Exception Tree
|
| 12 |
+
|
| 13 |
+
```
|
| 14 |
+
Exception (Python builtin)
|
| 15 |
+
βββ DeepBonerError (base)
|
| 16 |
+
βββ SearchError
|
| 17 |
+
β βββ RateLimitError
|
| 18 |
+
βββ JudgeError
|
| 19 |
+
βββ ConfigurationError
|
| 20 |
+
βββ EmbeddingError
|
| 21 |
+
βββ LLMError
|
| 22 |
+
β βββ QuotaExceededError
|
| 23 |
+
βββ SynthesisError
|
| 24 |
+
```
|
| 25 |
+
|
| 26 |
+
---
|
| 27 |
+
|
| 28 |
+
## Base Exception
|
| 29 |
+
|
| 30 |
+
### DeepBonerError
|
| 31 |
+
|
| 32 |
+
```python
|
| 33 |
+
class DeepBonerError(Exception):
|
| 34 |
+
"""Base exception for all DeepBoner errors."""
|
| 35 |
+
pass
|
| 36 |
+
```
|
| 37 |
+
|
| 38 |
+
**When to use:** Never directly. Use specific subclasses.
|
| 39 |
+
|
| 40 |
+
**Catch when:** You want to catch all DeepBoner-related errors.
|
| 41 |
+
|
| 42 |
+
```python
|
| 43 |
+
try:
|
| 44 |
+
result = orchestrator.run(query)
|
| 45 |
+
except DeepBonerError as e:
|
| 46 |
+
logger.error(f"Research failed: {e}")
|
| 47 |
+
```
|
| 48 |
+
|
| 49 |
+
---
|
| 50 |
+
|
| 51 |
+
## Search Exceptions
|
| 52 |
+
|
| 53 |
+
### SearchError
|
| 54 |
+
|
| 55 |
+
```python
|
| 56 |
+
class SearchError(DeepBonerError):
|
| 57 |
+
"""Raised when a search operation fails."""
|
| 58 |
+
pass
|
| 59 |
+
```
|
| 60 |
+
|
| 61 |
+
**When raised:**
|
| 62 |
+
- External API returns error status
|
| 63 |
+
- Network timeout
|
| 64 |
+
- Invalid response format
|
| 65 |
+
- No results found (in strict mode)
|
| 66 |
+
|
| 67 |
+
**Example:**
|
| 68 |
+
```python
|
| 69 |
+
from src.utils.exceptions import SearchError
|
| 70 |
+
|
| 71 |
+
if response.status_code != 200:
|
| 72 |
+
raise SearchError(f"PubMed returned {response.status_code}")
|
| 73 |
+
```
|
| 74 |
+
|
| 75 |
+
---
|
| 76 |
+
|
| 77 |
+
### RateLimitError
|
| 78 |
+
|
| 79 |
+
```python
|
| 80 |
+
class RateLimitError(SearchError):
|
| 81 |
+
"""Raised when we hit API rate limits."""
|
| 82 |
+
pass
|
| 83 |
+
```
|
| 84 |
+
|
| 85 |
+
**When raised:**
|
| 86 |
+
- HTTP 429 (Too Many Requests)
|
| 87 |
+
- PubMed rate limit exceeded
|
| 88 |
+
- ClinicalTrials.gov throttling
|
| 89 |
+
|
| 90 |
+
**Handling:**
|
| 91 |
+
```python
|
| 92 |
+
from src.utils.exceptions import RateLimitError
|
| 93 |
+
|
| 94 |
+
try:
|
| 95 |
+
results = pubmed.search(query)
|
| 96 |
+
except RateLimitError:
|
| 97 |
+
await asyncio.sleep(60) # Wait and retry
|
| 98 |
+
results = pubmed.search(query)
|
| 99 |
+
```
|
| 100 |
+
|
| 101 |
+
**Prevention:**
|
| 102 |
+
- Add `NCBI_API_KEY` for higher PubMed limits
|
| 103 |
+
- Use built-in rate limiter (`src/tools/rate_limiter.py`)
|
| 104 |
+
|
| 105 |
+
---
|
| 106 |
+
|
| 107 |
+
## Judge Exceptions
|
| 108 |
+
|
| 109 |
+
### JudgeError
|
| 110 |
+
|
| 111 |
+
```python
|
| 112 |
+
class JudgeError(DeepBonerError):
|
| 113 |
+
"""Raised when the judge fails to assess evidence."""
|
| 114 |
+
pass
|
| 115 |
+
```
|
| 116 |
+
|
| 117 |
+
**When raised:**
|
| 118 |
+
- LLM fails to produce valid assessment
|
| 119 |
+
- Assessment parsing fails
|
| 120 |
+
- Confidence below threshold
|
| 121 |
+
- Invalid judge response format
|
| 122 |
+
|
| 123 |
+
**Example:**
|
| 124 |
+
```python
|
| 125 |
+
from src.utils.exceptions import JudgeError
|
| 126 |
+
|
| 127 |
+
if not assessment.details:
|
| 128 |
+
raise JudgeError("Judge produced incomplete assessment")
|
| 129 |
+
```
|
| 130 |
+
|
| 131 |
+
---
|
| 132 |
+
|
| 133 |
+
## Configuration Exceptions
|
| 134 |
+
|
| 135 |
+
### ConfigurationError
|
| 136 |
+
|
| 137 |
+
```python
|
| 138 |
+
class ConfigurationError(DeepBonerError):
|
| 139 |
+
"""Raised when configuration is invalid."""
|
| 140 |
+
pass
|
| 141 |
+
```
|
| 142 |
+
|
| 143 |
+
**When raised:**
|
| 144 |
+
- Required API key missing
|
| 145 |
+
- Invalid setting value
|
| 146 |
+
- Environment variable malformed
|
| 147 |
+
- Conflicting configuration
|
| 148 |
+
|
| 149 |
+
**Example:**
|
| 150 |
+
```python
|
| 151 |
+
from src.utils.exceptions import ConfigurationError
|
| 152 |
+
|
| 153 |
+
def get_api_key(self) -> str:
|
| 154 |
+
if not self.openai_api_key:
|
| 155 |
+
raise ConfigurationError("OPENAI_API_KEY not set")
|
| 156 |
+
return self.openai_api_key
|
| 157 |
+
```
|
| 158 |
+
|
| 159 |
+
---
|
| 160 |
+
|
| 161 |
+
## Embedding Exceptions
|
| 162 |
+
|
| 163 |
+
### EmbeddingError
|
| 164 |
+
|
| 165 |
+
```python
|
| 166 |
+
class EmbeddingError(DeepBonerError):
|
| 167 |
+
"""Raised when embedding or vector store operations fail."""
|
| 168 |
+
pass
|
| 169 |
+
```
|
| 170 |
+
|
| 171 |
+
**When raised:**
|
| 172 |
+
- ChromaDB connection failure
|
| 173 |
+
- Sentence-transformers model load failure
|
| 174 |
+
- Vector dimension mismatch
|
| 175 |
+
- Embedding generation fails
|
| 176 |
+
|
| 177 |
+
**Example:**
|
| 178 |
+
```python
|
| 179 |
+
from src.utils.exceptions import EmbeddingError
|
| 180 |
+
|
| 181 |
+
try:
|
| 182 |
+
embeddings = model.encode(texts)
|
| 183 |
+
except Exception as e:
|
| 184 |
+
raise EmbeddingError(f"Embedding failed: {e}")
|
| 185 |
+
```
|
| 186 |
+
|
| 187 |
+
---
|
| 188 |
+
|
| 189 |
+
## LLM Exceptions
|
| 190 |
+
|
| 191 |
+
### LLMError
|
| 192 |
+
|
| 193 |
+
```python
|
| 194 |
+
class LLMError(DeepBonerError):
|
| 195 |
+
"""Raised when LLM operations fail (API errors, parsing errors, etc.)."""
|
| 196 |
+
pass
|
| 197 |
+
```
|
| 198 |
+
|
| 199 |
+
**When raised:**
|
| 200 |
+
- LLM API error
|
| 201 |
+
- Response parsing failure
|
| 202 |
+
- Invalid model output
|
| 203 |
+
- Context length exceeded
|
| 204 |
+
|
| 205 |
+
---
|
| 206 |
+
|
| 207 |
+
### QuotaExceededError
|
| 208 |
+
|
| 209 |
+
```python
|
| 210 |
+
class QuotaExceededError(LLMError):
|
| 211 |
+
"""Raised when LLM API quota is exceeded (402 errors)."""
|
| 212 |
+
pass
|
| 213 |
+
```
|
| 214 |
+
|
| 215 |
+
**When raised:**
|
| 216 |
+
- OpenAI billing limit hit
|
| 217 |
+
- HuggingFace rate limit exceeded
|
| 218 |
+
- HTTP 402 Payment Required
|
| 219 |
+
|
| 220 |
+
**Handling:**
|
| 221 |
+
```python
|
| 222 |
+
from src.utils.exceptions import QuotaExceededError
|
| 223 |
+
|
| 224 |
+
try:
|
| 225 |
+
response = client.chat_completion(messages)
|
| 226 |
+
except QuotaExceededError:
|
| 227 |
+
# Fall back to free tier or notify user
|
| 228 |
+
return fallback_response()
|
| 229 |
+
```
|
| 230 |
+
|
| 231 |
+
---
|
| 232 |
+
|
| 233 |
+
## Synthesis Exceptions
|
| 234 |
+
|
| 235 |
+
### SynthesisError
|
| 236 |
+
|
| 237 |
+
```python
|
| 238 |
+
class SynthesisError(DeepBonerError):
|
| 239 |
+
"""Raised when report synthesis fails after trying all available models.
|
| 240 |
+
|
| 241 |
+
Attributes:
|
| 242 |
+
message: Human-readable error description
|
| 243 |
+
attempted_models: List of model IDs that were tried
|
| 244 |
+
errors: List of error messages from each failed attempt
|
| 245 |
+
"""
|
| 246 |
+
|
| 247 |
+
def __init__(
|
| 248 |
+
self,
|
| 249 |
+
message: str,
|
| 250 |
+
attempted_models: list[str] | None = None,
|
| 251 |
+
errors: list[str] | None = None,
|
| 252 |
+
) -> None:
|
| 253 |
+
super().__init__(message)
|
| 254 |
+
self.attempted_models = attempted_models or []
|
| 255 |
+
self.errors = errors or []
|
| 256 |
+
```
|
| 257 |
+
|
| 258 |
+
**When raised:**
|
| 259 |
+
- All LLM models fail to synthesize report
|
| 260 |
+
- Report generation exceeds retry limit
|
| 261 |
+
|
| 262 |
+
**Example:**
|
| 263 |
+
```python
|
| 264 |
+
from src.utils.exceptions import SynthesisError
|
| 265 |
+
|
| 266 |
+
if all_attempts_failed:
|
| 267 |
+
raise SynthesisError(
|
| 268 |
+
"Failed to synthesize report",
|
| 269 |
+
attempted_models=["gpt-5", "gpt-4o"],
|
| 270 |
+
errors=["Rate limit", "Context too long"]
|
| 271 |
+
)
|
| 272 |
+
```
|
| 273 |
+
|
| 274 |
+
**Accessing details:**
|
| 275 |
+
```python
|
| 276 |
+
try:
|
| 277 |
+
report = synthesize(evidence)
|
| 278 |
+
except SynthesisError as e:
|
| 279 |
+
print(f"Failed: {e}")
|
| 280 |
+
print(f"Tried models: {e.attempted_models}")
|
| 281 |
+
print(f"Errors: {e.errors}")
|
| 282 |
+
```
|
| 283 |
+
|
| 284 |
+
---
|
| 285 |
+
|
| 286 |
+
## Usage Patterns
|
| 287 |
+
|
| 288 |
+
### Catching Specific Exceptions
|
| 289 |
+
|
| 290 |
+
```python
|
| 291 |
+
from src.utils.exceptions import (
|
| 292 |
+
SearchError,
|
| 293 |
+
RateLimitError,
|
| 294 |
+
JudgeError,
|
| 295 |
+
)
|
| 296 |
+
|
| 297 |
+
try:
|
| 298 |
+
result = orchestrator.run(query)
|
| 299 |
+
except RateLimitError:
|
| 300 |
+
# Specific handling for rate limits
|
| 301 |
+
await rate_limiter.wait()
|
| 302 |
+
result = orchestrator.run(query)
|
| 303 |
+
except SearchError:
|
| 304 |
+
# General search failure
|
| 305 |
+
return empty_result()
|
| 306 |
+
except JudgeError:
|
| 307 |
+
# Judge failed, use default assessment
|
| 308 |
+
return default_assessment()
|
| 309 |
+
```
|
| 310 |
+
|
| 311 |
+
### Exception Chaining
|
| 312 |
+
|
| 313 |
+
```python
|
| 314 |
+
try:
|
| 315 |
+
response = api_call()
|
| 316 |
+
except requests.RequestException as e:
|
| 317 |
+
raise SearchError(f"API call failed: {e}") from e
|
| 318 |
+
```
|
| 319 |
+
|
| 320 |
+
### Logging Exceptions
|
| 321 |
+
|
| 322 |
+
```python
|
| 323 |
+
import structlog
|
| 324 |
+
|
| 325 |
+
logger = structlog.get_logger()
|
| 326 |
+
|
| 327 |
+
try:
|
| 328 |
+
results = search(query)
|
| 329 |
+
except DeepBonerError as e:
|
| 330 |
+
logger.error("operation_failed", error=str(e), exc_info=True)
|
| 331 |
+
raise
|
| 332 |
+
```
|
| 333 |
+
|
| 334 |
+
---
|
| 335 |
+
|
| 336 |
+
## Best Practices
|
| 337 |
+
|
| 338 |
+
1. **Use specific exceptions** - Don't raise `DeepBonerError` directly
|
| 339 |
+
2. **Include context** - Error messages should explain what failed
|
| 340 |
+
3. **Chain exceptions** - Use `from e` to preserve stack trace
|
| 341 |
+
4. **Log before re-raising** - Capture context for debugging
|
| 342 |
+
5. **Handle at boundaries** - Catch exceptions at API/UI boundaries
|
| 343 |
+
|
| 344 |
+
---
|
| 345 |
+
|
| 346 |
+
## Related Documentation
|
| 347 |
+
|
| 348 |
+
- [Component Inventory](component-inventory.md)
|
| 349 |
+
- [Data Models](data-models.md)
|
| 350 |
+
- [Troubleshooting](../getting-started/troubleshooting.md)
|
|
@@ -0,0 +1,224 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Architecture Overview
|
| 2 |
+
|
| 3 |
+
> **Last Updated**: 2025-12-06
|
| 4 |
+
|
| 5 |
+
This document provides a comprehensive overview of DeepBoner's architecture.
|
| 6 |
+
|
| 7 |
+
## System Purpose
|
| 8 |
+
|
| 9 |
+
DeepBoner is an **AI-native sexual health research agent** that autonomously:
|
| 10 |
+
1. Searches biomedical databases (PubMed, ClinicalTrials.gov, Europe PMC, OpenAlex)
|
| 11 |
+
2. Evaluates evidence quality
|
| 12 |
+
3. Synthesizes research reports with citations
|
| 13 |
+
|
| 14 |
+
## High-Level Architecture
|
| 15 |
+
|
| 16 |
+
```
|
| 17 |
+
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 18 |
+
β USER INTERFACE β
|
| 19 |
+
β β
|
| 20 |
+
β ββββββββββββββββ ββββββββββββββββ ββββββββββββββββ β
|
| 21 |
+
β β Gradio UI β β MCP Server β β Examples β β
|
| 22 |
+
β β (src/app) β β(mcp_tools.py)β β (scripts) β β
|
| 23 |
+
β ββββββββ¬ββββββββ ββββββββ¬ββββββββ ββββββββ¬ββββββββ β
|
| 24 |
+
βββββββββββΌββββββββββββββββββββΌββββββββββββββββββββΌββββββββββββββββββββ
|
| 25 |
+
β β β
|
| 26 |
+
βΌ βΌ βΌ
|
| 27 |
+
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 28 |
+
β ORCHESTRATION LAYER β
|
| 29 |
+
β β
|
| 30 |
+
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
|
| 31 |
+
β β AdvancedOrchestrator β β
|
| 32 |
+
β β (Microsoft Agent Framework) β β
|
| 33 |
+
β β β β
|
| 34 |
+
β β βββββββββββ βββββββββββ βββββββββββ β β
|
| 35 |
+
β β β Search β β β Judge β β β Report β β β
|
| 36 |
+
β β β Agent β β Agent β β Agent β β β
|
| 37 |
+
β β βββββββββββ βββββββββββ βββββββββββ β β
|
| 38 |
+
β β β β
|
| 39 |
+
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
|
| 40 |
+
β β
|
| 41 |
+
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
|
| 42 |
+
β β LangGraph Orchestrator β β
|
| 43 |
+
β β (Experimental) β β
|
| 44 |
+
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
|
| 45 |
+
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 46 |
+
β
|
| 47 |
+
βΌ
|
| 48 |
+
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 49 |
+
β LLM BACKENDS β
|
| 50 |
+
β β
|
| 51 |
+
β βββββββββββββββββββββββ βββββββββββββββββββββββ β
|
| 52 |
+
β β OpenAI Client β β HuggingFace Client β β
|
| 53 |
+
β β (GPT-5) β β (Qwen 2.5 7B) β β
|
| 54 |
+
β β Premium Tier β β Free Tier β β
|
| 55 |
+
β βββββββββββββββββββββββ βββββββββββββββββββββββ β
|
| 56 |
+
β β
|
| 57 |
+
β Auto-selected by ClientFactory based on API key β
|
| 58 |
+
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 59 |
+
β
|
| 60 |
+
βΌ
|
| 61 |
+
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 62 |
+
β SEARCH TOOLS β
|
| 63 |
+
β β
|
| 64 |
+
β ββββββββββββ ββββββββββββββββ ββββββββββββ ββββββββββββ β
|
| 65 |
+
β β PubMed β βClinicalTrialsβ βEuropePMC β β OpenAlex β β
|
| 66 |
+
β ββββββββββββ ββββββββββββββββ ββββββββββββ ββββββββββββ β
|
| 67 |
+
β β
|
| 68 |
+
β SearchHandler: Parallel scatter-gather β
|
| 69 |
+
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 70 |
+
β
|
| 71 |
+
βΌ
|
| 72 |
+
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 73 |
+
β SERVICES β
|
| 74 |
+
β β
|
| 75 |
+
β ββββββββββββββββ ββββββββββββββββ ββββββββββββββββ β
|
| 76 |
+
β β Embeddings β β LlamaIndex β β Research β β
|
| 77 |
+
β β Service β β RAG β β Memory β β
|
| 78 |
+
β β (local) β β (premium) β β (shared) β β
|
| 79 |
+
β ββββββββββββββββ ββββββββββββββββ ββββββββββββββββ β
|
| 80 |
+
β β
|
| 81 |
+
β ChromaDB Vector Store β
|
| 82 |
+
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 83 |
+
```
|
| 84 |
+
|
| 85 |
+
## Core Research Loop
|
| 86 |
+
|
| 87 |
+
The system operates on a **search-and-judge loop**:
|
| 88 |
+
|
| 89 |
+
```
|
| 90 |
+
User Question
|
| 91 |
+
β
|
| 92 |
+
βΌ
|
| 93 |
+
βββββββββββββββ
|
| 94 |
+
β SEARCH β β Query PubMed, ClinicalTrials, Europe PMC, OpenAlex
|
| 95 |
+
ββββββββ¬βββββββ
|
| 96 |
+
β
|
| 97 |
+
βΌ
|
| 98 |
+
βββββββββββββββ
|
| 99 |
+
β GATHER β β Collect and deduplicate evidence (PMID/DOI)
|
| 100 |
+
ββββββββ¬βββββββ
|
| 101 |
+
β
|
| 102 |
+
βΌ
|
| 103 |
+
βββββββββββββββ ββββββββββββββββββββ
|
| 104 |
+
β JUDGE β βββΊ β "Enough evidence?"β
|
| 105 |
+
ββββββββ¬βββββββ ββββββββββ¬ββββββββββ
|
| 106 |
+
β β
|
| 107 |
+
β ββββββββββββββββββ΄βββββββββββββββββ
|
| 108 |
+
β β β
|
| 109 |
+
βΌ βΌ βΌ
|
| 110 |
+
βββββββββββββββ βββββββββββββββ
|
| 111 |
+
β REFINE β β NO: Expand query β SYNTHESIZE β β YES: Generate report
|
| 112 |
+
β & LOOP β and search again βββββββββββββββ
|
| 113 |
+
βββββββββββββββ
|
| 114 |
+
```
|
| 115 |
+
|
| 116 |
+
**Break Conditions:**
|
| 117 |
+
- Judge approves evidence as sufficient
|
| 118 |
+
- Token budget exceeded (50K max)
|
| 119 |
+
- Max iterations reached (default 10)
|
| 120 |
+
|
| 121 |
+
## Framework Integration
|
| 122 |
+
|
| 123 |
+
DeepBoner combines two AI frameworks:
|
| 124 |
+
|
| 125 |
+
| Framework | Role | Usage |
|
| 126 |
+
|-----------|------|-------|
|
| 127 |
+
| **Microsoft Agent Framework** | Multi-agent orchestration | Manager β Agent coordination |
|
| 128 |
+
| **Pydantic AI** | Structured outputs | Evidence models, judge assessments |
|
| 129 |
+
|
| 130 |
+
They work together - Microsoft AF handles the workflow, Pydantic AI handles data validation.
|
| 131 |
+
|
| 132 |
+
## Dual-Backend Architecture
|
| 133 |
+
|
| 134 |
+
The system auto-selects LLM backend:
|
| 135 |
+
|
| 136 |
+
```python
|
| 137 |
+
# src/clients/factory.py
|
| 138 |
+
def get_chat_client():
|
| 139 |
+
if settings.has_openai_key:
|
| 140 |
+
return OpenAIChatClient(...) # Premium
|
| 141 |
+
else:
|
| 142 |
+
return HuggingFaceChatClient(...) # Free
|
| 143 |
+
```
|
| 144 |
+
|
| 145 |
+
| Tier | Backend | Model | Features |
|
| 146 |
+
|------|---------|-------|----------|
|
| 147 |
+
| Free | HuggingFace | Qwen 2.5 7B | Full functionality, slower |
|
| 148 |
+
| Premium | OpenAI | GPT-5 | Full functionality, faster |
|
| 149 |
+
|
| 150 |
+
**Same orchestration logic** - only the LLM differs.
|
| 151 |
+
|
| 152 |
+
## Key Components
|
| 153 |
+
|
| 154 |
+
### Orchestrators (`src/orchestrators/`)
|
| 155 |
+
|
| 156 |
+
| Component | File | Purpose |
|
| 157 |
+
|-----------|------|---------|
|
| 158 |
+
| AdvancedOrchestrator | `advanced.py` | Main multi-agent orchestrator |
|
| 159 |
+
| OrchestratorFactory | `factory.py` | Backend selection |
|
| 160 |
+
| LangGraphOrchestrator | `langgraph_orchestrator.py` | Experimental workflow engine |
|
| 161 |
+
|
| 162 |
+
### Agents (`src/agents/`)
|
| 163 |
+
|
| 164 |
+
| Agent | File | Role |
|
| 165 |
+
|-------|------|------|
|
| 166 |
+
| SearchAgent | `search_agent.py` | Evidence retrieval |
|
| 167 |
+
| JudgeAgent | `judge_agent.py` | Evidence evaluation |
|
| 168 |
+
| ReportAgent | `report_agent.py` | Report synthesis |
|
| 169 |
+
| HypothesisAgent | `hypothesis_agent.py` | Mechanistic pathway analysis |
|
| 170 |
+
|
| 171 |
+
### Tools (`src/tools/`)
|
| 172 |
+
|
| 173 |
+
| Tool | File | API |
|
| 174 |
+
|------|------|-----|
|
| 175 |
+
| PubMed | `pubmed.py` | NCBI E-utilities |
|
| 176 |
+
| ClinicalTrials | `clinicaltrials.py` | ClinicalTrials.gov |
|
| 177 |
+
| EuropePMC | `europepmc.py` | Europe PMC API |
|
| 178 |
+
| OpenAlex | `openalex.py` | OpenAlex API |
|
| 179 |
+
| SearchHandler | `search_handler.py` | Parallel orchestration |
|
| 180 |
+
|
| 181 |
+
### Services (`src/services/`)
|
| 182 |
+
|
| 183 |
+
| Service | File | Purpose |
|
| 184 |
+
|---------|------|---------|
|
| 185 |
+
| EmbeddingService | `embeddings.py` | Local embeddings (sentence-transformers) |
|
| 186 |
+
| LlamaIndexRAG | `llamaindex_rag.py` | Premium RAG (OpenAI embeddings) |
|
| 187 |
+
| ResearchMemory | `research_memory.py` | Shared state across agents |
|
| 188 |
+
|
| 189 |
+
## Data Flow
|
| 190 |
+
|
| 191 |
+
1. **User Input** β Gradio UI / MCP Client
|
| 192 |
+
2. **Query** β AdvancedOrchestrator
|
| 193 |
+
3. **Search** β SearchHandler β [PubMed, ClinicalTrials, EuropePMC, OpenAlex]
|
| 194 |
+
4. **Evidence** β Deduplicated by PMID/DOI
|
| 195 |
+
5. **Judge** β LLM evaluates sufficiency
|
| 196 |
+
6. **Loop or Synthesize** β Based on judge decision
|
| 197 |
+
7. **Report** β Structured output with citations
|
| 198 |
+
8. **Response** β Back to user
|
| 199 |
+
|
| 200 |
+
## Configuration
|
| 201 |
+
|
| 202 |
+
Settings are loaded from environment via Pydantic Settings:
|
| 203 |
+
|
| 204 |
+
```python
|
| 205 |
+
# src/utils/config.py
|
| 206 |
+
class Settings(BaseSettings):
|
| 207 |
+
openai_api_key: str | None
|
| 208 |
+
huggingface_model: str = "Qwen/Qwen2.5-7B-Instruct"
|
| 209 |
+
max_iterations: int = 10
|
| 210 |
+
# ...
|
| 211 |
+
```
|
| 212 |
+
|
| 213 |
+
See [Configuration Reference](../reference/configuration.md) for all options.
|
| 214 |
+
|
| 215 |
+
## Related Documentation
|
| 216 |
+
|
| 217 |
+
- [Component Inventory](component-inventory.md) - Complete module catalog
|
| 218 |
+
- [Data Models](data-models.md) - Pydantic model reference
|
| 219 |
+
- [System Registry](system-registry.md) - Service wiring specification
|
| 220 |
+
- [Workflow Diagrams](workflow-diagrams.md) - Visual documentation
|
| 221 |
+
|
| 222 |
+
---
|
| 223 |
+
|
| 224 |
+
*"Architecturally rock solid."* ποΈ
|
|
@@ -0,0 +1,290 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Docker Deployment
|
| 2 |
+
|
| 3 |
+
> **Last Updated**: 2025-12-06
|
| 4 |
+
|
| 5 |
+
This guide covers deploying DeepBoner using Docker.
|
| 6 |
+
|
| 7 |
+
## Quick Start
|
| 8 |
+
|
| 9 |
+
```bash
|
| 10 |
+
# Build the image
|
| 11 |
+
docker build -t deepboner .
|
| 12 |
+
|
| 13 |
+
# Run the container
|
| 14 |
+
docker run -p 7860:7860 deepboner
|
| 15 |
+
```
|
| 16 |
+
|
| 17 |
+
Open http://localhost:7860
|
| 18 |
+
|
| 19 |
+
## Dockerfile Overview
|
| 20 |
+
|
| 21 |
+
The project uses a multi-stage approach:
|
| 22 |
+
|
| 23 |
+
```dockerfile
|
| 24 |
+
FROM python:3.11-slim
|
| 25 |
+
|
| 26 |
+
# Install system dependencies
|
| 27 |
+
RUN apt-get update && apt-get install -y git curl
|
| 28 |
+
|
| 29 |
+
# Install uv package manager
|
| 30 |
+
RUN pip install uv==0.5.4
|
| 31 |
+
|
| 32 |
+
# Copy project files
|
| 33 |
+
COPY pyproject.toml uv.lock src/ README.md .
|
| 34 |
+
|
| 35 |
+
# Install runtime dependencies (no dev tools)
|
| 36 |
+
RUN uv sync --frozen --no-dev --extra embeddings --extra magentic
|
| 37 |
+
|
| 38 |
+
# Create non-root user
|
| 39 |
+
RUN useradd --create-home appuser
|
| 40 |
+
USER appuser
|
| 41 |
+
|
| 42 |
+
# Pre-download embedding model
|
| 43 |
+
RUN uv run python -c "from sentence_transformers import SentenceTransformer; SentenceTransformer('all-MiniLM-L6-v2')"
|
| 44 |
+
|
| 45 |
+
# Expose port and run
|
| 46 |
+
EXPOSE 7860
|
| 47 |
+
CMD ["uv", "run", "python", "-m", "src.app"]
|
| 48 |
+
```
|
| 49 |
+
|
| 50 |
+
## Building
|
| 51 |
+
|
| 52 |
+
### Basic Build
|
| 53 |
+
|
| 54 |
+
```bash
|
| 55 |
+
docker build -t deepboner .
|
| 56 |
+
```
|
| 57 |
+
|
| 58 |
+
### With Build Arguments
|
| 59 |
+
|
| 60 |
+
```bash
|
| 61 |
+
# Custom tag
|
| 62 |
+
docker build -t deepboner:v0.1.0 .
|
| 63 |
+
|
| 64 |
+
# No cache (clean build)
|
| 65 |
+
docker build --no-cache -t deepboner .
|
| 66 |
+
```
|
| 67 |
+
|
| 68 |
+
### Multi-Platform Build
|
| 69 |
+
|
| 70 |
+
```bash
|
| 71 |
+
docker buildx build --platform linux/amd64,linux/arm64 -t deepboner .
|
| 72 |
+
```
|
| 73 |
+
|
| 74 |
+
## Running
|
| 75 |
+
|
| 76 |
+
### Basic Run
|
| 77 |
+
|
| 78 |
+
```bash
|
| 79 |
+
docker run -p 7860:7860 deepboner
|
| 80 |
+
```
|
| 81 |
+
|
| 82 |
+
### With Environment Variables
|
| 83 |
+
|
| 84 |
+
```bash
|
| 85 |
+
docker run -p 7860:7860 \
|
| 86 |
+
-e OPENAI_API_KEY=sk-your-key \
|
| 87 |
+
-e NCBI_API_KEY=your-ncbi-key \
|
| 88 |
+
-e LOG_LEVEL=INFO \
|
| 89 |
+
deepboner
|
| 90 |
+
```
|
| 91 |
+
|
| 92 |
+
### Using .env File
|
| 93 |
+
|
| 94 |
+
```bash
|
| 95 |
+
docker run -p 7860:7860 --env-file .env deepboner
|
| 96 |
+
```
|
| 97 |
+
|
| 98 |
+
### With Persistent Storage
|
| 99 |
+
|
| 100 |
+
```bash
|
| 101 |
+
# Persist ChromaDB data
|
| 102 |
+
docker run -p 7860:7860 \
|
| 103 |
+
-v $(pwd)/data/chroma:/app/chroma_db \
|
| 104 |
+
deepboner
|
| 105 |
+
```
|
| 106 |
+
|
| 107 |
+
### Detached Mode
|
| 108 |
+
|
| 109 |
+
```bash
|
| 110 |
+
docker run -d -p 7860:7860 --name deepboner-app deepboner
|
| 111 |
+
```
|
| 112 |
+
|
| 113 |
+
## Configuration
|
| 114 |
+
|
| 115 |
+
### Environment Variables
|
| 116 |
+
|
| 117 |
+
| Variable | Description | Required |
|
| 118 |
+
|----------|-------------|----------|
|
| 119 |
+
| `OPENAI_API_KEY` | OpenAI API key (premium mode) | No |
|
| 120 |
+
| `NCBI_API_KEY` | NCBI API key (higher rate limits) | No |
|
| 121 |
+
| `HF_TOKEN` | HuggingFace token | No |
|
| 122 |
+
| `LOG_LEVEL` | Logging level (DEBUG, INFO, WARNING, ERROR) | No |
|
| 123 |
+
| `MAX_ITERATIONS` | Max search iterations (1-50) | No |
|
| 124 |
+
|
| 125 |
+
### Ports
|
| 126 |
+
|
| 127 |
+
| Port | Service |
|
| 128 |
+
|------|---------|
|
| 129 |
+
| 7860 | Gradio UI + MCP Server |
|
| 130 |
+
|
| 131 |
+
### Volumes
|
| 132 |
+
|
| 133 |
+
| Path | Purpose |
|
| 134 |
+
|------|---------|
|
| 135 |
+
| `/app/chroma_db` | ChromaDB vector store |
|
| 136 |
+
| `/app/.cache` | HuggingFace model cache |
|
| 137 |
+
|
| 138 |
+
## Health Check
|
| 139 |
+
|
| 140 |
+
The container includes a health check:
|
| 141 |
+
|
| 142 |
+
```dockerfile
|
| 143 |
+
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
|
| 144 |
+
CMD curl -f http://localhost:7860/ || exit 1
|
| 145 |
+
```
|
| 146 |
+
|
| 147 |
+
Check health status:
|
| 148 |
+
|
| 149 |
+
```bash
|
| 150 |
+
docker inspect --format='{{.State.Health.Status}}' deepboner-app
|
| 151 |
+
```
|
| 152 |
+
|
| 153 |
+
## Docker Compose
|
| 154 |
+
|
| 155 |
+
Create `docker-compose.yml`:
|
| 156 |
+
|
| 157 |
+
```yaml
|
| 158 |
+
version: '3.8'
|
| 159 |
+
|
| 160 |
+
services:
|
| 161 |
+
deepboner:
|
| 162 |
+
build: .
|
| 163 |
+
ports:
|
| 164 |
+
- "7860:7860"
|
| 165 |
+
environment:
|
| 166 |
+
- LOG_LEVEL=INFO
|
| 167 |
+
env_file:
|
| 168 |
+
- .env
|
| 169 |
+
volumes:
|
| 170 |
+
- chroma_data:/app/chroma_db
|
| 171 |
+
restart: unless-stopped
|
| 172 |
+
healthcheck:
|
| 173 |
+
test: ["CMD", "curl", "-f", "http://localhost:7860/"]
|
| 174 |
+
interval: 30s
|
| 175 |
+
timeout: 10s
|
| 176 |
+
retries: 3
|
| 177 |
+
|
| 178 |
+
volumes:
|
| 179 |
+
chroma_data:
|
| 180 |
+
```
|
| 181 |
+
|
| 182 |
+
Run with:
|
| 183 |
+
|
| 184 |
+
```bash
|
| 185 |
+
docker-compose up -d
|
| 186 |
+
```
|
| 187 |
+
|
| 188 |
+
## Production Considerations
|
| 189 |
+
|
| 190 |
+
### Resource Limits
|
| 191 |
+
|
| 192 |
+
```bash
|
| 193 |
+
docker run -p 7860:7860 \
|
| 194 |
+
--memory=4g \
|
| 195 |
+
--cpus=2 \
|
| 196 |
+
deepboner
|
| 197 |
+
```
|
| 198 |
+
|
| 199 |
+
### Logging
|
| 200 |
+
|
| 201 |
+
```bash
|
| 202 |
+
# View logs
|
| 203 |
+
docker logs deepboner-app
|
| 204 |
+
|
| 205 |
+
# Follow logs
|
| 206 |
+
docker logs -f deepboner-app
|
| 207 |
+
|
| 208 |
+
# With timestamps
|
| 209 |
+
docker logs -t deepboner-app
|
| 210 |
+
```
|
| 211 |
+
|
| 212 |
+
### Security
|
| 213 |
+
|
| 214 |
+
The container runs as non-root user (`appuser`):
|
| 215 |
+
|
| 216 |
+
```dockerfile
|
| 217 |
+
RUN useradd --create-home appuser
|
| 218 |
+
USER appuser
|
| 219 |
+
```
|
| 220 |
+
|
| 221 |
+
Do not:
|
| 222 |
+
- Expose ports beyond 7860
|
| 223 |
+
- Mount sensitive host paths
|
| 224 |
+
- Run as root in production
|
| 225 |
+
|
| 226 |
+
### Reverse Proxy
|
| 227 |
+
|
| 228 |
+
For production, use a reverse proxy (nginx, traefik):
|
| 229 |
+
|
| 230 |
+
```nginx
|
| 231 |
+
server {
|
| 232 |
+
listen 80;
|
| 233 |
+
server_name deepboner.example.com;
|
| 234 |
+
|
| 235 |
+
location / {
|
| 236 |
+
proxy_pass http://localhost:7860;
|
| 237 |
+
proxy_http_version 1.1;
|
| 238 |
+
proxy_set_header Upgrade $http_upgrade;
|
| 239 |
+
proxy_set_header Connection "upgrade";
|
| 240 |
+
proxy_set_header Host $host;
|
| 241 |
+
}
|
| 242 |
+
}
|
| 243 |
+
```
|
| 244 |
+
|
| 245 |
+
## Troubleshooting
|
| 246 |
+
|
| 247 |
+
### Container exits immediately
|
| 248 |
+
|
| 249 |
+
Check logs:
|
| 250 |
+
```bash
|
| 251 |
+
docker logs deepboner-app
|
| 252 |
+
```
|
| 253 |
+
|
| 254 |
+
Common causes:
|
| 255 |
+
- Missing environment variables
|
| 256 |
+
- Port conflict
|
| 257 |
+
- Insufficient memory
|
| 258 |
+
|
| 259 |
+
### Slow startup
|
| 260 |
+
|
| 261 |
+
First run downloads models. Pre-warm the cache:
|
| 262 |
+
```bash
|
| 263 |
+
# Build includes model download
|
| 264 |
+
docker build -t deepboner .
|
| 265 |
+
```
|
| 266 |
+
|
| 267 |
+
### Out of memory
|
| 268 |
+
|
| 269 |
+
Increase memory limit:
|
| 270 |
+
```bash
|
| 271 |
+
docker run -p 7860:7860 --memory=8g deepboner
|
| 272 |
+
```
|
| 273 |
+
|
| 274 |
+
### Cannot connect to port
|
| 275 |
+
|
| 276 |
+
Check if port is in use:
|
| 277 |
+
```bash
|
| 278 |
+
lsof -i :7860
|
| 279 |
+
```
|
| 280 |
+
|
| 281 |
+
Use a different port:
|
| 282 |
+
```bash
|
| 283 |
+
docker run -p 8080:7860 deepboner
|
| 284 |
+
```
|
| 285 |
+
|
| 286 |
+
## Related Documentation
|
| 287 |
+
|
| 288 |
+
- [HuggingFace Spaces Deployment](huggingface-spaces.md)
|
| 289 |
+
- [MCP Integration](mcp-integration.md)
|
| 290 |
+
- [Configuration Reference](../reference/configuration.md)
|
|
@@ -0,0 +1,224 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# HuggingFace Spaces Deployment
|
| 2 |
+
|
| 3 |
+
> **Last Updated**: 2025-12-06
|
| 4 |
+
|
| 5 |
+
This guide covers deploying DeepBoner to HuggingFace Spaces.
|
| 6 |
+
|
| 7 |
+
## Overview
|
| 8 |
+
|
| 9 |
+
DeepBoner is deployed to HuggingFace Spaces at:
|
| 10 |
+
https://huggingface.co/spaces/MCP-1st-Birthday/DeepBoner
|
| 11 |
+
|
| 12 |
+
The Space runs the Gradio UI with MCP server support.
|
| 13 |
+
|
| 14 |
+
## Space Configuration
|
| 15 |
+
|
| 16 |
+
The Space is configured via the README.md frontmatter:
|
| 17 |
+
|
| 18 |
+
```yaml
|
| 19 |
+
---
|
| 20 |
+
title: DeepBoner
|
| 21 |
+
emoji: π
|
| 22 |
+
colorFrom: pink
|
| 23 |
+
colorTo: purple
|
| 24 |
+
sdk: gradio
|
| 25 |
+
sdk_version: "6.0.1"
|
| 26 |
+
python_version: "3.11"
|
| 27 |
+
app_file: src/app.py
|
| 28 |
+
pinned: true
|
| 29 |
+
license: apache-2.0
|
| 30 |
+
short_description: "Deep Research Agent for the Strongest Boners"
|
| 31 |
+
tags:
|
| 32 |
+
- mcp-hackathon
|
| 33 |
+
- agents
|
| 34 |
+
- sexual-health
|
| 35 |
+
- pydantic-ai
|
| 36 |
+
- pubmed
|
| 37 |
+
---
|
| 38 |
+
```
|
| 39 |
+
|
| 40 |
+
## Deployment Methods
|
| 41 |
+
|
| 42 |
+
### Method 1: Git Push (Recommended)
|
| 43 |
+
|
| 44 |
+
```bash
|
| 45 |
+
# Add HuggingFace remote
|
| 46 |
+
git remote add hf https://huggingface.co/spaces/MCP-1st-Birthday/DeepBoner
|
| 47 |
+
|
| 48 |
+
# Push to HuggingFace
|
| 49 |
+
git push hf main
|
| 50 |
+
```
|
| 51 |
+
|
| 52 |
+
### Method 2: HuggingFace Hub
|
| 53 |
+
|
| 54 |
+
Use the HuggingFace web interface to sync with GitHub.
|
| 55 |
+
|
| 56 |
+
## Secrets Configuration
|
| 57 |
+
|
| 58 |
+
Configure secrets in Space Settings β Variables and secrets:
|
| 59 |
+
|
| 60 |
+
| Secret | Purpose | Required |
|
| 61 |
+
|--------|---------|----------|
|
| 62 |
+
| `HF_TOKEN` | HuggingFace API token | Yes |
|
| 63 |
+
| `NCBI_API_KEY` | Higher PubMed rate limits | No |
|
| 64 |
+
| `OPENAI_API_KEY` | Premium mode (if offered) | No |
|
| 65 |
+
|
| 66 |
+
### Setting Secrets
|
| 67 |
+
|
| 68 |
+
1. Go to Space Settings
|
| 69 |
+
2. Click "Variables and secrets"
|
| 70 |
+
3. Add each secret:
|
| 71 |
+
- Name: `HF_TOKEN`
|
| 72 |
+
- Value: `hf_...` (your token)
|
| 73 |
+
- Click "Add"
|
| 74 |
+
|
| 75 |
+
**Important:** Use Secrets (not Variables) for API keys - secrets are hidden.
|
| 76 |
+
|
| 77 |
+
## Build Process
|
| 78 |
+
|
| 79 |
+
When you push to HuggingFace:
|
| 80 |
+
|
| 81 |
+
1. Space detects changes
|
| 82 |
+
2. Builds from Dockerfile (if present) or requirements.txt
|
| 83 |
+
3. Installs dependencies
|
| 84 |
+
4. Starts the application
|
| 85 |
+
|
| 86 |
+
Build logs are visible in the Logs tab.
|
| 87 |
+
|
| 88 |
+
## Collaboration Workflow
|
| 89 |
+
|
| 90 |
+
### Branch Strategy
|
| 91 |
+
|
| 92 |
+
```
|
| 93 |
+
GitHub (source of truth)
|
| 94 |
+
βββ main - Production, synced to HF
|
| 95 |
+
βββ dev - Development integration
|
| 96 |
+
|
| 97 |
+
HuggingFace
|
| 98 |
+
βββ main - Production (from GitHub)
|
| 99 |
+
βββ yourname-dev - Personal dev branches
|
| 100 |
+
```
|
| 101 |
+
|
| 102 |
+
### Guidelines
|
| 103 |
+
|
| 104 |
+
- **DO NOT** push directly to `main` on HuggingFace
|
| 105 |
+
- Use personal dev branches: `yourname-dev`
|
| 106 |
+
- GitHub is the source of truth for code review
|
| 107 |
+
- Sync production from GitHub only
|
| 108 |
+
|
| 109 |
+
### Personal Development
|
| 110 |
+
|
| 111 |
+
```bash
|
| 112 |
+
# Create your dev branch on HuggingFace
|
| 113 |
+
git checkout -b myname-dev
|
| 114 |
+
git push hf myname-dev
|
| 115 |
+
|
| 116 |
+
# Test on your branch
|
| 117 |
+
# Space will build from your branch if you switch to it
|
| 118 |
+
```
|
| 119 |
+
|
| 120 |
+
## Environment Differences
|
| 121 |
+
|
| 122 |
+
### Local vs Spaces
|
| 123 |
+
|
| 124 |
+
| Aspect | Local | HuggingFace Spaces |
|
| 125 |
+
|--------|-------|-------------------|
|
| 126 |
+
| API Keys | `.env` file | Secrets |
|
| 127 |
+
| Storage | Persistent | Ephemeral |
|
| 128 |
+
| Port | 7860 | Assigned |
|
| 129 |
+
| Memory | Unlimited | Limited (based on tier) |
|
| 130 |
+
|
| 131 |
+
### Handling Ephemeral Storage
|
| 132 |
+
|
| 133 |
+
ChromaDB data is not persisted on Space restart. For production use cases requiring persistence:
|
| 134 |
+
|
| 135 |
+
1. Use external database
|
| 136 |
+
2. Accept regeneration on restart
|
| 137 |
+
3. Consider paid Spaces with persistent storage
|
| 138 |
+
|
| 139 |
+
## Hardware Tiers
|
| 140 |
+
|
| 141 |
+
HuggingFace Spaces offers different hardware:
|
| 142 |
+
|
| 143 |
+
| Tier | CPU | RAM | GPU | Cost |
|
| 144 |
+
|------|-----|-----|-----|------|
|
| 145 |
+
| Free | 2 | 16GB | None | Free |
|
| 146 |
+
| CPU Basic | 2 | 16GB | None | $0.03/hr |
|
| 147 |
+
| CPU Upgrade | 8 | 32GB | None | $0.07/hr |
|
| 148 |
+
| T4 Small | 4 | 15GB | T4 | $0.60/hr |
|
| 149 |
+
|
| 150 |
+
DeepBoner runs on Free tier but benefits from CPU Upgrade for:
|
| 151 |
+
- Faster embedding generation
|
| 152 |
+
- More concurrent users
|
| 153 |
+
|
| 154 |
+
## Monitoring
|
| 155 |
+
|
| 156 |
+
### Logs
|
| 157 |
+
|
| 158 |
+
View logs in the Logs tab:
|
| 159 |
+
- Build logs (during deployment)
|
| 160 |
+
- Application logs (runtime)
|
| 161 |
+
|
| 162 |
+
### Health
|
| 163 |
+
|
| 164 |
+
Check Space status:
|
| 165 |
+
- Green: Running
|
| 166 |
+
- Yellow: Building
|
| 167 |
+
- Red: Error
|
| 168 |
+
|
| 169 |
+
## Troubleshooting
|
| 170 |
+
|
| 171 |
+
### Build fails
|
| 172 |
+
|
| 173 |
+
1. Check Build Logs tab
|
| 174 |
+
2. Common issues:
|
| 175 |
+
- Invalid requirements.txt
|
| 176 |
+
- Missing files
|
| 177 |
+
- Syntax errors in config
|
| 178 |
+
|
| 179 |
+
### App crashes on start
|
| 180 |
+
|
| 181 |
+
1. Check Application Logs
|
| 182 |
+
2. Common issues:
|
| 183 |
+
- Missing secrets
|
| 184 |
+
- Import errors
|
| 185 |
+
- Memory limits
|
| 186 |
+
|
| 187 |
+
### Slow performance
|
| 188 |
+
|
| 189 |
+
1. Check if on Free tier
|
| 190 |
+
2. Consider CPU Upgrade
|
| 191 |
+
3. Optimize model loading
|
| 192 |
+
|
| 193 |
+
### Space sleeping
|
| 194 |
+
|
| 195 |
+
Free Spaces sleep after inactivity:
|
| 196 |
+
- Wake time: 30-60 seconds
|
| 197 |
+
- Consider "pinned" for popular Spaces
|
| 198 |
+
|
| 199 |
+
## Git Hooks
|
| 200 |
+
|
| 201 |
+
To prevent accidental pushes to protected branches:
|
| 202 |
+
|
| 203 |
+
```bash
|
| 204 |
+
# .git/hooks/pre-push
|
| 205 |
+
#!/bin/bash
|
| 206 |
+
protected_branches=("main" "dev")
|
| 207 |
+
current_branch=$(git rev-parse --abbrev-ref HEAD)
|
| 208 |
+
remote="$1"
|
| 209 |
+
|
| 210 |
+
if [[ "$remote" == "hf" || "$remote" == "huggingface" ]]; then
|
| 211 |
+
for branch in "${protected_branches[@]}"; do
|
| 212 |
+
if [[ "$current_branch" == "$branch" ]]; then
|
| 213 |
+
echo "Direct push to $branch on HuggingFace is not allowed."
|
| 214 |
+
exit 1
|
| 215 |
+
fi
|
| 216 |
+
done
|
| 217 |
+
fi
|
| 218 |
+
```
|
| 219 |
+
|
| 220 |
+
## Related Documentation
|
| 221 |
+
|
| 222 |
+
- [Docker Deployment](docker.md)
|
| 223 |
+
- [MCP Integration](mcp-integration.md)
|
| 224 |
+
- [Configuration Reference](../reference/configuration.md)
|
|
@@ -0,0 +1,226 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# MCP Integration Guide
|
| 2 |
+
|
| 3 |
+
> **Last Updated**: 2025-12-06
|
| 4 |
+
|
| 5 |
+
This guide covers setting up DeepBoner's MCP (Model Context Protocol) server for integration with Claude Desktop and other MCP clients.
|
| 6 |
+
|
| 7 |
+
## Overview
|
| 8 |
+
|
| 9 |
+
DeepBoner exposes an MCP server via Gradio's built-in support. This allows Claude Desktop and other MCP-compatible clients to use DeepBoner's search tools directly.
|
| 10 |
+
|
| 11 |
+
## MCP Server URL
|
| 12 |
+
|
| 13 |
+
When DeepBoner is running:
|
| 14 |
+
|
| 15 |
+
```
|
| 16 |
+
http://localhost:7860/gradio_api/mcp/
|
| 17 |
+
```
|
| 18 |
+
|
| 19 |
+
On HuggingFace Spaces:
|
| 20 |
+
```
|
| 21 |
+
https://mcp-1st-birthday-deepboner.hf.space/gradio_api/mcp/
|
| 22 |
+
```
|
| 23 |
+
|
| 24 |
+
## Available Tools
|
| 25 |
+
|
| 26 |
+
| Tool | Description |
|
| 27 |
+
|------|-------------|
|
| 28 |
+
| `search_pubmed` | Search peer-reviewed biomedical literature |
|
| 29 |
+
| `search_clinical_trials` | Search ClinicalTrials.gov for active/completed trials |
|
| 30 |
+
| `search_europepmc` | Search Europe PMC preprints and papers |
|
| 31 |
+
| `search_all_sources` | Search all sources simultaneously with deduplication |
|
| 32 |
+
|
| 33 |
+
### Tool Signatures
|
| 34 |
+
|
| 35 |
+
```python
|
| 36 |
+
def search_pubmed(query: str, max_results: int = 10) -> list[Evidence]:
|
| 37 |
+
"""Search PubMed for biomedical literature."""
|
| 38 |
+
|
| 39 |
+
def search_clinical_trials(query: str, max_results: int = 10) -> list[Evidence]:
|
| 40 |
+
"""Search ClinicalTrials.gov."""
|
| 41 |
+
|
| 42 |
+
def search_europepmc(query: str, max_results: int = 10) -> list[Evidence]:
|
| 43 |
+
"""Search Europe PMC."""
|
| 44 |
+
|
| 45 |
+
def search_all_sources(query: str, max_results_per_source: int = 10) -> SearchResult:
|
| 46 |
+
"""Search all sources with cross-source deduplication."""
|
| 47 |
+
```
|
| 48 |
+
|
| 49 |
+
## Claude Desktop Setup
|
| 50 |
+
|
| 51 |
+
### 1. Start DeepBoner
|
| 52 |
+
|
| 53 |
+
```bash
|
| 54 |
+
uv run python src/app.py
|
| 55 |
+
```
|
| 56 |
+
|
| 57 |
+
### 2. Configure Claude Desktop
|
| 58 |
+
|
| 59 |
+
Edit your Claude Desktop configuration:
|
| 60 |
+
|
| 61 |
+
**macOS:** `~/Library/Application Support/Claude/claude_desktop_config.json`
|
| 62 |
+
**Windows:** `%APPDATA%\Claude\claude_desktop_config.json`
|
| 63 |
+
|
| 64 |
+
Add the MCP server:
|
| 65 |
+
|
| 66 |
+
```json
|
| 67 |
+
{
|
| 68 |
+
"mcpServers": {
|
| 69 |
+
"deepboner": {
|
| 70 |
+
"url": "http://localhost:7860/gradio_api/mcp/"
|
| 71 |
+
}
|
| 72 |
+
}
|
| 73 |
+
}
|
| 74 |
+
```
|
| 75 |
+
|
| 76 |
+
### 3. Restart Claude Desktop
|
| 77 |
+
|
| 78 |
+
Close and reopen Claude Desktop to load the new configuration.
|
| 79 |
+
|
| 80 |
+
### 4. Verify Connection
|
| 81 |
+
|
| 82 |
+
In Claude Desktop, you should see DeepBoner's tools available. Try:
|
| 83 |
+
|
| 84 |
+
```
|
| 85 |
+
Use the search_pubmed tool to find recent papers on testosterone therapy
|
| 86 |
+
```
|
| 87 |
+
|
| 88 |
+
## Using with HuggingFace Spaces
|
| 89 |
+
|
| 90 |
+
Point to the deployed Space:
|
| 91 |
+
|
| 92 |
+
```json
|
| 93 |
+
{
|
| 94 |
+
"mcpServers": {
|
| 95 |
+
"deepboner-cloud": {
|
| 96 |
+
"url": "https://mcp-1st-birthday-deepboner.hf.space/gradio_api/mcp/"
|
| 97 |
+
}
|
| 98 |
+
}
|
| 99 |
+
}
|
| 100 |
+
```
|
| 101 |
+
|
| 102 |
+
Note: HuggingFace Spaces may sleep after inactivity. The first request will wake the Space (30-60 second delay).
|
| 103 |
+
|
| 104 |
+
## Tool Implementation
|
| 105 |
+
|
| 106 |
+
Tools are defined in `src/mcp_tools.py`:
|
| 107 |
+
|
| 108 |
+
```python
|
| 109 |
+
def search_pubmed(query: str, max_results: int = 10) -> list[Evidence]:
|
| 110 |
+
"""Search PubMed for biomedical literature.
|
| 111 |
+
|
| 112 |
+
Args:
|
| 113 |
+
query: Search query for PubMed
|
| 114 |
+
max_results: Maximum number of results to return
|
| 115 |
+
|
| 116 |
+
Returns:
|
| 117 |
+
List of Evidence objects with citations
|
| 118 |
+
"""
|
| 119 |
+
tool = PubMedTool()
|
| 120 |
+
result = tool.search(query, max_results=max_results)
|
| 121 |
+
return result.evidence
|
| 122 |
+
```
|
| 123 |
+
|
| 124 |
+
## Adding New Tools
|
| 125 |
+
|
| 126 |
+
To expose additional tools via MCP:
|
| 127 |
+
|
| 128 |
+
1. Add the function to `src/mcp_tools.py`:
|
| 129 |
+
|
| 130 |
+
```python
|
| 131 |
+
def search_openalex(query: str, max_results: int = 10) -> list[Evidence]:
|
| 132 |
+
"""Search OpenAlex for scholarly metadata."""
|
| 133 |
+
tool = OpenAlexTool()
|
| 134 |
+
result = tool.search(query, max_results=max_results)
|
| 135 |
+
return result.evidence
|
| 136 |
+
```
|
| 137 |
+
|
| 138 |
+
2. Register in Gradio app (`src/app.py`):
|
| 139 |
+
|
| 140 |
+
The tools are automatically exposed via Gradio's MCP support when added to the interface.
|
| 141 |
+
|
| 142 |
+
## Troubleshooting
|
| 143 |
+
|
| 144 |
+
### Tools not appearing in Claude Desktop
|
| 145 |
+
|
| 146 |
+
1. Verify DeepBoner is running:
|
| 147 |
+
```bash
|
| 148 |
+
curl http://localhost:7860/gradio_api/mcp/
|
| 149 |
+
```
|
| 150 |
+
|
| 151 |
+
2. Check config syntax:
|
| 152 |
+
```bash
|
| 153 |
+
cat ~/Library/Application\ Support/Claude/claude_desktop_config.json | python -m json.tool
|
| 154 |
+
```
|
| 155 |
+
|
| 156 |
+
3. Restart Claude Desktop
|
| 157 |
+
|
| 158 |
+
### Connection refused
|
| 159 |
+
|
| 160 |
+
- Check DeepBoner is running on port 7860
|
| 161 |
+
- Verify no firewall blocking
|
| 162 |
+
- Try accessing in browser: http://localhost:7860
|
| 163 |
+
|
| 164 |
+
### Slow responses
|
| 165 |
+
|
| 166 |
+
- First query loads ML models
|
| 167 |
+
- HuggingFace Space may need to wake up
|
| 168 |
+
- External APIs have rate limits
|
| 169 |
+
|
| 170 |
+
### Authentication errors
|
| 171 |
+
|
| 172 |
+
MCP server doesn't require authentication for local use. For production:
|
| 173 |
+
- Use API gateway
|
| 174 |
+
- Implement auth middleware
|
| 175 |
+
|
| 176 |
+
## Security Considerations
|
| 177 |
+
|
| 178 |
+
### Local Development
|
| 179 |
+
|
| 180 |
+
Local MCP server is accessible only from localhost by default.
|
| 181 |
+
|
| 182 |
+
### Production
|
| 183 |
+
|
| 184 |
+
For production deployments:
|
| 185 |
+
|
| 186 |
+
1. **Use HTTPS** - Enable TLS via reverse proxy
|
| 187 |
+
2. **Add authentication** - Consider API keys or OAuth
|
| 188 |
+
3. **Rate limit** - Prevent abuse
|
| 189 |
+
4. **Monitor** - Log tool usage
|
| 190 |
+
|
| 191 |
+
### Data Privacy
|
| 192 |
+
|
| 193 |
+
- Search queries are sent to external APIs (PubMed, etc.)
|
| 194 |
+
- Review external API privacy policies
|
| 195 |
+
- Don't expose sensitive research queries
|
| 196 |
+
|
| 197 |
+
## Protocol Details
|
| 198 |
+
|
| 199 |
+
### MCP Protocol Version
|
| 200 |
+
|
| 201 |
+
DeepBoner uses MCP protocol via Gradio 6.x integration.
|
| 202 |
+
|
| 203 |
+
### Request/Response Format
|
| 204 |
+
|
| 205 |
+
Requests follow the MCP specification:
|
| 206 |
+
|
| 207 |
+
```json
|
| 208 |
+
{
|
| 209 |
+
"jsonrpc": "2.0",
|
| 210 |
+
"method": "tools/call",
|
| 211 |
+
"params": {
|
| 212 |
+
"name": "search_pubmed",
|
| 213 |
+
"arguments": {
|
| 214 |
+
"query": "testosterone therapy",
|
| 215 |
+
"max_results": 10
|
| 216 |
+
}
|
| 217 |
+
},
|
| 218 |
+
"id": 1
|
| 219 |
+
}
|
| 220 |
+
```
|
| 221 |
+
|
| 222 |
+
## Related Documentation
|
| 223 |
+
|
| 224 |
+
- [Docker Deployment](docker.md)
|
| 225 |
+
- [HuggingFace Spaces](huggingface-spaces.md)
|
| 226 |
+
- [Component Inventory](../architecture/component-inventory.md)
|
|
@@ -0,0 +1,373 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Code Style Guide
|
| 2 |
+
|
| 3 |
+
> **Last Updated**: 2025-12-06
|
| 4 |
+
|
| 5 |
+
This guide covers code style conventions and tooling for DeepBoner.
|
| 6 |
+
|
| 7 |
+
## Quick Reference
|
| 8 |
+
|
| 9 |
+
```bash
|
| 10 |
+
# Auto-format code
|
| 11 |
+
make format
|
| 12 |
+
|
| 13 |
+
# Check linting
|
| 14 |
+
make lint
|
| 15 |
+
|
| 16 |
+
# Type check
|
| 17 |
+
make typecheck
|
| 18 |
+
|
| 19 |
+
# Run all checks
|
| 20 |
+
make check
|
| 21 |
+
```
|
| 22 |
+
|
| 23 |
+
## Tooling
|
| 24 |
+
|
| 25 |
+
### Ruff (Linting & Formatting)
|
| 26 |
+
|
| 27 |
+
Configuration in `pyproject.toml`:
|
| 28 |
+
|
| 29 |
+
```toml
|
| 30 |
+
[tool.ruff]
|
| 31 |
+
line-length = 100
|
| 32 |
+
target-version = "py311"
|
| 33 |
+
src = ["src", "tests"]
|
| 34 |
+
|
| 35 |
+
[tool.ruff.lint]
|
| 36 |
+
select = [
|
| 37 |
+
"E", # pycodestyle errors
|
| 38 |
+
"F", # pyflakes
|
| 39 |
+
"B", # flake8-bugbear
|
| 40 |
+
"I", # isort
|
| 41 |
+
"N", # pep8-naming
|
| 42 |
+
"UP", # pyupgrade
|
| 43 |
+
"PL", # pylint
|
| 44 |
+
"RUF", # ruff-specific
|
| 45 |
+
]
|
| 46 |
+
```
|
| 47 |
+
|
| 48 |
+
### MyPy (Type Checking)
|
| 49 |
+
|
| 50 |
+
Configuration in `pyproject.toml`:
|
| 51 |
+
|
| 52 |
+
```toml
|
| 53 |
+
[tool.mypy]
|
| 54 |
+
python_version = "3.11"
|
| 55 |
+
strict = true
|
| 56 |
+
ignore_missing_imports = true
|
| 57 |
+
disallow_untyped_defs = true
|
| 58 |
+
warn_return_any = true
|
| 59 |
+
```
|
| 60 |
+
|
| 61 |
+
### Pre-commit Hooks
|
| 62 |
+
|
| 63 |
+
Hooks run automatically on commit:
|
| 64 |
+
|
| 65 |
+
```yaml
|
| 66 |
+
# .pre-commit-config.yaml
|
| 67 |
+
repos:
|
| 68 |
+
- repo: https://github.com/astral-sh/ruff-pre-commit
|
| 69 |
+
hooks:
|
| 70 |
+
- id: ruff
|
| 71 |
+
- id: ruff-format
|
| 72 |
+
- repo: https://github.com/pre-commit/mirrors-mypy
|
| 73 |
+
hooks:
|
| 74 |
+
- id: mypy
|
| 75 |
+
```
|
| 76 |
+
|
| 77 |
+
## Python Style
|
| 78 |
+
|
| 79 |
+
### Type Hints
|
| 80 |
+
|
| 81 |
+
All functions must have type annotations:
|
| 82 |
+
|
| 83 |
+
```python
|
| 84 |
+
# Good
|
| 85 |
+
def search(query: str, limit: int = 10) -> list[Evidence]:
|
| 86 |
+
"""Search for evidence."""
|
| 87 |
+
pass
|
| 88 |
+
|
| 89 |
+
# Bad
|
| 90 |
+
def search(query, limit=10):
|
| 91 |
+
pass
|
| 92 |
+
```
|
| 93 |
+
|
| 94 |
+
Use modern type hint syntax (Python 3.11+):
|
| 95 |
+
|
| 96 |
+
```python
|
| 97 |
+
# Good
|
| 98 |
+
def process(items: list[str] | None) -> dict[str, int]:
|
| 99 |
+
pass
|
| 100 |
+
|
| 101 |
+
# Avoid (old syntax)
|
| 102 |
+
from typing import List, Dict, Optional
|
| 103 |
+
def process(items: Optional[List[str]]) -> Dict[str, int]:
|
| 104 |
+
pass
|
| 105 |
+
```
|
| 106 |
+
|
| 107 |
+
### Docstrings
|
| 108 |
+
|
| 109 |
+
Use Google-style docstrings for public APIs:
|
| 110 |
+
|
| 111 |
+
```python
|
| 112 |
+
def search_pubmed(query: str, max_results: int = 10) -> SearchResult:
|
| 113 |
+
"""Search PubMed for biomedical literature.
|
| 114 |
+
|
| 115 |
+
Args:
|
| 116 |
+
query: The search query string.
|
| 117 |
+
max_results: Maximum number of results to return.
|
| 118 |
+
|
| 119 |
+
Returns:
|
| 120 |
+
SearchResult containing evidence and metadata.
|
| 121 |
+
|
| 122 |
+
Raises:
|
| 123 |
+
SearchError: If the API call fails.
|
| 124 |
+
RateLimitError: If rate limit is exceeded.
|
| 125 |
+
"""
|
| 126 |
+
pass
|
| 127 |
+
```
|
| 128 |
+
|
| 129 |
+
### Class Documentation
|
| 130 |
+
|
| 131 |
+
```python
|
| 132 |
+
class SearchHandler:
|
| 133 |
+
"""Orchestrates parallel searches across multiple sources.
|
| 134 |
+
|
| 135 |
+
This handler implements a scatter-gather pattern to query
|
| 136 |
+
multiple biomedical databases simultaneously.
|
| 137 |
+
|
| 138 |
+
Attributes:
|
| 139 |
+
sources: List of enabled search sources.
|
| 140 |
+
timeout: Timeout for each search in seconds.
|
| 141 |
+
|
| 142 |
+
Example:
|
| 143 |
+
handler = SearchHandler()
|
| 144 |
+
result = handler.search_all("testosterone therapy")
|
| 145 |
+
"""
|
| 146 |
+
|
| 147 |
+
def __init__(self, sources: list[str] | None = None) -> None:
|
| 148 |
+
"""Initialize the search handler.
|
| 149 |
+
|
| 150 |
+
Args:
|
| 151 |
+
sources: Optional list of sources to enable.
|
| 152 |
+
Defaults to all sources.
|
| 153 |
+
"""
|
| 154 |
+
pass
|
| 155 |
+
```
|
| 156 |
+
|
| 157 |
+
### Imports
|
| 158 |
+
|
| 159 |
+
Imports are sorted by isort (via ruff):
|
| 160 |
+
|
| 161 |
+
```python
|
| 162 |
+
# Standard library
|
| 163 |
+
import asyncio
|
| 164 |
+
from datetime import datetime
|
| 165 |
+
from typing import Any
|
| 166 |
+
|
| 167 |
+
# Third-party
|
| 168 |
+
import httpx
|
| 169 |
+
from pydantic import BaseModel
|
| 170 |
+
|
| 171 |
+
# Local
|
| 172 |
+
from src.utils.config import settings
|
| 173 |
+
from src.utils.exceptions import SearchError
|
| 174 |
+
```
|
| 175 |
+
|
| 176 |
+
### Line Length
|
| 177 |
+
|
| 178 |
+
Maximum 100 characters. Break long lines:
|
| 179 |
+
|
| 180 |
+
```python
|
| 181 |
+
# Good - break at logical points
|
| 182 |
+
result = very_long_function_name(
|
| 183 |
+
first_argument=value1,
|
| 184 |
+
second_argument=value2,
|
| 185 |
+
third_argument=value3,
|
| 186 |
+
)
|
| 187 |
+
|
| 188 |
+
# Good - string continuation
|
| 189 |
+
message = (
|
| 190 |
+
"This is a very long message that needs to be "
|
| 191 |
+
"split across multiple lines for readability."
|
| 192 |
+
)
|
| 193 |
+
```
|
| 194 |
+
|
| 195 |
+
### Naming Conventions
|
| 196 |
+
|
| 197 |
+
| Type | Convention | Example |
|
| 198 |
+
|------|------------|---------|
|
| 199 |
+
| Classes | PascalCase | `SearchHandler` |
|
| 200 |
+
| Functions | snake_case | `search_pubmed` |
|
| 201 |
+
| Variables | snake_case | `max_results` |
|
| 202 |
+
| Constants | UPPER_SNAKE | `MAX_ITERATIONS` |
|
| 203 |
+
| Private | leading underscore | `_internal_method` |
|
| 204 |
+
| Type vars | PascalCase | `T`, `ConfigT` |
|
| 205 |
+
|
| 206 |
+
### Exceptions
|
| 207 |
+
|
| 208 |
+
Custom exceptions in `src/utils/exceptions.py`:
|
| 209 |
+
|
| 210 |
+
```python
|
| 211 |
+
from src.utils.exceptions import SearchError
|
| 212 |
+
|
| 213 |
+
# Raising
|
| 214 |
+
raise SearchError(f"API returned {status_code}")
|
| 215 |
+
|
| 216 |
+
# With cause
|
| 217 |
+
try:
|
| 218 |
+
response = client.get(url)
|
| 219 |
+
except httpx.HTTPError as e:
|
| 220 |
+
raise SearchError(f"Request failed: {e}") from e
|
| 221 |
+
```
|
| 222 |
+
|
| 223 |
+
## Pydantic Models
|
| 224 |
+
|
| 225 |
+
### Model Definition
|
| 226 |
+
|
| 227 |
+
```python
|
| 228 |
+
from pydantic import BaseModel, Field
|
| 229 |
+
|
| 230 |
+
class Evidence(BaseModel):
|
| 231 |
+
"""A piece of evidence from search."""
|
| 232 |
+
|
| 233 |
+
content: str = Field(min_length=1, description="The evidence text")
|
| 234 |
+
relevance: float = Field(ge=0.0, le=1.0, default=0.0)
|
| 235 |
+
metadata: dict[str, Any] = Field(default_factory=dict)
|
| 236 |
+
|
| 237 |
+
model_config = {"frozen": True} # Make immutable
|
| 238 |
+
```
|
| 239 |
+
|
| 240 |
+
### Settings
|
| 241 |
+
|
| 242 |
+
```python
|
| 243 |
+
from pydantic_settings import BaseSettings
|
| 244 |
+
|
| 245 |
+
class Settings(BaseSettings):
|
| 246 |
+
"""Application settings from environment."""
|
| 247 |
+
|
| 248 |
+
model_config = SettingsConfigDict(
|
| 249 |
+
env_file=".env",
|
| 250 |
+
case_sensitive=False,
|
| 251 |
+
)
|
| 252 |
+
|
| 253 |
+
max_iterations: int = Field(default=10, ge=1, le=50)
|
| 254 |
+
```
|
| 255 |
+
|
| 256 |
+
## Async Code
|
| 257 |
+
|
| 258 |
+
### Async Functions
|
| 259 |
+
|
| 260 |
+
```python
|
| 261 |
+
async def search_async(query: str) -> SearchResult:
|
| 262 |
+
"""Async search implementation."""
|
| 263 |
+
async with httpx.AsyncClient() as client:
|
| 264 |
+
response = await client.get(url)
|
| 265 |
+
return parse_response(response)
|
| 266 |
+
```
|
| 267 |
+
|
| 268 |
+
### Concurrent Execution
|
| 269 |
+
|
| 270 |
+
```python
|
| 271 |
+
async def search_all(query: str) -> list[SearchResult]:
|
| 272 |
+
"""Search all sources concurrently."""
|
| 273 |
+
tasks = [
|
| 274 |
+
search_pubmed(query),
|
| 275 |
+
search_clinicaltrials(query),
|
| 276 |
+
search_europepmc(query),
|
| 277 |
+
]
|
| 278 |
+
return await asyncio.gather(*tasks, return_exceptions=True)
|
| 279 |
+
```
|
| 280 |
+
|
| 281 |
+
## Comments
|
| 282 |
+
|
| 283 |
+
### When to Comment
|
| 284 |
+
|
| 285 |
+
```python
|
| 286 |
+
# Good: Explain WHY, not WHAT
|
| 287 |
+
# PubMed rate limits without API key - add delay to avoid 429
|
| 288 |
+
await asyncio.sleep(0.34)
|
| 289 |
+
|
| 290 |
+
# Bad: Obvious comment
|
| 291 |
+
# Increment counter
|
| 292 |
+
counter += 1
|
| 293 |
+
```
|
| 294 |
+
|
| 295 |
+
### TODO Comments
|
| 296 |
+
|
| 297 |
+
```python
|
| 298 |
+
# TODO(username): Description of what needs to be done
|
| 299 |
+
# TODO: Short-term fix, proper solution needs X
|
| 300 |
+
```
|
| 301 |
+
|
| 302 |
+
## Ignored Rules
|
| 303 |
+
|
| 304 |
+
Some rules are disabled for good reasons:
|
| 305 |
+
|
| 306 |
+
```toml
|
| 307 |
+
ignore = [
|
| 308 |
+
"PLR0913", # Too many arguments (agents need many params)
|
| 309 |
+
"PLR0912", # Too many branches (complex orchestrator logic)
|
| 310 |
+
"PLR2004", # Magic values (statistical constants)
|
| 311 |
+
"PLW0603", # Global statement (singleton pattern)
|
| 312 |
+
"PLC0415", # Lazy imports for optional dependencies
|
| 313 |
+
]
|
| 314 |
+
```
|
| 315 |
+
|
| 316 |
+
## File Organization
|
| 317 |
+
|
| 318 |
+
### Module Structure
|
| 319 |
+
|
| 320 |
+
```python
|
| 321 |
+
"""Module docstring explaining purpose."""
|
| 322 |
+
|
| 323 |
+
# Imports (sorted)
|
| 324 |
+
import ...
|
| 325 |
+
|
| 326 |
+
# Constants
|
| 327 |
+
MAX_RESULTS = 100
|
| 328 |
+
|
| 329 |
+
# Type definitions
|
| 330 |
+
ResultType = dict[str, Any]
|
| 331 |
+
|
| 332 |
+
# Classes
|
| 333 |
+
class MyClass:
|
| 334 |
+
pass
|
| 335 |
+
|
| 336 |
+
# Functions
|
| 337 |
+
def my_function():
|
| 338 |
+
pass
|
| 339 |
+
|
| 340 |
+
# Module-level code (minimize)
|
| 341 |
+
if __name__ == "__main__":
|
| 342 |
+
main()
|
| 343 |
+
```
|
| 344 |
+
|
| 345 |
+
### Package Structure
|
| 346 |
+
|
| 347 |
+
```
|
| 348 |
+
src/tools/
|
| 349 |
+
βββ __init__.py # Public exports
|
| 350 |
+
βββ base.py # Base classes
|
| 351 |
+
βββ pubmed.py # PubMed implementation
|
| 352 |
+
βββ clinicaltrials.py
|
| 353 |
+
βββ search_handler.py
|
| 354 |
+
```
|
| 355 |
+
|
| 356 |
+
## Code Review Checklist
|
| 357 |
+
|
| 358 |
+
Before submitting a PR:
|
| 359 |
+
|
| 360 |
+
- [ ] All functions have type hints
|
| 361 |
+
- [ ] Public APIs have docstrings
|
| 362 |
+
- [ ] `make check` passes
|
| 363 |
+
- [ ] No hardcoded credentials
|
| 364 |
+
- [ ] Error cases are handled
|
| 365 |
+
- [ ] Tests cover new code
|
| 366 |
+
|
| 367 |
+
---
|
| 368 |
+
|
| 369 |
+
## Related Documentation
|
| 370 |
+
|
| 371 |
+
- [Testing Guide](testing.md)
|
| 372 |
+
- [Contributing Guide](../../CONTRIBUTING.md)
|
| 373 |
+
- [Architecture Overview](../architecture/overview.md)
|
|
@@ -0,0 +1,191 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Release Process
|
| 2 |
+
|
| 3 |
+
> **Last Updated**: 2025-12-06
|
| 4 |
+
|
| 5 |
+
This document describes the release workflow for DeepBoner.
|
| 6 |
+
|
| 7 |
+
## Version Numbering
|
| 8 |
+
|
| 9 |
+
DeepBoner uses [Semantic Versioning](https://semver.org/):
|
| 10 |
+
|
| 11 |
+
```
|
| 12 |
+
MAJOR.MINOR.PATCH
|
| 13 |
+
|
| 14 |
+
1.0.0 - First stable release
|
| 15 |
+
0.2.0 - New features (backwards compatible)
|
| 16 |
+
0.1.1 - Bug fixes only
|
| 17 |
+
```
|
| 18 |
+
|
| 19 |
+
### Pre-release Versions
|
| 20 |
+
|
| 21 |
+
```
|
| 22 |
+
0.1.0-alpha.1 - Early development
|
| 23 |
+
0.1.0-beta.1 - Feature complete, testing
|
| 24 |
+
0.1.0-rc.1 - Release candidate
|
| 25 |
+
```
|
| 26 |
+
|
| 27 |
+
## Release Workflow
|
| 28 |
+
|
| 29 |
+
### 1. Prepare the Release
|
| 30 |
+
|
| 31 |
+
```bash
|
| 32 |
+
# Ensure you're on main and up to date
|
| 33 |
+
git checkout main
|
| 34 |
+
git pull origin main
|
| 35 |
+
|
| 36 |
+
# Run all checks
|
| 37 |
+
make check
|
| 38 |
+
```
|
| 39 |
+
|
| 40 |
+
### 2. Update Version
|
| 41 |
+
|
| 42 |
+
Edit `pyproject.toml`:
|
| 43 |
+
|
| 44 |
+
```toml
|
| 45 |
+
[project]
|
| 46 |
+
version = "0.2.0" # Update this
|
| 47 |
+
```
|
| 48 |
+
|
| 49 |
+
### 3. Update CHANGELOG
|
| 50 |
+
|
| 51 |
+
Add release notes to `CHANGELOG.md`:
|
| 52 |
+
|
| 53 |
+
```markdown
|
| 54 |
+
## [0.2.0] - 2025-12-15
|
| 55 |
+
|
| 56 |
+
### Added
|
| 57 |
+
- New feature X
|
| 58 |
+
|
| 59 |
+
### Fixed
|
| 60 |
+
- Bug in Y
|
| 61 |
+
|
| 62 |
+
### Changed
|
| 63 |
+
- Improved Z
|
| 64 |
+
```
|
| 65 |
+
|
| 66 |
+
### 4. Create Release Commit
|
| 67 |
+
|
| 68 |
+
```bash
|
| 69 |
+
git add pyproject.toml CHANGELOG.md
|
| 70 |
+
git commit -m "release: v0.2.0"
|
| 71 |
+
```
|
| 72 |
+
|
| 73 |
+
### 5. Tag the Release
|
| 74 |
+
|
| 75 |
+
```bash
|
| 76 |
+
git tag -a v0.2.0 -m "Release v0.2.0"
|
| 77 |
+
```
|
| 78 |
+
|
| 79 |
+
### 6. Push
|
| 80 |
+
|
| 81 |
+
```bash
|
| 82 |
+
git push origin main
|
| 83 |
+
git push origin v0.2.0
|
| 84 |
+
```
|
| 85 |
+
|
| 86 |
+
### 7. Create GitHub Release
|
| 87 |
+
|
| 88 |
+
1. Go to GitHub β Releases β New Release
|
| 89 |
+
2. Select the tag (v0.2.0)
|
| 90 |
+
3. Copy release notes from CHANGELOG
|
| 91 |
+
4. Publish release
|
| 92 |
+
|
| 93 |
+
### 8. Deploy to HuggingFace Spaces
|
| 94 |
+
|
| 95 |
+
```bash
|
| 96 |
+
# Push to HuggingFace
|
| 97 |
+
git push huggingface-upstream main
|
| 98 |
+
```
|
| 99 |
+
|
| 100 |
+
## Release Checklist
|
| 101 |
+
|
| 102 |
+
### Before Release
|
| 103 |
+
|
| 104 |
+
- [ ] All tests pass (`make check`)
|
| 105 |
+
- [ ] CHANGELOG updated
|
| 106 |
+
- [ ] Version bumped in pyproject.toml
|
| 107 |
+
- [ ] Documentation updated
|
| 108 |
+
- [ ] No outstanding critical bugs
|
| 109 |
+
- [ ] Security audit clean (`uv run pip-audit`)
|
| 110 |
+
|
| 111 |
+
### After Release
|
| 112 |
+
|
| 113 |
+
- [ ] GitHub release created
|
| 114 |
+
- [ ] HuggingFace Space updated
|
| 115 |
+
- [ ] Announce release (if significant)
|
| 116 |
+
|
| 117 |
+
## Hotfix Process
|
| 118 |
+
|
| 119 |
+
For urgent fixes on released versions:
|
| 120 |
+
|
| 121 |
+
```bash
|
| 122 |
+
# Create hotfix branch from tag
|
| 123 |
+
git checkout -b hotfix/0.1.1 v0.1.0
|
| 124 |
+
|
| 125 |
+
# Make fix
|
| 126 |
+
# ...
|
| 127 |
+
|
| 128 |
+
# Bump patch version
|
| 129 |
+
# Update CHANGELOG
|
| 130 |
+
|
| 131 |
+
# Commit and tag
|
| 132 |
+
git commit -m "fix: critical bug in X"
|
| 133 |
+
git tag -a v0.1.1 -m "Hotfix v0.1.1"
|
| 134 |
+
|
| 135 |
+
# Push
|
| 136 |
+
git push origin v0.1.1
|
| 137 |
+
|
| 138 |
+
# Merge back to main
|
| 139 |
+
git checkout main
|
| 140 |
+
git merge hotfix/0.1.1
|
| 141 |
+
git push origin main
|
| 142 |
+
```
|
| 143 |
+
|
| 144 |
+
## CI/CD Integration
|
| 145 |
+
|
| 146 |
+
Releases trigger GitHub Actions:
|
| 147 |
+
|
| 148 |
+
```yaml
|
| 149 |
+
on:
|
| 150 |
+
push:
|
| 151 |
+
tags:
|
| 152 |
+
- 'v*'
|
| 153 |
+
|
| 154 |
+
jobs:
|
| 155 |
+
release:
|
| 156 |
+
runs-on: ubuntu-latest
|
| 157 |
+
steps:
|
| 158 |
+
- uses: actions/checkout@v4
|
| 159 |
+
- name: Build and test
|
| 160 |
+
run: make check
|
| 161 |
+
```
|
| 162 |
+
|
| 163 |
+
## Rollback Procedure
|
| 164 |
+
|
| 165 |
+
If a release has critical issues:
|
| 166 |
+
|
| 167 |
+
```bash
|
| 168 |
+
# Revert to previous version in HuggingFace
|
| 169 |
+
git push huggingface-upstream v0.1.0:main --force
|
| 170 |
+
|
| 171 |
+
# Document in CHANGELOG
|
| 172 |
+
# Plan hotfix release
|
| 173 |
+
```
|
| 174 |
+
|
| 175 |
+
## Version Locations
|
| 176 |
+
|
| 177 |
+
Keep these in sync:
|
| 178 |
+
|
| 179 |
+
| File | Field |
|
| 180 |
+
|------|-------|
|
| 181 |
+
| `pyproject.toml` | `version = "X.Y.Z"` |
|
| 182 |
+
| `CHANGELOG.md` | `## [X.Y.Z] - YYYY-MM-DD` |
|
| 183 |
+
| Git tag | `vX.Y.Z` |
|
| 184 |
+
|
| 185 |
+
---
|
| 186 |
+
|
| 187 |
+
## Related Documentation
|
| 188 |
+
|
| 189 |
+
- [CHANGELOG](../../CHANGELOG.md)
|
| 190 |
+
- [Contributing Guide](../../CONTRIBUTING.md)
|
| 191 |
+
- [Deployment Guide](../deployment/docker.md)
|
|
@@ -0,0 +1,408 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Testing Guide
|
| 2 |
+
|
| 3 |
+
> **Last Updated**: 2025-12-06
|
| 4 |
+
|
| 5 |
+
This guide covers testing strategy, patterns, and best practices for DeepBoner.
|
| 6 |
+
|
| 7 |
+
## Quick Reference
|
| 8 |
+
|
| 9 |
+
```bash
|
| 10 |
+
# Run all tests
|
| 11 |
+
make test
|
| 12 |
+
|
| 13 |
+
# Run with coverage
|
| 14 |
+
make test-cov
|
| 15 |
+
|
| 16 |
+
# Run specific file
|
| 17 |
+
uv run pytest tests/unit/utils/test_config.py -v
|
| 18 |
+
|
| 19 |
+
# Run specific test
|
| 20 |
+
uv run pytest tests/unit/utils/test_config.py::TestSettings::test_default -v
|
| 21 |
+
|
| 22 |
+
# Run by marker
|
| 23 |
+
uv run pytest -m unit # Unit tests only
|
| 24 |
+
uv run pytest -m integration # Integration tests only
|
| 25 |
+
uv run pytest -m "not slow" # Skip slow tests
|
| 26 |
+
```
|
| 27 |
+
|
| 28 |
+
## Test Organization
|
| 29 |
+
|
| 30 |
+
```
|
| 31 |
+
tests/
|
| 32 |
+
βββ conftest.py # Shared fixtures
|
| 33 |
+
βββ unit/ # Unit tests (mocked, fast)
|
| 34 |
+
β βββ orchestrators/
|
| 35 |
+
β βββ agents/
|
| 36 |
+
β βββ clients/
|
| 37 |
+
β βββ tools/
|
| 38 |
+
β βββ services/
|
| 39 |
+
β βββ utils/
|
| 40 |
+
β βββ prompts/
|
| 41 |
+
β βββ agent_factory/
|
| 42 |
+
β βββ config/
|
| 43 |
+
β βββ graph/
|
| 44 |
+
β βββ mcp/
|
| 45 |
+
βββ integration/ # Integration tests (real APIs)
|
| 46 |
+
βββ e2e/ # End-to-end tests
|
| 47 |
+
```
|
| 48 |
+
|
| 49 |
+
### Directory Mapping
|
| 50 |
+
|
| 51 |
+
Tests mirror the `src/` structure:
|
| 52 |
+
- `src/tools/pubmed.py` β `tests/unit/tools/test_pubmed.py`
|
| 53 |
+
- `src/utils/config.py` β `tests/unit/utils/test_config.py`
|
| 54 |
+
|
| 55 |
+
## Test Markers
|
| 56 |
+
|
| 57 |
+
### Available Markers
|
| 58 |
+
|
| 59 |
+
| Marker | Purpose | Example |
|
| 60 |
+
|--------|---------|---------|
|
| 61 |
+
| `@pytest.mark.unit` | Unit tests (mocked) | Most tests |
|
| 62 |
+
| `@pytest.mark.integration` | Real API calls | API testing |
|
| 63 |
+
| `@pytest.mark.slow` | Long-running tests | Full pipeline |
|
| 64 |
+
| `@pytest.mark.e2e` | End-to-end tests | Complete flows |
|
| 65 |
+
|
| 66 |
+
### Using Markers
|
| 67 |
+
|
| 68 |
+
```python
|
| 69 |
+
import pytest
|
| 70 |
+
|
| 71 |
+
@pytest.mark.unit
|
| 72 |
+
def test_search_returns_results():
|
| 73 |
+
"""Unit test with mocked API."""
|
| 74 |
+
pass
|
| 75 |
+
|
| 76 |
+
@pytest.mark.integration
|
| 77 |
+
def test_pubmed_real_api():
|
| 78 |
+
"""Integration test with real PubMed API."""
|
| 79 |
+
pass
|
| 80 |
+
```
|
| 81 |
+
|
| 82 |
+
### Running by Marker
|
| 83 |
+
|
| 84 |
+
```bash
|
| 85 |
+
uv run pytest -m unit # Only unit tests
|
| 86 |
+
uv run pytest -m "not integration" # Skip integration tests
|
| 87 |
+
uv run pytest -m "unit or slow" # Unit OR slow tests
|
| 88 |
+
```
|
| 89 |
+
|
| 90 |
+
## Test Fixtures
|
| 91 |
+
|
| 92 |
+
### Core Fixtures (conftest.py)
|
| 93 |
+
|
| 94 |
+
#### `mock_httpx_client`
|
| 95 |
+
|
| 96 |
+
Mocks httpx for HTTP testing:
|
| 97 |
+
|
| 98 |
+
```python
|
| 99 |
+
def test_pubmed_search(mock_httpx_client):
|
| 100 |
+
mock_httpx_client.get("https://eutils.ncbi.nlm.nih.gov/...").respond(
|
| 101 |
+
200,
|
| 102 |
+
json={"esearchresult": {"idlist": ["12345"]}}
|
| 103 |
+
)
|
| 104 |
+
|
| 105 |
+
tool = PubMedTool()
|
| 106 |
+
result = tool.search("test query")
|
| 107 |
+
assert len(result.evidence) > 0
|
| 108 |
+
```
|
| 109 |
+
|
| 110 |
+
#### `mock_llm_response`
|
| 111 |
+
|
| 112 |
+
Mocks LLM completions:
|
| 113 |
+
|
| 114 |
+
```python
|
| 115 |
+
def test_judge_evaluates(mock_llm_response):
|
| 116 |
+
mock_llm_response("The evidence is sufficient.")
|
| 117 |
+
|
| 118 |
+
judge = JudgeAgent()
|
| 119 |
+
assessment = judge.assess(evidence)
|
| 120 |
+
assert assessment.sufficient
|
| 121 |
+
```
|
| 122 |
+
|
| 123 |
+
#### `sample_evidence`
|
| 124 |
+
|
| 125 |
+
Provides test evidence data:
|
| 126 |
+
|
| 127 |
+
```python
|
| 128 |
+
def test_synthesis(sample_evidence):
|
| 129 |
+
report = synthesizer.create_report(sample_evidence)
|
| 130 |
+
assert report.title
|
| 131 |
+
```
|
| 132 |
+
|
| 133 |
+
### Creating Fixtures
|
| 134 |
+
|
| 135 |
+
```python
|
| 136 |
+
# tests/conftest.py
|
| 137 |
+
|
| 138 |
+
@pytest.fixture
|
| 139 |
+
def mock_search_handler(mocker):
|
| 140 |
+
"""Mock SearchHandler for unit tests."""
|
| 141 |
+
handler = mocker.Mock(spec=SearchHandler)
|
| 142 |
+
handler.search_all.return_value = SearchResult(
|
| 143 |
+
query="test",
|
| 144 |
+
evidence=[],
|
| 145 |
+
sources_searched=["pubmed"],
|
| 146 |
+
total_found=0
|
| 147 |
+
)
|
| 148 |
+
return handler
|
| 149 |
+
```
|
| 150 |
+
|
| 151 |
+
## Mocking Patterns
|
| 152 |
+
|
| 153 |
+
### HTTP Mocking with respx
|
| 154 |
+
|
| 155 |
+
```python
|
| 156 |
+
import respx
|
| 157 |
+
from httpx import Response
|
| 158 |
+
|
| 159 |
+
@pytest.mark.unit
|
| 160 |
+
def test_api_call():
|
| 161 |
+
with respx.mock:
|
| 162 |
+
respx.get("https://api.example.com/data").mock(
|
| 163 |
+
return_value=Response(200, json={"result": "ok"})
|
| 164 |
+
)
|
| 165 |
+
|
| 166 |
+
result = make_api_call()
|
| 167 |
+
assert result == "ok"
|
| 168 |
+
```
|
| 169 |
+
|
| 170 |
+
### General Mocking with pytest-mock
|
| 171 |
+
|
| 172 |
+
```python
|
| 173 |
+
def test_with_mock(mocker):
|
| 174 |
+
# Mock a function
|
| 175 |
+
mock_func = mocker.patch("src.tools.pubmed.fetch_results")
|
| 176 |
+
mock_func.return_value = {"results": []}
|
| 177 |
+
|
| 178 |
+
# Mock a class method
|
| 179 |
+
mocker.patch.object(PubMedTool, "search", return_value=[])
|
| 180 |
+
|
| 181 |
+
# Mock a property
|
| 182 |
+
mocker.patch.object(Settings, "has_openai_key", True)
|
| 183 |
+
```
|
| 184 |
+
|
| 185 |
+
### Mocking Async Functions
|
| 186 |
+
|
| 187 |
+
```python
|
| 188 |
+
import pytest
|
| 189 |
+
from unittest.mock import AsyncMock
|
| 190 |
+
|
| 191 |
+
@pytest.mark.asyncio
|
| 192 |
+
async def test_async_search(mocker):
|
| 193 |
+
mock_search = AsyncMock(return_value=[])
|
| 194 |
+
mocker.patch.object(SearchHandler, "search_all", mock_search)
|
| 195 |
+
|
| 196 |
+
result = await handler.search_all("query")
|
| 197 |
+
assert result == []
|
| 198 |
+
```
|
| 199 |
+
|
| 200 |
+
## Writing Tests
|
| 201 |
+
|
| 202 |
+
### Test Structure (AAA Pattern)
|
| 203 |
+
|
| 204 |
+
```python
|
| 205 |
+
def test_search_handler_aggregates_results():
|
| 206 |
+
"""Verify search handler combines results from multiple sources."""
|
| 207 |
+
# Arrange
|
| 208 |
+
handler = SearchHandler()
|
| 209 |
+
query = "testosterone therapy"
|
| 210 |
+
|
| 211 |
+
# Act
|
| 212 |
+
result = handler.search_all(query)
|
| 213 |
+
|
| 214 |
+
# Assert
|
| 215 |
+
assert len(result.evidence) > 0
|
| 216 |
+
assert "pubmed" in result.sources_searched
|
| 217 |
+
```
|
| 218 |
+
|
| 219 |
+
### Test Naming
|
| 220 |
+
|
| 221 |
+
```python
|
| 222 |
+
# Good: Describes behavior
|
| 223 |
+
def test_judge_returns_continue_when_evidence_insufficient():
|
| 224 |
+
pass
|
| 225 |
+
|
| 226 |
+
def test_search_raises_rate_limit_error_on_429():
|
| 227 |
+
pass
|
| 228 |
+
|
| 229 |
+
# Bad: Vague
|
| 230 |
+
def test_judge():
|
| 231 |
+
pass
|
| 232 |
+
|
| 233 |
+
def test_search_error():
|
| 234 |
+
pass
|
| 235 |
+
```
|
| 236 |
+
|
| 237 |
+
### Testing Exceptions
|
| 238 |
+
|
| 239 |
+
```python
|
| 240 |
+
import pytest
|
| 241 |
+
from src.utils.exceptions import SearchError
|
| 242 |
+
|
| 243 |
+
def test_search_raises_on_api_failure():
|
| 244 |
+
"""Verify SearchError is raised when API returns error."""
|
| 245 |
+
with pytest.raises(SearchError) as exc_info:
|
| 246 |
+
search_with_failing_api()
|
| 247 |
+
|
| 248 |
+
assert "API returned 500" in str(exc_info.value)
|
| 249 |
+
```
|
| 250 |
+
|
| 251 |
+
### Async Tests
|
| 252 |
+
|
| 253 |
+
```python
|
| 254 |
+
import pytest
|
| 255 |
+
|
| 256 |
+
@pytest.mark.asyncio
|
| 257 |
+
async def test_async_search():
|
| 258 |
+
"""Test async search operation."""
|
| 259 |
+
result = await search_handler.search_all("query")
|
| 260 |
+
assert result is not None
|
| 261 |
+
```
|
| 262 |
+
|
| 263 |
+
## Test Data
|
| 264 |
+
|
| 265 |
+
### Using Factories
|
| 266 |
+
|
| 267 |
+
```python
|
| 268 |
+
# tests/factories.py
|
| 269 |
+
|
| 270 |
+
def make_evidence(
|
| 271 |
+
content: str = "Test content",
|
| 272 |
+
source: str = "pubmed",
|
| 273 |
+
relevance: float = 0.8
|
| 274 |
+
) -> Evidence:
|
| 275 |
+
return Evidence(
|
| 276 |
+
content=content,
|
| 277 |
+
citation=Citation(
|
| 278 |
+
source=source,
|
| 279 |
+
title="Test Paper",
|
| 280 |
+
url="https://test.com",
|
| 281 |
+
date="2024-01-01",
|
| 282 |
+
authors=["Test Author"]
|
| 283 |
+
),
|
| 284 |
+
relevance=relevance,
|
| 285 |
+
metadata={}
|
| 286 |
+
)
|
| 287 |
+
```
|
| 288 |
+
|
| 289 |
+
### Parameterized Tests
|
| 290 |
+
|
| 291 |
+
```python
|
| 292 |
+
import pytest
|
| 293 |
+
|
| 294 |
+
@pytest.mark.parametrize("query,expected_count", [
|
| 295 |
+
("testosterone", 10),
|
| 296 |
+
("estrogen therapy", 5),
|
| 297 |
+
("very specific rare condition", 0),
|
| 298 |
+
])
|
| 299 |
+
def test_search_returns_expected_results(query, expected_count, mock_api):
|
| 300 |
+
result = search(query)
|
| 301 |
+
assert len(result.evidence) == expected_count
|
| 302 |
+
```
|
| 303 |
+
|
| 304 |
+
## Coverage
|
| 305 |
+
|
| 306 |
+
### Running with Coverage
|
| 307 |
+
|
| 308 |
+
```bash
|
| 309 |
+
# Terminal report
|
| 310 |
+
make test-cov
|
| 311 |
+
|
| 312 |
+
# HTML report
|
| 313 |
+
uv run pytest --cov=src --cov-report=html
|
| 314 |
+
open htmlcov/index.html
|
| 315 |
+
```
|
| 316 |
+
|
| 317 |
+
### Coverage Configuration
|
| 318 |
+
|
| 319 |
+
From `pyproject.toml`:
|
| 320 |
+
|
| 321 |
+
```toml
|
| 322 |
+
[tool.coverage.run]
|
| 323 |
+
source = ["src"]
|
| 324 |
+
omit = ["*/__init__.py"]
|
| 325 |
+
|
| 326 |
+
[tool.coverage.report]
|
| 327 |
+
exclude_lines = [
|
| 328 |
+
"pragma: no cover",
|
| 329 |
+
"if TYPE_CHECKING:",
|
| 330 |
+
"raise NotImplementedError",
|
| 331 |
+
]
|
| 332 |
+
```
|
| 333 |
+
|
| 334 |
+
### Coverage Targets
|
| 335 |
+
|
| 336 |
+
| Module | Target | Notes |
|
| 337 |
+
|--------|--------|-------|
|
| 338 |
+
| `utils/` | 90%+ | Core utilities |
|
| 339 |
+
| `tools/` | 80%+ | API wrappers |
|
| 340 |
+
| `orchestrators/` | 70%+ | Complex logic |
|
| 341 |
+
| `agents/` | 70%+ | LLM-dependent |
|
| 342 |
+
|
| 343 |
+
## CI Integration
|
| 344 |
+
|
| 345 |
+
Tests run in GitHub Actions:
|
| 346 |
+
|
| 347 |
+
```yaml
|
| 348 |
+
# .github/workflows/ci.yml
|
| 349 |
+
- name: Run Tests
|
| 350 |
+
run: uv run pytest --cov=src --cov-report=xml
|
| 351 |
+
|
| 352 |
+
- name: Upload Coverage
|
| 353 |
+
uses: codecov/codecov-action@v4
|
| 354 |
+
```
|
| 355 |
+
|
| 356 |
+
## Best Practices
|
| 357 |
+
|
| 358 |
+
### Do
|
| 359 |
+
|
| 360 |
+
- Write tests before implementation (TDD)
|
| 361 |
+
- Use descriptive test names
|
| 362 |
+
- Test edge cases and error conditions
|
| 363 |
+
- Keep tests fast (mock external dependencies)
|
| 364 |
+
- Use fixtures for shared setup
|
| 365 |
+
- Test one behavior per test
|
| 366 |
+
|
| 367 |
+
### Don't
|
| 368 |
+
|
| 369 |
+
- Test implementation details
|
| 370 |
+
- Make tests dependent on order
|
| 371 |
+
- Use real API keys in tests
|
| 372 |
+
- Skip error handling tests
|
| 373 |
+
- Leave flaky tests unfixed
|
| 374 |
+
|
| 375 |
+
## Troubleshooting
|
| 376 |
+
|
| 377 |
+
### Tests pass locally but fail in CI
|
| 378 |
+
|
| 379 |
+
1. Check for hardcoded paths
|
| 380 |
+
2. Verify timezone handling
|
| 381 |
+
3. Look for async timing issues
|
| 382 |
+
4. Check environment variables
|
| 383 |
+
|
| 384 |
+
### Async test hangs
|
| 385 |
+
|
| 386 |
+
```python
|
| 387 |
+
# Add timeout
|
| 388 |
+
@pytest.mark.asyncio
|
| 389 |
+
@pytest.mark.timeout(10)
|
| 390 |
+
async def test_with_timeout():
|
| 391 |
+
pass
|
| 392 |
+
```
|
| 393 |
+
|
| 394 |
+
### Mock not working
|
| 395 |
+
|
| 396 |
+
```python
|
| 397 |
+
# Ensure correct import path
|
| 398 |
+
mocker.patch("src.tools.pubmed.PubMedTool") # Correct
|
| 399 |
+
mocker.patch("tools.pubmed.PubMedTool") # Wrong
|
| 400 |
+
```
|
| 401 |
+
|
| 402 |
+
---
|
| 403 |
+
|
| 404 |
+
## Related Documentation
|
| 405 |
+
|
| 406 |
+
- [Code Style Guide](code-style.md)
|
| 407 |
+
- [Contributing Guide](../../CONTRIBUTING.md)
|
| 408 |
+
- [Component Inventory](../architecture/component-inventory.md)
|
|
@@ -0,0 +1,172 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Configuration Guide
|
| 2 |
+
|
| 3 |
+
DeepBoner uses [Pydantic Settings](https://docs.pydantic.dev/latest/concepts/pydantic_settings/) for configuration, loading values from environment variables and `.env` files.
|
| 4 |
+
|
| 5 |
+
## Configuration Sources
|
| 6 |
+
|
| 7 |
+
Settings are loaded in this order (later sources override earlier):
|
| 8 |
+
|
| 9 |
+
1. Default values in code
|
| 10 |
+
2. `.env` file in project root
|
| 11 |
+
3. Environment variables
|
| 12 |
+
|
| 13 |
+
## Quick Setup
|
| 14 |
+
|
| 15 |
+
```bash
|
| 16 |
+
# Copy the template
|
| 17 |
+
cp .env.example .env
|
| 18 |
+
|
| 19 |
+
# Edit with your settings
|
| 20 |
+
nano .env # or your preferred editor
|
| 21 |
+
```
|
| 22 |
+
|
| 23 |
+
## Configuration Categories
|
| 24 |
+
|
| 25 |
+
### LLM Configuration
|
| 26 |
+
|
| 27 |
+
| Variable | Type | Default | Description |
|
| 28 |
+
|----------|------|---------|-------------|
|
| 29 |
+
| `LLM_PROVIDER` | string | `"openai"` | LLM provider: `"openai"` or `"huggingface"` |
|
| 30 |
+
| `OPENAI_API_KEY` | string | None | OpenAI API key (enables premium mode) |
|
| 31 |
+
| `OPENAI_MODEL` | string | `"gpt-5"` | OpenAI model to use |
|
| 32 |
+
| `HUGGINGFACE_MODEL` | string | `"Qwen/Qwen2.5-7B-Instruct"` | HuggingFace model for free tier |
|
| 33 |
+
| `HF_TOKEN` | string | None | HuggingFace token for gated models |
|
| 34 |
+
|
| 35 |
+
**Notes:**
|
| 36 |
+
- If `OPENAI_API_KEY` is set, OpenAI is used automatically
|
| 37 |
+
- Without any key, free HuggingFace tier is used
|
| 38 |
+
- See CLAUDE.md for critical notes on HuggingFace model selection
|
| 39 |
+
|
| 40 |
+
### Embedding Configuration
|
| 41 |
+
|
| 42 |
+
| Variable | Type | Default | Description |
|
| 43 |
+
|----------|------|---------|-------------|
|
| 44 |
+
| `OPENAI_EMBEDDING_MODEL` | string | `"text-embedding-3-small"` | OpenAI embedding model (premium RAG) |
|
| 45 |
+
| `LOCAL_EMBEDDING_MODEL` | string | `"all-MiniLM-L6-v2"` | Local sentence-transformers model |
|
| 46 |
+
|
| 47 |
+
### External Services
|
| 48 |
+
|
| 49 |
+
| Variable | Type | Default | Description |
|
| 50 |
+
|----------|------|---------|-------------|
|
| 51 |
+
| `NCBI_API_KEY` | string | None | NCBI API key for higher PubMed rate limits |
|
| 52 |
+
| `CHROMA_DB_PATH` | string | `"./chroma_db"` | ChromaDB storage path |
|
| 53 |
+
|
| 54 |
+
### Agent Configuration
|
| 55 |
+
|
| 56 |
+
| Variable | Type | Default | Description |
|
| 57 |
+
|----------|------|---------|-------------|
|
| 58 |
+
| `MAX_ITERATIONS` | int | `10` | Maximum search-judge loop iterations (1-50) |
|
| 59 |
+
| `ADVANCED_MAX_ROUNDS` | int | `5` | Max coordination rounds for multi-agent mode |
|
| 60 |
+
| `ADVANCED_TIMEOUT` | float | `600.0` | Timeout for advanced mode in seconds |
|
| 61 |
+
| `SEARCH_TIMEOUT` | int | `30` | Seconds to wait for each search operation |
|
| 62 |
+
|
| 63 |
+
### Logging
|
| 64 |
+
|
| 65 |
+
| Variable | Type | Default | Description |
|
| 66 |
+
|----------|------|---------|-------------|
|
| 67 |
+
| `LOG_LEVEL` | string | `"INFO"` | Logging level: `DEBUG`, `INFO`, `WARNING`, `ERROR` |
|
| 68 |
+
|
| 69 |
+
## Example Configurations
|
| 70 |
+
|
| 71 |
+
### Minimal (Free Tier)
|
| 72 |
+
|
| 73 |
+
```bash
|
| 74 |
+
# .env - No keys required
|
| 75 |
+
LOG_LEVEL=INFO
|
| 76 |
+
MAX_ITERATIONS=5
|
| 77 |
+
```
|
| 78 |
+
|
| 79 |
+
### Development
|
| 80 |
+
|
| 81 |
+
```bash
|
| 82 |
+
# .env
|
| 83 |
+
LOG_LEVEL=DEBUG
|
| 84 |
+
MAX_ITERATIONS=3
|
| 85 |
+
SEARCH_TIMEOUT=15
|
| 86 |
+
```
|
| 87 |
+
|
| 88 |
+
### Production (With OpenAI)
|
| 89 |
+
|
| 90 |
+
```bash
|
| 91 |
+
# .env
|
| 92 |
+
OPENAI_API_KEY=sk-your-production-key
|
| 93 |
+
NCBI_API_KEY=your-ncbi-key
|
| 94 |
+
LOG_LEVEL=WARNING
|
| 95 |
+
MAX_ITERATIONS=10
|
| 96 |
+
CHROMA_DB_PATH=/data/chroma_db
|
| 97 |
+
```
|
| 98 |
+
|
| 99 |
+
### HuggingFace Spaces
|
| 100 |
+
|
| 101 |
+
```bash
|
| 102 |
+
# Set as Secrets in Space Settings
|
| 103 |
+
HF_TOKEN=hf_your-token
|
| 104 |
+
NCBI_API_KEY=your-ncbi-key
|
| 105 |
+
```
|
| 106 |
+
|
| 107 |
+
## Backend Selection Logic
|
| 108 |
+
|
| 109 |
+
The system auto-selects backends based on available keys:
|
| 110 |
+
|
| 111 |
+
```
|
| 112 |
+
Has OPENAI_API_KEY?
|
| 113 |
+
βββ YES β OpenAI GPT-5 (premium)
|
| 114 |
+
βββ NO β HuggingFace Qwen 2.5 7B (free)
|
| 115 |
+
```
|
| 116 |
+
|
| 117 |
+
Both backends use the same orchestration logic - only the LLM differs.
|
| 118 |
+
|
| 119 |
+
## Programmatic Access
|
| 120 |
+
|
| 121 |
+
Access settings in code:
|
| 122 |
+
|
| 123 |
+
```python
|
| 124 |
+
from src.utils.config import settings
|
| 125 |
+
|
| 126 |
+
# Check available backends
|
| 127 |
+
if settings.has_openai_key:
|
| 128 |
+
print("Premium mode available")
|
| 129 |
+
|
| 130 |
+
# Get specific settings
|
| 131 |
+
print(f"Max iterations: {settings.max_iterations}")
|
| 132 |
+
print(f"Log level: {settings.log_level}")
|
| 133 |
+
```
|
| 134 |
+
|
| 135 |
+
## Validation
|
| 136 |
+
|
| 137 |
+
Settings are validated on load:
|
| 138 |
+
|
| 139 |
+
```python
|
| 140 |
+
from src.utils.config import Settings
|
| 141 |
+
|
| 142 |
+
# These will raise ValidationError
|
| 143 |
+
Settings(max_iterations=100) # Must be 1-50
|
| 144 |
+
Settings(log_level="TRACE") # Invalid level
|
| 145 |
+
```
|
| 146 |
+
|
| 147 |
+
## Security Notes
|
| 148 |
+
|
| 149 |
+
- Never commit `.env` files to git
|
| 150 |
+
- Use environment variables in production
|
| 151 |
+
- API keys are never logged
|
| 152 |
+
- See [SECURITY.md](../../SECURITY.md) for full security policy
|
| 153 |
+
|
| 154 |
+
## Troubleshooting
|
| 155 |
+
|
| 156 |
+
**Settings not loading?**
|
| 157 |
+
- Check file is named `.env` (not `.env.txt`)
|
| 158 |
+
- Verify file is in project root
|
| 159 |
+
- Check for syntax errors (no spaces around `=`)
|
| 160 |
+
|
| 161 |
+
**API key not working?**
|
| 162 |
+
- Verify key is valid and not expired
|
| 163 |
+
- Check for trailing whitespace
|
| 164 |
+
- Ensure correct variable name
|
| 165 |
+
|
| 166 |
+
See [Troubleshooting](troubleshooting.md) for more help.
|
| 167 |
+
|
| 168 |
+
## Related Documentation
|
| 169 |
+
|
| 170 |
+
- [Environment Variables Reference](../reference/environment-variables.md)
|
| 171 |
+
- [Installation Guide](installation.md)
|
| 172 |
+
- [Deployment Guide](../deployment/docker.md)
|
|
@@ -0,0 +1,164 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Installation Guide
|
| 2 |
+
|
| 3 |
+
This guide covers installing DeepBoner for development or local use.
|
| 4 |
+
|
| 5 |
+
## Prerequisites
|
| 6 |
+
|
| 7 |
+
### Required
|
| 8 |
+
- **Python 3.11+** - Required for type hints and async features
|
| 9 |
+
- **uv** - Fast Python package manager ([install guide](https://github.com/astral-sh/uv))
|
| 10 |
+
- **Git** - For version control
|
| 11 |
+
|
| 12 |
+
### Optional
|
| 13 |
+
- **Docker** - For containerized deployment
|
| 14 |
+
- **OpenAI API key** - For premium features (GPT-5)
|
| 15 |
+
- **NCBI API key** - For higher PubMed rate limits
|
| 16 |
+
|
| 17 |
+
## Quick Install
|
| 18 |
+
|
| 19 |
+
```bash
|
| 20 |
+
# Clone the repository
|
| 21 |
+
git clone https://github.com/The-Obstacle-Is-The-Way/DeepBoner.git
|
| 22 |
+
cd DeepBoner
|
| 23 |
+
|
| 24 |
+
# Install all dependencies (including dev tools)
|
| 25 |
+
make install
|
| 26 |
+
```
|
| 27 |
+
|
| 28 |
+
This runs `uv sync --all-extras && uv run pre-commit install` behind the scenes.
|
| 29 |
+
|
| 30 |
+
## Manual Installation
|
| 31 |
+
|
| 32 |
+
If you prefer not to use `make`:
|
| 33 |
+
|
| 34 |
+
```bash
|
| 35 |
+
# Install uv if not already installed
|
| 36 |
+
pip install uv
|
| 37 |
+
|
| 38 |
+
# Sync all dependencies
|
| 39 |
+
uv sync --all-extras
|
| 40 |
+
|
| 41 |
+
# Install pre-commit hooks
|
| 42 |
+
uv run pre-commit install
|
| 43 |
+
```
|
| 44 |
+
|
| 45 |
+
## Optional Dependencies
|
| 46 |
+
|
| 47 |
+
DeepBoner has optional dependency groups for specific features:
|
| 48 |
+
|
| 49 |
+
```bash
|
| 50 |
+
# Core only (no dev tools)
|
| 51 |
+
uv sync
|
| 52 |
+
|
| 53 |
+
# With development tools
|
| 54 |
+
uv sync --extra dev
|
| 55 |
+
|
| 56 |
+
# With Microsoft Agent Framework (Magentic)
|
| 57 |
+
uv sync --extra magentic
|
| 58 |
+
|
| 59 |
+
# With LlamaIndex RAG support
|
| 60 |
+
uv sync --extra rag
|
| 61 |
+
|
| 62 |
+
# Everything
|
| 63 |
+
uv sync --all-extras
|
| 64 |
+
```
|
| 65 |
+
|
| 66 |
+
## Environment Configuration
|
| 67 |
+
|
| 68 |
+
1. Copy the example environment file:
|
| 69 |
+
```bash
|
| 70 |
+
cp .env.example .env
|
| 71 |
+
```
|
| 72 |
+
|
| 73 |
+
2. Edit `.env` with your settings:
|
| 74 |
+
```bash
|
| 75 |
+
# Required for premium features
|
| 76 |
+
OPENAI_API_KEY=sk-your-key-here
|
| 77 |
+
|
| 78 |
+
# Optional: Higher PubMed rate limits
|
| 79 |
+
NCBI_API_KEY=your-ncbi-key-here
|
| 80 |
+
|
| 81 |
+
# Optional: HuggingFace token for gated models
|
| 82 |
+
HF_TOKEN=hf_your-token-here
|
| 83 |
+
```
|
| 84 |
+
|
| 85 |
+
See [Configuration Guide](configuration.md) for all options.
|
| 86 |
+
|
| 87 |
+
## Verify Installation
|
| 88 |
+
|
| 89 |
+
Run the quality checks to verify everything works:
|
| 90 |
+
|
| 91 |
+
```bash
|
| 92 |
+
make check
|
| 93 |
+
```
|
| 94 |
+
|
| 95 |
+
This runs:
|
| 96 |
+
- Linting (ruff)
|
| 97 |
+
- Type checking (mypy)
|
| 98 |
+
- Unit tests (pytest)
|
| 99 |
+
|
| 100 |
+
All checks should pass before you start development.
|
| 101 |
+
|
| 102 |
+
## Running the Application
|
| 103 |
+
|
| 104 |
+
Start the Gradio UI:
|
| 105 |
+
|
| 106 |
+
```bash
|
| 107 |
+
uv run python src/app.py
|
| 108 |
+
```
|
| 109 |
+
|
| 110 |
+
Open http://localhost:7860 in your browser.
|
| 111 |
+
|
| 112 |
+
## Docker Installation
|
| 113 |
+
|
| 114 |
+
For containerized deployment:
|
| 115 |
+
|
| 116 |
+
```bash
|
| 117 |
+
# Build the image
|
| 118 |
+
docker build -t deepboner .
|
| 119 |
+
|
| 120 |
+
# Run the container
|
| 121 |
+
docker run -p 7860:7860 --env-file .env deepboner
|
| 122 |
+
```
|
| 123 |
+
|
| 124 |
+
See [Docker Deployment](../deployment/docker.md) for details.
|
| 125 |
+
|
| 126 |
+
## Troubleshooting
|
| 127 |
+
|
| 128 |
+
### Common Issues
|
| 129 |
+
|
| 130 |
+
**uv not found**
|
| 131 |
+
```bash
|
| 132 |
+
pip install uv
|
| 133 |
+
# or
|
| 134 |
+
curl -LsSf https://astral.sh/uv/install.sh | sh
|
| 135 |
+
```
|
| 136 |
+
|
| 137 |
+
**Python version mismatch**
|
| 138 |
+
```bash
|
| 139 |
+
# Check your Python version
|
| 140 |
+
python --version
|
| 141 |
+
|
| 142 |
+
# Should be 3.11 or higher
|
| 143 |
+
# Use pyenv to manage versions if needed
|
| 144 |
+
```
|
| 145 |
+
|
| 146 |
+
**Pre-commit hook failures**
|
| 147 |
+
```bash
|
| 148 |
+
# Run formatting to fix most issues
|
| 149 |
+
make format
|
| 150 |
+
```
|
| 151 |
+
|
| 152 |
+
**Import errors after install**
|
| 153 |
+
```bash
|
| 154 |
+
# Ensure you're using uv run
|
| 155 |
+
uv run python -c "import src.app"
|
| 156 |
+
```
|
| 157 |
+
|
| 158 |
+
See [Troubleshooting](troubleshooting.md) for more solutions.
|
| 159 |
+
|
| 160 |
+
## Next Steps
|
| 161 |
+
|
| 162 |
+
- [Quickstart Guide](quickstart.md) - Run your first query
|
| 163 |
+
- [Configuration Guide](configuration.md) - Configure all options
|
| 164 |
+
- [Architecture Overview](../architecture/overview.md) - Understand the system
|
|
@@ -0,0 +1,147 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Quickstart Guide
|
| 2 |
+
|
| 3 |
+
Get DeepBoner running in 5 minutes.
|
| 4 |
+
|
| 5 |
+
## Prerequisites
|
| 6 |
+
|
| 7 |
+
- Python 3.11+ installed
|
| 8 |
+
- Repository cloned and dependencies installed (see [Installation](installation.md))
|
| 9 |
+
|
| 10 |
+
## 1. Start the Application
|
| 11 |
+
|
| 12 |
+
```bash
|
| 13 |
+
# From the repository root
|
| 14 |
+
uv run python src/app.py
|
| 15 |
+
```
|
| 16 |
+
|
| 17 |
+
You should see:
|
| 18 |
+
```
|
| 19 |
+
Running on local URL: http://127.0.0.1:7860
|
| 20 |
+
```
|
| 21 |
+
|
| 22 |
+
## 2. Open the UI
|
| 23 |
+
|
| 24 |
+
Navigate to http://localhost:7860 in your browser.
|
| 25 |
+
|
| 26 |
+
You'll see a chat interface with:
|
| 27 |
+
- Input field for research questions
|
| 28 |
+
- Optional API key input (for premium features)
|
| 29 |
+
- Research results display
|
| 30 |
+
|
| 31 |
+
## 3. Ask Your First Question
|
| 32 |
+
|
| 33 |
+
Try one of these example queries:
|
| 34 |
+
|
| 35 |
+
```
|
| 36 |
+
What drugs improve female libido post-menopause?
|
| 37 |
+
```
|
| 38 |
+
|
| 39 |
+
```
|
| 40 |
+
Clinical trials for ED alternatives to PDE5 inhibitors?
|
| 41 |
+
```
|
| 42 |
+
|
| 43 |
+
```
|
| 44 |
+
Evidence for testosterone therapy in women with HSDD?
|
| 45 |
+
```
|
| 46 |
+
|
| 47 |
+
## 4. Understanding the Output
|
| 48 |
+
|
| 49 |
+
DeepBoner will:
|
| 50 |
+
|
| 51 |
+
1. **Search** multiple biomedical databases:
|
| 52 |
+
- PubMed (peer-reviewed literature)
|
| 53 |
+
- ClinicalTrials.gov (active/completed trials)
|
| 54 |
+
- Europe PMC (preprints and papers)
|
| 55 |
+
- OpenAlex (scholarly metadata)
|
| 56 |
+
|
| 57 |
+
2. **Judge** evidence quality using LLM
|
| 58 |
+
|
| 59 |
+
3. **Loop** if more evidence is needed
|
| 60 |
+
|
| 61 |
+
4. **Synthesize** a research report with citations
|
| 62 |
+
|
| 63 |
+
You'll see status updates as each phase completes.
|
| 64 |
+
|
| 65 |
+
## 5. Free vs Premium Mode
|
| 66 |
+
|
| 67 |
+
### Free Mode (No API Key)
|
| 68 |
+
|
| 69 |
+
- Uses HuggingFace Inference API
|
| 70 |
+
- Model: Qwen 2.5 7B Instruct
|
| 71 |
+
- Slower but fully functional
|
| 72 |
+
|
| 73 |
+
### Premium Mode (With OpenAI Key)
|
| 74 |
+
|
| 75 |
+
- Enter your OpenAI API key in the UI
|
| 76 |
+
- Uses GPT-5 for better synthesis
|
| 77 |
+
- Faster and more detailed reports
|
| 78 |
+
|
| 79 |
+
To use premium mode:
|
| 80 |
+
1. Get an API key from [OpenAI](https://platform.openai.com)
|
| 81 |
+
2. Enter it in the "OpenAI API Key" field
|
| 82 |
+
3. Your queries will automatically use GPT-5
|
| 83 |
+
|
| 84 |
+
## 6. Using MCP Tools
|
| 85 |
+
|
| 86 |
+
DeepBoner exposes MCP (Model Context Protocol) tools for integration with Claude Desktop and other clients.
|
| 87 |
+
|
| 88 |
+
### MCP Server URL
|
| 89 |
+
```
|
| 90 |
+
http://localhost:7860/gradio_api/mcp/
|
| 91 |
+
```
|
| 92 |
+
|
| 93 |
+
### Available Tools
|
| 94 |
+
- `search_pubmed` - Search peer-reviewed literature
|
| 95 |
+
- `search_clinical_trials` - Search clinical trials
|
| 96 |
+
- `search_europepmc` - Search Europe PMC
|
| 97 |
+
- `search_all_sources` - Search all sources with deduplication
|
| 98 |
+
|
| 99 |
+
### Claude Desktop Configuration
|
| 100 |
+
|
| 101 |
+
Add to your `claude_desktop_config.json`:
|
| 102 |
+
```json
|
| 103 |
+
{
|
| 104 |
+
"mcpServers": {
|
| 105 |
+
"deepboner": {
|
| 106 |
+
"url": "http://localhost:7860/gradio_api/mcp/"
|
| 107 |
+
}
|
| 108 |
+
}
|
| 109 |
+
}
|
| 110 |
+
```
|
| 111 |
+
|
| 112 |
+
## Example Scripts
|
| 113 |
+
|
| 114 |
+
For programmatic usage, see the example scripts:
|
| 115 |
+
|
| 116 |
+
```bash
|
| 117 |
+
# Search demo
|
| 118 |
+
uv run python examples/search_demo/run_search.py
|
| 119 |
+
|
| 120 |
+
# Full orchestrator demo
|
| 121 |
+
uv run python examples/orchestrator_demo/run_agent.py
|
| 122 |
+
|
| 123 |
+
# Multi-agent demo (requires OpenAI key)
|
| 124 |
+
uv run python examples/orchestrator_demo/run_magentic.py
|
| 125 |
+
```
|
| 126 |
+
|
| 127 |
+
## Next Steps
|
| 128 |
+
|
| 129 |
+
- [Configuration Guide](configuration.md) - Customize settings
|
| 130 |
+
- [MCP Integration](../deployment/mcp-integration.md) - Set up Claude Desktop
|
| 131 |
+
- [Architecture Overview](../architecture/overview.md) - Understand how it works
|
| 132 |
+
|
| 133 |
+
## Troubleshooting
|
| 134 |
+
|
| 135 |
+
**Slow first response?**
|
| 136 |
+
- First query loads ML models (sentence-transformers)
|
| 137 |
+
- Subsequent queries are faster
|
| 138 |
+
|
| 139 |
+
**No results?**
|
| 140 |
+
- Check your internet connection
|
| 141 |
+
- External APIs may have rate limits
|
| 142 |
+
|
| 143 |
+
**Rate limit errors?**
|
| 144 |
+
- Add NCBI_API_KEY for higher PubMed limits
|
| 145 |
+
- Wait and retry
|
| 146 |
+
|
| 147 |
+
See [Troubleshooting](troubleshooting.md) for more help.
|
|
@@ -0,0 +1,280 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Troubleshooting Guide
|
| 2 |
+
|
| 3 |
+
Common issues and their solutions.
|
| 4 |
+
|
| 5 |
+
## Installation Issues
|
| 6 |
+
|
| 7 |
+
### uv not found
|
| 8 |
+
|
| 9 |
+
**Symptom:** `command not found: uv`
|
| 10 |
+
|
| 11 |
+
**Solution:**
|
| 12 |
+
```bash
|
| 13 |
+
# Install uv
|
| 14 |
+
pip install uv
|
| 15 |
+
# or
|
| 16 |
+
curl -LsSf https://astral.sh/uv/install.sh | sh
|
| 17 |
+
```
|
| 18 |
+
|
| 19 |
+
### Python version mismatch
|
| 20 |
+
|
| 21 |
+
**Symptom:** `Python 3.11+ required` or syntax errors
|
| 22 |
+
|
| 23 |
+
**Solution:**
|
| 24 |
+
```bash
|
| 25 |
+
# Check version
|
| 26 |
+
python --version
|
| 27 |
+
|
| 28 |
+
# Install Python 3.11+ via pyenv
|
| 29 |
+
pyenv install 3.11
|
| 30 |
+
pyenv local 3.11
|
| 31 |
+
```
|
| 32 |
+
|
| 33 |
+
### Dependency conflicts
|
| 34 |
+
|
| 35 |
+
**Symptom:** Package version conflicts during install
|
| 36 |
+
|
| 37 |
+
**Solution:**
|
| 38 |
+
```bash
|
| 39 |
+
# Clean install
|
| 40 |
+
rm -rf .venv uv.lock
|
| 41 |
+
uv sync --all-extras
|
| 42 |
+
```
|
| 43 |
+
|
| 44 |
+
## Runtime Issues
|
| 45 |
+
|
| 46 |
+
### Slow first query
|
| 47 |
+
|
| 48 |
+
**Symptom:** First query takes 30+ seconds
|
| 49 |
+
|
| 50 |
+
**Cause:** Model loading (sentence-transformers) on first use
|
| 51 |
+
|
| 52 |
+
**Solution:** This is expected. Subsequent queries are faster.
|
| 53 |
+
|
| 54 |
+
### Rate limit errors
|
| 55 |
+
|
| 56 |
+
**Symptom:** `RateLimitError` or 429 HTTP status
|
| 57 |
+
|
| 58 |
+
**Cause:** Too many requests to external APIs
|
| 59 |
+
|
| 60 |
+
**Solutions:**
|
| 61 |
+
1. Add NCBI API key for PubMed:
|
| 62 |
+
```bash
|
| 63 |
+
NCBI_API_KEY=your-key-here
|
| 64 |
+
```
|
| 65 |
+
2. Wait and retry (rate limits reset)
|
| 66 |
+
3. Reduce `MAX_ITERATIONS`
|
| 67 |
+
|
| 68 |
+
### No search results
|
| 69 |
+
|
| 70 |
+
**Symptom:** Empty results from searches
|
| 71 |
+
|
| 72 |
+
**Possible causes:**
|
| 73 |
+
- Network issues
|
| 74 |
+
- External API downtime
|
| 75 |
+
- Query too specific
|
| 76 |
+
|
| 77 |
+
**Solutions:**
|
| 78 |
+
1. Check internet connection
|
| 79 |
+
2. Try a broader query
|
| 80 |
+
3. Check API status:
|
| 81 |
+
- [PubMed Status](https://www.ncbi.nlm.nih.gov/Status/)
|
| 82 |
+
- [ClinicalTrials.gov](https://clinicaltrials.gov/)
|
| 83 |
+
|
| 84 |
+
### HuggingFace 500/401 errors
|
| 85 |
+
|
| 86 |
+
**Symptom:** Internal server errors or auth errors from HuggingFace
|
| 87 |
+
|
| 88 |
+
**Cause:** Large models (70B+) are routed to unreliable third-party providers
|
| 89 |
+
|
| 90 |
+
**Solution:** Use default model (Qwen 2.5 7B) which stays on HuggingFace native infrastructure. See CLAUDE.md for details.
|
| 91 |
+
|
| 92 |
+
### OpenAI API errors
|
| 93 |
+
|
| 94 |
+
**Symptom:** Authentication errors with OpenAI
|
| 95 |
+
|
| 96 |
+
**Solutions:**
|
| 97 |
+
1. Verify key is valid: https://platform.openai.com/api-keys
|
| 98 |
+
2. Check for typos in `.env`
|
| 99 |
+
3. Ensure no trailing whitespace
|
| 100 |
+
4. Check quota: https://platform.openai.com/usage
|
| 101 |
+
|
| 102 |
+
### Import errors
|
| 103 |
+
|
| 104 |
+
**Symptom:** `ModuleNotFoundError` when running
|
| 105 |
+
|
| 106 |
+
**Solution:**
|
| 107 |
+
```bash
|
| 108 |
+
# Always use uv run
|
| 109 |
+
uv run python src/app.py
|
| 110 |
+
|
| 111 |
+
# Not this
|
| 112 |
+
python src/app.py # Won't find dependencies
|
| 113 |
+
```
|
| 114 |
+
|
| 115 |
+
### ChromaDB errors
|
| 116 |
+
|
| 117 |
+
**Symptom:** Embedding or vector store errors
|
| 118 |
+
|
| 119 |
+
**Solutions:**
|
| 120 |
+
```bash
|
| 121 |
+
# Clear the database
|
| 122 |
+
rm -rf ./chroma_db
|
| 123 |
+
|
| 124 |
+
# Verify path is writable
|
| 125 |
+
ls -la ./
|
| 126 |
+
```
|
| 127 |
+
|
| 128 |
+
## Development Issues
|
| 129 |
+
|
| 130 |
+
### Pre-commit hook failures
|
| 131 |
+
|
| 132 |
+
**Symptom:** Commits rejected by pre-commit
|
| 133 |
+
|
| 134 |
+
**Solution:**
|
| 135 |
+
```bash
|
| 136 |
+
# Auto-fix formatting
|
| 137 |
+
make format
|
| 138 |
+
|
| 139 |
+
# Check manually
|
| 140 |
+
make lint
|
| 141 |
+
make typecheck
|
| 142 |
+
```
|
| 143 |
+
|
| 144 |
+
### Type checking errors
|
| 145 |
+
|
| 146 |
+
**Symptom:** mypy errors on valid code
|
| 147 |
+
|
| 148 |
+
**Solutions:**
|
| 149 |
+
```bash
|
| 150 |
+
# Update stubs
|
| 151 |
+
uv add --dev types-package-name
|
| 152 |
+
|
| 153 |
+
# Or add ignore comment (last resort)
|
| 154 |
+
# type: ignore[error-code]
|
| 155 |
+
```
|
| 156 |
+
|
| 157 |
+
### Test failures
|
| 158 |
+
|
| 159 |
+
**Symptom:** Tests pass locally but fail in CI
|
| 160 |
+
|
| 161 |
+
**Possible causes:**
|
| 162 |
+
- Environment differences
|
| 163 |
+
- Async timing issues
|
| 164 |
+
- Missing test data
|
| 165 |
+
|
| 166 |
+
**Solutions:**
|
| 167 |
+
```bash
|
| 168 |
+
# Run exactly like CI
|
| 169 |
+
make check
|
| 170 |
+
|
| 171 |
+
# Run specific test with verbose output
|
| 172 |
+
uv run pytest tests/unit/path/test_file.py -v -s
|
| 173 |
+
```
|
| 174 |
+
|
| 175 |
+
## UI Issues
|
| 176 |
+
|
| 177 |
+
### Gradio not starting
|
| 178 |
+
|
| 179 |
+
**Symptom:** Application exits immediately or port conflict
|
| 180 |
+
|
| 181 |
+
**Solutions:**
|
| 182 |
+
```bash
|
| 183 |
+
# Check if port is in use
|
| 184 |
+
lsof -i :7860
|
| 185 |
+
|
| 186 |
+
# Kill existing process
|
| 187 |
+
kill -9 $(lsof -t -i :7860)
|
| 188 |
+
|
| 189 |
+
# Or use different port
|
| 190 |
+
uv run python -c "import gradio; print(gradio.__version__)"
|
| 191 |
+
```
|
| 192 |
+
|
| 193 |
+
### MCP tools not appearing
|
| 194 |
+
|
| 195 |
+
**Symptom:** Claude Desktop doesn't show DeepBoner tools
|
| 196 |
+
|
| 197 |
+
**Solutions:**
|
| 198 |
+
1. Verify URL: `http://localhost:7860/gradio_api/mcp/`
|
| 199 |
+
2. Check Claude Desktop config syntax
|
| 200 |
+
3. Restart Claude Desktop after config change
|
| 201 |
+
4. Ensure DeepBoner is running
|
| 202 |
+
|
| 203 |
+
## Deployment Issues
|
| 204 |
+
|
| 205 |
+
### Docker build fails
|
| 206 |
+
|
| 207 |
+
**Symptom:** Dockerfile build errors
|
| 208 |
+
|
| 209 |
+
**Solutions:**
|
| 210 |
+
```bash
|
| 211 |
+
# Clean build
|
| 212 |
+
docker build --no-cache -t deepboner .
|
| 213 |
+
|
| 214 |
+
# Check disk space
|
| 215 |
+
docker system df
|
| 216 |
+
docker system prune
|
| 217 |
+
```
|
| 218 |
+
|
| 219 |
+
### Container exits immediately
|
| 220 |
+
|
| 221 |
+
**Symptom:** Container starts and stops
|
| 222 |
+
|
| 223 |
+
**Solution:**
|
| 224 |
+
```bash
|
| 225 |
+
# Check logs
|
| 226 |
+
docker logs <container_id>
|
| 227 |
+
|
| 228 |
+
# Run interactively
|
| 229 |
+
docker run -it deepboner bash
|
| 230 |
+
```
|
| 231 |
+
|
| 232 |
+
### HuggingFace Spaces issues
|
| 233 |
+
|
| 234 |
+
**Symptom:** Space fails to build or run
|
| 235 |
+
|
| 236 |
+
**Solutions:**
|
| 237 |
+
1. Check Spaces logs in HuggingFace UI
|
| 238 |
+
2. Verify `requirements.txt` matches `pyproject.toml`
|
| 239 |
+
3. Check secrets are set correctly
|
| 240 |
+
|
| 241 |
+
## Getting More Help
|
| 242 |
+
|
| 243 |
+
### Enable debug logging
|
| 244 |
+
|
| 245 |
+
```bash
|
| 246 |
+
LOG_LEVEL=DEBUG uv run python src/app.py
|
| 247 |
+
```
|
| 248 |
+
|
| 249 |
+
### Check system info
|
| 250 |
+
|
| 251 |
+
```bash
|
| 252 |
+
uv run python -c "
|
| 253 |
+
import sys
|
| 254 |
+
print(f'Python: {sys.version}')
|
| 255 |
+
|
| 256 |
+
import src
|
| 257 |
+
print(f'DeepBoner loaded')
|
| 258 |
+
|
| 259 |
+
from src.utils.config import settings
|
| 260 |
+
print(f'OpenAI key: {bool(settings.openai_api_key)}')
|
| 261 |
+
print(f'HF key: {bool(settings.hf_token)}')
|
| 262 |
+
"
|
| 263 |
+
```
|
| 264 |
+
|
| 265 |
+
### Report an issue
|
| 266 |
+
|
| 267 |
+
If you can't resolve the issue:
|
| 268 |
+
|
| 269 |
+
1. Search existing issues: https://github.com/The-Obstacle-Is-The-Way/DeepBoner/issues
|
| 270 |
+
2. Create a new issue with:
|
| 271 |
+
- Steps to reproduce
|
| 272 |
+
- Expected vs actual behavior
|
| 273 |
+
- Environment info (Python version, OS)
|
| 274 |
+
- Relevant logs (redact API keys)
|
| 275 |
+
|
| 276 |
+
## Related Documentation
|
| 277 |
+
|
| 278 |
+
- [Installation Guide](installation.md)
|
| 279 |
+
- [Configuration Guide](configuration.md)
|
| 280 |
+
- [SECURITY.md](../../SECURITY.md)
|
|
@@ -0,0 +1,185 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Configuration Reference
|
| 2 |
+
|
| 3 |
+
> **Last Updated**: 2025-12-06
|
| 4 |
+
|
| 5 |
+
Complete reference for all configuration options in DeepBoner.
|
| 6 |
+
|
| 7 |
+
## Configuration System
|
| 8 |
+
|
| 9 |
+
DeepBoner uses [Pydantic Settings](https://docs.pydantic.dev/latest/concepts/pydantic_settings/) for configuration management.
|
| 10 |
+
|
| 11 |
+
### Loading Order
|
| 12 |
+
|
| 13 |
+
1. Default values in code (`src/utils/config.py`)
|
| 14 |
+
2. `.env` file in project root
|
| 15 |
+
3. Environment variables (highest priority)
|
| 16 |
+
|
| 17 |
+
### Location
|
| 18 |
+
|
| 19 |
+
```
|
| 20 |
+
/home/user/DeepBoner/
|
| 21 |
+
βββ .env # Your configuration (not in git)
|
| 22 |
+
βββ .env.example # Template (in git)
|
| 23 |
+
βββ src/utils/config.py # Settings class
|
| 24 |
+
```
|
| 25 |
+
|
| 26 |
+
## Settings Class
|
| 27 |
+
|
| 28 |
+
```python
|
| 29 |
+
from src.utils.config import settings
|
| 30 |
+
|
| 31 |
+
# Access settings
|
| 32 |
+
print(settings.max_iterations)
|
| 33 |
+
print(settings.has_openai_key)
|
| 34 |
+
```
|
| 35 |
+
|
| 36 |
+
## Configuration Categories
|
| 37 |
+
|
| 38 |
+
### LLM Configuration
|
| 39 |
+
|
| 40 |
+
| Setting | Type | Default | Env Variable | Description |
|
| 41 |
+
|---------|------|---------|--------------|-------------|
|
| 42 |
+
| `llm_provider` | Literal["openai", "huggingface"] | `"openai"` | `LLM_PROVIDER` | LLM backend to use |
|
| 43 |
+
| `openai_api_key` | str \| None | None | `OPENAI_API_KEY` | OpenAI API key |
|
| 44 |
+
| `openai_model` | str | `"gpt-5"` | `OPENAI_MODEL` | OpenAI model name |
|
| 45 |
+
| `huggingface_model` | str \| None | `"Qwen/Qwen2.5-7B-Instruct"` | `HUGGINGFACE_MODEL` | HuggingFace model |
|
| 46 |
+
| `hf_token` | str \| None | None | `HF_TOKEN` | HuggingFace API token |
|
| 47 |
+
|
| 48 |
+
### Embedding Configuration
|
| 49 |
+
|
| 50 |
+
| Setting | Type | Default | Env Variable | Description |
|
| 51 |
+
|---------|------|---------|--------------|-------------|
|
| 52 |
+
| `openai_embedding_model` | str | `"text-embedding-3-small"` | `OPENAI_EMBEDDING_MODEL` | OpenAI embeddings model |
|
| 53 |
+
| `local_embedding_model` | str | `"all-MiniLM-L6-v2"` | `LOCAL_EMBEDDING_MODEL` | Local sentence-transformers model |
|
| 54 |
+
|
| 55 |
+
### External Services
|
| 56 |
+
|
| 57 |
+
| Setting | Type | Default | Env Variable | Description |
|
| 58 |
+
|---------|------|---------|--------------|-------------|
|
| 59 |
+
| `ncbi_api_key` | str \| None | None | `NCBI_API_KEY` | NCBI API key for PubMed |
|
| 60 |
+
| `chroma_db_path` | str | `"./chroma_db"` | `CHROMA_DB_PATH` | ChromaDB storage path |
|
| 61 |
+
|
| 62 |
+
### Agent Configuration
|
| 63 |
+
|
| 64 |
+
| Setting | Type | Default | Env Variable | Description |
|
| 65 |
+
|---------|------|---------|--------------|-------------|
|
| 66 |
+
| `max_iterations` | int | 10 | `MAX_ITERATIONS` | Max search-judge iterations (1-50) |
|
| 67 |
+
| `advanced_max_rounds` | int | 5 | `ADVANCED_MAX_ROUNDS` | Max multi-agent rounds (1-20) |
|
| 68 |
+
| `advanced_timeout` | float | 600.0 | `ADVANCED_TIMEOUT` | Advanced mode timeout seconds (60-900) |
|
| 69 |
+
| `search_timeout` | int | 30 | `SEARCH_TIMEOUT` | Per-search timeout seconds |
|
| 70 |
+
|
| 71 |
+
### Domain Configuration
|
| 72 |
+
|
| 73 |
+
| Setting | Type | Default | Env Variable | Description |
|
| 74 |
+
|---------|------|---------|--------------|-------------|
|
| 75 |
+
| `research_domain` | ResearchDomain | `SEXUAL_HEALTH` | `RESEARCH_DOMAIN` | Research domain focus |
|
| 76 |
+
|
| 77 |
+
### Logging
|
| 78 |
+
|
| 79 |
+
| Setting | Type | Default | Env Variable | Description |
|
| 80 |
+
|---------|------|---------|--------------|-------------|
|
| 81 |
+
| `log_level` | Literal["DEBUG", "INFO", "WARNING", "ERROR"] | `"INFO"` | `LOG_LEVEL` | Logging verbosity |
|
| 82 |
+
|
| 83 |
+
## Helper Properties
|
| 84 |
+
|
| 85 |
+
The Settings class provides convenience properties:
|
| 86 |
+
|
| 87 |
+
```python
|
| 88 |
+
settings.has_openai_key # bool - Is OpenAI key set?
|
| 89 |
+
settings.has_huggingface_key # bool - Is HF token set?
|
| 90 |
+
settings.has_any_llm_key # bool - Any LLM key available?
|
| 91 |
+
```
|
| 92 |
+
|
| 93 |
+
## Helper Methods
|
| 94 |
+
|
| 95 |
+
```python
|
| 96 |
+
# Get API key for configured provider
|
| 97 |
+
api_key = settings.get_api_key()
|
| 98 |
+
|
| 99 |
+
# Get OpenAI key (raises ConfigurationError if not set)
|
| 100 |
+
openai_key = settings.get_openai_api_key()
|
| 101 |
+
```
|
| 102 |
+
|
| 103 |
+
## Backend Selection Logic
|
| 104 |
+
|
| 105 |
+
```python
|
| 106 |
+
# Automatic backend selection
|
| 107 |
+
if settings.has_openai_key:
|
| 108 |
+
# Use OpenAI GPT-5
|
| 109 |
+
client = OpenAIChatClient(api_key=settings.openai_api_key)
|
| 110 |
+
else:
|
| 111 |
+
# Use HuggingFace free tier
|
| 112 |
+
client = HuggingFaceChatClient(model=settings.huggingface_model)
|
| 113 |
+
```
|
| 114 |
+
|
| 115 |
+
## Validation
|
| 116 |
+
|
| 117 |
+
Settings are validated on load:
|
| 118 |
+
|
| 119 |
+
```python
|
| 120 |
+
# These will raise ValidationError
|
| 121 |
+
Settings(max_iterations=100) # Must be 1-50
|
| 122 |
+
Settings(log_level="TRACE") # Invalid level
|
| 123 |
+
Settings(advanced_timeout=10) # Minimum is 60
|
| 124 |
+
```
|
| 125 |
+
|
| 126 |
+
## Example Configurations
|
| 127 |
+
|
| 128 |
+
### Minimal (Free Tier)
|
| 129 |
+
|
| 130 |
+
```bash
|
| 131 |
+
# .env
|
| 132 |
+
LOG_LEVEL=INFO
|
| 133 |
+
MAX_ITERATIONS=5
|
| 134 |
+
```
|
| 135 |
+
|
| 136 |
+
### Development
|
| 137 |
+
|
| 138 |
+
```bash
|
| 139 |
+
# .env
|
| 140 |
+
LOG_LEVEL=DEBUG
|
| 141 |
+
MAX_ITERATIONS=3
|
| 142 |
+
SEARCH_TIMEOUT=15
|
| 143 |
+
```
|
| 144 |
+
|
| 145 |
+
### Production (Premium)
|
| 146 |
+
|
| 147 |
+
```bash
|
| 148 |
+
# .env
|
| 149 |
+
OPENAI_API_KEY=sk-...
|
| 150 |
+
NCBI_API_KEY=...
|
| 151 |
+
LOG_LEVEL=WARNING
|
| 152 |
+
MAX_ITERATIONS=10
|
| 153 |
+
ADVANCED_TIMEOUT=300
|
| 154 |
+
CHROMA_DB_PATH=/data/chroma
|
| 155 |
+
```
|
| 156 |
+
|
| 157 |
+
### HuggingFace Spaces
|
| 158 |
+
|
| 159 |
+
Set as Secrets (not Variables) in Space Settings:
|
| 160 |
+
|
| 161 |
+
```
|
| 162 |
+
HF_TOKEN=hf_...
|
| 163 |
+
NCBI_API_KEY=...
|
| 164 |
+
```
|
| 165 |
+
|
| 166 |
+
## Programmatic Configuration
|
| 167 |
+
|
| 168 |
+
Override settings in code (useful for testing):
|
| 169 |
+
|
| 170 |
+
```python
|
| 171 |
+
from src.utils.config import Settings
|
| 172 |
+
|
| 173 |
+
# Create with overrides
|
| 174 |
+
test_settings = Settings(
|
| 175 |
+
max_iterations=3,
|
| 176 |
+
log_level="DEBUG",
|
| 177 |
+
_env_file=None # Ignore .env
|
| 178 |
+
)
|
| 179 |
+
```
|
| 180 |
+
|
| 181 |
+
## Related Documentation
|
| 182 |
+
|
| 183 |
+
- [Environment Variables](environment-variables.md)
|
| 184 |
+
- [Getting Started - Configuration](../getting-started/configuration.md)
|
| 185 |
+
- [Troubleshooting](../getting-started/troubleshooting.md)
|
|
@@ -0,0 +1,284 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Environment Variables Reference
|
| 2 |
+
|
| 3 |
+
> **Last Updated**: 2025-12-06
|
| 4 |
+
|
| 5 |
+
Complete reference for all environment variables used by DeepBoner.
|
| 6 |
+
|
| 7 |
+
## Quick Reference
|
| 8 |
+
|
| 9 |
+
| Variable | Required | Default | Description |
|
| 10 |
+
|----------|----------|---------|-------------|
|
| 11 |
+
| `OPENAI_API_KEY` | No* | - | OpenAI API key |
|
| 12 |
+
| `HF_TOKEN` | No | - | HuggingFace token |
|
| 13 |
+
| `NCBI_API_KEY` | No | - | NCBI/PubMed API key |
|
| 14 |
+
| `LLM_PROVIDER` | No | `openai` | LLM backend |
|
| 15 |
+
| `MAX_ITERATIONS` | No | `10` | Max search iterations |
|
| 16 |
+
| `LOG_LEVEL` | No | `INFO` | Logging level |
|
| 17 |
+
|
| 18 |
+
*At least one of OPENAI_API_KEY or HF_TOKEN is needed for full functionality.
|
| 19 |
+
|
| 20 |
+
## LLM Configuration
|
| 21 |
+
|
| 22 |
+
### OPENAI_API_KEY
|
| 23 |
+
|
| 24 |
+
OpenAI API key for premium features.
|
| 25 |
+
|
| 26 |
+
```bash
|
| 27 |
+
OPENAI_API_KEY=sk-proj-xxxx
|
| 28 |
+
```
|
| 29 |
+
|
| 30 |
+
- **Format:** Starts with `sk-` or `sk-proj-`
|
| 31 |
+
- **Source:** https://platform.openai.com/api-keys
|
| 32 |
+
- **Effect:** Enables OpenAI GPT-5 as the LLM backend
|
| 33 |
+
|
| 34 |
+
### ANTHROPIC_API_KEY
|
| 35 |
+
|
| 36 |
+
Anthropic API key (reserved for future use).
|
| 37 |
+
|
| 38 |
+
```bash
|
| 39 |
+
ANTHROPIC_API_KEY=sk-ant-xxxx
|
| 40 |
+
```
|
| 41 |
+
|
| 42 |
+
### LLM_PROVIDER
|
| 43 |
+
|
| 44 |
+
Explicitly select LLM provider.
|
| 45 |
+
|
| 46 |
+
```bash
|
| 47 |
+
LLM_PROVIDER=openai # Use OpenAI
|
| 48 |
+
LLM_PROVIDER=huggingface # Use HuggingFace
|
| 49 |
+
```
|
| 50 |
+
|
| 51 |
+
- **Default:** `openai`
|
| 52 |
+
- **Note:** Auto-detection uses OPENAI_API_KEY presence
|
| 53 |
+
|
| 54 |
+
### OPENAI_MODEL
|
| 55 |
+
|
| 56 |
+
OpenAI model name.
|
| 57 |
+
|
| 58 |
+
```bash
|
| 59 |
+
OPENAI_MODEL=gpt-5
|
| 60 |
+
OPENAI_MODEL=gpt-4o
|
| 61 |
+
```
|
| 62 |
+
|
| 63 |
+
- **Default:** `gpt-5`
|
| 64 |
+
|
| 65 |
+
### HUGGINGFACE_MODEL
|
| 66 |
+
|
| 67 |
+
HuggingFace model for free tier.
|
| 68 |
+
|
| 69 |
+
```bash
|
| 70 |
+
HUGGINGFACE_MODEL=Qwen/Qwen2.5-7B-Instruct
|
| 71 |
+
```
|
| 72 |
+
|
| 73 |
+
- **Default:** `Qwen/Qwen2.5-7B-Instruct`
|
| 74 |
+
- **Warning:** Large models (70B+) route to unreliable third-party providers
|
| 75 |
+
|
| 76 |
+
### HF_TOKEN
|
| 77 |
+
|
| 78 |
+
HuggingFace API token.
|
| 79 |
+
|
| 80 |
+
```bash
|
| 81 |
+
HF_TOKEN=hf_xxxx
|
| 82 |
+
```
|
| 83 |
+
|
| 84 |
+
- **Source:** https://huggingface.co/settings/tokens
|
| 85 |
+
- **Effect:** Enables gated models and higher rate limits
|
| 86 |
+
|
| 87 |
+
## Embedding Configuration
|
| 88 |
+
|
| 89 |
+
### OPENAI_EMBEDDING_MODEL
|
| 90 |
+
|
| 91 |
+
OpenAI embedding model for premium RAG.
|
| 92 |
+
|
| 93 |
+
```bash
|
| 94 |
+
OPENAI_EMBEDDING_MODEL=text-embedding-3-small
|
| 95 |
+
OPENAI_EMBEDDING_MODEL=text-embedding-3-large
|
| 96 |
+
```
|
| 97 |
+
|
| 98 |
+
- **Default:** `text-embedding-3-small`
|
| 99 |
+
- **Requires:** `OPENAI_API_KEY`
|
| 100 |
+
|
| 101 |
+
### LOCAL_EMBEDDING_MODEL
|
| 102 |
+
|
| 103 |
+
Local sentence-transformers model.
|
| 104 |
+
|
| 105 |
+
```bash
|
| 106 |
+
LOCAL_EMBEDDING_MODEL=all-MiniLM-L6-v2
|
| 107 |
+
LOCAL_EMBEDDING_MODEL=all-mpnet-base-v2
|
| 108 |
+
```
|
| 109 |
+
|
| 110 |
+
- **Default:** `all-MiniLM-L6-v2`
|
| 111 |
+
- **Note:** Downloaded on first use
|
| 112 |
+
|
| 113 |
+
## External Services
|
| 114 |
+
|
| 115 |
+
### NCBI_API_KEY
|
| 116 |
+
|
| 117 |
+
NCBI API key for higher PubMed rate limits.
|
| 118 |
+
|
| 119 |
+
```bash
|
| 120 |
+
NCBI_API_KEY=xxxx
|
| 121 |
+
```
|
| 122 |
+
|
| 123 |
+
- **Source:** https://www.ncbi.nlm.nih.gov/account/settings/
|
| 124 |
+
- **Effect:** 10 requests/second instead of 3
|
| 125 |
+
|
| 126 |
+
### CHROMA_DB_PATH
|
| 127 |
+
|
| 128 |
+
ChromaDB storage location.
|
| 129 |
+
|
| 130 |
+
```bash
|
| 131 |
+
CHROMA_DB_PATH=./chroma_db
|
| 132 |
+
CHROMA_DB_PATH=/data/vectors
|
| 133 |
+
```
|
| 134 |
+
|
| 135 |
+
- **Default:** `./chroma_db`
|
| 136 |
+
- **Note:** Directory is created if it doesn't exist
|
| 137 |
+
|
| 138 |
+
## Agent Configuration
|
| 139 |
+
|
| 140 |
+
### MAX_ITERATIONS
|
| 141 |
+
|
| 142 |
+
Maximum search-judge loop iterations.
|
| 143 |
+
|
| 144 |
+
```bash
|
| 145 |
+
MAX_ITERATIONS=10
|
| 146 |
+
MAX_ITERATIONS=5 # Faster but less thorough
|
| 147 |
+
MAX_ITERATIONS=20 # More thorough
|
| 148 |
+
```
|
| 149 |
+
|
| 150 |
+
- **Default:** `10`
|
| 151 |
+
- **Range:** `1` to `50`
|
| 152 |
+
|
| 153 |
+
### ADVANCED_MAX_ROUNDS
|
| 154 |
+
|
| 155 |
+
Maximum multi-agent coordination rounds.
|
| 156 |
+
|
| 157 |
+
```bash
|
| 158 |
+
ADVANCED_MAX_ROUNDS=5
|
| 159 |
+
```
|
| 160 |
+
|
| 161 |
+
- **Default:** `5`
|
| 162 |
+
- **Range:** `1` to `20`
|
| 163 |
+
|
| 164 |
+
### ADVANCED_TIMEOUT
|
| 165 |
+
|
| 166 |
+
Timeout for advanced mode in seconds.
|
| 167 |
+
|
| 168 |
+
```bash
|
| 169 |
+
ADVANCED_TIMEOUT=600 # 10 minutes
|
| 170 |
+
ADVANCED_TIMEOUT=300 # 5 minutes
|
| 171 |
+
```
|
| 172 |
+
|
| 173 |
+
- **Default:** `600.0`
|
| 174 |
+
- **Range:** `60.0` to `900.0`
|
| 175 |
+
|
| 176 |
+
### SEARCH_TIMEOUT
|
| 177 |
+
|
| 178 |
+
Per-search operation timeout in seconds.
|
| 179 |
+
|
| 180 |
+
```bash
|
| 181 |
+
SEARCH_TIMEOUT=30
|
| 182 |
+
```
|
| 183 |
+
|
| 184 |
+
- **Default:** `30`
|
| 185 |
+
|
| 186 |
+
## Logging
|
| 187 |
+
|
| 188 |
+
### LOG_LEVEL
|
| 189 |
+
|
| 190 |
+
Logging verbosity.
|
| 191 |
+
|
| 192 |
+
```bash
|
| 193 |
+
LOG_LEVEL=DEBUG # Verbose
|
| 194 |
+
LOG_LEVEL=INFO # Normal
|
| 195 |
+
LOG_LEVEL=WARNING # Errors and warnings
|
| 196 |
+
LOG_LEVEL=ERROR # Errors only
|
| 197 |
+
```
|
| 198 |
+
|
| 199 |
+
- **Default:** `INFO`
|
| 200 |
+
|
| 201 |
+
## Gradio Configuration
|
| 202 |
+
|
| 203 |
+
### GRADIO_SERVER_NAME
|
| 204 |
+
|
| 205 |
+
Server bind address.
|
| 206 |
+
|
| 207 |
+
```bash
|
| 208 |
+
GRADIO_SERVER_NAME=0.0.0.0 # All interfaces
|
| 209 |
+
GRADIO_SERVER_NAME=127.0.0.1 # Localhost only
|
| 210 |
+
```
|
| 211 |
+
|
| 212 |
+
- **Default:** Set in Dockerfile for containers
|
| 213 |
+
|
| 214 |
+
### GRADIO_SERVER_PORT
|
| 215 |
+
|
| 216 |
+
Server port.
|
| 217 |
+
|
| 218 |
+
```bash
|
| 219 |
+
GRADIO_SERVER_PORT=7860
|
| 220 |
+
```
|
| 221 |
+
|
| 222 |
+
- **Default:** `7860`
|
| 223 |
+
|
| 224 |
+
## Python Configuration
|
| 225 |
+
|
| 226 |
+
### PYTHONPATH
|
| 227 |
+
|
| 228 |
+
Python module search path.
|
| 229 |
+
|
| 230 |
+
```bash
|
| 231 |
+
PYTHONPATH=/app
|
| 232 |
+
```
|
| 233 |
+
|
| 234 |
+
- **Note:** Set automatically in Docker
|
| 235 |
+
|
| 236 |
+
## .env File Format
|
| 237 |
+
|
| 238 |
+
```bash
|
| 239 |
+
# Comments start with #
|
| 240 |
+
KEY=value # No quotes needed for simple values
|
| 241 |
+
KEY="value" # Quotes for values with spaces
|
| 242 |
+
KEY='value' # Single quotes also work
|
| 243 |
+
|
| 244 |
+
# Empty lines are ignored
|
| 245 |
+
|
| 246 |
+
# Multi-line values not supported - use single line
|
| 247 |
+
```
|
| 248 |
+
|
| 249 |
+
## Security Notes
|
| 250 |
+
|
| 251 |
+
1. **Never commit .env files** - They're in .gitignore
|
| 252 |
+
2. **Use secrets for production** - HuggingFace Secrets, Docker secrets
|
| 253 |
+
3. **Rotate keys regularly** - Especially for production
|
| 254 |
+
4. **Limit permissions** - Use read-only keys where possible
|
| 255 |
+
|
| 256 |
+
## Validation
|
| 257 |
+
|
| 258 |
+
Variables are validated on application startup:
|
| 259 |
+
|
| 260 |
+
```python
|
| 261 |
+
# Invalid values raise ValidationError
|
| 262 |
+
MAX_ITERATIONS=100 # Error: must be 1-50
|
| 263 |
+
LOG_LEVEL=TRACE # Error: invalid level
|
| 264 |
+
```
|
| 265 |
+
|
| 266 |
+
## Debugging
|
| 267 |
+
|
| 268 |
+
Check loaded configuration:
|
| 269 |
+
|
| 270 |
+
```bash
|
| 271 |
+
LOG_LEVEL=DEBUG uv run python -c "
|
| 272 |
+
from src.utils.config import settings
|
| 273 |
+
print(f'Provider: {settings.llm_provider}')
|
| 274 |
+
print(f'Has OpenAI: {settings.has_openai_key}')
|
| 275 |
+
print(f'Has HF: {settings.has_huggingface_key}')
|
| 276 |
+
print(f'Max Iterations: {settings.max_iterations}')
|
| 277 |
+
"
|
| 278 |
+
```
|
| 279 |
+
|
| 280 |
+
## Related Documentation
|
| 281 |
+
|
| 282 |
+
- [Configuration Reference](configuration.md)
|
| 283 |
+
- [Getting Started - Configuration](../getting-started/configuration.md)
|
| 284 |
+
- [Deployment - Docker](../deployment/docker.md)
|
|
@@ -0,0 +1,409 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Technical Debt Registry
|
| 2 |
+
|
| 3 |
+
> **Last Updated**: 2025-12-06
|
| 4 |
+
|
| 5 |
+
This document tracks all known technical debt items in the DeepBoner codebase.
|
| 6 |
+
|
| 7 |
+
## Summary Dashboard
|
| 8 |
+
|
| 9 |
+
| Category | Open | In Progress | Resolved |
|
| 10 |
+
|----------|------|-------------|----------|
|
| 11 |
+
| Architecture | 3 | 0 | 0 |
|
| 12 |
+
| Code Quality | 4 | 0 | 0 |
|
| 13 |
+
| Testing | 2 | 0 | 0 |
|
| 14 |
+
| Documentation | 2 | 0 | 0 |
|
| 15 |
+
| Performance | 2 | 0 | 0 |
|
| 16 |
+
| Dependencies | 1 | 0 | 0 |
|
| 17 |
+
| **Total** | **14** | **0** | **0** |
|
| 18 |
+
|
| 19 |
+
---
|
| 20 |
+
|
| 21 |
+
## Architecture
|
| 22 |
+
|
| 23 |
+
### DEBT-001: Duplicate Agent Guide Files
|
| 24 |
+
|
| 25 |
+
**Category:** Architecture
|
| 26 |
+
**Severity:** Low
|
| 27 |
+
**Added:** 2025-12-06
|
| 28 |
+
**Status:** Open
|
| 29 |
+
|
| 30 |
+
**Description:**
|
| 31 |
+
CLAUDE.md, AGENTS.md, and GEMINI.md contain ~95% identical content. This violates DRY (Don't Repeat Yourself) and makes maintenance difficult.
|
| 32 |
+
|
| 33 |
+
**Impact:**
|
| 34 |
+
- Changes must be made in 3 places
|
| 35 |
+
- Risk of documentation drift
|
| 36 |
+
- Confusion about which file is canonical
|
| 37 |
+
|
| 38 |
+
**Current Workaround:**
|
| 39 |
+
Manual synchronization when updating.
|
| 40 |
+
|
| 41 |
+
**Proposed Solution:**
|
| 42 |
+
1. Keep CLAUDE.md as the canonical reference
|
| 43 |
+
2. Make AGENTS.md and GEMINI.md symlinks or include-references
|
| 44 |
+
3. Or consolidate into single DEVELOPMENT.md
|
| 45 |
+
|
| 46 |
+
**Effort Estimate:** S
|
| 47 |
+
|
| 48 |
+
---
|
| 49 |
+
|
| 50 |
+
### DEBT-002: Reserved but Empty Directories
|
| 51 |
+
|
| 52 |
+
**Category:** Architecture
|
| 53 |
+
**Severity:** Low
|
| 54 |
+
**Added:** 2025-12-06
|
| 55 |
+
**Status:** Open
|
| 56 |
+
|
| 57 |
+
**Description:**
|
| 58 |
+
`src/database_services/` and `src/retrieval_factory/` exist but are empty placeholders for future features.
|
| 59 |
+
|
| 60 |
+
**Impact:**
|
| 61 |
+
- Confusion about project structure
|
| 62 |
+
- Empty imports may cause issues
|
| 63 |
+
|
| 64 |
+
**Current Workaround:**
|
| 65 |
+
Document as "reserved" in component inventory.
|
| 66 |
+
|
| 67 |
+
**Proposed Solution:**
|
| 68 |
+
Either implement the features or remove the directories.
|
| 69 |
+
|
| 70 |
+
**Effort Estimate:** S
|
| 71 |
+
|
| 72 |
+
---
|
| 73 |
+
|
| 74 |
+
### DEBT-003: Experimental LangGraph Orchestrator
|
| 75 |
+
|
| 76 |
+
**Category:** Architecture
|
| 77 |
+
**Severity:** Medium
|
| 78 |
+
**Added:** 2025-12-06
|
| 79 |
+
**Status:** Open
|
| 80 |
+
|
| 81 |
+
**Description:**
|
| 82 |
+
`src/orchestrators/langgraph_orchestrator.py` is marked as experimental and may not be fully tested or integrated.
|
| 83 |
+
|
| 84 |
+
**Impact:**
|
| 85 |
+
- Unclear which orchestrator is preferred
|
| 86 |
+
- May have untested edge cases
|
| 87 |
+
- Maintenance burden of two orchestrators
|
| 88 |
+
|
| 89 |
+
**Current Workaround:**
|
| 90 |
+
Default to AdvancedOrchestrator in production.
|
| 91 |
+
|
| 92 |
+
**Proposed Solution:**
|
| 93 |
+
Either promote to production status with full testing, or deprecate and remove.
|
| 94 |
+
|
| 95 |
+
**Effort Estimate:** M
|
| 96 |
+
|
| 97 |
+
---
|
| 98 |
+
|
| 99 |
+
## Code Quality
|
| 100 |
+
|
| 101 |
+
### DEBT-004: Complex Orchestrator Logic
|
| 102 |
+
|
| 103 |
+
**Category:** Code Quality
|
| 104 |
+
**Severity:** Medium
|
| 105 |
+
**Added:** 2025-12-06
|
| 106 |
+
**Status:** Open
|
| 107 |
+
|
| 108 |
+
**Description:**
|
| 109 |
+
`src/orchestrators/advanced.py` has complex branching logic that required disabling pylint rules (PLR0912, PLR0913).
|
| 110 |
+
|
| 111 |
+
**Impact:**
|
| 112 |
+
- Difficult to understand and maintain
|
| 113 |
+
- Higher bug risk
|
| 114 |
+
- Harder to test comprehensively
|
| 115 |
+
|
| 116 |
+
**Current Workaround:**
|
| 117 |
+
Suppressed linter warnings with explicit ignores.
|
| 118 |
+
|
| 119 |
+
**Proposed Solution:**
|
| 120 |
+
Refactor into smaller, focused methods. Consider command pattern for orchestration steps.
|
| 121 |
+
|
| 122 |
+
**Effort Estimate:** L
|
| 123 |
+
|
| 124 |
+
---
|
| 125 |
+
|
| 126 |
+
### DEBT-005: Magic Numbers in Code
|
| 127 |
+
|
| 128 |
+
**Category:** Code Quality
|
| 129 |
+
**Severity:** Low
|
| 130 |
+
**Added:** 2025-12-06
|
| 131 |
+
**Status:** Open
|
| 132 |
+
|
| 133 |
+
**Description:**
|
| 134 |
+
Some statistical constants and thresholds are hardcoded (e.g., p-values, score thresholds), requiring PLR2004 ignore.
|
| 135 |
+
|
| 136 |
+
**Impact:**
|
| 137 |
+
- Difficult to tune parameters
|
| 138 |
+
- Magic numbers obscure intent
|
| 139 |
+
|
| 140 |
+
**Current Workaround:**
|
| 141 |
+
Documented with comments where used.
|
| 142 |
+
|
| 143 |
+
**Proposed Solution:**
|
| 144 |
+
Move to configuration or constants module with documentation.
|
| 145 |
+
|
| 146 |
+
**Effort Estimate:** S
|
| 147 |
+
|
| 148 |
+
---
|
| 149 |
+
|
| 150 |
+
### DEBT-006: Global Singleton Pattern
|
| 151 |
+
|
| 152 |
+
**Category:** Code Quality
|
| 153 |
+
**Severity:** Low
|
| 154 |
+
**Added:** 2025-12-06
|
| 155 |
+
**Status:** Open
|
| 156 |
+
|
| 157 |
+
**Description:**
|
| 158 |
+
Settings uses a singleton pattern (`settings = get_settings()`), requiring PLW0603 ignore.
|
| 159 |
+
|
| 160 |
+
**Impact:**
|
| 161 |
+
- Harder to test with different configurations
|
| 162 |
+
- Global state can cause issues
|
| 163 |
+
|
| 164 |
+
**Current Workaround:**
|
| 165 |
+
Test fixtures override settings.
|
| 166 |
+
|
| 167 |
+
**Proposed Solution:**
|
| 168 |
+
Consider dependency injection for settings, especially in tests.
|
| 169 |
+
|
| 170 |
+
**Effort Estimate:** M
|
| 171 |
+
|
| 172 |
+
---
|
| 173 |
+
|
| 174 |
+
### DEBT-007: ClinicalTrials Uses requests Instead of httpx
|
| 175 |
+
|
| 176 |
+
**Category:** Code Quality
|
| 177 |
+
**Severity:** Low
|
| 178 |
+
**Added:** 2025-12-06
|
| 179 |
+
**Status:** Open
|
| 180 |
+
|
| 181 |
+
**Description:**
|
| 182 |
+
`src/tools/clinicaltrials.py` uses `requests` library while rest of codebase uses `httpx` because ClinicalTrials.gov WAF blocks httpx.
|
| 183 |
+
|
| 184 |
+
**Impact:**
|
| 185 |
+
- Inconsistent HTTP client usage
|
| 186 |
+
- Two libraries for same purpose
|
| 187 |
+
|
| 188 |
+
**Current Workaround:**
|
| 189 |
+
Documented in code comments and pyproject.toml.
|
| 190 |
+
|
| 191 |
+
**Proposed Solution:**
|
| 192 |
+
1. Investigate httpx headers/options that work with WAF
|
| 193 |
+
2. Or accept this as necessary divergence and document
|
| 194 |
+
|
| 195 |
+
**Effort Estimate:** M
|
| 196 |
+
|
| 197 |
+
---
|
| 198 |
+
|
| 199 |
+
## Testing
|
| 200 |
+
|
| 201 |
+
### DEBT-008: Integration Tests Require Real APIs
|
| 202 |
+
|
| 203 |
+
**Category:** Testing
|
| 204 |
+
**Severity:** Medium
|
| 205 |
+
**Added:** 2025-12-06
|
| 206 |
+
**Status:** Open
|
| 207 |
+
|
| 208 |
+
**Description:**
|
| 209 |
+
Integration tests marked with `@pytest.mark.integration` make real API calls, which can be slow and flaky.
|
| 210 |
+
|
| 211 |
+
**Impact:**
|
| 212 |
+
- Slow CI runs
|
| 213 |
+
- Flaky tests due to network issues
|
| 214 |
+
- Rate limit risks
|
| 215 |
+
|
| 216 |
+
**Current Workaround:**
|
| 217 |
+
Integration tests are not run in CI by default.
|
| 218 |
+
|
| 219 |
+
**Proposed Solution:**
|
| 220 |
+
1. Use VCR-style recording for reproducible tests
|
| 221 |
+
2. Set up isolated test environment
|
| 222 |
+
3. Better mock infrastructure for external APIs
|
| 223 |
+
|
| 224 |
+
**Effort Estimate:** L
|
| 225 |
+
|
| 226 |
+
---
|
| 227 |
+
|
| 228 |
+
### DEBT-009: Incomplete E2E Test Coverage
|
| 229 |
+
|
| 230 |
+
**Category:** Testing
|
| 231 |
+
**Severity:** Medium
|
| 232 |
+
**Added:** 2025-12-06
|
| 233 |
+
**Status:** Open
|
| 234 |
+
|
| 235 |
+
**Description:**
|
| 236 |
+
End-to-end tests exist but don't cover all user scenarios, especially error paths.
|
| 237 |
+
|
| 238 |
+
**Impact:**
|
| 239 |
+
- Production bugs may not be caught in testing
|
| 240 |
+
- Edge cases untested
|
| 241 |
+
|
| 242 |
+
**Current Workaround:**
|
| 243 |
+
Manual testing before releases.
|
| 244 |
+
|
| 245 |
+
**Proposed Solution:**
|
| 246 |
+
Expand E2E test suite with more scenarios, especially:
|
| 247 |
+
- Error handling
|
| 248 |
+
- Rate limit recovery
|
| 249 |
+
- Multiple iterations
|
| 250 |
+
|
| 251 |
+
**Effort Estimate:** L
|
| 252 |
+
|
| 253 |
+
---
|
| 254 |
+
|
| 255 |
+
## Documentation
|
| 256 |
+
|
| 257 |
+
### DEBT-010: Outdated Inline Comments
|
| 258 |
+
|
| 259 |
+
**Category:** Documentation
|
| 260 |
+
**Severity:** Low
|
| 261 |
+
**Added:** 2025-12-06
|
| 262 |
+
**Status:** Open
|
| 263 |
+
|
| 264 |
+
**Description:**
|
| 265 |
+
Some code comments may reference old architecture or removed features from rapid hackathon development.
|
| 266 |
+
|
| 267 |
+
**Impact:**
|
| 268 |
+
- Confusion when reading code
|
| 269 |
+
- Comments don't match implementation
|
| 270 |
+
|
| 271 |
+
**Current Workaround:**
|
| 272 |
+
None - requires manual review.
|
| 273 |
+
|
| 274 |
+
**Proposed Solution:**
|
| 275 |
+
Systematic review of comments during code review process.
|
| 276 |
+
|
| 277 |
+
**Effort Estimate:** M
|
| 278 |
+
|
| 279 |
+
---
|
| 280 |
+
|
| 281 |
+
### DEBT-011: Missing API Documentation
|
| 282 |
+
|
| 283 |
+
**Category:** Documentation
|
| 284 |
+
**Severity:** Low
|
| 285 |
+
**Added:** 2025-12-06
|
| 286 |
+
**Status:** Open
|
| 287 |
+
|
| 288 |
+
**Description:**
|
| 289 |
+
No formal API documentation (e.g., Sphinx-generated) for public interfaces.
|
| 290 |
+
|
| 291 |
+
**Impact:**
|
| 292 |
+
- Developers must read source code
|
| 293 |
+
- Hard to know public vs internal APIs
|
| 294 |
+
|
| 295 |
+
**Current Workaround:**
|
| 296 |
+
Docstrings in code serve as documentation.
|
| 297 |
+
|
| 298 |
+
**Proposed Solution:**
|
| 299 |
+
Consider generating API docs with Sphinx or mkdocs.
|
| 300 |
+
|
| 301 |
+
**Effort Estimate:** M
|
| 302 |
+
|
| 303 |
+
---
|
| 304 |
+
|
| 305 |
+
## Performance
|
| 306 |
+
|
| 307 |
+
### DEBT-012: Model Loading on First Request
|
| 308 |
+
|
| 309 |
+
**Category:** Performance
|
| 310 |
+
**Severity:** Low
|
| 311 |
+
**Added:** 2025-12-06
|
| 312 |
+
**Status:** Open
|
| 313 |
+
|
| 314 |
+
**Description:**
|
| 315 |
+
Sentence-transformers model is loaded on first query, causing slow initial response.
|
| 316 |
+
|
| 317 |
+
**Impact:**
|
| 318 |
+
- First query takes 30+ seconds
|
| 319 |
+
- Poor user experience on first use
|
| 320 |
+
|
| 321 |
+
**Current Workaround:**
|
| 322 |
+
Docker pre-downloads the model during build.
|
| 323 |
+
|
| 324 |
+
**Proposed Solution:**
|
| 325 |
+
1. Pre-warm model on application startup
|
| 326 |
+
2. Or accept cold start with loading indicator
|
| 327 |
+
|
| 328 |
+
**Effort Estimate:** S
|
| 329 |
+
|
| 330 |
+
---
|
| 331 |
+
|
| 332 |
+
### DEBT-013: No Connection Pooling
|
| 333 |
+
|
| 334 |
+
**Category:** Performance
|
| 335 |
+
**Severity:** Low
|
| 336 |
+
**Added:** 2025-12-06
|
| 337 |
+
**Status:** Open
|
| 338 |
+
|
| 339 |
+
**Description:**
|
| 340 |
+
External API calls may not fully utilize connection pooling.
|
| 341 |
+
|
| 342 |
+
**Impact:**
|
| 343 |
+
- Slower requests due to connection overhead
|
| 344 |
+
- Higher latency under load
|
| 345 |
+
|
| 346 |
+
**Current Workaround:**
|
| 347 |
+
httpx AsyncClient provides some pooling.
|
| 348 |
+
|
| 349 |
+
**Proposed Solution:**
|
| 350 |
+
Audit and optimize connection handling for external APIs.
|
| 351 |
+
|
| 352 |
+
**Effort Estimate:** S
|
| 353 |
+
|
| 354 |
+
---
|
| 355 |
+
|
| 356 |
+
## Dependencies
|
| 357 |
+
|
| 358 |
+
### DEBT-014: Pinned Beta Dependencies
|
| 359 |
+
|
| 360 |
+
**Category:** Dependencies
|
| 361 |
+
**Severity:** Medium
|
| 362 |
+
**Added:** 2025-12-06
|
| 363 |
+
**Status:** Open
|
| 364 |
+
|
| 365 |
+
**Description:**
|
| 366 |
+
`agent-framework-core==1.0.0b*` is a beta release, pinned to avoid breaking changes.
|
| 367 |
+
|
| 368 |
+
**Impact:**
|
| 369 |
+
- May miss bug fixes and improvements
|
| 370 |
+
- Beta software may have stability issues
|
| 371 |
+
|
| 372 |
+
**Current Workaround:**
|
| 373 |
+
Version pinning with explicit documentation.
|
| 374 |
+
|
| 375 |
+
**Proposed Solution:**
|
| 376 |
+
1. Monitor for stable release
|
| 377 |
+
2. Upgrade and test when 1.0.0 releases
|
| 378 |
+
3. Add integration tests specific to agent framework
|
| 379 |
+
|
| 380 |
+
**Effort Estimate:** M
|
| 381 |
+
|
| 382 |
+
---
|
| 383 |
+
|
| 384 |
+
## Resolved Items
|
| 385 |
+
|
| 386 |
+
*No items resolved yet.*
|
| 387 |
+
|
| 388 |
+
---
|
| 389 |
+
|
| 390 |
+
## How to Update This Registry
|
| 391 |
+
|
| 392 |
+
### Adding Items
|
| 393 |
+
|
| 394 |
+
1. Create new section with next DEBT-XXX number
|
| 395 |
+
2. Fill in all fields
|
| 396 |
+
3. Update summary dashboard
|
| 397 |
+
|
| 398 |
+
### Resolving Items
|
| 399 |
+
|
| 400 |
+
1. Change status to "Resolved"
|
| 401 |
+
2. Add resolution notes
|
| 402 |
+
3. Move to "Resolved Items" section
|
| 403 |
+
4. Update summary dashboard
|
| 404 |
+
|
| 405 |
+
### Review Schedule
|
| 406 |
+
|
| 407 |
+
- Weekly: Triage new items
|
| 408 |
+
- Sprint: Plan debt reduction
|
| 409 |
+
- Monthly: Review progress
|
|
@@ -0,0 +1,106 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Technical Debt Overview
|
| 2 |
+
|
| 3 |
+
> **Last Updated**: 2025-12-06
|
| 4 |
+
|
| 5 |
+
This directory tracks technical debt, known issues, and areas for improvement in the DeepBoner codebase.
|
| 6 |
+
|
| 7 |
+
## What is Technical Debt?
|
| 8 |
+
|
| 9 |
+
Technical debt is the implied cost of future work caused by choosing an easy (but limited) solution now instead of a better approach that would take longer. Like financial debt, it accumulates interest over time.
|
| 10 |
+
|
| 11 |
+
## Documentation Structure
|
| 12 |
+
|
| 13 |
+
```
|
| 14 |
+
technical-debt/
|
| 15 |
+
βββ index.md # This file - overview and summary
|
| 16 |
+
βββ debt-registry.md # Itemized debt tracking
|
| 17 |
+
```
|
| 18 |
+
|
| 19 |
+
## Current Debt Summary
|
| 20 |
+
|
| 21 |
+
| Category | Count | Severity |
|
| 22 |
+
|----------|-------|----------|
|
| 23 |
+
| Architecture | 3 | Medium |
|
| 24 |
+
| Code Quality | 4 | Low |
|
| 25 |
+
| Testing | 2 | Medium |
|
| 26 |
+
| Documentation | 2 | Low |
|
| 27 |
+
| Performance | 2 | Low |
|
| 28 |
+
| Dependencies | 1 | Medium |
|
| 29 |
+
|
| 30 |
+
**Total Items:** 14
|
| 31 |
+
|
| 32 |
+
## Severity Levels
|
| 33 |
+
|
| 34 |
+
| Level | Description | Action |
|
| 35 |
+
|-------|-------------|--------|
|
| 36 |
+
| **Critical** | Blocks production or security risk | Fix immediately |
|
| 37 |
+
| **High** | Significant impact on reliability | Fix this sprint |
|
| 38 |
+
| **Medium** | Impacts developer experience | Plan for fix |
|
| 39 |
+
| **Low** | Nice to have improvement | Backlog |
|
| 40 |
+
|
| 41 |
+
## How to Use This Documentation
|
| 42 |
+
|
| 43 |
+
### For Developers
|
| 44 |
+
|
| 45 |
+
1. Before starting work, check if your area has known debt
|
| 46 |
+
2. When you encounter issues, document them here
|
| 47 |
+
3. When fixing debt, update the registry
|
| 48 |
+
|
| 49 |
+
### For Planning
|
| 50 |
+
|
| 51 |
+
1. Review debt before sprint planning
|
| 52 |
+
2. Allocate capacity for debt reduction
|
| 53 |
+
3. Prioritize by severity and effort
|
| 54 |
+
|
| 55 |
+
### For New Contributors
|
| 56 |
+
|
| 57 |
+
1. Read this to understand known limitations
|
| 58 |
+
2. Don't be surprised by documented issues
|
| 59 |
+
3. Consider fixing debt as a contribution
|
| 60 |
+
|
| 61 |
+
## Adding New Debt Items
|
| 62 |
+
|
| 63 |
+
Add to `debt-registry.md` using this format:
|
| 64 |
+
|
| 65 |
+
```markdown
|
| 66 |
+
### DEBT-XXX: Short Title
|
| 67 |
+
|
| 68 |
+
**Category:** Architecture | Code Quality | Testing | Documentation | Performance | Dependencies
|
| 69 |
+
**Severity:** Critical | High | Medium | Low
|
| 70 |
+
**Added:** YYYY-MM-DD
|
| 71 |
+
**Status:** Open | In Progress | Resolved
|
| 72 |
+
|
| 73 |
+
**Description:**
|
| 74 |
+
What is the issue?
|
| 75 |
+
|
| 76 |
+
**Impact:**
|
| 77 |
+
How does this affect the codebase/users?
|
| 78 |
+
|
| 79 |
+
**Current Workaround:**
|
| 80 |
+
How are we handling this now?
|
| 81 |
+
|
| 82 |
+
**Proposed Solution:**
|
| 83 |
+
How should we fix this?
|
| 84 |
+
|
| 85 |
+
**Effort Estimate:** S | M | L | XL
|
| 86 |
+
```
|
| 87 |
+
|
| 88 |
+
## Debt Reduction Goals
|
| 89 |
+
|
| 90 |
+
### Phase 1 (Current)
|
| 91 |
+
- Document all known debt (this effort)
|
| 92 |
+
- Prioritize by impact
|
| 93 |
+
|
| 94 |
+
### Phase 2 (Near-term)
|
| 95 |
+
- Address all High severity items
|
| 96 |
+
- Reduce Medium items by 50%
|
| 97 |
+
|
| 98 |
+
### Phase 3 (Long-term)
|
| 99 |
+
- Clear all Medium and High items
|
| 100 |
+
- Establish debt budget (no net increase)
|
| 101 |
+
|
| 102 |
+
## Related Documentation
|
| 103 |
+
|
| 104 |
+
- [Debt Registry](debt-registry.md) - Complete itemized list
|
| 105 |
+
- [Bugs](../bugs/active-bugs.md) - Active bug tracking
|
| 106 |
+
- [Contributing](../../CONTRIBUTING.md) - How to help
|