Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 81 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -65,17 +71,23 @@ 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=

# ── 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
Expand All @@ -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
Expand All @@ -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
Expand Down
21 changes: 21 additions & 0 deletions tests/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 ─────────────────────────────────────────────────────


Expand Down