diff --git a/.env.example b/.env.example index e8943b8..c748760 100644 --- a/.env.example +++ b/.env.example @@ -44,16 +44,22 @@ STATEWAVE_EMBEDDING_PROVIDER=stub # STATEWAVE_EMBEDDING_PROVIDER=litellm # STATEWAVE_LITELLM_API_KEY=sk-... # STATEWAVE_LITELLM_MODEL=gpt-4o-mini +# STATEWAVE_LITELLM_COMPILE_MODEL= # empty = use STATEWAVE_LITELLM_MODEL # STATEWAVE_LITELLM_EMBEDDING_MODEL=text-embedding-3-small # STATEWAVE_LITELLM_API_BASE= # e.g. http://host.docker.internal:11434 for Ollama +# STATEWAVE_LITELLM_EMBEDDING_API_BASE= # empty = use STATEWAVE_LITELLM_API_BASE # STATEWAVE_LITELLM_TIMEOUT_SECONDS=60 # STATEWAVE_LITELLM_MAX_RETRIES=2 +# STATEWAVE_LITELLM_SLOW_CALL_SECONDS=10 # STATEWAVE_LITELLM_TEMPERATURE=0.1 +# STATEWAVE_LITELLM_REASONING_EFFORT= # e.g. minimal, low, medium, high +# STATEWAVE_LITELLM_COMPILE_MAX_TOKENS=16000 # ── Database ───────────────────────────────────────────────── # Docker compose overrides this to point at the `db` service. Set this # only if you're running the API against a database OUTSIDE compose. # STATEWAVE_DATABASE_URL=postgresql+asyncpg://statewave:statewave@localhost:5432/statewave +# STATEWAVE_DATABASE_ECHO=false # ── Docker Compose — Host Port Overrides ──────────────────── # For local development: override the default host ports to resolve @@ -65,10 +71,15 @@ STATEWAVE_EMBEDDING_PROVIDER=stub # STATEWAVE_ADMIN_HOST_PORT=8080 # ── Server ─────────────────────────────────────────────────── -# STATEWAVE_DEBUG=true +# STATEWAVE_APP_NAME=statewave +# STATEWAVE_DEBUG=false # STATEWAVE_HOST=0.0.0.0 # STATEWAVE_PORT=8100 +# ── Context assembly ───────────────────────────────────────── +# STATEWAVE_TIKTOKEN_MODEL=cl100k_base +# STATEWAVE_DEFAULT_MAX_CONTEXT_TOKENS=4000 + # ── Authentication ─────────────────────────────────────────── # Set a key to require X-API-Key auth. Leave empty for open access. # STATEWAVE_API_KEY= @@ -76,6 +87,7 @@ STATEWAVE_EMBEDDING_PROVIDER=stub # ── Rate Limiting ──────────────────────────────────────────── # Requests per minute per client IP. 0 = disabled. # STATEWAVE_RATE_LIMIT_RPM=0 +# STATEWAVE_RATE_LIMIT_STRATEGY=memory # memory | distributed # ── Embedding dimensions ───────────────────────────────────── # STATEWAVE_EMBEDDING_DIMENSIONS=1536 @@ -84,6 +96,13 @@ STATEWAVE_EMBEDDING_PROVIDER=stub # HTTP endpoint for event notifications. Empty = disabled. # STATEWAVE_WEBHOOK_URL= # STATEWAVE_WEBHOOK_TIMEOUT=5.0 +# Comma-separated allowlist. Empty = deliver every event. +# STATEWAVE_WEBHOOK_EVENTS= + +# ── Receipt signing ─────────────────────────────────────────── +# JSON object of key IDs to base64-encoded HMAC keys (minimum 32 bytes). +# Empty JSON object = unsigned receipts. +# STATEWAVE_RECEIPT_SIGNING_KEYS={} # ── Multi-tenant (app-layer isolation — see README limitations) ── # STATEWAVE_TENANT_HEADER=X-Tenant-ID @@ -93,6 +112,67 @@ STATEWAVE_EMBEDDING_PROVIDER=stub # JSON array of allowed origins. ["*"] for local dev. # STATEWAVE_CORS_ORIGINS=["*"] +# ── Compilation ─────────────────────────────────────────────── +# Batch and retention limits. +# STATEWAVE_COMPILE_BATCH_SIZE=500 +# STATEWAVE_COMPILE_MAX_ITERATIONS=2000 +# STATEWAVE_COMPILE_JOB_RETENTION_HOURS=168 +# STATEWAVE_COMPILE_MAX_EPISODE_CHARS=60000 +# STATEWAVE_COMPILE_WINDOW_CHARS=6000 +# STATEWAVE_COMPILE_WINDOW_OVERLAP=200 +# STATEWAVE_COMPILE_MAX_CONCURRENCY=4 + +# Message-level extraction and recall controls. +# STATEWAVE_COMPILE_MESSAGE_LEVEL=false +# STATEWAVE_COMPILE_MESSAGES_PER_CHUNK=6 +# STATEWAVE_COMPILE_MESSAGE_OVERLAP=1 +# STATEWAVE_COMPILE_RECALL_SWEEP=false +# STATEWAVE_COMPILE_COMPOSE_UNIT=false + +# ── Compile-time reconciliation ─────────────────────────────── +# STATEWAVE_RECONCILE_COMPILE_ENABLED=true +# STATEWAVE_RECONCILE_CUMULATIVE_MERGE=false +# STATEWAVE_RECONCILE_CHUNK_SIZE=40 +# STATEWAVE_RECONCILE_CHUNK_TIMEOUT_SECONDS=30 +# STATEWAVE_RECONCILE_MAX_CANDIDATES=4000 +# STATEWAVE_RECONCILE_MAX_EXISTING=60 +# STATEWAVE_RECONCILE_TOP_K_PER_CANDIDATE=5 + +# ── Deduplication and reranking ─────────────────────────────── +# STATEWAVE_DEDUP_COMPILE_ENABLED=true +# STATEWAVE_DEDUP_SEMANTIC_ENABLED=true +# STATEWAVE_DEDUP_SIM_THRESHOLD=0.95 +# STATEWAVE_DEDUP_MAX_CANDIDATES=4000 +# STATEWAVE_RERANK_MAX_POOL=100 +# STATEWAVE_RERANK_MODEL= # empty = use the compile model + +# ── Entity extraction ───────────────────────────────────────── +# STATEWAVE_ENTITY_POPULATION_ENABLED=true +# STATEWAVE_ENTITY_EXTRACT_BATCH_SIZE=10 +# STATEWAVE_ENTITY_EXTRACT_CONCURRENCY=8 + +# ── Snapshots and labeling ──────────────────────────────────── +# STATEWAVE_ENABLE_SNAPSHOTS=false +# STATEWAVE_AUTO_LABELING_ENABLED=false +# STATEWAVE_AUTO_LABELING_PROVIDER=heuristic + +# ── Deployment safeguards ───────────────────────────────────── +# Set REGION for multi-region deployments; empty keeps single-region mode. +# STATEWAVE_REGION= +# Refuse startup when the database schema revision does not match. +# STATEWAVE_STRICT_SCHEMA=false + +# ── Bundled support memory ──────────────────────────────────── +# STATEWAVE_SUPPORT_SUBJECT_ID=statewave-support-docs +# STATEWAVE_SUPPORT_STARTER_PACK_ID=statewave-support-agent + +# ── Memory import limits ────────────────────────────────────── +# Guardrails applied to starter-pack, clone, and bulk imports. +# STATEWAVE_MEMORY_IMPORT_MAX_BYTES=52428800 +# STATEWAVE_MEMORY_IMPORT_MAX_EPISODES=50000 +# STATEWAVE_MEMORY_IMPORT_MAX_MEMORIES=50000 +# STATEWAVE_MEMORY_IMPORT_MAX_SUBJECTS=100 + # ── Memory TTL / expiry (v0.7.2+) ──────────────────────────── # Per-kind global expiry windows. JSON object keyed by MemoryKind: # profile_fact | episode_summary | procedure | artifact_ref diff --git a/tests/test_config.py b/tests/test_config.py index 5bd7814..f29524a 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -2,11 +2,32 @@ from __future__ import annotations +import re +from pathlib import Path + import pytest from server.core.config import Settings +def test_env_example_documents_every_setting(): + """Keep the operator-facing environment inventory in sync with Settings — + BOTH directions: a missing entry hides a setting from operators, and a + stale entry documents a knob that no longer exists.""" + env_example = (Path(__file__).parents[1] / ".env.example").read_text(encoding="utf-8") + documented = set(re.findall(r"^#?\s*(STATEWAVE_[A-Z0-9_]+)\s*=", env_example, re.MULTILINE)) + expected = {f"STATEWAVE_{name.upper()}" for name in Settings.model_fields} + # Compose-only host-port vars are legitimately not Settings fields. + documented -= {"STATEWAVE_API_HOST_PORT", "STATEWAVE_DB_HOST_PORT", "STATEWAVE_ADMIN_HOST_PORT"} + + assert expected <= documented, "Settings missing from .env.example: " + ", ".join( + sorted(expected - documented) + ) + assert documented <= expected, ".env.example documents settings that no longer exist: " + ", ".join( + sorted(documented - expected) + ) + + # ── rate_limit_strategy ─────────────────────────────────────────────────────