7a0da7932b
OSV-Scanner (Scheduled) / scan-scheduled (push) Failing after 0s
Create Release / test-gate (push) Has been cancelled
Create Release / release-gate (push) Has been cancelled
Create Release / ci-gate (push) Has been cancelled
Create Release / version-check (push) Has been cancelled
Create Release / e2e-test-gate (push) Has been cancelled
Create Release / responsive-test-gate (push) Has been cancelled
Create Release / compat-test-gate (push) Has been cancelled
Create Release / compose-integration-gate (push) Has been cancelled
Create Release / vulture-gate (push) Has been cancelled
Create Release / build (push) Has been cancelled
Create Release / provenance (push) Has been cancelled
Create Release / prerelease-docker (push) Has been cancelled
Create Release / publish-docker (push) Has been cancelled
Create Release / create-release (push) Has been cancelled
Create Release / cleanup-changelog (push) Has been cancelled
Create Release / trigger-pypi (push) Has been cancelled
Create Release / monitor-pypi (push) Has been cancelled
Create Release / Clean up orphan prerelease tags and signatures (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-form] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-metrics] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-workflow] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-core] (push) Has been cancelled
CodeQL Advanced / Analyze (javascript-typescript) (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [history-news] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [library] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [link-analytics] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-core] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-lifecycle] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [error-benchmark] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-pages] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) (push) Has been cancelled
Docker Tests (Consolidated) / Accessibility Tests (push) Has been cancelled
Docker Tests (Consolidated) / LLM Unit Tests (push) Has been cancelled
Docker Tests (Consolidated) / LLM Example Tests (push) Has been cancelled
Docker Tests (Consolidated) / Production Image Smoke Test (push) Has been cancelled
Docker Tests (Consolidated) / Infrastructure Tests (push) Has been cancelled
OSSF Scorecard / OSSF Security Scorecard Analysis (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [mobile] (push) Has been cancelled
Backwards Compatibility / Verify Encryption Constants (push) Has been cancelled
Backwards Compatibility / PyPI Version Compatibility (push) Has been cancelled
Backwards Compatibility / Database Migration Tests (push) Has been cancelled
CodeQL Advanced / Analyze (python) (push) Has been cancelled
Docker Tests (Consolidated) / detect-changes (push) Has been cancelled
Docker Tests (Consolidated) / Build Test Image (push) Has been cancelled
Docker Tests (Consolidated) / All Pytest Tests + Coverage (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [accessibility] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [api-crud] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-login] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-pages] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-register] (push) Has been cancelled
468 lines
13 KiB
Markdown
468 lines
13 KiB
Markdown
# Architecture Overview
|
|
|
|
This document provides a comprehensive overview of Local Deep Research's system architecture.
|
|
|
|
## Table of Contents
|
|
|
|
- [System Components](#system-components)
|
|
- [Entry Points](#entry-points)
|
|
- [Research Execution Flow](#research-execution-flow)
|
|
- [Research Status Lifecycle](#research-status-lifecycle)
|
|
- [Module Responsibilities](#module-responsibilities)
|
|
- [Threading Model](#threading-model)
|
|
- [Configuration System](#configuration-system)
|
|
- [Key Interfaces](#key-interfaces)
|
|
|
|
---
|
|
|
|
## System Components
|
|
|
|
```mermaid
|
|
graph TB
|
|
subgraph "Entry Points"
|
|
CLI[ldr CLI]
|
|
WEB[ldr-web Flask App]
|
|
API[REST API /api/v1]
|
|
end
|
|
|
|
subgraph "Core Research Engine"
|
|
SS[SearchSystem<br/>search_system.py]
|
|
SSF[StrategyFactory<br/>search_system_factory.py]
|
|
RG[ReportGenerator<br/>report_generator.py]
|
|
end
|
|
|
|
subgraph "Search Layer"
|
|
STRAT[32 Search Strategies<br/>advanced_search_system/strategies/]
|
|
ENG[30+ Search Engines<br/>web_search_engines/engines/]
|
|
RL[Rate Limiter<br/>rate_limiting/]
|
|
end
|
|
|
|
subgraph "Data Layer"
|
|
DB[(SQLCipher DB<br/>Per-User Encrypted)]
|
|
MODELS[20+ ORM Models<br/>database/models/]
|
|
CACHE[Memory Cache]
|
|
end
|
|
|
|
subgraph "LLM Layer"
|
|
PROV[LLM Providers<br/>Ollama, OpenAI, etc.]
|
|
EMB[Embeddings<br/>embeddings/]
|
|
RERANK[Reranker<br/>reranker/]
|
|
end
|
|
|
|
CLI --> SS
|
|
WEB --> SS
|
|
API --> SS
|
|
|
|
SS --> SSF
|
|
SS --> RG
|
|
SSF --> STRAT
|
|
STRAT --> ENG
|
|
ENG --> RL
|
|
|
|
SS --> PROV
|
|
SS --> DB
|
|
MODELS --> DB
|
|
|
|
RG --> PROV
|
|
ENG --> CACHE
|
|
```
|
|
|
|
---
|
|
|
|
## Entry Points
|
|
|
|
### Web Application (`ldr-web`)
|
|
|
|
**Location:** `src/local_deep_research/web/app.py`
|
|
|
|
The primary user interface. Launches a Flask server with SocketIO for real-time updates.
|
|
|
|
```mermaid
|
|
graph LR
|
|
A[Browser] -->|HTTP/WS| B[Flask App]
|
|
B --> C[Blueprints]
|
|
C --> D[research_routes]
|
|
C --> E[api_routes]
|
|
C --> F[settings_routes]
|
|
C --> G[auth_routes]
|
|
B -->|Real-time| H[SocketIO]
|
|
```
|
|
|
|
**Key files:**
|
|
- `web/app.py` - Main entry, starts server
|
|
- `web/app_factory.py` - Flask app creation with middleware
|
|
- `web/routes/` - Blueprint route handlers
|
|
- `web/services/` - Business logic services
|
|
|
|
### REST API (`/api/v1`)
|
|
|
|
**Location:** `src/local_deep_research/web/api.py`
|
|
|
|
Programmatic access for integrations.
|
|
|
|
| Endpoint | Method | Purpose |
|
|
|----------|--------|---------|
|
|
| `/api/v1/quick_summary` | POST | Quick research summary |
|
|
| `/api/v1/generate_report` | POST | Full research report |
|
|
| `/api/v1/analyze_documents` | POST | Search local collections |
|
|
| `/api/v1/health` | GET | Health check |
|
|
|
|
---
|
|
|
|
## Research Execution Flow
|
|
|
|
```mermaid
|
|
sequenceDiagram
|
|
participant User
|
|
participant Web as Flask App
|
|
participant SS as SearchSystem
|
|
participant SF as StrategyFactory
|
|
participant Strat as Strategy
|
|
participant Eng as SearchEngine
|
|
participant LLM as LLM Provider
|
|
participant DB as Database
|
|
|
|
User->>Web: Submit Query
|
|
Web->>SS: start_research()
|
|
SS->>SF: create_strategy(name)
|
|
SF-->>SS: Strategy instance
|
|
|
|
loop Research Iterations
|
|
SS->>Strat: analyze_topic(query)
|
|
Strat->>LLM: Generate questions
|
|
LLM-->>Strat: Questions
|
|
|
|
loop Per Question
|
|
Strat->>Eng: search(question)
|
|
Eng-->>Strat: Results
|
|
end
|
|
|
|
Strat->>LLM: Synthesize findings
|
|
LLM-->>Strat: Synthesis
|
|
Strat-->>SS: Findings
|
|
end
|
|
|
|
SS->>DB: Save results
|
|
SS-->>Web: Research complete
|
|
Web-->>User: Results via SocketIO
|
|
```
|
|
|
|
### Research Status Lifecycle
|
|
|
|
```mermaid
|
|
stateDiagram-v2
|
|
[*] --> QUEUED : Concurrency limit reached
|
|
[*] --> IN_PROGRESS : Slots available
|
|
|
|
QUEUED --> IN_PROGRESS : Worker picks up task
|
|
QUEUED --> SUSPENDED : User terminates
|
|
|
|
IN_PROGRESS --> COMPLETED : Research succeeds
|
|
IN_PROGRESS --> FAILED : Unrecoverable error
|
|
IN_PROGRESS --> SUSPENDED : User terminates
|
|
|
|
COMPLETED --> [*]
|
|
FAILED --> [*]
|
|
SUSPENDED --> [*]
|
|
|
|
note right of FAILED
|
|
Set by processor_v2 and
|
|
research_service on errors
|
|
end note
|
|
|
|
note left of SUSPENDED
|
|
Set when user clicks
|
|
terminate/stop
|
|
end note
|
|
```
|
|
|
|
> **Unused statuses:** `PENDING` (declared as a model default but never set by any creation
|
|
> path), `ERROR` (never set; predates `FAILED`), and `CANCELLED` (unused by research; used
|
|
> by benchmarks) exist in `ResearchStatus` for backward compatibility.
|
|
|
|
---
|
|
|
|
## Module Responsibilities
|
|
|
|
### Core Modules
|
|
|
|
| Module | Location | Responsibility |
|
|
|--------|----------|----------------|
|
|
| **SearchSystem** | `search_system.py` | Orchestrates research, coordinates strategies and engines |
|
|
| **StrategyFactory** | `search_system_factory.py` | Creates strategy instances based on configuration |
|
|
| **ReportGenerator** | `report_generator.py` | Generates structured reports from research findings |
|
|
| **CitationHandler** | `citation_handler.py` | Processes and validates citations |
|
|
|
|
### Search System
|
|
|
|
| Module | Location | Responsibility |
|
|
|--------|----------|----------------|
|
|
| **BaseSearchEngine** | `web_search_engines/search_engine_base.py` | Abstract base for all search engines |
|
|
| **SearchEngineFactory** | `web_search_engines/search_engine_factory.py` | Creates engine instances |
|
|
| **RateLimitTracker** | `web_search_engines/rate_limiting/tracker.py` | Adaptive rate limiting |
|
|
| **RetrieverRegistry** | `web_search_engines/retriever_registry.py` | LangChain retriever integration |
|
|
|
|
### Strategy System
|
|
|
|
| Module | Location | Responsibility |
|
|
|--------|----------|----------------|
|
|
| **BaseSearchStrategy** | `advanced_search_system/strategies/base_strategy.py` | Abstract base for strategies |
|
|
| **FindingsRepository** | `advanced_search_system/findings/` | Accumulates research findings |
|
|
| **QuestionGenerator** | `advanced_search_system/questions/` | Generates research questions |
|
|
|
|
### Web Application
|
|
|
|
| Module | Location | Responsibility |
|
|
|--------|----------|----------------|
|
|
| **SocketIOService** | `web/services/socket_service.py` | Real-time communication |
|
|
| **ResearchService** | `web/services/research_service.py` | Research execution |
|
|
| **QueueManager** | `web/queue/` | Background task queue |
|
|
| **SessionManager** | `web/auth/session_manager.py` | User session handling |
|
|
|
|
### Data Layer
|
|
|
|
| Module | Location | Responsibility |
|
|
|--------|----------|----------------|
|
|
| **Models** | `database/models/` | SQLAlchemy ORM models |
|
|
| **SessionContext** | `database/session_context.py` | Thread-safe DB sessions |
|
|
| **EncryptedDB** | `database/encrypted_db.py` | SQLCipher integration |
|
|
|
|
### LLM Integration
|
|
|
|
| Module | Location | Responsibility |
|
|
|--------|----------|----------------|
|
|
| **LLM Providers** | `llm/providers/implementations/` | Provider-specific LLM wrappers |
|
|
| **AutoDiscovery** | `llm/providers/auto_discovery.py` | Dynamic provider detection |
|
|
| **LLMRegistry** | `llm/llm_registry.py` | Custom LLM registration |
|
|
|
|
---
|
|
|
|
## Threading Model
|
|
|
|
```mermaid
|
|
graph TB
|
|
subgraph "Main Thread"
|
|
FLASK[Flask Server]
|
|
SOCKETIO[SocketIO Handler]
|
|
end
|
|
|
|
subgraph "Research Threads"
|
|
RT1[Research Thread 1]
|
|
RT2[Research Thread 2]
|
|
RTN[Research Thread N]
|
|
end
|
|
|
|
subgraph "Queue Processor"
|
|
QP[Queue Processor Thread]
|
|
end
|
|
|
|
subgraph "Thread-Local Storage"
|
|
TC[Thread Context<br/>Settings Snapshot]
|
|
DBS[DB Session<br/>Per-User]
|
|
end
|
|
|
|
FLASK --> RT1
|
|
FLASK --> RT2
|
|
FLASK --> RTN
|
|
|
|
RT1 --> TC
|
|
RT2 --> TC
|
|
RTN --> TC
|
|
|
|
QP --> RT1
|
|
|
|
RT1 -.-> SOCKETIO
|
|
RT2 -.-> SOCKETIO
|
|
```
|
|
|
|
**Key Threading Concepts:**
|
|
|
|
1. **Thread Context** (`config/thread_settings.py`)
|
|
- Each research thread has its own settings snapshot
|
|
- Prevents race conditions on configuration changes
|
|
|
|
2. **Per-User DB Sessions** (`database/session_context.py`)
|
|
- Each user has an isolated SQLCipher database
|
|
- Sessions are thread-local via context manager
|
|
|
|
3. **Queue Processing** (`web/queue/`)
|
|
- Background queue for long-running research
|
|
- Processes items from `QueuedResearch` table
|
|
|
|
4. **SocketIO Updates**
|
|
- Research threads emit progress via SocketIO
|
|
- Uses threading async mode (not asyncio)
|
|
|
|
---
|
|
|
|
## Configuration System
|
|
|
|
```mermaid
|
|
graph TB
|
|
subgraph "Configuration Sources"
|
|
ENV[Environment Variables]
|
|
DB[(Database Settings<br/>per-user)]
|
|
JSON[Default Settings<br/>default_settings.json]
|
|
end
|
|
|
|
subgraph "Settings Management"
|
|
SM[SettingsManager<br/>manager.py]
|
|
end
|
|
|
|
subgraph "Runtime Access"
|
|
SNAP[Settings Snapshot<br/>Thread-safe copy]
|
|
TC[Thread Context<br/>thread_settings.py]
|
|
end
|
|
|
|
ENV --> SM
|
|
JSON --> SM
|
|
DB --> SM
|
|
SM --> SNAP
|
|
SNAP --> TC
|
|
```
|
|
|
|
**Configuration Flow:**
|
|
|
|
1. **Defaults** - Default settings loaded from JSON
|
|
2. **Environment** - Environment variables override defaults
|
|
3. **Database** - User settings loaded from encrypted per-user DB
|
|
4. **Snapshot** - Thread-safe copy created for each research
|
|
5. **Access** - Code reads from snapshot via thread context
|
|
|
|
**Key Settings Categories:**
|
|
|
|
| Category | Examples |
|
|
|----------|----------|
|
|
| `llm.*` | Provider, model, temperature, API keys |
|
|
| `search.*` | Engine selection, max results, rate limits |
|
|
| `app.*` | Debug mode, logging, UI preferences |
|
|
| `notifications.*` | Email, webhook configurations |
|
|
|
|
---
|
|
|
|
## Key Interfaces
|
|
|
|
### Search Engine Interface
|
|
|
|
All search engines implement `BaseSearchEngine`:
|
|
|
|
```python
|
|
class BaseSearchEngine(ABC):
|
|
# Classification flags
|
|
is_public: bool = True
|
|
is_generic: bool = True
|
|
is_scientific: bool = False
|
|
is_local: bool = False
|
|
is_news: bool = False
|
|
is_code: bool = False
|
|
is_lexical: bool = False
|
|
needs_llm_relevance_filter: bool = False
|
|
|
|
@abstractmethod
|
|
def run(self, query: str) -> List[Dict[str, Any]]:
|
|
"""Execute search and return results."""
|
|
# Returns: [{"title": ..., "link": ..., "snippet": ...}]
|
|
```
|
|
|
|
### Strategy Interface
|
|
|
|
All strategies implement `BaseSearchStrategy`:
|
|
|
|
```python
|
|
class BaseSearchStrategy(ABC):
|
|
def __init__(self, search, model, all_links_of_system,
|
|
settings_snapshot, **kwargs):
|
|
...
|
|
|
|
@abstractmethod
|
|
def analyze_topic(self, query: str) -> Dict:
|
|
"""Execute research strategy."""
|
|
# Returns: {
|
|
# "findings": [...],
|
|
# "iterations": int,
|
|
# "questions": {...},
|
|
# "formatted_findings": str,
|
|
# "current_knowledge": {...}
|
|
# }
|
|
```
|
|
|
|
### LLM Provider Interface
|
|
|
|
All providers extend `BaseLLMProvider` (most extend `OpenAICompatibleProvider`):
|
|
|
|
```python
|
|
class OpenAICompatibleProvider(BaseLLMProvider):
|
|
provider_name: str
|
|
api_key_setting: str | None # Settings key, or None for no-key providers
|
|
api_key_optional: bool = False # If True, missing key uses placeholder
|
|
url_setting: str
|
|
default_base_url: str
|
|
default_model: str
|
|
|
|
@classmethod
|
|
def create_llm(cls, model_name, temperature, **kwargs) -> BaseChatModel:
|
|
"""Create LangChain LLM instance."""
|
|
```
|
|
|
|
---
|
|
|
|
## Directory Structure
|
|
|
|
```
|
|
src/local_deep_research/
|
|
├── search_system.py # Main orchestrator
|
|
├── search_system_factory.py # Strategy factory
|
|
├── report_generator.py # Report generation
|
|
├── citation_handler.py # Citation processing
|
|
│
|
|
├── web/ # Flask application
|
|
│ ├── app.py # Entry point
|
|
│ ├── app_factory.py # App creation
|
|
│ ├── routes/ # Blueprint handlers
|
|
│ ├── services/ # Business logic
|
|
│ ├── queue/ # Task queue
|
|
│ └── auth/ # Authentication
|
|
│
|
|
├── advanced_search_system/ # Search strategies
|
|
│ ├── strategies/ # 32 strategy implementations
|
|
│ ├── questions/ # Question generation
|
|
│ ├── findings/ # Findings management
|
|
│ └── ...
|
|
│
|
|
├── web_search_engines/ # Search engines
|
|
│ ├── engines/ # 30+ engine implementations
|
|
│ ├── search_engine_base.py # Abstract base
|
|
│ ├── search_engine_factory.py
|
|
│ └── rate_limiting/ # Adaptive rate limiting
|
|
│
|
|
├── database/ # Data layer
|
|
│ ├── models/ # 20+ ORM models
|
|
│ ├── session_context.py # Session management
|
|
│ └── encrypted_db.py # SQLCipher
|
|
│
|
|
├── llm/ # LLM integration
|
|
│ ├── providers/ # Provider implementations
|
|
│ └── llm_registry.py # Custom LLM registration
|
|
│
|
|
├── config/ # Configuration
|
|
│ ├── llm_config.py # LLM setup
|
|
│ ├── search_config.py # Search setup
|
|
│ └── thread_settings.py # Thread context
|
|
│
|
|
├── settings/ # Settings management
|
|
│ └── manager.py # SettingsManager
|
|
│
|
|
└── api/ # Programmatic API
|
|
├── client.py # HTTP client
|
|
└── research_functions.py # Direct functions
|
|
```
|
|
|
|
---
|
|
|
|
## See Also
|
|
|
|
- [Database Schema](./DATABASE_SCHEMA.md) - Detailed data model documentation
|
|
- [Semantic Search](./SEMANTIC_SEARCH.md) - Indexing pipeline, search modes, and three-tier merge algorithm
|
|
- [Extension Guide](../developing/EXTENDING.md) - How to add custom components
|
|
- [Troubleshooting](../troubleshooting.md) - Common issues and solutions
|