diff --git a/CLAUDE.md b/CLAUDE.md index 75c50699..17316e44 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -84,29 +84,15 @@ PostgreSQL with pgvector. Schema managed via Alembic migrations in `hindsight-ap Key tables: `banks`, `memory_units`, `documents`, `entities`, `entity_links` -### Database Backups (IMPORTANT) -**Before any operation that may affect the database, run a backup:** -```bash -docker exec hindsight /backups/backup.sh -``` - -Operations requiring backup: -- Running database migrations -- Modifying Alembic migration files -- Rebuilding Docker images -- Resetting or recreating containers -- Any schema changes -- Bulk data operations - -Backups are stored in `~/hindsight-backups/` on the host. - -To restore: -```bash -docker exec -it hindsight /backups/restore.sh -``` - ## Key Conventions +### Code Quality +**Always run the lint script after making Python or TypeScript/Node changes:** +```bash +./scripts/hooks/lint.sh +``` +This runs the same checks as the pre-commit hook (Ruff for Python, ESLint/Prettier for TypeScript). + ### Memory Banks - Each bank is isolated (no cross-bank data access) - Banks have dispositions (skepticism, literalism, empathy traits 1-5) affecting reflect @@ -127,6 +113,29 @@ docker exec -it hindsight /backups/restore.sh - Next.js App Router for control plane - Tailwind CSS with shadcn/ui components +### Adding New API Configuration Flags + +When adding a new environment variable configuration: + +1. **config.py** (`hindsight-api/hindsight_api/config.py`): + - Add `ENV_*` constant for the environment variable name + - Add `DEFAULT_*` constant for the default value + - Add field to `HindsightConfig` dataclass + - Add initialization in `from_env()` method + +2. **main.py** (`hindsight-api/hindsight_api/main.py`): + - Add field to the manual `HindsightConfig()` constructor call (search for "CLI override") + +3. **Use the config** in code: + ```python + from ...config import get_config + config = get_config() + value = config.your_new_field + ``` + +4. **Documentation** (`hindsight-docs/docs/developer/configuration.md`): + - Add to appropriate section table with Variable, Description, Default + ## Environment Setup ```bash diff --git a/hindsight-api/hindsight_api/config.py b/hindsight-api/hindsight_api/config.py index 2acac6f1..898a3685 100644 --- a/hindsight-api/hindsight_api/config.py +++ b/hindsight-api/hindsight_api/config.py @@ -47,6 +47,9 @@ ENV_MCP_INSTRUCTIONS = "HINDSIGHT_API_MCP_INSTRUCTIONS" ENV_OBSERVATION_MIN_FACTS = "HINDSIGHT_API_OBSERVATION_MIN_FACTS" ENV_OBSERVATION_TOP_ENTITIES = "HINDSIGHT_API_OBSERVATION_TOP_ENTITIES" +# Retain settings +ENV_RETAIN_MAX_COMPLETION_TOKENS = "HINDSIGHT_API_RETAIN_MAX_COMPLETION_TOKENS" + # Optimization flags ENV_SKIP_LLM_VERIFICATION = "HINDSIGHT_API_SKIP_LLM_VERIFICATION" ENV_LAZY_RERANKER = "HINDSIGHT_API_LAZY_RERANKER" @@ -77,6 +80,9 @@ DEFAULT_MCP_LOCAL_BANK_ID = "mcp" DEFAULT_OBSERVATION_MIN_FACTS = 5 # Min facts required to generate entity observations DEFAULT_OBSERVATION_TOP_ENTITIES = 5 # Max entities to process per retain batch +# Retain settings +DEFAULT_RETAIN_MAX_COMPLETION_TOKENS = 64000 # Max tokens for fact extraction LLM call + # Default MCP tool descriptions (can be customized via env vars) DEFAULT_MCP_RETAIN_DESCRIPTION = """Store important information to long-term memory. @@ -139,6 +145,9 @@ class HindsightConfig: observation_min_facts: int observation_top_entities: int + # Retain settings + retain_max_completion_tokens: int + # Optimization flags skip_llm_verification: bool lazy_reranker: bool @@ -179,6 +188,10 @@ class HindsightConfig: observation_top_entities=int( os.getenv(ENV_OBSERVATION_TOP_ENTITIES, str(DEFAULT_OBSERVATION_TOP_ENTITIES)) ), + # Retain settings + retain_max_completion_tokens=int( + os.getenv(ENV_RETAIN_MAX_COMPLETION_TOKENS, str(DEFAULT_RETAIN_MAX_COMPLETION_TOKENS)) + ), ) def get_llm_base_url(self) -> str: @@ -225,6 +238,19 @@ class HindsightConfig: logger.info(f"Graph retriever: {self.graph_retriever}") +# Cached config instance +_config_cache: HindsightConfig | None = None + + def get_config() -> HindsightConfig: - """Get the current configuration from environment variables.""" - return HindsightConfig.from_env() + """Get the cached configuration, loading from environment on first call.""" + global _config_cache + if _config_cache is None: + _config_cache = HindsightConfig.from_env() + return _config_cache + + +def clear_config_cache() -> None: + """Clear the config cache. Useful for testing or reloading config.""" + global _config_cache + _config_cache = None diff --git a/hindsight-api/hindsight_api/engine/retain/fact_extraction.py b/hindsight-api/hindsight_api/engine/retain/fact_extraction.py index f8c35738..63cbf88c 100644 --- a/hindsight-api/hindsight_api/engine/retain/fact_extraction.py +++ b/hindsight-api/hindsight_api/engine/retain/fact_extraction.py @@ -14,6 +14,7 @@ from typing import Literal from pydantic import BaseModel, ConfigDict, Field, field_validator +from ...config import get_config from ..llm_wrapper import LLMConfig, OutputTooLongError @@ -583,6 +584,7 @@ WHAT TO EXTRACT vs SKIP # Retry logic for JSON validation errors max_retries = 2 last_error = None + config = get_config() # Sanitize input text to prevent Unicode encoding errors (e.g., unpaired surrogates) sanitized_chunk = _sanitize_text(chunk) @@ -608,7 +610,7 @@ Text: response_format=FactExtractionResponse, scope="memory_extract_facts", temperature=0.1, - max_completion_tokens=65000, + max_completion_tokens=config.retain_max_completion_tokens, skip_validation=True, # Get raw JSON, we'll validate leniently ) diff --git a/hindsight-api/hindsight_api/main.py b/hindsight-api/hindsight_api/main.py index 398fb73f..7f973f52 100644 --- a/hindsight-api/hindsight_api/main.py +++ b/hindsight-api/hindsight_api/main.py @@ -184,6 +184,7 @@ def main(): graph_retriever=config.graph_retriever, observation_min_facts=config.observation_min_facts, observation_top_entities=config.observation_top_entities, + retain_max_completion_tokens=config.retain_max_completion_tokens, skip_llm_verification=config.skip_llm_verification, lazy_reranker=config.lazy_reranker, ) diff --git a/hindsight-docs/docs/developer/configuration.md b/hindsight-docs/docs/developer/configuration.md index 04ca35ff..9ef9593a 100644 --- a/hindsight-docs/docs/developer/configuration.md +++ b/hindsight-docs/docs/developer/configuration.md @@ -183,6 +183,14 @@ Controls when the system generates entity observations (summaries about entities | `HINDSIGHT_API_OBSERVATION_MIN_FACTS` | Minimum facts about an entity before generating observations | `5` | | `HINDSIGHT_API_OBSERVATION_TOP_ENTITIES` | Max entities to process per retain batch | `5` | +### Retain + +Controls the retain (memory ingestion) pipeline. + +| Variable | Description | Default | +|----------|-------------|---------| +| `HINDSIGHT_API_RETAIN_MAX_COMPLETION_TOKENS` | Max completion tokens for fact extraction LLM calls | `64000` | + ### Local MCP Server Configuration for the local MCP server (`hindsight-local-mcp` command).