From c0245c1c44968b41dccfa6b0e59a3adbfd8e1b11 Mon Sep 17 00:00:00 2001 From: Ashish-dwi99 Date: Tue, 31 Mar 2026 13:57:40 +0530 Subject: [PATCH] V2.2.2 --- CHANGELOG.md | 40 +++++++++++++++++++++++ dhee/cli.py | 5 +++ dhee/cli_config.py | 4 +-- dhee/configs/base.py | 6 ++-- dhee/configs/presets.py | 4 +-- dhee/core/forgetting.py | 12 +++---- dhee/mcp_server.py | 54 +++++++++++++++----------------- dhee/memory/core.py | 14 ++++----- dhee/memory/main.py | 28 ++++++++--------- dhee/memory/search_pipeline.py | 8 ++--- dhee/memory/smart.py | 4 +-- dhee/memory/write_pipeline.py | 14 ++++----- dhee/simple.py | 2 +- dhee/vector_stores/memory.py | 2 +- dhee/vector_stores/sqlite_vec.py | 2 +- dhee/vector_stores/zvec_store.py | 2 +- tests/test_locomo_plus_runner.py | 21 ++++++++----- tests/test_mcp_tools_slim.py | 11 +++++-- tests/test_openclaw.py | 4 +++ tests/test_orchestration_core.py | 14 ++++----- tests/test_power_packages.py | 6 ++++ tests/test_skills.py | 4 +-- 22 files changed, 163 insertions(+), 98 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 57ed72b..07d36e4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,46 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/), and this project adheres to [Semantic Versioning](https://semver.org/). +## [2.2.0b1] - 2026-03-31 — Architectural Cleanup + +Beta release focused on internal discipline rather than new features. + +### Changed — Architecture + +- **main.py decomposition**: Extracted `SearchPipeline`, `MemoryWritePipeline`, `OrchestrationEngine` from the 6,129-line monolith. main.py is now ~3,100 lines (49% reduction). +- **Public surface**: `dhee/__init__.py` rewritten for clean, narrow exports. `Memory = CoreMemory` (not FullMemory). Cognitive subsystems intentionally kept internal. +- **MCP split**: `mcp_slim.py` (4-tool product surface) vs `mcp_server.py` (24-tool power surface). Clear separation of concerns. + +### Changed — Rename Debt + +- All `FADEM_*` env vars → `DHEE_*` (with `FADEM_*` fallback for backward compat). +- Internal `fadem_config` → `fade_config` across memory package. +- Default collection name `fadem_memories` → `dhee_memories`. +- Config field `MemoryConfig.engram` → `MemoryConfig.fade`. +- CLI, MCP server, observability, presets: all `engram` product references removed. + +### Added — D2Skill Policy Improvements + +- **Dual-granularity policies**: `PolicyGranularity.TASK` (strategy) vs `PolicyGranularity.STEP` (local correction). Inspired by D2Skill (arXiv:2603.28716). +- **Utility scoring**: EMA-smoothed performance delta tracking on policies. Three-signal retrieval ranking (condition match + sigmoid utility + UCB exploration bonus). +- **Utility-based pruning**: `PolicyStore.prune()` removes deprecated policies first, protects validated ones. +- **Buddhi wiring**: `reflect()` accepts `outcome_score`, computes baseline vs actual delta, feeds it to policy `record_outcome()`. + +### Fixed + +- `buddhi.py`: Replaced dead `memory.get_last_session_digest()` call with working `get_last_session()` import. +- `mcp_server.py`: Fixed wrong "8 tools total" comment (actually 24), fixed `-> Memory` type hints (Memory not imported). +- CLI: Wired `benchmark` command into parser (existed but was unreachable). +- `PolicyStore.prune()`: Fixed bug where `candidates.pop()` pruned validated policies instead of deprecated ones. +- CHANGELOG 2.1.0: Removed false "Production/Stable" and "A-grade" claims. + +### Changed — Packaging + +- Version: 2.1.0 → 2.2.0b1 +- Classifier: `Development Status :: 4 - Beta` (was falsely claiming Production/Stable) + +--- + ## [2.1.0] - 2026-03-30 — Cognition Primitives Dhee V2.1: Adds first-class cognitive primitives (episodes, tasks, policies, beliefs, triggers) and a 60-test suite that exercises them. These are internal building blocks — the public API remains the 4-operation surface (remember/recall/context/checkpoint). diff --git a/dhee/cli.py b/dhee/cli.py index 6ee16a7..271dd01 100644 --- a/dhee/cli.py +++ b/dhee/cli.py @@ -10,6 +10,7 @@ dhee categories List categories dhee export Export to JSON dhee import Import from JSON + dhee benchmark Run performance benchmarks dhee status Version, config, DB info """ @@ -457,6 +458,9 @@ def build_parser() -> argparse.ArgumentParser: p_status = sub.add_parser("status", help="Show version, config, and agents") p_status.add_argument("--json", action="store_true", help="JSON output") + # benchmark + sub.add_parser("benchmark", help="Run performance benchmarks") + # uninstall sub.add_parser("uninstall", help="Remove ~/.dhee directory") @@ -477,6 +481,7 @@ def build_parser() -> argparse.ArgumentParser: "export": cmd_export, "import": cmd_import, "status": cmd_status, + "benchmark": cmd_benchmark, "uninstall": cmd_uninstall, } diff --git a/dhee/cli_config.py b/dhee/cli_config.py index e6b44ce..d1ab90f 100644 --- a/dhee/cli_config.py +++ b/dhee/cli_config.py @@ -125,7 +125,7 @@ def get_memory_instance(config: Optional[Dict[str, Any]] = None): provider="sqlite_vec", config={ "path": vec_db_path, - "collection_name": "fadem_memories", + "collection_name": "dhee_memories", "embedding_model_dims": embedding_dims, }, ), @@ -133,7 +133,7 @@ def get_memory_instance(config: Optional[Dict[str, Any]] = None): embedder=EmbedderConfig(provider=provider, config=embedder_cfg), history_db_path=history_db_path, embedding_model_dims=embedding_dims, - engram=FadeMemConfig(enable_forgetting=True), + fade=FadeMemConfig(enable_forgetting=True), ) return FullMemory(memory_config) diff --git a/dhee/configs/base.py b/dhee/configs/base.py index 570963a..c017ee9 100644 --- a/dhee/configs/base.py +++ b/dhee/configs/base.py @@ -24,7 +24,7 @@ class VectorStoreConfig(BaseModel): config: Dict[str, Any] = Field( default_factory=lambda: { "path": os.path.join(_dhee_data_dir(), "zvec"), - "collection_name": "fadem_memories", + "collection_name": "dhee_memories", } ) @@ -605,7 +605,7 @@ class MemoryConfig(BaseModel): history_db_path: str = Field( default_factory=lambda: os.path.join(_dhee_data_dir(), "history.db") ) - collection_name: str = "fadem_memories" + collection_name: str = "dhee_memories" embedding_model_dims: int = 4096 # nvidia/nv-embed-v1 default dimensions version: str = "v1.4" # Updated for CLS Distillation Memory custom_fact_extraction_prompt: Optional[str] = None @@ -613,7 +613,7 @@ class MemoryConfig(BaseModel): custom_fusion_prompt: Optional[str] = None custom_echo_prompt: Optional[str] = None custom_category_prompt: Optional[str] = None - engram: FadeMemConfig = Field(default_factory=FadeMemConfig) + fade: FadeMemConfig = Field(default_factory=FadeMemConfig) echo: EchoMemConfig = Field(default_factory=EchoMemConfig) category: CategoryMemConfig = Field(default_factory=CategoryMemConfig) scope: ScopeConfig = Field(default_factory=ScopeConfig) diff --git a/dhee/configs/presets.py b/dhee/configs/presets.py index 1a0d198..d20d0e4 100644 --- a/dhee/configs/presets.py +++ b/dhee/configs/presets.py @@ -45,7 +45,7 @@ def minimal_config(): history_db_path=os.path.join(data_dir, "history.db"), collection_name="dhee_memories", embedding_model_dims=384, - engram=FadeMemConfig(enable_forgetting=True), + fade=FadeMemConfig(enable_forgetting=True), echo=EchoMemConfig(enable_echo=False), category=CategoryMemConfig(enable_categories=False), graph=KnowledgeGraphConfig(enable_graph=False), @@ -122,7 +122,7 @@ def smart_config(): history_db_path=os.path.join(data_dir, "history.db"), collection_name="dhee_memories", embedding_model_dims=dims, - engram=FadeMemConfig(enable_forgetting=True), + fade=FadeMemConfig(enable_forgetting=True), echo=EchoMemConfig(enable_echo=has_llm), category=CategoryMemConfig(enable_categories=has_llm), graph=KnowledgeGraphConfig(enable_graph=True, use_llm_extraction=False), diff --git a/dhee/core/forgetting.py b/dhee/core/forgetting.py index 861bc52..5b4821a 100644 --- a/dhee/core/forgetting.py +++ b/dhee/core/forgetting.py @@ -29,14 +29,14 @@ def __init__( self, db: "SQLiteManager", config: "DistillationConfig", - fadem_config: "FadeMemConfig", + fade_config: "FadeMemConfig", resolve_conflict_fn=None, search_fn=None, llm=None, ): self.db = db self.config = config - self.fadem_config = fadem_config + self.fade_config = fade_config self.resolve_conflict_fn = resolve_conflict_fn self.search_fn = search_fn self.llm = llm @@ -90,7 +90,7 @@ def run( nearest = neighbors[0] similarity = float(nearest.score) - if similarity < self.fadem_config.conflict_similarity_threshold: + if similarity < self.fade_config.conflict_similarity_threshold: continue # Fetch the neighbor memory from DB @@ -319,12 +319,12 @@ def __init__( self, db: "SQLiteManager", config: "DistillationConfig", - fadem_config: "FadeMemConfig", + fade_config: "FadeMemConfig", delete_fn=None, ): self.db = db self.config = config - self.fadem_config = fadem_config + self.fade_config = fade_config self.delete_fn = delete_fn def run( @@ -373,7 +373,7 @@ def run( pressure = strength * pressure_factor * excess_ratio new_strength = max(0.0, strength - pressure) - if new_strength < self.fadem_config.forgetting_threshold: + if new_strength < self.fade_config.forgetting_threshold: if self.delete_fn: try: self.delete_fn(memory["id"]) diff --git a/dhee/mcp_server.py b/dhee/mcp_server.py index 8fe7038..9634b6c 100644 --- a/dhee/mcp_server.py +++ b/dhee/mcp_server.py @@ -57,7 +57,7 @@ def _get_embedding_dims_for_model(model: str, provider: str) -> int: "text-embedding-3-large": 3072, "text-embedding-ada-002": 1536, } - env_dims = os.environ.get("FADEM_EMBEDDING_DIMS") + env_dims = os.environ.get("DHEE_EMBEDDING_DIMS") or os.environ.get("FADEM_EMBEDDING_DIMS") if env_dims: return int(env_dims) if model in EMBEDDING_DIMS: @@ -69,8 +69,8 @@ def _get_embedding_dims_for_model(model: str, provider: str) -> int: return 3072 -def get_memory_instance() -> Memory: - """Create and return a configured Memory instance (FullMemory for MCP).""" +def get_memory_instance() -> FullMemory: + """Create and return a configured FullMemory instance for the MCP server.""" openai_key = os.environ.get("OPENAI_API_KEY") gemini_key = os.environ.get("GOOGLE_API_KEY") or os.environ.get("GEMINI_API_KEY") nvidia_key = ( @@ -79,13 +79,17 @@ def get_memory_instance() -> Memory: or os.environ.get("NVIDIA_EMBEDDING_API_KEY") ) + def _env(key: str, default: str = "") -> str: + """Read DHEE_ env var with FADEM_ fallback for backward compat.""" + return os.environ.get(f"DHEE_{key}") or os.environ.get(f"FADEM_{key}") or default + if openai_key: - embedder_model = os.environ.get("FADEM_EMBEDDER_MODEL", "text-embedding-3-small") + embedder_model = _env("EMBEDDER_MODEL", "text-embedding-3-small") embedding_dims = _get_embedding_dims_for_model(embedder_model, "openai") llm_config = LLMConfig( provider="openai", config={ - "model": os.environ.get("FADEM_LLM_MODEL", "gpt-4o-mini"), + "model": _env("LLM_MODEL", "gpt-4o-mini"), "temperature": 0.1, "max_tokens": 1024, "api_key": openai_key, } ) @@ -94,12 +98,12 @@ def get_memory_instance() -> Memory: config={"model": embedder_model, "api_key": openai_key}, ) elif gemini_key: - embedder_model = os.environ.get("FADEM_EMBEDDER_MODEL", "gemini-embedding-001") + embedder_model = _env("EMBEDDER_MODEL", "gemini-embedding-001") embedding_dims = _get_embedding_dims_for_model(embedder_model, "gemini") llm_config = LLMConfig( provider="gemini", config={ - "model": os.environ.get("FADEM_LLM_MODEL", "gemini-2.0-flash"), + "model": _env("LLM_MODEL", "gemini-2.0-flash"), "temperature": 0.1, "max_tokens": 1024, "api_key": gemini_key, } ) @@ -108,13 +112,12 @@ def get_memory_instance() -> Memory: config={"model": embedder_model, "api_key": gemini_key}, ) elif nvidia_key: - # Internal provider — not customer-documented - embedder_model = os.environ.get("FADEM_EMBEDDER_MODEL", "nvidia/llama-nemotron-embed-vl-1b-v2") + embedder_model = _env("EMBEDDER_MODEL", "nvidia/llama-nemotron-embed-vl-1b-v2") embedding_dims = 2048 llm_config = LLMConfig( provider="nvidia", config={ - "model": os.environ.get("FADEM_LLM_MODEL", "qwen/qwen3.5-397b-a17b"), + "model": _env("LLM_MODEL", "qwen/qwen3.5-397b-a17b"), "temperature": 0.2, "max_tokens": 4096, "api_key": nvidia_key, } ) @@ -131,17 +134,15 @@ def get_memory_instance() -> Memory: ) from dhee.configs.base import _dhee_data_dir - vec_db_path = os.environ.get( - "FADEM_VEC_DB_PATH", - os.path.join(_dhee_data_dir(), "zvec"), - ) + vec_db_path = _env("VEC_DB_PATH") or os.path.join(_dhee_data_dir(), "zvec") + collection = _env("COLLECTION", "dhee_memories") # Use in-memory vector store for simple embedder (no persistent storage needed) if embedder_config.provider == "simple": vector_store_config = VectorStoreConfig( provider="memory", config={ - "collection_name": os.environ.get("FADEM_COLLECTION", "fadem_memories"), + "collection_name": collection, "embedding_model_dims": embedding_dims, }, ) @@ -150,20 +151,17 @@ def get_memory_instance() -> Memory: provider="zvec", config={ "path": vec_db_path, - "collection_name": os.environ.get("FADEM_COLLECTION", "fadem_memories"), + "collection_name": collection, "embedding_model_dims": embedding_dims, }, ) - history_db_path = os.environ.get( - "FADEM_HISTORY_DB", - os.path.join(_dhee_data_dir(), "history.db"), - ) + history_db_path = _env("HISTORY_DB") or os.path.join(_dhee_data_dir(), "history.db") - fadem_config = FadeMemConfig( - enable_forgetting=os.environ.get("FADEM_ENABLE_FORGETTING", "true").lower() == "true", - sml_decay_rate=float(os.environ.get("FADEM_SML_DECAY_RATE", "0.15")), - lml_decay_rate=float(os.environ.get("FADEM_LML_DECAY_RATE", "0.02")), + fade_config = FadeMemConfig( + enable_forgetting=_env("ENABLE_FORGETTING", "true").lower() == "true", + sml_decay_rate=float(_env("SML_DECAY_RATE", "0.15")), + lml_decay_rate=float(_env("LML_DECAY_RATE", "0.02")), ) config = MemoryConfig( @@ -172,18 +170,18 @@ def get_memory_instance() -> Memory: embedder=embedder_config, history_db_path=history_db_path, embedding_model_dims=embedding_dims, - engram=fadem_config, + fade=fade_config, ) return FullMemory(config) # Global instances (lazy) -_memory: Optional[Memory] = None +_memory: Optional[FullMemory] = None _buddhi = None # type: ignore -def get_memory() -> Memory: +def get_memory() -> FullMemory: global _memory if _memory is None: _memory = get_memory_instance() @@ -203,7 +201,7 @@ def get_buddhi(): server = Server("dhee") -# Tool definitions — 8 tools total +# Tool definitions — 24 tools TOOLS = [ Tool( name="remember", diff --git a/dhee/memory/core.py b/dhee/memory/core.py index 51fb7f2..10cb1d1 100644 --- a/dhee/memory/core.py +++ b/dhee/memory/core.py @@ -65,7 +65,7 @@ def __init__( self.vector_store = VectorStoreFactory.create( self.config.vector_store.provider, self.config.vector_store.config ) - self.fadem_config = self.config.engram + self.fade_config = self.config.fade self.distillation_config = getattr(self.config, "distillation", None) # Query embedding LRU cache @@ -115,7 +115,7 @@ def add( # Boost fast trace if multi-trace is enabled if self.distillation_config and self.distillation_config.enable_multi_trace: s_fast = existing.get("s_fast") or 0.0 - boosted = boost_fast_trace(s_fast, self.fadem_config.access_strength_boost) + boosted = boost_fast_trace(s_fast, self.fade_config.access_strength_boost) self.db.update_memory(existing["id"], {"s_fast": boosted}) return { "results": [{ @@ -162,7 +162,7 @@ def add( "confidentiality_scope": metadata.get("confidentiality_scope", "work"), "source_type": "mcp", "source_app": source_app, - "decay_lambda": self.fadem_config.sml_decay_rate, + "decay_lambda": self.fade_config.sml_decay_rate, "status": "active", "importance": metadata.get("importance", 0.5), "sensitivity": metadata.get("sensitivity", "normal"), @@ -374,11 +374,11 @@ def apply_decay( last_accessed=mem.get("last_accessed", mem.get("created_at", "")), access_count=int(mem.get("access_count", 0)), layer=mem.get("layer", "sml"), - config=self.fadem_config, + config=self.fade_config, ) - if should_forget(new_strength, self.fadem_config): - if self.fadem_config.use_tombstone_deletion: + if should_forget(new_strength, self.fade_config): + if self.fade_config.use_tombstone_deletion: self.db.update_memory(mem["id"], {"tombstone": 1, "strength": new_strength}) else: self.db.delete_memory(mem["id"]) @@ -391,7 +391,7 @@ def apply_decay( mem.get("layer", "sml"), int(mem.get("access_count", 0)), new_strength, - self.fadem_config, + self.fade_config, ): self.db.update_memory(mem["id"], {"strength": new_strength, "layer": "lml"}) promoted += 1 diff --git a/dhee/memory/main.py b/dhee/memory/main.py index af6ee1c..2ba6b60 100644 --- a/dhee/memory/main.py +++ b/dhee/memory/main.py @@ -1287,7 +1287,7 @@ def _process_memory_batch( "source_type": "mcp", "source_app": items[i].get("source_app"), "source_event_id": mem_metadata.get("source_event_id"), - "decay_lambda": self.fadem_config.sml_decay_rate, + "decay_lambda": self.fade_config.sml_decay_rate, "status": "active", "importance": mem_metadata.get("importance", 0.5), "sensitivity": mem_metadata.get("sensitivity", "normal"), @@ -1875,9 +1875,9 @@ def update(self, memory_id: str, data: Union[str, Dict[str, Any]]) -> Dict[str, return {"id": memory_id, "memory": content, "event": "UPDATE" if success else "ERROR"} def delete(self, memory_id: str) -> Dict[str, Any]: - logger.info("Deleting memory %s (tombstone=%s)", memory_id, self.fadem_config.use_tombstone_deletion) + logger.info("Deleting memory %s (tombstone=%s)", memory_id, self.fade_config.use_tombstone_deletion) memory = self.db.get_memory(memory_id) - self.db.delete_memory(memory_id, use_tombstone=self.fadem_config.use_tombstone_deletion) + self.db.delete_memory(memory_id, use_tombstone=self.fade_config.use_tombstone_deletion) self._delete_vectors_for_memory(memory_id) self._record_cost_counter( phase="write", @@ -1960,7 +1960,7 @@ def reset(self) -> None: # FadeMem-specific methods def apply_decay(self, scope: Dict[str, Any] = None) -> Dict[str, Any]: - if not self.fadem_config.enable_forgetting: + if not self.fade_config.enable_forgetting: return {"decayed": 0, "forgotten": 0, "promoted": 0} stale_refs_removed = 0 @@ -2025,7 +2025,7 @@ def apply_decay(self, scope: Dict[str, Any] = None) -> Dict[str, Any]: last_accessed=memory.get("last_accessed", datetime.now(timezone.utc).isoformat()), access_count=memory.get("access_count", 0), layer=memory.get("layer", "sml"), - config=self.fadem_config, + config=self.fade_config, ) if ref_aware and int(ref_state.get("weak", 0)) > 0: @@ -2034,7 +2034,7 @@ def apply_decay(self, scope: Dict[str, Any] = None) -> Dict[str, Any]: retained_floor = memory.get("strength", 1.0) * (1.0 - 0.03 / dampening) new_strength = max(new_strength, retained_floor) - forget_threshold = self.fadem_config.forgetting_threshold + forget_threshold = self.fade_config.forgetting_threshold if ref_aware and int(ref_state.get("weak", 0)) > 0: weak = min(int(ref_state.get("weak", 0)), 10) forget_threshold = forget_threshold / (1.0 + weak * 0.25) @@ -2056,13 +2056,13 @@ def apply_decay(self, scope: Dict[str, Any] = None) -> Dict[str, Any]: memory.get("layer", "sml"), memory.get("access_count", 0), new_strength, - self.fadem_config, + self.fade_config, ): self.db.update_memory(memory["id"], {"layer": "lml"}) self.db.log_event(memory["id"], "PROMOTE", old_layer="sml", new_layer="lml") promoted += 1 - if self.fadem_config.use_tombstone_deletion: + if self.fade_config.use_tombstone_deletion: self.db.purge_tombstoned() # Gap 3: Advanced forgetting mechanisms @@ -2089,7 +2089,7 @@ def apply_decay(self, scope: Dict[str, Any] = None) -> Dict[str, Any]: pruner = InterferencePruner( db=self.db, config=self.distillation_config, - fadem_config=self.fadem_config, + fade_config=self.fade_config, resolve_conflict_fn=resolve_conflict, search_fn=self.vector_store.search, llm=self.llm, @@ -2115,7 +2115,7 @@ def _run_collapser(): pruner = InterferencePruner( db=self.db, config=self.distillation_config, - fadem_config=self.fadem_config, + fade_config=self.fade_config, resolve_conflict_fn=resolve_conflict, search_fn=self.vector_store.search, llm=self.llm, @@ -2135,7 +2135,7 @@ def _run_collapser(): normalizer = HomeostaticNormalizer( db=self.db, config=self.distillation_config, - fadem_config=self.fadem_config, + fade_config=self.fade_config, delete_fn=self.delete, ) homeostasis_stats = normalizer.run(user_id) @@ -2567,7 +2567,7 @@ def _forget_by_query(self, query: str, filters: Dict[str, Any]) -> Dict[str, Any if not cleaned: return {"deleted_count": 0, "deleted_ids": []} - threshold = max(self.fadem_config.conflict_similarity_threshold, 0.85) + threshold = max(self.fade_config.conflict_similarity_threshold, 0.85) query_embedding = self.embedder.embed(cleaned, memory_action="forget") results = self.vector_store.search(query=None, vectors=query_embedding, limit=20, filters=filters) @@ -2592,7 +2592,7 @@ def _forget_by_query(self, query: str, filters: Dict[str, Any]) -> Dict[str, Any def _find_similar(self, embedding: List[float], filters: Dict[str, Any]) -> Optional[Dict[str, Any]]: memory, similarity = self._nearest_memory(embedding, filters) - if memory and similarity >= self.fadem_config.conflict_similarity_threshold: + if memory and similarity >= self.fade_config.conflict_similarity_threshold: return memory return None @@ -2602,7 +2602,7 @@ def _check_promotion(self, memory_id: str) -> None: memory.get("layer", "sml"), memory.get("access_count", 0), memory.get("strength", 1.0), - self.fadem_config, + self.fade_config, ): self.db.update_memory(memory_id, {"layer": "lml"}) self.db.log_event(memory_id, "PROMOTE", old_layer="sml", new_layer="lml") diff --git a/dhee/memory/search_pipeline.py b/dhee/memory/search_pipeline.py index be45040..4e4d1e6 100644 --- a/dhee/memory/search_pipeline.py +++ b/dhee/memory/search_pipeline.py @@ -87,8 +87,8 @@ def _graph_config(self): return self._config.graph @property - def _fadem_config(self): - return self._config.engram + def _fade_config(self): + return self._config.fade @property def _distillation_config(self): @@ -368,8 +368,8 @@ def search( if boost_on_access: access_ids.append(memory["id"]) - if self._fadem_config.access_strength_boost > 0: - boosted_strength = min(1.0, strength + self._fadem_config.access_strength_boost) + if self._fade_config.access_strength_boost > 0: + boosted_strength = min(1.0, strength + self._fade_config.access_strength_boost) if boosted_strength != strength: strength_updates[memory["id"]] = boosted_strength strength = boosted_strength diff --git a/dhee/memory/smart.py b/dhee/memory/smart.py index 97c3b51..49ab752 100644 --- a/dhee/memory/smart.py +++ b/dhee/memory/smart.py @@ -281,7 +281,7 @@ def add( self.db.increment_access(existing["id"]) if self.distillation_config and self.distillation_config.enable_multi_trace: s_fast = existing.get("s_fast") or 0.0 - boosted = boost_fast_trace(s_fast, self.fadem_config.access_strength_boost) + boosted = boost_fast_trace(s_fast, self.fade_config.access_strength_boost) self.db.update_memory(existing["id"], {"s_fast": boosted}) return { "results": [{ @@ -373,7 +373,7 @@ def add( "confidentiality_scope": metadata.get("confidentiality_scope", "work"), "source_type": "mcp", "source_app": source_app, - "decay_lambda": self.fadem_config.sml_decay_rate, + "decay_lambda": self.fade_config.sml_decay_rate, "status": "active", "importance": metadata.get("importance", 0.5), "sensitivity": metadata.get("sensitivity", "normal"), diff --git a/dhee/memory/write_pipeline.py b/dhee/memory/write_pipeline.py index 69ceb64..c78805e 100644 --- a/dhee/memory/write_pipeline.py +++ b/dhee/memory/write_pipeline.py @@ -150,8 +150,8 @@ def _buddhi_layer(self): # ------------------------------------------------------------------ @property - def _fadem_config(self): - return self._config.engram + def _fade_config(self): + return self._config.fade @property def _echo_config(self): @@ -565,7 +565,7 @@ def _do_category(): write_embed_calls += 1.0 nearest, similarity = self._nearest_memory_fn(embedding, store_filters) - repeated_threshold = max(self._fadem_config.conflict_similarity_threshold - 0.05, 0.7) + repeated_threshold = max(self._fade_config.conflict_similarity_threshold - 0.05, 0.7) if similarity >= repeated_threshold: policy_repeated = True high_confidence = True @@ -577,10 +577,10 @@ def _do_category(): event = "ADD" existing = None resolution = None - if nearest and similarity >= self._fadem_config.conflict_similarity_threshold: + if nearest and similarity >= self._fade_config.conflict_similarity_threshold: existing = nearest - if existing and self._fadem_config.enable_forgetting: + if existing and self._fade_config.enable_forgetting: conflict_input_tokens = estimate_token_count(existing.get("memory", "")) + estimate_token_count(content) _add_llm_cost(conflict_input_tokens) resolution = resolve_conflict(existing, content, self._llm, self._config.custom_conflict_prompt) @@ -694,7 +694,7 @@ def _do_category(): "source_type": source_type, "source_app": source_app or mem_metadata.get("source_app"), "source_event_id": mem_metadata.get("source_event_id"), - "decay_lambda": self._fadem_config.sml_decay_rate, + "decay_lambda": self._fade_config.sml_decay_rate, "status": "active", "importance": mem_metadata.get("importance", 0.5), "sensitivity": mem_metadata.get("sensitivity", "normal"), @@ -1098,7 +1098,7 @@ def process_single_memory_lite( "source_type": source_type, "source_app": source_app or mem_metadata.get("source_app"), "source_event_id": mem_metadata.get("source_event_id"), - "decay_lambda": self._fadem_config.sml_decay_rate, + "decay_lambda": self._fade_config.sml_decay_rate, "status": "active", "importance": mem_metadata.get("importance", 0.5), "sensitivity": mem_metadata.get("sensitivity", "normal"), diff --git a/dhee/simple.py b/dhee/simple.py index 442340c..5cc9ef0 100644 --- a/dhee/simple.py +++ b/dhee/simple.py @@ -134,7 +134,7 @@ def __init__( llm=LLMConfig(provider=llm_provider), embedder=EmbedderConfig(provider=embedder_provider, **embedder_kwargs), vector_store=vector_config, - engram=FadeMemConfig( + fade=FadeMemConfig( enable_forgetting=enable_decay, ), echo=EchoMemConfig( diff --git a/dhee/vector_stores/memory.py b/dhee/vector_stores/memory.py index 65c428b..11b619c 100644 --- a/dhee/vector_stores/memory.py +++ b/dhee/vector_stores/memory.py @@ -12,7 +12,7 @@ class InMemoryVectorStore(VectorStoreBase): def __init__(self, config: Optional[Dict[str, Any]] = None): self.config = config or {} - self.collection_name = self.config.get("collection_name", "fadem_memories") + self.collection_name = self.config.get("collection_name", "dhee_memories") self.vector_size = self.config.get("embedding_model_dims") self._store: Dict[str, Dict[str, Any]] = {} self._lock = threading.RLock() diff --git a/dhee/vector_stores/sqlite_vec.py b/dhee/vector_stores/sqlite_vec.py index ee26bc0..e18e149 100644 --- a/dhee/vector_stores/sqlite_vec.py +++ b/dhee/vector_stores/sqlite_vec.py @@ -39,7 +39,7 @@ class SqliteVecStore(VectorStoreBase): def __init__(self, config: Optional[Dict[str, Any]] = None): config = config or {} self.config = config - self.collection_name = config.get("collection_name", "fadem_memories") + self.collection_name = config.get("collection_name", "dhee_memories") self.vector_size = ( config.get("embedding_model_dims") or config.get("vector_size") diff --git a/dhee/vector_stores/zvec_store.py b/dhee/vector_stores/zvec_store.py index f4ba919..d98564e 100644 --- a/dhee/vector_stores/zvec_store.py +++ b/dhee/vector_stores/zvec_store.py @@ -48,7 +48,7 @@ class ZvecStore(VectorStoreBase): def __init__(self, config: Optional[Dict[str, Any]] = None): config = config or {} self.config = config - self.collection_name = config.get("collection_name", "fadem_memories") + self.collection_name = config.get("collection_name", "dhee_memories") self.vector_size = ( config.get("embedding_model_dims") or config.get("vector_size") diff --git a/tests/test_locomo_plus_runner.py b/tests/test_locomo_plus_runner.py index 3c0cd9c..01468a3 100644 --- a/tests/test_locomo_plus_runner.py +++ b/tests/test_locomo_plus_runner.py @@ -3,14 +3,19 @@ import json from pathlib import Path -from scripts.run_locomo_plus_engram import ( - _build_output_record, - _extract_question_from_prompt, - _load_existing_predictions, - _parse_cognitive_sessions, - _parse_locomo_sessions, - _strip_question_block, -) +import pytest + +try: + from scripts.run_locomo_plus_engram import ( + _build_output_record, + _extract_question_from_prompt, + _load_existing_predictions, + _parse_cognitive_sessions, + _parse_locomo_sessions, + _strip_question_block, + ) +except ImportError: + pytest.skip("engram benchmark module not available", allow_module_level=True) def test_parse_locomo_sessions_with_date_blocks_and_question_strip() -> None: diff --git a/tests/test_mcp_tools_slim.py b/tests/test_mcp_tools_slim.py index 9c0b5f4..4f4049c 100644 --- a/tests/test_mcp_tools_slim.py +++ b/tests/test_mcp_tools_slim.py @@ -1,13 +1,15 @@ """Verify MCP server tool contract.""" -from dhee import mcp_server +import pytest + +mcp_server = pytest.importorskip("dhee.mcp_server", reason="mcp package not installed") EXPECTED_TOOL_NAMES = { "remember", "search_memory", "get_memory", "get_all_memories", - "engram_context", + "dhee_context", "get_last_session", "save_session_digest", "get_memory_stats", @@ -22,6 +24,11 @@ "decompose_skill", "apply_skill_with_bindings", "enrich_pending", + "think", + "anticipate", + "record_outcome", + "reflect", + "store_intention", } diff --git a/tests/test_openclaw.py b/tests/test_openclaw.py index 2cd8c50..15f6a73 100644 --- a/tests/test_openclaw.py +++ b/tests/test_openclaw.py @@ -5,6 +5,10 @@ import pytest +pytest.importorskip("engram_bus", reason="engram_bus package not installed") +pytest.importorskip("engram_router", reason="engram_router package not installed") +pytest.importorskip("engram_bridge", reason="engram_bridge package not installed") + from dhee.configs.base import MemoryConfig from dhee.memory.main import FullMemory as Memory from dhee.memory.projects import ProjectManager diff --git a/tests/test_orchestration_core.py b/tests/test_orchestration_core.py index 32912d5..b1afbce 100644 --- a/tests/test_orchestration_core.py +++ b/tests/test_orchestration_core.py @@ -97,7 +97,7 @@ def fake_search_episodes(**kwargs: Any) -> Dict[str, Any]: def fail_extract_atomic_facts(**kwargs: Any) -> List[Dict[str, Any]]: raise AssertionError("map stage should be skipped when episodic coverage is sufficient") - monkeypatch.setattr("engram.memory.main.extract_atomic_facts", fail_extract_atomic_facts) + monkeypatch.setattr("dhee.memory.main.extract_atomic_facts", fail_extract_atomic_facts) payload = mem.search_orchestrated( query="How many projects?", @@ -140,8 +140,8 @@ def fake_reduce_atomic_facts(**kwargs: Any): monkeypatch.setattr(mem, "search", fake_search) monkeypatch.setattr(mem, "search_episodes", fake_search_episodes) - monkeypatch.setattr("engram.memory.main.extract_atomic_facts", fake_extract_atomic_facts) - monkeypatch.setattr("engram.memory.main.reduce_atomic_facts", fake_reduce_atomic_facts) + monkeypatch.setattr("dhee.memory.main.extract_atomic_facts", fake_extract_atomic_facts) + monkeypatch.setattr("dhee.memory.main.reduce_atomic_facts", fake_reduce_atomic_facts) payload = mem.search_orchestrated( query="How many projects?", @@ -190,8 +190,8 @@ def fake_search_episodes(**kwargs: Any) -> Dict[str, Any]: monkeypatch.setattr(mem, "search", fake_search) monkeypatch.setattr(mem, "search_episodes", fake_search_episodes) - monkeypatch.setattr("engram.memory.main.extract_atomic_facts", lambda **kwargs: [{"value": "5", "relevant": True}]) - monkeypatch.setattr("engram.memory.main.reduce_atomic_facts", lambda **kwargs: ("5", {})) + monkeypatch.setattr("dhee.memory.main.extract_atomic_facts", lambda **kwargs: [{"value": "5", "relevant": True}]) + monkeypatch.setattr("dhee.memory.main.reduce_atomic_facts", lambda **kwargs: ("5", {})) payload = mem.search_orchestrated( query="How many projects have I led?", @@ -254,8 +254,8 @@ def fake_extract_atomic_facts(**kwargs: Any) -> List[Dict[str, Any]]: monkeypatch.setattr(mem, "search", fake_search) monkeypatch.setattr(mem, "search_episodes", fake_search_episodes) - monkeypatch.setattr("engram.memory.main.extract_atomic_facts", fake_extract_atomic_facts) - monkeypatch.setattr("engram.memory.main.reduce_atomic_facts", lambda **kwargs: ("4", {})) + monkeypatch.setattr("dhee.memory.main.extract_atomic_facts", fake_extract_atomic_facts) + monkeypatch.setattr("dhee.memory.main.reduce_atomic_facts", lambda **kwargs: ("4", {})) first = mem.search_orchestrated( query="How many projects have I led?", diff --git a/tests/test_power_packages.py b/tests/test_power_packages.py index 2cc9eeb..859802e 100644 --- a/tests/test_power_packages.py +++ b/tests/test_power_packages.py @@ -31,6 +31,12 @@ if not any(os.environ.get(key) for key in _NVIDIA_KEYS): pytest.skip("requires NVIDIA API credentials", allow_module_level=True) +# Power packages are separate installable packages (engram_router, engram_heartbeat, etc.) +try: + import engram_router # noqa: F401 +except ImportError: + pytest.skip("engram power packages not installed", allow_module_level=True) + @pytest.fixture(scope="session") def memory(): diff --git a/tests/test_skills.py b/tests/test_skills.py index 2aabece..a458048 100644 --- a/tests/test_skills.py +++ b/tests/test_skills.py @@ -293,11 +293,11 @@ def test_bounded(self): class TestDiscovery: def test_discover_skill_dirs_global(self): dirs = discover_skill_dirs() - assert any(".engram/skills" in d for d in dirs) + assert any(".dhee/skills" in d for d in dirs) def test_discover_skill_dirs_with_repo(self, tmp_path): dirs = discover_skill_dirs(repo_path=str(tmp_path)) - assert any(".engram/skills" in d for d in dirs) + assert any(".dhee/skills" in d for d in dirs) assert str(tmp_path) in dirs[0] def test_scan_skill_files(self, tmp_path):