Joseph Pollack
implements documentation improvements
d45d242
Implementation Patterns
This document outlines common implementation patterns used in The DETERMINATOR.
Search Tools
All tools implement SearchTool protocol (src/tools/base.py):
- Must have
name property
- Must implement
async def search(query, max_results) -> list[Evidence]
- Use
@retry decorator from tenacity for resilience
- Rate limiting: Implement
_rate_limit() for APIs with limits (e.g., PubMed)
- Error handling: Raise
SearchError or RateLimitError on failures
Example pattern:
class MySearchTool:
@property
def name(self) -> str:
return "mytool"
@retry(stop=stop_after_attempt(3), wait=wait_exponential(...))
async def search(self, query: str, max_results: int = 10) -> list[Evidence]:
return evidence_list
Judge Handlers
- Implement
JudgeHandlerProtocol (async def assess(question, evidence) -> JudgeAssessment)
- Use pydantic-ai
Agent with output_type=JudgeAssessment
- System prompts in
src/prompts/judge.py
- Support fallback handlers:
MockJudgeHandler, HFInferenceJudgeHandler
- Always return valid
JudgeAssessment (never raise exceptions)
Agent Factory Pattern
- Use factory functions for creating agents (
src/agent_factory/)
- Lazy initialization for optional dependencies (e.g., embeddings, Modal)
- Check requirements before initialization:
Check Magentic Requirements start_line:152 end_line:170
State Management
- Magentic Mode: Use
ContextVar for thread-safe state (src/agents/state.py)
- Simple Mode: Pass state via function parameters
- Never use global mutable state (except singletons via
@lru_cache)
Singleton Pattern
Use @lru_cache(maxsize=1) for singletons:
Singleton Pattern Example start_line:252 end_line:255
- Lazy initialization to avoid requiring dependencies at import time
See Also