Joseph Pollack commited on
Commit
d45d242
·
1 Parent(s): e6066ff

implements documentation improvements

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. AUDIO_INPUT_FIX.md +0 -94
  2. docs/contributing.md → CONTRIBUTING.md +114 -23
  3. ERROR_FIXES_SUMMARY.md +0 -156
  4. FILE_OUTPUT_IMPLEMENTATION_PLAN.md +0 -241
  5. FILE_OUTPUT_VERIFICATION.md +0 -224
  6. FIX_SUMMARY.md +0 -102
  7. MULTIMODAL_SETTINGS_IMPLEMENTATION_PLAN.md +0 -386
  8. MULTIMODAL_SETTINGS_IMPLEMENTATION_SUMMARY.md +0 -157
  9. Makefile +0 -42
  10. PDF_REPORT_INTEGRATION.md +0 -134
  11. README.md +3 -148
  12. REPORT_WRITING_AGENTS_ANALYSIS.md +0 -189
  13. SERPER_WEBSEARCH_IMPLEMENTATION_PLAN.md +0 -403
  14. WEB_SEARCH_TOOL_ASSESSMENT.md +0 -239
  15. dev/Makefile +0 -51
  16. dev/__init__.py +1 -0
  17. docs/MKDOCS_IMPROVEMENTS_ASSESSMENT.md +642 -0
  18. docs/api/agents.md +45 -85
  19. docs/api/models.md +21 -23
  20. docs/api/orchestrators.md +34 -75
  21. docs/api/services.md +123 -32
  22. docs/api/tools.md +57 -19
  23. docs/architecture/agents.md +114 -18
  24. docs/architecture/graph-orchestration.md +0 -138
  25. docs/architecture/graph_orchestration.md +54 -10
  26. docs/architecture/middleware.md +40 -20
  27. docs/architecture/orchestrators.md +45 -10
  28. docs/architecture/services.md +36 -19
  29. docs/architecture/tools.md +26 -12
  30. docs/architecture/workflow-diagrams.md +4 -17
  31. docs/configuration/CONFIGURATION.md +0 -557
  32. docs/contributing/code-quality.md +70 -4
  33. docs/contributing/code-style.md +39 -1
  34. docs/contributing/error-handling.md +1 -1
  35. docs/contributing/implementation-patterns.md +1 -1
  36. docs/contributing/index.md +121 -16
  37. docs/contributing/testing.md +68 -4
  38. docs/getting-started/examples.md +2 -22
  39. docs/getting-started/installation.md +18 -38
  40. docs/getting-started/mcp-integration.md +0 -13
  41. docs/getting-started/quick-start.md +1 -23
  42. docs/implementation/IMPLEMENTATION_SUMMARY.md +0 -188
  43. docs/implementation/TOKEN_AUTHENTICATION_REVIEW.md +0 -201
  44. docs/implementation/TTS_MODAL_IMPLEMENTATION.md +0 -142
  45. docs/index.md +9 -2
  46. docs/overview/architecture.md +15 -18
  47. docs/overview/features.md +36 -19
  48. docs/overview/quick-start.md +29 -8
  49. mkdocs.yml +1 -1
  50. mkdocs.yml.enhanced +166 -0
AUDIO_INPUT_FIX.md DELETED
@@ -1,94 +0,0 @@
1
- # Audio Input Display Fix
2
-
3
- ## Issue
4
- The audio input (microphone button) was not displaying in the ChatInterface multimodal textbox.
5
-
6
- ## Root Cause
7
- When `multimodal=True` is set on `gr.ChatInterface`, it should automatically show image and audio buttons. However:
8
- 1. The buttons might be hidden in a dropdown menu
9
- 2. Browser permissions might be blocking microphone access
10
- 3. The `file_types` parameter might not have been explicitly set
11
-
12
- ## Fix Applied
13
-
14
- ### 1. Added `file_types` Parameter
15
- Explicitly specified which file types are accepted to ensure audio is enabled:
16
-
17
- ```python
18
- gr.ChatInterface(
19
- fn=research_agent,
20
- multimodal=True,
21
- file_types=["image", "audio", "video"], # Explicitly enable image, audio, and video
22
- ...
23
- )
24
- ```
25
-
26
- **File:** `src/app.py` (line 929)
27
-
28
- ### 2. Enhanced UI Description
29
- Updated the description to make it clearer where to find the audio input:
30
-
31
- - Added explicit instructions about clicking the 📷 and 🎤 icons
32
- - Added a tip about looking for icons in the text input box
33
- - Clarified drag & drop functionality
34
-
35
- **File:** `src/app.py` (lines 942-948)
36
-
37
- ## How It Works Now
38
-
39
- 1. **Audio Recording Button**: The 🎤 microphone icon should appear in the textbox toolbar when `multimodal=True` is set
40
- 2. **File Upload**: Users can drag & drop audio files or click to upload
41
- 3. **Browser Permissions**: Browser will prompt for microphone access when user clicks the audio button
42
-
43
- ## Testing
44
-
45
- To verify the fix:
46
- 1. Look for the 🎤 microphone icon in the text input box
47
- 2. Click it to start recording (browser will ask for microphone permission)
48
- 3. Alternatively, drag & drop an audio file into the textbox
49
- 4. Check browser console for any permission errors
50
-
51
- ## Browser Requirements
52
-
53
- - **Chrome/Edge**: Should work with microphone permissions
54
- - **Firefox**: Should work with microphone permissions
55
- - **Safari**: May require additional configuration
56
- - **HTTPS Required**: Microphone access typically requires HTTPS (or localhost)
57
-
58
- ## Troubleshooting
59
-
60
- If audio input still doesn't appear:
61
-
62
- 1. **Check Browser Permissions**:
63
- - Open browser settings
64
- - Check microphone permissions for the site
65
- - Ensure microphone is not blocked
66
-
67
- 2. **Check Browser Console**:
68
- - Open Developer Tools (F12)
69
- - Look for permission errors or warnings
70
- - Check for any JavaScript errors
71
-
72
- 3. **Try Different Browser**:
73
- - Some browsers have stricter permission policies
74
- - Try Chrome or Firefox if Safari doesn't work
75
-
76
- 4. **Check Gradio Version**:
77
- - Ensure `gradio>=6.0.0` is installed
78
- - Update if needed: `pip install --upgrade gradio`
79
-
80
- 5. **HTTPS Requirement**:
81
- - Microphone access requires HTTPS (or localhost)
82
- - If deploying, ensure SSL is configured
83
-
84
- ## Additional Notes
85
-
86
- - The audio button is part of the MultimodalTextbox component
87
- - It should appear as an icon in the textbox toolbar
88
- - If it's still not visible, it might be in a dropdown menu (click the "+" or "..." button)
89
- - The `file_types` parameter ensures audio files are accepted for upload
90
-
91
-
92
-
93
-
94
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
docs/contributing.md → CONTRIBUTING.md RENAMED
@@ -12,7 +12,14 @@ Thank you for your interest in contributing to The DETERMINATOR! This guide will
12
  - [Key Principles](#key-principles)
13
  - [Pull Request Process](#pull-request-process)
14
 
15
- > **Note**: Additional sections (Code Style, Error Handling, Testing, Implementation Patterns, Code Quality, and Prompt Engineering) are available as separate pages in the navigation sidebar.
 
 
 
 
 
 
 
16
 
17
  ## Git Workflow
18
 
@@ -22,9 +29,31 @@ Thank you for your interest in contributing to The DETERMINATOR! This guide will
22
  - **NEVER** push directly to `main` or `dev` on HuggingFace
23
  - GitHub is source of truth; HuggingFace is for deployment
24
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
  ## Getting Started
26
 
27
- 1. **Fork the repository** on GitHub
28
  2. **Clone your fork**:
29
 
30
  ```bash
@@ -35,7 +64,8 @@ Thank you for your interest in contributing to The DETERMINATOR! This guide will
35
  3. **Install dependencies**:
36
 
37
  ```bash
38
- make install
 
39
  ```
40
 
41
  4. **Create a feature branch**:
@@ -48,7 +78,9 @@ Thank you for your interest in contributing to The DETERMINATOR! This guide will
48
  6. **Run checks**:
49
 
50
  ```bash
51
- make check
 
 
52
  ```
53
 
54
  7. **Commit and push**:
@@ -57,22 +89,72 @@ Thank you for your interest in contributing to The DETERMINATOR! This guide will
57
  git commit -m "Description of changes"
58
  git push origin yourname-feature-name
59
  ```
 
60
  8. **Create a pull request** on GitHub
61
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
62
  ## Development Commands
63
 
64
  ```bash
65
- make install # Install dependencies + pre-commit
66
- make check # Lint + typecheck + test (MUST PASS)
67
- make test # Run unit tests
68
- make lint # Run ruff
69
- make format # Format with ruff
70
- make typecheck # Run mypy
71
- make test-cov # Test with coverage
72
- make docs-build # Build documentation
73
- make docs-serve # Serve documentation locally
 
 
 
 
 
 
 
 
 
 
 
74
  ```
75
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
76
  ## Code Style & Conventions
77
 
78
  ### Type Safety
@@ -118,10 +200,10 @@ result = await loop.run_in_executor(None, cpu_bound_function, args)
118
 
119
  ### Pre-commit
120
 
121
- - Run `make check` before committing
122
  - Must pass: lint + typecheck + test-cov
123
- - Pre-commit hooks installed via `make install`
124
- - **CRITICAL**: Make sure you run the full pre-commit checks before opening a PR (not draft), otherwise Obstacle is the Way will lose his mind
125
 
126
  ## Error Handling & Logging
127
 
@@ -191,7 +273,7 @@ except httpx.HTTPError as e:
191
  1. Write failing test in `tests/unit/`
192
  2. Implement in `src/`
193
  3. Ensure test passes
194
- 4. Run `make check` (lint + typecheck + test)
195
 
196
  ### Test Examples
197
 
@@ -212,7 +294,8 @@ async def test_real_pubmed_search():
212
 
213
  ### Test Coverage
214
 
215
- - Run `make test-cov` for coverage report
 
216
  - Aim for >80% coverage on critical paths
217
  - Exclude: `__init__.py`, `TYPE_CHECKING` blocks
218
 
@@ -385,7 +468,7 @@ Example:
385
 
386
  ## Pull Request Process
387
 
388
- 1. Ensure all checks pass: `make check`
389
  2. Update documentation if needed
390
  3. Add tests for new features
391
  4. Update CHANGELOG if applicable
@@ -393,11 +476,19 @@ Example:
393
  6. Address review feedback
394
  7. Wait for approval before merging
395
 
 
 
 
 
 
 
 
 
 
396
  ## Questions?
397
 
398
- - Open an issue on GitHub
399
- - Check existing documentation
400
  - Review code examples in the codebase
401
 
402
- Thank you for contributing to DeepCritical!
403
-
 
12
  - [Key Principles](#key-principles)
13
  - [Pull Request Process](#pull-request-process)
14
 
15
+ > **Note**: Additional sections (Code Style, Error Handling, Testing, Implementation Patterns, Code Quality, and Prompt Engineering) are available as separate pages in the [documentation](https://deepcritical.github.io/GradioDemo/contributing/).
16
+ > **Note on Project Names**: "The DETERMINATOR" is the product name, "DeepCritical" is the organization/project name, and "determinator" is the Python package name.
17
+
18
+ ## Repository Information
19
+
20
+ - **GitHub Repository**: [`DeepCritical/GradioDemo`](https://github.com/DeepCritical/GradioDemo) (source of truth, PRs, code review)
21
+ - **HuggingFace Space**: [`DataQuests/DeepCritical`](https://huggingface.co/spaces/DataQuests/DeepCritical) (deployment/demo)
22
+ - **Package Name**: `determinator` (Python package name in `pyproject.toml`)
23
 
24
  ## Git Workflow
25
 
 
29
  - **NEVER** push directly to `main` or `dev` on HuggingFace
30
  - GitHub is source of truth; HuggingFace is for deployment
31
 
32
+ ### Dual Repository Setup
33
+
34
+ This project uses a dual repository setup:
35
+
36
+ - **GitHub (`DeepCritical/GradioDemo`)**: Source of truth for code, PRs, and code review
37
+ - **HuggingFace (`DataQuests/DeepCritical`)**: Deployment target for the Gradio demo
38
+
39
+ #### Remote Configuration
40
+
41
+ When cloning, set up remotes as follows:
42
+
43
+ ```bash
44
+ # Clone from GitHub
45
+ git clone https://github.com/DeepCritical/GradioDemo.git
46
+ cd GradioDemo
47
+
48
+ # Add HuggingFace remote (optional, for deployment)
49
+ git remote add huggingface-upstream https://huggingface.co/spaces/DataQuests/DeepCritical
50
+ ```
51
+
52
+ **Important**: Never push directly to `main` or `dev` on HuggingFace. Always work through GitHub PRs. GitHub is the source of truth; HuggingFace is for deployment/demo only.
53
+
54
  ## Getting Started
55
 
56
+ 1. **Fork the repository** on GitHub: [`DeepCritical/GradioDemo`](https://github.com/DeepCritical/GradioDemo)
57
  2. **Clone your fork**:
58
 
59
  ```bash
 
64
  3. **Install dependencies**:
65
 
66
  ```bash
67
+ uv sync --all-extras
68
+ uv run pre-commit install
69
  ```
70
 
71
  4. **Create a feature branch**:
 
78
  6. **Run checks**:
79
 
80
  ```bash
81
+ uv run ruff check src tests
82
+ uv run mypy src
83
+ uv run pytest --cov=src --cov-report=term-missing tests/unit/ -v -m "not openai" -p no:logfire
84
  ```
85
 
86
  7. **Commit and push**:
 
89
  git commit -m "Description of changes"
90
  git push origin yourname-feature-name
91
  ```
92
+
93
  8. **Create a pull request** on GitHub
94
 
95
+ ## Package Manager
96
+
97
+ This project uses [`uv`](https://github.com/astral-sh/uv) as the package manager. All commands should be prefixed with `uv run` to ensure they run in the correct environment.
98
+
99
+ ### Installation
100
+
101
+ ```bash
102
+ # Install uv if you haven't already (recommended: standalone installer)
103
+ # Unix/macOS/Linux:
104
+ curl -LsSf https://astral.sh/uv/install.sh | sh
105
+
106
+ # Windows (PowerShell):
107
+ powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
108
+
109
+ # Alternative: pipx install uv
110
+ # Or: pip install uv
111
+
112
+ # Sync all dependencies including dev extras
113
+ uv sync --all-extras
114
+
115
+ # Install pre-commit hooks
116
+ uv run pre-commit install
117
+ ```
118
+
119
  ## Development Commands
120
 
121
  ```bash
122
+ # Installation
123
+ uv sync --all-extras # Install all dependencies including dev
124
+ uv run pre-commit install # Install pre-commit hooks
125
+
126
+ # Code Quality Checks (run all before committing)
127
+ uv run ruff check src tests # Lint with ruff
128
+ uv run ruff format src tests # Format with ruff
129
+ uv run mypy src # Type checking
130
+ uv run pytest --cov=src --cov-report=term-missing tests/unit/ -v -m "not openai" -p no:logfire # Tests with coverage
131
+
132
+ # Testing Commands
133
+ uv run pytest tests/unit/ -v -m "not openai" -p no:logfire # Run unit tests (excludes OpenAI tests)
134
+ uv run pytest tests/ -v -m "huggingface" -p no:logfire # Run HuggingFace tests
135
+ uv run pytest tests/ -v -p no:logfire # Run all tests
136
+ uv run pytest --cov=src --cov-report=term-missing tests/unit/ -v -m "not openai" -p no:logfire # Tests with terminal coverage
137
+ uv run pytest --cov=src --cov-report=html -p no:logfire # Generate HTML coverage report (opens htmlcov/index.html)
138
+
139
+ # Documentation Commands
140
+ uv run mkdocs build # Build documentation
141
+ uv run mkdocs serve # Serve documentation locally (http://127.0.0.1:8000)
142
  ```
143
 
144
+ ### Test Markers
145
+
146
+ The project uses pytest markers to categorize tests. See [Testing Guidelines](docs/contributing/testing.md) for details:
147
+
148
+ - `unit`: Unit tests (mocked, fast)
149
+ - `integration`: Integration tests (real APIs)
150
+ - `slow`: Slow tests
151
+ - `openai`: Tests requiring OpenAI API key
152
+ - `huggingface`: Tests requiring HuggingFace API key
153
+ - `embedding_provider`: Tests requiring API-based embedding providers
154
+ - `local_embeddings`: Tests using local embeddings
155
+
156
+ **Note**: The `-p no:logfire` flag disables the logfire plugin to avoid conflicts during testing.
157
+
158
  ## Code Style & Conventions
159
 
160
  ### Type Safety
 
200
 
201
  ### Pre-commit
202
 
203
+ - Pre-commit hooks run automatically on commit
204
  - Must pass: lint + typecheck + test-cov
205
+ - Install hooks with: `uv run pre-commit install`
206
+ - Note: `uv sync --all-extras` installs the pre-commit package, but you must run `uv run pre-commit install` separately to set up the git hooks
207
 
208
  ## Error Handling & Logging
209
 
 
273
  1. Write failing test in `tests/unit/`
274
  2. Implement in `src/`
275
  3. Ensure test passes
276
+ 4. Run checks: `uv run ruff check src tests && uv run mypy src && uv run pytest --cov=src --cov-report=term-missing tests/unit/ -v -m "not openai" -p no:logfire`
277
 
278
  ### Test Examples
279
 
 
294
 
295
  ### Test Coverage
296
 
297
+ - Run `uv run pytest --cov=src --cov-report=term-missing tests/unit/ -v -m "not openai" -p no:logfire` for coverage report
298
+ - Run `uv run pytest --cov=src --cov-report=html -p no:logfire` for HTML coverage report (opens `htmlcov/index.html`)
299
  - Aim for >80% coverage on critical paths
300
  - Exclude: `__init__.py`, `TYPE_CHECKING` blocks
301
 
 
468
 
469
  ## Pull Request Process
470
 
471
+ 1. Ensure all checks pass: `uv run ruff check src tests && uv run mypy src && uv run pytest --cov=src --cov-report=term-missing tests/unit/ -v -m "not openai" -p no:logfire`
472
  2. Update documentation if needed
473
  3. Add tests for new features
474
  4. Update CHANGELOG if applicable
 
476
  6. Address review feedback
477
  7. Wait for approval before merging
478
 
479
+ ## Project Structure
480
+
481
+ - `src/`: Main source code
482
+ - `tests/`: Test files (`unit/` and `integration/`)
483
+ - `docs/`: Documentation source files (MkDocs)
484
+ - `examples/`: Example usage scripts
485
+ - `pyproject.toml`: Project configuration and dependencies
486
+ - `.pre-commit-config.yaml`: Pre-commit hook configuration
487
+
488
  ## Questions?
489
 
490
+ - Open an issue on [GitHub](https://github.com/DeepCritical/GradioDemo)
491
+ - Check existing [documentation](https://deepcritical.github.io/GradioDemo/)
492
  - Review code examples in the codebase
493
 
494
+ Thank you for contributing to The DETERMINATOR!
 
ERROR_FIXES_SUMMARY.md DELETED
@@ -1,156 +0,0 @@
1
- # Error Fixes Summary
2
-
3
- ## Issues Identified and Fixed
4
-
5
- ### 1. ✅ `'Settings' object has no attribute 'ocr_api_url'`
6
-
7
- **Error Location:** `src/services/image_ocr.py:33`
8
-
9
- **Root Cause:**
10
- The code was trying to access `settings.ocr_api_url` which doesn't exist in older versions of the config. This happens when running a previous version of the app where `ocr_api_url` wasn't added to the Settings class yet.
11
-
12
- **Fix Applied:**
13
- - Added defensive coding using `getattr()` with a fallback default URL
14
- - Default URL: `"https://prithivmlmods-multimodal-ocr3.hf.space"`
15
-
16
- **Code Change:**
17
- ```python
18
- # Before:
19
- self.api_url = api_url or settings.ocr_api_url
20
-
21
- # After:
22
- default_url = getattr(settings, "ocr_api_url", None) or "https://prithivmlmods-multimodal-ocr3.hf.space"
23
- self.api_url = api_url or default_url
24
- ```
25
-
26
- **File:** `src/services/image_ocr.py`
27
-
28
- ---
29
-
30
- ### 2. ✅ `Expected code to be unreachable, but got: ('research_complete', False)`
31
-
32
- **Error Location:** `src/orchestrator/graph_orchestrator.py` (decision node execution)
33
-
34
- **Root Cause:**
35
- When Pydantic AI encounters a validation error or returns an unexpected format, it may return a tuple like `('research_complete', False)` instead of the expected `KnowledgeGapOutput` object. The decision function was trying to access `result.research_complete` on a tuple, causing the error.
36
-
37
- **Fix Applied:**
38
- 1. **Enhanced decision function** in `graph_builder.py` to handle tuple formats
39
- 2. **Improved tuple handling** in `graph_orchestrator.py` decision node execution
40
- 3. **Better reconstruction** of `KnowledgeGapOutput` from validation error tuples
41
-
42
- **Code Changes:**
43
-
44
- **File: `src/agent_factory/graph_builder.py`**
45
- - Replaced lambda with named function `_decision_function()` that handles tuples
46
- - Added logic to extract `research_complete` from various tuple formats
47
- - Handles: `('research_complete', False)`, dicts in tuples, boolean values in tuples
48
-
49
- **File: `src/orchestrator/graph_orchestrator.py`**
50
- - Enhanced tuple detection and reconstruction in `_execute_decision_node()`
51
- - Added specific handling for `('research_complete', False)` format
52
- - Improved fallback logic for unexpected tuple formats
53
- - Better error messages and logging
54
-
55
- **File: `src/orchestrator/graph_orchestrator.py` (agent node execution)**
56
- - Improved handling of tuple outputs in `_execute_agent_node()`
57
- - Better reconstruction of `KnowledgeGapOutput` from validation errors
58
- - More graceful fallback for non-knowledge_gap nodes
59
-
60
- ---
61
-
62
- ### 3. ⚠️ `Local state is not initialized - app is not locally available` (Modal TTS)
63
-
64
- **Error Location:** Modal TTS service
65
-
66
- **Root Cause:**
67
- This is expected behavior when Modal credentials are not configured or the app is not running in a Modal environment. It's not a critical error - TTS will simply be unavailable.
68
-
69
- **Status:**
70
- - This is **not an error** - it's expected when Modal isn't configured
71
- - The app gracefully degrades and continues without TTS
72
- - Users can still use the app, just without audio output
73
-
74
- **No Fix Needed:** This is working as designed with graceful degradation.
75
-
76
- ---
77
-
78
- ### 4. ⚠️ `Invalid file descriptor: -1` (Asyncio cleanup)
79
-
80
- **Error Location:** Python asyncio event loop cleanup
81
-
82
- **Root Cause:**
83
- This is a Python asyncio cleanup warning that occurs during shutdown. It's not critical and doesn't affect functionality.
84
-
85
- **Status:**
86
- - This is a **warning**, not an error
87
- - Occurs during application shutdown
88
- - Doesn't affect runtime functionality
89
- - Common in Python 3.11+ with certain asyncio patterns
90
-
91
- **No Fix Needed:** This is a known Python asyncio quirk and doesn't impact functionality.
92
-
93
- ---
94
-
95
- ### 5. ⚠️ MCP Server Warning: `gr.State input will not be updated between tool calls`
96
-
97
- **Error Location:** Gradio MCP server setup
98
-
99
- **Root Cause:**
100
- Some MCP tools use `gr.State` inputs, which Gradio warns won't update between tool calls. This is a limitation of how MCP tools interact with Gradio state.
101
-
102
- **Status:**
103
- - This is a **warning**, not an error
104
- - MCP tools will still work, but state won't persist between calls
105
- - This is a known Gradio MCP limitation
106
-
107
- **No Fix Needed:** This is a Gradio limitation, not a bug in our code.
108
-
109
- ---
110
-
111
- ## Summary of Fixes
112
-
113
- ### Critical Fixes (Applied):
114
- 1. ✅ **OCR API URL Attribute Error** - Fixed with defensive coding
115
- 2. ✅ **Graph Orchestrator Tuple Handling** - Fixed with enhanced tuple detection and reconstruction
116
-
117
- ### Non-Critical (Expected Behavior):
118
- 3. ⚠️ **Modal TTS Error** - Expected when Modal not configured (graceful degradation)
119
- 4. ⚠️ **Asyncio Cleanup Warning** - Python asyncio quirk (non-critical)
120
- 5. ⚠️ **MCP State Warning** - Gradio limitation (non-critical)
121
-
122
- ## Testing Recommendations
123
-
124
- 1. **Test OCR functionality:**
125
- - Upload an image with text
126
- - Verify OCR processing works
127
- - Check logs for any remaining errors
128
-
129
- 2. **Test graph execution:**
130
- - Run a research query
131
- - Verify knowledge gap evaluation works
132
- - Check that decision nodes route correctly
133
- - Monitor logs for tuple handling warnings
134
-
135
- 3. **Test with/without Modal:**
136
- - Verify app works without Modal credentials
137
- - Test TTS if Modal is configured
138
- - Verify graceful degradation
139
-
140
- ## Files Modified
141
-
142
- 1. `src/services/image_ocr.py` - Added defensive `ocr_api_url` access
143
- 2. `src/orchestrator/graph_orchestrator.py` - Enhanced tuple handling in decision and agent nodes
144
- 3. `src/agent_factory/graph_builder.py` - Improved decision function to handle tuples
145
-
146
- ## Next Steps
147
-
148
- 1. Test the fixes with the reported error scenarios
149
- 2. Monitor logs for any remaining issues
150
- 3. Consider adding unit tests for tuple handling edge cases
151
- 4. Document the tuple format handling for future reference
152
-
153
-
154
-
155
-
156
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
FILE_OUTPUT_IMPLEMENTATION_PLAN.md DELETED
@@ -1,241 +0,0 @@
1
- # File Output Implementation Plan
2
-
3
- ## Overview
4
-
5
- This plan implements file writing and return functionality for report-writing agents, enabling reports to be saved as files and returned through the Gradio ChatInterface.
6
-
7
- ## Current State Analysis
8
-
9
- ✅ **Report Generation**: All agents generate markdown strings
10
- ✅ **File Output Integration**: `event_to_chat_message()` supports file paths
11
- ✅ **Graph Orchestrator**: Can handle file paths in results
12
- ❌ **File Writing**: No agents write files to disk
13
- ❌ **File Service**: No utility service for saving reports
14
-
15
- ---
16
-
17
- ## Implementation Plan
18
-
19
- ### PROJECT 1: File Writing Service
20
- **Goal**: Create a reusable service for saving reports to files
21
-
22
- #### Activity 1.1: Create Report File Service
23
- **File**: `src/services/report_file_service.py` (NEW)
24
-
25
- **Tasks**:
26
- 1. Create `ReportFileService` class
27
- 2. Implement `save_report()` method
28
- - Accepts: report content (str), filename (optional), output_dir (optional)
29
- - Returns: file path (str)
30
- - Uses temp directory by default
31
- - Supports custom output directory
32
- - Handles file naming with timestamps
33
- 3. Implement `save_report_multiple_formats()` method
34
- - Save as .md (always)
35
- - Optionally save as .html, .pdf (future)
36
- 4. Add configuration support
37
- - Read from settings
38
- - Enable/disable file saving
39
- - Configurable output directory
40
- 5. Add error handling and logging
41
- 6. Add file cleanup utilities (optional)
42
-
43
- **Line-level subtasks**:
44
- - Line 1-20: Imports and class definition
45
- - Line 21-40: `__init__()` method with settings
46
- - Line 41-80: `save_report()` method
47
- - Line 41-50: Input validation
48
- - Line 51-60: Directory creation
49
- - Line 61-70: File writing
50
- - Line 71-80: Error handling
51
- - Line 81-100: `save_report_multiple_formats()` method
52
- - Line 101-120: Helper methods (filename generation, cleanup)
53
-
54
- ---
55
-
56
- ### PROJECT 2: Configuration Updates
57
- **Goal**: Add settings for file output functionality
58
-
59
- #### Activity 2.1: Update Settings Model
60
- **File**: `src/utils/config.py`
61
-
62
- **Tasks**:
63
- 1. Add `save_reports_to_file: bool` field (default: True)
64
- 2. Add `report_output_directory: str | None` field (default: None, uses temp)
65
- 3. Add `report_file_format: Literal["md", "md_html", "md_pdf"]` field (default: "md")
66
- 4. Add `report_filename_template: str` field (default: "report_{timestamp}_{query_hash}.md")
67
-
68
- **Line-level subtasks**:
69
- - Line 166-170: Add `save_reports_to_file` field after TTS config
70
- - Line 171-175: Add `report_output_directory` field
71
- - Line 176-180: Add `report_file_format` field
72
- - Line 181-185: Add `report_filename_template` field
73
-
74
- ---
75
-
76
- ### PROJECT 3: Graph Orchestrator Integration
77
- **Goal**: Integrate file writing into graph execution
78
-
79
- #### Activity 3.1: Update Graph Orchestrator
80
- **File**: `src/orchestrator/graph_orchestrator.py`
81
-
82
- **Tasks**:
83
- 1. Import `ReportFileService` at top
84
- 2. Initialize service in `__init__()` (optional, can be lazy)
85
- 3. Modify `_execute_agent_node()` for synthesizer node
86
- - After `long_writer_agent.write_report()`, save to file
87
- - Return dict with `{"message": report, "file": file_path}`
88
- 4. Update final event generation to handle file paths
89
- - Already implemented, verify it works correctly
90
-
91
- **Line-level subtasks**:
92
- - Line 1-35: Add import for `ReportFileService`
93
- - Line 119-148: Update `__init__()` to accept optional file service
94
- - Line 589-650: Modify `_execute_agent_node()` synthesizer handling
95
- - Line 642-645: After `write_report()`, add file saving
96
- - Line 646-650: Return dict with file path
97
- - Line 534-564: Verify final event generation handles file paths (already done)
98
-
99
- ---
100
-
101
- ### PROJECT 4: Research Flow Integration
102
- **Goal**: Integrate file writing into research flows
103
-
104
- #### Activity 4.1: Update IterativeResearchFlow
105
- **File**: `src/orchestrator/research_flow.py`
106
-
107
- **Tasks**:
108
- 1. Import `ReportFileService` at top
109
- 2. Add optional file service to `__init__()`
110
- 3. Modify `_create_final_report()` method
111
- - After `writer_agent.write_report()`, save to file if enabled
112
- - Return string (backward compatible) OR dict with file path
113
-
114
- **Line-level subtasks**:
115
- - Line 1-50: Add import for `ReportFileService`
116
- - Line 48-120: Update `__init__()` to accept optional file service
117
- - Line 622-667: Modify `_create_final_report()` method
118
- - Line 647-652: After `write_report()`, add file saving
119
- - Line 653-667: Return report string (keep backward compatible for now)
120
-
121
- #### Activity 4.2: Update DeepResearchFlow
122
- **File**: `src/orchestrator/research_flow.py`
123
-
124
- **Tasks**:
125
- 1. Add optional file service to `__init__()` (if not already)
126
- 2. Modify `_create_final_report()` method
127
- - After `long_writer_agent.write_report()` or `proofreader_agent.proofread()`, save to file
128
- - Return string (backward compatible) OR dict with file path
129
-
130
- **Line-level subtasks**:
131
- - Line 670-750: Update `DeepResearchFlow.__init__()` to accept optional file service
132
- - Line 954-1005: Modify `_create_final_report()` method
133
- - Line 979-983: After `write_report()`, add file saving
134
- - Line 984-989: After `proofread()`, add file saving
135
- - Line 990-1005: Return report string (keep backward compatible)
136
-
137
- ---
138
-
139
- ### PROJECT 5: Agent Factory Integration
140
- **Goal**: Make file service available to agents if needed
141
-
142
- #### Activity 5.1: Update Agent Factory (Optional)
143
- **File**: `src/agent_factory/agents.py`
144
-
145
- **Tasks**:
146
- 1. Add optional file service parameter to agent creation functions (if needed)
147
- 2. Pass file service to agents that need it (currently not needed, agents return strings)
148
-
149
- **Line-level subtasks**:
150
- - Not required - agents return strings, file writing happens at orchestrator level
151
-
152
- ---
153
-
154
- ### PROJECT 6: Testing & Validation
155
- **Goal**: Ensure file output works end-to-end
156
-
157
- #### Activity 6.1: Unit Tests
158
- **File**: `tests/unit/services/test_report_file_service.py` (NEW)
159
-
160
- **Tasks**:
161
- 1. Test `save_report()` with default settings
162
- 2. Test `save_report()` with custom directory
163
- 3. Test `save_report()` with custom filename
164
- 4. Test error handling (permission errors, disk full, etc.)
165
- 5. Test file cleanup
166
-
167
- **Line-level subtasks**:
168
- - Line 1-30: Test fixtures and setup
169
- - Line 31-60: Test basic save functionality
170
- - Line 61-90: Test custom directory
171
- - Line 91-120: Test error handling
172
-
173
- #### Activity 6.2: Integration Tests
174
- **File**: `tests/integration/test_file_output_integration.py` (NEW)
175
-
176
- **Tasks**:
177
- 1. Test graph orchestrator with file output
178
- 2. Test research flows with file output
179
- 3. Test Gradio ChatInterface receives file paths
180
- 4. Test file download in Gradio UI
181
-
182
- **Line-level subtasks**:
183
- - Line 1-40: Test setup with mock orchestrator
184
- - Line 41-80: Test file generation in graph execution
185
- - Line 81-120: Test file paths in AgentEvent
186
- - Line 121-160: Test Gradio message conversion
187
-
188
- ---
189
-
190
- ## Implementation Order
191
-
192
- 1. **PROJECT 2** (Configuration) - Foundation
193
- 2. **PROJECT 1** (File Service) - Core functionality
194
- 3. **PROJECT 3** (Graph Orchestrator) - Primary integration point
195
- 4. **PROJECT 4** (Research Flows) - Secondary integration points
196
- 5. **PROJECT 6** (Testing) - Validation
197
- 6. **PROJECT 5** (Agent Factory) - Not needed, skip
198
-
199
- ---
200
-
201
- ## File Changes Summary
202
-
203
- ### New Files
204
- - `src/services/report_file_service.py` - File writing service
205
- - `tests/unit/services/test_report_file_service.py` - Unit tests
206
- - `tests/integration/test_file_output_integration.py` - Integration tests
207
-
208
- ### Modified Files
209
- - `src/utils/config.py` - Add file output settings
210
- - `src/orchestrator/graph_orchestrator.py` - Add file saving after report generation
211
- - `src/orchestrator/research_flow.py` - Add file saving in both flows
212
-
213
- ---
214
-
215
- ## Gradio Integration Notes
216
-
217
- According to Gradio ChatInterface documentation:
218
- - File paths in chat message content are automatically converted to download links
219
- - Markdown links like `[Download: filename](file_path)` work
220
- - Files must be accessible from the Gradio server
221
- - Temp files are fine as long as they exist during the session
222
-
223
- Current implementation in `event_to_chat_message()` already handles this correctly.
224
-
225
- ---
226
-
227
- ## Success Criteria
228
-
229
- ✅ Reports are saved to files when generated
230
- ✅ File paths are included in AgentEvent data
231
- ✅ File paths appear as download links in Gradio ChatInterface
232
- ✅ File saving is configurable (can be disabled)
233
- ✅ Backward compatible (existing code still works)
234
- ✅ Error handling prevents crashes if file writing fails
235
-
236
-
237
-
238
-
239
-
240
-
241
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
FILE_OUTPUT_VERIFICATION.md DELETED
@@ -1,224 +0,0 @@
1
- # File Output Implementation Verification
2
-
3
- ## Status: ✅ ALL CHANGES RETAINED
4
-
5
- All file output functionality has been successfully implemented and retained in the codebase.
6
-
7
- ---
8
-
9
- ## Verification Checklist
10
-
11
- ### ✅ PROJECT 1: File Writing Service
12
- - **File**: `src/services/report_file_service.py`
13
- - **Status**: ✅ EXISTS
14
- - **Key Components**:
15
- - `ReportFileService` class
16
- - `save_report()` method
17
- - `save_report_multiple_formats()` method
18
- - `_generate_filename()` helper
19
- - `_sanitize_filename()` helper
20
- - `cleanup_old_files()` method
21
- - `get_report_file_service()` singleton function
22
-
23
- ### ✅ PROJECT 2: Configuration Updates
24
- - **File**: `src/utils/config.py`
25
- - **Status**: ✅ ALL SETTINGS PRESENT
26
- - **Settings Added** (lines 181-195):
27
- - ✅ `save_reports_to_file: bool = True`
28
- - ✅ `report_output_directory: str | None = None`
29
- - ✅ `report_file_format: Literal["md", "md_html", "md_pdf"] = "md"`
30
- - ✅ `report_filename_template: str = "report_{timestamp}_{query_hash}.md"`
31
-
32
- ### ✅ PROJECT 3: Graph Orchestrator Integration
33
- - **File**: `src/orchestrator/graph_orchestrator.py`
34
- - **Status**: ✅ FULLY INTEGRATED
35
-
36
- #### Imports (Line 35)
37
- ```python
38
- from src.services.report_file_service import ReportFileService, get_report_file_service
39
- ```
40
- ✅ Present
41
-
42
- #### File Service Initialization (Line 152)
43
- ```python
44
- self._file_service: ReportFileService | None = None
45
- ```
46
- ✅ Present
47
-
48
- #### Helper Method (Lines 162-175)
49
- ```python
50
- def _get_file_service(self) -> ReportFileService | None:
51
- """Get file service instance (lazy initialization)."""
52
- ...
53
- ```
54
- ✅ Present
55
-
56
- #### Synthesizer Node File Saving (Lines 673-694)
57
- - ✅ Saves report after `long_writer_agent.write_report()`
58
- - ✅ Returns dict with `{"message": report, "file": file_path}` if file saved
59
- - ✅ Returns string if file saving fails (backward compatible)
60
- - ✅ Error handling with logging
61
-
62
- #### Writer Node File Saving (Lines 729-748)
63
- - ✅ Saves report after `writer_agent.write_report()`
64
- - ✅ Returns dict with `{"message": report, "file": file_path}` if file saved
65
- - ✅ Returns string if file saving fails (backward compatible)
66
- - ✅ Error handling with logging
67
-
68
- #### Final Event Handling (Lines 558-585)
69
- - ✅ Extracts file path from final result dict
70
- - ✅ Adds file path to `event_data["file"]` or `event_data["files"]`
71
- - ✅ Handles both single file and multiple files
72
- - ✅ Sets appropriate message
73
-
74
- ### ✅ PROJECT 4: Research Flow Integration
75
- - **File**: `src/orchestrator/research_flow.py`
76
- - **Status**: ✅ FULLY INTEGRATED
77
-
78
- #### Imports (Line 28)
79
- ```python
80
- from src.services.report_file_service import ReportFileService, get_report_file_service
81
- ```
82
- ✅ Present
83
-
84
- #### IterativeResearchFlow
85
- - **File Service Initialization** (Line 117): ✅ Present
86
- - **Helper Method** (Lines 119-132): ✅ Present
87
- - **File Saving in `_create_final_report()`** (Lines 683-692): ✅ Present
88
- - Saves after `writer_agent.write_report()`
89
- - Logs file path
90
- - Error handling with logging
91
-
92
- #### DeepResearchFlow
93
- - **File Service Initialization** (Line 761): ✅ Present
94
- - **Helper Method** (Lines 763-776): ✅ Present
95
- - **File Saving in `_create_final_report()`** (Lines 1055-1064): ✅ Present
96
- - Saves after `long_writer_agent.write_report()` or `proofreader_agent.proofread()`
97
- - Logs file path
98
- - Error handling with logging
99
-
100
- ### ✅ PROJECT 5: Gradio Integration
101
- - **File**: `src/app.py`
102
- - **Status**: ✅ ALREADY IMPLEMENTED (from previous work)
103
- - **Function**: `event_to_chat_message()` (Lines 209-350)
104
- - **Features**:
105
- - ✅ Detects file paths in `event.data["file"]` or `event.data["files"]`
106
- - ✅ Formats files as markdown download links
107
- - ✅ Handles both single and multiple files
108
- - ✅ Validates file paths with `_is_file_path()` helper
109
-
110
- ---
111
-
112
- ## Implementation Summary
113
-
114
- ### File Saving Locations
115
-
116
- 1. **Graph Orchestrator - Synthesizer Node** (Deep Research)
117
- - Location: `src/orchestrator/graph_orchestrator.py:673-694`
118
- - Trigger: After `long_writer_agent.write_report()`
119
- - Returns: Dict with file path or string (backward compatible)
120
-
121
- 2. **Graph Orchestrator - Writer Node** (Iterative Research)
122
- - Location: `src/orchestrator/graph_orchestrator.py:729-748`
123
- - Trigger: After `writer_agent.write_report()`
124
- - Returns: Dict with file path or string (backward compatible)
125
-
126
- 3. **IterativeResearchFlow**
127
- - Location: `src/orchestrator/research_flow.py:683-692`
128
- - Trigger: After `writer_agent.write_report()` in `_create_final_report()`
129
- - Returns: String (file path logged, not returned)
130
-
131
- 4. **DeepResearchFlow**
132
- - Location: `src/orchestrator/research_flow.py:1055-1064`
133
- - Trigger: After `long_writer_agent.write_report()` or `proofreader_agent.proofread()`
134
- - Returns: String (file path logged, not returned)
135
-
136
- ### File Path Flow
137
-
138
- ```
139
- Report Generation
140
-
141
- ReportFileService.save_report()
142
-
143
- File saved to disk (temp directory or configured directory)
144
-
145
- File path returned to orchestrator
146
-
147
- File path included in result dict: {"message": report, "file": file_path}
148
-
149
- Result dict stored in GraphExecutionContext
150
-
151
- Final event extraction (lines 558-585)
152
-
153
- File path added to AgentEvent.data["file"]
154
-
155
- event_to_chat_message() (src/app.py)
156
-
157
- File path formatted as markdown download link
158
-
159
- Gradio ChatInterface displays download link
160
- ```
161
-
162
- ---
163
-
164
- ## Testing Recommendations
165
-
166
- ### Unit Tests
167
- - [ ] Test `ReportFileService.save_report()` with various inputs
168
- - [ ] Test filename generation with templates
169
- - [ ] Test file sanitization
170
- - [ ] Test error handling (permission errors, disk full, etc.)
171
-
172
- ### Integration Tests
173
- - [ ] Test graph orchestrator file saving for synthesizer node
174
- - [ ] Test graph orchestrator file saving for writer node
175
- - [ ] Test file path inclusion in AgentEvent
176
- - [ ] Test Gradio message conversion with file paths
177
- - [ ] Test file download in Gradio UI
178
-
179
- ### Manual Testing
180
- - [ ] Run iterative research flow and verify file is created
181
- - [ ] Run deep research flow and verify file is created
182
- - [ ] Verify file appears as download link in Gradio ChatInterface
183
- - [ ] Test with file saving disabled (`save_reports_to_file=False`)
184
- - [ ] Test with custom output directory
185
-
186
- ---
187
-
188
- ## Configuration Options
189
-
190
- All settings are in `src/utils/config.py`:
191
-
192
- ```python
193
- # Enable/disable file saving
194
- save_reports_to_file: bool = True
195
-
196
- # Custom output directory (None = use temp directory)
197
- report_output_directory: str | None = None
198
-
199
- # File format (currently only "md" is fully implemented)
200
- report_file_format: Literal["md", "md_html", "md_pdf"] = "md"
201
-
202
- # Filename template with placeholders
203
- report_filename_template: str = "report_{timestamp}_{query_hash}.md"
204
- ```
205
-
206
- ---
207
-
208
- ## Conclusion
209
-
210
- ✅ **All file output functionality has been successfully implemented and retained.**
211
-
212
- The implementation is:
213
- - ✅ Complete (all planned features implemented)
214
- - ✅ Backward compatible (existing code continues to work)
215
- - ✅ Error resilient (file saving failures don't crash workflows)
216
- - ✅ Configurable (can be enabled/disabled via settings)
217
- - ✅ Integrated with Gradio (file paths appear as download links)
218
-
219
- No reimplementation needed. All changes are present and correct.
220
-
221
-
222
-
223
-
224
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
FIX_SUMMARY.md DELETED
@@ -1,102 +0,0 @@
1
- # Fix Summary: Research Results Not Returned to User
2
-
3
- ## Problem
4
- The application was returning "Research completed" instead of the actual research report content to users. Reports were being generated and saved to files, but the final result wasn't being properly extracted and returned to the Gradio interface.
5
-
6
- ## Root Causes
7
-
8
- 1. **Incomplete Result Extraction**: The `_execute_graph` method in `graph_orchestrator.py` only checked the last executed node (`current_node_id`) for the final result. If the graph execution broke early due to budget/time limits, or if the last node wasn't the synthesizer/writer exit node, the result wouldn't be found.
9
-
10
- 2. **Incomplete Dict Handling**: When the synthesizer or writer nodes returned a dict with `{"message": final_report, "file": file_path}`, the code only extracted the message if the dict had a "file" key. If the dict had a "message" key but no "file" key, the message wouldn't be extracted.
11
-
12
- 3. **No Fallback Logic**: There was no fallback to check all exit nodes for results if the current node wasn't an exit node.
13
-
14
- ## Solution
15
-
16
- ### Changes Made to `src/orchestrator/graph_orchestrator.py`
17
-
18
- 1. **Enhanced Result Extraction** (lines 555-600):
19
- - First checks if `current_node_id` is an exit node and gets its result
20
- - If no result, prioritizes checking "synthesizer" and "writer" exit nodes
21
- - Falls back to checking all exit nodes if still no result
22
- - Added comprehensive logging to help debug result extraction
23
-
24
- 2. **Improved Dict Handling** (lines 602-640):
25
- - Now checks for "message" key first (most important)
26
- - Extracts message from dict even if "file" key is missing
27
- - Only uses default messages if "message" key is not present
28
- - Added logging for result type and extraction process
29
-
30
- 3. **Better Error Handling**:
31
- - Logs warnings when no result is found, including all available node results
32
- - Logs unexpected result types for debugging
33
-
34
- ## Key Code Changes
35
-
36
- ### Before:
37
- ```python
38
- final_result = context.get_node_result(current_node_id) if current_node_id else None
39
- message: str = "Research completed"
40
-
41
- if isinstance(final_result, str):
42
- message = final_result
43
- elif isinstance(final_result, dict):
44
- if "file" in final_result:
45
- # Only extracts message if file exists
46
- message = final_result.get("message", "Report generated. Download available.")
47
- ```
48
-
49
- ### After:
50
- ```python
51
- # Check all exit nodes with priority
52
- final_result = None
53
- if current_node_id and current_node_id in self._graph.exit_nodes:
54
- final_result = context.get_node_result(current_node_id)
55
-
56
- if not final_result:
57
- # Prioritize synthesizer/writer nodes
58
- for exit_node_id in ["synthesizer", "writer"]:
59
- if exit_node_id in self._graph.exit_nodes:
60
- result = context.get_node_result(exit_node_id)
61
- if result:
62
- final_result = result
63
- break
64
-
65
- # Extract message from dict first
66
- if isinstance(final_result, dict):
67
- if "message" in final_result:
68
- message = final_result["message"] # Extract message regardless of file
69
- ```
70
-
71
- ## Testing Recommendations
72
-
73
- 1. **Test Deep Research Flow**:
74
- - Run a query that triggers deep research mode
75
- - Verify the full report is returned, not just "Research completed"
76
- - Check that reports are properly displayed in the UI
77
-
78
- 2. **Test Iterative Research Flow**:
79
- - Run a query that triggers iterative research mode
80
- - Verify the report is returned correctly
81
-
82
- 3. **Test Budget/Time Limits**:
83
- - Run queries that exceed budget or time limits
84
- - Verify that partial results are still returned if available
85
-
86
- 4. **Test File Saving**:
87
- - Verify reports are saved to files
88
- - Verify file paths are included in event data when available
89
-
90
- ## Files Modified
91
-
92
- - `src/orchestrator/graph_orchestrator.py`: Enhanced result extraction and message handling logic
93
-
94
- ## Expected Behavior After Fix
95
-
96
- - Users will see the full research report content in the chat interface
97
- - Reports will be properly extracted from synthesizer/writer nodes
98
- - File paths will be included in event data when reports are saved
99
- - Better logging will help debug any future issues with result extraction
100
-
101
-
102
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
MULTIMODAL_SETTINGS_IMPLEMENTATION_PLAN.md DELETED
@@ -1,386 +0,0 @@
1
- # Multimodal Settings & File Rendering - Implementation Plan
2
-
3
- ## Executive Summary
4
-
5
- This document provides a comprehensive analysis of the current settings implementation, multimodal input handling, and file rendering in `src/app.py`, along with a detailed implementation plan to improve the user experience.
6
-
7
- ## 1. Current Settings Analysis
8
-
9
- ### 1.1 Settings Structure in `src/app.py`
10
-
11
- **Current Implementation (Lines 741-887):**
12
-
13
- 1. **Sidebar Structure:**
14
- - Authentication section (lines 745-750)
15
- - About section (lines 752-764)
16
- - Settings section (lines 767-850):
17
- - Research Configuration Accordion (lines 771-796):
18
- - `mode_radio`: Orchestrator mode selector
19
- - `graph_mode_radio`: Graph research mode selector
20
- - `use_graph_checkbox`: Graph execution toggle
21
- - Audio Output Accordion (lines 798-850):
22
- - `enable_audio_output_checkbox`: TTS enable/disable
23
- - `tts_voice_dropdown`: Voice selection
24
- - `tts_speed_slider`: Speech speed control
25
- - `tts_gpu_dropdown`: GPU type (non-interactive, visible only if Modal available)
26
-
27
- 2. **Hidden Components (Lines 852-865):**
28
- - `hf_model_dropdown`: Hidden Textbox for model selection
29
- - `hf_provider_dropdown`: Hidden Textbox for provider selection
30
-
31
- 3. **Main Area Components (Lines 867-887):**
32
- - `audio_output`: Audio output component (visible based on `settings.enable_audio_output`)
33
- - Visibility update function for TTS components
34
-
35
- ### 1.2 Settings Flow
36
-
37
- **Settings → Function Parameters:**
38
- - Settings from sidebar accordions are passed via `additional_inputs` to `research_agent()` function
39
- - Hidden textboxes are also passed but use empty strings (converted to None)
40
- - OAuth token/profile are automatically passed by Gradio
41
-
42
- **Function Signature (Lines 535-546):**
43
- ```python
44
- async def research_agent(
45
- message: str | MultimodalPostprocess,
46
- history: list[dict[str, Any]],
47
- mode: str = "simple",
48
- hf_model: str | None = None,
49
- hf_provider: str | None = None,
50
- graph_mode: str = "auto",
51
- use_graph: bool = True,
52
- tts_voice: str = "af_heart",
53
- tts_speed: float = 1.0,
54
- oauth_token: gr.OAuthToken | None = None,
55
- oauth_profile: gr.OAuthProfile | None = None,
56
- )
57
- ```
58
-
59
- ### 1.3 Issues Identified
60
-
61
- 1. **Settings Organization:**
62
- - Audio output component is in main area, not sidebar
63
- - Hidden components (hf_model, hf_provider) should be visible or removed
64
- - No image input enable/disable setting (only audio input has this)
65
-
66
- 2. **Visibility:**
67
- - Audio output visibility is controlled by checkbox, but component placement is suboptimal
68
- - TTS settings visibility is controlled by checkbox change event
69
-
70
- 3. **Configuration Gaps:**
71
- - No `enable_image_input` setting in config (only `enable_audio_input` exists)
72
- - Image processing always happens if files are present (line 626 comment says "not just when enable_image_input is True" but setting doesn't exist)
73
-
74
- ## 2. Multimodal Input Analysis
75
-
76
- ### 2.1 Current Implementation
77
-
78
- **ChatInterface Configuration (Line 892-958):**
79
- - `multimodal=True`: Enables MultimodalTextbox component
80
- - MultimodalTextbox automatically provides:
81
- - Text input
82
- - Image upload button
83
- - Audio recording button
84
- - File upload support
85
-
86
- **Input Processing (Lines 613-642):**
87
- - Message can be `str` or `MultimodalPostprocess` (dict format)
88
- - MultimodalPostprocess format: `{"text": str, "files": list[FileData], "audio": tuple | None}`
89
- - Processing happens in `research_agent()` function:
90
- - Extracts text, files, and audio from message
91
- - Calls `multimodal_service.process_multimodal_input()`
92
- - Condition: `if files or (audio_input_data is not None and settings.enable_audio_input)`
93
-
94
- **Multimodal Service (src/services/multimodal_processing.py):**
95
- - Processes audio input if `settings.enable_audio_input` is True
96
- - Processes image files (no enable/disable check - always processes if files present)
97
- - Extracts text from images using OCR service
98
- - Transcribes audio using STT service
99
-
100
- ### 2.2 Gradio Documentation Findings
101
-
102
- **MultimodalTextbox (ChatInterface with multimodal=True):**
103
- - Automatically provides image and audio input capabilities
104
- - Inputs are always visible when ChatInterface is rendered
105
- - No explicit visibility control needed - it's part of the textbox component
106
- - Files are handled via `files` array in MultimodalPostprocess
107
- - Audio recording is handled via `audio` tuple in MultimodalPostprocess
108
-
109
- **Reference Implementation Pattern:**
110
- ```python
111
- gr.ChatInterface(
112
- fn=chat_function,
113
- multimodal=True, # Enables image/audio inputs
114
- # ... other parameters
115
- )
116
- ```
117
-
118
- ### 2.3 Issues Identified
119
-
120
- 1. **Visibility:**
121
- - Multimodal inputs ARE always visible (they're part of MultimodalTextbox)
122
- - No explicit control needed - this is working correctly
123
- - However, users may not realize image/audio inputs are available
124
-
125
- 2. **Configuration:**
126
- - No `enable_image_input` setting to disable image processing
127
- - Image processing always happens if files are present
128
- - Audio processing respects `settings.enable_audio_input`
129
-
130
- 3. **User Experience:**
131
- - No visual indication that multimodal inputs are available
132
- - Description mentions "🎤 Multimodal Support" but could be more prominent
133
-
134
- ## 3. File Rendering Analysis
135
-
136
- ### 3.1 Current Implementation
137
-
138
- **File Detection (Lines 168-195):**
139
- - `_is_file_path()`: Checks if text looks like a file path
140
- - Checks for file extensions and path separators
141
-
142
- **File Rendering in Events (Lines 242-298):**
143
- - For "complete" events, checks `event.data` for "files" or "file" keys
144
- - Validates files exist using `os.path.exists()`
145
- - Formats files as markdown download links: `📎 [Download: filename](filepath)`
146
- - Stores files in metadata for potential future use
147
-
148
- **File Links Format:**
149
- ```python
150
- file_links = "\n\n".join([
151
- f"📎 [Download: {_get_file_name(f)}]({f})"
152
- for f in valid_files
153
- ])
154
- result["content"] = f"{content}\n\n{file_links}"
155
- ```
156
-
157
- ### 3.2 Issues Identified
158
-
159
- 1. **Rendering Method:**
160
- - Uses markdown links in content string
161
- - May not work reliably in all Gradio versions
162
- - Better approach: Use Gradio's native file components or File component
163
-
164
- 2. **File Validation:**
165
- - Only checks if file exists
166
- - Doesn't validate file type or size
167
- - No error handling for inaccessible files
168
-
169
- 3. **User Experience:**
170
- - Files appear as text links, not as proper file components
171
- - No preview for images/PDFs
172
- - No file size information
173
-
174
- ## 4. Implementation Plan
175
-
176
- ### Activity 1: Settings Reorganization
177
-
178
- **Goal:** Move all settings to sidebar with better organization
179
-
180
- **File:** `src/app.py`
181
-
182
- **Tasks:**
183
-
184
- 1. **Move Audio Output Component to Sidebar (Lines 867-887)**
185
- - Move `audio_output` component into sidebar
186
- - Place it in Audio Output accordion or create separate section
187
- - Update visibility logic to work within sidebar
188
-
189
- 2. **Add Image Input Settings (New)**
190
- - Add `enable_image_input` checkbox to sidebar
191
- - Create "Image Input" accordion or add to existing "Multimodal Input" accordion
192
- - Update config to include `enable_image_input` setting
193
-
194
- 3. **Organize Settings Accordions**
195
- - Research Configuration (existing)
196
- - Multimodal Input (new - combine image and audio input settings)
197
- - Audio Output (existing - move component here)
198
- - Model Configuration (new - for hf_model, hf_provider if we make them visible)
199
-
200
- **Subtasks:**
201
- - [ ] Line 867-871: Move `audio_output` component definition into sidebar
202
- - [ ] Line 873-887: Update visibility update function to work with sidebar placement
203
- - [ ] Line 798-850: Reorganize Audio Output accordion to include audio_output component
204
- - [ ] Line 767-796: Keep Research Configuration as-is
205
- - [ ] After line 796: Add new "Multimodal Input" accordion with enable_image_input and enable_audio_input checkboxes
206
- - [ ] Line 852-865: Consider making hf_model and hf_provider visible or remove them
207
-
208
- ### Activity 2: Multimodal Input Visibility
209
-
210
- **Goal:** Ensure multimodal inputs are always visible and well-documented
211
-
212
- **File:** `src/app.py`
213
-
214
- **Tasks:**
215
-
216
- 1. **Verify Multimodal Inputs Are Visible**
217
- - Confirm `multimodal=True` in ChatInterface (already done - line 894)
218
- - Add visual indicators in description
219
- - Add tooltips or help text
220
-
221
- 2. **Add Image Input Configuration**
222
- - Add `enable_image_input` to config (src/utils/config.py)
223
- - Update multimodal processing to respect this setting
224
- - Add UI control in sidebar
225
-
226
- **Subtasks:**
227
- - [ ] Line 894: Verify `multimodal=True` is set (already correct)
228
- - [ ] Line 908: Enhance description to highlight multimodal capabilities
229
- - [ ] src/utils/config.py: Add `enable_image_input: bool = Field(default=True, ...)`
230
- - [ ] src/services/multimodal_processing.py: Add check for `settings.enable_image_input` before processing images
231
- - [ ] src/app.py: Add enable_image_input checkbox to sidebar
232
-
233
- ### Activity 3: File Rendering Improvements
234
-
235
- **Goal:** Improve file rendering using proper Gradio components
236
-
237
- **File:** `src/app.py`
238
-
239
- **Tasks:**
240
-
241
- 1. **Improve File Rendering Method**
242
- - Use Gradio File component or proper file handling
243
- - Add file previews for images
244
- - Show file size and type information
245
-
246
- 2. **Enhance File Validation**
247
- - Validate file types
248
- - Check file accessibility
249
- - Handle errors gracefully
250
-
251
- **Subtasks:**
252
- - [ ] Line 280-296: Replace markdown link approach with proper file component rendering
253
- - [ ] Line 168-195: Enhance `_is_file_path()` to validate file types
254
- - [ ] Line 242-298: Update `event_to_chat_message()` to use Gradio File components
255
- - [ ] Add file preview functionality for images
256
- - [ ] Add error handling for inaccessible files
257
-
258
- ### Activity 4: Configuration Updates
259
-
260
- **Goal:** Add missing configuration settings
261
-
262
- **File:** `src/utils/config.py`
263
-
264
- **Tasks:**
265
-
266
- 1. **Add Image Input Setting**
267
- - Add `enable_image_input` field
268
- - Add `ocr_api_url` field if missing
269
- - Add property methods for availability checks
270
-
271
- **Subtasks:**
272
- - [ ] After line 147: Add `enable_image_input: bool = Field(default=True, description="Enable image input (OCR) in multimodal interface")`
273
- - [ ] Check if `ocr_api_url` exists (should be in config)
274
- - [ ] Add `image_ocr_available` property if missing
275
-
276
- ### Activity 5: Multimodal Service Updates
277
-
278
- **Goal:** Respect image input enable/disable setting
279
-
280
- **File:** `src/services/multimodal_processing.py`
281
-
282
- **Tasks:**
283
-
284
- 1. **Add Image Input Check**
285
- - Check `settings.enable_image_input` before processing images
286
- - Log when image processing is skipped due to setting
287
-
288
- **Subtasks:**
289
- - [ ] Line 66-77: Add check for `settings.enable_image_input` before processing image files
290
- - [ ] Add logging when image processing is skipped
291
-
292
- ## 5. Detailed File-Level Tasks
293
-
294
- ### File: `src/app.py`
295
-
296
- **Line-Level Subtasks:**
297
-
298
- 1. **Lines 741-850: Sidebar Reorganization**
299
- - [ ] 741-765: Keep authentication and about sections
300
- - [ ] 767-796: Keep Research Configuration accordion
301
- - [ ] 797: Add new "Multimodal Input" accordion after Research Configuration
302
- - [ ] 798-850: Reorganize Audio Output accordion, move audio_output component here
303
- - [ ] 852-865: Review hidden components - make visible or remove
304
-
305
- 2. **Lines 867-887: Audio Output Component**
306
- - [ ] 867-871: Move `audio_output` definition into sidebar (Audio Output accordion)
307
- - [ ] 873-887: Update visibility function to work with sidebar placement
308
-
309
- 3. **Lines 892-958: ChatInterface Configuration**
310
- - [ ] 894: Verify `multimodal=True` (already correct)
311
- - [ ] 908: Enhance description with multimodal capabilities
312
- - [ ] 946-956: Review `additional_inputs` - ensure all settings are included
313
-
314
- 4. **Lines 242-298: File Rendering**
315
- - [ ] 280-296: Replace markdown links with proper file component rendering
316
- - [ ] Add file preview for images
317
- - [ ] Add file size/type information
318
-
319
- 5. **Lines 613-642: Multimodal Input Processing**
320
- - [ ] 626: Update condition to check `settings.enable_image_input` for files
321
- - [ ] Add logging for when image processing is skipped
322
-
323
- ### File: `src/utils/config.py`
324
-
325
- **Line-Level Subtasks:**
326
-
327
- 1. **Lines 143-180: Audio/Image Configuration**
328
- - [ ] 144-147: `enable_audio_input` exists (keep as-is)
329
- - [ ] After 147: Add `enable_image_input: bool = Field(default=True, description="Enable image input (OCR) in multimodal interface")`
330
- - [ ] Check if `ocr_api_url` exists (add if missing)
331
- - [ ] Add `image_ocr_available` property method
332
-
333
- ### File: `src/services/multimodal_processing.py`
334
-
335
- **Line-Level Subtasks:**
336
-
337
- 1. **Lines 65-77: Image Processing**
338
- - [ ] 66: Add check: `if files and settings.enable_image_input:`
339
- - [ ] 71-77: Keep image processing logic inside the new condition
340
- - [ ] Add logging when image processing is skipped
341
-
342
- ## 6. Testing Checklist
343
-
344
- - [ ] Verify all settings are in sidebar
345
- - [ ] Test multimodal inputs (image upload, audio recording)
346
- - [ ] Test file rendering (markdown, PDF, images)
347
- - [ ] Test enable/disable toggles for image and audio inputs
348
- - [ ] Test audio output generation and display
349
- - [ ] Test file download links
350
- - [ ] Verify settings persist across chat sessions
351
- - [ ] Test on different screen sizes (responsive design)
352
-
353
- ## 7. Implementation Order
354
-
355
- 1. **Phase 1: Configuration** (Foundation)
356
- - Add `enable_image_input` to config
357
- - Update multimodal service to respect setting
358
-
359
- 2. **Phase 2: Settings Reorganization** (UI)
360
- - Move audio output to sidebar
361
- - Add image input settings to sidebar
362
- - Organize accordions
363
-
364
- 3. **Phase 3: File Rendering** (Enhancement)
365
- - Improve file rendering method
366
- - Add file previews
367
- - Enhance validation
368
-
369
- 4. **Phase 4: Testing & Refinement** (Quality)
370
- - Test all functionality
371
- - Fix any issues
372
- - Refine UI/UX
373
-
374
- ## 8. Success Criteria
375
-
376
- - ✅ All settings are in sidebar
377
- - ✅ Multimodal inputs are always visible and functional
378
- - ✅ Files are rendered properly with previews
379
- - ✅ Image and audio input can be enabled/disabled
380
- - ✅ Settings are well-organized and intuitive
381
- - ✅ No regressions in existing functionality
382
-
383
-
384
-
385
-
386
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
MULTIMODAL_SETTINGS_IMPLEMENTATION_SUMMARY.md DELETED
@@ -1,157 +0,0 @@
1
- # Multimodal Settings & File Rendering - Implementation Summary
2
-
3
- ## ✅ Completed Implementation
4
-
5
- ### 1. Configuration Updates (`src/utils/config.py`)
6
-
7
- **Added Settings:**
8
- - ✅ `enable_image_input: bool = Field(default=True, ...)` - Enable/disable image OCR processing
9
- - ✅ `ocr_api_url: str | None = Field(default="https://prithivmlmods-multimodal-ocr3.hf.space", ...)` - OCR service URL
10
-
11
- **Location:** Lines 148-156 (after `enable_audio_output`)
12
-
13
- ### 2. Multimodal Service Updates (`src/services/multimodal_processing.py`)
14
-
15
- **Changes:**
16
- - ✅ Added check for `settings.enable_image_input` before processing image files
17
- - ✅ Image processing now respects the enable/disable setting (similar to audio input)
18
-
19
- **Location:** Line 66 - Added condition: `if files and settings.enable_image_input:`
20
-
21
- ### 3. Sidebar Reorganization (`src/app.py`)
22
-
23
- **New Accordion: "📷 Multimodal Input"**
24
- - ✅ Added `enable_image_input_checkbox` - Control image OCR processing
25
- - ✅ Added `enable_audio_input_checkbox` - Control audio STT processing
26
- - ✅ Located after "Research Configuration" accordion
27
-
28
- **Updated Accordion: "🔊 Audio Output"**
29
- - ✅ Moved `audio_output` component into this accordion (was in main area)
30
- - ✅ Component now appears in sidebar with other audio settings
31
- - ✅ Visibility controlled by `enable_audio_output_checkbox`
32
-
33
- **Settings Organization:**
34
- 1. 🔬 Research Configuration (existing)
35
- 2. 📷 Multimodal Input (NEW)
36
- 3. 🔊 Audio Output (updated - now includes audio_output component)
37
-
38
- **Location:** Lines 770-850
39
-
40
- ### 4. Function Signature Updates (`src/app.py`)
41
-
42
- **Updated `research_agent()` function:**
43
- - ✅ Added `enable_image_input: bool = True` parameter
44
- - ✅ Added `enable_audio_input: bool = True` parameter
45
- - ✅ Function now accepts UI settings directly from sidebar checkboxes
46
-
47
- **Location:** Lines 535-547
48
-
49
- ### 5. Multimodal Input Processing (`src/app.py`)
50
-
51
- **Updates:**
52
- - ✅ Uses function parameters (`enable_image_input`, `enable_audio_input`) instead of only config settings
53
- - ✅ Filters files and audio based on UI settings before processing
54
- - ✅ More responsive to user changes (no need to restart app)
55
-
56
- **Location:** Lines 624-636
57
-
58
- ### 6. File Rendering Improvements (`src/app.py`)
59
-
60
- **Enhancements:**
61
- - ✅ Added file size display in download links
62
- - ✅ Better error handling for file size retrieval
63
- - ✅ Improved formatting with file size information (B, KB, MB)
64
-
65
- **Location:** Lines 286-300
66
-
67
- ### 7. UI Description Updates (`src/app.py`)
68
-
69
- **Enhanced Description:**
70
- - ✅ Better explanation of multimodal capabilities
71
- - ✅ Clear list of supported input types (Images, Audio, Text)
72
- - ✅ Reference to sidebar settings for configuration
73
-
74
- **Location:** Lines 907-912
75
-
76
- ## 📋 Current Settings Structure
77
-
78
- ### Sidebar Layout:
79
-
80
- ```
81
- 🔐 Authentication
82
- - Login button
83
- - About section
84
-
85
- ⚙️ Settings
86
- ├─ 🔬 Research Configuration
87
- │ ├─ Orchestrator Mode
88
- │ ├─ Graph Research Mode
89
- │ └─ Use Graph Execution
90
-
91
- ├─ 📷 Multimodal Input (NEW)
92
- │ ├─ Enable Image Input (OCR)
93
- │ └─ Enable Audio Input (STT)
94
-
95
- └─ 🔊 Audio Output
96
- ├─ Enable Audio Output
97
- ├─ TTS Voice
98
- ├─ TTS Speech Speed
99
- ├─ TTS GPU Type (if Modal available)
100
- └─ 🔊 Audio Response (moved from main area)
101
- ```
102
-
103
- ## 🔍 Key Features
104
-
105
- ### Multimodal Inputs (Always Visible)
106
- - **Image Upload**: Available in ChatInterface textbox (multimodal=True)
107
- - **Audio Recording**: Available in ChatInterface textbox (multimodal=True)
108
- - **File Upload**: Supported via MultimodalTextbox
109
- - **Visibility**: Always visible - part of ChatInterface component
110
- - **Control**: Can be enabled/disabled via sidebar settings
111
-
112
- ### File Rendering
113
- - **Method**: Markdown download links in chat content
114
- - **Format**: `📎 [Download: filename (size)](filepath)`
115
- - **Validation**: Checks file existence before rendering
116
- - **Metadata**: Files stored in message metadata for future use
117
-
118
- ### Settings Flow
119
- 1. User changes settings in sidebar checkboxes
120
- 2. Settings passed to `research_agent()` via `additional_inputs`
121
- 3. Function uses UI settings (with config defaults as fallback)
122
- 4. Multimodal processing respects enable/disable flags
123
- 5. Settings persist during chat session
124
-
125
- ## 🧪 Testing Checklist
126
-
127
- - [ ] Verify all settings are in sidebar
128
- - [ ] Test image upload with OCR enabled/disabled
129
- - [ ] Test audio recording with STT enabled/disabled
130
- - [ ] Test file rendering (markdown, PDF, images)
131
- - [ ] Test audio output generation and display in sidebar
132
- - [ ] Test file download links
133
- - [ ] Verify settings work without requiring app restart
134
- - [ ] Test on different screen sizes (responsive design)
135
-
136
- ## 📝 Notes
137
-
138
- 1. **Multimodal Inputs Visibility**: The inputs are always visible because they're part of the `MultimodalTextbox` component when `multimodal=True` is set in ChatInterface. No additional visibility control is needed.
139
-
140
- 2. **Settings Persistence**: Settings are passed via function parameters, so they persist during the chat session but reset when the app restarts. For persistent settings across sessions, consider using Gradio's state management or session storage.
141
-
142
- 3. **File Rendering**: Gradio ChatInterface automatically handles markdown file links. The current implementation with file size information should work well. For more advanced file previews, consider using Gradio's File component in a custom Blocks layout.
143
-
144
- 4. **Hidden Components**: The `hf_model_dropdown` and `hf_provider_dropdown` are still hidden. Consider making them visible in a "Model Configuration" accordion if needed, or remove them if not used.
145
-
146
- ## 🚀 Next Steps (Optional Enhancements)
147
-
148
- 1. **Model Configuration Accordion**: Make hf_model and hf_provider visible in sidebar
149
- 2. **File Previews**: Add image previews for uploaded images in chat
150
- 3. **Settings Persistence**: Implement session-based settings storage
151
- 4. **Advanced File Rendering**: Use Gradio File component for better file handling
152
- 5. **Error Handling**: Add better error messages for failed file operations
153
-
154
-
155
-
156
-
157
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
Makefile DELETED
@@ -1,42 +0,0 @@
1
- .PHONY: install test lint format typecheck check clean all cov cov-html
2
-
3
- # Default target
4
- all: check
5
-
6
- install:
7
- uv sync --all-extras
8
- uv run pre-commit install
9
-
10
- test:
11
- uv run pytest tests/unit/ -v -m "not openai" -p no:logfire
12
-
13
- test-hf:
14
- uv run pytest tests/ -v -m "huggingface" -p no:logfire
15
-
16
- test-all:
17
- uv run pytest tests/ -v -p no:logfire
18
-
19
- # Coverage aliases
20
- cov: test-cov
21
- test-cov:
22
- uv run pytest --cov=src --cov-report=term-missing -m "not openai" -p no:logfire
23
-
24
- cov-html:
25
- uv run pytest --cov=src --cov-report=html -p no:logfire
26
- @echo "Coverage report: open htmlcov/index.html"
27
-
28
- lint:
29
- uv run ruff check src tests
30
-
31
- format:
32
- uv run ruff format src tests
33
-
34
- typecheck:
35
- uv run mypy src
36
-
37
- check: lint typecheck test-cov
38
- @echo "All checks passed!"
39
-
40
- clean:
41
- rm -rf .pytest_cache .mypy_cache .ruff_cache __pycache__ .coverage htmlcov
42
- find . -type d -name "__pycache__" -exec rm -rf {} + 2>/dev/null || true
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
PDF_REPORT_INTEGRATION.md DELETED
@@ -1,134 +0,0 @@
1
- # PDF Report Generation Integration
2
-
3
- ## Summary
4
-
5
- Integrated PDF generation functionality into the report file service using utilities from `folder/utils copy`. Reports can now be automatically converted to PDF format as a final step.
6
-
7
- ## Changes Made
8
-
9
- ### 1. Added PDF Conversion Utilities
10
-
11
- **Files Created:**
12
- - `src/utils/md_to_pdf.py` - Markdown to PDF conversion utility
13
- - `src/utils/markdown.css` - CSS styling for PDF output
14
-
15
- **Features:**
16
- - Uses `md2pdf` library for conversion
17
- - Includes error handling and graceful fallback
18
- - Supports custom CSS styling
19
- - Logs conversion status
20
-
21
- ### 2. Enhanced ReportFileService
22
-
23
- **File:** `src/services/report_file_service.py`
24
-
25
- **Changes:**
26
- - Added `_save_pdf()` method to generate PDF from markdown
27
- - Updated `save_report_multiple_formats()` to implement PDF generation
28
- - PDF is generated when `report_file_format` is set to `"md_pdf"`
29
- - Both markdown and PDF files are saved and returned
30
-
31
- **Method Signature:**
32
- ```python
33
- def _save_pdf(
34
- self,
35
- report_content: str,
36
- query: str | None = None,
37
- ) -> str:
38
- """Save report as PDF. Returns path to PDF file."""
39
- ```
40
-
41
- ### 3. Updated Graph Orchestrator
42
-
43
- **File:** `src/orchestrator/graph_orchestrator.py`
44
-
45
- **Changes:**
46
- - Updated synthesizer node to use `save_report_multiple_formats()`
47
- - Updated writer node to use `save_report_multiple_formats()`
48
- - Both nodes now return PDF paths in result dict when available
49
- - Result includes both `file` (markdown) and `files` (both formats) keys
50
-
51
- **Result Format:**
52
- ```python
53
- {
54
- "message": final_report, # Report content
55
- "file": "/path/to/report.md", # Markdown file
56
- "files": ["/path/to/report.md", "/path/to/report.pdf"] # Both formats
57
- }
58
- ```
59
-
60
- ## Configuration
61
-
62
- PDF generation is controlled by the `report_file_format` setting in `src/utils/config.py`:
63
-
64
- ```python
65
- report_file_format: Literal["md", "md_html", "md_pdf"] = Field(
66
- default="md",
67
- description="File format(s) to save reports in."
68
- )
69
- ```
70
-
71
- **Options:**
72
- - `"md"` - Save only markdown (default)
73
- - `"md_html"` - Save markdown + HTML (not yet implemented)
74
- - `"md_pdf"` - Save markdown + PDF ✅ **Now implemented**
75
-
76
- ## Usage
77
-
78
- ### Enable PDF Generation
79
-
80
- Set the environment variable or update settings:
81
- ```bash
82
- REPORT_FILE_FORMAT=md_pdf
83
- ```
84
-
85
- Or in code:
86
- ```python
87
- from src.utils.config import settings
88
- settings.report_file_format = "md_pdf"
89
- ```
90
-
91
- ### Dependencies
92
-
93
- PDF generation requires the `md2pdf` library:
94
- ```bash
95
- pip install md2pdf
96
- ```
97
-
98
- If `md2pdf` is not installed, the system will:
99
- - Log a warning
100
- - Continue with markdown-only saving
101
- - Not fail the report generation
102
-
103
- ## File Output
104
-
105
- When PDF generation is enabled:
106
- 1. Markdown file is always saved first
107
- 2. PDF is generated from the markdown content
108
- 3. Both file paths are returned in the result
109
- 4. Gradio interface can display/download both files
110
-
111
- ## Error Handling
112
-
113
- - If PDF generation fails, markdown file is still saved
114
- - Errors are logged but don't interrupt report generation
115
- - Graceful fallback ensures reports are always available
116
-
117
- ## Integration Points
118
-
119
- PDF generation is automatically triggered when:
120
- 1. Graph orchestrator synthesizer node completes
121
- 2. Graph orchestrator writer node completes
122
- 3. `save_report_multiple_formats()` is called
123
- 4. `report_file_format` is set to `"md_pdf"`
124
-
125
- ## Future Enhancements
126
-
127
- - HTML format support (`md_html`)
128
- - Custom PDF templates
129
- - PDF metadata (title, author, keywords)
130
- - PDF compression options
131
- - Batch PDF generation
132
-
133
-
134
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
README.md CHANGED
@@ -34,16 +34,15 @@ tags:
34
  > [!IMPORTANT]
35
  > **You are reading the Gradio Demo README!**
36
  >
37
- > - 📚 **Documentation**: See our [technical documentation](deepcritical.github.io/GradioDemo/) for detailed information
38
- > - 📖 **Complete README**: Check out the [full README](.github/README.md) for setup, configuration, and contribution guidelines
39
- > - 🏆 **Hackathon Submission**: Keep reading below for more information about our MCP Hackathon submission
40
 
41
  <div align="center">
42
 
43
  [![GitHub](https://img.shields.io/github/stars/DeepCritical/GradioDemo?style=for-the-badge&logo=github&logoColor=white&label=GitHub&labelColor=181717&color=181717)](https://github.com/DeepCritical/GradioDemo)
44
  [![Documentation](https://img.shields.io/badge/Docs-0080FF?style=for-the-badge&logo=readthedocs&logoColor=white&labelColor=0080FF&color=0080FF)](deepcritical.github.io/GradioDemo/)
45
  [![Demo](https://img.shields.io/badge/Demo-FFD21E?style=for-the-badge&logo=huggingface&logoColor=white&labelColor=FFD21E&color=FFD21E)](https://huggingface.co/spaces/DataQuests/DeepCritical)
46
- [![YouTube](https://img.shields.io/badge/YouTube-FF0000?style=for-the-badge&logo=youtube&logoColor=white&label=Watch%20Demo&labelColor=FF0000&color=FF0000)](https://www.youtube.com/watch?v=https://youtu.be/Mb0M83BqgOw)
47
  [![codecov](https://codecov.io/gh/DeepCritical/GradioDemo/graph/badge.svg?token=B1f05RCGpz)](https://codecov.io/gh/DeepCritical/GradioDemo)
48
  [![Join us on Discord](https://img.shields.io/discord/1109943800132010065?label=Discord&logo=discord&style=flat-square)](https://discord.gg/qdfnvSPcqP)
49
 
@@ -55,147 +54,3 @@ tags:
55
  ## About
56
 
57
  The DETERMINATOR is a powerful generalist deep research agent system that stops at nothing until finding precise answers to complex questions. It uses iterative search-and-judge loops to comprehensively investigate any research question from any domain.
58
-
59
-
60
- > For this hackathon we're proposing a simple yet powerful Deep Research Agent that iteratively looks for the answer until it finds it using general purpose websearch and special purpose retrievers for technical retrievers.
61
-
62
- ## Who We Are & Motivation
63
-
64
- We're a group from the `DeepCritical` Group that met in the `hugging-science` discord.
65
-
66
- We're enthusiastic about strongly typed and robust pythonic agentic frameworks , currently building ai-assisted multi-agent systems for research automations , like critical literature reviews , clinical data retrival , and bio informatics and computational medicine applications .
67
-
68
- Starting from Magentic Design Patterns for agentic systems , we discovered we could get better results with iterative graphs , orchestrators and planners with magentic agentics as single tools inside iterations.
69
-
70
- ## Do You Like This App ?
71
-
72
- Please join us @ https://hf.co/spaces/DataQuests/DeepCritical where we will keep maintaining it !
73
-
74
- ## The DETERMINATOR is Lightweight and POWERFUL
75
-
76
- - very accessible (multimodal inputs , audio and text out)
77
- - fully local embeddings
78
- - configurable providers (local/hosted) for websearch
79
- - all data stays local
80
- - fully configurable models and huggingface providers with login
81
- - easily extensible and hackable
82
- - uses Gradio a lot (clients, mcp , third party huggingface tools)
83
- - Modal for text-to-speech (remote gpu for "local model")
84
- - Braxel for statistical analysis (code execution sandbox)
85
- - Open Source Models from around the 🌐World
86
- - Using Google Gemma , Qwen , Zai , Llama , Mistral Reasoning Models
87
- - Nebius , Together , Scaleway , Hyperbolic, Novita , nscale , Sambanova , ovh , fireworks, all supported and configurable.
88
- - 💖 made with love
89
-
90
-
91
- ## What Can It Do ?
92
-
93
- - long running tasks (potentially millions of tokens over hours and hours)
94
- - data processing and rendering
95
- - statistical analyses
96
- - literature reviews
97
- - websearch
98
- - synthetize complex information
99
- - find hard to find information
100
-
101
- ## Deep Critical In the Media
102
-
103
- - Social Medial Posts about Deep Critical :
104
- - 𝕏 [![X](https://x.com/marioaderman/status/1995247432444133471)]
105
- - 💼 [![LinkedIn](https://www.linkedin.com/feed/update/urn:li:activity:7400984658496081920/)]
106
- - 𝕏 [![X](https://x.com/viratzzs/status/1995258812165664942)]
107
-
108
- -💼 [![LinkedIn](https://www.linkedin.com/in/ana-bossler-07304717?utm_source=share&utm_campaign=share_via&utm_content=profile&utm_medium=ios_app)
109
- -
110
- -
111
-
112
- > [!IMPORTANT]
113
- > **IF YOU ARE A JUDGE**
114
- >
115
- > This project was produced with passion by a group of volunteers please check out or documentation and readmes and please do keep reading below for our story
116
- >
117
- > - 📚 **Documentation**: See our [technical documentation](https://deepcritical.github.io/GradioDemo/) for detailed information
118
- > - 📖 **Complete README**: Check out the Github [full README](.github/README.md) for setup, configuration, and contribution guidelines
119
- > - 🏆 **Hackathon Submission**: Keep reading below for more information about our MCP Hackathon submission
120
-
121
-
122
- **Key Features**:
123
- - **Generalist**: Handles queries from any domain (medical, technical, business, scientific, etc.)
124
- - **Automatic Medical Detection**: Automatically determines if medical knowledge sources (PubMed, ClinicalTrials.gov) are needed
125
- - **Multi-Source Search**: Web search, PubMed, ClinicalTrials.gov, Europe PMC, RAG
126
- - **Stops at Nothing**: Only stops at configured limits (budget, time, iterations), otherwise continues until finding precise answers
127
- - **Evidence Synthesis**: Comprehensive reports with proper citations
128
-
129
- **Important**: The DETERMINATOR is a research tool that synthesizes evidence. It cannot provide medical advice or answer medical questions directly.
130
-
131
- ## Important information
132
-
133
- - **[readme](.github\README.md)**: configure, deploy , contribute and learn more here.
134
- - **[docs](deepcritical.github.io/GradioDemo/)**: want to know how all this works ? read our detailed technical documentation here.
135
- - **[demo](https://huggingface/spaces/DataQuests/DeepCritical)**: Try our demo on huggingface
136
- - **[team](### Team)**: Join us , or follow us !
137
- - **[video]**: See our demo video
138
-
139
- ## Future Developments
140
-
141
- - [] Apply Deep Research Systems To Generate Short Form Video (up to 5 minutes)
142
- - [] Visualize Pydantic Graphs as Loading Screens in the UI
143
- - [] Improve Data Science with more Complex Graph Agents
144
- - [] Create Deep Critical Drug Reporposing / Discovery Demo
145
- - [] Create Deep Critical Literal Review
146
- - [] Create Deep Critical Hypothesis Generator
147
- - [] Create PyPi Package
148
-
149
- ## Completed
150
-
151
- - [x] **Multi-Source Search**: PubMed, ClinicalTrials.gov, bioRxiv/medRxiv
152
- - [x] **MCP Integration**: Use our tools from Claude Desktop or any MCP client
153
- - [x] **HuggingFace OAuth**: Sign in with HuggingFace
154
- - [x] **Modal Sandbox**: Secure execution of AI-generated statistical code
155
- - [x] **LlamaIndex RAG**: Semantic search and evidence synthesis
156
- - [x] **HuggingfaceInference**:
157
- - [x] **HuggingfaceMCP Custom Config To Use Community Tools**:
158
- - [x] **Strongly Typed Composable Graphs**:
159
- - [x] **Specialized Research Teams of Agents**:
160
-
161
- ### Team
162
- - **ZJ**
163
- - 💼 [LinkedIn](https://www.linkedin.com/in/josephpollack/)
164
- - **Mario Aderman**
165
- - 🤗 [HuggingFace](https://huggingface.co/SeasonalFall84)
166
- - 💼 [LinkedIn](https://www.linkedin.com/in/mario-aderman/)
167
- - 𝕏 [X](https://x.com/marioaderman)
168
- - **Joseph Pollack**
169
- - 🤗 [HuggingFace](https://huggingface.co/Tonic)
170
- - 💼 [LinkedIn](https://www.linkedin.com/in/josephpollack/)
171
- - 𝕏 [X](https://x.com/josephpollack)
172
- - **Virat Chauran**
173
- - 𝕏 [X](https://x.com/viratzzs/)
174
- - 💼 [LinkedIn](https://www.linkedin.com/in/viratchauhan/)
175
- - 🤗 [HuggingFace](https://huggingface.co/ViratChauhan)
176
- - **Anna Bossler**
177
- - 💼 [LinkedIn](https://www.linkedin.com/in/ana-bossler-07304717)
178
-
179
-
180
- ## Acknowledgements
181
-
182
- - [DeepBoner](https://hf.co/spaces/mcp-1st-birthday/deepboner)
183
- - Magentic Paper
184
- - [Huggingface](https://hf.co)
185
- - [Gradio](https://gradio.app)
186
- - [DeepCritical](https://github.com/DeepCritical)
187
- - [Modal](https://modal.com)
188
- - Microsoft
189
- - Pydantic
190
- - Llama-index
191
- - Anthhropic/MCP
192
- - All our Tool Providers
193
-
194
-
195
- ## Links
196
-
197
- [![GitHub](https://img.shields.io/github/stars/DeepCritical/GradioDemo?style=for-the-badge&logo=github&logoColor=white&label=GitHub&labelColor=181717&color=181717)](https://github.com/DeepCritical/GradioDemo)
198
- [![Documentation](https://img.shields.io/badge/Docs-0080FF?style=for-the-badge&logo=readthedocs&logoColor=white&labelColor=0080FF&color=0080FF)](deepcritical.github.io/GradioDemo/)
199
- [![Demo](https://img.shields.io/badge/Demo-FFD21E?style=for-the-badge&logo=huggingface&logoColor=white&labelColor=FFD21E&color=FFD21E)](https://huggingface.co/spaces/DataQuests/DeepCritical)
200
- [![codecov](https://codecov.io/gh/DeepCritical/GradioDemo/graph/badge.svg?token=B1f05RCGpz)](https://codecov.io/gh/DeepCritical/GradioDemo)
201
- [![Join us on Discord](https://img.shields.io/discord/1109943800132010065?label=Discord&logo=discord&style=flat-square)](https://discord.gg/qdfnvSPcqP)
 
34
  > [!IMPORTANT]
35
  > **You are reading the Gradio Demo README!**
36
  >
37
+ > - 📚 **Documentation**: See our [technical documentation](https://deepcritical.github.io/GradioDemo/) for detailed information
38
+ > - 📖 **Complete README**: Check out the [Github README](.github/README.md) for setup, configuration, and contribution guidelines
39
+ > - ⚠️**This README is for our Gradio Demo Only !**
40
 
41
  <div align="center">
42
 
43
  [![GitHub](https://img.shields.io/github/stars/DeepCritical/GradioDemo?style=for-the-badge&logo=github&logoColor=white&label=GitHub&labelColor=181717&color=181717)](https://github.com/DeepCritical/GradioDemo)
44
  [![Documentation](https://img.shields.io/badge/Docs-0080FF?style=for-the-badge&logo=readthedocs&logoColor=white&labelColor=0080FF&color=0080FF)](deepcritical.github.io/GradioDemo/)
45
  [![Demo](https://img.shields.io/badge/Demo-FFD21E?style=for-the-badge&logo=huggingface&logoColor=white&labelColor=FFD21E&color=FFD21E)](https://huggingface.co/spaces/DataQuests/DeepCritical)
 
46
  [![codecov](https://codecov.io/gh/DeepCritical/GradioDemo/graph/badge.svg?token=B1f05RCGpz)](https://codecov.io/gh/DeepCritical/GradioDemo)
47
  [![Join us on Discord](https://img.shields.io/discord/1109943800132010065?label=Discord&logo=discord&style=flat-square)](https://discord.gg/qdfnvSPcqP)
48
 
 
54
  ## About
55
 
56
  The DETERMINATOR is a powerful generalist deep research agent system that stops at nothing until finding precise answers to complex questions. It uses iterative search-and-judge loops to comprehensively investigate any research question from any domain.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
REPORT_WRITING_AGENTS_ANALYSIS.md DELETED
@@ -1,189 +0,0 @@
1
- # Report Writing Agents Analysis
2
-
3
- ## Summary
4
-
5
- This document identifies all agents and methods in the repository that generate reports or write to files.
6
-
7
- ## Key Finding
8
-
9
- **All report-writing agents return strings (markdown) - NONE write directly to files.**
10
-
11
- The agents generate report content but do not save it to disk. File writing would need to be added as a separate step.
12
-
13
- ---
14
-
15
- ## Report Writing Agents
16
-
17
- ### 1. WriterAgent
18
- **File**: `src/agents/writer.py`
19
-
20
- **Method**: `async def write_report(query, findings, output_length, output_instructions) -> str`
21
-
22
- **Returns**: Markdown formatted report string
23
-
24
- **Purpose**: Generates final reports from research findings with numbered citations
25
-
26
- **File Writing**: ❌ **NO** - Returns string only
27
-
28
- **Key Features**:
29
- - Validates inputs
30
- - Truncates very long findings (max 50,000 chars)
31
- - Retry logic (3 retries)
32
- - Returns markdown with numbered citations
33
-
34
- ---
35
-
36
- ### 2. LongWriterAgent
37
- **File**: `src/agents/long_writer.py`
38
-
39
- **Methods**:
40
- - `async def write_next_section(original_query, report_draft, next_section_title, next_section_draft) -> LongWriterOutput`
41
- - `async def write_report(original_query, report_title, report_draft) -> str`
42
-
43
- **Returns**:
44
- - `write_next_section()`: `LongWriterOutput` object (structured output)
45
- - `write_report()`: Complete markdown report string
46
-
47
- **Purpose**: Iteratively writes report sections with proper citations and reference management
48
-
49
- **File Writing**: ❌ **NO** - Returns string only
50
-
51
- **Key Features**:
52
- - Writes sections iteratively
53
- - Reformats and deduplicates references
54
- - Adjusts heading levels
55
- - Aggregates references across sections
56
-
57
- ---
58
-
59
- ### 3. ProofreaderAgent
60
- **File**: `src/agents/proofreader.py`
61
-
62
- **Method**: `async def proofread(query, report_draft) -> str`
63
-
64
- **Returns**: Final polished markdown report string
65
-
66
- **Purpose**: Proofreads and finalizes report drafts
67
-
68
- **File Writing**: ❌ **NO** - Returns string only
69
-
70
- **Key Features**:
71
- - Combines sections
72
- - Removes duplicates
73
- - Adds summary
74
- - Preserves references
75
- - Polishes wording
76
-
77
- ---
78
-
79
- ### 4. ReportAgent
80
- **File**: `src/agents/report_agent.py`
81
-
82
- **Method**: `async def run(messages, thread, **kwargs) -> AgentRunResponse`
83
-
84
- **Returns**: `AgentRunResponse` with markdown text in `messages[0].text`
85
-
86
- **Purpose**: Generates structured scientific reports from evidence and hypotheses
87
-
88
- **File Writing**: ❌ **NO** - Returns `AgentRunResponse` object
89
-
90
- **Key Features**:
91
- - Uses structured `ResearchReport` model
92
- - Validates citations
93
- - Returns markdown via `report.to_markdown()`
94
-
95
- ---
96
-
97
- ## File Writing Operations Found
98
-
99
- ### Temporary File Writing (Not Reports)
100
-
101
- 1. **ImageOCRService** (`src/services/image_ocr.py`)
102
- - `_save_image_temp(image) -> str`
103
- - Saves temporary images for OCR processing
104
- - Returns temp file path
105
-
106
- 2. **STTService** (`src/services/stt_gradio.py`)
107
- - `_save_audio_temp(audio_array, sample_rate) -> str`
108
- - Saves temporary audio files for transcription
109
- - Returns temp file path
110
-
111
- ---
112
-
113
- ## Where Reports Are Used
114
-
115
- ### Graph Orchestrator
116
- **File**: `src/orchestrator/graph_orchestrator.py`
117
-
118
- - Line 642: `final_report = await long_writer_agent.write_report(...)`
119
- - Returns string result, stored in graph context
120
- - Final result passed through `AgentEvent` with `message` field
121
-
122
- ### Research Flows
123
- **File**: `src/orchestrator/research_flow.py`
124
-
125
- - `IterativeResearchFlow._create_final_report()`: Calls `writer_agent.write_report()`
126
- - `DeepResearchFlow._create_final_report()`: Calls `long_writer_agent.write_report()`
127
- - Both return strings
128
-
129
- ---
130
-
131
- ## Integration Points for File Writing
132
-
133
- To add file writing capability, you would need to:
134
-
135
- 1. **After report generation**: Save the returned string to a file
136
- 2. **In graph orchestrator**: After `write_report()`, save to file and include path in result
137
- 3. **In research flows**: After `_create_final_report()`, save to file
138
-
139
- ### Example Implementation Pattern
140
-
141
- ```python
142
- import tempfile
143
- from pathlib import Path
144
-
145
- # After report generation
146
- report_content = await writer_agent.write_report(...)
147
-
148
- # Save to file
149
- output_dir = Path("/tmp/reports") # or configurable
150
- output_dir.mkdir(exist_ok=True)
151
- file_path = output_dir / f"report_{timestamp}.md"
152
-
153
- with open(file_path, "w", encoding="utf-8") as f:
154
- f.write(report_content)
155
-
156
- # Return both content and file path
157
- return {
158
- "message": "Report generated successfully",
159
- "file": str(file_path)
160
- }
161
- ```
162
-
163
- ---
164
-
165
- ## Recommendations
166
-
167
- 1. **Add file writing utility**: Create a helper function to save reports to files
168
- 2. **Make it optional**: Add configuration flag to enable/disable file saving
169
- 3. **Use temp directory**: Save to temp directory by default, allow custom path
170
- 4. **Include in graph results**: Modify graph orchestrator to optionally save and return file paths
171
- 5. **Support multiple formats**: Consider saving as both `.md` and potentially `.pdf` or `.html`
172
-
173
- ---
174
-
175
- ## Current State
176
-
177
- ✅ **Report Generation**: Fully implemented
178
- ❌ **File Writing**: Not implemented
179
- ✅ **File Output Integration**: Recently added (see previous work on `event_to_chat_message`)
180
-
181
- The infrastructure to handle file outputs in Gradio is in place, but the agents themselves do not yet write files. They would need to be enhanced or wrapped to add file writing capability.
182
-
183
-
184
-
185
-
186
-
187
-
188
-
189
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
SERPER_WEBSEARCH_IMPLEMENTATION_PLAN.md DELETED
@@ -1,403 +0,0 @@
1
- # SERPER Web Search Implementation Plan
2
-
3
- ## Executive Summary
4
-
5
- This plan details the implementation of SERPER-based web search by vendoring code from `folder/tools/web_search.py` into `src/tools/`, creating a protocol-compliant `SerperWebSearchTool`, fixing the existing `WebSearchTool`, and integrating both into the main search flow.
6
-
7
- ## Project Structure
8
-
9
- ### Project 1: Vendor and Refactor Core Web Search Components
10
- **Goal**: Extract and vendor Serper/SearchXNG search logic from `folder/tools/web_search.py` into `src/tools/`
11
-
12
- ### Project 2: Create Protocol-Compliant SerperWebSearchTool
13
- **Goal**: Implement `SerperWebSearchTool` class that fully complies with `SearchTool` protocol
14
-
15
- ### Project 3: Fix Existing WebSearchTool Protocol Compliance
16
- **Goal**: Make existing `WebSearchTool` (DuckDuckGo) protocol-compliant
17
-
18
- ### Project 4: Integrate Web Search into SearchHandler
19
- **Goal**: Add web search tools to main search flow in `src/app.py`
20
-
21
- ### Project 5: Update Callers and Dependencies
22
- **Goal**: Update all code that uses web search to work with new implementation
23
-
24
- ### Project 6: Testing and Validation
25
- **Goal**: Add comprehensive tests for all web search implementations
26
-
27
- ---
28
-
29
- ## Detailed Implementation Plan
30
-
31
- ### PROJECT 1: Vendor and Refactor Core Web Search Components
32
-
33
- #### Activity 1.1: Create Vendor Module Structure
34
- **File**: `src/tools/vendored/__init__.py`
35
- - **Task 1.1.1**: Create `src/tools/vendored/` directory
36
- - **Task 1.1.2**: Create `__init__.py` with exports
37
-
38
- **File**: `src/tools/vendored/web_search_core.py`
39
- - **Task 1.1.3**: Vendor `ScrapeResult`, `WebpageSnippet`, `SearchResults` models from `folder/tools/web_search.py` (lines 23-37)
40
- - **Task 1.1.4**: Vendor `scrape_urls()` function (lines 274-299)
41
- - **Task 1.1.5**: Vendor `fetch_and_process_url()` function (lines 302-348)
42
- - **Task 1.1.6**: Vendor `html_to_text()` function (lines 351-368)
43
- - **Task 1.1.7**: Vendor `is_valid_url()` function (lines 371-410)
44
- - **Task 1.1.8**: Vendor `ssl_context` setup (lines 115-120)
45
- - **Task 1.1.9**: Add imports: `aiohttp`, `asyncio`, `BeautifulSoup`, `ssl`
46
- - **Task 1.1.10**: Add `CONTENT_LENGTH_LIMIT = 10000` constant
47
- - **Task 1.1.11**: Add type hints following project standards
48
- - **Task 1.1.12**: Add structlog logging
49
- - **Task 1.1.13**: Replace `print()` statements with `logger` calls
50
-
51
- **File**: `src/tools/vendored/serper_client.py`
52
- - **Task 1.1.14**: Vendor `SerperClient` class from `folder/tools/web_search.py` (lines 123-196)
53
- - **Task 1.1.15**: Remove dependency on `ResearchAgent` and `ResearchRunner`
54
- - **Task 1.1.16**: Replace filter agent with simple relevance filtering or remove it
55
- - **Task 1.1.17**: Add `__init__` that takes `api_key: str | None` parameter
56
- - **Task 1.1.18**: Update `search()` method to return `list[WebpageSnippet]` without filtering
57
- - **Task 1.1.19**: Remove `_filter_results()` method (or make it optional)
58
- - **Task 1.1.20**: Add error handling with `SearchError` and `RateLimitError`
59
- - **Task 1.1.21**: Add structlog logging
60
- - **Task 1.1.22**: Add type hints
61
-
62
- **File**: `src/tools/vendored/searchxng_client.py`
63
- - **Task 1.1.23**: Vendor `SearchXNGClient` class from `folder/tools/web_search.py` (lines 199-271)
64
- - **Task 1.1.24**: Remove dependency on `ResearchAgent` and `ResearchRunner`
65
- - **Task 1.1.25**: Replace filter agent with simple relevance filtering or remove it
66
- - **Task 1.1.26**: Add `__init__` that takes `host: str` parameter
67
- - **Task 1.1.27**: Update `search()` method to return `list[WebpageSnippet]` without filtering
68
- - **Task 1.1.28**: Remove `_filter_results()` method (or make it optional)
69
- - **Task 1.1.29**: Add error handling with `SearchError` and `RateLimitError`
70
- - **Task 1.1.30**: Add structlog logging
71
- - **Task 1.1.31**: Add type hints
72
-
73
- #### Activity 1.2: Create Rate Limiting for Web Search
74
- **File**: `src/tools/rate_limiter.py`
75
- - **Task 1.2.1**: Add `get_serper_limiter()` function (rate: "10/second" with API key)
76
- - **Task 1.2.2**: Add `get_searchxng_limiter()` function (rate: "5/second")
77
- - **Task 1.2.3**: Use `RateLimiterFactory.get()` pattern
78
-
79
- ---
80
-
81
- ### PROJECT 2: Create Protocol-Compliant SerperWebSearchTool
82
-
83
- #### Activity 2.1: Implement SerperWebSearchTool Class
84
- **File**: `src/tools/serper_web_search.py`
85
- - **Task 2.1.1**: Create new file `src/tools/serper_web_search.py`
86
- - **Task 2.1.2**: Add imports:
87
- - `from src.tools.base import SearchTool`
88
- - `from src.tools.vendored.serper_client import SerperClient`
89
- - `from src.tools.vendored.web_search_core import scrape_urls, WebpageSnippet`
90
- - `from src.tools.rate_limiter import get_serper_limiter`
91
- - `from src.tools.query_utils import preprocess_query`
92
- - `from src.utils.config import settings`
93
- - `from src.utils.exceptions import SearchError, RateLimitError`
94
- - `from src.utils.models import Citation, Evidence`
95
- - `import structlog`
96
- - `from tenacity import retry, stop_after_attempt, wait_exponential`
97
-
98
- - **Task 2.1.3**: Create `SerperWebSearchTool` class
99
- - **Task 2.1.4**: Add `__init__(self, api_key: str | None = None)` method
100
- - Line 2.1.4.1: Get API key from parameter or `settings.serper_api_key`
101
- - Line 2.1.4.2: Validate API key is not None, raise `ConfigurationError` if missing
102
- - Line 2.1.4.3: Initialize `SerperClient(api_key=self.api_key)`
103
- - Line 2.1.4.4: Get rate limiter: `self._limiter = get_serper_limiter(self.api_key)`
104
-
105
- - **Task 2.1.5**: Add `@property def name(self) -> str:` returning `"serper"`
106
-
107
- - **Task 2.1.6**: Add `async def _rate_limit(self) -> None:` method
108
- - Line 2.1.6.1: Call `await self._limiter.acquire()`
109
-
110
- - **Task 2.1.7**: Add `@retry(...)` decorator with exponential backoff
111
-
112
- - **Task 2.1.8**: Add `async def search(self, query: str, max_results: int = 10) -> list[Evidence]:` method
113
- - Line 2.1.8.1: Call `await self._rate_limit()`
114
- - Line 2.1.8.2: Preprocess query: `clean_query = preprocess_query(query)`
115
- - Line 2.1.8.3: Use `clean_query if clean_query else query`
116
- - Line 2.1.8.4: Call `search_results = await self._client.search(query, filter_for_relevance=False, max_results=max_results)`
117
- - Line 2.1.8.5: Call `scraped = await scrape_urls(search_results)`
118
- - Line 2.1.8.6: Convert `ScrapeResult` to `Evidence` objects:
119
- - Line 2.1.8.6.1: Create `Citation` with `title`, `url`, `source="serper"`, `date="Unknown"`, `authors=[]`
120
- - Line 2.1.8.6.2: Create `Evidence` with `content=scraped.text`, `citation`, `relevance=0.0`
121
- - Line 2.1.8.7: Return `list[Evidence]`
122
- - Line 2.1.8.8: Add try/except for `httpx.HTTPStatusError`:
123
- - Line 2.1.8.8.1: Check for 429 status, raise `RateLimitError`
124
- - Line 2.1.8.8.2: Otherwise raise `SearchError`
125
- - Line 2.1.8.9: Add try/except for `httpx.TimeoutException`, raise `SearchError`
126
- - Line 2.1.8.10: Add generic exception handler, log and raise `SearchError`
127
-
128
- #### Activity 2.2: Implement SearchXNGWebSearchTool Class
129
- **File**: `src/tools/searchxng_web_search.py`
130
- - **Task 2.2.1**: Create new file `src/tools/searchxng_web_search.py`
131
- - **Task 2.2.2**: Add imports (similar to SerperWebSearchTool)
132
- - **Task 2.2.3**: Create `SearchXNGWebSearchTool` class
133
- - **Task 2.2.4**: Add `__init__(self, host: str | None = None)` method
134
- - Line 2.2.4.1: Get host from parameter or `settings.searchxng_host`
135
- - Line 2.2.4.2: Validate host is not None, raise `ConfigurationError` if missing
136
- - Line 2.2.4.3: Initialize `SearchXNGClient(host=self.host)`
137
- - Line 2.2.4.4: Get rate limiter: `self._limiter = get_searchxng_limiter()`
138
-
139
- - **Task 2.2.5**: Add `@property def name(self) -> str:` returning `"searchxng"`
140
-
141
- - **Task 2.2.6**: Add `async def _rate_limit(self) -> None:` method
142
-
143
- - **Task 2.2.7**: Add `@retry(...)` decorator
144
-
145
- - **Task 2.2.8**: Add `async def search(self, query: str, max_results: int = 10) -> list[Evidence]:` method
146
- - Line 2.2.8.1-2.2.8.10: Similar structure to SerperWebSearchTool
147
-
148
- ---
149
-
150
- ### PROJECT 3: Fix Existing WebSearchTool Protocol Compliance
151
-
152
- #### Activity 3.1: Update WebSearchTool Class
153
- **File**: `src/tools/web_search.py`
154
- - **Task 3.1.1**: Add `@property def name(self) -> str:` method returning `"duckduckgo"` (after line 17)
155
-
156
- - **Task 3.1.2**: Change `search()` return type from `SearchResult` to `list[Evidence]` (line 19)
157
-
158
- - **Task 3.1.3**: Update `search()` method body:
159
- - Line 3.1.3.1: Keep existing search logic (lines 21-43)
160
- - Line 3.1.3.2: Instead of returning `SearchResult`, return `evidence` list directly (line 44)
161
- - Line 3.1.3.3: Update exception handler to return empty list `[]` instead of `SearchResult` (line 51)
162
-
163
- - **Task 3.1.4**: Add imports if needed:
164
- - Line 3.1.4.1: `from src.utils.exceptions import SearchError`
165
- - Line 3.1.4.2: Update exception handling to raise `SearchError` instead of returning error `SearchResult`
166
-
167
- - **Task 3.1.5**: Add query preprocessing:
168
- - Line 3.1.5.1: Import `from src.tools.query_utils import preprocess_query`
169
- - Line 3.1.5.2: Add `clean_query = preprocess_query(query)` before search
170
- - Line 3.1.5.3: Use `clean_query if clean_query else query`
171
-
172
- #### Activity 3.2: Update Retrieval Agent Caller
173
- **File**: `src/agents/retrieval_agent.py`
174
- - **Task 3.2.1**: Update `search_web()` function (line 31):
175
- - Line 3.2.1.1: Change `results = await _web_search.search(query, max_results)`
176
- - Line 3.2.1.2: Change to `evidence = await _web_search.search(query, max_results)`
177
- - Line 3.2.1.3: Update check: `if not evidence:` instead of `if not results.evidence:`
178
- - Line 3.2.1.4: Update state update: `new_count = state.add_evidence(evidence)` instead of `results.evidence`
179
- - Line 3.2.1.5: Update logging: `results_found=len(evidence)` instead of `len(results.evidence)`
180
- - Line 3.2.1.6: Update output formatting: `for i, r in enumerate(evidence[:max_results], 1):` instead of `results.evidence[:max_results]`
181
- - Line 3.2.1.7: Update deduplication: `await state.embedding_service.deduplicate(evidence)` instead of `results.evidence`
182
- - Line 3.2.1.8: Update output message: `Found {len(evidence)} web results` instead of `len(results.evidence)`
183
-
184
- ---
185
-
186
- ### PROJECT 4: Integrate Web Search into SearchHandler
187
-
188
- #### Activity 4.1: Create Web Search Tool Factory
189
- **File**: `src/tools/web_search_factory.py`
190
- - **Task 4.1.1**: Create new file `src/tools/web_search_factory.py`
191
- - **Task 4.1.2**: Add imports:
192
- - `from src.tools.web_search import WebSearchTool`
193
- - `from src.tools.serper_web_search import SerperWebSearchTool`
194
- - `from src.tools.searchxng_web_search import SearchXNGWebSearchTool`
195
- - `from src.utils.config import settings`
196
- - `from src.utils.exceptions import ConfigurationError`
197
- - `import structlog`
198
-
199
- - **Task 4.1.3**: Add `logger = structlog.get_logger()`
200
-
201
- - **Task 4.1.4**: Create `def create_web_search_tool() -> SearchTool | None:` function
202
- - Line 4.1.4.1: Check `settings.web_search_provider`
203
- - Line 4.1.4.2: If `"serper"`:
204
- - Line 4.1.4.2.1: Check `settings.serper_api_key` or `settings.web_search_available()`
205
- - Line 4.1.4.2.2: If available, return `SerperWebSearchTool()`
206
- - Line 4.1.4.2.3: Else log warning and return `None`
207
- - Line 4.1.4.3: If `"searchxng"`:
208
- - Line 4.1.4.3.1: Check `settings.searchxng_host` or `settings.web_search_available()`
209
- - Line 4.1.4.3.2: If available, return `SearchXNGWebSearchTool()`
210
- - Line 4.1.4.3.3: Else log warning and return `None`
211
- - Line 4.1.4.4: If `"duckduckgo"`:
212
- - Line 4.1.4.4.1: Return `WebSearchTool()` (always available)
213
- - Line 4.1.4.5: If `"brave"` or `"tavily"`:
214
- - Line 4.1.4.5.1: Log warning "Not yet implemented"
215
- - Line 4.1.4.5.2: Return `None`
216
- - Line 4.1.4.6: Default: return `WebSearchTool()` (fallback to DuckDuckGo)
217
-
218
- #### Activity 4.2: Update SearchHandler Initialization
219
- **File**: `src/app.py`
220
- - **Task 4.2.1**: Add import: `from src.tools.web_search_factory import create_web_search_tool`
221
-
222
- - **Task 4.2.2**: Update `configure_orchestrator()` function (around line 73):
223
- - Line 4.2.2.1: Before creating `SearchHandler`, call `web_search_tool = create_web_search_tool()`
224
- - Line 4.2.2.2: Create tools list: `tools = [PubMedTool(), ClinicalTrialsTool(), EuropePMCTool()]`
225
- - Line 4.2.2.3: If `web_search_tool is not None`:
226
- - Line 4.2.2.3.1: Append `web_search_tool` to tools list
227
- - Line 4.2.2.3.2: Log info: "Web search tool added to search handler"
228
- - Line 4.2.2.4: Update `SearchHandler` initialization to use `tools` list
229
-
230
- ---
231
-
232
- ### PROJECT 5: Update Callers and Dependencies
233
-
234
- #### Activity 5.1: Update web_search_adapter
235
- **File**: `src/tools/web_search_adapter.py`
236
- - **Task 5.1.1**: Update `web_search()` function to use new implementation:
237
- - Line 5.1.1.1: Import `from src.tools.web_search_factory import create_web_search_tool`
238
- - Line 5.1.1.2: Remove dependency on `folder.tools.web_search`
239
- - Line 5.1.1.3: Get tool: `tool = create_web_search_tool()`
240
- - Line 5.1.1.4: If `tool is None`, return error message
241
- - Line 5.1.1.5: Call `evidence = await tool.search(query, max_results=5)`
242
- - Line 5.1.1.6: Convert `Evidence` objects to formatted string:
243
- - Line 5.1.1.6.1: Format each evidence with title, URL, content preview
244
- - Line 5.1.1.7: Return formatted string
245
-
246
- #### Activity 5.2: Update Tool Executor
247
- **File**: `src/tools/tool_executor.py`
248
- - **Task 5.2.1**: Verify `web_search_adapter.web_search()` usage (line 86) still works
249
- - **Task 5.2.2**: No changes needed if adapter is updated correctly
250
-
251
- #### Activity 5.3: Update Planner Agent
252
- **File**: `src/orchestrator/planner_agent.py`
253
- - **Task 5.3.1**: Verify `web_search_adapter.web_search()` usage (line 14) still works
254
- - **Task 5.3.2**: No changes needed if adapter is updated correctly
255
-
256
- #### Activity 5.4: Remove Legacy Dependencies
257
- **File**: `src/tools/web_search_adapter.py`
258
- - **Task 5.4.1**: Remove import of `folder.llm_config` and `folder.tools.web_search`
259
- - **Task 5.4.2**: Update error messages to reflect new implementation
260
-
261
- ---
262
-
263
- ### PROJECT 6: Testing and Validation
264
-
265
- #### Activity 6.1: Unit Tests for Vendored Components
266
- **File**: `tests/unit/tools/test_vendored_web_search_core.py`
267
- - **Task 6.1.1**: Test `scrape_urls()` function
268
- - **Task 6.1.2**: Test `fetch_and_process_url()` function
269
- - **Task 6.1.3**: Test `html_to_text()` function
270
- - **Task 6.1.4**: Test `is_valid_url()` function
271
-
272
- **File**: `tests/unit/tools/test_vendored_serper_client.py`
273
- - **Task 6.1.5**: Mock SerperClient API calls
274
- - **Task 6.1.6**: Test successful search
275
- - **Task 6.1.7**: Test error handling
276
- - **Task 6.1.8**: Test rate limiting
277
-
278
- **File**: `tests/unit/tools/test_vendored_searchxng_client.py`
279
- - **Task 6.1.9**: Mock SearchXNGClient API calls
280
- - **Task 6.1.10**: Test successful search
281
- - **Task 6.1.11**: Test error handling
282
- - **Task 6.1.12**: Test rate limiting
283
-
284
- #### Activity 6.2: Unit Tests for Web Search Tools
285
- **File**: `tests/unit/tools/test_serper_web_search.py`
286
- - **Task 6.2.1**: Test `SerperWebSearchTool.__init__()` with valid API key
287
- - **Task 6.2.2**: Test `SerperWebSearchTool.__init__()` without API key (should raise)
288
- - **Task 6.2.3**: Test `name` property returns `"serper"`
289
- - **Task 6.2.4**: Test `search()` returns `list[Evidence]`
290
- - **Task 6.2.5**: Test `search()` with mocked SerperClient
291
- - **Task 6.2.6**: Test error handling (SearchError, RateLimitError)
292
- - **Task 6.2.7**: Test query preprocessing
293
- - **Task 6.2.8**: Test rate limiting
294
-
295
- **File**: `tests/unit/tools/test_searchxng_web_search.py`
296
- - **Task 6.2.9**: Similar tests for SearchXNGWebSearchTool
297
-
298
- **File**: `tests/unit/tools/test_web_search.py`
299
- - **Task 6.2.10**: Test `WebSearchTool.name` property returns `"duckduckgo"`
300
- - **Task 6.2.11**: Test `WebSearchTool.search()` returns `list[Evidence]`
301
- - **Task 6.2.12**: Test `WebSearchTool.search()` with mocked DDGS
302
- - **Task 6.2.13**: Test error handling
303
- - **Task 6.2.14**: Test query preprocessing
304
-
305
- #### Activity 6.3: Integration Tests
306
- **File**: `tests/integration/test_web_search_integration.py`
307
- - **Task 6.3.1**: Test `SerperWebSearchTool` with real API (marked `@pytest.mark.integration`)
308
- - **Task 6.3.2**: Test `SearchXNGWebSearchTool` with real API (marked `@pytest.mark.integration`)
309
- - **Task 6.3.3**: Test `WebSearchTool` with real DuckDuckGo (marked `@pytest.mark.integration`)
310
- - **Task 6.3.4**: Test `create_web_search_tool()` factory function
311
- - **Task 6.3.5**: Test SearchHandler with web search tool
312
-
313
- #### Activity 6.4: Update Existing Tests
314
- **File**: `tests/unit/agents/test_retrieval_agent.py`
315
- - **Task 6.4.1**: Update tests to expect `list[Evidence]` instead of `SearchResult`
316
- - **Task 6.4.2**: Mock `WebSearchTool.search()` to return `list[Evidence]`
317
-
318
- **File**: `tests/unit/tools/test_tool_executor.py`
319
- - **Task 6.4.3**: Verify tests still pass with updated `web_search_adapter`
320
-
321
- ---
322
-
323
- ## Implementation Order
324
-
325
- 1. **PROJECT 1**: Vendor core components (foundation)
326
- 2. **PROJECT 3**: Fix existing WebSearchTool (quick win, unblocks retrieval agent)
327
- 3. **PROJECT 2**: Create SerperWebSearchTool (new functionality)
328
- 4. **PROJECT 4**: Integrate into SearchHandler (main integration)
329
- 5. **PROJECT 5**: Update callers (cleanup dependencies)
330
- 6. **PROJECT 6**: Testing (validation)
331
-
332
- ---
333
-
334
- ## Dependencies and Prerequisites
335
-
336
- ### External Dependencies
337
- - `aiohttp` - Already in requirements
338
- - `beautifulsoup4` - Already in requirements
339
- - `duckduckgo-search` - Already in requirements
340
- - `tenacity` - Already in requirements
341
- - `structlog` - Already in requirements
342
-
343
- ### Internal Dependencies
344
- - `src/tools/base.py` - SearchTool protocol
345
- - `src/tools/rate_limiter.py` - Rate limiting utilities
346
- - `src/tools/query_utils.py` - Query preprocessing
347
- - `src/utils/config.py` - Settings and configuration
348
- - `src/utils/exceptions.py` - Custom exceptions
349
- - `src/utils/models.py` - Evidence, Citation models
350
-
351
- ### Configuration Requirements
352
- - `SERPER_API_KEY` - For Serper provider
353
- - `SEARCHXNG_HOST` - For SearchXNG provider
354
- - `WEB_SEARCH_PROVIDER` - Environment variable (default: "duckduckgo")
355
-
356
- ---
357
-
358
- ## Risk Assessment
359
-
360
- ### High Risk
361
- - **Breaking changes to retrieval_agent.py**: Must update carefully to handle `list[Evidence]` instead of `SearchResult`
362
- - **Legacy folder dependencies**: Need to ensure all code is properly vendored
363
-
364
- ### Medium Risk
365
- - **Rate limiting**: Serper API may have different limits than expected
366
- - **Error handling**: Need to handle API failures gracefully
367
-
368
- ### Low Risk
369
- - **Query preprocessing**: May need adjustment for web search vs PubMed
370
- - **Testing**: Integration tests require API keys
371
-
372
- ---
373
-
374
- ## Success Criteria
375
-
376
- 1. ✅ `SerperWebSearchTool` implements `SearchTool` protocol correctly
377
- 2. ✅ `WebSearchTool` implements `SearchTool` protocol correctly
378
- 3. ✅ Both tools can be added to `SearchHandler`
379
- 4. ✅ `web_search_adapter` works with new implementation
380
- 5. ✅ `retrieval_agent` works with updated `WebSearchTool`
381
- 6. ✅ All unit tests pass
382
- 7. ✅ Integration tests pass (with API keys)
383
- 8. ✅ No dependencies on `folder/tools/web_search.py` in `src/` code
384
- 9. ✅ Configuration supports multiple providers
385
- 10. ✅ Error handling is robust
386
-
387
- ---
388
-
389
- ## Notes
390
-
391
- - The vendored code should be self-contained and not depend on `folder/` modules
392
- - Filter agent functionality from original code is removed (can be added later if needed)
393
- - Rate limiting follows the same pattern as PubMed tool
394
- - Query preprocessing may need web-specific adjustments (less aggressive than PubMed)
395
- - Consider adding relevance scoring in the future
396
-
397
-
398
-
399
-
400
-
401
-
402
-
403
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
WEB_SEARCH_TOOL_ASSESSMENT.md DELETED
@@ -1,239 +0,0 @@
1
- # Web Search Tool Assessment
2
-
3
- ## Executive Summary
4
-
5
- The application has **two separate web search implementations** with different readiness levels:
6
-
7
- 1. **`WebSearchTool`** (`src/tools/web_search.py`) - **Partially Ready** ⚠️
8
- - Functional but **NOT compliant** with `SearchTool` protocol
9
- - **NOT integrated** into main search handler
10
- - Only used in magentic orchestrator's retrieval agent
11
-
12
- 2. **`web_search_adapter`** (`src/tools/web_search_adapter.py`) - **Functional** ✅
13
- - Used by tool executor for WebSearchAgent tasks
14
- - Relies on legacy `folder/tools/web_search.py` implementation
15
-
16
- ## Detailed Analysis
17
-
18
- ### 1. WebSearchTool (`src/tools/web_search.py`)
19
-
20
- #### Current Implementation
21
- - **Location**: `src/tools/web_search.py`
22
- - **Provider**: DuckDuckGo (no API key required)
23
- - **Status**: ⚠️ **Partially Ready**
24
-
25
- #### Issues Identified
26
-
27
- **❌ Protocol Non-Compliance:**
28
- ```python
29
- # Missing required 'name' property
30
- class WebSearchTool:
31
- # Should have: @property def name(self) -> str: return "web"
32
-
33
- # Wrong return type - should return list[Evidence], not SearchResult
34
- async def search(self, query: str, max_results: int = 10) -> SearchResult:
35
- # Returns SearchResult instead of list[Evidence]
36
- ```
37
-
38
- **Comparison with other tools:**
39
- - `PubMedTool` has `@property def name(self) -> str: return "pubmed"`
40
- - `PubMedTool.search()` returns `list[Evidence]`
41
- - `WebSearchTool` returns `SearchResult` (contains `evidence` list inside)
42
-
43
- **❌ Not Integrated:**
44
- - **NOT** included in `SearchHandler` initialization in `src/app.py`:
45
- ```python
46
- search_handler = SearchHandler(
47
- tools=[PubMedTool(), ClinicalTrialsTool(), EuropePMCTool()],
48
- # WebSearchTool() is missing!
49
- )
50
- ```
51
-
52
- **✅ Current Usage:**
53
- - Used in `src/agents/retrieval_agent.py` (magentic orchestrator):
54
- ```python
55
- from src.tools.web_search import WebSearchTool
56
- _web_search = WebSearchTool()
57
- ```
58
-
59
- #### Fix Required
60
- To make `WebSearchTool` compliant and usable:
61
-
62
- 1. **Add `name` property:**
63
- ```python
64
- @property
65
- def name(self) -> str:
66
- return "web"
67
- ```
68
-
69
- 2. **Fix return type:**
70
- ```python
71
- async def search(self, query: str, max_results: int = 10) -> list[Evidence]:
72
- # ... existing code ...
73
- return evidence # Return list[Evidence] directly, not SearchResult
74
- ```
75
-
76
- 3. **Register in SearchHandler:**
77
- ```python
78
- from src.tools.web_search import WebSearchTool
79
-
80
- search_handler = SearchHandler(
81
- tools=[
82
- PubMedTool(),
83
- ClinicalTrialsTool(),
84
- EuropePMCTool(),
85
- WebSearchTool() # Add this
86
- ],
87
- )
88
- ```
89
-
90
- ---
91
-
92
- ### 2. web_search_adapter (`src/tools/web_search_adapter.py`)
93
-
94
- #### Current Implementation
95
- - **Location**: `src/tools/web_search_adapter.py`
96
- - **Status**: ✅ **Functional**
97
- - **Provider**: Uses legacy `folder/tools/web_search.py` (Serper/SearchXNG)
98
-
99
- #### Usage
100
- - Used by `src/tools/tool_executor.py` for `WebSearchAgent` tasks:
101
- ```python
102
- if task.agent == "WebSearchAgent":
103
- result_text = await web_search(task.query)
104
- ```
105
-
106
- - Used by `src/orchestrator/planner_agent.py` for background context
107
-
108
- #### Dependencies
109
- - Requires `folder/tools/web_search.py` (legacy implementation)
110
- - Supports Serper API (requires `SERPER_API_KEY`)
111
- - Supports SearchXNG API (requires `SEARCHXNG_HOST`)
112
-
113
- #### Limitations
114
- - Returns formatted string (not `Evidence` objects)
115
- - Not integrated with `SearchHandler` (different execution path)
116
- - Depends on legacy folder structure
117
-
118
- ---
119
-
120
- ## Integration Status
121
-
122
- ### SearchHandler Integration
123
- **Current State**: ❌ **NOT Integrated**
124
-
125
- The main `SearchHandler` in `src/app.py` only includes:
126
- - `PubMedTool()`
127
- - `ClinicalTrialsTool()`
128
- - `EuropePMCTool()`
129
-
130
- **WebSearchTool is missing from the main search flow.**
131
-
132
- ### Tool Executor Integration
133
- **Current State**: ✅ **Integrated**
134
-
135
- `web_search_adapter` is used via `tool_executor.py`:
136
- - Executes when `AgentTask.agent == "WebSearchAgent"`
137
- - Used in iterative/deep research flows
138
- - Returns formatted text (not Evidence objects)
139
-
140
- ### Magentic Orchestrator Integration
141
- **Current State**: ✅ **Integrated**
142
-
143
- `WebSearchTool` is used in `retrieval_agent.py`:
144
- - Direct instantiation: `_web_search = WebSearchTool()`
145
- - Used via `search_web()` function
146
- - Updates workflow state with evidence
147
-
148
- ---
149
-
150
- ## Can It Be Used?
151
-
152
- ### WebSearchTool (`src/tools/web_search.py`)
153
- **Status**: ⚠️ **Can be used, but with limitations**
154
-
155
- **Can be used:**
156
- - ✅ In magentic orchestrator (already working)
157
- - ✅ As standalone tool (functional)
158
-
159
- **Cannot be used:**
160
- - ❌ In `SearchHandler` (protocol non-compliance)
161
- - ❌ In parallel search flows (not registered)
162
-
163
- **To make fully usable:**
164
- 1. Fix protocol compliance (add `name`, fix return type)
165
- 2. Register in `SearchHandler`
166
- 3. Test integration
167
-
168
- ### web_search_adapter
169
- **Status**: ✅ **Can be used**
170
-
171
- **Can be used:**
172
- - ✅ Via `tool_executor` for WebSearchAgent tasks
173
- - ✅ In planner agent for background context
174
- - ✅ In iterative/deep research flows
175
-
176
- **Limitations:**
177
- - Returns string format (not Evidence objects)
178
- - Requires legacy folder dependencies
179
- - Different execution path than SearchHandler
180
-
181
- ---
182
-
183
- ## Recommendations
184
-
185
- ### Priority 1: Fix WebSearchTool Protocol Compliance
186
- Make `WebSearchTool` fully compliant with `SearchTool` protocol:
187
-
188
- 1. Add `name` property
189
- 2. Change return type from `SearchResult` to `list[Evidence]`
190
- 3. Update all callers if needed
191
-
192
- ### Priority 2: Integrate into SearchHandler
193
- Add `WebSearchTool` to main search flow:
194
-
195
- ```python
196
- from src.tools.web_search import WebSearchTool
197
-
198
- search_handler = SearchHandler(
199
- tools=[
200
- PubMedTool(),
201
- ClinicalTrialsTool(),
202
- EuropePMCTool(),
203
- WebSearchTool() # Add web search
204
- ],
205
- )
206
- ```
207
-
208
- ### Priority 3: Consolidate Implementations
209
- Consider consolidating the two implementations:
210
- - Keep `WebSearchTool` as the main implementation
211
- - Deprecate or migrate `web_search_adapter` usage
212
- - Remove dependency on `folder/tools/web_search.py`
213
-
214
- ### Priority 4: Testing
215
- Add tests for:
216
- - Protocol compliance
217
- - SearchHandler integration
218
- - Error handling
219
- - Rate limiting (if needed)
220
-
221
- ---
222
-
223
- ## Summary Table
224
-
225
- | Component | Status | Protocol Compliant | Integrated | Can Be Used |
226
- |-----------|--------|-------------------|------------|-------------|
227
- | `WebSearchTool` | ⚠️ Partial | ❌ No | ❌ No | ⚠️ Limited |
228
- | `web_search_adapter` | ✅ Functional | N/A | ✅ Yes (tool_executor) | ✅ Yes |
229
-
230
- ---
231
-
232
- ## Conclusion
233
-
234
- The web search functionality exists in two forms:
235
- 1. **`WebSearchTool`** is functional but needs protocol fixes to be fully integrated
236
- 2. **`web_search_adapter`** is working but uses a different execution path
237
-
238
- **Recommendation**: Fix `WebSearchTool` protocol compliance and integrate it into `SearchHandler` for unified search capabilities across all orchestrators.
239
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
dev/Makefile DELETED
@@ -1,51 +0,0 @@
1
- .PHONY: install test lint format typecheck check clean all cov cov-html
2
-
3
- # Default target
4
- all: check
5
-
6
- install:
7
- uv sync --all-extras
8
- uv run pre-commit install
9
-
10
- test:
11
- uv run pytest tests/unit/ -v -m "not openai" -p no:logfire
12
-
13
- test-hf:
14
- uv run pytest tests/ -v -m "huggingface" -p no:logfire
15
-
16
- test-all:
17
- uv run pytest tests/ -v -p no:logfire
18
-
19
- # Coverage aliases
20
- cov: test-cov
21
- test-cov:
22
- uv run pytest --cov=src --cov-report=term-missing -m "not openai" -p no:logfire
23
-
24
- cov-html:
25
- uv run pytest --cov=src --cov-report=html -p no:logfire
26
- @echo "Coverage report: open htmlcov/index.html"
27
-
28
- lint:
29
- uv run ruff check src tests
30
-
31
- format:
32
- uv run ruff format src tests
33
-
34
- typecheck:
35
- uv run mypy src
36
-
37
- check: lint typecheck test-cov
38
- @echo "All checks passed!"
39
-
40
- docs-build:
41
- uv run mkdocs build
42
-
43
- docs-serve:
44
- uv run mkdocs serve
45
-
46
- docs-clean:
47
- rm -rf site/
48
-
49
- clean:
50
- rm -rf .pytest_cache .mypy_cache .ruff_cache __pycache__ .coverage htmlcov
51
- find . -type d -name "__pycache__" -exec rm -rf {} + 2>/dev/null || true
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
dev/__init__.py CHANGED
@@ -2,3 +2,4 @@
2
 
3
 
4
 
 
 
2
 
3
 
4
 
5
+
docs/MKDOCS_IMPROVEMENTS_ASSESSMENT.md ADDED
@@ -0,0 +1,642 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # MkDocs & Material UI Improvement Assessment
2
+
3
+ ## Current Configuration Analysis
4
+
5
+ Your current `mkdocs.yml` already includes many excellent features:
6
+ - ✅ Material theme with light/dark mode toggle
7
+ - ✅ Navigation tabs, sections, expand, and top navigation
8
+ - ✅ Search with suggestions and highlighting
9
+ - ✅ Code annotation and copy buttons
10
+ - ✅ Mermaid diagram support
11
+ - ✅ Code include plugin
12
+ - ✅ Minification for performance
13
+ - ✅ Comprehensive markdown extensions
14
+
15
+ ## Recommended Improvements
16
+
17
+ ### 1. **Versioning & Multi-Version Documentation** ⭐ High Priority
18
+
19
+ If you plan to maintain multiple versions or branches:
20
+
21
+ ```yaml
22
+ plugins:
23
+ - search
24
+ - mermaid2
25
+ - codeinclude
26
+ - minify:
27
+ minify_html: true
28
+ minify_js: true
29
+ minify_css: true
30
+ - git-revision-date-localized:
31
+ enable_creation_date: true
32
+ type: timeago
33
+ # Optional: For versioning
34
+ # - versioning:
35
+ # version: ['dev', 'main']
36
+ ```
37
+
38
+ **Benefits**: Shows when pages were last updated, helps users understand document freshness.
39
+
40
+ ### 2. **Git Integration & Revision Information** ⭐ High Priority
41
+
42
+ Add revision dates and authors to pages:
43
+
44
+ ```yaml
45
+ plugins:
46
+ - git-revision-date-localized:
47
+ enable_creation_date: true
48
+ type: timeago
49
+ fallback_to_build_date: true
50
+ - git-committers:
51
+ repository: DeepCritical/GradioDemo
52
+ branch: dev
53
+ ```
54
+
55
+ **Benefits**: Users see when content was last updated, builds trust in documentation freshness.
56
+
57
+ ### 3. **Enhanced Navigation Features** ⭐ High Priority
58
+
59
+ Add breadcrumbs and improve navigation:
60
+
61
+ ```yaml
62
+ theme:
63
+ features:
64
+ - navigation.tabs
65
+ - navigation.sections
66
+ - navigation.expand
67
+ - navigation.top
68
+ - navigation.indexes # Add index pages
69
+ - navigation.instant # Instant page loads
70
+ - navigation.tracking # Track scroll position
71
+ - navigation.smooth # Smooth scrolling
72
+ - search.suggest
73
+ - search.highlight
74
+ - content.code.annotate
75
+ - content.code.copy
76
+ - content.tabs.link # Link to specific tabs
77
+ - content.tooltips # Tooltips for abbreviations
78
+ ```
79
+
80
+ **Benefits**: Better UX, easier navigation, professional feel.
81
+
82
+ ### 4. **Content Tabs for Code Examples** ⭐ High Priority
83
+
84
+ Perfect for showing multiple code examples (Python, TypeScript, etc.):
85
+
86
+ ```yaml
87
+ markdown_extensions:
88
+ - pymdownx.tabbed:
89
+ alternate_style: true
90
+ combine_header_slug: true # Add this
91
+ ```
92
+
93
+ **Usage in docs**:
94
+ ````markdown
95
+ === "Python"
96
+ ```python
97
+ def example():
98
+ pass
99
+ ```
100
+
101
+ === "TypeScript"
102
+ ```typescript
103
+ function example() {}
104
+ ```
105
+ ````
106
+
107
+ **Benefits**: Clean way to show multiple implementations without cluttering pages.
108
+
109
+ ### 5. **Enhanced Admonitions** ⭐ Medium Priority
110
+
111
+ Add more admonition types and better styling:
112
+
113
+ ```yaml
114
+ markdown_extensions:
115
+ - admonition
116
+ - pymdownx.details
117
+ - pymdownx.superfences:
118
+ custom_fences:
119
+ - name: mermaid
120
+ class: mermaid
121
+ format: !!python/name:pymdownx.superfences.fence_code_format
122
+ # Add custom admonition fences
123
+ - name: danger
124
+ class: danger
125
+ format: !!python/name:pymdownx.superfences.fence_code_format
126
+ ```
127
+
128
+ **Usage**:
129
+ ```markdown
130
+ !!! danger "Important"
131
+ This is a critical warning.
132
+ ```
133
+
134
+ **Benefits**: Better visual hierarchy for warnings, tips, and important information.
135
+
136
+ ### 6. **Math Formula Support** ⭐ Medium Priority (if needed)
137
+
138
+ If your documentation includes mathematical formulas:
139
+
140
+ ```yaml
141
+ markdown_extensions:
142
+ - pymdownx.arithmatex:
143
+ generic: true
144
+ - pymdownx.superfences:
145
+ custom_fences:
146
+ - name: math
147
+ class: arithmetic
148
+ format: !!python/name:pymdownx.superfences.fence_code_format
149
+
150
+ extra_javascript:
151
+ - javascripts/mathjax.js
152
+ - https://polyfill.io/v3/polyfill.min.js?features=es6
153
+ - https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js
154
+ ```
155
+
156
+ **Benefits**: Essential for scientific/technical documentation with formulas.
157
+
158
+ ### 7. **Better Code Highlighting** ⭐ Medium Priority
159
+
160
+ Add more language support and better themes:
161
+
162
+ ```yaml
163
+ markdown_extensions:
164
+ - pymdownx.highlight:
165
+ anchor_linenums: true
166
+ line_spans: __span
167
+ pygments_lang_class: true
168
+ use_pygments: true
169
+ noclasses: false # Use CSS classes instead of inline styles
170
+ ```
171
+
172
+ **Benefits**: Better syntax highlighting, more language support.
173
+
174
+ ### 8. **Social Links Enhancement** ⭐ Low Priority
175
+
176
+ Add more social platforms and better icons:
177
+
178
+ ```yaml
179
+ extra:
180
+ social:
181
+ - icon: fontawesome/brands/github
182
+ link: https://github.com/DeepCritical/GradioDemo
183
+ name: GitHub
184
+ - icon: fontawesome/brands/twitter
185
+ link: https://twitter.com/yourhandle
186
+ name: Twitter
187
+ - icon: material/web
188
+ link: https://huggingface.co/spaces/DataQuests/DeepCritical
189
+ name: HuggingFace Space
190
+ - icon: fontawesome/brands/discord
191
+ link: https://discord.gg/yourserver
192
+ name: Discord
193
+ ```
194
+
195
+ **Benefits**: Better community engagement, more ways to connect.
196
+
197
+ ### 9. **Analytics Integration** ⭐ Medium Priority
198
+
199
+ Add privacy-respecting analytics:
200
+
201
+ ```yaml
202
+ extra:
203
+ analytics:
204
+ provider: google
205
+ property: G-XXXXXXXXXX
206
+ # Or use privacy-focused alternative:
207
+ # analytics:
208
+ # provider: plausible
209
+ # domain: yourdomain.com
210
+ ```
211
+
212
+ **Benefits**: Understand how users interact with your documentation.
213
+
214
+ ### 10. **Custom CSS/JS for Branding** ⭐ Low Priority
215
+
216
+ Add custom styling:
217
+
218
+ ```yaml
219
+ extra_css:
220
+ - stylesheets/extra.css
221
+
222
+ extra_javascript:
223
+ - javascripts/extra.js
224
+ ```
225
+
226
+ **Benefits**: Customize appearance, add interactive features.
227
+
228
+ ### 11. **Better Table of Contents** ⭐ Medium Priority
229
+
230
+ Enhance TOC with more options:
231
+
232
+ ```yaml
233
+ markdown_extensions:
234
+ - toc:
235
+ permalink: true
236
+ permalink_title: "Anchor link to this section"
237
+ baselevel: 1
238
+ toc_depth: 3
239
+ slugify: !!python/object/apply:pymdownx.slugs.slugify
240
+ kwds:
241
+ case: lower
242
+ ```
243
+
244
+ **Benefits**: Better navigation within long pages, SEO-friendly anchor links.
245
+
246
+ ### 12. **Image Optimization** ⭐ Medium Priority
247
+
248
+ Add image handling plugin:
249
+
250
+ ```yaml
251
+ plugins:
252
+ - search
253
+ - mermaid2
254
+ - codeinclude
255
+ - minify:
256
+ minify_html: true
257
+ minify_js: true
258
+ minify_css: true
259
+ - git-revision-date-localized:
260
+ enable_creation_date: true
261
+ type: timeago
262
+ # Optional: Image optimization
263
+ # - awesome-pages # For better page organization
264
+ ```
265
+
266
+ **Benefits**: Faster page loads, better mobile experience.
267
+
268
+ ### 13. **Keyboard Shortcuts** ⭐ Low Priority
269
+
270
+ Enable keyboard navigation:
271
+
272
+ ```yaml
273
+ theme:
274
+ keyboard_shortcuts:
275
+ search: true
276
+ previous: true
277
+ next: true
278
+ ```
279
+
280
+ **Benefits**: Power users can navigate faster.
281
+
282
+ ### 14. **Print Styles** ⭐ Low Priority
283
+
284
+ Better printing experience:
285
+
286
+ ```yaml
287
+ theme:
288
+ features:
289
+ - navigation.tabs
290
+ - navigation.sections
291
+ - navigation.expand
292
+ - navigation.top
293
+ - navigation.indexes
294
+ - navigation.instant
295
+ - navigation.tracking
296
+ - navigation.smooth
297
+ - search.suggest
298
+ - search.highlight
299
+ - content.code.annotate
300
+ - content.code.copy
301
+ - content.tabs.link
302
+ - content.tooltips
303
+ - content.action.edit # Edit button
304
+ - content.action.view # View source
305
+ ```
306
+
307
+ **Benefits**: Users can print documentation cleanly.
308
+
309
+ ### 15. **Better Search Configuration** ⭐ Medium Priority
310
+
311
+ Enhance search capabilities:
312
+
313
+ ```yaml
314
+ plugins:
315
+ - search:
316
+ lang:
317
+ - en
318
+ separator: '[\s\-,:!=\[\]()"`/]+|\.(?!\d)|&[lg]t;|&amp;'
319
+ prebuild_index: true # For faster search
320
+ indexing: full # Full-text indexing
321
+ ```
322
+
323
+ **Benefits**: Faster, more accurate search results.
324
+
325
+ ### 16. **API Documentation Enhancements** ⭐ High Priority (for your API docs)
326
+
327
+ Since you have extensive API documentation, consider:
328
+
329
+ ```yaml
330
+ markdown_extensions:
331
+ - pymdownx.superfences:
332
+ custom_fences:
333
+ - name: mermaid
334
+ class: mermaid
335
+ format: !!python/name:pymdownx.superfences.fence_code_format
336
+ preserve_tabs: true
337
+ # Add API-specific features
338
+ - attr_list
339
+ - md_in_html
340
+ - pymdownx.caret
341
+ - pymdownx.tilde
342
+ ```
343
+
344
+ **Benefits**: Better formatting for API endpoints, parameters, responses.
345
+
346
+ ### 17. **Blog/News Section** ⭐ Low Priority (if needed)
347
+
348
+ If you want to add a blog:
349
+
350
+ ```yaml
351
+ plugins:
352
+ - blog:
353
+ blog_dir: blog
354
+ blog_description: "News and updates"
355
+ post_date_format: full
356
+ post_url_format: '{slug}'
357
+ archive: true
358
+ ```
359
+
360
+ **Benefits**: Keep users updated with changelog, announcements.
361
+
362
+ ### 18. **Tags and Categories** ⭐ Low Priority
363
+
364
+ Organize content with tags:
365
+
366
+ ```yaml
367
+ markdown_extensions:
368
+ - meta
369
+ ```
370
+
371
+ Then in frontmatter:
372
+ ```markdown
373
+ ---
374
+ tags:
375
+ - api
376
+ - agents
377
+ - getting-started
378
+ ---
379
+ ```
380
+
381
+ **Benefits**: Better content organization, related content discovery.
382
+
383
+ ### 19. **Better Mobile Experience** ⭐ High Priority
384
+
385
+ Ensure mobile optimization:
386
+
387
+ ```yaml
388
+ theme:
389
+ features:
390
+ - navigation.tabs
391
+ - navigation.sections
392
+ - navigation.expand
393
+ - navigation.top
394
+ - navigation.instant # Helps on mobile
395
+ - navigation.tracking
396
+ - navigation.smooth
397
+ - search.suggest
398
+ - search.highlight
399
+ - content.code.annotate
400
+ - content.code.copy
401
+ - content.tabs.link
402
+ - content.tooltips
403
+ - toc.integrate # Better mobile TOC
404
+ ```
405
+
406
+ **Benefits**: Better experience for mobile users (growing segment).
407
+
408
+ ### 20. **Feedback Mechanism** ⭐ Medium Priority
409
+
410
+ Add feedback buttons:
411
+
412
+ ```yaml
413
+ extra:
414
+ feedback:
415
+ title: "Was this page helpful?"
416
+ ratings:
417
+ - icon: material/thumb-up-outline
418
+ name: "This page was helpful"
419
+ - icon: material/thumb-down-outline
420
+ name: "This page could be improved"
421
+ ```
422
+
423
+ **Benefits**: Understand what content needs improvement.
424
+
425
+ ## Priority Recommendations
426
+
427
+ ### Immediate (High Impact, Easy Implementation)
428
+ 1. ✅ **Git revision dates** - Shows content freshness
429
+ 2. ✅ **Enhanced navigation features** - Better UX
430
+ 3. ✅ **Content tabs** - Perfect for code examples
431
+ 4. ✅ **Better search configuration** - Faster search
432
+
433
+ ### Short-term (High Impact, Medium Effort)
434
+ 5. ✅ **API documentation enhancements** - Better API docs
435
+ 6. ✅ **Enhanced admonitions** - Better visual hierarchy
436
+ 7. ✅ **Mobile optimization** - Better mobile experience
437
+ 8. ✅ **Analytics** - Understand user behavior
438
+
439
+ ### Long-term (Nice to Have)
440
+ 9. ⚠️ **Versioning** - If you need multiple versions
441
+ 10. ⚠️ **Math formulas** - If you have mathematical content
442
+ 11. ⚠️ **Blog section** - If you want to publish updates
443
+ 12. ⚠️ **Custom CSS/JS** - For advanced customization
444
+
445
+ ## Implementation Example
446
+
447
+ Here's an enhanced `mkdocs.yml` with the high-priority improvements:
448
+
449
+ ```yaml
450
+ site_name: The DETERMINATOR
451
+ site_description: Generalist Deep Research Agent that Stops at Nothing
452
+ site_author: The DETERMINATOR Team
453
+ site_url: https://deepcritical.github.io/GradioDemo/
454
+
455
+ repo_name: DeepCritical/GradioDemo
456
+ repo_url: https://github.com/DeepCritical/GradioDemo
457
+ edit_uri: edit/dev/docs/
458
+
459
+ strict: false
460
+
461
+ theme:
462
+ name: material
463
+ palette:
464
+ - scheme: default
465
+ primary: orange
466
+ accent: red
467
+ toggle:
468
+ icon: material/brightness-7
469
+ name: Switch to dark mode
470
+ - scheme: slate
471
+ primary: orange
472
+ accent: red
473
+ toggle:
474
+ icon: material/brightness-4
475
+ name: Switch to light mode
476
+ features:
477
+ - navigation.tabs
478
+ - navigation.sections
479
+ - navigation.expand
480
+ - navigation.top
481
+ - navigation.indexes
482
+ - navigation.instant
483
+ - navigation.tracking
484
+ - navigation.smooth
485
+ - search.suggest
486
+ - search.highlight
487
+ - content.code.annotate
488
+ - content.code.copy
489
+ - content.tabs.link
490
+ - content.tooltips
491
+ - toc.integrate
492
+ icon:
493
+ repo: fontawesome/brands/github
494
+ language: en
495
+
496
+ plugins:
497
+ - search:
498
+ lang:
499
+ - en
500
+ separator: '[\s\-,:!=\[\]()"`/]+|\.(?!\d)|&[lg]t;|&amp;'
501
+ prebuild_index: true
502
+ indexing: full
503
+ - mermaid2
504
+ - codeinclude
505
+ - git-revision-date-localized:
506
+ enable_creation_date: true
507
+ type: timeago
508
+ fallback_to_build_date: true
509
+ - minify:
510
+ minify_html: true
511
+ minify_js: true
512
+ minify_css: true
513
+
514
+ markdown_extensions:
515
+ - dev.docs_plugins:
516
+ base_path: "."
517
+ - pymdownx.highlight:
518
+ anchor_linenums: true
519
+ line_spans: __span
520
+ pygments_lang_class: true
521
+ use_pygments: true
522
+ noclasses: false
523
+ - pymdownx.inlinehilite
524
+ - pymdownx.superfences:
525
+ custom_fences:
526
+ - name: mermaid
527
+ class: mermaid
528
+ format: !!python/name:pymdownx.superfences.fence_code_format
529
+ preserve_tabs: true
530
+ - pymdownx.tabbed:
531
+ alternate_style: true
532
+ combine_header_slug: true
533
+ - pymdownx.tasklist:
534
+ custom_checkbox: true
535
+ - pymdownx.emoji:
536
+ emoji_generator: !!python/name:pymdownx.emoji.to_svg
537
+ emoji_index: !!python/name:pymdownx.emoji.twemoji
538
+ - pymdownx.snippets
539
+ - admonition
540
+ - pymdownx.details
541
+ - attr_list
542
+ - md_in_html
543
+ - tables
544
+ - meta
545
+ - toc:
546
+ permalink: true
547
+ permalink_title: "Anchor link to this section"
548
+ baselevel: 1
549
+ toc_depth: 3
550
+ slugify: !!python/object/apply:pymdownx.slugs.slugify
551
+ kwds:
552
+ case: lower
553
+
554
+ nav:
555
+ - Home: index.md
556
+ - Overview:
557
+ - overview/architecture.md
558
+ - overview/features.md
559
+ - Getting Started:
560
+ - getting-started/installation.md
561
+ - getting-started/quick-start.md
562
+ - getting-started/mcp-integration.md
563
+ - getting-started/examples.md
564
+ - Configuration:
565
+ - configuration/index.md
566
+ - Architecture:
567
+ - "Graph Orchestration": architecture/graph_orchestration.md
568
+ - "Workflow Diagrams": architecture/workflow-diagrams.md
569
+ - "Agents": architecture/agents.md
570
+ - "Orchestrators": architecture/orchestrators.md
571
+ - "Tools": architecture/tools.md
572
+ - "Middleware": architecture/middleware.md
573
+ - "Services": architecture/services.md
574
+ - API Reference:
575
+ - api/agents.md
576
+ - api/tools.md
577
+ - api/orchestrators.md
578
+ - api/services.md
579
+ - api/models.md
580
+ - Contributing:
581
+ - contributing/index.md
582
+ - contributing/code-quality.md
583
+ - contributing/code-style.md
584
+ - contributing/error-handling.md
585
+ - contributing/implementation-patterns.md
586
+ - contributing/prompt-engineering.md
587
+ - contributing/testing.md
588
+ - License: LICENSE.md
589
+ - Team: team.md
590
+
591
+ extra:
592
+ social:
593
+ - icon: fontawesome/brands/github
594
+ link: https://github.com/DeepCritical/GradioDemo
595
+ name: GitHub
596
+ - icon: material/web
597
+ link: https://huggingface.co/spaces/DataQuests/DeepCritical
598
+ name: HuggingFace Space
599
+ version:
600
+ provider: mike
601
+ generator:
602
+ enabled: false
603
+
604
+ copyright: Copyright &copy; 2024 DeepCritical Team
605
+ ```
606
+
607
+ ## Additional Documentation Improvements
608
+
609
+ ### Content Structure
610
+ 1. **Add a changelog page** - Keep users informed of updates
611
+ 2. **Add a FAQ section** - Address common questions
612
+ 3. **Add a glossary** - Define technical terms
613
+ 4. **Add a troubleshooting guide** - Help users solve common issues
614
+ 5. **Add video tutorials** - Embed videos for complex topics
615
+
616
+ ### Visual Enhancements
617
+ 1. **Add diagrams** - Use more Mermaid diagrams for complex flows
618
+ 2. **Add screenshots** - Visual guides for UI features
619
+ 3. **Add code examples** - More practical examples
620
+ 4. **Add comparison tables** - Compare different approaches/options
621
+
622
+ ### SEO & Discoverability
623
+ 1. **Add meta descriptions** - Better search engine results
624
+ 2. **Add Open Graph tags** - Better social media sharing
625
+ 3. **Add sitemap** - Help search engines index your docs
626
+ 4. **Add robots.txt** - Control search engine crawling
627
+
628
+ ## Next Steps
629
+
630
+ 1. Review this assessment
631
+ 2. Prioritize features based on your needs
632
+ 3. Test changes in a branch
633
+ 4. Gather user feedback
634
+ 5. Iterate and improve
635
+
636
+ ## Resources
637
+
638
+ - [MkDocs User Guide](https://www.mkdocs.org/user-guide/)
639
+ - [Material for MkDocs Documentation](https://squidfunk.github.io/mkdocs-material/)
640
+ - [Material for MkDocs Reference](https://squidfunk.github.io/mkdocs-material/reference/)
641
+ - [MkDocs Plugins](https://github.com/mkdocs/mkdocs/wiki/MkDocs-Plugins)
642
+
docs/api/agents.md CHANGED
@@ -12,27 +12,19 @@ This page documents the API for DeepCritical agents.
12
 
13
  #### `evaluate`
14
 
15
- ```python
16
- async def evaluate(
17
- self,
18
- query: str,
19
- background_context: str,
20
- conversation_history: Conversation,
21
- iteration: int,
22
- time_elapsed_minutes: float,
23
- max_time_minutes: float
24
- ) -> KnowledgeGapOutput
25
- ```
26
 
27
  Evaluates research completeness and identifies outstanding knowledge gaps.
28
 
29
  **Parameters**:
30
  - `query`: Research query string
31
- - `background_context`: Background context for the query
32
- - `conversation_history`: Conversation history with previous iterations
33
- - `iteration`: Current iteration number
34
- - `time_elapsed_minutes`: Elapsed time in minutes
35
- - `max_time_minutes`: Maximum time limit in minutes
36
 
37
  **Returns**: `KnowledgeGapOutput` with:
38
  - `research_complete`: Boolean indicating if research is complete
@@ -48,21 +40,17 @@ Evaluates research completeness and identifies outstanding knowledge gaps.
48
 
49
  #### `select_tools`
50
 
51
- ```python
52
- async def select_tools(
53
- self,
54
- query: str,
55
- knowledge_gaps: list[str],
56
- available_tools: list[str]
57
- ) -> AgentSelectionPlan
58
- ```
59
 
60
- Selects tools for addressing knowledge gaps.
61
 
62
  **Parameters**:
 
63
  - `query`: Research query string
64
- - `knowledge_gaps`: List of knowledge gaps to address
65
- - `available_tools`: List of available tool names
66
 
67
  **Returns**: `AgentSelectionPlan` with list of `AgentTask` objects.
68
 
@@ -76,23 +64,17 @@ Selects tools for addressing knowledge gaps.
76
 
77
  #### `write_report`
78
 
79
- ```python
80
- async def write_report(
81
- self,
82
- query: str,
83
- findings: str,
84
- output_length: str = "medium",
85
- output_instructions: str | None = None
86
- ) -> str
87
- ```
88
 
89
  Generates a markdown report from research findings.
90
 
91
  **Parameters**:
92
  - `query`: Research query string
93
  - `findings`: Research findings to include in report
94
- - `output_length`: Desired output length ("short", "medium", "long")
95
- - `output_instructions`: Additional instructions for report generation
96
 
97
  **Returns**: Markdown string with numbered citations.
98
 
@@ -106,36 +88,25 @@ Generates a markdown report from research findings.
106
 
107
  #### `write_next_section`
108
 
109
- ```python
110
- async def write_next_section(
111
- self,
112
- query: str,
113
- draft: ReportDraft,
114
- section_title: str,
115
- section_content: str
116
- ) -> LongWriterOutput
117
- ```
118
 
119
  Writes the next section of a long-form report.
120
 
121
  **Parameters**:
122
- - `query`: Research query string
123
- - `draft`: Current report draft
124
- - `section_title`: Title of the section to write
125
- - `section_content`: Content/guidance for the section
126
 
127
- **Returns**: `LongWriterOutput` with updated draft.
128
 
129
  #### `write_report`
130
 
131
- ```python
132
- async def write_report(
133
- self,
134
- query: str,
135
- report_title: str,
136
- report_draft: ReportDraft
137
- ) -> str
138
- ```
139
 
140
  Generates final report from draft.
141
 
@@ -156,14 +127,9 @@ Generates final report from draft.
156
 
157
  #### `proofread`
158
 
159
- ```python
160
- async def proofread(
161
- self,
162
- query: str,
163
- report_title: str,
164
- report_draft: ReportDraft
165
- ) -> str
166
- ```
167
 
168
  Proofreads and polishes a report draft.
169
 
@@ -184,21 +150,17 @@ Proofreads and polishes a report draft.
184
 
185
  #### `generate_observations`
186
 
187
- ```python
188
- async def generate_observations(
189
- self,
190
- query: str,
191
- background_context: str,
192
- conversation_history: Conversation
193
- ) -> str
194
- ```
195
 
196
  Generates observations from conversation history.
197
 
198
  **Parameters**:
199
  - `query`: Research query string
200
- - `background_context`: Background context
201
- - `conversation_history`: Conversation history
 
202
 
203
  **Returns**: Observation string.
204
 
@@ -210,14 +172,11 @@ Generates observations from conversation history.
210
 
211
  ### Methods
212
 
213
- #### `parse_query`
214
 
215
- ```python
216
- async def parse_query(
217
- self,
218
- query: str
219
- ) -> ParsedQuery
220
- ```
221
 
222
  Parses and improves a user query.
223
 
@@ -241,6 +200,7 @@ All agents have factory functions in `src.agent_factory.agents`:
241
 
242
  **Parameters**:
243
  - `model`: Optional Pydantic AI model. If None, uses `get_model()` from settings.
 
244
 
245
  **Returns**: Agent instance.
246
 
 
12
 
13
  #### `evaluate`
14
 
15
+ <!--codeinclude-->
16
+ [KnowledgeGapAgent.evaluate](../src/agents/knowledge_gap.py) start_line:66 end_line:74
17
+ <!--/codeinclude-->
 
 
 
 
 
 
 
 
18
 
19
  Evaluates research completeness and identifies outstanding knowledge gaps.
20
 
21
  **Parameters**:
22
  - `query`: Research query string
23
+ - `background_context`: Background context for the query (default: "")
24
+ - `conversation_history`: History of actions, findings, and thoughts as string (default: "")
25
+ - `iteration`: Current iteration number (default: 0)
26
+ - `time_elapsed_minutes`: Elapsed time in minutes (default: 0.0)
27
+ - `max_time_minutes`: Maximum time limit in minutes (default: 10)
28
 
29
  **Returns**: `KnowledgeGapOutput` with:
30
  - `research_complete`: Boolean indicating if research is complete
 
40
 
41
  #### `select_tools`
42
 
43
+ <!--codeinclude-->
44
+ [ToolSelectorAgent.select_tools](../src/agents/tool_selector.py) start_line:78 end_line:84
45
+ <!--/codeinclude-->
 
 
 
 
 
46
 
47
+ Selects tools for addressing a knowledge gap.
48
 
49
  **Parameters**:
50
+ - `gap`: The knowledge gap to address
51
  - `query`: Research query string
52
+ - `background_context`: Optional background context (default: "")
53
+ - `conversation_history`: History of actions, findings, and thoughts as string (default: "")
54
 
55
  **Returns**: `AgentSelectionPlan` with list of `AgentTask` objects.
56
 
 
64
 
65
  #### `write_report`
66
 
67
+ <!--codeinclude-->
68
+ [WriterAgent.write_report](../src/agents/writer.py) start_line:67 end_line:73
69
+ <!--/codeinclude-->
 
 
 
 
 
 
70
 
71
  Generates a markdown report from research findings.
72
 
73
  **Parameters**:
74
  - `query`: Research query string
75
  - `findings`: Research findings to include in report
76
+ - `output_length`: Optional description of desired output length (default: "")
77
+ - `output_instructions`: Optional additional instructions for report generation (default: "")
78
 
79
  **Returns**: Markdown string with numbered citations.
80
 
 
88
 
89
  #### `write_next_section`
90
 
91
+ <!--codeinclude-->
92
+ [LongWriterAgent.write_next_section](../src/agents/long_writer.py) start_line:94 end_line:100
93
+ <!--/codeinclude-->
 
 
 
 
 
 
94
 
95
  Writes the next section of a long-form report.
96
 
97
  **Parameters**:
98
+ - `original_query`: The original research query
99
+ - `report_draft`: Current report draft as string (all sections written so far)
100
+ - `next_section_title`: Title of the section to write
101
+ - `next_section_draft`: Draft content for the next section
102
 
103
+ **Returns**: `LongWriterOutput` with formatted section and references.
104
 
105
  #### `write_report`
106
 
107
+ <!--codeinclude-->
108
+ [LongWriterAgent.write_report](../src/agents/long_writer.py) start_line:263 end_line:268
109
+ <!--/codeinclude-->
 
 
 
 
 
110
 
111
  Generates final report from draft.
112
 
 
127
 
128
  #### `proofread`
129
 
130
+ <!--codeinclude-->
131
+ [ProofreaderAgent.proofread](../src/agents/proofreader.py) start_line:72 end_line:76
132
+ <!--/codeinclude-->
 
 
 
 
 
133
 
134
  Proofreads and polishes a report draft.
135
 
 
150
 
151
  #### `generate_observations`
152
 
153
+ <!--codeinclude-->
154
+ [ThinkingAgent.generate_observations](../src/agents/thinking.py) start_line:70 end_line:76
155
+ <!--/codeinclude-->
 
 
 
 
 
156
 
157
  Generates observations from conversation history.
158
 
159
  **Parameters**:
160
  - `query`: Research query string
161
+ - `background_context`: Optional background context (default: "")
162
+ - `conversation_history`: History of actions, findings, and thoughts as string (default: "")
163
+ - `iteration`: Current iteration number (default: 1)
164
 
165
  **Returns**: Observation string.
166
 
 
172
 
173
  ### Methods
174
 
175
+ #### `parse`
176
 
177
+ <!--codeinclude-->
178
+ [InputParserAgent.parse](../src/agents/input_parser.py) start_line:82 end_line:82
179
+ <!--/codeinclude-->
 
 
 
180
 
181
  Parses and improves a user query.
182
 
 
200
 
201
  **Parameters**:
202
  - `model`: Optional Pydantic AI model. If None, uses `get_model()` from settings.
203
+ - `oauth_token`: Optional OAuth token from HuggingFace login (takes priority over env vars)
204
 
205
  **Returns**: Agent instance.
206
 
docs/api/models.md CHANGED
@@ -15,7 +15,7 @@ This page documents the Pydantic models used throughout DeepCritical.
15
  **Fields**:
16
  - `citation`: Citation information (title, URL, date, authors)
17
  - `content`: Evidence text content
18
- - `relevance_score`: Relevance score (0.0-1.0)
19
  - `metadata`: Additional metadata dictionary
20
 
21
  ## Citation
@@ -29,9 +29,10 @@ This page documents the Pydantic models used throughout DeepCritical.
29
  <!--/codeinclude-->
30
 
31
  **Fields**:
 
32
  - `title`: Article/trial title
33
  - `url`: Source URL
34
- - `date`: Publication date (optional)
35
  - `authors`: List of authors (optional)
36
 
37
  ## KnowledgeGapOutput
@@ -72,9 +73,10 @@ This page documents the Pydantic models used throughout DeepCritical.
72
  <!--/codeinclude-->
73
 
74
  **Fields**:
75
- - `agent_name`: Name of agent to use
76
- - `query`: Task query
77
- - `context`: Additional context dictionary
 
78
 
79
  ## ReportDraft
80
 
@@ -87,9 +89,7 @@ This page documents the Pydantic models used throughout DeepCritical.
87
  <!--/codeinclude-->
88
 
89
  **Fields**:
90
- - `title`: Report title
91
  - `sections`: List of report sections
92
- - `references`: List of citations
93
 
94
  ## ReportSection
95
 
@@ -102,9 +102,8 @@ This page documents the Pydantic models used throughout DeepCritical.
102
  <!--/codeinclude-->
103
 
104
  **Fields**:
105
- - `title`: Section title
106
- - `content`: Section content
107
- - `order`: Section order number
108
 
109
  ## ParsedQuery
110
 
@@ -134,7 +133,7 @@ This page documents the Pydantic models used throughout DeepCritical.
134
  <!--/codeinclude-->
135
 
136
  **Fields**:
137
- - `iterations`: List of iteration data
138
 
139
  ## IterationData
140
 
@@ -147,12 +146,10 @@ This page documents the Pydantic models used throughout DeepCritical.
147
  <!--/codeinclude-->
148
 
149
  **Fields**:
150
- - `iteration`: Iteration number
151
- - `observations`: Generated observations
152
- - `knowledge_gaps`: Identified knowledge gaps
153
- - `tool_calls`: Tool calls made
154
- - `findings`: Findings from tools
155
- - `thoughts`: Agent thoughts
156
 
157
  ## AgentEvent
158
 
@@ -180,12 +177,13 @@ This page documents the Pydantic models used throughout DeepCritical.
180
  <!--/codeinclude-->
181
 
182
  **Fields**:
183
- - `tokens_used`: Tokens used so far
184
- - `tokens_limit`: Token limit
185
- - `time_elapsed_seconds`: Elapsed time in seconds
186
- - `time_limit_seconds`: Time limit in seconds
187
- - `iterations`: Current iteration count
188
- - `iterations_limit`: Iteration limit
 
189
 
190
  ## See Also
191
 
 
15
  **Fields**:
16
  - `citation`: Citation information (title, URL, date, authors)
17
  - `content`: Evidence text content
18
+ - `relevance`: Relevance score (0.0-1.0)
19
  - `metadata`: Additional metadata dictionary
20
 
21
  ## Citation
 
29
  <!--/codeinclude-->
30
 
31
  **Fields**:
32
+ - `source`: Source name (e.g., "pubmed", "clinicaltrials", "europepmc", "web", "rag")
33
  - `title`: Article/trial title
34
  - `url`: Source URL
35
+ - `date`: Publication date (YYYY-MM-DD or "Unknown")
36
  - `authors`: List of authors (optional)
37
 
38
  ## KnowledgeGapOutput
 
73
  <!--/codeinclude-->
74
 
75
  **Fields**:
76
+ - `gap`: The knowledge gap being addressed (optional)
77
+ - `agent`: Name of agent to use
78
+ - `query`: The specific query for the agent
79
+ - `entity_website`: The website of the entity being researched, if known (optional)
80
 
81
  ## ReportDraft
82
 
 
89
  <!--/codeinclude-->
90
 
91
  **Fields**:
 
92
  - `sections`: List of report sections
 
93
 
94
  ## ReportSection
95
 
 
102
  <!--/codeinclude-->
103
 
104
  **Fields**:
105
+ - `section_title`: The title of the section
106
+ - `section_content`: The content of the section
 
107
 
108
  ## ParsedQuery
109
 
 
133
  <!--/codeinclude-->
134
 
135
  **Fields**:
136
+ - `history`: List of iteration data
137
 
138
  ## IterationData
139
 
 
146
  <!--/codeinclude-->
147
 
148
  **Fields**:
149
+ - `gap`: The gap addressed in the iteration
150
+ - `tool_calls`: The tool calls made
151
+ - `findings`: The findings collected from tool calls
152
+ - `thought`: The thinking done to reflect on the success of the iteration and next steps
 
 
153
 
154
  ## AgentEvent
155
 
 
177
  <!--/codeinclude-->
178
 
179
  **Fields**:
180
+ - `tokens_used`: Total tokens used
181
+ - `tokens_limit`: Token budget limit
182
+ - `time_elapsed_seconds`: Time elapsed in seconds
183
+ - `time_limit_seconds`: Time budget limit (default: 600.0 seconds / 10 minutes)
184
+ - `iterations`: Number of iterations completed
185
+ - `iterations_limit`: Maximum iterations (default: 10)
186
+ - `iteration_tokens`: Tokens used per iteration (iteration number -> token count)
187
 
188
  ## See Also
189
 
docs/api/orchestrators.md CHANGED
@@ -12,33 +12,21 @@ This page documents the API for DeepCritical orchestrators.
12
 
13
  #### `run`
14
 
15
- ```python
16
- async def run(
17
- self,
18
- query: str,
19
- background_context: str = "",
20
- max_iterations: int | None = None,
21
- max_time_minutes: float | None = None,
22
- token_budget: int | None = None
23
- ) -> AsyncGenerator[AgentEvent, None]
24
- ```
25
 
26
  Runs iterative research flow.
27
 
28
  **Parameters**:
29
  - `query`: Research query string
30
  - `background_context`: Background context (default: "")
31
- - `max_iterations`: Maximum iterations (default: from settings)
32
- - `max_time_minutes`: Maximum time in minutes (default: from settings)
33
- - `token_budget`: Token budget (default: from settings)
34
-
35
- **Yields**: `AgentEvent` objects for:
36
- - `started`: Research started
37
- - `search_complete`: Search completed
38
- - `judge_complete`: Evidence evaluation completed
39
- - `synthesizing`: Generating report
40
- - `complete`: Research completed
41
- - `error`: Error occurred
42
 
43
  ## DeepResearchFlow
44
 
@@ -50,33 +38,18 @@ Runs iterative research flow.
50
 
51
  #### `run`
52
 
53
- ```python
54
- async def run(
55
- self,
56
- query: str,
57
- background_context: str = "",
58
- max_iterations_per_section: int | None = None,
59
- max_time_minutes: float | None = None,
60
- token_budget: int | None = None
61
- ) -> AsyncGenerator[AgentEvent, None]
62
- ```
63
 
64
  Runs deep research flow.
65
 
66
  **Parameters**:
67
  - `query`: Research query string
68
- - `background_context`: Background context (default: "")
69
- - `max_iterations_per_section`: Maximum iterations per section (default: from settings)
70
- - `max_time_minutes`: Maximum time in minutes (default: from settings)
71
- - `token_budget`: Token budget (default: from settings)
72
-
73
- **Yields**: `AgentEvent` objects for:
74
- - `started`: Research started
75
- - `planning`: Creating research plan
76
- - `looping`: Running parallel research loops
77
- - `synthesizing`: Synthesizing results
78
- - `complete`: Research completed
79
- - `error`: Error occurred
80
 
81
  ## GraphOrchestrator
82
 
@@ -88,24 +61,19 @@ Runs deep research flow.
88
 
89
  #### `run`
90
 
91
- ```python
92
- async def run(
93
- self,
94
- query: str,
95
- research_mode: str = "auto",
96
- use_graph: bool = True
97
- ) -> AsyncGenerator[AgentEvent, None]
98
- ```
99
 
100
  Runs graph-based research orchestration.
101
 
102
  **Parameters**:
103
  - `query`: Research query string
104
- - `research_mode`: Research mode ("iterative", "deep", or "auto")
105
- - `use_graph`: Whether to use graph execution (default: True)
106
 
107
  **Yields**: `AgentEvent` objects during graph execution.
108
 
 
 
109
  ## Orchestrator Factory
110
 
111
  **Module**: `src.orchestrator_factory`
@@ -116,22 +84,18 @@ Runs graph-based research orchestration.
116
 
117
  #### `create_orchestrator`
118
 
119
- ```python
120
- def create_orchestrator(
121
- search_handler: SearchHandlerProtocol,
122
- judge_handler: JudgeHandlerProtocol,
123
- config: dict[str, Any],
124
- mode: str | None = None
125
- ) -> Any
126
- ```
127
 
128
  Creates an orchestrator instance.
129
 
130
  **Parameters**:
131
- - `search_handler`: Search handler protocol implementation
132
- - `judge_handler`: Judge handler protocol implementation
133
- - `config`: Configuration dictionary
134
- - `mode`: Orchestrator mode ("simple", "advanced", "magentic", or None for auto-detect)
 
135
 
136
  **Returns**: Orchestrator instance.
137
 
@@ -153,24 +117,19 @@ Creates an orchestrator instance.
153
 
154
  #### `run`
155
 
156
- ```python
157
- async def run(
158
- self,
159
- query: str,
160
- max_rounds: int = 15,
161
- max_stalls: int = 3
162
- ) -> AsyncGenerator[AgentEvent, None]
163
- ```
164
 
165
  Runs Magentic orchestration.
166
 
167
  **Parameters**:
168
  - `query`: Research query string
169
- - `max_rounds`: Maximum rounds (default: 15)
170
- - `max_stalls`: Maximum stalls before reset (default: 3)
171
 
172
  **Yields**: `AgentEvent` objects converted from Magentic events.
173
 
 
 
174
  **Requirements**:
175
  - `agent-framework-core` package
176
  - OpenAI API key
 
12
 
13
  #### `run`
14
 
15
+ <!--codeinclude-->
16
+ [IterativeResearchFlow.run](../src/orchestrator/research_flow.py) start_line:134 end_line:140
17
+ <!--/codeinclude-->
 
 
 
 
 
 
 
18
 
19
  Runs iterative research flow.
20
 
21
  **Parameters**:
22
  - `query`: Research query string
23
  - `background_context`: Background context (default: "")
24
+ - `output_length`: Optional description of desired output length (default: "")
25
+ - `output_instructions`: Optional additional instructions for report generation (default: "")
26
+
27
+ **Returns**: Final report string.
28
+
29
+ **Note**: `max_iterations`, `max_time_minutes`, and `token_budget` are constructor parameters, not `run()` parameters.
 
 
 
 
 
30
 
31
  ## DeepResearchFlow
32
 
 
38
 
39
  #### `run`
40
 
41
+ <!--codeinclude-->
42
+ [DeepResearchFlow.run](../src/orchestrator/research_flow.py) start_line:778 end_line:778
43
+ <!--/codeinclude-->
 
 
 
 
 
 
 
44
 
45
  Runs deep research flow.
46
 
47
  **Parameters**:
48
  - `query`: Research query string
49
+
50
+ **Returns**: Final report string.
51
+
52
+ **Note**: `max_iterations_per_section`, `max_time_minutes`, and `token_budget` are constructor parameters, not `run()` parameters.
 
 
 
 
 
 
 
 
53
 
54
  ## GraphOrchestrator
55
 
 
61
 
62
  #### `run`
63
 
64
+ <!--codeinclude-->
65
+ [GraphOrchestrator.run](../src/orchestrator/graph_orchestrator.py) start_line:177 end_line:177
66
+ <!--/codeinclude-->
 
 
 
 
 
67
 
68
  Runs graph-based research orchestration.
69
 
70
  **Parameters**:
71
  - `query`: Research query string
 
 
72
 
73
  **Yields**: `AgentEvent` objects during graph execution.
74
 
75
+ **Note**: `research_mode` and `use_graph` are constructor parameters, not `run()` parameters.
76
+
77
  ## Orchestrator Factory
78
 
79
  **Module**: `src.orchestrator_factory`
 
84
 
85
  #### `create_orchestrator`
86
 
87
+ <!--codeinclude-->
88
+ [create_orchestrator](../src/orchestrator_factory.py) start_line:44 end_line:50
89
+ <!--/codeinclude-->
 
 
 
 
 
90
 
91
  Creates an orchestrator instance.
92
 
93
  **Parameters**:
94
+ - `search_handler`: Search handler protocol implementation (optional, required for simple mode)
95
+ - `judge_handler`: Judge handler protocol implementation (optional, required for simple mode)
96
+ - `config`: Configuration object (optional)
97
+ - `mode`: Orchestrator mode ("simple", "advanced", "magentic", "iterative", "deep", "auto", or None for auto-detect)
98
+ - `oauth_token`: Optional OAuth token from HuggingFace login (takes priority over env vars)
99
 
100
  **Returns**: Orchestrator instance.
101
 
 
117
 
118
  #### `run`
119
 
120
+ <!--codeinclude-->
121
+ [MagenticOrchestrator.run](../src/orchestrator_magentic.py) start_line:101 end_line:101
122
+ <!--/codeinclude-->
 
 
 
 
 
123
 
124
  Runs Magentic orchestration.
125
 
126
  **Parameters**:
127
  - `query`: Research query string
 
 
128
 
129
  **Yields**: `AgentEvent` objects converted from Magentic events.
130
 
131
+ **Note**: `max_rounds` and `max_stalls` are constructor parameters, not `run()` parameters.
132
+
133
  **Requirements**:
134
  - `agent-framework-core` package
135
  - OpenAI API key
docs/api/services.md CHANGED
@@ -12,9 +12,9 @@ This page documents the API for DeepCritical services.
12
 
13
  #### `embed`
14
 
15
- ```python
16
- async def embed(self, text: str) -> list[float]
17
- ```
18
 
19
  Generates embedding for a text string.
20
 
@@ -68,6 +68,60 @@ Finds duplicate texts based on similarity threshold.
68
 
69
  **Returns**: List of (index1, index2) tuples for duplicate pairs.
70
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
71
  ### Factory Function
72
 
73
  #### `get_embedding_service`
@@ -89,63 +143,97 @@ Returns singleton EmbeddingService instance.
89
 
90
  #### `ingest_evidence`
91
 
92
- ```python
93
- async def ingest_evidence(self, evidence: list[Evidence]) -> None
94
- ```
95
 
96
  Ingests evidence into RAG service.
97
 
98
  **Parameters**:
99
- - `evidence`: List of Evidence objects to ingest
100
 
101
- **Note**: Requires OpenAI API key for embeddings.
102
 
103
  #### `retrieve`
104
 
105
  ```python
106
- async def retrieve(
107
  self,
108
  query: str,
109
- top_k: int = 5
110
- ) -> list[Document]
111
  ```
112
 
113
  Retrieves relevant documents for a query.
114
 
115
  **Parameters**:
116
  - `query`: Search query string
117
- - `top_k`: Number of top results to return (default: 5)
118
 
119
- **Returns**: List of Document objects with metadata.
120
 
121
  #### `query`
122
 
123
  ```python
124
- async def query(
125
  self,
126
- query: str,
127
- top_k: int = 5
128
  ) -> str
129
  ```
130
 
131
- Queries RAG service and returns formatted results.
132
 
133
  **Parameters**:
134
- - `query`: Search query string
135
- - `top_k`: Number of top results to return (default: 5)
 
 
 
 
 
 
 
 
 
 
 
136
 
137
- **Returns**: Formatted query results as string.
 
 
 
 
 
 
 
 
 
 
 
138
 
139
  ### Factory Function
140
 
141
  #### `get_rag_service`
142
 
143
  ```python
144
- @lru_cache(maxsize=1)
145
- def get_rag_service() -> LlamaIndexRAGService | None
 
 
 
146
  ```
147
 
148
- Returns singleton LlamaIndexRAGService instance, or None if OpenAI key not available.
 
 
 
 
 
 
 
 
 
149
 
150
  ## StatisticalAnalyzer
151
 
@@ -160,24 +248,27 @@ Returns singleton LlamaIndexRAGService instance, or None if OpenAI key not avail
160
  ```python
161
  async def analyze(
162
  self,
163
- hypothesis: str,
164
  evidence: list[Evidence],
165
- data_description: str | None = None
166
  ) -> AnalysisResult
167
  ```
168
 
169
- Analyzes a hypothesis using statistical methods.
170
 
171
  **Parameters**:
172
- - `hypothesis`: Hypothesis to analyze
173
- - `evidence`: List of Evidence objects
174
- - `data_description`: Optional data description
175
 
176
  **Returns**: `AnalysisResult` with:
177
  - `verdict`: SUPPORTED, REFUTED, or INCONCLUSIVE
178
- - `code`: Generated analysis code
179
- - `output`: Execution output
180
- - `error`: Error message if execution failed
 
 
 
181
 
182
  **Note**: Requires Modal credentials for sandbox execution.
183
 
 
12
 
13
  #### `embed`
14
 
15
+ <!--codeinclude-->
16
+ [EmbeddingService.embed](../src/services/embeddings.py) start_line:55 end_line:55
17
+ <!--/codeinclude-->
18
 
19
  Generates embedding for a text string.
20
 
 
68
 
69
  **Returns**: List of (index1, index2) tuples for duplicate pairs.
70
 
71
+ #### `add_evidence`
72
+
73
+ ```python
74
+ async def add_evidence(
75
+ self,
76
+ evidence_id: str,
77
+ content: str,
78
+ metadata: dict[str, Any]
79
+ ) -> None
80
+ ```
81
+
82
+ Adds evidence to vector store for semantic search.
83
+
84
+ **Parameters**:
85
+ - `evidence_id`: Unique identifier for the evidence
86
+ - `content`: Evidence text content
87
+ - `metadata`: Additional metadata dictionary
88
+
89
+ #### `search_similar`
90
+
91
+ ```python
92
+ async def search_similar(
93
+ self,
94
+ query: str,
95
+ n_results: int = 5
96
+ ) -> list[dict[str, Any]]
97
+ ```
98
+
99
+ Finds semantically similar evidence.
100
+
101
+ **Parameters**:
102
+ - `query`: Search query string
103
+ - `n_results`: Number of results to return (default: 5)
104
+
105
+ **Returns**: List of dictionaries with `id`, `content`, `metadata`, and `distance` keys.
106
+
107
+ #### `deduplicate`
108
+
109
+ ```python
110
+ async def deduplicate(
111
+ self,
112
+ new_evidence: list[Evidence],
113
+ threshold: float = 0.9
114
+ ) -> list[Evidence]
115
+ ```
116
+
117
+ Removes semantically duplicate evidence.
118
+
119
+ **Parameters**:
120
+ - `new_evidence`: List of evidence items to deduplicate
121
+ - `threshold`: Similarity threshold (default: 0.9, where 0.9 = 90% similar is duplicate)
122
+
123
+ **Returns**: List of unique evidence items (not already in vector store).
124
+
125
  ### Factory Function
126
 
127
  #### `get_embedding_service`
 
143
 
144
  #### `ingest_evidence`
145
 
146
+ <!--codeinclude-->
147
+ [LlamaIndexRAGService.ingest_evidence](../src/services/llamaindex_rag.py) start_line:290 end_line:290
148
+ <!--/codeinclude-->
149
 
150
  Ingests evidence into RAG service.
151
 
152
  **Parameters**:
153
+ - `evidence_list`: List of Evidence objects to ingest
154
 
155
+ **Note**: Supports multiple embedding providers (OpenAI, local sentence-transformers, Hugging Face).
156
 
157
  #### `retrieve`
158
 
159
  ```python
160
+ def retrieve(
161
  self,
162
  query: str,
163
+ top_k: int | None = None
164
+ ) -> list[dict[str, Any]]
165
  ```
166
 
167
  Retrieves relevant documents for a query.
168
 
169
  **Parameters**:
170
  - `query`: Search query string
171
+ - `top_k`: Number of top results to return (defaults to `similarity_top_k` from constructor)
172
 
173
+ **Returns**: List of dictionaries with `text`, `score`, and `metadata` keys.
174
 
175
  #### `query`
176
 
177
  ```python
178
+ def query(
179
  self,
180
+ query_str: str,
181
+ top_k: int | None = None
182
  ) -> str
183
  ```
184
 
185
+ Queries RAG service and returns synthesized response.
186
 
187
  **Parameters**:
188
+ - `query_str`: Query string
189
+ - `top_k`: Number of results to use (defaults to `similarity_top_k` from constructor)
190
+
191
+ **Returns**: Synthesized response string.
192
+
193
+ **Raises**:
194
+ - `ConfigurationError`: If no LLM API key is available for query synthesis
195
+
196
+ #### `ingest_documents`
197
+
198
+ ```python
199
+ def ingest_documents(self, documents: list[Any]) -> None
200
+ ```
201
 
202
+ Ingests raw LlamaIndex Documents.
203
+
204
+ **Parameters**:
205
+ - `documents`: List of LlamaIndex Document objects
206
+
207
+ #### `clear_collection`
208
+
209
+ ```python
210
+ def clear_collection(self) -> None
211
+ ```
212
+
213
+ Clears all documents from the collection.
214
 
215
  ### Factory Function
216
 
217
  #### `get_rag_service`
218
 
219
  ```python
220
+ def get_rag_service(
221
+ collection_name: str = "deepcritical_evidence",
222
+ oauth_token: str | None = None,
223
+ **kwargs: Any
224
+ ) -> LlamaIndexRAGService
225
  ```
226
 
227
+ Get or create a RAG service instance.
228
+
229
+ **Parameters**:
230
+ - `collection_name`: Name of the ChromaDB collection (default: "deepcritical_evidence")
231
+ - `oauth_token`: Optional OAuth token from HuggingFace login (takes priority over env vars)
232
+ - `**kwargs`: Additional arguments for LlamaIndexRAGService (e.g., `use_openai_embeddings=False`)
233
+
234
+ **Returns**: Configured LlamaIndexRAGService instance.
235
+
236
+ **Note**: By default, uses local embeddings (sentence-transformers) which require no API keys.
237
 
238
  ## StatisticalAnalyzer
239
 
 
248
  ```python
249
  async def analyze(
250
  self,
251
+ query: str,
252
  evidence: list[Evidence],
253
+ hypothesis: dict[str, Any] | None = None
254
  ) -> AnalysisResult
255
  ```
256
 
257
+ Analyzes a research question using statistical methods.
258
 
259
  **Parameters**:
260
+ - `query`: The research question
261
+ - `evidence`: List of Evidence objects to analyze
262
+ - `hypothesis`: Optional hypothesis dict with `drug`, `target`, `pathway`, `effect`, `confidence` keys
263
 
264
  **Returns**: `AnalysisResult` with:
265
  - `verdict`: SUPPORTED, REFUTED, or INCONCLUSIVE
266
+ - `confidence`: Confidence in verdict (0.0-1.0)
267
+ - `statistical_evidence`: Summary of statistical findings
268
+ - `code_generated`: Python code that was executed
269
+ - `execution_output`: Output from code execution
270
+ - `key_takeaways`: Key takeaways from analysis
271
+ - `limitations`: List of limitations
272
 
273
  **Note**: Requires Modal credentials for sandbox execution.
274
 
docs/api/tools.md CHANGED
@@ -56,8 +56,10 @@ Searches PubMed for articles.
56
  **Returns**: List of `Evidence` objects with PubMed articles.
57
 
58
  **Raises**:
59
- - `SearchError`: If search fails
60
- - `RateLimitError`: If rate limit is exceeded
 
 
61
 
62
  ## ClinicalTrialsTool
63
 
@@ -96,10 +98,10 @@ Searches ClinicalTrials.gov for trials.
96
 
97
  **Returns**: List of `Evidence` objects with clinical trials.
98
 
99
- **Note**: Only returns interventional studies with status: COMPLETED, ACTIVE_NOT_RECRUITING, RECRUITING, ENROLLING_BY_INVITATION
100
 
101
  **Raises**:
102
- - `SearchError`: If search fails
103
 
104
  ## EuropePMCTool
105
 
@@ -138,10 +140,10 @@ Searches Europe PMC for articles and preprints.
138
 
139
  **Returns**: List of `Evidence` objects with articles/preprints.
140
 
141
- **Note**: Includes both preprints (marked with `[PREPRINT - Not peer-reviewed]`) and peer-reviewed articles.
142
 
143
  **Raises**:
144
- - `SearchError`: If search fails
145
 
146
  ## RAGTool
147
 
@@ -149,6 +151,20 @@ Searches Europe PMC for articles and preprints.
149
 
150
  **Purpose**: Semantic search within collected evidence.
151
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
152
  ### Properties
153
 
154
  #### `name`
@@ -180,7 +196,10 @@ Searches collected evidence using semantic similarity.
180
 
181
  **Returns**: List of `Evidence` objects from collected evidence.
182
 
183
- **Note**: Requires evidence to be ingested into RAG service first.
 
 
 
184
 
185
  ## SearchHandler
186
 
@@ -188,32 +207,51 @@ Searches collected evidence using semantic similarity.
188
 
189
  **Purpose**: Orchestrates parallel searches across multiple tools.
190
 
191
- ### Methods
192
-
193
- #### `search`
194
 
195
  ```python
196
- async def search(
197
  self,
198
- query: str,
199
- tools: list[SearchTool] | None = None,
200
- max_results_per_tool: int = 10
201
- ) -> SearchResult
 
 
202
  ```
203
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
204
  Searches multiple tools in parallel.
205
 
206
  **Parameters**:
207
  - `query`: Search query string
208
- - `tools`: List of tools to use (default: all available tools)
209
  - `max_results_per_tool`: Maximum results per tool (default: 10)
210
 
211
  **Returns**: `SearchResult` with:
 
212
  - `evidence`: Aggregated list of evidence
213
- - `tool_results`: Results per tool
214
- - `total_count`: Total number of results
 
 
 
 
215
 
216
- **Note**: Uses `asyncio.gather()` for parallel execution. Handles tool failures gracefully.
217
 
218
  ## See Also
219
 
 
56
  **Returns**: List of `Evidence` objects with PubMed articles.
57
 
58
  **Raises**:
59
+ - `SearchError`: If search fails (timeout, HTTP error, XML parsing error)
60
+ - `RateLimitError`: If rate limit is exceeded (429 status code)
61
+
62
+ **Note**: Uses NCBI E-utilities (ESearch → EFetch). Rate limit: 0.34s between requests. Handles single vs. multiple articles.
63
 
64
  ## ClinicalTrialsTool
65
 
 
98
 
99
  **Returns**: List of `Evidence` objects with clinical trials.
100
 
101
+ **Note**: Only returns interventional studies with status: COMPLETED, ACTIVE_NOT_RECRUITING, RECRUITING, ENROLLING_BY_INVITATION. Uses `requests` library (NOT httpx - WAF blocks httpx). Runs in thread pool for async compatibility.
102
 
103
  **Raises**:
104
+ - `SearchError`: If search fails (HTTP error, request exception)
105
 
106
  ## EuropePMCTool
107
 
 
140
 
141
  **Returns**: List of `Evidence` objects with articles/preprints.
142
 
143
+ **Note**: Includes both preprints (marked with `[PREPRINT - Not peer-reviewed]`) and peer-reviewed articles. Handles preprint markers. Builds URLs from DOI or PMID.
144
 
145
  **Raises**:
146
+ - `SearchError`: If search fails (HTTP error, connection error)
147
 
148
  ## RAGTool
149
 
 
151
 
152
  **Purpose**: Semantic search within collected evidence.
153
 
154
+ ### Initialization
155
+
156
+ ```python
157
+ def __init__(
158
+ self,
159
+ rag_service: LlamaIndexRAGService | None = None,
160
+ oauth_token: str | None = None
161
+ ) -> None
162
+ ```
163
+
164
+ **Parameters**:
165
+ - `rag_service`: Optional RAG service instance. If None, will be lazy-initialized.
166
+ - `oauth_token`: Optional OAuth token from HuggingFace login (for RAG LLM)
167
+
168
  ### Properties
169
 
170
  #### `name`
 
196
 
197
  **Returns**: List of `Evidence` objects from collected evidence.
198
 
199
+ **Raises**:
200
+ - `ConfigurationError`: If RAG service is unavailable
201
+
202
+ **Note**: Requires evidence to be ingested into RAG service first. Wraps `LlamaIndexRAGService`. Returns Evidence from RAG results.
203
 
204
  ## SearchHandler
205
 
 
207
 
208
  **Purpose**: Orchestrates parallel searches across multiple tools.
209
 
210
+ ### Initialization
 
 
211
 
212
  ```python
213
+ def __init__(
214
  self,
215
+ tools: list[SearchTool],
216
+ timeout: float = 30.0,
217
+ include_rag: bool = False,
218
+ auto_ingest_to_rag: bool = True,
219
+ oauth_token: str | None = None
220
+ ) -> None
221
  ```
222
 
223
+ **Parameters**:
224
+ - `tools`: List of search tools to use
225
+ - `timeout`: Timeout for each search in seconds (default: 30.0)
226
+ - `include_rag`: Whether to include RAG tool in searches (default: False)
227
+ - `auto_ingest_to_rag`: Whether to automatically ingest results into RAG (default: True)
228
+ - `oauth_token`: Optional OAuth token from HuggingFace login (for RAG LLM)
229
+
230
+ ### Methods
231
+
232
+ #### `execute`
233
+
234
+ <!--codeinclude-->
235
+ [SearchHandler.execute](../src/tools/search_handler.py) start_line:86 end_line:86
236
+ <!--/codeinclude-->
237
+
238
  Searches multiple tools in parallel.
239
 
240
  **Parameters**:
241
  - `query`: Search query string
 
242
  - `max_results_per_tool`: Maximum results per tool (default: 10)
243
 
244
  **Returns**: `SearchResult` with:
245
+ - `query`: The search query
246
  - `evidence`: Aggregated list of evidence
247
+ - `sources_searched`: List of source names searched
248
+ - `total_found`: Total number of results
249
+ - `errors`: List of error messages from failed tools
250
+
251
+ **Raises**:
252
+ - `SearchError`: If search times out
253
 
254
+ **Note**: Uses `asyncio.gather()` for parallel execution. Handles tool failures gracefully (returns errors in `SearchResult.errors`). Automatically ingests evidence into RAG if enabled.
255
 
256
  ## See Also
257
 
docs/architecture/agents.md CHANGED
@@ -4,12 +4,16 @@ DeepCritical uses Pydantic AI agents for all AI-powered operations. All agents f
4
 
5
  ## Agent Pattern
6
 
7
- All agents use the Pydantic AI `Agent` class with the following structure:
 
 
8
 
9
  - **System Prompt**: Module-level constant with date injection
10
  - **Agent Class**: `__init__(model: Any | None = None)`
11
  - **Main Method**: Async method (e.g., `async def evaluate()`, `async def write_report()`)
12
- - **Factory Function**: `def create_agent_name(model: Any | None = None) -> AgentName`
 
 
13
 
14
  ## Model Initialization
15
 
@@ -155,43 +159,135 @@ For text output (writer agents), agents return `str` directly.
155
  - `key_entities`: List of key entities
156
  - `research_questions`: List of research questions
157
 
158
- ## Factory Functions
159
 
160
- All agents have factory functions in `src/agent_factory/agents.py`:
161
 
162
- <!--codeinclude-->
163
- [Factory Functions](../src/agent_factory/agents.py) start_line:77 end_line:97
164
- <!--/codeinclude-->
165
 
166
- Factory functions:
167
- - Use `get_model()` if no model provided
168
- - Raise `ConfigurationError` if creation fails
169
- - Log agent creation
170
 
171
- ## See Also
172
 
173
- - [Orchestrators](orchestrators.md) - How agents are orchestrated
174
- - [API Reference - Agents](../api/agents.md) - API documentation
175
- - [Contributing - Code Style](../contributing/code-style.md) - Development guidelines
176
- <<<<<<< HEAD
177
- =======
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
178
 
 
179
 
 
 
 
 
 
 
 
 
 
 
180
 
 
181
 
 
182
 
 
183
 
 
 
184
 
 
 
 
 
 
185
 
 
186
 
 
187
 
 
188
 
 
189
 
 
 
 
190
 
 
 
 
 
191
 
 
192
 
 
193
 
 
194
 
 
195
 
 
 
 
 
196
 
197
- >>>>>>> 8086ce5fefde1c867880661d57e1299029a91ead
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4
 
5
  ## Agent Pattern
6
 
7
+ ### Pydantic AI Agents
8
+
9
+ Pydantic AI agents use the `Agent` class with the following structure:
10
 
11
  - **System Prompt**: Module-level constant with date injection
12
  - **Agent Class**: `__init__(model: Any | None = None)`
13
  - **Main Method**: Async method (e.g., `async def evaluate()`, `async def write_report()`)
14
+ - **Factory Function**: `def create_agent_name(model: Any | None = None, oauth_token: str | None = None) -> AgentName`
15
+
16
+ **Note**: Factory functions accept an optional `oauth_token` parameter for HuggingFace authentication, which takes priority over environment variables.
17
 
18
  ## Model Initialization
19
 
 
159
  - `key_entities`: List of key entities
160
  - `research_questions`: List of research questions
161
 
162
+ ## Magentic Agents
163
 
164
+ The following agents use the `BaseAgent` pattern from `agent-framework` and are used exclusively with `MagenticOrchestrator`:
165
 
166
+ ### Hypothesis Agent
 
 
167
 
168
+ **File**: `src/agents/hypothesis_agent.py`
 
 
 
169
 
170
+ **Purpose**: Generates mechanistic hypotheses based on evidence.
171
 
172
+ **Pattern**: `BaseAgent` from `agent-framework`
173
+
174
+ **Methods**:
175
+ - `async def run(messages, thread, **kwargs) -> AgentRunResponse`
176
+
177
+ **Features**:
178
+ - Uses internal Pydantic AI `Agent` with `HypothesisAssessment` output type
179
+ - Accesses shared `evidence_store` for evidence
180
+ - Uses embedding service for diverse evidence selection (MMR algorithm)
181
+ - Stores hypotheses in shared context
182
+
183
+ ### Search Agent
184
+
185
+ **File**: `src/agents/search_agent.py`
186
+
187
+ **Purpose**: Wraps `SearchHandler` as an agent for Magentic orchestrator.
188
+
189
+ **Pattern**: `BaseAgent` from `agent-framework`
190
+
191
+ **Methods**:
192
+ - `async def run(messages, thread, **kwargs) -> AgentRunResponse`
193
+
194
+ **Features**:
195
+ - Executes searches via `SearchHandlerProtocol`
196
+ - Deduplicates evidence using embedding service
197
+ - Searches for semantically related evidence
198
+ - Updates shared evidence store
199
+
200
+ ### Analysis Agent
201
+
202
+ **File**: `src/agents/analysis_agent.py`
203
+
204
+ **Purpose**: Performs statistical analysis using Modal sandbox.
205
 
206
+ **Pattern**: `BaseAgent` from `agent-framework`
207
 
208
+ **Methods**:
209
+ - `async def run(messages, thread, **kwargs) -> AgentRunResponse`
210
+
211
+ **Features**:
212
+ - Wraps `StatisticalAnalyzer` service
213
+ - Analyzes evidence and hypotheses
214
+ - Returns verdict (SUPPORTED/REFUTED/INCONCLUSIVE)
215
+ - Stores analysis results in shared context
216
+
217
+ ### Report Agent (Magentic)
218
 
219
+ **File**: `src/agents/report_agent.py`
220
 
221
+ **Purpose**: Generates structured scientific reports from evidence and hypotheses.
222
 
223
+ **Pattern**: `BaseAgent` from `agent-framework`
224
 
225
+ **Methods**:
226
+ - `async def run(messages, thread, **kwargs) -> AgentRunResponse`
227
 
228
+ **Features**:
229
+ - Uses internal Pydantic AI `Agent` with `ResearchReport` output type
230
+ - Accesses shared evidence store and hypotheses
231
+ - Validates citations before returning
232
+ - Formats report as markdown
233
 
234
+ ### Judge Agent
235
 
236
+ **File**: `src/agents/judge_agent.py`
237
 
238
+ **Purpose**: Evaluates evidence quality and determines if sufficient for synthesis.
239
 
240
+ **Pattern**: `BaseAgent` from `agent-framework`
241
 
242
+ **Methods**:
243
+ - `async def run(messages, thread, **kwargs) -> AgentRunResponse`
244
+ - `async def run_stream(messages, thread, **kwargs) -> AsyncIterable[AgentRunResponseUpdate]`
245
 
246
+ **Features**:
247
+ - Wraps `JudgeHandlerProtocol`
248
+ - Accesses shared evidence store
249
+ - Returns `JudgeAssessment` with sufficient flag, confidence, and recommendation
250
 
251
+ ## Agent Patterns
252
 
253
+ DeepCritical uses two distinct agent patterns:
254
 
255
+ ### 1. Pydantic AI Agents (Traditional Pattern)
256
 
257
+ These agents use the Pydantic AI `Agent` class directly and are used in iterative and deep research flows:
258
 
259
+ - **Pattern**: `Agent(model, output_type, system_prompt)`
260
+ - **Initialization**: `__init__(model: Any | None = None)`
261
+ - **Methods**: Agent-specific async methods (e.g., `async def evaluate()`, `async def write_report()`)
262
+ - **Examples**: `KnowledgeGapAgent`, `ToolSelectorAgent`, `WriterAgent`, `LongWriterAgent`, `ProofreaderAgent`, `ThinkingAgent`, `InputParserAgent`
263
 
264
+ ### 2. Magentic Agents (Agent-Framework Pattern)
265
+
266
+ These agents use the `BaseAgent` class from `agent-framework` and are used in Magentic orchestrator:
267
+
268
+ - **Pattern**: `BaseAgent` from `agent-framework` with `async def run()` method
269
+ - **Initialization**: `__init__(evidence_store, embedding_service, ...)`
270
+ - **Methods**: `async def run(messages, thread, **kwargs) -> AgentRunResponse`
271
+ - **Examples**: `HypothesisAgent`, `SearchAgent`, `AnalysisAgent`, `ReportAgent`, `JudgeAgent`
272
+
273
+ **Note**: Magentic agents are used exclusively with the `MagenticOrchestrator` and follow the agent-framework protocol for multi-agent coordination.
274
+
275
+ ## Factory Functions
276
+
277
+ All agents have factory functions in `src/agent_factory/agents.py`:
278
+
279
+ <!--codeinclude-->
280
+ [Factory Functions](../src/agent_factory/agents.py) start_line:79 end_line:100
281
+ <!--/codeinclude-->
282
+
283
+ Factory functions:
284
+ - Use `get_model()` if no model provided
285
+ - Accept `oauth_token` parameter for HuggingFace authentication
286
+ - Raise `ConfigurationError` if creation fails
287
+ - Log agent creation
288
+
289
+ ## See Also
290
+
291
+ - [Orchestrators](orchestrators.md) - How agents are orchestrated
292
+ - [API Reference - Agents](../api/agents.md) - API documentation
293
+ - [Contributing - Code Style](../contributing/code-style.md) - Development guidelines
docs/architecture/graph-orchestration.md DELETED
@@ -1,138 +0,0 @@
1
- # Graph Orchestration Architecture
2
-
3
- ## Overview
4
-
5
- Phase 4 implements a graph-based orchestration system for research workflows using Pydantic AI agents as nodes. This enables better parallel execution, conditional routing, and state management compared to simple agent chains.
6
-
7
- ## Graph Structure
8
-
9
- ### Nodes
10
-
11
- Graph nodes represent different stages in the research workflow:
12
-
13
- 1. **Agent Nodes**: Execute Pydantic AI agents
14
- - Input: Prompt/query
15
- - Output: Structured or unstructured response
16
- - Examples: `KnowledgeGapAgent`, `ToolSelectorAgent`, `ThinkingAgent`
17
-
18
- 2. **State Nodes**: Update or read workflow state
19
- - Input: Current state
20
- - Output: Updated state
21
- - Examples: Update evidence, update conversation history
22
-
23
- 3. **Decision Nodes**: Make routing decisions based on conditions
24
- - Input: Current state/results
25
- - Output: Next node ID
26
- - Examples: Continue research vs. complete research
27
-
28
- 4. **Parallel Nodes**: Execute multiple nodes concurrently
29
- - Input: List of node IDs
30
- - Output: Aggregated results
31
- - Examples: Parallel iterative research loops
32
-
33
- ### Edges
34
-
35
- Edges define transitions between nodes:
36
-
37
- 1. **Sequential Edges**: Always traversed (no condition)
38
- - From: Source node
39
- - To: Target node
40
- - Condition: None (always True)
41
-
42
- 2. **Conditional Edges**: Traversed based on condition
43
- - From: Source node
44
- - To: Target node
45
- - Condition: Callable that returns bool
46
- - Example: If research complete → go to writer, else → continue loop
47
-
48
- 3. **Parallel Edges**: Used for parallel execution branches
49
- - From: Parallel node
50
- - To: Multiple target nodes
51
- - Execution: All targets run concurrently
52
-
53
- ## Graph Patterns
54
-
55
- ### Iterative Research Graph
56
-
57
- ```
58
- [Input] → [Thinking] → [Knowledge Gap] → [Decision: Complete?]
59
- ↓ No ↓ Yes
60
- [Tool Selector] [Writer]
61
-
62
- [Execute Tools] → [Loop Back]
63
- ```
64
-
65
- ### Deep Research Graph
66
-
67
- ```
68
- [Input] → [Planner] → [Parallel Iterative Loops] → [Synthesizer]
69
- ↓ ↓ ↓
70
- [Loop1] [Loop2] [Loop3]
71
- ```
72
-
73
- ## State Management
74
-
75
- State is managed via `WorkflowState` using `ContextVar` for thread-safe isolation:
76
-
77
- - **Evidence**: Collected evidence from searches
78
- - **Conversation**: Iteration history (gaps, tool calls, findings, thoughts)
79
- - **Embedding Service**: For semantic search
80
-
81
- State transitions occur at state nodes, which update the global workflow state.
82
-
83
- ## Execution Flow
84
-
85
- 1. **Graph Construction**: Build graph from nodes and edges
86
- 2. **Graph Validation**: Ensure graph is valid (no cycles, all nodes reachable)
87
- 3. **Graph Execution**: Traverse graph from entry node
88
- 4. **Node Execution**: Execute each node based on type
89
- 5. **Edge Evaluation**: Determine next node(s) based on edges
90
- 6. **Parallel Execution**: Use `asyncio.gather()` for parallel nodes
91
- 7. **State Updates**: Update state at state nodes
92
- 8. **Event Streaming**: Yield events during execution for UI
93
-
94
- ## Conditional Routing
95
-
96
- Decision nodes evaluate conditions and return next node IDs:
97
-
98
- - **Knowledge Gap Decision**: If `research_complete` → writer, else → tool selector
99
- - **Budget Decision**: If budget exceeded → exit, else → continue
100
- - **Iteration Decision**: If max iterations → exit, else → continue
101
-
102
- ## Parallel Execution
103
-
104
- Parallel nodes execute multiple nodes concurrently:
105
-
106
- - Each parallel branch runs independently
107
- - Results are aggregated after all branches complete
108
- - State is synchronized after parallel execution
109
- - Errors in one branch don't stop other branches
110
-
111
- ## Budget Enforcement
112
-
113
- Budget constraints are enforced at decision nodes:
114
-
115
- - **Token Budget**: Track LLM token usage
116
- - **Time Budget**: Track elapsed time
117
- - **Iteration Budget**: Track iteration count
118
-
119
- If any budget is exceeded, execution routes to exit node.
120
-
121
- ## Error Handling
122
-
123
- Errors are handled at multiple levels:
124
-
125
- 1. **Node Level**: Catch errors in individual node execution
126
- 2. **Graph Level**: Handle errors during graph traversal
127
- 3. **State Level**: Rollback state changes on error
128
-
129
- Errors are logged and yield error events for UI.
130
-
131
- ## Backward Compatibility
132
-
133
- Graph execution is optional via feature flag:
134
-
135
- - `USE_GRAPH_EXECUTION=true`: Use graph-based execution
136
- - `USE_GRAPH_EXECUTION=false`: Use agent chain execution (existing)
137
-
138
- This allows gradual migration and fallback if needed.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
docs/architecture/graph_orchestration.md CHANGED
@@ -1,9 +1,15 @@
1
  # Graph Orchestration Architecture
2
 
 
 
 
 
3
  ## Graph Patterns
4
 
5
  ### Iterative Research Graph
6
 
 
 
7
  ```
8
  [Input] → [Thinking] → [Knowledge Gap] → [Decision: Complete?]
9
  ↓ No ↓ Yes
@@ -12,14 +18,31 @@
12
  [Execute Tools] → [Loop Back]
13
  ```
14
 
 
 
 
 
 
 
15
  ### Deep Research Graph
16
 
 
 
17
  ```
18
- [Input] → [Planner] → [Parallel Iterative Loops] → [Synthesizer]
19
- ↓ ↓ ↓
20
- [Loop1] [Loop2] [Loop3]
21
  ```
22
 
 
 
 
 
 
 
 
 
 
23
  ### Deep Research
24
 
25
  ```mermaid
@@ -158,14 +181,35 @@ State transitions occur at state nodes, which update the global workflow state.
158
 
159
  ## Execution Flow
160
 
161
- 1. **Graph Construction**: Build graph from nodes and edges
162
- 2. **Graph Validation**: Ensure graph is valid (no cycles, all nodes reachable)
163
- 3. **Graph Execution**: Traverse graph from entry node
164
- 4. **Node Execution**: Execute each node based on type
165
- 5. **Edge Evaluation**: Determine next node(s) based on edges
 
 
 
 
166
  6. **Parallel Execution**: Use `asyncio.gather()` for parallel nodes
167
- 7. **State Updates**: Update state at state nodes
168
- 8. **Event Streaming**: Yield events during execution for UI
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
169
 
170
  ## Conditional Routing
171
 
 
1
  # Graph Orchestration Architecture
2
 
3
+ ## Overview
4
+
5
+ DeepCritical implements a graph-based orchestration system for research workflows using Pydantic AI agents as nodes. This enables better parallel execution, conditional routing, and state management compared to simple agent chains.
6
+
7
  ## Graph Patterns
8
 
9
  ### Iterative Research Graph
10
 
11
+ The iterative research graph follows this pattern:
12
+
13
  ```
14
  [Input] → [Thinking] → [Knowledge Gap] → [Decision: Complete?]
15
  ↓ No ↓ Yes
 
18
  [Execute Tools] → [Loop Back]
19
  ```
20
 
21
+ **Node IDs**: `thinking` → `knowledge_gap` → `continue_decision` → `tool_selector`/`writer` → `execute_tools` → (loop back to `thinking`)
22
+
23
+ **Special Node Handling**:
24
+ - `execute_tools`: State node that uses `search_handler` to execute searches and add evidence to workflow state
25
+ - `continue_decision`: Decision node that routes based on `research_complete` flag from `KnowledgeGapOutput`
26
+
27
  ### Deep Research Graph
28
 
29
+ The deep research graph follows this pattern:
30
+
31
  ```
32
+ [Input] → [Planner] → [Store Plan] → [Parallel Loops] → [Collect Drafts] → [Synthesizer]
33
+ ↓ ↓ ↓
34
+ [Loop1] [Loop2] [Loop3]
35
  ```
36
 
37
+ **Node IDs**: `planner` → `store_plan` → `parallel_loops` → `collect_drafts` → `synthesizer`
38
+
39
+ **Special Node Handling**:
40
+ - `planner`: Agent node that creates `ReportPlan` with report outline
41
+ - `store_plan`: State node that stores `ReportPlan` in context for parallel loops
42
+ - `parallel_loops`: Parallel node that executes `IterativeResearchFlow` instances for each section
43
+ - `collect_drafts`: State node that collects section drafts from parallel loops
44
+ - `synthesizer`: Agent node that calls `LongWriterAgent.write_report()` directly with `ReportDraft`
45
+
46
  ### Deep Research
47
 
48
  ```mermaid
 
181
 
182
  ## Execution Flow
183
 
184
+ 1. **Graph Construction**: Build graph from nodes and edges using `create_iterative_graph()` or `create_deep_graph()`
185
+ 2. **Graph Validation**: Ensure graph is valid (no cycles, all nodes reachable) via `ResearchGraph.validate_structure()`
186
+ 3. **Graph Execution**: Traverse graph from entry node using `GraphOrchestrator._execute_graph()`
187
+ 4. **Node Execution**: Execute each node based on type:
188
+ - **Agent Nodes**: Call `agent.run()` with transformed input
189
+ - **State Nodes**: Update workflow state via `state_updater` function
190
+ - **Decision Nodes**: Evaluate `decision_function` to get next node ID
191
+ - **Parallel Nodes**: Execute all parallel nodes concurrently via `asyncio.gather()`
192
+ 5. **Edge Evaluation**: Determine next node(s) based on edges and conditions
193
  6. **Parallel Execution**: Use `asyncio.gather()` for parallel nodes
194
+ 7. **State Updates**: Update state at state nodes via `GraphExecutionContext.update_state()`
195
+ 8. **Event Streaming**: Yield `AgentEvent` objects during execution for UI
196
+
197
+ ### GraphExecutionContext
198
+
199
+ The `GraphExecutionContext` class manages execution state during graph traversal:
200
+
201
+ - **State**: Current `WorkflowState` instance
202
+ - **Budget Tracker**: `BudgetTracker` instance for budget enforcement
203
+ - **Node Results**: Dictionary storing results from each node execution
204
+ - **Visited Nodes**: Set of node IDs that have been executed
205
+ - **Current Node**: ID of the node currently being executed
206
+
207
+ Methods:
208
+ - `set_node_result(node_id, result)`: Store result from node execution
209
+ - `get_node_result(node_id)`: Retrieve stored result
210
+ - `has_visited(node_id)`: Check if node was visited
211
+ - `mark_visited(node_id)`: Mark node as visited
212
+ - `update_state(updater, data)`: Update workflow state
213
 
214
  ## Conditional Routing
215
 
docs/architecture/middleware.md CHANGED
@@ -18,8 +18,8 @@ DeepCritical uses middleware for state management, budget tracking, and workflow
18
  - `embedding_service: Any`: Embedding service for semantic search
19
 
20
  **Methods**:
21
- - `add_evidence(evidence: Evidence)`: Adds evidence with URL-based deduplication
22
- - `async search_related(query: str, top_k: int = 5) -> list[Evidence]`: Semantic search
23
 
24
  **Initialization**:
25
 
@@ -30,7 +30,7 @@ DeepCritical uses middleware for state management, budget tracking, and workflow
30
  **Access**:
31
 
32
  <!--codeinclude-->
33
- [Get Workflow State](../src/middleware/state_machine.py) start_line:112 end_line:125
34
  <!--/codeinclude-->
35
 
36
  ## Workflow Manager
@@ -40,10 +40,10 @@ DeepCritical uses middleware for state management, budget tracking, and workflow
40
  **Purpose**: Coordinates parallel research loops
41
 
42
  **Methods**:
43
- - `add_loop(loop: ResearchLoop)`: Add a research loop to manage
44
- - `async run_loops_parallel() -> list[ResearchLoop]`: Run all loops in parallel
45
- - `update_loop_status(loop_id: str, status: str)`: Update loop status
46
- - `sync_loop_evidence_to_state()`: Synchronize evidence from loops to global state
47
 
48
  **Features**:
49
  - Uses `asyncio.gather()` for parallel execution
@@ -56,9 +56,22 @@ DeepCritical uses middleware for state management, budget tracking, and workflow
56
  from src.middleware.workflow_manager import WorkflowManager
57
 
58
  manager = WorkflowManager()
59
- manager.add_loop(loop1)
60
- manager.add_loop(loop2)
61
- completed_loops = await manager.run_loops_parallel()
 
 
 
 
 
 
 
 
 
 
 
 
 
62
  ```
63
 
64
  ## Budget Tracker
@@ -73,13 +86,13 @@ completed_loops = await manager.run_loops_parallel()
73
  - **Iterations**: Number of iterations
74
 
75
  **Methods**:
76
- - `create_budget(token_limit, time_limit_seconds, iterations_limit) -> BudgetStatus`
77
- - `add_tokens(tokens: int)`: Add token usage
78
- - `start_timer()`: Start time tracking
79
- - `update_timer()`: Update elapsed time
80
- - `increment_iteration()`: Increment iteration count
81
- - `check_budget() -> BudgetStatus`: Check current budget status
82
- - `can_continue() -> bool`: Check if research can continue
83
 
84
  **Token Estimation**:
85
  - `estimate_tokens(text: str) -> int`: ~4 chars per token
@@ -91,13 +104,20 @@ from src.middleware.budget_tracker import BudgetTracker
91
 
92
  tracker = BudgetTracker()
93
  budget = tracker.create_budget(
94
- token_limit=100000,
 
95
  time_limit_seconds=600,
96
  iterations_limit=10
97
  )
98
- tracker.start_timer()
99
  # ... research operations ...
100
- if not tracker.can_continue():
 
 
 
 
 
 
101
  # Budget exceeded, stop research
102
  pass
103
  ```
 
18
  - `embedding_service: Any`: Embedding service for semantic search
19
 
20
  **Methods**:
21
+ - `add_evidence(new_evidence: list[Evidence]) -> int`: Adds evidence with URL-based deduplication. Returns the number of new items added (excluding duplicates).
22
+ - `async search_related(query: str, n_results: int = 5) -> list[Evidence]`: Semantic search for related evidence using embedding service
23
 
24
  **Initialization**:
25
 
 
30
  **Access**:
31
 
32
  <!--codeinclude-->
33
+ [Get Workflow State](../src/middleware/state_machine.py) start_line:115 end_line:129
34
  <!--/codeinclude-->
35
 
36
  ## Workflow Manager
 
40
  **Purpose**: Coordinates parallel research loops
41
 
42
  **Methods**:
43
+ - `async add_loop(loop_id: str, query: str) -> ResearchLoop`: Add a new research loop to manage
44
+ - `async run_loops_parallel(loop_configs: list[dict], loop_func: Callable, judge_handler: Any | None = None, budget_tracker: Any | None = None) -> list[Any]`: Run multiple research loops in parallel. Takes configuration dicts and a loop function.
45
+ - `async update_loop_status(loop_id: str, status: LoopStatus, error: str | None = None)`: Update loop status
46
+ - `async sync_loop_evidence_to_state(loop_id: str)`: Synchronize evidence from a specific loop to global state
47
 
48
  **Features**:
49
  - Uses `asyncio.gather()` for parallel execution
 
56
  from src.middleware.workflow_manager import WorkflowManager
57
 
58
  manager = WorkflowManager()
59
+ await manager.add_loop("loop1", "Research query 1")
60
+ await manager.add_loop("loop2", "Research query 2")
61
+
62
+ async def run_research(config: dict) -> str:
63
+ loop_id = config["loop_id"]
64
+ query = config["query"]
65
+ # ... research logic ...
66
+ return "report"
67
+
68
+ results = await manager.run_loops_parallel(
69
+ loop_configs=[
70
+ {"loop_id": "loop1", "query": "Research query 1"},
71
+ {"loop_id": "loop2", "query": "Research query 2"},
72
+ ],
73
+ loop_func=run_research,
74
+ )
75
  ```
76
 
77
  ## Budget Tracker
 
86
  - **Iterations**: Number of iterations
87
 
88
  **Methods**:
89
+ - `create_budget(loop_id: str, tokens_limit: int = 100000, time_limit_seconds: float = 600.0, iterations_limit: int = 10) -> BudgetStatus`: Create a budget for a specific loop
90
+ - `add_tokens(loop_id: str, tokens: int)`: Add token usage to a loop's budget
91
+ - `start_timer(loop_id: str)`: Start time tracking for a loop
92
+ - `update_timer(loop_id: str)`: Update elapsed time for a loop
93
+ - `increment_iteration(loop_id: str)`: Increment iteration count for a loop
94
+ - `check_budget(loop_id: str) -> tuple[bool, str]`: Check if a loop's budget has been exceeded. Returns (exceeded: bool, reason: str)
95
+ - `can_continue(loop_id: str) -> bool`: Check if a loop can continue based on budget
96
 
97
  **Token Estimation**:
98
  - `estimate_tokens(text: str) -> int`: ~4 chars per token
 
104
 
105
  tracker = BudgetTracker()
106
  budget = tracker.create_budget(
107
+ loop_id="research_loop",
108
+ tokens_limit=100000,
109
  time_limit_seconds=600,
110
  iterations_limit=10
111
  )
112
+ tracker.start_timer("research_loop")
113
  # ... research operations ...
114
+ tracker.add_tokens("research_loop", 5000)
115
+ tracker.update_timer("research_loop")
116
+ exceeded, reason = tracker.check_budget("research_loop")
117
+ if exceeded:
118
+ # Budget exceeded, stop research
119
+ pass
120
+ if not tracker.can_continue("research_loop"):
121
  # Budget exceeded, stop research
122
  pass
123
  ```
docs/architecture/orchestrators.md CHANGED
@@ -25,7 +25,7 @@ DeepCritical supports multiple orchestration patterns for research workflows.
25
  **Usage**:
26
 
27
  <!--codeinclude-->
28
- [IterativeResearchFlow Initialization](../src/orchestrator/research_flow.py) start_line:56 end_line:77
29
  <!--/codeinclude-->
30
 
31
  ### DeepResearchFlow
@@ -48,7 +48,7 @@ DeepCritical supports multiple orchestration patterns for research workflows.
48
  **Usage**:
49
 
50
  <!--codeinclude-->
51
- [DeepResearchFlow Initialization](../src/orchestrator/research_flow.py) start_line:674 end_line:697
52
  <!--/codeinclude-->
53
 
54
  ## Graph Orchestrator
@@ -58,9 +58,10 @@ DeepCritical supports multiple orchestration patterns for research workflows.
58
  **Purpose**: Graph-based execution using Pydantic AI agents as nodes
59
 
60
  **Features**:
61
- - Uses Pydantic AI Graphs (when available) or agent chains (fallback)
62
  - Routes based on research mode (iterative/deep/auto)
63
  - Streams `AgentEvent` objects for UI
 
64
 
65
  **Node Types**:
66
  - **Agent Nodes**: Execute Pydantic AI agents
@@ -73,6 +74,22 @@ DeepCritical supports multiple orchestration patterns for research workflows.
73
  - **Conditional Edges**: Traversed based on condition
74
  - **Parallel Edges**: Used for parallel execution branches
75
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
76
  ## Orchestrator Factory
77
 
78
  **File**: `src/orchestrator_factory.py`
@@ -99,14 +116,26 @@ DeepCritical supports multiple orchestration patterns for research workflows.
99
  **Features**:
100
  - Uses `agent-framework-core`
101
  - ChatAgent pattern with internal LLMs per agent
102
- - `MagenticBuilder` with participants: searcher, hypothesizer, judge, reporter
103
- - Manager orchestrates agents via `OpenAIChatClient`
104
- - Requires OpenAI API key (function calling support)
105
- - Event-driven: converts Magentic events to `AgentEvent` for UI streaming
 
 
 
 
 
 
 
 
 
 
 
 
106
 
107
  **Requirements**:
108
  - `agent-framework-core` package
109
- - OpenAI API key
110
 
111
  ## Hierarchical Orchestrator
112
 
@@ -136,7 +165,7 @@ DeepCritical supports multiple orchestration patterns for research workflows.
136
  All orchestrators must initialize workflow state:
137
 
138
  <!--codeinclude-->
139
- [Initialize Workflow State](../src/middleware/state_machine.py) start_line:98 end_line:111
140
  <!--/codeinclude-->
141
 
142
  ## Event Streaming
@@ -145,17 +174,23 @@ All orchestrators yield `AgentEvent` objects:
145
 
146
  **Event Types**:
147
  - `started`: Research started
 
148
  - `search_complete`: Search completed
 
149
  - `judge_complete`: Evidence evaluation completed
 
150
  - `hypothesizing`: Generating hypotheses
 
 
151
  - `synthesizing`: Synthesizing results
152
  - `complete`: Research completed
153
  - `error`: Error occurred
 
154
 
155
  **Event Structure**:
156
 
157
  <!--codeinclude-->
158
- [AgentEvent Model](../src/utils/models.py) start_line:104 end_line:125
159
  <!--/codeinclude-->
160
 
161
  ## See Also
 
25
  **Usage**:
26
 
27
  <!--codeinclude-->
28
+ [IterativeResearchFlow Initialization](../src/orchestrator/research_flow.py) start_line:57 end_line:80
29
  <!--/codeinclude-->
30
 
31
  ### DeepResearchFlow
 
48
  **Usage**:
49
 
50
  <!--codeinclude-->
51
+ [DeepResearchFlow Initialization](../src/orchestrator/research_flow.py) start_line:709 end_line:728
52
  <!--/codeinclude-->
53
 
54
  ## Graph Orchestrator
 
58
  **Purpose**: Graph-based execution using Pydantic AI agents as nodes
59
 
60
  **Features**:
61
+ - Uses graph execution (`use_graph=True`) or agent chains (`use_graph=False`) as fallback
62
  - Routes based on research mode (iterative/deep/auto)
63
  - Streams `AgentEvent` objects for UI
64
+ - Uses `GraphExecutionContext` to manage execution state
65
 
66
  **Node Types**:
67
  - **Agent Nodes**: Execute Pydantic AI agents
 
74
  - **Conditional Edges**: Traversed based on condition
75
  - **Parallel Edges**: Used for parallel execution branches
76
 
77
+ **Special Node Handling**:
78
+
79
+ The `GraphOrchestrator` has special handling for certain nodes:
80
+
81
+ - **`execute_tools` node**: State node that uses `search_handler` to execute searches and add evidence to workflow state
82
+ - **`parallel_loops` node**: Parallel node that executes `IterativeResearchFlow` instances for each section in deep research mode
83
+ - **`synthesizer` node**: Agent node that calls `LongWriterAgent.write_report()` directly with `ReportDraft` instead of using `agent.run()`
84
+ - **`writer` node**: Agent node that calls `WriterAgent.write_report()` directly with findings instead of using `agent.run()`
85
+
86
+ **GraphExecutionContext**:
87
+
88
+ The orchestrator uses `GraphExecutionContext` to manage execution state:
89
+ - Tracks current node, visited nodes, and node results
90
+ - Manages workflow state and budget tracker
91
+ - Provides methods to store and retrieve node execution results
92
+
93
  ## Orchestrator Factory
94
 
95
  **File**: `src/orchestrator_factory.py`
 
116
  **Features**:
117
  - Uses `agent-framework-core`
118
  - ChatAgent pattern with internal LLMs per agent
119
+ - `MagenticBuilder` with participants:
120
+ - `searcher`: SearchAgent (wraps SearchHandler)
121
+ - `hypothesizer`: HypothesisAgent (generates hypotheses)
122
+ - `judge`: JudgeAgent (evaluates evidence)
123
+ - `reporter`: ReportAgent (generates final report)
124
+ - Manager orchestrates agents via chat client (OpenAI or HuggingFace)
125
+ - Event-driven: converts Magentic events to `AgentEvent` for UI streaming via `_process_event()` method
126
+ - Supports max rounds, stall detection, and reset handling
127
+
128
+ **Event Processing**:
129
+
130
+ The orchestrator processes Magentic events and converts them to `AgentEvent`:
131
+ - `MagenticOrchestratorMessageEvent` → `AgentEvent` with type based on message content
132
+ - `MagenticAgentMessageEvent` → `AgentEvent` with type based on agent name
133
+ - `MagenticAgentDeltaEvent` → `AgentEvent` for streaming updates
134
+ - `MagenticFinalResultEvent` → `AgentEvent` with type "complete"
135
 
136
  **Requirements**:
137
  - `agent-framework-core` package
138
+ - OpenAI API key or HuggingFace authentication
139
 
140
  ## Hierarchical Orchestrator
141
 
 
165
  All orchestrators must initialize workflow state:
166
 
167
  <!--codeinclude-->
168
+ [Initialize Workflow State](../src/middleware/state_machine.py) start_line:98 end_line:112
169
  <!--/codeinclude-->
170
 
171
  ## Event Streaming
 
174
 
175
  **Event Types**:
176
  - `started`: Research started
177
+ - `searching`: Search in progress
178
  - `search_complete`: Search completed
179
+ - `judging`: Evidence evaluation in progress
180
  - `judge_complete`: Evidence evaluation completed
181
+ - `looping`: Iteration in progress
182
  - `hypothesizing`: Generating hypotheses
183
+ - `analyzing`: Statistical analysis in progress
184
+ - `analysis_complete`: Statistical analysis completed
185
  - `synthesizing`: Synthesizing results
186
  - `complete`: Research completed
187
  - `error`: Error occurred
188
+ - `streaming`: Streaming update (delta events)
189
 
190
  **Event Structure**:
191
 
192
  <!--codeinclude-->
193
+ [AgentEvent Model](../src/utils/models.py) start_line:104 end_line:126
194
  <!--/codeinclude-->
195
 
196
  ## See Also
docs/architecture/services.md CHANGED
@@ -10,17 +10,18 @@ DeepCritical provides several services for embeddings, RAG, and statistical anal
10
 
11
  **Features**:
12
  - **No API Key Required**: Uses local sentence-transformers models
13
- - **Async-Safe**: All operations use `run_in_executor()` to avoid blocking
14
- - **ChromaDB Storage**: Vector storage for embeddings
15
- - **Deduplication**: 0.85 similarity threshold (85% similarity = duplicate)
16
 
17
  **Model**: Configurable via `settings.local_embedding_model` (default: `all-MiniLM-L6-v2`)
18
 
19
  **Methods**:
20
- - `async def embed(text: str) -> list[float]`: Generate embeddings
21
- - `async def embed_batch(texts: list[str]) -> list[list[float]]`: Batch embedding
22
- - `async def similarity(text1: str, text2: str) -> float`: Calculate similarity
23
- - `async def find_duplicates(texts: list[str], threshold: float = 0.85) -> list[tuple[int, int]]`: Find duplicates
 
24
 
25
  **Usage**:
26
  ```python
@@ -32,15 +33,21 @@ embedding = await service.embed("text to embed")
32
 
33
  ## LlamaIndex RAG Service
34
 
35
- **File**: `src/services/rag.py`
36
 
37
  **Purpose**: Retrieval-Augmented Generation using LlamaIndex
38
 
39
  **Features**:
40
- - **OpenAI Embeddings**: Requires `OPENAI_API_KEY`
41
- - **ChromaDB Storage**: Vector database for document storage
 
42
  - **Metadata Preservation**: Preserves source, title, URL, date, authors
43
- - **Lazy Initialization**: Graceful fallback if OpenAI key not available
 
 
 
 
 
44
 
45
  **Methods**:
46
  - `async def ingest_evidence(evidence: list[Evidence]) -> None`: Ingest evidence into RAG
@@ -49,9 +56,13 @@ embedding = await service.embed("text to embed")
49
 
50
  **Usage**:
51
  ```python
52
- from src.services.rag import get_rag_service
53
 
54
- service = get_rag_service()
 
 
 
 
55
  if service:
56
  documents = await service.retrieve("query", top_k=5)
57
  ```
@@ -92,13 +103,19 @@ result = await analyzer.analyze(
92
 
93
  ## Singleton Pattern
94
 
95
- All services use the singleton pattern with `@lru_cache(maxsize=1)`:
96
 
97
- ```python
98
- @lru_cache(maxsize=1)
99
- def get_embedding_service() -> EmbeddingService:
100
- return EmbeddingService()
101
- ```
 
 
 
 
 
 
102
 
103
  This ensures:
104
  - Single instance per process
 
10
 
11
  **Features**:
12
  - **No API Key Required**: Uses local sentence-transformers models
13
+ - **Async-Safe**: All operations use `run_in_executor()` to avoid blocking the event loop
14
+ - **ChromaDB Storage**: In-memory vector storage for embeddings
15
+ - **Deduplication**: 0.9 similarity threshold by default (90% similarity = duplicate, configurable)
16
 
17
  **Model**: Configurable via `settings.local_embedding_model` (default: `all-MiniLM-L6-v2`)
18
 
19
  **Methods**:
20
+ - `async def embed(text: str) -> list[float]`: Generate embeddings (async-safe via `run_in_executor()`)
21
+ - `async def embed_batch(texts: list[str]) -> list[list[float]]`: Batch embedding (more efficient)
22
+ - `async def add_evidence(evidence_id: str, content: str, metadata: dict[str, Any]) -> None`: Add evidence to vector store
23
+ - `async def search_similar(query: str, n_results: int = 5) -> list[dict[str, Any]]`: Find semantically similar evidence
24
+ - `async def deduplicate(new_evidence: list[Evidence], threshold: float = 0.9) -> list[Evidence]`: Remove semantically duplicate evidence
25
 
26
  **Usage**:
27
  ```python
 
33
 
34
  ## LlamaIndex RAG Service
35
 
36
+ **File**: `src/services/llamaindex_rag.py`
37
 
38
  **Purpose**: Retrieval-Augmented Generation using LlamaIndex
39
 
40
  **Features**:
41
+ - **Multiple Embedding Providers**: OpenAI embeddings (requires `OPENAI_API_KEY`) or local sentence-transformers (no API key)
42
+ - **Multiple LLM Providers**: HuggingFace LLM (preferred) or OpenAI LLM (fallback) for query synthesis
43
+ - **ChromaDB Storage**: Vector database for document storage (supports in-memory mode)
44
  - **Metadata Preservation**: Preserves source, title, URL, date, authors
45
+ - **Lazy Initialization**: Graceful fallback if dependencies not available
46
+
47
+ **Initialization Parameters**:
48
+ - `use_openai_embeddings: bool | None`: Force OpenAI embeddings (None = auto-detect)
49
+ - `use_in_memory: bool`: Use in-memory ChromaDB client (useful for tests)
50
+ - `oauth_token: str | None`: Optional OAuth token from HuggingFace login (takes priority over env vars)
51
 
52
  **Methods**:
53
  - `async def ingest_evidence(evidence: list[Evidence]) -> None`: Ingest evidence into RAG
 
56
 
57
  **Usage**:
58
  ```python
59
+ from src.services.llamaindex_rag import get_rag_service
60
 
61
+ service = get_rag_service(
62
+ use_openai_embeddings=False, # Use local embeddings
63
+ use_in_memory=True, # Use in-memory ChromaDB
64
+ oauth_token=token # Optional HuggingFace token
65
+ )
66
  if service:
67
  documents = await service.retrieve("query", top_k=5)
68
  ```
 
103
 
104
  ## Singleton Pattern
105
 
106
+ Services use singleton patterns for lazy initialization:
107
 
108
+ **EmbeddingService**: Uses a global variable pattern:
109
+
110
+ <!--codeinclude-->
111
+ [EmbeddingService Singleton](../src/services/embeddings.py) start_line:164 end_line:172
112
+ <!--/codeinclude-->
113
+
114
+ **LlamaIndexRAGService**: Direct instantiation (no caching):
115
+
116
+ <!--codeinclude-->
117
+ [LlamaIndexRAGService Factory](../src/services/llamaindex_rag.py) start_line:440 end_line:466
118
+ <!--/codeinclude-->
119
 
120
  This ensures:
121
  - Single instance per process
docs/architecture/tools.md CHANGED
@@ -14,14 +14,9 @@ All tools implement the `SearchTool` protocol from `src/tools/base.py`:
14
 
15
  All tools use the `@retry` decorator from tenacity:
16
 
17
- ```python
18
- @retry(
19
- stop=stop_after_attempt(3),
20
- wait=wait_exponential(...)
21
- )
22
- async def search(self, query: str, max_results: int = 10) -> list[Evidence]:
23
- # Implementation
24
- ```
25
 
26
  Tools with API rate limits implement `_rate_limit()` method and use shared rate limiters from `src/tools/rate_limiter.py`.
27
 
@@ -122,11 +117,23 @@ Missing fields are handled gracefully with defaults.
122
 
123
  **Purpose**: Orchestrates parallel searches across multiple tools
124
 
 
 
 
 
 
 
 
 
 
 
125
  **Features**:
126
- - Uses `asyncio.gather()` with `return_exceptions=True`
127
- - Aggregates results into `SearchResult`
128
- - Handles tool failures gracefully
129
  - Deduplicates results by URL
 
 
130
 
131
  ## Tool Registration
132
 
@@ -136,14 +143,21 @@ Tools are registered in the search handler:
136
  from src.tools.pubmed import PubMedTool
137
  from src.tools.clinicaltrials import ClinicalTrialsTool
138
  from src.tools.europepmc import EuropePMCTool
 
139
 
140
  search_handler = SearchHandler(
141
  tools=[
142
  PubMedTool(),
143
  ClinicalTrialsTool(),
144
  EuropePMCTool(),
145
- ]
 
 
 
146
  )
 
 
 
147
  ```
148
 
149
  ## See Also
 
14
 
15
  All tools use the `@retry` decorator from tenacity:
16
 
17
+ <!--codeinclude-->
18
+ [Retry Decorator Pattern](../src/tools/pubmed.py) start_line:46 end_line:50
19
+ <!--/codeinclude-->
 
 
 
 
 
20
 
21
  Tools with API rate limits implement `_rate_limit()` method and use shared rate limiters from `src/tools/rate_limiter.py`.
22
 
 
117
 
118
  **Purpose**: Orchestrates parallel searches across multiple tools
119
 
120
+ **Initialization Parameters**:
121
+ - `tools: list[SearchTool]`: List of search tools to use
122
+ - `timeout: float = 30.0`: Timeout for each search in seconds
123
+ - `include_rag: bool = False`: Whether to include RAG tool in searches
124
+ - `auto_ingest_to_rag: bool = True`: Whether to automatically ingest results into RAG
125
+ - `oauth_token: str | None = None`: Optional OAuth token from HuggingFace login (for RAG LLM)
126
+
127
+ **Methods**:
128
+ - `async def execute(query: str, max_results_per_tool: int = 10) -> SearchResult`: Execute search across all tools in parallel
129
+
130
  **Features**:
131
+ - Uses `asyncio.gather()` with `return_exceptions=True` for parallel execution
132
+ - Aggregates results into `SearchResult` with evidence and metadata
133
+ - Handles tool failures gracefully (continues with other tools)
134
  - Deduplicates results by URL
135
+ - Automatically ingests results into RAG if `auto_ingest_to_rag=True`
136
+ - Can add RAG tool dynamically via `add_rag_tool()` method
137
 
138
  ## Tool Registration
139
 
 
143
  from src.tools.pubmed import PubMedTool
144
  from src.tools.clinicaltrials import ClinicalTrialsTool
145
  from src.tools.europepmc import EuropePMCTool
146
+ from src.tools.search_handler import SearchHandler
147
 
148
  search_handler = SearchHandler(
149
  tools=[
150
  PubMedTool(),
151
  ClinicalTrialsTool(),
152
  EuropePMCTool(),
153
+ ],
154
+ include_rag=True, # Include RAG tool for semantic search
155
+ auto_ingest_to_rag=True, # Automatically ingest results into RAG
156
+ oauth_token=token # Optional HuggingFace token for RAG LLM
157
  )
158
+
159
+ # Execute search
160
+ result = await search_handler.execute("query", max_results_per_tool=10)
161
  ```
162
 
163
  ## See Also
docs/architecture/workflow-diagrams.md CHANGED
@@ -627,23 +627,10 @@ gantt
627
  ## Implementation Highlights
628
 
629
  **Simple 4-Agent Setup:**
630
- ```python
631
- workflow = (
632
- MagenticBuilder()
633
- .participants(
634
- hypothesis=HypothesisAgent(tools=[background_tool]),
635
- search=SearchAgent(tools=[web_search, rag_tool]),
636
- analysis=AnalysisAgent(tools=[code_execution]),
637
- report=ReportAgent(tools=[code_execution, visualization])
638
- )
639
- .with_standard_manager(
640
- chat_client=AnthropicClient(model="claude-sonnet-4"),
641
- max_round_count=15, # Prevent infinite loops
642
- max_stall_count=3 # Detect stuck workflows
643
- )
644
- .build()
645
- )
646
- ```
647
 
648
  **Manager handles quality assessment in its instructions:**
649
  - Checks hypothesis quality (testable, novel, clear)
 
627
  ## Implementation Highlights
628
 
629
  **Simple 4-Agent Setup:**
630
+
631
+ <!--codeinclude-->
632
+ [Magentic Workflow Builder](../src/orchestrator_magentic.py) start_line:72 end_line:99
633
+ <!--/codeinclude-->
 
 
 
 
 
 
 
 
 
 
 
 
 
634
 
635
  **Manager handles quality assessment in its instructions:**
636
  - Checks hypothesis quality (testable, novel, clear)
docs/configuration/CONFIGURATION.md DELETED
@@ -1,557 +0,0 @@
1
- # Configuration Guide
2
-
3
- ## Overview
4
-
5
- DeepCritical uses **Pydantic Settings** for centralized configuration management. All settings are defined in the `Settings` class in `src/utils/config.py` and can be configured via environment variables or a `.env` file.
6
-
7
- The configuration system provides:
8
-
9
- - **Type Safety**: Strongly-typed fields with Pydantic validation
10
- - **Environment File Support**: Automatically loads from `.env` file (if present)
11
- - **Case-Insensitive**: Environment variables are case-insensitive
12
- - **Singleton Pattern**: Global `settings` instance for easy access throughout the codebase
13
- - **Validation**: Automatic validation on load with helpful error messages
14
-
15
- ## Quick Start
16
-
17
- 1. Create a `.env` file in the project root
18
- 2. Set at least one LLM API key (`OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, or `HF_TOKEN`)
19
- 3. Optionally configure other services as needed
20
- 4. The application will automatically load and validate your configuration
21
-
22
- ## Configuration System Architecture
23
-
24
- ### Settings Class
25
-
26
- The `Settings` class extends `BaseSettings` from `pydantic_settings` and defines all application configuration:
27
-
28
- <!--codeinclude-->
29
- [Settings Class Definition](../src/utils/config.py) start_line:13 end_line:21
30
- <!--/codeinclude-->
31
-
32
- ### Singleton Instance
33
-
34
- A global `settings` instance is available for import:
35
-
36
- <!--codeinclude-->
37
- [Singleton Instance](../src/utils/config.py) start_line:234 end_line:235
38
- <!--/codeinclude-->
39
-
40
- ### Usage Pattern
41
-
42
- Access configuration throughout the codebase:
43
-
44
- ```python
45
- from src.utils.config import settings
46
-
47
- # Check if API keys are available
48
- if settings.has_openai_key:
49
- # Use OpenAI
50
- pass
51
-
52
- # Access configuration values
53
- max_iterations = settings.max_iterations
54
- web_search_provider = settings.web_search_provider
55
- ```
56
-
57
- ## Required Configuration
58
-
59
- ### LLM Provider
60
-
61
- You must configure at least one LLM provider. The system supports:
62
-
63
- - **OpenAI**: Requires `OPENAI_API_KEY`
64
- - **Anthropic**: Requires `ANTHROPIC_API_KEY`
65
- - **HuggingFace**: Optional `HF_TOKEN` or `HUGGINGFACE_API_KEY` (can work without key for public models)
66
-
67
- #### OpenAI Configuration
68
-
69
- ```bash
70
- LLM_PROVIDER=openai
71
- OPENAI_API_KEY=your_openai_api_key_here
72
- OPENAI_MODEL=gpt-5.1
73
- ```
74
-
75
- The default model is defined in the `Settings` class:
76
-
77
- <!--codeinclude-->
78
- [OpenAI Model Configuration](../src/utils/config.py) start_line:29 end_line:29
79
- <!--/codeinclude-->
80
-
81
- #### Anthropic Configuration
82
-
83
- ```bash
84
- LLM_PROVIDER=anthropic
85
- ANTHROPIC_API_KEY=your_anthropic_api_key_here
86
- ANTHROPIC_MODEL=claude-sonnet-4-5-20250929
87
- ```
88
-
89
- The default model is defined in the `Settings` class:
90
-
91
- <!--codeinclude-->
92
- [Anthropic Model Configuration](../src/utils/config.py) start_line:30 end_line:32
93
- <!--/codeinclude-->
94
-
95
- #### HuggingFace Configuration
96
-
97
- HuggingFace can work without an API key for public models, but an API key provides higher rate limits:
98
-
99
- ```bash
100
- # Option 1: Using HF_TOKEN (preferred)
101
- HF_TOKEN=your_huggingface_token_here
102
-
103
- # Option 2: Using HUGGINGFACE_API_KEY (alternative)
104
- HUGGINGFACE_API_KEY=your_huggingface_api_key_here
105
-
106
- # Default model
107
- HUGGINGFACE_MODEL=meta-llama/Llama-3.1-8B-Instruct
108
- ```
109
-
110
- The HuggingFace token can be set via either environment variable:
111
-
112
- <!--codeinclude-->
113
- [HuggingFace Token Configuration](../src/utils/config.py) start_line:33 end_line:35
114
- <!--/codeinclude-->
115
-
116
- <!--codeinclude-->
117
- [HuggingFace API Key Configuration](../src/utils/config.py) start_line:57 end_line:59
118
- <!--/codeinclude-->
119
-
120
- ## Optional Configuration
121
-
122
- ### Embedding Configuration
123
-
124
- DeepCritical supports multiple embedding providers for semantic search and RAG:
125
-
126
- ```bash
127
- # Embedding Provider: "openai", "local", or "huggingface"
128
- EMBEDDING_PROVIDER=local
129
-
130
- # OpenAI Embedding Model (used by LlamaIndex RAG)
131
- OPENAI_EMBEDDING_MODEL=text-embedding-3-small
132
-
133
- # Local Embedding Model (sentence-transformers, used by EmbeddingService)
134
- LOCAL_EMBEDDING_MODEL=all-MiniLM-L6-v2
135
-
136
- # HuggingFace Embedding Model
137
- HUGGINGFACE_EMBEDDING_MODEL=sentence-transformers/all-MiniLM-L6-v2
138
- ```
139
-
140
- The embedding provider configuration:
141
-
142
- <!--codeinclude-->
143
- [Embedding Provider Configuration](../src/utils/config.py) start_line:47 end_line:50
144
- <!--/codeinclude-->
145
-
146
- **Note**: OpenAI embeddings require `OPENAI_API_KEY`. The local provider (default) uses sentence-transformers and requires no API key.
147
-
148
- ### Web Search Configuration
149
-
150
- DeepCritical supports multiple web search providers:
151
-
152
- ```bash
153
- # Web Search Provider: "serper", "searchxng", "brave", "tavily", or "duckduckgo"
154
- # Default: "duckduckgo" (no API key required)
155
- WEB_SEARCH_PROVIDER=duckduckgo
156
-
157
- # Serper API Key (for Google search via Serper)
158
- SERPER_API_KEY=your_serper_api_key_here
159
-
160
- # SearchXNG Host URL (for self-hosted search)
161
- SEARCHXNG_HOST=http://localhost:8080
162
-
163
- # Brave Search API Key
164
- BRAVE_API_KEY=your_brave_api_key_here
165
-
166
- # Tavily API Key
167
- TAVILY_API_KEY=your_tavily_api_key_here
168
- ```
169
-
170
- The web search provider configuration:
171
-
172
- <!--codeinclude-->
173
- [Web Search Provider Configuration](../src/utils/config.py) start_line:71 end_line:74
174
- <!--/codeinclude-->
175
-
176
- **Note**: DuckDuckGo is the default and requires no API key, making it ideal for development and testing.
177
-
178
- ### PubMed Configuration
179
-
180
- PubMed search supports optional NCBI API key for higher rate limits:
181
-
182
- ```bash
183
- # NCBI API Key (optional, for higher rate limits: 10 req/sec vs 3 req/sec)
184
- NCBI_API_KEY=your_ncbi_api_key_here
185
- ```
186
-
187
- The PubMed tool uses this configuration:
188
-
189
- <!--codeinclude-->
190
- [PubMed Tool Configuration](../src/tools/pubmed.py) start_line:22 end_line:29
191
- <!--/codeinclude-->
192
-
193
- ### Agent Configuration
194
-
195
- Control agent behavior and research loop execution:
196
-
197
- ```bash
198
- # Maximum iterations per research loop (1-50, default: 10)
199
- MAX_ITERATIONS=10
200
-
201
- # Search timeout in seconds
202
- SEARCH_TIMEOUT=30
203
-
204
- # Use graph-based execution for research flows
205
- USE_GRAPH_EXECUTION=false
206
- ```
207
-
208
- The agent configuration fields:
209
-
210
- <!--codeinclude-->
211
- [Agent Configuration](../src/utils/config.py) start_line:80 end_line:85
212
- <!--/codeinclude-->
213
-
214
- ### Budget & Rate Limiting Configuration
215
-
216
- Control resource limits for research loops:
217
-
218
- ```bash
219
- # Default token budget per research loop (1000-1000000, default: 100000)
220
- DEFAULT_TOKEN_LIMIT=100000
221
-
222
- # Default time limit per research loop in minutes (1-120, default: 10)
223
- DEFAULT_TIME_LIMIT_MINUTES=10
224
-
225
- # Default iterations limit per research loop (1-50, default: 10)
226
- DEFAULT_ITERATIONS_LIMIT=10
227
- ```
228
-
229
- The budget configuration with validation:
230
-
231
- <!--codeinclude-->
232
- [Budget Configuration](../src/utils/config.py) start_line:87 end_line:105
233
- <!--/codeinclude-->
234
-
235
- ### RAG Service Configuration
236
-
237
- Configure the Retrieval-Augmented Generation service:
238
-
239
- ```bash
240
- # ChromaDB collection name for RAG
241
- RAG_COLLECTION_NAME=deepcritical_evidence
242
-
243
- # Number of top results to retrieve from RAG (1-50, default: 5)
244
- RAG_SIMILARITY_TOP_K=5
245
-
246
- # Automatically ingest evidence into RAG
247
- RAG_AUTO_INGEST=true
248
- ```
249
-
250
- The RAG configuration:
251
-
252
- <!--codeinclude-->
253
- [RAG Service Configuration](../src/utils/config.py) start_line:127 end_line:141
254
- <!--/codeinclude-->
255
-
256
- ### ChromaDB Configuration
257
-
258
- Configure the vector database for embeddings and RAG:
259
-
260
- ```bash
261
- # ChromaDB storage path
262
- CHROMA_DB_PATH=./chroma_db
263
-
264
- # Whether to persist ChromaDB to disk
265
- CHROMA_DB_PERSIST=true
266
-
267
- # ChromaDB server host (for remote ChromaDB, optional)
268
- CHROMA_DB_HOST=localhost
269
-
270
- # ChromaDB server port (for remote ChromaDB, optional)
271
- CHROMA_DB_PORT=8000
272
- ```
273
-
274
- The ChromaDB configuration:
275
-
276
- <!--codeinclude-->
277
- [ChromaDB Configuration](../src/utils/config.py) start_line:113 end_line:125
278
- <!--/codeinclude-->
279
-
280
- ### External Services
281
-
282
- #### Modal Configuration
283
-
284
- Modal is used for secure sandbox execution of statistical analysis:
285
-
286
- ```bash
287
- # Modal Token ID (for Modal sandbox execution)
288
- MODAL_TOKEN_ID=your_modal_token_id_here
289
-
290
- # Modal Token Secret
291
- MODAL_TOKEN_SECRET=your_modal_token_secret_here
292
- ```
293
-
294
- The Modal configuration:
295
-
296
- <!--codeinclude-->
297
- [Modal Configuration](../src/utils/config.py) start_line:110 end_line:112
298
- <!--/codeinclude-->
299
-
300
- ### Logging Configuration
301
-
302
- Configure structured logging:
303
-
304
- ```bash
305
- # Log Level: "DEBUG", "INFO", "WARNING", or "ERROR"
306
- LOG_LEVEL=INFO
307
- ```
308
-
309
- The logging configuration:
310
-
311
- <!--codeinclude-->
312
- [Logging Configuration](../src/utils/config.py) start_line:107 end_line:108
313
- <!--/codeinclude-->
314
-
315
- Logging is configured via the `configure_logging()` function:
316
-
317
- <!--codeinclude-->
318
- [Configure Logging Function](../src/utils/config.py) start_line:212 end_line:231
319
- <!--/codeinclude-->
320
-
321
- ## Configuration Properties
322
-
323
- The `Settings` class provides helpful properties for checking configuration state:
324
-
325
- ### API Key Availability
326
-
327
- Check which API keys are available:
328
-
329
- <!--codeinclude-->
330
- [API Key Availability Properties](../src/utils/config.py) start_line:171 end_line:189
331
- <!--/codeinclude-->
332
-
333
- **Usage:**
334
-
335
- ```python
336
- from src.utils.config import settings
337
-
338
- # Check API key availability
339
- if settings.has_openai_key:
340
- # Use OpenAI
341
- pass
342
-
343
- if settings.has_anthropic_key:
344
- # Use Anthropic
345
- pass
346
-
347
- if settings.has_huggingface_key:
348
- # Use HuggingFace
349
- pass
350
-
351
- if settings.has_any_llm_key:
352
- # At least one LLM is available
353
- pass
354
- ```
355
-
356
- ### Service Availability
357
-
358
- Check if external services are configured:
359
-
360
- <!--codeinclude-->
361
- [Modal Availability Property](../src/utils/config.py) start_line:143 end_line:146
362
- <!--/codeinclude-->
363
-
364
- <!--codeinclude-->
365
- [Web Search Availability Property](../src/utils/config.py) start_line:191 end_line:204
366
- <!--/codeinclude-->
367
-
368
- **Usage:**
369
-
370
- ```python
371
- from src.utils.config import settings
372
-
373
- # Check service availability
374
- if settings.modal_available:
375
- # Use Modal sandbox
376
- pass
377
-
378
- if settings.web_search_available:
379
- # Web search is configured
380
- pass
381
- ```
382
-
383
- ### API Key Retrieval
384
-
385
- Get the API key for the configured provider:
386
-
387
- <!--codeinclude-->
388
- [Get API Key Method](../src/utils/config.py) start_line:148 end_line:160
389
- <!--/codeinclude-->
390
-
391
- For OpenAI-specific operations (e.g., Magentic mode):
392
-
393
- <!--codeinclude-->
394
- [Get OpenAI API Key Method](../src/utils/config.py) start_line:162 end_line:169
395
- <!--/codeinclude-->
396
-
397
- ## Configuration Usage in Codebase
398
-
399
- The configuration system is used throughout the codebase:
400
-
401
- ### LLM Factory
402
-
403
- The LLM factory uses settings to create appropriate models:
404
-
405
- <!--codeinclude-->
406
- [LLM Factory Usage](../src/utils/llm_factory.py) start_line:129 end_line:144
407
- <!--/codeinclude-->
408
-
409
- ### Embedding Service
410
-
411
- The embedding service uses local embedding model configuration:
412
-
413
- <!--codeinclude-->
414
- [Embedding Service Usage](../src/services/embeddings.py) start_line:29 end_line:31
415
- <!--/codeinclude-->
416
-
417
- ### Orchestrator Factory
418
-
419
- The orchestrator factory uses settings to determine mode:
420
-
421
- <!--codeinclude-->
422
- [Orchestrator Factory Mode Detection](../src/orchestrator_factory.py) start_line:97 end_line:110
423
- <!--/codeinclude-->
424
-
425
- ## Environment Variables Reference
426
-
427
- ### Required (at least one LLM)
428
-
429
- - `OPENAI_API_KEY` - OpenAI API key (required for OpenAI provider)
430
- - `ANTHROPIC_API_KEY` - Anthropic API key (required for Anthropic provider)
431
- - `HF_TOKEN` or `HUGGINGFACE_API_KEY` - HuggingFace API token (optional, can work without for public models)
432
-
433
- #### LLM Configuration Variables
434
-
435
- - `LLM_PROVIDER` - Provider to use: `"openai"`, `"anthropic"`, or `"huggingface"` (default: `"huggingface"`)
436
- - `OPENAI_MODEL` - OpenAI model name (default: `"gpt-5.1"`)
437
- - `ANTHROPIC_MODEL` - Anthropic model name (default: `"claude-sonnet-4-5-20250929"`)
438
- - `HUGGINGFACE_MODEL` - HuggingFace model ID (default: `"meta-llama/Llama-3.1-8B-Instruct"`)
439
-
440
- #### Embedding Configuration Variables
441
-
442
- - `EMBEDDING_PROVIDER` - Provider: `"openai"`, `"local"`, or `"huggingface"` (default: `"local"`)
443
- - `OPENAI_EMBEDDING_MODEL` - OpenAI embedding model (default: `"text-embedding-3-small"`)
444
- - `LOCAL_EMBEDDING_MODEL` - Local sentence-transformers model (default: `"all-MiniLM-L6-v2"`)
445
- - `HUGGINGFACE_EMBEDDING_MODEL` - HuggingFace embedding model (default: `"sentence-transformers/all-MiniLM-L6-v2"`)
446
-
447
- #### Web Search Configuration Variables
448
-
449
- - `WEB_SEARCH_PROVIDER` - Provider: `"serper"`, `"searchxng"`, `"brave"`, `"tavily"`, or `"duckduckgo"` (default: `"duckduckgo"`)
450
- - `SERPER_API_KEY` - Serper API key (required for Serper provider)
451
- - `SEARCHXNG_HOST` - SearchXNG host URL (required for SearchXNG provider)
452
- - `BRAVE_API_KEY` - Brave Search API key (required for Brave provider)
453
- - `TAVILY_API_KEY` - Tavily API key (required for Tavily provider)
454
-
455
- #### PubMed Configuration Variables
456
-
457
- - `NCBI_API_KEY` - NCBI API key (optional, increases rate limit from 3 to 10 req/sec)
458
-
459
- #### Agent Configuration Variables
460
-
461
- - `MAX_ITERATIONS` - Maximum iterations per research loop (1-50, default: `10`)
462
- - `SEARCH_TIMEOUT` - Search timeout in seconds (default: `30`)
463
- - `USE_GRAPH_EXECUTION` - Use graph-based execution (default: `false`)
464
-
465
- #### Budget Configuration Variables
466
-
467
- - `DEFAULT_TOKEN_LIMIT` - Default token budget per research loop (1000-1000000, default: `100000`)
468
- - `DEFAULT_TIME_LIMIT_MINUTES` - Default time limit in minutes (1-120, default: `10`)
469
- - `DEFAULT_ITERATIONS_LIMIT` - Default iterations limit (1-50, default: `10`)
470
-
471
- #### RAG Configuration Variables
472
-
473
- - `RAG_COLLECTION_NAME` - ChromaDB collection name (default: `"deepcritical_evidence"`)
474
- - `RAG_SIMILARITY_TOP_K` - Number of top results to retrieve (1-50, default: `5`)
475
- - `RAG_AUTO_INGEST` - Automatically ingest evidence into RAG (default: `true`)
476
-
477
- #### ChromaDB Configuration Variables
478
-
479
- - `CHROMA_DB_PATH` - ChromaDB storage path (default: `"./chroma_db"`)
480
- - `CHROMA_DB_PERSIST` - Whether to persist ChromaDB to disk (default: `true`)
481
- - `CHROMA_DB_HOST` - ChromaDB server host (optional, for remote ChromaDB)
482
- - `CHROMA_DB_PORT` - ChromaDB server port (optional, for remote ChromaDB)
483
-
484
- #### External Services Variables
485
-
486
- - `MODAL_TOKEN_ID` - Modal token ID (optional, for Modal sandbox execution)
487
- - `MODAL_TOKEN_SECRET` - Modal token secret (optional, for Modal sandbox execution)
488
-
489
- #### Logging Configuration Variables
490
-
491
- - `LOG_LEVEL` - Log level: `"DEBUG"`, `"INFO"`, `"WARNING"`, or `"ERROR"` (default: `"INFO"`)
492
-
493
- ## Validation
494
-
495
- Settings are validated on load using Pydantic validation:
496
-
497
- - **Type Checking**: All fields are strongly typed
498
- - **Range Validation**: Numeric fields have min/max constraints (e.g., `ge=1, le=50` for `max_iterations`)
499
- - **Literal Validation**: Enum fields only accept specific values (e.g., `Literal["openai", "anthropic", "huggingface"]`)
500
- - **Required Fields**: API keys are checked when accessed via `get_api_key()` or `get_openai_api_key()`
501
-
502
- ### Validation Examples
503
-
504
- The `max_iterations` field has range validation:
505
-
506
- <!--codeinclude-->
507
- [Max Iterations Validation](../src/utils/config.py) start_line:81 end_line:81
508
- <!--/codeinclude-->
509
-
510
- The `llm_provider` field has literal validation:
511
-
512
- <!--codeinclude-->
513
- [LLM Provider Literal Validation](../src/utils/config.py) start_line:26 end_line:28
514
- <!--/codeinclude-->
515
-
516
- ## Error Handling
517
-
518
- Configuration errors raise `ConfigurationError` from `src/utils/exceptions.py`:
519
-
520
- <!--codeinclude-->
521
- [ConfigurationError Class](../src/utils/exceptions.py) start_line:22 end_line:25
522
- <!--/codeinclude-->
523
-
524
- ### Error Handling Example
525
-
526
- ```python
527
- from src.utils.config import settings
528
- from src.utils.exceptions import ConfigurationError
529
-
530
- try:
531
- api_key = settings.get_api_key()
532
- except ConfigurationError as e:
533
- print(f"Configuration error: {e}")
534
- ```
535
-
536
- ### Common Configuration Errors
537
-
538
- 1. **Missing API Key**: When `get_api_key()` is called but the required API key is not set
539
- 2. **Invalid Provider**: When `llm_provider` is set to an unsupported value
540
- 3. **Out of Range**: When numeric values exceed their min/max constraints
541
- 4. **Invalid Literal**: When enum fields receive unsupported values
542
-
543
- ## Configuration Best Practices
544
-
545
- 1. **Use `.env` File**: Store sensitive keys in `.env` file (add to `.gitignore`)
546
- 2. **Check Availability**: Use properties like `has_openai_key` before accessing API keys
547
- 3. **Handle Errors**: Always catch `ConfigurationError` when calling `get_api_key()`
548
- 4. **Validate Early**: Configuration is validated on import, so errors surface immediately
549
- 5. **Use Defaults**: Leverage sensible defaults for optional configuration
550
-
551
- ## Future Enhancements
552
-
553
- The following configurations are planned for future phases:
554
-
555
- 1. **Additional LLM Providers**: DeepSeek, OpenRouter, Gemini, Perplexity, Azure OpenAI, Local models
556
- 2. **Model Selection**: Reasoning/main/fast model configuration
557
- 3. **Service Integration**: Additional service integrations and configurations
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
docs/contributing/code-quality.md CHANGED
@@ -1,6 +1,6 @@
1
  # Code Quality & Documentation
2
 
3
- This document outlines code quality standards and documentation requirements.
4
 
5
  ## Linting
6
 
@@ -12,6 +12,9 @@ This document outlines code quality standards and documentation requirements.
12
  - `PLR2004`: Magic values (statistical constants)
13
  - `PLW0603`: Global statement (singleton pattern)
14
  - `PLC0415`: Lazy imports for optional dependencies
 
 
 
15
 
16
  ## Type Checking
17
 
@@ -22,12 +25,75 @@ This document outlines code quality standards and documentation requirements.
22
 
23
  ## Pre-commit
24
 
25
- - Run `make check` before committing
26
- - Must pass: lint + typecheck + test-cov
27
- - Pre-commit hooks installed via `make install`
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
 
29
  ## Documentation
30
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
  ### Docstrings
32
 
33
  - Google-style docstrings for all public functions
 
1
  # Code Quality & Documentation
2
 
3
+ This document outlines code quality standards and documentation requirements for The DETERMINATOR.
4
 
5
  ## Linting
6
 
 
12
  - `PLR2004`: Magic values (statistical constants)
13
  - `PLW0603`: Global statement (singleton pattern)
14
  - `PLC0415`: Lazy imports for optional dependencies
15
+ - `E402`: Module level import not at top (needed for pytest.importorskip)
16
+ - `E501`: Line too long (ignore line length violations)
17
+ - `RUF100`: Unused noqa (version differences between local/CI)
18
 
19
  ## Type Checking
20
 
 
25
 
26
  ## Pre-commit
27
 
28
+ Pre-commit hooks run automatically on commit to ensure code quality. Configuration is in `.pre-commit-config.yaml`.
29
+
30
+ ### Installation
31
+
32
+ ```bash
33
+ # Install dependencies (includes pre-commit package)
34
+ uv sync --all-extras
35
+
36
+ # Set up git hooks (must be run separately)
37
+ uv run pre-commit install
38
+ ```
39
+
40
+ **Note**: `uv sync --all-extras` installs the pre-commit package, but you must run `uv run pre-commit install` separately to set up the git hooks.
41
+
42
+ ### Pre-commit Hooks
43
+
44
+ The following hooks run automatically on commit:
45
+
46
+ 1. **ruff**: Lints code and fixes issues automatically
47
+ - Runs on: `src/` (excludes `tests/`, `reference_repos/`)
48
+ - Auto-fixes: Yes
49
+
50
+ 2. **ruff-format**: Formats code with ruff
51
+ - Runs on: `src/` (excludes `tests/`, `reference_repos/`)
52
+ - Auto-fixes: Yes
53
+
54
+ 3. **mypy**: Type checking
55
+ - Runs on: `src/` (excludes `folder/`)
56
+ - Additional dependencies: pydantic, pydantic-settings, tenacity, pydantic-ai
57
+
58
+ 4. **pytest-unit**: Runs unit tests (excludes OpenAI and embedding_provider tests)
59
+ - Runs: `tests/unit/` with `-m "not openai and not embedding_provider"`
60
+ - Always runs: Yes (not just on changed files)
61
+
62
+ 5. **pytest-local-embeddings**: Runs local embedding tests
63
+ - Runs: `tests/` with `-m "local_embeddings"`
64
+ - Always runs: Yes
65
+
66
+ ### Manual Pre-commit Run
67
+
68
+ To run pre-commit hooks manually (without committing):
69
+
70
+ ```bash
71
+ uv run pre-commit run --all-files
72
+ ```
73
+
74
+ ### Troubleshooting
75
+
76
+ - **Hooks failing**: Fix the issues shown in the output, then commit again
77
+ - **Skipping hooks**: Use `git commit --no-verify` (not recommended)
78
+ - **Hook not running**: Ensure hooks are installed with `uv run pre-commit install`
79
+ - **Type errors**: Check that all dependencies are installed with `uv sync --all-extras`
80
 
81
  ## Documentation
82
 
83
+ ### Building Documentation
84
+
85
+ Documentation is built using MkDocs. Source files are in `docs/`, and the configuration is in `mkdocs.yml`.
86
+
87
+ ```bash
88
+ # Build documentation
89
+ uv run mkdocs build
90
+
91
+ # Serve documentation locally (http://127.0.0.1:8000)
92
+ uv run mkdocs serve
93
+ ```
94
+
95
+ The documentation site is published at: <https://deepcritical.github.io/GradioDemo/>
96
+
97
  ### Docstrings
98
 
99
  - Google-style docstrings for all public functions
docs/contributing/code-style.md CHANGED
@@ -1,6 +1,44 @@
1
  # Code Style & Conventions
2
 
3
- This document outlines the code style and conventions for DeepCritical.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4
 
5
  ## Type Safety
6
 
 
1
  # Code Style & Conventions
2
 
3
+ This document outlines the code style and conventions for The DETERMINATOR.
4
+
5
+ ## Package Manager
6
+
7
+ This project uses [`uv`](https://github.com/astral-sh/uv) as the package manager. All commands should be prefixed with `uv run` to ensure they run in the correct environment.
8
+
9
+ ### Installation
10
+
11
+ ```bash
12
+ # Install uv if you haven't already (recommended: standalone installer)
13
+ # Unix/macOS/Linux:
14
+ curl -LsSf https://astral.sh/uv/install.sh | sh
15
+
16
+ # Windows (PowerShell):
17
+ powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
18
+
19
+ # Alternative: pipx install uv
20
+ # Or: pip install uv
21
+
22
+ # Sync all dependencies including dev extras
23
+ uv sync --all-extras
24
+ ```
25
+
26
+ ### Running Commands
27
+
28
+ All development commands should use `uv run` prefix:
29
+
30
+ ```bash
31
+ # Instead of: pytest tests/
32
+ uv run pytest tests/
33
+
34
+ # Instead of: ruff check src
35
+ uv run ruff check src
36
+
37
+ # Instead of: mypy src
38
+ uv run mypy src
39
+ ```
40
+
41
+ This ensures commands run in the correct virtual environment managed by `uv`.
42
 
43
  ## Type Safety
44
 
docs/contributing/error-handling.md CHANGED
@@ -1,6 +1,6 @@
1
  # Error Handling & Logging
2
 
3
- This document outlines error handling and logging conventions for DeepCritical.
4
 
5
  ## Exception Hierarchy
6
 
 
1
  # Error Handling & Logging
2
 
3
+ This document outlines error handling and logging conventions for The DETERMINATOR.
4
 
5
  ## Exception Hierarchy
6
 
docs/contributing/implementation-patterns.md CHANGED
@@ -1,6 +1,6 @@
1
  # Implementation Patterns
2
 
3
- This document outlines common implementation patterns used in DeepCritical.
4
 
5
  ## Search Tools
6
 
 
1
  # Implementation Patterns
2
 
3
+ This document outlines common implementation patterns used in The DETERMINATOR.
4
 
5
  ## Search Tools
6
 
docs/contributing/index.md CHANGED
@@ -1,6 +1,8 @@
1
- # Contributing to DeepCritical
2
 
3
- Thank you for your interest in contributing to DeepCritical! This guide will help you get started.
 
 
4
 
5
  ## Git Workflow
6
 
@@ -10,44 +12,138 @@ Thank you for your interest in contributing to DeepCritical! This guide will hel
10
  - **NEVER** push directly to `main` or `dev` on HuggingFace
11
  - GitHub is source of truth; HuggingFace is for deployment
12
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
  ## Development Commands
14
 
15
  ```bash
16
- make install # Install dependencies + pre-commit
17
- make check # Lint + typecheck + test (MUST PASS)
18
- make test # Run unit tests
19
- make lint # Run ruff
20
- make format # Format with ruff
21
- make typecheck # Run mypy
22
- make test-cov # Test with coverage
 
 
 
 
 
 
 
 
 
 
 
 
 
23
  ```
24
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
  ## Getting Started
26
 
27
- 1. **Fork the repository** on GitHub
 
28
  2. **Clone your fork**:
 
29
  ```bash
30
  git clone https://github.com/yourusername/GradioDemo.git
31
  cd GradioDemo
32
  ```
 
33
  3. **Install dependencies**:
 
34
  ```bash
35
- make install
 
36
  ```
 
37
  4. **Create a feature branch**:
 
38
  ```bash
39
  git checkout -b yourname-feature-name
40
  ```
 
41
  5. **Make your changes** following the guidelines below
 
42
  6. **Run checks**:
 
43
  ```bash
44
- make check
 
 
45
  ```
 
46
  7. **Commit and push**:
 
47
  ```bash
48
  git commit -m "Description of changes"
49
  git push origin yourname-feature-name
50
  ```
 
51
  8. **Create a pull request** on GitHub
52
 
53
  ## Development Guidelines
@@ -132,7 +228,7 @@ make test-cov # Test with coverage
132
 
133
  ## Pull Request Process
134
 
135
- 1. Ensure all checks pass: `make check`
136
  2. Update documentation if needed
137
  3. Add tests for new features
138
  4. Update CHANGELOG if applicable
@@ -140,10 +236,19 @@ make test-cov # Test with coverage
140
  6. Address review feedback
141
  7. Wait for approval before merging
142
 
 
 
 
 
 
 
 
 
 
143
  ## Questions?
144
 
145
- - Open an issue on GitHub
146
- - Check existing documentation
147
  - Review code examples in the codebase
148
 
149
- Thank you for contributing to DeepCritical!
 
1
+ # Contributing to The DETERMINATOR
2
 
3
+ Thank you for your interest in contributing to The DETERMINATOR! This guide will help you get started.
4
+
5
+ > **Note on Project Names**: "The DETERMINATOR" is the product name, "DeepCritical" is the organization/project name, and "determinator" is the Python package name.
6
 
7
  ## Git Workflow
8
 
 
12
  - **NEVER** push directly to `main` or `dev` on HuggingFace
13
  - GitHub is source of truth; HuggingFace is for deployment
14
 
15
+ ## Repository Information
16
+
17
+ - **GitHub Repository**: [`DeepCritical/GradioDemo`](https://github.com/DeepCritical/GradioDemo) (source of truth, PRs, code review)
18
+ - **HuggingFace Space**: [`DataQuests/DeepCritical`](https://huggingface.co/spaces/DataQuests/DeepCritical) (deployment/demo)
19
+ - **Package Name**: `determinator` (Python package name in `pyproject.toml`)
20
+
21
+ ### Dual Repository Setup
22
+
23
+ This project uses a dual repository setup:
24
+
25
+ - **GitHub (`DeepCritical/GradioDemo`)**: Source of truth for code, PRs, and code review
26
+ - **HuggingFace (`DataQuests/DeepCritical`)**: Deployment target for the Gradio demo
27
+
28
+ #### Remote Configuration
29
+
30
+ When cloning, set up remotes as follows:
31
+
32
+ ```bash
33
+ # Clone from GitHub
34
+ git clone https://github.com/DeepCritical/GradioDemo.git
35
+ cd GradioDemo
36
+
37
+ # Add HuggingFace remote (optional, for deployment)
38
+ git remote add huggingface-upstream https://huggingface.co/spaces/DataQuests/DeepCritical
39
+ ```
40
+
41
+ **Important**: Never push directly to `main` or `dev` on HuggingFace. Always work through GitHub PRs. GitHub is the source of truth; HuggingFace is for deployment/demo only.
42
+
43
+ ## Package Manager
44
+
45
+ This project uses [`uv`](https://github.com/astral-sh/uv) as the package manager. All commands should be prefixed with `uv run` to ensure they run in the correct environment.
46
+
47
+ ### Installation
48
+
49
+ ```bash
50
+ # Install uv if you haven't already (recommended: standalone installer)
51
+ # Unix/macOS/Linux:
52
+ curl -LsSf https://astral.sh/uv/install.sh | sh
53
+
54
+ # Windows (PowerShell):
55
+ powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
56
+
57
+ # Alternative: pipx install uv
58
+ # Or: pip install uv
59
+
60
+ # Sync all dependencies including dev extras
61
+ uv sync --all-extras
62
+
63
+ # Install pre-commit hooks
64
+ uv run pre-commit install
65
+ ```
66
+
67
  ## Development Commands
68
 
69
  ```bash
70
+ # Installation
71
+ uv sync --all-extras # Install all dependencies including dev
72
+ uv run pre-commit install # Install pre-commit hooks
73
+
74
+ # Code Quality Checks (run all before committing)
75
+ uv run ruff check src tests # Lint with ruff
76
+ uv run ruff format src tests # Format with ruff
77
+ uv run mypy src # Type checking
78
+ uv run pytest --cov=src --cov-report=term-missing tests/unit/ -v -m "not openai" -p no:logfire # Tests with coverage
79
+
80
+ # Testing Commands
81
+ uv run pytest tests/unit/ -v -m "not openai" -p no:logfire # Run unit tests (excludes OpenAI tests)
82
+ uv run pytest tests/ -v -m "huggingface" -p no:logfire # Run HuggingFace tests
83
+ uv run pytest tests/ -v -p no:logfire # Run all tests
84
+ uv run pytest --cov=src --cov-report=term-missing tests/unit/ -v -m "not openai" -p no:logfire # Tests with terminal coverage
85
+ uv run pytest --cov=src --cov-report=html -p no:logfire # Generate HTML coverage report (opens htmlcov/index.html)
86
+
87
+ # Documentation Commands
88
+ uv run mkdocs build # Build documentation
89
+ uv run mkdocs serve # Serve documentation locally (http://127.0.0.1:8000)
90
  ```
91
 
92
+ ### Test Markers
93
+
94
+ The project uses pytest markers to categorize tests. See [Testing Guidelines](testing.md) for details:
95
+
96
+ - `unit`: Unit tests (mocked, fast)
97
+ - `integration`: Integration tests (real APIs)
98
+ - `slow`: Slow tests
99
+ - `openai`: Tests requiring OpenAI API key
100
+ - `huggingface`: Tests requiring HuggingFace API key
101
+ - `embedding_provider`: Tests requiring API-based embedding providers
102
+ - `local_embeddings`: Tests using local embeddings
103
+
104
+ **Note**: The `-p no:logfire` flag disables the logfire plugin to avoid conflicts during testing.
105
+
106
  ## Getting Started
107
 
108
+ 1. **Fork the repository** on GitHub: [`DeepCritical/GradioDemo`](https://github.com/DeepCritical/GradioDemo)
109
+
110
  2. **Clone your fork**:
111
+
112
  ```bash
113
  git clone https://github.com/yourusername/GradioDemo.git
114
  cd GradioDemo
115
  ```
116
+
117
  3. **Install dependencies**:
118
+
119
  ```bash
120
+ uv sync --all-extras
121
+ uv run pre-commit install
122
  ```
123
+
124
  4. **Create a feature branch**:
125
+
126
  ```bash
127
  git checkout -b yourname-feature-name
128
  ```
129
+
130
  5. **Make your changes** following the guidelines below
131
+
132
  6. **Run checks**:
133
+
134
  ```bash
135
+ uv run ruff check src tests
136
+ uv run mypy src
137
+ uv run pytest --cov=src --cov-report=term-missing tests/unit/ -v -m "not openai" -p no:logfire
138
  ```
139
+
140
  7. **Commit and push**:
141
+
142
  ```bash
143
  git commit -m "Description of changes"
144
  git push origin yourname-feature-name
145
  ```
146
+
147
  8. **Create a pull request** on GitHub
148
 
149
  ## Development Guidelines
 
228
 
229
  ## Pull Request Process
230
 
231
+ 1. Ensure all checks pass: `uv run ruff check src tests && uv run mypy src && uv run pytest --cov=src --cov-report=term-missing tests/unit/ -v -m "not openai" -p no:logfire`
232
  2. Update documentation if needed
233
  3. Add tests for new features
234
  4. Update CHANGELOG if applicable
 
236
  6. Address review feedback
237
  7. Wait for approval before merging
238
 
239
+ ## Project Structure
240
+
241
+ - `src/`: Main source code
242
+ - `tests/`: Test files (`unit/` and `integration/`)
243
+ - `docs/`: Documentation source files (MkDocs)
244
+ - `examples/`: Example usage scripts
245
+ - `pyproject.toml`: Project configuration and dependencies
246
+ - `.pre-commit-config.yaml`: Pre-commit hook configuration
247
+
248
  ## Questions?
249
 
250
+ - Open an issue on [GitHub](https://github.com/DeepCritical/GradioDemo)
251
+ - Check existing [documentation](https://deepcritical.github.io/GradioDemo/)
252
  - Review code examples in the codebase
253
 
254
+ Thank you for contributing to The DETERMINATOR!
docs/contributing/testing.md CHANGED
@@ -1,12 +1,45 @@
1
  # Testing Requirements
2
 
3
- This document outlines testing requirements and guidelines for DeepCritical.
4
 
5
  ## Test Structure
6
 
7
  - Unit tests in `tests/unit/` (mocked, fast)
8
  - Integration tests in `tests/integration/` (real APIs, marked `@pytest.mark.integration`)
9
- - Use markers: `unit`, `integration`, `slow`
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10
 
11
  ## Mocking
12
 
@@ -20,7 +53,20 @@ This document outlines testing requirements and guidelines for DeepCritical.
20
  1. Write failing test in `tests/unit/`
21
  2. Implement in `src/`
22
  3. Ensure test passes
23
- 4. Run `make check` (lint + typecheck + test)
 
 
 
 
 
 
 
 
 
 
 
 
 
24
 
25
  ## Test Examples
26
 
@@ -41,9 +87,27 @@ async def test_real_pubmed_search():
41
 
42
  ## Test Coverage
43
 
44
- - Run `make test-cov` for coverage report
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45
  - Aim for >80% coverage on critical paths
46
  - Exclude: `__init__.py`, `TYPE_CHECKING` blocks
 
47
 
48
  ## See Also
49
 
 
1
  # Testing Requirements
2
 
3
+ This document outlines testing requirements and guidelines for The DETERMINATOR.
4
 
5
  ## Test Structure
6
 
7
  - Unit tests in `tests/unit/` (mocked, fast)
8
  - Integration tests in `tests/integration/` (real APIs, marked `@pytest.mark.integration`)
9
+ - Use markers: `unit`, `integration`, `slow`, `openai`, `huggingface`, `embedding_provider`, `local_embeddings`
10
+
11
+ ## Test Markers
12
+
13
+ The project uses pytest markers to categorize tests. These markers are defined in `pyproject.toml`:
14
+
15
+ - `@pytest.mark.unit`: Unit tests (mocked, fast) - Run with `-m "unit"`
16
+ - `@pytest.mark.integration`: Integration tests (real APIs) - Run with `-m "integration"`
17
+ - `@pytest.mark.slow`: Slow tests - Run with `-m "slow"`
18
+ - `@pytest.mark.openai`: Tests requiring OpenAI API key - Run with `-m "openai"` or exclude with `-m "not openai"`
19
+ - `@pytest.mark.huggingface`: Tests requiring HuggingFace API key or using HuggingFace models - Run with `-m "huggingface"`
20
+ - `@pytest.mark.embedding_provider`: Tests requiring API-based embedding providers (OpenAI, etc.) - Run with `-m "embedding_provider"`
21
+ - `@pytest.mark.local_embeddings`: Tests using local embeddings (sentence-transformers, ChromaDB) - Run with `-m "local_embeddings"`
22
+
23
+ ### Running Tests by Marker
24
+
25
+ ```bash
26
+ # Run only unit tests (excludes OpenAI tests by default)
27
+ uv run pytest tests/unit/ -v -m "not openai" -p no:logfire
28
+
29
+ # Run HuggingFace tests
30
+ uv run pytest tests/ -v -m "huggingface" -p no:logfire
31
+
32
+ # Run all tests
33
+ uv run pytest tests/ -v -p no:logfire
34
+
35
+ # Run only local embedding tests
36
+ uv run pytest tests/ -v -m "local_embeddings" -p no:logfire
37
+
38
+ # Exclude slow tests
39
+ uv run pytest tests/ -v -m "not slow" -p no:logfire
40
+ ```
41
+
42
+ **Note**: The `-p no:logfire` flag disables the logfire plugin to avoid conflicts during testing.
43
 
44
  ## Mocking
45
 
 
53
  1. Write failing test in `tests/unit/`
54
  2. Implement in `src/`
55
  3. Ensure test passes
56
+ 4. Run checks: `uv run ruff check src tests && uv run mypy src && uv run pytest --cov=src --cov-report=term-missing tests/unit/ -v -m "not openai" -p no:logfire`
57
+
58
+ ### Test Command Examples
59
+
60
+ ```bash
61
+ # Run unit tests (default, excludes OpenAI tests)
62
+ uv run pytest tests/unit/ -v -m "not openai" -p no:logfire
63
+
64
+ # Run HuggingFace tests
65
+ uv run pytest tests/ -v -m "huggingface" -p no:logfire
66
+
67
+ # Run all tests
68
+ uv run pytest tests/ -v -p no:logfire
69
+ ```
70
 
71
  ## Test Examples
72
 
 
87
 
88
  ## Test Coverage
89
 
90
+ ### Terminal Coverage Report
91
+
92
+ ```bash
93
+ uv run pytest --cov=src --cov-report=term-missing tests/unit/ -v -m "not openai" -p no:logfire
94
+ ```
95
+
96
+ This shows coverage with missing lines highlighted in the terminal output.
97
+
98
+ ### HTML Coverage Report
99
+
100
+ ```bash
101
+ uv run pytest --cov=src --cov-report=html -p no:logfire
102
+ ```
103
+
104
+ This generates an HTML coverage report in `htmlcov/index.html`. Open this file in your browser to see detailed coverage information.
105
+
106
+ ### Coverage Goals
107
+
108
  - Aim for >80% coverage on critical paths
109
  - Exclude: `__init__.py`, `TYPE_CHECKING` blocks
110
+ - Coverage configuration is in `pyproject.toml` under `[tool.coverage.*]`
111
 
112
  ## See Also
113
 
docs/getting-started/examples.md CHANGED
@@ -25,6 +25,7 @@ What clinical trials are investigating metformin for cancer prevention?
25
  ```
26
 
27
  **What The DETERMINATOR Does**:
 
28
  1. Searches ClinicalTrials.gov for relevant trials
29
  2. Searches PubMed for supporting literature
30
  3. Provides trial details and status
@@ -35,6 +36,7 @@ What clinical trials are investigating metformin for cancer prevention?
35
  ### Example 3: Comprehensive Review
36
 
37
  **Query**:
 
38
  ```
39
  Review the evidence for using metformin as an anti-aging intervention,
40
  including clinical trials, mechanisms of action, and safety profile.
@@ -194,25 +196,3 @@ USE_GRAPH_EXECUTION=true
194
  - Explore the [Architecture Documentation](../architecture/graph_orchestration.md)
195
  - Check out the [API Reference](../api/agents.md) for programmatic usage
196
 
197
-
198
-
199
-
200
-
201
-
202
-
203
-
204
-
205
-
206
-
207
-
208
-
209
-
210
-
211
- <<<<<<< Updated upstream
212
-
213
-
214
-
215
-
216
-
217
- =======
218
- >>>>>>> Stashed changes
 
25
  ```
26
 
27
  **What The DETERMINATOR Does**:
28
+
29
  1. Searches ClinicalTrials.gov for relevant trials
30
  2. Searches PubMed for supporting literature
31
  3. Provides trial details and status
 
36
  ### Example 3: Comprehensive Review
37
 
38
  **Query**:
39
+
40
  ```
41
  Review the evidence for using metformin as an anti-aging intervention,
42
  including clinical trials, mechanisms of action, and safety profile.
 
196
  - Explore the [Architecture Documentation](../architecture/graph_orchestration.md)
197
  - Check out the [API Reference](../api/agents.md) for programmatic usage
198
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
docs/getting-started/installation.md CHANGED
@@ -12,12 +12,29 @@ This guide will help you install and set up DeepCritical on your system.
12
 
13
  ### 1. Install uv (Recommended)
14
 
15
- `uv` is a fast Python package installer and resolver. Install it with:
16
 
 
17
  ```bash
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18
  pip install uv
19
  ```
20
 
 
 
21
  ### 2. Clone the Repository
22
 
23
  ```bash
@@ -133,40 +150,3 @@ uv run pre-commit install
133
  - Learn about [MCP Integration](mcp-integration.md)
134
  - Explore [Examples](examples.md)
135
 
136
-
137
-
138
-
139
-
140
-
141
-
142
-
143
-
144
-
145
-
146
-
147
-
148
-
149
- <<<<<<< HEAD
150
- <<<<<<< Updated upstream
151
- =======
152
- =======
153
- >>>>>>> 8086ce5fefde1c867880661d57e1299029a91ead
154
-
155
- <<<<<<< Updated upstream
156
-
157
-
158
-
159
-
160
-
161
- =======
162
- >>>>>>> Stashed changes
163
-
164
-
165
-
166
-
167
- <<<<<<< HEAD
168
-
169
- >>>>>>> Stashed changes
170
-
171
- =======
172
- >>>>>>> 8086ce5fefde1c867880661d57e1299029a91ead
 
12
 
13
  ### 1. Install uv (Recommended)
14
 
15
+ `uv` is a fast Python package installer and resolver. Install it using the standalone installer (recommended):
16
 
17
+ **Unix/macOS/Linux:**
18
  ```bash
19
+ curl -LsSf https://astral.sh/uv/install.sh | sh
20
+ ```
21
+
22
+ **Windows (PowerShell):**
23
+ ```powershell
24
+ powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
25
+ ```
26
+
27
+ **Alternative methods:**
28
+ ```bash
29
+ # Using pipx (recommended if you have pipx installed)
30
+ pipx install uv
31
+
32
+ # Or using pip
33
  pip install uv
34
  ```
35
 
36
+ After installation, restart your terminal or add `~/.cargo/bin` to your PATH.
37
+
38
  ### 2. Clone the Repository
39
 
40
  ```bash
 
150
  - Learn about [MCP Integration](mcp-integration.md)
151
  - Explore [Examples](examples.md)
152
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
docs/getting-started/mcp-integration.md CHANGED
@@ -201,16 +201,3 @@ You can configure multiple DeepCritical instances:
201
  - Read the [Architecture Documentation](../architecture/graph_orchestration.md)
202
 
203
 
204
-
205
-
206
-
207
-
208
-
209
-
210
-
211
-
212
-
213
-
214
-
215
-
216
-
 
201
  - Read the [Architecture Documentation](../architecture/graph_orchestration.md)
202
 
203
 
 
 
 
 
 
 
 
 
 
 
 
 
 
docs/getting-started/quick-start.md CHANGED
@@ -41,7 +41,7 @@ Get up and running with The DETERMINATOR in minutes.
41
  ## Start the Application
42
 
43
  ```bash
44
- uv run gradio run src/app.py
45
  ```
46
 
47
  Open your browser to `http://localhost:7860`.
@@ -140,25 +140,3 @@ What are the active clinical trials investigating Alzheimer's disease treatments
140
  - Read the [Configuration Guide](../configuration/index.md) for advanced settings
141
  - Check out the [Architecture Documentation](../architecture/graph_orchestration.md) to understand how it works
142
 
143
-
144
-
145
-
146
-
147
-
148
-
149
-
150
-
151
-
152
-
153
-
154
-
155
-
156
-
157
- <<<<<<< Updated upstream
158
-
159
-
160
-
161
-
162
-
163
- =======
164
- >>>>>>> Stashed changes
 
41
  ## Start the Application
42
 
43
  ```bash
44
+ gradio src/app.py
45
  ```
46
 
47
  Open your browser to `http://localhost:7860`.
 
140
  - Read the [Configuration Guide](../configuration/index.md) for advanced settings
141
  - Check out the [Architecture Documentation](../architecture/graph_orchestration.md) to understand how it works
142
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
docs/implementation/IMPLEMENTATION_SUMMARY.md DELETED
@@ -1,188 +0,0 @@
1
- # Multimodal Audio & Image Integration - Implementation Summary
2
-
3
- ## ✅ Completed Implementation
4
-
5
- ### 1. Configuration System (`src/utils/config.py`)
6
- - ✅ Added audio configuration fields:
7
- - `tts_model`, `tts_voice`, `tts_speed`, `tts_gpu`, `tts_timeout`
8
- - `stt_api_url`, `stt_source_lang`, `stt_target_lang`
9
- - `enable_audio_input`, `enable_audio_output`
10
- - ✅ Added image OCR configuration:
11
- - `ocr_api_url`, `enable_image_input`
12
- - ✅ Added property methods: `audio_available`, `image_ocr_available`
13
-
14
- ### 2. STT Service (`src/services/stt_gradio.py`)
15
- - ✅ Gradio Client integration for nvidia/canary-1b-v2
16
- - ✅ Supports file and numpy array audio input
17
- - ✅ Async transcription with error handling
18
- - ✅ Singleton factory pattern
19
-
20
- ### 3. TTS Service (`src/services/tts_modal.py`)
21
- - ✅ **Modal GPU function implementation** following Modal documentation
22
- - ✅ Kokoro 82M integration via Modal GPU
23
- - ✅ Module-level function definition with lazy initialization
24
- - ✅ GPU configuration (T4, A10, A100, L4, L40S)
25
- - ✅ Async wrapper for TTS synthesis
26
- - ✅ Error handling and graceful degradation
27
-
28
- ### 4. Image OCR Service (`src/services/image_ocr.py`)
29
- - ✅ Gradio Client integration for prithivMLmods/Multimodal-OCR3
30
- - ✅ Supports image files and PIL/numpy arrays
31
- - ✅ Text extraction from API results
32
- - ✅ Singleton factory pattern
33
-
34
- ### 5. Unified Services
35
- - ✅ `src/services/audio_processing.py` - Audio service layer
36
- - ✅ `src/services/multimodal_processing.py` - Multimodal service layer
37
-
38
- ### 6. ChatInterface Integration (`src/app.py`)
39
- - ✅ Enabled `multimodal=True` for MultimodalTextbox
40
- - ✅ Added Audio output component
41
- - ✅ Integrated STT/TTS/OCR into research flow
42
- - ✅ Multimodal input processing (text + images + audio)
43
- - ✅ TTS output generation for final responses
44
- - ✅ **Configuration UI in Settings Accordion**:
45
- - Voice dropdown (20+ Kokoro voices)
46
- - Speed slider (0.5x to 2.0x)
47
- - GPU dropdown (T4, A10, A100, L4, L40S) - read-only, requires restart
48
- - Enable audio output checkbox
49
- - ✅ Configuration values passed from UI to TTS service
50
-
51
- ### 7. MCP Integration (`src/mcp_tools.py`)
52
- - ✅ Added `extract_text_from_image` MCP tool
53
- - ✅ Added `transcribe_audio_file` MCP tool
54
- - ✅ Enabled MCP server in app launch
55
-
56
- ### 8. Dependencies (`pyproject.toml`)
57
- - ✅ Added audio dependencies (gradio-client, soundfile, Pillow)
58
- - ✅ Added TTS optional dependencies (torch, transformers)
59
- - ✅ Installed via `uv add --optional`
60
-
61
- ## 🔧 Modal GPU Implementation Details
62
-
63
- ### Function Definition Pattern
64
- The Modal GPU function is defined using Modal's recommended pattern:
65
-
66
- ```python
67
- @app.function(
68
- image=tts_image, # Image with Kokoro dependencies
69
- gpu="T4", # GPU type from settings.tts_gpu
70
- timeout=60, # Timeout from settings.tts_timeout
71
- )
72
- def kokoro_tts_function(text: str, voice: str, speed: float) -> tuple[int, np.ndarray]:
73
- """Modal GPU function for Kokoro TTS."""
74
- from kokoro import KModel, KPipeline
75
- import torch
76
-
77
- model = KModel().to("cuda").eval()
78
- pipeline = KPipeline(lang_code=voice[0])
79
- pack = pipeline.load_voice(voice)
80
-
81
- for _, ps, _ in pipeline(text, voice, speed):
82
- ref_s = pack[len(ps) - 1]
83
- audio = model(ps, ref_s, speed)
84
- return (24000, audio.numpy())
85
- ```
86
-
87
- ### Key Implementation Points
88
- 1. **Module-Level Definition**: Function defined inside `_setup_modal_function()` but attached to app instance
89
- 2. **Lazy Initialization**: Function set up on first use
90
- 3. **GPU Configuration**: Set at function definition time (requires restart to change)
91
- 4. **Runtime Parameters**: Voice and speed can be changed at runtime via UI
92
-
93
- ## 🔗 Configuration Flow
94
-
95
- ### Settings → Implementation
96
- 1. `settings.tts_voice` → Default voice (used if UI not configured)
97
- 2. `settings.tts_speed` → Default speed (used if UI not configured)
98
- 3. `settings.tts_gpu` → GPU type (set at function definition, requires restart)
99
- 4. `settings.tts_timeout` → Timeout (set at function definition)
100
-
101
- ### UI → Implementation
102
- 1. Voice dropdown → `tts_voice` parameter → `AudioService.generate_audio_output()`
103
- 2. Speed slider → `tts_speed` parameter → `AudioService.generate_audio_output()`
104
- 3. GPU dropdown → Informational only (changes require restart)
105
- 4. Enable checkbox → `settings.enable_audio_output` → Controls TTS generation
106
-
107
- ### Implementation → Modal
108
- 1. `TTSService.synthesize_async()` → Calls Modal GPU function
109
- 2. Modal function executes on GPU → Returns audio tuple
110
- 3. Audio tuple → Gradio Audio component → User hears response
111
-
112
- ## 📋 Configuration Points in UI
113
-
114
- ### Settings Accordion Components
115
- Located in `src/app.py` lines 667-712:
116
-
117
- 1. **Voice Dropdown** (`tts_voice_dropdown`)
118
- - 20+ Kokoro voices
119
- - Default: `settings.tts_voice`
120
- - Connected to `research_agent()` function
121
-
122
- 2. **Speed Slider** (`tts_speed_slider`)
123
- - Range: 0.5 to 2.0
124
- - Step: 0.1
125
- - Default: `settings.tts_speed`
126
- - Connected to `research_agent()` function
127
-
128
- 3. **GPU Dropdown** (`tts_gpu_dropdown`)
129
- - Choices: T4, A10, A100, L4, L40S
130
- - Default: `settings.tts_gpu or "T4"`
131
- - Read-only (interactive=False)
132
- - Note: Changes require app restart
133
-
134
- 4. **Enable Audio Output** (`enable_audio_output_checkbox`)
135
- - Default: `settings.enable_audio_output`
136
- - Controls whether TTS is generated
137
-
138
- ## 🎯 Usage Flow
139
-
140
- 1. User opens Settings accordion
141
- 2. Configures TTS voice and speed (optional)
142
- 3. Submits query (text, image, or audio)
143
- 4. Research agent processes query
144
- 5. Final response generated
145
- 6. If audio output enabled:
146
- - `AudioService.generate_audio_output()` called
147
- - Uses UI-configured voice/speed or settings defaults
148
- - Modal GPU function synthesizes audio
149
- - Audio displayed in Audio component
150
-
151
- ## 📝 Notes
152
-
153
- - **GPU Changes**: GPU type is set at Modal function definition time. Changes to `settings.tts_gpu` or UI dropdown require app restart.
154
- - **Voice/Speed Changes**: Can be changed at runtime via UI - no restart required.
155
- - **Graceful Degradation**: If TTS fails, application continues with text-only response.
156
- - **Modal Credentials**: Required for TTS. If not configured, TTS service unavailable (graceful fallback).
157
-
158
- ## ✅ Verification Checklist
159
-
160
- - [x] Modal GPU function correctly defined with `@app.function` decorator
161
- - [x] GPU parameter set from `settings.tts_gpu`
162
- - [x] Timeout parameter set from `settings.tts_timeout`
163
- - [x] Voice parameter passed from UI dropdown
164
- - [x] Speed parameter passed from UI slider
165
- - [x] Configuration UI elements in Settings accordion
166
- - [x] Configuration values connected to implementation
167
- - [x] Dependencies installed via uv
168
- - [x] Error handling and graceful degradation
169
- - [x] MCP tools added for audio/image processing
170
-
171
- ## 🚀 Next Steps
172
-
173
- 1. Test TTS with Modal credentials configured
174
- 2. Verify GPU function execution on Modal
175
- 3. Test voice and speed changes at runtime
176
- 4. Add unit tests for services
177
- 5. Add integration tests for Modal TTS
178
-
179
-
180
-
181
-
182
-
183
-
184
-
185
-
186
-
187
-
188
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
docs/implementation/TOKEN_AUTHENTICATION_REVIEW.md DELETED
@@ -1,201 +0,0 @@
1
- # Token Authentication Review - Gradio & HuggingFace
2
-
3
- ## Summary
4
-
5
- This document reviews the implementation of token authentication for Gradio Client API calls and HuggingFace API usage to ensure tokens are always passed correctly.
6
-
7
- ## ✅ Implementation Status
8
-
9
- ### 1. Gradio Client Services
10
-
11
- #### STT Service (`src/services/stt_gradio.py`)
12
- - ✅ **Token Support**: Service accepts `hf_token` parameter in `__init__` and methods
13
- - ✅ **Client Initialization**: `Client` is created with `hf_token` parameter when token is available
14
- - ✅ **Token Priority**: Method-level token > instance-level token
15
- - ✅ **Token Updates**: Client is recreated if token changes
16
-
17
- **Implementation Pattern:**
18
- ```python
19
- async def _get_client(self, hf_token: str | None = None) -> Client:
20
- token = hf_token or self.hf_token
21
- if token:
22
- self.client = Client(self.api_url, hf_token=token)
23
- else:
24
- self.client = Client(self.api_url)
25
- ```
26
-
27
- #### Image OCR Service (`src/services/image_ocr.py`)
28
- - ✅ **Token Support**: Service accepts `hf_token` parameter in `__init__` and methods
29
- - ✅ **Client Initialization**: `Client` is created with `hf_token` parameter when token is available
30
- - ✅ **Token Priority**: Method-level token > instance-level token
31
- - ✅ **Token Updates**: Client is recreated if token changes
32
-
33
- **Same pattern as STT Service**
34
-
35
- ### 2. Service Layer Integration
36
-
37
- #### Audio Service (`src/services/audio_processing.py`)
38
- - ✅ **Token Passthrough**: `process_audio_input()` accepts `hf_token` and passes to STT service
39
- - ✅ **Token Flow**: `audio_service.process_audio_input(audio, hf_token=token)`
40
-
41
- #### Multimodal Service (`src/services/multimodal_processing.py`)
42
- - ✅ **Token Passthrough**: `process_multimodal_input()` accepts `hf_token` and passes to both audio and OCR services
43
- - ✅ **Token Flow**: `multimodal_service.process_multimodal_input(..., hf_token=token)`
44
-
45
- ### 3. Application Layer (`src/app.py`)
46
-
47
- #### Token Extraction
48
- - ✅ **OAuth Token**: Extracted from `gr.OAuthToken` via `oauth_token.token`
49
- - ✅ **Fallback**: Uses `HF_TOKEN` or `HUGGINGFACE_API_KEY` from environment
50
- - ✅ **Token Priority**: `oauth_token > HF_TOKEN > HUGGINGFACE_API_KEY`
51
-
52
- **Implementation:**
53
- ```python
54
- token_value: str | None = None
55
- if oauth_token is not None:
56
- token_value = oauth_token.token if hasattr(oauth_token, "token") else None
57
-
58
- # Fallback to env vars
59
- effective_token = token_value or os.getenv("HF_TOKEN") or os.getenv("HUGGINGFACE_API_KEY")
60
- ```
61
-
62
- #### Token Usage in Services
63
- - ✅ **Multimodal Processing**: Token passed to `process_multimodal_input(..., hf_token=token_value)`
64
- - ✅ **Consistent Usage**: Token is extracted once and passed through all service layers
65
-
66
- ### 4. HuggingFace API Integration
67
-
68
- #### LLM Factory (`src/utils/llm_factory.py`)
69
- - ✅ **Token Priority**: `oauth_token > settings.hf_token > settings.huggingface_api_key`
70
- - ✅ **Provider Usage**: `HuggingFaceProvider(api_key=effective_hf_token)`
71
- - ✅ **Model Usage**: `HuggingFaceModel(model_name, provider=provider)`
72
-
73
- #### Judge Handler (`src/agent_factory/judges.py`)
74
- - ✅ **Token Priority**: `oauth_token > settings.hf_token > settings.huggingface_api_key`
75
- - ✅ **InferenceClient**: `InferenceClient(api_key=api_key)` when token provided
76
- - ✅ **Fallback**: Uses `HF_TOKEN` from environment if no token provided
77
-
78
- **Implementation:**
79
- ```python
80
- effective_hf_token = oauth_token or settings.hf_token or settings.huggingface_api_key
81
- hf_provider = HuggingFaceProvider(api_key=effective_hf_token)
82
- ```
83
-
84
- ### 5. MCP Tools (`src/mcp_tools.py`)
85
-
86
- #### Image OCR Tool
87
- - ✅ **Token Support**: `extract_text_from_image()` accepts `hf_token` parameter
88
- - ✅ **Token Fallback**: Uses `settings.hf_token` or `settings.huggingface_api_key` if not provided
89
- - ✅ **Service Integration**: Passes token to `ImageOCRService.extract_text()`
90
-
91
- #### Audio Transcription Tool
92
- - ✅ **Token Support**: `transcribe_audio_file()` accepts `hf_token` parameter
93
- - ✅ **Token Fallback**: Uses `settings.hf_token` or `settings.huggingface_api_key` if not provided
94
- - ✅ **Service Integration**: Passes token to `STTService.transcribe_file()`
95
-
96
- ## Token Flow Diagram
97
-
98
- ```
99
- User Login (OAuth)
100
-
101
- oauth_token.token
102
-
103
- app.py: token_value
104
-
105
- ┌─────────────────────────────────────┐
106
- │ Service Layer │
107
- ├─────────────────────────────────────┤
108
- │ MultimodalService │
109
- │ ↓ hf_token=token_value │
110
- │ AudioService │
111
- │ ↓ hf_token=token_value │
112
- │ STTService / ImageOCRService │
113
- │ ↓ hf_token=token_value │
114
- │ Gradio Client(hf_token=token) │
115
- └─────────────────────────────────────┘
116
-
117
- Alternative: Environment Variables
118
-
119
- HF_TOKEN or HUGGINGFACE_API_KEY
120
-
121
- settings.hf_token or settings.huggingface_api_key
122
-
123
- Same service flow as above
124
- ```
125
-
126
- ## Verification Checklist
127
-
128
- - [x] STT Service accepts and uses `hf_token` parameter
129
- - [x] Image OCR Service accepts and uses `hf_token` parameter
130
- - [x] Audio Service passes token to STT service
131
- - [x] Multimodal Service passes token to both audio and OCR services
132
- - [x] App.py extracts OAuth token correctly
133
- - [x] App.py passes token to multimodal service
134
- - [x] HuggingFace API calls use token via `HuggingFaceProvider`
135
- - [x] HuggingFace API calls use token via `InferenceClient`
136
- - [x] MCP tools accept and use token parameter
137
- - [x] Token priority is consistent: OAuth > Env Vars
138
- - [x] Fallback to environment variables when OAuth not available
139
-
140
- ## Token Parameter Naming
141
-
142
- All services consistently use `hf_token` parameter name:
143
- - `STTService.transcribe_audio(..., hf_token=...)`
144
- - `STTService.transcribe_file(..., hf_token=...)`
145
- - `ImageOCRService.extract_text(..., hf_token=...)`
146
- - `ImageOCRService.extract_text_from_image(..., hf_token=...)`
147
- - `AudioService.process_audio_input(..., hf_token=...)`
148
- - `MultimodalService.process_multimodal_input(..., hf_token=...)`
149
- - `extract_text_from_image(..., hf_token=...)` (MCP tool)
150
- - `transcribe_audio_file(..., hf_token=...)` (MCP tool)
151
-
152
- ## Gradio Client API Usage
153
-
154
- According to Gradio documentation, the `Client` constructor accepts:
155
- ```python
156
- Client(space_name, hf_token=None)
157
- ```
158
-
159
- Our implementation correctly uses:
160
- ```python
161
- Client(self.api_url, hf_token=token) # When token available
162
- Client(self.api_url) # When no token (public Space)
163
- ```
164
-
165
- ## HuggingFace API Usage
166
-
167
- ### HuggingFaceProvider
168
- ```python
169
- HuggingFaceProvider(api_key=effective_hf_token)
170
- ```
171
- ✅ Correctly passes token as `api_key` parameter
172
-
173
- ### InferenceClient
174
- ```python
175
- InferenceClient(api_key=api_key) # When token provided
176
- InferenceClient() # Falls back to HF_TOKEN env var
177
- ```
178
- ✅ Correctly passes token as `api_key` parameter
179
-
180
- ## Edge Cases Handled
181
-
182
- 1. **No Token Available**: Services work without token (public Gradio Spaces)
183
- 2. **Token Changes**: Client is recreated when token changes
184
- 3. **OAuth vs Env**: OAuth token takes priority over environment variables
185
- 4. **Multiple Token Sources**: Consistent priority across all services
186
- 5. **MCP Tools**: Support both explicit token and fallback to settings
187
-
188
- ## Recommendations
189
-
190
- ✅ **All implementations are correct and consistent**
191
-
192
- The token authentication is properly implemented throughout:
193
- - Gradio Client services accept and use tokens
194
- - Service layer passes tokens through correctly
195
- - Application layer extracts and passes OAuth tokens
196
- - HuggingFace API calls use tokens via correct parameters
197
- - MCP tools support token authentication
198
- - Token priority is consistent across all layers
199
-
200
- No changes needed - implementation follows best practices.
201
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
docs/implementation/TTS_MODAL_IMPLEMENTATION.md DELETED
@@ -1,142 +0,0 @@
1
- # TTS Modal GPU Implementation
2
-
3
- ## Overview
4
-
5
- The TTS (Text-to-Speech) service uses Kokoro 82M model running on Modal's GPU infrastructure. This document describes the implementation details and configuration.
6
-
7
- ## Implementation Details
8
-
9
- ### Modal GPU Function Pattern
10
-
11
- The implementation follows Modal's recommended pattern for GPU functions:
12
-
13
- 1. **Module-Level Function Definition**: Modal functions must be defined at module level and attached to an app instance
14
- 2. **Lazy Initialization**: The function is set up on first use via `_setup_modal_function()`
15
- 3. **GPU Configuration**: GPU type is set at function definition time (requires app restart to change)
16
-
17
- ### Key Files
18
-
19
- - `src/services/tts_modal.py` - Modal GPU executor for Kokoro TTS
20
- - `src/services/audio_processing.py` - Unified audio service wrapper
21
- - `src/utils/config.py` - Configuration settings
22
- - `src/app.py` - UI integration with settings accordion
23
-
24
- ### Configuration Options
25
-
26
- All TTS configuration is available in `src/utils/config.py`:
27
-
28
- ```python
29
- tts_model: str = "hexgrad/Kokoro-82M" # Model ID
30
- tts_voice: str = "af_heart" # Voice ID
31
- tts_speed: float = 1.0 # Speed multiplier (0.5-2.0)
32
- tts_gpu: str = "T4" # GPU type (T4, A10, A100, etc.)
33
- tts_timeout: int = 60 # Timeout in seconds
34
- enable_audio_output: bool = True # Enable/disable TTS
35
- ```
36
-
37
- ### UI Configuration
38
-
39
- TTS settings are available in the Settings accordion:
40
-
41
- - **Voice Dropdown**: Select from 20+ Kokoro voices (af_heart, af_bella, am_michael, etc.)
42
- - **Speed Slider**: Adjust speech speed (0.5x to 2.0x)
43
- - **GPU Dropdown**: Select GPU type (T4, A10, A100, L4, L40S) - visible only if Modal credentials configured
44
- - **Enable Audio Output**: Toggle TTS generation
45
-
46
- ### Modal Function Implementation
47
-
48
- The Modal GPU function is defined as:
49
-
50
- ```python
51
- @app.function(
52
- image=tts_image, # Image with Kokoro dependencies
53
- gpu="T4", # GPU type (from settings.tts_gpu)
54
- timeout=60, # Timeout (from settings.tts_timeout)
55
- )
56
- def kokoro_tts_function(text: str, voice: str, speed: float) -> tuple[int, np.ndarray]:
57
- """Modal GPU function for Kokoro TTS."""
58
- from kokoro import KModel, KPipeline
59
- import torch
60
-
61
- model = KModel().to("cuda").eval()
62
- pipeline = KPipeline(lang_code=voice[0])
63
- pack = pipeline.load_voice(voice)
64
-
65
- for _, ps, _ in pipeline(text, voice, speed):
66
- ref_s = pack[len(ps) - 1]
67
- audio = model(ps, ref_s, speed)
68
- return (24000, audio.numpy())
69
- ```
70
-
71
- ### Usage Flow
72
-
73
- 1. User submits query with audio output enabled
74
- 2. Research agent processes query and generates text response
75
- 3. `AudioService.generate_audio_output()` is called with:
76
- - Response text
77
- - Voice (from UI dropdown or settings default)
78
- - Speed (from UI slider or settings default)
79
- 4. `TTSService.synthesize_async()` calls Modal GPU function
80
- 5. Modal executes Kokoro TTS on GPU
81
- 6. Audio tuple `(sample_rate, audio_array)` is returned
82
- 7. Audio is displayed in Gradio Audio component
83
-
84
- ### Dependencies
85
-
86
- Installed via `uv add --optional`:
87
- - `gradio-client>=1.0.0` - For STT/OCR API calls
88
- - `soundfile>=0.12.0` - For audio file I/O
89
- - `Pillow>=10.0.0` - For image processing
90
-
91
- Kokoro is installed in Modal image from source:
92
- - `git+https://github.com/hexgrad/kokoro.git`
93
-
94
- ### GPU Types
95
-
96
- Modal supports various GPU types:
97
- - **T4**: Cheapest, good for testing (default)
98
- - **A10**: Good balance of cost/performance
99
- - **A100**: Fastest, most expensive
100
- - **L4**: NVIDIA L4 GPU
101
- - **L40S**: NVIDIA L40S GPU
102
-
103
- **Note**: GPU type is set at function definition time. Changes to `settings.tts_gpu` require app restart.
104
-
105
- ### Error Handling
106
-
107
- - If Modal credentials not configured: TTS service unavailable (graceful degradation)
108
- - If Kokoro import fails: ConfigurationError raised
109
- - If synthesis fails: Returns None, logs warning, continues without audio
110
- - If GPU unavailable: Modal will queue or fail with clear error message
111
-
112
- ### Configuration Connection
113
-
114
- 1. **Settings → Implementation**: `settings.tts_voice`, `settings.tts_speed` used as defaults
115
- 2. **UI → Implementation**: UI dropdowns/sliders passed to `research_agent()` function
116
- 3. **Implementation → Modal**: Voice and speed passed to Modal GPU function
117
- 4. **GPU Configuration**: Set at function definition time (requires restart to change)
118
-
119
- ### Testing
120
-
121
- To test TTS:
122
- 1. Ensure Modal credentials configured (`MODAL_TOKEN_ID`, `MODAL_TOKEN_SECRET`)
123
- 2. Enable audio output in settings
124
- 3. Submit a query
125
- 4. Check audio output component for generated speech
126
-
127
- ### References
128
-
129
- - [Kokoro TTS Space](https://huggingface.co/spaces/hexgrad/Kokoro-TTS) - Reference implementation
130
- - [Modal GPU Documentation](https://modal.com/docs/guide/gpu) - Modal GPU usage
131
- - [Kokoro GitHub](https://github.com/hexgrad/kokoro) - Source code
132
-
133
-
134
-
135
-
136
-
137
-
138
-
139
-
140
-
141
-
142
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
docs/index.md CHANGED
@@ -30,8 +30,15 @@ The DETERMINATOR is a powerful generalist deep research agent system that uses i
30
  ## Quick Start
31
 
32
  ```bash
33
- # Install uv if you haven't already
34
- pip install uv
 
 
 
 
 
 
 
35
 
36
  # Sync dependencies
37
  uv sync
 
30
  ## Quick Start
31
 
32
  ```bash
33
+ # Install uv if you haven't already (recommended: standalone installer)
34
+ # Unix/macOS/Linux:
35
+ curl -LsSf https://astral.sh/uv/install.sh | sh
36
+
37
+ # Windows (PowerShell):
38
+ powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
39
+
40
+ # Alternative: pipx install uv
41
+ # Or: pip install uv
42
 
43
  # Sync dependencies
44
  uv sync
docs/overview/architecture.md CHANGED
@@ -134,10 +134,11 @@ The graph orchestrator (`src/orchestrator/graph_orchestrator.py`) implements a f
134
  - **Research Flows**: Iterative and deep research patterns (`src/orchestrator/research_flow.py`)
135
  - **Graph Builder**: Graph construction utilities (`src/agent_factory/graph_builder.py`)
136
  - **Agents**: Pydantic AI agents (`src/agents/`, `src/agent_factory/agents.py`)
137
- - **Search Tools**: PubMed, ClinicalTrials.gov, Europe PMC, RAG (`src/tools/`)
138
  - **Judge Handler**: LLM-based evidence assessment (`src/agent_factory/judges.py`)
139
  - **Embeddings**: Semantic search & deduplication (`src/services/embeddings.py`)
140
  - **Statistical Analyzer**: Modal sandbox execution (`src/services/statistical_analyzer.py`)
 
141
  - **Middleware**: State management, budget tracking, workflow coordination (`src/middleware/`)
142
  - **MCP Tools**: Claude Desktop integration (`src/mcp_tools.py`)
143
  - **Gradio UI**: Web interface with MCP server and streaming (`src/app.py`)
@@ -169,29 +170,25 @@ The system supports complex research workflows through:
169
 
170
  - **Orchestrator Factory** (`src/orchestrator_factory.py`):
171
  - Auto-detects mode: "advanced" if OpenAI key available, else "simple"
172
- - Supports explicit mode selection: "simple", "magentic", "advanced"
173
  - Lazy imports for optional dependencies
174
 
175
- - **Research Modes**:
176
- - `iterative`: Single research loop
177
- - `deep`: Multi-section parallel research
178
- - `auto`: Auto-detect based on query complexity
 
 
 
 
 
 
 
179
 
180
  - **Execution Modes**:
181
  - `use_graph=True`: Graph-based execution (parallel, conditional routing)
182
  - `use_graph=False`: Agent chains (sequential, backward compatible)
183
 
184
-
185
-
186
-
187
-
188
-
189
-
190
-
191
-
192
-
193
-
194
-
195
-
196
 
197
 
 
134
  - **Research Flows**: Iterative and deep research patterns (`src/orchestrator/research_flow.py`)
135
  - **Graph Builder**: Graph construction utilities (`src/agent_factory/graph_builder.py`)
136
  - **Agents**: Pydantic AI agents (`src/agents/`, `src/agent_factory/agents.py`)
137
+ - **Search Tools**: Neo4j knowledge graph, PubMed, ClinicalTrials.gov, Europe PMC, Web search, RAG (`src/tools/`)
138
  - **Judge Handler**: LLM-based evidence assessment (`src/agent_factory/judges.py`)
139
  - **Embeddings**: Semantic search & deduplication (`src/services/embeddings.py`)
140
  - **Statistical Analyzer**: Modal sandbox execution (`src/services/statistical_analyzer.py`)
141
+ - **Multimodal Processing**: Image OCR and audio STT/TTS services (`src/services/multimodal_processing.py`, `src/services/audio_processing.py`)
142
  - **Middleware**: State management, budget tracking, workflow coordination (`src/middleware/`)
143
  - **MCP Tools**: Claude Desktop integration (`src/mcp_tools.py`)
144
  - **Gradio UI**: Web interface with MCP server and streaming (`src/app.py`)
 
170
 
171
  - **Orchestrator Factory** (`src/orchestrator_factory.py`):
172
  - Auto-detects mode: "advanced" if OpenAI key available, else "simple"
173
+ - Supports explicit mode selection: "simple", "magentic" (alias for "advanced"), "advanced", "iterative", "deep", "auto"
174
  - Lazy imports for optional dependencies
175
 
176
+ - **Orchestrator Modes** (selected in UI or via factory):
177
+ - `simple`: Legacy linear search-judge loop (Free Tier)
178
+ - `advanced` or `magentic`: Multi-agent coordination using Microsoft Agent Framework (requires OpenAI API key)
179
+ - `iterative`: Knowledge-gap-driven research with single loop (Free Tier)
180
+ - `deep`: Parallel section-based research with planning (Free Tier)
181
+ - `auto`: Intelligent mode detection based on query complexity (Free Tier)
182
+
183
+ - **Graph Research Modes** (used within graph orchestrator, separate from orchestrator mode):
184
+ - `iterative`: Single research loop pattern
185
+ - `deep`: Multi-section parallel research pattern
186
+ - `auto`: Auto-detect pattern based on query complexity
187
 
188
  - **Execution Modes**:
189
  - `use_graph=True`: Graph-based execution (parallel, conditional routing)
190
  - `use_graph=False`: Agent chains (sequential, backward compatible)
191
 
192
+ **Note**: The UI provides separate controls for orchestrator mode and graph research mode. When using graph-based orchestrators (iterative/deep/auto), the graph research mode determines the specific pattern used within the graph execution.
 
 
 
 
 
 
 
 
 
 
 
193
 
194
 
docs/overview/features.md CHANGED
@@ -7,6 +7,7 @@ The DETERMINATOR provides a comprehensive set of features for AI-assisted resear
7
  ### Multi-Source Search
8
 
9
  - **General Web Search**: Search general knowledge sources for any domain
 
10
  - **PubMed**: Search peer-reviewed biomedical literature via NCBI E-utilities (automatically used when medical knowledge needed)
11
  - **ClinicalTrials.gov**: Search interventional clinical trials (automatically used when medical knowledge needed)
12
  - **Europe PMC**: Search preprints and peer-reviewed articles (includes bioRxiv/medRxiv)
@@ -21,9 +22,11 @@ The DETERMINATOR provides a comprehensive set of features for AI-assisted resear
21
 
22
  ### Authentication
23
 
24
- - **HuggingFace OAuth**: Sign in with HuggingFace account for automatic API token usage
25
- - **Manual API Keys**: Support for OpenAI, Anthropic, and HuggingFace API keys
26
- - **Free Tier Support**: Automatic fallback to HuggingFace Inference API
 
 
27
 
28
  ### Secure Code Execution
29
 
@@ -44,9 +47,25 @@ The DETERMINATOR provides a comprehensive set of features for AI-assisted resear
44
  - **Parallel Research Loops**: Run multiple research tasks concurrently
45
  - **Iterative Research**: Single-loop research with search-judge-synthesize cycles that continues until precise answers are found
46
  - **Deep Research**: Multi-section parallel research with planning and synthesis
47
- - **Magentic Orchestration**: Multi-agent coordination using Microsoft Agent Framework
48
  - **Stops at Nothing**: Only stops at configured limits (budget, time, iterations), otherwise continues until finding precise answers
49
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
50
  ### Real-Time Streaming
51
 
52
  - **Event Streaming**: Real-time updates via `AsyncGenerator[AgentEvent]`
@@ -67,6 +86,16 @@ The DETERMINATOR provides a comprehensive set of features for AI-assisted resear
67
  - **Conversation History**: Track iteration history and agent interactions
68
  - **State Synchronization**: Share evidence across parallel loops
69
 
 
 
 
 
 
 
 
 
 
 
70
  ## Advanced Features
71
 
72
  ### Agent System
@@ -108,10 +137,12 @@ The DETERMINATOR provides a comprehensive set of features for AI-assisted resear
108
 
109
  ### Gradio Interface
110
 
111
- - **Real-Time Chat**: Interactive chat interface
112
  - **Streaming Updates**: Live progress updates
113
  - **Accordion UI**: Organized display of pending/done operations
114
  - **OAuth Integration**: Seamless HuggingFace authentication
 
 
115
 
116
  ### MCP Server
117
 
@@ -136,17 +167,3 @@ The DETERMINATOR provides a comprehensive set of features for AI-assisted resear
136
  - **Architecture Diagrams**: Visual architecture documentation
137
  - **API Reference**: Complete API documentation
138
 
139
-
140
-
141
-
142
-
143
-
144
-
145
-
146
-
147
-
148
-
149
-
150
-
151
-
152
-
 
7
  ### Multi-Source Search
8
 
9
  - **General Web Search**: Search general knowledge sources for any domain
10
+ - **Neo4j Knowledge Graph**: Search structured knowledge graph for papers and disease relationships
11
  - **PubMed**: Search peer-reviewed biomedical literature via NCBI E-utilities (automatically used when medical knowledge needed)
12
  - **ClinicalTrials.gov**: Search interventional clinical trials (automatically used when medical knowledge needed)
13
  - **Europe PMC**: Search preprints and peer-reviewed articles (includes bioRxiv/medRxiv)
 
22
 
23
  ### Authentication
24
 
25
+ - **REQUIRED**: Authentication is mandatory before using the application
26
+ - **HuggingFace OAuth**: Sign in with HuggingFace account for automatic API token usage (recommended)
27
+ - **Manual API Keys**: Support for HuggingFace API keys via environment variables (`HF_TOKEN` or `HUGGINGFACE_API_KEY`)
28
+ - **Free Tier Support**: Automatic fallback to HuggingFace Inference API (public models) when no API key is available
29
+ - **Authentication Check**: The application will display an error message if authentication is not provided
30
 
31
  ### Secure Code Execution
32
 
 
47
  - **Parallel Research Loops**: Run multiple research tasks concurrently
48
  - **Iterative Research**: Single-loop research with search-judge-synthesize cycles that continues until precise answers are found
49
  - **Deep Research**: Multi-section parallel research with planning and synthesis
50
+ - **Magentic Orchestration**: Multi-agent coordination using Microsoft Agent Framework (alias: "advanced" mode)
51
  - **Stops at Nothing**: Only stops at configured limits (budget, time, iterations), otherwise continues until finding precise answers
52
 
53
+ **Orchestrator Modes**:
54
+ - `simple`: Legacy linear search-judge loop
55
+ - `advanced` (or `magentic`): Multi-agent coordination (requires OpenAI API key)
56
+ - `iterative`: Knowledge-gap-driven research with single loop
57
+ - `deep`: Parallel section-based research with planning
58
+ - `auto`: Intelligent mode detection based on query complexity
59
+
60
+ **Graph Research Modes** (used within graph orchestrator):
61
+ - `iterative`: Single research loop pattern
62
+ - `deep`: Multi-section parallel research pattern
63
+ - `auto`: Auto-detect pattern based on query complexity
64
+
65
+ **Execution Modes**:
66
+ - `use_graph=True`: Graph-based execution with parallel and conditional routing
67
+ - `use_graph=False`: Agent chains with sequential execution (backward compatible)
68
+
69
  ### Real-Time Streaming
70
 
71
  - **Event Streaming**: Real-time updates via `AsyncGenerator[AgentEvent]`
 
86
  - **Conversation History**: Track iteration history and agent interactions
87
  - **State Synchronization**: Share evidence across parallel loops
88
 
89
+ ### Multimodal Input & Output
90
+
91
+ - **Image Input (OCR)**: Upload images and extract text using optical character recognition
92
+ - **Audio Input (STT)**: Record or upload audio files and transcribe to text using speech-to-text
93
+ - **Audio Output (TTS)**: Generate audio responses with text-to-speech synthesis
94
+ - **Configurable Settings**: Enable/disable multimodal features via sidebar settings
95
+ - **Voice Selection**: Choose from multiple TTS voices (American English: af_*, am_*)
96
+ - **Speech Speed Control**: Adjust TTS speech speed (0.5x to 2.0x)
97
+ - **Multimodal Processing Service**: Integrated service for processing images and audio files
98
+
99
  ## Advanced Features
100
 
101
  ### Agent System
 
137
 
138
  ### Gradio Interface
139
 
140
+ - **Real-Time Chat**: Interactive chat interface with multimodal support
141
  - **Streaming Updates**: Live progress updates
142
  - **Accordion UI**: Organized display of pending/done operations
143
  - **OAuth Integration**: Seamless HuggingFace authentication
144
+ - **Multimodal Input**: Support for text, images, and audio input in the same interface
145
+ - **Sidebar Settings**: Configuration accordions for research, multimodal, and audio settings
146
 
147
  ### MCP Server
148
 
 
167
  - **Architecture Diagrams**: Visual architecture documentation
168
  - **API Reference**: Complete API documentation
169
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
docs/overview/quick-start.md CHANGED
@@ -5,8 +5,15 @@ Get started with DeepCritical in minutes.
5
  ## Installation
6
 
7
  ```bash
8
- # Install uv if you haven't already
9
- pip install uv
 
 
 
 
 
 
 
10
 
11
  # Sync dependencies
12
  uv sync
@@ -23,21 +30,26 @@ Open your browser to `http://localhost:7860`.
23
 
24
  ## Basic Usage
25
 
26
- ### 1. Authentication (Optional)
 
 
27
 
28
- **HuggingFace OAuth Login**:
29
  - Click the "Sign in with HuggingFace" button at the top of the app
30
  - Your HuggingFace API token will be automatically used for AI inference
31
  - No need to manually enter API keys when logged in
32
 
33
- **Manual API Key (BYOK)**:
34
- - Provide your own API key in the Settings accordion
35
- - Supports HuggingFace, OpenAI, or Anthropic API keys
36
- - Manual keys take priority over OAuth tokens
37
 
38
  ### 2. Start a Research Query
39
 
40
  1. Enter your research question in the chat interface
 
 
 
41
  2. Click "Submit" or press Enter
42
  3. Watch the real-time progress as the system:
43
  - Generates observations
@@ -46,6 +58,12 @@ Open your browser to `http://localhost:7860`.
46
  - Evaluates evidence
47
  - Synthesizes findings
48
  4. Review the final research report
 
 
 
 
 
 
49
 
50
  ### 3. MCP Integration (Optional)
51
 
@@ -70,9 +88,12 @@ Connect DeepCritical to Claude Desktop:
70
  - `search_pubmed`: Search peer-reviewed biomedical literature
71
  - `search_clinical_trials`: Search ClinicalTrials.gov
72
  - `search_biorxiv`: Search bioRxiv/medRxiv preprints
 
73
  - `search_all`: Search all sources simultaneously
74
  - `analyze_hypothesis`: Secure statistical analysis using Modal sandboxes
75
 
 
 
76
  ## Next Steps
77
 
78
  - Read the [Installation Guide](../getting-started/installation.md) for detailed setup
 
5
  ## Installation
6
 
7
  ```bash
8
+ # Install uv if you haven't already (recommended: standalone installer)
9
+ # Unix/macOS/Linux:
10
+ curl -LsSf https://astral.sh/uv/install.sh | sh
11
+
12
+ # Windows (PowerShell):
13
+ powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
14
+
15
+ # Alternative: pipx install uv
16
+ # Or: pip install uv
17
 
18
  # Sync dependencies
19
  uv sync
 
30
 
31
  ## Basic Usage
32
 
33
+ ### 1. Authentication (REQUIRED)
34
+
35
+ **Authentication is mandatory** - you must authenticate before using the application. The app will display an error message if you try to use it without authentication.
36
 
37
+ **HuggingFace OAuth Login** (Recommended):
38
  - Click the "Sign in with HuggingFace" button at the top of the app
39
  - Your HuggingFace API token will be automatically used for AI inference
40
  - No need to manually enter API keys when logged in
41
 
42
+ **Manual API Key** (Alternative):
43
+ - Set environment variable `HF_TOKEN` or `HUGGINGFACE_API_KEY` before starting the app
44
+ - The app will automatically use these tokens if OAuth login is not available
45
+ - Supports HuggingFace API keys only (OpenAI/Anthropic keys are not used in the current implementation)
46
 
47
  ### 2. Start a Research Query
48
 
49
  1. Enter your research question in the chat interface
50
+ - **Text Input**: Type your question directly
51
+ - **Image Input**: Click the 📷 icon to upload images (OCR will extract text)
52
+ - **Audio Input**: Click the 🎤 icon to record or upload audio (STT will transcribe to text)
53
  2. Click "Submit" or press Enter
54
  3. Watch the real-time progress as the system:
55
  - Generates observations
 
58
  - Evaluates evidence
59
  - Synthesizes findings
60
  4. Review the final research report
61
+ - **Audio Output**: If enabled, the final response will include audio synthesis (TTS)
62
+
63
+ **Multimodal Features**:
64
+ - Configure image/audio input and output in the sidebar settings
65
+ - Image OCR and audio STT/TTS can be enabled/disabled independently
66
+ - TTS voice and speed can be customized in the Audio Output settings
67
 
68
  ### 3. MCP Integration (Optional)
69
 
 
88
  - `search_pubmed`: Search peer-reviewed biomedical literature
89
  - `search_clinical_trials`: Search ClinicalTrials.gov
90
  - `search_biorxiv`: Search bioRxiv/medRxiv preprints
91
+ - `search_neo4j`: Search Neo4j knowledge graph for papers and disease relationships
92
  - `search_all`: Search all sources simultaneously
93
  - `analyze_hypothesis`: Secure statistical analysis using Modal sandboxes
94
 
95
+ **Note**: The application automatically uses all available search tools (Neo4j, PubMed, ClinicalTrials.gov, Europe PMC, Web search, RAG) based on query analysis. Neo4j knowledge graph search is included by default for biomedical queries.
96
+
97
  ## Next Steps
98
 
99
  - Read the [Installation Guide](../getting-started/installation.md) for detailed setup
mkdocs.yml CHANGED
@@ -88,7 +88,7 @@ nav:
88
  - getting-started/mcp-integration.md
89
  - getting-started/examples.md
90
  - Configuration:
91
- - configuration/CONFIGURATION.md
92
  - Architecture:
93
  - "Graph Orchestration": architecture/graph_orchestration.md
94
  - "Workflow Diagrams": architecture/workflow-diagrams.md
 
88
  - getting-started/mcp-integration.md
89
  - getting-started/examples.md
90
  - Configuration:
91
+ - configuration/index.md
92
  - Architecture:
93
  - "Graph Orchestration": architecture/graph_orchestration.md
94
  - "Workflow Diagrams": architecture/workflow-diagrams.md
mkdocs.yml.enhanced ADDED
@@ -0,0 +1,166 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ site_name: The DETERMINATOR
2
+ site_description: Generalist Deep Research Agent that Stops at Nothing
3
+ site_author: The DeepCritical Team
4
+ site_url: https://deepcritical.github.io/GradioDemo/
5
+
6
+ repo_name: DeepCritical/GradioDemo
7
+ repo_url: https://github.com/DeepCritical/GradioDemo
8
+ edit_uri: edit/dev/docs/
9
+
10
+ # Ensure all files are included even if not in nav
11
+ # strict: false
12
+
13
+ theme:
14
+ name: material
15
+ palette:
16
+ # Light mode
17
+ - scheme: default
18
+ primary: orange
19
+ accent: red
20
+ toggle:
21
+ icon: material/brightness-7
22
+ name: Switch to dark mode
23
+ # Dark mode
24
+ - scheme: slate
25
+ primary: orange
26
+ accent: red
27
+ toggle:
28
+ icon: material/brightness-4
29
+ name: Switch to light mode
30
+ features:
31
+ # Navigation features
32
+ - navigation.tabs
33
+ - navigation.sections
34
+ - navigation.expand
35
+ - navigation.top
36
+ - navigation.indexes
37
+ - navigation.instant
38
+ - navigation.tracking
39
+ - navigation.smooth
40
+ # Search features
41
+ - search.suggest
42
+ - search.highlight
43
+ # Content features
44
+ - content.code.annotate
45
+ - content.code.copy
46
+ - content.tabs.link
47
+ - content.tooltips
48
+ - toc.integrate
49
+ icon:
50
+ repo: fontawesome/brands/github
51
+ language: en
52
+
53
+ plugins:
54
+ - search:
55
+ lang:
56
+ - en
57
+ separator: '[\s\-,:!=\[\]()"`/]+|\.(?!\d)|&[lg]t;|&amp;'
58
+ prebuild_index: true # Faster search initialization
59
+ indexing: full # Full-text indexing for better results
60
+ - mermaid2
61
+ - codeinclude
62
+ - git-revision-date-localized:
63
+ enable_creation_date: true
64
+ type: timeago # Shows "2 days ago" format
65
+ fallback_to_build_date: true
66
+ - minify:
67
+ minify_html: true
68
+ minify_js: true
69
+ minify_css: true
70
+
71
+ markdown_extensions:
72
+ - dev.docs_plugins:
73
+ base_path: "."
74
+ - pymdownx.highlight:
75
+ anchor_linenums: true
76
+ line_spans: __span # Allow line spans for highlighting
77
+ pygments_lang_class: true # Add language class to code blocks
78
+ use_pygments: true
79
+ noclasses: false # Use CSS classes for better theming
80
+ - pymdownx.inlinehilite
81
+ - pymdownx.superfences:
82
+ custom_fences:
83
+ - name: mermaid
84
+ class: mermaid
85
+ format: !!python/name:pymdownx.superfences.fence_code_format
86
+ preserve_tabs: true
87
+ - pymdownx.tabbed:
88
+ alternate_style: true
89
+ combine_header_slug: true # Better tab linking
90
+ - pymdownx.tasklist:
91
+ custom_checkbox: true
92
+ - pymdownx.emoji:
93
+ emoji_generator: !!python/name:pymdownx.emoji.to_svg
94
+ emoji_index: !!python/name:pymdownx.emoji.twemoji
95
+ - pymdownx.snippets
96
+ - admonition
97
+ - pymdownx.details
98
+ - attr_list
99
+ - md_in_html
100
+ - tables
101
+ - meta # Frontmatter support for tags, categories, etc.
102
+ - toc:
103
+ permalink: true
104
+ permalink_title: "Anchor link to this section"
105
+ baselevel: 1
106
+ toc_depth: 3
107
+ slugify: !!python/object/apply:pymdownx.slugs.slugify
108
+ kwds:
109
+ case: lower
110
+
111
+ nav:
112
+ - Home: index.md
113
+ - Overview:
114
+ - overview/architecture.md
115
+ - overview/features.md
116
+ - Getting Started:
117
+ - getting-started/installation.md
118
+ - getting-started/quick-start.md
119
+ - getting-started/mcp-integration.md
120
+ - getting-started/examples.md
121
+ - Configuration:
122
+ - configuration/index.md
123
+ - Architecture:
124
+ - "Graph Orchestration": architecture/graph_orchestration.md
125
+ - "Workflow Diagrams": architecture/workflow-diagrams.md
126
+ - "Agents": architecture/agents.md
127
+ - "Orchestrators": architecture/orchestrators.md
128
+ - "Tools": architecture/tools.md
129
+ - "Middleware": architecture/middleware.md
130
+ - "Services": architecture/services.md
131
+ - API Reference:
132
+ - api/agents.md
133
+ - api/tools.md
134
+ - api/orchestrators.md
135
+ - api/services.md
136
+ - api/models.md
137
+ - Contributing:
138
+ - contributing/index.md
139
+ - contributing/code-quality.md
140
+ - contributing/code-style.md
141
+ - contributing/error-handling.md
142
+ - contributing/implementation-patterns.md
143
+ - contributing/prompt-engineering.md
144
+ - contributing/testing.md
145
+ - License: LICENSE.md
146
+ - Team: team.md
147
+
148
+ extra:
149
+ social:
150
+ - icon: fontawesome/brands/github
151
+ link: https://github.com/DeepCritical/GradioDemo
152
+ name: GitHub
153
+ - icon: fontawesome/brands/twitter
154
+ link: https://twitter.com/josephpollack
155
+ name: Twitter
156
+ - icon: material/web
157
+ link: https://huggingface.co/spaces/DataQuests/DeepCritical
158
+ name: Live Demo
159
+ - icon: fontawesome/brands/discord
160
+ link: https://discord.gg/n8ytYeh25n
161
+ name: Discord
162
+ generator:
163
+ enabled: false # Hide generator meta tag
164
+
165
+ copyright: Copyright &copy; 2024 DeepCritical Team
166
+