superlocalmemory 3.6.22 → 3.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +52 -0
- package/README.md +275 -72
- package/bin/slm-npm +43 -89
- package/docs/pi-dev-integration.md +43 -0
- package/ide/configs/antigravity-mcp.json +2 -2
- package/ide/configs/chatgpt-desktop-mcp.json +1 -1
- package/ide/configs/claude-desktop-mcp.json +2 -2
- package/ide/configs/windsurf-mcp.json +2 -2
- package/ide/hooks/context-hook.js +6 -2
- package/ide/hooks/post-recall-hook.js +7 -3
- package/ide/hooks/tool-event-hook.sh +2 -1
- package/package.json +19 -10
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin/_GENERATED.md +1 -1
- package/plugin/agents/slm-memory-advisor.md +1 -1
- package/plugin/requirements.txt +1 -1
- package/plugin/skills/slm-session/SKILL.md +1 -1
- package/plugin-src/rules/AGENTS.md +1 -1
- package/pyproject.toml +40 -8
- package/scripts/postinstall-interactive.js +17 -94
- package/scripts/postinstall.js +185 -258
- package/scripts/preuninstall.js +9 -50
- package/src/superlocalmemory/__init__.py +2 -2
- package/src/superlocalmemory/attribution/mathematical_dna.py +1 -1
- package/src/superlocalmemory/attribution/signer.py +34 -19
- package/src/superlocalmemory/attribution/watermark.py +1 -1
- package/src/superlocalmemory/cli/_lazy_init.py +3 -5
- package/src/superlocalmemory/cli/commands.py +490 -195
- package/src/superlocalmemory/cli/context_commands.py +5 -4
- package/src/superlocalmemory/cli/daemon.py +282 -187
- package/src/superlocalmemory/cli/db_migrate.py +3 -1
- package/src/superlocalmemory/cli/diagnostics_cmd.py +28 -0
- package/src/superlocalmemory/cli/evidence_cmd.py +103 -0
- package/src/superlocalmemory/cli/ingest_cmd.py +7 -3
- package/src/superlocalmemory/cli/main.py +128 -31
- package/src/superlocalmemory/cli/pending_store.py +54 -38
- package/src/superlocalmemory/cli/scale_engine_cmd.py +37 -0
- package/src/superlocalmemory/cli/service_installer.py +57 -52
- package/src/superlocalmemory/cli/setup_wizard.py +142 -88
- package/src/superlocalmemory/cli/version_banner.py +2 -1
- package/src/superlocalmemory/code_graph/config.py +3 -1
- package/src/superlocalmemory/core/backend_orchestrator.py +81 -21
- package/src/superlocalmemory/core/config.py +65 -20
- package/src/superlocalmemory/core/consolidation_engine.py +9 -7
- package/src/superlocalmemory/core/context_cache.py +56 -8
- package/src/superlocalmemory/core/derivation_lineage.py +246 -0
- package/src/superlocalmemory/core/embedding_worker.py +32 -20
- package/src/superlocalmemory/core/embeddings.py +54 -18
- package/src/superlocalmemory/core/engine.py +150 -104
- package/src/superlocalmemory/core/engine_ingestion.py +513 -0
- package/src/superlocalmemory/core/engine_wiring.py +2 -0
- package/src/superlocalmemory/core/evidence_bundle.py +526 -0
- package/src/superlocalmemory/core/fact_consolidator.py +5 -11
- package/src/superlocalmemory/core/graph_analyzer.py +2 -2
- package/src/superlocalmemory/core/health_monitor.py +4 -2
- package/src/superlocalmemory/core/ingestion_command.py +636 -0
- package/src/superlocalmemory/core/injection.py +69 -18
- package/src/superlocalmemory/core/lifecycle_state.py +153 -0
- package/src/superlocalmemory/core/maintenance.py +23 -22
- package/src/superlocalmemory/core/maintenance_scheduler.py +51 -35
- package/src/superlocalmemory/core/mutations.py +143 -0
- package/src/superlocalmemory/core/platform_utils.py +7 -4
- package/src/superlocalmemory/core/ram_lock.py +16 -5
- package/src/superlocalmemory/core/rate_limit.py +1 -1
- package/src/superlocalmemory/core/recall_pipeline.py +60 -101
- package/src/superlocalmemory/core/recall_worker.py +76 -59
- package/src/superlocalmemory/core/registry.py +1 -1
- package/src/superlocalmemory/core/scale_engine.py +293 -0
- package/src/superlocalmemory/core/score_contract.py +62 -0
- package/src/superlocalmemory/core/security_primitives.py +3 -1
- package/src/superlocalmemory/core/slm_disabled.py +3 -5
- package/src/superlocalmemory/core/store_pipeline.py +172 -40
- package/src/superlocalmemory/core/tier_manager.py +32 -20
- package/src/superlocalmemory/core/worker_pool.py +13 -4
- package/src/superlocalmemory/dynamics/activation_guided_quantization.py +1 -1
- package/src/superlocalmemory/dynamics/eap_scheduler.py +10 -3
- package/src/superlocalmemory/dynamics/ebbinghaus_langevin_coupling.py +1 -1
- package/src/superlocalmemory/dynamics/fisher_langevin_coupling.py +1 -1
- package/src/superlocalmemory/encoding/auto_linker.py +1 -1
- package/src/superlocalmemory/encoding/cognitive_consolidator.py +7 -16
- package/src/superlocalmemory/encoding/consolidator.py +22 -5
- package/src/superlocalmemory/encoding/fact_extractor.py +1 -1
- package/src/superlocalmemory/encoding/foresight.py +2 -0
- package/src/superlocalmemory/encoding/graph_builder.py +1 -1
- package/src/superlocalmemory/encoding/temporal_parser.py +2 -0
- package/src/superlocalmemory/evaluation/__init__.py +13 -0
- package/src/superlocalmemory/evaluation/calibration.py +308 -0
- package/src/superlocalmemory/evolution/skill_evolver.py +2 -1
- package/src/superlocalmemory/graph/cozo_backend.py +256 -23
- package/src/superlocalmemory/hooks/_outcome_common.py +21 -11
- package/src/superlocalmemory/hooks/antigravity_adapter.py +10 -31
- package/src/superlocalmemory/hooks/auto_invoker.py +25 -27
- package/src/superlocalmemory/hooks/auto_recall.py +31 -6
- package/src/superlocalmemory/hooks/auto_recall_hook.py +13 -33
- package/src/superlocalmemory/hooks/before_web_hook.py +9 -7
- package/src/superlocalmemory/hooks/claude_code_hooks.py +126 -39
- package/src/superlocalmemory/hooks/codex_assets.py +59 -0
- package/src/superlocalmemory/hooks/codex_hooks.py +186 -0
- package/src/superlocalmemory/hooks/context_payload.py +1 -1
- package/src/superlocalmemory/hooks/copilot_adapter.py +9 -24
- package/src/superlocalmemory/hooks/cursor_adapter.py +10 -32
- package/src/superlocalmemory/hooks/hook_daemon.py +4 -2
- package/src/superlocalmemory/hooks/hook_handlers.py +241 -55
- package/src/superlocalmemory/hooks/memory_protocol.py +5 -3
- package/src/superlocalmemory/hooks/post_tool_async_hook.py +4 -2
- package/src/superlocalmemory/hooks/session_registry.py +15 -8
- package/src/superlocalmemory/hooks/stop_outcome_hook.py +10 -6
- package/src/superlocalmemory/hooks/topic_shift_hook.py +42 -12
- package/src/superlocalmemory/hooks/user_prompt_hook.py +9 -14
- package/src/superlocalmemory/hooks/user_prompt_rehash_hook.py +19 -11
- package/src/superlocalmemory/infra/auth_middleware.py +38 -5
- package/src/superlocalmemory/infra/backup.py +7 -5
- package/src/superlocalmemory/infra/cloud_backup.py +18 -8
- package/src/superlocalmemory/infra/daemon_identity.py +248 -0
- package/src/superlocalmemory/infra/data_root.py +199 -0
- package/src/superlocalmemory/infra/event_bus.py +3 -1
- package/src/superlocalmemory/infra/local_diagnostics.py +327 -0
- package/src/superlocalmemory/infra/process_reaper.py +23 -0
- package/src/superlocalmemory/ingestion/adapter_manager.py +27 -9
- package/src/superlocalmemory/ingestion/base_adapter.py +25 -31
- package/src/superlocalmemory/ingestion/calendar_adapter.py +13 -4
- package/src/superlocalmemory/ingestion/credentials.py +14 -7
- package/src/superlocalmemory/ingestion/gmail_adapter.py +13 -4
- package/src/superlocalmemory/ingestion/transcript_adapter.py +7 -2
- package/src/superlocalmemory/learning/consolidation_quantization_worker.py +1 -1
- package/src/superlocalmemory/learning/ensemble.py +11 -0
- package/src/superlocalmemory/learning/entity_compiler.py +1 -1
- package/src/superlocalmemory/learning/feedback.py +1 -1
- package/src/superlocalmemory/learning/forgetting_scheduler.py +12 -7
- package/src/superlocalmemory/learning/quantization_scheduler.py +1 -1
- package/src/superlocalmemory/learning/ranker.py +4 -1
- package/src/superlocalmemory/learning/source_quality.py +1 -1
- package/src/superlocalmemory/learning/trigram_index.py +3 -2
- package/src/superlocalmemory/llm/backbone.py +13 -8
- package/src/superlocalmemory/math/ebbinghaus.py +1 -1
- package/src/superlocalmemory/math/fisher.py +1 -1
- package/src/superlocalmemory/math/fisher_quantized.py +1 -1
- package/src/superlocalmemory/math/hopfield.py +1 -1
- package/src/superlocalmemory/math/langevin.py +1 -1
- package/src/superlocalmemory/math/polar_quant.py +3 -4
- package/src/superlocalmemory/math/qjl.py +1 -1
- package/src/superlocalmemory/math/sheaf.py +1 -1
- package/src/superlocalmemory/math/turbo_quant.py +3 -2
- package/src/superlocalmemory/mcp/_daemon_proxy.py +12 -11
- package/src/superlocalmemory/mcp/_pool_adapter.py +27 -0
- package/src/superlocalmemory/mcp/http_transport.py +53 -0
- package/src/superlocalmemory/mcp/server.py +39 -13
- package/src/superlocalmemory/mcp/shared.py +69 -3
- package/src/superlocalmemory/mcp/tools_active.py +141 -31
- package/src/superlocalmemory/mcp/tools_core.py +128 -29
- package/src/superlocalmemory/mcp/tools_evolution.py +5 -7
- package/src/superlocalmemory/mcp/tools_learning.py +42 -2
- package/src/superlocalmemory/mcp/tools_mesh.py +7 -23
- package/src/superlocalmemory/mcp/tools_optimize.py +8 -1
- package/src/superlocalmemory/mcp/tools_v28.py +23 -2
- package/src/superlocalmemory/mcp/tools_v3.py +26 -1
- package/src/superlocalmemory/mcp/tools_v33.py +56 -17
- package/src/superlocalmemory/mesh/broker.py +2 -0
- package/src/superlocalmemory/mesh/remote_sync.py +50 -12
- package/src/superlocalmemory/optimize/cache/manager.py +77 -1
- package/src/superlocalmemory/optimize/cache/semantic.py +23 -3
- package/src/superlocalmemory/optimize/compress/ccr.py +4 -0
- package/src/superlocalmemory/optimize/compress/router.py +6 -1
- package/src/superlocalmemory/optimize/config/__init__.py +5 -0
- package/src/superlocalmemory/optimize/config/store.py +6 -4
- package/src/superlocalmemory/optimize/proxy/_helpers.py +15 -5
- package/src/superlocalmemory/optimize/proxy/capture.py +3 -2
- package/src/superlocalmemory/optimize/proxy/server.py +2 -2
- package/src/superlocalmemory/optimize/storage/db.py +14 -13
- package/src/superlocalmemory/retrieval/agentic.py +1 -1
- package/src/superlocalmemory/retrieval/ann_index.py +1 -1
- package/src/superlocalmemory/retrieval/bm25_channel.py +35 -11
- package/src/superlocalmemory/retrieval/bridge_discovery.py +73 -8
- package/src/superlocalmemory/retrieval/engine.py +169 -79
- package/src/superlocalmemory/retrieval/entity_channel.py +289 -67
- package/src/superlocalmemory/retrieval/forgetting_filter.py +1 -1
- package/src/superlocalmemory/retrieval/fusion.py +1 -1
- package/src/superlocalmemory/retrieval/hopfield_channel.py +118 -30
- package/src/superlocalmemory/retrieval/profile_channel.py +1 -1
- package/src/superlocalmemory/retrieval/quantization_aware_search.py +16 -10
- package/src/superlocalmemory/retrieval/reranker.py +56 -20
- package/src/superlocalmemory/retrieval/scope_policy.py +85 -0
- package/src/superlocalmemory/retrieval/semantic_channel.py +122 -14
- package/src/superlocalmemory/retrieval/spreading_activation.py +141 -25
- package/src/superlocalmemory/retrieval/strategy.py +1 -1
- package/src/superlocalmemory/retrieval/temporal_channel.py +30 -15
- package/src/superlocalmemory/retrieval/vector_store.py +1 -1
- package/src/superlocalmemory/server/api.py +10 -7
- package/src/superlocalmemory/server/bandit_loops.py +4 -2
- package/src/superlocalmemory/server/recall_serializer.py +24 -0
- package/src/superlocalmemory/server/route_mutations.py +84 -0
- package/src/superlocalmemory/server/routes/agents.py +8 -6
- package/src/superlocalmemory/server/routes/brain.py +14 -12
- package/src/superlocalmemory/server/routes/chat.py +29 -12
- package/src/superlocalmemory/server/routes/data_io.py +55 -24
- package/src/superlocalmemory/server/routes/helpers.py +29 -4
- package/src/superlocalmemory/server/routes/ingest.py +53 -36
- package/src/superlocalmemory/server/routes/memories.py +104 -43
- package/src/superlocalmemory/server/routes/mesh.py +31 -0
- package/src/superlocalmemory/server/routes/profiles.py +26 -4
- package/src/superlocalmemory/server/routes/tiers.py +43 -11
- package/src/superlocalmemory/server/routes/timeline.py +5 -1
- package/src/superlocalmemory/server/routes/v3_api.py +76 -21
- package/src/superlocalmemory/server/security_middleware.py +1 -1
- package/src/superlocalmemory/server/ui.py +6 -3
- package/src/superlocalmemory/server/unified_daemon.py +680 -293
- package/src/superlocalmemory/server/write_identity.py +147 -0
- package/src/superlocalmemory/storage/access_log.py +4 -3
- package/src/superlocalmemory/storage/database.py +118 -25
- package/src/superlocalmemory/storage/migration_runner.py +84 -1
- package/src/superlocalmemory/storage/migration_v33.py +1 -1
- package/src/superlocalmemory/storage/migrations/M002_model_state_history.py +6 -60
- package/src/superlocalmemory/storage/migrations/M018_ingestion_operations.py +120 -0
- package/src/superlocalmemory/storage/migrations/M019_derivation_lineage.py +54 -0
- package/src/superlocalmemory/storage/migrations/M020_model_state_integrity.py +52 -0
- package/src/superlocalmemory/storage/migrations/__init__.py +5 -0
- package/src/superlocalmemory/storage/models.py +16 -0
- package/src/superlocalmemory/storage/quantized_store.py +20 -3
- package/src/superlocalmemory/storage/v2_migrator.py +5 -3
- package/src/superlocalmemory/ui/favicon.svg +5 -0
- package/src/superlocalmemory/ui/index.html +1 -0
- package/src/superlocalmemory/ui/js/compliance.js +1 -1
- package/src/superlocalmemory/ui/js/core.js +49 -8
- package/src/superlocalmemory/ui/js/dashboard.js +23 -2
- package/src/superlocalmemory/ui/js/feedback.js +1 -1
- package/src/superlocalmemory/ui/js/graph-filters.js +1 -1
- package/src/superlocalmemory/ui/js/graph-ui.js +1 -1
- package/src/superlocalmemory/ui/js/lifecycle.js +1 -1
- package/src/superlocalmemory/ui/js/ng-mesh.js +15 -49
- package/src/superlocalmemory/ui/js/settings.js +4 -2
- package/src/superlocalmemory/vector/lancedb_backend.py +57 -9
- package/bin/slm +0 -59
- package/bin/slm.bat +0 -77
- package/bin/slm.cmd +0 -5
- package/ide/integrations/langchain/README.md +0 -106
- package/ide/integrations/langchain/langchain_superlocalmemory/__init__.py +0 -9
- package/ide/integrations/langchain/langchain_superlocalmemory/chat_message_history.py +0 -201
- package/ide/integrations/langchain/pyproject.toml +0 -38
- package/ide/integrations/langchain/tests/__init__.py +0 -3
- package/ide/integrations/langchain/tests/test_chat_message_history.py +0 -215
- package/ide/integrations/langchain/tests/test_security.py +0 -117
- package/ide/integrations/llamaindex/README.md +0 -81
- package/ide/integrations/llamaindex/llama_index/storage/chat_store/superlocalmemory/__init__.py +0 -9
- package/ide/integrations/llamaindex/llama_index/storage/chat_store/superlocalmemory/base.py +0 -316
- package/ide/integrations/llamaindex/pyproject.toml +0 -43
- package/ide/integrations/llamaindex/tests/__init__.py +0 -3
- package/ide/integrations/llamaindex/tests/test_chat_store.py +0 -294
- package/ide/integrations/llamaindex/tests/test_security.py +0 -241
- package/plugin-src/.mcp.json +0 -12
- package/plugin-src/agents/slm-memory-advisor.md +0 -44
- package/plugin-src/agents/slm-optimize-advisor.md +0 -38
- package/plugin-src/hooks/.gitkeep +0 -0
- package/plugin-src/hooks/hooks.json +0 -23
- package/plugin-src/manifest.json +0 -25
- package/plugin-src/requirements.txt +0 -1
- package/plugin-src/rules/CLAUDE.md.fragment +0 -44
- package/plugin-src/scripts/ensure-venv.bat +0 -122
- package/plugin-src/scripts/ensure-venv.sh +0 -105
- package/plugin-src/scripts/slm-launch +0 -15
- package/plugin-src/scripts/slm-launch.bat +0 -17
- package/plugin-src/settings.json +0 -16
- package/plugin-src/skills/slm-cache/SKILL.md +0 -140
- package/plugin-src/skills/slm-compress/SKILL.md +0 -143
- package/plugin-src/skills/slm-graph/SKILL.md +0 -300
- package/plugin-src/skills/slm-recall/SKILL.md +0 -204
- package/plugin-src/skills/slm-remember/SKILL.md +0 -194
- package/plugin-src/skills/slm-session/SKILL.md +0 -207
- package/plugin-src/skills/slm-status/SKILL.md +0 -149
- package/scripts/__tests__/build-plugin.test.mjs +0 -613
- package/scripts/_savings_math.py +0 -270
- package/scripts/build-dmg.sh +0 -417
- package/scripts/build-plugin.js +0 -742
- package/scripts/build-slm-hook.ps1 +0 -40
- package/scripts/build-slm-hook.sh +0 -45
- package/scripts/build_entry.py +0 -452
- package/scripts/ci/stage5b_gate.sh +0 -50
- package/scripts/dogfood_savings.py +0 -490
- package/scripts/generate-thumbnails.py +0 -218
- package/scripts/install-skills.ps1 +0 -4
- package/scripts/install-skills.sh +0 -5
- package/scripts/install.ps1 +0 -701
- package/scripts/install.sh +0 -1015
- package/scripts/postinstall_binary.js +0 -287
- package/scripts/prepack.js +0 -33
- package/scripts/release_manifest.py +0 -273
- package/scripts/slm-hook.spec +0 -56
- package/scripts/start-dashboard.ps1 +0 -52
- package/scripts/start-dashboard.sh +0 -41
- package/scripts/sync-wiki.ps1 +0 -127
- package/scripts/sync-wiki.sh +0 -82
- package/scripts/test-dmg.sh +0 -161
- package/scripts/test-npm-package.ps1 +0 -252
- package/scripts/test-npm-package.sh +0 -207
- package/scripts/verify-install.ps1 +0 -294
- package/scripts/verify-install.sh +0 -266
- package/scripts/verify-v27.ps1 +0 -301
- package/scripts/verify-v27.sh +0 -233
- package/src/superlocalmemory.egg-info/PKG-INFO +0 -513
- package/src/superlocalmemory.egg-info/SOURCES.txt +0 -529
- package/src/superlocalmemory.egg-info/dependency_links.txt +0 -1
- package/src/superlocalmemory.egg-info/entry_points.txt +0 -2
- package/src/superlocalmemory.egg-info/requires.txt +0 -71
- package/src/superlocalmemory.egg-info/top_level.txt +0 -1
|
@@ -79,11 +79,11 @@ class BackendOrchestrator:
|
|
|
79
79
|
# 1. Apply schema (if not already applied)
|
|
80
80
|
self._apply_schema_v345()
|
|
81
81
|
|
|
82
|
-
# 2. Initialize TierManager (always)
|
|
82
|
+
# 2. Initialize TierManager (always). Backends are refreshed after
|
|
83
|
+
# optional projections have been opened below.
|
|
83
84
|
try:
|
|
84
|
-
from superlocalmemory.core.tier_manager import evaluate_tiers
|
|
85
|
+
from superlocalmemory.core.tier_manager import evaluate_tiers
|
|
85
86
|
self._tiers = evaluate_tiers
|
|
86
|
-
set_backends(cozo=self._cozo, lancedb=self._lancedb)
|
|
87
87
|
logger.info("BackendOrchestrator: TierManager initialized")
|
|
88
88
|
except Exception as exc:
|
|
89
89
|
logger.warning("TierManager init failed (non-fatal): %s", exc)
|
|
@@ -97,6 +97,16 @@ class BackendOrchestrator:
|
|
|
97
97
|
except Exception as exc:
|
|
98
98
|
logger.warning("Initial rebalance failed (non-fatal): %s", exc)
|
|
99
99
|
|
|
100
|
+
# Backends may be installed with the product, but installing a wheel
|
|
101
|
+
# is not authorization to mutate an existing data root. Only a
|
|
102
|
+
# verified, explicit promotion may initialize and migrate projections.
|
|
103
|
+
if getattr(self._config, "scale_engine_state", "local_core") != "promoted":
|
|
104
|
+
logger.info(
|
|
105
|
+
"Scale Engine remains on Local Core (state=%s)",
|
|
106
|
+
getattr(self._config, "scale_engine_state", "local_core"),
|
|
107
|
+
)
|
|
108
|
+
return
|
|
109
|
+
|
|
100
110
|
# 4. Initialize CozoDB if available
|
|
101
111
|
cozo_available = self._detect_cozo()
|
|
102
112
|
if cozo_available:
|
|
@@ -107,20 +117,18 @@ class BackendOrchestrator:
|
|
|
107
117
|
if lancedb_available:
|
|
108
118
|
self._init_lancedb()
|
|
109
119
|
|
|
110
|
-
#
|
|
120
|
+
# A promoted stage is already parity-verified. Never rebuild it at
|
|
121
|
+
# startup: automatic migration would bypass the staged lifecycle and
|
|
122
|
+
# could make the active projection diverge from canonical SQLite.
|
|
111
123
|
if self._cozo:
|
|
112
|
-
|
|
113
|
-
if status in ("not_initialized", "migrating"):
|
|
114
|
-
if status == "migrating":
|
|
115
|
-
logger.warning("CozoDB migration interrupted — rebuilding")
|
|
116
|
-
self._migrate_cozo()
|
|
117
|
-
|
|
124
|
+
self._update_status("cozo", "active", self._cozo.health_check().get("edges", 0))
|
|
118
125
|
if self._lancedb:
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
126
|
+
self._update_status("lancedb", "active", self._lancedb.health_check().get("vectors", 0))
|
|
127
|
+
try:
|
|
128
|
+
from superlocalmemory.core.tier_manager import set_backends
|
|
129
|
+
set_backends(cozo=self._cozo, lancedb=self._lancedb)
|
|
130
|
+
except Exception as exc:
|
|
131
|
+
logger.warning("TierManager backend registration failed (non-fatal): %s", exc)
|
|
124
132
|
|
|
125
133
|
logger.info("BackendOrchestrator: daemon ready (cozo=%s, lancedb=%s)",
|
|
126
134
|
"active" if self._cozo and self._cozo_status() == "active" else "off",
|
|
@@ -149,15 +157,38 @@ class BackendOrchestrator:
|
|
|
149
157
|
self._sync_fact_embedding(fact)
|
|
150
158
|
|
|
151
159
|
def _sync_fact_entities(self, fact: Any) -> None:
|
|
152
|
-
"""
|
|
160
|
+
"""Synchronize one fact's canonical entity bridge and fact edges."""
|
|
153
161
|
try:
|
|
162
|
+
# Retrying ingestion must not retain stale fact/entity links.
|
|
163
|
+
self._cozo.remove_fact(fact.fact_id)
|
|
154
164
|
entities = getattr(fact, "canonical_entities", []) or []
|
|
165
|
+
profile_id = getattr(fact, "profile_id", "default") or "default"
|
|
155
166
|
for eid in entities:
|
|
156
|
-
self.
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
167
|
+
rows = self._db.execute(
|
|
168
|
+
"SELECT canonical_name, entity_type, fact_count FROM canonical_entities "
|
|
169
|
+
"WHERE entity_id = ? AND profile_id = ?",
|
|
170
|
+
(eid, profile_id),
|
|
171
|
+
)
|
|
172
|
+
if rows:
|
|
173
|
+
entity = dict(rows[0])
|
|
174
|
+
self._cozo.add_entity(
|
|
175
|
+
eid,
|
|
176
|
+
entity.get("canonical_name") or eid,
|
|
177
|
+
entity.get("entity_type") or "concept",
|
|
178
|
+
{"fact_count": int(entity.get("fact_count") or 0)},
|
|
179
|
+
profile_id,
|
|
180
|
+
)
|
|
181
|
+
self._cozo.add_fact_entities(fact.fact_id, entities, profile_id)
|
|
182
|
+
for row in self._db.execute(
|
|
183
|
+
"SELECT source_id, target_id, edge_type, weight FROM graph_edges "
|
|
184
|
+
"WHERE profile_id = ? AND (source_id = ? OR target_id = ?)",
|
|
185
|
+
(profile_id, fact.fact_id, fact.fact_id),
|
|
186
|
+
):
|
|
187
|
+
edge = dict(row)
|
|
188
|
+
self._cozo.add_edge(
|
|
189
|
+
edge["source_id"], edge["target_id"], edge.get("edge_type") or "related",
|
|
190
|
+
float(edge.get("weight") or 1.0), profile_id=profile_id,
|
|
191
|
+
)
|
|
161
192
|
except Exception as exc:
|
|
162
193
|
logger.debug("CozoDB incremental sync skipped: %s", exc)
|
|
163
194
|
|
|
@@ -169,10 +200,30 @@ class BackendOrchestrator:
|
|
|
169
200
|
tier = getattr(fact, "lifecycle", "active")
|
|
170
201
|
self._lancedb.add_vectors(
|
|
171
202
|
[fact.fact_id], [embedding], [tier],
|
|
203
|
+
getattr(fact, "profile_id", "default") or "default",
|
|
172
204
|
)
|
|
173
205
|
except Exception as exc:
|
|
174
206
|
logger.debug("LanceDB incremental sync skipped: %s", exc)
|
|
175
207
|
|
|
208
|
+
def sync_deleted_fact(self, fact_id: str) -> None:
|
|
209
|
+
"""Remove a fact from derived projections after canonical deletion."""
|
|
210
|
+
if self._cozo and self._cozo_status() == "active":
|
|
211
|
+
try:
|
|
212
|
+
self._cozo.remove_fact(fact_id)
|
|
213
|
+
except Exception as exc:
|
|
214
|
+
logger.warning("Cozo deletion sync failed for %s: %s", fact_id[:16], exc)
|
|
215
|
+
if self._lancedb and self._lancedb_status() == "active":
|
|
216
|
+
try:
|
|
217
|
+
self._lancedb.remove_vector(fact_id)
|
|
218
|
+
except Exception as exc:
|
|
219
|
+
logger.warning("Lance deletion sync failed for %s: %s", fact_id[:16], exc)
|
|
220
|
+
|
|
221
|
+
def sync_changed_fact(self, fact_id: str) -> None:
|
|
222
|
+
"""Refresh projections after an authorized canonical fact update."""
|
|
223
|
+
fact = self._db.get_fact(fact_id)
|
|
224
|
+
if fact is not None:
|
|
225
|
+
self.sync_new_fact(fact)
|
|
226
|
+
|
|
176
227
|
# ------------------------------------------------------------------
|
|
177
228
|
# Backend Access
|
|
178
229
|
# ------------------------------------------------------------------
|
|
@@ -189,6 +240,15 @@ class BackendOrchestrator:
|
|
|
189
240
|
return self._lancedb
|
|
190
241
|
return None
|
|
191
242
|
|
|
243
|
+
def graph_retrieval_ready(self) -> bool:
|
|
244
|
+
"""Whether Cozo can be injected into entity recall.
|
|
245
|
+
|
|
246
|
+
Cozo carries both canonical entity mappings and fact graph edges. The
|
|
247
|
+
entity channel still shadows every projected result against SQLite and
|
|
248
|
+
fails closed on any mismatch, so availability never weakens recall.
|
|
249
|
+
"""
|
|
250
|
+
return bool(self._cozo and self._cozo_status() == "active")
|
|
251
|
+
|
|
192
252
|
# ------------------------------------------------------------------
|
|
193
253
|
# Health Check
|
|
194
254
|
# ------------------------------------------------------------------
|
|
@@ -13,13 +13,14 @@ Part of Qualixar | Author: Varun Pratap Bhardwaj
|
|
|
13
13
|
from __future__ import annotations
|
|
14
14
|
|
|
15
15
|
import logging
|
|
16
|
-
from dataclasses import dataclass, field
|
|
16
|
+
from dataclasses import asdict, dataclass, field
|
|
17
17
|
from pathlib import Path
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
from superlocalmemory.infra.data_root import DynamicStatePath, canonical_data_root
|
|
21
20
|
from superlocalmemory.storage.models import Mode
|
|
22
21
|
|
|
22
|
+
logger = logging.getLogger(__name__)
|
|
23
|
+
|
|
23
24
|
|
|
24
25
|
# ---------------------------------------------------------------------------
|
|
25
26
|
# Canonical limits (WP-02 — single source of truth across all surfaces)
|
|
@@ -35,7 +36,7 @@ CANONICAL_RECALL_LIMIT: int = 20
|
|
|
35
36
|
# Default Paths
|
|
36
37
|
# ---------------------------------------------------------------------------
|
|
37
38
|
|
|
38
|
-
DEFAULT_BASE_DIR =
|
|
39
|
+
DEFAULT_BASE_DIR = DynamicStatePath()
|
|
39
40
|
DEFAULT_DB_NAME = "memory.db"
|
|
40
41
|
DEFAULT_PROFILES_FILE = "profiles.json"
|
|
41
42
|
CURRENT_MODE_FILE = "current_mode"
|
|
@@ -43,6 +44,11 @@ CURRENT_MODE_FILE = "current_mode"
|
|
|
43
44
|
_MODE_CONFIG_NAMES: dict | None = None
|
|
44
45
|
|
|
45
46
|
|
|
47
|
+
def _runtime_base_dir() -> Path:
|
|
48
|
+
"""Resolve the process namespace when a config root is not explicit."""
|
|
49
|
+
return canonical_data_root()
|
|
50
|
+
|
|
51
|
+
|
|
46
52
|
# ---------------------------------------------------------------------------
|
|
47
53
|
# Embedding Config
|
|
48
54
|
# ---------------------------------------------------------------------------
|
|
@@ -768,7 +774,7 @@ class SLMConfig:
|
|
|
768
774
|
"""
|
|
769
775
|
|
|
770
776
|
mode: Mode = Mode.A
|
|
771
|
-
base_dir: Path =
|
|
777
|
+
base_dir: Path = field(default_factory=_runtime_base_dir)
|
|
772
778
|
db_path: Path | None = None # Computed from base_dir if None
|
|
773
779
|
active_profile: str = "default"
|
|
774
780
|
|
|
@@ -801,6 +807,9 @@ class SLMConfig:
|
|
|
801
807
|
# v3.5.0: scaling backends — "sqlite" / "cozo" / "auto" / "lancedb" / "sqlite-vec" / "auto".
|
|
802
808
|
graph_backend: str = "auto" # "auto" = cozo if pycozo installed, else sqlite
|
|
803
809
|
vector_backend: str = "auto" # "auto" = lancedb if installed, else sqlite-vec
|
|
810
|
+
# Scale Engine is installed separately from activation. Existing roots
|
|
811
|
+
# stay on SQLite until a staged parity check promotes these projections.
|
|
812
|
+
scale_engine_state: str = "local_core" # local_core | prepared | verified | promoted
|
|
804
813
|
evolution: EvolutionConfig = field(default_factory=EvolutionConfig)
|
|
805
814
|
health: HealthConfig = field(default_factory=HealthConfig)
|
|
806
815
|
|
|
@@ -824,16 +833,22 @@ class SLMConfig:
|
|
|
824
833
|
@classmethod
|
|
825
834
|
def load(cls, config_path: Path | None = None) -> SLMConfig:
|
|
826
835
|
"""Load config from JSON file. Returns default Mode A if file doesn't exist."""
|
|
827
|
-
#
|
|
828
|
-
#
|
|
836
|
+
# V3.7: process namespace selection is authoritative. A persisted
|
|
837
|
+
# base_dir may bootstrap a legacy custom root only when no environment
|
|
838
|
+
# alias selected the process namespace.
|
|
829
839
|
try:
|
|
830
|
-
from superlocalmemory.
|
|
831
|
-
|
|
840
|
+
from superlocalmemory.infra.data_root import (
|
|
841
|
+
canonical_data_root,
|
|
842
|
+
environment_data_root,
|
|
843
|
+
)
|
|
844
|
+
_environment_base = environment_data_root()
|
|
845
|
+
_runtime_base = canonical_data_root()
|
|
832
846
|
except Exception:
|
|
847
|
+
_environment_base = None
|
|
833
848
|
_runtime_base = DEFAULT_BASE_DIR
|
|
834
849
|
path = config_path or (_runtime_base / "config.json")
|
|
835
850
|
if not path.exists():
|
|
836
|
-
return cls.for_mode(Mode.A)
|
|
851
|
+
return cls.for_mode(Mode.A, base_dir=_runtime_base)
|
|
837
852
|
import json
|
|
838
853
|
try:
|
|
839
854
|
data = json.loads(path.read_text())
|
|
@@ -843,13 +858,21 @@ class SLMConfig:
|
|
|
843
858
|
logger.warning(
|
|
844
859
|
"config.json unreadable/corrupt (%s) — using Mode A default", exc
|
|
845
860
|
)
|
|
846
|
-
return cls.for_mode(Mode.A)
|
|
861
|
+
return cls.for_mode(Mode.A, base_dir=_runtime_base)
|
|
847
862
|
mode = Mode(data.get("mode", "a"))
|
|
848
863
|
llm_data = data.get("llm", {})
|
|
849
864
|
emb_data = data.get("embedding", {})
|
|
850
865
|
# V3.5.9: read base_dir before constructing config so for_mode() builds
|
|
851
866
|
# db_path from the user's directory, not DEFAULT_BASE_DIR.
|
|
852
|
-
|
|
867
|
+
if _environment_base is not None:
|
|
868
|
+
raw_base_dir = _environment_base
|
|
869
|
+
else:
|
|
870
|
+
try:
|
|
871
|
+
raw_base_dir = canonical_data_root(
|
|
872
|
+
configured_base_dir=data.get("base_dir", _runtime_base),
|
|
873
|
+
)
|
|
874
|
+
except Exception:
|
|
875
|
+
raw_base_dir = _runtime_base
|
|
853
876
|
config = cls.for_mode(
|
|
854
877
|
mode,
|
|
855
878
|
llm_provider=llm_data.get("provider", ""),
|
|
@@ -865,6 +888,13 @@ class SLMConfig:
|
|
|
865
888
|
base_dir=raw_base_dir,
|
|
866
889
|
)
|
|
867
890
|
config.active_profile = data.get("active_profile", "default")
|
|
891
|
+
config.graph_backend = data.get("graph_backend", "auto")
|
|
892
|
+
config.vector_backend = data.get("vector_backend", "auto")
|
|
893
|
+
state = data.get("scale_engine_state", "local_core")
|
|
894
|
+
config.scale_engine_state = (
|
|
895
|
+
state if state in {"local_core", "prepared", "verified", "promoted"}
|
|
896
|
+
else "local_core"
|
|
897
|
+
)
|
|
868
898
|
|
|
869
899
|
# V3.3 config fields (additive — defaults work if missing from JSON)
|
|
870
900
|
fg = data.get("forgetting", {})
|
|
@@ -1011,6 +1041,9 @@ class SLMConfig:
|
|
|
1011
1041
|
data = {
|
|
1012
1042
|
"mode": effective_mode,
|
|
1013
1043
|
"active_profile": self.active_profile,
|
|
1044
|
+
"graph_backend": self.graph_backend,
|
|
1045
|
+
"vector_backend": self.vector_backend,
|
|
1046
|
+
"scale_engine_state": self.scale_engine_state,
|
|
1014
1047
|
"base_dir": str(self.base_dir), # V3.5.9: persist so load() can restore custom paths
|
|
1015
1048
|
"llm": {
|
|
1016
1049
|
"provider": self.llm.provider,
|
|
@@ -1026,11 +1059,10 @@ class SLMConfig:
|
|
|
1026
1059
|
"api_key": self.embedding.api_key,
|
|
1027
1060
|
"deployment_name": self.embedding.deployment_name,
|
|
1028
1061
|
},
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
},
|
|
1062
|
+
# Persist the complete retrieval contract. Saving only the
|
|
1063
|
+
# cross-encoder subset silently reset channel limits, evidence
|
|
1064
|
+
# floors, and agentic settings on the next mode/provider change.
|
|
1065
|
+
"retrieval": asdict(self.retrieval),
|
|
1034
1066
|
}
|
|
1035
1067
|
|
|
1036
1068
|
# V3.4.11: Persist evolution config (C-CONFIGSAVE fix)
|
|
@@ -1165,6 +1197,7 @@ class SLMConfig:
|
|
|
1165
1197
|
base_dir=_base,
|
|
1166
1198
|
embedding=_a_emb,
|
|
1167
1199
|
llm=LLMConfig(), # No LLM
|
|
1200
|
+
temporal_validator=TemporalValidatorConfig(mode="a"),
|
|
1168
1201
|
retrieval=RetrievalConfig(
|
|
1169
1202
|
# V3.3.2: ONNX cross-encoder enabled for all modes (~200MB)
|
|
1170
1203
|
use_cross_encoder=True,
|
|
@@ -1206,6 +1239,7 @@ class SLMConfig:
|
|
|
1206
1239
|
api_base=llm_api_base or "http://localhost:11434",
|
|
1207
1240
|
api_key=llm_api_key or "",
|
|
1208
1241
|
),
|
|
1242
|
+
temporal_validator=TemporalValidatorConfig(mode="b"),
|
|
1209
1243
|
retrieval=RetrievalConfig(
|
|
1210
1244
|
# V3.3.2: ONNX cross-encoder enabled for all modes (~200MB)
|
|
1211
1245
|
use_cross_encoder=True,
|
|
@@ -1226,14 +1260,24 @@ class SLMConfig:
|
|
|
1226
1260
|
api_endpoint=embedding_endpoint,
|
|
1227
1261
|
api_key=embedding_key,
|
|
1228
1262
|
)
|
|
1229
|
-
|
|
1263
|
+
elif embedding_endpoint:
|
|
1230
1264
|
_c_emb = EmbeddingConfig(
|
|
1231
|
-
model_name="text-embedding-3-large",
|
|
1232
|
-
dimension=3072,
|
|
1265
|
+
model_name=embedding_model_name or "text-embedding-3-large",
|
|
1266
|
+
dimension=embedding_dimension or 3072,
|
|
1233
1267
|
api_endpoint=embedding_endpoint,
|
|
1234
1268
|
api_key=embedding_key,
|
|
1235
1269
|
deployment_name=embedding_deployment,
|
|
1236
1270
|
)
|
|
1271
|
+
else:
|
|
1272
|
+
# Mode C upgrades LLM capability; it must not silently require a
|
|
1273
|
+
# second paid embedding provider. A 3072-dim cloud embedding
|
|
1274
|
+
# contract without an endpoint/key was auto-routed to the local
|
|
1275
|
+
# 768-dim Ollama embedder, which made ingestion fail at vector
|
|
1276
|
+
# materialization. Cloud embeddings remain an explicit opt-in.
|
|
1277
|
+
_c_emb = EmbeddingConfig(
|
|
1278
|
+
model_name="nomic-ai/nomic-embed-text-v1.5",
|
|
1279
|
+
dimension=768,
|
|
1280
|
+
)
|
|
1237
1281
|
return cls(
|
|
1238
1282
|
mode=mode,
|
|
1239
1283
|
base_dir=_base,
|
|
@@ -1244,6 +1288,7 @@ class SLMConfig:
|
|
|
1244
1288
|
api_key=llm_api_key,
|
|
1245
1289
|
api_base=llm_api_base,
|
|
1246
1290
|
),
|
|
1291
|
+
temporal_validator=TemporalValidatorConfig(mode="c"),
|
|
1247
1292
|
channel_weights=ChannelWeights(
|
|
1248
1293
|
semantic=1.5,
|
|
1249
1294
|
bm25=1.2,
|
|
@@ -160,10 +160,9 @@ class ConsolidationEngine:
|
|
|
160
160
|
def mine(self, *a, **kw): return []
|
|
161
161
|
from superlocalmemory.hooks.auto_parameterize import AutoParameterizeHook
|
|
162
162
|
from superlocalmemory.core.config import ParameterizationConfig
|
|
163
|
-
from pathlib import Path as _Path
|
|
164
|
-
|
|
165
163
|
p_config = getattr(self._slm_config, "parameterization", ParameterizationConfig())
|
|
166
|
-
|
|
164
|
+
from superlocalmemory.infra.data_root import state_path
|
|
165
|
+
learning_db = str(state_path("learning.db"))
|
|
167
166
|
beh_store = BehavioralPatternStore(learning_db)
|
|
168
167
|
cross_proj = CrossProjectAggregator(self._db)
|
|
169
168
|
wf_miner = WorkflowMiner(self._db)
|
|
@@ -483,10 +482,13 @@ class ConsolidationEngine:
|
|
|
483
482
|
continue
|
|
484
483
|
|
|
485
484
|
# Promote: active -> warm (lifecycle transition)
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
485
|
+
from superlocalmemory.core.lifecycle_state import set_fact_lifecycle_zone
|
|
486
|
+
set_fact_lifecycle_zone(
|
|
487
|
+
self._db,
|
|
488
|
+
[fact_id],
|
|
489
|
+
"warm",
|
|
490
|
+
profile_id=profile_id,
|
|
491
|
+
from_atomic=("active",),
|
|
490
492
|
)
|
|
491
493
|
promoted += 1
|
|
492
494
|
|
|
@@ -27,6 +27,7 @@ import hashlib
|
|
|
27
27
|
import hmac
|
|
28
28
|
import json
|
|
29
29
|
import os
|
|
30
|
+
import secrets
|
|
30
31
|
import sqlite3
|
|
31
32
|
import time
|
|
32
33
|
from dataclasses import dataclass, field
|
|
@@ -38,10 +39,10 @@ from superlocalmemory.core.security_primitives import (
|
|
|
38
39
|
redact_secrets,
|
|
39
40
|
safe_resolve,
|
|
40
41
|
)
|
|
42
|
+
from superlocalmemory.infra.data_root import DynamicStatePath, canonical_data_root
|
|
41
43
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
INSTALL_TOKEN_DEFAULT: Path = Path.home() / ".superlocalmemory" / ".install_token"
|
|
44
|
+
CACHE_DB_DEFAULT = DynamicStatePath("active_brain_cache.db")
|
|
45
|
+
INSTALL_TOKEN_DEFAULT = DynamicStatePath(".install_token")
|
|
45
46
|
|
|
46
47
|
TTL_SECONDS: int = 120
|
|
47
48
|
CLEANUP_HORIZON_SECONDS: int = 600
|
|
@@ -90,6 +91,44 @@ def _read_install_token(home: Path) -> str | None:
|
|
|
90
91
|
return token or None
|
|
91
92
|
|
|
92
93
|
|
|
94
|
+
def _ensure_install_token_at(home: Path) -> str:
|
|
95
|
+
"""Create/read the binding token for an explicit cache namespace.
|
|
96
|
+
|
|
97
|
+
The shared security primitive owns the canonical namespace. This bounded
|
|
98
|
+
variant preserves ``home_dir`` as a real override without mutating global
|
|
99
|
+
path state or routing an explicit cache through the canonical token.
|
|
100
|
+
"""
|
|
101
|
+
if home.resolve(strict=False) == canonical_data_root():
|
|
102
|
+
return ensure_install_token()
|
|
103
|
+
|
|
104
|
+
token_path = home / ".install_token"
|
|
105
|
+
try:
|
|
106
|
+
token = token_path.read_text(encoding="utf-8").strip()
|
|
107
|
+
except FileNotFoundError:
|
|
108
|
+
token = ""
|
|
109
|
+
if token:
|
|
110
|
+
return token
|
|
111
|
+
|
|
112
|
+
token = secrets.token_hex(32)
|
|
113
|
+
flags = os.O_WRONLY | os.O_CREAT | os.O_EXCL
|
|
114
|
+
if hasattr(os, "O_NOFOLLOW"):
|
|
115
|
+
flags |= os.O_NOFOLLOW
|
|
116
|
+
try:
|
|
117
|
+
fd = os.open(str(token_path), flags, 0o600)
|
|
118
|
+
try:
|
|
119
|
+
os.write(fd, token.encode("utf-8"))
|
|
120
|
+
finally:
|
|
121
|
+
os.close(fd)
|
|
122
|
+
except FileExistsError:
|
|
123
|
+
existing = token_path.read_text(encoding="utf-8").strip()
|
|
124
|
+
if existing:
|
|
125
|
+
return existing
|
|
126
|
+
raise RuntimeError(f"install token is empty: {token_path}")
|
|
127
|
+
if os.name != "nt":
|
|
128
|
+
os.chmod(token_path, 0o600)
|
|
129
|
+
return token
|
|
130
|
+
|
|
131
|
+
|
|
93
132
|
# ---------------------------------------------------------------------------
|
|
94
133
|
# Writer (daemon-side)
|
|
95
134
|
# ---------------------------------------------------------------------------
|
|
@@ -108,10 +147,14 @@ class ContextCache:
|
|
|
108
147
|
db_path: Path | None = None,
|
|
109
148
|
home_dir: Path | None = None,
|
|
110
149
|
) -> None:
|
|
111
|
-
self._home =
|
|
150
|
+
self._home = Path(home_dir) if home_dir is not None else canonical_data_root()
|
|
112
151
|
self._home.mkdir(parents=True, exist_ok=True)
|
|
113
152
|
|
|
114
|
-
raw = db_path or (
|
|
153
|
+
raw = db_path or (
|
|
154
|
+
Path(CACHE_DB_DEFAULT)
|
|
155
|
+
if home_dir is None
|
|
156
|
+
else self._home / "active_brain_cache.db"
|
|
157
|
+
)
|
|
115
158
|
self._db_path = safe_resolve(self._home, Path(raw).name) \
|
|
116
159
|
if Path(raw).parent == self._home else \
|
|
117
160
|
safe_resolve(self._home, raw)
|
|
@@ -181,7 +224,7 @@ class ContextCache:
|
|
|
181
224
|
);
|
|
182
225
|
"""
|
|
183
226
|
)
|
|
184
|
-
token =
|
|
227
|
+
token = _ensure_install_token_at(self._home)
|
|
185
228
|
now = int(time.time())
|
|
186
229
|
self._write_conn.execute(
|
|
187
230
|
"INSERT OR IGNORE INTO slm_meta (key, value, created_at) "
|
|
@@ -313,12 +356,17 @@ def read_entry_fast(
|
|
|
313
356
|
- stdlib-only — no heavy imports, no daemon HTTP call.
|
|
314
357
|
"""
|
|
315
358
|
try:
|
|
316
|
-
home =
|
|
359
|
+
home = Path(home_dir) if home_dir is not None else canonical_data_root()
|
|
317
360
|
if not home.exists():
|
|
318
361
|
return None
|
|
319
362
|
|
|
320
363
|
requested = db_path or Path(
|
|
321
|
-
os.environ.get("SLM_CACHE_DB")
|
|
364
|
+
os.environ.get("SLM_CACHE_DB")
|
|
365
|
+
or (
|
|
366
|
+
Path(CACHE_DB_DEFAULT)
|
|
367
|
+
if home_dir is None
|
|
368
|
+
else home / "active_brain_cache.db"
|
|
369
|
+
),
|
|
322
370
|
)
|
|
323
371
|
try:
|
|
324
372
|
resolved = safe_resolve(home, Path(requested).resolve())
|