Spaces:
Running
A newer version of the Gradio SDK is available:
6.1.0
Configuration Guide
Overview
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.
The configuration system provides:
- Type Safety: Strongly-typed fields with Pydantic validation
- Environment File Support: Automatically loads from
.envfile (if present) - Case-Insensitive: Environment variables are case-insensitive
- Singleton Pattern: Global
settingsinstance for easy access throughout the codebase - Validation: Automatic validation on load with helpful error messages
Quick Start
- Create a
.envfile in the project root - Set at least one LLM API key (
OPENAI_API_KEY,ANTHROPIC_API_KEY, orHF_TOKEN) - Optionally configure other services as needed
- The application will automatically load and validate your configuration
Configuration System Architecture
Settings Class
The [Settings][settings-class] class extends BaseSettings from pydantic_settings and defines all application configuration:
class Settings(BaseSettings):
"""Strongly-typed application settings."""
model_config = SettingsConfigDict(
env_file=".env",
env_file_encoding="utf-8",
case_sensitive=False,
extra="ignore",
)
Singleton Instance
A global settings instance is available for import:
# Singleton for easy import
settings = get_settings()
Usage Pattern
Access configuration throughout the codebase:
from src.utils.config import settings
# Check if API keys are available
if settings.has_openai_key:
# Use OpenAI
pass
# Access configuration values
max_iterations = settings.max_iterations
web_search_provider = settings.web_search_provider
Required Configuration
LLM Provider
You must configure at least one LLM provider. The system supports:
- OpenAI: Requires
OPENAI_API_KEY - Anthropic: Requires
ANTHROPIC_API_KEY - HuggingFace: Optional
HF_TOKENorHUGGINGFACE_API_KEY(can work without key for public models)
OpenAI Configuration
LLM_PROVIDER=openai
OPENAI_API_KEY=your_openai_api_key_here
OPENAI_MODEL=gpt-5.1
The default model is defined in the Settings class:
openai_model: str = Field(default="gpt-5.1", description="OpenAI model name")
Anthropic Configuration
LLM_PROVIDER=anthropic
ANTHROPIC_API_KEY=your_anthropic_api_key_here
ANTHROPIC_MODEL=claude-sonnet-4-5-20250929
The default model is defined in the Settings class:
anthropic_model: str = Field(
default="claude-sonnet-4-5-20250929", description="Anthropic model"
)
HuggingFace Configuration
HuggingFace can work without an API key for public models, but an API key provides higher rate limits:
# Option 1: Using HF_TOKEN (preferred)
HF_TOKEN=your_huggingface_token_here
# Option 2: Using HUGGINGFACE_API_KEY (alternative)
HUGGINGFACE_API_KEY=your_huggingface_api_key_here
# Default model
HUGGINGFACE_MODEL=meta-llama/Llama-3.1-8B-Instruct
The HuggingFace token can be set via either environment variable:
hf_token: str | None = Field(
default=None, alias="HF_TOKEN", description="HuggingFace API token"
)
huggingface_api_key: str | None = Field(
default=None, description="HuggingFace API token (HF_TOKEN or HUGGINGFACE_API_KEY)"
)
Optional Configuration
Embedding Configuration
DeepCritical supports multiple embedding providers for semantic search and RAG:
# Embedding Provider: "openai", "local", or "huggingface"
EMBEDDING_PROVIDER=local
# OpenAI Embedding Model (used by LlamaIndex RAG)
OPENAI_EMBEDDING_MODEL=text-embedding-3-small
# Local Embedding Model (sentence-transformers, used by EmbeddingService)
LOCAL_EMBEDDING_MODEL=all-MiniLM-L6-v2
# HuggingFace Embedding Model
HUGGINGFACE_EMBEDDING_MODEL=sentence-transformers/all-MiniLM-L6-v2
The embedding provider configuration:
embedding_provider: Literal["openai", "local", "huggingface"] = Field(
default="local",
description="Embedding provider to use",
)
Note: OpenAI embeddings require OPENAI_API_KEY. The local provider (default) uses sentence-transformers and requires no API key.
Web Search Configuration
DeepCritical supports multiple web search providers:
# Web Search Provider: "serper", "searchxng", "brave", "tavily", or "duckduckgo"
# Default: "duckduckgo" (no API key required)
WEB_SEARCH_PROVIDER=duckduckgo
# Serper API Key (for Google search via Serper)
SERPER_API_KEY=your_serper_api_key_here
# SearchXNG Host URL (for self-hosted search)
SEARCHXNG_HOST=http://localhost:8080
# Brave Search API Key
BRAVE_API_KEY=your_brave_api_key_here
# Tavily API Key
TAVILY_API_KEY=your_tavily_api_key_here
The web search provider configuration:
web_search_provider: Literal["serper", "searchxng", "brave", "tavily", "duckduckgo"] = Field(
default="duckduckgo",
description="Web search provider to use",
)
Note: DuckDuckGo is the default and requires no API key, making it ideal for development and testing.
PubMed Configuration
PubMed search supports optional NCBI API key for higher rate limits:
# NCBI API Key (optional, for higher rate limits: 10 req/sec vs 3 req/sec)
NCBI_API_KEY=your_ncbi_api_key_here
The PubMed tool uses this configuration:
def __init__(self, api_key: str | None = None) -> None:
self.api_key = api_key or settings.ncbi_api_key
# Ignore placeholder values from .env.example
if self.api_key == "your-ncbi-key-here":
self.api_key = None
# Use shared rate limiter
self._limiter = get_pubmed_limiter(self.api_key)
Agent Configuration
Control agent behavior and research loop execution:
# Maximum iterations per research loop (1-50, default: 10)
MAX_ITERATIONS=10
# Search timeout in seconds
SEARCH_TIMEOUT=30
# Use graph-based execution for research flows
USE_GRAPH_EXECUTION=false
The agent configuration fields:
# Agent Configuration
max_iterations: int = Field(default=10, ge=1, le=50)
search_timeout: int = Field(default=30, description="Seconds to wait for search")
use_graph_execution: bool = Field(
default=False, description="Use graph-based execution for research flows"
)
Budget & Rate Limiting Configuration
Control resource limits for research loops:
# Default token budget per research loop (1000-1000000, default: 100000)
DEFAULT_TOKEN_LIMIT=100000
# Default time limit per research loop in minutes (1-120, default: 10)
DEFAULT_TIME_LIMIT_MINUTES=10
# Default iterations limit per research loop (1-50, default: 10)
DEFAULT_ITERATIONS_LIMIT=10
The budget configuration with validation:
# Budget & Rate Limiting Configuration
default_token_limit: int = Field(
default=100000,
ge=1000,
le=1000000,
description="Default token budget per research loop",
)
default_time_limit_minutes: int = Field(
default=10,
ge=1,
le=120,
description="Default time limit per research loop (minutes)",
)
default_iterations_limit: int = Field(
default=10,
ge=1,
le=50,
description="Default iterations limit per research loop",
)
RAG Service Configuration
Configure the Retrieval-Augmented Generation service:
# ChromaDB collection name for RAG
RAG_COLLECTION_NAME=deepcritical_evidence
# Number of top results to retrieve from RAG (1-50, default: 5)
RAG_SIMILARITY_TOP_K=5
# Automatically ingest evidence into RAG
RAG_AUTO_INGEST=true
The RAG configuration:
# RAG Service Configuration
rag_collection_name: str = Field(
default="deepcritical_evidence",
description="ChromaDB collection name for RAG",
)
rag_similarity_top_k: int = Field(
default=5,
ge=1,
le=50,
description="Number of top results to retrieve from RAG",
)
rag_auto_ingest: bool = Field(
default=True,
description="Automatically ingest evidence into RAG",
)
ChromaDB Configuration
Configure the vector database for embeddings and RAG:
# ChromaDB storage path
CHROMA_DB_PATH=./chroma_db
# Whether to persist ChromaDB to disk
CHROMA_DB_PERSIST=true
# ChromaDB server host (for remote ChromaDB, optional)
CHROMA_DB_HOST=localhost
# ChromaDB server port (for remote ChromaDB, optional)
CHROMA_DB_PORT=8000
The ChromaDB configuration:
chroma_db_path: str = Field(default="./chroma_db", description="ChromaDB storage path")
chroma_db_persist: bool = Field(
default=True,
description="Whether to persist ChromaDB to disk",
)
chroma_db_host: str | None = Field(
default=None,
description="ChromaDB server host (for remote ChromaDB)",
)
chroma_db_port: int | None = Field(
default=None,
description="ChromaDB server port (for remote ChromaDB)",
)
External Services
Modal Configuration
Modal is used for secure sandbox execution of statistical analysis:
# Modal Token ID (for Modal sandbox execution)
MODAL_TOKEN_ID=your_modal_token_id_here
# Modal Token Secret
MODAL_TOKEN_SECRET=your_modal_token_secret_here
The Modal configuration:
# External Services
modal_token_id: str | None = Field(default=None, description="Modal token ID")
modal_token_secret: str | None = Field(default=None, description="Modal token secret")
Logging Configuration
Configure structured logging:
# Log Level: "DEBUG", "INFO", "WARNING", or "ERROR"
LOG_LEVEL=INFO
The logging configuration:
# Logging
log_level: Literal["DEBUG", "INFO", "WARNING", "ERROR"] = "INFO"
Logging is configured via the configure_logging() function:
def configure_logging(settings: Settings) -> None:
"""Configure structured logging with the configured log level."""
# Set stdlib logging level from settings
logging.basicConfig(
level=getattr(logging, settings.log_level),
format="%(message)s",
)
structlog.configure(
processors=[
structlog.stdlib.filter_by_level,
structlog.stdlib.add_logger_name,
structlog.stdlib.add_log_level,
structlog.processors.TimeStamper(fmt="iso"),
structlog.processors.JSONRenderer(),
],
wrapper_class=structlog.stdlib.BoundLogger,
context_class=dict,
logger_factory=structlog.stdlib.LoggerFactory(),
)
Configuration Properties
The Settings class provides helpful properties for checking configuration state:
API Key Availability
Check which API keys are available:
@property
def has_openai_key(self) -> bool:
"""Check if OpenAI API key is available."""
return bool(self.openai_api_key)
@property
def has_anthropic_key(self) -> bool:
"""Check if Anthropic API key is available."""
return bool(self.anthropic_api_key)
@property
def has_huggingface_key(self) -> bool:
"""Check if HuggingFace API key is available."""
return bool(self.huggingface_api_key or self.hf_token)
@property
def has_any_llm_key(self) -> bool:
"""Check if any LLM API key is available."""
return self.has_openai_key or self.has_anthropic_key or self.has_huggingface_key
Usage:
from src.utils.config import settings
# Check API key availability
if settings.has_openai_key:
# Use OpenAI
pass
if settings.has_anthropic_key:
# Use Anthropic
pass
if settings.has_huggingface_key:
# Use HuggingFace
pass
if settings.has_any_llm_key:
# At least one LLM is available
pass
Service Availability
Check if external services are configured:
@property
def modal_available(self) -> bool:
"""Check if Modal credentials are configured."""
return bool(self.modal_token_id and self.modal_token_secret)
@property
def web_search_available(self) -> bool:
"""Check if web search is available (either no-key provider or API key present)."""
if self.web_search_provider == "duckduckgo":
return True # No API key required
if self.web_search_provider == "serper":
return bool(self.serper_api_key)
if self.web_search_provider == "searchxng":
return bool(self.searchxng_host)
if self.web_search_provider == "brave":
return bool(self.brave_api_key)
if self.web_search_provider == "tavily":
return bool(self.tavily_api_key)
return False
Usage:
from src.utils.config import settings
# Check service availability
if settings.modal_available:
# Use Modal sandbox
pass
if settings.web_search_available:
# Web search is configured
pass
API Key Retrieval
Get the API key for the configured provider:
def get_api_key(self) -> str:
"""Get the API key for the configured provider."""
if self.llm_provider == "openai":
if not self.openai_api_key:
raise ConfigurationError("OPENAI_API_KEY not set")
return self.openai_api_key
if self.llm_provider == "anthropic":
if not self.anthropic_api_key:
raise ConfigurationError("ANTHROPIC_API_KEY not set")
return self.anthropic_api_key
raise ConfigurationError(f"Unknown LLM provider: {self.llm_provider}")
For OpenAI-specific operations (e.g., Magentic mode):
def get_openai_api_key(self) -> str:
"""Get OpenAI API key (required for Magentic function calling)."""
if not self.openai_api_key:
raise ConfigurationError(
"OPENAI_API_KEY not set. Magentic mode requires OpenAI for function calling. "
"Use mode='simple' for other providers."
)
return self.openai_api_key
Configuration Usage in Codebase
The configuration system is used throughout the codebase:
LLM Factory
The LLM factory uses settings to create appropriate models:
if settings.llm_provider == "huggingface":
model_name = settings.huggingface_model or "meta-llama/Llama-3.1-8B-Instruct"
hf_provider = HuggingFaceProvider(api_key=settings.hf_token)
return HuggingFaceModel(model_name, provider=hf_provider)
if settings.llm_provider == "openai":
if not settings.openai_api_key:
raise ConfigurationError("OPENAI_API_KEY not set for pydantic-ai")
provider = OpenAIProvider(api_key=settings.openai_api_key)
return OpenAIModel(settings.openai_model, provider=provider)
if settings.llm_provider == "anthropic":
if not settings.anthropic_api_key:
raise ConfigurationError("ANTHROPIC_API_KEY not set for pydantic-ai")
anthropic_provider = AnthropicProvider(api_key=settings.anthropic_api_key)
return AnthropicModel(settings.anthropic_model, provider=anthropic_provider)
Embedding Service
The embedding service uses local embedding model configuration:
def __init__(self, model_name: str | None = None):
self._model_name = model_name or settings.local_embedding_model
self._model = SentenceTransformer(self._model_name)
Orchestrator Factory
The orchestrator factory uses settings to determine mode:
def _determine_mode(explicit_mode: str | None) -> str:
"""Determine which mode to use."""
if explicit_mode:
if explicit_mode in ("magentic", "advanced"):
return "advanced"
return "simple"
# Auto-detect: advanced if paid API key available
if settings.has_openai_key:
return "advanced"
return "simple"
Environment Variables Reference
Required (at least one LLM)
OPENAI_API_KEY- OpenAI API key (required for OpenAI provider)ANTHROPIC_API_KEY- Anthropic API key (required for Anthropic provider)HF_TOKENorHUGGINGFACE_API_KEY- HuggingFace API token (optional, can work without for public models)
LLM Configuration Variables
LLM_PROVIDER- Provider to use:"openai","anthropic", or"huggingface"(default:"huggingface")OPENAI_MODEL- OpenAI model name (default:"gpt-5.1")ANTHROPIC_MODEL- Anthropic model name (default:"claude-sonnet-4-5-20250929")HUGGINGFACE_MODEL- HuggingFace model ID (default:"meta-llama/Llama-3.1-8B-Instruct")
Embedding Configuration Variables
EMBEDDING_PROVIDER- Provider:"openai","local", or"huggingface"(default:"local")OPENAI_EMBEDDING_MODEL- OpenAI embedding model (default:"text-embedding-3-small")LOCAL_EMBEDDING_MODEL- Local sentence-transformers model (default:"all-MiniLM-L6-v2")HUGGINGFACE_EMBEDDING_MODEL- HuggingFace embedding model (default:"sentence-transformers/all-MiniLM-L6-v2")
Web Search Configuration Variables
WEB_SEARCH_PROVIDER- Provider:"serper","searchxng","brave","tavily", or"duckduckgo"(default:"duckduckgo")SERPER_API_KEY- Serper API key (required for Serper provider)SEARCHXNG_HOST- SearchXNG host URL (required for SearchXNG provider)BRAVE_API_KEY- Brave Search API key (required for Brave provider)TAVILY_API_KEY- Tavily API key (required for Tavily provider)
PubMed Configuration Variables
NCBI_API_KEY- NCBI API key (optional, increases rate limit from 3 to 10 req/sec)
Agent Configuration Variables
MAX_ITERATIONS- Maximum iterations per research loop (1-50, default:10)SEARCH_TIMEOUT- Search timeout in seconds (default:30)USE_GRAPH_EXECUTION- Use graph-based execution (default:false)
Budget Configuration Variables
DEFAULT_TOKEN_LIMIT- Default token budget per research loop (1000-1000000, default:100000)DEFAULT_TIME_LIMIT_MINUTES- Default time limit in minutes (1-120, default:10)DEFAULT_ITERATIONS_LIMIT- Default iterations limit (1-50, default:10)
RAG Configuration Variables
RAG_COLLECTION_NAME- ChromaDB collection name (default:"deepcritical_evidence")RAG_SIMILARITY_TOP_K- Number of top results to retrieve (1-50, default:5)RAG_AUTO_INGEST- Automatically ingest evidence into RAG (default:true)
ChromaDB Configuration Variables
CHROMA_DB_PATH- ChromaDB storage path (default:"./chroma_db")CHROMA_DB_PERSIST- Whether to persist ChromaDB to disk (default:true)CHROMA_DB_HOST- ChromaDB server host (optional, for remote ChromaDB)CHROMA_DB_PORT- ChromaDB server port (optional, for remote ChromaDB)
External Services Variables
MODAL_TOKEN_ID- Modal token ID (optional, for Modal sandbox execution)MODAL_TOKEN_SECRET- Modal token secret (optional, for Modal sandbox execution)
Logging Configuration Variables
LOG_LEVEL- Log level:"DEBUG","INFO","WARNING", or"ERROR"(default:"INFO")
Validation
Settings are validated on load using Pydantic validation:
- Type Checking: All fields are strongly typed
- Range Validation: Numeric fields have min/max constraints (e.g.,
ge=1, le=50formax_iterations) - Literal Validation: Enum fields only accept specific values (e.g.,
Literal["openai", "anthropic", "huggingface"]) - Required Fields: API keys are checked when accessed via
get_api_key()orget_openai_api_key()
Validation Examples
The max_iterations field has range validation:
max_iterations: int = Field(default=10, ge=1, le=50)
The llm_provider field has literal validation:
llm_provider: Literal["openai", "anthropic", "huggingface"] = Field(
default="openai", description="Which LLM provider to use"
)
Error Handling
Configuration errors raise ConfigurationError from src/utils/exceptions.py:
class ConfigurationError(DeepCriticalError):
"""Raised when configuration is invalid."""
pass
Error Handling Example
from src.utils.config import settings
from src.utils.exceptions import ConfigurationError
try:
api_key = settings.get_api_key()
except ConfigurationError as e:
print(f"Configuration error: {e}")
Common Configuration Errors
- Missing API Key: When
get_api_key()is called but the required API key is not set - Invalid Provider: When
llm_provideris set to an unsupported value - Out of Range: When numeric values exceed their min/max constraints
- Invalid Literal: When enum fields receive unsupported values
Configuration Best Practices
- Use
.envFile: Store sensitive keys in.envfile (add to.gitignore) - Check Availability: Use properties like
has_openai_keybefore accessing API keys - Handle Errors: Always catch
ConfigurationErrorwhen callingget_api_key() - Validate Early: Configuration is validated on import, so errors surface immediately
- Use Defaults: Leverage sensible defaults for optional configuration
Future Enhancements
The following configurations are planned for future phases:
- Additional LLM Providers: DeepSeek, OpenRouter, Gemini, Perplexity, Azure OpenAI, Local models
- Model Selection: Reasoning/main/fast model configuration
- Service Integration: Additional service integrations and configurations