| """
|
| HAIM Configuration System
|
| ========================
|
| Centralized, validated configuration with environment variable overrides.
|
| """
|
|
|
| import os
|
| from pathlib import Path
|
| from typing import Optional
|
| from dataclasses import dataclass, field
|
|
|
| import yaml
|
|
|
| from mnemocore.core.exceptions import ConfigurationError
|
|
|
|
|
| @dataclass(frozen=True)
|
| class TierConfig:
|
| max_memories: int
|
| ltp_threshold_min: float
|
| eviction_policy: str = "lru"
|
| consolidation_interval_hours: Optional[int] = None
|
| storage_backend: str = "memory"
|
| compression: str = "gzip"
|
| archive_threshold_days: int = 30
|
|
|
|
|
| @dataclass(frozen=True)
|
| class LTPConfig:
|
| initial_importance: float = 0.5
|
| decay_lambda: float = 0.01
|
| permanence_threshold: float = 0.95
|
| half_life_days: float = 30.0
|
|
|
|
|
| @dataclass(frozen=True)
|
| class HysteresisConfig:
|
| promote_delta: float = 0.15
|
| demote_delta: float = 0.10
|
|
|
|
|
| @dataclass(frozen=True)
|
| class RedisConfig:
|
| url: str = "redis://localhost:6379/0"
|
| stream_key: str = "haim:subconscious"
|
| max_connections: int = 10
|
| socket_timeout: int = 5
|
| password: Optional[str] = None
|
|
|
|
|
| @dataclass(frozen=True)
|
| class QdrantConfig:
|
| url: str = "http://localhost:6333"
|
| collection_hot: str = "haim_hot"
|
| collection_warm: str = "haim_warm"
|
| binary_quantization: bool = True
|
| always_ram: bool = True
|
| hnsw_m: int = 16
|
| hnsw_ef_construct: int = 100
|
| api_key: Optional[str] = None
|
|
|
|
|
| @dataclass(frozen=True)
|
| class GPUConfig:
|
| enabled: bool = False
|
| device: str = "cuda:0"
|
| batch_size: int = 1000
|
| fallback_to_cpu: bool = True
|
|
|
|
|
| @dataclass(frozen=True)
|
| class SecurityConfig:
|
| api_key: Optional[str] = None
|
| cors_origins: list[str] = field(default_factory=lambda: ["*"])
|
| rate_limit_enabled: bool = True
|
| rate_limit_requests: int = 100
|
| rate_limit_window: int = 60
|
|
|
|
|
| @dataclass(frozen=True)
|
| class ObservabilityConfig:
|
| metrics_port: int = 9090
|
| log_level: str = "INFO"
|
| structured_logging: bool = True
|
|
|
|
|
| @dataclass(frozen=True)
|
| class MCPConfig:
|
| enabled: bool = False
|
| transport: str = "stdio"
|
| host: str = "127.0.0.1"
|
| port: int = 8110
|
| api_base_url: str = "http://localhost:8100"
|
| api_key: Optional[str] = None
|
| timeout_seconds: int = 15
|
| allow_tools: list[str] = field(
|
| default_factory=lambda: [
|
| "memory_store",
|
| "memory_query",
|
| "memory_get",
|
| "memory_delete",
|
| "memory_stats",
|
| "memory_health",
|
| ]
|
| )
|
|
|
|
|
| @dataclass(frozen=True)
|
| class PathsConfig:
|
| data_dir: str = "./data"
|
| memory_file: str = "./data/memory.jsonl"
|
| codebook_file: str = "./data/codebook.json"
|
| concepts_file: str = "./data/concepts.json"
|
| synapses_file: str = "./data/synapses.json"
|
| warm_mmap_dir: str = "./data/warm_tier"
|
| cold_archive_dir: str = "./data/cold_archive"
|
|
|
|
|
| @dataclass(frozen=True)
|
| class AttentionMaskingConfig:
|
| """Configuration for XOR-based project isolation (Phase 4.1)."""
|
| enabled: bool = True
|
|
|
|
|
| @dataclass(frozen=True)
|
| class ConsolidationConfig:
|
| """Configuration for semantic consolidation (Phase 4.0+)."""
|
| enabled: bool = True
|
| interval_seconds: int = 3600
|
| similarity_threshold: float = 0.85
|
| min_cluster_size: int = 2
|
| hot_tier_enabled: bool = True
|
| warm_tier_enabled: bool = True
|
|
|
|
|
| @dataclass(frozen=True)
|
| class EncodingConfig:
|
| mode: str = "binary"
|
| token_method: str = "bundle"
|
|
|
|
|
| @dataclass(frozen=True)
|
| class SynapseConfig:
|
| """Configuration for Phase 12.1: Aggressive Synapse Formation"""
|
| similarity_threshold: float = 0.5
|
| auto_bind_on_store: bool = True
|
| multi_hop_depth: int = 2
|
|
|
|
|
| @dataclass(frozen=True)
|
| class ContextConfig:
|
| """Configuration for Phase 12.2: Contextual Awareness"""
|
| enabled: bool = True
|
| shift_threshold: float = 0.3
|
| rolling_window_size: int = 5
|
|
|
|
|
| @dataclass(frozen=True)
|
| class PreferenceConfig:
|
| """Configuration for Phase 12.3: Preference Learning"""
|
| enabled: bool = True
|
| learning_rate: float = 0.1
|
| history_limit: int = 100
|
|
|
|
|
| @dataclass(frozen=True)
|
| class AnticipatoryConfig:
|
| """Configuration for Phase 13.2: Anticipatory Memory"""
|
| enabled: bool = True
|
| predictive_depth: int = 1
|
|
|
|
|
| @dataclass(frozen=True)
|
| class DreamLoopConfig:
|
| """Configuration for the dream loop (subconscious background processing)."""
|
| enabled: bool = True
|
| frequency_seconds: int = 60
|
| batch_size: int = 10
|
| max_iterations: int = 0
|
| subconscious_queue_maxlen: Optional[int] = None
|
| ollama_url: str = "http://localhost:11434/api/generate"
|
| model: str = "gemma3:1b"
|
|
|
|
|
| @dataclass(frozen=True)
|
| class SubconsciousAIConfig:
|
| """
|
| Configuration for the Subconscious AI worker (Phase 4.4).
|
|
|
| A small LLM (Phi 3.5, Llama 7B) that pulses in the background,
|
| performing memory sorting, enhanced dreaming, and micro self-improvement.
|
|
|
| This is a BETA feature that must be explicitly enabled.
|
| """
|
|
|
| enabled: bool = False
|
| beta_mode: bool = True
|
|
|
|
|
| model_provider: str = "ollama"
|
| model_name: str = "phi3.5:3.8b"
|
| model_url: str = "http://localhost:11434"
|
| api_key: Optional[str] = None
|
| api_base_url: Optional[str] = None
|
|
|
|
|
| pulse_interval_seconds: int = 120
|
| pulse_backoff_enabled: bool = True
|
| pulse_backoff_max_seconds: int = 600
|
|
|
|
|
| max_cpu_percent: float = 30.0
|
| cycle_timeout_seconds: int = 30
|
| rate_limit_per_hour: int = 50
|
|
|
|
|
| memory_sorting_enabled: bool = True
|
| enhanced_dreaming_enabled: bool = True
|
| micro_self_improvement_enabled: bool = False
|
|
|
|
|
| dry_run: bool = True
|
| log_all_decisions: bool = True
|
| audit_trail_path: Optional[str] = "./data/subconscious_audit.jsonl"
|
| max_memories_per_cycle: int = 10
|
|
|
|
|
| @dataclass(frozen=True)
|
| class PulseConfig:
|
| """Configuration for Phase 5 AGI Pulse Loop orchestrator."""
|
| enabled: bool = True
|
| interval_seconds: int = 30
|
| max_agents_per_tick: int = 50
|
| max_episodes_per_tick: int = 200
|
|
|
| @dataclass(frozen=True)
|
| class HAIMConfig:
|
| """Root configuration for the HAIM system."""
|
|
|
| version: str = "4.5"
|
| dimensionality: int = 16384
|
| encoding: EncodingConfig = field(default_factory=EncodingConfig)
|
| tiers_hot: TierConfig = field(
|
| default_factory=lambda: TierConfig(max_memories=2000, ltp_threshold_min=0.7)
|
| )
|
| tiers_warm: TierConfig = field(
|
| default_factory=lambda: TierConfig(
|
| max_memories=100000,
|
| ltp_threshold_min=0.3,
|
| consolidation_interval_hours=1,
|
| storage_backend="mmap",
|
| )
|
| )
|
| tiers_cold: TierConfig = field(
|
| default_factory=lambda: TierConfig(
|
| max_memories=0,
|
| ltp_threshold_min=0.0,
|
| storage_backend="filesystem",
|
| )
|
| )
|
| ltp: LTPConfig = field(default_factory=LTPConfig)
|
| hysteresis: HysteresisConfig = field(default_factory=HysteresisConfig)
|
| redis: RedisConfig = field(default_factory=RedisConfig)
|
| qdrant: QdrantConfig = field(default_factory=QdrantConfig)
|
| gpu: GPUConfig = field(default_factory=GPUConfig)
|
| security: SecurityConfig = field(default_factory=SecurityConfig)
|
| observability: ObservabilityConfig = field(default_factory=ObservabilityConfig)
|
| mcp: MCPConfig = field(default_factory=MCPConfig)
|
| paths: PathsConfig = field(default_factory=PathsConfig)
|
| consolidation: ConsolidationConfig = field(default_factory=ConsolidationConfig)
|
| attention_masking: AttentionMaskingConfig = field(default_factory=AttentionMaskingConfig)
|
| synapse: SynapseConfig = field(default_factory=SynapseConfig)
|
| context: ContextConfig = field(default_factory=ContextConfig)
|
| preference: PreferenceConfig = field(default_factory=PreferenceConfig)
|
| anticipatory: AnticipatoryConfig = field(default_factory=AnticipatoryConfig)
|
| dream_loop: DreamLoopConfig = field(default_factory=DreamLoopConfig)
|
| subconscious_ai: SubconsciousAIConfig = field(default_factory=SubconsciousAIConfig)
|
| pulse: PulseConfig = field(default_factory=PulseConfig)
|
|
|
|
|
| def _env_override(key: str, default):
|
| """Check for HAIM_<KEY> environment variable override."""
|
| env_key = f"HAIM_{key.upper()}"
|
| val = os.environ.get(env_key)
|
| if val is None:
|
| return default
|
|
|
| if isinstance(default, bool):
|
| return val.lower() in ("true", "1", "yes")
|
| if isinstance(default, int):
|
| return int(val)
|
| if isinstance(default, float):
|
| return float(val)
|
| return val
|
|
|
|
|
| def _build_tier(name: str, raw: dict) -> TierConfig:
|
| prefix = f"TIERS_{name.upper()}"
|
| return TierConfig(
|
| max_memories=_env_override(f"{prefix}_MAX_MEMORIES", raw.get("max_memories", 0)),
|
| ltp_threshold_min=_env_override(f"{prefix}_LTP_THRESHOLD_MIN", raw.get("ltp_threshold_min", 0.0)),
|
| eviction_policy=raw.get("eviction_policy", "lru"),
|
| consolidation_interval_hours=raw.get("consolidation_interval_hours"),
|
| storage_backend=raw.get("storage_backend", "memory"),
|
| compression=raw.get("compression", "gzip"),
|
| archive_threshold_days=raw.get("archive_threshold_days", 30),
|
| )
|
|
|
|
|
| def _parse_optional_positive_int(value: Optional[object]) -> Optional[int]:
|
| """Parse positive int values. Non-positive/invalid values become None."""
|
| if value is None:
|
| return None
|
| try:
|
| parsed = int(value)
|
| except (TypeError, ValueError):
|
| return None
|
| return parsed if parsed > 0 else None
|
|
|
|
|
| def load_config(path: Optional[Path] = None) -> HAIMConfig:
|
| """
|
| Load configuration from YAML file with environment variable overrides.
|
|
|
| Priority: ENV > YAML > defaults.
|
|
|
| Args:
|
| path: Path to config.yaml. If None, searches ./config.yaml and ../config.yaml.
|
|
|
| Returns:
|
| Validated HAIMConfig instance.
|
|
|
| Raises:
|
| ConfigurationError: If dimensionality is not a multiple of 64.
|
| FileNotFoundError: If no config file is found and path is explicitly set.
|
| """
|
| if path is None:
|
|
|
| candidates = [
|
| Path("config.yaml"),
|
| Path(__file__).parent.parent.parent / "config.yaml",
|
| ]
|
| for candidate in candidates:
|
| if candidate.exists():
|
| path = candidate
|
| break
|
|
|
| raw = {}
|
| if path is not None and path.exists():
|
| with open(path) as f:
|
| loaded = yaml.safe_load(f) or {}
|
| raw = loaded.get("haim") or {}
|
|
|
|
|
| dimensionality = _env_override(
|
| "DIMENSIONALITY", raw.get("dimensionality", 16384)
|
| )
|
|
|
|
|
| if dimensionality % 64 != 0:
|
| raise ConfigurationError(
|
| config_key="dimensionality",
|
| reason=f"Dimensionality must be a multiple of 64 for efficient bit packing, got {dimensionality}"
|
| )
|
|
|
|
|
| tiers_raw = raw.get("tiers") or {}
|
| hot_raw = tiers_raw.get("hot", {"max_memories": 2000, "ltp_threshold_min": 0.7})
|
| warm_raw = tiers_raw.get(
|
| "warm",
|
| {
|
| "max_memories": 100000,
|
| "ltp_threshold_min": 0.3,
|
| "consolidation_interval_hours": 1,
|
| "storage_backend": "mmap",
|
| },
|
| )
|
| cold_raw = tiers_raw.get(
|
| "cold",
|
| {
|
| "max_memories": 0,
|
| "ltp_threshold_min": 0.0,
|
| "storage_backend": "filesystem",
|
| },
|
| )
|
|
|
|
|
| enc_raw = raw.get("encoding") or {}
|
| encoding = EncodingConfig(
|
| mode=_env_override("ENCODING_MODE", enc_raw.get("mode", "binary")),
|
| token_method=enc_raw.get("token_method", "bundle"),
|
| )
|
|
|
|
|
| paths_raw = raw.get("paths") or {}
|
| paths = PathsConfig(
|
| data_dir=_env_override("DATA_DIR", paths_raw.get("data_dir", "./data")),
|
| memory_file=_env_override("MEMORY_FILE", paths_raw.get("memory_file", "./data/memory.jsonl")),
|
| codebook_file=_env_override("CODEBOOK_FILE", paths_raw.get("codebook_file", "./data/codebook.json")),
|
| concepts_file=_env_override("CONCEPTS_FILE", paths_raw.get("concepts_file", "./data/concepts.json")),
|
| synapses_file=_env_override("SYNAPSES_FILE", paths_raw.get("synapses_file", "./data/synapses.json")),
|
| warm_mmap_dir=_env_override("WARM_MMAP_DIR", paths_raw.get("warm_mmap_dir", "./data/warm_tier")),
|
| cold_archive_dir=_env_override("COLD_ARCHIVE_DIR", paths_raw.get("cold_archive_dir", "./data/cold_archive")),
|
| )
|
|
|
|
|
| redis_raw = raw.get("redis") or {}
|
| redis = RedisConfig(
|
| url=_env_override("REDIS_URL", redis_raw.get("url", "redis://localhost:6379/0")),
|
| stream_key=redis_raw.get("stream_key", "haim:subconscious"),
|
| max_connections=redis_raw.get("max_connections", 10),
|
| socket_timeout=redis_raw.get("socket_timeout", 5),
|
| password=_env_override("REDIS_PASSWORD", redis_raw.get("password")),
|
| )
|
|
|
|
|
| qdrant_raw = raw.get("qdrant") or {}
|
| qdrant = QdrantConfig(
|
| url=_env_override(
|
| "QDRANT_URL", qdrant_raw.get("url", "http://localhost:6333")
|
| ),
|
| collection_hot=qdrant_raw.get("collection_hot", "haim_hot"),
|
| collection_warm=qdrant_raw.get("collection_warm", "haim_warm"),
|
| binary_quantization=qdrant_raw.get("binary_quantization", True),
|
| always_ram=qdrant_raw.get("always_ram", True),
|
| hnsw_m=qdrant_raw.get("hnsw_m", 16),
|
| hnsw_ef_construct=qdrant_raw.get("hnsw_ef_construct", 100),
|
| api_key=_env_override("QDRANT_API_KEY", qdrant_raw.get("api_key")),
|
| )
|
|
|
|
|
| gpu_raw = raw.get("gpu") or {}
|
| gpu = GPUConfig(
|
| enabled=_env_override("GPU_ENABLED", gpu_raw.get("enabled", False)),
|
| device=gpu_raw.get("device", "cuda:0"),
|
| batch_size=gpu_raw.get("batch_size", 1000),
|
| fallback_to_cpu=gpu_raw.get("fallback_to_cpu", True),
|
| )
|
|
|
|
|
| obs_raw = raw.get("observability") or {}
|
| observability = ObservabilityConfig(
|
| metrics_port=obs_raw.get("metrics_port", 9090),
|
| log_level=_env_override("LOG_LEVEL", obs_raw.get("log_level", "INFO")),
|
| structured_logging=obs_raw.get("structured_logging", True),
|
| )
|
|
|
|
|
| sec_raw = raw.get("security") or {}
|
|
|
|
|
| cors_env = os.environ.get("HAIM_CORS_ORIGINS")
|
| if cors_env:
|
| cors_origins = [o.strip() for o in cors_env.split(",")]
|
| else:
|
| cors_origins = sec_raw.get("cors_origins", ["*"])
|
|
|
| security = SecurityConfig(
|
| api_key=_env_override("API_KEY", sec_raw.get("api_key")),
|
| cors_origins=cors_origins,
|
| rate_limit_enabled=_env_override("RATE_LIMIT_ENABLED", sec_raw.get("rate_limit_enabled", True)),
|
| rate_limit_requests=_env_override("RATE_LIMIT_REQUESTS", sec_raw.get("rate_limit_requests", 100)),
|
| rate_limit_window=_env_override("RATE_LIMIT_WINDOW", sec_raw.get("rate_limit_window", 60)),
|
| )
|
|
|
|
|
| mcp_raw = raw.get("mcp") or {}
|
| allow_tools_default = [
|
| "memory_store",
|
| "memory_query",
|
| "memory_get",
|
| "memory_delete",
|
| "memory_stats",
|
| "memory_health",
|
| ]
|
| mcp = MCPConfig(
|
| enabled=_env_override("MCP_ENABLED", mcp_raw.get("enabled", False)),
|
| transport=_env_override("MCP_TRANSPORT", mcp_raw.get("transport", "stdio")),
|
| host=_env_override("MCP_HOST", mcp_raw.get("host", "127.0.0.1")),
|
| port=_env_override("MCP_PORT", mcp_raw.get("port", 8110)),
|
| api_base_url=_env_override("MCP_API_BASE_URL", mcp_raw.get("api_base_url", "http://localhost:8100")),
|
| api_key=_env_override("MCP_API_KEY", mcp_raw.get("api_key", sec_raw.get("api_key"))),
|
| timeout_seconds=_env_override("MCP_TIMEOUT_SECONDS", mcp_raw.get("timeout_seconds", 15)),
|
| allow_tools=mcp_raw.get("allow_tools", allow_tools_default),
|
| )
|
|
|
|
|
| hyst_raw = raw.get("hysteresis") or {}
|
| hysteresis = HysteresisConfig(
|
| promote_delta=_env_override("HYSTERESIS_PROMOTE_DELTA", hyst_raw.get("promote_delta", 0.15)),
|
| demote_delta=_env_override("HYSTERESIS_DEMOTE_DELTA", hyst_raw.get("demote_delta", 0.10)),
|
| )
|
|
|
|
|
| ltp_raw = raw.get("ltp") or {}
|
| ltp = LTPConfig(
|
| initial_importance=_env_override("LTP_INITIAL_IMPORTANCE", ltp_raw.get("initial_importance", 0.5)),
|
| decay_lambda=_env_override("LTP_DECAY_LAMBDA", ltp_raw.get("decay_lambda", 0.01)),
|
| permanence_threshold=_env_override("LTP_PERMANENCE_THRESHOLD", ltp_raw.get("permanence_threshold", 0.95)),
|
| half_life_days=_env_override("LTP_HALF_LIFE_DAYS", ltp_raw.get("half_life_days", 30.0)),
|
| )
|
|
|
|
|
| attn_raw = raw.get("attention_masking") or {}
|
| attention_masking = AttentionMaskingConfig(
|
| enabled=_env_override("ATTENTION_MASKING_ENABLED", attn_raw.get("enabled", True)),
|
| )
|
|
|
|
|
| cons_raw = raw.get("consolidation") or {}
|
| consolidation = ConsolidationConfig(
|
| enabled=_env_override("CONSOLIDATION_ENABLED", cons_raw.get("enabled", True)),
|
| interval_seconds=_env_override("CONSOLIDATION_INTERVAL_SECONDS", cons_raw.get("interval_seconds", 3600)),
|
| similarity_threshold=_env_override("CONSOLIDATION_SIMILARITY_THRESHOLD", cons_raw.get("similarity_threshold", 0.85)),
|
| min_cluster_size=_env_override("CONSOLIDATION_MIN_CLUSTER_SIZE", cons_raw.get("min_cluster_size", 2)),
|
| hot_tier_enabled=_env_override("CONSOLIDATION_HOT_TIER_ENABLED", cons_raw.get("hot_tier_enabled", True)),
|
| warm_tier_enabled=_env_override("CONSOLIDATION_WARM_TIER_ENABLED", cons_raw.get("warm_tier_enabled", True)),
|
| )
|
|
|
|
|
| dream_raw = raw.get("dream_loop") or {}
|
| raw_queue_maxlen = dream_raw.get("subconscious_queue_maxlen")
|
| env_queue_maxlen = os.environ.get("HAIM_DREAM_LOOP_SUBCONSCIOUS_QUEUE_MAXLEN")
|
| queue_maxlen = _parse_optional_positive_int(
|
| env_queue_maxlen if env_queue_maxlen is not None else raw_queue_maxlen
|
| )
|
| dream_loop = DreamLoopConfig(
|
| enabled=_env_override("DREAM_LOOP_ENABLED", dream_raw.get("enabled", True)),
|
| frequency_seconds=_env_override("DREAM_LOOP_FREQUENCY_SECONDS", dream_raw.get("frequency_seconds", 60)),
|
| batch_size=_env_override("DREAM_LOOP_BATCH_SIZE", dream_raw.get("batch_size", 10)),
|
| max_iterations=_env_override("DREAM_LOOP_MAX_ITERATIONS", dream_raw.get("max_iterations", 0)),
|
| subconscious_queue_maxlen=queue_maxlen,
|
| ollama_url=_env_override("DREAM_LOOP_OLLAMA_URL", dream_raw.get("ollama_url", "http://localhost:11434/api/generate")),
|
| model=_env_override("DREAM_LOOP_MODEL", dream_raw.get("model", "gemma3:1b")),
|
| )
|
|
|
|
|
| syn_raw = raw.get("synapse") or {}
|
| synapse = SynapseConfig(
|
| similarity_threshold=_env_override("SYNAPSE_SIMILARITY_THRESHOLD", syn_raw.get("similarity_threshold", 0.5)),
|
| auto_bind_on_store=_env_override("SYNAPSE_AUTO_BIND_ON_STORE", syn_raw.get("auto_bind_on_store", True)),
|
| multi_hop_depth=_env_override("SYNAPSE_MULTI_HOP_DEPTH", syn_raw.get("multi_hop_depth", 2)),
|
| )
|
|
|
|
|
| ctx_raw = raw.get("context") or {}
|
| context = ContextConfig(
|
| enabled=_env_override("CONTEXT_ENABLED", ctx_raw.get("enabled", True)),
|
| shift_threshold=_env_override("CONTEXT_SHIFT_THRESHOLD", ctx_raw.get("shift_threshold", 0.3)),
|
| rolling_window_size=_env_override("CONTEXT_ROLLING_WINDOW_SIZE", ctx_raw.get("rolling_window_size", 5)),
|
| )
|
|
|
|
|
| pref_raw = raw.get("preference") or {}
|
| preference = PreferenceConfig(
|
| enabled=_env_override("PREFERENCE_ENABLED", pref_raw.get("enabled", True)),
|
| learning_rate=_env_override("PREFERENCE_LEARNING_RATE", pref_raw.get("learning_rate", 0.1)),
|
| history_limit=_env_override("PREFERENCE_HISTORY_LIMIT", pref_raw.get("history_limit", 100)),
|
| )
|
|
|
|
|
| ant_raw = raw.get("anticipatory") or {}
|
| anticipatory = AnticipatoryConfig(
|
| enabled=_env_override("ANTICIPATORY_ENABLED", ant_raw.get("enabled", True)),
|
| predictive_depth=_env_override("ANTICIPATORY_PREDICTIVE_DEPTH", ant_raw.get("predictive_depth", 1)),
|
| )
|
|
|
|
|
| sub_raw = raw.get("subconscious_ai") or {}
|
| subconscious_ai = SubconsciousAIConfig(
|
| enabled=_env_override("SUBCONSCIOUS_AI_ENABLED", sub_raw.get("enabled", False)),
|
| beta_mode=_env_override("SUBCONSCIOUS_AI_BETA_MODE", sub_raw.get("beta_mode", True)),
|
| model_provider=_env_override("SUBCONSCIOUS_AI_MODEL_PROVIDER", sub_raw.get("model_provider", "ollama")),
|
| model_name=_env_override("SUBCONSCIOUS_AI_MODEL_NAME", sub_raw.get("model_name", "phi3.5:3.8b")),
|
| model_url=_env_override("SUBCONSCIOUS_AI_MODEL_URL", sub_raw.get("model_url", "http://localhost:11434")),
|
| api_key=_env_override("SUBCONSCIOUS_AI_API_KEY", sub_raw.get("api_key")),
|
| api_base_url=_env_override("SUBCONSCIOUS_AI_API_BASE_URL", sub_raw.get("api_base_url")),
|
| pulse_interval_seconds=_env_override("SUBCONSCIOUS_AI_PULSE_INTERVAL_SECONDS", sub_raw.get("pulse_interval_seconds", 120)),
|
| pulse_backoff_enabled=_env_override("SUBCONSCIOUS_AI_PULSE_BACKOFF_ENABLED", sub_raw.get("pulse_backoff_enabled", True)),
|
| pulse_backoff_max_seconds=_env_override("SUBCONSCIOUS_AI_PULSE_BACKOFF_MAX_SECONDS", sub_raw.get("pulse_backoff_max_seconds", 600)),
|
| max_cpu_percent=_env_override("SUBCONSCIOUS_AI_MAX_CPU_PERCENT", sub_raw.get("max_cpu_percent", 30.0)),
|
| cycle_timeout_seconds=_env_override("SUBCONSCIOUS_AI_CYCLE_TIMEOUT_SECONDS", sub_raw.get("cycle_timeout_seconds", 30)),
|
| rate_limit_per_hour=_env_override("SUBCONSCIOUS_AI_RATE_LIMIT_PER_HOUR", sub_raw.get("rate_limit_per_hour", 50)),
|
| memory_sorting_enabled=_env_override("SUBCONSCIOUS_AI_MEMORY_SORTING_ENABLED", sub_raw.get("memory_sorting_enabled", True)),
|
| enhanced_dreaming_enabled=_env_override("SUBCONSCIOUS_AI_ENHANCED_DREAMING_ENABLED", sub_raw.get("enhanced_dreaming_enabled", True)),
|
| micro_self_improvement_enabled=_env_override("SUBCONSCIOUS_AI_MICRO_SELF_IMPROVEMENT_ENABLED", sub_raw.get("micro_self_improvement_enabled", False)),
|
| dry_run=_env_override("SUBCONSCIOUS_AI_DRY_RUN", sub_raw.get("dry_run", True)),
|
| log_all_decisions=_env_override("SUBCONSCIOUS_AI_LOG_ALL_DECISIONS", sub_raw.get("log_all_decisions", True)),
|
| audit_trail_path=_env_override("SUBCONSCIOUS_AI_AUDIT_TRAIL_PATH", sub_raw.get("audit_trail_path", "./data/subconscious_audit.jsonl")),
|
| max_memories_per_cycle=_env_override("SUBCONSCIOUS_AI_MAX_MEMORIES_PER_CYCLE", sub_raw.get("max_memories_per_cycle", 10)),
|
| )
|
|
|
|
|
| pulse_raw = raw.get("pulse") or {}
|
| pulse = PulseConfig(
|
| enabled=_env_override("PULSE_ENABLED", pulse_raw.get("enabled", True)),
|
| interval_seconds=_env_override("PULSE_INTERVAL_SECONDS", pulse_raw.get("interval_seconds", 30)),
|
| max_agents_per_tick=_env_override("PULSE_MAX_AGENTS_PER_TICK", pulse_raw.get("max_agents_per_tick", 50)),
|
| max_episodes_per_tick=_env_override("PULSE_MAX_EPISODES_PER_TICK", pulse_raw.get("max_episodes_per_tick", 200)),
|
| )
|
|
|
| return HAIMConfig(
|
| version=raw.get("version", "4.5"),
|
| dimensionality=dimensionality,
|
| encoding=encoding,
|
| tiers_hot=_build_tier("hot", hot_raw),
|
| tiers_warm=_build_tier("warm", warm_raw),
|
| tiers_cold=_build_tier("cold", cold_raw),
|
| ltp=ltp,
|
| hysteresis=hysteresis,
|
| redis=redis,
|
| qdrant=qdrant,
|
| gpu=gpu,
|
| security=security,
|
| observability=observability,
|
| mcp=mcp,
|
| paths=paths,
|
| consolidation=consolidation,
|
| attention_masking=attention_masking,
|
| synapse=synapse,
|
| context=context,
|
| preference=preference,
|
| anticipatory=anticipatory,
|
| dream_loop=dream_loop,
|
| subconscious_ai=subconscious_ai,
|
| pulse=pulse,
|
| )
|
|
|
|
|
|
|
| _CONFIG: Optional[HAIMConfig] = None
|
|
|
|
|
| def get_config() -> HAIMConfig:
|
| """Get or initialize the global config singleton."""
|
| global _CONFIG
|
| if _CONFIG is None:
|
| _CONFIG = load_config()
|
| return _CONFIG
|
|
|
|
|
| def reset_config():
|
| """Reset the global config singleton (useful for testing)."""
|
| global _CONFIG
|
| _CONFIG = None
|
|
|